diff -u --recursive --new-file v2.4.3/linux/CREDITS linux/CREDITS
--- v2.4.3/linux/CREDITS	Sun Mar 25 18:14:20 2001
+++ linux/CREDITS	Fri Apr 20 16:23:12 2001
@@ -311,9 +311,6 @@
 W: http://samba.org/~anton/
 P: 1024/8462A731 4C 55 86 34 44 59 A7 99  2B 97 88 4A 88 9A 0D 97
 D: sun4 port, Sparc hacker
-S: 47 Robert Street
-S: Marrickville NSW 2204
-S: Australia
 
 N: Hugh Blemings
 E: hugh@misc.nu
@@ -331,6 +328,9 @@
 D: AUN network protocols
 D: Co-architect of the parallel port sharing system
 D: IPv6 netfilter
+S: FutureTV Labs Ltd
+S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG
+S: United Kingdom
 
 N: Thomas Bogendörfer
 E: tsbogend@alpha.franken.de
@@ -766,6 +766,11 @@
 S: S-114 53 Stockholm
 S: Sweden
 
+N: Michael Engel
+E: engel@unix-ag.org
+D: DECstation framebuffer drivers
+S: Germany
+
 N: Paal-Kristian Engstad
 E: engstad@intermetrics.com
 D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
@@ -1116,8 +1121,8 @@
 E: rth@twiddle.net
 E: rth@cygnus.com
 D: Alpha hacker, kernel and userland
-S: 50 E. Middlefield #10
-S: Mountain View, California 94043
+S: 1668 California St.
+S: Mountain View, California 94041
 S: USA
 
 N: Benjamin Herrenschmidt
@@ -1220,13 +1225,12 @@
 S: USA
 
 N: Harald Hoyer
-E: HarryH@Royal.Net
-W: http://hot.spotline.de/
-W: http://home.pages.de/~saturn
+E: harald.hoyer@parzelle.de
+W: http://parzelle.de/
 D: ip_masq_quake
 D: md boot support
-S: Alleenstrasse 27
-S: D-71679 Asperg
+S: Hohe Strasse 30
+S: D-70176 Stuttgart
 S: Germany
 
 N: Jan Hubicka
@@ -1479,8 +1483,9 @@
 D: 6pack driver for AX.25
 
 N: Harald Koerfgen
-E: harald@unix-ag.org
-D: DECstation port
+E: hkoerfg@web.de
+D: Linux/MIPS kernel hacks and fixes,
+D: DECstation port, Sharp Mobilon port
 S: D-50931 Koeln
 S: Germany
 
@@ -1725,12 +1730,8 @@
 S: Czech Republic
 
 N: Paul Mackerras
-E: paulus@linuxcare.com
+E: paulus@samba.org
 D: Linux port for PCI Power Macintosh
-S: Linuxcare, Inc.
-S: 24 Marcus Clarke Street
-S: Canberra ACT 2601
-S: Australia
 
 N: Pat Mackinlay
 E: pat@it.com.au
@@ -1879,6 +1880,11 @@
 S: 80050-430 - Curitiba - Paraná
 S: Brazil
 
+N: Karsten Merker
+E: merker@linuxtag.org
+D: DECstation framebuffer drivers
+S: Germany
+
 N: Michael Meskes
 E: meskes@debian.org
 P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03  AB AB 15 A3 AE AD 39 7D
@@ -2359,8 +2365,8 @@
 S: Brazil
 
 N: Stephen Rothwell
-E: sfr@linuxcare.com.au
-W: http://linuxcare.com.au/sfr
+E: sfr@canb.auug.org.au
+W: http://www.canb.auug.org.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
 D: Author, APM driver
@@ -2403,12 +2409,12 @@
 S: Germany
 
 N: Paul `Rusty' Russell
-E: rusty@linuxcare.com
+E: rusty@rustcorp.com.au
 W: http://www.samba.org/netfilter
 D: Ruggedly handsome.
 D: netfilter, ipchains with Michael Neuling.
-S: 301/222 City Walk
-S: Canberra ACT 2601
+S: 52 Moore St
+S: Turner ACT 2612
 S: Australia
 
 N: Bill Ryder
@@ -2429,11 +2435,11 @@
 S: Finland
 
 N: Thomas Sailer
-E: sailer@ife.ee.ethz.ch
+E: t.sailer@alumni.ethz.ch
 E: HB9JNX@HB9W.CHE.EU (packet radio)
 D: hfmodem, Baycom and sound card radio modem driver
-S: Weinbergstrasse 76
-S: 8408 Winterthur
+S: Markusstrasse 18
+S: 8006 Zuerich
 S: Switzerland
 
 N: Robert Sanders
@@ -2516,6 +2522,14 @@
 S: San Jose, California
 S: USA
 
+N: Robert Siemer
+E: Robert.Siemer@gmx.de
+P: 2048/C99A4289 2F DC 17 2E 56 62 01 C8  3D F2 AC 09 F2 E5 DD EE
+D: miroSOUND PCM20 radio RDS driver, ACI rewrite
+S: Klosterweg 28 / i309
+S: 76131 Karlsruhe
+S: Germany
+
 N: Jaspreet Singh
 E: jaspreet@sangoma.com
 W: www.sangoma.com
@@ -2696,7 +2710,7 @@
 
 N: Andrew Tridgell
 E: tridge@samba.org
-W: http://linuxcare.com.au/tridge/
+W: http://samba.org/tridge/
 D: dosemu, networking, samba
 S: 3 Ballow Crescent
 S: MacGregor A.C.T 2615
diff -u --recursive --new-file v2.4.3/linux/Documentation/Changes linux/Documentation/Changes
--- v2.4.3/linux/Documentation/Changes	Tue Mar  6 19:44:34 2001
+++ linux/Documentation/Changes	Wed Apr 11 19:02:27 2001
@@ -31,7 +31,7 @@
 Eine deutsche Version dieser Datei finden Sie unter
 <http://www.stefan-winter.de/Changes-2.4.0.txt>.
 
-Last updated: January 11, 2001
+Last updated: April 6, 2001
 
 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
 
@@ -54,7 +54,7 @@
 o  util-linux             2.10o                   # fdformat --version
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.19                    # tune2fs
-o  reiserfsprogs          3.x.0d                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.x.0j                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -148,7 +148,7 @@
 --------
 
 Upgrade to recent modutils to fix various outstanding bugs which are
-seen more frequently under 2.3.x, and to enable auto-loading of USB
+seen more frequently under 2.4.x, and to enable auto-loading of USB
 modules.  In addition, the layout of modules under
 /lib/modules/`uname -r`/ has been made more sane.  This change also
 requires that you upgrade to a recent modutils.
@@ -227,7 +227,7 @@
 
 The PPP driver has been restructured to support multilink and to
 enable it to operate over diverse media layers.  If you use PPP,
-upgrade pppd to at least 2.4.0b1.
+upgrade pppd to at least 2.4.0.
 
 If you are not using devfs, you must have the device file /dev/ppp
 which can be made by:
@@ -307,16 +307,16 @@
 
 Mkinitrd
 --------
-o  <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/mkinitrd-2.9-1.src.rpm>
+o  <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/>
 
 E2fsprogs
 ---------
-o  <ftp://download.sourceforge.net/pub/sourceforge/e2fsprogs/e2fsprogs-1.19.tar.gz>
-o  <ftp://download.sourceforge.net/pub/sourceforge/e2fsprogs/e2fsprogs-1.19.src.rpm>
+o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19.tar.gz>
+o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19-0.src.rpm>
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0d.tar.gz>
+o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0j.tar.gz>
 
 LVM toolset
 -----------
@@ -347,7 +347,7 @@
 
 PPP
 ---
-o  <ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0.tar.gz>
+o  <ftp://ftp.samba.org/ppp/ppp-2.4.0.tar.gz>
 
 Isdn4k-utils
 ------------
diff -u --recursive --new-file v2.4.3/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.3/linux/Documentation/Configure.help	Sun Mar 25 18:24:31 2001
+++ linux/Documentation/Configure.help	Fri Apr 20 16:23:12 2001
@@ -13,8 +13,10 @@
 #     http://www.traduc.org/kernelfr
 #   - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at
 #     http://visar.csustan.edu/~carlos/
+#     XXX: Site has moved, new location has no Configure.help trans.
 #   - Italian, by Alessandro Rubini (rubini@linux.it), at
 #     ftp://ftp-pavia1.linux.it/pub/linux/Configure.help
+#     XXX: ftp-pavia1.linux.it: Non-existent host/domain
 #   - Polish, by Cezar Cichocki (cezar@cs.net.pl), at
 #     http://www.cs.net.pl/~cezar/Kernel
 #   - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch
@@ -268,6 +270,11 @@
   Most normal users won't need the RAM disk functionality, and can
   thus say N here.
 
+Default RAM disk size
+CONFIG_BLK_DEV_RAM_SIZE
+  The default value is 4096. Only change this if you know what are
+  you doing. If you are using IBM S/390, then set this to 8192.
+
 Initial RAM disk (initrd) support
 CONFIG_BLK_DEV_INITRD
   The initial RAM disk is a RAM disk that is loaded by the boot loader
@@ -415,7 +422,7 @@
 
   To fine-tune ATA/IDE drive/interface parameters for improved
   performance, look for the hdparm package at
-  ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ .
+  http://www.ibiblio.org/pub/Linux/system/hardware .
 
   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),
@@ -711,7 +718,7 @@
 IGNORE word93 Validation BITS
 CONFIG_IDEDMA_IVB
   Since various rules were applied and created ... et al. as it relates
-  the detection of vaild cable signals.  This is a result of unclear terms
+  the detection of valid cable signals.  This is a result of unclear terms
   in ATA-4 and ATA-5 standards.
 
   It is normally safe to answer Y; however, the default is N.
@@ -1299,14 +1306,37 @@
   have a high-level driver for the type of device that you want to
   support.
 
-MicroSolutions backpack protocol
+Micro Solutions BACKPACK Series 5 protocol
 CONFIG_PARIDE_BPCK
-  This option enables support for the MicroSolutions backpack parallel
-  port IDE protocol. If you chose to build PARIDE support into your
-  kernel, you may answer Y here to build in the protocol driver,
-  otherwise you should answer M to build it as a loadable module. The
-  module will be called bpck.o. You must also have a high-level driver
-  for the type of device that you want to support.
+  This option enables support for the Micro Solutions BACKPACK parallel
+  port Series 5 IDE protocol. (Most BACKPACK drives made before 1999 were 
+  Series 5) Series 5 drives will NOT always have the Series noted on the
+  bottom of the drive. Series 6 drivers will. 
+
+  In other words, if your BACKPACK drive dosen't say "Series 6" on the
+  bottom, enable this option.
+
+  If you chose to build PARIDE support into your kernel, you may answer Y
+  here to build in the protocol driver, otherwise you should answer M to
+  build it as a loadable module. The module will be called bpck.o. You
+  must also have a high-level driver for the type of device that you want
+  to support.
+
+Micro Solutions BACKPACK Series 6 protocol
+CONFIG_PARIDE_BPCK6
+  This option enables support for the Micro Solutions BACKPACK parallel
+  port Series 6 IDE protocol. (Most BACKPACK drives made after 1999 were 
+  Series 6) Series 6 drives will have the Series noted on the bottom of
+  the drive. Series 5 drivers don't always have it noted. 
+
+  In other words, if your BACKPACK drive says "Series 6" on the bottom,
+  enable this option.
+
+  If you chose to build PARIDE support into your kernel, you may answer Y
+  here to build in the protocol driver, otherwise you should answer M to
+  build it as a loadable module. The module will be called bpck6.o. You
+  must also have a high-level driver for the type of device that you want
+  to support.
 
 DataStor Commuter protocol
 CONFIG_PARIDE_COMM
@@ -1587,6 +1617,27 @@
   This enables support for the VR5000-based NEC DDB Vrc-5074
   evaluation board.
 
+Support for NEC DDB Vrc-5476
+CONFIG_DDB5476
+  This enables support for the R5432-based NEC DDB Vrc-5476
+  evaluation board.
+
+  Features : kernel debugging, serial terminal, NFS root fs, on-board
+  ether port (with a patch to tulip driver), IDE controller, PS2 keyboard
+  PS2 mouse, etc.
+
+  TODO : USB, Compact-PCI interface.
+
+Support for MIPS Atlas board
+CONFIG_MIPS_ATLAS
+  This enables support for the QED R5231-based MIPS Atlas evaluation
+  board.
+
+Support for MIPS Malta board
+CONFIG_MIPS_MALTA
+  This enables support for the VR5000-based MIPS Malta evaluation
+  board.
+
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
@@ -1616,12 +1667,12 @@
 CONFIG_SGI_SN0_N_MODE
   The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be
   configured in either N-Modes which allows for more nodes or M-Mode
-  which allows for more more memory.  Your system is most probably
+  which allows for more memory.  Your system is most probably
   running in M-Mode, so you should say N here.
 
 MIPS JAZZ onboard SONIC Ethernet support
 CONFIG_MIPS_JAZZ_SONIC
-  This is the driver for the onboard card of of MIPS Magnum 4000,
+  This is the driver for the onboard card of MIPS Magnum 4000,
   Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
 
 MIPS JAZZ FAS216 SCSI support
@@ -1630,6 +1681,12 @@
   4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
   systems.
 
+Kernel floating-point instruction emulation
+CONFIG_MIPS_FPU_EMULATOR
+  This option enables the MIPS software floatingpoint support.  Due to the
+  way floatingpoint works you should always enable this option unless
+  you exactly know what you're doing.
+
 PCMCIA SCSI adapter support
 CONFIG_SCSI_PCMCIA
   Say Y here if you intend to attach a PCMCIA or CardBus card to your
@@ -1726,6 +1783,10 @@
   certain types of data to get through the socket. Linux Socket
   Filtering works on all socket types except TCP for now. See the text
   file Documentation/networking/filter.txt for more information.
+
+  You need to say Y here if you want to use PPP packet filtering
+  (see the CONFIG_PPP_FILTER option below).
+
   If unsure, say N.
 
 Network packet filtering
@@ -2110,7 +2171,6 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
-
 TCP Explicit Congestion Notification support
 CONFIG_INET_ECN
   Explicit Congestion Notification (ECN) allows routers to notify
@@ -2386,7 +2446,7 @@
   of those special I/O ports.
 
 SGI PROM Console Support
-CONFIG_SGI_PROM_CONSOLE
+CONFIG_ARC_CONSOLE
   Say Y here if you want to use the PROMs for console I/O.
 
 SGI Zilog85C30 serial support
@@ -2433,20 +2493,6 @@
   a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
-CardBus serial device support
-CONFIG_PCMCIA_SERIAL_CB
-  Say Y here to enable support for CardBus serial devices, including
-  serial port cards, modems, and the modem functions of multi-function
-  ethernet/modem devices. (CardBus cards are the newer and better 
-  version of PCMCIA- or PC-cards: credit card size devices often 
-  used with laptops.)
-
-  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 serial_cb.o. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt. If unsure,
-  say N.
-
 /dev/agpgart (AGP Support) (EXPERIMENTAL)
 CONFIG_AGP
   AGP (Accelerated Graphics Port) is a bus system mainly used to
@@ -2821,14 +2867,6 @@
   section 6.4 of the Linux Programmer's Guide, available from
   http://www.linuxdoc.org/docs.html#guide .
 
-  Shared memory is now implemented using a new (minimal) virtual file
-  system. To mount it automatically at system startup just add the
-  following line to your /etc/fstab:
-
-  none	/dev/shm	shm	defaults	0 0
-
-  Saying Y here enlarges your kernel by about 18 KB. Just say Y.
-
 BSD Process Accounting
 CONFIG_BSD_PROCESS_ACCT
   If you say Y here, a user level program will be able to instruct the
@@ -2994,14 +3032,16 @@
    - "Pentium-Classic" for the Intel Pentium.
    - "Pentium-MMX" for the Intel Pentium MMX.
    - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II.
-   - "Pentium-III" for the Intel Pentium III.
-   - "Pentium-4" for the Intel Pentium 4
+   - "Pentium-III" for the Intel Pentium III
+     and Celerons based on the coppermine core.
+   - "Pentium-4" for the Intel Pentium 4.
    - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
-   - "Athlon" for the AMD Athlon (K7).
+   - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
    - "Crusoe" for the Transmeta Crusoe series.
    - "Winchip-C6" for original IDT Winchip.
    - "Winchip-2" for IDT Winchip 2.
    - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+   - "CyrixIII" for VIA Cyrix III or VIA C3.
 
   If you don't know what to do, choose "386".
 
@@ -3509,7 +3549,7 @@
 Virtual Frame Buffer support (ONLY FOR TESTING!)
 CONFIG_FB_VIRTUAL
   This is a `virtual' frame buffer device. It operates on a chunk of
-  unswapable kernel memory instead of on the memory of a graphics
+  unswappable kernel memory instead of on the memory of a graphics
   board. This means you cannot see any output sent to this frame
   buffer device, while it does consume precious memory. The main use
   of this frame buffer device is testing and debugging the frame
@@ -4301,7 +4341,7 @@
   packets with different FWMARK ("firewalling mark") values
   (see ipchains(8), "-m" argument).
 
-Appletalk interfaces support
+AppleTalk interfaces support
 CONFIG_APPLETALK
   AppleTalk is the way Apple computers speak to each other on a
   network. If your Linux box is connected to such a network and you
@@ -4314,11 +4354,10 @@
   want to join the conversation, say Y. You will need to use the
   netatalk package so that your Linux box can act as a print and file
   server for Macs as well as access AppleTalk printers. Check out
-  http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW
-  for details. EtherTalk is the name used for AppleTalk over Ethernet
-  and the cheaper and slower LocalTalk is AppleTalk over a proprietary
-  Apple network using serial links. EtherTalk and LocalTalk are fully
-  supported by Linux.
+  http://www.zettabyte.net/netatalk/ on the WWW for details. EtherTalk 
+  is the name used for AppleTalk over Ethernet and the cheaper and 
+  slower LocalTalk is AppleTalk over a proprietary Apple network using
+  serial links. EtherTalk and LocalTalk are fully supported by Linux.
 
   General information about how to connect Linux, Windows machines and
   Macs is on the WWW at http://www.eats.com/linux_mac_win.html . The
@@ -4329,8 +4368,10 @@
   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 is called appletalk.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. I hear that
-  the GNU boycott of Apple is over, so even politically correct people
+  module, say M here and read Documentation/modules.txt.  You almost
+  certainly want to compile it as a module so you can restart your 
+  AppleTalk stack without rebooting your machine.  I hear that the 
+  GNU boycott of Apple is over, so even politically correct people
   are allowed to say Y here.
 
 AppleTalk-IP driver support
@@ -4831,7 +4872,7 @@
   with the Frames Diverter on, can do some *really* transparent www 
   caching using a Squid proxy for example.
 
-  This is very usefull when you don't want to change your router's
+  This is very useful when you don't want to change your router's
   config (or if you simply don't have access to it).
 
   The other possible usages of diverting Ethernet Frames are numberous:
@@ -4916,7 +4957,7 @@
 
 Routing messages
 CONFIG_RTNETLINK
-  If you say Y here, userspace programs can receive some network
+  If you say Y here, user space programs can receive some network
   related routing information over the netlink. 'rtmon', supplied
   with the iproute2 package (ftp://ftp.inr.ac.ru), can read and
   interpret this data.  Information sent to the kernel over this link
@@ -5084,6 +5125,15 @@
   Note that extended debugging may create certain race conditions
   itself. Enable this ONLY if you suspect problems with the driver.
 
+Fujitsu FireStream (FS50/FS155)
+CONFIG_ATM_FIRESTREAM
+  Driver for the Fujitsu FireStream 155 (MB86697) and 
+  FireStream 50 (MB86695) ATM PCI chips.
+
+  This driver is also available as a module. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. The
+  module will be called firestream.o.
+
 Enable usec resolution timestamps
 CONFIG_ATM_ZATM_EXACT_TS
   The uPD98401 SAR chip supports a high-resolution timer (approx. 30
@@ -7068,6 +7118,17 @@
 
   If unsure, say N.
 
+PPP filtering (EXPERIMENTAL)
+CONFIG_PPP_FILTER
+  Say Y here if you want to be able to filter the packets passing over
+  PPP interfaces.  This allows you to control which packets count as
+  activity (i.e. which packets will reset the idle timer or bring up
+  a demand-dialled link) and which packets are to be dropped entirely.
+  You need to say Y here if you wish to use the pass-filter and
+  active-filter options to pppd.
+
+  If unsure, say N.
+
 PPP support for async serial ports
 CONFIG_PPP_ASYNC
   Say Y (or M) here if you want to be able to use PPP over standard
@@ -8078,6 +8139,18 @@
   The module will be called cosa.o. For general information about
   modules read Documentation/modules.txt.
 
+Etinc PCISYNC serial boards support
+CONFIG_DSCC4
+  This is a driver for Etinc PCISYNC boards based on the Infineon
+  (ex. Siemens) DSCC4 chipset. It is supposed to work with the four
+  ports card. Take a look at http://www.cogenit.fr/dscc4
+  for further informations about the driver and his configuration.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dscc4.o. For general information about
+  modules read Documentation/modules.txt.
+
 Lan Media sync serial boards support
 CONFIG_LANMEDIA
   This is a driver for the following Lan Media family of serial boards.
@@ -8164,13 +8237,26 @@
 
 Sangoma WANPIPE(tm) multiprotocol cards
 CONFIG_VENDOR_SANGOMA
-  WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is
-  a family of intelligent multiprotocol WAN adapters with data
-  transfer rates up to T1 (1.544 Mbps). They are also known as
-  Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
-  or S508. These cards support the X.25, Frame Relay, and PPP
-  protocols. If you have one or more of these cards, say Y to this
-  option; you may then also want to read the file
+
+  WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com)
+  is a family of intelligent multiprotocol WAN adapters with data 
+  transfer rates up to 4Mbps. They are also known as Synchronous 
+  Data Link Adapters (SDLA) and are designated as S514-PCI or S508-ISA. 
+  These cards support
+  
+    - X.25, Frame Relay, PPP, Cisco HDLC protocols. 
+  
+    - API support for protocols like HDLC (LAPB), 
+      HDLC Streaming, X.25, Frame Relay and BiSync. 
+  
+    - Ethernet Bridging over Frame Relay protocol.
+
+    - MULTILINK PPP
+
+    - Async PPP (Modem Dialup)
+
+  If you have one or more of these cards, say M to this option; you
+  may then also want to read the file  
   Documentation/networking/wanpipe.txt. The next questions will ask
   you about the protocols you want the driver to support.
 
@@ -8179,44 +8265,58 @@
   The module will be called wanpipe.o. For general information about
   modules read Documentation/modules.txt.
 
-Maximum number of cards
-CONFIG_WANPIPE_CARDS
-  Enter number of WANPIPE adapters installed in your machine. The
-  driver can support up to 8 cards. You may enter more than you
-  actually have if you plan to add more cards in the future without
-  re-compiling the driver, but remember that in this case you'll waste
-  some kernel memory (about 1K per card).
-
-WANPIPE Cisco HDLC support
-CONFIG_WANPIPE_CHDLC
-  Say Y to this option if you are planning to connect a WANPIPE card
-  to a connection which uses the synchronous Cisco HDLC (High-level
-  Data Link Control) protocol. This protocol is often used on
-  high-speed leased lines like T1/E1.
-
 WANPIPE X.25 support
 CONFIG_WANPIPE_X25
   Say Y to this option if you are planning to connect a WANPIPE card
-  to an X.25 network. You should then also have said Y to "CCITT X.25
-  Packet Layer" and "LAPB Data Link Driver", above. If you say N, the
-  X.25 support will not be included in the driver (saves about 16 KB
-  of kernel memory).
+  to an X.25 network.  Note, this feature also includes the X.25 API
+  support used to develope custom applications over the X.25 protocol.
+  If you say N, the X.25 support will not be included in the driver. 
+  The X.25 option is supported on S514-PCI and S508-ISA cards.
 
 WANPIPE Frame Relay support
 CONFIG_WANPIPE_FR
   Say Y to this option if you are planning to connect a WANPIPE card
-  to a frame relay network. You should then also have said Y to "Frame
-  Relay (DLCI) support", above. If you say N, the frame relay
-  support will not be included in the driver (saves about 16 KB of
-  kernel memory).
+  to a frame relay network, or use frame relay API to develope 
+  custom applications over the Frame  Relay protocol.  
+  This feature also contains the Ethernet Bridging over Frame Relay,
+  where a WANPIPE frame relay link can be directly connected to the Linux
+  kernel bridge. If you say N, the frame relay support will
+  not be included in the driver. The Frame Relay option is 
+  supported on S514-PCI and S508-ISA cards.
 
 WANPIPE PPP support
 CONFIG_WANPIPE_PPP
   Say Y to this option if you are planning to connect a WANPIPE card
-  to a leased line using Point-to-Point protocol (PPP). You should
-  then also have said Y to "PPP (point-to-point) support", above. If
-  you say N, the PPP support will not be included in the driver (saves
-  about 16 KB of kernel memory).
+  to a leased line using Point-to-Point protocol (PPP). If you say N,
+  the PPP support will not be included in the driver. The PPP option
+  is supported on S514-PCI/S508-ISA cards.
+
+WANPIPE MultiPort PPP support
+CONFIG_WANPIPE_MULTPPP
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a leased line using Point-to-Point protocol (PPP). Note, the
+  MultiPort PPP uses the Linux Kernel SyncPPP protocol over the Sangoma
+  HDLC Streaming adapter.  In this case each Sangoma adapter port 
+  can support an independent PPP connection.  For example, a single
+  Quad-Port PCI adapter can support up to four independent 
+  PPP links. If you say N,the PPP support will not be included 
+  in the driver. The PPP option is supported on S514-PCI/S508-ISA cards.
+ 	
+WANPIPE Cisco HDLC support
+CONFIG_WANPIPE_CHDLC
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a leased line using the Cisco HDLC protocol. This now supports
+  Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards. 
+  This support also allows user to build applications using the 
+  HDLC streaming API. 
+  
+  CHDLC Streaming driver also supports MULTILINK PPP
+  support that can bind multiple WANPIPE T1 cards into
+  a single logical channel.
+  
+  If you say  N, the Cisco HDLC support and 
+  HDLC streaming API and MULTILINK PPP will not be 
+  included in the driver.
 
 MultiGate/COMX support
 CONFIG_COMX
@@ -8288,7 +8388,7 @@
   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
@@ -8351,6 +8451,49 @@
   If you say N, the X.25 support will not be included in the driver
   (saves about 11 KB of kernel memory).
 
+Generic HDLC driver
+CONFIG_HDLC
+  Say Y to this option if your Linux box contains a WAN card supported
+  by this driver and you are planning to connect the box to a WAN
+  ( = Wide Area Network). You will need supporting software from
+  http://hq.pm.waw.pl/hdlc/.
+  Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
+  Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
+
+  If unsure, say N here.
+
+Synchronous Point-to-Point Protocol (PPP)
+CONFIG_HDLC_PPP
+  Say Y to this option if you want generic HDLC driver to support
+  PPP over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
+CCITT X.25 protocol
+CONFIG_HDLC_X25
+  Say Y to this option if you want generic HDLC driver to support
+  X.25 protocol over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
+SDL RISCom/N2 driver
+CONFIG_N2
+  This driver is for RISCom/N2 single or dual channel ISA cards
+  made by SDL Communications Inc. If you have such a card,
+  say Y here and see http://hq.pm.waw.pl/pub/hdlc/
+
+  Note that N2csu and N2dds cards are not supported by this driver.
+
+  If unsure, say N here.
+
+Moxa C101 driver
+CONFIG_C101
+  This driver is for C101 SuperSync ISA cards made by Moxa
+  Technologies Co., Ltd. If you have such a card,
+  say Y here and see http://hq.pm.waw.pl/pub/hdlc/
+
+  If unsure, say N here.
+
 Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
   Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
@@ -10055,62 +10198,100 @@
 Memory Technology Device (MTD) support
 CONFIG_MTD
   Memory Technology Devices are flash, RAM and similar chips, often
-  used for solid state filesystems on embedded devices. This option
+  used for solid state file systems on embedded devices. This option
   will provide the generic support for MTD drivers to register
   themselves with the kernel and for potential users of MTD devices
   to enumerate the devices which are present and obtain a handle on
   them. It will also allow you to select individual drivers for 
   particular hardware and users of MTD device. If unsure, say N.
 
+MTD debugging support
+CONFIG_MTD_DEBUG
+  This turns on low-level debugging for the entire MTD sub-system.
+
+MTD debugging verbosity
+CONFIG_MTD_DEBUG_VERBOSE
+  Determines the verbosity level of the MTD debugging messages.
+
 M-Systems Disk-On-Chip 1000 support
 CONFIG_MTD_DOC1000
   This provides an MTD device driver for the M-Systems DiskOnChip
   1000 devices, which are obsolete so you probably want to say 'N'.
 
-M-Systems Disk-On-Chip 2000 support
+M-Systems Disk-On-Chip 2000 and Millennium support
 CONFIG_MTD_DOC2000
   This provides an MTD device driver for the M-Systems DiskOnChip
-  2000 devices. If you use this, you probably also want the NFTL
-  'NAND Flash Translation Layer' below, which is used to emulate
+  2000 and Millennium devices. Originally designed for the DiskOnChip
+  2000, it also now includes support for the DiskOnChip Millennium.
+  If you have problems with this driver and the DiskOnChip Millennium,
+  you may wish to try the alternative Millennium driver below. To use
+  the alternative driver, you will need to undefine DOC_SINGLE_DRIVER
+  in the drivers/mtd/docprobe.c source code.
+
+  If you use this device, you probably also want to enable the NFTL
+  'NAND Flash Translation Layer' option below, which is used to emulate
   a block device by using a kind of filesystem on the flash chips.
 
-M-Systems Disk-On-Chip Millennium support
+Alternative Disk-On-Chip Millennium support
 CONFIG_MTD_DOC2001
-  This provides an MTD device driver for the M-Systems DiskOnChip
-  Millennium devices. If you use this, you probably also want the
-  NFTL 'NAND Flash Translation Layer' below, which is used to emulate
+  This provides an alternative MTD device driver for the M-Systems
+  DiskOnChip Millennium devices. Use this if you have problems with
+  the combined DiskOnChip 2000 and Millennium driver above. To get
+  the DiskOnChip probe code to load and use this driver instead of
+  the other one, you will need to undefine DOC_SINGLE_DRIVER near
+  the beginning of drivers/mtd/docprobe.c
+
+  If you use this device, you probably also want to enable the NFTL
+  'NAND Flash Translation Layer' option below, which is used to emulate
   a block device by using a kind of filesystem on the flash chips.
 
+Ramix PMC551 PCI Mezzanine ram card support
+CONFIG_MTD_PMC551
+  This provides a MTD device driver for the Ramix PMC551 RAM PCI card
+  from Ramix Inc. (http://www.ramix.com/products/memory/pmc551.html).
+  These devices come in memory configurations from 32M - 1G.  If you
+  have one, you probably want to enable this.
+
+  If this driver is compiled as a module you get the ability to select the
+  size of the aperture window pointing into the devices memory.  What this
+  means is that if you have a 1G card, normally the kernel will use a 1G
+  memory map as it's view of the device.  As a module, you can select a
+  1M window into the memory and the driver will "slide" the window around
+  the PMC551's memory.  This was particularly useful on the 2.2 kernels
+  on PPC architectures as there was limited kernel space to deal with.
+
 Use extra onboard system memory as MTD device
 CONFIG_MTD_SLRAM
   If your CPU cannot cache all of the physical memory in your machine,
   you can still use it for storage or swap by using this driver to
   present it to the system as a Memory Technology Device.
 
-Ramix PMC551 PCI Mezzanine ram card support
-CONFIG_MTD_PMC551
-  This provides an MTD device driver for the Ramix PMC551 RAM card.
-  If you have one, you probably want to enable this.
-
-PMC551 256M DRAM Bugfix.
+PMC551 256M DRAM Bugfix
 CONFIG_MTD_PMC551_BUGFIX
-  Some PMC551 boards hacve invalid column and row mux values. This 
-  option will fix them, but will break other memory configurations.
+  Some of Ramix's PMC551 boards with 256M configurations have invalid
+  column and row mux values. This option will fix them, but will break
+  other memory configurations.  If unsure say N.
+
+PMC551 Debugging
+CONFIG_MTD_PMC551_DEBUG
+  This option makes the PMC551 more verbose during it's operation and is
+  only really useful if you are developing on this driver or suspect a
+  possible hardware or driver bug.  If unsure say N.
 
 Debugging RAM test driver
 CONFIG_MTD_MTDRAM
-  This enables a test MTD device driver which uses vmalloc() to 
-  provide storage. You probably want to say 'N' unless you're 
-  testing stuff, or unless you want to use it in place of a ramdisk
-  when I've eventually got round to making the CONFIG_BLK_DEV option
-  and you've turned it off.
+  This enables a test MTD device driver which uses vmalloc() to
+  provide storage. You probably want to say 'N' unless you're
+  testing stuff.
 
 Common Flash Interface (CFI) support
 CONFIG_MTD_CFI
-  Intel's Common Flash Interface specification provides a universal
-  method for probing the capabilities of flash devices. If you wish
-  to support any device which uses CFI-compliant devices, you need
-  to enable this option.
+  The Common Flash Interface specification was developed by Intel,
+  AMD and other flash manufactures that provides a universal method
+  for probing the capabilities of flash devices. If you wish to
+  support any device that is CFI-compliant, you need to enable this
+  option. Visit (http://www.amd.com/products/nvd/overview/cfi.html)
+  for more information on CFI.
 
 CFI support for Intel/Sharp Extended Command Set chips
 CONFIG_MTD_CFI_INTELEXT
@@ -10122,10 +10303,10 @@
 Flash chip mapping in physical memory
 CONFIG_MTD_PHYSMAP
   This provides a 'mapping' driver which allows the CFI probe and
-  command set driver code to communicate with flash chips which 
+  command set driver code to communicate with flash chips which
   are mapped physically into the CPU's memory. You will need to
   configure the physical address and size of the flash chips on
-  your particular board.
+  your particular board as well as the bus width.
 
 Physical start location of flash chip mapping
 CONFIG_MTD_PHYSMAP_START
@@ -10143,38 +10324,51 @@
   map which should hopefully be in the documentation for your
   board. 
 
+CONFIG_MTD_PHYSMAP_BUSWIDTH
+  This is the total width of the data bus of the flash devices
+  in octets. For example, if you have a data bus width of 32
+  bits, you would set the bus width octect value to 4. This is
+  used internally by the CFI drivers.
+
 Flash chip mapping on Mixcom piggyback card
 CONFIG_MTD_MIXMEM
   This supports the paging arrangement for access to flash chips
-  on the Mixcom piggyback card, allowing the flash chip drivers 
-  to get on with their job of driving the flash chips without 
+  on the MixCOM piggyback card, allowing the flash chip drivers
+  to get on with their job of driving the flash chips without
   having to know about the paging. If you have one of these boards,
-  you probably want to enable this mapping driver.
+  you probably want to enable this mapping driver. More info is at
+  (http://www.itc.hu/).
 
 Flash chip mapping on Nora
 CONFIG_MTD_NORA
   If you had to ask, you don't have one. Say 'N'.
 
+Flash chip mapping on PNC2000
+CONFIG_MTD_PNC2000
+  PNC-2000 is the name of Network Camera product from PHOTRON
+  Ltd. in Japan. It uses CFI-compliant flash.
+
 Flash chip mapping on Octagon 5066 SBC
 CONFIG_MTD_OCTAGON
   This provides a 'mapping' driver which supports the way in which
   the flash chips are connected in the Octagon-5066 Single Board
-  Computer. You will also need to complete and enable the driver
-  for JEDEC flash chips.
+  Computer. More information on the board is available at
+  (http://www.octagonsystems.com/Products/5066/5066.html).
 
 Flash chip mapping on RPXlite PPC board
 CONFIG_MTD_RPXLITE
-  The RPXLite PowerPC board has CFI-compliant chips mapped in 
+  The RPXLite PowerPC board has CFI-compliant chips mapped in
   a strange sparse mapping. This 'mapping' driver supports that
   arrangement, allowing the CFI probe and command set driver code
-  to communicate with the chips on the RPXLite board.
+  to communicate with the chips on the RPXLite board. More at
+  (http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm).
 
 Flash chip mapping on Tempustech VMAX SBC301
 CONFIG_MTD_VMAX
   This provides a 'mapping' driver which supports the way in which
   the flash chips are connected in the Tempustech VMAX SBC301 Single
-  Board Computer. You will also need to complete and enable the driver
-  for JEDEC flash chips.
+  Board Computer. More information on the board is available at
+  (http://www.tempustech.com/tt301.htm).
 
 Direct chardevice access to MTD devices
 CONFIG_MTD_CHAR
@@ -10195,15 +10389,15 @@
 
   Later, it may be extended to perform read/erase/modify/write cycles
   on flash chips to emulate a smaller block size. Needless to say,
-  this is very unsafe, but could be useful for filesystems which are
+  this is very unsafe, but could be useful for file systems which are
   almost never written to.
 
 FTL (Flash Translation Layer) support
 CONFIG_FTL
   This provides support for the original Flash Translation Layer which
   is part of the PCMCIA specification. It uses a kind of pseudo-
-  filesystem on a flash device to emulate a block device with 512-byte
-  sectors, on top of which you put a 'normal' filesystem. You may find
+  file system on a flash device to emulate a block device with 512-byte
+  sectors, on top of which you put a 'normal' file system. You may find
   that the algorithms used in this code are patented unless you live
   in the Free World where software patents aren't legal - in the USA
   you are only permitted to use this on PCMCIA hardware, although 
@@ -10214,8 +10408,8 @@
 CONFIG_NFTL
   This provides support for the NAND Flash Translation Layer which is
   used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
-  filesystem on a flash device to emulate a block device with 512-byte
-  sectors, on top of which you put a 'normal' filesystem. You may find
+  file system on a flash device to emulate a block device with 512-byte
+  sectors, on top of which you put a 'normal' file system. You may find
   that the algorithms used in this code are patented unless you live
   in the Free World where software patents aren't legal - in the USA
   you are only permitted to use this on DiskOnChip hardware, although 
@@ -10224,8 +10418,8 @@
 
 Write support for NFTL (EXPERIMENTAL)
 CONFIG_NFTL_RW
-  If you're lucky, this will actually work. Don't whinge if it doesn't.
-  Contact dwmw2@infradead.org if you want to help to make it more 
+  If you're lucky, this will actually work. Don't whine if it doesn't.
+  Contact (dwmw2@infradead.org) if you want to help to make it more
   reliable.
 
 Support for USB
@@ -10399,6 +10593,16 @@
 
   If unsure, say Y.
 
+Input core support
+CONFIG_INPUT
+  Say Y here if you want to enable any of the following options for
+  USB Human Interface Device (HID) support.
+
+  Say Y here if you want to enable any of the USB HID options in the
+  USB support section which require Input core support.
+
+  Otherwise, say N.
+
 Keyboard support
 CONFIG_INPUT_KEYBDEV
   Say Y here if you want your USB HID keyboard (or an ADB keyboard
@@ -10826,16 +11030,16 @@
 USB device file system
 CONFIG_USB_DEVICEFS
   If you say Y here (and to "/proc file system support" below), you
-  will get a file /proc/usb/devices which lists the devices currently
-  connected to your USB busses, a file /proc/usb/drivers which lists
-  the USB kernel client drivers currently loaded, and for every
-  connected device a file named "/proc/usb/xxx/yyy", where xxx is the
-  bus number and yyy the device number; the latter files can be used
-  by user space programs to talk directly to the device. These files
-  are "virtual", meaning they are generated on the fly and not stored
-  on the hard drive.
+  will get a file /proc/bus/usb/devices which lists the devices
+  currently connected to your USB busses, a file /proc/bus/usb/drivers
+  which lists the USB kernel client drivers currently loaded, and for
+  every connected device a file named "/proc/bus/usb/xxx/yyy", where
+  xxx is the bus number and yyy the device number; the latter files
+  can be used by user space programs to talk directly to the device.
+  These files are "virtual", meaning they are generated on the fly
+  and not stored on the hard drive.
   
-  For the format of the /proc/usb/ files, please read
+  For the format of the /proc/bus/usb/ files, please read
   Documentation/usb/proc_usb_info.txt. 
 
   Please note that this code is completely unrelated to devfs, the
@@ -11072,23 +11276,44 @@
 
   If unsure, say N.
    
+Virtual memory file system support
+CONFIG_TMPFS
+  Tmpfs is a file system which keeps all files in virtual memory.
+
+  In contrast to RAM disks, which get allocated a fixed amount of
+  physical RAM, tmpfs grows and shrinks to accommodate the files it
+  contains and is able to swap unneeded pages out to swap space.
+
+  Everything is "virtual" in the sense that no files will be created
+  on your hard drive; if you reboot, everything in tmpfs will be
+  lost.
+  
+  You should mount the filesystem somewhere to be able to use
+  POSIX shared memory. Adding the following line to /etc/fstab should
+  take care of things:
+
+  tmpfs		/dev/shm	tmpfs		defaults	0 0
+
+  Remember to create the directory that you intend to mount tmpfs on
+  if necessary (/dev/shm is automagically created if you use devfs).
+
+  You can set limits for the number of blocks and inodes used by the
+  filesystem with the mount options "size", "nr_blocks" and
+  "nr_inodes". These parameters accept a suffix k, m or g for kilo,
+  mega and giga and can be changed on remount.
+  
+  The initial permissions of the root directory can be set with the
+  mount option "mode".
+
 Simple RAM-based file system support
 CONFIG_RAMFS
   Ramfs is a file system which keeps all files in RAM. It allows
   read and write access.
 
-  In contrast to RAM disks, which get allocated a fixed amount of RAM,
-  ramfs grows and shrinks to accommodate the files it contains.
+  It is more of an programming example than a useable filesystem. If
+  you need a file system which lives in RAM with limit checking use
+  tmpfs.
 
-  Before you can use this RAM-based file system, it has to be mounted,
-  meaning it has to be given a location in the directory hierarchy. If
-  you want to use the location /ramfiles for example, you would have
-  to create that directory first and then mount the file system by
-  saying "mount -t ramfs ramfs /ramfiles" or the equivalent line in
-  /etc/fstab. Everything is "virtual" in the sense that no files will
-  be created on your hard drive; if you reboot, everything in
-  /ramfiles will be lost.
-  
   If you want to compile this 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
@@ -11634,21 +11859,16 @@
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called efs.o. 
 
-Journalling Flash File System (JFFS) support (EXPERIMENTAL)
+Support for the Journalling Flash Filesystem
 CONFIG_JFFS_FS
-  JFFS is a new file system designed for use on flash memory devices
-  rather than on block devices. It was developed on the 2.0 kernel
-  by Axis Communications AB for use on their Linux-based products,
-  and released under GPL, then 'borrowed' and ported to work with 
-  the 2.4 kernel and the new Memory Technology Device system. 
-
-  The 2.4 port is experimental and not yet supported by Axis. Basically,
-  the good bits are probably theirs, and if it's broken in 2.4 it's 
-  probably our fault. See http://www.developer.axis.com/software/jffs/
-  for more information about JFFS.
-
-  Any potential patches or queries should be sent to Axis' mailing 
-  list for JFFS: <jffs-dev@axis.com>
+  JFFS is the Journaling Flash File System developed by Axis
+  Communications in Sweden, aimed at providing a crash/powerdown-safe
+  filesystem for disk-less embedded devices. Further information is
+  available at (http://developer.axis.com/software/jffs/).
+
+JFFS debugging verbosity
+CONFIG_JFFS_FS_VERBOSE
+  Determines the verbosity level of the JFFS debugging messages.
 
 UFS file system support (read-only)
 CONFIG_UFS_FS
@@ -11723,6 +11943,12 @@
   file system support", above. If you don't know what all this is
   about, say N.
 
+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.
+
 Sun partition tables support
 CONFIG_SUN_PARTITION
   Like most systems, SunOS uses its own hard disk partition table
@@ -11749,6 +11975,12 @@
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
+Ultrix partition support
+CONFIG_ULTRIX_PARTITION
+  Say Y here if you would like to be able to read the hard disk
+  partition table format used by DEC (now Compaq) Ultrix machines.
+  Otherwise, say N.
+
 ADFS file system support (EXPERIMENTAL)
 CONFIG_ADFS_FS
   The Acorn Disc Filing System is the standard file system of the
@@ -11998,7 +12230,7 @@
 
 nls default codepage
 CONFIG_NLS_DEFAULT
-  The default NLS used when mounting filesystem. Currently, the valid
+  The default NLS used when mounting file system. Currently, the valid
   values are:
   big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861,
   cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936,
@@ -12187,7 +12419,7 @@
 
 nls codepage 932
 CONFIG_NLS_CODEPAGE_932
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft FAT file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -12199,7 +12431,7 @@
 
 nls codepage 936
 CONFIG_NLS_CODEPAGE_936
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft FAT file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -12210,7 +12442,7 @@
 
 nls codepage 949
 CONFIG_NLS_CODEPAGE_949
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft FAT file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -12220,7 +12452,7 @@
 
 nls codepage 950
 CONFIG_NLS_CODEPAGE_950
-  The Microsoft fat filesystem family can deal with filenames in
+  The Microsoft FAT file system family can deal with filenames in
   native language character sets. These character sets are stored in
   so-called DOS codepages. You need to include the appropriate
   codepage if you want to be able to read/write these filenames on
@@ -12736,8 +12968,8 @@
   how to pass options to the kernel at boot time.) The syntax of the
   "lp" command line option can be found in drivers/char/lp.c.
 
-  If you have more than 3 printers, you need to increase the LP_NO
-  variable in lp.c.
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
 
 Support for console on line printer
 CONFIG_LP_CONSOLE
@@ -13742,17 +13974,32 @@
   module, say M here and read Documentation/modules.txt. Most people
   will say N.
 
+ZF MachZ Watchdog
+CONFIG_MACHZ_WDT
+  If you are using a ZF Micro MachZ processor, say Y here, otherwise N.
+  This is the driver for the watchdog timer builtin on that processor
+  using ZF-Logic interface. This watchdog simply watches your kernel to
+  make sure it doesn't freeze, and if it does, it reboots your computer
+  after a certain amount of time.
+
+  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 is called machzwd.o. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
+
 Toshiba Laptop support
 CONFIG_TOSHIBA
-  If you intend to run this the kernel on a Toshiba portable say yes
-  here. This adds a driver to safely access the System Management
-  Mode of the CPU on Toshiba portables. The System Management Mode
+  This adds a driver to safely access the System Management Mode
+  of the CPU on Toshiba portables. The System Management Mode
   is used to set the BIOS and power saving options on Toshiba portables.
 
   For information on utilities to make use of this driver see the
-  Toshiba Linux utilities website at:
+  Toshiba Linux utilities web site at:
   http://www.buzzard.org.uk/toshiba/
 
+  Say Y if you intend to run this kernel on a Toshiba portable.
+  Say N otherwise.
+
 /dev/cpu/microcode - Intel IA32 CPU microcode support
 CONFIG_MICROCODE
   If you say Y here and also to "/dev file system support" in the
@@ -13787,6 +14034,18 @@
   with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
   /dev/cpu/31/cpuid.
 
+SBC-60XX Watchdog Timer
+CONFIG_60XX_WDT
+ This driver can be used with the watchdog timer found on some
+ single board computers, namely the 6010 PII based computer.
+ It may well work with other cards.  It reads port 0x443 to enable
+ and re-set the watchdog timer, and reads port 0x45 to disable
+ the watchdog.  If you have a card that behave in similar ways,
+ you can probably make this driver work with your card as well.
+
+ You can compile this driver directly into the kernel, or use
+ it as a module.  The module will be called sbc60xxwdt.o.
+
 Enhanced Real Time Clock Support
 CONFIG_RTC
   If you say Y here and create a character special file /dev/rtc with
@@ -14253,6 +14512,8 @@
   16 or Logitech SoundMan 16 sound card. Answer N if you have some
   other card made by Media Vision or Logitech since those are not
   PAS16 compatible. Please read Documentation/sound/PAS16.
+  It is not necessary to add Sound Blaster support separately; it
+  is included in PAS support.
 
   If you compile the driver into the kernel, you have to add
   "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
@@ -14459,13 +14720,15 @@
   See Documentation/sound/CS4232 for more information on configuring
   this card.
 
-Support for Yamaha OPL3-SA2, SA3, and SAx based PnP cards
+Support for Yamaha OPL3-SA2 and SA3 based PnP cards
 CONFIG_SOUND_OPL3SA2
   Say Y or M if you have a card based on one of these Yamaha
-  sound chipsets. Read Documentation/sound/OPL3-SA2 for more
-  information on configuring these cards.
+  sound chipsets or the "SAx", which is actually a SA3. Read
+  Documentation/sound/OPL3-SA2 for more information on configuring
+  these cards.
 
-  If you compile the driver into the kernel, you have to add
+  If you compile the driver into the kernel and do not also
+  configure in the optional ISA PnP support, you will have to add
   "opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>" to the kernel
   command line.
 
@@ -14647,7 +14910,7 @@
 
 SC-6600 CDROM Interface
 CONFIG_SC6600_CDROM
-  This is used to activate the the CDROM interface of the Audio Excel
+  This is used to activate the CDROM interface of the Audio Excel
   DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no
   CDROM present.
 
@@ -14661,6 +14924,11 @@
   driver as a module you have to specify the MPU I/O base address with
   the parameter 'mpu_base=0xNNN'.
 
+C-Media PCI (CMI8338/8378)
+CONFIG_SOUND_CMPCI
+  Say Y or M if you have a PCI sound card using the CMI8338
+  or the CMI8378 chip.set.
+
 Creative EMU10K1 based PCI sound cards
 CONFIG_SOUND_EMU10K1
   Say Y or M if you have a PCI sound card using the EMU10K1
@@ -15289,10 +15557,10 @@
   Enable support for the AVM T1 T1B card.
   Note: This is a PRI card and handle 30 B-channels.
 
-AVM C4 support
+AVM C4/C2 support
 CONFIG_ISDN_DRV_AVMB1_C4
-  Enable support for the AVM C4 PCI card.
-  This card handle 4 BRI ISDN lines (8 channels).
+  Enable support for the AVM C4/C2 PCI cards.
+  These cards handle 4/2 BRI ISDN lines (8/4 channels).
 
 Verbose reason code reporting (kernel size +=7K)
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
@@ -16523,6 +16791,68 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+IBM's S/390 architecture
+CONFIG_ARCH_S390
+  Select this option, if you want to run the Kernel on one of IBM's
+  mainframes of the S/390 generation. You should have installed the
+  s390-compiler released by IBM (based on gcc-2.95.1) before.
+
+Merge some code into the kernel to make the image IPLable
+CONFIG_IPLABLE
+  If you want to use the produced kernel to IPL directly from a
+  device, you have to merge a bootsector specific to the device
+  into the first bytes of the kernel. You will have to select the
+  IPL device on another question, that pops up, when you select
+  CONFIG_IPLABE.
+
+IPL from a /390 tape unit
+CONFIG_IPL_TAPE
+  Select this option if you want to IPL the image from a Tape.
+
+IPL from a virtual card reader emulated by VM/ESA
+CONFIG_IPL_RDR_VM
+  Select this option if you are running under VM/ESA and want 
+  to IPL the image from the emulated card reader.
+
+IPL from a real card reader
+CONFIG_IPL_RDR
+  Select this option if you want to IPL the image from a real
+  card reader. Maybe you still got one and want to try. We didn't
+  test.
+
+IBMs S/390 Harddisks (DASDs)
+CONFIG_DASD
+  Enable this option if you want to access DASDs directly utilizing
+  S/390s channel subsystem commands. This is necessary for running
+  natively on a single image or an LPAR.
+
+Enable DASD fast write
+CONFIG_DASD_FAST_IO
+  Enable fast I/O for DASDs. That means that the next I/O command
+  is already issued at interrupt time, if an I/O request is pending.
+  This option gives significant speedup of I/O, because we don't
+  schedule the bottom-halves as often as Intel.
+
+Support for IBM-style disk-labels (S/390)
+CONFIG_S390_PARTITION
+  Enable this option to assure standard IBM labels on the DASDs.
+  You must enable it, if you are planning to access DASDs also
+  attached to another IBM mainframe operation system (OS/390, 
+  VM/ESA, VSE/ESA).
+
+ECKD devices
+CONFIG_DASD_ECKD
+  ECKD devices are the most commonly used devices. you should enable
+  this option unless you are very sure to have no ECKD device.
+
+CKD devices
+CONFIG_DASD_CKD
+  CKD devices are currently unsupported.
+
+FBA devices
+CONFIG_DASD_FBA
+  FBA devices are currently unsupported.
+
 SAB3036 tuner support
 CONFIG_TUNER_3036
   Say Y here to include support for Philips SAB3036 compatible tuners.
@@ -16559,7 +16889,7 @@
   Saying N will reduce the size of the Footbridge kernel.
 
 Include support for the EBSA285
-CONFIG_ARCH_EBSA285
+CONFIG_ARCH_EBSA285_HOST
   Say Y here if you intend to run this kernel on the EBSA285 card
   in host ("central function") mode.
 
@@ -16645,50 +16975,14 @@
   http://www.visuaide.com/pagevictor.en.html for information on
   this system.
 
-Support ARM610 processor
-CONFIG_CPU_ARM6
-  Say Y here if you wish to include support for the ARM610 processor.
-
-Support ARM710 processor
-CONFIG_CPU_ARM7
-  Say Y here if you wish to include support for the ARM710 processor.
-
-Support StrongARM(R) SA-110 processor
-CONFIG_CPU_SA110
-  Say Y here if you wish to include support for the Intel(R)
-  StrongARM(R) SA-110 processor.
-
-Support ARM720 processor
-CONFIG_CPU_ARM720
-  Say Y here if you wish to include support for the ARM720 processor.
-
-Support ARM920
-CONFIG_CPU_ARM920
-  Say Y here if you wish to include support for the ARM920 processor.
-
-Support ARM610 processor
-CONFIG_CPU_ARM6
-  Say Y here if you wish to include support for the ARM610 processor.
-
-Support ARM710 processor
-CONFIG_CPU_ARM7
-  Say Y here if you wish to include support for the ARM710 processor.
-
-Support StrongARM(R) SA-110 processor
-CONFIG_CPU_SA110
-  Say Y here if you wish to include support for the Intel(R)
-  StrongARM(R) SA-110 processor.
-
-Support ARM720 processor
-CONFIG_CPU_ARM720
-  Say Y here if you wish to include support for the ARM720 processor.
-
-Support ARM920
-CONFIG_CPU_ARM920
-  Say Y here if you wish to include support for the ARM920 processor.
+Load kernel using Angel Debug Monitor
+CONFIG_ANGELBOOT
+  Say Y if you plan to load the kernel using Angel, ARM Ltd's target
+  debug stub.  If you are not using Angel, you must say N.  It is
+  important to get this setting correct.
 
 Math emulation
-CONFIG_NWFPE
+CONFIG_FPE_NWFPE
   Say Y to include the NWFPE floating point emulator in the kernel.
   This is necessary to run most binaries. Linux does not currently
   support floating point hardware so you need to say Y here even if
@@ -16702,6 +16996,23 @@
   You may say N here if you are going to load the Acorn FPEmulator
   early in the bootup.
 
+CONFIG_FPE_FASTFPE
+  Say Y here to include the FAST floating point emulator in the kernel.
+  This is an experimental much faster emulator which has only 32 bit
+  precision for the mantissa. It does not support any exceptions. This
+  makes it very simple, it is approximately 4-8 times faster than NWFPE.
+
+  It should be sufficient for most programs. It is definitely not
+  suitable if you do scientific calculations that need double precision
+  for iteration formulas that sum up lots of very small numbers. If you
+  do not feel you need a faster FP emulation you should better choose
+  NWFPE.
+
+  It is also possible to say M to build the emulator as a module
+  (fastfpe.o). But keep in mind that you should only load the FP emulator
+  early in the bootup. You should never change from NWFPE to FASTFPE or
+  vice versa in an active system!
+
 DS1620 Thermometer support
 CONFIG_DS1620
   Say Y here to include support for the thermal management hardware
@@ -16721,11 +17032,12 @@
   you are concerned with the code size or don't want to see these
   messages.
 
-Compile kernel with frame pointer
-CONFIG_FRAME_POINTER
-  If you say Y here, the resulting kernel will be slightly larger and
-  slower, but it will give useful debugging information. If you don't
-  debug the kernel, you can say N.
+Compile kernel without frame pointer
+CONFIG_NO_FRAME_POINTER
+  If you say Y here, the resulting kernel will be slightly smaller and
+  faster. However, when a problem occurs with the kernel, the
+  information that is reported is severely limited. Most people
+  should say N here.
 
 User fault debugging
 CONFIG_DEBUG_USER
@@ -16833,6 +17145,21 @@
   you can make the first serial port the console by answering Y to
   this option.
 
+L7200 SDB keyboard support
+CONFIG_KEYBOARD_L7200
+  Enable this option if you would like to be able to use a keyboard
+  on a LinkUp Systems L7200 board.
+
+L7200 SDB Fujitsu keyboard support
+CONFIG_KEYBOARD_L7200_NORM
+  Select the Fujitsu keyboard if you want a normal QWERTY style
+  keyboard on the LinkUp SDB.
+
+L7200 SDB Prototype keyboard support
+CONFIG_KEYBOARD_L7200_DEMO
+  Select the prototype keyboard if you want to play with the
+  LCD/keyboard combination on the LinkUp SDB.
+
 Footbridge Mode
 CONFIG_HOST_FOOTBRIDGE
   The 21285 Footbridge chip can operate in either `host mode' or
@@ -16903,8 +17230,7 @@
   infrared communication and is supported by most laptops and PDA's.
 
   To use Linux support for the IrDA (tm) protocols, you will also need
-  some user-space utilities like the irmanager and probably irattach
-  as well. For more information, see the file
+  some user-space utilities like irattach. For more information, see the file
   Documentation/networking/irda.txt. You also want to read the
   IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto .
 
@@ -16912,6 +17238,10 @@
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+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
@@ -16976,6 +17306,17 @@
   to another Linux machine running the IrLAN protocol for ad-hoc 
   networking!
 
+IrNET Protocol 
+CONFIG_IRNET
+  Say Y here if you want to build support for the IrNET protocol. If
+  you want to compile it as a module (irnet.o), say M here and read
+  Documentation/modules.txt. IrNET is a PPP driver, so you will also
+  need a working PPP subsystem (driver, daemon and config)...
+
+  IrNET is an alternate way to tranfer TCP/IP traffic over IrDA. It
+  uses synchronous PPP over a set of point to point IrDA sockets. You
+  can use it between Linux machine or with W2k.
+
 IrCOMM Protocol
 CONFIG_IRCOMM
   Say Y here if you want to build support for the IrCOMM protocol. If
@@ -17350,7 +17691,7 @@
 # LocalWords:  howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip
 # LocalWords:  proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS
 # LocalWords:  telnetting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl
-# LocalWords:  Mb SKB IPX Novell dosemu Appletalk DDP ATALK vmalloc visar ehome
+# LocalWords:  Mb SKB IPX Novell dosemu DDP ATALK vmalloc visar ehome
 # LocalWords:  SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA
 # LocalWords:  buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
 # LocalWords:  QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES
@@ -17378,7 +17719,7 @@
 # LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
 # LocalWords:  carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb
 # LocalWords:  pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
-# LocalWords:  RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
+# LocalWords:  RTNETLINK mknod xos MTU lwared Macs netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
 # LocalWords:  ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp
 # LocalWords:  thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern
@@ -17395,7 +17736,7 @@
 # LocalWords:  Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT
 # LocalWords:  OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP
 # LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles  XXXX LVM lvm
-ICN EDSS Cisco
+# LocalWords:  ICN EDSS Cisco
 # LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
 # LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
 # LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
@@ -17522,7 +17863,7 @@
 # LocalWords:  AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA
 # LocalWords:  swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs
 # LocalWords:  CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS
-# LocalWords:  CGthree TCX unswapable vfb fbcon hicolor truecolor AFB ILBM SOC
+# LocalWords:  CGthree TCX unswappable vfb fbcon hicolor truecolor AFB ILBM SOC
 # LocalWords:  IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx
 # LocalWords:  PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss pvv kerneli hd
 # LocalWords:  synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX Nx
diff -u --recursive --new-file v2.4.3/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.4.3/linux/Documentation/DMA-mapping.txt	Tue Mar  6 22:44:15 2001
+++ linux/Documentation/DMA-mapping.txt	Thu Apr 19 08:38:48 2001
@@ -32,6 +32,35 @@
 the dma_addr_t type which should be used everywhere you hold a DMA
 (bus) address returned from the DMA mapping functions.
 
+			 What memory is DMA'able?
+
+The first piece of information you must know is what kernel memory can
+be used with the DMA mapping facilitites.  There has been an unwritten
+set of rules regarding this, and this text is an attempt to finally
+write them down.
+
+If you acquired your memory via the page allocator
+(i.e. __get_free_page*()) or the generic memory allocators
+(i.e. kmalloc() or kmem_cache_alloc()) then you may DMA to/from
+that memory using the addresses returned from those routines.
+
+This means specifically that you may _not_ use the memory/addresses
+returned from vmalloc() for DMA.  It is possible to DMA to the
+_underlying_ memory mapped into a vmalloc() area, but this requires
+walking page tables to get the physical addresses, and then
+translating each of those pages back to a kernel address using
+something like __va().
+
+This rule also means that you may not use kernel image addresses
+(ie. items in the kernel's data/text/bss segment, or your driver's)
+nor may you use kernel stack addresses for DMA.  Both of these items
+might be mapped somewhere entirely different than the rest of physical
+memory.
+
+What about block I/O and networking buffers?  The block I/O and
+networking subsystems make sure that the buffers they use are valid
+for you to DMA from/to.
+
 			DMA addressing limitations
 
 Does your device have any DMA addressing limitations?  For example, is
@@ -168,16 +197,21 @@
   optimizations the hardware allows.  To this end, when using
   such mappings you must be explicit about what you want to happen.
 
+Neither type of DMA mapping has alignment restrictions that come
+from PCI, although some devices may have such restrictions.
+
 		 Using Consistent DMA mappings.
 
-To allocate and map a consistent DMA region, you should do:
+To allocate and map large (PAGE_SIZE or so) consistent DMA regions,
+you should do:
 
 	dma_addr_t dma_handle;
 
 	cpu_addr = pci_alloc_consistent(dev, size, &dma_handle);
 
 where dev is a struct pci_dev *. You should pass NULL for PCI like buses
-where devices don't have struct pci_dev (like ISA, EISA).
+where devices don't have struct pci_dev (like ISA, EISA).  This may be
+called in interrupt context. 
 
 This argument is needed because the DMA translations may be bus
 specific (and often is private to the bus which the device is attached
@@ -186,7 +220,9 @@
 Size is the length of the region you want to allocate.
 
 This routine will allocate RAM for that region, so it acts similarly to
-__get_free_pages (but takes size instead of a page order).
+__get_free_pages (but takes size instead of a page order).  If your
+driver needs regions sized smaller than a page, you may prefer using
+the pci_pool interface, described below.
 
 It returns two values: the virtual address which you can use to access
 it from the CPU and dma_handle which you pass to the card.
@@ -205,6 +241,51 @@
 where dev, size are the same as in the above call and cpu_addr and
 dma_handle are the values pci_alloc_consistent returned to you.
 
+If your driver needs lots of smaller memory regions, you can write
+custom code to subdivide pages returned by pci_alloc_consistent,
+or you can use the pci_pool API to do that.  A pci_pool is like
+a kmem_cache, but it uses pci_alloc_consistent not __get_free_pages.
+Also, it understands common hardware constraints for alignment,
+like queue heads needing to be aligned on N byte boundaries.
+
+Create a pci_pool like this:
+
+	struct pci_pool *pool;
+
+	pool = pci_pool_create(name, dev, size, align, alloc, flags);
+
+The "name" is for diagnostics (like a kmem_cache name); dev and size
+are as above.  The device's hardware alignment requirement for this
+type of data is "align" (a power of two).  The flags are SLAB_ flags
+as you'd pass to kmem_cache_create.  Not all flags are understood, but
+SLAB_POISON may help you find driver bugs.  If you call this in a non-
+sleeping context (f.e. in_interrupt is true or while holding SMP
+locks), pass SLAB_ATOMIC.  If your device has no boundary crossing
+restrictions, pass 0 for alloc; passing 4096 says memory allocated
+from this pool must not cross 4KByte boundaries.
+
+Allocate memory from a pci pool like this:
+
+	cpu_addr = pci_pool_alloc(pool, flags, &dma_handle);
+
+flags are SLAB_KERNEL if blocking is permitted (not in_interrupt nor
+holding SMP locks), SLAB_ATOMIC otherwise.  Like pci_alloc_consistent,
+this returns two values, cpu_addr and dma_handle,
+
+Free memory that was allocated from a pci_pool like this:
+
+	pci_pool_free(pool, cpu_addr, dma_handle);
+
+where pool is what you passed to pci_pool_alloc, and cpu_addr and
+dma_handle are the values pci_pool_alloc returned.
+
+Destroy a pci_pool by calling:
+
+	pci_pool_destroy(pool);
+
+Make sure you've called pci_pool_free for all memory allocated
+from a pool before you destroy the pool.
+
 			DMA Direction
 
 The interfaces described in subsequent portions of this document
@@ -389,9 +470,10 @@
 longer, nor should they use bus_to_virt. Some drivers have to be changed a
 little bit, because there is no longer an equivalent to bus_to_virt in the
 dynamic DMA mapping scheme - you have to always store the DMA addresses
-returned by the pci_alloc_consistent and pci_map_single calls (pci_map_sg
-stores them in the scatterlist itself if the platform supports dynamic DMA
-mapping in hardware) in your driver structures and/or in the card registers.
+returned by the pci_alloc_consistent, pci_pool_alloc, and pci_map_single
+calls (pci_map_sg stores them in the scatterlist itself if the platform
+supports dynamic DMA mapping in hardware) in your driver structures and/or
+in the card registers.
 
 This document, and the API itself, would not be in it's current
 form without the feedback and suggestions from numerous individuals.
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile
--- v2.4.3/linux/Documentation/DocBook/Makefile	Sat Feb  3 12:43:55 2001
+++ linux/Documentation/DocBook/Makefile	Fri Apr  6 10:42:55 2001
@@ -1,6 +1,7 @@
 BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
 	   kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
-	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml
+	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
+	   deviceiobook.sgml
 
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -9,12 +10,12 @@
 EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook))
 JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook))
 
+books:	$(BOOKS)
+
 $(BOOKS): $(TOPDIR)/scripts/docproc
 
 .PHONY:	books ps pdf html clean mrproper
 
-books:	$(BOOKS)
-
 ps:	$(PS)
 
 pdf:	$(PDF)
@@ -55,6 +56,9 @@
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \
 		<sis900.tmpl >sis900.sgml
 
+deviceiobook.sgml: deviceiobook.tmpl
+	$(TOPDIR)/scripts/docgen <deviceiobook.tmpl >deviceiobook.sgml
+
 mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \
 		<mcabook.tmpl >mcabook.sgml
@@ -64,6 +68,7 @@
 		<videobook.tmpl >videobook.sgml
 
 APISOURCES :=	$(TOPDIR)/drivers/media/video/videodev.c \
+		$(TOPDIR)/arch/i386/kernel/irq.c \
 		$(TOPDIR)/arch/i386/kernel/mca.c \
 		$(TOPDIR)/arch/i386/kernel/mtrr.c \
 		$(TOPDIR)/drivers/char/misc.c \
@@ -77,11 +82,24 @@
 		$(TOPDIR)/drivers/net/wan/syncppp.c \
 		$(TOPDIR)/drivers/net/wan/z85230.c \
 		$(TOPDIR)/drivers/usb/usb.c \
-		$(TOPDIR)/fs/locks.c \
+		$(TOPDIR)/drivers/video/fbmem.c \
+		$(TOPDIR)/drivers/video/fbcmap.c \
+		$(TOPDIR)/drivers/video/fbcon.c \
+		$(TOPDIR)/drivers/video/fbgen.c \
+		$(TOPDIR)/drivers/video/fonts.c \
+		$(TOPDIR)/drivers/video/macmodes.c \
+		$(TOPDIR)/drivers/video/modedb.c \
 		$(TOPDIR)/fs/devfs/base.c \
+		$(TOPDIR)/fs/locks.c \
+		$(TOPDIR)/include/asm-i386/bitops.h \
 		$(TOPDIR)/kernel/pm.c \
 		$(TOPDIR)/kernel/ksyms.c \
 		$(TOPDIR)/kernel/kmod.c \
+		$(TOPDIR)/kernel/printk.c \
+		$(TOPDIR)/kernel/sched.c \
+		$(TOPDIR)/kernel/sysctl.c \
+		$(TOPDIR)/lib/string.c \
+		$(TOPDIR)/lib/vsprintf.c \
 		$(TOPDIR)/net/netsyms.c
  
 kernel-api.sgml: kernel-api.tmpl $(APISOURCES)
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/deviceiobook.tmpl linux/Documentation/DocBook/deviceiobook.tmpl
--- v2.4.3/linux/Documentation/DocBook/deviceiobook.tmpl	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/DocBook/deviceiobook.tmpl	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,232 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="DoingIO">
+ <bookinfo>
+  <title>Bus-Independent Device Accesses</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Matthew</firstname>
+    <surname>Wilcox</surname>
+    <affiliation>
+     <address>
+      <email>matthew@wil.cx</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <authorgroup>
+   <author>
+    <firstname>Alan</firstname>
+    <surname>Cox</surname>
+    <affiliation>
+     <address>
+      <email>alan@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2001</year>
+   <holder>Matthew Wilcox</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+      <title>Introduction</title>
+  <para>
+	Linux provides an API which abstracts performing IO across all busses
+	and devices, allowing device drivers to be written independently of
+	bus type.
+  </para>
+  </chapter>
+
+  <chapter id="bugs">
+     <title>Known Bugs And Assumptions</title>
+  <para>
+	None.	
+  </para>
+  </chapter>
+
+  <chapter id="mmio">
+    <title>Memory Mapped IO</title>
+    <sect1>
+      <title>Getting Access to the Device</title>
+      <para>
+	The most widely supported form of IO is memory mapped IO.
+	That is, a part of the CPU's address space is interpreted
+	not as accesses to memory, but as accesses to a device.  Some
+	architectures define devices to be at a fixed address, but most
+	have some method of discovering devices.  The PCI bus walk is a
+	good example of such a scheme.	This document does not cover how
+	to receive such an address, but assumes you are starting with one.
+	Physical addresses are of type unsigned long. 
+      </para>
+
+      <para>
+	This address should not be used directly.  Instead, to get an
+	address suitable for passing to the accessor functions described
+	below, you should call <function>ioremap</function>.
+	An address suitable for accessing the device will be returned to you.
+      </para>
+
+      <para>
+	After you've finished using the device (say, in your module's
+	exit routine), call <function>iounmap</function> in order to return
+	the address space to the kernel.  Most architectures allocate new
+	address space each time you call <function>ioremap</function>, and
+	they can run out unless you call <function>iounmap</function>.
+      </para>
+    </sect1>
+
+    <sect1>
+      <title>Accessing the device</title>
+      <para>
+	The part of the interface most used by drivers is reading and
+	writing memory-mapped registers on the device.	Linux provides
+	interfaces to read and write 8-bit, 16-bit, 32-bit and 64-bit
+	quantities.  Due to a historical accident, these are named byte,
+	word, long and quad accesses.  Both read and write accesses are
+	supported; there is no prefetch support at this time.
+      </para>
+
+      <para>
+	The functions are named <function>readb</function>,
+	<function>readw</function>, <function>readl</function>,
+	<function>readq</function>, <function>writeb</function>,
+	<function>writew</function>, <function>writel</function> and
+	<function>writeq</function>.
+      </para>
+
+      <para>
+	Some devices (such as framebuffers) would like to use larger
+	transfers than 8 bytes at a time.  For these devices, the
+	<function>memcpy_toio</function>, <function>memcpy_fromio</function>
+	and <function>memset_io</function> functions are provided.
+	Do not use memset or memcpy on IO addresses; they
+	are not guaranteed to copy data in order.
+      </para>
+
+      <para>
+	The read and write functions are defined to be ordered. That is the
+	compiler is not permitted to reorder the I/O sequence. When the 
+	ordering can be compiler optimised, you can use <function>
+	__readb</function> and friends to indicate the relaxed ordering. Use 
+	this with care. The <function>rmb</function> provides a read memory 
+	barrier. The <function>wmb</function> provides a write memory barrier.
+      </para>
+
+      <para>
+	While the basic functions are defined to be synchronous with respect
+	to each other and ordered with respect to each other the busses the
+	devices sit on may themselves have asynchronocity. In paticular many
+	authors are burned by the fact that PCI bus writes are posted
+	asynchronously. A driver author must issue a read from the same
+	device to ensure that writes have occurred in the specific cases the
+	author cares. This kind of property cannot be hidden from driver
+	writers in the API.
+      </para>
+    </sect1>
+
+    <sect1>
+      <title>ISA legacy functions</title>
+      <para>
+	On older kernels (2.2 and earlier) the ISA bus could be read or
+	written with these functions and without ioremap being used. This is
+	no longer true in Linux 2.4. A set of equivalent functions exist for
+	easy legacy driver porting. The functions available are prefixed
+	with 'isa_' and are <function>isa_readb</function>,
+	<function>isa_writeb</function>, <function>isa_readw</function>, 
+	<function>isa_writew</function>, <function>isa_readl</function>,
+	<function>isa_writel</function), <function>isa_memcpy_fromio</function>
+	and <function>isa_memcpy_toio</function>
+      </para>
+      <para>
+	These functions should not be used in new drivers, and will
+	eventually be going away.
+      </para>
+    </sect1>
+
+  </chapter>
+
+  <chapter>
+    <title>Port Space Accesses</title>
+    <sect1>
+      <title>Port Space Explained</title>
+
+      <para>
+	Another form of IO commonly supported is Port Space.  This is a
+	range of addresses separate to the normal memory address space.
+	Access to these addresses is generally not as fast as accesses
+	to the memory mapped addresses, and it also has a potentially
+	smaller address space.
+      </para>
+
+      <para>
+	Unlike memory mapped IO, no preparation is required
+	to access port space.
+      </para>
+
+    </sect1>
+    <sect1>
+      <title>Accessing Port Space</title>
+      <para>
+	Accesses to this space are provided through a set of functions
+	which allow 8-bit, 16-bit and 32-bit accesses; also
+	known as byte, word and long.  These functions are
+	<function>inb</function>, <function>inw</function>,
+	<function>inl</function>, <function>outb</function>,
+	<function>outw</function> and <function>outl</function>.
+      </para>
+
+      <para>
+	Some variants are provided for these functions.  Some devices
+	require that accesses to their ports are slowed down.  This
+	functionality is provided by appending a <function>_p</function>
+	to the end of the function.  There are also equivalents to memcpy.
+	The <function>ins</function> and <function>outs</function>
+	functions copy bytes, words or longs to the given port.
+      </para>
+    </sect1>
+
+  </chapter>
+
+  <chapter id="pubfunctions">
+     <title>Public Functions Provided</title>
+!Einclude/asm-i386/io.h
+  </chapter>
+
+</book>
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl
--- v2.4.3/linux/Documentation/DocBook/kernel-api.tmpl	Fri Mar  2 18:43:10 2001
+++ linux/Documentation/DocBook/kernel-api.tmpl	Fri Apr  6 10:42:55 2001
@@ -36,7 +36,7 @@
 <toc></toc>
 
   <chapter id="Basics">
-     <title>Driver Basic</title>
+     <title>Driver Basics</title>
      <sect1><title>Driver Entry and Exit points</title>
 !Iinclude/linux/init.h
      </sect1>
@@ -44,6 +44,10 @@
      <sect1><title>Atomics</title>
 !Iinclude/asm-i386/atomic.h
      </sect1>
+
+     <sect1><title>Delaying, scheduling, and timer routines</title>
+!Ekernel/sched.c
+     </sect1>
   </chapter>
 
   <chapter id="adt">
@@ -53,6 +57,29 @@
      </sect1>
   </chapter>
 
+  <chapter id="libc">
+     <title>Basic C Library Functions</title>
+
+     <para>
+       When writing drivers, you cannot in general use routines which are
+       from the C Library.  Some of the functions have been found generally
+       useful and they are listed below.  The behaviour of these functions
+       may vary slightly from those defined by ANSI, and these deviations
+       are noted in the text.
+     </para>
+
+     <sect1><title>String Conversions</title>
+!Ilib/vsprintf.c
+!Elib/vsprintf.c
+     </sect1>
+     <sect1><title>String Manipulation</title>
+!Ilib/string.c
+     </sect1>
+     <sect1><title>Bit Operations</title>
+!Iinclude/asm-i386/bitops.h
+     </sect1>
+  </chapter>
+
   <chapter id="mm">
      <title>Memory Management in Linux</title>
      <sect1><title>The Slab Cache</title>
@@ -60,6 +87,14 @@
       </sect1>
   </chapter>
 
+  <chapter id="proc">
+     <title>The proc filesystem</title>
+ 
+     <sect1><title>sysctl interface</title>
+!Ekernel/sysctl.c
+     </sect1>
+  </chapter>
+
   <chapter id="vfs">
      <title>The Linux VFS</title>
      <sect1><title>The Directory Cache</title>
@@ -177,5 +212,68 @@
 !Edrivers/net/wan/z85230.c
   </chapter>
 
+  <chapter id="fbdev">
+     <title>Frame Buffer Library</title>
+
+     <para>
+       The frame buffer drivers depend heavily on four data structures.  
+       These structures are declared in include/linux/fb.h.  They are 
+       fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs. 
+       The last three can be made available to and from userland. 
+     </para>
+
+     <para>
+       fb_info defines the current state of a particular video card. 
+       Inside fb_info, there exists a fb_ops structure which is a 
+       collection of needed functions to make fbdev and fbcon work.
+       fb_info is only visible to the kernel.
+     </para>
+
+     <para>
+       fb_var_screeninfo is used to describe the features of a video card 
+       that are user defined.  With fb_var_screeninfo, things such as
+       depth and the resolution may be defined.
+     </para>
+
+     <para>
+       The next structure is fb_fix_screeninfo. This defines the 
+       properties of a card that are created when a mode is set and can't 
+       be changed otherwise.  A good example of this is the start of the 
+       frame buffer memory.  This "locks" the address of the frame buffer
+       memory, so that it cannot be changed or moved.
+     </para>
+
+     <para>
+       The last structure is fb_monospecs. In the old API, there was 
+       little importance for fb_monospecs. This allowed for forbidden things 
+       such as setting a mode of 800x600 on a fix frequency monitor. With 
+       the new API, fb_monospecs prevents such things, and if used 
+       correctly, can prevent a monitor from being cooked.  fb_monospecs
+       will not be useful until kernels 2.5.x.
+     </para>
+
+     <sect1><title>Frame Buffer Memory</title>
+!Edrivers/video/fbmem.c
+     </sect1>
+     <sect1><title>Frame Buffer Console</title>
+!Edrivers/video/fbcon.c
+     </sect1>
+     <sect1><title>Frame Buffer Colormap</title>
+!Edrivers/video/fbcmap.c
+     </sect1>
+     <sect1><title>Frame Buffer Generic Functions</title>
+!Idrivers/video/fbgen.c
+     </sect1>
+     <sect1><title>Frame Buffer Video Mode Database</title>
+!Idrivers/video/modedb.c
+!Edrivers/video/modedb.c
+     </sect1>
+     <sect1><title>Frame Buffer Macintosh Video Mode Database</title>
+!Idrivers/video/macmodes.c
+     </sect1>
+     <sect1><title>Frame Buffer Fonts</title>
+!Idrivers/video/fonts.c
+     </sect1>
+  </chapter>
 
 </book>
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl
--- v2.4.3/linux/Documentation/DocBook/kernel-hacking.tmpl	Thu Feb  8 16:32:44 2001
+++ linux/Documentation/DocBook/kernel-hacking.tmpl	Fri Apr  6 10:42:55 2001
@@ -11,7 +11,7 @@
     <surname>Russell</surname>
     <affiliation>
      <address>
-      <email>rusty@linuxcare.com</email>
+      <email>rusty@rustcorp.com.au</email>
      </address>
     </affiliation>
    </author>
@@ -336,6 +336,11 @@
   </para>
 
   <para>
+   If all your routine does is read or write some parameter, consider
+   implementing a <function>sysctl</function> interface instead.
+  </para>
+
+  <para>
    Inside the ioctl you're in user context to a process.  When a
    error occurs you return a negated errno (see
    <filename class=headerfile>include/linux/errno.h</filename>),
@@ -407,7 +412,7 @@
   <para>
    Note that some functions may sleep implicitly: common ones are
    the user space access functions (*_user) and memory allocation
-   functions without GFP_ATOMIC.
+   functions without <symbol>GFP_ATOMIC</symbol>.
   </para>
 
   <para>
@@ -608,7 +613,8 @@
     for some weird device, you have a problem: it is poorly supported
     in Linux because after some time memory fragmentation in a running
     kernel makes it hard.  The best way is to allocate the block early
-    in the boot process.
+    in the boot process via the <function>alloc_bootmem()</function>
+    routine.
    </para>
 
    <para>
@@ -631,6 +637,20 @@
    </para>
   </sect1>
 
+  <sect1 id="routines-udelay">
+   <title><function>udelay()</function>/<function>mdelay()</function>
+     <filename class=headerfile>include/asm/delay.h</filename> 
+     <filename class=headerfile>include/linux/delay.h</filename> 
+   </title>
+
+   <para>
+    The <function>udelay()</function> function can be used for small pauses.
+    Do not use large values with <function>udelay()</function> as you risk
+    overflow - the helper function <function>mdelay()</function> is useful
+    here, or even consider <function>schedule_timeout()</function>.
+   </para> 
+  </sect1>
+ 
   <sect1 id="routines-local-irqs">
    <title><function>local_irq_save()</function>/<function>local_irq_restore()</function>
     <filename class=headerfile>include/asm/system.h</filename>
@@ -687,8 +707,14 @@
     modules this directive is currently ignored).  <type>__exit</type>
     is used to declare a function which is only required on exit: the
     function will be dropped if this file is not compiled as a module.
-    See the header file for use.
+    See the header file for use. Note that it makes no sense for a function
+    marked with <type>__init</type> to be exported to modules with 
+    <function>EXPORT_SYMBOL()</function> - this will break.
    </para>
+   <para>
+   Static data structures marked as <type>__initdata</type> must be initialised
+   (as opposed to ordinary static data which is zeroed BSS).
+   </para> 
 
   </sect1>
 
@@ -775,6 +801,21 @@
         return 0;
 }
    </programlisting>
+
+   <para>
+   You can often avoid having to deal with these problems by using the 
+   <structfield>owner</structfield> field of the 
+   <structname>file_operations</structname> structure. Set this field
+   as the macro <symbol>THIS_MODULE</symbol>.
+   </para>
+
+   <para>
+   For more complicated module unload locking requirements, you can set the
+   <structfield>can_unload</structfield> function pointer to your own routine,
+   which should return <returnvalue>0</returnvalue> if the module is
+   unloadable, or <returnvalue>-EBUSY</returnvalue> otherwise.
+   </para> 
+  
   </sect1>
  </chapter>
 
@@ -822,6 +863,17 @@
     <returnvalue>-ERESTARTSYS</returnvalue> if a signal is received.
     The <function>wait_event()</function> version ignores signals.
    </para>
+   <para>
+   Do not use the <function>sleep_on()</function> function family -
+   it is very easy to accidentally introduce races; almost certainly
+   one of the <function>wait_event()</function> family will do, or a
+   loop around <function>schedule_timeout()</function>. If you choose
+   to loop around <function>schedule_timeout()</function> remember
+   you must set the task state (with 
+   <function>set_current_state()</function>) on each iteration to avoid
+   busy-looping.
+   </para>
+ 
   </sect1>
 
   <sect1 id="queue-waking">
@@ -1212,6 +1264,13 @@
      <filename>MAINTAINERS</filename> means you want to be consulted
      when changes are made to a subsystem, and hear about bugs; it
      implies a more-than-passing commitment to some part of the code.
+    </para>
+   </listitem>
+   
+   <listitem>
+    <para>
+     Finally, don't forget to read <filename>Documentation/SubmittingPatches</filename>
+     and possibly <filename>Documentation/SubmittingDrivers</filename>.
     </para>
    </listitem>
   </itemizedlist>
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl
--- v2.4.3/linux/Documentation/DocBook/kernel-locking.tmpl	Fri Feb 16 15:53:08 2001
+++ linux/Documentation/DocBook/kernel-locking.tmpl	Fri Apr  6 10:42:55 2001
@@ -11,7 +11,7 @@
     <surname>Russell</surname>
     <affiliation>
      <address>
-      <email>rusty@linuxcare.com</email>
+      <email>rusty@rustcorp.com.au</email>
      </address>
     </affiliation>
    </author>
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/parportbook.tmpl linux/Documentation/DocBook/parportbook.tmpl
--- v2.4.3/linux/Documentation/DocBook/parportbook.tmpl	Wed Jul 12 16:24:33 2000
+++ linux/Documentation/DocBook/parportbook.tmpl	Thu Apr 12 12:05:50 2001
@@ -2079,7 +2079,7 @@
                               | PARPORT_STATUS_BUSY);
         unsigned char val = (PARPORT_STATUS_ERROR
                               | PARPORT_STATUS_BUSY);
-        struct parport_frob_struct frob;
+        struct ppdev_frob_struct frob;
         struct timespec ts;
 
         /* Wait for printer to be ready */
diff -u --recursive --new-file v2.4.3/linux/Documentation/DocBook/tulip-user.tmpl linux/Documentation/DocBook/tulip-user.tmpl
--- v2.4.3/linux/Documentation/DocBook/tulip-user.tmpl	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/DocBook/tulip-user.tmpl	Wed Apr 18 14:40:06 2001
@@ -0,0 +1,325 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="TulipUserGuide">
+ <bookinfo>
+  <title>Tulip Driver User's Guide</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Jeff</firstname>
+    <surname>Garzik</surname>
+    <affiliation>
+     <address>
+      <email>jgarzik@mandrakesoft.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2001</year>
+   <holder>Jeff Garzik</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+  <chapter id="intro">
+    <title>Introduction</title>
+<para>
+The Tulip Ethernet Card Driver
+is maintained by Jeff Garzik (<email>jgarzik@mandrakesoft.com</email>).
+</para>
+
+<para>
+The Tulip driver was developed by Donald Becker and changed by
+Jeff Garzik, Takashi Manabe and a cast of thousands.
+</para>
+
+<para>
+For 2.4.x and later kernels, the Linux Tulip driver is available at
+<ULink URL="http://sourceforge.net/projects/tulip/">http://sourceforge.net/projects/tulip/</ULink>
+</para>
+
+<para>
+	This driver is for the Digital "Tulip" Ethernet adapter interface.
+	It should work with most DEC 21*4*-based chips/ethercards, as well as
+	with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
+</para>
+
+<para>
+        The original author may be reached as becker@scyld.com, or C/O
+        Scyld Computing Corporation,
+        410 Severn Ave., Suite 210,
+        Annapolis MD 21403
+</para>
+
+<para>
+	Additional information on Donald Becker's tulip.c
+	is available at <ULink URL="http://www.scyld.com/network/tulip.html">http://www.scyld.com/network/tulip.html</ULink>
+</para>
+
+  </chapter>
+
+  <chapter id="drvr_compat">
+    <title>Driver Compatibility</title>
+
+<para>
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI (now owned by Intel).
+Supported members of the family
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported.
+</para>
+
+<para>
+These chips are used on at least 140 unique PCI board designs.  The great
+number of chips and board designs supported is the reason for the
+driver size and complexity.  Almost of the increasing complexity is in the
+board configuration and media selection code.  There is very little
+increasing in the operational critical path length.
+</para>
+  </chapter>
+
+  <chapter id="board_settings">
+    <title>Board-specific Settings</title>
+
+<para>
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+</para>
+
+<para>
+Some boards have EEPROMs tables with default media entry.  The factory default
+is usually "autoselect".  This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation.
+</para>
+  </chapter>
+
+  <chapter id="driver_operation">
+    <title>Driver Operation</title>
+
+<sect1><title>Ring buffers</title>
+
+<para>
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers.  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 and replaced by a newly allocated
+skbuff.
+</para>
+
+<para>
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information).  For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data.  A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+</para>
+
+</sect1>
+
+<sect1><title>Synchronization</title>
+<para>
+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 other software.
+</para>
+
+<para>
+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 'tp->tx_full' flag.
+</para>
+
+<para>
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)	 After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+</para>
+
+</sect1>
+
+  </chapter>
+
+  <chapter id="errata">
+    <title>Errata</title>
+
+<para>
+The old DEC databooks were light on details.
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written.  Hmmm, now how is that possible?
+</para>
+
+<para>
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below.  Some boards do not have EEPROM
+media tables and need to be patched up.  Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
+</para>
+
+<para>
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them.  The MII transceiver status is polled using an kernel timer.
+</para>
+  </chapter>
+
+  <chapter id="changelog">
+    <title>Driver Change History</title>
+
+    <sect1><title>Version 0.9.14 (February 20, 2001)</title>
+    <itemizedlist>
+    <listitem><para>Fix PNIC problems (Manfred Spraul)</para></listitem>
+    <listitem><para>Add new PCI id for Accton comet</para></listitem>
+    <listitem><para>Support Davicom tulips</para></listitem>
+    <listitem><para>Fix oops in eeprom parsing</para></listitem>
+    <listitem><para>Enable workarounds for early PCI chipsets</para></listitem>
+    <listitem><para>IA64, hppa csr0 support</para></listitem>
+    <listitem><para>Support media types 5, 6</para></listitem>
+    <listitem><para>Interpret a bit more of the 21142 SROM extended media type 3</para></listitem>
+    <listitem><para>Add missing delay in eeprom reading</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.11 (November 3, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Eliminate extra bus accesses when sharing interrupts (prumpf)</para></listitem>
+    <listitem><para>Barrier following ownership descriptor bit flip (prumpf)</para></listitem>
+    <listitem><para>Endianness fixes for >14 addresses in setup frames (prumpf)</para></listitem>
+    <listitem><para>Report link beat to kernel/userspace via netif_carrier_*. (kuznet)</para></listitem>
+    <listitem><para>Better spinlocking in set_rx_mode.</para></listitem>
+    <listitem><para>Fix I/O resource request failure error messages (DaveM catch)</para></listitem>
+    <listitem><para>Handle DMA allocation failure.</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.10 (September 6, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Simple interrupt mitigation (via jamal)</para></listitem>
+    <listitem><para>More PCI ids</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.9 (August 11, 2000)</title>
+    <itemizedlist>
+    <listitem><para>More PCI ids</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.8 (July 13, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Correct signed/unsigned comparison for dummy frame index</para></listitem>
+    <listitem><para>Remove outdated references to struct enet_statistics</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.7 (June 17, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Timer cleanups (Andrew Morton)</para></listitem>
+    <listitem><para>Alpha compile fix (somebody?)</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.6 (May 31, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Revert 21143-related support flag patch</para></listitem>
+    <listitem><para>Add HPPA/media-table debugging printk</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.5 (May 30, 2000)</title>
+    <itemizedlist>
+    <listitem><para>HPPA support (willy@puffingroup)</para></listitem>
+    <listitem><para>CSR6 bits and tulip.h cleanup (Chris Smith)</para></listitem>
+    <listitem><para>Improve debugging messages a bit</para></listitem>
+    <listitem><para>Add delay after CSR13 write in t21142_start_nway</para></listitem>
+    <listitem><para>Remove unused ETHER_STATS code</para></listitem>
+    <listitem><para>Convert 'extern inline' to 'static inline' in tulip.h (Chris Smith)</para></listitem>
+    <listitem><para>Update DS21143 support flags in tulip_chip_info[]</para></listitem>
+    <listitem><para>Use spin_lock_irq, not _irqsave/restore, in tulip_start_xmit()</para></listitem>
+    <listitem><para>Add locking to set_rx_mode()</para></listitem>
+    <listitem><para>Fix race with chip setting DescOwned bit (Hal Murray)</para></listitem>
+    <listitem><para>Request 100% of PIO and MMIO resource space assigned to card</para></listitem>
+    <listitem><para>Remove error message from pci_enable_device failure</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.4.3 (April 14, 2000)</title>
+    <itemizedlist>
+    <listitem><para>mod_timer fix (Hal Murray)</para></listitem>
+    <listitem><para>PNIC2 resuscitation (Chris Smith)</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.4.2 (March 21, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Fix 21041 CSR7, CSR13/14/15 handling</para></listitem>
+    <listitem><para>Merge some PCI ids from tulip 0.91x</para></listitem>
+    <listitem><para>Merge some HAS_xxx flags and flag settings from tulip 0.91x</para></listitem>
+    <listitem><para>asm/io.h fix (submitted by many) and cleanup</para></listitem>
+    <listitem><para>s/HAS_NWAY143/HAS_NWAY/</para></listitem>
+    <listitem><para>Cleanup 21041 mode reporting</para></listitem>
+    <listitem><para>Small code cleanups</para></listitem>
+    </itemizedlist>
+    </sect1>
+
+    <sect1><title>Version 0.9.4.1 (March 18, 2000)</title>
+    <itemizedlist>
+    <listitem><para>Finish PCI DMA conversion (davem)</para></listitem>
+    <listitem><para>Do not netif_start_queue() at end of tulip_tx_timeout() (kuznet)</para></listitem>
+    <listitem><para>PCI DMA fix (kuznet)</para></listitem>
+    <listitem><para>eeprom.c code cleanup</para></listitem>
+    <listitem><para>Remove Xircom Tulip crud</para></listitem>
+    </itemizedlist>
+    </sect1>
+  </chapter>
+
+</book>
diff -u --recursive --new-file v2.4.3/linux/Documentation/SubmittingDrivers linux/Documentation/SubmittingDrivers
--- v2.4.3/linux/Documentation/SubmittingDrivers	Thu Feb  8 16:32:44 2001
+++ linux/Documentation/SubmittingDrivers	Fri Apr  6 10:42:55 2001
@@ -111,7 +111,7 @@
 
 Kernel traffic:
 	Weekly summary of kernel list activity (much easier to read)
-	[http://kt.linuxcare.com/kernel-traffic]
+	[http://kt.zork.net/kernel-traffic]
 
 Linux USB project:
 	http://sourceforge.net/projects/linux-usb/
diff -u --recursive --new-file v2.4.3/linux/Documentation/arm/README linux/Documentation/arm/README
--- v2.4.3/linux/Documentation/arm/README	Mon Nov 27 17:07:59 2000
+++ linux/Documentation/arm/README	Wed Apr 11 19:02:27 2001
@@ -1,5 +1,5 @@
-			   ARM Linux 2.4.0test1
-			   ====================
+			   ARM Linux 2.4
+			   =============
 
     Please check ftp.arm.linux.org.uk:/pub/armlinux for latest updates.
 
@@ -7,9 +7,8 @@
 ---------------------
 
   In order to compile ARM Linux, you will need a compiler capable of
-  generating ARM ELF code with GNU extensions.  GCC-2.7.2.2 ELF, GCC 2.8.1
-  and EGCS are good compilers.  Note that GCC-2.7.2.2 ELF is rare, and
-  you probably don't have it.
+  generating ARM ELF code with GNU extensions.  GCC 2.95.1 and EGCS 1.1.2
+  are good compilers.
 
   To build ARM Linux natively, you shouldn't have to alter the ARCH = line
   in the top level Makefile.  However, if you don't have the ARM Linux ELF
@@ -166,4 +165,4 @@
   receive a reply within one day.
 
 ---
-Russell King (12/06/2000)
+Russell King (26/01/2001)
diff -u --recursive --new-file v2.4.3/linux/Documentation/cris/README linux/Documentation/cris/README
--- v2.4.3/linux/Documentation/cris/README	Thu Feb  8 16:32:44 2001
+++ linux/Documentation/cris/README	Fri Apr  6 10:42:55 2001
@@ -1,20 +1,22 @@
 Linux 2.4 on the CRIS architecture
 ==================================
-$Id: README,v 1.5 2001/01/10 17:20:55 bjornw Exp $
+$Id: README,v 1.6 2001/02/21 15:27:25 bjornw Exp $
 
-This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded network CPU. For
-more information about CRIS and ETRAX please see further below.
+This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded 
+network CPU. For more information about CRIS and ETRAX please see further
+below.
 
-<... to come: instructions on how to grab the right gcc, compiling and booting ...>
+<to come: instructions on how to grab the right gcc, compiling and booting>
 
 
 What is CRIS ?
 --------------
 
-CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU architecture in Axis
-Communication AB's range of embedded network CPU's, called ETRAX. The latest CPU is called
-ETRAX 100LX, where LX stands for 'Linux' because the chip was designed to be a good host for
-the Linux operating system.
+CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU
+architecture in Axis Communication AB's range of embedded network CPU's,
+called ETRAX. The latest CPU is called ETRAX 100LX, where LX stands for
+'Linux' because the chip was designed to be a good host for the Linux
+operating system.
 
 The ETRAX 100LX chip
 --------------------
@@ -23,8 +25,8 @@
 
 http://www.axis.com/news/us/001101_etrax.htm
 
-The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad range of 
-built-in interfaces, all with modern scatter/gather DMA.
+The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad 
+range of  built-in interfaces, all with modern scatter/gather DMA.
 
 Memory interfaces:
 
@@ -44,40 +46,41 @@
 	* two parallel-ports
 	* two generic 8-bit ports
 	
-	(not all interfaces are available at the same time due to chip pin multiplexing)
+	(not all interfaces are available at the same time due to chip pin 
+         multiplexing)
 
-The previous version of the ETRAX, the ETRAX 100, sits in almost all of Axis shipping 
-thin-servers like the Axis 2100 web camera or the developer-board. It lacks an MMU so the
-Linux we run on that is a version of uClinux (Linux 2.0 without MM-support) ported to the CRIS
-architecture. The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will not
-run on the ETRAX 100. 
-
-A version of the Axis developer-board with ETRAX 100LX will be available as soon as the chip 
-is ramped up (please see http://developer.axis.com for further information on that).
+The previous version of the ETRAX, the ETRAX 100, sits in almost all of
+Axis shipping thin-servers like the Axis 2100 web camera or the ETRAX 100
+developer-board. It lacks an MMU so the Linux we run on that is a version
+of uClinux (Linux 2.0 without MM-support) ported to the CRIS architecture.
+The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will
+not run on the ETRAX 100.
 
+A version of the Axis developer-board with ETRAX 100LX (running Linux
+2.4) is now available. For more information please see developer.axis.com.
 
 
 Bootlog
 -------
 
-Just as an example, this is the debug-output from a boot of Linux 2.4 on an Axis
-developer-board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :)
+Just as an example, this is the debug-output from a boot of Linux 2.4 on
+a board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :)
 At the end you see some user-mode programs booting like telnet and ftp daemons.
 
-Linux version 2.4.0-test11 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #358 Wed Nov 22 19:29:15 CET 2000
-ROM fs in RAM, size 368640 bytes
+Linux version 2.4.1 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #207 Wed Feb 21 15:48:15 CET 2001
+ROM fs in RAM, size 1376256 bytes
 Setting up paging and the MMU.
-On node 0 totalpages: 1024
-zone(0): 1024 pages.
+On node 0 totalpages: 2048
+zone(0): 2048 pages.
 zone(1): 0 pages.
 zone(2): 0 pages.
-Linux/CRIS port (c) 2000 Axis Communications AB
+Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB
 Kernel command line: 
-Calibrating delay loop... 19.92 BogoMIPS
-Memory: 6864k/8192k available (531k kernel code, 1328k reserved, 85k data, 24k init)
+Calibrating delay loop... 19.91 BogoMIPS
+Memory: 13872k/16384k available (587k kernel code, 2512k reserved, 44k data, 24k init)
 kmem_create: Forcing size word alignment - vm_area_struct
 kmem_create: Forcing size word alignment - filp
-Dentry-cache hash table entries: 1024 (order: 0, 8192 bytes)
+Dentry-cache hash table entries: 2048 (order: 1, 16384 bytes)
 Buffer-cache hash table entries: 2048 (order: 0, 8192 bytes)
 Page-cache hash table entries: 2048 (order: 0, 8192 bytes)
 kmem_create: Forcing size word alignment - kiobuf
@@ -87,41 +90,52 @@
 POSIX conformance testing by UNIFIX
 Linux NET4.0 for Linux 2.4
 Based upon Swansea University Computer Society NET3.039
-kmem_create: Forcing size word alignment - skbuff_head_cache
 Starting kswapd v1.8
 kmem_create: Forcing size word alignment - file lock cache
 kmem_create: Forcing size word alignment - blkdev_requests
+block: queued sectors max/low 9109kB/3036kB, 64 slots per queue
 ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB
 eth0 initialized
 eth0: changed MAC to 00:40:8C:CD:00:00
-ETRAX 100LX serial-driver $Revision: 1.5 $, (c) 2000 Axis Communications AB
+ETRAX 100LX serial-driver $Revision: 1.6 $, (c) 2000 Axis Communications AB
 ttyS0 at 0xb0000060 is a builtin UART with DMA
 ttyS1 at 0xb0000068 is a builtin UART with DMA
 ttyS2 at 0xb0000070 is a builtin UART with DMA
 ttyS3 at 0xb0000078 is a builtin UART with DMA
+Axis flash mapping: 200000 at 50000000
+Axis flash: Found 1 x16 CFI device at 0x0 in 16 bit mode
+ Amd/Fujitsu Extended Query Table v1.0 at 0x0040
+Axis flash: JEDEC Device ID is 0xC4. Assuming broken CFI table.
+Axis flash: Swapping erase regions for broken CFI table.
+number of CFI chips: 1
+ Using default partition table
+I2C driver v2.2, (c) 1999-2001 Axis Communications AB
+ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB
 NET4: Linux TCP/IP 1.0 for NET4.0
 IP Protocols: ICMP, UDP, TCP
 kmem_create: Forcing size word alignment - ip_dst_cache
 IP: routing cache hash table of 1024 buckets, 8Kbytes
-TCP: Hash tables configured (established 1024 bind 1024)
+TCP: Hash tables configured (established 2048 bind 2048)
 NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
 VFS: Mounted root (cramfs filesystem) readonly.
 Init starts up...
+Mounted none on /proc ok.
 Setting up eth0 with ip 10.13.9.116 and mac 00:40:8c:18:04:60
 eth0: changed MAC to 00:40:8C:18:04:60
 Setting up lo with ip 127.0.0.1
 Default gateway is 10.13.9.1
 Hostname is bbox1
 Telnetd starting, using port 23.
-  using /bin/sh as shell.
-sftpd[14]: sftpd $Revision: 1.5 $ starting up
+  using /bin/sash as shell.
+sftpd[15]: sftpd $Revision: 1.6 $ starting up
+
 
 
 And here is how some /proc entries look:
 
 17# cd /proc
 17# cat cpuinfo
-cpu             : ETRAX
+cpu             : CRIS
 cpu revision    : 10
 cpu model       : ETRAX 100LX
 cache size      : 8 kB
@@ -133,6 +147,7 @@
 ata             : yes
 usb             : yes
 bogomips        : 99.84
+
 17# cat meminfo
         total:    used:    free:  shared: buffers:  cached:
 Mem:   7028736   925696  6103040   114688        0   229376
diff -u --recursive --new-file v2.4.3/linux/Documentation/dnotify.txt linux/Documentation/dnotify.txt
--- v2.4.3/linux/Documentation/dnotify.txt	Fri Mar  2 18:38:37 2001
+++ linux/Documentation/dnotify.txt	Fri Apr  6 10:42:48 2001
@@ -1,7 +1,7 @@
 		Linux Directory Notification
 		============================
 
-	   Stephen Rothwell <sfr@linuxcare.com.au>
+	   Stephen Rothwell <sfr@canb.auug.org.au>
 
 The intention of directory notification is to allow user applications
 to be notified when a directory, or any of the files in it, are changed.
diff -u --recursive --new-file v2.4.3/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.4.3/linux/Documentation/filesystems/devfs/ChangeLog	Wed Jul  5 21:36:49 2000
+++ linux/Documentation/filesystems/devfs/ChangeLog	Fri Apr  6 10:42:48 2001
@@ -495,7 +495,7 @@
 
 - Replaced dummy .epoch inode with .devfsd character device
 
-- Modified rc.devfs to take acount of above change
+- Modified rc.devfs to take account of above change
 
 - Removed spurious driver warning messages when CONFIG_DEVFS_FS=n
 
diff -u --recursive --new-file v2.4.3/linux/Documentation/filesystems/ext2.txt linux/Documentation/filesystems/ext2.txt
--- v2.4.3/linux/Documentation/filesystems/ext2.txt	Sun Oct  1 20:21:20 2000
+++ linux/Documentation/filesystems/ext2.txt	Fri Apr 20 16:18:35 2001
@@ -4,7 +4,7 @@
 
 ext2 was originally released in January 1993.  Written by R\'emy Card,
 Theodore Ts'o and Stephen Tweedie, it was a major rewrite of the
-Extended Filesystem.  It is currently (February 1999) the predominant
+Extended Filesystem.  It is currently still (April 2001) the predominant
 filesystem in use by Linux.  There are also implementations available
 for NetBSD, FreeBSD, the GNU HURD, Windows 95/98/NT, OS/2 and RISC OS.
 
@@ -17,11 +17,11 @@
 bsddf			(*)	Makes `df' act like BSD.
 minixdf				Makes `df' act like Minix.
 
-check=none, nocheck		Perform no checks upon the filesystem.
-check=normal		(*)	Perform normal checks on the filesystem.
-check=strict			Perform extra checks on the filesystem.
+check=none, nocheck	(*)	Don't do extra checking of bitmaps on mount
+				(check=normal and check=strict options removed)
 
-debug				For developers only.
+debug				Extra debugging information is sent to the
+				kernel syslog.  Useful for developers.
 
 errors=continue		(*)	Keep going on a filesystem error.
 errors=remount-ro		Remount the filesystem read-only on an error.
@@ -30,8 +30,8 @@
 grpid, bsdgroups		Give objects the same group ID as their parent.
 nogrpid, sysvgroups	(*)	New objects have the group ID of their creator.
 
-resuid=n			The user which may use the reserved blocks.
-resgid=n			The group which may use the reserved blocks. 
+resuid=n			The user ID which may use the reserved blocks.
+resgid=n			The group ID which may use the reserved blocks. 
 
 sb=n				Use alternate superblock at this location.
 
@@ -53,46 +53,53 @@
 ------
 
 The space in the device or file is split up into blocks.  These are
-a fixed size, of 1024, 2048 or 4096 bytes, which is decided when the
-filesystem is created.  Smaller blocks mean less wasted space per file,
-but require slightly more accounting overhead.
+a fixed size, of 1024, 2048 or 4096 bytes (8192 bytes on Alpha systems),
+which is decided when the filesystem is created.  Smaller blocks mean
+less wasted space per file, but require slightly more accounting overhead,
+and also impose other limits on the size of files and the filesystem.
+
+Block Groups
+------------
 
 Blocks are clustered into block groups in order to reduce fragmentation
-and minimise the amount of head seeking when reading a large amount of
-consecutive data.  Each block group has a descriptor and the array of
-descriptors is stored immediately after the superblock.  Two blocks at
-the start of each group are reserved for the block usage bitmap and
-the inode usage bitmap which show which blocks and inodes are used.
-Since each bitmap fits in a block, this means that the maximum size of
-a block group is 8 times the size of a block.
-
-The first (non-reserved) blocks in the block group are designated as
-the inode table for the block and the remainder are the data blocks.
-The block allocation algorithm attempts to allocate data blocks in the
-same block group as the inode which contains them.
+and minimise the amount of head seeking when reading a large amount
+of consecutive data.  Information about each block group is kept in a
+descriptor table stored in the block(s) immediately after the superblock.
+Two blocks near the start of each group are reserved for the block usage
+bitmap and the inode usage bitmap which show which blocks and inodes
+are in use.  Since each bitmap is limited to a single block, this means
+that the maximum size of a block group is 8 times the size of a block.
+
+The block(s) following the bitmaps in each block group are designated
+as the inode table for that block group and the remainder are the data
+blocks.  The block allocation algorithm attempts to allocate data blocks
+in the same block group as the inode which contains them.
 
 The Superblock
 --------------
 
 The superblock contains all the information about the configuration of
-the filing system.  It is stored in block 1 of the filesystem (numbering
-from 0) and it is essential to mounting it.  Since it is so important,
-backup copies of the superblock are stored in block groups throughout
-the filesystem.  The first revision of ext2 stores a copy at the start
-of every block group.  Later revisions can store a copy in only some
-block groups to reduce the amount of redundancy on large filesystems.
-The groups chosen are 0, 1 and powers of 3, 5 and 7.
-
-The information in the superblock contains fields such as how many
-inodes and blocks are in the filesystem and how many are unused, how
-many inodes and blocks are in a block group, when the filesystem was
-mounted, when it was modified, what version of the filesystem it is
-(see the Revisions section below) and which OS created it.
-
-If the revision of the filesystem is recent enough then there are extra
-fields, such as a volume name, a unique identifier, the inode size,
-support for compression, block preallocation and creating fewer backup
-superblocks.
+the filing system.  The primary copy of the superblock is stored at an
+offset of 1024 bytes from the start of the device, and it is essential
+to mounting the filesystem.  Since it is so important, backup copies of
+the superblock are stored in block groups throughout the filesystem.
+The first version of ext2 (revision 0) stores a copy at the start of
+every block group, along with backups of the group descriptor block(s).
+Because this can consume a considerable amount of space for large
+filesystems, later revisions can optionally reduce the number of backup
+copies by only putting backups in specific groups (this is the sparse
+superblock feature).  The groups chosen are 0, 1 and powers of 3, 5 and 7.
+
+The information in the superblock contains fields such as the total
+number of inodes and blocks in the filesystem and how many are free,
+how many inodes and blocks are in each block group, when the filesystem
+was mounted (and if it was cleanly unmounted), when it was modified,
+what version of the filesystem it is (see the Revisions section below)
+and which OS created it.
+
+If the filesystem is revision 1 or higher, then there are extra fields,
+such as a volume name, a unique identification number, the inode size,
+and space for optional filesystem features to store configuration info.
 
 All fields in the superblock (as in all other ext2 structures) are stored
 on the disc in little endian format, so a filesystem is portable between
@@ -101,23 +108,25 @@
 Inodes
 ------
 
-The inode (index node) is the fundamental concept in the ext2 filesystem.
+The inode (index node) is a fundamental concept in the ext2 filesystem.
 Each object in the filesystem is represented by an inode.  The inode
 structure contains pointers to the filesystem blocks which contain the
 data held in the object and all of the metadata about an object except
 its name.  The metadata about an object includes the permissions, owner,
 group, flags, size, number of blocks used, access time, change time,
 modification time, deletion time, number of links, fragments, version
-(for NFS) and ACLs.
+(for NFS) and extended attributes (EAs) and/or Access Control Lists (ACLs).
 
-There are several reserved fields which are currently unused in the inode
-structure and several which are overloaded.  One field is used for the
-directory ACL if the inode is a directory and for the top 32 bits of
-the file size if the inode is a regular file.  The translator field is
-unused under Linux, but is used by the HURD to reference the inode of
-a program which will be used to interpret this object.  The HURD also
-has larger permissions, owner and group fields, so it uses some of the
-other unused by Linux fields to store the extra bits.
+There are some reserved fields which are currently unused in the inode
+structure and several which are overloaded.  One field is reserved for the
+directory ACL if the inode is a directory and alternately for the top 32
+bits of the file size if the inode is a regular file (allowing file sizes
+larger than 2GB).  The translator field is unused under Linux, but is used
+by the HURD to reference the inode of a program which will be used to
+interpret this object.  Most of the remaining reserved fields have been
+used up for both Linux and the HURD for larger owner and group fields,
+The HURD also has a larger mode field so it uses another of the remaining
+fields to store the extra more bits.
 
 There are pointers to the first 12 blocks which contain the file's data
 in the inode.  There is a pointer to an indirect block (which contains
@@ -126,11 +135,12 @@
 trebly-indirect block (which contains pointers to doubly-indirect blocks).
 
 The flags field contains some ext2-specific flags which aren't catered
-for by the standard chmod flags.  These flags can be listed with
-lsattr and changed with the chattr command.  There are flags for secure
-deletion, undeletable, compression, synchronous updates, immutability,
-append-only, dumpable, no-atime, and btree directories.  Not all of
-these are supported yet.
+for by the standard chmod flags.  These flags can be listed with lsattr
+and changed with the chattr command, and allow specific filesystem
+behaviour on a per-file basis.  There are flags for secure deletion,
+undeletable, compression, synchronous updates, immutability, append-only,
+dumpable, no-atime, indexed directories, and data-journaling.  Not all
+of these are supported yet.
 
 Directories
 -----------
@@ -139,10 +149,19 @@
 It is a specially formatted file containing records which associate
 each name with an inode number.  Later revisions of the filesystem also
 encode the type of the object (file, directory, symlink, device, fifo,
-socket) in the directory entry for speed.  The current implementation
-of ext2 uses a linked list in directories; a planned enhancement will
-use btrees instead.  The current implementation also never shrinks
-directories once they have grown to accommodate more files.
+socket) to avoid the need to check the inode itself for this information
+(support for taking advantage of this feature does not yet exist in
+Glibc 2.2).
+
+The inode allocation code tries to assign inodes which are in the same
+block group as the directory in which they are first created.
+
+The current implementation of ext2 uses a singly-linked list to store
+the filenames in the directory; a pending enhancement uses hashing of the
+filenames to allow lookup without the need to scan the entire directory.
+
+The current implementation never removes empty directory blocks once they
+have been allocated to hold more files.
 
 Special files
 -------------
@@ -150,31 +169,23 @@
 Symbolic links are also filesystem objects with inodes.  They deserve
 special mention because the data for them is stored within the inode
 itself if the symlink is less than 60 bytes long.  It uses the fields
-which would normally be used to store the pointers to blocks to store
-the data.  This is a worthwhile optimisation to make as it does not then
-take up a block, and most symlinks are less than 60 characters long.
+which would normally be used to store the pointers to data blocks.
+This is a worthwhile optimisation as it we avoid allocating a full
+block for the symlink, and most symlinks are less than 60 characters long.
 
 Character and block special devices never have data blocks assigned to
 them.  Instead, their device number is stored in the inode, again reusing
-the fields which would be used to point to the blocks.
-
-Revisions
----------
-
-The revisioning mechanism used in ext2 is sophisticated.  The revisioning
-mechanism is not supported by version 0 (EXT2_GOOD_OLD_REV) of ext2 but
-was introduced in version 1.  There are three 32-bit fields, one for
-compatible features, one for read-only compatible features and one for
-incompatible features.
+the fields which would be used to point to the data blocks.
 
 Reserved Space
 --------------
 
 In ext2, there is a mechanism for reserving a certain number of blocks
 for a particular user (normally the super-user).  This is intended to
-allow for the system to continue functioning even if a user fills up
-all the available space.  It also keeps the filesystem from filling up
-entirely which helps combat fragmentation.
+allow for the system to continue functioning even if non-priveleged users
+fill up all the space available to them (this is independent of filesystem
+quotas).  It also keeps the filesystem from filling up entirely which
+helps combat fragmentation.
 
 Filesystem check
 ----------------
@@ -183,9 +194,66 @@
 filesystems.  The superblock of the ext2 filesystem contains several
 fields which indicate whether fsck should actually run (since checking
 the filesystem at boot can take a long time if it is large).  fsck will
-run if the filesystem was not unmounted without errors, if the maximum
-mount count has been exceeded or if the maximum time between checks has
-been exceeded.
+run if the filesystem was not cleanly unmounted, if the maximum mount
+count has been exceeded or if the maximum time between checks has been
+exceeded.
+
+Feature Compatibility
+---------------------
+
+The compatibility feature mechanism used in ext2 is sophisticated.
+It safely allows features to be added to the filesystem, without
+unnecessarily sacrificing compatibility with older versions of the
+filesystem code.  The feature compatibility mechanism is not supported by
+the original revision 0 (EXT2_GOOD_OLD_REV) of ext2, but was introduced in
+revision 1.  There are three 32-bit fields, one for compatible features
+(COMPAT), one for read-only compatible (RO_COMPAT) features and one for
+incompatible (INCOMPAT) features.
+
+These feature flags have specific meanings for the kernel as follows:
+
+A COMPAT flag indicates that a feature is present in the filesystem,
+but the on-disk format is 100% compatible with older on-disk formats, so
+a kernel which didn't know anything about this feature could read/write
+the filesystem without any chance of corrupting the filesystem (or even
+making it inconsistent).  This is essentially just a flag which says
+"this filesystem has a (hidden) feature" that the kernel or e2fsck may
+want to be aware of (more on e2fsck and feature flags later).  The ext3
+HAS_JOURNAL feature is a COMPAT flag because the ext3 journal is simply
+a regular file with data blocks in it so the kernel does not need to
+take any special notice of it if it doesn't understand ext3 journaling.
+
+An RO_COMPAT flag indicates that the on-disk format is 100% compatible
+with older on-disk formats for reading (i.e. the feature does not change
+the visible on-disk format).  However, an old kernel writing to such a
+filesystem would/could corrupt the filesystem, so this is prevented. The
+most common such feature, SPARSE_SUPER, is an RO_COMPAT feature because
+sparse groups allow file data blocks where superblock/group descriptor
+backups used to live, and ext2_free_blocks() refuses to free these blocks,
+which would leading to inconsistent bitmaps.  An old kernel would also
+get an error if it tried to free a series of blocks which crossed a group
+boundary, but this is a legitimate layout in a SPARSE_SUPER filesystem.
+
+An INCOMPAT flag indicates the on-disk format has changed in some
+way that makes it unreadable by older kernels, or would otherwise
+cause a problem if an old kernel tried to mount it.  FILETYPE is an
+INCOMPAT flag because older kernels would think a filename was longer
+than 256 characters, which would lead to corrupt directory listings.
+The COMPRESSION flag is an obvious INCOMPAT flag - if the kernel
+doesn't understand compression, you would just get garbage back from
+read() instead of it automatically decompressing your data.  The ext3
+RECOVER flag is needed to prevent a kernel which does not understand the
+ext3 journal from mounting the filesystem without replaying the journal.
+
+For e2fsck, it needs to be more strict with the handling of these
+flags than the kernel.  If it doesn't understand ANY of the COMPAT,
+RO_COMPAT, or INCOMPAT flags it will refuse to check the filesystem,
+because it has no way of verifying whether a given feature is valid
+or not.  Allowing e2fsck to succeed on a filesystem with an unknown
+feature is a false sense of security for the user.  Refusing to check
+a filesystem with unknown features is a good incentive for the user to
+update to the latest e2fsck.  This also means that anyone adding feature
+flags to ext2 also needs to update e2fsck to verify these features.
 
 Metadata
 --------
@@ -196,29 +264,98 @@
 respective fsck programs.
 
 If you're exceptionally paranoid, there are 3 ways of making metadata
-writes synchronous:
+writes synchronous on ext2:
 
-per-file if you have the source: use the O_SYNC argument to open()
-per-file if you don't have the source: use chattr +S
-per-filesystem: mount -o sync
+per-file if you have the program source: use the O_SYNC flag to open()
+per-file if you don't have the source: use "chattr +S" on the file
+per-filesystem: add the "sync" option to mount (or in /etc/fstab)
 
 the first and last are not ext2 specific but do force the metadata to
-be written synchronously.
+be written synchronously.  See also Journaling below.
+
+Limitations
+-----------
+
+There are various limits imposed by the on-disk layout of ext2.  Other
+limits are imposed by the current implementation of the kernel code.
+Many of the limits are determined at the time the filesystem is first
+created, and depend upon the block size chosen.  The ratio of inodes to
+data blocks is fixed at filesystem creation time, so the only way to
+increase the number of inodes is to increase the size of the filesystem.
+No tools currently exist which can change the ratio of inodes to blocks.
+
+Most of these limits could be overcome with slight changes in the on-disk
+format and using a compatibility flag to signal the format change (at
+the expense of some compatibility).
+
+Filesystem block size:     1kB        2kB        4kB        8kB
+
+File size limit:          16GB      256GB     2048GB     2048GB
+Filesystem size limit:  2047GB     8192GB    16384GB    32768GB
+
+There is a 2.4 kernel limit of 2048GB for a single block device, so no
+filesystem larger than that can be created at this time.  There is also
+an upper limit on the block size imposed by the page size of the kernel,
+so 8kB blocks are only allowed on Alpha systems (and other architectures
+which support larger pages).
+
+There is a "soft" upper limit of about 10-15k files in a single directory
+with the current linear linked-list directory implementation.  This limit
+stems from performance problems when creating and deleting (and also
+finding) files in such large directories.  Using a hashed directory index
+(under development) allows 100k-1M+ files in a single directory without
+performance problems (although RAM size becomes an issue at this point).
+
+The (meaningless) absolute upper limit of files in a single directory
+(imposed by the file size, the realistic limit is obviously much less)
+is over 130 trillion files.  It would be higher except there are not
+enough 4-character names to make up unique directory entries, so they
+have to be 8 character filenames, even then we are fairly close to
+running out of unique filenames.
+
+Journaling
+----------
+
+A journaling extension to the ext2 code has been developed by Stephen
+Tweedie.  It avoids the risks of metadata corruption and the need to
+wait for e2fsck to complete after a crash, without requiring a change
+to the on-disk ext2 layout.  In a nutshell, the journal is a regular
+file which stores whole metadata (and optionally data) blocks that have
+been modified, prior to writing them into the filesystem.  This means
+it is possible to add a journal to an existing ext2 filesystem without
+the need for data conversion.
+
+When changes to the filesystem (e.g. a file is renamed) they are stored in
+a transaction in the journal and can either be complete or incomplete at
+the time of a crash.  If a transaction is complete at the time of a crash
+(or in the normal case where the system does not crash), then any blocks
+in that transaction are guaranteed to represent a valid filesystem state,
+and are copied into the filesystem.  If a transaction is incomplete at
+the time of the crash, then there is no guarantee of consistency for
+the blocks in that transaction so they are discarded (which means any
+filesystem changes they represent are also lost).
+
+The ext3 code is currently (Apr 2001) available for 2.2 kernels only,
+and not yet available for 2.4 kernels.
 
 References
 ==========
 
 The kernel source	file:/usr/src/linux/fs/ext2/
-Design & Implementation	http://khg.redhat.com/HyperNews/get/fs/ext2intro.html
-Compression		http://debs.fuller.edu/e2compr/
-ACL support		ftp://tsx-11.mit.edu/pub/linux/ALPHA/ext2fs
-updated ACL work	http://aerobee.informatik.uni-bremen.de/acl_eng.html
-e2fsprogs 		ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs
+e2fsprogs (e2fsck)	http://e2fsprogs.sourceforge.net/
+Design & Implementation	http://e2fsprogs.sourceforge.net/ext2intro.html
+Journaling (ext3)	ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/
+Hashed Directories	http://kernelnewbies.org/~phillips/htree/
+Filesystem Resizing	http://ext2resize.sourceforge.net/
+Extended Attributes &
+Access Control Lists	http://acl.bestbits.at/
+Compression (*)		http://www.netspace.net.au/~reiter/e2compr/
 
 Implementations for:
+Windows 95/98/NT/2000	http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm
+Windows 95 (*)		http://www.yipton.demon.co.uk/content.html#FSDEXT2
+DOS client (*)		ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
 OS/2			http://perso.wanadoo.fr/matthieu.willm/ext2-os2/
-Windows 95		http://www.yipton.demon.co.uk/
-Windows NT		http://www.cyco.nl/~andreys/ext2fsnt/
-			http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm
-DOS client		ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
 RISC OS client		ftp://ftp.barnet.ac.uk/pub/acorn/armlinux/iscafs/
+
+(*) no longer actively developed/supported (as of Apr 2001)
diff -u --recursive --new-file v2.4.3/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt
--- v2.4.3/linux/Documentation/filesystems/proc.txt	Mon Nov 27 17:47:38 2000
+++ linux/Documentation/filesystems/proc.txt	Fri Apr  6 10:42:48 2001
@@ -49,7 +49,7 @@
 the SuSE  Linux distribution. As  there is  no complete documentation  for the
 /proc file system and we've used  many freely available sources to write these
 chapters, it  seems only fair  to give the work  back to the  Linux community.
-This work is  based on the 2.2.*  kernel version and the  upcomming 2.4.*. I'm
+This work is  based on the 2.2.*  kernel version and the  upcoming 2.4.*. I'm
 afraid it's still far from complete, but we  hope it will be useful. As far as
 we know, it is the first 'all-in-one' document about the /proc file system. It
 is focused  on the Intel  x86 hardware,  so if you  are looking for  PPC, ARM,
@@ -281,7 +281,7 @@
 
 ERR is incremented in the case of errors in the IO-APIC bus (the bus that
 connects the CPUs in a SMP system. This means that an error has been detected,
-the IO-APIC automatically retry the transmision, so it should not be a big
+the IO-APIC automatically retry the transmission, so it should not be a big
 problem, but you should read the SMP-FAQ.
 
 In this context it could be interesting to note the new irq directory in 2.4.
diff -u --recursive --new-file v2.4.3/linux/Documentation/filesystems/vfat.txt linux/Documentation/filesystems/vfat.txt
--- v2.4.3/linux/Documentation/filesystems/vfat.txt	Tue Dec 21 14:28:39 1999
+++ linux/Documentation/filesystems/vfat.txt	Wed Apr 11 19:02:27 2001
@@ -48,6 +48,9 @@
                  r: relaxed, case insensitive
                  n: normal, default setting, currently case insensitive
 
+nocase        -- Returning with having the 8.3 format alias kept in
+                 the disk. Default, return lowercase letter.
+
 <bool>: 0,1,yes,no,true,false
 
 TODO
diff -u --recursive --new-file v2.4.3/linux/Documentation/i386/boot.txt linux/Documentation/i386/boot.txt
--- v2.4.3/linux/Documentation/i386/boot.txt	Thu Jul 27 16:52:08 2000
+++ linux/Documentation/i386/boot.txt	Wed Apr 11 18:50:25 2001
@@ -146,9 +146,16 @@
 filled out, however:
 
   type_of_loader:
-	If your boot loader has an identifier assigned in
-	arch/i386/boot/setup.S, enter that value.  Otherwise, enter
-	0xFF here.
+	If your boot loader has an assigned id (see table below), enter
+	0xTV here, where T is an identifier for the boot loader and V is
+	a version number.  Otherwise, enter 0xFF here.
+
+	Assigned boot loader ids:
+	0  LILO
+	1  Loadlin
+	2  bootsect-loader
+	3  SYSLINUX
+	4  EtherBoot
 
   loadflags, heap_end_ptr:
 	If the protocol version is 2.01 or higher, enter the
diff -u --recursive --new-file v2.4.3/linux/Documentation/i810_rng.txt linux/Documentation/i810_rng.txt
--- v2.4.3/linux/Documentation/i810_rng.txt	Sun Mar 25 18:24:31 2001
+++ linux/Documentation/i810_rng.txt	Thu Apr 19 09:34:05 2001
@@ -70,6 +70,9 @@
 
 Change history:
 
+	Version 0.9.6:
+	* Internal driver cleanups, prep for 1.0.0 release.
+
 	Version 0.9.5:
 	* Rip out entropy injection via timer.  It never ever worked,
 	  and a better solution (rngd) is now available.
diff -u --recursive --new-file v2.4.3/linux/Documentation/isapnp.txt linux/Documentation/isapnp.txt
--- v2.4.3/linux/Documentation/isapnp.txt	Mon Oct  9 17:53:05 2000
+++ linux/Documentation/isapnp.txt	Wed Apr 18 11:49:11 2001
@@ -7,14 +7,14 @@
 Read commands:
 --------------
 
-No comment..
+No comment.
 
 Write commands:
 ---------------
 
-With the write interface you can simply activate or modify the configuration
-for ISA Plug & Play devices. It is mainly useable for drivers which has not
-use the ISA Plug & Play kernel support yet.
+With the write interface you can activate or modify the configuration of
+ISA Plug & Play devices.  It is mainly useful for drivers which have not
+been rewritten to use the ISA Plug & Play kernel support yet.
 
 card <idx> <vendor>	- select PnP device by vendor identification
 csn <CSN>		- select PnP device by CSN
@@ -33,8 +33,8 @@
 Explanation:
 	- variable <idx> begins with zero
 	- variable <CSN> begins with one
-	- <vendor> is in format 'PNP0000'
-	- <logdev> is in format 'PNP0000'
+	- <vendor> is in the standard format 'ABC1234'
+	- <logdev> is in the standard format 'ABC1234'
 
 Example:
 
@@ -58,38 +58,38 @@
 Information for developers
 ==========================
 
-Finding appropriate device
---------------------------
+Finding a device
+----------------
 
 extern struct pci_bus *isapnp_find_card(unsigned short vendor,
                                         unsigned short device,
                                         struct pci_bus *from);
 
-This function finds a ISA PnP card. For the vendor device should
-be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers.
-For the device number should be used ISAPNP_DEVICE(x) macro where x is
-integer value. Both vendor and device numbers can be taken from contents
-of the /proc/isapnp file.
+This function finds an ISA PnP card.  For the vendor argument, the
+ISAPNP_VENDOR(a,b,c) macro should be used, where a,b,c are characters or
+integers.  For the device argument the ISAPNP_DEVICE(x) macro should be
+used, where x is an integer value.  Both vendor and device arguments
+can be taken from contents of the /proc/isapnp file.
 
 extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
                                        unsigned short vendor,
                                        unsigned short function,
                                        struct pci_dev *from);
 
-This function finds the ISA PnP device. If card is NULL, then
-the global search mode is used (all devices are used for the searching).
-Otherwise only devices which belongs to the specified card are verified.
-For the function number can be used ISAPNP_FUNCTION(x) macro which works
-similarly as the ISAPNP_DEVICE(x) macro.
+This function finds an ISA PnP device. If card is NULL, then the global
+search mode is used (all devices are used for the searching).  Otherwise
+only devices which belong to the specified card are checked.  For the
+function number the ISAPNP_FUNCTION(x) macro can be used; it works
+similarly to the ISAPNP_DEVICE(x) macro.
 
 extern int isapnp_probe_cards(const struct isapnp_card_id *ids,
-			      int (*probe)(struct pci_bus *card,
-					   const struct isapnp_card_id *id));
+                              int (*probe)(struct pci_bus *card,
+                              const struct isapnp_card_id *id));
 
 
-This function is a helper for drivers which requires to use more than
-one device from an ISA PnP card. For each cards is called the probe
-callback with appropriate information.
+This function is a helper for drivers which need to use more than
+one device from an ISA PnP card.  The probe callback is called with
+appropriate arguments for each card.
 
 Example for ids parameter initialization:
 
@@ -109,13 +109,13 @@
 ISAPNP_CARD_TABLE(card_ids);
 
 extern int isapnp_probe_devs(const struct isapnp_device_id *ids,
-			     int (*probe)(struct pci_bus *card,
-					  const struct isapnp_device_id *id));
+                             int (*probe)(struct pci_bus *card,
+                             const struct isapnp_device_id *id));
 
 
-This function is a helper for drivers which requires to use one
-device from an ISA PnP card. For each matched devices is called the probe
-callback with appropriate information.
+This function is a helper for drivers which need to use one
+device from an ISA PnP card.  The probe callback is called with
+appropriate arguments for each matched device.
 
 Example for ids parameter initialization:
 
@@ -129,25 +129,25 @@
 ISA PnP configuration
 =====================
 
-There are two ways how can be ISA PnP interface used.
+There are two ways in which the ISA PnP interface can be used.
 
-First way is lowlevel
----------------------
+First way: low-level
+--------------------
 
-All ISA PNP configuration registers are accessible via lowlevel
+All ISA PNP configuration registers are accessible via the low-level
 isapnp_(read|write)_(byte|word|dword) functions.
 
 The function isapnp_cfg_begin() must be called before any lowlevel function.
 The function isapnp_cfg_end() must be always called after configuration
 otherwise the access to the ISA PnP configuration functions will be blocked.
 
-Second way is auto-configuration
---------------------------------
+Second way: auto-configuration
+------------------------------
 
-This feature gives to the driver the real power of the ISA PnP code.
-Function dev->prepare() initializes the resource members in the device
-structure. This structure contains all resources set to auto configuration
-values after the initialization. The device driver may modify some resources
+This feature gives to the driver the real power of the ISA PnP driver.
+The function dev->prepare() initializes the resource members in the device
+structure.  This structure contains all resources set to auto configuration
+values after the initialization.  The device driver may modify some resources
 to skip the auto configuration for a given resource.
 
 Once the device structure contains all requested resource values, the function
@@ -155,12 +155,12 @@
 with the auto configuration value.
 
 Function dev->activate() does:
-	- resources with the auto configuration value are configured
-	- the auto configuration is created using ISA PnP resource map
-	- the function writes configuration to ISA PnP configuration registers
-	- the function returns to the caller actual used resources
+   - resources with the auto configuration value are configured
+   - the auto configuration is created using ISA PnP resource map
+   - the function writes configuration to ISA PnP configuration registers
+   - the function returns to the caller actual used resources
 
-When the device driver is removing, function dev->deactivate() has to be
+When the device driver is removed, function dev->deactivate() has to be
 called to free all assigned resources.
 
 Example (game port initialization)
diff -u --recursive --new-file v2.4.3/linux/Documentation/joystick-api.txt linux/Documentation/joystick-api.txt
--- v2.4.3/linux/Documentation/joystick-api.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/joystick-api.txt	Fri Apr  6 10:42:48 2001
@@ -114,7 +114,7 @@
 ~~~~~~~~~~~~~~~~~
 
 The time an event was generated is stored in ``js_event.time''. It's a time
-in miliseconds since ... well, since sometime in the past.  This eases the
+in milliseconds since ... well, since sometime in the past.  This eases the
 task of detecting double clicks, figuring out if movement of axis and button
 presses happened at the same time, and similar.
 
diff -u --recursive --new-file v2.4.3/linux/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt
--- v2.4.3/linux/Documentation/kernel-docs.txt	Wed Aug 23 09:33:09 2000
+++ linux/Documentation/kernel-docs.txt	Fri Apr  6 10:42:48 2001
@@ -608,7 +608,7 @@
        produced during the week. Published every Thursday.
        
      * Name: "Kernel Traffic"
-       URL: http://kt.linuxcare.com
+       URL: http://kt.zork.net
        Keywords: linux-kernel mailing list, weekly kernel news.
        Description: Weekly newsletter covering the most relevant
        discussions of the linux-kernel mailing list.
diff -u --recursive --new-file v2.4.3/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.4.3/linux/Documentation/kernel-parameters.txt	Fri Mar  2 11:02:15 2001
+++ linux/Documentation/kernel-parameters.txt	Wed Apr 18 11:49:11 2001
@@ -22,6 +22,7 @@
 	HW	Appropriate hardware is enabled.
 	IA-32	IA-32 aka i386 architecture is enabled.
 	IA-64	IA-64 architecture is enabled.
+	ISAPNP  ISA PnP code is enabled.
 	ISDN	Appropriate ISDN support is enabled.
 	JOY 	Appropriate joystick support is enabled.
 	LP	Printer support is enabled.
@@ -246,6 +247,18 @@
 
 	ip=		[PNP]
 
+	isapnp=		[ISAPNP] Specify RDP, reset, pci_scan and verbosity.
+
+	isapnp_reserve_irq= [ISAPNP] Exclude IRQs for the autoconfiguration.
+
+	isapnp_reserve_dma= [ISAPNP] Exclude DMAs for the autoconfiguration.
+
+	isapnp_reserve_io= [ISAPNP] Exclude I/O ports for the autoconfiguration.
+				    Ranges are in pairs (I/O port base and size).
+
+	isapnp_reserve_mem= [ISAPNP] Exclude memory regions for the autoconfiguration.
+				     Ranges are in pairs (memory base and size).
+
 	isp16=		[HW,CD]
 
 	iucv=		[HW,NET] 
@@ -361,6 +374,8 @@
 	nohlt		[BUGS=ARM]
  
 	no-hlt		[BUGS=ix86]
+
+	noisapnp	[ISAPNP] Disables ISA PnP code.
 
 	noinitrd	[RAM] Tells the kernel not to load any configured
 			initial RAM disk.
diff -u --recursive --new-file v2.4.3/linux/Documentation/mips/GT64120.README linux/Documentation/mips/GT64120.README
--- v2.4.3/linux/Documentation/mips/GT64120.README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/mips/GT64120.README	Fri Apr 20 16:23:12 2001
@@ -0,0 +1,65 @@
+README for arch/mips/gt64120 directory and subdirectories
+
+Jun Sun, jsun@mvista.com or jsun@junsun.net
+01/27, 2001
+
+MOTIVATION
+----------
+
+Many MIPS boards share the same system controller (or CPU companian chip),
+such as GT-64120.  It is highly desirable to let these boards share
+the same controller code instead of duplicating them.
+
+This directory is meant to hold all MIPS boards that use GT-64120 or GT-64120A.
+
+
+HOW TO ADD A BOARD
+------------------
+ 
+. Create a subdirectory include/asm/gt64120/<board>.  
+
+. Create a file called gt64120_dep.h under that directory.
+
+. Modify include/asm/gt64120/gt64120.h file to include the new gt64120_dep.h
+  based on config options.  The board-dep section is at the end of 
+  include/asm/gt64120/gt64120.h file. There you can find all required
+  definitions include/asm/gt64120/<board>/gt64120_dep.h file must supply.
+
+. Create a subdirectory arch/mips/gt64120/<board> directory to hold
+  board specific routines.
+
+. The GT-64120 common code is supplied under arch/mips/gt64120/common directory.
+  It includes:
+	1) arch/mips/gt64120/pci.c -
+		common PCI routine, include the top-level pcibios_init()
+	2) arch/mips/gt64120/irq.c -
+		common IRQ routine, include the top-level do_IRQ() 
+	   [This part really belongs to arch/mips/kernel. jsun]
+ 	3) arch/mips/gt64120/gt_irq.c -
+		common IRQ routines for GT-64120 chip.  Currently it only handles
+	 	the timer interrupt.
+
+. Board-specific routines are supplied under arch/mips/gt64120/<board> dir.
+	1) arch/mips/gt64120/<board>/pci.c - it provides bus fixup routine
+	2) arch/mips/gt64120/<board>/irq.c - it provides enable/disable irqs
+		and board irq setup routine (irq_setup)
+	3) arch/mips/gt64120/<board>/int-handler.S -
+		The first-level interrupt dispatching routine.
+	4) a bunch of other "normal" stuff (setup, prom, dbg_io, reset, etc)
+
+. Follow other "normal" procedure to modify configuration files, etc.
+
+
+TO-DO LIST
+----------
+
+. Expand arch/mips/gt64120/gt_irq.c to handle all GT-64120 interrupts.
+  We probably need to introduce GT_IRQ_BASE  in board-dep header file,
+  which is used the starting irq_nr for all GT irqs.
+
+  A function, gt64120_handle_irq(), will be added so that the first-level
+  irq dispatcher will call this function if it detects an interrupt
+  from GT-64120.
+
+. More support for GT-64120 PCI features (2nd PCI bus, perhaps)
+
diff -u --recursive --new-file v2.4.3/linux/Documentation/mips/time.README linux/Documentation/mips/time.README
--- v2.4.3/linux/Documentation/mips/time.README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/mips/time.README	Fri Apr 20 16:23:12 2001
@@ -0,0 +1,161 @@
+README for MIPS time services
+
+Jun Sun
+jsun@mvista.com or jsun@junsun.net
+
+
+ABOUT
+-----
+This file describes the new arch/mips/kernel/time.c, related files and the 
+services they provide. 
+
+If you are short in patience and just want to know how to use time.c for a 
+new board or convert an existing board, go to the last section.
+
+
+FILES, COMPATABILITY AND CONFIGS
+---------------------------------
+
+The old arch/mips/kernel/time.c is renamed to old-time.c.
+
+A new time.c is put there, together with include/asm-mips/time.h.
+
+Two configs variables are introduced, CONFIG_OLD_TIME_C and CONFIG_NEW_TIME_C.
+So we allow boards using 
+
+	1) old time.c (CONFIG_OLD_TIME_C)
+	2) new time.c (CONFIG_NEW_TIME_C)
+	3) neither (their own private time.c)
+
+However, it is expected every board will move to the new time.c in the near
+future.
+
+
+WHAT THE NEW CODE PROVIDES?
+--------------------------- 
+
+The new time code provide the following services:
+
+  a) Implements functions required by Linux common code:
+	time_init
+	do_gettimeofday
+	do_settimeofday
+
+  b) provides an abstraction of RTC and null RTC implementation as default.
+	extern unsigned long (*rtc_get_time)(void);
+	extern int (*rtc_set_time)(unsigned long);
+
+  c) a set of gettimeoffset functions for different CPUs and different
+     needs.
+
+  d) high-level and low-level timer interrupt routines where the timer 
+     interrupt source  may or may not be the CPU timer.  The high-level 
+     routine is dispatched through do_IRQ() while the low-level is 
+     dispatched in assemably code (usually int-handler.S)
+
+
+WHAT THE NEW CODE REQUIRES?
+---------------------------
+
+For the new code to work properly, each board implementation needs to supply
+the following functions or values:
+
+  a) board_time_init - a function pointer.  Invoked at the beginnig of
+     time_init().  It is optional.
+	1. (optional) set up RTC routines
+	2. (optional) calibrate and set the mips_counter_frequency
+
+  b) board_timer_setup - a function pointer.  Invoked at the end of time_init()
+	1. (optional) over-ride any decisions made in time_init()
+	2. set up the irqaction for timer interrupt.
+	3. enable the timer interrupt
+
+  c) (optional) board-specific RTC routines.
+
+  d) (optional) mips_counter_frequency - It must be definied if the board
+     is using CPU counter for timer interrupt or it is using fixed rate
+     gettimeoffset().
+
+
+PORTING GUIDE
+-------------
+
+Step 1: decide how you like to implement the time services.
+
+  a) does this board have a RTC?  If yes, implement the two RTC funcs.
+
+  b) does the CPU have counter/compare registers? 
+
+     If the answer is no, you need a timer to provide the timer interrupt
+     at 100 HZ speed.
+
+     You cannot use the fast gettimeoffset functions, i.e.,
+
+	unsigned long fixed_rate_gettimeoffset(void);
+	unsigned long calibrate_div32_gettimeoffset(void);
+	unsigned long calibrate_div64_gettimeoffset(void);
+
+    You can use null_gettimeoffset() will gives the same time resolution as
+    jiffy.  Or you can implement your own gettimeoffset (probably based on 
+    some ad hoc hardware on your machine.)
+
+  c) The following sub steps assume your CPU has counter register.
+     Do you plan to use the CPU counter register as the timer interrupt
+     or use an exnternal timer?
+
+     In order to CPU counter register as the timer interrupt source, you must
+     know the counter speed (mips_counter_frequency).  It is usually the
+     same as the CPU speed (Or it is ALWAYS the same?)
+
+  d) decide on whether you want to use high-level or low-level timer
+     interrupt routines.  The low-level one is presumably faster, but should
+     not make too mcuh difference.
+
+
+Step 2:  the machine setup() function
+
+  If you supply board_time_init(), set the function poointer.
+
+  Set the function pointer board_timer_setup() (mandatory)
+
+
+Step 3: implement rtc routines, board_time_init() and board_timer_setup()
+  if needed.
+
+  board_time_init() - 
+  	a) (optional) set up RTC routines, 
+        b) (optional) calibrate and set the mips_counter_frequency
+ 	    (only needed if you intended to use fixed_rate_gettimeoffset
+ 	     or use cpu counter as timer interrupt source)
+
+  board_timer_setup() - 
+ 	a) (optional) over-write any choices made above by time_init().
+ 	b) machine specific code should setup the timer irqaction.
+ 	c) enable the timer interrupt
+
+
+  If the RTC chip is a common chip, I suggest the routines are put under
+  arch/mips/libs.  For example, for DS1386 chip, one would create
+  rtc-ds1386.c under arch/mips/lib directory.  Add the following line to
+  the arch/mips/lib/Makefile:
+
+	obj-$(CONFIG_DDB5476) += rtc-ds1386.o
+
+Step 4: if you are using low-level timer interrupt, change your interrupt
+  dispathcing code to check for timer interrupt and jump to 
+  ll_timer_interrupt() directly  if one is detected.
+
+Step 5: Modify arch/mips/config.in and add CONFIG_NEW_TIME_C to your machine.
+  Modify the appropriate defconfig if applicable.
+
+Final notes: 
+
+For some tricky cases, you may need to add your own wrapper functions 
+for some of the functions in time.c.  
+
+For example, you may define your own timer interrupt routine, which does
+its own processing and in turn calls timer_interrupt().
+
+You can also over-ride any of the built-in functions (gettimeoffset,
+RTC routines and/or timer interrupt routine).
+
diff -u --recursive --new-file v2.4.3/linux/Documentation/mtrr.txt linux/Documentation/mtrr.txt
--- v2.4.3/linux/Documentation/mtrr.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/mtrr.txt	Wed Apr 11 19:02:27 2001
@@ -16,10 +16,13 @@
   these, the ARRs are used to emulate the MTRRs.
 
   The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
-  MTRRs. These are supported.
+  MTRRs. These are supported.  The AMD Athlon family provide 8 Intel
+  style MTRRs.
   
   The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
   are supported.
+
+  The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
 
   The CONFIG_MTRR option creates a /proc/mtrr file which may be used
   to manipulate your MTRRs. Typically the X server should use
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt
--- v2.4.3/linux/Documentation/networking/8139too.txt	Sun Mar 25 18:24:31 2001
+++ linux/Documentation/networking/8139too.txt	Thu Apr 19 09:32:48 2001
@@ -185,6 +185,24 @@
 Change History
 --------------
 
+Version 0.9.16 - April 14, 2001
+
+* Complete MMIO audit, disable read-after-every-write
+* Update Rx interrupt handling
+* Enable Early Rx thresholds, highly recommended to reduce
+  Rx FIFO overflow
+* Make 8129 support conditional
+* Support for new 2.4.3 kernel APIs
+* More correct PIO/MMIO PCI BAR region size checking
+* Add check for totally dead/missing hardware
+* Disable media timer code to "set full duplex"
+* s/spin_lock_irq/spin_lock_irqsave/
+* Only set AcceptMulticast if more than one mc address
+* Only set rx_mode if changed, in set_rx_mode
+* Only suspend/resume if interface is up
+* Always print out version upon module load, even if no devices found
+
+
 Version 0.9.15 - February 20, 2001
 
 * Call pci_enable_device to wake up/assign resource to device,
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/TODO linux/Documentation/networking/TODO
--- v2.4.3/linux/Documentation/networking/TODO	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/TODO	Thu Apr 19 13:43:40 2001
@@ -0,0 +1,25 @@
+To-do items for network drivers
+-------------------------------
+
+* Move ethernet crc routine to generic code
+
+* (for 2.5) Integrate Jamal Hadi Salim's netdev Rx polling API change
+
+* Audit all net drivers to make sure magic packet / wake-on-lan /
+  similar features are disabled in the driver by default.
+
+* Audit all net drivers to make sure the module always prints out a
+  version string when loaded as a module, but only prints a version
+  string when built into the kernel if a device is detected.
+
+* Add ETHTOOL_GDRVINFO ioctl support to all ethernet drivers.
+
+
+
+To-do items to consider for network drivers
+-------------------------------------------
+* Make a single function which handles the ethtool ioctl for
+  most MII-compatible devices?  Ideally the driver would pass function
+  pointers to its existing mdio_{read,write} functions when calling the
+  generic ioctl handler.
+
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/comx.txt linux/Documentation/networking/comx.txt
--- v2.4.3/linux/Documentation/networking/comx.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/networking/comx.txt	Fri Apr  6 10:42:48 2001
@@ -162,7 +162,7 @@
 some restricions in order to be able to use non-async lines too.
 If configured, this driver can use Van Jacobson TCP header compression (you'll
 need the slhc.o module for this).
-Additionaly to use this protocol, enable async ppp in your kernel config, and
+Additionally to use this protocol, enable async ppp in your kernel config, and
 create the comx device special files in /dev. They're character special files
 with major 88, and their names must be the same as their network interface
 counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/olympic.txt linux/Documentation/networking/olympic.txt
--- v2.4.3/linux/Documentation/networking/olympic.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/networking/olympic.txt	Wed Apr 18 11:39:21 2001
@@ -3,18 +3,21 @@
 
 Release 0.2.0 - Release    
 	June 8th 1999 Peter De Schrijver & Mike Phillips
-
+Release 0.9.C - Release
+	April 18th 2001 Mike Phillips
 
 Thanks:
 Erik De Cock, Adrian Bridgett and Frank Fiene for their 
-patience and testing.  
-Paul Norton without whose tr.c code we would have had
-a lot more work to do.
+patience and testing.
+Donald Champion for the cardbus support
+Kyle Lucke for the dma api changes.   
+Jonathon Bitner for hardware support. 
+Everybody on linux-tr for their continued support.  
  
 Options:
 
-The driver accepts three options: ringspeed, pkt_buf_sz, and  
-message_level.
+The driver accepts four options: ringspeed, pkt_buf_sz,  
+message_level and network_monitor.
 
 These options can be specified differently for each card found. 
 
@@ -40,6 +43,17 @@
 value will display all soft messages as well.  NB This does not turn 
 debugging messages on, that must be done by modified the source code.
 
+network_monitor: Any non-zero value will provide a quasi network monitoring 
+mode.  All unexpected MAC frames (beaconing etc.) will be received
+by the driver and the source and destination addresses printed. 
+Also an entry will be added in  /proc/net called olympic_tr%d, where tr%d
+is the registered device name, i.e tr0, tr1, etc. This displays low
+level information about the configuration of the ring and the adapter.
+This feature has been designed for network administrators to assist in 
+the diagnosis of network / ring problems. (This used to OLYMPIC_NETWORK_MONITOR,
+but has now changed to allow each adapter to be configured differently and
+to alleviate the necessity to re-compile olympic to turn the option on).
+
 Multi-card:
 
 The driver will detect multiple cards and will work with shared interrupts,
@@ -60,16 +74,6 @@
 building routers, gateway's etc, you could start to use a lot of memory
 real fast.
 
-Network Monitor Mode:
-
-By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the 
-source code the driver will implement a quasi network monitoring 
-mode.  All unexpected MAC frames (beaconing etc.) will be received
-by the driver and the source and destination addresses printed. 
-Also an entry will be added in  /proc/net called olympic_tr. This 
-displays low level information about the configuration of the ring and
-the adapter. This feature has been designed for network administrators
-to assist in the diagnosis of network / ring problems.
 
 6/8/99 Peter De Schrijver and Mike Phillips
 
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/tuntap.txt linux/Documentation/networking/tuntap.txt
--- v2.4.3/linux/Documentation/networking/tuntap.txt	Fri Sep 22 15:19:30 2000
+++ linux/Documentation/networking/tuntap.txt	Wed Apr 25 14:59:56 2001
@@ -37,7 +37,7 @@
 	alias char-major-10-200 tun
      
      Run:
-        modprobe -a 
+        depmod -a 
 
      Driver will be automatically loaded when application access /dev/net/tun.
 
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt
--- v2.4.3/linux/Documentation/networking/wan-router.txt	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/networking/wan-router.txt	Thu Apr 12 12:11:39 2001
@@ -1,27 +1,12 @@
 ------------------------------------------------------------------------------
-WAN Router for Linux Operating System
+Linux WAN Router Utilities Package
 ------------------------------------------------------------------------------
-Version 2.1.1 - Nov 08, 1999
-Version 2.0.8 - Nov 02, 1999
-Version 2.0.7 - Aug 26, 1999
-Version 2.0.6 - Aug 17, 1999
-Version 2.0.5 - Aug 12, 1999
-Version 2.0.4 - Nov 26, 1998
-Version 2.0.3 - Aug 25, 1998
-Version 2.0.2 - Dec 09, 1997
-Version 2.0.1 - Nov 28, 1997
-Version 2.0.0 - Nov 06, 1997
-Version 1.0.3 - June 3, 1997
-Version 1.0.1 - January 30, 1997
+Version 2.2.1 
+Mar 28, 2001
 Author: Nenad Corbic <ncorbic@sangoma.com>
-Copyright (c) 1995-1999 Sangoma Technologies Inc.
+Copyright (c) 1995-2001 Sangoma Technologies Inc.
 ------------------------------------------------------------------------------
 
-
-WARNING:  This Version of WANPIPE supports only the S508 and S508/FT1 cards.  
-IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR 
-AN UPGRADE.  ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. 
-
 INTRODUCTION
 
 Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs)
@@ -41,7 +26,7 @@
 Unix-like operating system anyway). With a number of relatively inexpensive WAN
 interface cards available on the market, a perfectly usable router can be
 built for less than half a price of an external router.  Yet a Linux box
-acting as a router can still be used for other purposes, such as firewalling,
+acting as a router can still be used for other purposes, such as fire-walling,
 running FTP, WWW or DNS server, etc.
 
 This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux
@@ -87,15 +72,28 @@
 To ba able to use the Linux WAN Router you will also need a WAN Tools package
 available from
 
-	ftp.sangoma.com/pub/linux/vX.Y.Z/wantools-X.Y.Z.tgz
-			or
-	ftp.sangoma.com/pub/linux/vX.Y.Z/wanpipe-X.Y.Z.tgz
+	ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz
+
+where vX.Y.Z represent the wanpipe version number.
+
+For technical questions and/or comments please e-mail to ncorbic@sangoma.com.
+For general inquiries please contact Sangoma Technologies Inc. by
 
-where vX.Y.Z represent the Linux kernel version number.
+	Hotline:	1-800-388-2475	(USA and Canada, toll free)
+	Phone:		(905) 474-1990  ext: 106
+	Fax:		(905) 474-9223
+	E-mail:		dm@sangoma.com	(David Mandelstam)
+	WWW:		http://www.sangoma.com
 
-For technical questions and/or comments regarding this product please e-mail
-to jaspreet@sangoma.com or dm@sangoma.com.
 
+INSTALLATION
+
+Please read the WanpipeForLinux.pdf manual on how to 
+install the WANPIPE tools and drivers properly. 
+
+
+After installing wanpipe package: /usr/local/wanrouter/doc. 
+On the ftp.sangoma.com : /linux/current_wanpipe/doc
 
 
 COPYRIGHT AND LICENSING INFORMATION
@@ -114,120 +112,511 @@
 
 
 
-ACKNOWLEDGMENTS
+ACKNOWLEDGEMENTS
 
 This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
-by Sangoma Technologies Inc. for Linux 1.2.x.  Release of Linux 2.0 in summer
-1996 commanded adequate changes to the WANPIPE code to take full advantage of
-new Linux features.  Instead of continuing developing proprietary interface
-specific to Sangoma WAN cards, we decided to put all hardware-independent code
-into a separate module and define two levels of interfaces - one for user-
-level applications and another for kernel-level WAN drivers.
+by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x.  Success of the WANPIPE
+together with the next major release of Linux kernel in summer 1996 commanded
+adequate changes to the WANPIPE code to take full advantage of new Linux
+features.
+
+Instead of continuing developing proprietary interface tied to Sangoma WAN
+cards, we decided to separate all hardware-independent code into a separate
+module and defined two levels of interfaces - one for user-level applications
+and another for kernel-level WAN drivers.  WANPIPE is now implemented as a
+WAN driver compliant with the WAN Link Driver interface.  Also a general
+purpose WAN configuration utility and a set of shell scripts was developed to 
+support WAN router at the user level.
 
 Many useful ideas concerning hardware-independent interface implementation
 were given by Mike McLagan <mike.mclagan@linux.org> and his implementation
 of the Frame Relay router and drivers for Sangoma cards (dlci/sdla).
 
+With the new implementation of the APIs being incorporated into the WANPIPE,
+a special thank goes to Alan Cox in providing insight into BSD sockets.
+
 Special thanks to all the WANPIPE users who performed field-testing, reported
 bugs and made valuable comments and suggestions that help us to improve this
 product.
 
 
 
+NEW IN THIS RELEASE
+
+	o Updated the WANCFG utility
+		Calls the pppconfig to configure the PPPD
+		for async connections.
+
+	o Added the PPPCONFIG utility
+		Used to configure the PPPD dameon for the
+		WANPIPE Async PPP and standard serial port.
+		The wancfg calls the pppconfig to configure
+		the pppd.
+
+	o Fixed the PCI autodetect feature.  
+		The SLOT 0 was used as an autodetect option
+		however, some high end PC's slot numbers start
+		from 0. 
+
+	o This release has been tested with the new backupd
+	  daemon release.
+	
+
+PRODUCT COMPONENTS AND RELATED FILES
+
+/etc: (or user defined)
+	wanpipe1.conf	default router configuration file
+
+/lib/modules/X.Y.Z/misc:
+	wanrouter.o	router kernel loadable module
+	af_wanpipe.o	wanpipe api socket module
+
+/lib/modules/X.Y.Z/net:
+	sdladrv.o	Sangoma SDLA support module
+	wanpipe.o	Sangoma WANPIPE(tm) driver module
+
+/proc/net/wanrouter
+	Config		reads current router configuration
+	Status		reads current router status
+	{name}		reads WAN driver statistics
+
+/usr/sbin:
+	wanrouter	wanrouter start-up script
+	wanconfig	wanrouter configuration utility
+	sdladump	WANPIPE adapter memory dump utility
+        fpipemon        Monitor for Frame Relay
+        cpipemon        Monitor for Cisco HDLC
+	ppipemon 	Monitor for PPP
+	xpipemon 	Monitor for X25
+	wpkbdmon        WANPIPE keyboard led monitor/debugger
+
+/usr/local/wanrouter:
+	README		this file
+	COPYING		GNU General Public License
+	Setup		installation script
+	Filelist	distribution definition file
+	wanrouter.rc	meta-configuration file 
+			(used by the Setup and wanrouter script)
+
+/usr/local/wanrouter/doc:
+	wanpipeForLinux.pdf 	WAN Router User's Manual
+
+/usr/local/wanrouter/patches:
+	wanrouter-v2213.gz  	patch for Linux kernels 2.2.11 up to 2.2.13.
+	wanrouter-v2214.gz	patch for Linux kernel 2.2.14. 
+	wanrouter-v2215.gz	patch for Linux kernels 2.2.15 to 2.2.17.
+	wanrouter-v2218.gz	patch for Linux kernels 2.2.18 and up.
+	wanrouter-v240.gz	patch for Linux kernel 2.4.0.  
+	wanrouter-v242.gz	patch for Linux kernel 2.4.2 and up.
+	wanrouter-v2034.gz	patch for Linux kernel 2.0.34
+	wanrouter-v2036.gz 	patch for Linux kernel 2.0.36 and up. 
+
+/usr/local/wanrouter/patches/kdrivers:
+	Sources of the latest WANPIPE device drivers.
+	These are used to UPGRADE the linux kernel to the newest
+	version if the kernel source has already been pathced with
+	WANPIPE drivers.
+
+/usr/local/wanrouter/samples:
+	interface	sample interface configuration file
+	wanpipe1.cpri 	CHDLC primary port
+     	wanpipe2.csec 	CHDLC secondary port
+     	wanpipe1.fr   	Frame Relay protocol
+     	wanpipe1.ppp  	PPP protocol ) 
+	wanpipe1.asy	CHDLC ASYNC protocol
+	wanpipe1.x25	X25 protocol
+	wanpipe1.stty	Sync TTY driver (Used by Kernel PPPD daemon)
+	wanpipe1.atty	Async TTY driver (Used by Kernel PPPD daemon)
+	wanrouter.rc	sample meta-configuration file
+
+/usr/local/wanrouter/util:
+	*		wan-tools utilities source code
+
+/usr/local/wanrouter/api/x25:
+	*		x25 api sample programs.
+/usr/local/wanrouter/api/chdlc:
+	*		chdlc api sample programs.
+/usr/local/wanrouter/api/fr:
+	*		fr api sample programs.
+/usr/local/wanrouter/config/wancfg:
+	wancfg		WANPIPE GUI configuration program.
+                        Creates wanpipe#.conf files. 
+/usr/local/wanrouter/config/cfgft1:
+	cfgft1		GUI CSU/DSU configuration program.
+
+/usr/include/linux:
+	wanrouter.h	router API definitions
+	wanpipe.h	WANPIPE API definitions
+	sdladrv.h	SDLA support module API definitions
+	sdlasfm.h	SDLA firmware module definitions
+	if_wanpipe.h	WANPIPE Socket definitions
+	if_wanpipe_common.h	WANPIPE Socket/Driver common definitions.
+	sdlapci.h	WANPIPE PCI definitions
+	
+
+/usr/src/linux/net/wanrouter:
+	*		wanrouter source code
+
+/var/log:
+	wanrouter	wanrouter start-up log (created by the Setup script)
+
+/var/lock:  (or /var/lock/subsys for RedHat)
+	wanrouter	wanrouter lock file (created by the Setup script)
+
+/usr/local/wanrouter/firmware:
+	fr514.sfm	Frame relay firmware for Sangoma S508/S514 card
+	cdual514.sfm	Dual Port Cisco HDLC firmware for Sangoma S508/S514 card
+	ppp514.sfm      PPP Firmware for Sangoma S508 and S514 cards
+	x25_508.sfm	X25 Firmware for Sangoma S508 card.
+
+
 REVISION HISTORY
 
-2.1.1   Nov 09, 1999 		- New code for S514PCI card
-                                - Completely redesigned drivers
-                                  fully tested and optimized.
-
-2.0.8   Nov 02, 1999            - Fixed up the X25API code.
-                                - Clear call bug fixed.i
-                                - Enabled driver for multi-card
-                                  operation.                                
-
-2.0.7   Aug 26, 1999		- Merged X25API code into WANPIPE.
-				- Fixed a memory leak for X25API
-				- Updated the X25API code for 2.2.X kernels.
-				- Improved NEM handling.
-
-2.0.6   Aug 17, 1999            - Kernel patch works for both 2.2.10 and 2.2.11 kernels
-                                - Fixed up 2.0.5 installation bugs
-                                - No functional difference between 2.0.6 and 2.0.5         
-
-2.0.5   Aug 12, 1999            - NEW PPP, interrupt drive code
-				- NEW X25 Xpipmon debugger
-				- Comments added to setup scripts
-				- Numerous bug fixes
-
-2.0.4	Nov 26, 1998		- NEW Cisco Dual Port support. 
-				- NEW support for BiSync Streaming API.
-				- NEW support for HDLC (LAPB) API.
-				- WANPIPE provides an API for application 
-				  development using the BSD socket interface.
-
-2.0.3 	Aug 25, 1998		- NEW support for Cisco HDLC, with cpipemon 
-				  utility for monitoring
-				- CIR support for Frame-relay
-				- Support for PAP and CHAP for ppp has been 
-				  implemented
-				- Dynamic IP assignment for PPP
-				- Multiple channel IPX support for Frame-relay 
-				  and X25
-				- Inverse Arp support for Frame-relay
-				- FT1 Configuration utility for linux
-				- Man Pages for router.conf, router, sdladump,
-				  cfgft1, fpipemon, ppipemon and cpipemon
-
-2.0.2	Dev 09, 1997	      - Implemented PAP and CHAP for ppp.
-
-2.0.1	Nov 28, 1997	      -	Protection of "enable_irq()" while
-                                "disable_irq()" has been enabled from any other
-                                routine (for Frame Relay, PPP and X25).
-			      - Added additional Stats for Fpipemon and Ppipemon
-                              - Improved Load Sharing for multiple boards.
-
-2.0.0   Nov 07, 1997          - Implemented protection of RACE conditions by
-                                critical flags for FRAME RELAY and PPP.
-                              - DLCI List interrupt mode implemented.
-                              - IPX support in FRAME RELAY and PPP.
-                              - IPX Server Support (MARS)
-                              - More driver specific stats included in FPIPEMON
-                                and PIPEMON.
-
-1.0.5   July 28, 1997         - Configurable T391,T392,N391,N392,N393 for Frame
-                                Relay in router.conf.
-                              - Configurable Memory Address through router.conf
-                                for Frame Relay, PPP and X.25. (commenting this
-                                out enables auto-detection).
-                              - Fixed freeing up received buffers using kfree()
-                                for Frame Relay and X.25.
-                              - Protect sdla_peek() by calling save_flags(),
-                                cli() and restore_flags().
-                              - Changed number of Trace elements from 32 to 20
-                              - Added DLCI specific data monitoring in FPIPEMON.
-
-1.0.4   July 10, 1997         - S508/FT1 monitoring capability in fpipemon and
-                                ppipemon utilities.
-                              - Configurable TTL for UDP packets.
-                              - Multicast and Broadcast IP source addresses are
-                                silently discarded.
-
-1.0.3	June 3, 1997
-	 		      -	UDP port for multiple boards (Frame relay, PPP)
-	 			Continuous Transmission of Configure Request 
-			      -	Packet for PPP (this support is only added for 
-			   	508 cards)
-	 		      -	Connection Timeout for PPP changed from 900 to 0
-	 	              -	Flow Control for multiple boards and multiple 
-				channels (Frame Relay)
-
-1.0.1	January 30, 1997
+1.0.0	December 31, 1996	Initial version
+
+1.0.1	January 30, 1997	Status and statistics can be read via /proc
+				filesystem entries.
+
+1.0.2   April 30, 1997          Added UDP management via monitors.
+
+1.0.3	June 3, 1997		UDP management for multiple boards using Frame
+				Relay and PPP
+				Enabled continuous transmission of Configure 
+				Request Packet for PPP (for 508 only)
+				Connection Timeout for PPP changed from 900 to 0
+				Flow Control Problem fixed for Frame Relay
+
+1.0.4	July 10, 1997		S508/FT1 monitoring capability in fpipemon and
+				ppipemon utilities.
+				Configurable TTL for UDP packets.
+				Multicast and Broadcast IP source addresses are
+				silently discarded.
+
+1.0.5	July 28, 1997		Configurable T391,T392,N391,N392,N393 for Frame
+				Relay in router.conf.
+				Configurable Memory Address through router.conf 
+				for Frame Relay, PPP and X.25. (commenting this
+ 				out enables auto-detection).
+				Fixed freeing up received buffers using kfree()
+ 				for Frame Relay and X.25.
+				Protect sdla_peek() by calling save_flags(),
+				cli() and restore_flags().
+				Changed number of Trace elements from 32 to 20
+				Added DLCI specific data monitoring in FPIPEMON. 
+2.0.0	Nov 07, 1997		Implemented protection of RACE conditions by 
+				critical flags for FRAME RELAY and PPP.
+				DLCI List interrupt mode implemented.
+				IPX support in FRAME RELAY and PPP.
+				IPX Server Support (MARS)
+				More driver specific stats included in FPIPEMON
+				and PIPEMON.
+
+2.0.1	Nov 28, 1997		Bug Fixes for version 2.0.0.
+				Protection of "enable_irq()" while 
+				"disable_irq()" has been enabled from any other
+				routine (for Frame Relay, PPP and X25).
+				Added additional Stats for Fpipemon and Ppipemon
+				Improved Load Sharing for multiple boards
+
+2.0.2	Dec 09, 1997		Support for PAP and CHAP for ppp has been
+				implemented.
+
+2.0.3	Aug 15, 1998		New release supporting Cisco HDLC, CIR for Frame
+				relay, Dynamic IP assignment for PPP and Inverse
+				Arp support for Frame-relay.  Man Pages are 
+				included for better support and a new utility
+				for configuring FT1 cards.
+
+2.0.4	Dec 09, 1998	        Dual Port support for Cisco HDLC.
+				Support for HDLC (LAPB) API.
+				Supports BiSync Streaming code for S502E 
+				and S503 cards.
+				Support for Streaming HDLC API.
+				Provides a BSD socket interface for 
+				creating applications using BiSync
+   				streaming.        
+
+2.0.5   Aug 04, 1999 		CHDLC initializatin bug fix.
+				PPP interrupt driven driver: 
+  				Fix to the PPP line hangup problem.
+				New PPP firmware
+				Added comments to the startup SYSTEM ERROR messages
+				Xpipemon debugging application for the X25 protocol
+				New USER_MANUAL.txt
+				Fixed the odd boundary 4byte writes to the board.
+				BiSync Streaming code has been taken out.  
+				 Available as a patch.
+				Streaming HDLC API has been taken out.  
+				 Available as a patch.                 
+
+2.0.6   Aug 17, 1999		Increased debugging in statup scripts
+				Fixed insallation bugs from 2.0.5
+				Kernel patch works for both 2.2.10 and 2.2.11 kernels.
+				There is no functional difference between the two packages         
+
+2.0.7   Aug 26, 1999		o  Merged X25API code into WANPIPE.
+				o  Fixed a memeory leak for X25API
+				o  Updated the X25API code for 2.2.X kernels.
+				o  Improved NEM handling.   
+
+2.1.0	Oct 25, 1999		o New code for S514 PCI Card
+				o New CHDLC and Frame Relay drivers
+				o PPP and X25 are not supported in this release    
+
+2.1.1	Nov 30, 1999		o PPP support for S514 PCI Cards
+
+2.1.3   Apr 06, 2000		o Socket based x25api 
+				o Socket based chdlc api
+				o Socket based fr api
+				o Dual Port Receive only CHDLC support.
+				o Asynchronous CHDLC support (Secondary Port)
+				o cfgft1 GUI csu/dsu configurator
+				o wancfg GUI configuration file 
+				  configurator.
+				o Architectual directory changes.
+
+beta-2.1.4 Jul 2000		o Dynamic interface configuration:
+					Network interfaces reflect the state
+					of protocol layer.  If the protocol becomes
+					disconnected, driver will bring down
+					the interface.  Once the protocol reconnects
+					the interface will be brought up. 
+					
+					Note: This option is turned off by default.
+
+				o Dynamic wanrouter setup using 'wanconfig':
+					wanconfig utility can be used to
+					shutdown,restart,start or reconfigure 
+					a virtual circuit dynamically.
+				     
+					Frame Relay:  Each DLCI can be: 
+						      created,stopped,restarted and reconfigured
+						      dynamically using wanconfig.
+					
+						      ex: wanconfig card wanpipe1 dev wp1_fr16 up
+				  
+				o Wanrouter startup via command line arguments:
+					wanconfig also supports wanrouter startup via command line
+					arguments.  Thus, there is no need to create a wanpipe#.conf
+					configuration file.  
+
+				o Socket based x25api update/bug fixes.
+					Added support for LCN numbers greater than 255.
+					Option to pass up modem messages.
+					Provided a PCI IRQ check, so a single S514
+					card is guaranteed to have a non-sharing interrupt.
+
+				o Fixes to the wancfg utility.
+				o New FT1 debugging support via *pipemon utilities.
+				o Frame Relay ARP support Enabled.
+
+beta3-2.1.4 Jul 2000		o X25 M_BIT Problem fix.
+				o Added the Multi-Port PPP
+				  Updated utilites for the Multi-Port PPP.
+
+2.1.4	Aut 2000
+				o In X25API:
+					Maximum packet an application can send
+					to the driver has been extended to 4096 bytes.
+
+					Fixed the x25 startup bug. Enable 
+					communications only after all interfaces
+					come up.  HIGH SVC/PVC is used to calculate
+					the number of channels.
+					Enable protocol only after all interfaces
+					are enabled.
+
+				o Added an extra state to the FT1 config, kernel module.
+				o Updated the pipemon debuggers.
+
+				o Blocked the Multi-Port PPP from running on kernels
+				  2.2.16 or greater, due to syncppp kernel module
+				  change. 
+	  
+beta1-2.1.5 	Nov 15 2000
+				o Fixed the MulitPort PPP Support for kernels 2.2.16 and above.
+				  2.2.X kernels only
+
+				o Secured the driver UDP debugging calls
+					- All illegal netowrk debugging calls are reported to
+					  the log.
+					- Defined a set of allowed commands, all other denied.
+					
+				o Cpipemon
+					- Added set FT1 commands to the cpipemon. Thus CSU/DSU
+					  configuraiton can be performed using cpipemon.
+					  All systems that cannot run cfgft1 GUI utility should
+					  use cpipemon to configure the on board CSU/DSU.
+
+
+				o Keyboard Led Monitor/Debugger
+					- A new utilty /usr/sbin/wpkbdmon uses keyboard leds
+					  to convey operatinal statistic information of the 
+					  Sangoma WANPIPE cards.
+					NUM_LOCK    = Line State  (On=connected,    Off=disconnected)
+					CAPS_LOCK   = Tx data     (On=transmitting, Off=no tx data)
+					SCROLL_LOCK = Rx data     (On=receiving,    Off=no rx data
+					
+				o Hardware probe on module load and dynamic device allocation
+					- During WANPIPE module load, all Sangoma cards are probed
+					  and found information is printed in the /var/log/messages.
+					- If no cards are found, the module load fails.
+					- Appropriate number of devices are dynamically loaded 
+					  based on the number of Sangoma cards found.
+
+					  Note: The kernel configuraiton option 
+						CONFIG_WANPIPE_CARDS has been taken out.
+					
+				o Fixed the Frame Relay and Chdlc network interfaces so they are
+				  compatible with libpcap libraries.  Meaning, tcpdump, snort,
+				  ethereal, and all other packet sniffers and debuggers work on
+				  all WANPIPE netowrk interfaces.
+					- Set the network interface encoding type to ARPHRD_PPP.
+					  This tell the sniffers that data obtained from the
+					  network interface is in pure IP format.
+				  Fix for 2.2.X kernels only.
+				
+				o True interface encoding option for Frame Relay and CHDLC
+					- The above fix sets the network interface encoding
+					  type to ARPHRD_PPP, however some customers use
+					  the encoding interface type to determine the
+					  protocol running.  Therefore, the TURE ENCODING
+					  option will set the interface type back to the
+					  original value.  
+
+					  NOTE: If this option is used with Frame Relay and CHDLC
+						libpcap library support will be broken.  
+						i.e. tcpdump will not work.
+					Fix for 2.2.x Kernels only.
+						
+				o Ethernet Bridgind over Frame Relay
+					- The Frame Relay bridging has been developed by 
+					  Kristian Hoffmann and Mark Wells.  
+					- The Linux kernel bridge is used to send ethernet 
+					  data over the frame relay links.
+					For 2.2.X Kernels only.
+
+				o Added extensive 2.0.X support. Most new features of
+				  2.1.5 for protocols Frame Relay, PPP and CHDLC are
+				  supported under 2.0.X kernels. 
+
+beta1-2.2.0 	Dec 30 2000
+				o Updated drivers for 2.4.X kernels.
+				o Updated drivers for SMP support.
+				o X25API is now able to share PCI interrupts.
+				o Took out a general polling routine that was used
+				  only by X25API. 
+				o Added appropriate locks to the dynamic reconfiguration
+				  code.
+				o Fixed a bug in the keyboard debug monitor.
+
+beta2-2.2.0	Jan 8 2001
+				o Patches for 2.4.0 kernel
+				o Patches for 2.2.18 kernel
+				o Minor updates to PPP and CHLDC drivers.
+				  Note: No functinal difference. 
+
+beta3-2.2.9	Jan 10 2001
+				o I missed the 2.2.18 kernel patches in beta2-2.2.0
+				  release.  They are included in this release.
+
+Stable Release
+2.2.0		Feb 01 2001
+				o Bug fix in wancfg GUI configurator.
+					The edit function didn't work properly.
+
+
+bata1-2.2.1	Feb 09 2001
+			o WANPIPE TTY Driver emulation. 
+			  Two modes of operation Sync and Async.
+				Sync: Using the PPPD daemon, kernel SyncPPP layer
+				      and the Wanpipe sync TTY driver: a PPP protocol 
+				      connection can be established via Sangoma adapter, over
+				      a T1 leased line.
+			
+				      The 2.4.0 kernel PPP layer supports MULTILINK
+				      protocol, that can be used to bundle any number of Sangoma
+				      adapters (T1 lines) into one, under a single IP address.
+				      Thus, efficiently obtaining multiple T1 throughput. 
+
+				      NOTE: The remote side must also implement MULTILINK PPP
+					    protocol.
+
+				Async:Using the PPPD daemon, kernel AsyncPPP layer
+				      and the WANPIPE async TTY driver: a PPP protocol
+				      connection can be established via Sangoma adapter and
+				      a modem, over a telephone line.
+
+				      Thus, the WANPIPE async TTY driver simulates a serial
+				      TTY driver that would normally be used to interface the 
+				      MODEM to the linux kernel.
+				
+			o WANPIPE PPP Backup Utility
+				This utility will monitor the state of the PPP T1 line.
+				In case of failure, a dial up connection will be established
+				via pppd daemon, ether via a serial tty driver (serial port), 
+				or a WANPIPE async TTY driver (in case serial port is unavailable).
+				
+				Furthermore, while in dial up mode, the primary PPP T1 link
+				will be monitored for signs of life.  
+
+				If the PPP T1 link comes back to life, the dial up connection
+				will be shutdown and T1 line re-established.
+			
+
+			o New Setup installation script.
+				Option to UPGRADE device drivers if the kernel source has
+				already been patched with WANPIPE.
+
+				Option to COMPILE WANPIPE modules against the currently 
+				running kernel, thus no need for manual kernel and module
+				re-compilatin.
+			
+			o Updates and Bug Fixes to wancfg utility.
+
+bata2-2.2.1	Feb 20 2001
+
+			o Bug fixes to the CHDLC device drivers.
+				The driver had compilation problmes under kernels
+				2.2.14 or lower.
+
+			o Bug fixes to the Setup installation script.
+				The device drivers compilation options didn't work
+				properly.
+
+			o Update to the wpbackupd daemon.  
+				Optimized the cross-over times, between the primary
+				link and the backup dialup.
+
+beta3-2.2.1	Mar 02 2001
+			o Patches for 2.4.2 kernel.
+
+			o Bug fixes to util/ make files.
+			o Bug fixes to the Setup installation script.
+
+			o Took out the backupd support and made it into
+			  as separate package.
+			  
+beta4-2.2.1     Mar 12 2001
+
+		o Fix to the Frame Relay Device driver.
+			IPSAC sends a packet of zero length
+			header to the frame relay driver.  The
+			driver tries to push its own 2 byte header
+			into the packet, which causes the driver to
+			crash.
+
+		o Fix the WANPIPE re-configuration code.
+			Bug was found by trying to run  the cfgft1 while the
+			interface was already running.  
+
+		o Updates to cfgft1.
+			Writes a wanpipe#.cfgft1 configuration file
+			once the CSU/DSU is configured. This file can
+			holds the current CSU/DSU configuration.
+
 
-			      -	Implemented user-readable status and statistics
-				via /proc filesystem
 
-1.0.0	December 31, 1996
+>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 
-			      -	Initial version
 
->>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
diff -u --recursive --new-file v2.4.3/linux/Documentation/networking/wanpipe.txt linux/Documentation/networking/wanpipe.txt
--- v2.4.3/linux/Documentation/networking/wanpipe.txt	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/networking/wanpipe.txt	Thu Apr 12 12:11:39 2001
@@ -1,32 +1,100 @@
 ------------------------------------------------------------------------------
 Linux WAN Router Utilities Package
 ------------------------------------------------------------------------------
-Version 2.1.1
-Nov 08, 1999
+Version 2.2.1 
+Mar 28, 2001
 Author: Nenad Corbic <ncorbic@sangoma.com>
-Copyright (c) 1995-1999 Sangoma Technologies Inc.
+Copyright (c) 1995-2001 Sangoma Technologies Inc.
 ------------------------------------------------------------------------------
 
 INTRODUCTION
 
-This is a set of utilities and shell scripts you need in order to be able to
-use Linux kernel-level WAN Router.  Please read WAN Router User's manual
-(router.txt) and WANPIPE driver documentation found in /usr/lib/router/doc
-directory for installation and configuration instructions.
+Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs)
+and/or stand-alone hosts over vast distances with data transfer rates
+significantly higher than those achievable with commonly used dial-up
+connections.
+
+Usually an external device called `WAN router' sitting on your local network
+or connected to your machine's serial port provides physical connection to
+WAN.  Although router's job may be as simple as taking your local network
+traffic, converting it to WAN format and piping it through the WAN link, these
+devices are notoriously expensive, with prices as much as 2 - 5 times higher
+then the price of a typical PC box.
+
+Alternatively, considering robustness and multitasking capabilities of Linux,
+an internal router can be built (most routers use some sort of stripped down
+Unix-like operating system anyway). With a number of relatively inexpensive WAN
+interface cards available on the market, a perfectly usable router can be
+built for less than half a price of an external router.  Yet a Linux box
+acting as a router can still be used for other purposes, such as fire-walling,
+running FTP, WWW or DNS server, etc.
+
+This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux
+operating system and provides generic hardware-independent services for such
+drivers.  Why can existing Linux network device interface not be used for
+this purpose?  Well, it can.  However, there are a few key differences between
+a typical network interface (e.g. Ethernet) and a WAN link.
+
+Many WAN protocols, such as X.25 and frame relay, allow for multiple logical
+connections (known as `virtual circuits' in X.25 terminology) over a single
+physical link.  Each such virtual circuit may (and almost always does) lead
+to a different geographical location and, therefore, different network.  As a
+result, it is the virtual circuit, not the physical link, that represents a
+route and, therefore, a network interface in Linux terms.
+
+To further complicate things, virtual circuits are usually volatile in nature
+(excluding so called `permanent' virtual circuits or PVCs).  With almost no
+time required to set up and tear down a virtual circuit, it is highly desirable
+to implement on-demand connections in order to minimize network charges.  So
+unlike a typical network driver, the WAN driver must be able to handle multiple
+network interfaces and cope as multiple virtual circuits come into existence
+and go away dynamically.
+ 
+Last, but not least, WAN configuration is much more complex than that of say
+Ethernet and may well amount to several dozens of parameters.  Some of them
+are "link-wide"  while others are virtual circuit-specific.  The same holds
+true for WAN statistics which is by far more extensive and extremely useful
+when troubleshooting WAN connections.  Extending the ifconfig utility to suit
+these needs may be possible, but does not seem quite reasonable.  Therefore, a
+WAN configuration utility and corresponding application programmer's interface
+is needed for this purpose.
+
+Most of these problems are taken care of by this module.  Its goal is to
+provide a user with more-or-less standard look and feel for all WAN devices and
+assist a WAN device driver writer by providing common services, such as:
+
+ o User-level interface via /proc file system
+ o Centralized configuration
+ o Device management (setup, shutdown, etc.)
+ o Network interface management (dynamic creation/destruction)
+ o Protocol encapsulation/decapsulation
 
-You can find the latest version of this software in /pub/linux directory on
-Sangoma Technologies' anonymous FTP server (ftp.sangoma.com). 
+To ba able to use the Linux WAN Router you will also need a WAN Tools package
+available from
+
+	ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz
+
+where vX.Y.Z represent the wanpipe version number.
 
 For technical questions and/or comments please e-mail to ncorbic@sangoma.com.
 For general inquiries please contact Sangoma Technologies Inc. by
 
 	Hotline:	1-800-388-2475	(USA and Canada, toll free)
-	Phone:		(905) 474-1990
+	Phone:		(905) 474-1990  ext: 106
 	Fax:		(905) 474-9223
 	E-mail:		dm@sangoma.com	(David Mandelstam)
 	WWW:		http://www.sangoma.com
 
 
+INSTALLATION
+
+Please read the WanpipeForLinux.pdf manual on how to 
+install the WANPIPE tools and drivers properly. 
+
+
+After installing wanpipe package: /usr/local/wanrouter/doc. 
+On the ftp.sangoma.com : /linux/current_wanpipe/doc
+
 
 COPYRIGHT AND LICENSING INFORMATION
 
@@ -47,7 +115,7 @@
 ACKNOWLEDGEMENTS
 
 This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
-by Sangoma Technologies Inc. for Linux 2.2.x.  Success of the WANPIPE
+by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x.  Success of the WANPIPE
 together with the next major release of Linux kernel in summer 1996 commanded
 adequate changes to the WANPIPE code to take full advantage of new Linux
 features.
@@ -75,22 +143,33 @@
 
 NEW IN THIS RELEASE
 
-o Renamed startup script to wanrouter
-o Option to turn off/on each router 
-  separately
-o New source directory /usr/lib/wanrouter
-o New PPP driver 
-o X25 is not supported in this release 
+	o Updated the WANCFG utility
+		Calls the pppconfig to configure the PPPD
+		for async connections.
+
+	o Added the PPPCONFIG utility
+		Used to configure the PPPD dameon for the
+		WANPIPE Async PPP and standard serial port.
+		The wancfg calls the pppconfig to configure
+		the pppd.
+
+	o Fixed the PCI autodetect feature.  
+		The SLOT 0 was used as an autodetect option
+		however, some high end PC's slot numbers start
+		from 0. 
 
+	o This release has been tested with the new backupd
+	  daemon release.
 	
+
 PRODUCT COMPONENTS AND RELATED FILES
 
-/etc:
+/etc: (or user defined)
 	wanpipe1.conf	default router configuration file
-	wanrouter.rc	meta-configuration file (used by the Setup script)
 
 /lib/modules/X.Y.Z/misc:
 	wanrouter.o	router kernel loadable module
+	af_wanpipe.o	wanpipe api socket module
 
 /lib/modules/X.Y.Z/net:
 	sdladrv.o	Sangoma SDLA support module
@@ -102,64 +181,93 @@
 	{name}		reads WAN driver statistics
 
 /usr/sbin:
-	wanrouter	router start-up script
-	wanconfig	router configuration utility
+	wanrouter	wanrouter start-up script
+	wanconfig	wanrouter configuration utility
 	sdladump	WANPIPE adapter memory dump utility
         fpipemon        Monitor for Frame Relay
         cpipemon        Monitor for Cisco HDLC
+	ppipemon 	Monitor for PPP
+	xpipemon 	Monitor for X25
+	wpkbdmon        WANPIPE keyboard led monitor/debugger
 
-/usr/lib/wanrouter:
+/usr/local/wanrouter:
 	README		this file
 	COPYING		GNU General Public License
 	Setup		installation script
-	Configure	configuration script
 	Filelist	distribution definition file
+	wanrouter.rc	meta-configuration file 
+			(used by the Setup and wanrouter script)
 
-/usr/lib/wanrouter/doc:
-	WANPIPE_USER_MANUAL.txt WAN Router User's Manual
-	WANPIPE_CONFIG.txt	WAN Configuration Manual
-
-/usr/lib/wanrouter/interfaces:
-	*		interface configuration files (TCP/IP configuration)
-
-/usr/lib/wanrouter/patches:
-	wanrouter-22.gz	patch for Linux kernel 2.2.10 and 2.2.11 
-			(compatible for all 2.2.X kernels)
-	wanrouter-20.gz patch for Linux kernel 2.0.36 
+/usr/local/wanrouter/doc:
+	wanpipeForLinux.pdf 	WAN Router User's Manual
 
-	Fix_2.2.11.gz   patch to fix the 2.2.11 kernel so other patches
-                        can be applied properly.
+/usr/local/wanrouter/patches:
+	wanrouter-v2213.gz  	patch for Linux kernels 2.2.11 up to 2.2.13.
+	wanrouter-v2214.gz	patch for Linux kernel 2.2.14. 
+	wanrouter-v2215.gz	patch for Linux kernels 2.2.15 to 2.2.17.
+	wanrouter-v2218.gz	patch for Linux kernels 2.2.18 and up.
+	wanrouter-v240.gz	patch for Linux kernel 2.4.0.  
+	wanrouter-v242.gz	patch for Linux kernel 2.4.2 and up.
+	wanrouter-v2034.gz	patch for Linux kernel 2.0.34
+	wanrouter-v2036.gz 	patch for Linux kernel 2.0.36 and up. 
+
+/usr/local/wanrouter/patches/kdrivers:
+	Sources of the latest WANPIPE device drivers.
+	These are used to UPGRADE the linux kernel to the newest
+	version if the kernel source has already been pathced with
+	WANPIPE drivers.
 
-/usr/lib/wanrouter/samples:
+/usr/local/wanrouter/samples:
 	interface	sample interface configuration file
 	wanpipe1.cpri 	CHDLC primary port
      	wanpipe2.csec 	CHDLC secondary port
      	wanpipe1.fr   	Frame Relay protocol
      	wanpipe1.ppp  	PPP protocol ) 
+	wanpipe1.asy	CHDLC ASYNC protocol
+	wanpipe1.x25	X25 protocol
+	wanpipe1.stty	Sync TTY driver (Used by Kernel PPPD daemon)
+	wanpipe1.atty	Async TTY driver (Used by Kernel PPPD daemon)
 	wanrouter.rc	sample meta-configuration file
 
-/usr/lib/wanrouter/src:
-	*		wan-tools source code
+/usr/local/wanrouter/util:
+	*		wan-tools utilities source code
+
+/usr/local/wanrouter/api/x25:
+	*		x25 api sample programs.
+/usr/local/wanrouter/api/chdlc:
+	*		chdlc api sample programs.
+/usr/local/wanrouter/api/fr:
+	*		fr api sample programs.
+/usr/local/wanrouter/config/wancfg:
+	wancfg		WANPIPE GUI configuration program.
+                        Creates wanpipe#.conf files. 
+/usr/local/wanrouter/config/cfgft1:
+	cfgft1		GUI CSU/DSU configuration program.
 
 /usr/include/linux:
 	wanrouter.h	router API definitions
 	wanpipe.h	WANPIPE API definitions
 	sdladrv.h	SDLA support module API definitions
 	sdlasfm.h	SDLA firmware module definitions
+	if_wanpipe.h	WANPIPE Socket definitions
+	if_wanpipe_common.h	WANPIPE Socket/Driver common definitions.
+	sdlapci.h	WANPIPE PCI definitions
+	
 
-/usr/src/linux/net/router:
-	*		router source code
+/usr/src/linux/net/wanrouter:
+	*		wanrouter source code
 
 /var/log:
-	wanrouter	router start-up log (created by the Setup script)
+	wanrouter	wanrouter start-up log (created by the Setup script)
 
-/var/lock:
-	wanrouter	router lock file (created by the Setup script)
+/var/lock:  (or /var/lock/subsys for RedHat)
+	wanrouter	wanrouter lock file (created by the Setup script)
 
-/usr/lib/wanrouter/wanpipe:
+/usr/local/wanrouter/firmware:
 	fr514.sfm	Frame relay firmware for Sangoma S508/S514 card
 	cdual514.sfm	Dual Port Cisco HDLC firmware for Sangoma S508/S514 card
 	ppp514.sfm      PPP Firmware for Sangoma S508 and S514 cards
+	x25_508.sfm	X25 Firmware for Sangoma S508 card.
 
 
 REVISION HISTORY
@@ -228,7 +336,7 @@
 				creating applications using BiSync
    				streaming.        
 
-2.0.5   Aug 04, 1999 		CHDLC initialization bug fix.
+2.0.5   Aug 04, 1999 		CHDLC initializatin bug fix.
 				PPP interrupt driven driver: 
   				Fix to the PPP line hangup problem.
 				New PPP firmware
@@ -241,17 +349,274 @@
 				Streaming HDLC API has been taken out.  
 				 Available as a patch.                 
 
-2.0.6   Aug 17, 1999		Increased debugging in startup scripts
-				Fixed installation bugs from 2.0.5
+2.0.6   Aug 17, 1999		Increased debugging in statup scripts
+				Fixed insallation bugs from 2.0.5
 				Kernel patch works for both 2.2.10 and 2.2.11 kernels.
 				There is no functional difference between the two packages         
 
 2.0.7   Aug 26, 1999		o  Merged X25API code into WANPIPE.
-				o  Fixed a memory leak for X25API
+				o  Fixed a memeory leak for X25API
 				o  Updated the X25API code for 2.2.X kernels.
 				o  Improved NEM handling.   
 
 2.1.0	Oct 25, 1999		o New code for S514 PCI Card
 				o New CHDLC and Frame Relay drivers
 				o PPP and X25 are not supported in this release    
+
+2.1.1	Nov 30, 1999		o PPP support for S514 PCI Cards
+
+2.1.3   Apr 06, 2000		o Socket based x25api 
+				o Socket based chdlc api
+				o Socket based fr api
+				o Dual Port Receive only CHDLC support.
+				o Asynchronous CHDLC support (Secondary Port)
+				o cfgft1 GUI csu/dsu configurator
+				o wancfg GUI configuration file 
+				  configurator.
+				o Architectual directory changes.
+
+beta-2.1.4 Jul 2000		o Dynamic interface configuration:
+					Network interfaces reflect the state
+					of protocol layer.  If the protocol becomes
+					disconnected, driver will bring down
+					the interface.  Once the protocol reconnects
+					the interface will be brought up. 
+					
+					Note: This option is turned off by default.
+
+				o Dynamic wanrouter setup using 'wanconfig':
+					wanconfig utility can be used to
+					shutdown,restart,start or reconfigure 
+					a virtual circuit dynamically.
+				     
+					Frame Relay:  Each DLCI can be: 
+						      created,stopped,restarted and reconfigured
+						      dynamically using wanconfig.
+					
+						      ex: wanconfig card wanpipe1 dev wp1_fr16 up
+				  
+				o Wanrouter startup via command line arguments:
+					wanconfig also supports wanrouter startup via command line
+					arguments.  Thus, there is no need to create a wanpipe#.conf
+					configuration file.  
+
+				o Socket based x25api update/bug fixes.
+					Added support for LCN numbers greater than 255.
+					Option to pass up modem messages.
+					Provided a PCI IRQ check, so a single S514
+					card is guaranteed to have a non-sharing interrupt.
+
+				o Fixes to the wancfg utility.
+				o New FT1 debugging support via *pipemon utilities.
+				o Frame Relay ARP support Enabled.
+
+beta3-2.1.4 Jul 2000		o X25 M_BIT Problem fix.
+				o Added the Multi-Port PPP
+				  Updated utilites for the Multi-Port PPP.
+
+2.1.4	Aut 2000
+				o In X25API:
+					Maximum packet an application can send
+					to the driver has been extended to 4096 bytes.
+
+					Fixed the x25 startup bug. Enable 
+					communications only after all interfaces
+					come up.  HIGH SVC/PVC is used to calculate
+					the number of channels.
+					Enable protocol only after all interfaces
+					are enabled.
+
+				o Added an extra state to the FT1 config, kernel module.
+				o Updated the pipemon debuggers.
+
+				o Blocked the Multi-Port PPP from running on kernels
+				  2.2.16 or greater, due to syncppp kernel module
+				  change. 
+	  
+beta1-2.1.5 	Nov 15 2000
+				o Fixed the MulitPort PPP Support for kernels 2.2.16 and above.
+				  2.2.X kernels only
+
+				o Secured the driver UDP debugging calls
+					- All illegal netowrk debugging calls are reported to
+					  the log.
+					- Defined a set of allowed commands, all other denied.
+					
+				o Cpipemon
+					- Added set FT1 commands to the cpipemon. Thus CSU/DSU
+					  configuraiton can be performed using cpipemon.
+					  All systems that cannot run cfgft1 GUI utility should
+					  use cpipemon to configure the on board CSU/DSU.
+
+
+				o Keyboard Led Monitor/Debugger
+					- A new utilty /usr/sbin/wpkbdmon uses keyboard leds
+					  to convey operatinal statistic information of the 
+					  Sangoma WANPIPE cards.
+					NUM_LOCK    = Line State  (On=connected,    Off=disconnected)
+					CAPS_LOCK   = Tx data     (On=transmitting, Off=no tx data)
+					SCROLL_LOCK = Rx data     (On=receiving,    Off=no rx data
+					
+				o Hardware probe on module load and dynamic device allocation
+					- During WANPIPE module load, all Sangoma cards are probed
+					  and found information is printed in the /var/log/messages.
+					- If no cards are found, the module load fails.
+					- Appropriate number of devices are dynamically loaded 
+					  based on the number of Sangoma cards found.
+
+					  Note: The kernel configuraiton option 
+						CONFIG_WANPIPE_CARDS has been taken out.
+					
+				o Fixed the Frame Relay and Chdlc network interfaces so they are
+				  compatible with libpcap libraries.  Meaning, tcpdump, snort,
+				  ethereal, and all other packet sniffers and debuggers work on
+				  all WANPIPE netowrk interfaces.
+					- Set the network interface encoding type to ARPHRD_PPP.
+					  This tell the sniffers that data obtained from the
+					  network interface is in pure IP format.
+				  Fix for 2.2.X kernels only.
+				
+				o True interface encoding option for Frame Relay and CHDLC
+					- The above fix sets the network interface encoding
+					  type to ARPHRD_PPP, however some customers use
+					  the encoding interface type to determine the
+					  protocol running.  Therefore, the TURE ENCODING
+					  option will set the interface type back to the
+					  original value.  
+
+					  NOTE: If this option is used with Frame Relay and CHDLC
+						libpcap library support will be broken.  
+						i.e. tcpdump will not work.
+					Fix for 2.2.x Kernels only.
+						
+				o Ethernet Bridgind over Frame Relay
+					- The Frame Relay bridging has been developed by 
+					  Kristian Hoffmann and Mark Wells.  
+					- The Linux kernel bridge is used to send ethernet 
+					  data over the frame relay links.
+					For 2.2.X Kernels only.
+
+				o Added extensive 2.0.X support. Most new features of
+				  2.1.5 for protocols Frame Relay, PPP and CHDLC are
+				  supported under 2.0.X kernels. 
+
+beta1-2.2.0 	Dec 30 2000
+				o Updated drivers for 2.4.X kernels.
+				o Updated drivers for SMP support.
+				o X25API is now able to share PCI interrupts.
+				o Took out a general polling routine that was used
+				  only by X25API. 
+				o Added appropriate locks to the dynamic reconfiguration
+				  code.
+				o Fixed a bug in the keyboard debug monitor.
+
+beta2-2.2.0	Jan 8 2001
+				o Patches for 2.4.0 kernel
+				o Patches for 2.2.18 kernel
+				o Minor updates to PPP and CHLDC drivers.
+				  Note: No functinal difference. 
+
+beta3-2.2.9	Jan 10 2001
+				o I missed the 2.2.18 kernel patches in beta2-2.2.0
+				  release.  They are included in this release.
+
+Stable Release
+2.2.0		Feb 01 2001
+				o Bug fix in wancfg GUI configurator.
+					The edit function didn't work properly.
+
+
+bata1-2.2.1	Feb 09 2001
+			o WANPIPE TTY Driver emulation. 
+			  Two modes of operation Sync and Async.
+				Sync: Using the PPPD daemon, kernel SyncPPP layer
+				      and the Wanpipe sync TTY driver: a PPP protocol 
+				      connection can be established via Sangoma adapter, over
+				      a T1 leased line.
+			
+				      The 2.4.0 kernel PPP layer supports MULTILINK
+				      protocol, that can be used to bundle any number of Sangoma
+				      adapters (T1 lines) into one, under a single IP address.
+				      Thus, efficiently obtaining multiple T1 throughput. 
+
+				      NOTE: The remote side must also implement MULTILINK PPP
+					    protocol.
+
+				Async:Using the PPPD daemon, kernel AsyncPPP layer
+				      and the WANPIPE async TTY driver: a PPP protocol
+				      connection can be established via Sangoma adapter and
+				      a modem, over a telephone line.
+
+				      Thus, the WANPIPE async TTY driver simulates a serial
+				      TTY driver that would normally be used to interface the 
+				      MODEM to the linux kernel.
+				
+			o WANPIPE PPP Backup Utility
+				This utility will monitor the state of the PPP T1 line.
+				In case of failure, a dial up connection will be established
+				via pppd daemon, ether via a serial tty driver (serial port), 
+				or a WANPIPE async TTY driver (in case serial port is unavailable).
+				
+				Furthermore, while in dial up mode, the primary PPP T1 link
+				will be monitored for signs of life.  
+
+				If the PPP T1 link comes back to life, the dial up connection
+				will be shutdown and T1 line re-established.
+			
+
+			o New Setup installation script.
+				Option to UPGRADE device drivers if the kernel source has
+				already been patched with WANPIPE.
+
+				Option to COMPILE WANPIPE modules against the currently 
+				running kernel, thus no need for manual kernel and module
+				re-compilatin.
+			
+			o Updates and Bug Fixes to wancfg utility.
+
+bata2-2.2.1	Feb 20 2001
+
+			o Bug fixes to the CHDLC device drivers.
+				The driver had compilation problmes under kernels
+				2.2.14 or lower.
+
+			o Bug fixes to the Setup installation script.
+				The device drivers compilation options didn't work
+				properly.
+
+			o Update to the wpbackupd daemon.  
+				Optimized the cross-over times, between the primary
+				link and the backup dialup.
+
+beta3-2.2.1	Mar 02 2001
+			o Patches for 2.4.2 kernel.
+
+			o Bug fixes to util/ make files.
+			o Bug fixes to the Setup installation script.
+
+			o Took out the backupd support and made it into
+			  as separate package.
+			  
+beta4-2.2.1     Mar 12 2001
+
+		o Fix to the Frame Relay Device driver.
+			IPSAC sends a packet of zero length
+			header to the frame relay driver.  The
+			driver tries to push its own 2 byte header
+			into the packet, which causes the driver to
+			crash.
+
+		o Fix the WANPIPE re-configuration code.
+			Bug was found by trying to run  the cfgft1 while the
+			interface was already running.  
+
+		o Updates to cfgft1.
+			Writes a wanpipe#.cfgft1 configuration file
+			once the CSU/DSU is configured. This file can
+			holds the current CSU/DSU configuration.
+
+
+
 >>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+
diff -u --recursive --new-file v2.4.3/linux/Documentation/parport.txt linux/Documentation/parport.txt
--- v2.4.3/linux/Documentation/parport.txt	Mon Mar 26 15:41:19 2001
+++ linux/Documentation/parport.txt	Fri Apr  6 10:42:51 2001
@@ -174,7 +174,7 @@
 		peripherals.  This is a port-wide setting, i.e. it
 		applies to all devices on a particular port.
 
-timeslice	The number of miliseconds that a device driver is
+timeslice	The number of milliseconds that a device driver is
 		allowed to keep a port claimed for.  This is advisory,
 		and driver can ignore it if it must.
 
diff -u --recursive --new-file v2.4.3/linux/Documentation/pm.txt linux/Documentation/pm.txt
--- v2.4.3/linux/Documentation/pm.txt	Thu Oct 26 14:22:24 2000
+++ linux/Documentation/pm.txt	Fri Apr  6 10:42:55 2001
@@ -33,7 +33,7 @@
 Go ahead and start both.  If ACPI or APM is not available on your
 system the associated daemon will exit gracefully.
 
-  apmd:   http://linuxcare.com.au/apm/
+  apmd:   http://worldvisions.ca/~apenwarr/apmd/
   acpid:  http://phobos.fs.tum.de/acpi/
 
 Driver Interface
diff -u --recursive --new-file v2.4.3/linux/Documentation/s390/3270.ChangeLog linux/Documentation/s390/3270.ChangeLog
--- v2.4.3/linux/Documentation/s390/3270.ChangeLog	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/3270.ChangeLog	Thu Apr 12 12:03:50 2001
@@ -0,0 +1,15 @@
+ChangeLog for the UTS Global 3270-support patch
+
+Feb 6, 2001:
+	* This changelog is new
+	* tub3270 now supports 3270 console:
+		Specify y for CONFIG_3270 and y for CONFIG_3270_CONSOLE.
+		Support for 3215 will not appear if 3270 console support
+		is chosen.
+		NOTE:  The default is 3270 console support, NOT 3215.
+	* the components are remodularized: added source modules are
+	  tubttybld.c and tubttyscl.c, for screen-building code and
+	  scroll-timeout code.
+	* tub3270 source for this (2.4.0) version is #ifdeffed to
+	  build with both 2.4.0 and 2.2.16.2.
+	* color support and minimal other ESC-sequence support is added.
diff -u --recursive --new-file v2.4.3/linux/Documentation/s390/3270.txt linux/Documentation/s390/3270.txt
--- v2.4.3/linux/Documentation/s390/3270.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/3270.txt	Thu Apr 12 12:03:50 2001
@@ -0,0 +1,280 @@
+IBM 3270 Display System support
+
+This file describes the driver that supports local channel attachment
+of IBM 3270 devices.  It consists of three sections:
+	* Introduction
+	* Installation
+	* Operation
+
+
+INTRODUCTION.
+
+This paper describes installing and operating 3270 devices under
+Linux/390.  A 3270 device is a block-mode rows-and-columns terminal of
+which I'm sure hundreds of millions were sold by IBM and clonemakers
+twenty and thirty years ago.
+
+You may have 3270s in-house and not know it.  If you're using the
+VM-ESA operating system, define a 3270 to your virtual machine by using
+the command "DEF GRAF <hex-address>"  This paper presumes you will be
+defining four 3270s with the CP/CMS commands
+
+	DEF GRAF 620
+	DEF GRAF 621
+	DEF GRAF 622
+	DEF GRAF 623
+
+Your network connection from VM-ESA allows you to use x3270, tn3270, or
+another 3270 emulator, started from an xterm window on your PC or
+workstation.  With the DEF GRAF command, an application such as xterm,
+and this Linux-390 3270 driver, you have another way of talking to your
+Linux box.
+
+This paper covers installation of the driver and operation of a
+dialed-in x3270.
+
+
+HELP !!!
+
+The device name of e.g. /dev/3270/tty620 noted below is at variance
+with "standard" Linux device names.  What should it be?  The portion
+"/dev/3270" was recommended by H. Peter Anvin, maintainer of the
+official Linux major-numbers list; the portion "tty620" was recommended
+by me.  Please send your thoughts on this issue at least to me at
+rbh00@utsglobal.com.  Even if you think it's okay as is, please let me
+know.  Thanks.
+
+
+INSTALLATION.
+
+You install the driver by installing a patch, doing a kernel build, and
+running the configuration script (config3270.sh, in this directory).
+
+WARNING:  If you are using 3270 console support, you must rerun the
+configuration script every time you change the console's address (perhaps
+by using the condev= parameter in silo's /boot/parmfile).  More precisely,
+you should rerun the configuration script every time your set of 3270s,
+including the console 3270, changes subchannel identifier relative to
+one another.  ReIPL as soon as possible after running the configuration
+script and the resulting /tmp/mkdev3270.
+
+If you have chosen to make tub3270 a module, you add a line to
+/etc/modules.conf.  If you are working on a VM virtual machine, you
+can use DEF GRAF to define virtual 3270 devices.  If you generate 3270
+console support, the driver automatically converts your console at boot
+time to a 3270 if it is a 3215.
+
+In brief, these are the steps:
+	1. Install the tub3270 patch
+	2. (If a module) add a line to /etc/modules.conf
+	3. (If VM) define devices with DEF GRAF
+	4. Reboot
+	5. Configure
+
+To test that everything works, assuming VM and x3270,
+	1. Bring up an x3270 window.
+	2. Use the DIAL command in that window.
+	3. You should immediately see a Linux login screen.
+
+Here are the installation steps in detail:
+
+	0.  Retrieve the patch file via anonymous ftp from
+	ftp://ftp.utsglobal.com/pub/tub3270.  The patch is designed
+	to apply smoothly to an IBM 2.4.0 system with no other
+	UTS-Global patches applied.  We know of some easily resolvable
+	conflicts between this and other of our patches.
+
+	1. Apply the patch.  Then do
+		make oldconfig
+			(Reply "y" or "m" for CONFIG_3270; if "y",
+			reply "y" or "n" for CONFIG_3270_CONSOLE)
+		make dep
+		make image
+		make modules
+		make modules_install
+		<run silo in the usual way>
+
+	2. (Perform this step only if you have configured tub3270 as a
+	module.)  Add a line to /etc/modules.conf to automatically
+	load the driver when it's needed.  With this line added,
+	you will see login prompts appear on your 3270s as soon as
+	boot is complete (or with emulated 3270s, as soon as you dial
+	into your vm guest using the command "DIAL <vmguestname>").
+	Since the line-mode major number is 212, the line to add to
+	/etc/modules.conf should be:
+		alias char-major-212 tub3270
+
+	3. Define graphic devices to your vm guest machine, if you
+	haven't already.  Define them before you reboot (reipl):
+		DEFINE GRAF 620
+		DEFINE GRAF 621
+		DEFINE GRAF 622
+		DEFINE GRAF 623
+
+	4. Reboot.  The reboot process scans hardware devices, including
+	3270s, and this enables the tub3270 driver once loaded to respond
+	correctly to the configuration requests of the next step.  If
+	you have chosen 3270 console support, your console now behaves
+	as a 3270, not a 3215.
+
+	5. Run the 3270 configuration script config3270.  It is
+	distributed in this same directory, Documentation/s390, as
+	config3270.sh.	Inspect the output script it produces,
+	/tmp/mkdev3270, and then run that script.  This will create the
+	necessary character special device files and make the necessary
+	changes to /etc/inittab.  Then notify /sbin/init that /etc/inittab
+	has changed, by issuing the telinit command with the q operand:
+		cd /usr/src/linux/Documentation/s390
+		sh config3270.sh
+		sh /tmp/mkdev3270
+		telinit q
+	This should be sufficient for your first time.	If your 3270
+	configuration has changed and you're reusing config3270, you
+	should follow these steps:
+		Change 3270 configuration
+		Reboot
+		Run config3270 and /tmp/mkdev3270
+		Reboot
+
+Here are the testing steps in detail:
+
+	1. Bring up an x3270 window, or use an actual hardware 3278 or
+	3279, or use the 3270 emulator of your choice.  You would be
+	running the emulator on your PC or workstation.  You would use
+	the command, for example,
+		x3270 vm-esa-domain-name &
+	if you wanted a 3278 Model 4 with 43 rows of 80 columns, the
+	default model number.  The driver does not take advantage of
+	extended attributes.
+
+	The screen you should now see contains a VM logo with input
+	lines near the bottom.  Use TAB to move to the bottom line,
+	probably labeled "COMMAND  ===>".
+
+	2. Use the DIAL command instead of the LOGIN command to connect
+	to one of the virtual 3270s you defined with the DEF GRAF
+	commands:
+		dial my-vm-guest-name
+
+	3. You should immediately see a login prompt from your
+	Linux-390 operating system.  If that does not happen, you would
+	see instead the line "DIALED TO my-vm-guest-name   0620".
+
+	To troubleshoot:  do these things.
+
+	A. Is the driver loaded?  Use the lsmod command (no operands)
+	to find out.  Probably it isn't.  Try loading it manually, with
+	the command "insmod tub3270".  Does that command give error
+	messages?  Ha!  There's your problem.
+
+	B. Is the /etc/inittab file modified as in installation step 3
+	above?  Use the grep command to find out; for instance, issue
+	"grep 3270 /etc/inittab".  Nothing found?  There's your
+	problem!
+
+	C. Are the device special files created, as in installation
+	step 2 above?  Use the ls -l command to find out; for instance,
+	issue "ls -l /dev/3270/tty620".  The output should start with the
+	letter "c" meaning character device and should contain "212, 1"
+	just to the left of the device name.  No such file?  no "c"?
+	Wrong major number?  Wrong minor number?  There's your
+	problem!
+
+	D. Do you get the message
+		 "HCPDIA047E my-vm-guest-name 0620 does not exist"?
+	If so, you must issue the command "DEF GRAF 620" from your VM
+	3215 console and then reboot the system.
+
+
+
+OPERATION.
+
+The driver defines three areas on the 3270 screen:  the log area, the
+input area, and the status area.
+
+The log area takes up all but the bottom two lines of the screen.  The
+driver writes terminal output to it, starting at the top line and going
+down.  When it fills, the status area changes from "Linux Running" to
+"Linux More...".  After a scrolling timeout of (default) 5 sec, the
+screen clears and more output is written, from the top down.
+
+The input area extends from the beginning of the second-to-last screen
+line to the start of the status area.  You type commands in this area
+and hit ENTER to execute them.
+
+The status area initializes to "Linux Running" to give you a warm
+fuzzy feeling.  When the log area fills up and output awaits, it
+changes to "Linux More...".  At this time you can do several things or
+nothing.  If you do nothing, the screen will clear in (default) 5 sec
+and more output will appear.  You may hit ENTER with nothing typed in
+the input area to toggle between "Linux More..." and "Linux Holding",
+which indicates no scrolling will occur.  (If you hit ENTER with "Linux
+Running" and nothing typed, the application receives a newline.)
+
+You may change the scrolling timeout value.  For example, the following
+command line:
+	echo scrolltime=60 > /proc/tty/driver/tty3270
+changes the scrolling timeout value to 60 sec.  Set scrolltime to 0 if
+you wish to prevent scrolling entirely.
+
+Other things you may do when the log area fills up are:  hit PA2 to
+clear the log area and write more output to it, or hit CLEAR to clear
+the log area and the input area and write more output to the log area.
+
+Some of the Program Function (PF) and Program Attention (PA) keys are
+preassigned special functions.  The ones that are not yield an alarm
+when pressed.
+
+PA1 causes a SIGINT to the currently running application.  You may do
+the same thing from the input area, by typing "^C" and hitting ENTER.
+
+PA2 causes the log area to be cleared.  If output awaits, it is then
+written to the log area.
+
+PF3 causes an EOF to be received as input by the application.  You may
+cause an EOF also by typing "^D" and hitting ENTER.
+
+No PF key is preassigned to cause a job suspension, but you may cause a
+job suspension by typing "^Z" and hitting ENTER.  You may wish to
+assign this function to a PF key.  To make PF7 cause job suspension,
+execute the command:
+	echo pf7=^z > /proc/tty/driver/tty3270
+
+If the input you type does not end with the two characters "^n", the
+driver appends a newline character and sends it to the tty driver;
+otherwise the driver strips the "^n" and does not append a newline.
+The IBM 3215 driver behaves similarly.
+
+Pf10 causes the most recent command to be retrieved from the tube's
+command stack (default depth 20) and displayed in the input area.  You
+may hit PF10 again for the next-most-recent command, and so on.  A
+command is entered into the stack only when the input area is not made
+invisible (such as for password entry) and it is not identical to the
+current top entry.  PF10 rotates backward through the command stack;
+PF11 rotates forward.  You may assign the backward function to any PF
+key (or PA key, for that matter), say, PA3, with the command:
+	echo -e pa3=\\033k > /proc/tty/driver/tty3270
+This assigns the string ESC-k to PA3.  Similarly, the string ESC-j
+performs the forward function.  (Rationale:  In bash with vi-mode line
+editing, ESC-k and ESC-j retrieve backward and forward history.
+Suggestions welcome.)
+
+Is a stack size of twenty commands not to your liking?  Change it on
+the fly.  To change to saving the last 100 commands, execute the
+command:
+	echo recallsize=100 > /proc/tty/driver/tty3270
+
+Have a command you issue frequently?  Assign it to a PF or PA key!  Use
+the command
+	echo pf24="mkdir foobar; cd foobar" > /proc/tty/driver/tty3270 
+to execute the commands mkdir foobar and cd foobar immediately when you
+hit PF24.  Want to see the command line first, before you execute it?
+Use the -n option of the echo command:
+	echo -n pf24="mkdir foo; cd foo" > /proc/tty/driver/tty3270
+
+
+
+Happy testing!  I welcome any and all comments about this document, the
+driver, etc etc.
+
+Dick Hitt <rbh00@utsglobal.com>
diff -u --recursive --new-file v2.4.3/linux/Documentation/s390/Debugging390.txt linux/Documentation/s390/Debugging390.txt
--- v2.4.3/linux/Documentation/s390/Debugging390.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/Debugging390.txt	Thu Apr 12 12:16:35 2001
@@ -0,0 +1,2439 @@
+              
+                          Debugging on Linux for s/390 & zSeries
+			               by
+		Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+		Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+                              Best viewed with fixed width fonts 
+
+Overview of Document:
+=====================
+This document is intended to give an good overview of how to debug 
+Linux for s/390 & zSeries it isn't intended as a complete reference & not a
+tutorial on the fundamentals of C & assembly, it dosen't go into
+390 IO in any detail. It is intended to compliment the documents in the
+reference section below & any other worthwhile references you get.
+
+It is intended like the Enterprise Systems Architecture/390 Reference Summary
+to be printed out & used as a quick cheat sheet self help style reference when
+problems occur.
+
+Contents
+========
+Register Set
+Address Spaces on Intel Linux
+Address Spaces on Linux for s/390 & zSeries
+The Linux for s/390 & zSeries Kernel Task Structure
+Register Usage & Stackframes on Linux for s/390 & zSeries
+A sample program with comments
+Compiling programs for debugging on Linux for s/390 & zSeries
+Figuring out gcc compile errors
+Debugging Tools
+objdump
+strace
+Performance Debugging 
+Debugging under VM
+s/390 & zSeries IO Overview
+Debugging IO on s/390 & zSeries under VM
+GDB on s/390 & zSeries
+Stack chaining in gdb by hand
+Examining core dumps
+ldd
+Debugging modules
+The proc file system
+Starting points for debugging scripting languages etc.
+Tools soon to be available
+SysRq
+References
+
+Register Set
+============
+The current architectures have the following registers.
+ 
+16  General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. 
+
+16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment,
+interrupt control,debugging control etc.
+
+16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries
+not used by normal programs but potentially could 
+be used as temporary storage. Their main purpose is their 1 to 1
+association with general purpose registers and are used in
+the kernel for copying data between kernel & user address spaces.
+Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) )
+is currently used by the pthread library as a pointer to
+the current running threads private area.
+
+16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating 
+point format compliant on G5 upwards & a Floating point control reg (FPC) 
+4  64 bit registers (fp0,fp2,fp4 & fp6) HFP only on older machines.
+Note:
+Linux (currently) always uses IEEE & emulates G5 IEEE format on older machines,
+( provided the kernel is configured for this ).
+
+
+The PSW is the most important register on the machine it
+is 64 bit on s/390 & 128 bit on zSeries & serves the roles of 
+a program counter (pc), condition code register,memory space designator.
+In IBM standard notation I am counting bit 0 as the MSB.
+It has several advantages over a normal program counter
+in that you can change address translation & program counter 
+in a single instruction. To change address translation,
+e.g. switching address translation off requires that you
+have a logical=physical mapping for the address you are
+currently running at.
+
+      Bit           Value
+s/390 zSeries
+0       0     Reserved ( must be 0 ) otherwise specification exception occurs.
+
+1       1     Program Event Recording 1 PER enabled, 
+	      PER is used to facilititate debugging e.g. single stepping.
+
+2-4    2-4    Reserved ( must be 0 ). 
+
+5       5     Dynamic address translation 1=DAT on.
+
+6       6     Input/Output interrupt Mask
+
+7       7     External interrupt Mask used primarily for interprocessor signalling & 
+	      clock interupts.
+
+8-11  8-11    PSW Key used for complex memory protection mechanism not used under linux
+
+12      12    1 on s/390 0 on zSeries
+
+13      13    Machine Check Mask 1=enable machine check interrupts
+
+14      14    Wait State set this to 1 to stop the processor except for interrupts & give 
+	      time to other LPARS used in CPU idle in the kernel to increase overall 
+	      usage of processor resources.
+
+15      15    Problem state ( if set to 1 certain instructions are disabled )
+	      all linux user programs run with this bit 1 
+	      ( useful info for debugging under VM ).
+
+16-17 16-17   Address Space Control
+
+	      00 Primary Space Mode when DAT on
+	      The linux kernel currently runs in this mode, CR1 is affiliated with 
+              this mode & points to the primary segment table origin etc.
+
+	      01 Access register mode this mode is used in functions to 
+	      copy data between kernel & user space.
+
+	      10 Secondary space mode not used in linux however CR7 the
+	      register affiliated with this mode is & this & normally
+	      CR13=CR7 to allow us to copy data between kernel & user space.
+	      We do this as follows:
+	      We set ar2 to 0 to designate its
+	      affiliated gpr ( gpr2 )to point to primary=kernel space.
+	      We set ar4 to 1 to designate its
+	      affiliated gpr ( gpr4 ) to point to secondary=home=user space
+	      & then essentially do a memcopy(gpr2,gpr4,size) to
+	      copy data between the address spaces, the reason we use home space for the
+	      kernel & don't keep secondary space free is that code will not run in 
+	      secondary space.
+
+	      11 Home Space Mode all user programs run in this mode.
+	      it is affiliated with CR13.
+
+18-19 18-19   Condition codes (CC)
+
+20    20      Fixed point overflow mask if 1=FPU exceptions for this event 
+              occur ( normally 0 ) 
+
+21    21      Decimal overflow mask if 1=FPU exceptions for this event occur 
+              ( normally 0 )
+
+22    22      Exponent underflow mask if 1=FPU exceptions for this event occur 
+              ( normally 0 )
+
+23    23      Significance Mask if 1=FPU exceptions for this event occur 
+              ( normally 0 )
+
+24-31 24-30   Reserved Must be 0.
+
+      31      Extended Addressing Mode
+      32      Basic Addressing Mode
+              Used to set addressing mode
+	      PSW 31   PSW 32
+                0         0        24 bit
+                0         1        31 bit
+                1         1        64 bit
+
+32             1=31 bit addressing mode 0=24 bit addressing mode (for backward 
+               compatibility ), linux always runs with this bit set to 1
+
+33-64          Instruction address.
+      33-63    Reserved must be 0
+      64-127   Address
+               In 24 bits mode bits 64-103=0 bits 104-127 Address 
+               In 31 bits mode bits 64-96=0 bits 97-127 Address
+               Note: unlike 31 bit mode on s/390 bit 96 must be zero
+	       when loading the address with LPSWE otherwise a 
+               specification exception occurs, LPSW is fully backward
+               compatible.
+ 	  
+	  
+Prefix Page
+-----------	  
+This per cpu memory area is too intimately tied to the processor not to mention.
+It exists between the real addresses 0-4096 on the processor & is exchanged 
+with a page in absolute storage by the set prefix instruction in linux'es startup. 
+This page different on each processor.
+Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such
+information as exception indications & entry points for exceptions.
+Bytes after 0xc00 hex are used by linux for per processor globals.
+The closest thing to this on traditional architectures is the interrupt
+vector table. This is a good thing & does simplify some of the kernel coding
+however it means that we now cannot catch stray NULL pointers in the
+kernel without hard coded checks.
+
+
+
+Address Spaces on Intel Linux
+=============================
+
+The traditional Intel Linux is approximately mapped as follows forgive
+the ascii art.
+0xFFFFFFFF 4GB Himem                        *****************
+                                            *               *
+                                            * Kernel Space  *
+                                            *               *
+                                            *****************          ****************
+User Space Himem (typically 0xC0000000 3GB )*  User Stack   *          *              *
+				            *****************          *              *
+					    *  Shared Libs  *          * Next Process *          
+                                            *****************          *     to       *  
+					    *               *    <==   *     Run      *  <==
+					    *  User Program *          *              *
+					    *   Data BSS    *          *              *
+                                            *	 Text       *          *              *
+         			            *   Sections    *          *              *
+0x00000000         			    *****************          ****************
+
+Now it is easy to see that on Intel it is quite easy to recognise a kernel address 
+as being one greater than user space himem ( in this case 0xC0000000).
+& addresses of less than this are the ones in the current running program on this
+processor ( if an smp box ).
+If using the virtual machine ( VM ) as a debugger it is quite difficult to
+know which user process is running as the address space you are looking at
+could be from any process in the run queue.
+Thankfully you normally get lucky as address spaces don't overlap that &
+you can recognise the code at by cross referencing with a dump made by objdump
+( more about that later ).
+
+The limitation of Intels addressing technique is that the linux
+kernel uses a very simple real address to virtual addressing technique
+of Real Address=Virtual Address-User Space Himem.
+This means that on Intel the kernel linux can typically only address
+Himem=0xFFFFFFFF-0xC0000000=1GB & this is all the RAM these machines
+can typically use.
+They can lower User Himem to 2GB or lower & thus be
+able to use 2GB of RAM however this shrinks the maximum size
+of User Space from 3GB to 2GB they have a no win limit of 4GB unless
+they go to 64 Bit.
+
+
+On 390 our limitations & strengths make us slightly different.
+For backward compatibility we are only allowed use 31 bits (2GB)
+of our 32 bit addresses,however, we use entirely separate address 
+spaces for the user & kernel.
+
+This means we can support 2GB of non Extended RAM, & more
+with the Extended memory managment swap device & 64 Bit
+when it comes along.
+
+
+Address Spaces on Linux for S390
+================================
+
+Our addressing scheme is as follows
+
+
+Himem 0x7fffffff 2GB on s/390   *****************          ****************
+2^64 bytes on zSeries           *  User Stack   *          *              *
+				*****************          *              *
+		                *  Shared Libs  *          *              *          
+                                *****************          *              *  
+			        *               *          *    Kernel    *  
+		                *  User Program *          *              *
+		                *   Data BSS    *          *              *
+                                *    Text       *          *              *
+            			*   Sections    *          *              *
+0x00000000                      *****************          ****************
+
+This also means that we need to look at the PSW problem state bit
+or the addressing mode to decide whether we are looking at
+user or kernel space. 
+
+The Linux for s/390 & zSeries Kernel Task Structure
+===================================================
+Each process/thread under Linux for S390 has its own kernel task_struct
+defined in linux/include/linux/sched.h
+The S390 on initialisation & resuming of a process on a cpu sets
+the __LC_KERNEL_STACK variable in the spare prefix area for this cpu
+( which we use for per processor globals).
+
+The kernel stack pointer is intimately tied with the task stucture for
+each processor as follows.
+
+                      s/390
+            ************************
+            *  1 page kernel stack *
+	    *        ( 4K )        *
+            ************************
+            *   1 page task_struct *        
+            *        ( 4K )        *
+8K aligned  ************************ 
+
+                     zSeries
+            ************************
+            *  2 page kernel stack *
+	    *        ( 8K )        *
+            ************************
+            *  2 page task_struct  *        
+            *        ( 8K )        *
+16K aligned ************************ 
+
+What this means is that we don't need to dedicate any register or global variable
+to point to the current running process & can retrieve it with the following
+very simple construct for s/390 & one very similar for zSeries.
+
+static inline struct task_struct * get_current(void)
+{
+        struct task_struct *current;
+        __asm__("lhi   %0,-8192\n\t"
+                "nr    %0,15"
+                : "=r" (current) );
+        return current;
+}
+
+i.e. just anding the current kernel stack pointer with the mask -8192.
+Thankfully because Linux dosen't have support for nested IO interrupts
+& our devices have large buffers can survive interrupts being shut for 
+short amounts of time we don't need a separate stack for interrupts.
+
+
+
+
+Register Usage & Stackframes on Linux for s/390 & zSeries
+=========================================================
+Overview:
+---------
+This is the code that gcc produces at the top & the bottom of
+each function, it usually is fairly consistent & similar from 
+function to function & if you know its layout you can probalby
+make some headway in finding the ultimate cause of a problem
+after a crash without a source level debugger.
+
+Note: To follow stackframes requires a knowledge of C or Pascal &
+limited knowledge of one assembly language.
+
+It should be noted that there are some differences between the
+s/390 & zSeries stack layouts as the zSeries stack layout didn't have
+to maintain compatibility with older linkage formats.
+
+Glossary:
+---------
+alloca:
+This is a built in compiler function for runtime allocation
+of extra space on the callers stack which is obviously freed
+up on function exit ( e.g. the caller may choose to allocate nothing
+of a buffer of 4k if required for temporary purposes ), it generates 
+very efficent code ( a few cycles  ) when compared to alternatives 
+like malloc.
+
+automatics: These are local variables on the stack,
+i.e they aren't in registers & they aren't static.
+
+back-chain:
+This is a pointer to the stack pointer before entering a
+framed functions ( see frameless function ) prologue got by 
+deferencing the address of the current stack pointer,
+ i.e. got by accessing the 32 bit value at the stack pointers
+current location.
+
+base-pointer:
+This is a pointer to the back of the literal pool which
+is an area just behind each procedure used to store constants
+in each function.
+
+call-clobbered: The caller probably needs to save these registers if there 
+is something of value in them, on the stack or elsewhere before making a 
+call to another procedure so that it can restore it later.
+
+epilogue:
+The code generated by the compiler to return to the caller.
+
+frameless-function
+A frameless function in Linux for s390 & zSeries is one which doesn't need 
+more than the register save area ( 96 bytes on s/390, 160 on zSeries )
+given to it by the caller.
+A frameless function never:
+1) Sets up a back chain.
+2) Calls alloca.
+3) Calls other normal functions
+4) Has automatics.
+
+GOT-pointer:
+This is a pointer to the global-offset-table in ELF
+( Executable Linkable Format, Linux'es most common executable format ),
+all globals & shared library objects are found using this pointer.
+
+lazy-binding
+ELF shared libraries are typically only loaded when routines in the shared
+library are actually first called at runtime. This is lazy binding.
+
+procedure-linkage-table
+This is a table found from the GOT which contains pointers to routines
+in other shared libraries which can't be called to by easier means.
+
+prologue:
+The code generated by the compiler to set up the stack frame.
+
+outgoing-args:
+This is extra area allocated on the stack of the calling function if the
+parameters for the callee's cannot all be put in registers, the same
+area can be reused by each function the caller calls.
+
+routine-descriptor:
+A COFF  executable format based concept of a procedure reference 
+actually being 8 bytes or more as opposed to a simple pointer to the routine.
+This is typically defined as follows
+Routine Descriptor offset 0=Pointer to Function
+Routine Descriptor offset 4=Pointer to Table of Contents
+The table of contents/TOC is roughly equivalent to a GOT pointer.
+& it means that shared libraries etc. can be shared between several
+environments each with their own TOC.
+
+ 
+static-chain: This is used in nested functions a concept adopted from pascal 
+by gcc not used in ansi C or C++ ( although quite useful ), basically it
+is a pointer used to reference local variables of enclosing functions.
+You might come across this stuff once or twice in your lifetime.
+
+e.g.
+The function below should return 11 though gcc may get upset & toss warnings 
+about unused variables.
+int FunctionA(int a)
+{
+	int b;
+	FunctionC(int c)
+	{
+		b=c+1;
+	}
+	FunctionC(10);
+	return(b);
+}
+
+
+s/390 & zSeries Register usage
+==============================
+r0       used by syscalls/assembly                  call-clobbered
+r1	 used by syscalls/assembly                  call-clobbered
+r2       argument 0 / return value 0                call-clobbered
+r3       argument 1 / return value 1 (if long long) call-clobbered
+r4       argument 2                                 call-clobbered
+r5       argument 3                                 call-clobbered
+r6	 argument 5                                 saved
+r7       pointer-to arguments 5 to ...              saved      
+r8       this & that                                saved
+r9       this & that                                saved
+r10      static-chain ( if nested function )        saved
+r11      frame-pointer ( if function used alloca )  saved
+r12      got-pointer                                saved
+r13      base-pointer                               saved
+r14      return-address                             saved
+r15      stack-pointer                              saved
+
+f0       argument 0 / return value ( float/double ) call-clobbered
+f2       argument 1                                 call-clobbered
+f4       zSeries argument 2                           saved
+f6       zSeries argument 3                           saved
+The remaining floating points
+f1,f3,f5 f7-f15 are call-clobbered.
+
+Notes:
+------
+1) The only requirement is that registers which are used
+by the callee are saved, e.g. the compiler is perfectly
+capible of using r11 for purposes other than a frame a
+frame pointer if a frame pointer is not needed.
+2) In functions with variable arguments e.g. printf the calling procedure 
+is identical to one without variable arguments & the same number of 
+parameters. However, the prologue of this function is somewhat more
+hairy owing to it having to move these parameters to the stack to
+get va_start, va_arg & va_end to work.
+3) Access registers are currently unused by gcc but are used in
+the kernel. Possibilities exist to use them at the moment for
+temporary storage but it isn't recommended.
+4) Only 4 of the floating point registers are used for
+parameter passing as older machines such as G3 only have only 4
+& it keeps the stack frame compatible with other compilers.
+However with IEEE floating point emulation under linux on the
+older machines you are free to use the other 12.
+5) A long long or double parameter cannot be have the 
+first 4 bytes in a register & the second four bytes in the 
+outgoing args area. It must be purely in the outgoing args
+area if crossing this boundary.
+6) Floating point parameters are mixed with outgoing args
+on the outgoing args area in the order the are passed in as parameters.
+7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries
+
+
+Stack Frame Layout
+------------------
+s/390     zSeries
+0         0             back chain ( a 0 here signifies end of back chain )
+4         8             eos ( end of stack, not used on Linux for S390 used in other linkage formats )
+8         16            glue used in other s/390 linkage formats for saved routine descriptors etc.
+12        24            glue used in other s/390 linkage formats for saved routine descriptors etc.
+16        32            scratch area
+20        40            scratch area
+24        48            saved r6 of caller function
+28        56            saved r7 of caller function
+32        64            saved r8 of caller function
+36        72            saved r9 of caller function
+40        80            saved r10 of caller function
+44        88            saved r11 of caller function
+48        96            saved r12 of caller function
+52        104           saved r13 of caller function
+56        112           saved r14 of caller function
+60        120           saved r15 of caller function
+64        128           saved f4 of caller function
+72        132           saved f6 of caller function
+80                      undefined
+96        160           outgoing args passed from caller to callee
+96+x      160+x         possible stack alignment ( 8 bytes desirable )
+96+x+y    160+x+y       alloca space of caller ( if used )
+96+x+y+z  160+x+y+z     automatics of caller ( if used )
+0                       back-chain
+
+A sample program with comments.
+===============================
+
+Comments on the function test
+-----------------------------
+1) It didn't need to set up a pointer to the constant pool gpr13 as it isn't used
+( :-( ).
+2) This is a frameless function & no stack is bought.
+3) The compiler was clever enough to recognise that it could return the
+value in r2 as well as use it for the passed in parameter ( :-) ).
+4) The basr ( branch relative & save ) trick works as follows the instruction 
+has a special case with r0,r0 with some instruction operands is understood as 
+the literal value 0, some risc architectures also do this ). So now
+we are branching to the next address & the address new program counter is
+in r13,so now we subtract the size of the function prologue we have executed
++ the size of the literal pool to get to the top of the literal pool
+0040037c int test(int b)
+{                                                          # Function prologue below
+  40037c:	90 de f0 34 	stm	%r13,%r14,52(%r15) # Save registers r13 & r14
+  400380:	0d d0       	basr	%r13,%r0           # Set up pointer to constant pool using
+  400382:	a7 da ff fa 	ahi	%r13,-6            # basr trick
+	return(5+b);
+	                                                   # Huge main program
+  400386:	a7 2a 00 05 	ahi	%r2,5              # add 5 to r2
+
+                                                           # Function epilogue below 
+  40038a:	98 de f0 34 	lm	%r13,%r14,52(%r15) # restore registers r13 & 14
+  40038e:	07 fe       	br	%r14               # return
+}
+
+Comments on the function main
+-----------------------------
+1) The compiler did this function optimally ( 8-) )
+
+Literal pool for main.
+400390:	ff ff ff ec 	.long 0xffffffec
+main(int argc,char *argv[])
+{                                                          # Function prologue below
+  400394:	90 bf f0 2c 	stm	%r11,%r15,44(%r15) # Save necessary registers
+  400398:	18 0f       	lr	%r0,%r15           # copy stack pointer to r0
+  40039a:	a7 fa ff a0 	ahi	%r15,-96           # Make area for callee saving 
+  40039e:	0d d0       	basr	%r13,%r0           # Set up r13 to point to
+  4003a0:	a7 da ff f0 	ahi	%r13,-16           # literal pool
+  4003a4:	50 00 f0 00 	st	%r0,0(%r15)        # Save backchain
+
+	return(test(5));                                   # Main Program Below
+  4003a8:	58 e0 d0 00 	l	%r14,0(%r13)       # load relative address of test from
+						           # literal pool
+  4003ac:	a7 28 00 05 	lhi	%r2,5              # Set first parameter to 5
+  4003b0:	4d ee d0 00 	bas	%r14,0(%r14,%r13)  # jump to test setting r14 as return
+							   # address using branch & save instruction.
+
+							   # Function Epilogue below
+  4003b4:	98 bf f0 8c 	lm	%r11,%r15,140(%r15)# Restore necessary registers.
+  4003b8:	07 fe       	br	%r14               # return to do program exit 
+}
+
+
+Compiler updates
+----------------
+
+main(int argc,char *argv[])
+{
+  4004fc:	90 7f f0 1c       	stm	%r7,%r15,28(%r15)
+  400500:	a7 d5 00 04       	bras	%r13,400508 <main+0xc>
+  400504:	00 40 04 f4       	.long	0x004004f4 
+  # compiler now puts constant pool in code to so it saves an instruction 
+  400508:	18 0f             	lr	%r0,%r15
+  40050a:	a7 fa ff a0       	ahi	%r15,-96
+  40050e:	50 00 f0 00       	st	%r0,0(%r15)
+	return(test(5));
+  400512:	58 10 d0 00       	l	%r1,0(%r13)
+  400516:	a7 28 00 05       	lhi	%r2,5
+  40051a:	0d e1             	basr	%r14,%r1
+  # compiler adds 1 extra instruction to epilogue this is done to
+  # avoid processor pipeline stalls owing to data dependencies on g5 &
+  # above as register 14 in the old code was needed directly after being loaded 
+  # by the lm	%r11,%r15,140(%r15) for the br %14.
+  40051c:	58 40 f0 98       	l	%r4,152(%r15)
+  400520:	98 7f f0 7c       	lm	%r7,%r15,124(%r15)
+  400524:	07 f4             	br	%r4
+}
+
+
+Hartmut ( our compiler developer ) also has been threatening to take out the
+stack backchain in optimised code as this also causes pipeline stalls, you
+have been warned.
+
+64 bit zSeries code disassembly
+-------------------------------
+
+If you understand the stuff above you'll understand the stuff
+below too so I'll avoid repeating myself & just say that 
+some of the instructions have g's on the end of them to indicate
+they are 64 bit & the stack offsets are a bigger, 
+the only other difference you'll find between 32 & 64 bit is that
+we now use f4 & f6 for floating point arguments on 64 bit.
+00000000800005b0 <test>:
+int test(int b)
+{
+	return(5+b);
+    800005b0:	a7 2a 00 05       	ahi	%r2,5
+    800005b4:	b9 14 00 22       	lgfr	%r2,%r2 # downcast to integer
+    800005b8:	07 fe             	br	%r14
+    800005ba:	07 07             	bcr	0,%r7
+
+
+}
+
+00000000800005bc <main>:
+main(int argc,char *argv[])
+{ 
+    800005bc:	eb bf f0 58 00 24 	stmg	%r11,%r15,88(%r15)
+    800005c2:	b9 04 00 1f       	lgr	%r1,%r15
+    800005c6:	a7 fb ff 60       	aghi	%r15,-160
+    800005ca:	e3 10 f0 00 00 24 	stg	%r1,0(%r15)
+	return(test(5));
+    800005d0:	a7 29 00 05       	lghi	%r2,5
+    # brasl allows jumps > 64k & is overkill here bras would do fune
+    800005d4:	c0 e5 ff ff ff ee 	brasl	%r14,800005b0 <test> 
+    800005da:	e3 40 f1 10 00 04 	lg	%r4,272(%r15)
+    800005e0:	eb bf f0 f8 00 04 	lmg	%r11,%r15,248(%r15)
+    800005e6:	07 f4             	br	%r4
+}
+
+
+
+Compiling programs for debugging on Linux for s/390 & zSeries
+=============================================================
+-gdwarf2 now works & normal -g debugging works much better now
+Thanks to the IBM java compiler developers bug reports. 
+
+This is typically done adding/appending the flags -g to the 
+CFLAGS & LDFLAGS variables Makefile of the program concerned.
+
+If using gdb & you would like accurate displays of registers &
+ stack traces compile without optimisation i.e make sure
+that there is no -O2 or similar on the CFLAGS line of the Makefile &
+the emitted gcc commands, obviously this will produce worse code 
+( not advisable for shipment ) but it is an  aid to the debugging process.
+
+This aids debugging because the compiler will copy parameters passed in
+in registers onto the stack so backtracing & looking at passed in
+parameters will work, however some larger programs which use inline functions
+will not compile without optimisation.
+
+Debugging with optimisation has since much improved after fixing
+some bugs, please make sure you are using gdb-5.0 or later developed 
+after Nov'2000.
+
+Figuring out gcc compile errors
+===============================
+If you are getting a lot of syntax errors compiling a program & the problem
+isn't blatantly obvious from the source.
+It often helps to just preprocess the file, this is done with the -E
+option in gcc.
+What this does is that it runs through the very first phase of compilation
+( compilation in gcc is done in several stages & gcc calls many programs to
+achieve its end result ) with the -E option gcc just calls the gcc preprocessor (cpp).
+The c preprocessor does the following, it joins all the files #included together
+recursively ( #include files can #include other files ) & also the c file you wish to compile.
+It puts a fully qualified path of the #included files in a comment & it
+does macro expansion.
+This is useful for debugging because
+1) You can double check whether the files you expect to be included are the ones
+that are being included ( e.g. double check that you aren't going to the i386 asm directory ).
+2) Check that macro definitions aren't clashing with typedefs,
+3) Check that definitons aren't being used before they are being included.
+4) Helps put the line emitting the error under the microscope if it contains macros.
+
+For convenience the Linux kernel's makefile will do preprocessing automatically for you
+by suffixing the file you want built with .i ( instead of .o )
+
+e.g.
+from the linux directory type
+make arch/s390/kernel/signal.i
+this will build
+
+s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce   -E arch/s390/kernel/signal.c
+> arch/s390/kernel/signal.i  
+
+Now look at signal.i you should see something like.
+
+
+# 1 "/home1/barrow/linux/include/asm/types.h" 1
+typedef unsigned short umode_t;
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+If instead you are getting errors further down e.g.
+unknown instruction:2515 "move.l" or better still unknown instruction:2515 
+"Fixme not implemented yet, call Martin" you are probably are attempting to compile some code 
+meant for another architecture or code that is simply not implemented, with a fixme statement
+stuck into the inline assembly code so that the author of the file now knows he has work to do.
+To look at the assembly emitted by gcc just before it is about to call gas ( the gnu assembler )
+use the -S option.
+Again for your convenience the Linux kernel's Makefile will hold your hand &
+do all this donkey work for you also by building the file with the .s suffix.
+e.g.
+from the Linux directory type 
+make arch/s390/kernel/signal.s 
+
+s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce  -S arch/s390/kernel/signal.c 
+-o arch/s390/kernel/signal.s  
+
+
+This will output something like, ( please note the constant pool & the useful comments
+in the prologue to give you a hand at interpreting it ).
+
+.LC54:
+	.string	"misaligned (__u16 *) in __xchg\n"
+.LC57:
+	.string	"misaligned (__u32 *) in __xchg\n"
+.L$PG1: # Pool sys_sigsuspend
+.LC192:
+	.long	-262401
+.LC193:
+	.long	-1
+.LC194:
+	.long	schedule-.L$PG1
+.LC195:
+	.long	do_signal-.L$PG1
+	.align 4
+.globl sys_sigsuspend
+	.type	 sys_sigsuspend,@function
+sys_sigsuspend:
+#	leaf function           0
+#	automatics              16
+#	outgoing args           0
+#	need frame pointer      0
+#	call alloca             0
+#	has varargs             0
+#	incoming args (stack)   0
+#	function length         168
+	STM	8,15,32(15)
+	LR	0,15
+	AHI	15,-112
+	BASR	13,0
+.L$CO1:	AHI	13,.L$PG1-.L$CO1
+	ST	0,0(15)
+	LR    8,2
+	N     5,.LC192-.L$PG1(13) 
+
+Adding -g to the above output makes the output even more useful
+e.g. typing
+make CC:="s390-gcc -g" kernel/sched.s
+
+which compiles.
+s390-gcc -g -D__KERNEL__ -I/home/barrow/linux-2.3/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce   -S kernel/sched.c -o kernel/sched.s 
+
+also outputs stabs ( debugger ) info, from this info you can find out the
+offsets & sizes of various elements in structures.
+e.g. the stab for the structure
+struct rlimit {
+	unsigned long	rlim_cur;
+	unsigned long	rlim_max;
+};
+is
+.stabs "rlimit:T(151,2)=s8rlim_cur:(0,5),0,32;rlim_max:(0,5),32,32;;",128,0,0,0
+from this stab you can see that 
+rlimit_cur starts at bit offset 0 & is 32 bits in size
+rlimit_max starts at bit offset 32 & is 32 bits in size.
+
+
+Debugging Tools:
+================
+
+objdump
+=======
+This is a tool with many options the most useful being ( if compiled with -g).
+objdump --source <victim program or object file> > <victims debug listing >
+
+
+The whole kernel can be compiled like this ( Doing this will make a 17MB kernel
+& a 200 MB listing ) however you have to strip it before building the image
+using the strip command to make it a more reasonable size to boot it.
+
+A source/assembly mixed dump of the kernel can be done with the line
+objdump --source vmlinux > vmlinux.lst
+Also if the file isn't compiled -g this will output as much debugging information
+as it can ( e.g. function names ), however, this is very slow as it spends lots
+of time searching for debugging info, the following self explanitory line should be used 
+instead if the code isn't compiled -g.
+objdump --disassemble-all --syms vmlinux > vmlinux.lst  
+as it is much faster
+
+As hard drive space is valuble most of us use the following approach.
+1) Look at the emitted psw on the console to find the crash address in the kernel.
+2) Look at the file System.map ( in the linux directory ) produced when building 
+the kernel to find the closest address less than the current PSW to find the
+offending function.
+3) use grep or similar to search the source tree looking for the source file
+ with this function if you don't know where it is.
+4) rebuild this object file with -g on, as an example suppose the file was
+( /arch/s390/kernel/signal.o ) 
+5) Assuming the file with the erroneous function is signal.c Move to the base of the 
+Linux source tree.
+6) rm /arch/s390/kernel/signal.o
+7) make /arch/s390/kernel/signal.o
+8) watch the gcc command line emitted
+9) type it in again or alernatively cut & paste it on the console adding the -g option.
+10) objdump --source arch/s390/kernel/signal.o > signal.lst
+This will output the source & the assembly intermixed, as the snippet below shows
+This will unfortunately output addresses which aren't the same
+as the kernel ones you should be able to get around the mental arithmetic
+by playing with the --adjust-vma parameter to objdump.
+
+
+
+
+extern inline void spin_lock(spinlock_t *lp)
+{
+      a0:       18 34           lr      %r3,%r4
+      a2:       a7 3a 03 bc     ahi     %r3,956
+        __asm__ __volatile("    lhi   1,-1\n"
+      a6:       a7 18 ff ff     lhi     %r1,-1
+      aa:       1f 00           slr     %r0,%r0
+      ac:       ba 01 30 00     cs      %r0,%r1,0(%r3)
+      b0:       a7 44 ff fd     jm      aa <sys_sigsuspend+0x2e>
+        saveset = current->blocked;
+      b4:       d2 07 f0 68     mvc     104(8,%r15),972(%r4)
+      b8:       43 cc
+        return (set->sig[0] & mask) != 0;
+} 
+
+6) If debugging under VM go down to that section in the document for more info.
+
+
+I now have a tool which takes the pain out of --adjust-vma
+& you are able to do something like
+make /arch/s390/kernel/traps.lst
+& it automatically generates the correctly relocated entries for
+the text segment in traps.lst.
+This tool is now standard in linux distro's in scripts/makelst
+
+strace:
+-------
+Q. What is it ?
+A. It is a tool for intercepting calls to the kernel & logging them
+to a file & on the screen.
+
+Q. What use is it ?
+A. You can used it to find out what files a particular program opens.
+
+
+
+Example 1
+---------
+If you wanted to know does ping work but didn't have the source 
+strace ping -c 1 127.0.0.1  
+& then look at the man pages for each of the syscalls below,
+( In fact this is sometimes easier than looking at some spagetti
+source which conditionally compiles for several architectures )
+Not everything that it throws out needs to make sense immeadiately
+
+Just looking quickly you can see that it is making up a RAW socket
+for the ICMP protocol.
+Doing an alarm(10) for a 10 second timeout
+& doing a gettimeofday call before & after each read to see 
+how long the replies took, & writing some text to stdout so the user
+has an idea what is going on.
+
+socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
+getuid()                                = 0
+setuid(0)                               = 0
+stat("/usr/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory)
+stat("/usr/share/locale/libc/C", 0xbffff134) = -1 ENOENT (No such file or directory)
+stat("/usr/local/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory)
+getpid()                                = 353
+setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
+setsockopt(3, SOL_SOCKET, SO_RCVBUF, [49152], 4) = 0
+fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(3, 1), ...}) = 0
+mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40008000
+ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0
+write(1, "PING 127.0.0.1 (127.0.0.1): 56 d"..., 42PING 127.0.0.1 (127.0.0.1): 56 data bytes
+) = 42
+sigaction(SIGINT, {0x8049ba0, [], SA_RESTART}, {SIG_DFL}) = 0 
+sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {SIG_DFL}) = 0
+gettimeofday({948904719, 138951}, NULL) = 0
+sendto(3, "\10\0D\201a\1\0\0\17#\2178\307\36"..., 64, 0, {sin_family=AF_INET,
+sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 64
+sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0
+sigaction(SIGALRM, {0x8049ba0, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0
+alarm(10)                               = 0
+recvfrom(3, "E\0\0T\0005\0\0@\1|r\177\0\0\1\177"..., 192, 0, 
+{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84
+gettimeofday({948904719, 160224}, NULL) = 0
+recvfrom(3, "E\0\0T\0006\0\0\377\1\275p\177\0"..., 192, 0, 
+{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84
+gettimeofday({948904719, 166952}, NULL) = 0
+write(1, "64 bytes from 127.0.0.1: icmp_se"..., 
+5764 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=28.0 ms
+
+Example 2
+---------
+strace passwd 2>&1 | grep open
+produces the following output
+open("/etc/ld.so.cache", O_RDONLY)      = 3
+open("/opt/kde/lib/libc.so.5", O_RDONLY) = -1 ENOENT (No such file or directory)
+open("/lib/libc.so.5", O_RDONLY)        = 3
+open("/dev", O_RDONLY)                  = 3
+open("/var/run/utmp", O_RDONLY)         = 3
+open("/etc/passwd", O_RDONLY)           = 3
+open("/etc/shadow", O_RDONLY)           = 3
+open("/etc/login.defs", O_RDONLY)       = 4
+open("/dev/tty", O_RDONLY)              = 4 
+
+The 2>&1 is done to redirect stderr to stdout & grep is then filtering this input 
+through the pipe for each line containing the string open.
+
+
+Example 3
+---------
+Getting sophistocated
+telnetd crashes on & I don't know why
+Steps
+-----
+1) Replace the following line in /etc/inetd.conf
+telnet  stream  tcp     nowait  root    /usr/sbin/in.telnetd -h 
+with
+telnet  stream  tcp     nowait  root    /blah
+
+2) Create the file /blah with the following contents to start tracing telnetd 
+#!/bin/bash
+/usr/bin/strace -o/t1 -f /usr/sbin/in.telnetd -h 
+3) chmod 700 /blah to make it executable only to root
+4)
+killall -HUP inetd
+or ps aux | grep inetd
+get inetd's process id
+& kill -HUP inetd to restart it.
+
+Important options
+-----------------
+-o is used to tell strace to output to a file in our case t1 in the root directory
+-f is to follow children i.e.
+e.g in our case above telnetd will start the login process & subsequently a shell like bash.
+You will be able to tell which is which from the process ID's listed on the left hand side
+of the strace output.
+-p<pid> will tell strace to attach to a running process, yup this can be done provided
+ it isn't being traced or debugged already & you have enough privileges,
+the reason 2 processes cannot trace or debug the same program is that strace
+becomes the parent process of the one being debugged & processes ( unlike people )
+can have only one parent.
+
+
+However the file /t1 will get big quite quickly
+to test it telnet 127.0.0.1
+
+now look at what files in.telnetd execve'd
+413   execve("/usr/sbin/in.telnetd", ["/usr/sbin/in.telnetd", "-h"], [/* 17 vars */]) = 0
+414   execve("/bin/login", ["/bin/login", "-h", "localhost", "-p"], [/* 2 vars */]) = 0 
+
+Whey it worked!.
+
+
+Other hints:
+------------
+If the program is not very interactive ( i.e. not much keyboard input )
+& is crashing in one architecture but not in another you can do 
+an strace of both programs under as identical a scenario as you can
+on both architectures outputting to a file then.
+do a diff of the two traces using the diff program
+i.e.
+diff output1 output2
+& maybe you'll be able to see where the call paths differed, this
+is possibly near the cause of the crash. 
+
+More info
+---------
+Look at man pages for strace & the various syscalls
+e.g. man strace, man alarm, man socket.
+
+
+Performance Debugging
+=====================
+gcc is capible of compiling in profiling code just add the -p option
+to the CFLAGS, this obviously affects program size & performance.
+This can be used by the gprof gnu profiling tool or the
+gcov the gnu code coverage tool ( code coverage is a means of testing
+code quality by checking if all the code in an executable in exercised by
+a tester ).
+
+
+Using top to find out where processes are sleeping in the kernel
+----------------------------------------------------------------
+To do this copy the System.map from the root directory where
+the linux kernel was built to the /boot directory on your 
+linux machine.
+Start top
+Now type fU<return>
+You should see a new field called WCHAN which
+tells you where each process is sleeping here is a typical output.
+ 
+ 6:59pm  up 41 min,  1 user,  load average: 0.00, 0.00, 0.00
+28 processes: 27 sleeping, 1 running, 0 zombie, 0 stopped
+CPU states:  0.0% user,  0.1% system,  0.0% nice, 99.8% idle
+Mem:   254900K av,   45976K used,  208924K free,       0K shrd,   28636K buff
+Swap:       0K av,       0K used,       0K free                    8620K cached
+
+  PID USER     PRI  NI  SIZE  RSS SHARE WCHAN     STAT  LIB %CPU %MEM   TIME COMMAND
+  750 root      12   0   848  848   700 do_select S       0  0.1  0.3   0:00 in.telnetd
+  767 root      16   0  1140 1140   964           R       0  0.1  0.4   0:00 top
+    1 root       8   0   212  212   180 do_select S       0  0.0  0.0   0:00 init
+    2 root       9   0     0    0     0 down_inte SW      0  0.0  0.0   0:00 kmcheck
+
+The time command
+----------------
+Another related command is the time command which gives you an indication
+of where a process is spending the majority of its time.
+e.g.
+time ping -c 5 nc
+outputs
+real	0m4.054s
+user	0m0.010s
+sys	0m0.010s
+
+Debugging under VM
+==================
+
+Notes
+-----
+Addresses & values in the VM debugger are always hex never decimal
+Address ranges are of the format <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2> 
+e.g. The address range  0x2000 to 0x3000 can be described described as
+2000-3000 or 2000.1000
+
+The VM Debugger is case insensitive.
+
+VM's strengths are usually other debuggers weaknesses you can get at any resource
+no matter how sensitive e.g. memory managment resources,change address translation
+in the PSW. For kernel hacking you will reap dividends if you get good at it.
+
+The VM Debugger displays operators but not operands, probably because some
+of it was written when memory was expensive & the programmer was probably proud that
+it fitted into 2k of memory & the programmers & didn't want to shock hardcore VM'ers by
+changing the interface :-), also the debugger displays useful information on the same line & 
+the author of the code probably felt that it was a good idea not to go over 
+the 80 columns on the screen. 
+
+As some of you are probably in a panic now this isn't as unintuitive as it may seem
+as the 390 instructions are easy to decode mentally & you can make a good guess at a lot 
+of them as all the operands are nibble ( half byte aligned ) & if you have an objdump listing
+also it is quite easy to follow, if you don't have an objdump listing keep a copy of
+the s/390 Reference Summary & look at between pages 2 & 7 or alternatively the
+s/390 principles of operation.
+e.g. even I can guess that 
+0001AFF8' LR    180F        CC 0
+is a ( load register ) lr r0,r15 
+
+Also it is very easy to tell the length of a 390 instruction from the 2 most significant
+bits in the instruction ( not that this info is really useful except if you are trying to
+make sense of a hexdump of code ).
+Here is a table
+Bits                    Instruction Length
+------------------------------------------
+00                          2 Bytes
+01                          4 Bytes
+10                          4 Bytes
+11                          6 Bytes
+
+
+
+
+The debugger also displays other useful info on the same line such as the
+addresses being operated on destination addresses of branches & condition codes.
+e.g.  
+00019736' AHI   A7DAFF0E    CC 1
+000198BA' BRC   A7840004 -> 000198C2'   CC 0
+000198CE' STM   900EF068 >> 0FA95E78    CC 2
+
+
+
+Useful VM debugger commands
+---------------------------
+
+I suppose I'd better mention this before I start
+to list the current active traces do 
+Q TR
+there can be a maximum of 255 of these per set
+( more about trace sets later ).
+To stop traces issue a
+TR END.
+To delete a particular breakpoint issue
+TR DEL <breakpoint number>
+
+The PA1 key drops to CP mode so you can issue debugger commands,
+Doing alt c (on my 3270 console at least ) clears the screen. 
+hitting b <enter> comes back to the running operating system
+from cp mode ( in our case linux ).
+It is typically useful to add shortcuts to your profile.exec file
+if you have one ( this is roughly equivalent to autoexec.bat in DOS ).
+file here are a few from mine.
+/* this gives me command history on issuing f12 */
+set pf12 retrieve 
+/* this continues */
+set pf8 imm b
+/* goes to trace set a */
+set pf1 imm tr goto a
+/* goes to trace set b */
+set pf2 imm tr goto b
+/* goes to trace set c */
+set pf3 imm tr goto c
+
+
+
+Instruction Tracing
+-------------------
+Setting a simple breakpoint
+TR I PSWA <address>
+To debug a particular function try
+TR I R <function address range>
+TR I on its own will single step.
+TR I DATA <MNEMONIC> <OPTIONAL RANGE> will trace for particular mnemonics
+e.g.
+TR I DATA 4D R 0197BC.4000
+will trace for BAS'es ( opcode 4D ) in the range 0197BC.4000
+if you were inclined you could add traces for all branch instructions &
+suffix them with the run prefix so you would have a backtrace on screen 
+when a program crashes.
+TR BR <INTO OR FROM> will trace branches into or out of an address.
+e.g.
+TR BR INTO 0 is often quite useful if a program is getting awkward & deciding
+to branch to 0 & crashing as this will stop at the address before in jumps to 0.
+TR I R <address range> RUN cmd d g
+single steps a range of addresses but stays running &
+displays the gprs on each step.
+
+
+
+Displaying & modifying Registers
+--------------------------------
+D G will display all the gprs
+Adding a extra G to all the commands is neccessary to access the full 64 bit 
+content in VM on zSeries obviously this isn't required for access registers
+as these are still 32 bit.
+e.g. DGG instead of DG 
+D X will display all the control registers
+D AR will display all the access registers
+D AR4-7 will display access registers 4 to 7
+CPU ALL D G will display the GRPS of all CPUS in the configuration
+D PSW will display the current PSW
+st PSW 2000 will put the value 2000 into the PSW &
+cause crash your machine.
+D PREFIX displays the prefix offset
+
+
+Displaying Memory
+-----------------
+To display memory mapped using the current PSW's mapping try
+D <range>
+To make VM display a message each time it hits a particular address & continue try
+D I<range> will disassemble/display a range of instructions.
+ST addr 32 bit word will store a 32 bit aligned address
+D T<range> will display the EBCDIC in an address ( if you are that way inclined )
+D R<range> will display real addresses ( without DAT ) but with prefixing.
+There are other complex options to display if you need to get at say home space
+but are in primary space the easiest thing to do is to temporarily
+modify the PSW to the other addressing mode, display the stuff & then
+restore it.
+
+
+ 
+Hints
+-----
+If you want to issue a debugger command without halting your virtual machine with the
+PA1 key try prefixing the command with #CP e.g.
+#cp tr i pswa 2000
+also suffixing most debugger commands with RUN will cause them not
+to stop just display the mnemonic at the current instruction on the console.
+If you have several breakpoints you want to put into your program &
+you get fed up of cross referencing with System.map
+you can do the following trick for several symbols.
+grep do_signal System.map 
+which emits the following among other things
+0001f4e0 T do_signal 
+now you can do
+
+TR I PSWA 0001f4e0 cmd msg * do_signal
+This sends a message to your own console each time do_signal is entered.
+( As an aside I wrote a perl script once which automatically generated a REXX
+script with breakpoints on every kernel procedure, this isn't a good idea
+because there are thousands of these routines & VM can only set 255 breakpoints
+at a time so you nearly had to spend as long pruning the file down as you would 
+entering the msg's by hand ),however, the trick might be useful for a single object file.
+On linux'es 3270 emulator x3270 there is a very useful option under the file ment
+Save Screens In File this is very good of keeping a copy of traces. 
+
+From CMS help <command name> will give you online help on a particular command. 
+e.g. 
+HELP DISPLAY
+
+Also CP has a file called profile.exec which automatically gets called
+on startup of CMS ( like autoexec.bat ), keeping on a DOS analogy session
+CP has a feature similar to doskey, it may be useful for you to
+use profile.exec to define some keystrokes. 
+e.g.
+SET PF9 IMM B
+This does a single step in VM on pressing F8. 
+SET PF10  ^
+This sets up the ^ key.
+which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly into some 3270 consoles.
+SET PF11 ^-
+This types the starting keystrokes for a sysrq see SysRq below.
+SET PF12 RETRIEVE
+This retrieves command history on pressing F12.
+
+
+Sometimes in VM the display is set up to scroll automatically this
+can be very annoying if there are messages you wish to look at
+to stop this do
+TERM MORE 255 255
+This will nearly stop automatic screen updates, however it will
+cause a denial of service if lots of messages go to the 3270 console,
+so it would be foolish to use this as the default on a production machine.
+ 
+
+Tracing particular processes
+----------------------------
+The kernels text segment is intentionally at an address in memory that it will
+very seldom collide with text segments of user programs ( thanks Martin ),
+this simplifies debugging the kernel.
+However it is quite common for user processes to have addresses which collide
+this can make debugging a particular process under VM painful under normal
+circumstances as the process may change when doing a 
+TR I R <address range>.
+Thankfully after reading VM's online help I figured out how to debug
+I particular process.
+
+Your first problem is to find the STD ( segment table designation )
+of the program you wish to debug.
+There are several ways you can do this here are a few
+1) objdump --syms <program to be debugged> | grep main
+To get the address of main in the program.
+tr i pswa <address of main>
+Start the program, if VM drops to CP on what looks like the entry
+point of the main function this is most likely the process you wish to debug.
+Now do a D X13 or D XG13 on zSeries.
+On 31 bit the STD is bits 1-19 ( the STO segment table origin ) 
+& 25-31 ( the STL segment table length ) of CR13.
+now type
+TR I R STD <CR13's value> 0.7fffffff
+e.g.
+TR I R STD 8F32E1FF 0.7fffffff
+Another very useful variation is
+TR STORE INTO STD <CR13's value> <address range>
+
+
+
+
+Tracing Program Exceptions
+--------------------------
+If you get a crash which says something like
+illegal operation or specification exception followed by a register dump
+You can restart linux & trace these using the tr prog <range or value> trace option.
+
+
+
+The most common ones you will normally be tracing for is
+1=operation exception
+2=privileged operation exception
+4=protection exception
+5=addressing exception
+6=specification exception
+10=segment translation exception
+11=page translation exception
+
+The full list of these is on page 22 of the current s/390 Reference Summary.
+e.g.
+tr prog 10 will trace segment translation exceptions.
+tr prog on its own will trace all program interruption codes.
+
+Trace Sets
+----------
+On starting VM you are initially in the INITIAL trace set.
+You can do a Q TR to verify this.
+If you have a complex tracing situation where you wish to wait for instance 
+till a driver is open before you start tracing IO, but know in your
+heart that you are going to have to make several runs through the code till you
+have a clue whats going on. 
+
+What you can do is
+TR I PSWA <Driver open address>
+hit b to continue till breakpoint
+reach the breakpoint
+now do your
+TR GOTO B 
+TR IO 7c08-7c09 inst int run 
+or whatever the IO channels you wish to trace are & hit b
+
+To got back to the initial trace set do
+TR GOTO INITIAL
+& the TR I PSWA <Driver open address> will be the only active breakpoint again.
+
+
+Tracing linux syscalls under VM
+-------------------------------
+Syscalls are implemented on Linux for S390 by the Supervisor call instruction (SVC) there 256 
+possibilities of these as the instruction is made up of a  0xA opcode & the second byte being
+the syscall number. They are traced using the simple command.
+TR SVC  <Optional value or range>
+the syscalls are defined in linux/include/asm-s390/unistd.h
+e.g. to trace all file opens just do
+TR SVC 5 ( as this is the syscall number of open )
+
+
+SMP Specific commands
+---------------------
+To find out how many cpus you have
+Q CPUS displays all the CPU's available to your virtual machine
+To find the cpu that the current cpu VM debugger commands are being directed at do
+Q CPU to change the current cpu cpu VM debugger commands are being directed at do
+CPU <desired cpu no>
+
+On a SMP guest issue a command to all CPUs try prefixing the command with cpu all.
+To issue a command to a particular cpu try cpu <cpu number> e.g.
+CPU 01 TR I R 2000.3000
+If you are running on a guest with several cpus & you have a IO related problem
+& cannot follow the flow of code but you know it isnt smp related.
+from the bash prompt issue
+shutdown -h now or halt.
+do a Q CPUS to find out how many cpus you have
+detach each one of them from cp except cpu 0 
+by issueing a 
+DETACH CPU 01-(number of cpus in configuration)
+& boot linux again.
+TR SIGP will trace inter processor signal processor instructions.
+DEFINE CPU 01-(number in configuration) 
+will get your guests cpus back.
+
+
+Help for displaying ascii textstrings
+-------------------------------------
+As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have 
+written this little program which will convert a command line of hex digits to ascii text
+which can be compiled under linux & you can copy the hex digits from your x3270 terminal to
+your xterm if you are debugging from a linuxbox.
+
+This is quite useful when looking at a parameter passed in as a text string
+under VM ( unless you are good at decoding ASCII in your head ).
+
+e.g. consider tracing an open syscall
+TR SVC 5
+We have stopped at a breakpoint
+000151B0' SVC   0A05     -> 0001909A'   CC 0
+
+D 20.8 to check the SVC old psw in the prefix area & see was it from userspace
+( for the layout of the prefix area consult P18 of the s/390 390 Reference Summary 
+if you have it available ).
+V00000020  070C2000 800151B2
+The problem state bit wasn't set &  it's also too early in the boot sequence
+for it to be a userspace SVC if it was we would have to temporarily switch the 
+psw to user space addressing so we could get at the first parameter of the open in
+gpr2.
+Next do a 
+D G2
+GPR  2 =  00014CB4
+Now display what gpr2 is pointing to
+D 00014CB4.20
+V00014CB4  2F646576 2F636F6E 736F6C65 00001BF5
+V00014CC4  FC00014C B4001001 E0001000 B8070707
+Now copy the text till the first 00 hex ( which is the end of the string
+to an xterm & do hex2ascii on it.
+hex2ascii 2F646576 2F636F6E 736F6C65 00 
+outputs
+Decoded Hex:=/ d e v / c o n s o l e 0x00 
+We were opening the console device,
+
+You can compile the code below yourself for practice :-),
+/*
+ *    hex2ascii.c
+ *    a useful little tool for converting a hexadecimal command line to ascii
+ *
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *    (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation.
+ */   
+#include <stdio.h>
+
+int main(int argc,char *argv[])
+{
+  int cnt1,cnt2,len,toggle=0;
+  int startcnt=1;
+  unsigned char c,hex;
+  
+  if(argc>1&&(strcmp(argv[1],"-a")==0))
+     startcnt=2;
+  printf("Decoded Hex:=");
+  for(cnt1=startcnt;cnt1<argc;cnt1++)
+  {
+    len=strlen(argv[cnt1]);
+    for(cnt2=0;cnt2<len;cnt2++)
+    {
+       c=argv[cnt1][cnt2];
+       if(c>='0'&&c<='9')
+	  c=c-'0';
+       if(c>='A'&&c<='F')
+	  c=c-'A'+10;
+       if(c>='a'&&c<='F')
+	  c=c-'a'+10;
+       switch(toggle)
+       {
+	  case 0:
+	     hex=c<<4;
+	     toggle=1;
+	  break;
+	  case 1:
+	     hex+=c;
+	     if(hex<32||hex>127)
+	     {
+		if(startcnt==1)
+		   printf("0x%02X ",(int)hex);
+		else
+		   printf(".");
+	     }
+	     else
+	     {
+	       printf("%c",hex);
+	       if(startcnt==1)
+		  printf(" ");
+	     }
+	     toggle=0;
+	  break;
+       }
+    }
+  }
+  printf("\n");
+}
+
+
+
+
+Stack tracing under VM
+----------------------
+A basic backtrace
+-----------------
+
+Here are the tricks I use 9 out of 10 times it works pretty well,
+
+When your backchain reaches a dead end
+--------------------------------------
+This can happen when an exception happens in the kernel & the kernel is entered twice
+if you reach the NULL pointer at the end of the back chain you should be
+able to sniff further back if you follow the following tricks.
+1) A kernel address should be easy to recognise since it is in
+primary space & the problem state bit isn't set & also
+The Hi bit of the address is set.
+2) Another backchain should also be easy to recognise since it is an 
+address pointing to another address approximately 100 bytes or 0x70 hex
+behind the current stackpointer.
+
+
+Here is some practice.
+boot the kernel & hit PA1 at some random time
+d g to display the gprs, this should display something like
+GPR  0 =  00000001  00156018  0014359C  00000000
+GPR  4 =  00000001  001B8888  000003E0  00000000
+GPR  8 =  00100080  00100084  00000000  000FE000
+GPR 12 =  00010400  8001B2DC  8001B36A  000FFED8
+Note that GPR14 is a return address but as we are real men we are going to
+trace the stack.
+display 0x40 bytes after the stack pointer.
+
+V000FFED8  000FFF38 8001B838 80014C8E 000FFF38
+V000FFEE8  00000000 00000000 000003E0 00000000
+V000FFEF8  00100080 00100084 00000000 000FE000
+V000FFF08  00010400 8001B2DC 8001B36A 000FFED8
+
+
+Ah now look at whats in sp+56 (sp+0x38) this is 8001B36A our saved r14 if
+you look above at our stackframe & also agrees with GPR14.
+
+now backchain 
+d 000FFF38.40
+we now are taking the contents of SP to get our first backchain.
+
+V000FFF38  000FFFA0 00000000 00014995 00147094
+V000FFF48  00147090 001470A0 000003E0 00000000
+V000FFF58  00100080 00100084 00000000 001BF1D0
+V000FFF68  00010400 800149BA 80014CA6 000FFF38
+
+This displays a 2nd return address of 80014CA6
+
+now do d 000FFFA0.40 for our 3rd backchain
+
+V000FFFA0  04B52002 0001107F 00000000 00000000
+V000FFFB0  00000000 00000000 FF000000 0001107F
+V000FFFC0  00000000 00000000 00000000 00000000
+V000FFFD0  00010400 80010802 8001085A 000FFFA0
+
+
+our 3rd return address is 8001085A
+
+as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines
+for the sake of optimisation dont set up a backchain.
+
+now look at System.map to see if the addresses make any sense.
+
+grep -i 0001b3 System.map
+outputs among other things
+0001b304 T cpu_idle 
+so 8001B36A
+is cpu_idle+0x66 ( quiet the cpu is asleep, don't wake it )
+
+
+grep -i 00014 System.map 
+produces among other things
+00014a78 T start_kernel  
+so 0014CA6 is start_kernel+some hex number I can't add in my head.
+
+grep -i 00108 System.map 
+this produces
+00010800 T _stext
+so   8001085A is _stext+0x5a
+
+Congrats you've done your first backchain.
+
+
+
+s/390 & zSeries IO Overview
+===========================
+
+I am not going to give a course in 390 IO architecture as this would take me quite a
+while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have 
+the s/390 principles of operation available read this instead. If nothing else you may find a few 
+useful keywords in here & be able to use them on a web search engine like altavista to find 
+more useful information.
+
+Unlike other bus architectures modern 390 systems do their IO using mostly
+fibre optics & devices such as tapes & disks can be shared between several mainframes,
+also S390 can support upto 65536 devices while a high end PC based system might be choking 
+with around 64. Here is some of the common IO terminology
+
+Subchannel:
+This is the logical number most IO commands use to talk to an IO device there can be upto
+0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM
+for simplicity they are allocated contiguously, however on the native hardware they are not
+they typically stay consistent between boots provided no new hardware is inserted or removed.
+Under Linux for 390 we use these as IRQ's & also when issuing an IO command (CLEAR SUBCHANNEL,
+HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCHANNEL & 
+TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most
+important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check
+whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel
+can have up to 8 channel paths to a device this offers redunancy if one is not available.
+
+
+Device Number:
+This number remains static & Is closely tied to the hardware, there are 65536 of these
+also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) 
+& another lsb 8 bits. These remain static even if more devices are inserted or removed
+from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided
+devices arent inserted or removed.
+
+Channel Control Words:
+CCWS are linked lists of instructions initially pointed to by an operation request block (ORB),
+which is initially given to Start Subchannel (SSCH) command along with the subchannel number
+for the IO subsystem to process while the CPU continues executing normal code.
+These come in two flavours, Format 0 ( 24 bit for backward )
+compatibility & Format 1 ( 31 bit ). These are typically used to issue read & write 
+( & many other instructions ) they consist of a length field & an absolute address field.
+For each IO typically get 1 or 2 interrupts one for channel end ( primary status ) when the
+channel is idle & the second for device end ( secondary status ) sometimes you get both
+concurrently, you check how the IO went on by issueing a TEST SUBCHANNEL at each interrupt,
+from which you receive an Interruption response block (IRB). If you get channel & device end 
+status in the IRB without channel checks etc. your IO probably went okay. If you didn't you
+probably need a doctorto examine the IRB & extended status word etc.
+If an error occurs more sophistocated control units have a facitity known as
+concurrent sense this means that if an error occurs Extended sense information will
+be presented in the Extended status word in the IRB if not you have to issue a
+subsequent SENSE CCW command after the test subchannel. 
+
+
+TPI( Test pending interrupt) can also be used for polled IO but in multitasking multiprocessor
+systems it isn't recommended except for checking special cases ( i.e. non looping checks for
+pending IO etc. ).
+
+Store Subchannel & Modify Subchannel can be used to examine & modify operating characteristics
+of a subchannel ( e.g. channel paths ).
+
+Other IO related Terms:
+Sysplex: S390's Clustering Technology
+QDIO: S390's new high speed IO architecture to support devices such as gigabit ethernet,
+this architecture is also designed to be forward compatible with up & coming 64 bit machines.
+
+
+General Concepts 
+
+Input Output Processors (IOP's) are responsible for communicating between
+the mainframe CPU's & the channel & relieve the mainframe CPU's from the
+burden of communicating with IO devices directly, this allows the CPU's to 
+concentrate on data processing. 
+
+IOP's can use one or more links ( known as channel paths ) to talk to each 
+IO device. It first checks for path availability & chooses an available one,
+then starts ( & sometimes terminates IO ).
+There are two types of channel path ESCON & the Paralell IO interface.
+
+IO devices are attached to control units, control units provide the
+logic to interface the channel paths & channel path IO protocols to 
+the IO devices, they can be integrated with the devices or housed separately
+& often talk to several similar devices ( typical examples would be raid 
+controllers or a control unit which connects to 1000 3270 terminals ).
+
+
+    +---------------------------------------------------------------+
+    | +-----+ +-----+ +-----+ +-----+  +----------+  +----------+   |
+    | | CPU | | CPU | | CPU | | CPU |  |  Main    |  | Expanded |   |
+    | |     | |     | |     | |     |  |  Memory  |  |  Storage |   |
+    | +-----+ +-----+ +-----+ +-----+  +----------+  +----------+   | 
+    |---------------------------------------------------------------+
+    |   IOP        |      IOP      |       IOP                      |
+    |---------------------------------------------------------------
+    | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | 
+    ----------------------------------------------------------------
+         ||                                              ||
+         ||  Bus & Tag Channel Path                      || ESCON
+         ||  ======================                      || Channel
+         ||  ||                  ||                      || Path
+    +----------+               +----------+         +----------+
+    |          |               |          |         |          |
+    |    CU    |               |    CU    |         |    CU    |
+    |          |               |          |         |          |
+    +----------+               +----------+         +----------+
+       |      |                     |                |       |
++----------+ +----------+      +----------+   +----------+ +----------+
+|I/O Device| |I/O Device|      |I/O Device|   |I/O Device| |I/O Device|
++----------+ +----------+      +----------+   +----------+ +----------+
+  CPU = Central Processing Unit    
+  C = Channel                      
+  IOP = IP Processor               
+  CU = Control Unit
+
+The 390 IO systems come in 2 flavours the current 390 machines support both
+
+The Older 360 & 370 Interface,sometimes called the paralell I/O interface,
+sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers
+Interface (OEMI).
+
+This byte wide paralell channel path/bus has parity & data on the "Bus" cable 
+& control lines on the "Tag" cable. These can operate in byte multiplex mode for
+sharing between several slow devices or burst mode & monopolize the channel for the
+whole burst. Upto 256 devices can be addressed  on one of these cables. These cables are
+about one inch in diameter. The maximum unextended length supported by these cables is
+125 Meters but this can be extended up to 2km with a fibre optic channel extended 
+such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however
+some really old processors support only transfer rates of 3.0, 2.0 & 1.0 MB/sec.
+One of these paths can be daisy chained to up to 8 control units.
+
+
+ESCON if fibre optic it is also called FICON 
+Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers
+for communication at a signaling rate of upto 200 megabits/sec. As 10bits are transferred
+for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once
+control info & CRC are added. ESCON only operates in burst mode.
+ 
+ESCONs typical max cable length is 3km for the led version & 20km for the laser version
+known as XDF ( extended distance facility ). This can be further extended by using an
+ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is
+serial it uses a packet switching architecture the standard Bus & Tag control protocol
+is however present within the packets. Upto 256 devices can be attached to each control 
+unit that uses one of these interfaces.
+
+Common 390 Devices include:
+Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters,
+Consoles 3270 & 3215 ( a teletype emulated under linux for a line mode console ).
+DASD's direct access storage devices ( otherwise known as hard disks ).
+Tape Drives.
+CTC ( Channel to Channel Adapters ),
+ESCON or Paralell Cables used as a very high speed serial link
+between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
+
+
+Debugging IO on s/390 & zSeries under VM
+=========================================
+
+Now we are ready to go on with IO tracing commands under VM
+
+A few self explanatory queries:
+Q OSA
+Q CTC
+Q DISK
+Q DASD
+
+
+
+
+
+
+Q OSA on my machine returns
+OSA  7C08 ON OSA   7C08 SUBCHANNEL = 0000
+OSA  7C09 ON OSA   7C09 SUBCHANNEL = 0001
+OSA  7C14 ON OSA   7C14 SUBCHANNEL = 0002
+OSA  7C15 ON OSA   7C15 SUBCHANNEL = 0003
+
+If you have a guest with certain priviliges you may be able to see devices
+which don't belong to you to avoid this do add the option V.
+e.g.
+Q V OSA
+
+Now using the device numbers returned by this command we will
+Trace the io starting up on the first device 7c08 & 7c09
+In our simplest case we can trace the 
+start subchannels
+like TR SSCH 7C08-7C09
+or the halt subchannels
+or TR HSCH 7C08-7C09
+MSCH's ,STSCH's I think you can guess the rest
+
+Ingo's favourite trick is tracing all the IO's & CCWS & spooling them into the reader of another
+VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you
+ a look at the output.
+
+1) Spool stdout to VM reader
+SP PRT TO (another vm guest ) or * for the local vm guest
+2) Fill the reader with the trace
+TR IO 7c08-7c09 INST INT CCW PRT RUN
+3) Start up linux 
+i 00c  
+4) Finish the trace
+TR END
+5) close the reader
+C PRT
+6) list reader contents
+RDRLIST
+7) copy it to linux4's minidisk 
+RECEIVE / LOG TXT A1 ( replace
+8)
+filel & press F11 to look at it
+You should see someting like.
+
+00020942' SSCH  B2334000    0048813C    CC 0    SCH 0000    DEV 7C08
+          CPA 000FFDF0   PARM 00E2C9C4    KEY 0  FPI C0  LPM 80
+          CCW    000FFDF0  E4200100 00487FE8   0000  E4240100 ........
+          IDAL                                      43D8AFE8
+          IDAL                                      0FB76000
+00020B0A'   I/O DEV 7C08 -> 000197BC'   SCH 0000   PARM 00E2C9C4
+00021628' TSCH  B2354000 >> 00488164    CC 0    SCH 0000    DEV 7C08
+          CCWA 000FFDF8   DEV STS 0C  SCH STS 00  CNT 00EC
+           KEY 0   FPI C0  CC 0   CTLS 4007
+00022238' STSCH B2344000 >> 00488108    CC 0    SCH 0000    DEV 7C08
+
+If you don't like messing up your readed ( because you possibly booted from it )
+you can alternatively spool it to another readers guest.
+
+
+Other common VM device related commands
+---------------------------------------------
+These commands are listed only because they have
+been of use to me in the past & may be of use to
+you too. For more complete info on each of the commands
+use type HELP <command> from CMS.
+detaching devices
+DET <devno range>
+ATT <devno range> <guest> 
+attach a device to guest * for your own guest
+READY <devno> cause VM to issue a fake interrupt.
+
+The VARY command is normally only available to VM administrators.
+VARY ON PATH <path> TO <devno range>
+VARY OFF PATH <PATH> FROM <devno range>
+This is used to switch on or off channel paths to devices.
+
+Q CHPID <channel path ID>
+This displays state of devices using this channel path
+D SCHIB <subchannel>
+This displays the subchannel information SCHIB block for the device.
+this I believe is also only available to administrators.
+DEFINE CTC <devno>
+defines a virtual CTC channel to channel connection
+2 need to be defined on each guest for the CTC driver to use.
+COUPLE  devno userid remote devno
+Joins a local virtual device to a remote virtual device
+( commonly used for the CTC driver ).
+
+Building a VM ramdisk under CMS which linux can use
+def vfb-<blocksize> <subchannel> <number blocks>
+blocksize is commonly 4096 for linux.
+Formatting it
+format <subchannel> <driver letter e.g. x> (blksize <blocksize>
+
+Sharing a disk between multiple guests
+LINK userid devno1 devno2 mode password
+
+
+
+GDB on S390
+===========
+N.B. if compiling for debugging gdb works better without optimisation 
+( see Compiling programs for debugging )
+
+invocation
+----------
+gdb <victim program> <optional corefile>
+
+Online help
+-----------
+help: gives help on commands
+e.g.
+help
+help display
+Note gdb's online help is very good use it.
+
+
+Assembly
+--------
+info registers: displays registers other than floating point.
+info all-registers: displays floating points as well.
+disassemble: dissassembles
+e.g.
+disassemble without parameters will disassemble the current function
+disassemble $pc $pc+10 
+
+Viewing & modifying variables
+-----------------------------
+print or p: displays variable or register
+e.g. p/x $sp will display the stack pointer
+
+display: prints variable or register each time program stops
+e.g.
+display/x $pc will display the program counter
+display argc
+
+undisplay : undo's display's
+
+info breakpoints: shows all current breakpoints
+
+info stack: shows stack back trace ( if this dosent work too well, I'll show you the
+stacktrace by hand below ).
+
+info locals: displays local variables.
+
+info args: display current procedure arguments.
+
+set args: will set argc & argv each time the victim program is invoked.
+
+set <variable>=value
+set argc=100
+set $pc=0
+
+
+
+Modifying execution
+-------------------
+step: steps n lines of sourcecode
+step steps 1 line.
+step 100 steps 100 lines of code.
+
+next: like step except this will not step into subroutines
+
+stepi: steps a single machine code instruction.
+e.g. stepi 100
+
+nexti: steps a single machine code instruction but will not step into subroutines.
+
+finish: will run until exit of the current routine
+
+run: (re)starts a program
+
+cont: continues a program
+
+quit: exits gdb.
+
+
+breakpoints
+------------
+
+break
+sets a breakpoint
+e.g.
+
+break main
+
+break *$pc
+
+break *0x400618
+
+heres a really useful one for large programs
+rbr
+Set a breakpoint for all functions matching REGEXP
+e.g.
+rbr 390
+will set a breakpoint with all functions with 390 in their name.
+
+info breakpoints
+lists all breakpoints
+
+delete: delete breakpoint by number or delete them all
+e.g.
+delete 1 will delete the first breakpoint
+delete will delete them all
+
+watch: This will set a watchpoint ( usually hardware assisted ),
+This will watch a variable till it changes
+e.g.
+watch cnt, will watch the variable cnt till it changes.
+As an aside unfortunately gdb's, architecture independent watchpoint code
+is inconsistent & not very good, watchpoints usually work but not always.
+
+info watchpoints: Display currently active watchpoints
+
+condition: ( another useful one )
+Specify breakpoint number N to break only if COND is true.
+Usage is `condition N COND', where N is an integer and COND is an
+expression to be evaluated whenever breakpoint N is reached.
+
+
+
+User defined functions/macros
+-----------------------------
+define: ( Note this is very very useful,simple & powerful )
+usage define <name> <list of commands> end
+
+examples which you should consider putting into .gdbinit in your home directory
+define d
+stepi
+disassemble $pc $pc+10
+end
+
+define e
+nexti
+disassemble $pc $pc+10
+end
+
+
+Other hard to classify stuff
+----------------------------
+signal n:
+sends the victim program a signal.
+e.g. signal 3 will send a SIGQUIT.
+
+info signals:
+what gdb does when the victim receives certain signals.
+
+list:
+e.g.
+list lists current function source
+list 1,10 list first 10 lines of curret file.
+list test.c:1,10
+
+
+directory:
+Adds directories to be searched for source if gdb cannot find the source.
+(note it is a bit sensititive about slashes ) 
+e.g. To add the root of the filesystem to the searchpath do
+directory //
+
+
+call <function>
+This calls a function in the victim program, this is pretty powerful
+e.g.
+(gdb) call printf("hello world")
+outputs:
+$1 = 11 
+
+You might now be thinking that the line above didn't work, something extra had to be done.
+(gdb) call fflush(stdout)
+hello world$2 = 0
+As an aside the debugger also calls malloc & free under the hood 
+to make space for the "hello world" string.
+
+
+
+hints
+-----
+1) command completion works just like bash 
+( if you are a bad typist like me this really helps )
+e.g. hit br <TAB> & cursor up & down :-).
+
+2) if you have a debugging problem that takes a few steps to recreate
+put the steps into a file called .gdbinit in your current working directory
+if you have defined a few extra useful user defined commands put these in 
+your home directory & they will be read each time gdb is launched.
+
+A typical .gdbinit file might be.
+break main
+run
+break runtime_exception
+cont 
+
+
+stack chaining in gdb by hand
+-----------------------------
+This is done using a the same trick described for VM 
+p/x (*($sp+56))&0x7fffffff get the first backchain.
+
+For zSeries do
+p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff
+in the macros below.
+
+this outputs 
+$5 = 0x528f18 
+on my machine.
+Now you can use 
+info symbol (*($sp+56))&0x7fffffff 
+you might see something like.
+rl_getc + 36 in section .text  telling you what is located at address 0x528f18
+Now do.
+p/x (*(*$sp+56))&0x7fffffff 
+This outputs
+$6 = 0x528ed0
+Now do.
+info symbol (*(*$sp+56))&0x7fffffff
+rl_read_key + 180 in section .text
+now do
+p/x (*(**$sp+56))&0x7fffffff
+& so on.
+
+Disassembling instructions without debug info
+---------------------------------------------
+gdb typically compains if there is a lack of debugging
+symbols in  the disassemble command with 
+"No function contains specified address." to get around
+this do 
+x/<number lines to disassemble>xi <address>
+e.g.
+x/20xi 0x400730
+
+
+
+Note: Remember gdb has history just like bash you don't need to retype the
+whole line just use the up & down arrows.
+
+
+
+For more info
+-------------
+From your linuxbox do 
+man gdb or info gdb.
+
+core dumps
+----------
+What a core dump ?,
+A core dump is a file generated by the kernel ( if allowed ) which contains the registers,
+& all active pages of the program which has crashed.
+From this file gdb will allow you to look at the registers & stack trace & memory of the
+program as if it just crashed on your system, it is usually called core & created in the
+current working directory.
+This is very useful in that a customer can mail a core dump to a technical support department
+& the technical support department can reconstruct what happened.
+Provided the have an indentical copy of this program with debugging symbols compiled in & 
+the source base of this build is available.
+In short it is far more useful than something like a crash log could ever hope to be.
+
+In theory all that is missing to restart a core dumped program is a kernel patch which
+will do the following.
+1) Make a new kernel task structure
+2) Reload all the dumped pages back into the kernels memory managment structures.
+3) Do the required clock fixups
+4) Get all files & network connections for the process back into an identical state ( really difficult ).
+5) A few more difficult things I haven't thought of.
+
+
+
+Why have I never seen one ?.
+Probably because you haven't used the command 
+ulimit -c unlimited in bash
+to allow core dumps, now do 
+ulimit -a 
+to verify that the limit was accepted.
+
+A sample core dump
+To create this I'm going to do
+ulimit -c unlimited
+gdb 
+to launch gdb (my victim app. ) now be bad & do the following from another 
+telnet/xterm session to the same machine
+ps -aux | grep gdb
+kill -SIGSEGV <gdb's pid>
+or alternatively use killall -SIGSEGV gdb if you have the killall command.
+Now look at the core dump.
+./gdb ./gdb core
+Displays the following
+GNU gdb 4.18
+Copyright 1998 Free Software Foundation, Inc.
+GDB is free software, covered by the GNU General Public License, and you are
+welcome to change it and/or distribute copies of it under certain conditions.
+Type "show copying" to see the conditions.
+There is absolutely no warranty for GDB.  Type "show warranty" for details.
+This GDB was configured as "s390-ibm-linux"...
+Core was generated by `./gdb'.
+Program terminated with signal 11, Segmentation fault.
+Reading symbols from /usr/lib/libncurses.so.4...done.
+Reading symbols from /lib/libm.so.6...done.
+Reading symbols from /lib/libc.so.6...done.
+Reading symbols from /lib/ld-linux.so.2...done.
+#0  0x40126d1a in read () from /lib/libc.so.6
+Setting up the environment for debugging gdb.
+Breakpoint 1 at 0x4dc6f8: file utils.c, line 471.
+Breakpoint 2 at 0x4d87a4: file top.c, line 2609.
+(top-gdb) info stack
+#0  0x40126d1a in read () from /lib/libc.so.6
+#1  0x528f26 in rl_getc (stream=0x7ffffde8) at input.c:402
+#2  0x528ed0 in rl_read_key () at input.c:381
+#3  0x5167e6 in readline_internal_char () at readline.c:454
+#4  0x5168ee in readline_internal_charloop () at readline.c:507
+#5  0x51692c in readline_internal () at readline.c:521
+#6  0x5164fe in readline (prompt=0x7ffff810 "\177˙řx\177˙÷Ř\177˙řxŔ")
+    at readline.c:349
+#7  0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1,
+    annotation_suffix=0x4d6b44 "prompt") at top.c:2091
+#8  0x4d6cf0 in command_loop () at top.c:1345
+#9  0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635
+
+
+LDD
+===
+This is a program which lists the shared libraries which a library needs,
+Note you also get the relocations of the shared library text segments which
+help when using objdump --source.
+e.g.
+ ldd ./gdb
+outputs
+libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40018000)
+libm.so.6 => /lib/libm.so.6 (0x4005e000)
+libc.so.6 => /lib/libc.so.6 (0x40084000)
+/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
+
+
+Debugging shared libraries
+==========================
+Most programs use shared libraries, however it can be very painful
+when you single step instruction into a function like printf for the 
+first time & you end up in functions like _dl_runtime_resolve this is
+the ld.so doing lazy binding, lazy binding is a concept in ELF where 
+shared library functions are not loaded into memory unless they are 
+actually used, great for saving memory but a pain to debug.
+To get around this either relink the program -static or exit gdb type 
+export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing 
+the program in question.
+ 
+
+
+Debugging modules
+=================
+As modules are dynamically loaded into the kernel their address can be
+anywhere to get around this use the -m option with insmod to emit a load
+map which can be piped into a file if required.
+
+The proc file system
+====================
+What is it ?.
+It is a filesystem created by the kernel with files which are created on demand
+by the kernel if read, or can be used to modify kernel parameters,
+it is a powerful concept.
+
+e.g.
+
+cat /proc/sys/net/ipv4/ip_forward 
+On my machine outputs 
+0 
+telling me ip_forwarding is not on to switch it on I can do
+echo 1 >  /proc/sys/net/ipv4/ip_forward
+cat it again
+cat /proc/sys/net/ipv4/ip_forward 
+On my machine now outputs
+1
+IP forwarding is on.
+There is a lot of useful info in here best found by going in & having a look around,
+so I'll take you through some entries I consider important.
+
+All the processes running on the machine have there own entry defined by
+/proc/<pid>
+So lets have a look at the init process
+cd /proc/1
+
+cat cmdline
+emits
+init [2]
+
+cd /proc/1/fd
+This contains numerical entries of all the open files,
+some of these you can cat e.g. stdout (2)
+
+cat /proc/29/maps
+on my machine emits
+
+00400000-00478000 r-xp 00000000 5f:00 4103       /bin/bash
+00478000-0047e000 rw-p 00077000 5f:00 4103       /bin/bash
+0047e000-00492000 rwxp 00000000 00:00 0
+40000000-40015000 r-xp 00000000 5f:00 14382      /lib/ld-2.1.2.so
+40015000-40016000 rw-p 00014000 5f:00 14382      /lib/ld-2.1.2.so
+40016000-40017000 rwxp 00000000 00:00 0
+40017000-40018000 rw-p 00000000 00:00 0
+40018000-4001b000 r-xp 00000000 5f:00 14435      /lib/libtermcap.so.2.0.8
+4001b000-4001c000 rw-p 00002000 5f:00 14435      /lib/libtermcap.so.2.0.8
+4001c000-4010d000 r-xp 00000000 5f:00 14387      /lib/libc-2.1.2.so
+4010d000-40111000 rw-p 000f0000 5f:00 14387      /lib/libc-2.1.2.so
+40111000-40114000 rw-p 00000000 00:00 0
+40114000-4011e000 r-xp 00000000 5f:00 14408      /lib/libnss_files-2.1.2.so
+4011e000-4011f000 rw-p 00009000 5f:00 14408      /lib/libnss_files-2.1.2.so
+7fffd000-80000000 rwxp ffffe000 00:00 0
+
+
+Showing us the shared libraries init uses where they are in memory
+& memory access permissions for each virtual memory area.
+
+/proc/1/cwd is a softlink to the current working directory.
+/proc/1/root is the root of the filesystem for this process. 
+
+/proc/1/mem is the current running processes memory which you
+can read & write to like a file.
+strace uses this sometimes as it is a bit faster than the
+rather inefficent ptrace interface for peeking at DATA.
+
+
+cat status 
+
+Name:   init
+State:  S (sleeping)
+Pid:    1
+PPid:   0
+Uid:    0       0       0       0
+Gid:    0       0       0       0
+Groups:
+VmSize:      408 kB
+VmLck:         0 kB
+VmRSS:       208 kB
+VmData:       24 kB
+VmStk:         8 kB
+VmExe:       368 kB
+VmLib:         0 kB
+SigPnd: 0000000000000000
+SigBlk: 0000000000000000
+SigIgn: 7fffffffd7f0d8fc
+SigCgt: 00000000280b2603
+CapInh: 00000000fffffeff
+CapPrm: 00000000ffffffff
+CapEff: 00000000fffffeff
+
+User PSW:    070de000 80414146
+task: 004b6000 tss: 004b62d8 ksp: 004b7ca8 pt_regs: 004b7f68
+User GPRS:
+00000400  00000000  0000000b  7ffffa90
+00000000  00000000  00000000  0045d9f4
+0045cafc  7ffffa90  7fffff18  0045cb08
+00010400  804039e8  80403af8  7ffff8b0
+User ACRS:
+00000000  00000000  00000000  00000000
+00000001  00000000  00000000  00000000
+00000000  00000000  00000000  00000000
+00000000  00000000  00000000  00000000
+Kernel BackChain  CallChain    BackChain  CallChain
+       004b7ca8   8002bd0c     004b7d18   8002b92c
+       004b7db8   8005cd50     004b7e38   8005d12a
+       004b7f08   80019114                     
+Showing among other things memory usage & status of some signals &
+the processes'es registers from the kernel task_structure
+as well as a backchain which may be useful if a process crashes
+in the kernel for some unknown reason.
+
+Some driver debugging techniques
+================================
+high level debugging network drivers
+------------------------------------
+ifconfig is a quite useful command
+it gives the current state of network drivers.
+
+If you suspect your network device driver is dead
+one way to check is type 
+ifconfig <network device> 
+e.g. tr0
+You should see something like
+tr0       Link encap:16/4 Mbps Token Ring (New)  HWaddr 00:04:AC:20:8E:48
+          inet addr:9.164.185.132  Bcast:9.164.191.255  Mask:255.255.224.0
+          UP BROADCAST RUNNING MULTICAST  MTU:2000  Metric:1
+          RX packets:246134 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:100
+
+if the device doesn't say up
+try
+/etc/rc.d/init.d/network start 
+( this starts the network stack & hopefully calls ifconfig tr0 up ).
+ifconfig looks at the output of /proc/net/dev & presents it in a more presentable form
+Now ping the device from a machine in the same subnet.
+if the RX packets count & TX packets counts don't increment you probably
+have problems.
+next 
+cat /proc/net/arp
+Do you see any hardware addresses in the cache if not you may have problems.
+Next try
+ping -c 5 <broadcast_addr> i.e. the Bcast field above in the output of
+ifconfig. Do you see any replies from machines other than the local machine
+if not you may have problems. also if the TX packets count in ifconfig
+hasn't incremented either you have serious problems in your driver 
+(e.g. the txbusy field of the network device being stuck on ) 
+or you may have multiple network devices connected.
+
+
+chandev
+-------
+There is a new device layer for channel devices, some
+drivers e.g. lcs are registered with this layer.
+If the device uses the channel device layer you'll be
+able to find what interupts it uses & the current state 
+of the device.
+See the manpage chandev.8 &type cat /proc/chandev for more info.
+
+
+
+Starting points for debugging scripting languages etc.
+======================================================
+
+bash/sh
+
+bash -x <scriptname>
+e.g. bash -x /usr/bin/bashbug
+displays the following lines as it executes them.
++ MACHINE=i586
++ OS=linux-gnu
++ CC=gcc
++ CFLAGS= -DPROGRAM='bash' -DHOSTTYPE='i586' -DOSTYPE='linux-gnu' -DMACHTYPE='i586-pc-linux-gnu' -DSHELL -DHAVE_CONFIG_H   -I. -I. -I./lib -O2 -pipe
++ RELEASE=2.01
++ PATCHLEVEL=1
++ RELSTATUS=release
++ MACHTYPE=i586-pc-linux-gnu   
+
+perl -d <scriptname> runs the perlscript in a fully intercative debugger
+<like gdb>.
+Type 'h' in the debugger for help.
+
+for debugging java type
+jdb <filename> another fully interactive gdb style debugger.
+& type ? in the debugger for help.
+
+
+Debugging Drivers
+=================
+Some of our drivers now support a debug logging feature in
+/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
+for more info.
+e.g. 
+to switch on lcs debugging
+echo 5 > /proc/s390dbf/lcs/level
+& then after the error occured.
+cat /proc/s390dbf/lcs/sprintf >/logfile
+the logfile now contains some information which may help
+tech support resolve a problem in the field.
+
+If you have VM look at the chapter Debugging IO on S390 under VM.
+
+
+
+
+Tools soon to be available
+==========================
+
+Dumptool & Lcrash
+-----------------
+Michael Holzheu & others here at IBM have a fairly mature port of 
+SGI's lcrash tool which allows one to look at kernel structures in a
+running kernel.
+
+It also complements a tool called dumptool which dumps all the kernels
+memory pages & registers to either a tape or a disk.
+This can be used by tech support or an ambitous end user do
+post mortem debugging of a machine like gdb core dumps.
+
+Going into how to use this tool in detail will be explained
+in other documentation supplied by IBM & the lcrash homepage
+http://oss.sgi.com/projects/lkcd/.
+
+How they work
+-------------
+Lcrash is a perfectly normal application
+however it requires an additional file.
+It is built using a patch to the kernel source base.
+
+
+Debugging a live system it uses /dev/mem
+alternatively for post mortem debugging it uses the data 
+collected by dumptool.
+
+
+Ltrace
+------
+We also have a tool called ltrace in our CVS repository 
+no plans on a delivery date yet.
+ltrace is a superset of strace in that it also allows
+tracing of shared libraries calls as well as system calls,
+man ltrace for more info.
+
+SysRq
+=====
+This is now supported by linux for s/390 & zSeries.
+To enable it do compile the kernel with 
+Kernel Hacking -> Magic SysRq Key Enabled
+echo "1" > /proc/sys/kernel/sysrq.
+On 390 all commands are prefixed with
+^-
+e.g.
+^-t will show tasks.
+^-? or some unknown command will display help.
+The sysrq key reading is very picky ( I have to type the keys in an
+ xterm session & paste them  into the x3270 console )
+& it may be wise to predefine the keys as described in the VM hints above
+
+This is particularly useful for syncing disks unmounting & rebooting
+if the machine gets partially hung.
+
+Read Documentation/sysrq.txt for more info
+
+References:
+===========
+Enterprise Systems Architecture Reference Summary
+Enterprise Systems Architecture Principles of Operation
+Hartmut Penners s390 stack frame sheet.
+IBM Mainframe Channel Attachment a technology brief from a CISCO webpage
+Various bits of man & info pages of Linux.
+Linux & GDB source.
+Various info & man pages.
+CMS Help on tracing commands.
+Linux for s/390 Elf Application Binary Interface
+Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended )
+z/Architecture Principles of Operation SA22-7832-00
+Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the
+Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05
+
+
+
+
+
+
+
diff -u --recursive --new-file v2.4.3/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8
--- v2.4.3/linux/Documentation/s390/chandev.8	Fri Feb 16 15:53:08 2001
+++ linux/Documentation/s390/chandev.8	Wed Apr 11 19:02:27 2001
@@ -42,8 +42,16 @@
 .It
 Or from the boot command line using the 'chandev=' keyword
 .El
+.Bl -item
+.It
 Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows.
 /bin/chandev <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>.
+The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script.
+.It
+#!/bin/bash
+.It
+exec >/dev/console 2>&1 0>&1
+.El
 
 e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the  parameters would be.
 
diff -u --recursive --new-file v2.4.3/linux/Documentation/s390/config3270.sh linux/Documentation/s390/config3270.sh
--- v2.4.3/linux/Documentation/s390/config3270.sh	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/config3270.sh	Wed Apr 11 19:02:27 2001
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# config3270 -- Autoconfigure /dev/3270/* and /etc/inittab
+#
+#       Usage:
+#               config3270
+#
+#       Output:
+#               /tmp/mkdev3270
+#
+#       Operation:
+#               1. Run this script
+#               2. Run the script it produces: /tmp/mkdev3270
+#               3. Issue "telinit q" or reboot, as appropriate.
+#
+P=/proc/tty/driver/tty3270
+ROOT=
+D=$ROOT/dev
+SUBD=3270
+TTY=$SUBD/tty
+TUB=$SUBD/tub
+SCR=$ROOT/tmp/mkdev3270
+SCRTMP=$SCR.a
+GETTYLINE=:2345:respawn:/sbin/mingetty
+INITTAB=$ROOT/etc/inittab
+NINITTAB=$ROOT/etc/NEWinittab
+OINITTAB=$ROOT/etc/OLDinittab
+ADDNOTE=\\"# Additional mingettys for the 3270/tty* driver, tub3270 ---\\"
+
+if ! ls $P > /dev/null 2>&1; then
+	modprobe tub3270 > /dev/null 2>&1
+fi
+ls $P > /dev/null 2>&1 || exit 1
+
+# Initialize two files, one for /dev/3270 commands and one
+# to replace the /etc/inittab file (old one saved in OLDinittab)
+echo "#!/bin/sh" > $SCR || exit 1
+echo " " >> $SCR
+echo "# Script built by /sbin/config3270" >> $SCR
+echo rm -rf "$D/$SUBD/*" >> $SCR
+echo "grep -v $TTY $INITTAB > $NINITTAB" > $SCRTMP || exit 1
+echo "echo $ADDNOTE >> $NINITTAB" >> $SCRTMP
+echo mkdir -p $D/$SUBD >> $SCR
+
+# Now query the tub3270 driver for 3270 device information
+# and add appropriate mknod and mingetty lines to our files
+echo what=config > $P
+while read devno maj min;do
+	if [ $min = 0 ]; then
+		fsmaj=$maj
+		echo mknod $D/$TUB c $fsmaj 0 >> $SCR
+		echo chmod 666 $D/$TUB >> $SCR
+	elif [ $maj = CONSOLE ]; then
+		echo mknod $D/$TUB$devno c $fsmaj $min >> $SCR
+	else
+		echo mknod $D/$TTY$devno c $maj $min >>$SCR
+		echo mknod $D/$TUB$devno c $fsmaj $min >> $SCR
+		echo "echo t$min$GETTYLINE $TTY$devno >> $NINITTAB" >> $SCRTMP
+	fi
+done < $P
+
+echo mv $INITTAB $OINITTAB >> $SCRTMP || exit 1
+echo mv $NINITTAB $INITTAB >> $SCRTMP
+cat $SCRTMP >> $SCR
+rm $SCRTMP
+exit 0
diff -u --recursive --new-file v2.4.3/linux/Documentation/s390/s390dbf.txt linux/Documentation/s390/s390dbf.txt
--- v2.4.3/linux/Documentation/s390/s390dbf.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/s390dbf.txt	Wed Apr 11 19:02:27 2001
@@ -0,0 +1,558 @@
+S390 Debug Feature
+==================
+
+files: arch/s390/kernel/debug.c
+       include/asm-s390/debug.h
+
+Description:
+------------
+The goal of this feature is to provide a kernel debug logging API 
+where log records can be stored efficiently in memory, where each component 
+(e.g. device drivers) can have one seperate debug log.
+One purpose of this is to inspect the debug logs after a production system crash
+in order to analyze the reason for the crash.
+If the system still runs but only a subcomponent which uses dbf failes,
+it is possible to look at the debug logs on a live system via the Linux proc
+filesystem.
+The debug feature may also very usefull for kernel and driver development.
+
+Design:
+-------
+Kernel components (e.g. device drivers) can register themselves at the debug 
+feature with the function call debug_register(). This function initializes a 
+debug log for the caller. For each debug log exists a number of debug areas 
+where exactly one is active at one time.  Each debug area consists of contiguous
+pages in memory. In the debug areas there are stored debug entries (log records)
+which are written by event- and exception-calls. 
+
+An event-call writes the specified debug entry to the active debug
+area and updates the log pointer for the active area. If the end 
+of the active debug area is reached, a wrap around is done (ring buffer) 
+and the next debug entry will be written at the beginning of the active 
+debug area.
+
+An exception-call writes the specified debug entry to the log and
+switches to the next debug area. This is done in order to be sure
+that the records which describe the origin of the exception are not
+overwritten when a wrap around for the current area occurs.
+
+The debug areas itselve are also ordered in form of a ring buffer. 
+When an exception is thrown in the last debug area, the following debug 
+entries are then written again in the very first area.
+
+There are three versions for the event- and exception-calls: One for
+logging raw data, one for text and one for numbers.
+
+Each debug entry contains the following data:
+
+- Timestamp
+- Cpu-Number of calling task
+- Level of debug entry (0...6)
+- Return Address to caller
+- Flag, if entry is an exception or not
+
+The debug logs can be inspected in a live system through entries in
+the proc-filesystem. Under the path /proc/s390dbf there is 
+a directory for each registered component, which is named like the
+corresponding component.
+
+The content of the directories are files which represent different views
+to the debug log. Each component can decide which views should be
+used through registering them with the function debug_register_view().
+Predefined views for hex/ascii, sprintf and raw binary data are provided.
+It is also possible to define other views. The content of
+a view can be inspected simply by reading the corresponding proc file.
+
+All debug logs have an an actual debug level (range from 0 to 6).
+The default level is 3. Event and Exception functions have a 'level'
+parameter. Only debug entries with a level that is lower or equal
+than the actual level are written to the log. This means that high 
+priority log entries should have a low level value whereas low priority
+entries should have a high one. 
+The actual debug level can be changed with the help of the proc-filesystem 
+through writing a number string "x" to the 'level' proc file which is
+provided for every debug log. Debugging can be switched off completely
+by using "-" on the 'level' proc file.
+
+Example:
+
+> echo "-" > /proc/s390dbf/dasd/level
+
+Kernel Interfaces:
+------------------
+
+----------------------------------------------------------------------------
+debug_info_t *debug_register(char *name, int pages_index, int nr_areas,
+                             int buf_size);
+
+Parameter:    name:        Name of debug log (e.g. used for proc entry) 
+              pages_index: 2^pages_index pages will be allocated per area
+              nr_areas:    number of debug areas
+              buf_size:    size of data area in each debug entry
+
+Return Value: Handle for generated debug area   
+              NULL if register failed 
+
+Description:  Allocates memory for a debug log     
+              Must not be called within an interrupt handler 
+
+---------------------------------------------------------------------------
+void debug_unregister (debug_info_t * id);
+
+Parameter:     id:   handle for debug log  
+
+Return Value:  none 
+
+Description:   frees memory for a debug log     
+               Must not be called within an interrupt handler 
+
+---------------------------------------------------------------------------
+void debug_set_level (debug_info_t * id, int new_level);
+
+Parameter:     id:        handle for debug log  
+               new_level: new debug level 
+
+Return Value:  none 
+
+Description:   Sets new actual debug level if new_level is valid. 
+---------------------------------------------------------------------------
+debug_entry_t* debug_event (debug_info_t* id, int level, void* data, 
+                            int length);
+
+Parameter:     id:     handle for debug log  
+               level:  debug level           
+               data:   pointer to data for debug entry  
+               length: length of data in bytes       
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry to active debug area (if level <= actual 
+               debug level)    
+
+---------------------------------------------------------------------------
+debug_entry_t* debug_int_event (debug_info_t * id, int level, 
+                                unsigned int data);
+debug_entry_t* debug_long_event(debug_info_t * id, int level,
+                                unsigned long data);
+
+Parameter:     id:     handle for debug log  
+               level:  debug level           
+               data:   integer value for debug entry           
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry to active debug area (if level <= actual 
+               debug level)    
+
+---------------------------------------------------------------------------
+debug_entry_t* debug_text_event (debug_info_t * id, int level, 
+                                 const char* data);
+
+Parameter:     id:     handle for debug log  
+               level:  debug level           
+               data:   string for debug entry  
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry in ascii format to active debug area 
+               (if level <= actual debug level)     
+
+---------------------------------------------------------------------------
+debug_entry_t* debug_sprintf_event (debug_info_t * id, int level, 
+                                    char* string,...);
+
+Parameter:     id:    handle for debug log 
+               level: debug level
+               string: format string for debug entry 
+               ...: varargs used as in sprintf()
+
+Return Value:  Address of written debug entry
+
+Description:   writes debug entry with format string and varargs (longs) to 
+               active debug area (if level $<=$ actual debug level). 
+               floats and long long datatypes cannot be used as varargs.
+
+---------------------------------------------------------------------------
+
+debug_entry_t* debug_exception (debug_info_t* id, int level, void* data, 
+                                int length);
+
+Parameter:     id:     handle for debug log  
+               level:  debug level           
+               data:   pointer to data for debug entry  
+               length: length of data in bytes       
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry to active debug area (if level <= actual 
+               debug level) and switches to next debug area  
+
+---------------------------------------------------------------------------
+debug_entry_t* debug_int_exception (debug_info_t * id, int level, 
+                                    unsigned int data);
+debug_entry_t* debug_long_exception(debug_info_t * id, int level,
+                                    unsigned long data);
+
+Parameter:     id:     handle for debug log  
+               level:  debug level           
+               data:   integer value for debug entry           
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry to active debug area (if level <= actual 
+               debug level) and switches to next debug area  
+
+---------------------------------------------------------------------------
+debug_entry_t* debug_text_exception (debug_info_t * id, int level, 
+                                     const char* data);
+
+Parameter:     id:     handle for debug log  
+               level:  debug level           
+               data:   string for debug entry  
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry in ascii format to active debug area 
+               (if level <= actual debug level) and switches to next debug 
+               area  
+
+---------------------------------------------------------------------------
+debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level,
+                                        char* string,...);
+
+Parameter:     id:    handle for debug log  
+               level: debug level  
+               string: format string for debug entry  
+               ...: varargs used as in sprintf()
+
+Return Value:  Address of written debug entry 
+
+Description:   writes debug entry with format string and varargs (longs) to 
+               active debug area (if level $<=$ actual debug level) and
+               switches to next debug area. 
+               floats and long long datatypes cannot be used as varargs.
+
+---------------------------------------------------------------------------
+
+int debug_register_view (debug_info_t * id, struct debug_view *view);
+
+Parameter:     id:    handle for debug log  
+               view:  pointer to debug view struct 
+
+Return Value:  0  : ok 
+               < 0: Error 
+
+Description:   registers new debug view and creates proc dir entry 
+
+---------------------------------------------------------------------------
+int debug_unregister_view (debug_info_t * id, struct debug_view *view); 
+
+Parameter:     id:    handle for debug log  
+               view:  pointer to debug view struct 
+
+Return Value:  0  : ok 
+               < 0: Error 
+
+Description:   unregisters debug view and removes proc dir entry 
+
+
+
+Predefined views:
+-----------------
+
+extern struct debug_view debug_hex_ascii_view;
+extern struct debug_view debug_raw_view;
+extern struct debug_view debug_sprintf_view;
+
+Examples
+--------
+
+/*
+ * hex_ascii- + raw-view Example
+ */
+
+#include <linux/module.h>
+#include <asm/debug.h>
+
+static debug_info_t* debug_info;
+
+int init_module(void)
+{
+    /* register 4 debug areas with one page each and 4 byte data field */
+
+    debug_info = debug_register ("test", 0, 4, 4 );
+    debug_register_view(debug_info,&debug_hex_ascii_view);
+    debug_register_view(debug_info,&debug_raw_view);
+
+    debug_text_event(debug_info, 4 , "one ");
+    debug_int_exception(debug_info, 4, 4711);
+    debug_event(debug_info, 3, &debug_info, 4);
+
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    debug_unregister (debug_info);
+}
+
+---------------------------------------------------------------------------
+
+/*
+ * sprintf-view Example
+ */
+
+#include <linux/module.h>
+#include <asm/debug.h>
+
+static debug_info_t* debug_info;
+
+int init_module(void)
+{
+    /* register 4 debug areas with one page each and data field for */
+    /* format string pointer + 2 varargs (= 3 * sizeof(long))       */
+
+    debug_info = debug_register ("test", 0, 4, sizeof(long) * 3);
+    debug_register_view(debug_info,&debug_sprintf_view);
+
+    debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__);
+    debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info);
+
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    debug_unregister (debug_info);
+}
+
+
+
+ProcFS Interface
+----------------
+Views to the debug logs can be investigated through reading the corresponding 
+proc-files:
+
+Example:
+
+> ls /proc/s390dbf/dasd
+hex_ascii  level      raw
+> cat /proc/s390dbf/dasd/hex_ascii | sort +1
+00 00974733272:680099 2 - 02 0006ad7e  07 ea 4a 90 | ....
+00 00974733272:682210 2 - 02 0006ade6  46 52 45 45 | FREE
+00 00974733272:682213 2 - 02 0006adf6  07 ea 4a 90 | ....
+00 00974733272:682281 1 * 02 0006ab08  41 4c 4c 43 | EXCP 
+01 00974733272:682284 2 - 02 0006ab16  45 43 4b 44 | ECKD
+01 00974733272:682287 2 - 02 0006ab28  00 00 00 04 | ....
+01 00974733272:682289 2 - 02 0006ab3e  00 00 00 20 | ... 
+01 00974733272:682297 2 - 02 0006ad7e  07 ea 4a 90 | ....
+01 00974733272:684384 2 - 00 0006ade6  46 52 45 45 | FREE
+01 00974733272:684388 2 - 00 0006adf6  07 ea 4a 90 | ....
+
+See section about predefined views for explanation of the above output!
+
+Changing the debug level
+------------------------
+
+Example:
+
+
+> cat /proc/s390dbf/dasd/level
+3
+> echo "5" > /proc/s390dbf/dasd/level
+> cat /proc/s390dbf/dasd/level
+5
+
+lcrash Interface
+----------------
+It is planned that the dump analysis tool lcrash gets an additional command
+'s390dbf' to display all the debug logs. With this tool it will be possible 
+to investigate the debug logs on a live system and with a memory dump after 
+a system crash.
+
+Investigating raw memory
+------------------------
+One last possibility to investigate the debug logs at a live
+system and after a system crash is to look at the raw memory
+under VM or at the Service Element.
+It is possible to find the anker of the debug-logs through
+the 'debug_area_first' symbol in the System map. Then one has
+to follow the correct pointers of the data-structures defined
+in debug.h and find the debug-areas in memory.
+Normally modules which use the debug feature will also have
+a global variable with the pointer to the debug-logs. Following
+this pointer it will also be possible to find the debug logs in
+memory.
+
+For this method it is recommended to use '16 * x + 4' byte (x = 0..n)
+for the length of the data field in debug_register() in
+order to see the debug entries well formatted.
+
+
+Predefined Views
+----------------
+
+There are three predefined views: hex_ascii, raw and sprintf. 
+The hex_ascii view shows the data field in hex and ascii representation 
+(e.g. '45 43 4b 44 | ECKD'). 
+The raw view returns a bytestream as the debug areas are stored in memory.
+
+The sprintf view formats the debug entries in the same way as the sprintf
+function would do. The sprintf event/expection fuctions write to the 
+debug entry a pointer to the format string (size = sizeof(long)) 
+and for each vararg a long value. So e.g. for a debug entry with a format 
+string plus two varargs one would need to allocate a (3 * sizeof(long)) 
+byte data area in the debug_register() function.
+
+
+NOTE: If using the sprintf view do NOT use other event/exception functions
+than the sprintf-event and -exception functions.
+
+The format of the hex_ascii and sprintf view is as follows:
+- Number of area
+- Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated 
+  Universal Time (UTC), January 1, 1970)
+- level of debug entry
+- Exception flag (* = Exception)
+- Cpu-Number of calling task
+- Return Address to caller
+- data field
+
+The format of the raw view is:
+- Header as described in debug.h
+- datafield 
+
+A typical line of the hex_ascii view will look like the following (first line 
+is only for explanation and will not be displayed when 'cating' the view):
+
+area  time           level exception cpu caller    data (hex + ascii)
+--------------------------------------------------------------------------
+00    00964419409:440690 1 -         00  88023fe   
+
+
+Defining views
+--------------
+
+Views are specified with the 'debug_view' structure. There are defined
+callback functions which are used for reading and writing the proc files:
+
+struct debug_view {
+        char name[DEBUG_MAX_PROCF_LEN];  
+        debug_prolog_proc_t* prolog_proc; 
+        debug_header_proc_t* header_proc;
+        debug_format_proc_t* format_proc;
+        debug_input_proc_t*  input_proc;
+	void*                private_data;
+};
+
+where
+
+typedef int (debug_header_proc_t) (debug_info_t* id,
+                                   struct debug_view* view,
+                                   int area,
+                                   debug_entry_t* entry,
+                                   char* out_buf);
+
+typedef int (debug_format_proc_t) (debug_info_t* id,
+                                   struct debug_view* view, char* out_buf,
+                                   const char* in_buf);
+typedef int (debug_prolog_proc_t) (debug_info_t* id,
+                                   struct debug_view* view,
+                                   char* out_buf);
+typedef int (debug_input_proc_t) (debug_info_t* id,
+                                  struct debug_view* view,
+                                  struct file* file, const char* user_buf,
+                                  size_t in_buf_size, loff_t* offset);
+
+
+The "private_data" member can be used as pointer to view specific data.
+It is not used by the debug feature itself.
+
+The output when reading a debug-proc file is structured like this:
+
+"prolog_proc output"
+
+"header_proc output 1"  "format_proc output 1"
+"header_proc output 2"  "format_proc output 2"
+"header_proc output 3"  "format_proc output 3"
+...
+
+When a view is read from the proc fs, the Debug Feature calls the 
+'prolog_proc' once for writing the prolog.
+Then 'header_proc' and 'format_proc' are called for each 
+existing debug entry.
+
+The input_proc can be used to implement functionality when it is written to 
+the view (e.g. like with 'echo "0" > /proc/s390dbf/dasd/level).
+
+For header_proc there can be used the default function
+debug_dflt_header_fn() which is defined in in debug.h.
+and which produces the same header output as the predefined views.
+E.g:
+00 00964419409:440761 2 - 00 88023ec
+
+In order to see how to use the callback functions check the implementation
+of the default views!
+
+Example
+
+#include <asm/debug.h>
+
+#define UNKNOWNSTR "data: %08x"
+
+const char* messages[] =
+{"This error...........\n",
+ "That error...........\n",
+ "Problem..............\n",
+ "Something went wrong.\n",
+ "Everything ok........\n",
+ NULL
+};
+
+static int debug_test_format_fn(
+   debug_info_t * id, struct debug_view *view, 
+   char *out_buf, const char *in_buf
+)
+{
+  int i, rc = 0;
+
+  if(id->buf_size >= 4) {
+     int msg_nr = *((int*)in_buf);
+     if(msg_nr < sizeof(messages)/sizeof(char*) - 1)
+        rc += sprintf(out_buf, "%s", messages[msg_nr]);	
+     else
+        rc += sprintf(out_buf, UNKNOWNSTR, msg_nr);
+  }
+ out:
+   return rc;
+}
+
+struct debug_view debug_test_view = {
+  "myview",                 /* name of view */
+  NULL,                     /* no prolog */
+  &debug_dflt_header_fn,    /* default header for each entry */
+  &debug_test_format_fn,    /* our own format function */
+  NULL,                     /* no input function */
+  NULL                      /* no private data */
+};
+
+=====
+test:
+=====
+debug_info_t *debug_info;
+...
+debug_info = debug_register ("test", 0, 4, 4 ));
+debug_register_view(debug_info, &debug_test_view);
+for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i);
+
+> cat /proc/s390dbf/test/myview
+00 00964419734:611402 1 - 00 88042ca   This error...........
+00 00964419734:611405 1 - 00 88042ca   That error...........
+00 00964419734:611408 1 - 00 88042ca   Problem..............
+00 00964419734:611411 1 - 00 88042ca   Something went wrong.
+00 00964419734:611414 1 - 00 88042ca   Everything ok........
+00 00964419734:611417 1 - 00 88042ca   data: 00000005
+00 00964419734:611419 1 - 00 88042ca   data: 00000006
+00 00964419734:611422 1 - 00 88042ca   data: 00000007
+00 00964419734:611425 1 - 00 88042ca   data: 00000008
+00 00964419734:611428 1 - 00 88042ca   data: 00000009
diff -u --recursive --new-file v2.4.3/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt
--- v2.4.3/linux/Documentation/scsi-generic.txt	Thu Feb  8 16:32:44 2001
+++ linux/Documentation/scsi-generic.txt	Thu Apr 12 12:03:50 2001
@@ -1,6 +1,6 @@
-            Notes on Linux's SG driver version 2.1.36
+            Notes on Linux's SG driver version 2.1.39
             -----------------------------------------
-                                                        20000110
+                                                        20010329
 
 Introduction
 ============
@@ -12,7 +12,7 @@
 amongst other things.
 
 These are notes on the Linux SCSI generic packet device driver (sg)
-describing version 2.1.36 . The original driver was written by Lawrence
+describing version 2.1.39 . The original driver was written by Lawrence
 Foard and remained in place with minimal changes since circa 1992.
 Version 2 of this driver remains backward compatible (binary and
 source **) with the original. It adds scatter gather, command queuing,
@@ -23,6 +23,10 @@
 at the linux/Documentation directory. The full document can be found
 at http://www.torque.net/sg/p/scsi-generic_long.txt .
 
+The Linux 2.4 series kernels have now been released. Lk 2.4 contains
+an upgraded "version 3" sg driver which is described in a supplementary
+document at http://www.torque.net/sg/p/scsi-generic_v3.txt .
+
 The interface and usage of the original sg driver have been documented
 by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
 of the document is version 1.5 dated 7th May 1996. It can found at
@@ -41,7 +45,8 @@
 The SCSI generic packet device driver (sg) is a character based device.
 It is one of the four high level device driver in the SCSI sub-system;
 the others are sd (for direct-access devices - disks), st (for tapes)
-and sr (for data cdroms). The other three devices are block devices.
+and sr (for data cdroms). Sd and sr are block devices while st (like sg)
+is a character device.
 
 The unifying layer of the SCSI sub-system is the so-called mid-level.
 Below that are the "low level" drivers which are the drivers for the
@@ -236,10 +241,11 @@
 /dev/sg[a-z]
 /dev/sg[0,1,2,...]
 or a symbolic link to one of these. [Devfs has its own sub-directory for
-sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI
-devices are allocated to sg minor numbers in the same order as they appear
-in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver.
-This means it has an open/close/read/write/ioctl type interface.
+sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .]
+It seems as though SCSI devices are allocated to sg minor numbers in the
+same order as they appear in 'cat /proc/scsi/scsi'. Sg is a "character"
+based Linux device driver.  This means it has an open/close/read/write/ioctl
+type interface.
 
 Flags can be either O_RDONLY or O_RDWR or-ed with either
 O_EXCL          waits for other opens on sg device to be closed before
@@ -396,7 +402,7 @@
 (which is called 'sg_release()' in the version 2 driver) to facilitate
 the cleanup mentioned above.
 
-A problem persists in version 2.1.36 if the sg driver is a module and is
+A problem persists in version 2.1.39 if the sg driver is a module and is
 removed while packets are still "in flight".
 
 Returns 0 if successful, otherwise -1 implies an error.
@@ -595,6 +601,8 @@
 do much (may in the future after other issues are resolved). Yields an
 EBUSY error if the SCSI bus or the associated device is being reset
 when this ioctl() is called, otherwise returns 0.
+N.B. In some recent distributions there is a patch to the SCSI mid level
+code that activates this ioctl. Check your distribution.
 
 SG_SET_DEBUG +:
 Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
@@ -640,7 +648,7 @@
 found, switching to normal blocked io. A working example of this logic
 is in the sg_scan utility program.
 
-open("/dev/sga", O_RDONLY | O_NONBLOCK)
+open("/dev/sg0", O_RDONLY | O_NONBLOCK)
 /* check device, EBUSY means some other process has O_EXCL lock on it */
 /* when the device you want is found then ... */
 flags = fcntl(sg_fd, F_GETFL)
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/PAS16 linux/Documentation/sound/PAS16
--- v2.4.3/linux/Documentation/sound/PAS16	Sun Apr  2 15:38:53 2000
+++ linux/Documentation/sound/PAS16	Wed Apr 11 19:02:27 2001
@@ -1,7 +1,7 @@
 Pro Audio Spectrum 16 for 2.3.99 and later
 =========================================
 by Thomas Molina (tmolina@home.com)
-last modified 26 Mar 2000
+last modified 3 Mar 2001
 Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken
 from Configure.help, Riccardo Facchetti for stuff from README.OSS,
 and others whose names I could not find.
@@ -48,14 +48,6 @@
           if you want to use the SB emulation of PAS16. It's also possible to
           the emulation if you want to use a true SB card together with PAS16
           (there is another question about this that is asked later).
-  "Sound Blaster support",
-        - Answer 'y' if you have an original SB card made by Creative Labs
-          or a full 100% hardware compatible clone (like Thunderboard or
-          SM Games). If your card was in the list of supported cards (above),
-          please look at the card specific instructions later in this file
-          before answering this question. For an unknown card you may answer
-          'y' if the card claims to be SB compatible.
-         Enable this option also with PAS16.
 
   "Generic OPL2/OPL3 FM synthesizer support",
         - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
@@ -113,27 +105,13 @@
   Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
   16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
   some other card made by Media Vision or Logitech since they are not
-  PAS16 compatible.
+  PAS16 compatible.  It is not necessary to enable the  separate
+  Sound Blaster support; it is included in the PAS driver.
+
   If you compile the driver into the kernel, you have to add
   "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
   to the kernel command line.
 
-100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
-CONFIG_SOUND_SB
-  Answer Y if you have an original Sound Blaster card made by Creative
-  Labs or a 100% hardware compatible clone (like the Thunderboard or
-  SM Games). For an unknown card you may answer Y if the card claims
-  to be Sound Blaster-compatible.  The PAS16 has 8-bit Soundblaster
-  support, so you can answer Y here for it.
-
-  Please read the file Documentation/sound/Soundblaster.
-
-  If you compile the driver into the kernel and don't want to use isapnp,
-  you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
-
-  You can say M here to compile this driver as a module; the module is
-  called sb.o.
-
 FM Synthesizer (YM3812/OPL-3) support
 CONFIG_SOUND_YM3812
   Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
@@ -167,7 +145,7 @@
 CONFIG_SOUND_TRACEINIT=y
 CONFIG_SOUND_DMAP=y
 CONFIG_SOUND_PAS=y
-CONFIG_SOUND_SB=y
+CONFIG_SOUND_SB=n
 CONFIG_SOUND_YM3812=m
 
 I have also included the following append line in /etc/lilo.conf:
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/PCM1-pro linux/Documentation/sound/PCM1-pro
--- v2.4.3/linux/Documentation/sound/PCM1-pro	Mon Apr 12 16:18:27 1999
+++ linux/Documentation/sound/PCM1-pro	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-In Documentation/sound/README.OSS was a remark saying noone was sure the
-mixer on the PCM1-pro worked with the ACI driver. Well, it does.
-I've been using the drivers for the MAD16 and the driver for the mixer
-since kernel 2.0.32 with a MiroSound PCM1-pro and it works great.
-
-I've got it working with the following configuration:
-
-MAD16 audio I/O base = 530
-MAD16  audio IRQ = 7
-MAD16 Audio DMA = 1
-MAD16 MIDI I/O = 330
-MAD16 MIDI IRQ = 9
-
-And I've enabled the ACI mixer (miro PCM12) .
-
-
-Bas van der Linden.
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/README.OSS linux/Documentation/sound/README.OSS
--- v2.4.3/linux/Documentation/sound/README.OSS	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/sound/README.OSS	Wed Apr 11 19:02:27 2001
@@ -17,6 +17,7 @@
 document can be still interesting and very helpful.
 
 [ File edited 17.01.1999 - Riccardo Facchetti ]
+[ Edited miroSOUND section 17.09.2000 - Robert Siemer ]
 
 OSS/Free version 3.8 release notes
 ----------------------------------
@@ -1325,26 +1326,38 @@
 miroSOUND
 ---------
 
-The miroSOUND PCM12 has been used successfully. This card is based on
-the MAD16, OPL4, and CS4231A chips and everything said in the section
-about MAD16 cards applies here, too. The only major difference between
-the PCM12 and other MAD16 cards is that instead of the mixer in the
-CS4231 codec a separate mixer controlled by an on-board 80C32
-microcontroller is used. Control of the mixer takes place via the ACI
-(miro's audio control interface) protocol that is implemented in a
-separate lowlevel driver. Make sure you compile this ACI driver
-together with the normal MAD16 support when you use a miroSOUND PCM12
-card. The ACI mixer is controlled by /dev/mixer and the CS4231 mixer
-by /dev/mixer2. You usually don't want to change anything on the
-CS4231 mixer.
-
-The miroSOUND PCM12 is capable of full duplex operation (simultaneous
-PCM replay and recording), which allows you to implement nice
-real-time signal processing audio effect software and network
-telephones. The ACI mixer has to be configured into a special "solo"
+The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used
+successfully. This card is based on the MAD16, OPL4, and CS4231A chips
+and everything said in the section about MAD16 cards applies here,
+too. The only major difference between the PCMxx and other MAD16 cards
+is that instead of the mixer in the CS4231 codec a separate mixer
+controlled by an on-board 80C32 microcontroller is used. Control of
+the mixer takes place via the ACI (miro's audio control interface)
+protocol that is implemented in a separate lowlevel driver. Make sure
+you compile this ACI driver together with the normal MAD16 support
+when you use a miroSOUND PCMxx card. The ACI mixer is controlled by
+/dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load
+time). Only in special cases you want to change something on the CS4231
+mixer.
+
+The miroSOUND PCM12 and PCM20 radio is capable of full duplex
+operation (simultaneous PCM replay and recording), which allows you to
+implement nice real-time signal processing audio effect software and
+network telephones. The ACI mixer has to be switched into the "solo"
 mode for duplex operation in order to avoid feedback caused by the
-mixer (input hears output signal). See lowlevel/aci.c for details on
-the ioctl() for activating the "solo" mode.
+mixer (input hears output signal). You can de-/activate this mode
+through toggleing the record button for the wave controller with an
+OSS-mixer.
+
+The PCM20 contains a radio tuner, which is also controlled by
+ACI. This radio tuner is supported by the ACI driver together with the
+miropcm20.o module. Also the 7-band equalizer is integrated
+(limited by the OSS-design). Developement has started and maybe
+finished for the RDS decoder on this card, too. You will be able to
+read radio text, the program service name, program type and
+others. Even the v4l radio module benefits from it with a refined
+strength value. See aci.c, radio-miropcm20.c and rds-miropcm20.c for
+more details.
 
 The following configuration parameters have worked fine for the PCM12
 in Markus Kuhn's system, many other configurations might work, too:
@@ -1352,13 +1365,8 @@
 CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10,
 DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000.
 
-The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12.
-Perhaps the same ACI driver also works for these cards, however this
-has never actually been tested. The PCM20 contains a radio tuner,
-which is also controlled by ACI. This radio tuner is currently not
-supported by the ACI driver, but documentation for it was provided by
-miro and ACI tuner support could easily be added if someone is really
-interested.
+Bas van der Linden is using his PCM1-pro with a configuration that
+differs in: CONFIG_MAD16_IRQ=7, CONFIG_MAD16_DMA=1, CONFIG_MAD16_MPU_IRQ=9
 
 Compaq Deskpro XL
 -----------------
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/es1370 linux/Documentation/sound/es1370
--- v2.4.3/linux/Documentation/sound/es1370	Fri Jul 10 14:03:35 1998
+++ linux/Documentation/sound/es1370	Wed Apr 11 19:02:27 2001
@@ -1,3 +1,11 @@
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
 ALaw/uLaw sample formats
 ------------------------
 
@@ -59,4 +67,4 @@
 
 
 Thomas Sailer
-sailer@ife.ee.ethz.ch
+t.sailer@alumni.ethz.ch
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/es1371 linux/Documentation/sound/es1371
--- v2.4.3/linux/Documentation/sound/es1371	Fri Jul 10 14:03:35 1998
+++ linux/Documentation/sound/es1371	Wed Apr 11 19:02:27 2001
@@ -1,3 +1,11 @@
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
 ALaw/uLaw sample formats
 ------------------------
 
@@ -53,4 +61,4 @@
 
 
 Thomas Sailer
-sailer@ife.ee.ethz.ch
+t.sailer@alumni.ethz.ch
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/solo1 linux/Documentation/sound/solo1
--- v2.4.3/linux/Documentation/sound/solo1	Mon Aug 23 11:15:27 1999
+++ linux/Documentation/sound/solo1	Wed Apr 11 19:02:27 2001
@@ -1,3 +1,25 @@
+Recording
+---------
+
+Recording does not work on the author's card, but there
+is at least one report of it working on later silicon.
+The chip behaves differently than described in the data sheet,
+likely due to a chip bug. Working around this would require
+the help of ESS (for example by publishing an errata sheet),
+but ESS has not done so so far.
+
+Also, the chip only supports 24 bit addresses for recording,
+which means it cannot work on some Alpha mainboards.
+
+
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
 ALaw/uLaw sample formats
 ------------------------
 
@@ -45,4 +67,4 @@
 The card has an OPL compatible FM synthesizer.
 
 Thomas Sailer
-sailer@ife.ee.ethz.ch
+t.sailer@alumni.ethz.ch
diff -u --recursive --new-file v2.4.3/linux/Documentation/sound/sonicvibes linux/Documentation/sound/sonicvibes
--- v2.4.3/linux/Documentation/sound/sonicvibes	Fri Jul 10 14:03:35 1998
+++ linux/Documentation/sound/sonicvibes	Wed Apr 11 19:02:27 2001
@@ -1,3 +1,11 @@
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
 ALaw/uLaw sample formats
 ------------------------
 
@@ -70,4 +78,4 @@
 
 
 Thomas Sailer
-sailer@ife.ee.ethz.ch
+t.sailer@alumni.ethz.ch
diff -u --recursive --new-file v2.4.3/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.3/linux/MAINTAINERS	Sun Mar 25 18:14:20 2001
+++ linux/MAINTAINERS	Wed Apr 25 14:35:25 2001
@@ -106,6 +106,13 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+ACI MIXER DRIVER
+P:	Robert Siemer
+M:	Robert.Siemer@gmx.de
+L:	linux-sound@vger.kernel.org
+W:	http://www.uni-karlsruhe.de/~Robert.Siemer/Private/
+S:	Maintained
+
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
@@ -133,6 +140,11 @@
 M:	fizban@tin.it
 S:	Maintained
 
+AFFS FILE SYSTEM
+P:	Roman Zippel
+M:	zippel@linux-m68k.org
+S:	Maintained
+
 AHA152X SCSI DRIVER
 P:	Juergen E. Fischer
 M:	Juergen Fischer <fischer@norbit.de>
@@ -141,9 +153,9 @@
 
 APM DRIVER
 P:	Stephen Rothwell
-M:	apm@linuxcare.com.au
+M:	sfr@canb.auug.org.au
 L:	linux-laptop@vger.kernel.org
-W:	http://linuxcare.com.au/apm/
+W:	http://www.canb.auug.org.au/~sfr/
 S:	Supported
 
 APPLETALK NETWORK LAYER
@@ -293,6 +305,13 @@
 M:	jam@acm.org
 S:	Maintained
 
+CRIS PORT
+P:	Bjorn Wesen
+M:	bjornw@axis.com
+L:	dev-etrax@axis.com
+W:	http://developer.axis.com
+S:	Maintained
+
 CYBERPRO FB DRIVER
 P:	Russell King
 M:	linux@arm.linux.org.uk
@@ -368,7 +387,7 @@
 
 DIRECTORY NOTIFICATION
 P:	Stephen Rothwell
-M:	sfr@linuxcare.com.au
+M:	sfr@canb.auug.org.au
 L:	linux-kernel@vger.kernel.org
 S:	Supported
 
@@ -398,6 +417,12 @@
 L:	dri-devel@lists.sourceforge.net
 S:	Supported
 
+DSCC4 DRIVER
+P:	François Romieu
+M:	romieu@cogenit.fr
+M:	romieu@ensta.fr
+S:	Maintained
+
 EATA-DMA SCSI DRIVER
 P:	Michael Neuffer
 M:	mike@i-Connect.Net
@@ -490,6 +515,12 @@
 W:	http://www.icp-vortex.com/
 S:	Supported
 
+GENERIC HDLC DRIVER, N2 AND C101 DRIVERS
+P:	Krzysztof Halasa
+M:	khc@pm.waw.pl
+W:	http://hq.pm.waw.pl/hdlc/
+S:	Maintained
+
 HAYES ESP SERIAL DRIVER
 P:	Andrew J. Robinson
 M:	arobinso@nyx.net
@@ -535,7 +566,7 @@
 
 HIPPI
 P:	Jes Sorensen
-M:	Jes.Sorensen@cern.ch
+M:	jes@linuxcare.com
 L:	linux-hippi@sunsite.auc.dk
 S:	Maintained
 
@@ -600,7 +631,14 @@
 W:	http://www.kernel.dk
 S:	Maintained
 
-IDE/ATAPI TAPE/FLOPPY DRIVERS
+IDE/ATAPI FLOPPY DRIVERS
+P:	Paul Bristow
+M:	Paul Bristow <paul@paulbristow.net>
+W:	http://paulbristow.net/linux/idefloppy.html
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
+IDE/ATAPI TAPE DRIVERS
 P:	Gadi Oxman
 M:	Gadi Oxman <gadio@netvision.net.il>
 L:	linux-kernel@vger.kernel.org
@@ -750,14 +788,14 @@
 
 LINUX FOR POWER MACINTOSH
 P:	Paul Mackerras
-M:	paulus@linuxcare.com
+M:	paulus@samba.org
 W:	http://www.linuxppc.org/
 L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
 
 M68K
 P:	Jes Sorensen
-M:	Jes.Sorensen@cern.ch
+M:	jes@linuxcare.com
 W:	http://www.clark.net/pub/lawrencc/linux/index.html
 L:	linux-m68k@lists.linux-m68k.org
 S:	Maintained
@@ -775,7 +813,7 @@
 W:	http://www.tazenda.demon.co.uk/phil/linux-hp
 S:	Maintained
 
-MAESTRO PCI SOUND DRIVER
+MAESTRO PCI SOUND DRIVERS
 P:	Zach Brown
 M:	zab@zabbo.net
 S:	Odd Fixes
@@ -787,6 +825,12 @@
 L:	mtd@infradead.org
 S:	Maintained
 
+MICROTEK X6 SCANNER
+P:      Oliver Neukum
+M:      drivers@neukum.org
+W:      http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html
+S:      Maintained
+
 MIPS
 P:	Ralf Baechle
 M:	ralf@gnu.ai.mit.edu
@@ -837,10 +881,14 @@
 
 NETFILTER
 P:	Rusty Russell
-M:	rusty@linuxcare.com
+M:	rusty@rustcorp.com.au
 P:	Marc Boucher
 M:	marc@mbsi.ca
-W:	http://www.samba.org/netfilter/
+P:	James Morris
+M:	jamesm@intercode.com.au
+P:	Harald Welte
+M:	laforge@gnumonks.org
+W:	http://netfilter.samba.org
 W:	http://netfilter.kernelnotes.org
 W:	http://netfilter.filewatcher.org
 L:	netfilter@lists.samba.org
@@ -904,8 +952,9 @@
 NTFS FILESYSTEM
 P:	Anton Altaparmakov
 M:	aia21@cus.cam.ac.uk
+L:	linux-ntfs-dev@lists.sourceforge.net
 L:	linux-kernel@vger.kernel.org
-S:	Odd Fixes
+S:	Maintained
 
 NVIDIA (RIVA) FRAMEBUFFER DRIVER
 P:	Ani Joshi
@@ -917,9 +966,9 @@
 P:	Peter De Shrijver
 M:	p2@ace.ulyssis.sutdent.kuleuven.ac.be	
 P:	Mike Phillips
-M:	phillim@amtrak.com
+M:	mikep@linuxtr.net 
 L:	linux-net@vger.kernel.org
-L:	linux-tr@emissary.aus-etc.com
+L:	linux-tr@linuxtr.net
 W:	http://www.linuxtr.net
 S:	Maintained
 
@@ -997,7 +1046,7 @@
 
 PPP PROTOCOL DRIVERS AND COMPRESSORS
 P:	Paul Mackerras
-M:	paulus@linuxcare.com
+M:	paulus@samba.org
 L:	linux-ppp@vger.kernel.org
 S:	Maintained
 
@@ -1037,6 +1086,13 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+REISERFS FILE SYSTEM
+P:      Hans Reiser
+M:      reiserfs-dev@namesys.com
+L:      reiserfs-list@namesys.com
+W:      http://www.namesys.com
+S:      Supported
+
 ROSE NETWORK LAYER
 P:	Jean-Paul Roubelat
 M:	jpr@f6fbb.org
@@ -1056,6 +1112,14 @@
 W:	www.rtlinux.org
 S:	Maintained
 
+S390
+P:	Martin Schwidefsky
+M:	schwidefsky@de.ibm.com
+M:	linux390@de.ibm.com
+L:	linux-390@vm.marist.edu
+W:	http://oss.software.ibm.com/developerworks/opensource/linux390
+S:	Supported
+
 SA1100 SUPPORT
 P:	Nicolas Pitre
 M:	nico@cam.org
@@ -1174,6 +1238,11 @@
 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
 S:	Unsupported ?
@@ -1357,11 +1426,11 @@
 
 USB SERIAL KEYSPAN DRIVER
 P:	Hugh Blemings
-M:	hugh@linuxcare.com
+M:	hugh@misc.nu
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
-W:	http://www.linuxcare.com.au/hugh/keyspan.html
+W:	http://misc.nu/hugh/keyspan/
 
 USB SERIAL DRIVER
 P:	Greg Kroah-Hartman
@@ -1430,8 +1499,8 @@
 S:	Maintained for 2.2 only
 
 WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
-P:     Jaspreet Singh
-M:     jaspreet@sangoma.com
+P:     Nenad Corbic
+M:     ncorbic@sangoma.com
 M:     dm@sangoma.com
 W:     http://www.sangoma.com
 S:     Supported
@@ -1457,6 +1526,12 @@
 X86 3-LEVEL PAGING (PAE) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
+S:	Maintained
+
+YAM DRIVER FOR AX.25
+P:	Jean-Paul Roubelat
+M:	jpr@f6fbb.org
+L:	linux-hams@vger.kernel.org
 S:	Maintained
 
 Z85230 SYNCHRONOUS DRIVER
diff -u --recursive --new-file v2.4.3/linux/Makefile linux/Makefile
--- v2.4.3/linux/Makefile	Thu Mar 29 20:13:15 2001
+++ linux/Makefile	Mon Apr 23 15:29:21 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 3
-EXTRAVERSION =
+SUBLEVEL = 4
+EXTRAVERSION =-pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.4.3/linux/REPORTING-BUGS linux/REPORTING-BUGS
--- v2.4.3/linux/REPORTING-BUGS	Mon Aug 21 08:57:35 2000
+++ linux/REPORTING-BUGS	Fri Apr  6 10:42:48 2001
@@ -25,10 +25,9 @@
 overlook things, and easier for the developers to find the pieces of 
 information they're really interested in. Don't feel you have to follow it.
 
-   First run the ver_linux script included as scripts/ver_linux or
-at <URL:ftp://ftp.sai.msu.su/pub/Linux/ver_linux> It checks out
-the version of some important subsystems.  Run it with the command
-"sh scripts/ver_linux"
+      First run the ver_linux script included as scripts/ver_linux, which
+reports the version of some important subsystems.  Run this script with
+the command "sh scripts/ver_linux".
 
 Use that information to fill in all fields of the bug report form, and
 post it to the mailing list with a subject of "PROBLEM: <one line
diff -u --recursive --new-file v2.4.3/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.4.3/linux/arch/alpha/config.in	Fri Dec 29 14:07:19 2000
+++ linux/arch/alpha/config.in	Tue Apr 17 17:19:24 2001
@@ -5,6 +5,8 @@
 
 define_bool CONFIG_ALPHA y
 define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_name "Kernel configuration of Linux for Alpha machines"
 
diff -u --recursive --new-file v2.4.3/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.4.3/linux/arch/alpha/kernel/alpha_ksyms.c	Fri Mar  2 11:15:47 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Fri Apr 20 18:26:15 2001
@@ -173,9 +173,6 @@
 EXPORT_SYMBOL(down_interruptible);
 EXPORT_SYMBOL(down_trylock);
 EXPORT_SYMBOL(up);
-EXPORT_SYMBOL(__down_read_failed);
-EXPORT_SYMBOL(__down_write_failed);
-EXPORT_SYMBOL(__rwsem_wake);
 EXPORT_SYMBOL(down_read);
 EXPORT_SYMBOL(down_write);
 EXPORT_SYMBOL(up_read);
@@ -190,7 +187,6 @@
 EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL(flush_tlb_all);
 EXPORT_SYMBOL(flush_tlb_mm);
-EXPORT_SYMBOL(flush_tlb_page);
 EXPORT_SYMBOL(flush_tlb_range);
 EXPORT_SYMBOL(smp_imb);
 EXPORT_SYMBOL(cpu_data);
diff -u --recursive --new-file v2.4.3/linux/arch/alpha/kernel/semaphore.c linux/arch/alpha/kernel/semaphore.c
--- v2.4.3/linux/arch/alpha/kernel/semaphore.c	Sun Nov 12 19:31:11 2000
+++ linux/arch/alpha/kernel/semaphore.c	Tue Apr 17 17:19:24 2001
@@ -263,185 +263,3 @@
 #endif
 	__up(sem);
 }
-
-
-/*
- * RW Semaphores
- */
-
-void
-__down_read_failed(struct rw_semaphore *sem, int count)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
- retry_down:
-	if (count < 0) {
-		/* Waiting on multiple readers and/or writers.  */
-		
-		/* Undo the acquisition we started in down_read.  */
-		atomic_inc(&sem->count);
-
-		current->state = TASK_UNINTERRUPTIBLE;
-		wmb();
-		add_wait_queue(&sem->wait, &wait);
-		mb();
-		while (atomic_read(&sem->count) < 0) {
-			schedule();
-			set_task_state(current, TASK_UNINTERRUPTIBLE);
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		current->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_dec_return(&sem->count);
-		if (count <= 0)
-			goto retry_down;
-	} else {
-		/* Waiting on exactly one writer.  */
-
-		current->state = TASK_UNINTERRUPTIBLE;
-		wmb();
-		add_wait_queue(&sem->wait, &wait);
-		mb();
-
-		while (!test_and_clear_bit(0, &sem->granted)) {
-			schedule();
-			set_task_state(current, TASK_UNINTERRUPTIBLE);
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		current->state = TASK_RUNNING;
-	}
-}
-
-void
-__down_write_failed(struct rw_semaphore *sem, int count)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
- retry_down:
-	if (count + RW_LOCK_BIAS < 0) {
-		/* Waiting on multiple readers and/or writers.  */
-
-		/* Undo the acquisition we started in down_write.  */
-		atomic_add(RW_LOCK_BIAS, &sem->count);
-
-		current->state = TASK_UNINTERRUPTIBLE;
-		wmb();
-		add_wait_queue_exclusive(&sem->wait, &wait);
-		mb();
-	
-		while (atomic_read(&sem->count) + RW_LOCK_BIAS < 0) {
-			schedule();
-			set_task_state(current, TASK_UNINTERRUPTIBLE);
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		current->state = TASK_RUNNING;
-
-		count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-		if (count != 0)
-			goto retry_down;
-	} else {
-		/* Waiting on exactly one writer.  */
-
-		current->state = TASK_UNINTERRUPTIBLE;
-		wmb();
-		add_wait_queue_exclusive(&sem->wait, &wait);
-		mb();
-
-		while (!test_and_clear_bit(1, &sem->granted)) {
-			schedule();
-			set_task_state(current, TASK_UNINTERRUPTIBLE);
-		}
-
-		remove_wait_queue(&sem->write_bias_wait, &wait);
-		current->state = TASK_RUNNING;
-
-		/* If the lock is currently unbiased, awaken the sleepers.
-		   FIXME: This wakes up the readers early in a bit of a
-		   stampede -> bad!  */
-		count = atomic_read(&sem->count);
-		if (__builtin_expect(count >= 0, 0))
-			wake_up(&sem->wait);
-	}
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, int readers)
-{
-	if (readers) {
-		if (test_and_set_bit(0, &sem->granted))
-			BUG();
-		wake_up(&sem->wait);
-	} else {
-		if (test_and_set_bit(1, &sem->granted))
-			BUG();
-		wake_up(&sem->write_bias_wait);
-	}
-}
-
-void
-down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-	__down_read(sem);
-#if WAITQUEUE_DEBUG
-	if (sem->granted & 2)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-void
-down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-	__down_write(sem);
-#if WAITQUEUE_DEBUG
-	if (sem->granted & 3)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-void
-up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-	if (sem->granted & 2)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-void
-up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-	if (sem->granted & 3)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.4.3/linux/arch/alpha/mm/init.c	Tue Nov 28 22:43:39 2000
+++ linux/arch/alpha/mm/init.c	Fri Apr 13 20:26:06 2001
@@ -43,20 +43,6 @@
 struct pgtable_cache_struct quicklists;
 #endif
 
-void
-__bad_pmd(pgd_t *pgd)
-{
-	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-	pgd_set(pgd, BAD_PAGETABLE);
-}
-
-void
-__bad_pte(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-}
-
 pgd_t *
 get_pgd_slow(void)
 {
@@ -80,66 +66,26 @@
 	return ret;
 }
 
-pmd_t *
-get_pmd_slow(pgd_t *pgd, unsigned long offset)
-{
-	pmd_t *pmd;
-
-	pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-	if (pgd_none(*pgd)) {
-		if (pmd) {
-			clear_page((void *)pmd);
-			pgd_set(pgd, pmd);
-			return pmd + offset;
-		}
-		pgd_set(pgd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)pmd);
-	if (pgd_bad(*pgd)) {
-		__bad_pmd(pgd);
-		return NULL;
-	}
-	return (pmd_t *) pgd_page(*pgd) + offset;
-}
-
-pte_t *
-get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page((void *)pte);
-			pmd_set(pmd, pte);
-			return pte + offset;
-		}
-		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
-        if(pgtable_cache_size > high) {
-                do {
-                        if(pgd_quicklist)
-                                free_pgd_slow(get_pgd_fast()), freed++;
-                        if(pmd_quicklist)
-                                free_pmd_slow(get_pmd_fast()), freed++;
-                        if(pte_quicklist)
-                                free_pte_slow(get_pte_fast()), freed++;
-                } while(pgtable_cache_size > low);
-        }
-        return freed;
+	if(pgtable_cache_size > high) {
+		do {
+			if(pgd_quicklist) {
+				free_pgd_slow(get_pgd_fast());
+				freed++;
+			}
+			if(pmd_quicklist) {
+				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+				freed++;
+			}
+			if(pte_quicklist) {
+				pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed++;
+			}
+		} while(pgtable_cache_size > low);
+	}
+	return freed;
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.4.3/linux/arch/arm/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/Makefile	Thu Apr 12 12:20:31 2001
@@ -1,52 +1,36 @@
 #
 # arch/arm/Makefile
 #
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
-#
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 1995-2000 by Russell King
+# Copyright (C) 1995-2001 by Russell King
 
 LINKFLAGS	:=-p -X -T arch/arm/vmlinux.lds
 GZFLAGS		:=-9
 CFLAGS		+=-fno-common -pipe
 
-ifdef CONFIG_FRAME_POINTER
+ifneq ($(CONFIG_NO_FRAME_POINTER),y)
 CFLAGS		:=$(CFLAGS:-fomit-frame-pointer=)
 endif
 
-ifdef CONFIG_DEBUG_INFO
+ifeq ($(CONFIG_DEBUG_INFO),y)
 CFLAGS		+=-g
 endif
 
-# Ensure this is ld "2.9.4" or later
-NEW_LINKER	:= $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?)
-
-ifneq ($(NEW_LINKER),0)
-dummy:;		@echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.'
-		@echo '*** Please upgrade your binutils to 2.9.5.'
-		@false
-endif
-
 # Select CPU dependent flags.  Note that order of declaration is important;
 # the options further down the list override previous items.
 #
-apcs-$(CONFIG_CPU_26)		:=-mapcs-26 -mcpu=arm3 -Os
-apcs-$(CONFIG_CPU_32)		:=-mapcs-32
+apcs-y				:=
+apcs-$(CONFIG_CPU_26)		:=-mcpu=arm3 -Os
 
-arch-$(CONFIG_CPU_32v3)		:=-march=armv3
+arch-y				:=
+arch-$(CONFIG_CPU_32v3)		:=-march=armv3m
 arch-$(CONFIG_CPU_32v4)		:=-march=armv4
 arch-$(CONFIG_CPU_32v5)		:=-march=armv5
 
-proc-$(CONFIG_CPU_32v3)		:=-marmv3m
-proc-$(CONFIG_CPU_32v4)		:=-marmv4
-proc-$(CONFIG_CPU_32v5)		:=-marmv5
-
+tune-y				:=
 tune-$(CONFIG_CPU_ARM610)	:=-mtune=arm610
 tune-$(CONFIG_CPU_ARM710)	:=-mtune=arm710
 tune-$(CONFIG_CPU_ARM720T)	:=-mtune=arm7tdmi
@@ -54,19 +38,27 @@
 tune-$(CONFIG_CPU_SA110)	:=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)	:=-mtune=strongarm1100
 
-CFLAGS		+= $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
-AFLAGS		+= $(apcs-y) $(proc-y) -mno-fpu
+CFLAGS		+= -mapcs-32 $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
+AFLAGS		+= -mapcs-32 $(apcs-y) $(arch-y) -mno-fpu
 
 LIBGCC		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
 
 ifeq ($(CONFIG_CPU_26),y)
 PROCESSOR	 = armo
-TEXTADDR	 = 0x02080000
+  ifeq ($(CONFIG_ROM_KERNEL),y)
+    DATAADDR	 = 0x02080000
+    TEXTADDR	 = 0x03800000
+    LDSCRIPT	 = arch/arm/vmlinux-armo-rom.lds.in
+  else
+    TEXTADDR	 = 0x02080000
+    LDSCRIPT	 = arch/arm/vmlinux-armo.lds.in
+  endif
 endif
 
 ifeq ($(CONFIG_CPU_32),y)
 PROCESSOR	 = armv
 TEXTADDR	 = 0xC0008000
+LDSCRIPT	 = arch/arm/vmlinux-armv.lds.in
 endif
 
 ifeq ($(CONFIG_ARCH_ARCA5K),y)
@@ -97,8 +89,13 @@
 INCDIR		 = ebsa285
 endif
 
-ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
-MACHINE		 = nexuspci
+ifeq ($(CONFIG_ARCH_FTVPCI),y)
+MACHINE		 = ftvpci
+INCDIR		 = nexuspci
+endif
+
+ifeq ($(CONFIG_ARCH_TBOX),y)
+MACHINE		 = tbox
 endif
 
 ifeq ($(CONFIG_ARCH_SHARK),y)
@@ -134,6 +131,10 @@
 INCDIR		:= $(MACHINE)
 endif
 
+ifeq ($(origin DATAADDR), undefined)
+DATAADDR	:= .
+endif
+
 # If we have a machine-specific directory, then include it in the build.
 MACHDIR		:= arch/arm/mach-$(MACHINE)
 ifeq ($(MACHDIR),$(wildcard $(MACHDIR)))
@@ -143,13 +144,17 @@
 
 HEAD		:= arch/arm/kernel/head-$(PROCESSOR).o \
 		   arch/arm/kernel/init_task.o
-SUBDIRS		+= arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe
+SUBDIRS		+= arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe \
+		   arch/arm/fastfpe
 CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
-LIBS		:= arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC)
+LIBS		:= arch/arm/lib/lib.a $(LIBS) $(LIBGCC)
 
-ifeq ($(CONFIG_NWFPE),y)
+ifeq ($(CONFIG_FPE_NWFPE),y)
 LIBS		:= arch/arm/nwfpe/math-emu.o $(LIBS)
 endif
+ifeq ($(CONFIG_FPE_FASTFPE),y)
+LIBS		:= arch/arm/fastfpe/fast-math-emu.o $(LIBS)
+endif
 
 ifeq ($(CONFIG_ARCH_CLPS7500),y)
 SUBDIRS		+= drivers/acorn/char
@@ -157,21 +162,13 @@
 endif
 
 MAKEBOOT	 = $(MAKE) -C arch/$(ARCH)/boot
+MAKETOOLS	 = $(MAKE) -C arch/$(ARCH)/tools
 
 # The following is a hack to get 'constants.h' up
 # to date before starting compilation
 
-$(patsubst %, _dir_%, $(SUBDIRS)) init/main.o init/version.o : \
-	include/asm-arm/mach-types.h
-
-$(patsubst %, _dir_%, $(SUBDIRS)) : constants
-
-include/asm-arm/mach-types.h: arch/arm/tools/mach-types  \
-			      arch/arm/tools/gen-mach-types
-	@awk -f arch/arm/tools/gen-mach-types arch/arm/tools/mach-types > $@
-
-constants: dummy
-	@$(MAKE) -C arch/arm/lib constants.h
+$(patsubst %,_dir_%, $(SUBDIRS)): maketools
+$(patsubst %,_modsubdir_%,$(MOD_DIRS)): maketools
 
 symlinks: archsymlinks
 
@@ -181,8 +178,8 @@
 
 vmlinux: arch/arm/vmlinux.lds
 
-arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy
-	@sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@
+arch/arm/vmlinux.lds: $(LDSCRIPT) dummy
+	@sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@
 
 arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
 	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
@@ -190,17 +187,42 @@
 bzImage zImage zinstall Image bootpImage install: vmlinux
 	@$(MAKEBOOT) $@
 
+CLEAN_FILES	+= \
+	arch/arm/vmlinux.lds
+
+MRPROPER_FILES	+= \
+	include/asm-arm/arch \
+	include/asm-arm/proc \
+	include/asm-arm/constants.h* \
+	include/asm-arm/mach-types.h
+
+# We use MRPROPER_FILES and CLEAN_FILES now
 archmrproper:
-	$(RM) include/asm-arm/arch include/asm-arm/proc
+	@/bin/true
 
 archclean:
 	@$(MAKEBOOT) clean
-	$(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds
-	$(RM) include/asm-arm/mach-types.h
 
-archdep: archsymlinks
+archdep: scripts/mkdep archsymlinks
+	@$(MAKETOOLS) dep
 	@$(MAKEBOOT) dep
 
+maketools: checkbin
+	@$(MAKETOOLS) all
+
+# Ensure this is ld "2.9.4" or later
+NEW_LINKER	:= $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?)
+
+ifneq ($(NEW_LINKER),0)
+checkbin:
+	@echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.'
+	@echo '*** Please upgrade your binutils to 2.9.5.'
+	@false
+else
+checkbin:
+	@true
+endif
+
 # My testing targets (that short circuit a few dependencies)
 zImg:;	@$(MAKEBOOT) zImage
 Img:;	@$(MAKEBOOT) Image
@@ -211,15 +233,7 @@
 #
 # Configuration targets.  Use these to select a
 # configuration for your architecture
-CFGS=	a5k_config		ebsa110_config		\
-	footbridge_config	rpc_config		\
-	brutus_config		victor_config		\
-	empeg_config		graphicsclient_config	\
-	assabet_config		lart_config		\
-	cerf_config		lusl7200_config 	\
-	sherman_config		pangolin_config
-
-$(CFGS):
+%_config:
 	@( \
 	CFG=$(@:_config=); \
 	if [ -f arch/arm/def-configs/$$CFG ]; then \
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile
--- v2.4.3/linux/arch/arm/boot/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/Makefile	Thu Apr 12 12:03:50 2001
@@ -55,8 +55,7 @@
 endif
 
 ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
-ZTEXTADDR	 = 0x40200000
-ZRELADDR	 = 0x40008000
+ZTEXTADDR	 = 0x40008000
 endif
 
 ifeq ($(CONFIG_ARCH_L7200),y)
@@ -72,7 +71,6 @@
 
 ifeq ($(CONFIG_ARCH_P720T),y)
 ZTEXTADDR	 = 0xc0018000
-ZRELADDR	 = 0xc0018000
 PARAMS_PHYS	 = 0xc0000100
 INITRD_PHYS	 = 0xc0400000
 INITRD_VIRT	 = 0xc0400000
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
--- v2.4.3/linux/arch/arm/boot/compressed/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/compressed/Makefile	Thu Apr 12 12:03:50 2001
@@ -9,7 +9,7 @@
 
 HEAD		 = head.o
 OBJS		 = misc.o
-CFLAGS		 = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC)
+CFLAGS		 = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) -msoft-float
 FONTC		 = $(TOPDIR)/drivers/video/font_acorn_8x8.c
 ZLDFLAGS	 = -p -X -T vmlinux.lds
 
@@ -25,16 +25,24 @@
 OBJS		+= head-netwinder.o
 endif
 
+ifeq ($(CONFIG_ARCH_SHARK),y)
+OBJS		+= head-shark.o ofw-shark.o
+endif
+
 ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
 OBJS		+= head-netwinder.o
 endif
 
-ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
-HEAD		 = head-nexuspci.o
+ifeq ($(CONFIG_ARCH_FTVPCI),y)
+OBJS		+= head-ftvpci.o
 endif
 
 ifeq ($(CONFIG_ARCH_L7200),y)
 OBJS		+= head-l7200.o
+endif
+
+ifeq ($(CONFIG_ARCH_CLPS7500),y)
+HEAD		= head-clps7500.o
 endif
 
 ifeq ($(CONFIG_ARCH_P720T),y)
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/head-clps7500.S linux/arch/arm/boot/compressed/head-clps7500.S
--- v2.4.3/linux/arch/arm/boot/compressed/head-clps7500.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/boot/compressed/head-clps7500.S	Thu Apr 12 12:03:50 2001
@@ -0,0 +1,87 @@
+/*
+ * linux/arch/arm/boot/compressed/head.S
+ *
+ * Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd
+ */
+
+#include <linux/config.h>
+
+		/* There are three different ways the kernel can be
+		   booted on a 7500 system: from Angel (loaded in RAM), from
+		   16-bit ROM or from 32-bit Flash.  Luckily, a single kernel
+		   image does for them all. */
+		/* This branch is taken if the CPU memory width matches the
+		   actual device in use.  The default at power on is 16 bits
+		   so we must be prepared for a mismatch. */
+		.section ".start", #alloc, #execinstr
+2:
+		b	1f
+		.word	0xffff
+		.word	0xb632		@ mov r11, #0x03200000
+		.word	0xe3a0
+		.word	0x0000		@ mov r0, #0
+		.word	0xe3a0
+		.word	0x0080		@ strb r0, [r11, #0x80]
+		.word	0xe5cb
+		.word	0xf000		@ mov pc, #0
+		.word	0xe3a0
+1:
+		adr	r1, 2b
+		teq	r1, #0
+		bne	.Langel
+		/* This is a direct-from-ROM boot.  Copy the kernel into 
+		   RAM and run it there. */
+		mov	r0, #0x30
+		mcr	p15, 0, r0, c1, c0, 0
+		mov	r0, #0x13
+		msr	cpsr, r0
+		mov	r12, #0x03000000	@ point to LEDs
+		orr	r12, r12, #0x00020000
+		orr	r12, r12, #0xba00
+		mov	r0, #0x5500
+		str	r0, [r12]
+		mov	r0, #0x10000000
+		orr	r0, r0, #0x8000
+		mov	r4, r0
+		ldr	r2, =_end
+2:
+		ldr	r3, [r1], #4
+		str	r3, [r0], #4
+		teq	r0, r2
+		bne	2b
+		mov	r0, #0xff00
+		str	r0, [r12]
+1:	
+		mov	r12, #0x03000000	@ point to LEDs
+		orr	r12, r12, #0x00020000
+		orr	r12, r12, #0xba00
+		mov	r0, #0xfe00
+		str	r0, [r12]
+
+		adr	lr, 1f
+		mov	r0, #0
+		mov	r1, #14		/* MACH_TYPE_CLPS7500 */
+		mov	pc, lr
+.Langel:
+#ifdef CONFIG_ANGELBOOT
+		/* Call Angel to switch into SVC mode. */
+		mov	r0, #0x17
+		swi	0x123456
+#endif
+		/* Ensure all interrupts are off and MMU disabled */
+		mrs	r0, cpsr
+		orr	r0, r0, #0xc0
+		msr	cpsr, r0
+
+		adr	lr, 1b
+		orr	lr, lr, #0x10000000
+		mov	r0, #0x30		@ MMU off
+		mcr	p15, 0, r0, c1, c0, 0
+		mov	r0, r0
+	 	mov	pc, lr
+
+		.ltorg
+
+1:
+/* And the rest */
+#include "head.S"
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/head-shark.S linux/arch/arm/boot/compressed/head-shark.S
--- v2.4.3/linux/arch/arm/boot/compressed/head-shark.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/compressed/head-shark.S	Thu Apr 12 12:03:50 2001
@@ -1,5 +1,5 @@
 /* The head-file for the Shark
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * Does the following:
  * - get the memory layout from firmware. This can only be done as long as the mmu
@@ -20,8 +20,6 @@
 
 		b	__beginning
 	
-__serial_addr:	.long	0xf7eff3f8
-		.long	0				@ space
 __ofw_data:	.long	0				@ the number of memory blocks
 		.space  128				@ (startaddr,size) ...
 		.space  128				@ bootargs
@@ -31,14 +29,10 @@
 
 		mov	r0, #0xC0			@ disable irq and fiq
 		mov	r1, r0
-		mrs	r3, cpsr_all
+		mrs	r3, cpsr
 		bic	r2, r3, r0
 		eor	r2, r2, r1
-		msr	cpsr_all, r2
-
-		ldr	r0, __serial_addr		@ disable serial interrupt
-		mov	r1, #0				@ hangs the machine, I don t know why.
-		strb	r1, [r0, #0x01]
+		msr	cpsr_c, r2
 
 		mov	r0, r4				@ get the Memory layout from firmware
 		adr	r1, __ofw_data
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S
--- v2.4.3/linux/arch/arm/boot/compressed/head.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/compressed/head.S	Thu Apr 12 12:03:50 2001
@@ -87,7 +87,8 @@
 
 		b	1f
 		.word	0x016f2818		@ Magic numbers to help the loader
-		.word	start	
+		.word	start			@ absolute load/run zImage address
+		.word	_edata			@ zImage end address
 1:		mov	r7, r1			@ save architecture ID
 		mov	r8, #0			@ save r0
 #ifdef CONFIG_ANGELBOOT
@@ -210,7 +211,7 @@
 		mov	r0, r3
 		mov	r8, r0, lsr #18
 		mov	r8, r8, lsl #18		@ start of RAM
-		add	r9, r8, #0x20000000	@ the maximum RAM size
+		add	r9, r8, #0x10000000	@ a reasonable RAM size
 		mov	r1, #0x12
 		orr	r1, r1, #3 << 10
 		add	r2, r3, #16384
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/ll_char_wr.S linux/arch/arm/boot/compressed/ll_char_wr.S
--- v2.4.3/linux/arch/arm/boot/compressed/ll_char_wr.S	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/boot/compressed/ll_char_wr.S	Thu Apr 12 12:03:50 2001
@@ -16,7 +16,7 @@
 @ Regs: [] = corruptible
 @       {} = used
 @       () = do not use
-#define __ASSEMBLY__
+
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 		.text
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/ofw-shark.c linux/arch/arm/boot/compressed/ofw-shark.c
--- v2.4.3/linux/arch/arm/boot/compressed/ofw-shark.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/compressed/ofw-shark.c	Thu Apr 12 12:03:50 2001
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/boot/compressed/ofw-shark.c
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * This file is used to get some basic information
  * about the memory layout of the shark we are running
@@ -11,6 +11,7 @@
 
 
 #include <linux/kernel.h>
+#include <linux/types.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 
@@ -18,7 +19,7 @@
 asmlinkage void
 create_params (unsigned long *buffer)
 {
-	/* Is there a better address? Also change in kernel/arch.c */
+	/* Is there a better address? Also change in mach-shark/arch.c */
 	struct param_struct *params = (struct param_struct *) 0x08003000;
 	int j,i,m,k,nr_banks,size;
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S
--- v2.4.3/linux/arch/arm/boot/compressed/setup-sa1100.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/boot/compressed/setup-sa1100.S	Thu Apr 12 12:03:50 2001
@@ -24,6 +24,9 @@
 PPC_BASE:	.long	0x90060000
 #define PPAR	0x08
 
+IC_BASE:	.long	0x90050000
+#define ICMR	0x04
+
 UART1_BASE:	.long	0x80010000
 UART3_BASE:	.long	0x80050000
 #define UTCR0           0x00
@@ -52,6 +55,11 @@
 ENTRY(sa1100_setup)
 		mov	r3, r0			@ keep machine type in r3
 
+		@ Clear all interrupt sources
+		ldr	r0, IC_BASE
+		mov	r1, #0
+		str	r1, [r0, #ICMR]
+
 @ Read System Configuration "Register" for Assabet.
 @ (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
 @ User's Guide," p.4-9)
@@ -87,6 +95,7 @@
 		@ Initialize UART (if bootloader has not done it yet)...
 		teq	r3, #MACH_TYPE_BRUTUS
 		teqne	r3, #MACH_TYPE_ASSABET
+		teqne	r3, #MACH_TYPE_GRAPHICSCLIENT
 		bne	skip_uart
 
 		@ UART3 if Assabet is used with Neponset
@@ -95,6 +104,11 @@
 		ldreq	r0, UART3_BASE
 		beq	uart_init
 
+		@ UART3 on GraphicsClient
+		teq	r3, #MACH_TYPE_GRAPHICSCLIENT
+		ldreq	r0, UART3_BASE
+		beq	uart_init
+
 		@ At least for Brutus, the UART1 is used through
 		@ the alternate GPIO function...
 		teq	r3, #MACH_TYPE_BRUTUS
@@ -115,7 +129,8 @@
 
 uart1:		ldr	r0, UART1_BASE
 
-uart_init:	ldr	r1, [r0, #UTSR1]
+uart_init:
+1:		ldr	r1, [r0, #UTSR1]
 		tst	r1, #1<<0		@ TBY
 		bne	1b
 		mov	r1, #0
diff -u --recursive --new-file v2.4.3/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.4.3/linux/arch/arm/config.in	Fri Feb  9 11:38:27 2001
+++ linux/arch/arm/config.in	Tue Apr 17 17:19:24 2001
@@ -9,6 +9,8 @@
 define_bool CONFIG_SBUS n
 define_bool CONFIG_MCA n
 define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 
 mainmenu_option next_comment
@@ -21,10 +23,8 @@
 mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
-fi
+dep_bool '  Set version information on all module symbols' CONFIG_MODVERSIONS $CONFIG_MODULES
+dep_bool '  Kernel module loader' CONFIG_KMOD $CONFIG_MODULES
 endmenu
 
 
@@ -36,71 +36,62 @@
 	 Cirrus-CL-PS7500FE     CONFIG_ARCH_CLPS7500 \
 	 Co-EBSA285		CONFIG_ARCH_CO285 \
 	 EBSA-110		CONFIG_ARCH_EBSA110 \
+	 LinkUp-L7200		CONFIG_ARCH_L7200 \
 	 FootBridge		CONFIG_ARCH_FOOTBRIDGE \
 	 Integrator		CONFIG_ARCH_INTEGRATOR \
 	 RiscPC			CONFIG_ARCH_RPC \
- 	 SA1100-based		CONFIG_ARCH_SA1100" RiscPC
-
-# the following are placeholders for when they are fully integrated
-#	 LinkUp-L7200		CONFIG_ARCH_L7200
+ 	 SA1100-based		CONFIG_ARCH_SA1100 \
+ 	 CLPS711x/EP721x-based	CONFIG_ARCH_CLPS711X" RiscPC
 
 mainmenu_option next_comment
 comment 'Archimedes/A5000 Implementations'
-if [ "$CONFIG_ARCH_ARCA5K" = "y" ]; then
-   # These architectures will be combined.  However, until this
-   # is complete...  Note that the ARC will take precidence over
-   # A5K
-   comment 'Archimedes/A5000 Implementations (select only ONE)'
-
-   bool '  Archimedes' CONFIG_ARCH_ARC
-   bool '  A5000' CONFIG_ARCH_A5K
-fi
+# These architectures will be combined.  However, until this
+# is complete...  Note that the ARC will take precedence over
+# A5K
+comment 'Archimedes/A5000 Implementations (select only ONE)'
+dep_bool '  Archimedes' CONFIG_ARCH_ARC $CONFIG_ARCH_ARCA5K
+dep_bool '  A5000' CONFIG_ARCH_A5K $CONFIG_ARCH_ARCA5K
 endmenu
 
 mainmenu_option next_comment
 comment 'Footbridge Implementations'
-if [ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then
-   bool '  CATS' CONFIG_ARCH_CATS
-   bool '  Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER
-   bool '  EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN
-   bool '  EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST
-   bool '  NetWinder' CONFIG_ARCH_NETWINDER
-fi
+dep_bool '  CATS' CONFIG_ARCH_CATS $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  NetWinder' CONFIG_ARCH_NETWINDER $CONFIG_ARCH_FOOTBRIDGE
 endmenu
 
 mainmenu_option next_comment
 comment 'SA11x0 Implementations'
-if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
-
-   bool '  Assabet' CONFIG_SA1100_ASSABET
-   if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then
-      bool '    Include support for Neponset' CONFIG_ASSABET_NEPONSET
-   fi
-   bool '  Brutus' CONFIG_SA1100_BRUTUS
-   bool '  CerfBoard' CONFIG_SA1100_CERF
-   bool '  Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY
-#   bool '  Empeg' CONFIG_SA1100_EMPEG
-#   bool '  Itsy' CONFIG_SA1100_ITSY
-   bool '  LART' CONFIG_SA1100_LART
-#   bool '  PLEB' CONFIG_SA1100_PLEB
-   bool '  ThinClient' CONFIG_SA1100_THINCLIENT
-   bool '  GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT
-   bool '  nanoEngine' CONFIG_SA1100_NANOENGINE
-   bool '  Victor' CONFIG_SA1100_VICTOR
-#   bool '  Tifon' CONFIG_SA1100_TIFON
-   bool '  XP860' CONFIG_SA1100_XP860
-
-   # Someday, we'll support this as a general option.
-   bool '  Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT
-
-   # Determine if SA1111 support is required
-   if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
-	"$CONFIG_SA1100_XP860" = "y" ]; then
-      define_bool CONFIG_SA1111 y
-   fi
+dep_bool '  Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100
+dep_bool '    Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET
+dep_bool '  Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100
+dep_bool '  CerfBoard' CONFIG_SA1100_CERF $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY $CONFIG_ARCH_SA1100
+#dep_bool '  Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100
+#dep_bool '  Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100
+dep_bool '  LART' CONFIG_SA1100_LART $CONFIG_ARCH_SA1100
+#dep_bool '  PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100
+dep_bool '  GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100
+dep_bool '  nanoEngine' CONFIG_SA1100_NANOENGINE $CONFIG_ARCH_SA1100
+dep_bool '  Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100
+dep_bool '  Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100
+dep_bool '  XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100
+dep_bool '  Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100
+
+# Determine if SA1111 support is required
+if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
+     "$CONFIG_SA1100_XP860" = "y" ]; then
+   define_bool CONFIG_SA1111 y
 fi
 endmenu
 
+mainmenu_option next_comment
+comment 'CLPS711X/EP721X Implementations'
+dep_bool '  P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X
+endmenu
+
 # Definitions to make life easier
 if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \
      "$CONFIG_ARCH_RPC" = "y" ]; then
@@ -147,49 +138,77 @@
 
 comment 'Processor Type'
 
-# Select CPU and optimisation dependent on architecture
-if [ "$CONFIG_ARCH_RPC" = "y" ]; then
+# Firstly, figure out what processor architecture version we should be using.
+if [ "$CONFIG_ARCH_RPC"        = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
    define_bool CONFIG_CPU_32v3 y
-   bool 'Support ARM610 processor' CONFIG_CPU_ARM6
-   bool 'Support ARM710 processor' CONFIG_CPU_ARM7
-   bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110
+else
+   define_bool CONFIG_CPU_32v3 n
 fi
-if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
-     "$CONFIG_FOOTBRIDGE" = "y" -o \
-     "$CONFIG_ARCH_TBOX" = "y" -o \
-     "$CONFIG_ARCH_SHARK" = "y" -o \
-     "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
+if [ "$CONFIG_ARCH_EBSA110"    = "y" -o "$CONFIG_FOOTBRIDGE"    = "y" -o \
+     "$CONFIG_ARCH_TBOX"       = "y" -o "$CONFIG_ARCH_SHARK"    = "y" -o \
+     "$CONFIG_ARCH_NEXUSPCI"   = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \
+     "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100"   = "y" -o \
+     "$CONFIG_ARCH_L7200"      = "y" ]; then
    define_bool CONFIG_CPU_32v4 y
-   define_bool CONFIG_CPU_SA110 y
+else
+   define_bool CONFIG_CPU_32v4 n
 fi
+
+# Select CPU types depending on the architecture selected.
+# We use this to select which CPUs are supported, and to select
+# the compiler tuning options.
+
+# ARM610
+if [ "$CONFIG_ARCH_RPC" = "y" ]; then
+   bool 'Support ARM610 processor' CONFIG_CPU_ARM610
+else
+   define_bool CONFIG_CPU_ARM610 n
+fi
+
+# ARM710
 if [ "$CONFIG_ARCH_CLPS7500" = "y" ]; then
-   define_bool CONFIG_CPU_32v3 y
-   define_bool CONFIG_CPU_ARM7 y
+   define_bool CONFIG_CPU_ARM710 y
+else
+   if [ "$CONFIG_ARCH_RPC" = "y" ]; then
+      bool 'Support ARM710 processor' CONFIG_CPU_ARM710
+   else
+      define_bool CONFIG_CPU_ARM710 n
+   fi
 fi
-if [ "$CONFIG_ARCH_L7200" = "y" ]; then
-   define_bool CONFIG_CPU_32v4 y
-   define_bool CONFIG_CPU_ARM720 y
+
+# ARM720T
+if [ "$CONFIG_ARCH_CLPS711X" = "y" -o "$CONFIG_ARCH_L7200" = "y" ]; then
+   define_bool CONFIG_CPU_ARM720T y
+else
+   if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+      bool 'Support ARM720T processor' CONFIG_CPU_ARM720T
+   else
+      define_bool CONFIG_CPU_ARM720T n
+   fi
 fi
+
+# ARM920T
 if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
-   define_bool CONFIG_CPU_32v4 y
-   bool 'Support ARM720 processor' CONFIG_CPU_ARM720
-   bool 'Support ARM920 processor' CONFIG_CPU_ARM920
-#   bool 'Support ARM10 processor' CONFIG_CPU_ARM10
-fi
-if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
-   define_bool CONFIG_CPU_32v4 y
-   define_bool CONFIG_CPU_SA1100 y
+   bool 'Support ARM920T processor' CONFIG_CPU_ARM920T
+else
+   define_bool CONFIG_CPU_ARM920T n
 fi
-
-if [ "$CONFIG_CPU_ARM920" = "y" ]; then
-   bool '  ARM920 CPU idle' CONFIG_CPU_ARM920_CPU_IDLE
-   bool '  ARM920 I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON
-   bool '  ARM920 D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON
+if [ "$CONFIG_CPU_ARM920T" = "y" ]; then
+   bool '  ARM920T CPU idle' CONFIG_CPU_ARM920_CPU_IDLE
+   bool '  ARM920T I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON
+   bool '  ARM920T D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON
    if [ "$CONFIG_CPU_ARM920_D_CACHE_ON" = "y" ] ; then
-      bool '  Force write through caches on ARM920' CONFIG_CPU_ARM920_WRITETHROUGH
+      bool '  Force write through caches on ARM920T' CONFIG_CPU_ARM920_WRITETHROUGH
    fi
 fi
-#if [ "$CONFIG_CPU_ARM10" = "y" ]; then
+
+# ARM1020
+#if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+#   bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020
+#else
+    define_bool CONFIG_CPU_ARM1020 n
+#fi
+#if [ "$CONFIG_CPU_ARM1020" = "y" ]; then
 #   bool '  ARM10 I-Cache on' CONFIG_CPU_ARM10_I_CACHE_ON
 #   bool '  ARM10 D-Cache on' CONFIG_CPU_ARM10_D_CACHE_ON
 #   if [ "$CONFIG_CPU_ARM10_D_CACHE_ON" = "y" ] ; then
@@ -197,6 +216,30 @@
 #   fi
 #fi
 
+# SA110
+if [ "$CONFIG_ARCH_EBSA110"  = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \
+     "$CONFIG_ARCH_TBOX"     = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \
+     "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
+   define_bool CONFIG_CPU_SA110 y
+else
+   if [ "$CONFIG_ARCH_RPC" = "y" ]; then
+      bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110
+   else
+      define_bool CONFIG_CPU_SA110 n
+   fi
+fi
+
+# SA1100
+if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+   define_bool CONFIG_CPU_SA1100 y
+else
+   define_bool CONFIG_CPU_SA1100 n
+fi
+
+#if [ "$CONFIG_CPU_32" = "y" ]; then
+#   bool 'Support Thumb instructions' CONFIG_ARM_THUMB
+#fi
+
 # Select various configuration options depending on the machine type
 if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
    define_bool CONFIG_DISCONTIGMEM y
@@ -209,8 +252,12 @@
 mainmenu_option next_comment
 comment 'General setup'
 
+comment 'Please ensure that you have read the help on the next option'
+bool 'Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT
+
 # Now handle the bus types
-if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
+if [ "$CONFIG_ARCH_FTVPCI" = "y" -o \
+     "$CONFIG_ARCH_SHARK" = "y" -o \
      "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then
    define_bool CONFIG_PCI y
 else
@@ -223,21 +270,19 @@
 fi
 
 if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
-     "$CONFIG_ARCH_SHARK" = "y" ]; then
+     "$CONFIG_ARCH_SHARK" = "y" -o \
+     "$CONFIG_ARCH_CLPS7500" = "y" -o \
+     "$CONFIG_ARCH_EBSA110" = "y" ]; then
    define_bool CONFIG_ISA y
-   define_bool CONFIG_ISA_DMA y
 else
    define_bool CONFIG_ISA n
-   define_bool CONFIG_ISA_DMA n
 fi
 
-# Do we have a PC-type keyboard in this architecture?
-if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then
-   define_bool CONFIG_PC_KEYB y
-   define_bool CONFIG_PC_KEYMAP y
-fi
-if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then
-   define_bool CONFIG_PC_KEYMAP y
+if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
+     "$CONFIG_ARCH_SHARK" = "y" ]; then
+   define_bool CONFIG_ISA_DMA y
+else
+   define_bool CONFIG_ISA_DMA n
 fi
 
 source drivers/pci/Config.in
@@ -251,42 +296,44 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'NWFPE math emulation' CONFIG_NWFPE
+tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE
+dep_tristate 'FastFPE math emulation (experimental)' CONFIG_FPE_FASTFPE $CONFIG_EXPERIMENTAL
 choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
 	 A.OUT		CONFIG_KCORE_AOUT" ELF
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
+dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool 'Power Management support' CONFIG_PM
-fi
-
-if [ "$CONFIG_CPU_32" = "y" ]; then
-   tristate 'RISC OS personality' CONFIG_ARTHUR
-fi
-if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
-     "$CONFIG_ARCH_SA1100" = "y" -o \
-     "$CONFIG_ARCH_CLPS7500" = "y" -o \
+if [ "$CONFIG_ARCH_EBSA110" = "y" -o         \
+     "$CONFIG_ARCH_SA1100" = "y" -o          \
+     "$CONFIG_ARCH_CLPS7500" = "y" -o        \
      "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \
-     "$CONFIG_ARCH_CATS" = "y" -o \
-     "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+     "$CONFIG_ARCH_CATS" = "y" -o            \
+     "$CONFIG_ARCH_INTEGRATOR" = "y" -o      \
+     "$CONFIG_ARCH_P720T" = "y" ]; then
    string 'Default kernel command string' CONFIG_CMDLINE ""
 fi
-if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
-     "$CONFIG_ARCH_EBSA110" = "y" -o   \
-     "$CONFIG_ARCH_EBSA285" = "y" -o   \
-     "$CONFIG_ARCH_CO285" = "y" -o     \
-     "$CONFIG_ARCH_SA1100" = "y" -o    \
-     "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+if [ "$CONFIG_ARCH_NETWINDER" = "y" -o  \
+     "$CONFIG_ARCH_EBSA110" = "y" -o    \
+     "$CONFIG_ARCH_EBSA285" = "y" -o    \
+     "$CONFIG_ARCH_FTVPCI" = "y" -o     \
+     "$CONFIG_ARCH_SHARK" = "y" -o      \
+     "$CONFIG_ARCH_CO285" = "y" -o      \
+     "$CONFIG_ARCH_SA1100" = "y" -o     \
+     "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+     "$CONFIG_ARCH_P720T" = "y" ]; then
    bool 'Timer and CPU usage LEDs' CONFIG_LEDS
    if [ "$CONFIG_LEDS" = "y" ]; then
-      if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
-	   "$CONFIG_ARCH_EBSA285" = "y" -o   \
-	   "$CONFIG_ARCH_CO285" = "y" -o     \
-	   "$CONFIG_ARCH_SA1100" = "y" -o    \
-           "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+      if [ "$CONFIG_ARCH_NETWINDER" = "y" -o  \
+	   "$CONFIG_ARCH_EBSA285" = "y" -o    \
+	   "$CONFIG_ARCH_SHARK" = "y" -o      \
+	   "$CONFIG_ARCH_CO285" = "y" -o      \
+	   "$CONFIG_ARCH_SA1100" = "y" -o     \
+           "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+	   "$CONFIG_ARCH_P720T" = "y" ]; then
          bool '  Timer LED' CONFIG_LEDS_TIMER
          bool '  CPU usage LED' CONFIG_LEDS_CPU
       fi
@@ -350,9 +397,13 @@
 fi
 endmenu
 
+if [ "$CONFIG_ARCH_CLPS711X" = "y" ]; then
+   source drivers/ssi/Config.in
+fi
+
 source drivers/ieee1394/Config.in
 
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 
 mainmenu_option next_comment
 comment 'ISDN subsystem'
@@ -363,6 +414,11 @@
 fi
 endmenu
 
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
+
 source drivers/char/Config.in
 if [ "$CONFIG_ARCH_ACORN" = "y" -a \
      "$CONFIG_BUSMOUSE" = "y" ]; then
@@ -373,11 +429,34 @@
    fi
 fi
 
+source drivers/media/Config.in
+
 source fs/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
    comment 'Console drivers'
+   # Select the keyboard type for this architecture.
+   if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
+        "$CONFIG_ARCH_CLPS7500" = "y" -o   \
+        "$CONFIG_ARCH_SHARK" = "y" ]; then
+      define_bool CONFIG_PC_KEYB y
+   fi
+   if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+      define_bool CONFIG_KMI_KEYB y
+      define_bool CONFIG_KMI_MOUSE y
+   fi
+
+   # Do we use the PC-type keyboard map?
+   if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
+        "$CONFIG_ARCH_SHARK" = "y" -o      \
+        "$CONFIG_ARCH_SA1100" = "y" -o     \
+        "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+        "$CONFIG_ARCH_TBOX" = "y" -o       \
+        "$CONFIG_ARCH_CLPS7500" = "y" -o   \
+        "$CONFIG_ARCH_P720T" = "y" ]; then
+      define_bool CONFIG_PC_KEYMAP y
+   fi
    if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
       bool 'VGA text console' CONFIG_VGA_CONSOLE
    fi
@@ -388,6 +467,7 @@
 
 if [ "$CONFIG_ARCH_ACORN" = "y" -o \
      "$CONFIG_ARCH_CLPS7500" = "y" -o \
+     "$CONFIG_ARCH_TBOX" = "y" -o \
      "$CONFIG_ARCH_SHARK" = "y" -o \
      "$CONFIG_PCI" = "y" ]; then
    mainmenu_option next_comment
@@ -408,23 +488,14 @@
 
 # Always compile kernel with framepointer (until 2.4 real comes out)
 # Bug reports aren't much use without this.
-#bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
-define_bool CONFIG_FRAME_POINTER y
+bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER
 bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS
 bool 'Verbose user fault messages' CONFIG_DEBUG_USER
 bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-if [ "$CONFIG_CPU_26" = "y" ]; then
-   bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE
-fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   # These options are only for real kernel hackers
-   # who want to get their hands dirty. 
-   bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL
-   if [ "$CONFIG_DEBUG_LL" = "y" ]; then
-      if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
-         bool 'Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT
-      fi
-   fi
-fi
+dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
+# These options are only for real kernel hackers who want to get their hands dirty. 
+dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL
+dep_bool '  Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
+dep_bool '  kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
 endmenu
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.4.3/linux/arch/arm/kernel/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/kernel/Makefile	Thu Apr 12 12:20:31 2001
@@ -13,16 +13,18 @@
 AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR)
 AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR)
 
+# This is depreciated.
 O_OBJS_arc        = dma-arc.o oldlatches.o
 O_OBJS_rpc        = dma-rpc.o
 O_OBJS_footbridge = dma-footbridge.o isa.o
 O_OBJS_l7200      = fiq.o
 
-pci-nexuspci	  = plx90x0.o
+pci-ftvpci	  = plx90x0.o
 pci-footbridge	  = dec21285.o
 pci-shark	  = via82c505.o
 
-pci-$(CONFIG_ARCH_NEXUSPCI) += ftv-pci.o
+# this is here to allow us to eventually move it out to mach-ftvpci
+pci-$(CONFIG_ARCH_FTVPCI) += ftv-pci.o
 
 
 O_TARGET := kernel.o
@@ -36,7 +38,7 @@
 obj-n		:=
 obj-		:=
 
-export-objs	:= armksyms.o dma.o ecard.o fiq.o oldlatches.o time.o
+export-objs	:= armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o
 
 no-irq-arch	:= $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \
 		   $(CONFIG_ARCH_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110)
@@ -46,16 +48,21 @@
 endif
 
 obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o
+obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o
 obj-$(CONFIG_DEBUG_LL)	+= debug-$(PROCESSOR).o
 obj-$(CONFIG_MODULES)	+= armksyms.o
 obj-$(CONFIG_ARTHUR)	+= arthur.o
 obj-$(CONFIG_ISA_DMA)	+= dma-isa.o
 obj-$(CONFIG_PCI)	+= bios32.o $(pci-$(MACHINE)) $(pci-y)
 
+ifneq ($(MACHINE),ebsa110)
+  obj-y		+= io.o
+endif
+
 all: kernel.o $(HEAD_OBJ) init_task.o
 
 include $(TOPDIR)/Rules.make
 
 # Spell out some dependencies that `make dep' doesn't spot
-entry-armv.o: calls.S ../lib/constants.h
-entry-armo.o: calls.S ../lib/constants.h
+entry-armv.o: calls.S $(TOPDIR)/include/asm-arm/constants.h
+entry-armo.o: calls.S $(TOPDIR)/include/asm-arm/constants.h
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c
--- v2.4.3/linux/arch/arm/kernel/arch.c	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/kernel/arch.c	Thu Apr 12 12:20:31 2001
@@ -19,10 +19,9 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/dec21285.h>
 
-unsigned int vram_size;
+extern void genarch_init_irq(void);
 
-extern void setup_initrd(unsigned int start, unsigned int size);
-extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
+unsigned int vram_size;
 
 #ifdef CONFIG_ARCH_ACORN
 
@@ -79,6 +78,7 @@
 	DISABLE_PARPORT(1)
 	FIXUP(fixup_acorn)
 	MAPIO(rpc_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_ARC
@@ -86,6 +86,7 @@
 	MAINTAINER("Dave Gilbert")
 	BOOT_PARAMS(0x0207c000)
 	FIXUP(fixup_acorn)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_A5K
@@ -93,11 +94,13 @@
 	MAINTAINER("Russell King")
 	BOOT_PARAMS(0x0207c000)
 	FIXUP(fixup_acorn)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #endif
 
 #ifdef CONFIG_ARCH_L7200
+extern void __init l7200_map_io(void);
 
 static void __init
 fixup_l7200(struct machine_desc *desc, struct param_struct *params,
@@ -109,34 +112,28 @@
         mi->bank[0].node  = 0;
 
         ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
-        setup_ramdisk( 1, 0, 0, 8192 );
-        setup_initrd( __phys_to_virt(0xf1000000), 0x00162b0d);
-}
+        setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE);
+        setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b);
 
-extern void __init l7200_map_io(void);
+        /* Serial Console COM2 and LCD */
+	strcpy( *cmdline, "console=tty0 console=ttyLU1,115200");
+
+        /* Serial Console COM1 and LCD */
+	//strcpy( *cmdline, "console=tty0 console=ttyLU0,115200");
+
+        /* Console on LCD */
+	//strcpy( *cmdline, "console=tty0");
+}
 
-MACHINE_START(L7200, "LinkUp Systems L7200SDB")
-	MAINTAINER("Steve Hill")
+MACHINE_START(L7200, "LinkUp Systems L7200")
+	MAINTAINER("Steve Hill / Scott McConnell")
 	BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000)
 	FIXUP(fixup_l7200)
 	MAPIO(l7200_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 
-#ifdef CONFIG_ARCH_EBSA110
-
-extern void __init ebsa110_map_io(void);
-
-MACHINE_START(EBSA110, "EBSA110")
-	MAINTAINER("Russell King")
-	BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
-	BOOT_PARAMS(0x00000400)
-	DISABLE_PARPORT(0)
-	DISABLE_PARPORT(2)
-	SOFT_REBOOT
-	MAPIO(ebsa110_map_io)
-MACHINE_END
-#endif
 #ifdef CONFIG_ARCH_NEXUSPCI
 
 extern void __init nexuspci_map_io(void);
@@ -145,6 +142,7 @@
 	MAINTAINER("Philip Blundell")
 	BOOT_MEM(0x40000000, 0x10000000, 0xe0000000)
 	MAPIO(nexuspci_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_TBOX
@@ -155,21 +153,25 @@
 	MAINTAINER("Philip Blundell")
 	BOOT_MEM(0x80000000, 0x00400000, 0xe0000000)
 	MAPIO(tbox_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_CLPS7110
 MACHINE_START(CLPS7110, "CL-PS7110")
 	MAINTAINER("Werner Almesberger")
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_ETOILE
 MACHINE_START(ETOILE, "Etoile")
 	MAINTAINER("Alex de Vries")
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_LACIE_NAS
 MACHINE_START(LACIE_NAS, "LaCie_NAS")
 	MAINTAINER("Benjamin Herrenschmidt")
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_ARCH_CLPS7500
@@ -180,5 +182,6 @@
 	MAINTAINER("Philip Blundell")
 	BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
 	MAPIO(clps7500_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.4.3/linux/arch/arm/kernel/armksyms.c	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/kernel/armksyms.c	Thu Apr 12 12:20:31 2001
@@ -48,7 +48,6 @@
 extern int sys_read(int, char *, int);
 extern int sys_lseek(int, off_t, int);
 extern int sys_exit(int);
-extern int sys_wait4(int, int *, int, struct rusage *);
 
 /*
  * libgcc functions - functions that are used internally by the
@@ -77,15 +76,18 @@
 extern void fpundefinstr(void);
 extern void fp_enter(void);
 
-#define EXPORT_SYMBOL_ALIAS(sym,orig) \
- const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \
-    __MODULE_STRING(##sym##); \
- const struct module_symbol __ksymtab_##sym __attribute__((section("__ksymtab"))) = \
+#define EXPORT_SYMBOL_ALIAS(sym,orig)		\
+ const char __kstrtab_##sym##[]			\
+  __attribute__((section(".kstrtab"))) =	\
+    __MODULE_STRING(sym);			\
+ const struct module_symbol __ksymtab_##sym	\
+  __attribute__((section("__ksymtab"))) =	\
     { (unsigned long)&##orig, __kstrtab_##sym };
-	/*
-	 * floating point math emulator support.
-	 * These symbols will never change their calling convention...
-	 */
+
+/*
+ * floating point math emulator support.
+ * These symbols will never change their calling convention...
+ */
 EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter);
 EXPORT_SYMBOL_ALIAS(fp_printk,printk);
 EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
@@ -95,7 +97,9 @@
 EXPORT_SYMBOL(ret_from_exception);
 #endif
 
+#ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
+#endif
 
 	/* platform dependent support */
 EXPORT_SYMBOL(dump_thread);
@@ -150,8 +154,6 @@
 #ifndef CONFIG_NO_PGT_CACHE
 EXPORT_SYMBOL(quicklists);
 #endif
-EXPORT_SYMBOL(__handle_bad_pmd);
-EXPORT_SYMBOL(__handle_bad_pmd_kernel);
 
 	/* string / mem functions */
 EXPORT_SYMBOL_NOVERS(strcpy);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/arthur.c linux/arch/arm/kernel/arthur.c
--- v2.4.3/linux/arch/arm/kernel/arthur.c	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/kernel/arthur.c	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,9 @@
 /*
- * Arthur personality
+ *  linux/arch/arm/kernel/arthur.c
+ *
+ *  Copyright (C) 1998, 1999, 2000 Philip Blundell
  *
- * Copyright (C) 1998, 1999, 2000 Philip Blundell
+ * Arthur personality
  */
 
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.4.3/linux/arch/arm/kernel/bios32.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/kernel/bios32.c	Thu Apr 12 12:20:31 2001
@@ -307,7 +307,8 @@
 		 * parity line correctly.
 		 */
 		if (dev->vendor == PCI_VENDOR_ID_INTERG &&
-		    dev->device == PCI_DEVICE_ID_INTERG_2000)
+		    (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
+		     dev->device == PCI_DEVICE_ID_INTERG_2010))
 			busdata->features &= ~(PCI_COMMAND_SERR |
 					       PCI_COMMAND_PARITY);
 
@@ -394,6 +395,7 @@
 extern struct hw_pci netwinder_pci;
 extern struct hw_pci personal_server_pci;
 extern struct hw_pci ftv_pci;
+extern struct hw_pci shark_pci;
 extern struct hw_pci integrator_pci;
 
 void __init pcibios_init(void)
@@ -409,6 +411,12 @@
 			break;
 		}
 #endif
+#ifdef CONFIG_ARCH_SHARK
+		if (machine_is_shark()) {
+			hw_pci = &shark_pci;
+			break;
+		}
+#endif
 #ifdef CONFIG_ARCH_CATS
 		if (machine_is_cats()) {
 			hw_pci = &cats_pci;
@@ -427,8 +435,8 @@
 			break;
 		}
 #endif
-#ifdef CONFIG_ARCH_NEXUSPCI
-		if (machine_is_nexuspci()) {
+#ifdef CONFIG_ARCH_FTVPCI
+		if (machine_is_ftvpci()) {
 			hw_pci = &ftv_pci;
 			break;
 		}
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S
--- v2.4.3/linux/arch/arm/kernel/debug-armv.S	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/kernel/debug-armv.S	Thu Apr 12 12:20:31 2001
@@ -12,7 +12,6 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/hardware.h>
-#include <asm/hardware/dec21285.h>
 
 		.text
 
@@ -67,8 +66,31 @@
 		tst	\rd, #0x10
 		beq	1001b
 		.endm
+ 	
+#elif defined(CONFIG_ARCH_SHARK)
+		.macro	addruart,rx
+		mov	\rx, #0xe0000000
+		orr	\rx, \rx, #0x000003f8
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+		mov	\rd, #0
+1001:		add	\rd, \rd, #1
+		teq	\rd, #0x10000
+		bne	1001b
+		.endm
+
+		.macro	waituart,rd,rx
+		.endm
 
 #elif defined(CONFIG_FOOTBRIDGE)
+
+#include <asm/hardware/dec21285.h>
+
 #ifndef CONFIG_DEBUG_DC21285_PORT
 	/* For NetWinder debugging */
 		.macro	addruart,rx
@@ -120,9 +142,12 @@
 		.macro	waituart,rd,rx
 		.endm
 #endif
-#elif defined(CONFIG_ARCH_NEXUSPCI)
+#elif defined(CONFIG_ARCH_FTVPCI)
 		.macro	addruart,rx
-		ldr	\rx, =0xfff00000
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		movne	\rx, #0xe0000000
+		moveq	\rx, #0x10000000
 		.endm
 
 		.macro	senduart,rd,rx
@@ -131,8 +156,8 @@
 
 		.macro	busyuart,rd,rx
 1001:		ldr	\rd, [\rx, #0x4]
-		tst	\rd, #1 << 0
-		bne	1001b
+		tst	\rd, #1 << 2
+		beq	1001b
 		.endm
 
 		.macro	waituart,rd,rx
@@ -164,6 +189,26 @@
 		bne	1001b
 		.endm
 
+#elif defined(CONFIG_ARCH_CLPS7500)
+		.macro	addruart,rx
+		mov	\rx, #0xe0000000
+		orr	\rx, \rx, #0x00010000
+		orr	\rx, \rx, #0x00000be0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x14]
+		tst	\rd, #0x20
+		beq	1001b
+		.endm
+
 #elif defined(CONFIG_ARCH_L7200)
 
 		.equ	io_virt, IO_BASE
@@ -174,12 +219,12 @@
 		tst	\rx, #1			@ MMU enabled?
 		moveq	\rx, #io_phys		@ physical base address
 		movne	\rx, #io_virt		@ virtual address
-		add	\rx, \rx, #0x00044000	@ Ser1
-@		add	\rx, \rx, #0x00045000	@ Ser2
+		add	\rx, \rx, #0x00044000	@ UART1
+@		add	\rx, \rx, #0x00045000	@ UART2
 		.endm
 
 		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0x0]	@ UARTDR1
+		str	\rd, [\rx, #0x0]	@ UARTDR
 		.endm
 
 		.macro	waituart,rd,rx
@@ -198,9 +243,6 @@
 
 #include <asm/hardware/serial_amba.h>
 
-		.equ	io_virt, 0xf0000000 + (0x16000000 >> 4)
-		.equ	io_phys, 0x16000000
-
 		.macro	addruart,rx
 		mrc	p15, 0, \rx, c1, c0
 		tst	\rx, #1			@ MMU enabled?
@@ -223,6 +265,41 @@
 1001:		ldr	\rd, [\rx, #0x18]	@ UARTFLG
 		tst	\rd, #1 << 3		@ UARTFLGUBUSY - 1 when busy
 		bne	1001b
+		.endm
+
+#elif defined(CONFIG_ARCH_CLPS711X)
+
+#include <asm/hardware/clps7111.h>
+
+		.macro	addruart,rx
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		moveq	\rx, #CLPS7111_PHYS_BASE
+		movne	\rx, #CLPS7111_VIRT_BASE
+#ifndef CONFIG_DEBUG_CLPS711X_UART2
+		add	\rx, \rx, #0x0000	@ UART1
+#else
+		add	\rx, \rx, #0x1000	@ UART2
+#endif
+		.endm
+
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #0x0480]	@ UARTDR
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldr	\rd, [\rx, #0x0140]	@ SYSFLGx
+		tst	\rd, #1 << 11		@ UBUSYx
+		bne	1001b
+		.endm
+
+		.macro	busyuart,rd,rx
+		tst	\rx, #0x1000		@ UART2 does not have CTS here
+		bne	1002f
+1001:		ldr	\rd, [\rx, #0x0140]	@ SYSFLGx
+		tst	\rd, #1 << 8		@ CTS
+		bne	1001b
+1002:
 		.endm
 
 #else
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.4.3/linux/arch/arm/kernel/ecard.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/arm/kernel/ecard.c	Thu Apr 12 12:20:31 2001
@@ -37,6 +37,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
+#include <linux/notifier.h>
 #include <linux/init.h>
 
 #include <asm/dma.h>
@@ -46,6 +47,7 @@
 #include <asm/irq.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
+#include <asm/mach/irq.h>
 
 #ifndef CONFIG_ARCH_RPC
 #define HAVE_EXPMASK
@@ -53,7 +55,7 @@
 
 enum req {
 	req_readbytes,
-	req_reset
+	req_reset_all
 };
 
 struct ecard_request {
@@ -134,19 +136,14 @@
 #define POD_INT_ADDR(x)	((volatile unsigned char *)\
 			 ((BUS_ADDR((x)) - IO_BASE) + IO_START))
 
-static void
-ecard_task_reset(struct ecard_request *req)
+static inline void ecard_task_reset(void)
 {
-	if (req->ec == NULL) {
-		ecard_t *ec;
+	ecard_t *ec;
 
-		for (ec = cards; ec; ec = ec->next)
-			if (ec->loader)
-				ecard_loader_reset(POD_INT_ADDR(ec->podaddr),
-						   ec->loader);
-	} else if (req->ec->loader)
-		ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr),
-				   req->ec->loader);
+	for (ec = cards; ec; ec = ec->next)
+		if (ec->loader)
+			ecard_loader_reset(POD_INT_ADDR(ec->podaddr),
+					   ec->loader);
 }
 
 static void
@@ -156,48 +153,47 @@
 	volatile unsigned char *base_addr =
 		(volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr);
 	unsigned int len = req->length;
+	unsigned int off = req->address;
 
 	if (req->ec->slot_no == 8) {
 		/*
-		 * The card maintains an index which
-		 * increments the address into a 4096-byte
-		 * page on each access.  We need to keep
+		 * The card maintains an index which increments the address
+		 * into a 4096-byte page on each access.  We need to keep
 		 * track of the counter.
 		 */
 		static unsigned int index;
-		unsigned int offset, page;
-		unsigned char byte = 0; /* keep gcc quiet */
-
-		offset = req->address & 4095;
-		page   = req->address >> 12;
+		unsigned int page;
 
-		if (page > 256)
+		page = (off >> 12) * 4;
+		if (page > 256 * 4)
 			return;
 
-		page *= 4;
+		off &= 4095;
 
-		if (offset == 0 || index > offset) {
-			/*
-			 * We need to reset the index counter.
-			 */
+		/*
+		 * If we are reading offset 0, or our current index is
+		 * greater than the offset, reset the hardware index counter.
+		 */
+		if (off == 0 || index > off) {
 			*base_addr = 0;
 			index = 0;
 		}
 
-		while (index <= offset) {
+		/*
+		 * Increment the hardware index counter until we get to the
+		 * required offset.  The read bytes are discarded.
+		 */
+		while (index < off) {
+			unsigned char byte;
 			byte = base_addr[page];
 			index += 1;
 		}
 
 		while (len--) {
-			*buf++ = byte;
-			if (len) {
-				byte = base_addr[page];
-				index += 1;
-			}
+			*buf++ = base_addr[page];
+			index += 1;
 		}
 	} else {
-		unsigned int off = req->address;
 
 		if (!req->use_loader || !req->ec->loader) {
 			off *= 4;
@@ -220,50 +216,30 @@
 
 }
 
+static void ecard_do_request(struct ecard_request *req)
+{
+	switch (req->req) {
+	case req_readbytes:
+		ecard_task_readbytes(req);
+		break;
+
+	case req_reset_all:
+		ecard_task_reset();
+		break;
+	}
+}
+
 #ifdef CONFIG_CPU_32
 static pid_t ecard_pid;
 static wait_queue_head_t ecard_wait;
-static wait_queue_head_t ecard_done;
 static struct ecard_request *ecard_req;
 
-/* to be removed when exec_mmap becomes extern */
-static int exec_mmap(void)
-{
-	struct mm_struct * mm, * old_mm;
-
-	old_mm = current->mm;
-	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
-		flush_cache_mm(old_mm);
-		mm_release();
-		exit_mmap(old_mm);
-		flush_tlb_mm(old_mm);
-		return 0;
-	}
-
-	mm = mm_alloc();
-	if (mm) {
-		struct mm_struct *active_mm = current->active_mm;
-
-		current->mm = mm;
-		current->active_mm = mm;
-		activate_mm(active_mm, mm);
-		mm_release();
-		if (old_mm) {
-			if (active_mm != old_mm) BUG();
-			mmput(old_mm);
-			return 0;
-		}
-		mmdrop(active_mm);
-		return 0;
-	}
-	return -ENOMEM;
-}
+static DECLARE_MUTEX_LOCKED(ecard_done_sem);
 
 /*
- * Set up the expansion card
- * daemon's environment.
+ * Set up the expansion card daemon's page tables.
  */
-static void ecard_init_task(int force)
+static void ecard_init_pgtables(struct mm_struct *mm)
 {
 	/* We want to set up the page tables for the following mapping:
 	 *  Virtual	Physical
@@ -279,29 +255,41 @@
 	pgd_t *src_pgd, *dst_pgd;
 	unsigned int dst_addr = IO_START;
 
-	if (!force)
-		exec_mmap();
-
-	src_pgd = pgd_offset(current->mm, IO_BASE);
-	dst_pgd = pgd_offset(current->mm, dst_addr);
+	src_pgd = pgd_offset(mm, IO_BASE);
+	dst_pgd = pgd_offset(mm, dst_addr);
 
 	while (dst_addr < IO_START + IO_SIZE) {
 		*dst_pgd++ = *src_pgd++;
 		dst_addr += PGDIR_SIZE;
 	}
 
-	flush_tlb_range(current->mm, IO_START, IO_START + IO_SIZE);
-
 	dst_addr = EASI_START;
-	src_pgd = pgd_offset(current->mm, EASI_BASE);
-	dst_pgd = pgd_offset(current->mm, dst_addr);
+	src_pgd = pgd_offset(mm, EASI_BASE);
+	dst_pgd = pgd_offset(mm, dst_addr);
 
 	while (dst_addr < EASI_START + EASI_SIZE) {
 		*dst_pgd++ = *src_pgd++;
 		dst_addr += PGDIR_SIZE;
 	}
 
-	flush_tlb_range(current->mm, EASI_START, EASI_START + EASI_SIZE);
+	flush_tlb_range(mm, IO_START, IO_START + IO_SIZE);
+	flush_tlb_range(mm, EASI_START, EASI_START + EASI_SIZE);
+}
+
+static int ecard_init_mm(void)
+{
+	struct mm_struct * mm = mm_alloc();
+	struct mm_struct *active_mm = current->active_mm;
+
+	if (!mm)
+		return -ENOMEM;
+
+	current->mm = mm;
+	current->active_mm = mm;
+	activate_mm(active_mm, mm);
+	mmdrop(active_mm);
+	ecard_init_pgtables(mm);
+	return 0;
 }
 
 static int
@@ -309,22 +297,23 @@
 {
 	struct task_struct *tsk = current;
 
-	tsk->session = 1;
-	tsk->pgrp = 1;
-
 	/*
 	 * We don't want /any/ signals, not even SIGKILL
 	 */
 	sigfillset(&tsk->blocked);
 	sigemptyset(&tsk->pending.signal);
 	recalc_sigpending(tsk);
-
 	strcpy(tsk->comm, "kecardd");
+	daemonize();
 
 	/*
-	 * Set up the environment
+	 * Allocate a mm.  We're not a lazy-TLB kernel task since we need
+	 * to set page table entries where the user space would be.  Note
+	 * that this also creates the page tables.  Failure is not an
+	 * option here.
 	 */
-	ecard_init_task(0);
+	if (ecard_init_mm())
+		panic("kecardd: unable to alloc mm\n");
 
 	while (1) {
 		struct ecard_request *req;
@@ -338,16 +327,8 @@
 			}
 		} while (req == NULL);
 
-		switch (req->req) {
-		case req_readbytes:
-			ecard_task_readbytes(req);
-			break;
-
-		case req_reset:
-			ecard_task_reset(req);
-			break;
-		}
-		wake_up(&ecard_done);
+		ecard_do_request(req);
+		up(&ecard_done_sem);
 	}
 }
 
@@ -357,76 +338,90 @@
  * FIXME: The test here is not sufficient to detect if the
  * kcardd is running.
  */
-static inline void
+static void
 ecard_call(struct ecard_request *req)
 {
 	/*
-	 * If we're called from task 0, or from an
-	 * interrupt (will be keyboard interrupt),
-	 * we forcefully set up the memory map, and
-	 * call the loader.  We can't schedule, or
-	 * sleep for this call.
+	 * Make sure we have a context that is able to sleep.
 	 */
-	if ((current == &init_task || in_interrupt()) &&
-	    req->req == req_reset && req->ec == NULL) {
-		ecard_init_task(1);
-		ecard_task_reset(req);
-	} else {
-		if (ecard_pid <= 0)
-			ecard_pid = kernel_thread(ecard_task, NULL,
-					CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (current == &init_task || in_interrupt())
+		BUG();
 
-		ecard_req = req;
+	if (ecard_pid <= 0)
+		ecard_pid = kernel_thread(ecard_task, NULL,
+				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 
-		wake_up(&ecard_wait);
+	ecard_req = req;
+	wake_up(&ecard_wait);
 
-		sleep_on(&ecard_done);
-	}
+	/*
+	 * Now wait for kecardd to run.
+	 */
+	down(&ecard_done_sem);
 }
 #else
 /*
  * On 26-bit processors, we don't need the kcardd thread to access the
  * expansion card loaders.  We do it directly.
  */
-static inline void
-ecard_call(struct ecard_request *req)
-{
-	if (req->req == req_reset)
-		ecard_task_reset(req);
-	else
-		ecard_task_readbytes(req);
-}
+#define ecard_call(req)	ecard_do_request(req)
 #endif
 
 /* ======================= Mid-level card control ===================== */
+
 /*
- * This is called to reset the loaders for each expansion card on reboot.
+ * This function is responsible for resetting the expansion cards to a
+ * sensible state immediately prior to rebooting the system.  This function
+ * has process state (keventd), so we can sleep.
+ *
+ * Possible "val" values here:
+ *  SYS_RESTART   -  restarting system
+ *  SYS_HALT      - halting system
+ *  SYS_POWER_OFF - powering down system
  *
- * This is required to make sure that the card is in the correct state
- * that RiscOS expects it to be.
+ * We ignore all calls, unless it is a SYS_RESTART call - power down/halts
+ * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
  */
-void
-ecard_reset(int slot)
+static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
 {
 	struct ecard_request req;
 
-	req.req = req_reset;
+	if (val != SYS_RESTART)
+		return;
 
-	if (slot < 0)
-		req.ec = NULL;
-	else
-		req.ec = slot_to_ecard(slot);
+	/*
+	 * Disable the expansion card interrupt
+	 */
+	disable_irq(IRQ_EXPANSIONCARD);
 
+	/*
+	 * If we have any expansion card loader code which will handle
+	 * the reset for us, call it now.
+	 */
+	req.req = req_reset_all;
 	ecard_call(&req);
 
+	/*
+	 * Disable the expansion card interrupt again, just to be sure.
+	 */
+	disable_irq(IRQ_EXPANSIONCARD);
+
+	/*
+	 * Finally, reset the expansion card interrupt mask to
+	 * all enable (RISC OS doesn't set this)
+	 */
 #ifdef HAS_EXPMASK
-	if (have_expmask && slot < 0) {
-		have_expmask |= ~0;
-		EXPMASK_ENABLE = have_expmask;
-	}
+	have_expmask = ~0;
+	__raw_writeb(have_expmask, EXPMASK_ENABLE);
 #endif
 }
 
+static struct notifier_block ecard_reboot_notifier = {
+	notifier_call:	ecard_reboot,
+};
+
+
+
 static void
 ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
 {
@@ -506,7 +501,7 @@
 #ifdef HAS_EXPMASK
 	if (irqnr < 4 && have_expmask) {
 		have_expmask |= 1 << irqnr;
-		EXPMASK_ENABLE = have_expmask;
+		__raw_writeb(have_expmask, EXPMASK_ENABLE);
 	}
 #endif
 }
@@ -516,7 +511,7 @@
 #ifdef HAS_EXPMASK
 	if (irqnr < 4 && have_expmask) {
 		have_expmask &= ~(1 << irqnr);
-		EXPMASK_ENABLE = have_expmask;
+		__raw_writeb(have_expmask, EXPMASK_ENABLE);
 	}
 #endif
 }
@@ -556,7 +551,7 @@
  *
  * They are not meant to be called directly, but via enable/disable_irq.
  */
-void ecard_enableirq(unsigned int irqnr)
+static void ecard_enableirq(unsigned int irqnr)
 {
 	ecard_t *ec = slot_to_ecard(irqnr - 32);
 
@@ -572,7 +567,7 @@
 	}
 }
 
-void ecard_disableirq(unsigned int irqnr)
+static void ecard_disableirq(unsigned int irqnr)
 {
 	ecard_t *ec = slot_to_ecard(irqnr - 32);
 
@@ -717,7 +712,7 @@
 	const unsigned int statusmask = 15;
 	unsigned int status;
 
-	status = EXPMASK_STATUS & statusmask;
+	status = __raw_readb(EXPMASK_STATUS) & statusmask;
 	if (status) {
 		unsigned int slot;
 		ecard_t *ec;
@@ -739,18 +734,21 @@
 			 * otherwise you will lose serial data at high speeds!
 			 */
 			oldexpmask = have_expmask;
-			EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]);
+			have_expmask &= priority_masks[slot];
+			__raw_writeb(have_expmask, EXPMASK_ENABLE);
 			sti();
 			do_ecard_IRQ(ec->irq, regs);
 			cli();
-			EXPMASK_ENABLE = have_expmask = oldexpmask;
-			status = EXPMASK_STATUS & statusmask;
+			have_expmask = oldexpmask;
+			__raw_writeb(have_expmask, EXPMASK_ENABLE);
+			status = __raw_readb(EXPMASK_STATUS) & statusmask;
 			if (status)
 				goto again;
 		} else {
 			printk(KERN_WARNING "card%d: interrupt from unclaimed "
 			       "card???\n", slot);
-			EXPMASK_ENABLE = (have_expmask &= ~(1 << slot));
+			have_expmask &= ~(1 << slot);
+			__raw_writeb(have_expmask, EXPMASK_ENABLE);
 		}
 	} else
 		printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
@@ -762,10 +760,10 @@
 	ecard_t *ec;
 	int found;
 
-	EXPMASK_ENABLE = 0x00;
-	EXPMASK_STATUS = 0xff;
-	found = ((EXPMASK_STATUS & 15) == 0);
-	EXPMASK_ENABLE = 0xff;
+	__raw_writeb(0x00, EXPMASK_ENABLE);
+	__raw_writeb(0xff, EXPMASK_STATUS);
+	found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
+	__raw_writeb(0xff, EXPMASK_ENABLE);
 
 	if (!found)
 		return;
@@ -781,7 +779,7 @@
 	for (ec = cards; ec; ec = ec->next)
 		have_expmask |= 1 << ec->slot_no;
 
-	EXPMASK_ENABLE = have_expmask;
+	__raw_writeb(have_expmask, EXPMASK_ENABLE);
 }
 #else
 #define ecard_probeirqhw()
@@ -830,7 +828,7 @@
 	}
 
 #ifdef IOMD_ECTCR
-	outb(ectcr, IOMD_ECTCR);
+	iomd_writeb(ectcr, IOMD_ECTCR);
 #endif
 	return address;
 }
@@ -910,9 +908,8 @@
 	int i, rc = -ENOMEM;
 
 	ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
-
 	if (!ec)
-		goto nodev;
+		goto nomem;
 
 	memset(ec, 0, sizeof(ecard_t));
 
@@ -969,27 +966,31 @@
 	if (slot == 8)
 		ec->irq = 11;
 #endif
+	/*
+	 * hook the interrupt handlers
+	 */
+	if (ec->irq != 0 && ec->irq >= 32) {
+		irq_desc[ec->irq].mask_ack = ecard_disableirq;
+		irq_desc[ec->irq].mask     = ecard_disableirq;
+		irq_desc[ec->irq].unmask   = ecard_enableirq;
+		irq_desc[ec->irq].valid    = 1;
+	}
+
 #ifdef CONFIG_ARCH_RPC
 	/* On RiscPC, only first two slots have DMA capability */
 	if (slot < 2)
 		ec->dma = 2 + slot;
 #endif
-#if 0	/* We don't support FIQs on expansion cards at the moment */
-	ec->fiq = 96 + slot;
-#endif
-
-	rc = 0;
 
 	for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
 
 	*ecp = ec;
+	slot_to_expcard[slot] = ec;
+	return 0;
 
 nodev:
-	if (rc && ec)
-		kfree(ec);
-	else
-		slot_to_expcard[slot] = ec;
-
+	kfree(ec);
+nomem:
 	return rc;
 }
 
@@ -1058,9 +1059,13 @@
 {
 	int slot;
 
+	/*
+	 * Register our reboot notifier
+	 */
+	register_reboot_notifier(&ecard_reboot_notifier);
+
 #ifdef CONFIG_CPU_32
 	init_waitqueue_head(&ecard_wait);
-	init_waitqueue_head(&ecard_done);
 #endif
 
 	printk("Probing expansion cards\n");
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.4.3/linux/arch/arm/kernel/entry-armv.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/kernel/entry-armv.S	Thu Apr 12 12:20:31 2001
@@ -89,41 +89,52 @@
 		.if	ioc_base_low
 		orr	r4, r4, #ioc_base_low
 		.endif
-		ldrb	\irqstat, [r4, #0x24]		@ get high priority first
-		adr	\base, irq_prio_h
+		ldrb	\irqstat, [r4, #IOMD_IRQREQB]	@ get high priority first
+		ldr	\base, =irq_prio_h
 		teq	\irqstat, #0
 #ifdef IOMD_BASE
-		ldreqb	\irqstat, [r4, #0x1f4]		@ get dma
-		adreq	\base, irq_prio_d
+		ldreqb	\irqstat, [r4, #IOMD_DMAREQ]	@ get dma
+		addeq	\base, \base, #256		@ irq_prio_h table size
 		teqeq	\irqstat, #0
+		bne	2406f
 #endif
-		ldreqb	\irqstat, [r4, #0x14]		@ get low priority
-		adreq	\base, irq_prio_l
-
-		teq	\irqstat, #0
-		ldrneb	\irqnr, [\base, \irqstat]	@ get IRQ number
+		ldreqb	\irqstat, [r4, #IOMD_IRQREQA]	@ get low priority
+		addeq	\base, \base, #256		@ irq_prio_d table size
+		teqeq	\irqstat, #0
+#ifdef IOMD_IRQREQC
+		ldreqb	\irqstat, [r4, #IOMD_IRQREQC]
+		addeq	\base, \base, #256		@ irq_prio_l table size
+		teqeq	\irqstat, #0
+#endif
+#ifdef IOMD_IRQREQD
+		ldreqb	\irqstat, [r4, #IOMD_IRQREQD]
+		addeq	\base, \base, #256		@ irq_prio_lc table size
+		teqeq	\irqstat, #0
+#endif
+2406:		ldrneb	\irqnr, [\base, \irqstat]	@ get IRQ number
 		.endm
 
 /*
- * Interrupt table (incorporates priority)
+ * Interrupt table (incorporates priority).  Please note that we
+ * rely on the order of these tables (see above code).
  */
 		.macro	irq_prio_table
-irq_prio_l:	.byte	 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
-		.byte	 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
-		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
-		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
-		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
-		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
-		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
-		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+irq_prio_h:	.byte	 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
 #ifdef IOMD_BASE
 irq_prio_d:	.byte	 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
 		.byte	20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
@@ -142,26 +153,64 @@
 		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
 		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
 #endif
-irq_prio_h:	.byte	 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
-		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+irq_prio_l:	.byte	 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+#ifdef IOMD_IRQREQC
+irq_prio_lc:	.byte	24,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27
+		.byte	28,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27
+		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
+		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
+		.byte	30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27
+		.byte	30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27
+		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
+		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+#endif
+#ifdef IOMD_IRQREQD
+irq_prio_ld:	.byte	40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43
+		.byte	44,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43
+		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
+		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
+		.byte	46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43
+		.byte	46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43
+		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
+		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+#endif
 		.endm
 
 #elif defined(CONFIG_ARCH_EBSA110)
 
+#define IRQ_STAT		0xff000000	/* read */
+
 		.macro	disable_fiq
 		.endm
 
@@ -457,7 +506,9 @@
 		.macro	irq_prio_table
 		.endm
 
-#elif defined(CONFIG_ARCH_P720T)
+#elif defined(CONFIG_ARCH_CLPS711X)
+
+#include <asm/hardware/clps7111.h>
 
 		.macro	disable_fiq
 		.endm
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.4.3/linux/arch/arm/kernel/entry-common.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/kernel/entry-common.S	Thu Apr 12 12:20:31 2001
@@ -35,9 +35,7 @@
 
 		.align	5
 fast_syscall_return:
-		str	r0, [sp, #S_R0 + S_OFF]	@ returned r0
-slow_syscall_return:
-		add	sp, sp, #S_OFF
+		str	r0, [sp, #S_R0+S_OFF]!	@ returned r0
 ret_from_sys_call:				@ external entry
 		get_softirq r0
 		get_current_task r5
@@ -52,6 +50,7 @@
 		bne	ret_reschedule
 		teq	r1, #0			@ check for signals
 		blne	ret_signal
+
 ret_from_all:	restore_user_regs		@ internal
 
 ret_signal:	mov	r1, sp			@ internal
@@ -132,7 +131,8 @@
 		str	ip, [sp, #S_IP + S_OFF]	@ trace exit [IP = 1]
 		bl	SYMBOL_NAME(syscall_trace)
 		str	tip, [sp, #S_IP + S_OFF]
-		b	slow_syscall_return
+		add	sp, sp, #S_OFF
+		b	ret_from_sys_call
 
 2:		add	r1, sp, #S_OFF
 		tst	scno, #0x00f00000	@ is it a Unix SWI?
@@ -142,8 +142,9 @@
 		b	SYMBOL_NAME(sys_ni_syscall) @ not private func
 
 3:		eor	r0, scno, #OS_NUMBER <<20	@ Put OS number back
-		adrsvc	al, lr, slow_syscall_return
-		b	SYMBOL_NAME(deferred)
+		bl	SYMBOL_NAME(deferred)
+		add	sp, sp, #S_OFF
+		b	ret_from_sys_call
 
 		.align	5
 		.type	__irq_stat, #object
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c
--- v2.4.3/linux/arch/arm/kernel/fiq.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/kernel/fiq.c	Thu Apr 12 12:20:31 2001
@@ -124,7 +124,7 @@
 #ifdef CONFIG_CPU_26
 	"mov	%0, pc
 	bic	%1, %0, #0x3
-	orr	%1, %1, #0x0c000001
+	orr	%1, %1, %3
 	teqp	%1, #0		@ select FIQ mode
 	mov	r0, r0
 	ldmia	%2, {r8 - r14}
@@ -133,7 +133,7 @@
 #endif
 #ifdef CONFIG_CPU_32
 	"mrs	%0, cpsr
-	mov	%1, #0xc1
+	mov	%1, %3
 	msr	cpsr_c, %1	@ select FIQ mode
 	mov	r0, r0
 	ldmia	%2, {r8 - r14}
@@ -141,7 +141,7 @@
 	mov	r0, r0"
 #endif
 	: "=&r" (tmp), "=&r" (tmp2)
-	: "r" (&regs->ARM_r8)
+	: "r" (&regs->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE)
 	/* These registers aren't modified by the above code in a way
 	   visible to the compiler, but we mark them as clobbers anyway
 	   so that GCC won't put any of the input or output operands in
@@ -156,7 +156,7 @@
 #ifdef CONFIG_CPU_26
 	"mov	%0, pc
 	bic	%1, %0, #0x3
-	orr	%1, %1, #0x0c000001
+	orr	%1, %1, %3
 	teqp	%1, #0		@ select FIQ mode
 	mov	r0, r0
 	stmia	%2, {r8 - r14}
@@ -165,7 +165,7 @@
 #endif
 #ifdef CONFIG_CPU_32
 	"mrs	%0, cpsr
-	mov	%1, #0xc1
+	mov	%1, %3
 	msr	cpsr_c, %1	@ select FIQ mode
 	mov	r0, r0
 	stmia	%2, {r8 - r14}
@@ -173,7 +173,7 @@
 	mov	r0, r0"
 #endif
 	: "=&r" (tmp), "=&r" (tmp2)
-	: "r" (&regs->ARM_r8)
+	: "r" (&regs->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE)
 	/* These registers aren't modified by the above code in a way
 	   visible to the compiler, but we mark them as clobbers anyway
 	   so that GCC won't put any of the input or output operands in
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S
--- v2.4.3/linux/arch/arm/kernel/head-armo.S	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/kernel/head-armo.S	Thu Apr 12 12:20:31 2001
@@ -82,9 +82,9 @@
 		mov	r1, #0
 		str	r0, [r1, #4]
 		ldr	r0, arm2_id
-		swp	r2, r2, [r1]		@ check for swp (ARM2 can't)
+		swp	r2, r2, [r1]		@ check for swp (ARM2 cant)
 		ldr	r0, arm250_id
-		mrc	15, 0, r3, c0, c0	@ check for CP#15 (ARM250 can't)
+		mrc	15, 0, r3, c0, c0	@ check for CP#15 (ARM250 cant)
 		mov	r0, r3
 continue:	mov	r2, #0xeb000000		@ Make undef vector loop
 		sub	r2, r2, #2
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.4.3/linux/arch/arm/kernel/head-armv.S	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/kernel/head-armv.S	Thu Apr 12 12:20:31 2001
@@ -26,7 +26,9 @@
  *
  * Note that swapper_pg_dir is the virtual address of the page tables, and
  * pgtbl gives us a position-independent reference to these tables.  We can
- * do this because stext == TEXT_ADDR
+ * do this because stext == TEXTADDR
+ *
+ * swapper_pg_dir, pgtbl and krnladr are all closely related.
  */
 #if (TEXTADDR & 0xffff) != 0x8000
 #error TEXTADDR must start at 0xXXXX8000
@@ -35,24 +37,36 @@
 		.globl	SYMBOL_NAME(swapper_pg_dir)
 		.equ	SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000
 
-		.macro	pgtbl, reg
+		.macro	pgtbl, reg, rambase
 		adr	\reg, stext
 		sub	\reg, \reg, #0x4000
 		.endm
 
+/*
+ * Since the page table is closely related to the kernel start address, we
+ * can convert the page table base address to the base address of the section
+ * containing both.
+ */
+		.macro	krnladr, rd, pgtable, rambase
+		bic	\rd, \pgtable, #0x000ff000
+		.endm
+
+/*
+ *  Kernel startup entry point.
+ *
+ * The rules are:
+ *  r0      - should be 0
+ *  r1      - unique architecture number
+ *  MMU     - off
+ *  I-cache - on or off
+ *  D-cache - off
+ *
+ * See linux/arch/arm/tools/mach-types for the complete list of numbers
+ * for r1.
+ */
 		.section ".text.init",#alloc,#execinstr
 		.type	stext, #function
 ENTRY(stext)
-/*
- * Entry point.  The general rules are:
- *  should be called with r0 == 0
- *  r1 contains the unique architecture number
- *  with MMU is off, I-cache may be on or off, D-cache should be off.
- * See linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h
- * for the complete list of numbers for r1.  If you require a new number,
- * please follow the instructions given towards the end of
- * linux/Documentation/arm/README.
- */
 		mov	r12, r0
 /*
  * NOTE!  Any code which is placed here should be done for one of
@@ -115,7 +129,7 @@
 #endif
 
 		mov	r0, #F_BIT | I_BIT | MODE_SVC	@ make sure svc mode
-		msr	cpsr_c, r0			@ and all irqs diabled
+		msr	cpsr_c, r0			@ and all irqs disabled
 		bl	__lookup_processor_type
 		teq	r10, #0				@ invalid processor?
 		moveq	r0, #'p'			@ yes, error 'p'
@@ -129,6 +143,7 @@
 		add	pc, r10, #12			@ initialise processor
 							@ (return control reg)
 
+		.type	__switch_data, %object
 __switch_data:	.long	__mmap_switched
 		.long	SYMBOL_NAME(compat)
 		.long	SYMBOL_NAME(__bss_start)
@@ -138,6 +153,7 @@
 		.long	SYMBOL_NAME(cr_alignment)
 		.long	SYMBOL_NAME(init_task_union)+8192
 
+		.type	__ret, %function
 __ret:		ldr	lr, __switch_data
 		mcr	p15, 0, r0, c1, c0
 		mov	r0, r0
@@ -190,31 +206,37 @@
  * r8 = page table flags
  */
 __create_page_tables:
-		pgtbl	r4
+		pgtbl	r4, r5				@ page table address
+
+		/*
+		 * Clear the 16K level 1 swapper page table
+		 */
 		mov	r0, r4
 		mov	r3, #0
-		add	r2, r0, #0x4000			@ 16k of page table
-1:		str	r3, [r0], #4			@ Clear page table
+		add	r2, r0, #0x4000
+1:		str	r3, [r0], #4
 		str	r3, [r0], #4
 		str	r3, [r0], #4
 		str	r3, [r0], #4
 		teq	r0, r2
 		bne	1b
+
 		/*
-		 * Create identity mapping for first MB of kernel.
-		 * This is marked cacheable and bufferable.
-		 *
-		 * The identity mapping will be removed by  paging_init()
+		 * Create identity mapping for first MB of kernel to
+		 * cater for the MMU enable.  This identity mapping
+		 * will be removed by paging_init()
 		 */
-		add	r3, r8, r5			@ mmuflags + start of RAM
-		add	r0, r4, r5, lsr #18
-		str	r3, [r0]			@ identity mapping
+		krnladr	r2, r4, r5			@ start of kernel
+		add	r3, r8, r2			@ flags + kernel base
+		str	r3, [r4, r2, lsr #18]		@ identity mapping
+
 		/*
 		 * Now setup the pagetables for our kernel direct
 		 * mapped region.  We round TEXTADDR down to the
 		 * nearest megabyte boundary.
 		 */
-		add	r0, r4, #(TEXTADDR & 0xfff00000) >> 18 @ start of kernel
+		add	r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
+		add	r0, r0, #(TEXTADDR & 0x00f00000) >> 18
 		str	r3, [r0], #4			@ PAGE_OFFSET + 0MB
 		add	r3, r3, #1 << 20
 		str	r3, [r0], #4			@ PAGE_OFFSET + 1MB
@@ -223,13 +245,25 @@
 		add	r3, r3, #1 << 20
 		str	r3, [r0], #4			@ PAGE_OFFSET + 3MB
 
+		/*
+		 * Ensure that the first section of RAM is present.
+		 * we assume that:
+		 *  1. the RAM is aligned to a 256MB boundary
+		 *  2. the kernel is executing in the same 256MB chunk
+		 *     as the start of RAM.
+		 */
+		bic	r0, r0, #0x0ff00000 >> 18	@ round down
+		and	r2, r5, #0xf0000000		@ round down
+		add	r3, r8, r2			@ flags + rambase
+		str	r3, [r0]
+
 		bic	r8, r8, #0x0c			@ turn off cacheable
 							@ and bufferable bits
 #ifdef CONFIG_DEBUG_LL
 		/*
 		 * Map in IO space for serial debugging.
 		 * This allows debug messages to be output
-		 * via a serial before paging_init.
+		 * via a serial console before paging_init.
 		 */
 		add	r0, r4, r7
 		rsb	r3, r7, #0x4000	@ PTRS_PER_PGD*sizeof(long)
@@ -241,12 +275,13 @@
 		add	r3, r3, #1 << 20
 		teq	r0, r2
 		bne	1b
-#ifdef CONFIG_ARCH_NETWINDER
+#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
 		/*
 		 * If we're using the NetWinder, we need to map in
 		 * the 16550-type serial port for the debug messages
 		 */
-		teq	r1, #5
+		teq	r1, #MACH_TYPE_NETWINDER
+		teqne	r1, #MACH_TYPE_CATS
 		bne	1f
 		add	r0, r4, #0x3fc0
 		mov	r3, #0x7c000000
@@ -263,13 +298,12 @@
 		 * Similar reasons here - for debug.  This is
 		 * only for Acorn RiscPC architectures.
 		 */
-		teq	r5, #0
-		addne	r0, r4, #0x80			@ 02000000
-		movne	r3, #0x02000000
-		orrne	r3, r3, r8
-		strne	r3, [r0]
-		addne	r0, r4, #0x3600			@ d8000000
-		strne	r3, [r0]
+		add	r0, r4, #0x80			@ 02000000
+		mov	r3, #0x02000000
+		orr	r3, r3, r8
+		str	r3, [r0]
+		add	r0, r4, #0x3600			@ d8000000
+		str	r3, [r0]
 #endif
 		mov	pc, lr
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/io.c linux/arch/arm/kernel/io.c
--- v2.4.3/linux/arch/arm/kernel/io.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/io.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,49 @@
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void _memcpy_fromio(void * to, unsigned long from, size_t count)
+{
+	while (count) {
+		count--;
+		*(char *) to = readb(from);
+		((char *) to)++;
+		from++;
+	}
+}
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void _memcpy_toio(unsigned long to, const void * from, size_t count)
+{
+	while (count) {
+		count--;
+		writeb(*(char *) from, to);
+		((char *) from)++;
+		to++;
+	}
+}
+
+/*
+ * "memset" on IO memory space.
+ * This needs to be optimized.
+ */
+void _memset_io(unsigned long dst, int c, size_t count)
+{
+	while (count) {
+		count--;
+		writeb(c, dst);
+		dst++;
+	}
+}
+
+EXPORT_SYMBOL(_memcpy_fromio);
+EXPORT_SYMBOL(_memcpy_toio);
+EXPORT_SYMBOL(_memset_io);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/irq-arch.c linux/arch/arm/kernel/irq-arch.c
--- v2.4.3/linux/arch/arm/kernel/irq-arch.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/irq-arch.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,41 @@
+/*
+ *  linux/arch/arm/kernel/irq-arch.c
+ *
+ *  Copyright (C) 1995-2000 Russell King.
+ *
+ * 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.
+ *
+ *  We contain the architecture-specific parts of interrupt handling
+ *  in this file.  In 2.5, it will move into the various arch/arm/mach-*
+ *  directories.
+ */
+#include <linux/ptrace.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/mach/irq.h>
+
+/*
+ * Get architecture specific interrupt handlers
+ * and interrupt initialisation.
+ */
+#include <asm/arch/irq.h>
+
+void __init genarch_init_irq(void)
+{
+	irq_init_irq();
+}
+
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.4.3/linux/arch/arm/kernel/irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/arm/kernel/irq.c	Thu Apr 12 12:20:31 2001
@@ -2,7 +2,7 @@
  *  linux/arch/arm/kernel/irq.c
  *
  *  Copyright (C) 1992 Linus Torvalds
- *  Modifications for ARM processor Copyright (C) 1995-1998 Russell King.
+ *  Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
  *
  * 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
@@ -29,9 +29,11 @@
 #include <linux/smp.h>
 #include <linux/init.h>
 
-#include <asm/hardware.h>
-#include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/system.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/irq.h>	/* pick up fixup_irq definition */
 
 /*
  * Maximum IRQ count.  Currently, this is arbitary.  However, it should
@@ -42,41 +44,11 @@
  */
 #define MAX_IRQ_CNT	100000
 
-spinlock_t irq_controller_lock;
-
-int setup_arm_irq(int, struct irqaction *);
-extern int get_fiq_list(char *);
-extern void init_FIQ(void);
-
-struct irqdesc {
-	unsigned int	 nomask   : 1;		/* IRQ does not mask in IRQ   */
-	unsigned int	 enabled  : 1;		/* IRQ is currently enabled   */
-	unsigned int	 triggered: 1;		/* IRQ has occurred	      */
-	unsigned int	 probing  : 1;		/* IRQ in use for a probe     */
-	unsigned int	 probe_ok : 1;		/* IRQ can be used for probe  */
-	unsigned int	 valid    : 1;		/* IRQ claimable	      */
-	unsigned int	 noautoenable : 1;	/* don't automatically enable IRQ */
-	unsigned int	 unused   :25;
-	void (*mask_ack)(unsigned int irq);	/* Mask and acknowledge IRQ   */
-	void (*mask)(unsigned int irq);		/* Mask IRQ		      */
-	void (*unmask)(unsigned int irq);	/* Unmask IRQ		      */
-	struct irqaction *action;
-	/*
-	 * IRQ lock detection
-	 */
-	unsigned int	 lck_cnt;
-	unsigned int	 lck_pc;
-	unsigned int	 lck_jif;
-};
-
-static struct irqdesc irq_desc[NR_IRQS];
 static volatile unsigned long irq_err_count;
+static spinlock_t irq_controller_lock;
 
-/*
- * Get architecture specific interrupt handlers
- * and interrupt initialisation.
- */
-#include <asm/arch/irq.h>
+struct irqdesc irq_desc[NR_IRQS];
+void (*init_arch_irq)(void) __initdata = NULL;
 
 /*
  * Dummy mask/unmask handler
@@ -85,6 +57,14 @@
 {
 }
 
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line.
+ *
+ *	This function may be called - with care - from IRQ context.
+ */
 void disable_irq(unsigned int irq)
 {
 	unsigned long flags;
@@ -95,6 +75,14 @@
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
+/**
+ *	enable_irq - enable interrupt handling on an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Re-enables the processing of interrupts on this IRQ line
+ *
+ *	This function may be called from IRQ context.
+ */
 void enable_irq(unsigned int irq)
 {
 	unsigned long flags;
@@ -271,6 +259,7 @@
 	int shared = 0;
 	struct irqaction *old, **p;
 	unsigned long flags;
+	struct irqdesc *desc;
 
 	/*
 	 * Some drivers like serial.c use request_irq() heavily,
@@ -292,8 +281,9 @@
 	/*
 	 * The following block of code has to be executed atomically
 	 */
+	desc = irq_desc + irq;
 	spin_lock_irqsave(&irq_controller_lock, flags);
-	p = &irq_desc[irq].action;
+	p = &desc->action;
 	if ((old = *p) != NULL) {
 		/* Can't share interrupts unless both agree to */
 		if (!(old->flags & new->flags & SA_SHIRQ)) {
@@ -312,11 +302,11 @@
 	*p = new;
 
 	if (!shared) {
-		irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
-		irq_desc[irq].probing = 0;
-		if (!irq_desc[irq].noautoenable) {
-			irq_desc[irq].enabled = 1;
-			irq_desc[irq].unmask(irq);
+		desc->nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
+		desc->probing = 0;
+		if (!desc->noautoenable) {
+			desc->enabled = 1;
+			desc->unmask(irq);
 		}
 	}
 
@@ -324,13 +314,45 @@
 	return 0;
 }
 
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 		 unsigned long irq_flags, const char * devname, void *dev_id)
 {
 	unsigned long retval;
 	struct irqaction *action;
 
-	if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler)
+	if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
+	    (irq_flags & SA_SHIRQ && !dev_id))
 		return -EINVAL;
 
 	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
@@ -351,6 +373,18 @@
 	return retval;
 }
 
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function.
+ *
+ *	This function may be called from interrupt context.
+ */
 void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction * action, **p;
@@ -486,6 +520,6 @@
 		irq_desc[irq].unmask   = dummy_mask_unmask_irq;
 	}
 
-	irq_init_irq();
+	init_arch_irq();
 	init_dma();
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/leds-ebsa110.c linux/arch/arm/kernel/leds-ebsa110.c
--- v2.4.3/linux/arch/arm/kernel/leds-ebsa110.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/kernel/leds-ebsa110.c	Wed Dec 31 16:00:00 1969
@@ -1,51 +0,0 @@
-/*
- *  linux/arch/arm/kernel/leds-ebsa110.c
- *
- *  Copyright (C) 1998 Russell King
- *
- * 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.
- *
- *  EBSA-110 LED control routines.  We use the led as follows:
- *
- *   - Red - toggles state every 50 timer interrupts
- */
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-
-#include <asm/hardware.h>
-#include <asm/leds.h>
-#include <asm/system.h>
-#include <asm/mach-types.h>
-
-static spinlock_t leds_lock;
-
-static void ebsa110_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&leds_lock, flags);
-
-	switch(ledevt) {
-	case led_timer:
-		*(volatile unsigned char *)0xf2400000 ^= 128;
-		break;
-
-	default:
-		break;
-	}
-
-	spin_unlock_irqrestore(&leds_lock, flags);
-}
-
-static int __init leds_init(void)
-{
-	if (machine_is_ebsa110())
-		leds_event = ebsa110_leds_event;
-
-	return 0;
-}
-
-__initcall(leds_init);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c
--- v2.4.3/linux/arch/arm/kernel/oldlatches.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/kernel/oldlatches.c	Thu Apr 12 12:20:31 2001
@@ -59,7 +59,7 @@
 	}
 }
 
-initcall(oldlatch_init);
+__initcall(oldlatch_init);
 
 EXPORT_SYMBOL(oldlatch_aupdate);
 EXPORT_SYMBOL(oldlatch_bupdate);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c
--- v2.4.3/linux/arch/arm/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/arm/kernel/semaphore.c	Tue Apr 17 17:19:24 2001
@@ -165,321 +165,3 @@
 	spin_unlock_irqrestore(&semaphore_lock, flags);
 	return 1;
 }
-
-struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
-{
-        struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-
-	return sem;
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	/* this takes care of granting the lock */
-	__up_op_read(sem, __rwsem_wake);
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	/* this takes care of granting the lock */
-	__up_op_write(sem, __rwsem_wake);
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-	return sem;
-}
-
-struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-	return sem;
-}
-
-/*
- * The semaphore operations have a special calling sequence that
- * allow us to do a simpler in-line version of them. These routines
- * need to convert that sequence back into the C sequence when
- * there is contention on the semaphore.
- *
- * ip contains the semaphore pointer on entry. Save the C-clobbered
- * registers (r0 to r3 and lr), but not ip, as we use it as a return
- * value in some cases..
- */
-#ifdef CONFIG_CPU_26
-asm("	.section	.text.lock, \"ax\"
-	.align	5
-	.globl	__down_failed
-__down_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__down
-	ldmfd	sp!, {r0 - r3, pc}^
-
-	.align	5
-	.globl	__down_interruptible_failed
-__down_interruptible_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__down_interruptible
-	mov	ip, r0
-	ldmfd	sp!, {r0 - r3, pc}^
-
-	.align	5
-	.globl	__down_trylock_failed
-__down_trylock_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__down_trylock
-	mov	ip, r0
-	ldmfd	sp!, {r0 - r3, pc}^
-
-	.align	5
-	.globl	__up_wakeup
-__up_wakeup:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__up
-	ldmfd	sp!, {r0 - r3, pc}^
-
-	.align	5
-	.globl	__down_read_failed
-__down_read_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bcc	1f
-1:	bl	down_read_failed_biased
-	ldmfd	sp!, {r0 - r3, pc}^
-2:	bl	down_read_failed
-	mov	r1, pc
-	orr	r2, r1, #
-	teqp r2, #0
-
-	ldr	r3, [r0]
-	subs	r3, r3, #1
-	str	r3, [r0]
-	ldmplfd	sp!, {r0 - r3, pc}^
-  orrcs r1, r1, #0x20000000   @ Set carry
-  teqp r1, #0
-	bcc	2b
-	b	1b
-
-	.align	5
-	.globl	__down_write_failed
-__down_write_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bcc	1f
-1:	bl	down_write_failed_biased
-	ldmfd	sp!, {r0 - r3, pc}^
-2:	bl	down_write_failed
-	mov r1, pc
-	orr	r2, r1, #128
-	teqp r2, #0
-
-	ldr	r3, [r0]
-	subs	r3, r3, #"RW_LOCK_BIAS_STR"
-	str	r3, [r0]
-	ldmeqfd	sp!, {r0 - r3, pc}^
-  orrcs r1, r1, #0x20000000   @ Set carry
-	teqp r1, #0
-	bcc	2b
-	b	1b
-
-	.align	5
-	.globl	__rwsem_wake
-__rwsem_wake:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	beq	1f
-	bl	rwsem_wake_readers
-	ldmfd	sp!, {r0 - r3, pc}^
-1:	bl	rwsem_wake_writer
-	ldmfd	sp!, {r0 - r3, pc}^
-
-	.previous
-	");
-
-#else
-/* 32 bit version */
-asm("	.section	.text.lock, \"ax\"
-	.align	5
-	.globl	__down_failed
-__down_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__down
-	ldmfd	sp!, {r0 - r3, pc}
-
-	.align	5
-	.globl	__down_interruptible_failed
-__down_interruptible_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__down_interruptible
-	mov	ip, r0
-	ldmfd	sp!, {r0 - r3, pc}
-
-	.align	5
-	.globl	__down_trylock_failed
-__down_trylock_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__down_trylock
-	mov	ip, r0
-	ldmfd	sp!, {r0 - r3, pc}
-
-	.align	5
-	.globl	__up_wakeup
-__up_wakeup:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bl	__up
-	ldmfd	sp!, {r0 - r3, pc}
-
-	.align	5
-	.globl	__down_read_failed
-__down_read_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bcc	1f
-1:	bl	down_read_failed_biased
-	ldmfd	sp!, {r0 - r3, pc}
-2:	bl	down_read_failed
-	mrs	r1, cpsr
-	orr	r2, r1, #128
-	msr	cpsr_c, r2
-	ldr	r3, [r0]
-	subs	r3, r3, #1
-	str	r3, [r0]
-	msr	cpsr_c, r1
-	ldmplfd	sp!, {r0 - r3, pc}
-	bcc	2b
-	b	1b
-
-	.align	5
-	.globl	__down_write_failed
-__down_write_failed:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	bcc	1f
-1:	bl	down_write_failed_biased
-	ldmfd	sp!, {r0 - r3, pc}
-2:	bl	down_write_failed
-	mrs	r1, cpsr
-	orr	r2, r1, #128
-	msr	cpsr_c, r2
-	ldr	r3, [r0]
-	subs	r3, r3, #"RW_LOCK_BIAS_STR"
-	str	r3, [r0]
-	msr	cpsr_c, r1
-	ldmeqfd	sp!, {r0 - r3, pc}
-	bcc	2b
-	b	1b
-
-	.align	5
-	.globl	__rwsem_wake
-__rwsem_wake:
-	stmfd	sp!, {r0 - r3, lr}
-	mov	r0, ip
-	beq	1f
-	bl	rwsem_wake_readers
-	ldmfd	sp!, {r0 - r3, pc}
-1:	bl	rwsem_wake_writer
-	ldmfd	sp!, {r0 - r3, pc}
-
-	.previous
-	");
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.4.3/linux/arch/arm/kernel/setup.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/kernel/setup.c	Thu Apr 12 12:20:31 2001
@@ -26,6 +26,7 @@
 #include <asm/mach-types.h>
 
 #include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
 
 #ifndef MEM_SIZE
 #define MEM_SIZE	(16*1024*1024)
@@ -35,10 +36,21 @@
 #define CONFIG_CMDLINE ""
 #endif
 
+#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
+char fpe_type[8];
+
+static int __init fpe_setup(char *line)
+{
+	memcpy(fpe_type, line, 8);
+	return 1;
+}
+
+__setup("fpe=", fpe_setup);
+#endif
+
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
 extern void bootmem_init(struct meminfo *);
 extern void reboot_setup(char *str);
-extern void disable_hlt(void);
 extern unsigned long memparse(char *ptr, char **retptr);
 extern int root_mountflags;
 extern int _stext, _text, _etext, _edata, _end;
@@ -71,9 +83,10 @@
 char elf_platform[ELF_PLATFORM_SIZE];
 char saved_command_line[COMMAND_LINE_SIZE];
 
+static struct meminfo meminfo __initdata = { 0, };
 static struct proc_info_item proc_info;
 static const char *machine_name;
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
+static char command_line[COMMAND_LINE_SIZE];
 
 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
 static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
@@ -306,71 +319,222 @@
 		request_resource(&ioport_resource, &lp2);
 }
 
+/*
+ *  Tag parsing.
+ *
+ * This is the new way of passing data to the kernel at boot time.  Rather
+ * than passing a fixed inflexible structure to the kernel, we pass a list
+ * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
+ * tag for the list to be recognised (to distinguish the tagged list from
+ * a param_struct).  The list is terminated with a zero-length tag (this tag
+ * is not parsed in any way).
+ */
+static int __init parse_tag_core(const struct tag *tag)
+{
+	if ((tag->u.core.flags & 1) == 0)
+		root_mountflags &= ~MS_RDONLY;
+	ROOT_DEV = to_kdev_t(tag->u.core.rootdev);
+	return 0;
+}
+
+static int __init parse_tag_mem32(const struct tag *tag)
+{
+	if (meminfo.nr_banks >= NR_BANKS) {
+		printk(KERN_WARNING
+		       "Ignoring memory bank 0x%08x size %dKB\n",
+			tag->u.mem.start, tag->u.mem.size / 1024);
+		return -EINVAL;
+	}
+	meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start;
+	meminfo.bank[meminfo.nr_banks].size  = tag->u.mem.size;
+	meminfo.bank[meminfo.nr_banks].node  = 0;
+	meminfo.nr_banks += 1;
+
+	return 0;
+}
+
+static int __init parse_tag_videotext(const struct tag *tag)
+{
+	screen_info.orig_x            = tag->u.videotext.x;
+	screen_info.orig_y            = tag->u.videotext.y;
+	screen_info.orig_video_page   = tag->u.videotext.video_page;
+	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
+	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
+	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
+	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
+	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
+	screen_info.orig_video_points = tag->u.videotext.video_points;
+	return 0;
+}
+
+static int __init parse_tag_ramdisk(const struct tag *tag)
+{
+	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
+		      (tag->u.ramdisk.flags & 2) == 0,
+		      tag->u.ramdisk.start, tag->u.ramdisk.size);
+	return 0;
+}
+
+static int __init parse_tag_initrd(const struct tag *tag)
+{
+	setup_initrd(tag->u.initrd.start, tag->u.initrd.size);
+	return 0;
+}
+
+static int __init parse_tag_serialnr(const struct tag *tag)
+{
+	system_serial_low = tag->u.serialnr.low;
+	system_serial_high = tag->u.serialnr.high;
+	return 0;
+}
+
+static int __init parse_tag_revision(const struct tag *tag)
+{
+	system_rev = tag->u.revision.rev;
+	return 0;
+}
+
+static int __init parse_tag_cmdline(const struct tag *tag)
+{
+	strncpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
+	default_command_line[COMMAND_LINE_SIZE - 1] = '\0';
+	return 0;
+}
+
+/*
+ * This is the core tag table; these are the tags
+ * that we recognise for any machine type.
+ */
+static const struct tagtable core_tagtable[] __init = {
+	{ ATAG_CORE,      parse_tag_core      },
+	{ ATAG_MEM,       parse_tag_mem32     },
+	{ ATAG_VIDEOTEXT, parse_tag_videotext },
+	{ ATAG_RAMDISK,   parse_tag_ramdisk   },
+	{ ATAG_INITRD,    parse_tag_initrd    },
+	{ ATAG_SERIAL,    parse_tag_serialnr  },
+	{ ATAG_REVISION,  parse_tag_revision  },
+	{ ATAG_CMDLINE,   parse_tag_cmdline   }
+};
+
+/*
+ * Scan one tag table for this tag, and call its parse function.
+ */
+static int __init
+parse_tag(const struct tagtable *tbl, int size, const struct tag *t)
+{
+	int i;
+
+	for (i = 0; i < size; i++, tbl++)
+		if (t->hdr.tag == tbl->tag) {
+			tbl->parse(t);
+			break;
+		}
+
+	return i < size;
+}
+
+/*
+ * Parse all tags in the list, checking both the global and architecture
+ * specific tag tables.
+ */
+static void __init
+parse_tags(const struct tagtable *tbl, int size, const struct tag *t)
+{
+	/*
+	 * The tag list is terminated with a zero-sized tag.  Size is
+	 * defined to be in units of 32-bit quantities.
+	 */
+	for (; t->hdr.size; t = (struct tag *)((u32 *)t + t->hdr.size)) {
+		if (parse_tag(core_tagtable, ARRAY_SIZE(core_tagtable), t))
+			continue;
+
+		if (tbl && parse_tag(tbl, size, t))
+			continue;
+
+		printk(KERN_WARNING
+		       "Ignoring unrecognised tag 0x%08x\n", t->hdr.tag);
+	}
+}
+
+static void __init parse_params(struct param_struct *params)
+{
+	if (params->u1.s.page_size != PAGE_SIZE) {
+		printk(KERN_WARNING "Warning: bad configuration page, "
+		       "trying to continue\n");
+		return;
+	}
+
+	ROOT_DEV	   = to_kdev_t(params->u1.s.rootdev);
+	system_rev	   = params->u1.s.system_rev;
+	system_serial_low  = params->u1.s.system_serial_low;
+	system_serial_high = params->u1.s.system_serial_high;
+
+	if (params->u1.s.mem_fclk_21285 > 0)
+		mem_fclk_21285 = params->u1.s.mem_fclk_21285;  
+
+	setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0,
+		      (params->u1.s.flags & FLAG_RDPROMPT) == 0,
+		      params->u1.s.rd_start,
+		      params->u1.s.ramdisk_size);
+
+	setup_initrd(params->u1.s.initrd_start,
+		     params->u1.s.initrd_size);
+
+	if (!(params->u1.s.flags & FLAG_READONLY))
+		root_mountflags &= ~MS_RDONLY;
+
+	strncpy(default_command_line, params->commandline, COMMAND_LINE_SIZE);
+	default_command_line[COMMAND_LINE_SIZE - 1] = '\0';
+
+	if (meminfo.nr_banks == 0) {
+		meminfo.nr_banks      = 1;
+		meminfo.bank[0].start = PHYS_OFFSET;
+		meminfo.bank[0].size  = params->u1.s.nr_pages << PAGE_SHIFT;
+	}
+}
+
 void __init setup_arch(char **cmdline_p)
 {
 	struct param_struct *params = NULL;
 	struct machine_desc *mdesc;
-	struct meminfo meminfo;
 	char *from = default_command_line;
 
-	memset(&meminfo, 0, sizeof(meminfo));
-
-	setup_processor();
-
 	ROOT_DEV = MKDEV(0, 255);
 
+	setup_processor();
 	mdesc = setup_architecture(machine_arch_type);
 	machine_name = mdesc->name;
 
-	if (mdesc->broken_hlt)
-		disable_hlt();
-
 	if (mdesc->soft_reboot)
 		reboot_setup("s");
 
 	if (mdesc->param_offset)
 		params = phys_to_virt(mdesc->param_offset);
 
+	/*
+	 * Do the machine-specific fixups before we parse the
+	 * parameters or tags.
+	 */
 	if (mdesc->fixup)
 		mdesc->fixup(mdesc, params, &from, &meminfo);
 
-	if (params && params->u1.s.page_size != PAGE_SIZE) {
-		printk(KERN_WARNING "Warning: bad configuration page, "
-		       "trying to continue\n");
-		params = NULL;
-	}
-
 	if (params) {
-		ROOT_DEV	   = to_kdev_t(params->u1.s.rootdev);
-		system_rev	   = params->u1.s.system_rev;
-		system_serial_low  = params->u1.s.system_serial_low;
-		system_serial_high = params->u1.s.system_serial_high;
-
-		if (params->u1.s.mem_fclk_21285 > 0)
-			mem_fclk_21285 = params->u1.s.mem_fclk_21285;  
-
-		setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0,
-			      (params->u1.s.flags & FLAG_RDPROMPT) == 0,
-			      params->u1.s.rd_start,
-			      params->u1.s.ramdisk_size);
-
-		setup_initrd(params->u1.s.initrd_start,
-			     params->u1.s.initrd_size);
-
-		if (!(params->u1.s.flags & FLAG_READONLY))
-			root_mountflags &= ~MS_RDONLY;
+		struct tag *tag = (struct tag *)params;
 
-		from = params->commandline;
+		/*
+		 * Is the first tag the CORE tag?  This differentiates
+		 * between the tag list and the parameter table.
+		 */
+		if (tag->hdr.tag == ATAG_CORE)
+			parse_tags(mdesc->tagtable, mdesc->tagsize, tag);
+		else
+			parse_params(params);
 	}
 
 	if (meminfo.nr_banks == 0) {
 		meminfo.nr_banks      = 1;
 		meminfo.bank[0].start = PHYS_OFFSET;
-		meminfo.bank[0].node  = 0;
-		if (params)
-			meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT;
-		else
-			meminfo.bank[0].size = MEM_SIZE;
+		meminfo.bank[0].size  = MEM_SIZE;
 	}
 
 	init_mm.start_code = (unsigned long) &_text;
@@ -385,6 +549,11 @@
 	paging_init(&meminfo, mdesc);
 	request_standard_resources(&meminfo, mdesc);
 
+	/*
+	 * Set up various architecture-specific pointers
+	 */
+	init_arch_irq = mdesc->init_irq;
+
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
 	conswitchp = &vga_con;
@@ -403,8 +572,8 @@
 		     (int)processor_id & 15, elf_platform);
 
 	p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n",
-		     (loops_per_sec+2500) / 500000,
-		     ((loops_per_sec+2500) / 5000) % 100);
+		     loops_per_jiffy / (500000/HZ),
+		     (loops_per_jiffy / (5000/HZ)) % 100);
 
 	p += sprintf(p, "Hardware\t: %s\n", machine_name);
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/time-acorn.c linux/arch/arm/kernel/time-acorn.c
--- v2.4.3/linux/arch/arm/kernel/time-acorn.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/kernel/time-acorn.c	Thu Apr 12 12:20:31 2001
@@ -28,17 +28,17 @@
 	unsigned int count1, count2, status1, status2;
 	unsigned long offset = 0;
 
-	status1 = inb(IOC_IRQREQA);
+	status1 = ioc_readb(IOC_IRQREQA);
 	barrier ();
-	outb (0, IOC_T0LATCH);
+	ioc_writeb (0, IOC_T0LATCH);
 	barrier ();
-	count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
+	count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
 	barrier ();
-	status2 = inb(IOC_IRQREQA);
+	status2 = ioc_readb(IOC_IRQREQA);
 	barrier ();
-	outb (0, IOC_T0LATCH);
+	ioc_writeb (0, IOC_T0LATCH);
 	barrier ();
-	count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
+	count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
 
 	if (count2 < count1) {
 		/*
@@ -67,9 +67,9 @@
 
 void __init ioctime_init(void)
 {
-	outb(LATCH & 255, IOC_T0LTCHL);
-	outb(LATCH >> 8, IOC_T0LTCHH);
-	outb(0, IOC_T0GO);
+	ioc_writeb(LATCH & 255, IOC_T0LTCHL);
+	ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
+	ioc_writeb(0, IOC_T0GO);
 
 	gettimeoffset = ioctime_gettimeoffset;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/kernel/via82c505.c linux/arch/arm/kernel/via82c505.c
--- v2.4.3/linux/arch/arm/kernel/via82c505.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/kernel/via82c505.c	Thu Apr 12 12:20:31 2001
@@ -106,8 +106,8 @@
 	    break;
 	  case PCI_BASE_ADDRESS_0:
 	    if (size_wanted) {
-	      /* 0x00900000 bytes long */
-	      *value = 0xff700000;
+	      /* 0x00900000 bytes long (0xff700000) */
+	      *value = 0xff000000;
 	      size_wanted = 0;
 	    } else {
 	      *value = FB_START;
@@ -117,7 +117,7 @@
 	    *value = 6;
 	    break;
 	  default:
-	    *value=0;
+	    *value = 0;
 	  }
 	return PCIBIOS_SUCCESSFUL;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.4.3/linux/arch/arm/lib/Makefile	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/lib/Makefile	Thu Apr 12 12:20:31 2001
@@ -17,8 +17,6 @@
 obj-m		:=
 obj-n		:=
 
-export-objs	:= io.o
-
 obj-arc		:= ecard.o io-acorn.o floppydma.o
 obj-rpc		:= ecard.o io-acorn.o floppydma.o
 obj-clps7500	:= io-acorn.o
@@ -47,10 +45,6 @@
 
 ifeq ($(PROCESSOR),armo)
   obj-y		+= uaccess-armo.o
-endif
-
-ifneq ($(MACHINE),ebsa110)
-  obj-y		+= io.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/arm/lib/backtrace.S linux/arch/arm/lib/backtrace.S
--- v2.4.3/linux/arch/arm/lib/backtrace.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/backtrace.S	Thu Apr 12 12:20:31 2001
@@ -26,7 +26,7 @@
 
 ENTRY(c_backtrace)
 
-#ifndef CONFIG_FRAME_POINTER
+#ifdef CONFIG_NO_FRAME_POINTER
 		mov	pc, lr
 #else
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/lib/delay.S linux/arch/arm/lib/delay.S
--- v2.4.3/linux/arch/arm/lib/delay.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/delay.S	Thu Apr 12 12:20:31 2001
@@ -11,19 +11,26 @@
 #include <asm/assembler.h>
 		.text
 
-LC0:		.word	SYMBOL_NAME(loops_per_sec)
+LC0:		.word	SYMBOL_NAME(loops_per_jiffy)
 
+/*
+ * 0 <= r0 <= 2000
+ */
 ENTRY(udelay)
-		mov	r2, #0x1000
-		orr	r2, r2, #0x00c6
+		mov	r2,     #0x6800
+		orr	r2, r2, #0x00db
 		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 --recursive --new-file v2.4.3/linux/arch/arm/lib/io-shark.c linux/arch/arm/lib/io-shark.c
--- v2.4.3/linux/arch/arm/lib/io-shark.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/io-shark.c	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/lib/io-shark.c
  *
- *  by Alexander.Schulz@stud.uni-karlsruhe.de
+ *  by Alexander Schulz <aschulz@netwinder.org>
  *
  * derived from:
  * linux/arch/arm/lib/io-ebsa.S
diff -u --recursive --new-file v2.4.3/linux/arch/arm/lib/io.c linux/arch/arm/lib/io.c
--- v2.4.3/linux/arch/arm/lib/io.c	Sun Feb  6 17:45:25 2000
+++ linux/arch/arm/lib/io.c	Wed Dec 31 16:00:00 1969
@@ -1,50 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-
-/*
- * Copy data from IO memory space to "real" memory space.
- * This needs to be optimized.
- */
-void _memcpy_fromio(void * to, unsigned long from, size_t count)
-{
-	while (count) {
-		count--;
-		*(char *) to = readb(from);
-		((char *) to)++;
-		from++;
-	}
-}
-
-/*
- * Copy data from "real" memory space to IO memory space.
- * This needs to be optimized.
- */
-void _memcpy_toio(unsigned long to, const void * from, size_t count)
-{
-	while (count) {
-		count--;
-		writeb(*(char *) from, to);
-		((char *) from)++;
-		to++;
-	}
-}
-
-/*
- * "memset" on IO memory space.
- * This needs to be optimized.
- */
-void _memset_io(unsigned long dst, int c, size_t count)
-{
-	while (count) {
-		count--;
-		writeb(c, dst);
-		dst++;
-	}
-}
-
-EXPORT_SYMBOL(_memcpy_fromio);
-EXPORT_SYMBOL(_memcpy_toio);
-EXPORT_SYMBOL(_memset_io);
-
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/Makefile linux/arch/arm/mach-ebsa110/Makefile
--- v2.4.3/linux/arch/arm/mach-ebsa110/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/Makefile	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,23 @@
+#
+# Makefile for the linux kernel.
+#
+# 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).
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET		:= ebsa110.o
+
+# Object file lists.
+
+obj-y			:= arch.o io.o irq.o mm.o time.o
+obj-m			:=
+obj-n			:=
+obj-			:=
+
+export-objs		:= io.o
+
+obj-$(CONFIG_LEDS)	+= leds.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/arch.c linux/arch/arm/mach-ebsa110/arch.c
--- v2.4.3/linux/arch/arm/mach-ebsa110/arch.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/arch.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,33 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/arch.c
+ *
+ *  Architecture specific fixups.  This is where any
+ *  parameters in the params struct are fixed up, or
+ *  any additional architecture specific information
+ *  is pulled from the params struct.
+ */
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+
+#include <asm/elf.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/hardware/dec21285.h>
+
+extern void ebsa110_map_io(void);
+extern void ebsa110_init_irq(void);
+
+MACHINE_START(EBSA110, "EBSA110")
+	MAINTAINER("Russell King")
+	BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
+	BOOT_PARAMS(0x00000400)
+	DISABLE_PARPORT(0)
+	DISABLE_PARPORT(2)
+	SOFT_REBOOT
+	MAPIO(ebsa110_map_io)
+	INITIRQ(ebsa110_init_irq)
+MACHINE_END
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/io.c linux/arch/arm/mach-ebsa110/io.c
--- v2.4.3/linux/arch/arm/mach-ebsa110/io.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/io.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,320 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/isamem.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * Perform "ISA" memory and IO accesses.  The EBSA110 has some "peculiarities"
+ * in the way it handles accesses to odd IO ports on 16-bit devices.  These
+ * devices have their D0-D15 lines connected to the processors D0-D15 lines.
+ * Since they expect all byte IO operations to be performed on D0-D7, and the
+ * StrongARM expects to transfer the byte to these odd addresses on D8-D15,
+ * we must use a trick to get the required behaviour.
+ *
+ * The trick employed here is to use long word stores to odd address -1.  The
+ * glue logic picks this up as a "trick" access, and asserts the LSB of the
+ * peripherals address bus, thereby accessing the odd IO port.  Meanwhile, the
+ * StrongARM transfers its data on D0-D7 as expected.
+ *
+ * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller
+ * wiring was screwed in such a way that it had limited memory space access.
+ * Luckily, the work-around for this is not too horrible.  See
+ * __isamem_convert_addr for the details.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+
+static u32 __isamem_convert_addr(void *addr)
+{
+	u32 ret, a = (u32) addr;
+
+	/*
+	 * The PCMCIA controller is wired up as follows:
+	 *        +---------+---------+---------+---------+---------+---------+
+	 * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1     |         |         |
+	 *        | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 |
+	 *        +---------+---------+---------+---------+---------+---------+
+	 *  CPU   | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1   |         |         |
+	 *        | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x |
+	 *        +---------+---------+---------+---------+---------+---------+
+	 *
+	 * This means that we can access PCMCIA regions as follows:
+	 *	0x*10000 -> 0x*1ffff
+	 *	0x*70000 -> 0x*7ffff
+	 *	0x*90000 -> 0x*9ffff
+	 *	0x*f0000 -> 0x*fffff
+	 */
+	ret  = (a & 0xf803fe) << 1;
+	ret |= (a & 0x03fc00) << 2;
+
+	ret += 0xe8000000;
+
+	if ((a & 0x20000) == (a & 0x40000) >> 1)
+		return ret;
+
+	BUG();
+	return 0;
+}
+
+/*
+ * read[bwl] and write[bwl]
+ */
+u8 __readb(void *addr)
+{
+	u32 ret, a = __isamem_convert_addr(addr);
+
+	if ((int)addr & 1)
+		ret = __arch_getl(a);
+	else
+		ret = __arch_getb(a);
+	return ret;
+}
+
+u16 __readw(void *addr)
+{
+	u32 a = __isamem_convert_addr(addr);
+
+	if ((int)addr & 1)
+		BUG();
+
+	return __arch_getw(a);
+}
+
+u32 __readl(void *addr)
+{
+	u32 ret, a = __isamem_convert_addr(addr);
+
+	if ((int)addr & 3)
+		BUG();
+
+	ret = __arch_getw(a);
+	ret |= __arch_getw(a + 4) << 16;
+	return ret;
+}
+
+EXPORT_SYMBOL(__readb);
+EXPORT_SYMBOL(__readw);
+EXPORT_SYMBOL(__readl);
+
+void __writeb(u8 val, void *addr)
+{
+	u32 a = __isamem_convert_addr(addr);
+
+	if ((int)addr & 1)
+		__arch_putl(val, a);
+	else
+		__arch_putb(val, a);
+}
+
+void __writew(u16 val, void *addr)
+{
+	u32 a = __isamem_convert_addr(addr);
+
+	if ((int)addr & 1)
+		BUG();
+
+	__arch_putw(val, a);
+}
+
+void __writel(u32 val, void *addr)
+{
+	u32 a = __isamem_convert_addr(addr);
+
+	if ((int)addr & 3)
+		BUG();
+
+	__arch_putw(val, a);
+	__arch_putw(val >> 16, a + 4);
+}
+
+EXPORT_SYMBOL(__writeb);
+EXPORT_SYMBOL(__writew);
+EXPORT_SYMBOL(__writel);
+
+#define SUPERIO_PORT(p) \
+	(((p) >> 3) == (0x3f8 >> 3) || \
+	 ((p) >> 3) == (0x2f8 >> 3) || \
+	 ((p) >> 3) == (0x378 >> 3))
+
+u8 __inb(int port)
+{
+	u32 ret;
+
+	/*
+	 * The SuperIO registers use sane addressing techniques...
+	 */
+	if (SUPERIO_PORT(port))
+		ret = __arch_getb(ISAIO_BASE + (port << 2));
+	else {
+		u32 a = ISAIO_BASE + ((port & ~1) << 1);
+
+		/*
+		 * Shame nothing else does
+		 */
+		if (port & 1)
+			ret = __arch_getl(a);
+		else
+			ret = __arch_getb(a);
+	}
+	return ret;
+}
+
+u16 __inw(int port)
+{
+	u32 ret;
+
+	/*
+	 * The SuperIO registers use sane addressing techniques...
+	 */
+	if (SUPERIO_PORT(port))
+		ret = __arch_getw(ISAIO_BASE + (port << 2));
+	else {
+		u32 a = ISAIO_BASE + ((port & ~1) << 1);
+
+		/*
+		 * Shame nothing else does
+		 */
+		if (port & 1)
+			BUG();
+
+		ret = __arch_getw(a);
+	}
+	return ret;
+}
+
+u32 __inl(int port)
+{
+	BUG();
+}
+
+EXPORT_SYMBOL(__inb);
+EXPORT_SYMBOL(__inw);
+EXPORT_SYMBOL(__inl);
+
+void __outb(u8 val, int port)
+{
+	/*
+	 * The SuperIO registers use sane addressing techniques...
+	 */
+	if (SUPERIO_PORT(port))
+		__arch_putb(val, ISAIO_BASE + (port << 2));
+	else {
+		u32 a = ISAIO_BASE + ((port & ~1) << 1);
+
+		/*
+		 * Shame nothing else does
+		 */
+		if (port & 1)
+			__arch_putl(val, a);
+		else
+			__arch_putb(val, a);
+	}
+}
+
+void __outw(u16 val, int port)
+{
+	u32 off;
+
+	/*
+	 * The SuperIO registers use sane addressing techniques...
+	 */
+	if (SUPERIO_PORT(port))
+		off = port << 2;
+	else {
+		off = (port & ~1) << 1;
+		if (port & 1)
+			BUG();
+
+	}
+	__arch_putw(val, ISAIO_BASE + off);
+}
+
+void __outl(u32 val, int port)
+{
+	BUG();
+}
+
+EXPORT_SYMBOL(__outb);
+EXPORT_SYMBOL(__outw);
+EXPORT_SYMBOL(__outl);
+
+extern void __arch_writesb(unsigned long virt, const void *from, int len);
+extern void __arch_writesw(unsigned long virt, const void *from, int len);
+extern void __arch_writesl(unsigned long virt, const void *from, int len);
+extern void __arch_readsb(unsigned long virt, void *from, int len);
+extern void __arch_readsw(unsigned long virt, void *from, int len);
+extern void __arch_readsl(unsigned long virt, void *from, int len);
+
+void outsb(unsigned int port, const void *from, int len)
+{
+	u32 off;
+
+	if (SUPERIO_PORT(port))
+		off = port << 2;
+	else {
+		off = (port & ~1) << 1;
+		if (port & 1)
+			BUG();
+	}
+
+	__arch_writesb(ISAIO_BASE + off, from, len);
+}
+
+void insb(unsigned int port, void *from, int len)
+{
+	u32 off;
+
+	if (SUPERIO_PORT(port))
+		off = port << 2;
+	else {
+		off = (port & ~1) << 1;
+		if (port & 1)
+			BUG();
+	}
+
+	__arch_readsb(ISAIO_BASE + off, from, len);
+}
+
+void outsw(unsigned int port, const void *from, int len)
+{
+	u32 off;
+
+	if (SUPERIO_PORT(port))
+		off = port << 2;
+	else {
+		off = (port & ~1) << 1;
+		if (port & 1)
+			BUG();
+	}
+
+	__arch_writesw(ISAIO_BASE + off, from, len);
+}
+
+void insw(unsigned int port, void *from, int len)
+{
+	u32 off;
+
+	if (SUPERIO_PORT(port))
+		off = port << 2;
+	else {
+		off = (port & ~1) << 1;
+		if (port & 1)
+			BUG();
+	}
+
+	__arch_readsw(ISAIO_BASE + off, from, len);
+}
+
+void outsl(unsigned int port, const void *from, int len)
+{
+	panic("outsl not supported on this architecture");
+}
+
+void insl(unsigned int port, void *from, int len)
+{
+	panic("insl not supported on this architecture");
+}
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/irq.c linux/arch/arm/mach-ebsa110/irq.c
--- v2.4.3/linux/arch/arm/mach-ebsa110/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/irq.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,55 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/irq.c
+ *
+ *  Copyright (C) 1996-1998 Russell King
+ *
+ * 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.
+ *
+ *  Changelog:
+ *   22-08-1998	RMK	Restructured IRQ routines
+ */
+#include <linux/init.h>
+
+#include <asm/mach/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "hardware.h"
+
+static void ebsa110_mask_irq(unsigned int irq)
+{
+	__raw_writeb(1 << irq, IRQ_MCLR);
+}
+
+static void ebsa110_unmask_irq(unsigned int irq)
+{
+	__raw_writeb(1 << irq, IRQ_MSET);
+}
+ 
+void __init ebsa110_init_irq(void)
+{
+	unsigned long flags;
+	int irq;
+
+	save_flags_cli (flags);
+	__raw_writeb(0xff, IRQ_MCLR);
+	__raw_writeb(0x55, IRQ_MSET);
+	__raw_writeb(0x00, IRQ_MSET);
+	if (__raw_readb(IRQ_MASK) != 0x55)
+		while (1);
+	__raw_writeb(0xff, IRQ_MCLR);	/* clear all interrupt enables */
+	restore_flags (flags);
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= ebsa110_mask_irq;
+		irq_desc[irq].mask	= ebsa110_mask_irq;
+		irq_desc[irq].unmask	= ebsa110_unmask_irq;
+	}
+}
+
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/leds.c linux/arch/arm/mach-ebsa110/leds.c
--- v2.4.3/linux/arch/arm/mach-ebsa110/leds.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/leds.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,51 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/leds.c
+ *
+ *  Copyright (C) 1998 Russell King
+ *
+ * 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.
+ *
+ *  EBSA-110 LED control routines.  We use the led as follows:
+ *
+ *   - Red - toggles state every 50 timer interrupts
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+static spinlock_t leds_lock;
+
+static void ebsa110_leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&leds_lock, flags);
+
+	switch(ledevt) {
+	case led_timer:
+		*(volatile unsigned char *)SOFT_BASE ^= 128;
+		break;
+
+	default:
+		break;
+	}
+
+	spin_unlock_irqrestore(&leds_lock, flags);
+}
+
+static int __init leds_init(void)
+{
+	if (machine_is_ebsa110())
+		leds_event = ebsa110_leds_event;
+
+	return 0;
+}
+
+__initcall(leds_init);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/mm.c linux/arch/arm/mach-ebsa110/mm.c
--- v2.4.3/linux/arch/arm/mach-ebsa110/mm.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/mm.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,43 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/mm.c
+ *
+ *  Copyright (C) 1998-1999 Russell King
+ *
+ * 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.
+ *
+ *  Extra MM routines for the EBSA-110 architecture
+ */
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+
+#include "hardware.h"
+ 
+static struct map_desc ebsa110_io_desc[] __initdata = {
+	/*
+	 * sparse external-decode ISAIO space
+	 */
+	{ IRQ_STAT,    TRICK4_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_STAT/IRQ_MCLR */
+	{ IRQ_MASK,    TRICK3_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_MASK/IRQ_MSET */
+	{ SOFT_BASE,   TRICK1_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* SOFT_BASE */
+	{ PIT_BASE,    TRICK0_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* PIT_BASE */
+
+	/*
+	 * self-decode ISAIO space
+	 */
+	{ ISAIO_BASE,  ISAIO_PHYS,  ISAIO_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
+	{ ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
+	LAST_DESC
+};
+
+void __init ebsa110_map_io(void)
+{
+	iotable_init(ebsa110_io_desc);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-ebsa110/time.c linux/arch/arm/mach-ebsa110/time.c
--- v2.4.3/linux/arch/arm/mach-ebsa110/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/time.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,113 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/time.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * 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.
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define PIT_CTRL		(PIT_BASE + 0x0d)
+#define PIT_T2			(PIT_BASE + 0x09)
+#define PIT_T1			(PIT_BASE + 0x05)
+#define PIT_T0			(PIT_BASE + 0x01)
+
+/*
+ * This is the rate at which your MCLK signal toggles (in Hz)
+ * This was measured on a 10 digit frequency counter sampling
+ * over 1 second.
+ */
+#define MCLK	47894000
+
+/*
+ * This is the rate at which the PIT timers get clocked
+ */
+#define CLKBY7	(MCLK / 7)
+
+/*
+ * If CLKBY7 is larger than this, then we must do software
+ * division of the timer interrupt.
+ */
+#if CLKBY7 > 6553500
+#define DIVISOR	2
+#else
+#define DIVISOR 1
+#endif
+
+/*
+ * This is the counter value
+ */
+#define COUNT	((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ))
+
+extern unsigned long (*gettimeoffset)(void);
+
+static unsigned long divisor;
+
+/*
+ * Get the time offset from the system PIT.  Note that if we have missed an
+ * interrupt, then the PIT counter will roll over (ie, be negative).
+ * This actually works out to be convenient.
+ */
+static unsigned long ebsa110_gettimeoffset(void)
+{
+	unsigned long offset, count;
+
+	__raw_writeb(0x40, PIT_CTRL);
+	count = __raw_readb(PIT_T1);
+	count |= __raw_readb(PIT_T1) << 8;
+
+	/*
+	 * If count > COUNT, make the number negative.
+	 */
+	if (count > COUNT)
+		count |= 0xffff0000;
+
+	offset = COUNT * (DIVISOR - divisor);
+	offset -= count;
+
+	/*
+	 * `offset' is in units of timer counts.  Convert
+	 * offset to units of microseconds.
+	 */
+	offset = offset * (1000000 / HZ) / (COUNT * DIVISOR);
+
+	return offset;
+}
+
+int ebsa110_reset_timer(void)
+{
+	u32 count;
+
+	/* latch and read timer 1 */
+	__raw_writeb(0x40, PIT_CTRL);
+	count = __raw_readb(PIT_T1);
+	count |= __raw_readb(PIT_T1) << 8;
+
+	count += COUNT;
+
+	__raw_writeb(count & 0xff, PIT_T1);
+	__raw_writeb(count >> 8, PIT_T1);
+
+	if (divisor == 0)
+		divisor = DIVISOR;
+	divisor -= 1;
+	return divisor;
+}
+
+void __init ebsa110_setup_timer(void)
+{
+	/*
+	 * Timer 1, mode 2, LSB/MSB
+	 */
+	__raw_writeb(0x70, PIT_CTRL);
+	__raw_writeb(COUNT & 0xff, PIT_T1);
+	__raw_writeb(COUNT >> 8, PIT_T1);
+	divisor = DIVISOR - 1;
+
+	gettimeoffset = ebsa110_gettimeoffset;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/Makefile linux/arch/arm/mach-footbridge/Makefile
--- v2.4.3/linux/arch/arm/mach-footbridge/Makefile	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mach-footbridge/Makefile	Thu Apr 12 12:20:31 2001
@@ -5,42 +5,32 @@
 # removes any old dependencies. DON'T put your own dependencies here
 # unless it's something special (ie not a .c file).
 
+USE_STANDARD_AS_RULE := true
+
 O_TARGET		:= footbridge.o
 
 # Object file lists.
 
-obj-y			:= arch.o #dma.o mm.o
+obj-y			:= arch.o irq.o mm.o #dma.o
 obj-m			:=
 obj-n			:=
 obj-			:=
 
 export-objs		:= netwinder-hw.o
 
-ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_ARCH_CATS) += cats-pci.o
-obj-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o
-obj-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o
-obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o
-endif
-
-ifeq ($(CONFIG_LEDS),y)
-obj-$(CONFIG_ARCH_CO285) += ebsa285-leds.o
-obj-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o
-obj-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o
-endif
+pci-$(CONFIG_ARCH_CATS) += cats-pci.o
+pci-$(CONFIG_ARCH_EBSA285) += ebsa285-pci.o
+pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o
+pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o
+
+leds-$(CONFIG_ARCH_CO285) += ebsa285-leds.o
+leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o
+leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o
 
 obj-$(CONFIG_ARCH_CATS) += cats-hw.o
 obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o
 
-# Files that are both resident and modular; remove from modular.
-
-obj-m		:= $(filter-out $(obj-y), $(obj-m))
-
-# Translate to Rules.make lists.
-
-O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
-OX_OBJS 	:= $(filter	$(export-objs), $(obj-y))
-M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS 	:= $(sort $(filter     $(export-objs), $(obj-m)))
+obj-$(CONFIG_PCI)	+=$(pci-y)
+obj-$(CONFIG_LEDS)	+=$(leds-y)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/arch.c linux/arch/arm/mach-footbridge/arch.c
--- v2.4.3/linux/arch/arm/mach-footbridge/arch.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mach-footbridge/arch.c	Thu Apr 12 12:20:31 2001
@@ -19,9 +19,8 @@
 
 #include <asm/mach/arch.h>
 
-extern void setup_initrd(unsigned int start, unsigned int size);
-extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
-extern void __init footbridge_map_io(void);
+extern void footbridge_map_io(void);
+extern void footbridge_init_irq(void);
 
 #ifdef CONFIG_ARCH_EBSA285
 
@@ -42,6 +41,7 @@
 	VIDEO(0x000a0000, 0x000bffff)
 	FIXUP(fixup_ebsa285)
 	MAPIO(footbridge_map_io)
+	INITIRQ(footbridge_init_irq)
 MACHINE_END
 #endif
 
@@ -91,6 +91,7 @@
 	DISABLE_PARPORT(2)
 	FIXUP(fixup_netwinder)
 	MAPIO(footbridge_map_io)
+	INITIRQ(footbridge_init_irq)
 MACHINE_END
 #endif
 
@@ -111,9 +112,11 @@
 MACHINE_START(CATS, "Chalice-CATS")
 	MAINTAINER("Philip Blundell")
 	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+	BOOT_PARAMS(0x00000100)
 	SOFT_REBOOT
 	FIXUP(fixup_cats)
 	MAPIO(footbridge_map_io)
+	INITIRQ(footbridge_init_irq)
 MACHINE_END
 #endif
 
@@ -139,6 +142,7 @@
 	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000)
 	FIXUP(fixup_coebsa285)
 	MAPIO(footbridge_map_io)
+	INITIRQ(footbridge_init_irq)
 MACHINE_END
 #endif
 
@@ -148,5 +152,6 @@
 	BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
 	BOOT_PARAMS(0x00000100)
 	MAPIO(footbridge_map_io)
+	INITIRQ(footbridge_init_irq)
 MACHINE_END
 #endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/irq.c linux/arch/arm/mach-footbridge/irq.c
--- v2.4.3/linux/arch/arm/mach-footbridge/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-footbridge/irq.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,223 @@
+/*
+ *  linux/arch/arm/mach-footbridge/irq.c
+ *
+ *  Copyright (C) 1996-2000 Russell King
+ *
+ * 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.
+ *
+ *  Changelog:
+ *   22-Aug-1998 RMK	Restructured IRQ routines
+ *   03-Sep-1998 PJB	Merged CATS support
+ *   20-Jan-1998 RMK	Started merge of EBSA286, CATS and NetWinder
+ *   26-Jan-1999 PJB	Don't use IACK on CATS
+ *   16-Mar-1999 RMK	Added autodetect of ISA PICs
+ */
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/dec21285.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+/*
+ * Footbridge IRQ translation table
+ *  Converts from our IRQ numbers into FootBridge masks
+ */
+static const int fb_irq_mask[] = {
+	IRQ_MASK_UART_RX,	/*  0 */
+	IRQ_MASK_UART_TX,	/*  1 */
+	IRQ_MASK_TIMER1,	/*  2 */
+	IRQ_MASK_TIMER2,	/*  3 */
+	IRQ_MASK_TIMER3,	/*  4 */
+	IRQ_MASK_IN0,		/*  5 */
+	IRQ_MASK_IN1,		/*  6 */
+	IRQ_MASK_IN2,		/*  7 */
+	IRQ_MASK_IN3,		/*  8 */
+	IRQ_MASK_DOORBELLHOST,	/*  9 */
+	IRQ_MASK_DMA1,		/* 10 */
+	IRQ_MASK_DMA2,		/* 11 */
+	IRQ_MASK_PCI,		/* 12 */
+	IRQ_MASK_SDRAMPARITY,	/* 13 */
+	IRQ_MASK_I2OINPOST,	/* 14 */
+	IRQ_MASK_PCI_ABORT,	/* 15 */
+	IRQ_MASK_PCI_SERR,	/* 16 */
+	IRQ_MASK_DISCARD_TIMER,	/* 17 */
+	IRQ_MASK_PCI_DPERR,	/* 18 */
+	IRQ_MASK_PCI_PERR,	/* 19 */
+};
+
+static void fb_mask_irq(unsigned int irq)
+{
+	*CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)];
+}
+
+static void fb_unmask_irq(unsigned int irq)
+{
+	*CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)];
+}
+
+static void __init __fb_init_irq(void)
+{
+	int irq;
+
+	/*
+	 * setup DC21285 IRQs
+	 */
+	*CSR_IRQ_DISABLE = -1;
+	*CSR_FIQ_DISABLE = -1;
+
+	for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= fb_mask_irq;
+		irq_desc[irq].mask	= fb_mask_irq;
+		irq_desc[irq].unmask	= fb_unmask_irq;
+	}
+}
+
+extern int isa_irq;
+
+static void isa_mask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+}
+
+static void isa_mask_ack_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+	outb(0x20, PIC_LO);
+}
+
+static void isa_unmask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
+}
+
+static void isa_mask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
+}
+
+static void isa_mask_ack_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
+	outb(0x62, PIC_LO);
+	outb(0x20, PIC_HI);
+}
+
+static void isa_unmask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
+}
+
+static void no_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static struct irqaction irq_cascade = { handler: no_action, name: "cascade", };
+static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
+static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
+
+static void __init isa_init_irq(int irq)
+{
+	/*
+	 * Setup, and then probe for an ISA PIC
+	 * If the PIC is not there, then we
+	 * ignore the PIC.
+	 */
+	outb(0x11, PIC_LO);
+	outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
+	outb(0x04, PIC_MASK_LO);	/* Slave on Ch2		*/
+	outb(0x01, PIC_MASK_LO);	/* x86			*/
+	outb(0xf5, PIC_MASK_LO);	/* pattern: 11110101	*/
+
+	outb(0x11, PIC_HI);
+	outb(_ISA_IRQ(8), PIC_MASK_HI);	/* IRQ number		*/
+	outb(0x02, PIC_MASK_HI);	/* Slave on Ch1		*/
+	outb(0x01, PIC_MASK_HI);	/* x86			*/
+	outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
+
+	outb(0x0b, PIC_LO);
+	outb(0x0b, PIC_HI);
+
+	if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
+		outb(0xff, PIC_MASK_LO);/* mask all IRQs	*/
+		outb(0xff, PIC_MASK_HI);/* mask all IRQs	*/
+		isa_irq = irq;
+	} else
+		isa_irq = -1;
+
+	if (isa_irq != -1) {
+		for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
+			irq_desc[irq].valid	= 1;
+			irq_desc[irq].probe_ok	= 1;
+			irq_desc[irq].mask_ack	= isa_mask_ack_pic_lo_irq;
+			irq_desc[irq].mask	= isa_mask_pic_lo_irq;
+			irq_desc[irq].unmask	= isa_unmask_pic_lo_irq;
+		}
+
+		for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
+			irq_desc[irq].valid	= 1;
+			irq_desc[irq].probe_ok	= 1;
+			irq_desc[irq].mask_ack	= isa_mask_ack_pic_hi_irq;
+			irq_desc[irq].mask	= isa_mask_pic_hi_irq;
+			irq_desc[irq].unmask	= isa_unmask_pic_hi_irq;
+		}
+
+		request_resource(&ioport_resource, &pic1_resource);
+		request_resource(&ioport_resource, &pic2_resource);
+		setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
+		setup_arm_irq(isa_irq, &irq_cascade);
+
+		/*
+		 * On the NetWinder, don't automatically
+		 * enable ISA IRQ11 when it is requested.
+		 * There appears to be a missing pull-up
+		 * resistor on this line.
+		 */
+		if (machine_is_netwinder())
+			irq_desc[_ISA_IRQ(11)].noautoenable = 1;
+	}
+}
+
+void __init footbridge_init_irq(void)
+{
+	__fb_init_irq();
+
+	if (!footbridge_cfn_mode())
+		return;
+
+	if (machine_is_ebsa285())
+		/* The following is dependent on which slot
+		 * you plug the Southbridge card into.  We
+		 * currently assume that you plug it into
+		 * the right-hand most slot.
+		 */
+		isa_init_irq(IRQ_PCI);
+
+	if (machine_is_cats())
+		isa_init_irq(IRQ_IN2);
+
+	if (machine_is_netwinder())
+		isa_init_irq(IRQ_IN3);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-footbridge/mm.c linux/arch/arm/mach-footbridge/mm.c
--- v2.4.3/linux/arch/arm/mach-footbridge/mm.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-footbridge/mm.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,117 @@
+/*
+ *  linux/arch/arm/mach-footbridge/mm.c
+ *
+ *  Copyright (C) 1998-2000 Russell King, Dave Gilbert.
+ *
+ * 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.
+ *
+ *  Extra MM routines for the EBSA285 architecture
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+ 
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/hardware/dec21285.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/map.h>
+
+/*
+ * Common mapping for all systems.  Note that the outbound write flush is
+ * commented out since there is a "No Fix" problem with it.  Not mapping
+ * it means that we have extra bullet protection on our feet.
+ */
+static struct map_desc fb_common_io_desc[] __initdata = {
+ { ARMCSR_BASE,	 DC21285_ARMCSR_BASE,	    ARMCSR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
+ { XBUS_BASE,    0x40000000,		    XBUS_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
+ LAST_DESC
+};
+
+/*
+ * The mapping when the footbridge is in host mode.  We don't map any of
+ * this when we are in add-in mode.
+ */
+static struct map_desc ebsa285_host_io_desc[] __initdata = {
+#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST)
+ { PCIMEM_BASE,  DC21285_PCI_MEM,	    PCIMEM_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
+ { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
+ { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
+ { PCIIACK_BASE, DC21285_PCI_IACK,	    PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
+ { PCIO_BASE,    DC21285_PCI_IO,	    PCIO_SIZE,	  DOMAIN_IO, 0, 1, 0, 0 },
+#endif
+ LAST_DESC
+};
+
+/*
+ * The CO-ebsa285 mapping.
+ */
+static struct map_desc co285_io_desc[] __initdata = {
+#ifdef CONFIG_ARCH_CO285
+ { PCIO_BASE,	 DC21285_PCI_IO,	    PCIO_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
+ { PCIMEM_BASE,	 DC21285_PCI_MEM,	    PCIMEM_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
+#endif
+ LAST_DESC
+};
+
+void __init footbridge_map_io(void)
+{
+	struct map_desc *desc = NULL;
+
+	/*
+	 * Set up the common mapping first; we need this to
+	 * determine whether we're in host mode or not.
+	 */
+	iotable_init(fb_common_io_desc);
+
+	/*
+	 * Now, work out what we've got to map in addition on this
+	 * platform.
+	 */
+	if (machine_is_co285())
+		desc = co285_io_desc;
+	else if (footbridge_cfn_mode())
+		desc = ebsa285_host_io_desc;
+
+	if (desc)
+		iotable_init(desc);
+}
+
+#ifdef CONFIG_FOOTBRIDGE_ADDIN
+
+/*
+ * These two functions convert virtual addresses to PCI addresses and PCI
+ * addresses to virtual addresses.  Note that it is only legal to use these
+ * on memory obtained via get_free_page or kmalloc.
+ */
+unsigned long __virt_to_bus(unsigned long res)
+{
+#ifdef CONFIG_DEBUG_ERRORS
+	if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
+		printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res);
+		__backtrace();
+	}
+#endif
+	return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
+}
+
+unsigned long __bus_to_virt(unsigned long res)
+{
+	res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
+	res += PAGE_OFFSET;
+
+#ifdef CONFIG_DEBUG_ERRORS
+	if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
+		printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res);
+		__backtrace();
+	}
+#endif
+	return res;
+}
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/Makefile linux/arch/arm/mach-sa1100/Makefile
--- v2.4.3/linux/arch/arm/mach-sa1100/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/mach-sa1100/Makefile	Thu Apr 12 12:20:31 2001
@@ -11,13 +11,14 @@
 
 # Object file lists.
 
-obj-y			:= arch.o hw.o #dma.o mm.o
+obj-y			:= arch.o hw.o dma-sa1100.o # mm.o
 obj-m			:=
 obj-n			:=
 obj-			:=
 
-export-objs		:= hw.o leds.o
+export-objs		:= dma-sa1100.o dma-sa1111.o hw.o leds.o
 
 obj-$(CONFIG_LEDS)	+= leds.o
+obj-$(CONFIG_SA1111)	+= dma-sa1111.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/arch.c linux/arch/arm/mach-sa1100/arch.c
--- v2.4.3/linux/arch/arm/mach-sa1100/arch.c	Fri Mar  2 11:12:06 2001
+++ linux/arch/arm/mach-sa1100/arch.c	Thu Apr 12 12:20:31 2001
@@ -19,8 +19,23 @@
 
 #include <asm/mach/arch.h>
 
-extern void setup_initrd(unsigned int start, unsigned int size);
-extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
+extern void genarch_init_irq(void);
+
+
+static void sa1100_power_off(void)
+{
+	mdelay(100);
+	cli();
+	/* disable internal oscillator, float CS lines */
+	PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
+	/* set lowest clock */
+	PPCR = 0;
+	/* set all GPIOs to input mode */
+	GPDR = 0;
+	/* enter sleep mode */
+	PMCR = PMCR_SF;
+}
+
 
 static void victor_power_off(void)
 {
@@ -47,10 +62,13 @@
 	mi->bank[__nr].start = (__start), \
 	mi->bank[__nr].size = (__size), \
 	mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
+
 static void __init
 fixup_sa1100(struct machine_desc *desc, struct param_struct *params,
 	     char **cmdline, struct meminfo *mi)
 {
+	pm_power_off = sa1100_power_off;
+
 	if (machine_is_assabet()) {
 		/* 
 		 * On Assabet, we must probe for the Neponset board *before*
@@ -82,6 +100,16 @@
 		setup_initrd( 0xc0800000, 3*1024*1024 );
 	}
 
+	else if (machine_is_pangolin()) {
+		SET_BANK( 0, 0xc0000000, 32*1024*1024 );
+		SET_BANK( 1, 0xc8000000, 32*1024*1024 );
+		mi->nr_banks = 2;
+		
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+		setup_ramdisk( 1, 0, 0, 16384 );
+		setup_initrd( 0xc0800000, 9*1024*1024 );
+	}
+
 	else if (machine_is_brutus()) {
 		SET_BANK( 0, 0xc0000000, 4*1024*1024 );
 		SET_BANK( 1, 0xc8000000, 4*1024*1024 );
@@ -133,7 +161,7 @@
 		setup_initrd(0xc0400000, 4*1024*1024);
 	}
 
-	else if (machine_is_thinclient() || machine_is_graphicsclient()) {
+	else if (machine_is_graphicsclient()) {
 		SET_BANK( 0, 0xc0000000, 16*1024*1024 );
 		mi->nr_banks = 1;
 
@@ -154,15 +182,6 @@
 		if( *((char*)0xc0000100) )
 			*cmdline = ((char *)0xc0000100);
 	}
-	else if (machine_is_tifon()) {
-		SET_BANK( 0, 0xc0000000, 16*1024*1024 );
-		SET_BANK( 1, 0xc8000000, 16*1024*1024 );
-		mi->nr_banks = 2;
-
-		ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
-		setup_ramdisk(1, 0, 0, 4096);
-		setup_initrd( 0xd0000000 + 0x1100004, 0x140000 );
-	}
 
 	else if (machine_is_victor()) {
 		SET_BANK( 0, 0xc0000000, 4*1024*1024 );
@@ -180,6 +199,16 @@
 		pm_power_off = victor_power_off;
 	}
 
+        else if (machine_is_sherman()) {
+                SET_BANK( 0, 0xc0000000, 64*1024*1024 );
+                SET_BANK( 1, 0xc8000000, 64*1024*1024 );
+                mi->nr_banks = 2;
+
+                ROOT_DEV = MKDEV( 60, 2 );
+                setup_ramdisk( 1, 0, 0, 8192 );
+//              setup_initrd( 0xc0400000, 8*1024*1024 );
+}
+
 	else if (machine_is_xp860()) {
 		SET_BANK( 0, 0xc0000000, 32*1024*1024 );
 		mi->nr_banks = 1;
@@ -193,6 +222,15 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+MACHINE_START(PANGOLIN, "Dialogue-Pangolin")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	FIXUP(fixup_sa1100)
+	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_BITSY
@@ -201,6 +239,7 @@
 	BOOT_PARAMS(0xc0000100)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_BRUTUS
@@ -208,6 +247,7 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_CERF
@@ -216,6 +256,7 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_EMPEG
@@ -223,6 +264,7 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
@@ -230,14 +272,16 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_ITSY
 MACHINE_START(ITSY, "Compaq Itsy")
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	BOOT_PARAMS(0xc0000100
+	BOOT_PARAMS(0xc0000100)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_LART
@@ -245,6 +289,7 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_NANOENGINE
@@ -252,6 +297,7 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_PLEB
@@ -259,20 +305,7 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
-MACHINE_END
-#endif
-#ifdef CONFIG_SA1100_THINCLIENT
-MACHINE_START(THINCLIENT, "ADS ThinClient")
-	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	FIXUP(fixup_sa1100)
-	MAPIO(sa1100_map_io)
-MACHINE_END
-#endif
-#ifdef CONFIG_SA1100_TIFON
-MACHINE_START(TIFON, "Tifon")
-	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	FIXUP(fixup_sa1100)
-	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_VICTOR
@@ -280,6 +313,15 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
+MACHINE_END
+#endif
+#ifdef CONFIG_SA1100_SHERMAN
+MACHINE_START(SHERMAN, "Blazie Engineering Sherman")
+        BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+        FIXUP(fixup_sa1100)
+        MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
 #ifdef CONFIG_SA1100_XP860
@@ -287,5 +329,6 @@
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	FIXUP(fixup_sa1100)
 	MAPIO(sa1100_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
 #endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1100.c linux/arch/arm/mach-sa1100/dma-sa1100.c
--- v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1100.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/dma-sa1100.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,538 @@
+/*
+ * arch/arm/kernel/dma-sa1100.c
+ *
+ * Support functions for the SA11x0 internal DMA channels.
+ * (see also Documentation/arm/SA1100/DMA)
+ *
+ * Copyright (C) 2000 Nicolas Pitre
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/mach/dma.h>
+
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK( s, arg... )  printk( "dma<%s>: " s, dma->device_id , ##arg )
+#else
+#define DPRINTK( x... )
+#endif
+
+
+/*
+ * Maximum physical DMA buffer size
+ */
+#define MAX_DMA_SIZE		0x1fff
+#define MAX_DMA_ORDER		12
+
+
+/*
+ * DMA control register structure
+ */
+typedef struct {
+	volatile u_long DDAR;
+	volatile u_long SetDCSR;
+	volatile u_long ClrDCSR;
+	volatile u_long RdDCSR;
+	volatile dma_addr_t DBSA;
+	volatile u_long DBTA;
+	volatile dma_addr_t DBSB;
+	volatile u_long DBTB;
+} dma_regs_t;
+
+
+/*
+ * DMA buffer structure
+ */
+struct dma_buf_s {
+	int size;		/* buffer size */
+	dma_addr_t dma_start;	/* starting DMA address */
+	dma_addr_t dma_ptr;	/* current DMA pointer position */
+	int ref;		/* number of DMA references */
+	void *id;		/* to identify buffer from outside */
+	struct dma_buf_s *next;	/* next buffer to process */
+};
+
+
+#include "dma.h"
+
+sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS];
+
+
+/*
+ * DMA processing...
+ */
+
+static inline int start_sa1100_dma(sa1100_dma_t * dma, dma_addr_t dma_ptr, int size)
+{
+	dma_regs_t *regs = dma->regs;
+	int status;
+	int use_bufa;
+
+	status = regs->RdDCSR;
+
+	/* If both DMA buffers are started, there's nothing else we can do. */
+	if ((status & DCSR_STRTA) && (status & DCSR_STRTB)) {
+		DPRINTK("start: st %#x busy\n", status);
+		return -EBUSY;
+	}
+
+	use_bufa = (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
+		    (!(status & DCSR_BIU) && !(status & DCSR_STRTA)));
+	if (use_bufa) {
+		regs->ClrDCSR = DCSR_DONEA | DCSR_STRTA;
+		regs->DBSA = dma_ptr;
+		regs->DBTA = size;
+		regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
+		DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
+	} else {
+		regs->ClrDCSR = DCSR_DONEB | DCSR_STRTB;
+		regs->DBSB = dma_ptr;
+		regs->DBTB = size;
+		regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
+		DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
+	}
+
+	return 0;
+}
+
+
+static int start_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, int size)
+{
+	if (channel_is_sa1111_sac(dma - dma_chan))
+		return start_sa1111_sac_dma(dma, dma_ptr, size);
+	return start_sa1100_dma(dma, dma_ptr, size);
+}
+
+
+/* This must be called with IRQ disabled */
+static void process_dma(sa1100_dma_t * dma)
+{
+	dma_buf_t *buf;
+	int chunksize;
+
+	for (;;) {
+		buf = dma->tail;
+
+		if (!buf) {
+			/* no more data available */
+			DPRINTK("process: no more buf (dma %s)\n",
+				dma->curr ? "active" : "inactive");
+			/*
+			 * Some devices may require DMA still sending data
+			 * at any time for clock reference, etc.
+			 * Note: if there is still a data buffer being
+			 * processed then the ref count is negative.  This
+			 * allows for the DMA termination to be accounted in
+			 * the proper order.
+			 */
+			if (dma->spin_size && dma->spin_ref >= 0) {
+				chunksize = dma->spin_size;
+				if (chunksize > MAX_DMA_SIZE)
+					chunksize = (1 << MAX_DMA_ORDER);
+				while (start_dma(dma, dma->spin_addr, chunksize) == 0)
+					dma->spin_ref++;
+				if (dma->curr != NULL)
+					dma->spin_ref = -dma->spin_ref;
+			}
+			break;
+		}
+
+		/*
+		 * Let's try to start DMA on the current buffer.
+		 * If DMA is busy then we break here.
+		 */
+		chunksize = buf->size;
+		if (chunksize > MAX_DMA_SIZE)
+			chunksize = (1 << MAX_DMA_ORDER);
+		DPRINTK("process: b=%#x s=%d\n", (int) buf->id, buf->size);
+		if (start_dma(dma, buf->dma_ptr, chunksize) != 0)
+			break;
+		dma->active = 1;
+		if (!dma->curr)
+			dma->curr = buf;
+		buf->ref++;
+		buf->dma_ptr += chunksize;
+		buf->size -= chunksize;
+		if (buf->size == 0) {
+			/* current buffer is done: move tail to the next one */
+			dma->tail = buf->next;
+			DPRINTK("process: next b=%#x\n", (int) dma->tail);
+		}
+	}
+}
+
+
+/* This must be called with IRQ disabled */
+void sa1100_dma_done (sa1100_dma_t *dma)
+{
+	dma_buf_t *buf = dma->curr;
+
+	if (dma->spin_ref > 0) {
+		dma->spin_ref--;
+	} else if (buf) {
+		buf->ref--;
+		if (buf->ref == 0 && buf->size == 0) {
+			/*
+			 * Current buffer is done.
+			 * Move current reference to the next one and send
+			 * the processed buffer to the callback function,
+			 * then discard it.
+			 */
+			DPRINTK("IRQ: buf done\n");
+			dma->curr = buf->next;
+			if (dma->curr == NULL)
+				dma->spin_ref = -dma->spin_ref;
+			if (dma->head == buf)
+				dma->head = NULL;
+			buf->size = buf->dma_ptr - buf->dma_start;
+			if (dma->callback)
+				dma->callback(buf->id, buf->size);
+			kfree(buf);
+		}
+	}
+
+	process_dma(dma);
+}
+
+
+static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	sa1100_dma_t *dma = (sa1100_dma_t *) dev_id;
+	int status = dma->regs->RdDCSR;
+
+	DPRINTK("IRQ: b=%#x st=%#x\n", (int) dma->curr->id, status);
+
+	dma->regs->ClrDCSR = DCSR_ERROR | DCSR_DONEA | DCSR_DONEB;
+	if (!(status & (DCSR_DONEA | DCSR_DONEB)))
+		return;
+
+	sa1100_dma_done (dma);
+}
+
+
+/*
+ * DMA interface functions
+ */
+
+/*
+ * Get dma list
+ * for /proc/dma
+ */
+int sa1100_get_dma_list(char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i < MAX_SA1100_DMA_CHANNELS; i++) {
+		if (dma_chan[i].lock)
+			len += sprintf(buf + len, "%2d: %s\n",
+				       i, dma_chan[i].device_id);
+	}
+	return len;
+}
+
+int sa1100_request_dma(dmach_t * channel, const char *device_id)
+{
+	sa1100_dma_t *dma = NULL;
+	dma_regs_t *regs;
+	int ch, err;
+
+	*channel = -1;		/* to be sure we catch the freeing of a misregistered channel */
+
+	for (ch = 0; ch < SA1100_DMA_CHANNELS; ch++) {
+		dma = &dma_chan[ch];
+		if (xchg(&dma->lock, 1) == 0)
+			break;
+	}
+	if (ch >= SA1100_DMA_CHANNELS) {
+		printk(KERN_ERR "%s: no free DMA channel available\n",
+		       device_id);
+		return -EBUSY;
+	}
+
+	err = request_irq(dma->irq, dma_irq_handler, SA_INTERRUPT,
+			  device_id, (void *) dma);
+	if (err) {
+		printk(KERN_ERR
+		       "%s: unable to request IRQ %d for DMA channel %d\n",
+		       device_id, dma->irq, ch);
+		dma->lock = 0;
+		return err;
+	}
+
+	*channel = ch;
+	dma->device_id = device_id;
+	dma->callback = NULL;
+	dma->spin_size = 0;
+
+	regs = dma->regs;
+	regs->ClrDCSR =
+	    (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
+	     DCSR_IE | DCSR_ERROR | DCSR_RUN);
+	regs->DDAR = 0;
+
+	DPRINTK("requested\n");
+	return 0;
+}
+
+
+int sa1100_dma_set_callback(dmach_t channel, dma_callback_t cb)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+
+	dma->callback = cb;
+	DPRINTK("cb = %p\n", cb);
+	return 0;
+}
+
+
+int sa1100_dma_set_device(dmach_t channel, dma_device_t device)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	dma_regs_t *regs = dma->regs;
+
+	if (dma->ready)
+		return -EINVAL;
+
+	regs->ClrDCSR = DCSR_STRTA | DCSR_STRTB | DCSR_IE | DCSR_RUN;
+	regs->DDAR = device;
+	DPRINTK("DDAR = %#x\n", device);
+	dma->ready = 1;
+	return 0;
+}
+
+
+int sa1100_dma_set_spin(dmach_t channel, dma_addr_t addr, int size)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	int flags;
+
+	if (channel >= SA1100_DMA_CHANNELS)
+		return -EINVAL;
+
+	DPRINTK("set spin %d at %#x\n", size, addr);
+	local_irq_save(flags);
+	dma->spin_addr = addr;
+	dma->spin_size = size;
+	if (size)
+		process_dma(dma);
+	local_irq_restore(flags);
+	return 0;
+}
+
+
+int sa1100_dma_queue_buffer(dmach_t channel, void *buf_id,
+			    dma_addr_t data, int size)
+{
+	sa1100_dma_t *dma;
+	dma_buf_t *buf;
+	int flags;
+
+	dma = &dma_chan[channel];
+	if (!dma->ready)
+		return -EINVAL;
+
+	buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+	if (!buf)
+		return -ENOMEM;
+
+	buf->next = NULL;
+	buf->ref = 0;
+	buf->dma_ptr = buf->dma_start = data;
+	buf->size = size;
+	buf->id = buf_id;
+	DPRINTK("queueing b=%#x a=%#x s=%d\n", (int) buf_id, data, size);
+
+	local_irq_save(flags);
+	if (dma->head)
+		dma->head->next = buf;
+	dma->head = buf;
+	if (!dma->tail)
+		dma->tail = buf;
+	process_dma(dma);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+
+int sa1100_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	dma_regs_t *regs = dma->regs;
+	int flags, ret;
+
+	if (channel_is_sa1111_sac(channel))
+		return sa1111_dma_get_current(channel, buf_id, addr);
+
+	local_irq_save(flags);
+	if (dma->curr && dma->spin_ref <= 0) {
+		dma_buf_t *buf = dma->curr;
+		int status, using_bufa;
+
+		status = regs->RdDCSR;
+		/*
+		 * If we got here, that's because there is, or recently was, a
+		 * buffer being processed.  We must determine whether buffer
+		 * A or B is active.  Two possibilities: either we are
+		 * in the middle of a buffer, or the DMA controller just
+		 * switched to the next toggle but the interrupt hasn't been
+		 * serviced yet.  The former case is straight forward.  In
+		 * the later case, we'll do like if DMA is just at the end
+		 * of the previous toggle since all registers haven't been
+		 * reset yet.  This goes around the edge case and since we're
+		 * always a little behind anyways it shouldn't make a big
+		 * difference.  If DMA has been stopped prior calling this
+		 * then the position is always exact.
+		 */
+		using_bufa = ((!(status & DCSR_BIU) &&  (status & DCSR_STRTA)) ||
+			      ( (status & DCSR_BIU) && !(status & DCSR_STRTB)));
+		if (buf_id)
+			*buf_id = buf->id;
+		*addr = (using_bufa) ? regs->DBSA : regs->DBSB;
+		/*
+		 * Clamp funky pointers sometimes returned by the hardware
+		 * on completed DMA transfers
+		 */
+		if (*addr < buf->dma_start ||
+		    *addr > buf->dma_ptr)
+			*addr = buf->dma_ptr;
+		DPRINTK("curr_pos: b=%#x a=%#x\n", (int)dma->curr->id, *addr);
+		ret = 0;
+	} else {
+		if (buf_id)
+			*buf_id = NULL;
+		*addr = 0;
+		DPRINTK("curr_pos: spinning\n");
+		ret = -ENXIO;
+	}
+	local_irq_restore(flags);
+	return ret;
+}
+
+
+int sa1100_dma_stop(dmach_t channel)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	dma_regs_t *regs = dma->regs;
+
+	if (channel_is_sa1111_sac(channel))
+		return sa1111_dma_stop(channel);
+
+	regs->ClrDCSR = DCSR_RUN | DCSR_IE;
+	return 0;
+}
+
+
+int sa1100_dma_resume(dmach_t channel)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	dma_regs_t *regs = dma->regs;
+
+	if (channel_is_sa1111_sac(channel))
+		return sa1111_dma_resume(channel);
+
+	regs->SetDCSR = DCSR_RUN | DCSR_IE;
+	return 0;
+}
+
+
+int sa1100_dma_flush_all(dmach_t channel)
+{
+	sa1100_dma_t *dma;
+	dma_buf_t *buf, *next_buf;
+	int flags;
+
+	dma = &dma_chan[channel];
+	local_irq_save(flags);
+	if (channel_is_sa1111_sac(channel))
+		sa1111_reset_sac_dma(channel);
+	else
+		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
+	buf = dma->curr;
+	if (!buf)
+		buf = dma->tail;
+	dma->head = dma->tail = dma->curr = NULL;
+	dma->active = 0;
+	dma->spin_ref = 0;
+	if (dma->spin_size)
+		process_dma(dma);
+	local_irq_restore(flags);
+	while (buf) {
+		next_buf = buf->next;
+		kfree(buf);
+		buf = next_buf;
+	}
+	DPRINTK("flushed\n");
+	return 0;
+}
+
+
+void sa1100_free_dma(dmach_t channel)
+{
+	sa1100_dma_t *dma;
+
+	if ((unsigned) channel >= MAX_SA1100_DMA_CHANNELS)
+		return;
+
+	dma = &dma_chan[channel];
+	if (!dma->lock) {
+		printk(KERN_ERR "Trying to free free DMA%d\n", channel);
+		return;
+	}
+
+	sa1100_dma_set_spin(channel, 0, 0);
+	sa1100_dma_flush_all(channel);
+	dma->ready = 0;
+
+	if (channel_is_sa1111_sac(channel)) {
+		sa1111_cleanup_sac_dma(channel);
+	} else {
+		free_irq(IRQ_DMA0 + channel, (void *) dma);
+	}
+	dma->lock = 0;
+
+	DPRINTK("freed\n");
+}
+
+
+EXPORT_SYMBOL(sa1100_request_dma);
+EXPORT_SYMBOL(sa1100_dma_set_callback);
+EXPORT_SYMBOL(sa1100_dma_set_device);
+EXPORT_SYMBOL(sa1100_dma_set_spin);
+EXPORT_SYMBOL(sa1100_dma_queue_buffer);
+EXPORT_SYMBOL(sa1100_dma_get_current);
+EXPORT_SYMBOL(sa1100_dma_stop);
+EXPORT_SYMBOL(sa1100_dma_resume);
+EXPORT_SYMBOL(sa1100_dma_flush_all);
+EXPORT_SYMBOL(sa1100_free_dma);
+
+
+static int __init sa1100_init_dma(void)
+{
+	int channel;
+	for (channel = 0; channel < SA1100_DMA_CHANNELS; channel++) {
+		dma_chan[channel].regs =
+		    (dma_regs_t *) io_p2v(_DDAR(channel));
+		dma_chan[channel].irq = IRQ_DMA0 + channel;
+	}
+	return 0;
+}
+
+__initcall(sa1100_init_dma);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1111.c linux/arch/arm/mach-sa1100/dma-sa1111.c
--- v2.4.3/linux/arch/arm/mach-sa1100/dma-sa1111.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/dma-sa1111.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,346 @@
+/*
+ *  linux/arch/arm/mach-sa1100/dma-sa1111.c
+ *
+ *  Copyright (C) 2000 John Dorsey
+ *
+ *  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.
+ *
+ *  4 September 2000 - created.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+
+// #define DEBUG
+#ifdef DEBUG
+#define DPRINTK( s, arg... )  printk( "dma<%s>: " s, dma->device_id , ##arg )
+#else
+#define DPRINTK( x... )
+#endif
+
+
+/*
+ * Control register structure for the SA1111 SAC DMA
+ */
+
+typedef struct {
+	volatile u_long SAD_CS;
+	volatile dma_addr_t SAD_SA;
+	volatile u_long SAD_CA;
+	volatile dma_addr_t SAD_SB;
+	volatile u_long SAD_CB;
+} dma_regs_t;
+
+#include "dma.h"
+
+
+void sa1111_reset_sac_dma(dmach_t channel)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	dma->regs->SAD_CS = 0;
+	mdelay(1);
+	dma->dma_a = dma->dma_b = 0;
+}
+
+
+int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size)
+{
+  	dma_regs_t *sac_regs = dma->regs;
+
+	DPRINTK(" SAC DMA %cCS %02x at %08x (%d)\n",
+		(sac_regs==&SADTCS)?'T':'R', sac_regs->SAD_CS, dma_ptr, size);
+
+	/* The minimum transfer length requirement has not yet been
+	 * verified:
+	 */
+	if( size < SA1111_SAC_DMA_MIN_XFER )
+	  printk(KERN_WARNING "Warning: SAC xfers below %u bytes may be buggy!"
+		 " (%u bytes)\n", SA1111_SAC_DMA_MIN_XFER, size);
+
+	if( dma->dma_a && dma->dma_b ){
+	  	DPRINTK("  neither engine available! (A %d, B %d)\n",
+			dma->dma_a, dma->dma_b);
+	  	return -1;
+	}
+
+	if( sa1111_check_dma_bug(dma_ptr) )
+	  	printk(KERN_WARNING "Warning: DMA address %08x is buggy!\n",
+		       dma_ptr);
+
+	if( (dma->last_dma || dma->dma_b) && dma->dma_a == 0 ){
+	  	if( sac_regs->SAD_CS & SAD_CS_DBDB ){
+		  	DPRINTK("  awaiting \"done B\" interrupt, not starting\n");
+			return -1;
+		}
+		sac_regs->SAD_SA = SA1111_DMA_ADDR((u_int)dma_ptr);
+		sac_regs->SAD_CA = size;
+		sac_regs->SAD_CS = SAD_CS_DSTA | SAD_CS_DEN;
+		++dma->dma_a;
+		DPRINTK("  with A [%02lx %08lx %04lx]\n", sac_regs->SAD_CS,
+			sac_regs->SAD_SA, sac_regs->SAD_CA);
+	} else {
+	  	if( sac_regs->SAD_CS & SAD_CS_DBDA ){
+		  	DPRINTK("  awaiting \"done A\" interrupt, not starting\n");
+			return -1;
+		}
+		sac_regs->SAD_SB = SA1111_DMA_ADDR((u_int)dma_ptr);
+		sac_regs->SAD_CB = size;
+		sac_regs->SAD_CS = SAD_CS_DSTB | SAD_CS_DEN;
+		++dma->dma_b;
+		DPRINTK("  with B [%02lx %08lx %04lx]\n", sac_regs->SAD_CS,
+			sac_regs->SAD_SB, sac_regs->SAD_CB);
+	}
+
+	/* Additional delay to avoid DMA engine lockup during record: */
+	if( sac_regs == (dma_regs_t*)&SADRCS )
+	  	mdelay(1);	/* NP : wouuuh! ugly... */
+
+	return 0;
+}
+
+
+static void sa1111_sac_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+  	sa1100_dma_t *dma = (sa1100_dma_t *) dev_id;
+
+	DPRINTK("irq %d, last DMA serviced was %c, CS %02x\n", irq,
+		dma->last_dma?'B':'A', dma->regs->SAD_CS);
+
+	/* Occasionally, one of the DMA engines (A or B) will
+	 * lock up. We try to deal with this by quietly kicking
+	 * the control register for the afflicted transfer
+	 * direction.
+	 *
+	 * Note for the debugging-inclined: we currently aren't
+	 * properly flushing the DMA engines during channel
+	 * shutdown. A slight hiccup at the beginning of playback
+	 * after a channel has been stopped can be heard as
+	 * evidence of this. Programmatically, this shows up
+	 * as either a locked engine, or a spurious interrupt. -jd
+	 */
+
+	if(irq==AUDXMTDMADONEA || irq==AUDRCVDMADONEA){
+
+	  	if(dma->last_dma == 0){
+		  	DPRINTK("DMA B has locked up!\n");
+			dma->regs->SAD_CS = 0;
+			mdelay(1);
+			dma->dma_a = dma->dma_b = 0;
+		} else {
+		  	if(dma->dma_a == 0)
+			  	DPRINTK("spurious SAC IRQ %d\n", irq);
+			else {
+			  	--dma->dma_a;
+
+				/* Servicing the SAC DMA engines too quickly
+				 * after they issue a DONE interrupt causes
+				 * them to lock up.
+				 */
+				if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB)
+				  	mdelay(1);
+			}
+		}
+
+		dma->regs->SAD_CS = SAD_CS_DBDA | SAD_CS_DEN; /* w1c */
+		dma->last_dma = 0;
+
+	} else {
+
+	  	if(dma->last_dma == 1){
+		  	DPRINTK("DMA A has locked up!\n");
+			dma->regs->SAD_CS = 0;
+			mdelay(1);
+			dma->dma_a = dma->dma_b = 0;
+		} else {
+		  	if(dma->dma_b == 0)
+			  	DPRINTK("spurious SAC IRQ %d\n", irq);
+			else {
+			  	--dma->dma_b;
+
+				/* See lock-up note above. */
+				if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB)
+				  	mdelay(1);
+			}
+		}
+
+		dma->regs->SAD_CS = SAD_CS_DBDB | SAD_CS_DEN; /* w1c */
+		dma->last_dma = 1;
+
+	}
+
+	/* NP: maybe this shouldn't be called in all cases? */
+	sa1100_dma_done (dma);
+}
+
+
+int sa1111_sac_request_dma(dmach_t *channel, const char *device_id,
+			   unsigned int direction)
+{
+	sa1100_dma_t *dma = NULL;
+	int ch, irq, err;
+
+	*channel = -1;		/* to be sure we catch the freeing of a misregistered channel */
+
+	ch = SA1111_SAC_DMA_BASE + direction;
+
+	if (!channel_is_sa1111_sac(ch)) {
+	  	printk(KERN_ERR "%s: invalid SA-1111 SAC DMA channel (%d)\n",
+		       device_id, ch);
+		return -1;
+	}
+
+	dma = &dma_chan[ch];
+
+	if (xchg(&dma->lock, 1) == 1) {
+	  	printk(KERN_ERR "%s: SA-1111 SAC DMA channel %d in use\n",
+		       device_id, ch);
+		return -EBUSY;
+	}
+
+	irq = AUDXMTDMADONEA + direction;
+	err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT,
+			  device_id, (void *) dma);
+	if (err) {
+		printk(KERN_ERR
+		       "%s: unable to request IRQ %d for DMA channel %d (A)\n",
+		       device_id, irq, ch);
+		dma->lock = 0;
+		return err;
+	}
+
+	irq = AUDXMTDMADONEB + direction;
+	err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT,
+			  device_id, (void *) dma);
+	if (err) {
+		printk(KERN_ERR
+		       "%s: unable to request IRQ %d for DMA channel %d (B)\n",
+		       device_id, irq, ch);
+		dma->lock = 0;
+		return err;
+	}
+
+	*channel = ch;
+	dma->device_id = device_id;
+	dma->callback = NULL;
+	dma->spin_size = 0;
+	dma->ready = 1;
+
+	return 0;
+}
+
+
+/* FIXME:  need to complete the three following functions */
+
+int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr)
+{
+	return -ENOSYS;
+}
+
+int sa1111_dma_stop(dmach_t channel)
+{
+	return 0;
+}
+
+int sa1111_dma_resume(dmach_t channel)
+{
+	return 0;
+}
+
+
+void sa1111_cleanup_sac_dma(dmach_t channel)
+{
+	sa1100_dma_t *dma = &dma_chan[channel];
+	free_irq(AUDXMTDMADONEA + (channel - SA1111_SAC_DMA_BASE), (void*) dma);
+	free_irq(AUDXMTDMADONEB + (channel - SA1111_SAC_DMA_BASE), (void*) dma);
+}
+
+
+/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
+ * Chip Specification Update" (June 2000), errata #7, there is a
+ * significant bug in Serial Audio Controller DMA. If the SAC is
+ * accessing a region of memory above 1MB relative to the bank base,
+ * it is important that address bit 10 _NOT_ be asserted. Depending
+ * on the configuration of the RAM, bit 10 may correspond to one
+ * of several different (processor-relative) address bits.
+ *
+ * This routine only identifies whether or not a given DMA address
+ * is susceptible to the bug.
+ */
+int sa1111_check_dma_bug(dma_addr_t addr){
+	unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr);
+
+	/* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
+	 * User's Guide" mentions that jumpers R51 and R52 control the
+	 * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
+	 * SDRAM bank 1 on Neponset). The default configuration selects
+	 * Assabet, so any address in bank 1 is necessarily invalid.
+	 */
+	if(machine_is_assabet() && addr >= _DRAMBnk1)
+	  	return -1;
+
+	/* The bug only applies to buffers located more than one megabyte
+	 * above the start of the target bank:
+	 */
+	if(physaddr<(1<<20))
+	  	return 0;
+
+	switch(FExtr(SMCR, SMCR_DRAC)){
+	case 01: /* 10 row + bank address bits, A<20> must not be set */
+	  	if(physaddr & (1<<20))
+		  	return -1;
+		break;
+	case 02: /* 11 row + bank address bits, A<23> must not be set */
+	  	if(physaddr & (1<<23))
+		  	return -1;
+		break;
+	case 03: /* 12 row + bank address bits, A<24> must not be set */
+	  	if(physaddr & (1<<24))
+		  	return -1;
+		break;
+	case 04: /* 13 row + bank address bits, A<25> must not be set */
+	  	if(physaddr & (1<<25))
+		  	return -1;
+		break;
+	case 05: /* 14 row + bank address bits, A<20> must not be set */
+	  	if(physaddr & (1<<20))
+		  	return -1;
+		break;
+	case 06: /* 15 row + bank address bits, A<20> must not be set */
+	  	if(physaddr & (1<<20))
+		  	return -1;
+		break;
+	default:
+	  	printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%o\n",
+		       __FUNCTION__, FExtr(SMCR, SMCR_DRAC));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+EXPORT_SYMBOL(sa1111_sac_request_dma);
+EXPORT_SYMBOL(sa1111_check_dma_bug);
+
+
+static void __init sa1111_init_sac_dma(void)
+{
+	int channel = SA1111_SAC_DMA_BASE;
+	dma_chan[channel++].regs = (dma_regs_t *) &SADTCS;
+	dma_chan[channel++].regs = (dma_regs_t *) &SADRCS;
+}
+
+__initcall(sa1111_init_sac_dma);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-sa1100/dma.h linux/arch/arm/mach-sa1100/dma.h
--- v2.4.3/linux/arch/arm/mach-sa1100/dma.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-sa1100/dma.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,56 @@
+/*
+ * Definitions shared between dma-sa1100.c and dma-sa1111.c
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * 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.
+ */
+
+
+/*
+ * DMA channel structure.
+ */
+
+typedef struct dma_buf_s dma_buf_t;
+
+typedef struct {
+	unsigned int lock;      /* Device is allocated */
+	const char *device_id;  /* Device name */
+	dma_buf_t *head;        /* where to insert buffers */
+	dma_buf_t *tail;        /* where to remove buffers */
+	dma_buf_t *curr;        /* buffer currently DMA'ed */
+	int ready;              /* 1 if DMA can occur */
+	int active;             /* 1 if DMA is actually processing data */
+	dma_regs_t *regs;       /* points to appropriate DMA registers */
+	int irq;                /* IRQ used by the channel */
+	dma_callback_t callback;        /* ... to call when buffers are done */
+	int spin_size;          /* > 0 when DMA should spin when no more buffer */
+	dma_addr_t spin_addr;   /* DMA address to spin onto */
+	int spin_ref;           /* number of spinning references */
+#ifdef CONFIG_SA1111
+	int dma_a, dma_b, last_dma;	/* SA-1111 specific */
+#endif
+} sa1100_dma_t;
+
+extern sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS];
+
+
+int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size);
+int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr);
+int sa1111_dma_stop(dmach_t channel);
+int sa1111_dma_resume(dmach_t channel);
+void sa1111_reset_sac_dma(dmach_t channel);
+void sa1111_cleanup_sac_dma(dmach_t channel);
+
+void sa1100_dma_done (sa1100_dma_t *dma);
+
+
+#ifdef CONFIG_SA1111
+#define channel_is_sa1111_sac(ch) \
+	((ch) >= SA1111_SAC_DMA_BASE && \
+	 (ch) <  SA1111_SAC_DMA_BASE + SA1111_SAC_DMA_CHANNELS)
+#else
+#define channel_is_sa1111_sac(ch) (0)
+#endif
+
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/Makefile linux/arch/arm/mach-shark/Makefile
--- v2.4.3/linux/arch/arm/mach-shark/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/mach-shark/Makefile	Thu Apr 12 12:20:31 2001
@@ -18,6 +18,6 @@
 
 export-objs		:= 
 
-#obj-$(CONFIG_LEDS)	+= leds.o
+obj-$(CONFIG_LEDS)	+= leds.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/arch.c linux/arch/arm/mach-shark/arch.c
--- v2.4.3/linux/arch/arm/mach-shark/arch.c	Tue Sep 19 08:31:53 2000
+++ linux/arch/arm/mach-shark/arch.c	Thu Apr 12 12:20:31 2001
@@ -18,14 +18,31 @@
 
 #include <asm/mach/arch.h>
 
-extern void setup_initrd(unsigned int start, unsigned int size);
-extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
-extern void __init footbridge_map_io(void);
-extern void __init shark_map_io(void);
+static void __init
+fixup_shark(struct machine_desc *desc, struct param_struct *params,
+	char **cmdline, struct meminfo *mi) {
+	int i;
+
+	mi->nr_banks=0;
+	for (i=0;i<NR_BANKS;i++) {
+		if (params->u1.s.pages_in_bank[i] != 0) {
+			mi->nr_banks++;
+			mi->bank[i].node  = 0;
+			mi->bank[i].start = params->u1.s.pages_in_bank[i] & 0xffff0000;
+			mi->bank[i].size  = (params->u1.s.pages_in_bank[i] & 0xffff)*PAGE_SIZE;
+			params->u1.s.pages_in_bank[i] &= 0xffff;
+		}
+	}
+}
+
+extern void shark_map_io(void);
+extern void genarch_init_irq(void);
 
 MACHINE_START(SHARK, "Shark")
 	MAINTAINER("Alexander Schulz")
 	BOOT_MEM(0x08000000, 0x40000000, 0xe0000000)
-	VIDEO(0x06000000, 0x061fffff)
+	BOOT_PARAMS(0x08003000)
+	FIXUP(fixup_shark)
 	MAPIO(shark_map_io)
+	INITIRQ(genarch_init_irq)
 MACHINE_END
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/dma.c linux/arch/arm/mach-shark/dma.c
--- v2.4.3/linux/arch/arm/mach-shark/dma.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mach-shark/dma.c	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/mach-shark/dma.c
  *
- *  by Alexander.Schulz@stud.uni-karlsruhe.de
+ *  by Alexander Schulz <aschulz@netwinder.org>
  *
  *  derived from:
  *  arch/arm/kernel/dma-ebsa285.c
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/leds.c linux/arch/arm/mach-shark/leds.c
--- v2.4.3/linux/arch/arm/mach-shark/leds.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-shark/leds.c	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,163 @@
+/*
+ * arch/arm/kernel/leds-shark.c
+ * by Alexander Schulz <aschulz@netwinder.org>
+ *
+ * derived from:
+ * arch/arm/kernel/leds-footbridge.c
+ * Copyright (C) 1998-1999 Russell King
+ *
+ * DIGITAL Shark LED control routines.
+ *
+ * The leds use is as follows:
+ *  - Green front - toggles state every 50 timer interrupts
+ *  - Amber front - Unused, this is a dual color led (Amber/Green)
+ *  - Amber back  - On if system is not idle
+ *
+ * Changelog:
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define LED_STATE_ENABLED	1
+#define LED_STATE_CLAIMED	2
+static char led_state;
+static short hw_led_state;
+static short saved_state;
+
+static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED;
+
+short sequoia_read(int addr) {
+  outw(addr,0x24);
+  return inw(0x26);
+}
+
+void sequoia_write(short value,short addr) {
+  outw(addr,0x24);
+  outw(value,0x26);
+}
+
+static void sequoia_leds_event(led_event_t evt)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&leds_lock, flags);
+
+	hw_led_state = sequoia_read(0x09);
+
+	switch (evt) {
+	case led_start:
+		hw_led_state |= SEQUOIA_LED_GREEN;
+		hw_led_state |= SEQUOIA_LED_AMBER;
+#ifdef CONFIG_LEDS_CPU
+		hw_led_state |= SEQUOIA_LED_BACK;
+#else
+		hw_led_state &= ~SEQUOIA_LED_BACK;
+#endif
+		led_state |= LED_STATE_ENABLED;
+		break;
+
+	case led_stop:
+		hw_led_state &= ~SEQUOIA_LED_BACK;
+		hw_led_state |= SEQUOIA_LED_GREEN;
+		hw_led_state |= SEQUOIA_LED_AMBER;
+		led_state &= ~LED_STATE_ENABLED;
+		break;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		saved_state = hw_led_state;
+		hw_led_state &= ~SEQUOIA_LED_BACK;
+		hw_led_state |= SEQUOIA_LED_GREEN;
+		hw_led_state |= SEQUOIA_LED_AMBER;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		hw_led_state = saved_state;
+		break;
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state ^= SEQUOIA_LED_GREEN;
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state &= ~SEQUOIA_LED_BACK;
+		break;
+
+	case led_idle_end:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state |= SEQUOIA_LED_BACK;
+		break;
+#endif
+
+	case led_green_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~SEQUOIA_LED_GREEN;
+		break;
+
+	case led_green_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= SEQUOIA_LED_GREEN;
+		break;
+
+	case led_amber_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~SEQUOIA_LED_AMBER;
+		break;
+
+	case led_amber_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= SEQUOIA_LED_AMBER;
+		break;
+
+	case led_red_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= SEQUOIA_LED_BACK;
+		break;
+
+	case led_red_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~SEQUOIA_LED_BACK;
+		break;
+
+	default:
+		break;
+	}
+
+	if  (led_state & LED_STATE_ENABLED)
+		sequoia_write(hw_led_state,0x09);
+
+	spin_unlock_irqrestore(&leds_lock, flags);
+}
+
+static int __init leds_init(void)
+{
+	extern void (*leds_event)(led_event_t);
+	short temp;
+	
+	leds_event = sequoia_leds_event;
+
+	/* Make LEDs independent of power-state */
+	request_region(0x24,4,"sequoia");
+	temp = sequoia_read(0x09);
+	temp |= 1<<10;
+	sequoia_write(temp,0x09);
+	leds_event(led_start);
+	return 0;
+}
+
+__initcall(leds_init);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mach-shark/mm.c linux/arch/arm/mach-shark/mm.c
--- v2.4.3/linux/arch/arm/mach-shark/mm.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mach-shark/mm.c	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/mach-shark/mm.c
  *
- *  by Alexander.Schulz@stud.uni-karlsruhe.de
+ *  by Alexander Schulz <aschulz@netwinder.org>
  *
  * 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
@@ -19,8 +19,6 @@
 
 static struct map_desc shark_io_desc[] __initdata = {
 	{ IO_BASE	, IO_START	, IO_SIZE	, DOMAIN_IO, 0, 1, 0, 0 },
-	{ FB_BASE	, FB_START	, FB_SIZE	, DOMAIN_IO, 0, 1, 0, 0 },
-	{ FBREG_BASE	, FBREG_START	, FBREG_SIZE	, DOMAIN_IO, 0, 1, 0, 0 },
 	LAST_DESC
 };
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile
--- v2.4.3/linux/arch/arm/mm/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/mm/Makefile	Thu Apr 12 12:20:31 2001
@@ -13,13 +13,22 @@
 
 # Object file lists.
 
-obj-y		:= extable.o fault-common.o fault-$(PROCESSOR).o init.o \
-		   mm-$(PROCESSOR).o small_page.o
+obj-y		:= init.o
 obj-m		:=
 obj-n		:=
 obj-		:=
 export-objs	:= proc-syms.o
 
+cpu32-y		:= consistent.o fault-armv.o ioremap.o mm-armv.o
+cpu32-$(CONFIG_MODULES) += proc-syms.o
+
+obj-y		+= extable.o fault-common.o
+obj-$(CONFIG_CPU_26) += fault-armo.o mm-armo.o small_page.o
+obj-$(CONFIG_CPU_32) += $(cpu32-y)
+
+obj-$(CONFIG_DISCONTIGMEM) += discontig.o
+
+# Select the processor-specific files
 p-$(CONFIG_CPU_26)	+= proc-arm2,3.o
 p-$(CONFIG_CPU_ARM610)	+= proc-arm6,7.o
 p-$(CONFIG_CPU_ARM710)	+= proc-arm6,7.o
@@ -29,11 +38,6 @@
 p-$(CONFIG_CPU_SA110)	+= proc-sa110.o
 p-$(CONFIG_CPU_SA1100)	+= proc-sa110.o
 
-obj-$(CONFIG_CPU_32)  	+= consistent.o ioremap.o
-ifeq ($(CONFIG_CPU_32),y)
-obj-$(CONFIG_MODULES)	+= proc-syms.o
-endif
-
 # Integrator follows "new style"
 # Soon, others will do too, and we can get rid of this
 MMMACH		:= mm-$(MACHINE).c
@@ -46,10 +50,4 @@
 include $(TOPDIR)/Rules.make
 
 # Special dependencies
-proc-arm2,3.o:	../lib/constants.h
-proc-arm6,7.o:	../lib/constants.h
-proc-arm720.o:	../lib/constants.h
-proc-arm920.o:	../lib/constants.h
-proc-arm10.o:	../lib/constants.h
-proc-sa110.o:	../lib/constants.h
-
+$(p-y):	$(TOPDIR)/include/asm-arm/constants.h
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c
--- v2.4.3/linux/arch/arm/mm/consistent.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/consistent.c	Thu Apr 12 12:20:31 2001
@@ -34,9 +34,9 @@
  */
 void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
 {
-	int order;
-	unsigned long page;
-	void *ret;
+	struct page *page, *end, *free;
+	unsigned long order;
+	void *ret, *virt;
 
 	if (in_interrupt())
 		BUG();
@@ -44,37 +44,47 @@
 	size = PAGE_ALIGN(size);
 	order = get_order(size);
 
-	page = __get_free_pages(gfp, order);
+	page = alloc_pages(gfp, order);
 	if (!page)
 		goto no_page;
 
-	ret = __ioremap(virt_to_phys((void *)page), size, 0);
-	if (ret) {
-		/* free wasted pages */
-		unsigned long end;
-
-		/*
-		 * we need to ensure that there are no
-		 * cachelines in use, or worse dirty in
-		 * this area.
-		 */
-		invalidate_dcache_range(page, page + size);
-		invalidate_dcache_range((unsigned long)ret, (unsigned long)ret + size);
-
-		*dma_handle = __virt_to_bus(page);
-
-		end = page + (PAGE_SIZE << order);
-		page += size;
-		while (page < end) {
-			free_page(page);
-			page += PAGE_SIZE;
-		}
-		return ret;
+	/*
+	 * We could do with a page_to_phys and page_to_bus here.
+	 */
+	virt = page_address(page);
+	*dma_handle = virt_to_bus(virt);
+	ret = __ioremap(virt_to_phys(virt), size, 0);
+	if (!ret)
+		goto no_remap;
+
+#if 0 /* ioremap_does_flush_cache_all */
+	/*
+	 * we need to ensure that there are no cachelines in use, or
+	 * worse dirty in this area.  Really, we don't need to do
+	 * this since __ioremap does a flush_cache_all() anyway. --rmk
+	 */
+	invalidate_dcache_range(virt, virt + size);
+#endif
+
+	/*
+	 * free wasted pages.  We skip the first page since
+	 * we know that it will have count = 1 and won't
+	 * require freeing.
+	 */
+	page = virt_to_page(virt);
+	free = page + (size >> PAGE_SHIFT);
+	end  = page + (1 << order);
+
+	while (++page < end) {
+		set_page_count(page, 1);
+		if (page >= free)
+			__free_page(page);
 	}
+	return ret;
 
-	free_pages(page, order);
+no_remap:
+	__free_pages(page, order);
 no_page:
-	BUG();
 	return NULL;
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.4.3/linux/arch/arm/mm/fault-armv.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/mm/fault-armv.c	Thu Apr 12 12:20:31 2001
@@ -2,7 +2,7 @@
  *  linux/arch/arm/mm/fault-armv.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Modifications for ARM processor (c) 1995-1999 Russell King
+ *  Modifications for ARM processor (c) 1995-2001 Russell King
  *
  * 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
@@ -29,7 +29,13 @@
 
 extern void die_if_kernel(const char *str, struct pt_regs *regs, int err);
 extern void show_pte(struct mm_struct *mm, unsigned long addr);
-extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs);
+extern int do_page_fault(unsigned long addr, int error_code,
+			 struct pt_regs *regs);
+extern int do_translation_fault(unsigned long addr, int error_code,
+				struct pt_regs *regs);
+extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
+			unsigned long addr, int error_code,
+			struct pt_regs *regs);
 
 #ifdef CONFIG_ALIGNMENT_TRAP
 /*
@@ -37,12 +43,11 @@
  * /proc/sys/debug/alignment, modified and integrated into
  * Linux 2.1 by Russell King
  *
+ * Speed optimisations and better fault handling by Russell King.
+ *
  * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet.  Also,
  * it seems to give a severe performance impact (1 abort/ms - NW runs at
  * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
- *
- * IMHO, I don't think that the trap handler is advantageous on ARM6,7
- * processors (they'll run like an ARM3).  We'll see.
  */
 #define CODING_BITS(i)	(i & 0x0e000000)
 
@@ -115,91 +120,323 @@
 __initcall(alignment_init);
 #endif /* CONFIG_SYSCTL */
 
+union offset_union {
+	unsigned long un;
+	  signed long sn;
+};
+
+#define TYPE_ERROR	0
+#define TYPE_FAULT	1
+#define TYPE_LDST	2
+#define TYPE_DONE	3
+
+#define get8_unaligned_check(val,addr,err)		\
+	__asm__(					\
+	"1:	ldrb	%1, [%2]\n"			\
+	"2:\n"						\
+	"	.section .fixup,\"ax\"\n"		\
+	"	.align	2\n"				\
+	"3:	mov	%0, #1\n"			\
+	"	b	2b\n"				\
+	"	.previous\n"				\
+	"	.section __ex_table,\"a\"\n"		\
+	"	.align	3\n"				\
+	"	.long	1b, 3b\n"			\
+	"	.previous\n"				\
+	: "=r" (err), "=&r" (val), "=r" (addr)		\
+	: "0" (err), "2" (addr))
+
+#define get8t_unaligned_check(val,addr,err)		\
+	__asm__(					\
+	"1:	ldrbt	%1, [%2]\n"			\
+	"2:\n"						\
+	"	.section .fixup,\"ax\"\n"		\
+	"	.align	2\n"				\
+	"3:	mov	%0, #1\n"			\
+	"	b	2b\n"				\
+	"	.previous\n"				\
+	"	.section __ex_table,\"a\"\n"		\
+	"	.align	3\n"				\
+	"	.long	1b, 3b\n"			\
+	"	.previous\n"				\
+	: "=r" (err), "=&r" (val), "=r" (addr)		\
+	: "0" (err), "2" (addr))
+
+#define get16_unaligned_check(val,addr)				\
+	do {							\
+		unsigned int err = 0, v, a = addr;		\
+		get8_unaligned_check(val,a,err);		\
+		get8_unaligned_check(v,a,err);			\
+		val |= v << 8;					\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define put16_unaligned_check(val,addr)				\
+	do {							\
+		unsigned int err = 0, v = val, a = addr;	\
+		__asm__(					\
+		"1:	strb	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"2:	strb	%1, [%2]\n"			\
+		"3:\n"						\
+		"	.section .fixup,\"ax\"\n"		\
+		"	.align	2\n"				\
+		"4:	mov	%0, #1\n"			\
+		"	b	3b\n"				\
+		"	.previous\n"				\
+		"	.section __ex_table,\"a\"\n"		\
+		"	.align	3\n"				\
+		"	.long	1b, 4b\n"			\
+		"	.long	2b, 4b\n"			\
+		"	.previous\n"				\
+		: "=r" (err), "=&r" (v), "=&r" (a)		\
+		: "0" (err), "1" (v), "2" (a));			\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define __put32_unaligned_check(ins,val,addr)			\
+	do {							\
+		unsigned int err = 0, v = val, a = addr;	\
+		__asm__(					\
+		"1:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"2:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"3:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"4:	"ins"	%1, [%2]\n"			\
+		"5:\n"						\
+		"	.section .fixup,\"ax\"\n"		\
+		"	.align	2\n"				\
+		"6:	mov	%0, #1\n"			\
+		"	b	5b\n"				\
+		"	.previous\n"				\
+		"	.section __ex_table,\"a\"\n"		\
+		"	.align	3\n"				\
+		"	.long	1b, 6b\n"			\
+		"	.long	2b, 6b\n"			\
+		"	.long	3b, 6b\n"			\
+		"	.long	4b, 6b\n"			\
+		"	.previous\n"				\
+		: "=r" (err), "=&r" (v), "=&r" (a)		\
+		: "0" (err), "1" (v), "2" (a));			\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define get32_unaligned_check(val,addr)				\
+	do {							\
+		unsigned int err = 0, v, a = addr;		\
+		get8_unaligned_check(val,a,err);		\
+		get8_unaligned_check(v,a,err);			\
+		val |= v << 8;					\
+		get8_unaligned_check(v,a,err);			\
+		val |= v << 16;					\
+		get8_unaligned_check(v,a,err);			\
+		val |= v << 24;					\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define put32_unaligned_check(val,addr)	 \
+	__put32_unaligned_check("strb", val, addr)
+
+#define get32t_unaligned_check(val,addr)			\
+	do {							\
+		unsigned int err = 0, v, a = addr;		\
+		get8t_unaligned_check(val,a,err);		\
+		get8t_unaligned_check(v,a,err);			\
+		val |= v << 8;					\
+		get8t_unaligned_check(v,a,err);			\
+		val |= v << 16;					\
+		get8t_unaligned_check(v,a,err);			\
+		val |= v << 24;					\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define put32t_unaligned_check(val,addr) \
+	__put32_unaligned_check("strbt", val, addr)
+
+static void
+do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
+{
+	if (!LDST_U_BIT(instr))
+		offset.un = -offset.un;
+
+	if (!LDST_P_BIT(instr))
+		addr += offset.un;
+
+	if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
+		regs->uregs[RN_BITS(instr)] = addr;
+}
+
 static int
-do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
+do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
 {
-	unsigned int instr, rd, rn, correction, nr_regs, regbits;
-	unsigned long eaddr;
-	union { unsigned long un; signed long sn; } offset;
+	unsigned int rd = RD_BITS(instr);
 
-	if (user_mode(regs)) {
-		set_cr(cr_no_alignment);
-		ai_user += 1;
-		return 0;
-	}
+	if ((instr & 0x01f00ff0) == 0x01000090)
+		goto swp;
 
-	ai_sys += 1;
+	if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
+		goto bad;
+
+	ai_half += 1;
+
+	if (LDST_L_BIT(instr)) {
+		unsigned long val;
+		get16_unaligned_check(val, addr);
+
+		/* signed half-word? */
+		if (instr & 0x40)
+			val = (signed long)((signed short) val);
+
+		regs->uregs[rd] = val;
+	} else
+		put16_unaligned_check(regs->uregs[rd], addr);
+
+	return TYPE_LDST;
+
+swp:
+	printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
+bad:
+	return TYPE_ERROR;
+
+fault:
+	return TYPE_FAULT;
+}
+
+static int
+do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs)
+{
+	unsigned int rd = RD_BITS(instr);
+
+	ai_word += 1;
+
+	if (!LDST_P_BIT(instr) && LDST_W_BIT(instr))
+		goto trans;
+
+	if (LDST_L_BIT(instr))
+		get32_unaligned_check(regs->uregs[rd], addr);
+	else
+		put32_unaligned_check(regs->uregs[rd], addr);
+	return TYPE_LDST;
+
+trans:
+	if (LDST_L_BIT(instr))
+		get32t_unaligned_check(regs->uregs[rd], addr);
+	else
+		put32t_unaligned_check(regs->uregs[rd], addr);
+	return TYPE_LDST;
+
+fault:
+	return TYPE_FAULT;
+}
+
+static int
+do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
+{
+	unsigned int rd, rn, correction, nr_regs, regbits;
+	unsigned long eaddr;
 
-	instr = *(unsigned long *)instruction_pointer(regs);
 	correction = 4; /* sometimes 8 on ARMv3 */
-	regs->ARM_pc += correction + 4;
+	regs->ARM_pc += correction;
 
 	rd = RD_BITS(instr);
 	rn = RN_BITS(instr);
 	eaddr = regs->uregs[rn];
 
-	switch(CODING_BITS(instr)) {
-	case 0x00000000:
-		if ((instr & 0x0ff00ff0) == 0x01000090) {
-			ai_skipped += 1;
-			printk(KERN_ERR "Unaligned trap: not handling swp instruction\n");
-			return 1;
-		}
+	if (LDM_S_BIT(instr))
+		goto bad;
 
-		if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) {
-			ai_half += 1;
-			if (LDSTH_I_BIT(instr))
-				offset.un = (instr & 0xf00) >> 4 | (instr & 15);
-			else
-				offset.un = regs->uregs[RM_BITS(instr)];
-
-			if (LDST_P_BIT(instr)) {
-				if (LDST_U_BIT(instr))
-					eaddr += offset.un;
-				else
-					eaddr -= offset.un;
-			}
+	ai_multi += 1;
+
+	for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
+		nr_regs += 4;
 
-			/*
-			 * This is a "hint" - we already have eaddr worked out by the
-			 * processor for us.
-			 */
-			if (addr != eaddr)
-				printk(KERN_ERR "LDRHSTRH: PC = %08lx, instr = %08x, "
-					"addr = %08lx, eaddr = %08lx\n",
-					 instruction_pointer(regs), instr, addr, eaddr);
-
-			if (LDST_L_BIT(instr))
-				regs->uregs[rd] = get_unaligned((unsigned short *)eaddr);
-			else
-				put_unaligned(regs->uregs[rd], (unsigned short *)eaddr);
-
-			/* signed half-word? */
-			if (instr & 0x40)
-				regs->uregs[rd] = (long)((short) regs->uregs[rd]);
-
-			if (!LDST_P_BIT(instr)) {
-				if (LDST_U_BIT(instr))
-					eaddr += offset.un;
-				else
-					eaddr -= offset.un;
-				regs->uregs[rn] = eaddr;
-			} else if (LDST_W_BIT(instr))
-				regs->uregs[rn] = eaddr;
-			break;
+	if (!LDST_U_BIT(instr))
+		eaddr -= nr_regs;
+
+	/*
+	 * This is a "hint" - we already have eaddr worked out by the
+	 * processor for us.
+	 */
+	if (addr != eaddr)
+		printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
+			"addr = %08lx, eaddr = %08lx\n",
+			 instruction_pointer(regs), instr, addr, eaddr);
+
+	if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
+	    (LDST_U_BIT(instr)      && LDST_P_BIT(instr)))
+		eaddr += 4;
+
+	for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
+		if (regbits & 1) {
+			if (LDST_L_BIT(instr)) {
+				get32_unaligned_check(regs->uregs[rd], eaddr);
+				if (rd == 15)
+					correction = 0;
+			} else
+				put32_unaligned_check(regs->uregs[rd], eaddr);
+			eaddr += 4;
 		}
 
-	default:
-		ai_skipped += 1;
-		panic("Alignment trap: not handling instruction %08X at %08lX",
-				instr, regs->ARM_pc - correction - 4);
+	if (LDST_W_BIT(instr)) {
+		if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
+			eaddr -= nr_regs;
+		else if (LDST_P_BIT(instr))
+			eaddr -= 4;
+		else if (!LDST_U_BIT(instr))
+			eaddr -= 4 + nr_regs;
+		regs->uregs[rn] = eaddr;
+	}
+	regs->ARM_pc -= correction;
+	return TYPE_DONE;
+
+fault:
+	return TYPE_FAULT;
+
+bad:
+	printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
+	return TYPE_ERROR;
+}
+
+static int
+do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
+{
+	union offset_union offset;
+	unsigned long instr, instrptr;
+	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
+	unsigned int type;
+
+	if (user_mode(regs))
+		goto user;
+
+	ai_sys += 1;
+
+	instrptr = instruction_pointer(regs);
+	instr = *(unsigned long *)instrptr;
+
+	regs->ARM_pc += 4;
+
+	switch (CODING_BITS(instr)) {
+	case 0x00000000:	/* ldrh or strh */
+		if (LDSTH_I_BIT(instr))
+			offset.un = (instr & 0xf00) >> 4 | (instr & 15);
+		else
+			offset.un = regs->uregs[RM_BITS(instr)];
+		handler = do_alignment_ldrhstrh;
 		break;
 
-	case 0x04000000:
+	case 0x04000000:	/* ldr or str immediate */
 		offset.un = OFFSET_BITS(instr);
-		goto ldr_str;
+		handler = do_alignment_ldrstr;
+		break;
 
-	case 0x06000000:
+	case 0x06000000:	/* ldr or str register */
 		offset.un = regs->uregs[RM_BITS(instr)];
 
 		if (IS_SHIFT(instr)) {
@@ -229,97 +466,49 @@
 				break;
 			}
 		}
-
-	ldr_str:
-		ai_word += 1;
-		if (LDST_P_BIT(instr)) {
-			if (LDST_U_BIT(instr))
-				eaddr += offset.un;
-			else
-				eaddr -= offset.un;
-		} else {
-			if (LDST_W_BIT(instr)) {
-				printk(KERN_ERR "Not handling ldrt/strt correctly\n");
-				return 1;
-			}
-		}
-
-		/*
-		 * This is a "hint" - we already have eaddr worked out by the
-		 * processor for us.
-		 */
-		if (addr != eaddr)
-			printk(KERN_ERR "LDRSTR: PC = %08lx, instr = %08x, "
-				"addr = %08lx, eaddr = %08lx\n",
-				 instruction_pointer(regs), instr, addr, eaddr);
-
-		if (LDST_L_BIT(instr)) {
-			regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
-			if (rd == 15)
-				correction = 0;
-		} else
-			put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
-
-		if (!LDST_P_BIT(instr)) {
-			if (LDST_U_BIT(instr))
-				eaddr += offset.un;
-			else
-				eaddr -= offset.un;
-
-			regs->uregs[rn] = eaddr;
-		} else if (LDST_W_BIT(instr))
-			regs->uregs[rn] = eaddr;
+		handler = do_alignment_ldrstr;
 		break;
 
-	case 0x08000000:
-		if (LDM_S_BIT(instr))
-			panic("Alignment trap: not handling LDM with s-bit\n");
-		ai_multi += 1;
-
-		for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
-			nr_regs += 4;
+	case 0x08000000:	/* ldm or stm */
+		handler = do_alignment_ldmstm;
+		break;
 
-		if  (!LDST_U_BIT(instr))
-			eaddr -= nr_regs;
+	default:
+		goto bad;
+	}
 
-		/*
-		 * This is a "hint" - we already have eaddr worked out by the
-		 * processor for us.
-		 */
-		if (addr != eaddr)
-			printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08x, "
-				"addr = %08lx, eaddr = %08lx\n",
-				 instruction_pointer(regs), instr, addr, eaddr);
+	type = handler(addr, instr, regs);
 
-		if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
-		    (LDST_U_BIT(instr)      && LDST_P_BIT(instr)))
-			eaddr += 4;
+	if (type == TYPE_ERROR || type == TYPE_FAULT)
+		goto bad_or_fault;
 
-		for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
-			if (regbits & 1) {
-				if (LDST_L_BIT(instr)) {
-					regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
-					if (rd == 15)
-						correction = 0;
-				} else
-					put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
-				eaddr += 4;
-			}
+	if (type == TYPE_LDST)
+		do_alignment_finish_ldst(addr, instr, regs, offset);
 
-		if (LDST_W_BIT(instr)) {
-			if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
-				eaddr -= nr_regs;
-			else if (LDST_P_BIT(instr))
-				eaddr -= 4;
-			else if (!LDST_U_BIT(instr))
-				eaddr -= 4 + nr_regs;
-			regs->uregs[rn] = eaddr;
-		}
-		break;
-	}
+	return 0;
 
-	regs->ARM_pc -= correction;
+bad_or_fault:
+	if (type == TYPE_ERROR)
+		goto bad;
+	regs->ARM_pc -= 4;
+	/*
+	 * We got a fault - fix it up, or die.
+	 */
+	do_bad_area(current, current->mm, addr, error_code, regs);
+	return 0;
 
+bad:
+	/*
+	 * Oops, we didn't handle the instruction.
+	 */
+	printk(KERN_ERR "Alignment trap: not handling instruction "
+		"%08lx at [<%08lx>]", instr, instrptr);
+	ai_skipped += 1;
+	return 1;
+
+user:
+	set_cr(cr_no_alignment);
+	ai_user += 1;
 	return 0;
 }
 
@@ -332,35 +521,13 @@
 /*
  * Some section permission faults need to be handled gracefully, for
  * instance, when they happen due to a __{get,put}_user during an oops).
- * In this case, we should return an error to the __{get,put}_user caller
- * instead of causing another oops.  We should also fixup this fault as
- * the user could pass a pointer to a section to the kernel.
  */
 static int
 do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
 {
-	unsigned long fixup;
-
-	if (user_mode(regs)) {
-#ifdef CONFIG_DEBUG_USER
-		printk("%s: permission fault on section, "
-		       "address=0x%08lx, code %d\n",
-		       current->comm, addr, error_code);
-#endif
-		goto fail;
-	}
-
-	fixup = search_exception_table(instruction_pointer(regs));
-	if (fixup != 0) {
-#ifdef DEBUG
-		printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
-			tsk->comm, regs->ARM_pc, addr, fixup);
-#endif
-		regs->ARM_pc = fixup;
-		return 0;
-	}
-fail:
-	return 1;	/* not fixed up */
+	struct task_struct *tsk = current;
+	do_bad_area(tsk, tsk->active_mm, addr, error_code, regs);
+	return 0;
 }
 
 static const struct fsr_info {
@@ -369,17 +536,17 @@
 	char	*name;
 } fsr_info[] = {
 	{ NULL,			SIGSEGV, "vector exception"		   },
-	{ do_alignment,		SIGBUS,	 "alignment exception"		   },
+	{ do_alignment,		SIGILL,	 "alignment exception"		   },
 	{ NULL,			SIGKILL, "terminal exception"		   },
-	{ do_alignment,		SIGBUS,	 "alignment exception"		   },
+	{ do_alignment,		SIGILL,	 "alignment exception"		   },
 	{ NULL,			SIGBUS,	 "external abort on linefetch"	   },
-	{ do_page_fault,	SIGSEGV, "page fault"			   },
+	{ do_translation_fault,	SIGSEGV, "section translation fault"	   },
 	{ NULL,			SIGBUS,	 "external abort on linefetch"	   },
-	{ do_page_fault,	SIGSEGV, "page fault"			   },
+	{ do_page_fault,	SIGSEGV, "page translation fault"	   },
 	{ NULL,			SIGBUS,	 "external abort on non-linefetch" },
-	{ NULL,			SIGSEGV, "domain fault"			   },
+	{ NULL,			SIGSEGV, "section domain fault"		   },
 	{ NULL,			SIGBUS,	 "external abort on non-linefetch" },
-	{ NULL,			SIGSEGV, "domain fault"			   },
+	{ NULL,			SIGSEGV, "page domain fault"		   },
 	{ NULL,			SIGBUS,	 "external abort on translation"   },
 	{ do_sect_fault,	SIGSEGV, "section permission fault"	   },
 	{ NULL,			SIGBUS,	 "external abort on translation"   },
@@ -398,7 +565,7 @@
 	if (addr == regs->ARM_pc)
 		goto sa1_weirdness;
 #endif
-#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP)
+#if defined(CONFIG_CPU_ARM720) && defined(CONFIG_ALIGNMENT_TRAP)
 	if (addr & 3 && (fsr & 13) != 1)
 		goto arm720_weirdness;
 #endif
@@ -410,7 +577,6 @@
 		return;
 bad:
 	force_sig(inf->sig, current);
-
 	printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n",
 		inf->name, fsr, addr);
 	show_pte(current->mm, addr);
@@ -431,7 +597,7 @@
 		goto bad;
 	return;
 #endif
-#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP)
+#if defined(CONFIG_CPU_ARM720) && defined(CONFIG_ALIGNMENT_TRAP)
 arm720_weirdness:
 	if (!user_mode(regs)) {
 		unsigned long instr;
@@ -462,6 +628,6 @@
 asmlinkage int
 do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
 {
-	do_page_fault(addr, 0, regs);
+	do_translation_fault(addr, 0, regs);
 	return 1;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.4.3/linux/arch/arm/mm/fault-common.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/arm/mm/fault-common.c	Thu Apr 12 12:20:31 2001
@@ -2,7 +2,7 @@
  *  linux/arch/arm/mm/fault-common.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Modifications for ARM processor (c) 1995-1999 Russell King
+ *  Modifications for ARM processor (c) 1995-2001 Russell King
  *
  * 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
@@ -93,8 +93,82 @@
 	printk("\n");
 }
 
+/*
+ * Oops.  The kernel tried to access some page that wasn't present.
+ */
+static void
+__do_kernel_fault(struct mm_struct *mm, unsigned long addr, int error_code,
+		  struct pt_regs *regs)
+{
+	unsigned long fixup;
+
+	/*
+	 * Are we prepared to handle this kernel fault?
+	 */
+	if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
+			tsk->comm, regs->ARM_pc, addr, fixup);
+#endif
+		regs->ARM_pc = fixup;
+		return;
+	}
+
+	/*
+	 * No handler, we'll have to terminate things with extreme prejudice.
+	 */
+	printk(KERN_ALERT
+		"Unable to handle kernel %s at virtual address %08lx\n",
+		(addr < PAGE_SIZE) ? "NULL pointer dereference" :
+		"paging request", addr);
+
+	show_pte(mm, addr);
+	die("Oops", regs, error_code);
+	do_exit(SIGKILL);
+}
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * User mode accesses just cause a SIGSEGV
+ */
+static void
+__do_user_fault(struct task_struct *tsk, unsigned long addr, int error_code,
+		int code, struct pt_regs *regs)
+{
+	struct siginfo si;
+
+#ifdef CONFIG_DEBUG_USER
+	printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, "
+	       "lr=0x%08lx (bad address=0x%08lx, code %d)\n",
+	       tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code);
+#endif
+
+	tsk->thread.address = addr;
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 14;
+	si.si_signo = SIGSEGV;
+	si.si_errno = 0;
+	si.si_code = code;
+	si.si_addr = (void *)addr;
+	force_sig_info(SIGSEGV, &si, tsk);
+}
+
+void
+do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
+	    int error_code, struct pt_regs *regs)
+{
+	/*
+	 * If we are in kernel mode at this point, we
+	 * have no context to handle this fault with.
+	 */
+	if (user_mode(regs))
+		__do_user_fault(tsk, addr, error_code, SEGV_MAPERR, regs);
+	else
+		__do_kernel_fault(mm, addr, error_code, regs);
+}
+
 static int
-__do_page_fault(struct mm_struct *mm, unsigned long addr, int mode,
+__do_page_fault(struct mm_struct *mm, unsigned long addr, int error_code,
 		struct task_struct *tsk)
 {
 	struct vm_area_struct *vma;
@@ -112,7 +186,7 @@
 	 * memory access, so we can handle it.
 	 */
 good_area:
-	if (READ_FAULT(mode)) /* read? */
+	if (READ_FAULT(error_code)) /* read? */
 		mask = VM_READ|VM_EXEC;
 	else
 		mask = VM_WRITE;
@@ -127,7 +201,7 @@
 	 * than endlessly redo the fault.
 	 */
 survive:
-	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(mode));
+	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(error_code));
 
 	/*
 	 * Handle the "normal" cases first - successful and sigbus
@@ -161,62 +235,16 @@
 	return fault;
 }
 
-static int __do_vmalloc_fault(unsigned long addr, struct mm_struct *mm)
-{
-	/* Synchronise this task's top level page-table
-	 * with the 'reference' page table.
-	 */
-	int offset = __pgd_offset(addr);
-	pgd_t *pgd, *pgd_k;
-	pmd_t *pmd, *pmd_k;
-
-	pgd_k = init_mm.pgd + offset;
-	if (!pgd_present(*pgd_k))
-		goto bad_area;
-
-	pgd = mm->pgd + offset;
-#if 0	/* note that we are two-level */
-	if (!pgd_present(*pgd))
-		set_pgd(pgd, *pgd_k);
-#endif
-
-	pmd_k = pmd_offset(pgd_k, addr);
-	if (pmd_none(*pmd_k))
-		goto bad_area;
-
-	pmd = pmd_offset(pgd, addr);
-	if (!pmd_none(*pmd))
-		goto bad_area;
-	set_pmd(pmd, *pmd_k);
-	return 1;
-
-bad_area:
-	return -2;
-}
-
-int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
+int do_page_fault(unsigned long addr, int error_code, struct pt_regs *regs)
 {
 	struct task_struct *tsk;
 	struct mm_struct *mm;
-	unsigned long fixup;
 	int fault;
 
 	tsk = current;
 	mm  = tsk->mm;
 
 	/*
-	 * We fault-in kernel-space virtual memory on-demand. The
-	 * 'reference' page table is init_mm.pgd.
-	 *
-	 * NOTE! We MUST NOT take any locks for this case. We may
-	 * be in an interrupt or a critical region, and should
-	 * only copy the information from the master page table,
-	 * nothing more.
-	 */
-	if (addr >= TASK_SIZE)
-		goto vmalloc_fault;
-
-	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
@@ -224,10 +252,9 @@
 		goto no_context;
 
 	down_read(&mm->mmap_sem);
-	fault = __do_page_fault(mm, addr, mode, tsk);
+	fault = __do_page_fault(mm, addr, error_code, tsk);
 	up_read(&mm->mmap_sem);
 
-ret:
 	/*
 	 * Handle the "normal" case first
 	 */
@@ -255,28 +282,9 @@
 		 */
 		printk("VM: killing process %s\n", tsk->comm);
 		do_exit(SIGKILL);
-	} else {
-		/*
-		 * Something tried to access memory that isn't in our memory map..
-		 * User mode accesses just cause a SIGSEGV
-		 */
-		struct siginfo si;
-
-#ifdef CONFIG_DEBUG_USER
-		printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, "
-		       "lr=0x%08lx (bad address=0x%08lx, code %d)\n",
-		       tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-#endif
-
-		tsk->thread.address = addr;
-		tsk->thread.error_code = mode;
-		tsk->thread.trap_no = 14;
-		si.si_signo = SIGSEGV;
-		si.si_errno = 0;
-		si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR;
-		si.si_addr = (void *)addr;
-		force_sig_info(SIGSEGV, &si, tsk);
-	}
+	} else
+		__do_user_fault(tsk, addr, error_code, fault == -1 ?
+				SEGV_ACCERR : SEGV_MAPERR, regs);
 	return 0;
 
 
@@ -290,7 +298,7 @@
 	 * or user mode.
 	 */
 	tsk->thread.address = addr;
-	tsk->thread.error_code = mode;
+	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = 14;
 	force_sig(SIGBUS, tsk);
 
@@ -299,32 +307,64 @@
 		return 0;
 
 no_context:
-	/* Are we prepared to handle this kernel fault?  */
-	if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
-#ifdef DEBUG
-		printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
-			tsk->comm, regs->ARM_pc, addr, fixup);
+	__do_kernel_fault(mm, addr, error_code, regs);
+	return 0;
+}
+
+/*
+ * First Level Translation Fault Handler
+ *
+ * We enter here because the first level page table doesn't contain
+ * a valid entry for the address.
+ *
+ * If the address is in kernel space (>= TASK_SIZE), then we are
+ * probably faulting in the vmalloc() area.
+ *
+ * If the init_task's first level page tables contains the relevant
+ * entry, we copy the it to this task.  If not, we send the process
+ * a signal, fixup the exception, or oops the kernel.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may be in an
+ * interrupt or a critical region, and should only copy the information
+ * from the master page table, nothing more.
+ */
+int do_translation_fault(unsigned long addr, int error_code, struct pt_regs *regs)
+{
+	struct task_struct *tsk;
+	struct mm_struct *mm;
+	int offset;
+	pgd_t *pgd, *pgd_k;
+	pmd_t *pmd, *pmd_k;
+
+	if (addr < TASK_SIZE)
+		return do_page_fault(addr, error_code, regs);
+
+	tsk = current;
+	mm  = tsk->active_mm;
+
+	offset = __pgd_offset(addr);
+
+	pgd_k = init_mm.pgd + offset;
+	pgd   = mm->pgd + offset;
+
+	if (pgd_none(*pgd_k))
+		goto bad_area;
+
+#if 0	/* note that we are two-level */
+	if (!pgd_present(*pgd))
+		set_pgd(pgd, *pgd_k);
 #endif
-		regs->ARM_pc = fixup;
-		return 0;
-	}
 
-	/*
-	 * Oops. The kernel tried to access some bad page. We'll have to
-	 * terminate things with extreme prejudice.
-	 */
-	printk(KERN_ALERT
-		"Unable to handle kernel %s at virtual address %08lx\n",
-		(addr < PAGE_SIZE) ? "NULL pointer dereference" :
-		"paging request", addr);
+	pmd_k = pmd_offset(pgd_k, addr);
+	pmd   = pmd_offset(pgd, addr);
 
-	show_pte(mm, addr);
-	die("Oops", regs, mode);
-	do_exit(SIGKILL);
+	if (pmd_none(*pmd_k))
+		goto bad_area;
 
+	set_pmd(pmd, *pmd_k);
 	return 0;
 
-vmalloc_fault:
-	fault = __do_vmalloc_fault(addr, mm);
-	goto ret;
+bad_area:
+	do_bad_area(tsk, mm, addr, error_code, regs);
+	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.4.3/linux/arch/arm/mm/init.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/mm/init.c	Thu Apr 12 12:20:31 2001
@@ -59,52 +59,10 @@
 static struct meminfo meminfo __initdata = { 0, };
 
 /*
- * empty_bad_page is the page that is used for page faults when
- * linux is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * empty_bad_pte_table is the accompanying page-table: it is
- * initialized to point to BAD_PAGE entries.
- *
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
  */
 struct page *empty_zero_page;
-struct page *empty_bad_page;
-pte_t *empty_bad_pte_table;
-
-pte_t *get_bad_pte_table(void)
-{
-	pte_t v;
-	int i;
-
-	v = pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
-
-	for (i = 0; i < PTRS_PER_PTE; i++)
-		set_pte(empty_bad_pte_table + i, v);
-
-	return empty_bad_pte_table;
-}
-
-void __handle_bad_pmd(pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-#ifdef CONFIG_DEBUG_ERRORS
-	__backtrace();
-#endif
-	set_pmd(pmd, mk_user_pmd(get_bad_pte_table()));
-}
-
-void __handle_bad_pmd_kernel(pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-#ifdef CONFIG_DEBUG_ERRORS
-	__backtrace();
-#endif
-	set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table()));
-}
 
 #ifndef CONFIG_NO_PGT_CACHE
 struct pgtable_cache_struct quicklists;
@@ -120,12 +78,12 @@
 				freed++;
 			}
 			if(pmd_quicklist) {
-				free_pmd_slow(get_pmd_fast());
+				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
 				freed++;
 			}
 			if(pte_quicklist) {
-				free_pte_slow(get_pte_fast());
-				 freed++;
+				pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed++;
 			}
 		} while(pgtable_cache_size > low);
 	}
@@ -514,18 +472,15 @@
  */
 void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
 {
-	void *zero_page, *bad_page, *bad_table;
+	void *zero_page;
 	int node;
 
 	memcpy(&meminfo, mi, sizeof(meminfo));
 
 	/*
-	 * allocate what we need for the bad pages.
-	 * note that we count on this going ok.
+	 * allocate the zero page.  Note that we count on this going ok.
 	 */
 	zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
-	bad_page  = alloc_bootmem_low_pages(PAGE_SIZE);
-	bad_table = alloc_bootmem_low_pages(TABLE_SIZE);
 
 	/*
 	 * initialise the page tables.
@@ -586,11 +541,7 @@
 	 * the mem_map is initialised
 	 */
 	memzero(zero_page, PAGE_SIZE);
-	memzero(bad_page, PAGE_SIZE);
-
 	empty_zero_page = virt_to_page(zero_page);
-	empty_bad_page  = virt_to_page(bad_page);
-	empty_bad_pte_table = ((pte_t *)bad_table) + TABLE_OFFSET;
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c
--- v2.4.3/linux/arch/arm/mm/ioremap.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/ioremap.c	Thu Apr 12 12:20:31 2001
@@ -44,14 +44,18 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
 	do {
-		if (!pte_none(*pte))
+		if (!pte_none(*pte)) {
 			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
 		set_pte(pte, mk_pte_phys(phys_addr, pgprot));
 		address += PAGE_SIZE;
 		phys_addr += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -67,40 +71,50 @@
 		end = PGDIR_SIZE;
 
 	phys_addr -= address;
+	if (address >= end)
+		BUG();
+
 	pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 	return 0;
 }
 
 static int remap_area_pages(unsigned long address, unsigned long phys_addr,
 				 unsigned long size, unsigned long flags)
 {
+	int error;
 	pgd_t * dir;
 	unsigned long end = address + size;
 
 	phys_addr -= address;
 	dir = pgd_offset(&init_mm, address);
 	flush_cache_all();
-	while (address < end) {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
 		if (!pmd)
-			return -ENOMEM;
+			break;
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
-			return -ENOMEM;
-		set_pgdir(address, *dir);
+			break;
+		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
-	return 0;
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c
--- v2.4.3/linux/arch/arm/mm/mm-armo.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-armo.c	Thu Apr 12 12:20:31 2001
@@ -22,120 +22,98 @@
 #include <asm/mach/map.h>
 
 #define MEMC_TABLE_SIZE (256*sizeof(unsigned long))
-#define PGD_TABLE_SIZE	(PTRS_PER_PGD * BYTES_PER_PTR)
 
+kmem_cache_t *pte_cache, *pgd_cache;
 int page_nr;
 
-extern unsigned long get_page_2k(int prio);
-extern void free_page_2k(unsigned long);
-extern pte_t *get_bad_pte_table(void);
-
 /*
  * Allocate a page table.  Note that we place the MEMC
  * table before the page directory.  This means we can
  * easily get to both tightly-associated data structures
  * with a single pointer.
- *
- * We actually only need 1152 bytes, 896 bytes is wasted.
- * We could try to fit 7 PTEs into that slot somehow.
  */
-static inline void *alloc_pgd_table(int priority)
+static inline pgd_t *alloc_pgd_table(int priority)
 {
-	unsigned long pg2k;
+	void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
 
-	pg2k = get_page_2k(priority);
 	if (pg2k)
 		pg2k += MEMC_TABLE_SIZE;
 
-	return (void *)pg2k;
+	return (pgd_t *)pg2k;
 }
 
 void free_pgd_slow(pgd_t *pgd)
 {
 	unsigned long tbl = (unsigned long)pgd;
 
+	/*
+	 * CHECKME: are we leaking pte tables here???
+	 */
+
 	tbl -= MEMC_TABLE_SIZE;
-	free_page_2k(tbl);
+
+	kmem_cache_free(pgd_cache, (void *)tbl);
 }
 
-/*
- * FIXME: the following over-allocates by 1600%
- */
-static inline void *alloc_pte_table(int size, int prio)
+pgd_t *get_pgd_slow(struct mm_struct *mm)
 {
-	if (size != 128)
-		printk("invalid table size\n");
-	return (void *)get_page_2k(prio);
-}
-
-void free_pte_slow(pte_t *pte)
-{
-	unsigned long tbl = (unsigned long)pte;
-	free_page_2k(tbl);
-}
-
-pgd_t *get_pgd_slow(void)
-{
-	pgd_t *pgd = (pgd_t *)alloc_pgd_table(GFP_KERNEL);
-	pmd_t *new_pmd;
-
-	if (pgd) {
-		pgd_t *init = pgd_offset(&init_mm, 0);
-		
-		memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t));
-		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-
-		/*
-		 * On ARM, first page must always be allocated
-		 */
-		if (!pmd_alloc(pgd, 0))
-			goto nomem;
-		else {
-			pmd_t *old_pmd = pmd_offset(init, 0);
-			new_pmd = pmd_offset(pgd, 0);
-
-			if (!pte_alloc(new_pmd, 0))
-				goto nomem_pmd;
-			else {
-				pte_t *new_pte = pte_offset(new_pmd, 0);
-				pte_t *old_pte = pte_offset(old_pmd, 0);
-
-				set_pte (new_pte, *old_pte);
-			}
-		}
-		/* update MEMC tables */
-		cpu_memc_update_all(pgd);
-	}
-	return pgd;
+	pgd_t *new_pgd, *init_pgd;
+	pmd_t *new_pmd, *init_pmd;
+	pte_t *new_pte, *init_pte;
+
+	new_pgd = alloc_pgd_table(GFP_KERNEL);
+	if (!new_pgd)
+		goto no_pgd;
+
+	/*
+	 * This lock is here just to satisfy pmd_alloc and pte_lock
+	 */
+	spin_lock(&mm->page_table_lock);
+
+	/*
+	 * On ARM, first page must always be allocated since it contains
+	 * the machine vectors.
+	 */
+	new_pmd = pmd_alloc(mm, new_pgd, 0);
+	if (!new_pmd)
+		goto no_pmd;
 
-nomem_pmd:
+	new_pte = pte_alloc(mm, new_pmd, 0);
+	if (!new_pte)
+		goto no_pte;
+
+	init_pgd = pgd_offset_k(0);
+	init_pmd = pmd_offset(init_pgd, 0);
+	init_pte = pte_offset(init_pmd, 0);
+
+	set_pte(new_pte, *init_pte);
+
+	/*
+	 * most of the page table entries are zeroed
+	 * wne the table is created.
+	 */
+	memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD,
+		(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+
+	spin_unlock(&mm->page_table_lock);
+
+	/* update MEMC tables */
+	cpu_memc_update_all(new_pgd);
+	return new_pgd;
+
+no_pte:
+	spin_unlock(&mm->page_table_lock);
 	pmd_free(new_pmd);
-nomem:
-	free_pgd_slow(pgd);
+	free_pgd_slow(new_pgd);
 	return NULL;
-}
 
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
+no_pmd:
+	spin_unlock(&mm->page_table_lock);
+	free_pgd_slow(new_pgd);
+	return NULL;
 
-	pte = (pte_t *)alloc_pte_table(PTRS_PER_PTE * sizeof(pte_t), GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memzero(pte, PTRS_PER_PTE * sizeof(pte_t));
-			set_pmd(pmd, mk_user_pmd(pte));
-			return pte + offset;
-		}
-		set_pmd(pmd, mk_user_pmd(get_bad_pte_table()));
-		return NULL;
-	}
-	free_pte_slow(pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
+no_pgd:
+	return NULL;
 }
 
 /*
@@ -160,7 +138,7 @@
 
 	pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t));
 	pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY);
-	set_pmd(pmd_offset(swapper_pg_dir, 0), mk_kernel_pmd(pte));
+	pmd_populate(&init_mm, pmd_offset(swapper_pg_dir, 0), pte);
 
 	for (i = 1; i < PTRS_PER_PGD; i++)
 		pgd_val(swapper_pg_dir[i]) = 0;
@@ -176,4 +154,31 @@
  */
 void __init create_memmap_holes(struct meminfo *mi)
 {
+}
+
+static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
+{
+	memzero(pte, sizeof(pte_t) * PTRS_PER_PTE);
+}
+
+static void pgd_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
+{
+	pgd_t *pgd = (pte + MEMC_TABLE_SIZE);
+
+	memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t));
+}
+
+void __init pgtable_cache_init(void)
+{
+	pte_cache = kmem_cache_create("pte-cache",
+				sizeof(pte_t) * PTRS_PER_PTE,
+				0, 0, pte_cache_ctor, NULL);
+	if (!pte_cache)
+		BUG();
+
+	pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE +
+				sizeof(pgd_t) * PTRS_PER_PGD,
+				0, 0, pgd_cache_ctor, NULL);
+	if (!pgd_cache)
+		BUG();
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- v2.4.3/linux/arch/arm/mm/mm-armv.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/mm/mm-armv.c	Thu Apr 12 12:20:31 2001
@@ -22,12 +22,6 @@
 
 #include <asm/mach/map.h>
 
-unsigned long *valid_addr_bitmap;
-
-extern unsigned long get_page_2k(int priority);
-extern void free_page_2k(unsigned long page);
-extern pte_t *get_bad_pte_table(void);
-
 /*
  * These are useful for identifing cache coherency
  * problems by allowing the cache or the cache and
@@ -73,47 +67,68 @@
 /*
  * need to get a 16k page for level 1
  */
-pgd_t *get_pgd_slow(void)
+pgd_t *get_pgd_slow(struct mm_struct *mm)
 {
-	pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
-	pmd_t *new_pmd;
+	pgd_t *new_pgd, *init_pgd;
+	pmd_t *new_pmd, *init_pmd;
+	pte_t *new_pte, *init_pte;
+
+	new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
+	if (!new_pgd)
+		goto no_pgd;
+
+	memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
+
+	/*
+	 * This lock is here just to satisfy pmd_alloc and pte_lock
+	 */
+	spin_lock(&mm->page_table_lock);
 
-	if (pgd) {
-		pgd_t *init = pgd_offset_k(0);
+	/*
+	 * On ARM, first page must always be allocated since it contains
+	 * the machine vectors.
+	 */
+	new_pmd = pmd_alloc(mm, new_pgd, 0);
+	if (!new_pmd)
+		goto no_pmd;
+
+	new_pte = pte_alloc(mm, new_pmd, 0);
+	if (!new_pte)
+		goto no_pte;
+
+	init_pgd = pgd_offset_k(0);
+	init_pmd = pmd_offset(init_pgd, 0);
+	init_pte = pte_offset(init_pmd, 0);
 
-		memzero(pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
-		memcpy(pgd  + FIRST_KERNEL_PGD_NR, init + FIRST_KERNEL_PGD_NR,
+	set_pte(new_pte, *init_pte);
+
+	/*
+	 * Copy over the kernel and IO PGD entries
+	 */
+	memcpy(new_pgd  + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
 		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
-		/*
-		 * FIXME: this should not be necessary
-		 */
-		clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t));
 
-		/*
-		 * On ARM, first page must always be allocated
-		 */
-		if (!pmd_alloc(pgd, 0))
-			goto nomem;
-		else {
-			pmd_t *old_pmd = pmd_offset(init, 0);
-			new_pmd = pmd_offset(pgd, 0);
-
-			if (!pte_alloc(new_pmd, 0))
-				goto nomem_pmd;
-			else {
-				pte_t *new_pte = pte_offset(new_pmd, 0);
-				pte_t *old_pte = pte_offset(old_pmd, 0);
+	spin_unlock(&mm->page_table_lock);
 
-				set_pte(new_pte, *old_pte);
-			}
-		}
-	}
-	return pgd;
+	/*
+	 * FIXME: this should not be necessary
+	 */
+	clean_cache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
+
+	return new_pgd;
 
-nomem_pmd:
+no_pte:
+	spin_unlock(&mm->page_table_lock);
 	pmd_free(new_pmd);
-nomem:
-	free_pages((unsigned long)pgd, 2);
+	free_pages((unsigned long)new_pgd, 2);
+	return NULL;
+
+no_pmd:
+	spin_unlock(&mm->page_table_lock);
+	free_pages((unsigned long)new_pgd, 2);
+	return NULL;
+
+no_pgd:
 	return NULL;
 }
 
@@ -142,59 +157,6 @@
 	free_pages((unsigned long) pgd, 2);
 }
 
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *)get_page_2k(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t));
-			clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t));
-			pte += PTRS_PER_PTE;
-			set_pmd(pmd, mk_user_pmd(pte));
-			return pte + offset;
-		}
-		set_pmd(pmd, mk_user_pmd(get_bad_pte_table()));
-		return NULL;
-	}
-	free_page_2k((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *)get_page_2k(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t));
-			clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t));
-			pte += PTRS_PER_PTE;
-			set_pmd(pmd, mk_kernel_pmd(pte));
-			return pte + offset;
-		}
-		set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table()));
-		return NULL;
-	}
-	free_page_2k((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-void free_pte_slow(pte_t *pte)
-{
-	free_page_2k((unsigned long)(pte - PTRS_PER_PTE));
-}
-
 /*
  * Create a SECTION PGD between VIRT and PHYS in domain
  * DOMAIN with protection PROT
@@ -481,4 +443,42 @@
 
 	for (node = 0; node < numnodes; node++)
 		free_unused_memmap_node(node, mi);
+}
+
+/*
+ * PTE table allocation cache.
+ *
+ * This is a move away from our custom 2K page allocator.  We now use the
+ * slab cache to keep track of these objects.
+ *
+ * With this, it is questionable as to whether the PGT cache gains us
+ * anything.  We may be better off dropping the PTE stuff from our PGT
+ * cache implementation.
+ */
+kmem_cache_t *pte_cache;
+
+/*
+ * The constructor gets called for each object within the cache when the
+ * cache page is created.  Note that if slab tries to misalign the blocks,
+ * we BUG() loudly.
+ */
+static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
+{
+	unsigned long block = (unsigned long)pte;
+
+	if (block & 2047)
+		BUG();
+
+	memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t));
+	cpu_cache_clean_invalidate_range(block, block +
+			PTRS_PER_PTE * sizeof(pte_t), 0);
+}
+
+void __init pgtable_cache_init(void)
+{
+	pte_cache = kmem_cache_create("pte-cache",
+				2 * PTRS_PER_PTE * sizeof(pte_t), 0, 0,
+				pte_cache_ctor, NULL);
+	if (!pte_cache)
+		BUG();
 }
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-clps7500.c linux/arch/arm/mm/mm-clps7500.c
--- v2.4.3/linux/arch/arm/mm/mm-clps7500.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-clps7500.c	Thu Apr 12 12:20:31 2001
@@ -6,6 +6,7 @@
  *
  * Extra MM routines for CL7500 architecture
  */
+#include <linux/types.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c
--- v2.4.3/linux/arch/arm/mm/mm-ebsa110.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-ebsa110.c	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- *  linux/arch/arm/mm/mm-ebsa110.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * 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.
- *
- *  Extra MM routines for the EBSA-110 architecture
- */
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/hardware.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
- 
-static struct map_desc ebsa110_io_desc[] __initdata = {
-	{ IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-	{ IO_BASE             , IO_START  , IO_SIZE   , DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
-};
-
-void __init ebsa110_map_io(void)
-{
-	iotable_init(ebsa110_io_desc);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c
--- v2.4.3/linux/arch/arm/mm/mm-footbridge.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-footbridge.c	Wed Dec 31 16:00:00 1969
@@ -1,117 +0,0 @@
-/*
- *  linux/arch/arm/mm/mm-footbridge.c
- *
- *  Copyright (C) 1998-2000 Russell King, Dave Gilbert.
- *
- * 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.
- *
- *  Extra MM routines for the EBSA285 architecture
- */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
- 
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/hardware/dec21285.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/map.h>
-
-/*
- * Common mapping for all systems.  Note that the outbound write flush is
- * commented out since there is a "No Fix" problem with it.  Not mapping
- * it means that we have extra bullet protection on our feet.
- */
-static struct map_desc fb_common_io_desc[] __initdata = {
- { ARMCSR_BASE,	 DC21285_ARMCSR_BASE,	    ARMCSR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
- { XBUS_BASE,    0x40000000,		    XBUS_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
- LAST_DESC
-};
-
-/*
- * The mapping when the footbridge is in host mode.  We don't map any of
- * this when we are in add-in mode.
- */
-static struct map_desc ebsa285_host_io_desc[] __initdata = {
-#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST)
- { PCIMEM_BASE,  DC21285_PCI_MEM,	    PCIMEM_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
- { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
- { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
- { PCIIACK_BASE, DC21285_PCI_IACK,	    PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
- { PCIO_BASE,    DC21285_PCI_IO,	    PCIO_SIZE,	  DOMAIN_IO, 0, 1, 0, 0 },
-#endif
- LAST_DESC
-};
-
-/*
- * The CO-ebsa285 mapping.
- */
-static struct map_desc co285_io_desc[] __initdata = {
-#ifdef CONFIG_ARCH_CO285
- { PCIO_BASE,	 DC21285_PCI_IO,	    PCIO_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
- { PCIMEM_BASE,	 DC21285_PCI_MEM,	    PCIMEM_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
-#endif
- LAST_DESC
-};
-
-void __init footbridge_map_io(void)
-{
-	struct map_desc *desc = NULL;
-
-	/*
-	 * Set up the common mapping first; we need this to
-	 * determine whether we're in host mode or not.
-	 */
-	iotable_init(fb_common_io_desc);
-
-	/*
-	 * Now, work out what we've got to map in addition on this
-	 * platform.
-	 */
-	if (machine_is_co285())
-		desc = co285_io_desc;
-	else if (footbridge_cfn_mode())
-		desc = ebsa285_host_io_desc;
-
-	if (desc)
-		iotable_init(desc);
-}
-
-#ifdef CONFIG_FOOTBRIDGE_ADDIN
-
-/*
- * These two functions convert virtual addresses to PCI addresses and PCI
- * addresses to virtual addresses.  Note that it is only legal to use these
- * on memory obtained via get_free_page or kmalloc.
- */
-unsigned long __virt_to_bus(unsigned long res)
-{
-#ifdef CONFIG_DEBUG_ERRORS
-	if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
-		printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res);
-		__backtrace();
-	}
-#endif
-	return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
-}
-
-unsigned long __bus_to_virt(unsigned long res)
-{
-	res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
-	res += PAGE_OFFSET;
-
-#ifdef CONFIG_DEBUG_ERRORS
-	if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
-		printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res);
-		__backtrace();
-	}
-#endif
-	return res;
-}
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-l7200.c linux/arch/arm/mm/mm-l7200.c
--- v2.4.3/linux/arch/arm/mm/mm-l7200.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-l7200.c	Thu Apr 12 12:20:31 2001
@@ -17,6 +17,9 @@
 static struct map_desc l7200_io_desc[] __initdata = {
 	{ IO_BASE,	IO_START,	IO_SIZE,	DOMAIN_IO, 0, 1 ,0 ,0},
 	{ IO_BASE_2,	IO_START_2,	IO_SIZE_2,	DOMAIN_IO, 0, 1 ,0 ,0},
+	{ AUX_BASE,     AUX_START,      AUX_SIZE,       DOMAIN_IO, 0, 1 ,0 ,0},
+	{ FLASH1_BASE,  FLASH1_START,   FLASH1_SIZE,    DOMAIN_IO, 0, 1 ,0 ,0},
+	{ FLASH2_BASE,  FLASH2_START,   FLASH2_SIZE,    DOMAIN_IO, 0, 1 ,0 ,0},
 	LAST_DESC
 };
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c
--- v2.4.3/linux/arch/arm/mm/mm-sa1100.c	Fri Mar  2 11:12:06 2001
+++ linux/arch/arm/mm/mm-sa1100.c	Thu Apr 12 12:20:31 2001
@@ -15,9 +15,8 @@
  *
  */
 #include <linux/config.h>
-#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
 
 #include <asm/hardware.h>
 #include <asm/pgtable.h>
@@ -109,22 +108,9 @@
   LAST_DESC
 };
 
-static struct map_desc thinclient_io_desc[] __initdata = {
-#ifdef CONFIG_SA1100_THINCLIENT
-#if 0
-  { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
-#else
-  { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
-#endif
-  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
-#endif
-  LAST_DESC
-};
-
-static struct map_desc tifon_io_desc[] __initdata = {
-#ifdef CONFIG_SA1100_TIFON
-  { 0xe8000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
-  { 0xe8800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
+static struct map_desc sherman_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_SHERMAN
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash*/
 #endif
   LAST_DESC
 };
@@ -138,9 +124,16 @@
 
 static struct map_desc xp860_io_desc[] __initdata = {
 #ifdef CONFIG_SA1100_XP860
-  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
   { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */
   { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */
+  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+#endif
+  LAST_DESC
+};
+
+static struct map_desc pangolin_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_PANGOLIN
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
 #endif
   LAST_DESC
 };
@@ -153,8 +146,6 @@
 
 	if (machine_is_assabet())
 		desc = assabet_io_desc;
-	else if (machine_is_nanoengine())
-		desc = nanoengine_io_desc;
 	else if (machine_is_bitsy())
 		desc = bitsy_io_desc;
 	else if (machine_is_cerf())
@@ -165,38 +156,21 @@
 		desc = graphicsclient_io_desc;
 	else if (machine_is_lart())
 	        desc = lart_io_desc;
-	else if (machine_is_thinclient())
-		desc = thinclient_io_desc;
-	else if (machine_is_tifon())
-		desc = tifon_io_desc;
+	else if (machine_is_nanoengine())
+		desc = nanoengine_io_desc;
+	else if (machine_is_sherman())
+		desc = sherman_io_desc;
 	else if (machine_is_victor())
 		desc = victor_io_desc;
 	else if (machine_is_xp860())
 		desc = xp860_io_desc;
+	else if (machine_is_pangolin())
+		desc = pangolin_io_desc;
 
 	if (desc)
 		iotable_init(desc);
 }
 
-
-#ifdef CONFIG_DISCONTIGMEM
-
-/*
- * Our node_data structure for discontigous memory.
- * There is 4 possible nodes i.e. the 4 SA1100 RAM banks.
- */
-
-static bootmem_data_t node_bootmem_data[4];
-
-pg_data_t sa1100_node_data[4] =
-{ { bdata: &node_bootmem_data[0] },
-  { bdata: &node_bootmem_data[1] },
-  { bdata: &node_bootmem_data[2] },
-  { bdata: &node_bootmem_data[3] } };
-
-#endif
-
-  
 /*
  * On Assabet, we must probe for the Neponset board *before* paging_init() 
  * has occurred to actually determine the amount of RAM available.  To do so, 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.4.3/linux/arch/arm/mm/proc-sa110.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/mm/proc-sa110.S	Thu Apr 12 12:20:31 2001
@@ -556,7 +556,7 @@
 	mov	pc, lr
 
 /*
- * cpu_sa110_arm920_set_pte(ptep, pte)
+ * cpu_sa110_set_pte(ptep, pte)
  *
  * Set a PTE and flush it out
  */
@@ -737,7 +737,7 @@
 	b	__sa110_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
 	.long	cpu_sa110_info
 	.long	sa110_processor_functions
 	.size	__sa110_proc_info, . - __sa110_proc_info
@@ -750,7 +750,7 @@
 	b	__sa1100_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
 	.long	cpu_sa1100_info
 	.long	sa1100_processor_functions
 	.size	__sa1100_proc_info, . - __sa1100_proc_info
@@ -763,7 +763,7 @@
 	b	__sa1100_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
 	.long	cpu_sa1110_info
 	.long	sa1100_processor_functions
 	.size	__sa1110_proc_info, . - __sa1110_proc_info
diff -u --recursive --new-file v2.4.3/linux/arch/arm/mm/small_page.c linux/arch/arm/mm/small_page.c
--- v2.4.3/linux/arch/arm/mm/small_page.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/small_page.c	Thu Apr 12 12:20:31 2001
@@ -202,17 +202,6 @@
 	printk("Trying to free free small page from %p\n", __builtin_return_address(0));
 }
 
-unsigned long get_page_2k(int priority)
-{
-	return __get_small_page(priority, orders+0);
-}
-
-void free_page_2k(unsigned long spage)
-{
-	__free_small_page(spage, orders+0);
-}
-
-#if PAGE_SIZE > 8192
 unsigned long get_page_8k(int priority)
 {
 	return __get_small_page(priority, orders+1);
@@ -222,4 +211,3 @@
 {
 	__free_small_page(spage, orders+1);
 }
-#endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile
--- v2.4.3/linux/arch/arm/nwfpe/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/nwfpe/Makefile	Wed Apr 11 19:02:27 2001
@@ -1,7 +1,7 @@
 #
 # linux/arch/arm/nwfpe/Makefile
 #
-# Copyright (C) 1998, 1999 Philip Blundell
+# Copyright (C) 1998, 1999, 2001 Philip Blundell
 #
 
 USE_STANDARD_AS_RULE := true
@@ -14,7 +14,7 @@
 
 list-multi		:= nwfpe.o
 
-obj-$(CONFIG_NWFPE)	+= nwfpe.o
+obj-$(CONFIG_FPE_NWFPE)	+= nwfpe.o
 
 nwfpe-objs		:= fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
 			   fpmodule.o fpopcode.o softfloat.o \
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/config.h linux/arch/arm/nwfpe/config.h
--- v2.4.3/linux/arch/arm/nwfpe/config.h	Mon Aug 30 18:15:19 1999
+++ linux/arch/arm/nwfpe/config.h	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/*
-    NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
-
-    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
-
-    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.
-*/
-
-#ifndef __CONFIG_H__
-#define __CONFIG_H__
-
-#if 1
-#define C_SYMBOL_NAME(foo)	foo
-#else
-#define C_SYMBOL_NAME(foo)	_##foo
-#endif
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/double_cpdo.c linux/arch/arm/nwfpe/double_cpdo.c
--- v2.4.3/linux/arch/arm/nwfpe/double_cpdo.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/nwfpe/double_cpdo.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -22,10 +22,6 @@
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
-
-extern FPA11 *fpa11;
-
-float64 getDoubleConstant(unsigned int);
 
 float64 float64_exp(float64 Fm);
 float64 float64_ln(float64 Fm);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/entry.S linux/arch/arm/nwfpe/entry.S
--- v2.4.3/linux/arch/arm/nwfpe/entry.S	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/entry.S	Wed Apr 11 19:02:27 2001
@@ -1,7 +1,7 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Corel Computer Corporation, 1998
-    (c) Philip Blundell 1998-1999
+    (c) Rebel.COM, 1998
+    (c) 1998, 1999 Philip Blundell
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -86,7 +86,7 @@
 
         ldr r5, [r4, #60]	 	@ get contents of PC;
 	sub r8, r5, #4
-.Lx2:	ldrt r0, [r8], #0		@ get actual instruction into r0
+.Lx2:	ldrt r0, [r8]			@ get actual instruction into r0
 emulate:
 	bl EmulateAll			@ emulate the instruction
    	cmp r0, #0			@ was emulation successful
@@ -115,15 +115,17 @@
         mov r0, r6			@ prepare for EmulateAll()
    	b emulate			@ if r0 != 0, goto EmulateAll
 
-	@ We need to be prepared for the instruction at .Lx1 or .Lx2
-	@ to fault.
+	@ We need to be prepared for the instructions at .Lx1 and .Lx2 
+	@ to fault.  Emit the appropriate exception gunk to fix things up.
+	@ ??? For some reason, faults can happen at .Lx2 even with a
+	@ plain LDR instruction.  Weird, but it seems harmless.
 	.section .fixup,"ax"
-	.align
-.Lfix:	mov	pc, r9
+	.align	2
+.Lfix:	mov	pc, r9			@ let the user eat segfaults
 	.previous
 
 	.section __ex_table,"a"
-	.align 3
-	.long	.Lx2, .Lfix
+	.align	3
 	.long	.Lx1, .Lfix
+	.long	.Lx2, .Lfix
 	.previous
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S
--- v2.4.3/linux/arch/arm/nwfpe/entry26.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/nwfpe/entry26.S	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Corel Computer Corporation, 1998
+    (c) Rebel.COM, 1998
     (c) Philip Blundell 1998-1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
@@ -84,7 +84,7 @@
 	beq	fpundefinstr		@ no, return failure
 
 next:
-	ldrt	r6, [r5], #4		@ get the next instruction and
+.Lx1:	ldrt	r6, [r5], #4		@ get the next instruction and
 					@ increment PC
 
 	and	r2, r6, #0x0F000000	@ test for FP insns
@@ -110,3 +110,13 @@
 	adr	lr, 1b
 	orr	lr, lr, #3
 	b	EmulateAll		@ if r0 != 0, goto EmulateAll
+
+.Lret:	b	ret_from_exception	@ let the user eat segfaults
+	
+	@ We need to be prepared for the instruction at .Lx1 to fault.
+	@ Emit the appropriate exception gunk to fix things up.
+	.section __ex_table,"a"
+	.align	3
+	.long	.Lx1
+	ldr	lr, [lr, $(.Lret - .Lx1)/4]
+	.previous
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/extended_cpdo.c linux/arch/arm/nwfpe/extended_cpdo.c
--- v2.4.3/linux/arch/arm/nwfpe/extended_cpdo.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/nwfpe/extended_cpdo.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -22,8 +22,6 @@
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
-
-floatx80 getExtendedConstant(unsigned int);
 
 floatx80 floatx80_exp(floatx80 Fm);
 floatx80 floatx80_ln(floatx80 Fm);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c
--- v2.4.3/linux/arch/arm/nwfpe/fpa11.c	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/fpa11.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -46,8 +46,8 @@
     fpa11->fType[i] = typeNone;
   }
   
-  /* FPSR: set system id to FP_EMULATOR, clear all other bits */
-  fpa11->fpsr = FP_EMULATOR;
+  /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
+  fpa11->fpsr = FP_EMULATOR | BIT_AC;
   
   /* FPCR: set SB, AB and DA bits, clear all others */
 #if MAINTAIN_FPCR
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11.inl linux/arch/arm/nwfpe/fpa11.inl
--- v2.4.3/linux/arch/arm/nwfpe/fpa11.inl	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/fpa11.inl	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Corel Computer Corporation, 1998
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11_cpdo.c linux/arch/arm/nwfpe/fpa11_cpdo.c
--- v2.4.3/linux/arch/arm/nwfpe/fpa11_cpdo.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/nwfpe/fpa11_cpdo.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpa11_cprt.c linux/arch/arm/nwfpe/fpa11_cprt.c
--- v2.4.3/linux/arch/arm/nwfpe/fpa11_cprt.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/nwfpe/fpa11_cprt.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
     (c) Philip Blundell, 1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c
--- v2.4.3/linux/arch/arm/nwfpe/fpmodule.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/nwfpe/fpmodule.c	Wed Apr 11 19:02:27 2001
@@ -55,6 +55,8 @@
 #else
 #define fp_send_sig	send_sig
 #define kern_fp_enter	fp_enter
+
+extern char fpe_type[];
 #endif
 
 /* kernel function prototypes required */
@@ -72,24 +74,45 @@
 /* Address of user registers on the kernel stack. */
 unsigned int *userRegisters;
 
-int __init fpe_init(void)
+#ifdef MODULE
+/*
+ * Return 0 if we can be unloaded.  This can only happen if
+ * kern_fp_enter is still pointing at nwfpe_enter
+ */
+static int fpe_unload(void)
+{
+  return (kern_fp_enter == nwfpe_enter) ? 0 : 1;
+}
+#endif
+
+static int __init fpe_init(void)
 {
-  if (sizeof(FPA11) > sizeof(union fp_state))
+  if (sizeof(FPA11) > sizeof(union fp_state)) {
     printk(KERN_ERR "nwfpe: bad structure size\n");
-  else {
-    /* Display title, version and copyright information. */
-    printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 "
-	   "(c) 1998-1999 Rebel.com\n");
-
-    /* Save pointer to the old FP handler and then patch ourselves in */
-    orig_fp_enter = kern_fp_enter;
-    kern_fp_enter = nwfpe_enter;
+    return -EINVAL;
   }
 
+#ifdef MODULE
+  if (!mod_member_present(&__this_module, can_unload))
+    return -EINVAL;
+  __this_module.can_unload = fpe_unload;
+#else
+  if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
+    return 0;
+#endif
+
+  /* Display title, version and copyright information. */
+  printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 "
+	 "(c) 1998-1999 Rebel.com\n");
+
+  /* Save pointer to the old FP handler and then patch ourselves in */
+  orig_fp_enter = kern_fp_enter;
+  kern_fp_enter = nwfpe_enter;
+
   return 0;
 }
 
-void __exit fpe_exit(void)
+static void __exit fpe_exit(void)
 {
   /* Restore the values we saved earlier. */
   kern_fp_enter = orig_fp_enter;
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpmodule.inl linux/arch/arm/nwfpe/fpmodule.inl
--- v2.4.3/linux/arch/arm/nwfpe/fpmodule.inl	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/fpmodule.inl	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
-   NetWinder Floating Point Emulator
-   (c) Rebel.com, 1998-1999
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpopcode.c linux/arch/arm/nwfpe/fpopcode.c
--- v2.4.3/linux/arch/arm/nwfpe/fpopcode.c	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/fpopcode.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -26,7 +26,7 @@
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
-static floatx80 floatx80Constant[] = {
+const floatx80 floatx80Constant[] = {
   { 0x0000, 0x0000000000000000ULL},	/* extended 0.0 */
   { 0x3fff, 0x8000000000000000ULL},	/* extended 1.0 */
   { 0x4000, 0x8000000000000000ULL},	/* extended 2.0 */
@@ -37,7 +37,7 @@
   { 0x4002, 0xa000000000000000ULL}	/* extended 10.0 */
 };  
 
-static float64 float64Constant[] = {
+const float64 float64Constant[] = {
   0x0000000000000000ULL,		/* double 0.0 */
   0x3ff0000000000000ULL,		/* double 1.0 */
   0x4000000000000000ULL,		/* double 2.0 */
@@ -48,7 +48,7 @@
   0x4024000000000000ULL			/* double 10.0 */
 };  
 
-static float32 float32Constant[] = {
+const float32 float32Constant[] = {
   0x00000000,				/* single 0.0 */
   0x3f800000,				/* single 1.0 */
   0x40000000,				/* single 2.0 */
@@ -59,21 +59,6 @@
   0x41200000				/* single 10.0 */
 };  
 
-floatx80 getExtendedConstant(const unsigned int nIndex)
-{
-   return floatx80Constant[nIndex];
-} 
-
-float64 getDoubleConstant(const unsigned int nIndex)
-{
-   return float64Constant[nIndex];
-} 
-
-float32 getSingleConstant(const unsigned int nIndex)
-{
-   return float32Constant[nIndex];
-} 
-
 unsigned int getTransferLength(const unsigned int opcode)
 {
   unsigned int nRc;
@@ -135,10 +120,10 @@
   return(nRc);
 }
 
-/* contition code lookup table
+/* condition code lookup table
  index into the table is test code: EQ, NE, ... LT, GT, AL, NV
  bit position in short is condition code: NZCV */
-unsigned short aCC[16] = {
+static const unsigned short aCC[16] = {
     0xF0F0, // EQ == Z set
     0x0F0F, // NE
     0xCCCC, // CS == C set
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/fpopcode.h linux/arch/arm/nwfpe/fpopcode.h
--- v2.4.3/linux/arch/arm/nwfpe/fpopcode.h	Mon Aug 30 18:15:19 1999
+++ linux/arch/arm/nwfpe/fpopcode.h	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -366,11 +366,25 @@
 /* Get the rounding mode from the opcode. */
 #define getRoundingMode(opcode)		((opcode & MASK_ROUNDING_MODE) >> 5)
 
-float32 getSingleConstant(const unsigned int nIndex);
-float64 getDoubleConstant(const unsigned int nIndex);
-floatx80 getExtendedConstant(const unsigned int nIndex);
+static inline const floatx80 getExtendedConstant(const unsigned int nIndex)
+{
+   extern const floatx80 floatx80Constant[];
+   return floatx80Constant[nIndex];
+} 
+
+static inline const float64 getDoubleConstant(const unsigned int nIndex)
+{
+   extern const float64 float64Constant[];
+   return float64Constant[nIndex];
+} 
+
+static inline const float32 getSingleConstant(const unsigned int nIndex)
+{
+   extern const float32 float32Constant[];
+   return float32Constant[nIndex];
+} 
 
-unsigned int getRegisterCount(const unsigned int opcode);
-unsigned int getDestinationSize(const unsigned int opcode);
+extern unsigned int getRegisterCount(const unsigned int opcode);
+extern unsigned int getDestinationSize(const unsigned int opcode);
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/arch/arm/nwfpe/single_cpdo.c linux/arch/arm/nwfpe/single_cpdo.c
--- v2.4.3/linux/arch/arm/nwfpe/single_cpdo.c	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/single_cpdo.c	Wed Apr 11 19:02:27 2001
@@ -1,6 +1,6 @@
 /*
     NetWinder Floating Point Emulator
-    (c) Rebel.com, 1998-1999
+    (c) Rebel.COM, 1998,1999
 
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
@@ -22,8 +22,6 @@
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
-
-float32 getSingleConstant(unsigned int);
 
 float32 float32_exp(float32 Fm);
 float32 float32_ln(float32 Fm);
diff -u --recursive --new-file v2.4.3/linux/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c
--- v2.4.3/linux/arch/arm/tools/getconstants.c	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/tools/getconstants.c	Wed Apr 11 19:02:27 2001
@@ -14,14 +14,8 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-/*
- * Make sure that the compiler and target are compatible
- */
-#if (defined(__APCS_32__) && defined(CONFIG_CPU_26))
-#error Your compiler targets APCS-32 but this kernel requires APCS-26.
-#endif
-#if (defined(__APCS_26__) && defined(CONFIG_CPU_32))
-#error Your compiler targets APCS-26 but this kernel requires APCS-32.
+#ifndef __APCS_32__
+#error APCS-32 required
 #endif
 
 #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n)
diff -u --recursive --new-file v2.4.3/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types
--- v2.4.3/linux/arch/arm/tools/mach-types	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/tools/mach-types	Wed Apr 11 19:02:27 2001
@@ -1,10 +1,12 @@
 # Database of machine macros and numbers
 #
+# This file is linux/arch/arm/tools/mach-types
+#
 # Please do not send patches to this file; it is automatically generated!
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Fri Feb  9 22:27:32 2001
+# Last update: Sat Apr 7 09:45:09 2001
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -35,7 +37,7 @@
 assabet			SA1100_ASSABET		ASSABET			25
 victor			SA1100_VICTOR		VICTOR			26
 lart			SA1100_LART		LART			27
-ranger			ARCH_RANGER		RANGER			28
+ranger			SA1100_RANGER		RANGER			28
 graphicsclient		SA1100_GRAPHICSCLIENT	GRAPHICSCLIENT		29
 xp860			SA1100_XP860		XP860			30
 cerf			SA1100_CERF		CERF			31
@@ -48,7 +50,7 @@
 netport			SA1100_NETPORT		NETPORT			38
 pangolin		SA1100_PANGOLIN		PANGOLIN		39
 yopy			SA1100_YOPY		YOPY			40
-coolidge		SA1100_COOLIDGE		coolidge		41
+coolidge		SA1100_COOLIDGE		COOLIDGE		41
 huw_webpanel		SA1100_HUW_WEBPANEL	HUW_WEBPANEL		42
 spotme			ARCH_SPOTME		SPOTME			43
 freebird		ARCH_FREEBIRD		FREEBIRD		44
@@ -65,6 +67,16 @@
 webpal			ARCH_WEBPAL		WEBPAL			55
 linpda			SA1100_LINPDA		LINPDA			56
 anakin			ARCH_ANAKIN		ANAKIN			57
+mvi			SA1100_MVI		MVI			58
+jupiter			SA1100_JUPITER		JUPITER			59
+psionw			ARCH_PSIONW		PSIONW			60
+aln			SA1100_ALN		ALN			61
+camelot			ARCH_CAMELOT		CAMELOT			62
+gds2200			SA1100_GDS2200		GDS2200			63
+psion_series7		SA1100_PSION_SERIES7	PSION_SERIES7		64
+xfile			SA1100_XFILE		XFILE			65
+accelent_ep9312		ARCH_ACCELENT_EP9312	ACCELENT_EP9312		66
+ic200			ARCH_IC200		IC200			67
 
 # The following are unallocated
 empeg			SA1100_EMPEG		EMPEG
diff -u --recursive --new-file v2.4.3/linux/arch/cris/Makefile linux/arch/cris/Makefile
--- v2.4.3/linux/arch/cris/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/Makefile	Fri Apr  6 10:42:55 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.11 2000/11/27 17:58:30 bjornw Exp $
+# $Id: Makefile,v 1.15 2001/02/16 17:50:04 larsv Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -25,7 +25,7 @@
 # regenerating stuff (even for incremental linking of subsystems!) is
 # even more nauseating.
 LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \
-          sed -e s/@ETRAX_DRAM_BASE@/0x$(ETRAX_DRAM_BASE)/ \
+          sed -e s/@ETRAX_DRAM_VIRTUAL_BASE@/0x$(ETRAX_DRAM_VIRTUAL_BASE)/ \
               -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \
               < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \
      else true; \
@@ -49,7 +49,7 @@
 
 HEAD := arch/cris/kernel/head.o
 
-SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers
+SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers arch/cris/boot/rescue
 CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o
 LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
 LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
@@ -76,10 +76,18 @@
 
 cramfs:
 ## cramfs      - Creates a cramfs image
-	mkcramfs -p 8192 root cramfs.img
+	mkcramfs -b 8192 root cramfs.img
 	cat vmlinux.bin cramfs.img >timage
 
-zImage: vmlinux
+clinux: vmlinux.bin decompress.bin rescue.bin
+
+decompress.bin: dummy
+	@make -C arch/cris/boot/compressed decompress.bin
+
+rescue.bin: dummy
+	@make -C arch/cris/boot/rescue rescue.bin
+
+zImage: vmlinux.bin
 ## zImage     - Compressed kernel (gzip)
 	@$(MAKEBOOT) zImage
 
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/Makefile linux/arch/cris/boot/compressed/Makefile
--- v2.4.3/linux/arch/cris/boot/compressed/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/boot/compressed/Makefile	Fri Apr  6 10:42:55 2001
@@ -16,11 +16,14 @@
 
 all: vmlinuz
 
-vmlinuz: piggy.img $(OBJECTS)
-	$(LD) -mcriself -T decompress.ld -o decompress.o $(OBJECTS)
+decompress.bin: $(OBJECTS)
+	$(LD) -T decompress.ld -o decompress.o $(OBJECTS)
 	$(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin
 # save it for mkprod in the topdir.
 	cp decompress.bin $(TOPDIR)
+
+
+vmlinuz: piggy.img decompress.bin
 	cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz
 	rm -f piggy.img
 
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/decompress.ld linux/arch/cris/boot/compressed/decompress.ld
--- v2.4.3/linux/arch/cris/boot/compressed/decompress.ld	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/boot/compressed/decompress.ld	Fri Apr  6 10:42:55 2001
@@ -1,3 +1,5 @@
+OUTPUT_FORMAT(elf32-us-cris)
+
 MEMORY 
 	{
 	dram : ORIGIN = 0x40700000,
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/head.S linux/arch/cris/boot/compressed/head.S
--- v2.4.3/linux/arch/cris/boot/compressed/head.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/boot/compressed/head.S	Fri Apr  6 10:42:55 2001
@@ -8,7 +8,6 @@
  *
  */
 
-#include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
 #include <asm/sv_addr_ag.h>
 
@@ -22,23 +21,24 @@
 	nop
 	di
 
-#ifndef CONFIG_SVINTO_SIM	
-
-	;; We need to setup the bus registers before we start using the DRAM
+	;; We need to initialze DRAM registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+	
+dram_init_finished:
+	
+	;; Initiate the PA and PB ports
 
-	move.d   DEF_R_WAITSTATES, r0
-	move.d   r0, [R_WAITSTATES]
+	move.b   DEF_R_PORT_PA_DATA, r0
+	move.b   r0, [R_PORT_PA_DATA]
 
-	move.d   DEF_R_BUS_CONFIG, r0
-	move.d   r0, [R_BUS_CONFIG]
-  
-	move.d   DEF_R_DRAM_CONFIG, r0
-	move.d   r0, [R_DRAM_CONFIG]
+	move.b   DEF_R_PORT_PA_DIR, r0
+	move.b   r0, [R_PORT_PA_DIR]
 
-	move.d   DEF_R_DRAM_TIMING, r0
-	move.d   r0, [R_DRAM_TIMING]
+	move.b   DEF_R_PORT_PB_DATA, r0
+	move.b   r0, [R_PORT_PB_DATA]
 
-#endif
+	move.b   DEF_R_PORT_PB_DIR, r0
+	move.b   r0, [R_PORT_PB_DIR]
 
 	;; Setup the stack to a suitably high address.
 	;; We assume 8 MB is the minimum DRAM in an eLinux
@@ -83,7 +83,7 @@
 	;; Do the decompression and save compressed size in _inptr
 	
 	jsr	_decompress_kernel
-
+	
 	;; Put start address of cramfs in r9 so the kernel can use it
 	;; when mounting from flash
 
@@ -91,7 +91,6 @@
 	add.d	[_inptr], r9		; size of compressed kernel
 
 	;; Enter the decompressed kernel
-		
 	jump	0x40004000	; kernel is linked to this address
 	
 	.data
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c
--- v2.4.3/linux/arch/cris/boot/compressed/misc.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/cris/boot/compressed/misc.c	Fri Apr  6 10:42:55 2001
@@ -13,7 +13,7 @@
  */
 
 /* where the piggybacked kernel image expects itself to live.
- * it is the same address we use when we network load an uncompressed
+ * it is the same adress we use when we network load an uncompressed
  * image into DRAM, and it is the address the kernel is linked to live
  * at by etrax100.ld.
  */
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/Makefile linux/arch/cris/boot/rescue/Makefile
--- v2.4.3/linux/arch/cris/boot/rescue/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/boot/rescue/Makefile	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,50 @@
+#
+# Makefile for rescue code
+#
+ifndef TOPDIR
+TOPDIR = ../../../..
+endif
+CC = gcc-cris -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = ld-cris
+OBJCOPY = objcopy-cris
+
+all: rescue.bin testrescue.bin kimagerescue.bin
+
+rescue: rescue.bin
+	# do nothing
+
+rescue.bin: head.o
+	$(LD) -T rescue.ld -o rescue.o head.o
+	$(OBJCOPY) -O binary --remove-section=.bss rescue.o rescue.bin
+	cp rescue.bin $(TOPDIR)
+
+testrescue.bin: testrescue.o
+	$(OBJCOPY) -O binary --remove-section=.bss testrescue.o tr.bin
+# Pad it to 784 bytes
+	dd if=/dev/zero of=tmp2423 bs=1 count=784
+	cat tr.bin tmp2423 >testrescue_tmp.bin
+	dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784
+	rm tr.bin tmp2423 testrescue_tmp.bin
+
+kimagerescue.bin: kimagerescue.o
+	$(OBJCOPY) -O binary --remove-section=.bss kimagerescue.o ktr.bin
+# Pad it to 784 bytes, that's what the rescue loader expects
+	dd if=/dev/zero of=tmp2423 bs=1 count=784
+	cat ktr.bin tmp2423 >kimagerescue_tmp.bin
+	dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784
+	rm ktr.bin tmp2423 kimagerescue_tmp.bin
+
+head.o: head.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+testrescue.o: testrescue.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+kimagerescue.o: kimagerescue.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+clean:
+	rm -f *.o *.bin
+
+fastdep:
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S
--- v2.4.3/linux/arch/cris/boot/rescue/head.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/boot/rescue/head.S	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,323 @@
+	;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv Exp $
+	;; 
+	;; Rescue code, made to reside at the beginning of the
+	;; flash-memory. when it starts, it checks a partition
+	;; table at the first sector after the rescue sector.
+	;; the partition table was generated by the product builder
+	;; script and contains offsets, lengths, types and checksums
+	;; for each partition that this code should check.
+	;;
+	;; If any of the checksums fail, we assume the flash is so
+	;; corrupt that we cant use it to boot into the ftp flash
+	;; loader, and instead we initialize the serial port to
+	;; receive a flash-loader and new flash image. we dont include
+	;; any flash code here, but just accept a certain amount of
+	;; bytes from the serial port and jump into it. the downloaded
+	;; code is put in the cache.
+	;;
+	;; The partitiontable is designed so that it is transparent to
+	;; code execution - it has a relative branch opcode in the
+	;; beginning that jumps over it. each entry contains extra
+	;; data so we can add stuff later.
+	;;
+	;; Partition table format:
+	;;
+	;;     Code transparency:
+	;; 
+	;;     2 bytes    [opcode 'nop']
+	;;     2 bytes    [opcode 'di']
+	;;     4 bytes    [opcode 'ba <offset>', 8-bit or 16-bit version]
+	;;     2 bytes    [opcode 'nop', delay slot]
+	;;
+	;;     Table validation (at +10):	
+	;; 
+	;;     2 bytes    [magic/version word for partitiontable - 0xef, 0xbe]
+	;;     2 bytes    [length of all entries plus the end marker]
+	;;     4 bytes    [checksum for the partitiontable itself]
+	;;
+	;;     Entries, each with the following format, last has offset -1:	
+	;;    
+	;;        4 bytes    [offset in bytes, from start of flash]
+	;;        4 bytes    [length in bytes of partition]
+	;;        4 bytes    [checksum, simple longword sum]
+	;;        2 bytes    [partition type]
+	;;        2 bytes    [flags, only bit 0 used, ro/rw = 1/0]
+	;;        16 bytes   [reserved for future use]
+	;;
+	;;     End marker
+	;;
+	;;        4 bytes    [-1]
+	;; 
+	;;	 10 bytes    [0, padding]
+	;; 
+	;; Bit 0 in flags signifies RW or RO. The rescue code only bothers
+	;; to check the checksum for RO partitions, since the others will
+	;; change its data without updating the checksums. A 1 in bit 0
+	;; means RO, 0 means RW. That way, it is possible to set a partition
+	;; in RO mode initially, and later mark it as RW, since you can always
+	;; write 0's to the flash.
+	;;
+	;; During the wait for serial input, the status LED will flash so the
+	;; user knows something went wrong.
+	;; 
+	;; Copyright (C) 1999 Axis Communications AB
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+	;; The partitiontable is looked for at the first sector after the boot
+	;; sector. Sector size is 65536 bytes in all flashes we use.
+		
+#define PTABLE_START 0x10000
+#define PTABLE_MAGIC 0xbeef
+
+	;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0.
+	;; That is not where we put our downloaded serial boot-code. The length is
+	;; enough for downloading code that loads the rest of itself (after
+	;; having setup the DRAM etc). It is the same length as the on-chip
+	;; ROM loads, so the same host loader can be used to load a rescued
+	;; product as well as one booted through the Etrax serial boot code.
+		
+#define CODE_START 0x40000000
+#define CODE_LENGTH 784
+
+#ifdef CONFIG_RESCUE_SER0
+#define SERXOFF R_SERIAL0_XOFF
+#define SERBAUD R_SERIAL0_BAUD
+#define SERRECC R_SERIAL0_REC_CTRL
+#define SERRDAT R_SERIAL0_REC_DATA
+#define SERSTAT R_SERIAL0_STATUS
+#endif
+#ifdef CONFIG_RESCUE_SER1
+#define SERXOFF R_SERIAL1_XOFF
+#define SERBAUD R_SERIAL1_BAUD
+#define SERRECC R_SERIAL1_REC_CTRL
+#define SERRDAT R_SERIAL1_REC_DATA
+#define SERSTAT R_SERIAL1_STATUS
+#endif
+#ifdef CONFIG_RESCUE_SER2
+#define SERXOFF R_SERIAL2_XOFF
+#define SERBAUD R_SERIAL2_BAUD
+#define SERRECC R_SERIAL2_REC_CTRL
+#define SERRDAT R_SERIAL2_REC_DATA
+#define SERSTAT R_SERIAL2_STATUS
+#endif	
+#ifdef CONFIG_RESCUE_SER3
+#define SERXOFF R_SERIAL3_XOFF
+#define SERBAUD R_SERIAL3_BAUD
+#define SERRECC R_SERIAL3_REC_CTRL
+#define SERRDAT R_SERIAL3_REC_DATA
+#define SERSTAT R_SERIAL3_STATUS
+#endif
+
+#define NOP_DI 0xf025050f
+	
+	.text
+	
+	;; This is the entry point of the rescue code
+	;; 0x80000000 if loaded in flash (as it should be)
+	;; since etrax actually starts at address 2 when booting from flash, we
+	;; put a nop (2 bytes) here first so we dont accidentally skip the di
+	
+	nop	
+	di
+
+	jump	in_cache	; enter cached area instead
+in_cache:	
+
+	;; first put a jump test to give a possibility of upgrading the rescue code
+	;; without erasing/reflashing the sector. we put a longword of -1 here and if
+	;; its not -1, we jump using the value as jump target. since we can always
+	;; change 1's to 0's without erasing the sector, it is possible to add new
+	;; code after this and altering the jumptarget in an upgrade.
+
+jtcd:	move.d	[jumptarget], r0
+	cmp.d	0xffffffff, r0
+	beq	no_newjump
+	nop
+	
+	jump	[r0]
+
+jumptarget:	
+	.dword	0xffffffff	; can be overwritten later to insert new code
+	
+no_newjump:	
+	;; We need to setup the bus registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+
+	;; we now should go through the checksum-table and check the listed
+	;; partitions for errors.
+	
+	move.d	PTABLE_START, r3
+	move.d	[r3], r0
+	cmp.d	NOP_DI, r0	; make sure the nop/di is there...
+	bne	do_rescue
+	nop
+	
+	;; skip the code transparency block (10 bytes).
+
+	addq	10, r3
+	
+	;; check for correct magic
+	
+	move.w	[r3+], r0
+	cmp.w	PTABLE_MAGIC, r0
+	bne	do_rescue	; didn't recognize - trig rescue
+	nop
+
+	;; check for correct ptable checksum
+
+	movu.w	[r3+], r2	; ptable length
+	move.d	r2, r8		; save for later, length of total ptable
+	addq	28, r8		; account for the rest
+	move.d	[r3+], r4	; ptable checksum
+	move.d	r3, r1
+	jsr	checksum	; r1 source, r2 length, returns in r0
+
+	cmp.d	r0, r4
+	bne	do_rescue	; didn't match - trig rescue
+	nop
+	
+	;; ptable is ok. validate each entry.
+
+	moveq	-1, r7
+	
+ploop:	move.d	[r3+], r1	; partition offset (from ptable start)
+	bne	notfirst	; check if its the partition containing ptable
+	nop			; yes..
+	move.d	r8, r1		; for its checksum check, skip the ptable
+	move.d	[r3+], r2	; partition length
+	sub.d	r8, r2		; minus the ptable length
+	ba	bosse
+	nop
+notfirst:	
+	cmp.d	-1, r1		; the end of the ptable ?
+	beq	flash_ok	;   if so, the flash is validated
+	move.d	[r3+], r2	; partition length
+bosse:	move.d	[r3+], r5	; checksum
+	move.d	[r3+], r4	; type and flags
+	addq	16, r3		; skip the reserved bytes
+	btstq	16, r4		; check ro flag
+	bpl	ploop		;   rw partition, skip validation
+	nop
+	btstq	17, r4		; check bootable flag
+	bpl	1f
+	nop
+	move.d	r1, r7		; remember boot partition offset
+1:	
+
+	add.d	PTABLE_START, r1
+	
+	jsr	checksum	; checksum the partition
+	
+	cmp.d	r0, r5
+	beq	ploop		; checksums matched, go to next entry
+	nop
+
+	;; otherwise fall through to the rescue code.
+	
+do_rescue:
+	;; setup port PA and PB default initial directions and data
+	;; (so we can flash LEDs, and so that DTR and others are set)
+	
+	move.b	DEF_R_PORT_PA_DIR, r0
+	move.b	r0, [R_PORT_PA_DIR]
+	move.b	DEF_R_PORT_PA_DATA, r0
+	move.b	r0, [R_PORT_PA_DATA]
+	
+	move.b	DEF_R_PORT_PB_DIR, r0
+	move.b	r0, [R_PORT_PB_DIR]
+	move.b	DEF_R_PORT_PB_DATA, r0
+	move.b	r0, [R_PORT_PB_DATA]
+
+	;; setup the serial port at 115200 baud
+	
+	moveq	0, r0
+	move.d	r0, [SERXOFF] 
+
+	move.b	0x99, r0
+	move.b	r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+
+	move.b	0x40, r0		; rec enable
+	move.b	r0, [SERRECC] 
+
+	moveq	0, r1		; "timer" to clock out a LED red flash
+	move.d	CODE_START, r3	; destination counter
+	movu.w	CODE_LENGTH, r4	; length
+	
+wait_ser:
+	addq	1, r1
+#ifndef CONFIG_ETRAX_NO_LEDS
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	DEF_R_PORT_PA_DATA, r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	DEF_R_PORT_PB_DATA, r2
+#endif
+	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0
+	btstq	16, r1
+	bpl	1f
+	nop
+	or.d	r0, r2		; set bit
+	ba	2f
+	nop
+1:	not	r0		; clear bit
+	and.d	r0, r2
+2:	
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	r2, [R_PORT_PA_DATA]	
+#endif	
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	r2, [R_PORT_PB_DATA]	
+#endif
+#ifdef CONFIG_ETRAX_90000000_LEDS
+	move.b	r2, [0x90000000]
+#endif
+#endif
+	
+	;; check if we got something on the serial port
+	
+	move.b	[SERSTAT], r0
+	btstq	0, r0		; data_avail
+	bpl	wait_ser
+	nop
+
+	;; got something - copy the byte and loop
+
+	move.b	[SERRDAT], r0
+	move.b	r0, [r3+]
+	
+	subq	1, r4		; decrease length
+	bne	wait_ser
+	nop
+
+	;; jump into downloaded code
+	
+	jump	CODE_START
+
+flash_ok:
+	;; check r7, which contains either -1 or the partition to boot from
+
+	cmp.d	-1, r7
+	bne	1f
+	nop
+	move.d	PTABLE_START, r7; otherwise use the ptable start
+1:	
+	jump	r7		; boot!
+
+
+	;; Helper subroutines
+
+	;; Will checksum by simple addition
+	;; r1 - source
+	;; r2 - length in bytes
+	;; result will be in r0
+checksum:
+	moveq	0, r0
+1:	addu.b	[r1+], r0
+	subq	1, r2
+	bne	1b
+	nop
+	ret
+	nop
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/kimagerescue.S linux/arch/cris/boot/rescue/kimagerescue.S
--- v2.4.3/linux/arch/cris/boot/rescue/kimagerescue.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/boot/rescue/kimagerescue.S	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,143 @@
+	;; $Id: kimagerescue.S,v 1.2 2001/02/14 16:57:25 larsv Exp $
+	;; 
+	;; Rescue code to be prepended on a kimage and copied to the
+	;; rescue serial port.
+	;; This is called from the rescue code, it will copy received data to
+	;; 4000500 and after a timeout jump to it.
+	
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+#define CODE_START 0x40000500
+#define CODE_LENGTH 784
+#define TIMEOUT_VALUE 1000
+	
+		
+#ifdef CONFIG_RESCUE_SER0
+#define SERXOFF R_SERIAL0_XOFF
+#define SERBAUD R_SERIAL0_BAUD
+#define SERRECC R_SERIAL0_REC_CTRL
+#define SERRDAT R_SERIAL0_REC_DATA
+#define SERSTAT R_SERIAL0_STATUS
+#endif
+#ifdef CONFIG_RESCUE_SER1
+#define SERXOFF R_SERIAL1_XOFF
+#define SERBAUD R_SERIAL1_BAUD
+#define SERRECC R_SERIAL1_REC_CTRL
+#define SERRDAT R_SERIAL1_REC_DATA
+#define SERSTAT R_SERIAL1_STATUS
+#endif
+#ifdef CONFIG_RESCUE_SER2
+#define SERXOFF R_SERIAL2_XOFF
+#define SERBAUD R_SERIAL2_BAUD
+#define SERRECC R_SERIAL2_REC_CTRL
+#define SERRDAT R_SERIAL2_REC_DATA
+#define SERSTAT R_SERIAL2_STATUS
+#endif	
+#ifdef CONFIG_RESCUE_SER3
+#define SERXOFF R_SERIAL3_XOFF
+#define SERBAUD R_SERIAL3_BAUD
+#define SERRECC R_SERIAL3_REC_CTRL
+#define SERRDAT R_SERIAL3_REC_DATA
+#define SERSTAT R_SERIAL3_STATUS
+#endif
+
+	.text
+	;; This is the entry point of the rescue code
+	;; 0x80000000 if loaded in flash (as it should be)
+	;; since etrax actually starts at address 2 when booting from flash, we
+	;; put a nop (2 bytes) here first so we dont accidentally skip the di
+	
+	nop	
+	di
+#ifndef CONFIG_SVINTO_SIM	
+	;; setup port PA and PB default initial directions and data
+	;; (so we can flash LEDs, and so that DTR and others are set)
+	
+	move.b	DEF_R_PORT_PA_DIR, r0
+	move.b	r0, [R_PORT_PA_DIR]
+	move.b	DEF_R_PORT_PA_DATA, r0
+	move.b	r0, [R_PORT_PA_DATA]
+	
+	move.b	DEF_R_PORT_PB_DIR, r0
+	move.b	r0, [R_PORT_PB_DIR]
+	move.b	DEF_R_PORT_PB_DATA, r0
+	move.b	r0, [R_PORT_PB_DATA]
+	
+	;; We need to setup the bus registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+	
+#endif
+	;; Setup the stack to a suitably high address.
+	;; We assume 8 MB is the minimum DRAM in an eLinux
+	;; product and put the sp at the top for now.
+
+	move.d	0x40800000, sp
+	
+	;; setup the serial port at 115200 baud
+	
+	moveq	0, r0
+	move.d	r0, [SERXOFF] 
+
+	move.b	0x99, r0
+	move.b	r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+
+	move.b	0x40, r0		; rec enable
+	move.b	r0, [SERRECC] 
+
+
+	moveq	0, r1		; "timer" to clock out a LED red flash
+	move.d	CODE_START, r3	; destination counter
+	move.d	CODE_LENGTH, r4	; length
+	move.d	TIMEOUT_VALUE, r5	; "timeout" until jump
+
+wait_ser:
+	addq	1, r1
+	subq	1, r5		; decrease timeout
+	beq	jump_start	; timed out
+	nop
+#ifndef CONFIG_ETRAX_NO_LEDS
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	DEF_R_PORT_PA_DATA, r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	DEF_R_PORT_PB_DATA, r2
+#endif
+	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0
+	btstq	16, r1
+	bpl	1f
+	nop
+	or.d	r0, r2		; set bit
+	ba	2f
+	nop
+1:	not	r0		; clear bit
+	and.d	r0, r2
+2:	
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	r2, [R_PORT_PA_DATA]
+#endif	
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	r2, [R_PORT_PB_DATA]
+#endif
+#endif
+		
+	;; check if we got something on the serial port
+	
+	move.b	[SERSTAT], r0
+	btstq	0, r0		; data_avail
+	bpl	wait_ser
+	nop
+
+	;; got something - copy the byte and loop
+
+	move.b	[SERRDAT], r0
+	move.b	r0, [r3+]
+	move.d	TIMEOUT_VALUE, r5	; reset "timeout"
+	subq	1, r4		; decrease length
+	bne	wait_ser
+	nop
+jump_start:
+	;; jump into downloaded code
+
+	jump	CODE_START
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/rescue.ld linux/arch/cris/boot/rescue/rescue.ld
--- v2.4.3/linux/arch/cris/boot/rescue/rescue.ld	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/boot/rescue/rescue.ld	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,20 @@
+MEMORY 
+	{
+	flash : ORIGIN = 0x00000000,
+	        LENGTH = 0x00100000
+	}
+
+SECTIONS
+{
+	.text :
+	{
+		_stext = . ;
+		*(.text)
+		_etext = . ;
+	} > flash
+	.data :
+	{
+		*(.data)
+		_edata = . ;
+	} > flash
+}
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/testrescue.S linux/arch/cris/boot/rescue/testrescue.S
--- v2.4.3/linux/arch/cris/boot/rescue/testrescue.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/boot/rescue/testrescue.S	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,25 @@
+	;; $Id: testrescue.S,v 1.1 2001/01/31 15:32:09 johana Exp $
+	;;
+	;; Simple testcode to download by the rescue block.
+	;; Just lits some LEDs to show it was downloaded correctly.
+	;; 
+	;; Copyright (C) 1999 Axis Communications AB
+
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+	.text
+
+	nop
+	nop
+	moveq	-1, r2
+	move.b	r2, [R_PORT_PA_DIR]
+	moveq	0, r2
+	move.b	r2, [R_PORT_PA_DATA]	
+
+endless:
+	nop
+	ba	endless
+	nop
+
+	
diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/tools/build.c linux/arch/cris/boot/tools/build.c
--- v2.4.3/linux/arch/cris/boot/tools/build.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/boot/tools/build.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,288 @@
+/*
+ *  linux/tools/build.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - setup: 8086 machine code, sets up system parm
+ * - system: 80386 code for actual system
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
+/*
+ * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
+ */
+
+#include <stdio.h>	/* fprintf */
+#include <string.h>
+#include <stdlib.h>	/* contains exit */
+#include <sys/types.h>	/* unistd.h needs this */
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>	/* contains read/write */
+#include <fcntl.h>
+#include <linux/a.out.h>
+#include <errno.h>
+
+#define MINIX_HEADER 32
+
+#define N_MAGIC_OFFSET 1024
+#ifndef __BFD__
+static int GCC_HEADER = sizeof(struct exec);
+#endif
+
+#ifdef __BIG_KERNEL__
+#define SYS_SIZE 0xffff
+#else
+#define SYS_SIZE DEF_SYSSIZE
+#endif
+
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
+
+/* max nr of sectors of setup: don't change unless you also change
+ * bootsect etc */
+#define SETUP_SECTS 4
+
+#define STRINGIFY(x) #x
+
+typedef union {
+	int i;
+	long l;
+	short s[2];
+	char b[4];
+} conv;
+
+long intel_long(long l)
+{
+	conv t;
+
+	t.b[0] = l & 0xff; l >>= 8;
+	t.b[1] = l & 0xff; l >>= 8;
+	t.b[2] = l & 0xff; l >>= 8;
+	t.b[3] = l & 0xff; l >>= 8;
+	return t.l;
+}
+
+int intel_int(int i)
+{
+	conv t;
+
+	t.b[0] = i & 0xff; i >>= 8;
+        t.b[1] = i & 0xff; i >>= 8;
+        t.b[2] = i & 0xff; i >>= 8;
+        t.b[3] = i & 0xff; i >>= 8;
+        return t.i;
+}
+
+short intel_short(short l)
+{
+	conv t;
+
+	t.b[0] = l & 0xff; l >>= 8;
+	t.b[1] = l & 0xff; l >>= 8;
+	return t.s[0];
+}
+
+void die(const char * str)
+{
+	fprintf(stderr,"%s\n",str);
+	exit(1);
+}
+
+void usage(void)
+{
+	die("Usage: build bootsect setup system [rootdev] [> image]");
+}
+
+int main(int argc, char ** argv)
+{
+	int i,c,id,sz,tmp_int;
+	unsigned long sys_size, tmp_long;
+	char buf[1024];
+#ifndef __BFD__
+	struct exec *ex = (struct exec *)buf;
+#endif
+	char major_root, minor_root;
+	struct stat sb;
+	unsigned char setup_sectors;
+
+	if ((argc < 4) || (argc > 5))
+		usage();
+	if (argc > 4) {
+		if (!strcmp(argv[4], "CURRENT")) {
+			if (stat("/", &sb)) {
+				perror("/");
+				die("Couldn't stat /");
+			}
+			major_root = major(sb.st_dev);
+			minor_root = minor(sb.st_dev);
+		} else if (strcmp(argv[4], "FLOPPY")) {
+			if (stat(argv[4], &sb)) {
+				perror(argv[4]);
+				die("Couldn't stat root device.");
+			}
+			major_root = major(sb.st_rdev);
+			minor_root = minor(sb.st_rdev);
+		} else {
+			major_root = 0;
+			minor_root = 0;
+		}
+	} else {
+		major_root = DEFAULT_MAJOR_ROOT;
+		minor_root = DEFAULT_MINOR_ROOT;
+	}
+	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+	for (i=0;i<sizeof buf; i++) buf[i]=0;
+	if ((id=open(argv[1],O_RDONLY,0))<0)
+		die("Unable to open 'boot'");
+	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+		die("Unable to read header of 'boot'");
+	if (((long *) buf)[0]!=intel_long(0x04100301))
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[3] != 0)
+		die("Illegal data segment in 'boot'");
+	if (((long *) buf)[4] != 0)
+		die("Illegal bss in 'boot'");
+	if (((long *) buf)[5] != 0)
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[7] != 0)
+		die("Illegal symbol table in 'boot'");
+	i=read(id,buf,sizeof buf);
+	fprintf(stderr,"Boot sector %d bytes.\n",i);
+	if (i != 512)
+		die("Boot block must be exactly 512 bytes");
+	if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55))
+		die("Boot block hasn't got boot flag (0xAA55)");
+	buf[508] = (char) minor_root;
+	buf[509] = (char) major_root;	
+	i=write(1,buf,512);
+	if (i!=512)
+		die("Write call failed");
+	close (id);
+	
+	if ((id=open(argv[2],O_RDONLY,0))<0)
+		die("Unable to open 'setup'");
+	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+		die("Unable to read header of 'setup'");
+	if (((long *) buf)[0]!=intel_long(0x04100301))
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[3] != 0)
+		die("Illegal data segment in 'setup'");
+	if (((long *) buf)[4] != 0)
+		die("Illegal bss in 'setup'");
+	if (((long *) buf)[5] != 0)
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[7] != 0)
+		die("Illegal symbol table in 'setup'");
+	for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+#ifdef __BIG_KERNEL__
+	{
+		if (!i) {
+			/* Working with memcpy because of alignment constraints
+			   on Sparc - Gertjan */
+			memcpy(&tmp_long, &buf[2], sizeof(long));
+			if (tmp_long != intel_long(0x53726448) )
+				die("Wrong magic in loader header of 'setup'");
+			memcpy(&tmp_int, &buf[6], sizeof(int));
+			if (tmp_int < intel_int(0x200))
+				die("Wrong version of loader header of 'setup'");
+			buf[0x11] = 1; /* LOADED_HIGH */
+			tmp_long = intel_long(0x100000);
+			memcpy(&buf[0x14], &tmp_long, sizeof(long));  /* code32_start */
+		}
+#endif
+		if (write(1,buf,c)!=c)
+			die("Write call failed");
+#ifdef __BIG_KERNEL__
+	}
+#endif
+	if (c != 0)
+		die("read-error on 'setup'");
+	close (id);
+	setup_sectors = (unsigned char)((i + 511) / 512);
+	/* for compatibility with LILO */
+	if (setup_sectors < SETUP_SECTS)
+		setup_sectors = SETUP_SECTS;
+	fprintf(stderr,"Setup is %d bytes.\n",i);
+	for (c=0 ; c<sizeof(buf) ; c++)
+		buf[c] = '\0';
+	while (i < setup_sectors * 512) {
+		c = setup_sectors * 512 - i;
+		if (c > sizeof(buf))
+			c = sizeof(buf);
+		if (write(1,buf,c) != c)
+			die("Write call failed");
+		i += c;
+	}
+	
+	if ((id=open(argv[3],O_RDONLY,0))<0)
+		die("Unable to open 'system'");
+#ifndef __BFD__
+	if (read(id,buf,GCC_HEADER) != GCC_HEADER)
+		die("Unable to read header of 'system'");
+	if (N_MAGIC(*ex) == ZMAGIC) {
+		GCC_HEADER = N_MAGIC_OFFSET;
+		lseek(id, GCC_HEADER, SEEK_SET);
+	} else if (N_MAGIC(*ex) != QMAGIC)
+		die("Non-GCC header of 'system'");
+	fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n",
+		(ex->a_text+ex->a_data+ex->a_bss)/1024,
+		ex->a_text /1024,
+		ex->a_data /1024,
+		ex->a_bss  /1024);
+	sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
+#else
+	if (fstat (id, &sb)) {
+	  perror ("fstat");
+	  die ("Unable to stat 'system'");
+	}
+	sz = sb.st_size;
+	fprintf (stderr, "System is %d kB\n", sz/1024);
+#endif
+	sys_size = (sz + 15) / 16;
+	if (sys_size > SYS_SIZE)
+		die("System is too big");
+	while (sz > 0) {
+		int l, n;
+
+		l = sz;
+		if (l > sizeof(buf))
+			l = sizeof(buf);
+		if ((n=read(id, buf, l)) != l) {
+			if (n == -1) 
+				perror(argv[1]);
+			else
+				fprintf(stderr, "Unexpected EOF\n");
+			die("Can't read 'system'");
+		}
+		if (write(1, buf, l) != l)
+			die("Write failed");
+		sz -= l;
+	}
+	close(id);
+	if (lseek(1, 497, 0) == 497) {
+		if (write(1, &setup_sectors, 1) != 1)
+			die("Write of setup sectors failed");
+	}
+	if (lseek(1,500,0) == 500) {
+		buf[0] = (sys_size & 0xff);
+		buf[1] = ((sys_size >> 8) & 0xff);
+		if (write(1, buf, 2) != 2)
+			die("Write failed");
+	}
+	return(0);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/cris/config.in linux/arch/cris/config.in
--- v2.4.3/linux/arch/cris/config.in	Fri Feb 16 15:53:08 2001
+++ linux/arch/cris/config.in	Tue Apr 17 17:19:24 2001
@@ -5,6 +5,8 @@
 mainmenu_name "Linux/CRIS Kernel Configuration"
 
 define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -36,15 +38,19 @@
 comment 'Hardware setup'
 
 choice 'Processor type' \
-	"Etrax-100-LX	CONFIG_ETRAX100LX	\
-	 Etrax-100-LX-for-xsim-simulator   CONFIG_SVINTO_SIM" Etrax-100-LX
+	"Etrax-100-LX-v1	CONFIG_ETRAX100LX	\
+	 Etrax-100-LX-v2	CONFIG_ETRAX100LX_V2	\
+	 Etrax-100-LX-for-xsim-simulator   CONFIG_SVINTO_SIM" Etrax-100-LX-v1
 
 # For both LX version 1 and the current simulator we enable the low VM mapping
-# Later when LX version 2 and above exist, this should be done with an if
 
-define_bool CONFIG_CRIS_LOW_MAP y
+if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then
+	define_bool CONFIG_CRIS_LOW_MAP y
+	define_hex  ETRAX_DRAM_VIRTUAL_BASE 60000000
+else
+	define_hex  ETRAX_DRAM_VIRTUAL_BASE c0000000
+fi
 
-hex 'DRAM base (hex)' ETRAX_DRAM_BASE 40000000
 int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8
 
 int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2
@@ -69,12 +75,29 @@
 	"Serial-0	CONFIG_DEBUG_PORT0	\
 	 Serial-1	CONFIG_DEBUG_PORT1	\
 	 Serial-2	CONFIG_DEBUG_PORT2	\
-	 Serial-3	CONFIG_DEBUG_PORT3" Serial-0
+	 Serial-3	CONFIG_DEBUG_PORT3	\
+	 disabled	CONFIG_DEBUG_PORT_NULL" Serial-0 
+
+choice 'Product rescue-port' \
+	"Serial-0	CONFIG_RESCUE_SER0	\
+	 Serial-1	CONFIG_RESCUE_SER1	\
+	 Serial-2	CONFIG_RESCUE_SER2	\
+	 Serial-3	CONFIG_RESCUE_SER3" Serial-0
 
 hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6
 hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104
-hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040
-hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611
+
+bool 'SDRAM support' CONFIG_SDRAM n
+if [ "$CONFIG_SDRAM" = "n" ]; then
+	hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040
+	hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611
+fi
+
+if [ "$CONFIG_SDRAM" = "y" ]; then
+	hex 'R_SDRAM_CONFIG' DEF_R_SDRAM_CONFIG d2fa7878
+	hex 'R_SDRAM_TIMING' DEF_R_SDRAM_TIMING 80004801
+fi
+
 hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c
 hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00
 hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00
@@ -82,24 +105,6 @@
 hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff
 
 endmenu
-
-# only configure IP numbers if the kernel ifconfig/route setup is enabled
-
-if [ "$CONFIG_KERNEL_IFCONFIG" = "y" ]; then
-  mainmenu_option next_comment	
-  comment 'IP address selection'
-
-  comment 'All addresses are in hexadecimal form without 0x prefix'
-
-  hex 'IP address' ELTEST_IPADR ab1005af
-  hex 'Network' ELTEST_NETWORK ab100000
-  hex 'Netmask' ELTEST_NETMASK ffff0000
-  hex 'Broadcast' ELTEST_BROADCAST ab10ffff
-  hex 'Gateway' ELTEST_GATEWAY ab100101
-  hwaddr 'Ethernet address' ELTEST_ETHADR 00408ccd0000
-
-  endmenu
-fi
 
 # bring in Etrax built-in drivers
 
diff -u --recursive --new-file v2.4.3/linux/arch/cris/cris.ld linux/arch/cris/cris.ld
--- v2.4.3/linux/arch/cris/cris.ld	Tue Feb 13 14:13:43 2001
+++ linux/arch/cris/cris.ld	Fri Apr  6 10:42:55 2001
@@ -1,13 +1,10 @@
 /* ld script to make the Linux/CRIS kernel
  * Authors: Bjorn Wesen (bjornw@axis.com)
- *
- * For now, on Etrax-100 LX, the DRAM starts virtually at 0x6. Normally
- * it should be at 0xc.
  */	
 
 SECTIONS
 {
-	. = 0x60000000;               /* DRAM starts virtually at 0x60000000 */
+	. = @ETRAX_DRAM_VIRTUAL_BASE@;
 	_dram_start = .;
 	_ibr_start = .;
 	. = . + 0x4000; /* see head.S and pages reserved at the start */
@@ -21,6 +18,7 @@
 		*(.fixup)
 		*(.text.__*)
 		*(.rodata)
+		*(.rodata.__*)
 	}
 
 	. = ALIGN(4);                /* Exception table */
@@ -77,5 +75,5 @@
 		*(.exitcall.exit)
         }
 
-	_dram_end = 0x60000000 + @ETRAX_DRAM_SIZE_M@*1024*1024;
+	_dram_end = _dram_start + @ETRAX_DRAM_SIZE_M@*1024*1024;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/cris/defconfig linux/arch/cris/defconfig
--- v2.4.3/linux/arch/cris/defconfig	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/defconfig	Fri Apr  6 10:42:55 2001
@@ -24,10 +24,13 @@
 # Hardware setup
 #
 CONFIG_ETRAX100LX=y
+# CONFIG_ETRAX100LX_V2 is not set
 # CONFIG_SVINTO_SIM is not set
 CONFIG_CRIS_LOW_MAP=y
-ETRAX_DRAM_BASE=40000000
+ETRAX_DRAM_VIRTUAL_BASE=60000000
 ETRAX_DRAM_SIZE=8
+CONFIG_ETRAX_FLASH_LENGTH=2
+CONFIG_ETRAX_FLASH_BUSWIDTH=2
 CONFIG_ETRAX_PA_LEDS=y
 # CONFIG_ETRAX_PB_LEDS is not set
 # CONFIG_ETRAX_90000000_LEDS is not set
@@ -40,8 +43,13 @@
 # CONFIG_DEBUG_PORT1 is not set
 # CONFIG_DEBUG_PORT2 is not set
 # CONFIG_DEBUG_PORT3 is not set
+CONFIG_RESCUE_SER0=y
+# CONFIG_RESCUE_SER1 is not set
+# CONFIG_RESCUE_SER2 is not set
+# CONFIG_RESCUE_SER3 is not set
 DEF_R_WAITSTATES=95a6
 DEF_R_BUS_CONFIG=104
+# CONFIG_SDRAM is not set
 DEF_R_DRAM_CONFIG=1a200040
 DEF_R_DRAM_TIMING=5611
 DEF_R_PORT_PA_DIR=1d
@@ -56,6 +64,87 @@
 CONFIG_ETRAX_ETHERNET=y
 CONFIG_NET_ETHERNET=y
 CONFIG_ETRAX_SERIAL=y
+# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set
+CONFIG_ETRAX_SERIAL_PORT1=y
+# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set
+# CONFIG_ETRAX_SERIAL_PORT2 is not set
+# CONFIG_ETRAX_SERIAL_PORT3 is not set
+# CONFIG_RS485 is not set
+# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set
+# CONFIG_ETRAX_IDE is not set
+CONFIG_ETRAX_AXISFLASHMAP=y
+CONFIG_MTD=y
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_AMDSTD=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_ETRAX_I2C=y
+CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y
+CONFIG_ETRAX_GPIO=y
+CONFIG_ETRAX_PA_BUTTON_BITMASK=02
+CONFIG_PA_CHANGEABLE_DIR=00
+CONFIG_PA_CHANGEABLE_BITS=FF
+CONFIG_PB_CHANGEABLE_DIR=00
+CONFIG_PB_CHANGEABLE_BITS=FF
+# CONFIG_JULIETTE is not set
+# CONFIG_JULIETTE_VIDEO is not set
+# CONFIG_JULIETTE_CCD is not set
+# CONFIG_JULIETTE_SS1M is not set
+# CONFIG_JULIETTE_MEGCCD is not set
+# CONFIG_ETRAX_USB_HOST is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_AMDSTD=y
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_SBC_MEDIAGX is not set
+# CONFIG_MTD_ELAN_104NC is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_CSTM_CFI_JEDEC is not set
+# CONFIG_MTD_JEDEC is not set
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_VMAX is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_SPIA is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
 # Block devices
@@ -90,10 +179,6 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
@@ -101,6 +186,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -112,11 +198,61 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+
+#
 # SCSI support
 #
 # CONFIG_SCSI is not set
 
 #
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -177,6 +313,16 @@
 # CONFIG_WAN is not set
 
 #
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -187,6 +333,60 @@
 # CONFIG_CD_NO_IDESCSI is not set
 
 #
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # File systems
 #
 # CONFIG_QUOTA is not set
@@ -259,59 +459,14 @@
 # CONFIG_NLS is not set
 
 #
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_JOYSTICK is not set
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
+# Sound
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+# CONFIG_SOUND is not set
 
 #
-# Sound
+# USB support
 #
-# CONFIG_SOUND is not set
+# CONFIG_USB is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in
--- v2.4.3/linux/arch/cris/drivers/Config.in	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/drivers/Config.in	Fri Apr  6 10:42:55 2001
@@ -1,16 +1,74 @@
 mainmenu_option next_comment
 comment 'Drivers for Etrax built-in interfaces'
 
-bool 'Ethernet support' CONFIG_ETRAX_ETHERNET y
+bool 'Ethernet support' CONFIG_ETRAX_ETHERNET
 if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then
 # this is just so that the user does not have to go into the
 # normal ethernet driver section just to enable ethernetworking
   define_bool CONFIG_NET_ETHERNET y
+else
+  define_bool CONFIG_NET_ETHERNET n
 fi
 
-bool 'Serial-port support' CONFIG_ETRAX_SERIAL y
+bool 'Serial-port support' CONFIG_ETRAX_SERIAL
+if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
+  comment '  Port 0 is always enabled'
+  bool '  Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
+  if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
+    int '    Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
+    int '    Ser0 RI  on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
+    int '    Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
+    int '    Ser0 CD  on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+  fi
+ 
+  bool '  Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1
+  if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then
+    bool '  Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
+      int '    Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
+      int '    Ser1 RI  on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
+      int '    Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
+      int '    Ser1 CD  on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+    fi
+  fi
+  if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \
+       "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
+    comment 'Make sure you dont have the same PB bits more than once!'
+  fi
+  bool '  Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2
+  if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then
+    bool '    Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then
+      int '      Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
+      int '      Ser2 RI  on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
+      int '      Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
+      int '      Ser2 CD  on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
+    fi 
+  fi
+  bool '  Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3
+  bool '  RS-485 support' CONFIG_RS485
+  if [ "$CONFIG_RS485" = "y" ]; then
+    bool '    RS-485 mode on PA' CONFIG_RS485_ON_PA
+    if [ "$CONFIG_RS485_ON_PA" = "y" ]; then
+      int '      RS-485 mode on PA bit' CONFIG_RS485_ON_PA_BIT 3
+    fi
+    bool '    Disable serial receiver' CONFIG_RS485_DISABLE_RECEIVER
+  fi
+fi
+
+bool 'Synchronous serial port support' CONFIG_ETRAX_SYNCHRONOUS_SERIAL
+if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL" = "y" ]; then 
+  bool '  Synchronous serial port 0 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0
+  if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0" = "y" ]; then
+    bool '    Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA y
+  fi
+  bool '  Synchronous serial port 1 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1
+  if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1" = "y" ]; then
+    bool '    Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA y
+  fi 
+fi
 
-bool 'ATA/IDE support' CONFIG_ETRAX_IDE n
+bool 'ATA/IDE support' CONFIG_ETRAX_IDE
 
 if [ "$CONFIG_ETRAX_IDE" = "y" ]; then
 # here we should add the CONFIG_'s necessary to enable the basic
@@ -25,14 +83,18 @@
 
 	define_bool CONFIG_BLK_DEV_IDEDMA y
 	define_bool CONFIG_DMA_NONPCI y
- 
+	
+	int 'Delay for drives to regain consciousness' CONFIG_IDE_DELAY 15
+	
 	choice 'IDE reset pin' \
   	"Port_PB_Bit_7  CONFIG_ETRAX_IDE_PB7_RESET\
    	 Port_G_Bit_27  CONFIG_ETRAX_IDE_G27_RESET\
    	 Port_CSE1_Bit_16  CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 
+else
+	define_bool CONFIG_IDE n
 fi
 
-bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP n
+bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP
 
 if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then
 # here we define the CONFIG_'s necessary to enable MTD support
@@ -43,7 +105,39 @@
 	define_bool CONFIG_MTD_CFI_INTELEXT n
 	define_bool CONFIG_MTD_CFI_AMDSTD y
 
+	define_bool CONFIG_MTD_AMDSTD y
+
 	define_bool CONFIG_MTD_CHAR y
+	define_bool CONFIG_MTD_BLOCK y
+fi
+
+bool 'I2C support' CONFIG_ETRAX_I2C
+if [ "$CONFIG_ETRAX_I2C" = "y" ]; then
+# this is true for most products since PB-I2C seems to be somewhat
+# flawed.. 
+	bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+fi
+
+bool 'GPIO support' CONFIG_ETRAX_GPIO
+if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then
+  hex  '  PA-buttons bitmask' CONFIG_ETRAX_PA_BUTTON_BITMASK 02
+  hex  '  PA user changeable dir mask' CONFIG_PA_CHANGEABLE_DIR 00
+  hex  '  PA user changeable bits mask' CONFIG_PA_CHANGEABLE_BITS FF
+  hex  '  PB user changeable dir mask' CONFIG_PB_CHANGEABLE_DIR 00
+  hex  '  PB user changeable bits mask' CONFIG_PB_CHANGEABLE_BITS FF
+fi
+
+bool 'Juliette support' CONFIG_JULIETTE n
+
+if [ "$CONFIG_JULIETTE" = "y" ]; then
+   source arch/cris/drivers/juliette/Config.in
+fi
+
+bool 'USB host' CONFIG_ETRAX_USB_HOST
+if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then
+	define_bool CONFIG_USB y
+	bool '  USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 n
+	bool '  USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 n
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile
--- v2.4.3/linux/arch/cris/drivers/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/drivers/Makefile	Fri Apr  6 10:42:55 2001
@@ -6,9 +6,16 @@
 
 obj-y :=
 
-obj-$(CONFIG_ETRAX_ETHERNET)     += ethernet.o
-obj-$(CONFIG_ETRAX_SERIAL)       += serial.o
-obj-$(CONFIG_ETRAX_IDE)          += ide.o
-obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
+
+obj-$(CONFIG_ETRAX_ETHERNET)           += ethernet.o
+obj-$(CONFIG_ETRAX_SERIAL)             += serial.o
+obj-$(CONFIG_ETRAX_IDE)                += ide.o
+obj-$(CONFIG_ETRAX_AXISFLASHMAP)       += axisflashmap.o
+obj-$(CONFIG_ETRAX_I2C) 	       += i2c.o
+obj-$(CONFIG_ETRAX_GPIO) 	       += gpio.o
+obj-$(CONFIG_ETRAX_USB_HOST)           += usb-host.o
+obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
+obj-$(CONFIG_JULIETTE)                 += juliette/juliette.o
+subdir-$(CONFIG_JULIETTE)              += juliette
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c
--- v2.4.3/linux/arch/cris/drivers/axisflashmap.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/drivers/axisflashmap.c	Fri Apr  6 10:42:55 2001
@@ -11,6 +11,17 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.4  2001/02/23 12:47:15  bjornw
+ * Uncached flash in LOW_MAP moved from 0xe to 0x8
+ *
+ * Revision 1.3  2001/02/16 12:11:45  jonashg
+ * MTD driver amd_flash is now included in MTD CVS repository.
+ * (It's now in drivers/mtd).
+ *
+ * Revision 1.2  2001/02/09 11:12:22  jonashg
+ * Support for AMD compatible non-CFI flash chips.
+ * Only tested with Toshiba TC58FVT160 so far.
+ *
  * Revision 1.1  2001/01/12 17:01:18  bjornw
  * * Added axisflashmap.c, a physical mapping for MTD that reads and understands
  *   Axis partition-table format.
@@ -31,7 +42,7 @@
 #include <asm/mmu.h>
 
 #ifdef CONFIG_CRIS_LOW_MAP
-#define FLASH_UNCACHED_ADDR  KSEG_E
+#define FLASH_UNCACHED_ADDR  KSEG_8
 #define FLASH_CACHED_ADDR    KSEG_5
 #else
 #define FLASH_UNCACHED_ADDR  KSEG_E
@@ -205,8 +216,14 @@
 
 	mymtd = do_cfi_probe(&axis_map);
 
+#ifdef CONFIG_MTD_AMDSTD
+	if (!mymtd) {
+		mymtd = do_amd_flash_probe(&axis_map);
+	}
+#endif
+
 	if(!mymtd) {
-		printk("cfi_probe erred %d\n", mymtd);
+		printk("%s: No flash chip found!\n", axis_map.name);
 		return -ENXIO;
 	}
 
@@ -218,7 +235,8 @@
 	 * now at least.
 	 */
 
-	ptable_head = FLASH_CACHED_ADDR + PTABLE_SECTOR + PARTITION_TABLE_OFFSET;
+	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
+		PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
 	pidx++;  /* first partition is always set to the default */
 
 	if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c
--- v2.4.3/linux/arch/cris/drivers/ethernet.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/cris/drivers/ethernet.c	Fri Apr  6 10:42:55 2001
@@ -1,12 +1,23 @@
-/* $Id: ethernet.c,v 1.5 2000/11/29 17:22:22 bjornw Exp $
+/* $Id: ethernet.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
- * Copyright (c) 1998-2000 Axis Communications AB.
+ * Copyright (c) 1998-2001 Axis Communications AB.
  *
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.8  2001/02/27 13:52:48  bjornw
+ * malloc.h -> slab.h
+ *
+ * Revision 1.7  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.6  2001/01/26 15:21:04  starvik
+ * Don't disable interrupts while reading MDIO registers (MDIO is slow)
+ * Corrected promiscuous mode
+ * Improved deallocation of IRQs ("ifconfig eth0 down" now works)
+ *
  * Revision 1.5  2000/11/29 17:22:22  bjornw
  * Get rid of the udword types legacy stuff
  *
@@ -39,7 +50,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -53,7 +64,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <asm/svinto.h>
+#include <asm/svinto.h>     /* DMA and register descriptions */
 
 //#define ETHDEBUG
 
@@ -483,9 +494,6 @@
 	unsigned short data;   /* Data read from MDIO */
 	int bitCounter;
 	
-	save_flags(flags);
-	cli();
-	
 	/* Start of frame, OP Code, Physical Address, Register Address */
 	cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) |
 		(reg_num << 2);
@@ -498,8 +506,7 @@
 	for(bitCounter=15; bitCounter>=0 ; bitCounter--) {
 		data |= (e100_receive_mdio_bit() << bitCounter);
 	}
-	
-	restore_flags(flags);
+
 	return data;
 }
 
@@ -555,9 +562,6 @@
 	unsigned short data;
 	int bitCounter;
 
-	save_flags(flags);
-	cli();
-
 	data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
 
 	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2);
@@ -569,8 +573,6 @@
 	for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
 		e100_send_mdio_bit(GET_BIT(bitCounter, data));
 	}
-	
-	restore_flags(flags);
 }
 
 /* Called by upper layers if they decide it took too long to complete
@@ -858,9 +860,9 @@
 
 	/* Flush the Tx and disable Rx here. */
 
-	free_irq(NETWORK_DMARX_IRQ, NULL);
-	free_irq(NETWORK_DMATX_IRQ, NULL);
-	free_irq(NETWORK_STATUS_IRQ, NULL);
+	free_irq(NETWORK_DMARX_IRQ, (void *)dev);
+	free_irq(NETWORK_DMATX_IRQ, (void *)dev);
+	free_irq(NETWORK_STATUS_IRQ, (void *)dev);
 
 	free_dma(0);
 	free_dma(1);
@@ -926,10 +928,21 @@
 		/* promiscuous mode */
 		lo_bits = 0xfffffffful;
 		hi_bits = 0xfffffffful;
+
+                /* Enable individual receive */
+		*R_NETWORK_REC_CONFIG =
+		  IO_STATE(R_NETWORK_REC_CONFIG, broadcast,  receive) |
+		  IO_STATE(R_NETWORK_REC_CONFIG, ma0,        enable) |
+		  IO_STATE(R_NETWORK_REC_CONFIG, individual, receive);
 	} else if (num_addr == 0) {
 		/* Normal, clear the mc list */
 		lo_bits = 0x00000000ul;
 		hi_bits = 0x00000000ul;
+
+                /* Disable individual receive */
+		*R_NETWORK_REC_CONFIG =
+		  IO_STATE(R_NETWORK_REC_CONFIG, broadcast,  receive) |
+		  IO_STATE(R_NETWORK_REC_CONFIG, ma0,        enable);
 	} else {
 		/* MC mode, receive normal and MC packets */
 		char hash_ix;
@@ -971,6 +984,10 @@
 			}
 			dmi = dmi->next;
 		}
+                /* Disable individual receive */
+		*R_NETWORK_REC_CONFIG =
+		  IO_STATE(R_NETWORK_REC_CONFIG, broadcast,  receive) |
+		  IO_STATE(R_NETWORK_REC_CONFIG, ma0,        enable);
 	}
 	*R_NETWORK_GA_0 = lo_bits;
 	*R_NETWORK_GA_1 = hi_bits;
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/examples/kiobuftest.c linux/arch/cris/drivers/examples/kiobuftest.c
--- v2.4.3/linux/arch/cris/drivers/examples/kiobuftest.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/examples/kiobuftest.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,108 @@
+/*
+ * Example showing how to pin down a range of virtual pages from user-space
+ * to be able to do for example DMA directly into them.
+ *
+ * It is necessary because the pages the virtual pointers reference, might
+ * not exist in memory (could be mapped to the zero-page, filemapped etc)
+ * and DMA cannot trigger the MMU to force them in (and would have time 
+ * contraints making it impossible to wait for it anyway).
+ *
+ * Author:  Bjorn Wesen
+ *
+ * $Log: kiobuftest.c,v $
+ * Revision 1.2  2001/02/27 13:52:50  bjornw
+ * malloc.h -> slab.h
+ *
+ * Revision 1.1  2001/01/19 15:57:49  bjornw
+ * Example of how to do direct HW -> user-mode DMA
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/iobuf.h>
+
+#define KIOBUFTEST_MAJOR 124  /* in the local range, experimental */
+
+
+static ssize_t
+kiobuf_read(struct file *filp, char *buf, size_t len, loff_t *ppos)
+{
+
+     struct kiobuf *iobuf;
+     int res, i;
+ 
+     /* Make a kiobuf that maps the entire length the reader has given
+      * us
+      */
+
+     res = alloc_kiovec(1, &iobuf);
+     if (res)
+	     return res;
+     
+     if((res = map_user_kiobuf(READ, iobuf, (unsigned long)buf, len))) {
+	     printk("map_user_kiobuf failed, return %d\n", res);
+	     return res;
+     }
+
+     /* At this point, the virtual area buf[0] -> buf[len-1] will
+      * have corresponding pages mapped in physical memory and locked
+      * until we unmap the kiobuf. They cannot be swapped out or moved
+      * around.
+      */
+
+     printk("nr_pages == %d\noffset == %d\nlength == %d\n",
+	    iobuf->nr_pages, iobuf->offset, iobuf->length);
+
+     for(i = 0; i < iobuf->nr_pages; i++) {
+	     printk("page_add(maplist[%d]) == 0x%x\n", i,
+		    page_address(iobuf->maplist[i]));
+     }
+
+     /* This is the place to create the necessary scatter-gather vector
+      * for the DMA using the iobuf->maplist array and page_address
+      * (don't forget __pa if the DMA needs the actual physical DRAM address)
+      * and run it.
+      */
+
+
+
+
+     /* Release the mapping and exit */
+
+     unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */
+
+     return len;
+}
+
+
+static struct file_operations kiobuf_fops = {
+	owner:    THIS_MODULE,
+	read:     kiobuf_read
+};
+
+static int __init
+kiobuftest_init(void)
+{
+	int res;
+
+	/* register char device */
+
+	res = register_chrdev(KIOBUFTEST_MAJOR, "kiobuftest", &kiobuf_fops);
+	if(res < 0) {
+		printk(KERN_ERR "kiobuftest: couldn't get a major number.\n");
+		return res;
+	}
+
+	printk("Initializing kiobuf-test device\n");
+}
+
+module_init(kiobuftest_init);
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c
--- v2.4.3/linux/arch/cris/drivers/gpio.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/gpio.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,298 @@
+/* $Id: gpio.c,v 1.4 2001/02/27 13:52:48 bjornw Exp $
+ *
+ * Etrax general port I/O device
+ *
+ * Copyright (c) 1999, 2000, 2001 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen      (initial version)
+ *             Ola Knutsson     (LED handling)
+ *             Johan Adolfsson  (read/set directions)
+ *
+ * $Log: gpio.c,v $
+ * Revision 1.4  2001/02/27 13:52:48  bjornw
+ * malloc.h -> slab.h
+ *
+ * Revision 1.3  2001/01/24 15:06:48  bjornw
+ * gpio_wq correct type
+ *
+ * Revision 1.2  2001/01/18 16:07:30  bjornw
+ * 2.4 port
+ *
+ * Revision 1.1  2001/01/18 15:55:16  bjornw
+ * Verbatim copy of etraxgpio.c from elinux 2.0 added
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/etraxgpio.h>
+#include <asm/svinto.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define GPIO_MAJOR 120  /* experimental MAJOR number */
+
+#define D(x)
+
+static char gpio_name[] = "etrax gpio";
+
+static wait_queue_head_t *gpio_wq;
+
+static int gpio_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg);
+static int gpio_open(struct inode *inode, struct file *filp);
+static int gpio_release(struct inode *inode, struct file *filp);
+static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
+
+/* private data per open() of this driver */
+
+struct gpio_private {
+	struct gpio_private *next;
+	volatile unsigned char *port, *shadow;
+	volatile unsigned char *dir, *dir_shadow;
+	unsigned char changeable_dir;
+	unsigned char changeable_bits;
+	unsigned char highalarm, lowalarm;
+	wait_queue_head_t alarm_wq;
+	int minor;
+};
+
+/* linked list of alarms to check for */
+
+static struct gpio_private *alarmlist = 0;
+
+#define NUM_PORTS 2
+static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA };
+static volatile unsigned char *shads[2] = {
+	&port_pa_data_shadow, &port_pb_data_shadow };
+
+/* What direction bits that are user changeable 1=changeable*/
+#ifndef CONFIG_PA_CHANGEABLE_DIR
+#define CONFIG_PA_CHANGEABLE_DIR 0x00
+#endif
+#ifndef CONFIG_PB_CHANGEABLE_DIR
+#define CONFIG_PB_CHANGEABLE_DIR 0x00
+#endif
+
+#ifndef CONFIG_PA_CHANGEABLE_BITS
+#define CONFIG_PA_CHANGEABLE_BITS 0xFF
+#endif
+#ifndef CONFIG_PB_CHANGEABLE_BITS
+#define CONFIG_PB_CHANGEABLE_BITS 0xFF
+#endif
+
+
+static unsigned char changeable_dir[2] = { CONFIG_PA_CHANGEABLE_DIR,
+                                           CONFIG_PB_CHANGEABLE_DIR };
+static unsigned char changeable_bits[2] = { CONFIG_PA_CHANGEABLE_BITS,
+                                            CONFIG_PB_CHANGEABLE_BITS };
+
+static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR };
+
+static volatile unsigned char *dir_shadow[2] = {
+	&port_pa_dir_shadow, &port_pb_dir_shadow };
+
+#define LEDS 2
+
+static unsigned int 
+gpio_poll(struct file *filp,
+	  struct poll_table_struct *wait)
+{
+	/* TODO poll on alarms! */
+#if 0
+        if(!ANYTHING_WANTED) {
+		D(printk("gpio_select sleeping task\n"));
+	        select_wait(&gpio_wq, table);
+	        return 0;
+	}
+	D(printk("gpio_select ready\n"));
+#endif
+	return 1;
+}
+
+static int
+gpio_open(struct inode *inode, struct file *filp)
+{
+	struct gpio_private *priv;
+	int p = MINOR(inode->i_rdev);
+
+	if(p >= NUM_PORTS && p != LEDS)
+		return -EINVAL;
+
+	priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), 
+					      GFP_KERNEL);
+
+	if(!priv)
+		return -ENOMEM;
+
+	priv->minor = p;
+
+	/* initialize the io/alarm struct and link it into our alarmlist */
+
+	priv->next = alarmlist;
+	alarmlist = priv;
+	priv->port = ports[p];
+	priv->shadow = shads[p];
+
+	priv->changeable_dir = changeable_dir[p];
+	priv->changeable_bits = changeable_bits[p];
+	priv->dir = dir[p];
+	priv->dir_shadow = dir_shadow[p];
+
+	priv->highalarm = 0;
+	priv->lowalarm = 0;
+	init_waitqueue_head(&priv->alarm_wq);
+
+	filp->private_data = (void *)priv;
+
+	return 0;
+}
+
+static int
+gpio_release(struct inode *inode, struct file *filp)
+{
+	struct gpio_private *p = alarmlist;
+	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
+
+	/* unlink from alarmlist and free the private structure */
+
+	if(p == todel) {
+		alarmlist = todel->next;
+	} else {
+		while(p->next != todel)
+			p = p->next;
+		p->next = todel->next;
+	}
+
+	kfree(todel);
+
+	return 0;
+}
+
+/* Main device API. ioctl's to read/set/clear bits, as well as to 
+ * set alarms to wait for using a subsequent select().
+ */
+
+static int
+gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
+
+static int
+gpio_ioctl(struct inode *inode, struct file *file,
+	   unsigned int cmd, unsigned long arg)
+{
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+
+	if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+		return -EINVAL;
+	}
+
+	switch (_IOC_NR(cmd)) {
+		case IO_READBITS:
+			// read the port
+			return *priv->port;
+		case IO_SETBITS:
+			// set changeable bits with a 1 in arg
+			*priv->port = *priv->shadow |= 
+			  ((unsigned char)arg & priv->changeable_bits);
+			break;
+		case IO_CLRBITS:
+			// clear changeable bits with a 1 in arg
+			*priv->port = *priv->shadow &= 
+			  ~((unsigned char)arg & priv->changeable_bits);
+			break;
+		case IO_HIGHALARM:
+			// set alarm when bits with 1 in arg go high
+			priv->highalarm |= (unsigned char)arg;
+			break;
+		case IO_LOWALARM:
+			// set alarm when bits with 1 in arg go low
+			priv->lowalarm |= (unsigned char)arg;
+			break;
+		case IO_CLRALARM:
+			// clear alarm for bits with 1 in arg
+			priv->highalarm &= ~(unsigned char)arg;
+			priv->lowalarm  &= ~(unsigned char)arg;
+			break;
+		case IO_READDIR:
+			/* Read direction 0=input 1=output */
+			return *priv->dir_shadow;
+		case IO_SETINPUT:
+			/* Set direction 0=unchanged 1=input */
+			*priv->dir = *priv->dir_shadow &= 
+			~((unsigned char)arg & priv->changeable_dir);
+			return *priv->dir_shadow;
+		case IO_SETOUTPUT:
+			/* Set direction 0=unchanged 1=output */
+			*priv->dir = *priv->dir_shadow |= 
+			  ((unsigned char)arg & priv->changeable_dir);
+			return *priv->dir_shadow;
+		default:
+			if(priv->minor == LEDS)
+				return gpio_leds_ioctl(cmd, arg);
+			else
+				return -EINVAL;
+	}
+	
+	return 0;
+}
+
+static int
+gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
+{
+	unsigned char green;
+	unsigned char red;
+
+	switch (_IOC_NR(cmd)) {
+		case IO_LEDACTIVE_SET:
+			green = ((unsigned char) arg) & 1;
+			red   = (((unsigned char) arg) >> 1) & 1;
+			LED_ACTIVE_SET_G(green);
+			LED_ACTIVE_SET_R(red);
+			break;
+		default:
+			return -EINVAL;
+	}
+}
+
+struct file_operations gpio_fops = {
+	owner:       THIS_MODULE,
+	poll:        gpio_poll,
+	ioctl:       gpio_ioctl,
+	open:        gpio_open,
+	release:     gpio_release,
+};
+
+/* main driver initialization routine, called from mem.c */
+
+static __init int
+gpio_init(void)
+{
+	int res;
+
+	/* do the formalities */
+
+	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
+	if(res < 0) {
+		printk(KERN_ERR "gpio: couldn't get a major number.\n");
+		return res;
+	}
+	
+	printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n");
+
+	return res;
+}
+
+/* this makes sure that gpio_init is called during kernel boot */
+
+module_init(gpio_init);
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/i2c.c linux/arch/cris/drivers/i2c.c
--- v2.4.3/linux/arch/cris/drivers/i2c.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/i2c.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,691 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : i2c.c
+*!
+*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other
+*!              kernel modules (i2c_writereg/readreg) and from userspace using
+*!              ioctl()'s
+*!
+*! Nov 30 1998  Torbjorn Eliasson  Initial version.
+*!              Bjorn Wesen        Elinux kernel version.
+*! Jan 14 2000  Johan Adolfsson    Fixed PB shadow register stuff - 
+*!                                 don't use PB_I2C if DS1302 uses same bits,
+*!                                 use PB.
+*! $Log: i2c.c,v $
+*! Revision 1.5  2001/02/27 13:52:48  bjornw
+*! malloc.h -> slab.h
+*!
+*! Revision 1.4  2001/02/15 07:17:40  starvik
+*! Corrected usage if port_pb_i2c_shadow
+*!
+*! Revision 1.3  2001/01/26 17:55:13  bjornw
+*! * Made I2C_USES_PB_NOT_PB_I2C a CONFIG option instead of assigning it
+*!   magically. Config.in needs to set it for the options that need it, like
+*!   Dallas 1302 support. Actually, it should be default since it screws up
+*!   the PB bits even if you don't use I2C..
+*! * Include linux/config.h to get the above
+*!
+*! Revision 1.2  2001/01/18 15:49:30  bjornw
+*! 2.4 port of I2C including some cleanups (untested of course)
+*!
+*! Revision 1.1  2001/01/18 15:35:25  bjornw
+*! Verbatim copy of the Etrax i2c driver, 2.0 elinux version
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+/* $Id: i2c.c,v 1.5 2001/02/27 13:52:48 bjornw Exp $ */
+/****************** INCLUDE FILES SECTION ***********************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/etraxi2c.h>
+
+#include <asm/system.h>
+#include <asm/svinto.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "i2c.h"
+
+/****************** I2C DEFINITION SECTION *************************/
+
+#define D(x)
+
+#define I2C_MAJOR 123  /* LOCAL/EXPERIMENTAL */
+static const char i2c_name[] = "i2c";
+
+#define CLOCK_LOW_TIME            8
+#define CLOCK_HIGH_TIME           8
+#define START_CONDITION_HOLD_TIME 8
+#define STOP_CONDITION_HOLD_TIME  8
+#define ENABLE_OUTPUT 0x01
+#define ENABLE_INPUT 0x00
+#define I2C_CLOCK_HIGH 1
+#define I2C_CLOCK_LOW 0
+#define I2C_DATA_HIGH 1
+#define I2C_DATA_LOW 0
+
+#if 0
+/* TODO: fix this so the CONFIG_ETRAX_I2C_USES... is set in Config.in instead */
+#if defined(CONFIG_DS1302) && (CONFIG_DS1302_SDABIT==0) && \
+           (CONFIG_DS1302_SCLBIT == 1)
+#define CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+#endif
+#endif
+
+#ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+/* Use PB and not PB_I2C */
+#define SDABIT 0
+#define SCLBIT 1
+#define i2c_enable() 
+#define i2c_disable() 
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+
+#define i2c_dir_out() \
+  REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1)
+#define i2c_dir_in()  \
+  REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0)
+
+/* control the i2c clock and data signals */
+
+#define i2c_clk(x) \
+  REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SCLBIT, x)
+#define i2c_data(x) \
+  REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x)
+
+/* read a bit from the i2c interface */
+
+#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT))
+
+#else
+/* enable or disable the i2c interface */
+
+#define i2c_enable() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_en))
+#define i2c_disable() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_en))
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+
+#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_))
+#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_))
+
+/* control the i2c clock and data signals */
+
+#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x)))
+
+#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x)))
+
+/* read a bit from the i2c interface */
+
+#define i2c_getbit() (*R_PORT_PB_READ & 0x1)
+#endif
+
+/* use the kernels delay routine */
+
+#define i2c_delay(usecs) udelay(usecs)
+
+
+/****************** FUNCTION DEFINITION SECTION *************************/
+
+
+/* generate i2c start condition */
+
+static void
+i2c_start(void)
+{
+	//
+	// SCL=1 SDA=1
+	//
+	i2c_dir_out();
+	i2c_delay(CLOCK_HIGH_TIME/6);
+	i2c_data(I2C_DATA_HIGH);
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	//
+	// SCL=1 SDA=0
+	//
+	i2c_data(I2C_DATA_LOW);
+	i2c_delay(START_CONDITION_HOLD_TIME);
+	//
+	// SCL=0 SDA=0
+	//
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_LOW_TIME);
+}
+
+/* generate i2c stop condition */
+
+static void
+i2c_stop(void)
+{
+	i2c_dir_out();
+
+	//
+	// SCL=0 SDA=0
+	//
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_data(I2C_DATA_LOW);
+	i2c_delay(CLOCK_LOW_TIME*2);
+	//
+	// SCL=1 SDA=0
+	//
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME*2);
+	//
+	// SCL=1 SDA=1
+	//
+	i2c_data(I2C_DATA_HIGH);
+	i2c_delay(STOP_CONDITION_HOLD_TIME);
+
+	i2c_dir_in();
+}
+
+/* write a byte to the i2c interface */
+
+static void
+i2c_outbyte(unsigned char x)
+{
+	int i;
+	
+	i2c_dir_out();
+
+	for (i = 0; i < 8; i++) {
+		if (x & 0x80)
+			i2c_data(I2C_DATA_HIGH);
+		else
+			i2c_data(I2C_DATA_LOW);
+		
+		i2c_delay(CLOCK_LOW_TIME/2);
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME/2);
+		x <<= 1;
+	}
+	i2c_data(I2C_DATA_LOW);
+	i2c_delay(CLOCK_LOW_TIME/2);
+
+	//
+	// enable input
+	//
+	i2c_dir_in();
+}
+
+/* read a byte from the i2c interface */
+
+static unsigned char
+i2c_inbyte(void)
+{
+	unsigned char aBitByte = 0;
+	int i;
+	int iaa;
+	//int dd= 0;
+
+	//
+	// enable output
+	//
+	i2c_dir_out();
+	//
+	// Release data bus by setting
+	// data high
+	//
+	i2c_data(I2C_DATA_HIGH);
+	//
+	// enable input
+	//
+	i2c_dir_in();
+	//
+	// Use PORT PB instead of I2C
+	// for input. (I2C not working)
+	//
+	i2c_clk(1);
+	i2c_data(1);
+/*	*R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/
+	//
+	// get bits
+	//
+	for (i = 0; i < 8; i++) {
+		i2c_delay(CLOCK_LOW_TIME/2);
+		//
+		// low clock period
+		//
+		i2c_clk(I2C_CLOCK_HIGH);
+		//
+		// switch off I2C
+		//
+		i2c_data(1);
+		i2c_disable();
+		i2c_dir_in();
+		//
+		// wait before getting bit
+		//
+		i2c_delay(CLOCK_HIGH_TIME/2);
+		aBitByte = (aBitByte << 1);
+		iaa = i2c_getbit();
+		aBitByte = aBitByte | iaa ;
+		//if (iaa > 0) dd++;
+		//
+		// wait
+		//
+		i2c_delay(CLOCK_HIGH_TIME/2);
+		//
+		// end clock puls
+		//
+		i2c_enable();
+		i2c_dir_out();
+		i2c_clk(I2C_CLOCK_LOW);
+		//
+		// low clock period
+		//
+		i2c_delay(CLOCK_LOW_TIME/2);
+	}
+	i2c_dir_out();
+	return aBitByte;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_getack
+*#
+*# DESCRIPTION  : checks if ack was received from ic2
+*#
+*#--------------------------------------------------------------------------*/
+
+static int
+i2c_getack(void)
+{
+	int ack = 1;
+	//
+	// enable output
+	//
+	i2c_dir_out();
+	//
+	// Release data bus by setting
+	// data high
+	//
+	i2c_data(I2C_DATA_HIGH);
+	//
+	// enable input
+	//
+	i2c_dir_in();
+	i2c_delay(CLOCK_HIGH_TIME/4);
+	//
+	// generate ACK clock pulse
+	//
+	i2c_clk(I2C_CLOCK_HIGH);
+	//
+	// Use PORT PB instead of I2C
+	// for input. (I2C not working)
+	//
+	i2c_clk(1);
+	i2c_data(1);
+  
+/*	*R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/
+	//
+	// switch off I2C
+	//
+	i2c_data(1);
+	i2c_disable();
+	i2c_dir_in();
+	//
+	// now wait for ack
+	//
+	i2c_delay(CLOCK_HIGH_TIME/2);
+	//
+	// check for ack
+	//
+	if(i2c_getbit())
+		ack = 0;
+	i2c_delay(CLOCK_HIGH_TIME/2);
+	if(!ack){
+		if(!i2c_getbit()) /* receiver pulld SDA low */
+			ack = 1;
+		i2c_delay(CLOCK_HIGH_TIME/2);
+	}
+
+	//
+	// end clock pulse
+	//
+	i2c_enable();
+	i2c_dir_out();
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_HIGH_TIME/4);
+	//
+	// enable output
+	//
+	i2c_dir_out();
+	//
+	// remove ACK clock pulse
+	//
+	i2c_data(I2C_DATA_HIGH);
+	i2c_delay(CLOCK_LOW_TIME/2);
+	return ack;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: I2C::sendAck
+*#
+*# DESCRIPTION  : Send ACK on received data
+*#
+*#--------------------------------------------------------------------------*/
+static void
+i2c_sendack(void)
+{
+	//
+	// enable output
+	//
+	i2c_delay(CLOCK_LOW_TIME);
+	i2c_dir_out();
+	//
+	// set ack pulse high
+	//
+	i2c_data(I2C_DATA_LOW);
+	//
+	// generate clock pulse
+	//
+	i2c_delay(CLOCK_HIGH_TIME/6);
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	i2c_clk(I2C_CLOCK_LOW);
+	i2c_delay(CLOCK_LOW_TIME/6);
+	//
+	// reset data out
+	//
+	i2c_data(I2C_DATA_HIGH);
+	i2c_delay(CLOCK_LOW_TIME);
+	//
+	i2c_dir_in();
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_writereg
+*#
+*# DESCRIPTION  : Writes a value to an I2C device
+*#
+*#--------------------------------------------------------------------------*/
+int
+i2c_writereg(unsigned char theSlave, unsigned char theReg,
+	     unsigned char theValue)
+{
+	int error, cntr = 3;
+		
+	do {
+		error = 0;
+		//
+		// we don't like to be interrupted
+		//
+		cli();
+		//
+		// generate start condition
+		//
+		i2c_start();
+		//
+		// dummy preamble
+		//
+		i2c_outbyte(0x01);
+		i2c_data(I2C_DATA_HIGH);
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */
+		i2c_data(I2C_DATA_LOW);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+
+		i2c_start();
+		//
+		// send slave address
+		//
+		i2c_outbyte(theSlave);
+		//
+		// wait for ack
+		//
+		if(!i2c_getack())
+			error = 1;
+		//
+		// now select register
+		//
+		i2c_dir_out();
+		i2c_outbyte(theReg);
+		//
+		// now it's time to wait for ack
+		//
+		if(!i2c_getack())
+			error |= 2;
+		//
+		// send register register data
+		//
+		i2c_outbyte(theValue);
+		//
+		// now it's time to wait for ack
+		//
+		if(!i2c_getack())
+			error |= 4;
+		//
+		// end byte stream
+		//
+		i2c_stop();
+		//
+		// enable interrupt again
+		//
+		sti();
+		
+	} while(error && cntr--);
+	
+	i2c_delay(CLOCK_LOW_TIME);
+	
+	return -error;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_readreg
+*#
+*# DESCRIPTION  : Reads a value from the decoder registers.
+*#
+*#--------------------------------------------------------------------------*/
+unsigned char
+i2c_readreg(unsigned char theSlave, unsigned char theReg)
+{
+	unsigned char b = 0;
+	int error, cntr = 3;
+		
+	do {
+		error = 0;
+		//
+		// we don't like to be interrupted
+		//
+		cli();
+		//
+		// generate start condition
+		//
+		i2c_start();
+		//
+		// dummy preamble
+		//
+		i2c_outbyte(0x01);
+		i2c_data(I2C_DATA_HIGH);
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+		i2c_clk(I2C_CLOCK_HIGH);
+		i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */
+		i2c_data(I2C_DATA_LOW);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+    
+		i2c_start();
+    
+		//
+		// send slave address
+		//
+		i2c_outbyte(theSlave);
+		//
+		// wait for ack
+		//
+		if(!i2c_getack())
+			error = 1;
+		//
+		// now select register
+		//
+		i2c_dir_out();
+		i2c_outbyte(theReg);
+		//
+		// now it's time to wait for ack
+		//
+		if(!i2c_getack())
+			error = 1;
+		//
+		// repeat start condition
+		//
+		i2c_delay(CLOCK_LOW_TIME);
+		i2c_start();
+		//
+		// send slave address
+		//
+		i2c_outbyte(theSlave | 0x01);
+		//
+		// wait for ack
+		//
+		if(!i2c_getack())
+			error = 1;
+		//
+		// fetch register
+		//
+		b = i2c_inbyte();
+		//
+		// send Ack
+		//
+		i2c_sendack();
+		//
+		// end sequence
+		//
+		i2c_stop();
+		//
+		// enable interrupt again
+		//
+		sti();	
+	} while(error && cntr--);
+
+	return b;
+}
+
+static int
+i2c_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static int
+i2c_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+/* Main device API. ioctl's to write or read to/from i2c registers.
+ */
+
+static int
+i2c_ioctl(struct inode *inode, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+	if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
+		return -EINVAL;
+	}
+
+	switch (_IOC_NR(cmd)) {
+		case I2C_WRITEREG:
+			// write to an i2c slave
+			D(printk("i2cw %d %d %d\n", 
+				 I2C_ARGSLAVE(arg),
+				 I2C_ARGREG(arg),
+				 I2C_ARGVALUE(arg)));
+
+			return i2c_writereg(I2C_ARGSLAVE(arg),
+					    I2C_ARGREG(arg),
+					    I2C_ARGVALUE(arg));
+		case I2C_READREG:
+		{
+			unsigned char val;
+			// read from an i2c slave
+			D(printk("i2cr %d %d ", 
+				I2C_ARGSLAVE(arg),
+				I2C_ARGREG(arg)));
+			val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg));
+			D(printk("= %d\n", val));
+			return val;
+		}					    
+		default:
+			return -EINVAL;
+
+	}
+	
+	return 0;
+}
+
+static struct file_operations i2c_fops = {
+	owner:    THIS_MODULE,
+	ioctl:    i2c_ioctl,
+	open:     i2c_open,
+	release:  i2c_release,
+};
+
+static int __init
+i2c_init(void)
+{
+	int res;
+
+	/* Setup and enable the Port B I2C interface */
+
+#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+	*R_PORT_PB_I2C = port_pb_i2c_shadow |= 
+		IO_STATE(R_PORT_PB_I2C, i2c_en,  on) |
+		IO_FIELD(R_PORT_PB_I2C, i2c_d,   1)  |
+		IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1)  |
+		IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable);
+#endif
+
+	port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0);
+	port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1);
+
+	*R_PORT_PB_DIR = (port_pb_dir_shadow |=
+			  IO_STATE(R_PORT_PB_DIR, dir0, input)  |
+			  IO_STATE(R_PORT_PB_DIR, dir1, output));
+
+	/* register char device */
+
+	res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
+	if(res < 0) {
+		printk(KERN_ERR "i2c: couldn't get a major number.\n");
+		return res;
+	}
+
+	printk("I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
+}
+
+/* this makes sure that i2c_init is called during boot */
+
+module_init(i2c_init);
+
+/****************** END OF FILE i2c.c ********************************/
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/i2c.h linux/arch/cris/drivers/i2c.h
--- v2.4.3/linux/arch/cris/drivers/i2c.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/i2c.h	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,16 @@
+/* $Id: i2c.h,v 1.2 2001/01/18 15:49:30 bjornw Exp $ */
+
+/* High level I2C actions */
+int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
+unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
+
+/* Low level I2C */
+static void i2c_start(void);
+static void i2c_stop(void);
+static void i2c_outbyte(unsigned char x);
+static unsigned char i2c_inbyte(void);
+static int i2c_getack(void);
+static void i2c_sendack(void);
+
+
+
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- v2.4.3/linux/arch/cris/drivers/ide.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/cris/drivers/ide.c	Fri Apr  6 10:42:55 2001
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.4 2001/01/10 21:14:32 bjornw Exp $
+/* $Id: ide.c,v 1.9 2001/03/01 13:11:18 bjornw Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,23 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.9  2001/03/01 13:11:18  bjornw
+ * 100 -> HZ
+ *
+ * Revision 1.8  2001/03/01 09:32:56  matsfg
+ * Moved IDE delay to a CONFIG-parameter instead
+ *
+ * Revision 1.7  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.6  2001/02/22 15:44:30  bjornw
+ * * Use ioremap when mapping the CSE1 memory-mapped reset-line for LX v2
+ * * sw_len for a 65536 descriptor is 0, not 65536
+ * * Express concern for G27 reset code
+ *
+ * Revision 1.5  2001/02/16 07:35:38  matsfg
+ * Now handles DMA request blocks between 64k and 128k by split into two descriptors.
+ *
  * Revision 1.4  2001/01/10 21:14:32  bjornw
  * Initialize hwif->ideproc, for the new way of handling ide_xxx_data
  *
@@ -63,8 +80,13 @@
 /* number of Etrax DMA descriptors */
 #define MAX_DMA_DESCRS 64
 
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+/* address where the memory-mapped IDE reset bit lives, if used */
+static volatile unsigned long *reset_addr;
+#endif
+
 #define LOWDB(x)
-#define D(x)
+#define D(x) 
 
 void OUT_BYTE(unsigned char data, ide_ioreg_t reg) {
 	LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg));
@@ -208,7 +230,8 @@
 static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
 			  void *buffer, unsigned int length);        /* defined below */
 
-void __init init_e100_ide (void)
+void __init 
+init_e100_ide (void)
 {
 	volatile unsigned int dummy;
 	int h;
@@ -226,6 +249,8 @@
 	}
 	/* actually reset and configure the etrax100 ide/ata interface */
 
+	/* This is mystifying; why is not G27 SET anywhere ? It's just reset here twice. */
+
 	/* de-assert bus-reset */
 #ifdef CONFIG_ETRAX_IDE_PB7_RESET  
 	port_pb_dir_shadow = port_pb_dir_shadow | 
@@ -252,7 +277,16 @@
 	*R_GEN_CONFIG = genconfig_shadow;
 
 #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-	*(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 0;
+#ifndef CONFIG_CRIS_LOW_MAP
+	/* remap the I/O-mapped reset-bit from CSE1 to something inside our kernel space */
+	reset_addr = (unsigned long *)ioremap((unsigned long)(MEM_CSE1_START |
+							      MEM_NON_CACHEABLE), 16);
+	*reset_addr = 0;
+#else
+	/* LOW_MAP, can't do the ioremap, but it's already mapped straight over */
+	reset_addr = (unsigned long *)(MEM_CSE1_START | MEM_NON_CACHEABLE);
+	*reset_addr = 0;
+#endif
 #endif
 
 	/* wait some */
@@ -262,9 +296,11 @@
 	dummy = 3;
 
 #ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-	*(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 1 << 16;
-	*R_PORT_G_DATA = 0;  /* de-assert bus-reset */
+	*reset_addr = 1 << 16;
 #endif
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+	*R_PORT_G_DATA = 0; /* de-assert bus-reset */
+#endif 
 
 	/* make a dummy read to set the ata controller in a proper state */
 	dummy = *R_ATA_STATUS_DATA;
@@ -286,9 +322,9 @@
 			     IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
 			     IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
 
-	printk("ide: waiting 10 seconds for drives to regain consciousness\n");
+	printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_IDE_DELAY);
 
-	h = jiffies + 1000;
+	h = jiffies + (CONFIG_IDE_DELAY * HZ);
 	while(jiffies < h) ;
 
   /* reset the dma channels we will use */
@@ -560,14 +596,6 @@
 			return 1;
 		}
 
-		/* uh.. I'm lazy.. if size >= 65536, it should loop below and split it in
-		   more than one descriptor */
-
-		if(size >= 65536) {
-			printk("too large ATA DMA request block, size = %d!\n", size);
-			return 1;
-		}
-
 		/* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
 		   than 65536 words per transfer, so in that case we need to either 
 		   1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
@@ -581,8 +609,22 @@
 			return 1;
 		}
 
-		/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+		/* If size > 65536 it has to be splitted into new descriptors. Since we don't handle 
+                   size > 131072 only one split is necessary */
 
+		if(size > 65536) {
+ 		        /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+                        ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
+                        ata_descrs[count].ctrl = 0;
+                        ata_descrs[count].buf = addr;
+                        ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+                        count++;
+                        ata_tot_size += 65536;
+                        /* size and addr should refere to not handled data */
+                        size -= 65536;
+                        addr += 65536;
+                }
+		/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
 		ata_descrs[count].sw_len = size;
 		ata_descrs[count].ctrl = 0;
 		ata_descrs[count].buf = addr;
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c
--- v2.4.3/linux/arch/cris/drivers/serial.c	Fri Mar  2 18:38:40 2001
+++ linux/arch/cris/drivers/serial.c	Fri Apr  6 10:42:55 2001
@@ -1,12 +1,26 @@
-/* $Id: serial.c,v 1.6 2000/11/22 16:36:09 bjornw Exp $
+/* $Id: serial.c,v 1.10 2001/03/05 13:14:07 bjornw Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
- *      Copyright (C) 1998, 1999, 2000  Axis Communications AB
+ *      Copyright (C) 1998, 1999, 2000, 2001  Axis Communications AB
  *
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.10  2001/03/05 13:14:07  bjornw
+ * Another spelling fix
+ *
+ * Revision 1.9  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.8  2001/01/23 14:56:35  markusl
+ * Made use of ser1 optional
+ * Needed by USB
+ *
+ * Revision 1.7  2001/01/19 16:14:48  perf
+ * Added kernel options for serial ports 234.
+ * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ.
+ *
  * Revision 1.6  2000/11/22 16:36:09  bjornw
  * Please marketing by using the correct case when spelling Etrax.
  *
@@ -176,7 +190,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.6 $";
+static char *serial_version = "$Revision: 1.10 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -252,12 +266,12 @@
 //#define SERIAL_HANDLE_EARLY_ERRORS
 
 
-#ifndef CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS
+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
 /* Default number of timer ticks before flushing rx fifo 
  * When using "little data, low latency applications: use 0
  * When using "much data applications (PPP)" use ~5
  */
-#define CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS 5 
+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 
 #endif
 
 #define MAX_FLUSH_TIME 8
@@ -367,36 +381,36 @@
 {
 /* Ser 0 */
   {
-#if defined(CONFIG_ETRAX100_SER0_DTR_RI_DSR_CD_ON_PB)
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
     R_PORT_PB_DATA,  &port_pb_data_shadow,  &port_pb_dir_shadow,
-    CONFIG_ETRAX100_SER0_DTR_ON_PB_BIT,
-	  CONFIG_ETRAX100_SER0_RI_ON_PB_BIT, 
-	  CONFIG_ETRAX100_SER0_DSR_ON_PB_BIT, 
-	  CONFIG_ETRAX100_SER0_CD_ON_PB_BIT
+    CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
+    CONFIG_ETRAX_SER0_RI_ON_PB_BIT, 
+    CONFIG_ETRAX_SER0_DSR_ON_PB_BIT, 
+    CONFIG_ETRAX_SER0_CD_ON_PB_BIT
 #else
     &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
 #endif   
   },
 /* Ser 1 */
   {
-#if defined(CONFIG_ETRAX100_SER1_DTR_RI_DSR_CD_ON_PB)
+#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
     R_PORT_PB_DATA,  &port_pb_data_shadow,  &port_pb_dir_shadow,
-    CONFIG_ETRAX100_SER1_DTR_ON_PB_BIT,
-	  CONFIG_ETRAX100_SER1_RI_ON_PB_BIT, 
-	  CONFIG_ETRAX100_SER1_DSR_ON_PB_BIT, 
-	  CONFIG_ETRAX100_SER1_CD_ON_PB_BIT
+    CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
+    CONFIG_ETRAX_SER1_RI_ON_PB_BIT, 
+    CONFIG_ETRAX_SER1_DSR_ON_PB_BIT, 
+    CONFIG_ETRAX_SER1_CD_ON_PB_BIT
 #else
     &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
 #endif   
   },  
 /* Ser 2 */
   {
-#if defined(CONFIG_ETRAX100_SER2_DTR_RI_DSR_CD_ON_PA)
+#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
     R_PORT_PA_DATA,  &port_pa_data_shadow,  &port_pa_dir_shadow,
-    CONFIG_ETRAX100_SER2_DTR_ON_PA_BIT,
-	  CONFIG_ETRAX100_SER2_RI_ON_PA_BIT, 
-	  CONFIG_ETRAX100_SER2_DSR_ON_PA_BIT, 
-	  CONFIG_ETRAX100_SER2_CD_ON_PA_BIT
+    CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
+    CONFIG_ETRAX_SER2_RI_ON_PA_BIT, 
+    CONFIG_ETRAX_SER2_DSR_ON_PA_BIT, 
+    CONFIG_ETRAX_SER2_CD_ON_PA_BIT
 #else
     &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
 #endif   
@@ -459,7 +473,7 @@
 static struct semaphore tmp_buf_sem = MUTEX;
 #endif
 
-#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST
+#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
 #define TIMER1_IRQ_NBR 3
 
 /* clock select 10 for timer 1 gives 230400 Hz */
@@ -494,7 +508,7 @@
 	*R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
 	fast_timer_started = 1;
 }
-#endif /* CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST */
+#endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */
 
 /*
  * This function maps from the Bxxxx defines in asm/termbits.h into real
@@ -1267,12 +1281,12 @@
 
 /* dma fifo/buffer timeout handler
    forces an end-of-packet for the dma input channel if no chars 
-   have been received for CONFIG_ETRAX100_RX_TIMEOUT_TICKS/100 s.
-   If CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST is configured then this
+   have been received for CONFIG_ETRAX_RX_TIMEOUT_TICKS/100 s.
+   If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this
    handler is instead run at 15360 Hz.
 */
 
-#ifndef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST
+#ifndef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
 static int timeout_divider = 0;
 #endif
 
@@ -1467,7 +1481,7 @@
 		info->xmit.buf = (unsigned char *) page;
 		
 #ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit_buf);
+	printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf);
 #endif
 
 	if(info->tty) {
@@ -2688,12 +2702,15 @@
 		return -ENODEV;
 
 	/* dont allow opening ports that are not enabled in the HW config */
-
-#ifndef CONFIG_ETRAX100_SERIAL_PORT2
+#ifndef CONFIG_ETRAX_SERIAL_PORT1
+	if (line == 1)
+		return -ENODEV;
+#endif
+#ifndef CONFIG_ETRAX_SERIAL_PORT2
 	if (line == 2)
 		return -ENODEV;
 #endif
-#ifndef CONFIG_ETRAX100_SERIAL_PORT3
+#ifndef CONFIG_ETRAX_SERIAL_PORT3
 	if (line == 3)
 		return -ENODEV;
 #endif
@@ -2955,7 +2972,7 @@
 	for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
 		info->line = i;
 		info->tty = 0;
-		info->type = PORT_ETRAX100;
+		info->type = PORT_ETRAX;
 		info->tr_running = 0;
 		info->fifo_magic = 0;
 		info->fifo_didmagic = 0;
@@ -2990,25 +3007,27 @@
 	if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL))
 		panic("irq8");
 #endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
 	if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
 		panic("irq24");
 	if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
 		panic("irq25");
-#ifdef CONFIG_ETRAX100_SERIAL_PORT2
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
 	/* DMA Shared with par0 (and SCSI0 and ATA) */
 	if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL))
 		panic("irq18");
 	if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL))
 		panic("irq19");
 #endif
-#ifdef CONFIG_ETRAX100_SERIAL_PORT3
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
 	/* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
 	if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL))
 		panic("irq20");
 	if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL))
 		panic("irq21");
 #endif
-#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST
+#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
 	/* TODO: a timeout_interrupt needs to be written that calls timeout_handler */
 	if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ,
 		       "fast serial dma timeout", NULL)) {
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h
--- v2.4.3/linux/arch/cris/drivers/serial.h	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/drivers/serial.h	Fri Apr  6 10:42:55 2001
@@ -4,8 +4,8 @@
  * Copyright (C) 1998, 1999, 2000 Axis Communications AB
  */
 
-#ifndef _ETRAX100_SERIAL_H
-#define _ETRAX100_SERIAL_H
+#ifndef _ETRAX_SERIAL_H
+#define _ETRAX_SERIAL_H
 
 #include <linux/config.h>
 #include <linux/circ_buf.h>
@@ -64,7 +64,7 @@
 	unsigned long		event;
 	unsigned long		last_active;
 	int			line;
-	int                     type;  /* PORT_ETRAX100 */
+	int                     type;  /* PORT_ETRAX */
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
 	long			session; /* Session of opening process */
@@ -93,7 +93,7 @@
  * system.
  */
 
-#define PORT_ETRAX100 1
+#define PORT_ETRAX 1
 
 /*
  * Events are used to schedule things to happen at timer-interrupt
@@ -103,4 +103,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* !(_ETRAX100_SERIAL_H) */
+#endif /* !(_ETRAX_SERIAL_H) */
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/sync_serial.c linux/arch/cris/drivers/sync_serial.c
--- v2.4.3/linux/arch/cris/drivers/sync_serial.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/sync_serial.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,873 @@
+/*  
+ * Simple synchronous serial port driver for ETRAX 100LX.
+ *
+ * Synchronous serial ports are used for continous streamed data like audio.
+ * The deault setting for this driver is compatible with the STA 013 MP3 decoder
+ * The driver can easily be tuned to fit other audio encoder/decoders and SPI
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ * 
+ * Author: Mikael Starvik 
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/svinto.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/sync_serial.h>
+
+/* The receiver is a bit tricky beacuse of the continous stream of data. */
+/*									 */
+/* Two DMA descriptors are linked together. Each DMA descriptor is	 */
+/* responsible for one half of a common buffer.				 */
+/*									 */
+/* ------------------------------					 */
+/* |   ----------   ----------	|					 */
+/* --> | Descr1 |-->| Descr2 |---					 */
+/*     ----------   ----------						 */
+/*	 |	       |						 */
+/*	 v	       v						 */
+/*	 -----------------------------					 */
+/*	 |	      BUFFER	     |					 */
+/*	 -----------------------------					 */
+/*	 |		|						 */
+/*	readp	      writep						 */
+/*									 */
+/* If the application keeps up the pace readp will be right after writep.*/
+/* If the application can't keep the pace we have to throw away data.	 */ 
+/* The idea is that readp should be ready with the data pointed out by	 */
+/* Descr1 when the DMA has filled in Descr2. Otherwise we will discard	 */
+/* the rest of the data pointed out by Descr1 and set readp to the start */
+/* of Descr2								 */
+
+#define SYNC_SERIAL_MAJOR 125
+
+#define IN_BUFFER_SIZE 8192
+#define OUT_BUFFER_SIZE 4096
+
+#define DEBUG(x) 
+
+/* Define some macros to access Etrax 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
+					  IO_FIELD(##reg##, field, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
+					  IO_STATE(##reg##, field, val)
+
+typedef struct sync_port
+{
+	/* Etrax registers and bits*/
+	volatile unsigned * const status;
+	volatile unsigned * const ctrl_data;
+	volatile unsigned * const output_dma_first;
+	volatile unsigned char * const output_dma_cmd;
+	volatile unsigned char * const output_dma_clr_irq;
+	volatile unsigned * const input_dma_first;
+	volatile unsigned char * const input_dma_cmd;
+	volatile unsigned char * const input_dma_clr_irq;
+	volatile unsigned * const data_out;
+	volatile unsigned * const data_in;
+	char data_avail_bit; /* In R_IRQ_MASK1_RD */
+	char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */
+	char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */
+	char input_dma_eop_bit;   /* In R_IRQ_MASK2_RD */
+	char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */
+	char output_dma_bit; /* In R_IRQ_MASK2_RD */
+	char eop_bit; /* In R_SET_EOP */
+
+	int enabled;  /* 1 if port is enabled */
+	int use_dma;  /* 1 if port uses dma */
+	int port_nbr; /* Port 0 or 1 */
+	unsigned ctrl_data_shadow; /* Register shadow */
+	char busy; /* 1 if port is busy */
+	wait_queue_head_t out_wait_q;
+	wait_queue_head_t in_wait_q;
+	struct etrax_dma_descr out_descr;
+	struct etrax_dma_descr in_descr1;
+	struct etrax_dma_descr in_descr2;
+	char out_buffer[OUT_BUFFER_SIZE];
+	int out_count; /* Remaining bytes for current transfer */
+	char* outp; /* Current position in out_buffer */
+	char in_buffer[IN_BUFFER_SIZE];
+	volatile char* readp;  /* Next byte to be read by application */
+	volatile char* writep; /* Next byte to be written by etrax */
+	int odd_output; /* 1 if writing odd nible in 12 bit mode */
+	int odd_input;  /* 1 if reading odd nible in 12 bit mode */
+} sync_port;
+
+
+static int etrax_sync_serial_init(void);
+static void initialize_port(int portnbr);
+static int sync_serial_open(struct inode *, struct file*);
+static int sync_serial_release(struct inode*, struct file*);
+static int sync_serial_ioctl(struct inode*, struct file*,
+			     unsigned int cmd, unsigned long arg);
+static ssize_t sync_serial_write(struct file * file, const char * buf, 
+				 size_t count, loff_t *ppos);
+static ssize_t sync_serial_manual_write(struct file * file, const char * buf, 
+					size_t count, loff_t *ppos);
+static ssize_t sync_serial_read(struct file *file, char *buf, 
+				size_t count, loff_t *ppos);
+static void send_word(sync_port* port);
+static void start_dma(struct sync_port *port, const char* data, int count);
+static void start_dma_in(sync_port* port);
+static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static void flush_handler(void);
+
+/* The ports */
+static struct sync_port ports[]=
+{
+	{
+		R_SYNC_SERIAL1_STATUS,  /* status */
+		R_SYNC_SERIAL1_CTRL,    /* ctrl_data */
+		R_DMA_CH8_FIRST,	    /* output_dma_first */
+		R_DMA_CH8_CMD,	    /* output_dma_cmd */
+		R_DMA_CH8_CLR_INTR,	    /* output_dma_clr_irq */
+		R_DMA_CH9_FIRST,	    /* input_dma_first */
+		R_DMA_CH9_CMD,	    /* input_dma_cmd */
+		R_DMA_CH9_CLR_INTR,	    /* input_dma_clr_irq */
+		R_SYNC_SERIAL1_TR_DATA, /* data_out */
+		R_SYNC_SERIAL1_REC_DATA,/* data in */
+		IO_BITNR(R_IRQ_MASK1_RD, ser1_data),   /* data_avail_bit */
+		IO_BITNR(R_IRQ_MASK1_RD, ser1_ready),  /* transmitter_ready_bit */
+		IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma9_eop),	   /* input_dma_eop_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma9_descr),  /* input_dma_descr_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma8_eop),	   /* output_dma_bit */
+		IO_BITNR(R_SET_EOP, ch9_eop)	   /* eop_bit */
+	},
+	{
+		R_SYNC_SERIAL3_STATUS,  /* status */
+		R_SYNC_SERIAL3_CTRL,    /* ctrl_data */
+		R_DMA_CH4_FIRST,	    /* output_dma_first */
+		R_DMA_CH4_CMD,	    /* output_dma_cmd */
+		R_DMA_CH4_CLR_INTR,	    /* output_dma_clr_irq */
+		R_DMA_CH5_FIRST,	    /* input_dma_first */
+		R_DMA_CH5_CMD,	    /* input_dma_cmd */
+		R_DMA_CH5_CLR_INTR,	    /* input_dma_clr_irq */
+		R_SYNC_SERIAL3_TR_DATA, /* data_out */
+		R_SYNC_SERIAL3_REC_DATA,/* data in */
+		IO_BITNR(R_IRQ_MASK1_RD, ser3_data),   /* data_avail_bit */
+		IO_BITNR(R_IRQ_MASK1_RD, ser3_ready),  /* transmitter_ready_bit */
+		IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma5_eop),	   /* input_dma_eop_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma5_descr),  /* input_dma_eop_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma4_eop),	   /* output_dma_bit */
+		IO_BITNR(R_SET_EOP, ch5_eop)	   /* eop_bit */
+	}
+};
+
+/* Register shadows */
+static unsigned sync_serial_prescale_shadow = 0;
+static unsigned gen_config_ii_shadow = 0;
+
+/* Timer used to flush data from the DMA */
+static struct timer_list flush_timer;
+
+#define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port))
+
+static struct file_operations sync_serial_fops = {
+       owner:	THIS_MODULE,
+       write:	sync_serial_write,
+       read:	sync_serial_read,
+       ioctl:	sync_serial_ioctl,
+       open:	sync_serial_open,
+       release: sync_serial_release
+};
+
+static int __init etrax_sync_serial_init(void)
+{
+	ports[0].enabled = 0;
+	ports[1].enabled = 0;
+
+	if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) 
+	{
+		printk("unable to get major for synchronous serial port\n");
+		return -EBUSY;
+	}
+
+	/* Deselect synchronous serial ports */
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async);
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async);
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, ser3, select);
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+  
+	/* Initialize Ports */
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
+	ports[0].enabled = 1;
+	SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser1, ss1extra); 
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync);
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
+	ports[0].use_dma = 1;
+	initialize_port(0);
+	if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", NULL))
+		 panic("Can't allocate sync serial port 1 IRQ");
+	if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", NULL))
+		panic("Can't allocate sync serial port 1 IRQ");
+	RESET_DMA(8); WAIT_DMA(8);
+	RESET_DMA(9); WAIT_DMA(9);
+	*R_DMA_CH8_CLR_INTR = 3;  /* Clear IRQ */
+	*R_DMA_CH9_CLR_INTR = 3;  /* Clear IRQ */
+	*R_IRQ_MASK2_SET =
+	  IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) |
+	  IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) |
+          IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | 
+          IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
+	start_dma_in(&ports[0]);
+#else
+	ports[0].use_dma = 0;
+	initialize_port(0);
+	if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL))
+		panic("Can't allocate sync serial manual irq");
+	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
+#endif
+#endif
+
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+	ports[1].enabled = 1;
+	SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser3, ss3extra);
+	SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync);
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
+	ports[1].use_dma = 1;
+	initialize_port(1);
+	if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", NULL))
+		panic("Can't allocate sync serial port 1 IRQ");
+	if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", NULL))
+		panic("Can't allocate sync serial port 1 IRQ");
+	RESET_DMA(4); WAIT_DMA(4);
+	RESET_DMA(5); WAIT_DMA(5);
+	*R_DMA_CH4_CLR_INTR = 3;  /* Clear IRQ */
+	*R_DMA_CH5_CLR_INTR = 3;  /* Clear IRQ */
+	*R_IRQ_MASK2_SET =
+	  IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
+	  IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) |
+	  IO_STATE(R_IRQ_MASK2_SET, dma5_eop, set) | 
+	  IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);
+	start_dma_in(&ports[1]);
+#else
+	ports[1].use_dma = 0;	
+	initialize_port(1);
+	if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */
+	{
+		if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL))
+			panic("Can't allocate sync serial manual irq");
+	}
+	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
+#endif
+#endif
+
+	*R_PORT_PB_I2C = port_pb_i2c_shadow; /* Use PB4/PB7 */
+
+	/* Set up timing */
+	*R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow = (
+	  IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec) | 
+	  IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u1, external) | 
+	  IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | 
+	  IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | 
+	  IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | 
+	  IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, 0) | 
+	  IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, 7) | 
+	  IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal));
+
+	/* Select synchronous ports */
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+
+	/*Initialize DMA flush timer if dma is used */
+	if (ports[0].use_dma || ports[1].use_dma) 
+	{
+		init_timer(&flush_timer);
+		flush_timer.function = flush_handler;
+		mod_timer(&flush_timer, jiffies + 10);
+	}
+
+	printk("Etrax100LX synchronous serial port driver\n");
+	return 0;
+}
+
+static void initialize_port(int portnbr)
+{
+	struct sync_port* port = &ports[portnbr];
+
+	DEBUG(printk("Init sync serial port %d\n", portnbr));
+    
+	port->port_nbr = portnbr;	
+	port->busy = 0;		
+	port->readp = port->in_buffer;
+	port->writep = port->in_buffer + IN_BUFFER_SIZE/2;
+	port->odd_input = 0;
+
+	init_waitqueue_head(&port->out_wait_q);
+	init_waitqueue_head(&port->in_wait_q);
+
+	port->ctrl_data_shadow =
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, tr_baud, c115k2Hz)   | 
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, mode, master_output) | 
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, error, ignore)       |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, rec_enable, disable) |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, f_synctype, normal)  |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word)    |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on)	     |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal)    |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, running)   |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb)	     |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, enable)   |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit)  |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8)    |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8)     |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled)  |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_polarity, neg)   |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, frame_polarity, normal)|
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, status_polarity, inverted)|
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_driver, normal)   |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, frame_driver, normal) |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, status_driver, normal)|
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, def_out0, high);
+  
+	if (port->use_dma)
+		port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, on);
+	else
+		port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, off);
+  
+	*port->ctrl_data = port->ctrl_data_shadow;
+}
+
+static int sync_serial_open(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev);
+	DEBUG(printk("Open sync serial port %d\n", dev)); 
+  
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	{
+		DEBUG(printk("Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	if (ports[dev].busy)
+	{
+		DEBUG(printk("Device is busy.. \n"));
+		return -EBUSY;
+	}
+	ports[dev].busy = 1;
+	return 0;
+}
+
+static int sync_serial_release(struct inode *inode, struct file *file)
+{
+	ports[MINOR(inode->i_rdev)].busy = 0;
+	return 0;
+}
+
+static int sync_serial_ioctl(struct inode *inode, struct file *file,
+		  unsigned int cmd, unsigned long arg)
+{
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	sync_port* port = &ports[dev];
+
+	/* Disable port while changing config */
+	if (dev)
+	{
+		RESET_DMA(4); WAIT_DMA(4);
+		*R_DMA_CH4_CLR_INTR = 3;  
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async);
+	}
+	else
+	{
+		RESET_DMA(8); WAIT_DMA(8);
+		*R_DMA_CH8_CLR_INTR = 3;  
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async);
+	}
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+
+	switch(cmd)
+	{
+		case SSP_SPEED:
+			if (GET_SPEED(arg) == CODEC)
+			{
+				if (dev)
+					SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec);
+				else
+					SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec);
+
+				SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, prescaler, GET_FREQ(arg));
+				SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, frame_rate, GET_FRAME_RATE(arg));
+				SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, word_rate, GET_WORD_RATE(arg));
+			}
+			else
+			{
+				SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_baud, GET_SPEED(arg));
+				if (dev)
+					SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, baudrate);
+				else
+					SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, baudrate);
+			}
+			break;
+		case SSP_MODE:
+			if (arg > 5)
+				return -EINVAL;
+			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg);
+			break;
+		case SSP_FRAME_SYNC:
+			if (arg & NORMAL_SYNC)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal);
+			else if (arg & EARLY_SYNC)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, early);
+    
+			if (arg & BIT_SYNC)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, bit);
+			else if (arg & WORD_SYNC)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word);
+			else if (arg & EXTENDED_SYNC)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, extended);
+    
+			if (arg & SYNC_ON)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on);
+			else if (arg & SYNC_OFF)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, off);
+    
+			if (arg & WORD_SIZE_8)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit);
+			else if (arg & WORD_SIZE_12)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size12bit);
+			else if (arg & WORD_SIZE_16)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size16bit);
+			else if (arg & WORD_SIZE_24)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size24bit);
+			else if (arg & WORD_SIZE_32)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size32bit);
+    
+			if (arg & BIT_ORDER_MSB)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb);
+			else if (arg & BIT_ORDER_LSB)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, lsb);
+
+			if (arg & FLOW_CONTROL_ENABLE)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled);
+			else if (arg & FLOW_CONTROL_DISABLE)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled);
+
+			if (arg & CLOCK_NOT_GATED)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal);
+			else if (arg & CLOCK_GATED)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);
+    
+			break;
+		case SSP_IPOLARITY:
+			if (arg & CLOCK_NORMAL)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg);
+			else if (arg & CLOCK_INVERT)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, pos);
+
+			if (arg & FRAME_NORMAL)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, normal);
+			else if (arg & FRAME_INVERT)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted);
+
+			if (arg & STATUS_NORMAL)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, normal);
+			else if (arg & STATUS_INVERT)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, inverted);
+			break;
+		case SSP_OPOLARITY:
+			if (arg & CLOCK_NORMAL)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, normal);
+			else if (arg & CLOCK_INVERT)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted);
+    
+			if (arg & FRAME_NORMAL)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, normal);
+			else if (arg & FRAME_INVERT)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted);
+
+			if (arg & STATUS_NORMAL)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, normal);
+			else if (arg & STATUS_INVERT)
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, inverted);
+			break;
+		case SSP_SPI:
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word);
+			SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal);
+			if (arg & SPI_SLAVE)
+			{
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted);
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg);
+				SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, SLAVE_INPUT);
+			}
+			else
+			{
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted);
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted);
+				SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, MASTER_OUTPUT);
+			}
+			break;
+		default:
+			return -EINVAL;
+	}
+	/* Set config and enable port */
+	*port->ctrl_data = port->ctrl_data_shadow;
+	*R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow;
+	if (dev)
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync);
+	else
+		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync);
+
+	*R_GEN_CONFIG_II = gen_config_ii_shadow;
+	return 0;
+}
+
+static ssize_t sync_serial_manual_write(struct file * file, const char * buf, 
+                                        size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	sync_port* port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)];
+
+	copy_from_user(port->out_buffer, buf, count);
+	port->outp = port->out_buffer;
+	port->out_count = count;
+	port->odd_output = 1;
+	add_wait_queue(&port->out_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
+	send_word(port); /* Start sender by sending first word */
+	schedule();
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&port->out_wait_q, &wait);
+	return count;
+}
+
+static ssize_t sync_serial_write(struct file * file, const char * buf, 
+                                 size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)];
+
+	DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count));
+
+	if (!port->use_dma)
+	{
+		return sync_serial_manual_write(file, buf, count, ppos); 
+	}
+  
+	copy_from_user(port->out_buffer, buf, count);
+	add_wait_queue(&port->out_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	start_dma(port, buf, count);
+	schedule();
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&port->out_wait_q, &wait);
+	return count;
+}
+
+static ssize_t sync_serial_read(struct file * file, char * buf, 
+				size_t count, loff_t *ppos)
+{
+	int avail;
+	sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)];
+	char* start; 
+	char* end;
+	unsigned long flags;	
+
+	DEBUG(printk("Read dev %d count\n"));
+
+	/* Calculate number of available bytes */
+	while (port->readp == port->writep) /* No data */
+	{
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+			interruptible_sleep_on(&port->in_wait_q);
+	}
+	
+	/* Save pointers to avoid that they are modified by interrupt */
+	start = port->readp;
+	end = port->writep;
+
+	/* Lazy read, never return wrapped data. */
+	if (end > start)
+		avail = end - start;
+	else 
+		avail = port->in_buffer + IN_BUFFER_SIZE - start;
+  
+	count = count > avail ? avail : count;
+	copy_to_user(buf, start, count);
+
+	/* Disable interrupts while updating readp */
+	save_flags(flags);
+	cli();	
+	port->readp += count;
+	if (port->readp == port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
+		port->readp = port->in_buffer;
+	restore_flags(flags);
+
+	DEBUG(printk("%d bytes read\n", count));
+	return count;
+}
+
+static void send_word(sync_port* port)
+{
+	switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize))
+	{
+		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit):
+			port->out_count--;
+			*port->data_out = *port->outp++;
+			break;
+		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
+			port->out_count--;
+			if (port->odd_output)
+				*port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1));
+			else
+				*port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1));
+			port->odd_output = !port->odd_output;
+			port->outp++;
+			break;
+		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
+			port->out_count-=2;
+			*port->data_out = *(unsigned short *)port->outp;
+			port->outp+=2;
+			break;
+		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit):
+			port->out_count-=3;
+			*port->data_out = *(unsigned int *)port->outp;
+			port->outp+=3;
+			break;
+		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit):
+			port->out_count-=4;
+			*port->data_out = *(unsigned int *)port->outp;
+			port->outp+=4;
+			break;
+	}
+}
+
+static void start_dma(struct sync_port* port, const char* data, int count)
+{
+	port->out_descr.hw_len = 0;
+	port->out_descr.next = 0;
+	port->out_descr.ctrl = d_int | d_eol | d_eop;
+	port->out_descr.sw_len = count;
+	port->out_descr.buf = virt_to_phys(port->out_buffer);
+	port->out_descr.status = 0;
+
+	*port->output_dma_first = virt_to_phys(&port->out_descr);
+	*port->output_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start);
+}
+
+static void start_dma_in(sync_port* port)
+{
+	if (port->writep > port->in_buffer + IN_BUFFER_SIZE)
+	{
+		panic("Offset too large in sync serial driver\n");
+		return;
+	}
+	port->in_descr1.hw_len = 0;
+	port->in_descr1.ctrl = d_eop | d_int;
+	port->in_descr1.status = 0;
+	port->in_descr1.next = virt_to_phys(&port->in_descr2);
+	port->in_descr2.hw_len = 0;
+	port->in_descr2.next = virt_to_phys(&port->in_descr1);
+	port->in_descr2.ctrl = d_eop | d_int;
+	port->in_descr2.status = 0;
+
+	/* Find out which descriptor to start */
+	if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2)
+	{
+		/* Start descriptor 2 */
+		port->in_descr1.sw_len = IN_BUFFER_SIZE/2; /* All data available in 1 */
+		port->in_descr1.buf = virt_to_phys(port->in_buffer);
+		port->in_descr2.sw_len = port->in_buffer + IN_BUFFER_SIZE - port->writep;
+		port->in_descr2.buf = virt_to_phys(port->writep);
+		*port->input_dma_first = virt_to_phys(&port->in_descr2);
+	}
+	else
+	{
+		/* Start descriptor 1 */
+		port->in_descr1.sw_len = port->in_buffer + IN_BUFFER_SIZE/2 - port->writep;
+		port->in_descr1.buf = virt_to_phys(port->writep);
+		port->in_descr2.sw_len = IN_BUFFER_SIZE/2;
+		port->in_descr2.buf = virt_to_phys(port->in_buffer + IN_BUFFER_SIZE / 2);
+		*port->input_dma_first = virt_to_phys(&port->in_descr1);
+	}
+	*port->input_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start);
+}
+
+static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned long ireg = *R_IRQ_MASK2_RD;
+	int i;
+
+	for (i = 0; i < NUMBER_OF_PORTS; i++) 
+	{
+		sync_port *port = &ports[i];
+		if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */
+		{
+			/* Clear IRQ */
+			*port->output_dma_clr_irq = 
+			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) |
+			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
+			wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */
+		} 
+	}
+}
+
+static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned long ireg = *R_IRQ_MASK2_RD;
+	int i;	
+
+	for (i = 0; i < NUMBER_OF_PORTS; i++) 
+	{
+		int update = 0;
+		sync_port *port = &ports[i];
+
+		if (!port->enabled)
+		{
+			continue;
+		}    
+
+		if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */
+		{
+			/* DMA has reached end of descriptor */
+			*port->input_dma_clr_irq = 
+			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
+			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
+
+			/* Find out which descriptor that is ready */
+			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) 
+			{
+				/* Descr 2 was ready. Restart DMA at descriptor 1 */
+				port->writep = port->in_buffer;
+	
+				/* Throw away data? */
+				if (port->readp < port->in_buffer + IN_BUFFER_SIZE/2)
+					port->readp = port->in_buffer + IN_BUFFER_SIZE/2;
+			}
+			else
+			{
+				/* Descr 1 was ready. Restart DMA at descriptor 2 */
+				port->writep = port->in_buffer + IN_BUFFER_SIZE/2;
+
+				/* Throw away data? */
+				if (port->readp >= port->in_buffer + IN_BUFFER_SIZE/2)
+					port->readp = port->in_buffer;
+			}
+			start_dma_in(port);
+			wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */
+		}
+		else if (ireg & (1 << port->input_dma_eop_bit)) /* EOP interrupt */
+		{
+			/* EOP interrupt means that DMA has not reached end of descriptor */
+			*port->input_dma_clr_irq = 
+			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
+			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
+
+			/* Find out the current descriptor */
+			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2)
+				port->writep += port->in_descr2.hw_len;
+			else
+				port->writep += port->in_descr1.hw_len;
+
+			start_dma_in(port);
+			wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */
+		}
+	}
+}
+
+static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int i;
+
+	for (i = 0; i < NUMBER_OF_PORTS; i++)
+	{
+		sync_port* port = &ports[i];
+
+		if (!port->enabled)
+		{
+			continue;
+		}
+
+		if (*R_IRQ_MASK1_RD & (1 << port->data_avail_bit))	/* Data received? */
+		{
+			/* Read data */
+			switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize))
+			{
+				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit):
+					*port->writep++ = *(volatile char *)port->data_in;
+					break;
+				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
+				{
+					int data = *(unsigned short *)port->data_in;
+					if (port->odd_input)
+					{
+						*port->writep |= (data & 0x0f00) >> 8;
+						*(port->writep + 1) = data & 0xff;
+					}
+					else
+					{
+						*port->writep = (data & 0x0ff0) >> 4;
+						*(port->writep + 1) = (data & 0x0f) << 4;
+					}
+					port->odd_input = !port->odd_input;
+					port->writep+=1;
+				}
+				break;
+				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
+					*(unsigned short*)port->writep = *(volatile unsigned short *)port->data_in;
+					port->writep+=2;
+					break;
+				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit):
+					*(unsigned int*)port->writep = *port->data_in;
+					port->writep+=3;
+					break;
+				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit):
+					*(unsigned int*)port->writep = *port->data_in;
+					port->writep+=4;
+					break;
+			}
+
+			if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
+				port->writep = port->in_buffer;
+			wake_up_interruptible(&port->in_wait_q); /* Wake up application */
+		}
+
+		if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */
+		{
+			if (port->out_count) /* More data to send */
+				send_word(port);
+			else /* transmission finished */
+			{
+				*R_IRQ_MASK1_CLR = 1 << port->ready_irq_bit; /* Turn off IRQ */
+				wake_up_interruptible(&port->out_wait_q); /* Wake up application */
+			}
+		}
+	}
+}
+
+static void flush_handler(void)
+{
+	int i;
+	
+	for (i = 0; i < NUMBER_OF_PORTS; i++)
+	{
+		if (ports[i].enabled)
+		{
+			*R_SET_EOP = 1 << ports[i].eop_bit;  
+		}
+	}
+	/* restart flush timer */
+	mod_timer(&flush_timer, jiffies + 10);
+}
+
+module_init(etrax_sync_serial_init);
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c
--- v2.4.3/linux/arch/cris/drivers/usb-host.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/usb-host.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,2501 @@
+/*
+ * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
+ *
+ * Copyright (c) 2001 Axis Communications AB.
+ *
+ * $Id: usb-host.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/list.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/svinto.h>
+
+#include <linux/usb.h>
+#include "usb-host.h"
+
+#define ETRAX_USB_HC_IRQ 31
+#define ETRAX_USB_RX_IRQ 25
+#define ETRAX_USB_TX_IRQ 24
+
+static const char *usb_hcd_version = "$Revision: 1.8 $";
+
+#undef KERN_DEBUG
+#define KERN_DEBUG ""
+
+#undef USB_DEBUG_RH
+#undef USB_DEBUG_EP
+#undef USB_DEBUG_DESC
+#undef USB_DEBUG_TRACE
+#undef USB_DEBUG_CTRL
+#undef USB_DEBUG_BULK
+#undef USB_DEBUG_INTR
+
+#ifdef USB_DEBUG_RH
+#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
+#else
+#define dbg_rh(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_EP
+#define dbg_ep(format, arg...) printk(KERN_DEBUG __FILE__ ": (EP) " format "\n" , ## arg)
+#else
+#define dbg_ep(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_CTRL
+#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
+#else
+#define dbg_ctrl(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_BULK
+#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
+#else
+#define dbg_bulk(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_INTR
+#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
+#else
+#define dbg_intr(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_TRACE
+#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering : " __FUNCTION__ "\n"))
+#define DBFEXIT  (printk(KERN_DEBUG __FILE__ ": Exiting  : " __FUNCTION__ "\n"))
+#else
+#define DBFENTER (NULL)
+#define DBFEXIT  (NULL)
+#endif
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+static __u8 root_hub_dev_des[] =
+{
+	0x12,  /*  __u8  bLength; */
+	0x01,  /*  __u8  bDescriptorType; Device */
+	0x00,  /*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,  /*  __u8  bDeviceSubClass; */
+	0x00,  /*  __u8  bDeviceProtocol; */
+	0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,  /*  __u16 idVendor; */
+	0x00,
+	0x00,  /*  __u16 idProduct; */
+	0x00,
+	0x00,  /*  __u16 bcdDevice; */
+	0x00,
+	0x00,  /*  __u8  iManufacturer; */
+	0x02,  /*  __u8  iProduct; */
+	0x01,  /*  __u8  iSerialNumber; */
+	0x01   /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,  /*  __u8  bLength; */
+	0x02,  /*  __u8  bDescriptorType; Configuration */
+	0x19,  /*  __u16 wTotalLength; */
+	0x00,
+	0x01,  /*  __u8  bNumInterfaces; */
+	0x01,  /*  __u8  bConfigurationValue; */
+	0x00,  /*  __u8  iConfiguration; */
+	0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */
+	0x00,  /*  __u8  MaxPower; */
+
+     /* interface */
+	0x09,  /*  __u8  if_bLength; */
+	0x04,  /*  __u8  if_bDescriptorType; Interface */
+	0x00,  /*  __u8  if_bInterfaceNumber; */
+	0x00,  /*  __u8  if_bAlternateSetting; */
+	0x01,  /*  __u8  if_bNumEndpoints; */
+	0x09,  /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,  /*  __u8  if_bInterfaceSubClass; */
+	0x00,  /*  __u8  if_bInterfaceProtocol; */
+	0x00,  /*  __u8  if_iInterface; */
+
+     /* endpoint */
+	0x07,  /*  __u8  ep_bLength; */
+	0x05,  /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,  /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,  /*  __u8  ep_bmAttributes; Interrupt */
+	0x08,  /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff   /*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+	0x09,  /*  __u8  bLength; */
+	0x29,  /*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,  /*  __u8  bNbrPorts; */
+	0x00,  /* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,  /*  __u8  bHubContrCurrent; 0 mA */
+	0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+
+#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break
+#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
+{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
+
+static submit_urb_count = 0;
+
+//#define ETRAX_USB_INTR_IRQ
+//#define ETRAX_USB_INTR_ERROR_FATAL
+
+#define RX_BUF_SIZE        32768
+#define RX_DESC_BUF_SIZE   64
+#define NBR_OF_RX_DESC     (RX_BUF_SIZE / RX_DESC_BUF_SIZE)
+
+#define NBR_OF_EP_DESC     32
+
+#define MAX_INTR_INTERVAL 128
+
+static __u32 ep_usage_bitmask;
+static __u32 ep_really_active;
+
+static unsigned char RxBuf[RX_BUF_SIZE];
+static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
+
+static volatile USB_IN_Desc_t *myNextRxDesc;
+static volatile USB_IN_Desc_t *myLastRxDesc;
+static volatile USB_IN_Desc_t *myPrevRxDesc;
+
+static USB_EP_Desc_t TxCtrlEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4)));
+static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4)));
+
+static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
+static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
+
+static urb_t *URB_List[NBR_OF_EP_DESC];
+static kmem_cache_t *usb_desc_cache;
+static struct usb_bus *etrax_usb_bus;
+
+static void dump_urb (purb_t purb);
+static void init_rx_buffers(void);
+static int etrax_rh_unlink_urb (urb_t *urb);
+static void etrax_rh_send_irq(urb_t *urb);
+static void etrax_rh_init_int_timer(urb_t *urb);
+static void etrax_rh_int_timer_do(unsigned long ptr);
+
+static void etrax_usb_setup_epid(char epid, char devnum, char endpoint,
+				 char packsize, char slow);
+static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp);
+static int etrax_usb_allocate_epid(void);
+static void etrax_usb_free_epid(char epid);
+static void cleanup_sb(USB_SB_Desc_t *sb);
+
+static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen);
+static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen);
+
+static int etrax_usb_submit_ctrl_urb(urb_t *urb);
+
+static int etrax_usb_submit_urb(urb_t *urb);
+static int etrax_usb_unlink_urb(urb_t *urb);
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
+static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
+static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
+
+static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs);
+
+static int etrax_rh_submit_urb (urb_t *urb);
+
+static int etrax_usb_hc_init(void);
+static void etrax_usb_hc_cleanup(void);
+
+static struct usb_operations etrax_usb_device_operations =
+{
+	etrax_usb_allocate_dev,
+	etrax_usb_deallocate_dev,
+	etrax_usb_get_frame_number,
+	etrax_usb_submit_urb,
+	etrax_usb_unlink_urb
+};
+
+#ifdef USB_DEBUG_DESC
+static void dump_urb(purb_t purb)
+{
+	printk("\nurb                   :0x%08X\n", purb);
+	printk("next                  :0x%08X\n", purb->next);
+	printk("dev                   :0x%08X\n", purb->dev);
+	printk("pipe                  :0x%08X\n", purb->pipe);
+	printk("status                :%d\n", purb->status);
+	printk("transfer_flags        :0x%08X\n", purb->transfer_flags);
+	printk("transfer_buffer       :0x%08X\n", purb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
+	printk("actual_length         :%d\n", purb->actual_length);
+	printk("setup_packet          :0x%08X\n", purb->setup_packet);
+	printk("start_frame           :%d\n", purb->start_frame);
+	printk("number_of_packets     :%d\n", purb->number_of_packets);
+	printk("interval              :%d\n", purb->interval);
+	printk("error_count           :%d\n", purb->error_count);
+	printk("context               :0x%08X\n", purb->context);
+	printk("complete              :0x%08X\n\n", purb->complete);
+}
+
+static void dump_in_desc(USB_IN_Desc_t *in)
+{
+	printk("\nUSB_IN_Desc at 0x%08X\n", in);
+	printk("  sw_len  : 0x%04X (%d)\n", in->sw_len, in->sw_len);
+	printk("  command : 0x%04X\n", in->command);
+	printk("  next    : 0x%08X\n", in->next);
+	printk("  buf     : 0x%08X\n", in->buf);
+	printk("  hw_len  : 0x%04X (%d)\n", in->hw_len, in->hw_len);
+	printk("  status  : 0x%04X\n\n", in->status);
+}
+
+static void dump_sb_desc(USB_SB_Desc_t *sb)
+{
+	printk("\nUSB_SB_Desc at 0x%08X\n", sb);
+	printk("  sw_len  : 0x%04X (%d)\n", sb->sw_len, sb->sw_len);
+	printk("  command : 0x%04X\n", sb->command);
+	printk("  next    : 0x%08X\n", sb->next);
+	printk("  buf     : 0x%08X\n\n", sb->buf);
+}
+
+
+static void dump_ep_desc(USB_EP_Desc_t *ep)
+{
+	printk("\nUSB_EP_Desc at 0x%08X\n", ep);
+	printk("  hw_len  : 0x%04X (%d)\n", ep->hw_len, ep->hw_len);
+	printk("  command : 0x%08X\n", ep->command);
+	printk("  sub     : 0x%08X\n", ep->sub);
+	printk("  nep     : 0x%08X\n\n", ep->nep);
+}
+
+
+#else
+#define dump_urb(...)     (NULL)
+#define dump_ep_desc(...) (NULL)
+#define dump_sb_desc(...) (NULL)
+#define dump_in_desc(...) (NULL)
+#endif
+
+static void init_rx_buffers(void)
+{
+	int i;
+	
+	DBFENTER;
+	
+	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+		RxDescList[i].command = 0;
+		RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
+		RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+		RxDescList[i].hw_len = 0;
+		RxDescList[i].status = 0;
+	}
+	
+	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+	RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
+	RxDescList[i].next = virt_to_phys(&RxDescList[0]);
+	RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+	RxDescList[i].hw_len = 0;
+	RxDescList[i].status = 0;
+
+	myNextRxDesc = &RxDescList[0];
+	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+
+	*R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
+	*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
+	
+	DBFEXIT;
+}
+
+static void init_tx_ctrl_ep(void)
+{
+	int i;
+	
+	DBFENTER;
+	
+	for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) {
+		TxCtrlEPList[i].hw_len = 0;
+		TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxCtrlEPList[i].sub = 0;
+		TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[i + 1]);
+	}
+	
+	TxCtrlEPList[i].hw_len = 0;
+	TxCtrlEPList[i].command = IO_STATE(USB_EP_command, eol, yes) |
+		IO_FIELD(USB_EP_command, epid, i);
+
+	TxCtrlEPList[i].sub = 0;
+	TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[0]);
+	
+	*R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
+	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+	
+	DBFEXIT;
+}
+
+static void init_tx_bulk_ep(void)
+{
+	int i;
+	
+	DBFENTER;
+	
+	for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) {
+		TxBulkEPList[i].hw_len = 0;
+		TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxBulkEPList[i].sub = 0;
+		TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[i + 1]);
+	}
+	
+	TxBulkEPList[i].hw_len = 0;
+	TxBulkEPList[i].command = IO_STATE(USB_EP_command, eol, yes) |
+		IO_FIELD(USB_EP_command, epid, i);
+
+	TxBulkEPList[i].sub = 0;
+	TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[0]);
+	
+	*R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[0]);
+	*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+	
+	DBFEXIT;
+}
+
+static void init_tx_intr_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	TxIntrSB_zout.sw_len = 0;
+	TxIntrSB_zout.next = 0;
+	TxIntrSB_zout.buf = 0;
+	TxIntrSB_zout.command = IO_FIELD(USB_SB_command, rem, 0) |
+		IO_STATE(USB_SB_command, tt, zout) |
+		IO_STATE(USB_SB_command, full, yes) |
+		IO_STATE(USB_SB_command, eot, yes) |
+		IO_STATE(USB_SB_command, eol, yes);
+
+	for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
+		TxIntrEPList[i].hw_len = 0;
+		TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) |
+			IO_STATE(USB_EP_command, enable, yes) |
+			IO_FIELD(USB_EP_command, epid, 0);
+		TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+		TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[i + 1]);
+	}
+	
+	TxIntrEPList[i].hw_len = 0;
+	TxIntrEPList[i].command =
+		IO_STATE(USB_EP_command, eof, yes) |
+		IO_STATE(USB_EP_command, enable, yes) |
+		IO_FIELD(USB_EP_command, epid, 0);
+	TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+	TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[0]);
+
+	*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+	
+	DBFEXIT;
+}
+
+
+static int etrax_usb_unlink_intr_urb(urb_t *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	etrax_hc_t *hc = usb_dev->bus->hcpriv;
+
+	USB_EP_Desc_t *tmp_ep;
+	USB_EP_Desc_t *first_ep;
+	
+	USB_EP_Desc_t *ep_desc;
+	USB_SB_Desc_t *sb_desc;
+	
+	char epid;
+	char devnum;
+	char endpoint;
+	char slow;
+	int maxlen;
+	int i;
+	
+	etrax_urb_priv_t *urb_priv;
+	unsigned long flags;
+	
+	DBFENTER;
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	slow = usb_pipeslow(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe,
+			       usb_pipeout(urb->pipe));
+
+	epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen);
+	if (epid == -1) {
+		err("Trying to unlink urb that is not in traffic queue!!");
+		return -1;  /* fix this */
+	}
+
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, stop);
+	/* Somehow wait for the DMA to finish current activities */
+	i = jiffies + 100;
+	while (jiffies < i);	
+	
+	first_ep = &TxIntrEPList[0];
+	tmp_ep = first_ep;
+	
+	do {
+		if (IO_EXTRACT(USB_EP_command, epid, ((USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep))->command)
+		    == epid) {
+			/* Unlink it !!! */
+			dbg_intr("Found urb to unlink for epid %d", epid);
+			
+			ep_desc = phys_to_virt(tmp_ep->nep);
+			tmp_ep->nep = ep_desc->nep;
+			kmem_cache_free(usb_desc_cache, phys_to_virt(ep_desc->sub));
+			kmem_cache_free(usb_desc_cache, ep_desc);
+		}
+
+		tmp_ep = phys_to_virt(tmp_ep->nep);
+		
+	} while (tmp_ep != first_ep);
+
+	/* We should really try to move the EP register to an EP that is not removed
+	   instead of restarting, but this will work too */
+	*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+
+	clear_bit(epid, (void *)&ep_really_active);
+	URB_List[epid] = NULL;
+	etrax_usb_free_epid(epid);
+	
+	DBFEXIT;
+
+	return 0;
+}
+
+void etrax_usb_do_intr_recover(int epid)
+{
+	USB_EP_Desc_t *first_ep, *tmp_ep;
+	
+	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
+	tmp_ep = first_ep;
+
+	do {
+		if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
+		    !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
+			tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
+		}
+		
+		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep);
+		
+	} while (tmp_ep != first_ep);
+}
+
+static int etrax_usb_submit_intr_urb(urb_t *urb)
+{
+	USB_EP_Desc_t *tmp_ep;
+	USB_EP_Desc_t *first_ep;
+	
+	USB_SB_Desc_t *sb_desc;
+	
+	char epid;
+	char devnum;
+	char endpoint;
+	char maxlen;
+	char slow;
+	int interval;
+	int i;
+	
+	etrax_urb_priv_t *urb_priv;
+	unsigned long flags;
+	
+	DBFENTER;
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe,
+			       usb_pipeout(urb->pipe));
+
+	slow = usb_pipeslow(urb->pipe);
+	interval = urb->interval;
+
+	dbg_intr("Intr traffic for dev %d, endpoint %d, maxlen %d, slow %d",
+		 devnum, endpoint, maxlen, slow);
+	
+	epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen);
+	if (epid == -1) {
+		epid = etrax_usb_allocate_epid();
+		if (epid == -1) {
+			/* We're out of endpoints, return some error */
+			err("We're out of endpoints");
+			return -ENOMEM;
+		}
+		/* Now we have to fill in this ep */
+		etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow);
+	}
+	/* Ok, now we got valid endpoint, lets insert some traffic */
+
+	urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL);
+	urb_priv->first_sb = 0;
+	urb_priv->rx_offset = 0;
+	urb_priv->eot = 0;
+	INIT_LIST_HEAD(&urb_priv->ep_in_list);
+	urb->hcpriv = urb_priv;
+
+	/* This is safe since there cannot be any other URB's for this epid */
+	URB_List[epid] = urb;
+#if 0
+	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
+#else
+	first_ep = &TxIntrEPList[0];
+#endif
+
+	/* Round of the interval to 2^n, it is obvious that this code favours
+	   smaller numbers, but that is actually a good thing */
+	for (i = 0; interval; i++) {
+		interval = interval >> 1;
+	}
+
+	urb->interval = interval = 1 << (i - 1);
+
+	dbg_intr("Interval rounded to %d", interval);
+
+	tmp_ep = first_ep;
+	i = 0;
+	do {
+		if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
+			if ((i % interval) == 0) {
+				/* Insert the traffic ep after tmp_ep */
+				USB_EP_Desc_t *traffic_ep;
+				USB_SB_Desc_t *traffic_sb;
+
+				traffic_ep = (USB_EP_Desc_t *)
+					kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+				traffic_sb = (USB_SB_Desc_t *)
+					kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+
+				traffic_ep->hw_len = 0;
+				traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) |
+					IO_STATE(USB_EP_command, enable, yes);
+				traffic_ep->sub = virt_to_phys(traffic_sb);
+
+				if (usb_pipein(urb->pipe)) {
+					traffic_sb->sw_len = urb->transfer_buffer_length ?
+						(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+					traffic_sb->next = 0;
+					traffic_sb->buf = 0;
+					traffic_sb->command = IO_FIELD(USB_SB_command, rem,
+								       urb->transfer_buffer_length % maxlen) |
+						IO_STATE(USB_SB_command, tt, in) |
+						IO_STATE(USB_SB_command, eot, yes) |
+						IO_STATE(USB_SB_command, eol, yes);
+					
+				} else if (usb_pipeout(urb->pipe)) {
+					traffic_sb->sw_len = urb->transfer_buffer_length;
+					traffic_sb->next = 0;
+					traffic_sb->buf = virt_to_phys(urb->transfer_buffer);
+					traffic_sb->command = IO_FIELD(USB_SB_command, rem, 0) |
+						IO_STATE(USB_SB_command, tt, out) |
+						IO_STATE(USB_SB_command, eot, yes) |
+						IO_STATE(USB_SB_command, eol, yes) |
+						IO_STATE(USB_SB_command, full, yes);
+				}
+
+				traffic_ep->nep = tmp_ep->nep;
+				tmp_ep->nep = virt_to_phys(traffic_ep);
+				dbg_intr("One ep successfully inserted");
+			}
+			i++;
+		}
+		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep);
+	} while (tmp_ep != first_ep);
+
+	set_bit(epid, (void *)&ep_really_active);
+	
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+
+	DBFEXIT;
+	
+	return 0;
+}
+
+
+static int handle_intr_transfer_attn(char epid, int status)
+{
+	urb_t *old_urb;
+
+	DBFENTER;
+
+	old_urb = URB_List[epid];
+	
+	/* if (status == 0 && IN) find data and copy to urb */
+	if (status == 0 && usb_pipein(old_urb->pipe)) {
+		unsigned long flags;
+		etrax_urb_priv_t *urb_priv;
+		struct list_head *entry;
+		struct in_chunk *in;
+
+		urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv;
+		
+		save_flags(flags);
+		cli();
+
+		list_for_each(entry, &urb_priv->ep_in_list) {
+			in = list_entry(entry, struct in_chunk, list);
+			memcpy(old_urb->transfer_buffer, in->data, in->length);
+			old_urb->actual_length = in->length;
+			old_urb->status = status;
+			
+			if (old_urb->complete) {
+				old_urb->complete(old_urb);
+			}
+			
+			list_del(entry);
+			kfree(in->data);
+			kfree(in);
+		}		
+		
+		restore_flags(flags);
+
+	} else if (status != 0) {
+		warn("Some sort of error for INTR EP !!!!");
+#ifdef ETRAX_USB_INTR_ERROR_FATAL
+		/* This means that an INTR error is fatal for that endpoint */
+		etrax_usb_unlink_intr_urb(old_urb);
+		old_urb->status = status;
+		if (old_urb->complete) {
+			old_urb->complete(old_urb);
+		}
+#else
+		/* In this case we reenable the disabled endpoint(s) */
+		etrax_usb_do_intr_recover(epid);
+#endif	
+	}
+	
+	DBFEXIT;
+}
+
+static int etrax_rh_unlink_urb (urb_t *urb)
+{
+	etrax_hc_t *hc;
+	
+	DBFENTER;
+	
+	hc = urb->dev->bus->hcpriv;
+	
+	if (hc->rh.urb == urb) {
+		hc->rh.send = 0;
+		del_timer(&hc->rh.rh_int_timer);
+	}
+	
+	DBFEXIT;
+	return 0;
+}
+
+static void etrax_rh_send_irq(urb_t *urb)
+{
+	__u16 data = 0;
+	etrax_hc_t *hc = urb->dev->bus->hcpriv;
+//	static prev_wPortStatus_1 = 0;
+//	static prev_wPortStatus_2 = 0;
+	
+/*	DBFENTER; */
+	
+	
+/*
+  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);
+  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
+*/
+	
+	data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
+	data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
+
+	*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
+	urb->actual_length = 1;
+	urb->status = 0;
+
+	
+	if (data && hc->rh.send && urb->complete) {
+		dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); 
+		dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
+
+		urb->complete(urb);
+	}
+  
+/*	DBFEXIT; */
+}
+
+static void etrax_rh_init_int_timer(urb_t *urb)
+{
+	etrax_hc_t *hc;
+	
+/*	DBFENTER; */
+	
+	hc = urb->dev->bus->hcpriv;
+	hc->rh.interval = urb->interval;
+	init_timer(&hc->rh.rh_int_timer);
+	hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
+	hc->rh.rh_int_timer.data = (unsigned long)urb;
+	hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
+	add_timer(&hc->rh.rh_int_timer);
+	
+/*	DBFEXIT; */
+}
+
+static void etrax_rh_int_timer_do(unsigned long ptr)
+{
+	urb_t *urb;
+	etrax_hc_t *hc;
+	
+/*	DBFENTER; */
+	
+	urb = (urb_t*)ptr;
+	hc = urb->dev->bus->hcpriv;
+	
+	if (hc->rh.send) {
+		etrax_rh_send_irq(urb);
+	}
+	
+	etrax_rh_init_int_timer(urb);
+	
+/*	DBFEXIT; */
+}
+
+static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, char packsize, char slow)
+{
+	unsigned long flags;
+	
+	DBFENTER;
+
+	save_flags(flags);
+	cli();
+	
+	if (test_bit(epid, (void *)&ep_usage_bitmask)) {
+		warn("Trying to setup used epid %d", epid);
+		DBFEXIT;
+		return;
+	}
+	
+	set_bit(epid, (void *)&ep_usage_bitmask);
+	dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d",
+	       epid, devnum, endpoint, packsize);
+	
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
+		IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
+		IO_FIELD(R_USB_EPT_DATA, dev, devnum) |
+		IO_FIELD(R_USB_EPT_DATA, max_len, packsize) |
+		IO_FIELD(R_USB_EPT_DATA, low_speed, slow);
+
+	restore_flags(flags);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_free_epid(char epid)
+{
+	unsigned long flags;
+	
+	DBFENTER;
+
+	if (!test_bit(epid, (void *)&ep_usage_bitmask)) {
+		warn("Trying to free unused epid %d", epid);
+		DBFEXIT;
+		return;
+	}
+
+	save_flags(flags);
+	cli();
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold))printk("+");
+	*R_USB_EPT_DATA = 0;
+	clear_bit(epid, (void *)&ep_usage_bitmask);
+	restore_flags(flags);
+	dbg_ep("epid: %d freed", epid);
+	
+	DBFEXIT;
+}
+
+
+static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp)
+{
+	int i;
+	unsigned long flags;
+	__u32 data;
+	
+	DBFENTER;
+
+	save_flags(flags);
+	
+	/* Skip first ep_id since it is reserved when intr. or iso traffic is used */
+	for (i = 0; i < NBR_OF_EP_DESC; i++) {
+		if (test_bit(i, (void *)&ep_usage_bitmask)) {
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
+			nop();
+			data = *R_USB_EPT_DATA;
+			if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
+			    (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
+			    (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
+			    (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
+			    (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxp)) {
+				dbg_ep("Found ep_id %d for devnum %d, endpoint %d",
+				       i, devnum, endpoint);
+				DBFEXIT;
+				return i;
+			}
+		}
+	}
+
+	restore_flags(flags);
+	
+	dbg_ep("Found no ep_id for devnum %d, endpoint %d",
+	       devnum, endpoint);
+	DBFEXIT;
+	return -1;
+}
+
+static int etrax_usb_allocate_epid(void)
+{
+	int i;
+	
+	DBFENTER;
+
+	for (i = 0; i < NBR_OF_EP_DESC; i++) {
+		if (!test_bit(i, (void *)&ep_usage_bitmask)) {
+			dbg_ep("Found free ep_id at %d", i);
+			DBFEXIT;
+			return i;
+		}
+	}
+
+	dbg_ep("Found no free ep_id's");
+	DBFEXIT;
+	return -1;
+}
+
+static int etrax_usb_submit_bulk_urb(urb_t *urb)
+{
+	char epid;
+	char devnum;
+	char endpoint;
+	char maxlen;
+	char slow;
+
+	urb_t *tmp_urb;
+	
+	etrax_urb_priv_t *urb_priv;
+	unsigned long flags;
+	
+	DBFENTER;
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe,
+			       usb_pipeout(urb->pipe));
+	slow = usb_pipeslow(urb->pipe);
+	
+	epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen);
+	if (epid == -1) {
+		epid = etrax_usb_allocate_epid();
+		if (epid == -1) {
+			/* We're out of endpoints, return some error */
+			err("We're out of endpoints");
+			return -ENOMEM;
+		}
+		/* Now we have to fill in this ep */
+		etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow);
+	}
+	/* Ok, now we got valid endpoint, lets insert some traffic */
+
+	urb->status = -EINPROGRESS;
+
+	save_flags(flags);
+	cli();
+	
+	if (URB_List[epid]) {
+		/* Find end of list and add */
+		for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next)
+			dump_urb(tmp_urb);
+
+		tmp_urb->next = urb;
+		restore_flags(flags);
+	} else {
+		/* If this is the first URB, add the URB and do HW add */
+		URB_List[epid] = urb;
+		restore_flags(flags);
+		etrax_usb_do_bulk_hw_add(urb, epid, maxlen);
+	}
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen)
+{
+	USB_SB_Desc_t *sb_desc_1;
+
+	etrax_urb_priv_t *urb_priv;
+
+	unsigned long flags;
+	__u32 r_usb_ept_data;
+
+	DBFENTER;
+
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL);
+	sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+
+	if (usb_pipeout(urb->pipe)) {
+
+		dbg_bulk("Bulk transfer for epid %d is OUT", epid);
+		dbg_bulk("transfer_buffer_length == %d", urb->transfer_buffer_length);
+		dbg_bulk("actual_length == %d", urb->actual_length);
+	
+		if (urb->transfer_buffer_length > 0xffff) {
+			panic(__FILE__ __FUNCTION__ ":urb->transfer_buffer_length > 0xffff\n");
+		}
+
+		sb_desc_1->sw_len = urb->transfer_buffer_length;  /* was actual_length */
+		sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) |
+			IO_STATE(USB_SB_command, tt, out) |
+
+#if 0
+			IO_STATE(USB_SB_command, full, no) |
+#else
+			IO_STATE(USB_SB_command, full, yes) |
+#endif
+
+			IO_STATE(USB_SB_command, eot, yes) |
+			IO_STATE(USB_SB_command, eol, yes);
+		
+		dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer);
+		
+		sb_desc_1->buf = virt_to_phys(urb->transfer_buffer);
+		sb_desc_1->next = 0;
+		
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_bulk("Transfer for epid %d is IN", epid);
+		dbg_bulk("transfer_buffer_length = %d", urb->transfer_buffer_length);
+		dbg_bulk("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
+		
+		sb_desc_1->sw_len = urb->transfer_buffer_length ?
+			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+		dbg_bulk("sw_len got %d", sb_desc_1->sw_len);
+		dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer);
+		
+		sb_desc_1->command =
+			IO_FIELD(USB_SB_command, rem,
+				 urb->transfer_buffer_length % maxlen) |
+			IO_STATE(USB_SB_command, tt, in) |
+			IO_STATE(USB_SB_command, eot, yes) |
+			IO_STATE(USB_SB_command, eol, yes);
+		
+		sb_desc_1->buf = 0;
+		sb_desc_1->next = 0;
+
+		urb_priv->rx_offset = 0;
+		urb_priv->eot = 0;
+	}
+	
+	urb_priv->first_sb = sb_desc_1;
+	
+	urb->hcpriv = (void *)urb_priv;
+	
+	/* Reset toggle bits and reset error count, remeber to di and ei */
+	/* Warning: it is possible that this locking doesn't work with bottom-halves */
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop();
+	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+		panic("Hold was set in %s\n", __FUNCTION__);
+	}
+
+	*R_USB_EPT_DATA &=
+		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+		  IO_MASK(R_USB_EPT_DATA, error_count_out));
+	
+	if (usb_pipeout(urb->pipe)) {
+		char toggle =
+		usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
+		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
+	} else {
+		char toggle =
+		usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
+		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
+	}
+		
+	/* Enable the EP descr. */
+
+	set_bit(epid, (void *)&ep_really_active);
+	
+	TxBulkEPList[epid].sub = virt_to_phys(sb_desc_1);
+	TxBulkEPList[epid].hw_len = 0;
+	TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+	restore_flags(flags);
+
+	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+		*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+		
+	}
+
+	DBFEXIT;
+}
+
+static int handle_bulk_transfer_attn(char epid, int status)
+{
+	urb_t *old_urb;
+	etrax_urb_priv_t *hc_priv;
+	unsigned long flags;
+
+	DBFENTER;
+
+	clear_bit(epid, (void *)&ep_really_active);
+	
+	old_urb = URB_List[epid];
+	URB_List[epid] = old_urb->next;
+
+	/* if (status == 0 && IN) find data and copy to urb */
+	if (status == 0 && usb_pipein(old_urb->pipe)) {
+		etrax_urb_priv_t *urb_priv;
+		
+		urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv;
+		save_flags(flags);
+		cli();
+		if (urb_priv->eot == 1) {
+			old_urb->actual_length = urb_priv->rx_offset;
+		} else {
+			if (urb_priv->rx_offset == 0) {
+				status = 0;
+			} else {
+				status = -EPROTO;
+			}
+			
+			old_urb->actual_length = 0;
+			err("(BULK) No eot set in IN data!!! rx_offset is: %d", urb_priv->rx_offset);
+		}
+		
+		restore_flags(flags);
+	}
+
+	save_flags(flags);
+	cli();
+		
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop();
+	if (usb_pipeout(old_urb->pipe)) {
+		char toggle =
+		IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
+		usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe),
+			      usb_pipeout(old_urb->pipe), toggle);
+	} else {
+		char toggle =
+		IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
+		usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe),
+			      usb_pipeout(old_urb->pipe), toggle);
+	}
+	restore_flags(flags);
+	
+	/* If there are any more URB's in the list we'd better start sending */
+	if (URB_List[epid]) {
+		etrax_usb_do_bulk_hw_add(URB_List[epid], epid,
+					 usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe,
+						       usb_pipeout(URB_List[epid]->pipe)));
+	}
+#if 1
+	else {
+		/* This means that this EP is now free, deconfigure it */
+		etrax_usb_free_epid(epid);
+	}
+#endif
+	
+	/* Remember to free the SB's */
+	hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv;
+	cleanup_sb(hc_priv->first_sb);
+	kfree(hc_priv);
+
+	old_urb->status = status;
+	if (old_urb->complete) {
+		old_urb->complete(old_urb);
+	}
+
+	DBFEXIT;
+}
+
+/* ---------------------------------------------------------------------------- */
+
+static int etrax_usb_submit_ctrl_urb(urb_t *urb)
+{
+	char epid;
+	char devnum;
+	char endpoint;
+	char maxlen;
+	char slow;
+
+	urb_t *tmp_urb;
+	
+	etrax_urb_priv_t *urb_priv;
+	unsigned long flags;
+	
+	DBFENTER;
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe,
+			       usb_pipeout(urb->pipe));
+	slow = usb_pipeslow(urb->pipe);
+	
+	epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen);
+	if (epid == -1) {
+		epid = etrax_usb_allocate_epid();
+		if (epid == -1) {
+			/* We're out of endpoints, return some error */
+			err("We're out of endpoints");
+			return -ENOMEM;
+		}
+		/* Now we have to fill in this ep */
+		etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow);
+	}
+	/* Ok, now we got valid endpoint, lets insert some traffic */
+
+	urb->status = -EINPROGRESS;
+
+	save_flags(flags);
+	cli();
+	
+	if (URB_List[epid]) {
+		/* Find end of list and add */
+		for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next)
+			dump_urb(tmp_urb);
+
+		tmp_urb->next = urb;
+		restore_flags(flags);
+	} else {
+		/* If this is the first URB, add the URB and do HW add */
+		URB_List[epid] = urb;
+		restore_flags(flags);
+		etrax_usb_do_ctrl_hw_add(urb, epid, maxlen);
+	}
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen)
+{
+	USB_SB_Desc_t *sb_desc_1;
+	USB_SB_Desc_t *sb_desc_2;
+	USB_SB_Desc_t *sb_desc_3;
+
+	etrax_urb_priv_t *urb_priv;
+
+	unsigned long flags;
+	__u32 r_usb_ept_data;
+	
+
+	DBFENTER;
+
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL);
+	sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+	sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+
+	if (!(sb_desc_1 && sb_desc_2)) {
+		panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n");
+	}
+	
+	sb_desc_1->sw_len = 8;
+	sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) |
+		IO_STATE(USB_SB_command, tt, setup) |
+		IO_STATE(USB_SB_command, full, yes) |
+		IO_STATE(USB_SB_command, eot, yes);
+	
+	sb_desc_1->buf = virt_to_phys(urb->setup_packet);
+	sb_desc_1->next = virt_to_phys(sb_desc_2);
+	dump_sb_desc(sb_desc_1);
+
+	if (usb_pipeout(urb->pipe)) {
+		dbg_ctrl("Transfer for epid %d is OUT", epid);
+
+		/* If this Control OUT transfer has an optional data stage we add an OUT token
+		   before the mandatory IN (status) token, hence the reordered SB list */
+		
+		if (urb->transfer_buffer) {
+			dbg_ctrl("This OUT transfer has an extra data stage");
+			sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+
+			sb_desc_1->next = virt_to_phys(sb_desc_3);
+			
+			sb_desc_3->sw_len = urb->transfer_buffer_length;
+			sb_desc_3->command = IO_STATE(USB_SB_command, tt, out) |
+				IO_STATE(USB_SB_command, full, yes) |
+				IO_STATE(USB_SB_command, eot, yes);
+			sb_desc_3->buf = virt_to_phys(urb->transfer_buffer);
+			sb_desc_3->next = virt_to_phys(sb_desc_2);
+		}
+		
+		sb_desc_2->sw_len = 1;
+		sb_desc_2->command = IO_FIELD(USB_SB_command, rem, 0) |
+			IO_STATE(USB_SB_command, tt, in) |
+			IO_STATE(USB_SB_command, eot, yes) |
+			IO_STATE(USB_SB_command, eol, yes);
+
+		sb_desc_2->buf = 0;
+		sb_desc_2->next = 0;
+		dump_sb_desc(sb_desc_2);
+		
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_ctrl("Transfer for epid %d is IN", epid);
+		dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
+		dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
+
+		sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+		
+		sb_desc_2->sw_len = urb->transfer_buffer_length ?
+			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+		dbg_ctrl("sw_len got %d", sb_desc_2->sw_len);
+		
+		sb_desc_2->command =
+			IO_FIELD(USB_SB_command, rem,
+				 urb->transfer_buffer_length % maxlen) |
+			IO_STATE(USB_SB_command, tt, in) |
+			IO_STATE(USB_SB_command, eot, yes);
+		
+		sb_desc_2->buf = 0;
+		sb_desc_2->next = virt_to_phys(sb_desc_3);
+		dump_sb_desc(sb_desc_2);
+
+		sb_desc_3->sw_len = 1;
+		sb_desc_3->command = IO_FIELD(USB_SB_command, rem, 0) |
+			IO_STATE(USB_SB_command, tt, zout) |
+			IO_STATE(USB_SB_command, full, yes) |
+			IO_STATE(USB_SB_command, eot, yes) |
+			IO_STATE(USB_SB_command, eol, yes);
+				
+		sb_desc_3->buf = 0;
+		sb_desc_3->next = 0;
+		dump_sb_desc(sb_desc_3);
+
+		urb_priv->rx_offset = 0;
+		urb_priv->eot = 0;
+	}
+	
+	urb_priv->first_sb = sb_desc_1;
+	
+	urb->hcpriv = (void *)urb_priv;
+	
+	/* Reset toggle bits and reset error count, remeber to di and ei */
+	/* Warning: it is possible that this locking doesn't work with bottom-halves */
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop();
+	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+		panic("Hold was set in %s\n", __FUNCTION__);
+	}
+	
+
+	*R_USB_EPT_DATA &=
+		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+		  IO_MASK(R_USB_EPT_DATA, error_count_out) |
+		  IO_MASK(R_USB_EPT_DATA, t_in) |
+		  IO_MASK(R_USB_EPT_DATA, t_out));
+
+	/* Enable the EP descr. */
+
+	set_bit(epid, (void *)&ep_really_active);
+	
+	TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_1);
+	TxCtrlEPList[epid].hw_len = 0;
+	TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+	restore_flags(flags);
+
+	dump_ep_desc(&TxCtrlEPList[epid]);
+
+	if (!(*R_DMA_CH8_SUB1_CMD & IO_MASK(R_DMA_CH8_SUB1_CMD, cmd))) {
+		*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+		
+	}
+	
+	DBFEXIT;
+}
+
+static int etrax_usb_submit_urb(urb_t *urb)
+{
+	etrax_hc_t *hc;
+	int rval = -EINVAL;
+	
+	DBFENTER;
+
+	dump_urb(urb);
+	submit_urb_count++;
+	
+	hc = (etrax_hc_t*) urb->dev->bus->hcpriv;
+	
+	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+		/* This request if for the Virtual Root Hub */
+		rval = etrax_rh_submit_urb(urb);
+		
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		rval = etrax_usb_submit_ctrl_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+		rval = etrax_usb_submit_bulk_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+		int bustime;
+
+		if (urb->bandwidth == 0) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				rval = bustime;
+			} else {
+				usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+				rval = etrax_usb_submit_intr_urb(urb);
+			}
+			
+		}
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		warn("Isochronous traffic is not supported !!!");
+		rval = -EINVAL;
+	}
+
+	DBFEXIT;
+
+	return rval;
+}
+
+static int etrax_usb_unlink_urb(urb_t *urb)
+{
+	etrax_hc_t *hc = urb->dev->bus->hcpriv;
+	int epid;
+	int pos;
+	int devnum, endpoint, slow, maxlen;
+	etrax_urb_priv_t *hc_priv;
+	unsigned long flags;
+	
+	DBFENTER;
+	dump_urb(urb);
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	slow = usb_pipeslow(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe,
+			       usb_pipeout(urb->pipe));
+
+	epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen);
+
+	if (epid == -1)
+		return 0;
+	
+	
+	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+		int ret;
+		ret =  etrax_rh_unlink_urb(urb);
+		DBFEXIT;
+		return ret;
+	} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) {
+		int ret;
+		ret = etrax_usb_unlink_intr_urb(urb);
+		urb->status = -ENOENT;
+		if (urb->complete) {
+			urb->complete(urb);
+		}
+		DBFEXIT;
+		return ret;
+	}
+
+	info("Unlink of BULK or CTRL");
+
+	save_flags(flags);
+	cli();
+	
+	for (epid = 0; epid < 32; epid++) {
+		urb_t *u = URB_List[epid];
+		pos = 0;
+
+		for (; u; u = u->next) {
+			pos++;
+			if (u == urb) {
+				info("Found urb at epid %d, pos %d", epid, pos);
+
+				if (pos == 1) {
+					if (usb_pipetype(u->pipe) == PIPE_CONTROL) {
+						if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+							/* The EP was enabled, disable it and wait */
+							TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+							while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));
+						}
+						
+					} else if (usb_pipetype(u->pipe) == PIPE_BULK) {
+						if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+							TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+							while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));
+						}
+					}
+
+					URB_List[epid] = u->next;
+				
+				} else {
+					urb_t *up;
+					for (up = URB_List[epid]; up->next != u; up = up->next);
+					up->next = u->next;
+				}
+				u->status = -ENOENT;
+				if (u->complete) {
+					u->complete(u);
+				}
+				
+				hc_priv = (etrax_urb_priv_t *)u->hcpriv;
+				cleanup_sb(hc_priv->first_sb);
+				kfree(hc_priv);
+			}
+		}
+	}
+
+	restore_flags(flags);
+		
+	DBFEXIT;
+	return 0;
+}
+
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
+{
+	DBFENTER;
+	DBFEXIT;
+	return (*R_USB_FM_NUMBER);
+}
+
+static int etrax_usb_allocate_dev(struct usb_device *usb_dev)
+{  
+	DBFENTER;
+	DBFEXIT;
+	return 0;
+}
+
+static int etrax_usb_deallocate_dev(struct usb_device *usb_dev)
+{
+	DBFENTER;
+	DBFEXIT;
+	return 0;
+}
+
+static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+	etrax_hc_t *hc = (etrax_hc_t *)vhc;
+	int epid;
+	char eol;
+	urb_t *urb;
+	USB_EP_Desc_t *tmp_ep;
+	USB_SB_Desc_t *tmp_sb;
+	
+	DBFENTER;
+
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
+		info("dma8_sub0_descr (BULK) intr.");
+		*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
+		info("dma8_sub1_descr (CTRL) intr.");
+		*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
+		info("dma8_sub2_descr (INT) intr.");
+		*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
+		info("dma8_sub3_descr (ISO) intr.");
+		*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
+	}
+	
+	DBFEXIT;
+}
+
+static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+	int epid = 0;
+	urb_t *urb;
+	etrax_urb_priv_t *urb_priv;
+		
+	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
+
+	while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
+		if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+
+			goto skip_out;
+		}
+
+		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
+			
+			goto skip_out;
+		}
+		
+		epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
+
+		urb = URB_List[epid];
+
+		if (urb && usb_pipein(urb->pipe)) {
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+
+			if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+				struct in_chunk *in;
+				dbg_intr("Packet for epid %d in rx buffers", epid);
+				in = kmalloc(sizeof(struct in_chunk), GFP_ATOMIC);
+				in->length = myNextRxDesc->hw_len;
+				in->data = kmalloc(in->length, GFP_ATOMIC);
+				memcpy(in->data, phys_to_virt(myNextRxDesc->buf), in->length);
+				list_add_tail(&in->list, &urb_priv->ep_in_list);
+#ifndef ETRAX_USB_INTR_IRQ
+				etrax_usb_hc_intr_top_half(irq, vhc, regs);
+#endif
+				
+			} else {
+				if ((urb_priv->rx_offset + myNextRxDesc->hw_len) >
+				    urb->transfer_buffer_length) {
+					err("Packet (epid: %d) in RX buffer was bigger "
+					    "than the URB has room for !!!", epid);
+					goto skip_out;
+				}
+				
+				memcpy(urb->transfer_buffer + urb_priv->rx_offset,
+				       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
+				
+				urb_priv->rx_offset += myNextRxDesc->hw_len;
+			}
+			
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
+				urb_priv->eot = 1;
+			}
+			
+		} else {
+			err("This is almost fatal, inpacket for epid %d which does not exist "
+			    " or is out !!!\nURB was at 0x%08X", epid, urb);
+			
+			goto skip_out;
+		}
+
+	skip_out:
+		myPrevRxDesc = myNextRxDesc;
+		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
+		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
+		myLastRxDesc = myPrevRxDesc;
+
+		myNextRxDesc->status = 0;
+		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+	}
+}
+
+
+
+static void cleanup_sb(USB_SB_Desc_t *sb)
+{
+	USB_SB_Desc_t *next_sb;
+	
+	DBFENTER;
+
+	if (sb == NULL) {
+		err("cleanup_sb was given a NULL pointer");
+		return;
+	}
+
+	while (!(sb->command & IO_MASK(USB_SB_command, eol))) {
+		next_sb = (USB_SB_Desc_t *)phys_to_virt(sb->next);
+		kmem_cache_free(usb_desc_cache, sb);
+		sb = next_sb;
+	}
+
+	kmem_cache_free(usb_desc_cache, sb);
+
+	DBFEXIT;
+
+}
+
+static int handle_control_transfer_attn(char epid, int status)
+{
+	urb_t *old_urb;
+	etrax_urb_priv_t *hc_priv;	
+
+	DBFENTER;
+
+	clear_bit(epid, (void *)&ep_really_active);
+	
+	old_urb = URB_List[epid];
+	URB_List[epid] = old_urb->next;
+	
+	/* if (status == 0 && IN) find data and copy to urb */
+	if (status == 0 && usb_pipein(old_urb->pipe)) {
+		unsigned long flags;
+		etrax_urb_priv_t *urb_priv;
+
+		urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv;
+		save_flags(flags);
+		cli();
+		if (urb_priv->eot == 1) {
+			old_urb->actual_length = urb_priv->rx_offset;
+			dbg_ctrl("urb_priv->rx_offset: %d in handle_control_attn", urb_priv->rx_offset);
+		} else {
+			status = -EPROTO;
+			old_urb->actual_length = 0;
+			err("(CTRL) No eot set in IN data!!! rx_offset: %d", urb_priv->rx_offset);
+		}
+
+		restore_flags(flags);
+	}
+	
+	/* If there are any more URB's in the list we'd better start sending */
+	if (URB_List[epid]) {
+		etrax_usb_do_ctrl_hw_add(URB_List[epid], epid,
+					 usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe,
+						       usb_pipeout(URB_List[epid]->pipe)));
+	}
+#if 1
+	else {
+		/* This means that this EP is now free, deconfigure it */
+		etrax_usb_free_epid(epid);
+	}
+#endif
+	
+	/* Remember to free the SB's */
+	hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv;
+	cleanup_sb(hc_priv->first_sb);
+	kfree(hc_priv);
+
+	old_urb->status = status;
+	if (old_urb->complete) {
+		old_urb->complete(old_urb);
+	}
+
+	DBFEXIT;
+}
+
+
+
+static void etrax_usb_hc_intr_bottom_half(void *data)
+{
+	struct usb_reg_context *reg = (struct usb_reg_context *)data;
+	urb_t *old_urb;
+	
+	int error_code;
+	int epid;
+
+	__u32 r_usb_ept_data;
+
+	etrax_hc_t *hc = reg->hc; 
+	__u16 r_usb_rh_port_status_1;
+	__u16 r_usb_rh_port_status_2;
+	
+	DBFENTER;
+
+	if (reg->r_usb_irq_mask_read & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
+
+		/*
+		  The Etrax RH does not include a wPortChange register, so this has
+		  to be handled in software. See section 11.16.2.6.2 in USB 1.1 spec
+		  for details.
+		*/
+		
+		r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1;
+		r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2;
+		
+		dbg_rh("port_status pending");
+		dbg_rh("r_usb_rh_port_status_1: 0x%04X", r_usb_rh_port_status_1);
+		dbg_rh("r_usb_rh_port_status_2: 0x%04X", r_usb_rh_port_status_2);
+
+		/* C_PORT_CONNECTION is set on any transition */
+		hc->rh.wPortChange_1 |=
+			((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) !=
+			 (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ?
+			(1 << RH_PORT_CONNECTION) : 0;
+		
+		hc->rh.wPortChange_2 |=
+			((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) !=
+			 (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ?
+			(1 << RH_PORT_CONNECTION) : 0;
+
+		/* C_PORT_ENABLE is _only_ set on a one to zero transition */
+		hc->rh.wPortChange_1 |=
+			((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE))
+			 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
+			(1 << RH_PORT_ENABLE) : 0;
+		
+		hc->rh.wPortChange_2 |=
+			((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE))
+			 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
+			(1 << RH_PORT_ENABLE) : 0;
+		
+		/* C_PORT_SUSPEND seems difficult, lets ignore it.. (for now) */
+		
+		/* C_PORT_RESET is _only_ set on a transition from the resetting state
+		   to the enabled state */
+		hc->rh.wPortChange_1 |=
+			((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET))
+			 && (r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
+			(1 << RH_PORT_RESET) : 0;
+		
+		hc->rh.wPortChange_2 |=
+			((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET))
+			 && (r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
+			(1 << RH_PORT_RESET) : 0;
+		
+		hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1;
+		hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2;	
+	}
+
+	for (epid = 0; epid < 32; epid++) {
+
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop();
+		r_usb_ept_data = *R_USB_EPT_DATA;
+		restore_flags(flags);
+
+		if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+			warn("Was hold for epid %d", epid);
+			continue;
+		}
+
+		if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
+			continue;
+		}
+		
+		
+		if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
+
+			if (URB_List[epid] == NULL) {
+				err("R_USB_EPT_DATA is 0x%08X", r_usb_ept_data);
+				err("submit urb has been called %d times..", submit_urb_count);
+				err("EPID_ATTN for epid %d, with NULL entry in list", epid);
+				return;
+			}
+			
+			dbg_ep("r_usb_ept_data [%d] == 0x%08X", epid,
+			       r_usb_ept_data);
+			
+			error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code,
+						r_usb_ept_data);
+			
+			if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+				/* no_error means that this urb was successfully sent or that we have
+				   some undefinde error*/
+				
+				if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 ||
+				    IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3) {
+				/* Actually there were transmission errors */
+					warn("Undefined error for endpoint %d", epid);
+					if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) {
+						handle_control_transfer_attn(epid, -EPROTO);
+					} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) {
+						handle_bulk_transfer_attn(epid, -EPROTO);
+					} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) {
+						handle_intr_transfer_attn(epid, -EPROTO);
+					}
+							   
+				} else {
+
+					if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+						if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) {
+							etrax_usb_do_intr_recover(epid);
+						} else {
+							panic("Epid attention for epid %d (none INTR), with no errors and no "
+							      "exessive retry r_usb_status is 0x%02X\n",
+							      epid, reg->r_usb_status);
+						}
+						
+					} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+						panic("Epid attention for epid %d, with no errors and no "
+						      "exessive retry r_usb_status is 0x%02X\n",
+						      epid, reg->r_usb_status);
+						
+					}
+					
+					warn("Epid attention for epid %d, with no errors and no "
+					     "exessive retry r_usb_status is 0x%02X",
+					     epid, reg->r_usb_status);
+					warn("OUT error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_out,
+									       r_usb_ept_data));
+					warn("IN  error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_in,
+									       r_usb_ept_data));
+					
+
+				}
+				
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) {
+				warn("Stall for endpoint %d", epid);
+				if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) {
+					handle_control_transfer_attn(epid, -EPIPE);
+				} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) {
+					handle_bulk_transfer_attn(epid, -EPIPE);
+				} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) {
+					handle_intr_transfer_attn(epid, -EPIPE);
+				}
+				
+				
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) {
+				panic("USB bus error for endpoint %d\n", epid);
+				
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+				warn("Buffer error for endpoint %d", epid);
+
+				if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) {
+					handle_control_transfer_attn(epid, -EPROTO);
+				} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) {
+					handle_bulk_transfer_attn(epid, -EPROTO);
+				} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) {
+					handle_intr_transfer_attn(epid, -EPROTO);
+				}
+
+			}
+		} else if (test_bit(epid, (void *)&ep_really_active)) {
+			/* Should really be else if (testbit(really active)) */
+
+			if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) {
+
+				if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+					/* Now we have to verify that this CTRL endpoint got disabled
+					   cause it reached end of list with no error */
+					
+					if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
+					    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+						/*
+						  This means that the endpoint has no error, is disabled
+						  and had inserted traffic,
+						  i.e. transfer successfully completed
+						*/
+						dbg_ctrl("Last SB for CTRL %d sent successfully", epid);
+						handle_control_transfer_attn(epid, 0);
+					}
+				}
+				
+			} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) {
+				if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+					/* Now we have to verify that this BULK endpoint go disabled
+					   cause it reached end of list with no error */
+
+					if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
+					    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+						/*
+						  This means that the endpoint has no error, is disabled
+						  and had inserted traffic,
+						  i.e. transfer successfully completed
+						*/
+						dbg_bulk("Last SB for BULK %d sent successfully", epid);
+						handle_bulk_transfer_attn(epid, 0);
+					}
+				}
+			} else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) {
+				handle_intr_transfer_attn(epid, 0);
+			}
+		}
+		
+	}	
+
+	kfree(reg);
+
+	DBFEXIT;
+}
+
+
+static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs)
+{
+	struct usb_reg_context *reg;
+
+	DBFENTER;
+
+	reg = (struct usb_reg_context *)kmalloc(sizeof(struct usb_reg_context), GFP_ATOMIC);
+
+	if (!(reg)) {
+		panic("kmalloc failed in top_half\n");
+	}
+
+	reg->hc = (etrax_hc_t *)vhc;
+	reg->r_usb_irq_mask_read    = *R_USB_IRQ_MASK_READ;
+	reg->r_usb_status           = *R_USB_STATUS;
+
+#if 0
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+		panic("r_usb_status said perror\n");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+		panic("r_usb_status said ourun !!!\n");
+	}
+#endif
+	
+	reg->r_usb_epid_attn        = *R_USB_EPID_ATTN;
+
+	reg->r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1;
+	reg->r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2;
+
+	reg->usb_bh.sync = 0;
+	reg->usb_bh.routine = etrax_usb_hc_intr_bottom_half;
+	reg->usb_bh.data = reg;
+
+	queue_task(&reg->usb_bh, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	DBFEXIT;
+}
+
+static int etrax_rh_submit_urb(urb_t *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	etrax_hc_t *hc = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	devrequest *cmd = (devrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = 0;
+	int stat = 0;
+	int i;
+
+	__u16 cstatus;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBFENTER;
+
+	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+		dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval);
+		hc->rh.urb = urb;
+		hc->rh.send = 1;
+		hc->rh.interval = urb->interval;
+		etrax_rh_init_int_timer(urb);
+		DBFEXIT;
+		
+		return 0;
+	}
+
+	bmRType_bReq = cmd->requesttype | cmd->request << 8;
+	wValue = le16_to_cpu(cmd->value);
+	wIndex = le16_to_cpu(cmd->index);
+	wLength = le16_to_cpu(cmd->length);
+
+	dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq);
+	dbg_rh("wValue       : 0x%04X (%d)", wValue, wValue);
+	dbg_rh("wIndex       : 0x%04X (%d)", wIndex, wIndex);
+	dbg_rh("wLength      : 0x%04X (%d)", wLength, wLength);
+	
+	switch (bmRType_bReq) {
+		
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data = cpu_to_le16 (1);
+		OK (2);
+		
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+		
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+		
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data = cpu_to_le32 (0);
+		OK (4);		/* hub power ** */
+		
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+                if (wIndex == 1) {
+			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
+			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
+                }
+                else if (wIndex == 2) {
+			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
+			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
+                }
+                else {
+			dbg_rh("RH_GET_STATUS whith invalid wIndex !!");
+			OK(0);
+                }
+		
+                OK(4);
+                
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case (RH_C_HUB_OVER_CURRENT):
+			OK (0);	/* hub power over current ** */
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			if (wIndex == 1) {
+
+				dbg_rh("trying to do disable of port 1");
+
+				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
+				while (hc->rh.prev_wPortStatus_1 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes));
+				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+				dbg_rh("Port 1 is disabled");
+
+			} else if (wIndex == 2) {
+
+				dbg_rh("trying to do disable of port 2");
+				
+				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
+				while (hc->rh.prev_wPortStatus_2 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes));
+				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+				dbg_rh("Port 2 is disabled");
+
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE "
+				       "with invalid wIndex == %d!!", wIndex);
+			}			
+				
+			OK (0);
+		case (RH_PORT_SUSPEND):
+			/* Opposite to suspend should be resume, so well do a resume */
+			if (wIndex == 1) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, resume)|
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else if (wIndex == 2) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, resume)|
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND "
+				       "with invalid wIndex == %d!!", wIndex);
+			}
+			
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_C_PORT_CONNECTION):
+			
+                        if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
+                        }
+                        else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
+                        }
+                        else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
+				       "with invalid wIndex == %d!!", wIndex);
+                        }
+
+			OK (0);
+		case (RH_C_PORT_ENABLE):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE);
+			}
+			else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE);
+			}
+			else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE "
+				       "with invalid wIndex == %d!!", wIndex);
+			}
+			OK (0);
+		case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK (0);
+		case (RH_C_PORT_OVER_CURRENT):
+			OK (0);	/* port power over current ** */
+		case (RH_C_PORT_RESET):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET);
+			}
+			else if (wIndex == 2) {
+				dbg_rh("This is wPortChange before clear: 0x%04X", hc->rh.wPortChange_2);
+				
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET);
+				dbg_rh("This is wPortChange after clear: 0x%04X", hc->rh.wPortChange_2);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET "
+				       "with invalid index == %d!!", wIndex);
+			}
+
+			OK (0);
+		
+		}
+		break;
+		
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			if (wIndex == 1) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else if (wIndex == 2) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_C_PORT_SUSPEND "
+				       "with invalid wIndex == %d!!", wIndex);
+			}			
+
+			OK (0);
+		case (RH_PORT_RESET):
+                        if (wIndex == 1) {
+				int port1_retry;
+				
+			port1_redo:
+				dbg_rh("Doing reset of port 1");
+
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+					IO_STATE(R_USB_COMMAND, port_sel, port1);
+
+				/* We must once again wait at least 10ms for the device to recover */
+
+				port1_retry = 0;
+				while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_1)) &
+					 IO_STATE(R_USB_RH_PORT_STATUS_1,
+						  enabled, yes))) {
+					printk(""); if (port1_retry++ >= 10000) {goto port1_redo;}
+				}
+				
+				/* This only seems to work if we use printk,
+				   not even schedule() works !!! WHY ?? */
+
+				udelay(15000);
+                        }
+                        else if (wIndex == 2) {
+				int port2_retry;
+				
+			port2_redo:
+				dbg_rh("Doing reset of port 2");
+				
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+					IO_STATE(R_USB_COMMAND, port_sel, port2);
+
+				/* We must once again wait at least 10ms for the device to recover */
+
+				port2_retry = 0;
+				while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_2)) &
+					 IO_STATE(R_USB_RH_PORT_STATUS_2,
+						  enabled, yes))) {
+					printk(""); if (port2_retry++ >= 10000) {goto port2_redo;}
+				}
+				
+				/* This only seems to work if we use printk,
+				   not even schedule() works !!! WHY ?? */
+
+				udelay(15000);
+                        }
+
+			/* Try to bring the HC into running state */
+			*R_USB_COMMAND =
+				IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+			
+			nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+			
+                        dbg_rh("...Done");
+                        OK(0);
+                        
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_PORT_ENABLE):
+			/* There is no rh port enable command in the Etrax USB interface!!!! */
+			OK (0);
+                        
+		}
+		break;
+		
+	case RH_SET_ADDRESS:
+		hc->rh.devnum = wValue;
+                dbg_rh("RH address set to: %d", hc->rh.devnum);
+		OK (0);
+		
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min (leni, min (sizeof (root_hub_dev_des), wLength));
+			memcpy (data, root_hub_dev_des, len);
+			OK (len);
+		case (0x02):	/* configuration descriptor */
+			len = min (leni, min (sizeof (root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK (len);
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+						   0xff, "ETRAX 100LX",
+						   data, wLength);
+			if (len > 0) {
+				OK (min (leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+		
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = hc->rh.numports;
+		len = min (leni, min (sizeof (root_hub_hub_des), wLength));
+		memcpy (data, root_hub_hub_des, len);
+		OK (len);
+		
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data = 0x01;
+		OK (1);
+		
+	case RH_SET_CONFIGURATION:
+		OK (0);
+		
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+	urb->status = stat;
+	urb->dev=NULL;
+	if (urb->complete) {
+		urb->complete (urb);
+	}
+	DBFEXIT;
+	
+	return 0;
+}
+
+static int __init etrax_usb_hc_init(void)
+{
+	static etrax_hc_t *hc;
+	struct usb_bus *bus;
+	struct usb_device *usb_rh;
+	
+	DBFENTER;
+
+	info("ETRAX 100LX USB-HCD %s (c) 2001 Axis Communications AB\n", usb_hcd_version);
+	
+	hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL);
+
+	/* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
+	usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, 0, 0, 0);
+	if (!usb_desc_cache) {
+		panic("USB Desc Cache allocation failed !!!\n");
+	}
+	
+	etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
+	hc->bus = bus;
+	bus->hcpriv = hc;
+        
+	/* Initalize RH to the default address.
+	   And make sure that we have no status change indication */
+	hc->rh.numports = 2;  /* The RH has two ports */
+	hc->rh.devnum = 0;
+	hc->rh.wPortChange_1 = 0;
+	hc->rh.wPortChange_2 = 0;
+
+	/* Also initate the previous values to zero */
+	hc->rh.prev_wPortStatus_1 = 0;
+	hc->rh.prev_wPortStatus_2 = 0;
+
+	/* Initialize the intr-traffic flags */
+	hc->intr.sleeping = 0;
+	hc->intr.wq = NULL;
+        
+	/* Initially all ep's are free except ep 0 */
+	ep_usage_bitmask = 0;
+	set_bit(0, (void *)&ep_usage_bitmask);
+	ep_really_active = 0;
+
+	memset(URB_List, 0, sizeof(URB_List));
+
+	/* This code should really be moved */
+
+        if (request_dma(8, "ETRAX 100LX built-in USB (Tx)")) {
+		err("Could not allocate DMA ch 8 for USB");
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+	
+	if (request_dma(9, "ETRAX 100LX built-in USB (Rx)")) {
+		err("Could not allocate DMA ch 9 for USB");
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}	
+#if 0  /* Moved to head.S */        
+	*R_GEN_CONFIG = genconfig_shadow =
+		(genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) |
+				      IO_MASK(R_GEN_CONFIG, usb2) |
+				      IO_MASK(R_GEN_CONFIG, dma8) |
+				      IO_MASK(R_GEN_CONFIG, dma9))) |
+		IO_STATE(R_GEN_CONFIG, dma8, usb) |
+		IO_STATE(R_GEN_CONFIG, dma9, usb)
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+		| IO_STATE(R_GEN_CONFIG, usb1, select)
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+		| IO_STATE(R_GEN_CONFIG, usb2, select)
+#endif
+	;
+#endif
+	
+	usb_register_bus(hc->bus);
+
+	/* We may have to set more bits, but these are the obvious ones */
+	*R_IRQ_MASK2_SET =
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
+
+	*R_IRQ_MASK2_SET =
+		IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
+
+	*R_USB_IRQ_MASK_SET = 
+		IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, ctl_eot, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
+#ifdef ETRAX_USB_INTR_IRQ
+		IO_STATE(R_USB_IRQ_MASK_SET, intr_eot, set) |
+#endif
+		IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, port_status, set);
+	
+	if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_intr_top_half, 0,
+			"ETRAX 100LX built-in USB (HC)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+	
+	if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0,
+			"ETRAX 100LX built-in USB (Rx)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+	
+	if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0,
+			"ETRAX 100LX built-in USB (Tx)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	/* Reset the USB interface (configures as HC) */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset);
+	
+	nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+#if 1
+	/* Initate PSTART to all unallocatable bit times */
+	*R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 10000);
+#endif
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+	*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+#endif
+	
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+	*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+#endif
+	
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset);
+	
+	nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, port1) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset);
+
+	nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Here we must wait at least 10ms so the device has time to recover */
+	udelay(15000);
+
+	init_rx_buffers();
+	init_tx_bulk_ep();
+	init_tx_ctrl_ep();
+	init_tx_intr_ep();
+
+	/* This works. It seems like the host_run command only has effect when a device is connected,
+	 i.e. it has to be done when a interrup */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+	
+	nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	usb_rh = usb_alloc_dev(NULL, hc->bus);
+	hc->bus->root_hub = usb_rh;
+	usb_connect(usb_rh);
+	usb_new_device(usb_rh);
+
+	DBFEXIT;
+	
+	return 0;
+}
+
+static void etrax_usb_hc_cleanup(void)
+{
+	DBFENTER;
+	
+	free_irq(ETRAX_USB_HC_IRQ, NULL);
+	free_irq(ETRAX_USB_RX_IRQ, NULL);
+	free_irq(ETRAX_USB_TX_IRQ, NULL);
+
+	free_dma(8);
+	free_dma(9);
+	usb_deregister_bus(etrax_usb_bus);
+
+	DBFEXIT;
+}
+
+module_init(etrax_usb_hc_init);
+module_exit(etrax_usb_hc_cleanup);
diff -u --recursive --new-file v2.4.3/linux/arch/cris/drivers/usb-host.h linux/arch/cris/drivers/usb-host.h
--- v2.4.3/linux/arch/cris/drivers/usb-host.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/usb-host.h	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,245 @@
+#ifndef __LINUX_ETRAX_USB_H
+#define __LINUX_ETRAX_USB_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+typedef struct USB_IN_Desc {
+	__u16 sw_len;
+	__u16 command;
+	unsigned long next;
+	unsigned long buf;
+	__u16 hw_len;
+	__u16 status;
+} USB_IN_Desc_t;
+
+typedef struct USB_SB_Desc {
+	__u16 sw_len;
+	__u16 command;
+	unsigned long next;
+	unsigned long buf;
+	__u32 dummy;
+} USB_SB_Desc_t;
+
+typedef struct USB_EP_Desc {
+	__u16 hw_len;
+	__u16 command;
+	unsigned long sub;
+	unsigned long nep;
+	__u32 dummy;
+} USB_EP_Desc_t;
+
+struct virt_root_hub {
+	int devnum;
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	struct timer_list rh_int_timer;
+	__u16 wPortChange_1;
+	__u16 wPortChange_2;
+	__u16 prev_wPortStatus_1;
+	__u16 prev_wPortStatus_2;
+};
+
+struct etrax_usb_intr_traffic {
+	int sleeping;
+	int error;
+	struct wait_queue *wq;
+};
+
+typedef struct etrax_usb_hc {
+	struct usb_bus *bus;
+	struct virt_root_hub rh;
+	struct etrax_usb_intr_traffic intr;
+} etrax_hc_t;
+
+typedef enum {idle, eot, nodata}  etrax_usb_rx_state_t;
+
+typedef struct etrax_usb_urb_priv {
+	USB_SB_Desc_t *first_sb;
+	__u32 rx_offset;
+	etrax_usb_rx_state_t rx_state;
+	__u8 eot;
+	struct list_head ep_in_list;
+} etrax_urb_priv_t;
+
+
+struct usb_reg_context
+{
+	etrax_hc_t *hc;
+	__u32 r_usb_epid_attn;
+	__u8 r_usb_status;
+	__u32 r_usb_rh_port_status_1;
+	__u32 r_usb_rh_port_status_2;
+	__u32 r_usb_irq_mask_read;
+	struct tq_struct usb_bh;
+#if 0
+	__u32 r_usb_ept_data[32];
+#endif
+};
+
+struct in_chunk
+{
+	void *data;
+	int length;
+	char epid;
+	struct list_head list;
+};
+
+  
+/* --------------------------------------------------------------------------- 
+   Virtual Root HUB 
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/* Field definitions for */
+
+#define USB_IN_command__eol__BITNR      0 /* command macros */
+#define USB_IN_command__eol__WIDTH      1
+#define USB_IN_command__eol__no         0
+#define USB_IN_command__eol__yes        1
+
+#define USB_IN_command__intr__BITNR     3
+#define USB_IN_command__intr__WIDTH     1
+#define USB_IN_command__intr__no        0
+#define USB_IN_command__intr__yes       1
+
+#define USB_IN_status__eop__BITNR       1 /* status macros. */
+#define USB_IN_status__eop__WIDTH       1
+#define USB_IN_status__eop__no          0
+#define USB_IN_status__eop__yes         1
+
+#define USB_IN_status__eot__BITNR       5
+#define USB_IN_status__eot__WIDTH       1
+#define USB_IN_status__eot__no          0
+#define USB_IN_status__eot__yes         1
+
+#define USB_IN_status__error__BITNR     6
+#define USB_IN_status__error__WIDTH     1
+#define USB_IN_status__error__no        0
+#define USB_IN_status__error__yes       1
+
+#define USB_IN_status__nodata__BITNR    7
+#define USB_IN_status__nodata__WIDTH    1
+#define USB_IN_status__nodata__no       0
+#define USB_IN_status__nodata__yes      1
+
+#define USB_IN_status__epid__BITNR      8
+#define USB_IN_status__epid__WIDTH      5
+
+#define USB_EP_command__eol__BITNR      0
+#define USB_EP_command__eol__WIDTH      1
+#define USB_EP_command__eol__no         0
+#define USB_EP_command__eol__yes        1
+
+#define USB_EP_command__eof__BITNR      1
+#define USB_EP_command__eof__WIDTH      1
+#define USB_EP_command__eof__no         0
+#define USB_EP_command__eof__yes        1
+
+#define USB_EP_command__intr__BITNR     3
+#define USB_EP_command__intr__WIDTH     1
+#define USB_EP_command__intr__no        0
+#define USB_EP_command__intr__yes       1
+
+#define USB_EP_command__enable__BITNR   4
+#define USB_EP_command__enable__WIDTH   1
+#define USB_EP_command__enable__no      0
+#define USB_EP_command__enable__yes     1
+
+#define USB_EP_command__hw_valid__BITNR 5
+#define USB_EP_command__hw_valid__WIDTH 1
+#define USB_EP_command__hw_valid__no    0
+#define USB_EP_command__hw_valid__yes   1
+
+#define USB_EP_command__epid__BITNR     8
+#define USB_EP_command__epid__WIDTH     5
+
+#define USB_SB_command__eol__BITNR      0 /* command macros. */
+#define USB_SB_command__eol__WIDTH      1
+#define USB_SB_command__eol__no         0
+#define USB_SB_command__eol__yes        1
+
+#define USB_SB_command__eot__BITNR      1
+#define USB_SB_command__eot__WIDTH      1
+#define USB_SB_command__eot__no         0
+#define USB_SB_command__eot__yes        1
+
+#define USB_SB_command__intr__BITNR     3
+#define USB_SB_command__intr__WIDTH     1
+#define USB_SB_command__intr__no        0
+#define USB_SB_command__intr__yes       1
+
+#define USB_SB_command__tt__BITNR       4
+#define USB_SB_command__tt__WIDTH       2
+#define USB_SB_command__tt__zout        0
+#define USB_SB_command__tt__in          1
+#define USB_SB_command__tt__out         2
+#define USB_SB_command__tt__setup       3
+
+
+#define USB_SB_command__rem__BITNR      8
+#define USB_SB_command__rem__WIDTH      6
+
+#define USB_SB_command__full__BITNR     6
+#define USB_SB_command__full__WIDTH     1
+#define USB_SB_command__full__no        0
+#define USB_SB_command__full__yes       1
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
--- v2.4.3/linux/arch/cris/kernel/entry.S	Fri Mar  2 18:38:40 2001
+++ linux/arch/cris/kernel/entry.S	Fri Apr  6 10:42:55 2001
@@ -1,12 +1,30 @@
-/* $Id: entry.S,v 1.11 2001/01/10 21:13:29 bjornw Exp $
+/* $Id: entry.S,v 1.15 2001/03/05 13:14:30 bjornw Exp $
  *
  *  linux/arch/cris/entry.S
  *
- *  Copyright (C) 2000 Axis Communications AB
+ *  Copyright (C) 2000, 2001 Axis Communications AB
  *
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.15  2001/03/05 13:14:30  bjornw
+ *  Spelling fix
+ *
+ *  Revision 1.14  2001/02/23 08:36:36  perf
+ *  New ABI; syscallnr=r9, arg5=mof, arg6=srp.
+ *  Corrected tracesys call check.
+ *
+ *  Revision 1.13  2001/02/15 08:40:55  perf
+ *  H-P by way of perf;
+ *  - (_system_call): Don't read system call function address into r1.
+ *  - (RBFExit): There is no such thing as a null pop.  Adjust sp by addq.
+ *  - (_system_call): Don't use r10 and don't save and restore it.
+ *  - (THREAD_ESP0): New constant.
+ *  - (_system_call): Inline set_esp0.
+ *
+ *  Revision 1.12  2001/01/31 17:56:25  orjanf
+ *  Added definition of LTASK_PID and made it global.
+ *
  *  Revision 1.11  2001/01/10 21:13:29  bjornw
  *  SYMBOL_NAME is defined incorrectly for the compiler options we currently use
  *
@@ -79,7 +97,8 @@
 	.globl _mmu_bus_fault
 				
 	.globl _sys_call_table
-		
+	
+	.globl LTASK_PID	
 	;; syscall error codes
 	
 LENOSYS = 38
@@ -90,7 +109,17 @@
 LTASK_SIGPENDING  =  8
 LTASK_NEEDRESCHED = 20
 LTASK_PTRACE      = 24
+LTASK_PID         = 105
+
+	;; process bits for ptrace
 
+PT_TRACESYS_BIT	  = 1
+
+	;; Offset for esp0 into task_struct: current->thread.esp0.
+	;; FIXME: In need of padding somewhere, to get dword-alignment.
+
+THREAD_ESP0	  = 597
+	
 	;; some pt_regs offsets (from ptrace.h)
 	
 LORIG_R10	= 4
@@ -98,8 +127,8 @@
 LR12		= 12
 LR11		= 16
 LR10		= 20
-LR1		= 56
-LR0		= 60	
+LR9		= 24
+LMOF		= 64
 LDCCR		= 68
 LSRP		= 72
 LIRP		= 76
@@ -124,7 +153,7 @@
 	nop
 	ba	ret_with_reschedule  ; go back but check schedule and signals first 
 	nop
-		
+
 reschedule:
 	;; keep r9 intact
 	push	r9
@@ -170,41 +199,38 @@
 	push	r10		; push orig_r10
 	clear.d [sp=sp-4]	; frametype == 0, normal stackframe
 	
-	move.d	r10,r2		; save for later
-	
-	movs.w	-LENOSYS,r10
-	move.d	r10,[sp+LR10]	; put the default return value in r10 in the frame
-	
-	move.d	sp,r10
-	jsr	_set_esp0	; save top of frame (clobbers r9...)
+	movs.w	-LENOSYS,r0
+	move.d	r0,[sp+LR10]	; put the default return value in r10 in the frame
+
+	;; Perform "current->thread.esp0 = sp".
+	;; This used to be a separate function; set_esp0(ssp).
+	movs.w -8192,r0		; THREAD_SIZE == 8192
+	and.d sp,r0
+
+	move.d sp,[r0+THREAD_ESP0]
 
 	;; check if this process is syscall-traced
 
-	move.d	sp, r10
-	and.d	-8192, r10		; THREAD_SIZE == 8192
-	move.d	[r10+LTASK_PTRACE],r10
-	btstq	2, r10	                ; PT_TRACESYS
+	move.d	[r0+LTASK_PTRACE],r0
+	btstq	PT_TRACESYS_BIT, r0
 	bmi	tracesys
 	nop	
 
 	;; check for sanity in the requested syscall number
 	
-	cmpu.w	NR_syscalls,r1	
+	cmpu.w	NR_syscalls,r9	
 	bcc	_ret_from_sys_call
-	lslq	2,r1		;  multiply by 4, in the delay slot
-
-	;; read the system call vector into r1
-	
-	move.d	[r1+_sys_call_table],r1	
+	lslq	2,r9		;  multiply by 4, in the delay slot
 
-	;; the parameter carrying registers r11, r12 and 13 are intact - restore r10.
-	;; the fifth parameter (if any) was in r0, and we need to put it on the stack
+	;; the parameter carrying registers r10, r11, r12 and 13 are intact.
+	;; the fifth and sixth parameters (if any) was in mof and srp 
+	;; respectively, and we need to put them on the stack.
 
-	push	r0
-	move.d	r2,r10
+	push	srp
+	push	mof
 	
-	jsr	r1		; actually call the corresponding system call
-	addq	4,sp		; pop the r0 parameter
+	jsr	[r9+_sys_call_table]	; actually do the system call
+	addq	2*4,sp		; pop the mof and srp parameters
 	move.d	r10,[sp+LR10]	; save the return value
 
 	moveq	1,r9		; "parameter" to ret_from_sys_call to show it was a sys call
@@ -269,10 +295,8 @@
 	;; just get the PC value to restart it with, and skip the rest of
 	;; the frame.
 	pop	irp		; fixup location will be here
-	pop	p8		; null pop
-	pop	p8		; null pop
 	reti			; return to IRP, taking U-flag into account
-	pop	p8		; null pop in delayslot
+	addq	12,sp		; Skip rest of SBFS frame.
 
 
 tracesys:
@@ -289,30 +313,32 @@
 
 	;; check for sanity in the requested syscall number
 
-	move.d	[sp+LR1], r1
+	move.d	[sp+LR9], r9
 	movs.w	-LENOSYS, r10
-	cmpu.w	NR_syscalls,r1	
+	cmpu.w	NR_syscalls,r9	
 	bcc	1f
-	lslq	2,r1		;  multiply by 4, in the delay slot
+	lslq	2,r9		;  multiply by 4, in the delay slot
 
-	;; read the system call vector entry into r1
+	;; read the system call vector entry into r9
 	
-	move.d	[r1+_sys_call_table],r1
+	move.d	[r9+_sys_call_table],r9
 
-	;; restore r10, r11, r12, r13 and r0 into the needed registers
+	;; restore r10, r11, r12, r13, mof and srp into the needed registers
 
 	move.d	[sp+LORIG_R10], r10  ; LR10 is already filled with -LENOSYS
 	move.d	[sp+LR11],      r11
 	move.d	[sp+LR12],      r12
 	move.d	[sp+LR13],      r13
-	move.d	[sp+LR0],       r0
+	move	[sp+LMOF],      mof
+	move	[sp+LSRP],      srp
 
-	;; the fifth parameter needs to be put on the stack for the system
-	;; call to find it
+	;; the fifth and sixth parameters needs to be put on the stack for
+	;; the system call to find them
 
-	push	r0
-	jsr	r1		; actually call the system-call
-	addq	4,sp		; pop the r0 parameter
+	push	srp
+	push	mof
+	jsr	r9		; actually call the system-call
+	addq	2*4,sp		; pop the r0 parameter
 
 1:	move.d	r10,[sp+LR10]	; save the return value
 
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S
--- v2.4.3/linux/arch/cris/kernel/head.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/head.S	Fri Apr  6 10:42:55 2001
@@ -1,46 +1,75 @@
-	;; $Id: head.S,v 1.11 2001/01/16 16:31:38 bjornw Exp $
-	;; 
-	;; Head of the kernel - alter with care
-	;;
-	;; Copyright (C) 2000, 2001 Axis Communications AB
-	;;
-	;; Authors:	Bjorn Wesen (bjornw@axis.com)
-	;; 
-	;; $Log: head.S,v $
-	;; Revision 1.11  2001/01/16 16:31:38  bjornw
-	;; * Changed name and semantics of running_from_flash to romfs_in_flash,
-	;;   set by head.S to indicate to setup.c whether there is a cramfs image
-	;;   after the kernels BSS or not. Should work for all three boot-cases
-	;;   (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
-	;;    and flash with cramfs in flash)
-	;;
-	;; Revision 1.10  2001/01/16 14:12:21  bjornw
-	;; * Check for cramfs start passed in r9 from the decompressor, if all other
-	;;   cramfs options fail (if we boot from DRAM but don't find a cramfs image
-	;;   after the kernel in DRAM, it is probably still in the flash)
-	;; * Check magic in cramfs detection when booting from flash directly
-	;;
-	;; Revision 1.9  2001/01/15 17:17:02  bjornw
-	;; * Corrected the code that detects the cramfs lengths
-	;; * Added a comment saying that the above does not work due to other
-	;;   reasons..
-	;;
-	;; Revision 1.8  2001/01/15 16:27:51  jonashg
-	;; Made boot after flashing work.
-	;; * end destination is __vmlinux_end in RAM.
-	;; * _romfs_start moved because of virtual memory.
-	;;
-	;; Revision 1.7  2000/11/21 13:55:29  bjornw
-	;; Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
-	;;
-	;; Revision 1.6  2000/10/06 12:36:55  bjornw
-	;; Forgot swapper_pg_dir when changing memory map..
-	;;
-	;; Revision 1.5  2000/10/04 16:49:30  bjornw
-	;; * Fixed memory mapping in LX
-	;; * Check for cramfs instead of romfs
-	;;
-	;;
+/* $Id: head.S,v 1.20 2001/02/23 12:47:56 bjornw Exp $
+ * 
+ * Head of the kernel - alter with care
+ *
+ * Copyright (C) 2000, 2001 Axis Communications AB
+ *
+ * Authors:	Bjorn Wesen (bjornw@axis.com)
+ * 
+ * $Log: head.S,v $
+ * Revision 1.20  2001/02/23 12:47:56  bjornw
+ * MMU regs during LOW_MAP updated to reflect a newer reality
+ *
+ * Revision 1.19  2001/02/19 11:12:07  bjornw
+ * Changed comment header format
+ *
+ * Revision 1.18  2001/02/15 07:25:38  starvik
+ * Added support for synchronous serial ports
+ *
+ * Revision 1.17  2001/02/08 15:53:13  starvik
+ * Last commit removed some important ifdefs
+ *
+ * Revision 1.16  2001/02/08 15:20:38  starvik
+ * Include dram_init.S as inline
+ *
+ * Revision 1.15  2001/01/29 18:12:01  bjornw
+ * Corrected some comments
+ *
+ * Revision 1.14  2001/01/29 13:11:29  starvik
+ * Include dram_init.S (with DRAM/SDRAM initialization)
+ *
+ * Revision 1.13  2001/01/23 14:54:57  markusl
+ * Updated for USB
+ * i.e. added r_gen_config settings
+ *
+ * Revision 1.12  2001/01/19 16:16:29  perf
+ * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion.
+ * Renamed serial options from ETRAX100 to ETRAX.
+ *
+ * Revision 1.11  2001/01/16 16:31:38  bjornw
+ * * Changed name and semantics of running_from_flash to romfs_in_flash,
+ *   set by head.S to indicate to setup.c whether there is a cramfs image
+ *   after the kernels BSS or not. Should work for all three boot-cases
+ *   (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
+ *    and flash with cramfs in flash)
+ *
+ * Revision 1.10  2001/01/16 14:12:21  bjornw
+ * * Check for cramfs start passed in r9 from the decompressor, if all other
+ *   cramfs options fail (if we boot from DRAM but don't find a cramfs image
+ *   after the kernel in DRAM, it is probably still in the flash)
+ * * Check magic in cramfs detection when booting from flash directly
+ *
+ * Revision 1.9  2001/01/15 17:17:02  bjornw
+ * * Corrected the code that detects the cramfs lengths
+ * * Added a comment saying that the above does not work due to other
+ *   reasons..
+ *
+ * Revision 1.8  2001/01/15 16:27:51  jonashg
+ * Made boot after flashing work.
+ * * end destination is __vmlinux_end in RAM.
+ * * _romfs_start moved because of virtual memory.
+ *
+ * Revision 1.7  2000/11/21 13:55:29  bjornw
+ * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
+ *
+ * Revision 1.6  2000/10/06 12:36:55  bjornw
+ * Forgot swapper_pg_dir when changing memory map..
+ *
+ * Revision 1.5  2000/10/04 16:49:30  bjornw
+ * * Fixed memory mapping in LX
+ * * Check for cramfs instead of romfs
+ *
+ */
 	
 #include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
@@ -82,13 +111,13 @@
 	;; slightly different. We also let the simulator get this mapping for now.
 
 #ifdef CONFIG_CRIS_LOW_MAP
-	move.d	0x0800b000, r0	; kseg mappings
+	move.d	0x0004b098, r0	; kseg mappings, temporary map of 0xc0->0x40
 	move.d	r0, [R_MMU_KBASE_HI]
 
 	move.d	0x04040000, r0	; temporary map of 0x40->0x40 and 0x00->0x00 
 	move.d	r0, [R_MMU_KBASE_LO]
 
-	move.d	0x80074871, r0	; mmu enable, segs e,b,6,5,4,0 segment mapped
+	move.d	0x80075c71, r0	; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped
 	move.d	r0, [R_MMU_CONFIG]
 #else
 	move.d	0x0804b000, r0	; kseg mappings
@@ -131,24 +160,9 @@
 	jump	inram		; enter cached ram
 	
 inflash:
+	;; We need to initialze DRAM registers before we start using the DRAM
+#include "../lib/dram_init.S"	
 
-#ifndef CONFIG_SVINTO_SIM	
-
-	;; We need to setup the bus registers before we start using the DRAM
-
-	move.d   DEF_R_WAITSTATES, r0
-	move.d   r0, [R_WAITSTATES]
-
-	move.d   DEF_R_BUS_CONFIG, r0
-	move.d   r0, [R_BUS_CONFIG]
-  
-	move.d   DEF_R_DRAM_CONFIG, r0
-	move.d   r0, [R_DRAM_CONFIG]
-
-	move.d   DEF_R_DRAM_TIMING, r0
-	move.d   r0, [R_DRAM_TIMING]
-
-#endif
 	;; Copy text+data to DRAM
 	;; This is fragile - the calculation of r4 as the image size depends
 	;; on that the labels below actually are the first and last positions
@@ -357,27 +371,38 @@
 #if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY)
 	or.d	0x140000,r0	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
 #endif
-#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1)
+#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1)	
 	or.d	0xc00000,r0	; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
-#endif
+#endif	
 #ifdef CONFIG_DMA_MEMCPY
 	or.d	0x003c0000,r0	; 6/7 memory-memory DMA
 #endif
-#ifdef CONFIG_ETRAX100_SERIAL_PORT2
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
 	or.d	0x2808,r0	; DMA channels 2 and 3 to serport 2, port 2 enabled
 #endif
-#ifdef CONFIG_ETRAX100_SERIAL_PORT3
+#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
 	or.d	0x28100,r0	; DMA channels 4 and 5 to serport 3, port 3 enabled
-#endif
-#if defined(CONFIG_ETRAX100_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+#endif	
+#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
 	or.w	0x4,r0	; parport 0 enabled using DMA 2/3
 #endif
-#if defined(CONFIG_ETRAX100_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
 	or.w	0x80,r0	; parport 1 enabled using DMA 4/5
 #endif
 #ifdef CONFIG_BLK_DEV_ETRAXIDE
 	or.d	0x3c02,r0	; DMA channels 2 and 3 to ATA, ATA enabled
 #endif
+	
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+	or.d	0x20000000,r0	; Set the USB port 1 enable bit
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+	or.d	0x40000000,r0	; Set the USB port 2 enable bit
+#endif
+#ifdef CONFIG_ETRAX_USB_HOST
+	and.d	0xff3fffff,r0	; Connect DMA channels 8 and 9 to USB
+#endif
+	
 #ifdef CONFIG_JULIETTE
 	or.d	0x3c000,r0	; DMA channels 4 and 5 to EXTDMA0, for Juliette
 #ifndef CONFIG_BLK_DEV_ETRAXIDE
@@ -438,6 +463,9 @@
 	move.b	DEF_R_PORT_PB_DATA,r0
 	move.b	r0,[_port_pb_data_shadow]
 	move.b	r0,[R_PORT_PB_DATA]
+	move.d  0, r0
+	move.d  r0,[_port_pb_i2c_shadow]
+	move.d  r0, [R_PORT_PB_I2C]
 
 	moveq	0,r0
 	move.d	r0,[_port_g_data_shadow]
@@ -478,7 +506,7 @@
 	move.d	r0,[0x90000000]
 #endif
 	
-#ifdef CONFIG_ETRAX100_SERIAL_PORT3	
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	
 	;; setup the serial port 3 at 115200 baud for debug purposes
 	
 	moveq	0,r0
@@ -497,8 +525,7 @@
 #endif /* CONFIG_SVINTO_SIM */
 
 	jump	_start_kernel	; jump into the C-function _start_kernel in init/main.c
-
-	
+		
 	.data
 _etrax_irv:	
 	.dword	0
@@ -508,7 +535,7 @@
 	.dword	0
 _romfs_in_flash:
 	.dword	0
-
+	
 	;; put some special pages at the beginning of the kernel aligned
 	;; to page boundaries - the kernel cannot start until after this
 
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c
--- v2.4.3/linux/arch/cris/kernel/irq.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/irq.c	Fri Apr  6 10:42:55 2001
@@ -1,8 +1,8 @@
-/* $Id: irq.c,v 1.5 2000/08/17 15:35:15 bjornw Exp $
+/* $Id: irq.c,v 1.11 2001/02/27 13:52:52 bjornw Exp $
  *
  *	linux/arch/cris/kernel/irq.c
  *
- *      Copyright (c) 2000 Axis Communications AB
+ *      Copyright (c) 2000,2001 Axis Communications AB
  *
  *      Authors: Bjorn Wesen (bjornw@axis.com)
  *
@@ -30,7 +30,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/random.h>
 
 #include <asm/system.h>
@@ -160,6 +160,8 @@
 BUILD_IRQ(23, 0x800000)
 BUILD_IRQ(24, 0x1000000)
 BUILD_IRQ(25, 0x2000000)
+/* IRQ 26-30 are resereved */	
+BUILD_IRQ(31, 0x80000000)
  
 /*
  * Pointers to the low-level handlers 
@@ -172,7 +174,8 @@
 	IRQ12_interrupt, IRQ13_interrupt, NULL, NULL,	
 	IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,	
 	IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,	
-	IRQ24_interrupt, IRQ25_interrupt
+	IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
+	IRQ31_interrupt
 };
 
 static void (*sinterrupt[NR_IRQS])(void) = {
@@ -182,7 +185,8 @@
 	sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL,	
 	sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt,	
 	sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt,	
-	sIRQ24_interrupt, sIRQ25_interrupt
+	sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
+	sIRQ31_interrupt
 };
 
 static void (*bad_interrupt[NR_IRQS])(void) = {
@@ -198,7 +202,9 @@
 	bad_IRQ18_interrupt, bad_IRQ19_interrupt,
 	bad_IRQ20_interrupt, bad_IRQ21_interrupt,
 	bad_IRQ22_interrupt, bad_IRQ23_interrupt,
-	bad_IRQ24_interrupt, bad_IRQ25_interrupt
+	bad_IRQ24_interrupt, bad_IRQ25_interrupt,
+	NULL, NULL, NULL, NULL, NULL,
+	bad_IRQ31_interrupt
 };
 
 /*
@@ -212,7 +218,8 @@
 	NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL,
-	NULL, NULL
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL
 };
 
 int get_irq_list(char *buf)
@@ -412,6 +419,8 @@
 */
 
 void system_call(void);  /* from entry.S */
+void gdb_handle_breakpoint(void); /* from traps.c */
+void do_sigtrap(void); /* also from traps.c */
 
 void init_IRQ(void)
 {
@@ -431,14 +440,22 @@
 
 	for(i = 0; i < NR_IRQS; i++)
 		irq_shortcuts[i] = NULL;
-	
-	for (i = 0; i < 256; i++)
-		etrax_irv->v[i] = weird_irq;
-      
+        
+        for (i = 0; i < 256; i++)
+               etrax_irv->v[i] = weird_irq;
+
+        /* the entries in the break vector contain actual code to be
+           executed by the associated break handler, rather than just a jump
+           address. therefore we need to setup a default breakpoint handler
+           for all breakpoints */
+
+	for (i = 0; i < 16; i++)
+                set_break_vector(i, do_sigtrap);
+        
 	/* set all etrax irq's to the bad handlers */
 	for (i = 2; i < NR_IRQS; i++)
 		set_int_vector(i, bad_interrupt[i], 0);
-
+        
 	/* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
 
 	set_int_vector(15, multiple_interrupt, 0);
@@ -456,12 +473,15 @@
 
 	set_break_vector(13, system_call);
 
+        /* setup a breakpoint handler for debugging used for both user and
+           kernel mode debugging  (which is why it is not inside an ifdef
+           CONFIG_KGDB) */
+        set_break_vector(8, gdb_handle_breakpoint);
+
 #ifdef CONFIG_KGDB
 	/* setup kgdb if its enabled, and break into the debugger */
-
 	kgdb_init();
-
 	breakpoint();
 #endif
 
-} 
+}
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c
--- v2.4.3/linux/arch/cris/kernel/kgdb.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/kgdb.c	Fri Apr  6 10:42:55 2001
@@ -18,6 +18,12 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.4  2001/02/23 13:45:19  bjornw
+*! config.h check
+*!
+*! Revision 1.3  2001/01/31 18:08:23  orjanf
+*! Removed kgdb_handle_breakpoint from being the break 8 handler.
+*!
 *! Revision 1.2  2001/01/12 14:22:25  orjanf
 *! Updated kernel debugging support to work with ETRAX 100LX.
 *!
@@ -43,7 +49,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.2 2001/01/12 14:22:25 orjanf Exp $
+*! $Id: kgdb.c,v 1.4 2001/02/23 13:45:19 bjornw Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
@@ -1531,7 +1537,7 @@
 {
 	/* could initialize debug port as well but it's done in head.S already... */
 
-	set_break_vector(8, kgdb_handle_breakpoint);
+        /* breakpoint handler is now set in irq.c */
 	set_int_vector(8, kgdb_handle_serial, 0);
 	
 	enableDebugIRQ();
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c
--- v2.4.3/linux/arch/cris/kernel/process.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/process.c	Fri Apr  6 10:42:55 2001
@@ -1,9 +1,9 @@
-/* $Id: process.c,v 1.8 2000/09/13 14:34:13 bjornw Exp $
+/* $Id: process.c,v 1.12 2001/02/27 13:52:52 bjornw Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Copyright (C) 2000  Axis Communications AB
+ *  Copyright (C) 2000, 2001  Axis Communications AB
  *
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
@@ -23,7 +23,7 @@
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
@@ -71,11 +71,6 @@
 
 #define currentregs ((struct pt_regs *)current->thread.esp0)
 
-asmlinkage void set_esp0(unsigned long ssp)
-{
-	current->thread.esp0 = ssp;
-}
-
 void disable_hlt(void)
 {
 	hlt_counter++;
@@ -134,7 +129,7 @@
 	register long __a __asm__ ("r10");
 	
 	__asm__ __volatile__
-		("movu.w %1,r1\n\t"     /* r1 contains syscall number, to sys_clone */
+		("movu.w %1,r9\n\t"     /* r9 contains syscall number, to sys_clone */
 		 "clear.d r10\n\t"      /* r10 is argument 1 to clone */
 		 "move.d %2,r11\n\t"    /* r11 is argument 2 to clone, the flags */
 		 "break 13\n\t"         /* call sys_clone, this will fork */
@@ -143,14 +138,14 @@
 		 "nop\n\t"              /* delay slot */
 		 "move.d %4,r10\n\t"    /* set argument to function to call */
 		 "jsr %5\n\t"           /* call specified function */
-		 "movu.w %3,r1\n\t"     /* r1 is sys_exit syscall number */
+		 "movu.w %3,r9\n\t"     /* r9 is sys_exit syscall number */
 		 "moveq -1,r10\n\t"     /* Give a really bad exit-value */
 		 "break 13\n\t"         /* call sys_exit, killing the child */
 		 "1:\n\t"
 		 : "=r" (__a) 
 		 : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit),
 		   "r" (arg), "r" (fn) 
-		 : "r10", "r11", "r1");
+		 : "r10", "r11", "r9");
 	
 	return __a;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/semaphore.c linux/arch/cris/kernel/semaphore.c
--- v2.4.3/linux/arch/cris/kernel/semaphore.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/semaphore.c	Tue Apr 17 17:19:24 2001
@@ -127,112 +127,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-/*
- * RW Semaphores
- */
-void
-__down_read(struct rw_semaphore *sem, int count)
-{
-	DOWN_VAR;
-
- retry_down:
-	if (count < 0) {
-		/* Wait for the lock to become unbiased.  Readers
-		   are non-exclusive.  */
-		
-		/* This takes care of granting the lock.  */
-		up_read(sem);
-
-		add_wait_queue(&sem->wait, &wait);
-		while (atomic_read(&sem->count) < 0) {
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&sem->count) >= 0)
-				break;
-			schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_dec_return(&sem->count);
-		if (count <= 0)
-			goto retry_down;
-	} else {
-		add_wait_queue(&sem->wait, &wait);
-
-		while (1) {
-			if (test_and_clear_bit(0, &sem->granted))
-				break;
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if ((sem->granted & 1) == 0)
-				schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-	}
-}
-
-void
-__down_write(struct rw_semaphore *sem, int count)
-{
-	DOWN_VAR;
-
- retry_down:
-	if (count + RW_LOCK_BIAS < 0) {
-		up_write(sem);
-
-		add_wait_queue_exclusive(&sem->wait, &wait);
-	
-		while (atomic_read(&sem->count) < 0) {
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
-				break;
-			schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-		if (count != 0)
-			goto retry_down;
-	} else {
-		/* Put ourselves at the end of the list.  */
-		add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
-		while (1) {
-			if (test_and_clear_bit(1, &sem->granted))
-				break;
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if ((sem->granted & 2) == 0)
-				schedule();
-		}
-
-		remove_wait_queue(&sem->write_bias_wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		/* If the lock is currently unbiased, awaken the sleepers.
-		   FIXME: This wakes up the readers early in a bit of a
-		   stampede -> bad!  */
-		if (atomic_read(&sem->count) >= 0)
-			wake_up(&sem->wait);
-	}
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
-	if (readers) {
-		if (test_and_set_bit(0, &sem->granted))
-			BUG();
-		wake_up(&sem->wait);
-	} else {
-		if (test_and_set_bit(1, &sem->granted))
-			BUG();
-		wake_up(&sem->write_bias_wait);
-	}
-}
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c
--- v2.4.3/linux/arch/cris/kernel/setup.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/setup.c	Fri Apr  6 10:42:55 2001
@@ -1,9 +1,9 @@
-/* $Id: setup.c,v 1.8 2001/01/16 16:31:38 bjornw Exp $
+/* $Id: setup.c,v 1.11 2001/03/02 15:52:03 bjornw Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Copyright (c) 2000  Axis Communications AB
+ *  Copyright (c) 2001  Axis Communications AB
  */
 
 /*
@@ -17,7 +17,7 @@
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
@@ -75,7 +75,8 @@
  *
  */
 
-void __init setup_arch(char **cmdline_p)
+void __init 
+setup_arch(char **cmdline_p)
 {
         unsigned long bootmap_size;
 	unsigned long start_pfn, max_pfn;
@@ -179,7 +180,7 @@
 
 	/* give credit for the CRIS port */
 
-	printk("Linux/CRIS port on ETRAX 100LX (c) 2000 Axis Communications AB\n");
+	printk("Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n");
 
 }
 
@@ -192,6 +193,7 @@
 #define HAS_ATA		0x0020
 #define HAS_USB		0x0040
 #define HAS_IRQ_BUG	0x0080
+#define HAS_MMU_BUG     0x0100
 
 static struct cpu_info {
 	char *model;
@@ -214,7 +216,8 @@
 	{ "Simulator",     8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
 	{ "ETRAX 100",     8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG },
 	{ "ETRAX 100",     8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
-	{ "ETRAX 100LX",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU },
+	{ "ETRAX 100LX",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG },
+	{ "ETRAX 100LX v2",  8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU },
 	{ "Unknown",   0, 0 },
 };
 
@@ -241,6 +244,7 @@
 		       "cache size\t: %d kB\n"
 		       "fpu\t\t: %s\n"
 		       "mmu\t\t: %s\n"
+		       "mmu DMA bug\t: %s\n"
 		       "ethernet\t: %s Mbps\n"
 		       "token ring\t: %s\n"
 		       "scsi\t\t: %s\n"
@@ -253,6 +257,7 @@
 		       cpu_info[revision].cache,
 		       cpu_info[revision].flags & HAS_FPU ? "yes" : "no",
 		       cpu_info[revision].flags & HAS_MMU ? "yes" : "no",
+		       cpu_info[revision].flags & HAS_MMU_BUG ? "yes" : "no",
 		       cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10",
 		       cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
 		       cpu_info[revision].flags & HAS_SCSI ? "yes" : "no",
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c
--- v2.4.3/linux/arch/cris/kernel/signal.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/signal.c	Fri Apr  6 10:42:55 2001
@@ -38,9 +38,6 @@
 
 #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
 
-int sys_wait4(pid_t pid, unsigned long *stat_addr,
-			 int options, unsigned long *ru);
-
 int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
 
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
@@ -391,9 +388,9 @@
 	} else {
 		/* trampoline - the desired return ip is the retcode itself */
 		return_ip = (unsigned long)&frame->retcode;
-		/* This is movu.w __NR_sigreturn, r1; break 13; */
+		/* This is movu.w __NR_sigreturn, r9; break 13; */
 		/* TODO: check byteorder */
-		err |= __put_user(0x1c5f,         (short *)(frame->retcode+0));
+		err |= __put_user(0x9c5f,         (short *)(frame->retcode+0));
 		err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
 		err |= __put_user(0xe93d,         (short *)(frame->retcode+4));
 	}
@@ -453,9 +450,9 @@
 	} else {
 		/* trampoline - the desired return ip is the retcode itself */
 		return_ip = (unsigned long)&frame->retcode;
-		/* This is movu.w __NR_sigreturn, r1; break 13; */
+		/* This is movu.w __NR_sigreturn, r9; break 13; */
 		/* TODO: check byteorder */
-		err |= __put_user(0x1c5f,         (short *)(frame->retcode+0));
+		err |= __put_user(0x9c5f,         (short *)(frame->retcode+0));
 		err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
 		err |= __put_user(0xe93d,         (short *)(frame->retcode+4));
 	}
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c
--- v2.4.3/linux/arch/cris/kernel/sys_cris.c	Mon Mar 19 12:35:11 2001
+++ linux/arch/cris/kernel/sys_cris.c	Fri Apr  6 10:42:55 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_cris.c,v 1.3 2000/08/02 13:59:02 bjornw Exp $
+/* $Id: sys_cris.c,v 1.4 2001/01/31 14:55:58 perf Exp $
  *
  * linux/arch/cris/kernel/sys_etrax.c
  *
@@ -97,10 +97,22 @@
         return error;
 }
 
-asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot,
-                                  int flags, int fd, off_t offset)
-{
-        return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+asmlinkage unsigned long old_mmap(unsigned long *args)
+{        
+	unsigned long buffer[6];
+	int err = -EFAULT;
+
+	if (copy_from_user(&buffer, args, sizeof(buffer)))
+		goto out;
+
+	err = -EINVAL;
+	if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */
+		goto out;
+
+	err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3],
+                       buffer[4], buffer[5] >> PAGE_SHIFT);
+out:
+	return err;
 }
 
 asmlinkage long
diff -u --recursive --new-file v2.4.3/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c
--- v2.4.3/linux/arch/cris/kernel/traps.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/traps.c	Fri Apr  6 10:42:55 2001
@@ -1,16 +1,19 @@
-/* $Id: traps.c,v 1.3 2000/10/04 16:50:06 bjornw Exp $
+/* $Id: traps.c,v 1.8 2001/02/23 13:45:20 bjornw Exp $
  *
  *  linux/arch/cris/traps.c
  *
- *  Etrax100 does not have any hardware traps, only IRQ's, which we setup
- *  in irq.c instead. Here we just define the die_if_kernel Oops'er.
- *
- *  Copyright (C) 2000 Axis Communications AB
+ *  Here we handle the break vectors not used by the system call 
+ *  mechanism, as well as some general stack/register dumping 
+ *  things.
+ * 
+ *  Copyright (C) 2000,2001 Axis Communications AB
  *
  *  Authors:   Bjorn Wesen
+ *             Orjan Friberg
  *
  */
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -35,7 +38,8 @@
 
 #define MODULE_RANGE (8*1024*1024)
 
-void show_stack(unsigned long *sp)
+void 
+show_stack(unsigned long *sp)
 {
         unsigned long *stack, addr, module_start, module_end;
         int i;
@@ -86,7 +90,8 @@
 #if 0
 /* displays a short stack trace */
 
-int show_stack()
+int 
+show_stack()
 {
 	unsigned long *sp = (unsigned long *)rdusp();
 	int i;
@@ -97,7 +102,8 @@
 }
 #endif
 
-void show_registers(struct pt_regs * regs)
+void 
+show_registers(struct pt_regs * regs)
 {
 	unsigned long usp = rdusp();
 
@@ -145,9 +151,8 @@
 #endif
 }
 
-
-
-void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+void 
+die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
 	if(user_mode(regs))
 		return;
@@ -160,8 +165,68 @@
 	do_exit(SIGSEGV);
 }
 
-void __init trap_init(void)
+void __init 
+trap_init(void)
 {
-  
 
 }
+
+/* Use static variables instead of the stack for temporary storage.  */
+static int saved_r0 = 0;
+static int saved_dccr = 0;
+
+asm ("
+  .global _gdb_handle_breakpoint
+  .global _do_sigtrap
+_gdb_handle_breakpoint:
+;;
+;; This handles a break instruction for entering a debug session.
+;;
+  move     dccr,[_saved_dccr]       ; Save dccr.
+  move.d   r0,[_saved_r0]           ; Save r0. "
+#ifdef CONFIG_KGDB
+" 
+  move     ccr,r0                   
+  btstq    8,r0                     ; Test the U-flag.
+  bmi      _ugdb_handle_breakpoint  ; Go to user mode debugging.
+  nop                               ; Delay slot.
+  move.d   [_saved_r0],r0           ; Restore r0.
+  move     [_saved_dccr],dccr       ; Restore dccr.
+  ba       _kgdb_handle_breakpoint  ; Go to kernel debugging.
+  nop                               ; Delay slot. "
+#endif
+" 
+_ugdb_handle_breakpoint:
+;;
+;; Yes, we could do a 'push brp' here and let gdb adjust the pc once it
+;; starts talking to the target again, but this way we avoid a 'P' packet.
+;;
+  move     brp,r0               ; Use r0 temporarily for calculation.
+  subq     2,r0                 ; Set to address of previous instruction.
+  move     r0,brp               ; Restore new brp.
+  move.d   [_saved_r0],r0       ; Restore r0.
+  move     [_saved_dccr],dccr   ; Restore dccr.
+
+_do_sigtrap:
+;; 
+;; SIGTRAP the process that executed the break instruction.
+;; Make a frame that Rexit in entry.S expects.
+;;
+  push     brp                  ; Push breakpoint return pointer.
+  push     srp                  ; Push subroutine return pointer.
+  push     dccr                 ; Push condition codes.
+  push     mof                  ; Push multiply overflow reg.
+  di                            ; Need to disable irq's at this point.
+  subq     14*4,sp              ; Make room for r0-r13.
+  movem    r13,[sp]             ; Push the r0-r13 registers.
+  push     r10                  ; Push orig_r10.
+  clear.d  [sp=sp-4]            ; Frametype - this is a normal stackframe.
+
+  movs.w   -8192,r9             ; THREAD_SIZE == 8192
+  and.d    sp,r9
+  move.d   [r9+LTASK_PID],r10   ; current->pid as arg1.
+  moveq    5,r11                ; SIGTRAP as arg2.
+  jsr      _sys_kill       
+
+  jump     _ret_from_intr       ; Use the return routine for interrupts.
+");
diff -u --recursive --new-file v2.4.3/linux/arch/cris/lib/checksum.S linux/arch/cris/lib/checksum.S
--- v2.4.3/linux/arch/cris/lib/checksum.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/checksum.S	Fri Apr  6 10:42:55 2001
@@ -1,16 +1,21 @@
-	;; $Id: checksum.S,v 1.1 2000/07/10 16:25:21 bjornw Exp $
-	;; A fast checksum routine using movem
-	;; Copyright (c) 1998 Bjorn Wesen/Axis Communications AB
+/* $Id: checksum.S,v 1.4 2001/02/19 11:11:33 bjornw Exp $
+ * A fast checksum routine using movem
+ * Copyright (c) 1998-2001 Axis Communications AB
+ *
+ * csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
 
-	;; csum_partial(const unsigned char * buff, int len, unsigned int sum)
-	
 	.globl	_csum_partial
 _csum_partial:
 	
+	;; r10 - src
+	;; r11 - length
+	;; r12 - checksum
+
 	;; check for breakeven length between movem and normal word looping versions
 	
 	cmpu.w	80,r11
-	bcs	no_movem
+	blo	word_loop
 	nop
 
 	;; need to save the registers we use below in the movem loop
@@ -21,10 +26,6 @@
 	
 	;; do a movem checksum
 
-	;; r10 - src
-	;; r11 - length
-	;; r12 - checksum
-
 	subq	10*4,r11	; update length for the first loop
 	
 mloop:	movem	[r10+],r9	; read 10 longwords
@@ -65,23 +66,30 @@
 
 	addq	10*4,r11	; compensate for last loop underflowing length
 
-	;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
-	
-	moveq	-1,r1		; put 0xffff in r1, faster than move.d 0xffff,r1
-	lsrq	16,r1
-	
-	move.d	r12,r0
-	lsrq	16,r0		; r0 = checksum >> 16
-	and.d	r1,r12		; checksum = checksum & 0xffff
-	add.d	r0,r12		; checksum += r0
-	move.d	r12,r0		; do the same again, maybe we got a carry last add
-	lsrq	16,r0
-	and.d	r1,r12
-	add.d	r0,r12
-	
 	movem	[sp+],r8	; restore regs
 
-no_movem:
+word_loop:
+	;; only fold if there is anything to fold.
+
+	cmpq	0,r12
+	beq	no_fold
+
+	;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below.
+	;; r9 and r13 can be used as temporaries.
+	
+	moveq	-1,r9		; put 0xffff in r9, faster than move.d 0xffff,r9
+	lsrq	16,r9
+	
+	move.d	r12,r13
+	lsrq	16,r13		; r13 = checksum >> 16
+	and.d	r9,r12		; checksum = checksum & 0xffff
+	add.d	r13,r12		; checksum += r13
+	move.d	r12,r13		; do the same again, maybe we got a carry last add
+	lsrq	16,r13
+	and.d	r9,r12
+	add.d	r13,r12
+
+no_fold:
 	cmpq	2,r11
 	blt	no_words
 	nop
@@ -110,4 +118,3 @@
 	ret
 	move.d	r12, r10
 		
-	
\ No newline at end of file
diff -u --recursive --new-file v2.4.3/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S
--- v2.4.3/linux/arch/cris/lib/checksumcopy.S	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/checksumcopy.S	Fri Apr  6 10:42:55 2001
@@ -1,19 +1,25 @@
-	;; $Id: checksumcopy.S,v 1.2 2000/08/08 16:57:31 bjornw Exp $
-	;; A fast checksum+copy routine using movem
-	;; Copyright (c) 1998, 2000 Axis Communications AB
-	;;
-	;; Authors:	Bjorn Wesen
-	;; 
-	;; csum_partial_copy_nocheck(const char *src, char *dst,
-	;;		             int len, unsigned int sum)
+/* $Id: checksumcopy.S,v 1.4 2001/02/19 11:11:34 bjornw Exp $
+ * A fast checksum+copy routine using movem
+ * Copyright (c) 1998, 2001 Axis Communications AB
+ *
+ * Authors:	Bjorn Wesen
+ * 
+ * csum_partial_copy_nocheck(const char *src, char *dst,
+ *		             int len, unsigned int sum)
+ */
 
 	.globl	_csum_partial_copy_nocheck
 _csum_partial_copy_nocheck:	
 	
+	;; r10 - src
+	;; r11 - dst
+	;; r12 - length
+	;; r13 - checksum
+
 	;; check for breakeven length between movem and normal word looping versions
 	
 	cmpu.w	80,r12
-	bcs	no_movem
+	blo	word_loop
 	nop
 
 	;; need to save the registers we use below in the movem loop
@@ -24,11 +30,6 @@
 	
 	;; do a movem copy and checksum
 
-	;; r10 - src
-	;; r11 - dst
-	;; r12 - length
-	;; r13 - checksum
-
 	subq	10*4,r12	; update length for the first loop
 	
 mloop:	movem	[r10+],r9	; read 10 longwords
@@ -61,6 +62,8 @@
 	
 	ax
 	addq	0,r13
+	ax			; do it again, since we might have generated a carry
+	addq	0,r13
 
 	subq	10*4,r12
 	bge	mloop
@@ -68,23 +71,27 @@
 
 	addq	10*4,r12	; compensate for last loop underflowing length
 
+	movem	[sp+],r8	; restore regs
+
+word_loop:
+	;; only fold if there is anything to fold.
+
+	cmpq	0,r13
+	beq	no_fold
+
 	;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
+	;; r9 can be used as temporary.
 	
-	moveq	-1,r1		; put 0xffff in r1, faster than move.d 0xffff,r1
-	lsrq	16,r1
-	
-	move.d	r13,r0
-	lsrq	16,r0		; r0 = checksum >> 16
-	and.d	r1,r13		; checksum = checksum & 0xffff
-	add.d	r0,r13		; checksum += r0
-	move.d	r13,r0		; do the same again, maybe we got a carry last add
-	lsrq	16,r0
-	and.d	r1,r13
-	add.d	r0,r13
+	move.d	r13,r9
+	lsrq	16,r9		; r0 = checksum >> 16
+	and.d	0xffff,r13	; checksum = checksum & 0xffff
+	add.d	r9,r13		; checksum += r0
+	move.d	r13,r9		; do the same again, maybe we got a carry last add
+	lsrq	16,r9
+	and.d	0xffff,r13
+	add.d	r9,r13
 	
-	movem	[sp+],r8	; restore regs
-		
-no_movem:
+no_fold:
 	cmpq	2,r12
 	blt	no_words
 	nop
@@ -117,4 +124,4 @@
 	ret
 	move.d	r13, r10
 		
-	
\ No newline at end of file
+	
diff -u --recursive --new-file v2.4.3/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S
--- v2.4.3/linux/arch/cris/lib/dram_init.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/lib/dram_init.S	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,123 @@
+	;; $Id: dram_init.S,v 1.2 2001/02/08 15:20:00 starvik Exp $
+	;; 
+	;; DRAM/SDRAM initialization - alter with care
+	;; This file is intended to be included from other assembler files
+	;;
+	;; Copyright (C) 2000 Axis Communications AB
+	;;
+	;; Authors:  Mikael Starvik (starvik@axis.com)	
+	;;           Bjorn Wesen (bjornw@axis.com)
+	;; 
+	;; $Log: dram_init.S,v $
+	;; Revision 1.2  2001/02/08 15:20:00  starvik
+	;; Corrected SDRAM initialization
+	;; Should now be included as inline
+	;;
+	;; Revision 1.1  2001/01/29 13:08:02  starvik
+	;; Initial version
+	;; This file should be included from all assembler files that needs to
+	;; initialize DRAM/SDRAM.
+	;;
+	;;
+	;;
+
+#include <linux/config.h>
+
+#ifndef CONFIG_SVINTO_SIM	
+	move.d   DEF_R_WAITSTATES, r0
+	move.d   r0, [R_WAITSTATES]
+
+	move.d   DEF_R_BUS_CONFIG, r0
+	move.d   r0, [R_BUS_CONFIG]
+	
+#ifndef CONFIG_SDRAM
+	move.d   DEF_R_DRAM_CONFIG, r0
+	move.d   r0, [R_DRAM_CONFIG]
+
+	move.d   DEF_R_DRAM_TIMING, r0
+	move.d   r0, [R_DRAM_TIMING]
+#else	
+	; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization
+	
+	; Bank configuration
+        move.d   DEF_R_SDRAM_CONFIG, r0
+	move.d   r0, [R_SDRAM_CONFIG]
+
+	; Calculate value of mrs_data 
+	; cas_delay = 2 && bus_width = 32 => 0x40
+	; cas_delay = 3 && bus_width = 32 => 0x60
+	; cas_delay = 2 && bus_width = 16 => 0x20
+	; cas_delay = 3 && bus_width = 16 => 0x30
+	
+	move.d   0x40, r2       ; Assume 32 bits and cas_delay = 2
+	move.d   DEF_R_SDRAM_TIMING, r1
+	and.d    0x0c, r1	; Get cas delay
+	cmp.d    0x08, r1	; cas_delay = 2?
+        beq      bw_check
+	nop
+	or.d     0x20, r2       ; cas_delay = 3
+bw_check:
+	move.d   DEF_R_SDRAM_CONFIG, r1
+	and.d    0x800000, r1	; DRAM width is bit 23
+	bne      set_timing
+	nop
+	lsrq     1, r2		;  16 bits. Shift down value.
+
+	; Set timing parameters. Starts master clock
+set_timing:
+	move.d   DEF_R_SDRAM_TIMING, r1
+	or.d     0x80000000, r1	; Make sure sdram enable bit is set
+	lslq     16, r2		; mrs data starts at bit 16
+	or.d     r2, r1 
+	move.d   r1, [R_SDRAM_TIMING]	
+		
+	; Wait 200ns
+	move.d   10, r2
+sdram_loop:
+	bne      sdram_loop
+	subq     1, r2
+	
+	; Issue initialization command sequence
+	move.d   sdram_commands_start, r2
+	move.d   sdram_commands_end,  r3
+command_loop:
+	clear.d  r4
+	move.b   [r2+], r4
+	lslq     9, r4		; Command starts at bit 9
+	or.d     r1, r4
+	move.d   r4, [R_SDRAM_TIMING]
+	nop			; Wait five nop cycles between each command
+	nop
+	nop
+	nop
+	nop
+	cmp.d    r2, r3
+	bne      command_loop
+	nop
+	ba       sdram_commands_end
+	nop
+
+sdram_commands_start:
+	.byte   3	; Precharge
+	.byte   0       ; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   2	; refresh
+	.byte   0	; nop
+	.byte   1	; mrs
+	.byte   0	; nop 
+sdram_commands_end:		
+#endif
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/cris/mm/Makefile linux/arch/cris/mm/Makefile
--- v2.4.3/linux/arch/cris/mm/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/mm/Makefile	Fri Apr  6 10:42:55 2001
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-obj-y	 := init.o fault.o tlb.o extable.o
+obj-y	 := init.o fault.o tlb.o extable.o ioremap.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c
--- v2.4.3/linux/arch/cris/mm/fault.c	Mon Mar 19 12:35:11 2001
+++ linux/arch/cris/mm/fault.c	Fri Apr  6 10:42:55 2001
@@ -6,6 +6,9 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.9  2001/03/05 13:22:20  bjornw
+ *  Spell-fix and fix in vmalloc_fault handling
+ *
  *  Revision 1.8  2000/11/22 14:45:31  bjornw
  *  * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping
  *    into all processes. Instead we fill in the missing PTE entries on demand.
@@ -301,7 +304,7 @@
 	/* Are we prepared to handle this kernel fault?
 	 *
 	 * (The kernel has valid exception-points in the source 
-	 *  when it acesses user-memory. When it fails in one
+	 *  when it accesses user-memory. When it fails in one
 	 *  of those points, we find it in a table and do a jump
 	 *  to some fixup code that loads an appropriate error
 	 *  code)
diff -u --recursive --new-file v2.4.3/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c
--- v2.4.3/linux/arch/cris/mm/init.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/mm/init.c	Fri Apr  6 10:42:55 2001
@@ -2,11 +2,22 @@
  *  linux/arch/cris/mm/init.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Copyright (C) 2000  Axis Communications AB
+ *  Copyright (C) 2000,2001  Axis Communications AB
  *
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.18  2001/02/23 12:46:44  bjornw
+ *  * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached
+ *    flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O
+ *    is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe)
+ *
+ *  Revision 1.17  2001/02/22 15:05:21  bjornw
+ *  Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs
+ *
+ *  Revision 1.16  2001/02/22 15:02:35  bjornw
+ *  Map 0xc straight over during LOW_MAP to allow for memory mapped I/O
+ *
  *  Revision 1.15  2001/01/10 21:12:10  bjornw
  *  loops_per_sec -> loops_per_jiffy
  *
@@ -287,16 +298,19 @@
 	 * The Juliette chip is mapped at 0xa so we pass that segment straight
 	 * through. We cannot vremap it because the vmalloc area is below 0x8
 	 * and Juliette needs an uncached area above 0x8.
+	 *
+	 * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards.
+	 * We map them straight over in LOW_MAP, but use vremap in LX version 2.
 	 */
 
 	*R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) | 
-			IO_STATE(R_MMU_KSEG, seg_e, seg  ) |  /* uncached flash */
+			IO_STATE(R_MMU_KSEG, seg_e, page ) |
 			IO_STATE(R_MMU_KSEG, seg_d, page ) | 
-			IO_STATE(R_MMU_KSEG, seg_c, page ) | 
+			IO_STATE(R_MMU_KSEG, seg_c, page ) |   
 			IO_STATE(R_MMU_KSEG, seg_b, seg  ) |  /* kernel reg area */
 			IO_STATE(R_MMU_KSEG, seg_a, seg  ) |  /* Juliette etc. */
-			IO_STATE(R_MMU_KSEG, seg_9, page ) |
-			IO_STATE(R_MMU_KSEG, seg_8, page ) |
+			IO_STATE(R_MMU_KSEG, seg_9, seg  ) |  /* LED's on some boards */
+			IO_STATE(R_MMU_KSEG, seg_8, seg  ) |  /* CSE0/1, flash and I/O */
 			IO_STATE(R_MMU_KSEG, seg_7, page ) |  /* kernel vmalloc area */
 			IO_STATE(R_MMU_KSEG, seg_6, seg  ) |  /* kernel DRAM area */
 			IO_STATE(R_MMU_KSEG, seg_5, seg  ) |  /* cached flash */
@@ -307,13 +321,13 @@
 			IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */
 
 	*R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) );
+			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) );
 	
 	*R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) |
diff -u --recursive --new-file v2.4.3/linux/arch/cris/mm/ioremap.c linux/arch/cris/mm/ioremap.c
--- v2.4.3/linux/arch/cris/mm/ioremap.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/mm/ioremap.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,164 @@
+/*
+ * arch/cris/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * Needed for memory-mapped I/O devices mapped outside our normal DRAM
+ * window (that is, all memory-mapped I/O devices).
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ * CRIS-port by Axis Communications AB
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | 
+							     __WRITEABLE | _PAGE_GLOBAL |
+							     _PAGE_KERNEL | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc_kernel(pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc_kernel(dir, address);
+		if (!pmd)
+			return -ENOMEM;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			return -ENOMEM;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	flush_tlb_all();
+	return 0;
+}
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+	void * addr;
+	struct vm_struct * area;
+	unsigned long offset, last_addr;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
+
+#if 0
+	/* TODO: Here we can put checks for driver-writer abuse...  */
+
+	/*
+	 * Don't remap the low PCI/ISA area, it's always mapped..
+	 */
+	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+		return phys_to_virt(phys_addr);
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using..
+	 */
+	if (phys_addr < virt_to_phys(high_memory)) {
+		char *t_addr, *t_end;
+		struct page *page;
+
+		t_addr = __va(phys_addr);
+		t_end = t_addr + (size - 1);
+	   
+		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
+			if(!PageReserved(page))
+				return NULL;
+	}
+#endif
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
+
+	/*
+	 * Ok, go for it..
+	 */
+	area = get_vm_area(size, VM_IOREMAP);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+	return (void *) (offset + (char *)addr);
+}
+
+void iounmap(void *addr)
+{
+	if (addr > high_memory)
+		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
diff -u --recursive --new-file v2.4.3/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.4.3/linux/arch/i386/Makefile	Wed Jan 10 15:06:14 2001
+++ linux/arch/i386/Makefile	Thu Apr 12 12:20:31 2001
@@ -82,6 +82,10 @@
 CFLAGS += -march=i586
 endif
 
+ifdef CONFIG_MCYRIXIII
+CFLAGS += -march=i586
+endif
+
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib
diff -u --recursive --new-file v2.4.3/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.4.3/linux/arch/i386/boot/setup.S	Sat Jan 27 10:51:35 2001
+++ linux/arch/i386/boot/setup.S	Wed Apr 11 18:50:25 2001
@@ -18,7 +18,7 @@
  * March 1993/June 1994 (Christoph.Niemann@linux.org)
  *
  * add APM BIOS checking by Stephen Rothwell, May 1994
- * (Stephen.Rothwell@canb.auug.org.au)
+ * (sfr@canb.auug.org.au)
  *
  * High load stuff, initrd support and position independency
  * by Hans Lermen & Werner Almesberger, February 1996
@@ -81,14 +81,9 @@
 
 type_of_loader:	.byte	0		# = 0, old one (LILO, Loadlin,
 					#      Bootlin, SYSLX, bootsect...)
-					# Else it is set by the loader:
-					# 0xTV: T=0 for LILO
-					#	T=1 for Loadlin
-					#	T=2 for bootsect-loader
-					#	T=3 for SYSLX
-					#	T=4 for ETHERBOOT
-					#       V = version
-
+					# See Documentation/i386/boot.txt for
+					# assigned ids
+	
 # flags, unused bits must be zero (RFU) bit within loadflags
 loadflags:
 LOADED_HIGH	= 1			# If set, the kernel is loaded high
diff -u --recursive --new-file v2.4.3/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.4.3/linux/arch/i386/config.in	Mon Jan  8 13:27:56 2001
+++ linux/arch/i386/config.in	Fri Apr 20 18:26:15 2001
@@ -36,24 +36,31 @@
 	 Pentium-III			CONFIG_MPENTIUMIII \
 	 Pentium-4			CONFIG_MPENTIUM4 \
 	 K6/K6-II/K6-III		CONFIG_MK6 \
-	 Athlon/K7			CONFIG_MK7 \
+	 Athlon/Duron/K7		CONFIG_MK7 \
 	 Crusoe				CONFIG_MCRUSOE \
 	 Winchip-C6			CONFIG_MWINCHIPC6 \
 	 Winchip-2			CONFIG_MWINCHIP2 \
-	 Winchip-2A/Winchip-3		CONFIG_MWINCHIP3D" Pentium-Pro
+	 Winchip-2A/Winchip-3		CONFIG_MWINCHIP3D \
+	 CyrixIII/C3			CONFIG_MCYRIXIII" Pentium-Pro
 #
 # Define implied options from the CPU selection here
 #
 
 if [ "$CONFIG_M386" = "y" ]; then
    define_bool CONFIG_X86_CMPXCHG n
+   define_bool CONFIG_X86_XADD n
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
+   define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+   define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
    define_bool CONFIG_X86_CMPXCHG y
+   define_bool CONFIG_X86_XADD y
    define_bool CONFIG_X86_BSWAP y
    define_bool CONFIG_X86_POPAD_OK y
+   define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+   define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 fi
 if [ "$CONFIG_M486" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
@@ -111,6 +118,13 @@
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
+   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+fi
+if [ "$CONFIG_MCYRIXIII" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MCRUSOE" = "y" ]; then
diff -u --recursive --new-file v2.4.3/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.3/linux/arch/i386/defconfig	Fri Mar 23 16:05:44 2001
+++ linux/arch/i386/defconfig	Tue Apr 17 17:28:02 2001
@@ -5,6 +5,8 @@
 CONFIG_ISA=y
 # CONFIG_SBUS is not set
 CONFIG_UID16=y
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 
 #
 # Code maturity level options
@@ -35,9 +37,11 @@
 # CONFIG_MWINCHIPC6 is not set
 # CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
+# CONFIG_MCYRIXIII is not set
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
 CONFIG_X86_L1_CACHE_SHIFT=5
@@ -383,6 +387,9 @@
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -561,6 +568,7 @@
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
 # CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.4.3/linux/arch/i386/kernel/apm.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/i386/kernel/apm.c	Fri Apr  6 10:42:47 2001
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  * APM BIOS driver for Linux
- * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com)
+ * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au)
  *
  * Initial development of this driver was funded by NEC Australia P/L
  *	and NEC Corporation
@@ -23,7 +23,7 @@
  * March 1996, Rik Faith (faith@cs.unc.edu):
  *    Prohibit APM BIOS calls unless apm_enabled.
  *    (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>)
- * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
+ * April 1996, Stephen Rothwell (sfr@canb.auug.org.au)
  *    Version 1.0 and 1.1
  * May 1996, Version 1.2
  * Feb 1998, Version 1.3
@@ -119,7 +119,7 @@
  *         Make power off under SMP work again.
  *         Fix thinko with initial engaging of BIOS.
  *         Make sure power off only happens on CPU 0
- *         (Paul "Rusty" Russell <rusty@linuxcare.com>).
+ *         (Paul "Rusty" Russell <rusty@rustcorp.com.au>).
  *         Do error notification to user mode if BIOS calls fail.
  *         Move entrypoint offset fix to ...boot/setup.S
  *         where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>).
@@ -227,6 +227,8 @@
  * P: Toshiba 1950S: battery life information only gets updated after resume
  * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
  * 	broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
+ * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP
+ * 	Neale Banks <neale@lowendale.com.au> December 2000
  *
  * Legend: U = unusable with APM patches
  *         P = partially usable with APM patches
@@ -1550,6 +1552,9 @@
 			apm_disabled = 1;
 		if (strncmp(str, "on", 2) == 0)
 			apm_disabled = 0;
+		if ((strncmp(str, "broken-psr", 10) == 0) ||
+		    (strncmp(str, "broken_psr", 10) == 0))
+			apm_info.get_power_status_broken = 1;
 		invert = (strncmp(str, "no-", 3) == 0);
 		if (invert)
 			str += 3;
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
--- v2.4.3/linux/arch/i386/kernel/bluesmoke.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/i386/kernel/bluesmoke.c	Wed Apr 11 19:02:27 2001
@@ -45,6 +45,7 @@
 				printk(" at %08x%08x", 
 					high, low);
 			}
+			printk("\n");
 			/* Clear it */
 			wrmsr(0x401+i*4, 0UL, 0UL);
 			/* Serialize */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.4.3/linux/arch/i386/kernel/head.S	Sun Mar 25 17:38:31 2001
+++ linux/arch/i386/kernel/head.S	Fri Apr 20 16:23:30 2001
@@ -169,9 +169,7 @@
 	rep
 	movsl
 1:
-#ifdef CONFIG_SMP
 checkCPUtype:
-#endif
 
 	movl $-1,X86_CPUID		#  -1 for no CPUID initially
 
@@ -244,9 +242,7 @@
 	orl $2,%eax		# set MP
 2:	movl %eax,%cr0
 	call check_x87
-#ifdef CONFIG_SMP
 	incb ready
-#endif
 	lgdt gdt_descr
 	lidt idt_descr
 	ljmp $(__KERNEL_CS),$1f
@@ -278,9 +274,7 @@
 	jmp L6			# main should never return here, but
 				# just in case, we know what happens.
 
-#ifdef CONFIG_SMP
 ready:	.byte 0
-#endif
 
 /*
  * We depend on ET to be correct. This checks for 287/387.
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.4.3/linux/arch/i386/kernel/i386_ksyms.c	Fri Mar  2 12:03:49 2001
+++ linux/arch/i386/kernel/i386_ksyms.c	Wed Apr 25 13:31:03 2001
@@ -61,7 +61,6 @@
 EXPORT_SYMBOL(dump_extended_fpu);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(__io_virt_debug);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
@@ -73,13 +72,14 @@
 EXPORT_SYMBOL(apm_info);
 EXPORT_SYMBOL(gdt);
 
+#ifdef CONFIG_IO_DEBUG
+EXPORT_SYMBOL(__io_virt_debug);
+#endif
+
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
-EXPORT_SYMBOL_NOVERS(__down_write_failed);
-EXPORT_SYMBOL_NOVERS(__down_read_failed);
-EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
@@ -97,6 +97,7 @@
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(simple_strtol);
+EXPORT_SYMBOL(strstr);
 
 EXPORT_SYMBOL(strncpy_from_user);
 EXPORT_SYMBOL(__strncpy_from_user);
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.4.3/linux/arch/i386/kernel/ldt.c	Mon Mar 19 12:35:09 2001
+++ linux/arch/i386/kernel/ldt.c	Wed Apr 11 19:05:37 2001
@@ -94,8 +94,6 @@
 			goto out_unlock;
 		memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
 		
-		if (atomic_read(&mm->mm_users) > 1)
-			printk(KERN_WARNING "LDT allocated for cloned task!\n");
 		/*
 		 * Possibly do an SMP cross-call to other CPUs to reload
 		 * their LDTs?
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.4.3/linux/arch/i386/kernel/mtrr.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/i386/kernel/mtrr.c	Wed Apr 11 19:02:27 2001
@@ -231,6 +231,20 @@
   v1.37
     20001109   H. Peter Anvin <hpa@zytor.com>
 	       Use the new centralized CPU feature detects.
+
+  v1.38
+    20010309   Dave Jones <davej@suse.de>
+	       Add support for Cyrix III.
+
+  v1.39
+    20010312   Dave Jones <davej@suse.de>
+               Ugh, I broke AMD support.
+	       Reworked fix by Troels Walsted Hansen <troels@thule.no>
+
+  v1.40
+    20010327   Dave Jones <davej@suse.de>
+	       Adapted Cyrix III support to include VIA C3.
+
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -250,6 +264,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #define MTRR_NEED_STRINGS
 #include <asm/mtrr.h>
 #include <linux/init.h>
@@ -269,7 +284,7 @@
 #include <asm/hardirq.h>
 #include <linux/irq.h>
 
-#define MTRR_VERSION            "1.37 (20001109)"
+#define MTRR_VERSION            "1.40 (20010327)"
 
 #define TRUE  1
 #define FALSE 0
@@ -464,6 +479,27 @@
 static int have_wrcomb (void)
 {
     unsigned long config, dummy;
+    struct pci_dev *dev = NULL;
+    
+   /* ServerWorks LE chipsets have problems with  write-combining 
+      Don't allow it and  leave room for other chipsets to be tagged */
+
+    if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
+	switch(dev->vendor) {
+        case PCI_VENDOR_ID_SERVERWORKS:
+ 	    switch (dev->device) {
+	    case PCI_DEVICE_ID_SERVERWORKS_LE:
+		return 0;
+		break;
+	    default:
+		break;
+	    }
+	    break;
+	default:
+	    break;
+	}
+    }
+
 
     switch ( mtrr_if )
     {
@@ -538,7 +574,7 @@
      * Note: shift==0xf means 4G, this is unsupported.
      */
     if (shift)
-      *size = (reg < 7 ? 0x1UL : 0x40UL) << shift;
+      *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
     else
       *size = 0;
 
@@ -1777,7 +1813,8 @@
     }
     devfs_set_file_size (devfs_handle, ascii_buf_bytes);
 #  ifdef CONFIG_PROC_FS
-    proc_root_mtrr->size = ascii_buf_bytes;
+    if (proc_root_mtrr)
+	proc_root_mtrr->size = ascii_buf_bytes;
 #  endif  /*  CONFIG_PROC_FS  */
 }   /*  End Function compute_ascii  */
 
@@ -1938,6 +1975,7 @@
 	get_mtrr = intel_get_mtrr;
 	set_mtrr_up = intel_set_mtrr_up;
 	switch (boot_cpu_data.x86_vendor) {
+
 	case X86_VENDOR_AMD:
 		/* The original Athlon docs said that
 		   total addressable memory is 44 bits wide.
@@ -1956,12 +1994,27 @@
 			size_and_mask = ~size_or_mask & 0xfff00000;
 			break;
 		}
+		size_or_mask  = 0xff000000; /* 36 bits */
+		size_and_mask = 0x00f00000;
+		break;
+
+	case X86_VENDOR_CENTAUR:
+		/* Cyrix III has Intel style MTRRs, but doesn't support PAE */
+		if (boot_cpu_data.x86 == 6 &&
+			(boot_cpu_data.x86_model == 6 ||
+			 boot_cpu_data.x86_model == 7)) {
+			size_or_mask  = 0xfff00000; /* 32 bits */
+			size_and_mask = 0;
+		}
+		break;
+
 	default:
 		/* Intel, etc. */
 		size_or_mask  = 0xff000000; /* 36 bits */
 		size_and_mask = 0x00f00000;
 		break;
 	}
+
     } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
 	/* Pre-Athlon (K6) AMD CPU MTRRs */
 	mtrr_if = MTRR_IF_AMD_K6;
@@ -2072,8 +2125,10 @@
 
 #ifdef CONFIG_PROC_FS
     proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
-    proc_root_mtrr->owner = THIS_MODULE;
-    proc_root_mtrr->proc_fops = &mtrr_fops;
+    if (proc_root_mtrr) {
+	proc_root_mtrr->owner = THIS_MODULE;
+	proc_root_mtrr->proc_fops = &mtrr_fops;
+    }
 #endif
 #ifdef CONFIG_DEVFS_FS
     devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0,
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.4.3/linux/arch/i386/kernel/pci-pc.c	Thu Mar 29 11:24:17 2001
+++ linux/arch/i386/kernel/pci-pc.c	Thu Apr 19 22:57:06 2001
@@ -843,6 +843,8 @@
 	pcibios_last_bus = -1;
 }
 
+#if 0
+/* Until we get proper handling pray the BIOS gets it right */
 /*
  * ServerWorks host bridges -- Find and scan all secondary buses.
  * Register 0x44 contains first, 0x45 last bus number routed there.
@@ -860,6 +862,7 @@
 		printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus);
 	}
 }
+#endif
 
 #if 0
 /* Our bus code shouldnt need this fixup any more. Delete once verified */
@@ -957,34 +960,6 @@
 	d->irq = 9;
 }
 
-static void __init pci_fixup_vt8363(struct pci_dev *d)
-{
-	/*
-	 * The VIA bridge will corrupt disks without these settings.
-	 */
-	u8 tmp;
-	pci_read_config_byte(d, 0x54, &tmp);
-	if(tmp & (1<<2)) {
-		printk("PCI: Bus master Pipeline request disabled\n");
-		pci_write_config_byte(d, 0x54, tmp & ~(1<<2));
-	}
-	pci_read_config_byte(d, 0x70, &tmp);
-	if(tmp & (1<<3)) {
-		printk("PCI: Disabled enhanced CPU to PCI writes\n");
-		pci_write_config_byte(d, 0x70, tmp & ~(1<<3));
-	}
-	pci_read_config_byte(d, 0x71, &tmp);
-	if((tmp & (1<<3)) == 0) {
-		printk("PCI: Bursting cornercase bug worked around\n");
-		pci_write_config_byte(d, 0x71, tmp | (1<<3));
-	}
-	pci_read_config_byte(d, 0x76, &tmp);
-	if(tmp & (1<<7)) {
-		printk("PCI: Post Write Fail set to Retry\n");
-		pci_write_config_byte(d, 0x76, tmp & ~(1<<7));
-	}
-}
-
 static void __init pci_fixup_via691(struct pci_dev *d)
 {
 	/*
@@ -1033,7 +1008,6 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	pci_fixup_via_acpi },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	pci_fixup_via_acpi },
- 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_vt8363 },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C691,	pci_fixup_via691 },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C598_1,	pci_fixup_via691_2 },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/semaphore.c linux/arch/i386/kernel/semaphore.c
--- v2.4.3/linux/arch/i386/kernel/semaphore.c	Sat Nov 18 17:31:25 2000
+++ linux/arch/i386/kernel/semaphore.c	Thu Apr 12 12:22:53 2001
@@ -14,7 +14,6 @@
  */
 #include <linux/config.h>
 #include <linux/sched.h>
-
 #include <asm/semaphore.h>
 
 /*
@@ -179,6 +178,7 @@
  * value..
  */
 asm(
+".text\n"
 ".align 4\n"
 ".globl __down_failed\n"
 "__down_failed:\n\t"
@@ -193,6 +193,7 @@
 );
 
 asm(
+".text\n"
 ".align 4\n"
 ".globl __down_failed_interruptible\n"
 "__down_failed_interruptible:\n\t"
@@ -205,6 +206,7 @@
 );
 
 asm(
+".text\n"
 ".align 4\n"
 ".globl __down_failed_trylock\n"
 "__down_failed_trylock:\n\t"
@@ -217,6 +219,7 @@
 );
 
 asm(
+".text\n"
 ".align 4\n"
 ".globl __up_wakeup\n"
 "__up_wakeup:\n\t"
@@ -230,199 +233,9 @@
 	"ret"
 );
 
-asm(
-"
-.align 4
-.globl __down_read_failed
-__down_read_failed:
-	pushl	%edx
-	pushl	%ecx
-	jnc	2f
-
-3:	call	down_read_failed_biased
-
-1:	popl	%ecx
-	popl	%edx
-	ret
-
-2:	call	down_read_failed
-	" LOCK "subl	$1,(%eax)
-	jns	1b
-	jnc	2b
-	jmp	3b
-"
-);
-
-asm(
-"
-.align 4
-.globl __down_write_failed
-__down_write_failed:
-	pushl	%edx
-	pushl	%ecx
-	jnc	2f
-
-3:	call	down_write_failed_biased
-
-1:	popl	%ecx
-	popl	%edx
-	ret
-
-2:	call	down_write_failed
-	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax)
-	jz	1b
-	jnc	2b
-	jmp	3b
-"
-);
-
-struct rw_semaphore *FASTCALL(rwsem_wake_readers(struct rw_semaphore *sem));
-struct rw_semaphore *FASTCALL(rwsem_wake_writer(struct rw_semaphore *sem));
-
-struct rw_semaphore *FASTCALL(down_read_failed_biased(struct rw_semaphore *sem));
-struct rw_semaphore *FASTCALL(down_write_failed_biased(struct rw_semaphore *sem));
-struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem));
-struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem));
-
-struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-
-	return sem;
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	__up_read(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-asm(
-"
-.align 4
-.globl __rwsem_wake
-__rwsem_wake:
-	pushl	%edx
-	pushl	%ecx
-
-	jz	1f
-	call	rwsem_wake_readers
-	jmp	2f
-
-1:	call	rwsem_wake_writer
-
-2:	popl	%ecx
-	popl	%edx
-	ret
-"
-);
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
+/*
+ * rw spinlock fallbacks
  */
-struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-	return sem;
-}
-
-struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-	return sem;
-}
-
 #if defined(CONFIG_SMP)
 asm(
 "
@@ -451,4 +264,3 @@
 "
 );
 #endif
-
diff -u --recursive --new-file v2.4.3/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.4.3/linux/arch/i386/kernel/setup.c	Sun Mar 25 18:24:31 2001
+++ linux/arch/i386/kernel/setup.c	Fri Apr  6 10:42:55 2001
@@ -58,6 +58,12 @@
  *  Massive cleanup of CPU detection and bug handling;
  *  Transmeta CPU detection,
  *  H. Peter Anvin <hpa@zytor.com>, November 2000
+ *
+ *  Added E820 sanitization routine (removes overlapping memory regions);
+ *  Brian Moyle <bmoyle@mvista.com>, February 2001
+ *
+ *  VIA C3 Support.
+ *  Dave Jones <davej@suse.de>, March 2001
  */
 
 /*
@@ -440,6 +446,170 @@
 }
 
 /*
+ * Sanitize the BIOS e820 map.
+ *
+ * Some e820 responses include overlapping entries.  The following 
+ * replaces the original e820 map with a new one, removing overlaps.
+ *
+ */
+static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+{
+	struct change_member {
+		struct e820entry *pbios; /* pointer to original bios entry */
+		unsigned long long addr; /* address for this change point */
+	};
+	struct change_member change_point_list[2*E820MAX];
+	struct change_member *change_point[2*E820MAX];
+	struct e820entry *overlap_list[E820MAX];
+	struct e820entry new_bios[E820MAX];
+	struct change_member *change_tmp;
+	unsigned long current_type, last_type;
+	unsigned long long last_addr;
+	int chgidx, still_changing;
+	int overlap_entries;
+	int new_bios_entry;
+	int old_nr, new_nr;
+	int i;
+
+	/*
+		Visually we're performing the following (1,2,3,4 = memory types)...
+
+		Sample memory map (w/overlaps):
+		   ____22__________________
+		   ______________________4_
+		   ____1111________________
+		   _44_____________________
+		   11111111________________
+		   ____________________33__
+		   ___________44___________
+		   __________33333_________
+		   ______________22________
+		   ___________________2222_
+		   _________111111111______
+		   _____________________11_
+		   _________________4______
+
+		Sanitized equivalent (no overlap):
+		   1_______________________
+		   _44_____________________
+		   ___1____________________
+		   ____22__________________
+		   ______11________________
+		   _________1______________
+		   __________3_____________
+		   ___________44___________
+		   _____________33_________
+		   _______________2________
+		   ________________1_______
+		   _________________4______
+		   ___________________2____
+		   ____________________33__
+		   ______________________4_
+	*/
+
+	/* if there's only one memory region, don't bother */
+	if (*pnr_map < 2)
+		return -1;
+
+	old_nr = *pnr_map;
+
+	/* bail out if we find any unreasonable addresses in bios map */
+	for (i=0; i<old_nr; i++)
+		if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
+			return -1;
+
+	/* create pointers for initial change-point information (for sorting) */
+	for (i=0; i < 2*old_nr; i++)
+		change_point[i] = &change_point_list[i];
+
+	/* record all known change-points (starting and ending addresses) */
+	chgidx = 0;
+	for (i=0; i < old_nr; i++)	{
+		change_point[chgidx]->addr = biosmap[i].addr;
+		change_point[chgidx++]->pbios = &biosmap[i];
+		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+		change_point[chgidx++]->pbios = &biosmap[i];
+	}
+
+	/* sort change-point list by memory addresses (low -> high) */
+	still_changing = 1;
+	while (still_changing)	{
+		still_changing = 0;
+		for (i=1; i < 2*old_nr; i++)  {
+			/* if <current_addr> > <last_addr>, swap */
+			/* or, if current=<start_addr> & last=<end_addr>, swap */
+			if ((change_point[i]->addr < change_point[i-1]->addr) ||
+				((change_point[i]->addr == change_point[i-1]->addr) &&
+				 (change_point[i]->addr == change_point[i]->pbios->addr) &&
+				 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
+			   )
+			{
+				change_tmp = change_point[i];
+				change_point[i] = change_point[i-1];
+				change_point[i-1] = change_tmp;
+				still_changing=1;
+			}
+		}
+	}
+
+	/* create a new bios memory map, removing overlaps */
+	overlap_entries=0;	 /* number of entries in the overlap table */
+	new_bios_entry=0;	 /* index for creating new bios map entries */
+	last_type = 0;		 /* start with undefined memory type */
+	last_addr = 0;		 /* start with 0 as last starting address */
+	/* loop through change-points, determining affect on the new bios map */
+	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
+	{
+		/* keep track of all overlapping bios entries */
+		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
+		{
+			/* add map entry to overlap list (> 1 entry implies an overlap) */
+			overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
+		}
+		else
+		{
+			/* remove entry from list (order independent, so swap with last) */
+			for (i=0; i<overlap_entries; i++)
+			{
+				if (overlap_list[i] == change_point[chgidx]->pbios)
+					overlap_list[i] = overlap_list[overlap_entries-1];
+			}
+			overlap_entries--;
+		}
+		/* if there are overlapping entries, decide which "type" to use */
+		/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
+		current_type = 0;
+		for (i=0; i<overlap_entries; i++)
+			if (overlap_list[i]->type > current_type)
+				current_type = overlap_list[i]->type;
+		/* continue building up new bios map based on this information */
+		if (current_type != last_type)	{
+			if (last_type != 0)	 {
+				new_bios[new_bios_entry].size =
+					change_point[chgidx]->addr - last_addr;
+				/* move forward only if the new size was non-zero */
+				if (new_bios[new_bios_entry].size != 0)
+					if (++new_bios_entry >= E820MAX)
+						break; 	/* no more space left for new bios entries */
+			}
+			if (current_type != 0)	{
+				new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
+				new_bios[new_bios_entry].type = current_type;
+				last_addr=change_point[chgidx]->addr;
+			}
+			last_type = current_type;
+		}
+	}
+	new_nr = new_bios_entry;   /* retain count for new bios entries */
+
+	/* copy new bios mapping into original location */
+	memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
+	*pnr_map = new_nr;
+
+	return 0;
+}
+
+/*
  * Copy the BIOS e820 map into a safe place.
  *
  * Sanity-check it while we're at it..
@@ -506,6 +676,7 @@
 	 * Otherwise fake a memory map; one section from 0k->640k,
 	 * the next section from 1mb->appropriate_mem_k
 	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
 	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
 		unsigned long mem_size;
 
@@ -560,7 +731,7 @@
 				 * blow away any automatically generated
 				 * size
 				 */
-				unsigned long start_at, mem_size;
+				unsigned long long start_at, mem_size;
  
 				if (usermem == 0) {
 					/* first time in: zap the whitelist
@@ -1401,7 +1572,7 @@
 
 		case 6:
 			switch (c->x86_model) {
-				case 6:	/* Cyrix III */
+				case 6 ... 7:		/* Cyrix III or C3 */
 					rdmsr (0x1107, lo, hi);
 					lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
 					wrmsr (0x1107, lo, hi);
@@ -1481,6 +1652,32 @@
 	wrmsr(0x80860004, cap_mask, uk);
 }
 
+
+static void __init init_rise(struct cpuinfo_x86 *c)
+{
+	printk("CPU: Rise iDragon");
+	if (c->x86_model > 2)
+		printk(" II");
+	printk("\n");
+	printk("If you have one of these please email davej@suse.de\n");
+
+	/* Unhide possibly hidden capability flags
+	   The mp6 iDragon family don't have MSRs.
+	   We switch on extra features with this cpuid wierdness: */
+	__asm__ (
+		"movl $0x6363452a, %%eax\n\t"
+		"movl $0x3231206c, %%ecx\n\t"
+		"movl $0x2a32313a, %%edx\n\t"
+		"cpuid\n\t"
+		"movl $0x63634523, %%eax\n\t"
+		"movl $0x32315f6c, %%ecx\n\t"
+		"movl $0x2333313a, %%edx\n\t"
+		"cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
+	);
+	set_bit(X86_FEATURE_CX8, &c->x86_capability);
+}
+
+
 extern void trap_init_f00f_bug(void);
 
 static void __init init_intel(struct cpuinfo_x86 *c)
@@ -1732,8 +1929,8 @@
 	  { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_RISE,	5,
-	  { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL,
-	    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+	  { "iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL,
+	    NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL }},
 };
 
 /* Look up CPU names by table lookup. */
@@ -1997,6 +2194,15 @@
 	case X86_VENDOR_UNKNOWN:
 	default:
 		/* Not much we can do here... */
+		/* Check if at least it has cpuid */
+		if (c->cpuid_level == -1)
+		{
+			/* No cpuid. It must be an ancient CPU */
+			if (c->x86 == 4)
+				strcpy(c->x86_model_id, "486");
+			else if (c->x86 == 3)
+				strcpy(c->x86_model_id, "386");
+		}
 		break;
 
 	case X86_VENDOR_CYRIX:
@@ -2021,6 +2227,10 @@
 
 	case X86_VENDOR_TRANSMETA:
 		init_transmeta(c);
+		break;
+
+	case X86_VENDOR_RISE:
+		init_rise(c);
 		break;
 	}
 	
diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.4.3/linux/arch/i386/lib/Makefile	Fri Dec 29 14:07:20 2000
+++ linux/arch/i386/lib/Makefile	Wed Apr 25 13:31:03 2001
@@ -8,8 +8,8 @@
 L_TARGET = lib.a
 
 obj-y = checksum.o old-checksum.o delay.o \
-	usercopy.o getuser.o putuser.o iodebug.o \
-	memcpy.o
+	usercopy.o getuser.o putuser.o \
+	memcpy.o strstr.o
 
 obj-$(CONFIG_X86_USE_3DNOW) += mmx.o
 obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c
--- v2.4.3/linux/arch/i386/lib/mmx.c	Thu Mar  1 18:04:34 2001
+++ linux/arch/i386/lib/mmx.c	Wed Apr 11 19:02:27 2001
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/sched.h>
@@ -5,6 +6,7 @@
 #include <asm/i387.h>
 #include <asm/hardirq.h> 
 
+
 /*
  *	MMX 3DNow! library helper functions
  *
@@ -95,6 +97,13 @@
 	return p;
 }
 
+#ifdef CONFIG_MK7
+
+/*
+ *	The K7 has streaming cache bypass load/store. The Cyrix III, K6 and
+ *	other MMX using processors do not.
+ */
+
 static void fast_clear_page(void *page)
 {
 	int i;
@@ -194,6 +203,118 @@
 	);
 	kernel_fpu_end();
 }
+
+#else
+
+/*
+ *	Generic MMX implementation without K7 specific streaming
+ */
+ 
+static void fast_clear_page(void *page)
+{
+	int i;
+	if (!(current->flags & PF_USEDFPU))
+		clts();
+	else
+	{
+		__asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387));
+		current->flags &= ~PF_USEDFPU;
+	}
+	
+	__asm__ __volatile__ (
+		"  pxor %%mm0, %%mm0\n" : :
+	);
+
+	for(i=0;i<4096/128;i++)
+	{
+		__asm__ __volatile__ (
+		"  movq %%mm0, (%0)\n"
+		"  movq %%mm0, 8(%0)\n"
+		"  movq %%mm0, 16(%0)\n"
+		"  movq %%mm0, 24(%0)\n"
+		"  movq %%mm0, 32(%0)\n"
+		"  movq %%mm0, 40(%0)\n"
+		"  movq %%mm0, 48(%0)\n"
+		"  movq %%mm0, 56(%0)\n"
+		"  movq %%mm0, 64(%0)\n"
+		"  movq %%mm0, 72(%0)\n"
+		"  movq %%mm0, 80(%0)\n"
+		"  movq %%mm0, 88(%0)\n"
+		"  movq %%mm0, 96(%0)\n"
+		"  movq %%mm0, 104(%0)\n"
+		"  movq %%mm0, 112(%0)\n"
+		"  movq %%mm0, 120(%0)\n"
+		: : "r" (page) : "memory");
+		page+=128;
+	}
+	stts();
+}
+
+static void fast_copy_page(void *to, void *from)
+{
+	int i;
+	if (!(current->flags & PF_USEDFPU))
+		clts();
+	else
+	{
+		__asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387));
+		current->flags &= ~PF_USEDFPU;
+	}
+
+	__asm__ __volatile__ (
+		"1: prefetch (%0)\n"
+		"   prefetch 64(%0)\n"
+		"   prefetch 128(%0)\n"
+		"   prefetch 192(%0)\n"
+		"   prefetch 256(%0)\n"
+		"2:  \n"
+		".section .fixup, \"ax\"\n"
+		"3: movw $0x1AEB, 1b\n"	/* jmp on 26 bytes */
+		"   jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long 1b, 3b\n"
+		".previous"
+		: : "r" (from) );
+
+	for(i=0; i<4096/64; i++)
+	{
+		__asm__ __volatile__ (
+		"1: prefetch 320(%0)\n"
+		"2: movq (%0), %%mm0\n"
+		"   movq 8(%0), %%mm1\n"
+		"   movq 16(%0), %%mm2\n"
+		"   movq 24(%0), %%mm3\n"
+		"   movq %%mm0, (%1)\n"
+		"   movq %%mm1, 8(%1)\n"
+		"   movq %%mm2, 16(%1)\n"
+		"   movq %%mm3, 24(%1)\n"
+		"   movq 32(%0), %%mm0\n"
+		"   movq 40(%0), %%mm1\n"
+		"   movq 48(%0), %%mm2\n"
+		"   movq 56(%0), %%mm3\n"
+		"   movq %%mm0, 32(%1)\n"
+		"   movq %%mm1, 40(%1)\n"
+		"   movq %%mm2, 48(%1)\n"
+		"   movq %%mm3, 56(%1)\n"
+		".section .fixup, \"ax\"\n"
+		"3: movw $0x05EB, 1b\n"	/* jmp on 5 bytes */
+		"   jmp 2b\n"
+		".previous\n"
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long 1b, 3b\n"
+		".previous"
+		: : "r" (from), "r" (to) : "memory");
+		from+=64;
+		to+=64;
+	}
+	stts();
+}
+
+
+#endif
 
 /*
  *	Favour MMX for page clear and copy. 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/strstr.c linux/arch/i386/lib/strstr.c
--- v2.4.3/linux/arch/i386/lib/strstr.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/lib/strstr.c	Fri Apr  6 10:42:47 2001
@@ -0,0 +1,31 @@
+#include <linux/string.h>
+
+char * strstr(const char * cs,const char * ct)
+{
+int	d0, d1;
+register char * __res;
+__asm__ __volatile__(
+	"movl %6,%%edi\n\t"
+	"repne\n\t"
+	"scasb\n\t"
+	"notl %%ecx\n\t"
+	"decl %%ecx\n\t"	/* NOTE! This also sets Z if searchstring='' */
+	"movl %%ecx,%%edx\n"
+	"1:\tmovl %6,%%edi\n\t"
+	"movl %%esi,%%eax\n\t"
+	"movl %%edx,%%ecx\n\t"
+	"repe\n\t"
+	"cmpsb\n\t"
+	"je 2f\n\t"		/* also works for empty string, see above */
+	"xchgl %%eax,%%esi\n\t"
+	"incl %%esi\n\t"
+	"cmpb $0,-1(%%eax)\n\t"
+	"jne 1b\n\t"
+	"xorl %%eax,%%eax\n\t"
+	"2:"
+	:"=a" (__res), "=&c" (d0), "=&S" (d1)
+	:"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
+	:"dx", "di");
+return __res;
+}
+
diff -u --recursive --new-file v2.4.3/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c
--- v2.4.3/linux/arch/i386/lib/usercopy.c	Fri Nov 12 04:29:47 1999
+++ linux/arch/i386/lib/usercopy.c	Fri Apr 13 20:26:07 2001
@@ -34,6 +34,8 @@
 		else
 			mmx_copy_user_zeroing(to, from, n);
 	}
+	else
+		memset(to, 0, n);
 	return n;
 }
 
@@ -52,6 +54,8 @@
 {
 	if (access_ok(VERIFY_READ, from, n))
 		__copy_user_zeroing(to,from,n);
+	else
+		memset(to, 0, n);
 	return n;
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/control_w.h linux/arch/i386/math-emu/control_w.h
--- v2.4.3/linux/arch/i386/math-emu/control_w.h	Thu Jun 29 08:25:27 1995
+++ linux/arch/i386/math-emu/control_w.h	Fri Apr  6 10:42:47 2001
@@ -42,4 +42,4 @@
 /* FULL_PRECISION simulates all exceptions masked */
 #define FULL_PRECISION  (PR_64_BITS | RC_RND | 0x3f)
 
-#endif _CONTROLW_H_
+#endif /* _CONTROLW_H_ */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/div_Xsig.S linux/arch/i386/math-emu/div_Xsig.S
--- v2.4.3/linux/arch/i386/math-emu/div_Xsig.S	Fri Aug 27 10:18:17 1999
+++ linux/arch/i386/math-emu/div_Xsig.S	Fri Apr  6 10:42:47 2001
@@ -70,7 +70,7 @@
 	.long	0
 FPU_result_1:
 	.long	0
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */
 
 
 .text
@@ -79,7 +79,7 @@
 	movl	%esp,%ebp
 #ifndef NON_REENTRANT_FPU
 	subl	$28,%esp
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */ 
 
 	pushl	%esi
 	pushl	%edi
@@ -91,7 +91,7 @@
 #ifdef PARANOID
 	testl	$0x80000000, XsigH(%ebx)	/* Divisor */
 	je	L_bugged
-#endif PARANOID
+#endif /* PARANOID */
 
 
 /*---------------------------------------------------------------------------+
@@ -164,7 +164,7 @@
 
 #ifdef PARANOID
 	jb	L_bugged_1
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	/* need to subtract another once of the denom */
 	incl	FPU_result_3	/* Correct the answer */
@@ -177,7 +177,7 @@
 #ifdef PARANOID
 	sbbl	$0,FPU_accum_3
 	jne	L_bugged_1	/* Must check for non-zero result here */
-#endif PARANOID
+#endif /* PARANOID */ 
 
 /*----------------------------------------------------------------------*/
 /* Half of the main problem is done, there is just a reduced numerator
@@ -207,7 +207,7 @@
 
 #ifdef PARANOID
 	je	L_bugged_2	/* Can't bump the result to 1.0 */
-#endif PARANOID
+#endif /* PARANOID */ 
 
 LDo_2nd_div:
 	cmpl	$0,%ecx		/* augmented denom msw */
@@ -230,7 +230,7 @@
 
 #ifdef PARANOID
 	jc	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */
 
 	movl	FPU_result_2,%eax	/* Get the result back */
 	mull	XsigL(%ebx)	/* now mul the ls dw of the denom */
@@ -241,14 +241,14 @@
 
 #ifdef PARANOID
 	jc	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */
 
 	jz	LDo_3rd_32_bits
 
 #ifdef PARANOID
 	cmpl	$1,FPU_accum_2
 	jne	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	/* need to subtract another once of the denom */
 	movl	XsigL(%ebx),%eax
@@ -260,14 +260,14 @@
 #ifdef PARANOID
 	jc	L_bugged_2
 	jne	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	addl	$1,FPU_result_2	/* Correct the answer */
 	adcl	$0,FPU_result_3
 
 #ifdef PARANOID
 	jc	L_bugged_2	/* Must check for non-zero result here */
-#endif PARANOID
+#endif /* PARANOID */ 
 
 /*----------------------------------------------------------------------*/
 /* The division is essentially finished here, we just need to perform
@@ -362,4 +362,4 @@
 	call	EXCEPTION
 	pop	%ebx
 	jmp	L_exit
-#endif PARANOID
+#endif /* PARANOID */ 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/errors.c linux/arch/i386/math-emu/errors.c
--- v2.4.3/linux/arch/i386/math-emu/errors.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/errors.c	Fri Apr  6 10:42:47 2001
@@ -141,7 +141,7 @@
 if ( partial_status & SW_Zero_Div )    printk("SW: divide by zero\n");
 if ( partial_status & SW_Denorm_Op )   printk("SW: denormalized operand\n");
 if ( partial_status & SW_Invalid )     printk("SW: invalid operation\n");
-#endif DEBUGGING
+#endif /* DEBUGGING */
 
   printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
 	 partial_status & 0x8000 ? 1 : 0,   /* busy */
@@ -327,7 +327,7 @@
 #ifdef PRINT_MESSAGES
       /* My message from the sponsor */
       printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
-#endif PRINT_MESSAGES
+#endif /* PRINT_MESSAGES */
       
       /* Get a name string for error reporting */
       for (i=0; exception_names[i].type; i++)
@@ -338,7 +338,7 @@
 	{
 #ifdef PRINT_MESSAGES
 	  printk("FP Exception: %s!\n", exception_names[i].name);
-#endif PRINT_MESSAGES
+#endif /* PRINT_MESSAGES */
 	}
       else
 	printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
@@ -351,7 +351,7 @@
 #ifdef PRINT_MESSAGES
       else
 	FPU_printall();
-#endif PRINT_MESSAGES
+#endif /* PRINT_MESSAGES */
 
       /*
        * The 80486 generates an interrupt on the next non-control FPU
@@ -363,7 +363,7 @@
 
 #ifdef __DEBUG__
   math_abort(FPU_info,SIGFPE);
-#endif __DEBUG__
+#endif /* __DEBUG__ */
 
 }
 
@@ -469,7 +469,7 @@
   else
 #ifdef PARANOID
     if (tagb == TW_NaN)
-#endif PARANOID
+#endif /* PARANOID */
     {
       signalling = !(b->sigh & 0x40000000);
       x = b;
@@ -481,7 +481,7 @@
       EXCEPTION(EX_INTERNAL|0x113);
       x = &CONST_QNaN;
     }
-#endif PARANOID
+#endif /* PARANOID */
 
   if ( (!signalling) || (control_word & CW_Invalid) )
     {
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/exception.h linux/arch/i386/math-emu/exception.h
--- v2.4.3/linux/arch/i386/math-emu/exception.h	Mon Dec 11 13:34:33 2000
+++ linux/arch/i386/math-emu/exception.h	Fri Apr  6 10:42:47 2001
@@ -18,7 +18,7 @@
 
 #ifndef SW_C1
 #include "fpu_emu.h"
-#endif SW_C1
+#endif /* SW_C1 */
 
 #define FPU_BUSY        Const_(0x8000)   /* FPU busy bit (8087 compatibility) */
 #define EX_ErrorSummary Const_(0x0080)   /* Error summary status */
@@ -48,6 +48,6 @@
 #define	EXCEPTION(x)	FPU_exception(x)
 #endif
 
-#endif __ASSEMBLY__
+#endif /* __ASSEMBLY__ */ 
 
-#endif _EXCEPTION_H_
+#endif /* _EXCEPTION_H_ */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_asm.h linux/arch/i386/math-emu/fpu_asm.h
--- v2.4.3/linux/arch/i386/math-emu/fpu_asm.h	Mon Dec 11 13:34:33 2000
+++ linux/arch/i386/math-emu/fpu_asm.h	Fri Apr  6 10:42:47 2001
@@ -29,4 +29,4 @@
 #define	SIGL(x)	SIGL_OFFSET##(x)
 #define	SIGH(x)	4(x)
 
-#endif _FPU_ASM_H_
+#endif /* _FPU_ASM_H_ */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h
--- v2.4.3/linux/arch/i386/math-emu/fpu_emu.h	Mon Dec 11 13:34:33 2000
+++ linux/arch/i386/math-emu/fpu_emu.h	Fri Apr  6 10:42:47 2001
@@ -88,7 +88,7 @@
 #else
 #  define RE_ENTRANT_CHECK_OFF
 #  define RE_ENTRANT_CHECK_ON
-#endif RE_ENTRANT_CHECKING
+#endif /* RE_ENTRANT_CHECKING */
 
 #define FWAIT_OPCODE 0x9b
 #define OP_SIZE_PREFIX 0x66
@@ -212,6 +212,6 @@
 #include "fpu_proto.h"
 #endif
 
-#endif __ASSEMBLY__
+#endif /* __ASSEMBLY__ */
 
-#endif _FPU_EMU_H_
+#endif /* _FPU_EMU_H_ */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- v2.4.3/linux/arch/i386/math-emu/fpu_entry.c	Mon Jun 19 18:10:44 2000
+++ linux/arch/i386/math-emu/fpu_entry.c	Fri Apr  6 10:42:47 2001
@@ -78,7 +78,7 @@
   fdivr_,   FPU_trigb,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
 };
 
-#endif NO_UNDOC_CODE
+#endif /* NO_UNDOC_CODE */
 
 
 #define _NONE_ 0   /* Take no special action */
@@ -120,12 +120,12 @@
   _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
 };
 
-#endif NO_UNDOC_CODE
+#endif /* NO_UNDOC_CODE */
 
 
 #ifdef RE_ENTRANT_CHECKING
 u_char emulating=0;
-#endif RE_ENTRANT_CHECKING
+#endif /* RE_ENTRANT_CHECKING */
 
 static int valid_prefix(u_char *Byte, u_char **fpu_eip,
 			overrides *override);
@@ -152,7 +152,7 @@
       printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
     }
   RE_ENTRANT_CHECK_ON;
-#endif RE_ENTRANT_CHECKING
+#endif /* RE_ENTRANT_CHECKING */
 
   if (!current->used_math)
     {
@@ -251,7 +251,7 @@
 #ifdef PARANOID
       EXCEPTION(EX_INTERNAL|0x128);
       math_abort(FPU_info,SIGILL);
-#endif PARANOID
+#endif /* PARANOID */
     }
 
   RE_ENTRANT_CHECK_OFF;
@@ -386,7 +386,7 @@
 			/* fdiv or fsub */
 			real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
 		      else
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */ 
 			/* fadd, fdivr, fmul, or fsubr */
 			real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
 		    }
@@ -497,7 +497,7 @@
 	 to do this: */
       operand_address.offset = 0;
       operand_address.selector = FPU_DS;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 
       st0_ptr = &st(0);
       st0_tag = FPU_gettag0();
@@ -557,7 +557,7 @@
   RE_ENTRANT_CHECK_OFF;
   FPU_printall();
   RE_ENTRANT_CHECK_ON;
-#endif DEBUG
+#endif /* DEBUG */
 
   if (FPU_lookahead && !current->need_resched)
     {
@@ -669,7 +669,7 @@
 	__asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
 #ifdef PARANOID
       printk("ERROR: wm-FPU-emu math_abort failed!\n");
-#endif PARANOID
+#endif /* PARANOID */
 }
 
 
@@ -739,7 +739,7 @@
   S387->twd |= 0xffff0000;
   S387->fcs &= ~0xf8000000;
   S387->fos |= 0xffff0000;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
   __copy_to_user(d, &S387->cwd, 7*4);
   RE_ENTRANT_CHECK_ON;
 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_etc.c linux/arch/i386/math-emu/fpu_etc.c
--- v2.4.3/linux/arch/i386/math-emu/fpu_etc.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/fpu_etc.c	Fri Apr  6 10:42:47 2001
@@ -68,7 +68,7 @@
 	      /* This is weird! */
 	      if (getsign(st0_ptr) == SIGN_POS)
 		setcc(SW_C3);
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	      return;
 	    }
 	  break;
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/fpu_trig.c linux/arch/i386/math-emu/fpu_trig.c
--- v2.4.3/linux/arch/i386/math-emu/fpu_trig.c	Thu Nov  4 09:10:22 1999
+++ linux/arch/i386/math-emu/fpu_trig.c	Fri Apr  6 10:42:47 2001
@@ -98,7 +98,7 @@
 	      q++;
 	    }
 	}
-#endif BETTER_THAN_486
+#endif /* BETTER_THAN_486 */
     }
 #ifdef BETTER_THAN_486
   else
@@ -138,7 +138,7 @@
 	    }
 	}
     }
-#endif BETTER_THAN_486
+#endif /* BETTER_THAN_486 */
 
   FPU_settag0(st0_tag);
   control_word = old_cw;
@@ -186,7 +186,7 @@
 #ifdef PARANOID
   else
     EXCEPTION(EX_INTERNAL|0x0112);
-#endif PARANOID
+#endif /* PARANOID */
 }
 
 
@@ -232,7 +232,7 @@
 #ifdef PARANOID
     default:
       EXCEPTION(EX_INTERNAL|0x0112);
-#endif PARANOID
+#endif /* PARANOID */
     }
 }
 
@@ -463,7 +463,7 @@
 #ifdef PARANOID
   else
     EXCEPTION(EX_INTERNAL | 0x119);
-#endif PARANOID
+#endif /* PARANOID */
 }
 
 
@@ -716,7 +716,7 @@
 	  set_precision_flag_down();  /* 80486 appears to do this. */
 #else
 	  set_precision_flag_up();  /* Must be up. */
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	  return 0;
 	}
     }
@@ -1008,7 +1008,7 @@
 	      setcc(SW_C2);
 #else
 	      setcc(0);
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	      return;
 	    }
 	  cc = SW_C2;
@@ -1114,7 +1114,7 @@
 #ifdef PARANOID
   if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
       EXCEPTION(EX_INTERNAL | 0x118);
-#endif PARANOID
+#endif /* PARANOID */
 
   real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
 
@@ -1315,7 +1315,7 @@
 	  sign = getsign(st1_ptr);
 	  if ( FPU_divide_by_zero(1, sign) < 0 )
 	    return;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 
 	  changesign(st1_ptr);
 	}
@@ -1451,7 +1451,7 @@
 #ifdef PARANOID
   else
     EXCEPTION(EX_INTERNAL | 0x125);
-#endif PARANOID
+#endif /* PARANOID */
 
   FPU_pop();
   set_precision_flag_up();  /* We do not really know if up or down */
@@ -1542,7 +1542,7 @@
 #ifdef PARANOID
 	  EXCEPTION(EX_INTERNAL | 0x116);
 	  return;
-#endif PARANOID
+#endif /* PARANOID */
 	}
     }
   else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
@@ -1560,7 +1560,7 @@
 #else
 		  if ( arith_invalid(1) < 0 )
 		    return;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 		}
 	      else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 		return;
@@ -1583,7 +1583,7 @@
 		  changesign(st1_ptr);
 #else
 		  if ( arith_invalid(1) < 0 ) return;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 		}
 	      else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 		return;
@@ -1618,14 +1618,14 @@
 	  /* This should have higher priority than denormals, but... */
 	  if ( arith_invalid(1) < 0 )  /* log(-infinity) */
 	    return;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	  if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
 #ifdef PECULIAR_486
 	  /* Denormal operands actually get higher priority */
 	  if ( arith_invalid(1) < 0 )  /* log(-infinity) */
 	    return;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	}
       else if ( st1_tag == TAG_Zero )
 	{
@@ -1654,7 +1654,7 @@
       EXCEPTION(EX_INTERNAL | 0x117);
       return;
     }
-#endif PARANOID
+#endif /* PARANOID */
 
   FPU_pop();
   return;
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/get_address.c linux/arch/i386/math-emu/get_address.c
--- v2.4.3/linux/arch/i386/math-emu/get_address.c	Mon Jun 19 12:56:08 2000
+++ linux/arch/i386/math-emu/get_address.c	Fri Apr  6 10:42:47 2001
@@ -143,7 +143,7 @@
       EXCEPTION(EX_INTERNAL|0x130);
       math_abort(FPU_info,SIGSEGV);
     }
-#endif PARANOID
+#endif /* PARANOID */
   addr->selector = VM86_REG_(segment);
   return (unsigned long)VM86_REG_(segment) << 4;
 }
@@ -166,7 +166,7 @@
       EXCEPTION(EX_INTERNAL|0x132);
       math_abort(FPU_info,SIGSEGV);
     }
-#endif PARANOID
+#endif /* PARANOID */
 
   switch ( segment )
     {
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/load_store.c linux/arch/i386/math-emu/load_store.c
--- v2.4.3/linux/arch/i386/math-emu/load_store.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/load_store.c	Fri Apr  6 10:42:47 2001
@@ -85,7 +85,7 @@
 #ifdef PARANOID
       else
 	EXCEPTION(EX_INTERNAL|0x140);
-#endif PARANOID
+#endif /* PARANOID */
     }
 
   switch ( type_table[type] )
@@ -112,7 +112,7 @@
     default:
       EXCEPTION(EX_INTERNAL|0x141);
       return 0;
-#endif PARANOID
+#endif /* PARANOID */
     }
 
   switch ( type )
@@ -217,7 +217,7 @@
 	partial_status &= ~(SW_Summary | SW_Backward);
 #ifdef PECULIAR_486
       control_word |= 0x40;  /* An 80486 appears to always set this bit */
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
       return 1;
     case 025:      /* fld m80real */
       clear_C1();
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly.h linux/arch/i386/math-emu/poly.h
--- v2.4.3/linux/arch/i386/math-emu/poly.h	Thu Nov  4 09:10:22 1999
+++ linux/arch/i386/math-emu/poly.h	Fri Apr  6 10:42:47 2001
@@ -118,4 +118,4 @@
                :"=g" (*x):"g" (x):"si","ax","cx");
 }
 
-#endif _POLY_H
+#endif /* _POLY_H */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_2xm1.c linux/arch/i386/math-emu/poly_2xm1.c
--- v2.4.3/linux/arch/i386/math-emu/poly_2xm1.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/poly_2xm1.c	Fri Apr  6 10:42:47 2001
@@ -67,7 +67,7 @@
       EXCEPTION(EX_INTERNAL|0x127);
       return 1;
     }
-#endif PARANOID
+#endif /* PARANOID */
 
   argSignif.lsw = 0;
   XSIG_LL(argSignif) = Xll = significand(arg);
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_atan.c linux/arch/i386/math-emu/poly_atan.c
--- v2.4.3/linux/arch/i386/math-emu/poly_atan.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/poly_atan.c	Fri Apr  6 10:42:47 2001
@@ -124,7 +124,7 @@
 	      EXCEPTION(EX_INTERNAL|0x104);  /* There must be a logic error */
 	      return;
 	    }
-#endif PARANOID
+#endif /* PARANOID */
 	  argSignif.msw = 0;   /* Make the transformed arg -> 0.0 */
 	}
       else
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_l2.c linux/arch/i386/math-emu/poly_l2.c
--- v2.4.3/linux/arch/i386/math-emu/poly_l2.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/poly_l2.c	Fri Apr  6 10:42:47 2001
@@ -157,7 +157,7 @@
 #else
 	  if ( arith_invalid(1) < 0 )
 	    return 1;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	}
 
       /* 80486 appears to do this */
@@ -243,7 +243,7 @@
 	  /* The argument is too large */
 	}
     }
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 
   arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif);
   adj = norm_Xsig(&argSignif);
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_sin.c linux/arch/i386/math-emu/poly_sin.c
--- v2.4.3/linux/arch/i386/math-emu/poly_sin.c	Thu Nov  4 09:10:22 1999
+++ linux/arch/i386/math-emu/poly_sin.c	Fri Apr  6 10:42:47 2001
@@ -199,7 +199,7 @@
     {
       EXCEPTION(EX_INTERNAL|0x150);
     }
-#endif PARANOID
+#endif /* PARANOID */
 
 }
 
@@ -224,7 +224,7 @@
       FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
       return;
     }
-#endif PARANOID
+#endif /* PARANOID */
 
   exponent = exponent(st0_ptr);
 
@@ -392,6 +392,6 @@
     {
       EXCEPTION(EX_INTERNAL|0x151);
     }
-#endif PARANOID
+#endif /* PARANOID */
 
 }
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/poly_tan.c linux/arch/i386/math-emu/poly_tan.c
--- v2.4.3/linux/arch/i386/math-emu/poly_tan.c	Wed Jul  5 10:56:13 2000
+++ linux/arch/i386/math-emu/poly_tan.c	Fri Apr  6 10:42:47 2001
@@ -66,7 +66,7 @@
 #ifdef PARANOID
   if ( signnegative(st0_ptr) )	/* Can't hack a number < 0.0 */
     { arith_invalid(0); return; }  /* Need a positive number */
-#endif PARANOID
+#endif /* PARANOID */
 
   /* Split the problem into two domains, smaller and larger than pi/4 */
   if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_compare.c linux/arch/i386/math-emu/reg_compare.c
--- v2.4.3/linux/arch/i386/math-emu/reg_compare.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/reg_compare.c	Fri Apr  6 10:42:47 2001
@@ -136,7 +136,7 @@
 #ifdef PARANOID
   if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
-#endif PARANOID
+#endif /* PARANOID */
 
   diff = exp0 - expb;
   if ( diff == 0 )
@@ -203,7 +203,7 @@
 	EXCEPTION(EX_INTERNAL|0x121);
 	f = SW_C3 | SW_C2 | SW_C0;
 	break;
-#endif PARANOID
+#endif /* PARANOID */
       }
   setcc(f);
   if (c & COMP_Denormal)
@@ -255,7 +255,7 @@
 	EXCEPTION(EX_INTERNAL|0x122);
 	f = SW_C3 | SW_C2 | SW_C0;
 	break;
-#endif PARANOID
+#endif /* PARANOID */
       }
   setcc(f);
   if (c & COMP_Denormal)
@@ -312,7 +312,7 @@
 	EXCEPTION(EX_INTERNAL|0x123);
 	f = SW_C3 | SW_C2 | SW_C0;
 	break;
-#endif PARANOID
+#endif /* PARANOID */ 
       }
   setcc(f);
   if (c & COMP_Denormal)
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_constant.h linux/arch/i386/math-emu/reg_constant.h
--- v2.4.3/linux/arch/i386/math-emu/reg_constant.h	Mon Dec 11 13:34:34 2000
+++ linux/arch/i386/math-emu/reg_constant.h	Fri Apr  6 10:42:47 2001
@@ -28,4 +28,4 @@
 extern FPU_REG const CONST_MINF;
 extern FPU_REG const CONST_QNaN;
 
-#endif _REG_CONSTANT_H_
+#endif /* _REG_CONSTANT_H_ */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_divide.c linux/arch/i386/math-emu/reg_divide.c
--- v2.4.3/linux/arch/i386/math-emu/reg_divide.c	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/reg_divide.c	Fri Apr  6 10:42:47 2001
@@ -201,6 +201,6 @@
       EXCEPTION(EX_INTERNAL|0x102);
       return FPU_Exception;
     }
-#endif PARANOID
+#endif /* PARANOID */ 
 
 }
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_ld_str.c linux/arch/i386/math-emu/reg_ld_str.c
--- v2.4.3/linux/arch/i386/math-emu/reg_ld_str.c	Sun Jan 25 11:01:48 1998
+++ linux/arch/i386/math-emu/reg_ld_str.c	Fri Apr  6 10:42:47 2001
@@ -439,7 +439,7 @@
 		 converts to decide underflow. */
 	      if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
 		  (st0_ptr->sigl & 0x000007ff)) )
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 		{
 		  EXCEPTION(EX_Underflow);
 		  /* This is a special case: see sec 16.2.5.1 of
@@ -559,7 +559,7 @@
 	  /* Underflow has priority. */
 	  if ( control_word & CW_Underflow )
 	    denormal_operand();
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 	  reg_copy(st0_ptr, &tmp);
 	  goto denormal_arg;
 	}
@@ -659,7 +659,7 @@
 		 converts to decide underflow. */
 	      if ( !((tmp.sigl == 0x00800000) &&
 		  ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 		{
 		  EXCEPTION(EX_Underflow);
 		  /* This is a special case: see sec 16.2.5.1 of
@@ -776,7 +776,7 @@
 	  /* Underflow has priority. */
 	  if ( control_word & CW_Underflow )
 	    denormal_operand();
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */ 
 	  goto denormal_arg;
 	}
       else if (st0_tag == TW_Infinity)
@@ -1221,7 +1221,7 @@
 
 #ifdef PECULIAR_486
   control_word &= ~0xe080;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */ 
 
   top = (partial_status >> SW_Top_Shift) & 7;
 
@@ -1303,7 +1303,7 @@
       FPU_put_user(control_word & ~0xe080, (unsigned long *) d);
 #else
       FPU_put_user(control_word, (unsigned short *) d);
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
       FPU_put_user(status_word(), (unsigned short *) (d+2));
       FPU_put_user(fpu_tag_word, (unsigned short *) (d+4));
       FPU_put_user(instruction_address.offset, (unsigned short *) (d+6));
@@ -1335,7 +1335,7 @@
       fpu_tag_word |= 0xffff0000;
       I387.soft.fcs &= ~0xf8000000;
       I387.soft.fos |= 0xffff0000;
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
       __copy_to_user(d, &control_word, 7*4);
       RE_ENTRANT_CHECK_ON;
       d += 0x1c;
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_mul.c linux/arch/i386/math-emu/reg_mul.c
--- v2.4.3/linux/arch/i386/math-emu/reg_mul.c	Wed Jun 24 14:30:08 1998
+++ linux/arch/i386/math-emu/reg_mul.c	Fri Apr  6 10:42:47 2001
@@ -126,6 +126,6 @@
       EXCEPTION(EX_INTERNAL|0x102);
       return FPU_Exception;
     }
-#endif PARANOID
+#endif /* PARANOID */ 
 
 }
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_round.S linux/arch/i386/math-emu/reg_round.S
--- v2.4.3/linux/arch/i386/math-emu/reg_round.S	Thu Nov  4 09:10:22 1999
+++ linux/arch/i386/math-emu/reg_round.S	Fri Apr  6 10:42:47 2001
@@ -100,7 +100,7 @@
 	.byte	0
 FPU_denormal:
 	.byte	0
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */
 
 
 .text
@@ -126,13 +126,13 @@
 
 #ifndef NON_REENTRANT_FPU
 	pushl	%ebx		/* adjust the stack pointer */
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */ 
 
 #ifdef PARANOID
 /* Cannot use this here yet */
 /*	orl	%eax,%eax */
 /*	jns	L_entry_bugged */
-#endif PARANOID
+#endif /* PARANOID */
 
 	cmpw	EXP_UNDER,EXP(%edi)
 	jle	L_Make_denorm			/* The number is a de-normal */
@@ -160,12 +160,12 @@
 	je	LRound_To_64
 #ifdef PARANOID
 	jmp	L_bugged_denorm_486
-#endif PARANOID
+#endif /* PARANOID */ 
 #else
 #ifdef PARANOID
 	jmp	L_bugged_denorm	/* There is no bug, just a bad control word */
-#endif PARANOID
-#endif PECULIAR_486
+#endif /* PARANOID */ 
+#endif /* PECULIAR_486 */
 
 
 /* Round etc to 24 bit precision */
@@ -186,7 +186,7 @@
 
 #ifdef PARANOID
 	jmp	L_bugged_round24
-#endif PARANOID
+#endif /* PARANOID */ 
 
 LUp_24:
 	cmpb	SIGN_POS,PARAM5
@@ -266,7 +266,7 @@
 
 #ifdef PARANOID
 	jmp	L_bugged_round53
-#endif PARANOID
+#endif /* PARANOID */ 
 
 LUp_53:
 	cmpb	SIGN_POS,PARAM5
@@ -340,7 +340,7 @@
 
 #ifdef PARANOID
 	jmp	L_bugged_round64
-#endif PARANOID
+#endif /* PARANOID */ 
 
 LUp_64:
 	cmpb	SIGN_POS,PARAM5
@@ -430,7 +430,7 @@
 
 #ifndef NON_REENTRANT_FPU
 	popl	%ebx		/* adjust the stack pointer */
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */ 
 
 fpu_Arith_exit:
 	popl	%ebx
@@ -570,7 +570,7 @@
 	/* But check it... just in case. */
 	cmpw	EXP_UNDER+1,EXP(%edi)
 	jne	L_norm_bugged
-#endif PARANOID
+#endif /* PARANOID */
 
 #ifdef PECULIAR_486
 	/*
@@ -586,7 +586,7 @@
 #else
 	orl	%eax,%eax		/* ms bits */
 	js	L_Normalised		/* No longer a denormal */
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */ 
 
 	jnz	LDenormal_adj_exponent
 
@@ -673,7 +673,7 @@
 	call	EXCEPTION
 	popl	%ebx
 	jmp	L_exception_exit
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */ 
 
 L_bugged_round24:
 	pushl	EX_INTERNAL|0x231
@@ -706,4 +706,4 @@
 L_exception_exit:
 	mov	$-1,%eax
 	jmp	fpu_reg_round_special_exit
-#endif PARANOID
+#endif /* PARANOID */ 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_add.S linux/arch/i386/math-emu/reg_u_add.S
--- v2.4.3/linux/arch/i386/math-emu/reg_u_add.S	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/reg_u_add.S	Fri Apr  6 10:42:47 2001
@@ -72,7 +72,7 @@
 
 	testl	$0x80000000,SIGH(%esi)
 	je	L_bugged
-#endif PARANOID
+#endif /* PARANOID */
 
 /* The number to be shifted is in %eax:%ebx:%edx */
 	cmpw	$32,%cx		/* shrd only works for 0..31 bits */
@@ -164,4 +164,4 @@
 	popl	%esi
 	leave
 	ret
-#endif PARANOID
+#endif /* PARANOID */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_div.S linux/arch/i386/math-emu/reg_u_div.S
--- v2.4.3/linux/arch/i386/math-emu/reg_u_div.S	Fri Aug 27 10:18:17 1999
+++ linux/arch/i386/math-emu/reg_u_div.S	Fri Apr  6 10:42:47 2001
@@ -67,7 +67,7 @@
 	.long	0
 FPU_ovfl_flag:
 	.byte	0
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */
 
 #define REGA	PARAM1
 #define REGB	PARAM2
@@ -79,7 +79,7 @@
 	movl	%esp,%ebp
 #ifndef NON_REENTRANT_FPU
 	subl	$28,%esp
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */
 
 	pushl	%esi
 	pushl	%edi
@@ -112,7 +112,7 @@
 /*	je	L_bugged */
 	testl	$0x80000000, SIGH(%ebx)	/* Divisor */
 	je	L_bugged
-#endif PARANOID
+#endif /* PARANOID */ 
 
 /* Check if the divisor can be treated as having just 32 bits */
 	cmpl	$0,SIGL(%ebx)
@@ -248,7 +248,7 @@
 
 #ifdef PARANOID
 	jb	L_bugged_1
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	/* need to subtract another once of the denom */
 	incl	FPU_result_2	/* Correct the answer */
@@ -261,7 +261,7 @@
 #ifdef PARANOID
 	sbbl	$0,FPU_accum_3
 	jne	L_bugged_1	/* Must check for non-zero result here */
-#endif PARANOID
+#endif /* PARANOID */ 
 
 /*----------------------------------------------------------------------*/
 /* Half of the main problem is done, there is just a reduced numerator
@@ -291,7 +291,7 @@
 
 #ifdef PARANOID
 	je	L_bugged_2	/* Can't bump the result to 1.0 */
-#endif PARANOID
+#endif /* PARANOID */ 
 
 LDo_2nd_div:
 	cmpl	$0,%ecx		/* augmented denom msw */
@@ -314,7 +314,7 @@
 
 #ifdef PARANOID
 	jc	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	movl	FPU_result_1,%eax	/* Get the result back */
 	mull	SIGL(%ebx)	/* now mul the ls dw of the denom */
@@ -325,14 +325,14 @@
 
 #ifdef PARANOID
 	jc	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	jz	LDo_3rd_32_bits
 
 #ifdef PARANOID
 	cmpl	$1,FPU_accum_2
 	jne	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */
 
 	/* need to subtract another once of the denom */
 	movl	SIGL(%ebx),%eax
@@ -344,14 +344,14 @@
 #ifdef PARANOID
 	jc	L_bugged_2
 	jne	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	addl	$1,FPU_result_1	/* Correct the answer */
 	adcl	$0,FPU_result_2
 
 #ifdef PARANOID
 	jc	L_bugged_2	/* Must check for non-zero result here */
-#endif PARANOID
+#endif /* PARANOID */
 
 /*----------------------------------------------------------------------*/
 /* The division is essentially finished here, we just need to perform
@@ -470,4 +470,4 @@
 
 	leave
 	ret
-#endif PARANOID
+#endif /* PARANOID */ 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_mul.S linux/arch/i386/math-emu/reg_u_mul.S
--- v2.4.3/linux/arch/i386/math-emu/reg_u_mul.S	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/reg_u_mul.S	Fri Apr  6 10:42:47 2001
@@ -40,7 +40,7 @@
 	.long	0
 FPU_accum_1:
 	.long	0
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */
 
 
 .text
@@ -49,7 +49,7 @@
 	movl	%esp,%ebp
 #ifndef NON_REENTRANT_FPU
 	subl	$8,%esp
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */ 
 
 	pushl	%esi
 	pushl	%edi
@@ -63,7 +63,7 @@
 	jz	L_bugged
 	testl	$0x80000000,SIGH(%edi)
 	jz	L_bugged
-#endif PARANOID
+#endif /* PARANOID */
 
 	xorl	%ecx,%ecx
 	xorl	%ebx,%ebx
@@ -144,5 +144,5 @@
 	popl	%esi
 	leave
 	ret
-#endif PARANOID
+#endif /* PARANOID */ 
 
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/reg_u_sub.S linux/arch/i386/math-emu/reg_u_sub.S
--- v2.4.3/linux/arch/i386/math-emu/reg_u_sub.S	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/reg_u_sub.S	Fri Apr  6 10:42:47 2001
@@ -54,7 +54,7 @@
 
 	testl	$0x80000000,SIGH(%esi)
 	je	L_bugged_2
-#endif PARANOID
+#endif /* PARANOID */
 
 /*--------------------------------------+
  |	Form a register holding the     |
@@ -165,7 +165,7 @@
 #ifdef PARANOID
 	/* We can never get a borrow */
 	jc	L_bugged
-#endif PARANOID
+#endif /* PARANOID */
 
 /*--------------------------------------+
  |	Normalize the result		|
@@ -199,7 +199,7 @@
 #ifdef PARANOID
 	orl	%edx,%edx
 	jnz	L_bugged_3
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	/* The result is zero */
 	movw	$0,EXP(%edi)		/* exponent */
@@ -262,7 +262,7 @@
 L_error_exit:
 	movl	$-1,%eax
 
-#endif PARANOID
+#endif /* PARANOID */
 
 L_exit:
 	popl	%ebx
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/status_w.h linux/arch/i386/math-emu/status_w.h
--- v2.4.3/linux/arch/i386/math-emu/status_w.h	Mon Dec 11 13:34:33 2000
+++ linux/arch/i386/math-emu/status_w.h	Fri Apr  6 10:42:47 2001
@@ -58,8 +58,8 @@
 #  define clear_C1()  { partial_status &= ~SW_C1; }
 # else
 #  define clear_C1()
-#endif PECULIAR_486
+#endif /* PECULIAR_486 */
 
-#endif __ASSEMBLY__
+#endif /* __ASSEMBLY__ */
 
-#endif _STATUS_H_
+#endif /* _STATUS_H_ */
diff -u --recursive --new-file v2.4.3/linux/arch/i386/math-emu/wm_sqrt.S linux/arch/i386/math-emu/wm_sqrt.S
--- v2.4.3/linux/arch/i386/math-emu/wm_sqrt.S	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/wm_sqrt.S	Fri Apr  6 10:42:47 2001
@@ -70,7 +70,7 @@
 	.long	0
 FPU_fsqrt_arg_0:
 	.long	0		/* ls word, at most the ms bit is set */
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */ 
 
 
 .text
@@ -79,7 +79,7 @@
 	movl	%esp,%ebp
 #ifndef NON_REENTRANT_FPU
 	subl	$28,%esp
-#endif NON_REENTRANT_FPU
+#endif /* NON_REENTRANT_FPU */
 	pushl	%esi
 	pushl	%edi
 	pushl	%ebx
@@ -210,7 +210,7 @@
 /* It should be possible to get here only if the arg is ffff....ffff */
 	cmp	$0xffffffff,FPU_fsqrt_arg_1
 	jnz	sqrt_stage_2_error
-#endif PARANOID
+#endif /* PARANOID */
 
 /* The best rounded result. */
 	xorl	%eax,%eax
@@ -224,7 +224,7 @@
 sqrt_stage_2_error:
 	pushl	EX_INTERNAL|0x213
 	call	EXCEPTION
-#endif PARANOID
+#endif /* PARANOID */ 
 
 sqrt_stage_2_done:
 
@@ -279,7 +279,7 @@
 	call	EXCEPTION
 
 sqrt_stage_3_no_error:
-#endif PARANOID
+#endif /* PARANOID */
 
 	movl	FPU_accum_2,%edx
 	movl	FPU_accum_1,%eax
@@ -385,7 +385,7 @@
 	call	EXCEPTION
 
 sqrt_near_exact_ok:
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	or	%ebx,%ebx
 	js	sqrt_near_exact_small
@@ -445,7 +445,7 @@
 	call	EXCEPTION
 
 sqrt_more_prec_ok:
-#endif PARANOID
+#endif /* PARANOID */ 
 
 	or	%ebx,%ebx
 	js	sqrt_more_prec_small
diff -u --recursive --new-file v2.4.3/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.4.3/linux/arch/i386/mm/init.c	Mon Mar 26 11:01:56 2001
+++ linux/arch/i386/mm/init.c	Fri Apr 20 16:15:20 2001
@@ -309,14 +309,11 @@
 	 * Zap initial low-memory mappings.
 	 *
 	 * Note that "pgd_clear()" doesn't do it for
-	 * us in this case, because pgd_clear() is a
-	 * no-op in the 2-level case (pmd_clear() is
-	 * the thing that clears the page-tables in
-	 * that case).
+	 * us, because pgd_clear() is a no-op on i386.
 	 */
 	for (i = 0; i < USER_PTRS_PER_PGD; i++)
 #if CONFIG_X86_PAE
-		pgd_clear(swapper_pg_dir+i);
+		set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
 #else
 		set_pgd(swapper_pg_dir+i, __pgd(0));
 #endif
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/Makefile linux/arch/ia64/Makefile
--- v2.4.3/linux/arch/ia64/Makefile	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/Makefile	Thu Apr  5 12:51:46 2001
@@ -5,7 +5,7 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 1998-2000 by David Mosberger-Tang <davidm@hpl.hp.com>
+# Copyright (C) 1998-2001 by David Mosberger-Tang <davidm@hpl.hp.com>
 #
 
 NM := $(CROSS_COMPILE)nm -B
@@ -14,13 +14,13 @@
 export AWK
 
 LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds
-AFLAGS += -Wa,-x 
+AFLAGS += -Wa,-x
 AFLAGS_KERNEL := -mconstant-gp
 EXTRA	=
 
 CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \
 	  -funwind-tables -falign-functions=32
-# -frename-registers
+# -frename-registers (this crashes the Nov 17 compiler...)
 CFLAGS_KERNEL := -mconstant-gp
 
 ifeq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y)
@@ -53,7 +53,7 @@
 endif
 
 ifdef CONFIG_IA64_SGI_SN1
-CFLAGS += -DBRINGUP
+	CFLAGS		+= -DBRINGUP
         SUBDIRS         :=      arch/$(ARCH)/sn/sn1	\
 				arch/$(ARCH)/sn		\
 				arch/$(ARCH)/sn/io	\
@@ -103,6 +103,11 @@
 
 FORCE: ;
 
+compressed: vmlinux
+	$(OBJCOPY) --strip-all vmlinux vmlinux-tmp
+	gzip -9 vmlinux-tmp
+	mv vmlinux-tmp.gz vmlinux.gz
+
 rawboot:
 	@$(MAKEBOOT) rawboot
 
@@ -120,8 +125,6 @@
 	@$(MAKEBOOT) srmboot
 
 archclean:
-	@$(MAKE) -C arch/$(ARCH)/kernel clean
-	@$(MAKE) -C arch/$(ARCH)/tools clean
 	@$(MAKEBOOT) clean
 
 archmrproper:
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/boot/bootloader.c linux/arch/ia64/boot/bootloader.c
--- v2.4.3/linux/arch/ia64/boot/bootloader.c	Mon Oct  9 17:54:53 2000
+++ linux/arch/ia64/boot/bootloader.c	Thu Apr  5 12:51:47 2001
@@ -3,8 +3,8 @@
  *
  * Loads an ELF kernel.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
  * 01/07/99 S.Eranian modified to pass command line arguments to kernel
@@ -65,35 +65,22 @@
 	}
 }
 
-void
-enter_virtual_mode (unsigned long new_psr)
-{
-	long tmp;
-
-	asm volatile ("movl %0=1f" : "=r"(tmp));
-	asm volatile ("mov cr.ipsr=%0" :: "r"(new_psr));
-	asm volatile ("mov cr.iip=%0" :: "r"(tmp));
-	asm volatile ("mov cr.ifs=r0");
-	asm volatile ("rfi;;");
-	asm volatile ("1:");
-}
-
 #define MAX_ARGS 32
 
 void
 _start (void)
 {
-	register long sp asm ("sp");
 	static char stack[16384] __attribute__ ((aligned (16)));
 	static char mem[4096];
 	static char buffer[1024];
-	unsigned long flags, off;
+	unsigned long off;
 	int fd, i;
 	struct disk_req req;
 	struct disk_stat stat;
 	struct elfhdr *elf;
 	struct elf_phdr *elf_phdr;	/* program header */
 	unsigned long e_entry, e_phoff, e_phnum;
+	register struct ia64_boot_param *bp;
 	char *kpath, *args;
 	long arglen = 0;
 
@@ -107,15 +94,13 @@
 	ssc(0, 0, 0, 0, SSC_CONSOLE_INIT);
 
 	/*
-	 * S.Eranian: extract the commandline argument from the 
-	 * simulator
+	 * S.Eranian: extract the commandline argument from the simulator
 	 *
 	 * The expected format is as follows:
          *
 	 *	kernelname args...
 	 *
-	 * Both are optional but you can't have the second one without the 
-	 * first.
+	 * Both are optional but you can't have the second one without the first.
 	 */
 	arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS);
 
@@ -183,6 +168,10 @@
 		e_phoff += sizeof(*elf_phdr);
 
 		elf_phdr = (struct elf_phdr *) mem;
+
+		if (elf_phdr->p_type != PT_LOAD)
+			continue;
+
 		req.len = elf_phdr->p_filesz;
 		req.addr = __pa(elf_phdr->p_vaddr);
 		ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ);
@@ -197,38 +186,12 @@
 	/* fake an I/O base address: */
 	asm volatile ("mov ar.k0=%0" :: "r"(0xffffc000000UL));
 
-	/*
-	 * Install a translation register that identity maps the
-	 * kernel's 256MB page.
-	 */
-	ia64_clear_ic(flags);
-	ia64_set_rr(          0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2));
-	ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2));
-	ia64_srlz_d();
-	ia64_itr(0x3, 0, 1024*1024,
-		 pte_val(mk_pte_phys(1024*1024, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))),
-		 _PAGE_SIZE_1M);
-	ia64_itr(0x3, 1, PAGE_OFFSET,
-		 pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))),
-		 _PAGE_SIZE_256M);
-	ia64_srlz_i();
-
-	enter_virtual_mode(flags | IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT
-			   | IA64_PSR_DFH | IA64_PSR_BN);
-
-	sys_fw_init(args, arglen);
+	bp = sys_fw_init(args, arglen);
 
 	ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
 
-	/*
-	 * Install the kernel's command line argument on ZERO_PAGE
-	 * just after the botoparam structure.
-	 * In case we don't have any argument just put \0
-	 */
-	memcpy(((struct ia64_boot_param *)ZERO_PAGE_ADDR) + 1, args, arglen);
-	sp = __pa(&stack);
-
-	asm volatile ("br.sptk.few %0" :: "b"(e_entry));
+	asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0"
+		      :: "b"(e_entry), "r"(bp), "r"(__pa(&stack)));
 
 	cons_write("kernel returned!\n");
 	ssc(-1, 0, 0, 0, SSC_EXIT);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.4.3/linux/arch/ia64/config.in	Fri Feb 16 15:53:08 2001
+++ linux/arch/ia64/config.in	Tue Apr 17 17:19:24 2001
@@ -23,6 +23,12 @@
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_SBUS n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
+choice 'IA-64 processor type' \
+	"Itanium			CONFIG_ITANIUM \
+	 McKinley			CONFIG_MCKINLEY" Itanium
 
 choice 'IA-64 system type'					\
 	"generic		CONFIG_IA64_GENERIC		\
@@ -36,24 +42,47 @@
 	 16KB			CONFIG_IA64_PAGE_SIZE_16KB		\
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
 
-if [ "$CONFIG_IA64_DIG" = "y" ]; then
-	define_bool CONFIG_ITANIUM y
+if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
 	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
 	  bool '   Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
+        fi
+	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
 	  bool '   Enable Itanium B1-step specific code' CONFIG_ITANIUM_B1_SPECIFIC
+	fi
+	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
 	  bool '   Enable Itanium B2-step specific code' CONFIG_ITANIUM_B2_SPECIFIC
 	fi
 	bool '  Enable Itanium C-step specific code' CONFIG_ITANIUM_CSTEP_SPECIFIC
 	if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then
 	  bool '   Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC
 	fi
+	if [ "$CONFIG_ITANIUM_ASTEP_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \
+	     -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then
+	  define_bool CONFIG_ITANIUM_PTCG n
+	else
+	  define_bool CONFIG_ITANIUM_PTCG y
+	fi
+	if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
+	  define_int CONFIG_IA64_L1_CACHE_SHIFT 7 # align cache-sensitive data to 128 bytes
+	else
+	  define_int CONFIG_IA64_L1_CACHE_SHIFT 6 # align cache-sensitive data to 64 bytes
+	fi
+fi
+
+if [ "$CONFIG_MCKINLEY" = "y" ]; then
+	define_bool CONFIG_ITANIUM_PTCG y
+	define_int CONFIG_IA64_L1_CACHE_SHIFT 7
+	bool '  Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC
+	if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then
+	  bool '   Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC
+	fi
+fi
+
+if [ "$CONFIG_IA64_DIG" = "y" ]; then
 	bool '  Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR
-	bool '  Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG
-	bool '  Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS
-	bool '  Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS
 	bool '  Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
 	bool '  Enable ACPI 2.0 with errata 1.3' CONFIG_ACPI20
 	bool '  ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG
@@ -65,11 +94,6 @@
 fi
 
 if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
-	bool '  Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG
-	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
-	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
-	  bool '    Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
-	fi
 	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM
 	define_bool CONFIG_DEVFS_DEBUG y
 	define_bool CONFIG_DEVFS_FS y
@@ -87,7 +111,8 @@
 
 bool 'SMP support' CONFIG_SMP
 bool 'Performance monitor support' CONFIG_PERFMON
-bool '/proc/pal support' CONFIG_IA64_PALINFO
+tristate '/proc/pal support' CONFIG_IA64_PALINFO
+tristate '/proc/efi support' CONFIG_IA64_EFIVARS
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -253,7 +278,6 @@
 bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
 bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
 bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS
-bool 'Enable new unwind support' CONFIG_IA64_NEW_UNWIND
 bool 'Disable VHPT' CONFIG_DISABLE_VHPT
 
 endmenu
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c
--- v2.4.3/linux/arch/ia64/dig/setup.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/dig/setup.c	Thu Apr  5 12:51:47 2001
@@ -1,9 +1,9 @@
 /*
- * Platform dependent support for Intel SoftSDV simulator.
+ * Platform dependent support for DIG64 platforms.
  *
  * Copyright (C) 1999 Intel Corp.
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
@@ -48,18 +48,14 @@
 	 */
 	ROOT_DEV = to_kdev_t(0x0802);		/* default to second partition on first drive */
 
-#ifdef	CONFIG_IA64_SOFTSDV_HACKS
-	ROOT_DEV = to_kdev_t(0x0302);		/* 2nd partion on 1st IDE */
-#endif /* CONFIG_IA64_SOFTSDV_HACKS */
-
 #ifdef CONFIG_SMP
 	init_smp_config();
 #endif
 
 	memset(&screen_info, 0, sizeof(screen_info));
 
-	if (!ia64_boot_param.console_info.num_rows
-	    || !ia64_boot_param.console_info.num_cols)
+	if (!ia64_boot_param->console_info.num_rows
+	    || !ia64_boot_param->console_info.num_cols)
 	{
 		printk("dig_setup: warning: invalid screen-info, guessing 80x25\n");
 		orig_x = 0;
@@ -68,10 +64,10 @@
 		num_rows = 25;
 		font_height = 16;
 	} else {
-		orig_x = ia64_boot_param.console_info.orig_x;
-		orig_y = ia64_boot_param.console_info.orig_y;
-		num_cols = ia64_boot_param.console_info.num_cols;
-		num_rows = ia64_boot_param.console_info.num_rows;
+		orig_x = ia64_boot_param->console_info.orig_x;
+		orig_y = ia64_boot_param->console_info.orig_y;
+		num_cols = ia64_boot_param->console_info.num_cols;
+		num_rows = ia64_boot_param->console_info.num_rows;
 		font_height = 400 / num_rows;
 	}
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/hp/hpsim_irq.c linux/arch/ia64/hp/hpsim_irq.c
--- v2.4.3/linux/arch/ia64/hp/hpsim_irq.c	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/hp/hpsim_irq.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Platform dependent support for HP simulator.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/init.h>
@@ -35,10 +35,12 @@
 void __init
 hpsim_irq_init (void)
 {
+	irq_desc_t *idesc;
 	int i;
 
-	for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) {
-		if (irq_desc[i].handler == &no_irq_type)
-			irq_desc[i].handler = &irq_type_hp_sim;
+	for (i = 0; i < NR_IRQS; ++i) {
+		idesc = irq_desc(i);
+		if (idesc->handler == &no_irq_type)
+			idesc->handler = &irq_type_hp_sim;
 	}
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c
--- v2.4.3/linux/arch/ia64/ia32/binfmt_elf32.c	Thu Mar 22 09:24:58 2001
+++ linux/arch/ia64/ia32/binfmt_elf32.c	Thu Apr  5 12:51:47 2001
@@ -57,28 +57,30 @@
 
 	if (page_count(page) != 1)
 		printk("mem_map disagrees with %p at %08lx\n", (void *) page, address);
+
 	pgd = pgd_offset(tsk->mm, address);
-	pmd = pmd_alloc(pgd, address);
-	if (!pmd) {
-		__free_page(page);
-		force_sig(SIGKILL, tsk);
-		return 0;
-	}
-	pte = pte_alloc(pmd, address);
-	if (!pte) {
-		__free_page(page);
-		force_sig(SIGKILL, tsk);
-		return 0;
-	}
-	if (!pte_none(*pte)) {
-		pte_ERROR(*pte);
-		__free_page(page);
-		return 0;
+
+	spin_lock(&tsk->mm->page_table_lock);
+	{
+		pmd = pmd_alloc(tsk->mm, pgd, address);
+		if (!pmd)
+			goto out;
+		pte = pte_alloc(tsk->mm, pmd, address);
+		if (!pte)
+			goto out;
+		if (!pte_none(*pte))
+			goto out;
+		flush_page_to_ram(page);
+		set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED)));
 	}
-	flush_page_to_ram(page);
-	set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED)));
+	spin_unlock(&tsk->mm->page_table_lock);
 	/* no need for flush_tlb */
 	return page;
+
+  out:
+	spin_unlock(&tsk->mm->page_table_lock);
+	__free_page(page);
+	return 0;
 }
 
 void ia64_elf32_init(struct pt_regs *regs)
@@ -90,12 +92,13 @@
 		put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE);
 
 	nr = smp_processor_id();
-	
+
 	/* Do all the IA-32 setup here */
 
-	current->thread.map_base  =  0x40000000;
-	current->thread.task_size =  0xc0000000;	/* use what Linux/x86 uses... */
- 
+	current->thread.map_base  = 0x40000000;
+	current->thread.task_size = 0xc0000000;		/* use what Linux/x86 uses... */
+	set_fs(USER_DS);				/* set addr limit for new TASK_SIZE */
+
 	/* setup ia32 state for ia32_load_state */
 
 	current->thread.eflag = IA32_EFLAG;
@@ -124,14 +127,8 @@
 		: "r" ((ulong)IA32_FCR_DEFAULT));
 	__asm__("mov ar.fir = r0");
 	__asm__("mov ar.fdr = r0");
-	__asm__("mov %0=ar.k0 ;;" : "=r" (current->thread.old_iob));
-	__asm__("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE));
-	/* TSS */
-	__asm__("mov ar.k1 = %0"
-		: /* no outputs */
-		: "r" IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE,
-					  0x1FFFL, 0xBL, 1L,
-					  3L, 1L, 1L, 1L));
+	current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
+	ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
 
 	/* Get the segment selectors right */
 	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
@@ -149,23 +146,10 @@
 	regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L,
 					1L, 1L, 1L);
 
-       	/* Clear psr.ac */
+	/* Clear psr.ac */
 	regs->cr_ipsr &= ~IA64_PSR_AC;
 
 	regs->loadrs = 0;
-	/*
-	 *  According to the ABI %edx points to an `atexit' handler.
-	 *  Since we don't have one we'll set it to 0 and initialize
-	 *  all the other registers just to make things more deterministic,
-	 *  ala the i386 implementation.
-	 */
-	regs->r8 = 0;	/* %eax */
-	regs->r11 = 0;	/* %ebx */
-	regs->r9 = 0;	/* %ecx */
-	regs->r10 = 0;	/* %edx */
-	regs->r13 = 0;	/* %ebp */
-	regs->r14 = 0;	/* %esi */
-	regs->r15 = 0;	/* %edi */
 }
 
 #undef STACK_TOP
@@ -185,9 +169,9 @@
 	bprm->exec += stack_base;
 
 	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!mpnt) 
-		return -ENOMEM; 
-	
+	if (!mpnt)
+		return -ENOMEM;
+
 	{
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -200,7 +184,7 @@
 		mpnt->vm_private_data = 0;
 		insert_vm_struct(current->mm, mpnt);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-	} 
+	}
 
 	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
 		if (bprm->page[i]) {
@@ -208,7 +192,7 @@
 		}
 		stack_base += PAGE_SIZE;
 	}
-	
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S
--- v2.4.3/linux/arch/ia64/ia32/ia32_entry.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/ia32/ia32_entry.S	Thu Apr  5 12:51:47 2001
@@ -4,11 +4,34 @@
 
 #include "../kernel/entry.h"
 
+	/*
+	 * execve() is special because in case of success, we need to
+	 * setup a null register window frame (in case an IA-32 process
+	 * is exec'ing an IA-64 program).
+	 */
+ENTRY(ia32_execve)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)
+	alloc loc1=ar.pfs,3,2,4,0
+	mov loc0=rp
+	.body
+	mov out0=in0			// filename
+	;;				// stop bit between alloc and call
+	mov out1=in1			// argv
+	mov out2=in2			// envp
+	add out3=16,sp			// regs
+	br.call.sptk.few rp=sys32_execve
+1:	cmp4.ge p6,p0=r8,r0
+	mov ar.pfs=loc1			// restore ar.pfs
+	;;
+(p6)	mov ar.pfs=r0			// clear ar.pfs in case of success
+	sxt4 r8=r8			// return 64-bit result
+	mov rp=loc0
+	br.ret.sptk.few rp
+END(ia32_execve)
+
 	//
 	// Get possibly unaligned sigmask argument into an aligned
 	//   kernel buffer
-	.text
-
 GLOBAL_ENTRY(ia32_rt_sigsuspend)
 	// We'll cheat and not do an alloc here since we are ultimately
 	// going to do a simple branch to the IA64 sys_rt_sigsuspend.
@@ -16,38 +39,30 @@
 	// We copy this 4-byte aligned value to an 8-byte aligned buffer
 	// in the task structure and then jump to the IA64 code.
 
-	mov r8=r0		// no memory access errors yet
-	add r10=4,r32
-	;;
-1:
-	ld4 r2=[r32]		// get first half of sigmask
-	ld4 r3=[r10]		// get second half of sigmask
-2:
-	cmp.lt p6,p0=r8,r0	// check memory access
+	EX(.Lfail, ld4 r2=[r32],4)		// load low part of sigmask
 	;;
-(p6)	br.ret.sptk.many rp	//   it failed
-
+	EX(.Lfail, ld4 r3=[r32])		// load high part of sigmask
 	adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13
+	;;
+	st8 [r32]=r2
 	adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13
 	;;
-	st4 [r32]=r2
+
 	st4 [r10]=r3
 	br.cond.sptk.many sys_rt_sigsuspend
-END(ia32_rt_sigsuspend)
 
-	.section __ex_table,"a"
-	data4 @gprel(1b)
-	data4 (2b-1b)|1
-	.previous
+.Lfail:	br.ret.sptk.many rp	// failed to read sigmask
+END(ia32_rt_sigsuspend)
 
 GLOBAL_ENTRY(ia32_ret_from_syscall)
 	PT_REGS_UNWIND_INFO(0)
 
 	cmp.ge p6,p7=r8,r0                      // syscall executed successfully?
 	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp    // r2 = &pt_regs.r8
-	;; 
+	;;
+	alloc r3=ar.pfs,0,0,0,0			// drop the syscall argument frame
 	st8 [r2]=r8                             // store return value in slot for r8
-	br.cond.sptk.few ia64_leave_kernel
+	br.cond.sptk.many ia64_leave_kernel
 END(ia32_ret_from_syscall)
 
 	//
@@ -69,7 +84,8 @@
 	;;
 	st8.spill [r2]=r8			// store return value in slot for r8
 	br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value
-.ret2:	br.cond.sptk.many ia64_leave_kernel	// rp MUST be != ia64_leave_kernel!
+.ret2:	alloc r2=ar.pfs,0,0,0,0			// drop the syscall argument frame
+	br.cond.sptk.many ia64_leave_kernel	// rp MUST be != ia64_leave_kernel!
 END(ia32_trace_syscall)
 
 GLOBAL_ENTRY(sys32_vfork)
@@ -79,7 +95,7 @@
 END(sys32_vfork)
 
 GLOBAL_ENTRY(sys32_fork)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
 	alloc r16=ar.pfs,2,2,4,0
 	mov out0=SIGCHLD			// out0 = clone_flags
 	;;
@@ -88,14 +104,14 @@
 	mov loc1=r16				// save ar.pfs across do_fork
 	DO_SAVE_SWITCH_STACK
 
-	UNW(.body)
+	.body
 
 	mov out1=0
 	mov out3=0
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
 	br.call.sptk.few rp=do_fork
 .ret3:	mov ar.pfs=loc1
-	UNW(.restore sp)
+	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
 	mov rp=loc0
 	br.ret.sptk.many rp
@@ -104,7 +120,7 @@
 	.rodata
 	.align 8
 	.globl ia32_syscall_table
-ia32_syscall_table:	
+ia32_syscall_table:
 	data8 sys32_ni_syscall	  /* 0	-  old "setup(" system call*/
 	data8 sys_exit
 	data8 sys32_fork
@@ -116,7 +132,7 @@
 	data8 sys_creat
 	data8 sys_link
 	data8 sys_unlink	  /* 10 */
-	data8 sys32_execve
+	data8 ia32_execve
 	data8 sys_chdir
 	data8 sys32_time
 	data8 sys_mknod
@@ -133,8 +149,8 @@
 	data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */  /* 25 */
 	data8 sys32_ptrace
 	data8 sys32_alarm
-	data8 sys_pause
 	data8 sys32_ni_syscall
+	data8 sys_pause
 	data8 ia32_utime	  /* 30 */
 	data8 sys32_ni_syscall	  /* old stty syscall holder */
 	data8 sys32_ni_syscall	  /* old gtty syscall holder */
@@ -153,7 +169,7 @@
 	data8 sys_brk		  /* 45 */
 	data8 sys_setgid
 	data8 sys_getgid
-	data8 sys32_ni_syscall
+	data8 sys32_signal
 	data8 sys_geteuid
 	data8 sys_getegid	  /* 50 */
 	data8 sys_acct
@@ -227,7 +243,7 @@
 	data8 sys32_sigreturn
 	data8 sys_clone		  /* 120 */
 	data8 sys_setdomainname
-	data8 sys_newuname
+	data8 sys32_newuname
 	data8 sys_modify_ldt
 	data8 sys_adjtimex
 	data8 sys32_mprotect	  /* 125 */
@@ -249,12 +265,12 @@
 	data8 sys32_getdents
 	data8 sys32_select
 	data8 sys_flock
-	data8 sys_msync
+	data8 sys32_msync
 	data8 sys32_readv	  /* 145 */
 	data8 sys32_writev
 	data8 sys_getsid
 	data8 sys_fdatasync
-	data8 sys_sysctl
+	data8 sys32_sysctl
 	data8 sys_mlock		  /* 150 */
 	data8 sys_munlock
 	data8 sys_mlockall
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c
--- v2.4.3/linux/arch/ia64/ia32/ia32_support.c	Mon Oct  9 17:54:53 2000
+++ linux/arch/ia64/ia32/ia32_support.c	Thu Apr  5 12:51:47 2001
@@ -2,6 +2,7 @@
  * IA32 helper functions
  *
  * 06/16/00	A. Mallick	added csd/ssd/tssd for ia32 thread context
+ * 02/19/01	D. Mosberger	dropped tssd; it's not needed
  */
 
 #include <linux/kernel.h>
@@ -22,7 +23,7 @@
 void
 ia32_save_state (struct thread_struct *thread)
 {
-	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd;
+	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
 
 	asm ("mov %0=ar.eflag;"
 	     "mov %1=ar.fsr;"
@@ -31,9 +32,7 @@
 	     "mov %4=ar.fdr;"
 	     "mov %5=ar.csd;"
 	     "mov %6=ar.ssd;"
-	     "mov %7=ar.k1"
-	     : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr),
-	       "=r"(csd), "=r"(ssd), "=r"(tssd));
+	     : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd));
 	thread->eflag = eflag;
 	thread->fsr = fsr;
 	thread->fcr = fcr;
@@ -41,14 +40,13 @@
 	thread->fdr = fdr;
 	thread->csd = csd;
 	thread->ssd = ssd;
-	thread->tssd = tssd;
 	asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob));
 }
 
 void
 ia32_load_state (struct thread_struct *thread)
 {
-	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd;
+	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
 
 	eflag = thread->eflag;
 	fsr = thread->fsr;
@@ -57,7 +55,6 @@
 	fdr = thread->fdr;
 	csd = thread->csd;
 	ssd = thread->ssd;
-	tssd = thread->tssd;
 
 	asm volatile ("mov ar.eflag=%0;"
 		      "mov ar.fsr=%1;"
@@ -66,9 +63,7 @@
 		      "mov ar.fdr=%4;"
 		      "mov ar.csd=%5;"
 		      "mov ar.ssd=%6;"
-		      "mov ar.k1=%7"
-		      :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr),
-		         "r"(csd), "r"(ssd), "r"(tssd));
+		      :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd));
 	asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob));
 	asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE));
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- v2.4.3/linux/arch/ia64/ia32/sys_ia32.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/ia64/ia32/sys_ia32.c	Thu Apr  5 12:51:47 2001
@@ -1,12 +1,12 @@
 /*
  * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
- *             sys_sparc32 
+ *             sys_sparc32
  *
  * Copyright (C) 2000		VA Linux Co
  * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
- * Copyright (C) 1999 		Arun Sharma <arun.sharma@intel.com>
- * Copyright (C) 1997,1998 	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 2000		Hewlett-Packard Co.
  * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
  *
@@ -16,9 +16,10 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/sysctl.h>
 #include <linux/sched.h>
-#include <linux/fs.h> 
-#include <linux/file.h> 
+#include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/signal.h>
 #include <linux/utime.h>
 #include <linux/resource.h>
@@ -64,96 +65,87 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 
 extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);
-extern asmlinkage long sys_munmap (unsigned long, size_t len);
 extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);
 
 static int
-nargs(unsigned int arg, char **ap)
+nargs (unsigned int arg, char **ap)
 {
 	int n, err, addr;
 
+	if (!arg)
+		return 0;
+
 	n = 0;
 	do {
 		err = get_user(addr, (int *)A(arg));
 		if (err)
 			return err;
-		if (ap) {		/* no access_ok needed, we allocated */
-			err = __put_user((char *)A(addr), ap++);
-			if (err)
-				return err;
-		}
+		if (ap)
+			*ap++ = (char *) A(addr);
 		arg += sizeof(unsigned int);
 		n++;
 	} while (addr);
-	return(n - 1);
+	return n - 1;
 }
 
 asmlinkage long
-sys32_execve(
-char *filename,
-unsigned int argv,
-unsigned int envp,
-int dummy3,
-int dummy4,
-int dummy5,
-int dummy6,
-int dummy7,
-int stack)
+sys32_execve (char *filename, unsigned int argv, unsigned int envp,
+	      int dummy3, int dummy4, int dummy5, int dummy6, int dummy7,
+	      int stack)
 {
 	struct pt_regs *regs = (struct pt_regs *)&stack;
+	unsigned long old_map_base, old_task_size;
 	char **av, **ae;
 	int na, ne, len;
 	long r;
 
 	na = nargs(argv, NULL);
 	if (na < 0)
-		return(na);
+		return na;
 	ne = nargs(envp, NULL);
 	if (ne < 0)
-		return(ne);
+		return ne;
 	len = (na + ne + 2) * sizeof(*av);
-	/*
-	 *  kmalloc won't work because the `sys_exec' code will attempt
-	 *  to do a `get_user' on the arg list and `get_user' will fail
-	 *  on a kernel address (simplifies `get_user').  Instead we
-	 *  do an mmap to get a user address.  Note that since a successful
-	 *  `execve' frees all current memory we only have to do an
-	 *  `munmap' if the `execve' failes.
-	 */
-	down_write(&current->mm->mmap_sem);
-
-	av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE,
-				     MAP_PRIVATE | MAP_ANONYMOUS, 0);
-
-	up_write(&current->mm->mmap_sem);
+	av = kmalloc(len, GFP_KERNEL);
+	if (!av)
+		return -ENOMEM;
 
-	if (IS_ERR(av))
-		return (long)av;
 	ae = av + na + 1;
-	r = __put_user(0, (av + na));
-	if (r)
-		goto out;
-	r = __put_user(0, (ae + ne));
-	if (r)
-		goto out;
+	av[na] = NULL;
+	ae[ne] = NULL;
+
 	r = nargs(argv, av);
 	if (r < 0)
 		goto out;
 	r = nargs(envp, ae);
 	if (r < 0)
 		goto out;
+
+	old_map_base  = current->thread.map_base;
+	old_task_size = current->thread.task_size;
+
+	/* we may be exec'ing a 64-bit process: reset map base & task-size: */
+	current->thread.map_base  = DEFAULT_MAP_BASE;
+	current->thread.task_size = DEFAULT_TASK_SIZE;
+
+	set_fs(KERNEL_DS);
 	r = sys_execve(filename, av, ae, regs);
-	if (r < 0)
-out:
-		sys_munmap((unsigned long) av, len);
-	return(r);
+	if (r < 0) {
+		/* oops, execve failed, switch back to old map base & task-size: */
+		current->thread.map_base  = old_map_base;
+		current->thread.task_size = old_task_size;
+		set_fs(USER_DS);	/* establish new task-size as the address-limit */
+	  out:
+		kfree(av);
+	}
+	return r;
 }
 
 static inline int
 putstat(struct stat32 *ubuf, struct stat *kbuf)
 {
 	int err;
-	
+
 	err = put_user (kbuf->st_dev, &ubuf->st_dev);
 	err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
 	err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
@@ -178,8 +170,8 @@
 	int ret;
 	struct stat s;
 	mm_segment_t old_fs = get_fs();
-	
-	set_fs (KERNEL_DS);
+
+	set_fs(KERNEL_DS);
 	ret = sys_newstat(filename, &s);
 	set_fs (old_fs);
 	if (putstat (statbuf, &s))
@@ -195,7 +187,7 @@
 	int ret;
 	struct stat s;
 	mm_segment_t old_fs = get_fs();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_newlstat(filename, &s);
 	set_fs (old_fs);
@@ -212,7 +204,7 @@
 	int ret;
 	struct stat s;
 	mm_segment_t old_fs = get_fs();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_newfstat(fd, &s);
 	set_fs (old_fs);
@@ -221,7 +213,6 @@
 	return ret;
 }
 
-#define ALIGN4K(a)	(((a) + 0xfff) & ~0xfff)
 #define OFFSET4K(a)	((a) & 0xfff)
 
 unsigned long
@@ -287,19 +278,19 @@
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	prot |= PROT_EXEC;
 
- 	if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK)))
- 		error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset);
+	if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK)))
+		error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset);
 	else {
- 		poff = offset & PAGE_MASK;
- 		len += offset - poff;
+		poff = offset & PAGE_MASK;
+		len += offset - poff;
+
+		down_write(&current->mm->mmap_sem);
+		error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT);
+		up_write(&current->mm->mmap_sem);
 
- 		down_write(&current->mm->mmap_sem);
- 		error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT);
-  		up_write(&current->mm->mmap_sem);
-
- 		if (!IS_ERR((void *) error))
- 			error += offset - poff;
- 	}
+		if (!IS_ERR((void *) error))
+			error += offset - poff;
+	}
 	return error;
 }
 
@@ -328,18 +319,46 @@
 	if (copy_from_user(&a, arg, sizeof(a)))
 		return -EFAULT;
 
+	if (PAGE_ALIGN(a.len) == 0)
+		return a.addr;
+
 	if (!(a.flags & MAP_ANONYMOUS)) {
 		file = fget(a.fd);
 		if (!file)
 			return -EBADF;
 	}
+#ifdef	CONFIG_IA64_PAGE_SIZE_4KB
+	if ((a.offset & ~PAGE_MASK) != 0)
+		return -EINVAL;
+
+	down_write(&current->mm->mmap_sem);
+	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT);
+	up_write(&current->mm->mmap_sem);
+#else	// CONFIG_IA64_PAGE_SIZE_4KB
 	retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+#endif	// CONFIG_IA64_PAGE_SIZE_4KB
 	if (file)
 		fput(file);
 	return retval;
 }
 
 asmlinkage long
+sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+{
+
+#ifdef	CONFIG_IA64_PAGE_SIZE_4KB
+	return(sys_mprotect(start, len, prot));
+#else	// CONFIG_IA64_PAGE_SIZE_4KB
+	if (prot == 0)
+		return(0);
+	len += start & ~PAGE_MASK;
+	if ((start & ~PAGE_MASK) && (prot & PROT_WRITE))
+		prot |= PROT_EXEC;
+	return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot));
+#endif	// CONFIG_IA64_PAGE_SIZE_4KB
+}
+
+asmlinkage long
 sys32_pipe(int *fd)
 {
 	int retval;
@@ -355,15 +374,17 @@
 }
 
 asmlinkage long
-sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+sys32_signal (int sig, unsigned int handler)
 {
+	struct k_sigaction new_sa, old_sa;
+	int ret;
 
-	if (prot == 0)
-		return(0);
-	len += start & ~PAGE_MASK;
-	if ((start & ~PAGE_MASK) && (prot & PROT_WRITE))
-		prot |= PROT_EXEC;
-	return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot));
+	new_sa.sa.sa_handler = (__sighandler_t) A(handler);
+	new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+
+	ret = do_sigaction(sig, &new_sa, &old_sa);
+
+	return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
 }
 
 asmlinkage long
@@ -393,7 +414,7 @@
 				| (((long)set32.sig[1]) << 32);
 		}
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		
+
 		if (ret)
 			return -EFAULT;
 	}
@@ -436,7 +457,7 @@
 	sigset32_t s32;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-	
+
 	if (set) {
 		if (copy_from_user (&s32, set, sizeof(sigset32_t)))
 			return -EFAULT;
@@ -449,7 +470,7 @@
 	}
 	set_fs (KERNEL_DS);
 	ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL,
-				 sigsetsize); 
+				 sigsetsize);
 	set_fs (old_fs);
 	if (ret) return ret;
 	if (oset) {
@@ -469,7 +490,7 @@
 put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
-	
+
 	err = put_user (kbuf->f_type, &ubuf->f_type);
 	err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
 	err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
@@ -491,7 +512,7 @@
 	int ret;
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_statfs((const char *)path, &s);
 	set_fs (old_fs);
@@ -508,7 +529,7 @@
 	int ret;
 	struct statfs s;
 	mm_segment_t old_fs = get_fs();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_fstatfs(fd, &s);
 	set_fs (old_fs);
@@ -534,7 +555,6 @@
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 		(__get_user(o->tv_sec, &i->tv_sec) |
 		 __get_user(o->tv_usec, &i->tv_usec)));
-	return ENOSYS;
 }
 
 static inline long
@@ -553,18 +573,16 @@
 		 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
 		 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
 		 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
-	return ENOSYS;
 }
 
 static inline long
 put_it32(struct itimerval32 *o, struct itimerval *i)
 {
-	return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
 		 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
 		 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
 		 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
-	return ENOSYS;
 }
 
 extern int do_getitimer(int which, struct itimerval *value);
@@ -605,7 +623,7 @@
 	return 0;
 
 }
-asmlinkage unsigned long 
+asmlinkage unsigned long
 sys32_alarm(unsigned int seconds)
 {
 	struct itimerval it_new, it_old;
@@ -638,7 +656,7 @@
 ia32_utime(char * filename, struct utimbuf_32 *times32)
 {
 	mm_segment_t old_fs = get_fs();
-	struct timeval tv[2];
+	struct timeval tv[2], *tvp;
 	long ret;
 
 	if (times32) {
@@ -647,15 +665,10 @@
 		get_user(tv[1].tv_sec, &times32->mtime);
 		tv[1].tv_usec = 0;
 		set_fs (KERNEL_DS);
-	} else {
-		set_fs (KERNEL_DS);
-		ret = sys_gettimeofday(&tv[0], 0);
-		if (ret < 0)
-			goto out;
-		tv[1] = tv[0];
-	}
-	ret = sys_utimes(filename, tv);
-  out:
+		tvp = tv;
+	} else
+		tvp = NULL;
+	ret = sys_utimes(filename, tvp);
 	set_fs (old_fs);
 	return ret;
 }
@@ -685,7 +698,7 @@
 	struct timeval ktv;
 	struct timezone ktz;
 
- 	if (tv) {
+	if (tv) {
 		if (get_tv32(&ktv, tv))
 			return -EFAULT;
 	}
@@ -872,7 +885,7 @@
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
 	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
+	 * long-words.
 	 */
 	ret = -ENOMEM;
 	size = FDS_BYTES(n);
@@ -946,11 +959,11 @@
 }
 
 struct timespec32 {
-	int 	tv_sec;
+	int	tv_sec;
 	int	tv_nsec;
 };
 
-extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); 
+extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
 
 asmlinkage long
 sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
@@ -958,7 +971,7 @@
 	struct timespec t;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	if (get_user (t.tv_sec, &rqtp->tv_sec) ||
 	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
 		return -EFAULT;
@@ -967,7 +980,7 @@
 	set_fs (old_fs);
 	if (rmtp && ret == -EINTR) {
 		if (__put_user (t.tv_sec, &rmtp->tv_sec) ||
-	    	    __put_user (t.tv_nsec, &rmtp->tv_nsec))
+		    __put_user (t.tv_nsec, &rmtp->tv_nsec))
 			return -EFAULT;
 	}
 	return ret;
@@ -1072,7 +1085,7 @@
 	struct rlimit r;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_getrlimit(resource, &r);
 	set_fs (old_fs);
@@ -1092,7 +1105,7 @@
 	int ret;
 	mm_segment_t old_fs = get_fs ();
 
-	if (resource >= RLIM_NLIMITS) return -EINVAL;	
+	if (resource >= RLIM_NLIMITS) return -EINVAL;
 	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
 	    __get_user (r.rlim_max, &rlim->rlim_max))
 		return -EFAULT;
@@ -1109,7 +1122,7 @@
 /*
  *  Declare the IA32 version of the msghdr
  */
- 
+
 struct msghdr32 {
 	unsigned int    msg_name;	/* Socket name			*/
 	int		msg_namelen;	/* Length of name		*/
@@ -1157,7 +1170,7 @@
 {
 	int size, err, ct;
 	struct iovec32 *iov32;
-	
+
 	if(m->msg_namelen)
 	{
 		if(mode==VERIFY_READ)
@@ -1166,7 +1179,7 @@
 			if(err<0)
 				goto out;
 		}
-		
+
 		m->msg_name = address;
 	} else
 		m->msg_name = NULL;
@@ -1195,7 +1208,7 @@
 }
 
 /* XXX This really belongs in some header file... -DaveM */
-#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain -
 					   16 for IP, 16 for IPX,
 					   24 for IPv6,
 					   about 80 for AX.25 */
@@ -1215,13 +1228,13 @@
 	unsigned char *ctl_buf = ctl;
 	struct msghdr msg_sys;
 	int err, ctl_len, iov_size, total_len;
-	
+
 	err = -EFAULT;
 	if (shape_msg(&msg_sys, msg))
-		goto out; 
+		goto out;
 
 	sock = sockfd_lookup(fd, &err);
-	if (!sock) 
+	if (!sock)
 		goto out;
 
 	/* do not move before msg_sys is valid */
@@ -1240,7 +1253,7 @@
 
 	/* This will also move the address data into kernel space */
 	err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ);
-	if (err < 0) 
+	if (err < 0)
 		goto out_freeiov;
 	total_len = err;
 
@@ -1248,14 +1261,14 @@
 
 	if (msg_sys.msg_controllen > INT_MAX)
 		goto out_freeiov;
-	ctl_len = msg_sys.msg_controllen; 
-	if (ctl_len) 
+	ctl_len = msg_sys.msg_controllen;
+	if (ctl_len)
 	{
 		if (ctl_len > sizeof(ctl))
 		{
 			err = -ENOBUFS;
 			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
-			if (ctl_buf == NULL) 
+			if (ctl_buf == NULL)
 				goto out_freeiov;
 		}
 		err = -EFAULT;
@@ -1270,14 +1283,14 @@
 	err = sock_sendmsg(sock, &msg_sys, total_len);
 
 out_freectl:
-	if (ctl_buf != ctl)    
+	if (ctl_buf != ctl)
 		sock_kfree_s(sock->sk, ctl_buf, ctl_len);
 out_freeiov:
 	if (iov != iovstack)
 		sock_kfree_s(sock->sk, iov, iov_size);
 out_put:
 	sockfd_put(sock);
-out:       
+out:
 	return err;
 }
 
@@ -1301,7 +1314,7 @@
 	/* user mode address pointers */
 	struct sockaddr *uaddr;
 	int *uaddr_len;
-	
+
 	err=-EFAULT;
 	if (shape_msg(&msg_sys, msg))
 		goto out;
@@ -1313,7 +1326,7 @@
 	err = -EINVAL;
 	if (msg_sys.msg_iovlen > UIO_MAXIOV)
 		goto out_put;
-	
+
 	/* Check whether to allocate the iovec area*/
 	err = -ENOMEM;
 	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
@@ -1327,7 +1340,7 @@
 	 *	Save the user-mode address (verify_iovec will change the
 	 *	kernel msghdr to use the kernel address space)
 	 */
-	 
+
 	uaddr = msg_sys.msg_name;
 	uaddr_len = &msg->msg_namelen;
 	err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE);
@@ -1337,7 +1350,7 @@
 
 	cmsg_ptr = (unsigned long)msg_sys.msg_control;
 	msg_sys.msg_flags = 0;
-	
+
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
 	err = sock_recvmsg(sock, &msg_sys, total_len, flags);
@@ -1353,7 +1366,7 @@
 	err = __put_user(msg_sys.msg_flags, &msg->msg_flags);
 	if (err)
 		goto out_freeiov;
-	err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, 
+	err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
 							 &msg->msg_controllen);
 	if (err)
 		goto out_freeiov;
@@ -1371,15 +1384,15 @@
 /* Argument list sizes for sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))
 static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
-                                AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
-                                AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+				AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
 #undef AL
 
 extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
 extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr,
 				  int addrlen);
 extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr,
-				 int *upeer_addrlen); 
+				 int *upeer_addrlen);
 extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr,
 				      int *usockaddr_len);
 extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr,
@@ -1406,15 +1419,15 @@
 	int ret;
 	u32 a[6];
 	u32 a0,a1;
-				 
+
 	if (call<SYS_SOCKET||call>SYS_RECVMSG)
 		return -EINVAL;
 	if (copy_from_user(a, args, nas[call]))
 		return -EFAULT;
 	a0=a[0];
 	a1=a[1];
-	
-	switch(call) 
+
+	switch(call)
 	{
 		case SYS_SOCKET:
 			ret = sys_socket(a0, a1, a[2]);
@@ -1490,52 +1503,52 @@
 
 struct ipc_perm32
 {
-	key_t    	  key;
-        __kernel_uid_t32  uid;
-        __kernel_gid_t32  gid;
-        __kernel_uid_t32  cuid;
-        __kernel_gid_t32  cgid;
-        __kernel_mode_t32 mode;
-        unsigned short  seq;
+	key_t	  key;
+	__kernel_uid_t32  uid;
+	__kernel_gid_t32  gid;
+	__kernel_uid_t32  cuid;
+	__kernel_gid_t32  cgid;
+	__kernel_mode_t32 mode;
+	unsigned short  seq;
 };
 
 struct semid_ds32 {
-        struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
-        __kernel_time_t32 sem_otime;              /* last semop time */
-        __kernel_time_t32 sem_ctime;              /* last change time */
-        u32 sem_base;              /* ptr to first semaphore in array */
-        u32 sem_pending;          /* pending operations to be processed */
-        u32 sem_pending_last;    /* last pending operation */
-        u32 undo;                  /* undo requests on this array */
-        unsigned short  sem_nsems;              /* no. of semaphores in array */
+	struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
+	__kernel_time_t32 sem_otime;              /* last semop time */
+	__kernel_time_t32 sem_ctime;              /* last change time */
+	u32 sem_base;              /* ptr to first semaphore in array */
+	u32 sem_pending;          /* pending operations to be processed */
+	u32 sem_pending_last;    /* last pending operation */
+	u32 undo;                  /* undo requests on this array */
+	unsigned short  sem_nsems;              /* no. of semaphores in array */
 };
 
 struct msqid_ds32
 {
-        struct ipc_perm32 msg_perm;
-        u32 msg_first;
-        u32 msg_last;
-        __kernel_time_t32 msg_stime;
-        __kernel_time_t32 msg_rtime;
-        __kernel_time_t32 msg_ctime;
-        u32 wwait;
-        u32 rwait;
-        unsigned short msg_cbytes;
-        unsigned short msg_qnum;  
-        unsigned short msg_qbytes;
-        __kernel_ipc_pid_t32 msg_lspid;
-        __kernel_ipc_pid_t32 msg_lrpid;
+	struct ipc_perm32 msg_perm;
+	u32 msg_first;
+	u32 msg_last;
+	__kernel_time_t32 msg_stime;
+	__kernel_time_t32 msg_rtime;
+	__kernel_time_t32 msg_ctime;
+	u32 wwait;
+	u32 rwait;
+	unsigned short msg_cbytes;
+	unsigned short msg_qnum;
+	unsigned short msg_qbytes;
+	__kernel_ipc_pid_t32 msg_lspid;
+	__kernel_ipc_pid_t32 msg_lrpid;
 };
 
 struct shmid_ds32 {
-        struct ipc_perm32       shm_perm;
-        int                     shm_segsz;
-        __kernel_time_t32       shm_atime;
-        __kernel_time_t32       shm_dtime;
-        __kernel_time_t32       shm_ctime;
-        __kernel_ipc_pid_t32    shm_cpid; 
-        __kernel_ipc_pid_t32    shm_lpid; 
-        unsigned short          shm_nattch;
+	struct ipc_perm32       shm_perm;
+	int                     shm_segsz;
+	__kernel_time_t32       shm_atime;
+	__kernel_time_t32       shm_dtime;
+	__kernel_time_t32       shm_ctime;
+	__kernel_ipc_pid_t32    shm_cpid;
+	__kernel_ipc_pid_t32    shm_lpid;
+	unsigned short          shm_nattch;
 };
 
 #define IPCOP_MASK(__x)	(1UL << (__x))
@@ -1876,7 +1889,7 @@
 		err = do_sys32_shmat (first, second, third,
 				      version, (void *)AA(ptr));
 		break;
-	case SHMDT: 
+	case SHMDT:
 		err = sys_shmdt ((char *)AA(ptr));
 		break;
 	case SHMGET:
@@ -1902,7 +1915,7 @@
 {
 	int i;
 
-	/* SMP: This is fairly trivial. We grab CURRENT_TIME and 
+	/* SMP: This is fairly trivial. We grab CURRENT_TIME and
 	   stuff it to user space. No side effects */
 	i = CURRENT_TIME;
 	if (tloc) {
@@ -1913,29 +1926,29 @@
 }
 
 struct rusage32 {
-        struct timeval32 ru_utime;
-        struct timeval32 ru_stime;
-        int    ru_maxrss;
-        int    ru_ixrss;
-        int    ru_idrss;
-        int    ru_isrss;
-        int    ru_minflt;
-        int    ru_majflt;
-        int    ru_nswap;
-        int    ru_inblock;
-        int    ru_oublock;
-        int    ru_msgsnd; 
-        int    ru_msgrcv; 
-        int    ru_nsignals;
-        int    ru_nvcsw;
-        int    ru_nivcsw;
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	int    ru_maxrss;
+	int    ru_ixrss;
+	int    ru_idrss;
+	int    ru_isrss;
+	int    ru_minflt;
+	int    ru_majflt;
+	int    ru_nswap;
+	int    ru_inblock;
+	int    ru_oublock;
+	int    ru_msgsnd;
+	int    ru_msgrcv;
+	int    ru_nsignals;
+	int    ru_nvcsw;
+	int    ru_nivcsw;
 };
 
 static int
 put_rusage (struct rusage32 *ru, struct rusage *r)
 {
 	int err;
-	
+
 	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
 	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
 	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
@@ -1968,7 +1981,7 @@
 		int ret;
 		unsigned int status;
 		mm_segment_t old_fs = get_fs();
-		
+
 		set_fs (KERNEL_DS);
 		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
 		set_fs (old_fs);
@@ -1995,7 +2008,7 @@
 	struct rusage r;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-		
+
 	set_fs (KERNEL_DS);
 	ret = sys_getrusage(who, &r);
 	set_fs (old_fs);
@@ -2009,7 +2022,7 @@
 	__kernel_clock_t32 tms_cutime;
 	__kernel_clock_t32 tms_cstime;
 };
-                                
+
 extern asmlinkage long sys_times(struct tms * tbuf);
 
 asmlinkage long
@@ -2019,7 +2032,7 @@
 	long ret;
 	mm_segment_t old_fs = get_fs ();
 	int err;
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_times(tbuf ? &t : NULL);
 	set_fs (old_fs);
@@ -2069,7 +2082,7 @@
 #define PT_GS	10
 #define PT_ORIG_EAX 11
 #define PT_EIP	12
-#define PT_CS 	13
+#define PT_CS	13
 #define PT_EFL	14
 #define PT_UESP	15
 #define PT_SS	16
@@ -2385,7 +2398,7 @@
 		break;
 
 	      case IA32_PTRACE_GETREGS:
-	  	if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) {
+		if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
@@ -2399,7 +2412,7 @@
 	      case IA32_PTRACE_SETREGS:
 	      {
 		unsigned int tmp;
-	  	if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) {
+		if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
@@ -2444,7 +2457,7 @@
 get_flock32(struct flock *kfl, struct flock32 *ufl)
 {
 	int err;
-	
+
 	err = get_user(kfl->l_type, &ufl->l_type);
 	err |= __get_user(kfl->l_whence, &ufl->l_whence);
 	err |= __get_user(kfl->l_start, &ufl->l_start);
@@ -2457,7 +2470,7 @@
 put_flock32(struct flock *kfl, struct flock32 *ufl)
 {
 	int err;
-	
+
 	err = __put_user(kfl->l_type, &ufl->l_type);
 	err |= __put_user(kfl->l_whence, &ufl->l_whence);
 	err |= __put_user(kfl->l_start, &ufl->l_start);
@@ -2480,7 +2493,7 @@
 	case F_GETLK:
 	case F_SETLK:
 	case F_SETLKW:
-		if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg)))
+		if(get_flock32(&f, (struct flock32 *)((long)arg)))
 			return -EFAULT;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
@@ -2501,27 +2514,27 @@
 asmlinkage long
 sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
 {
-        struct k_sigaction new_ka, old_ka;
-        int ret;
+	struct k_sigaction new_ka, old_ka;
+	int ret;
 
-        if (act) {
+	if (act) {
 		old_sigset32_t mask;
-		
+
 		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 		ret |= __get_user(mask, &act->sa_mask);
 		if (ret)
 			return ret;
 		siginitset(&new_ka.sa.sa_mask, mask);
-        }
+	}
 
-        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
 	if (!ret && oact) {
 		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
 		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-        }
+	}
 
 	return ret;
 }
@@ -2658,6 +2671,85 @@
 	return -ERESTARTNOHAND;
 }
 
+asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
+
+asmlinkage int
+sys32_msync(unsigned int start, unsigned int len, int flags)
+{
+	unsigned int addr;
+
+	if (OFFSET4K(start))
+		return -EINVAL;
+	addr = start & PAGE_MASK;
+	return(sys_msync(addr, len + (start - addr), flags));
+}
+
+struct sysctl_ia32 {
+	unsigned int	name;
+	int		nlen;
+	unsigned int	oldval;
+	unsigned int	oldlenp;
+	unsigned int	newval;
+	unsigned int	newlen;
+	unsigned int	__unused[4];
+};
+
+extern asmlinkage long sys_sysctl(struct __sysctl_args *args);
+
+asmlinkage long
+sys32_sysctl(struct sysctl_ia32 *args32)
+{
+	struct sysctl_ia32 a32;
+	mm_segment_t old_fs = get_fs ();
+	void *oldvalp, *newvalp;
+	size_t oldlen;
+	int *namep;
+	long ret;
+
+	if (copy_from_user(&a32, args32, sizeof (a32)))
+		return -EFAULT;
+
+	/*
+	 * We need to pre-validate these because we have to disable address checking
+	 * before calling do_sysctl() because of OLDLEN but we can't run the risk of the
+	 * user specifying bad addresses here.  Well, since we're dealing with 32 bit
+	 * addresses, we KNOW that access_ok() will always succeed, so this is an
+	 * expensive NOP, but so what...
+	 */
+	namep = (int *) A(a32.name);
+	oldvalp = (void *) A(a32.oldval);
+	newvalp = (void *) A(a32.newval);
+
+	if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp)))
+	    || !access_ok(VERIFY_WRITE, namep, 0)
+	    || !access_ok(VERIFY_WRITE, oldvalp, 0)
+	    || !access_ok(VERIFY_WRITE, newvalp, 0))
+		return -EFAULT;
+
+	set_fs(KERNEL_DS);
+	lock_kernel();
+	ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen);
+	unlock_kernel();
+	set_fs(old_fs);
+
+	if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp)))
+		return -EFAULT;
+
+	return ret;
+}
+
+asmlinkage long
+sys32_newuname(struct new_utsname * name)
+{
+	extern asmlinkage long sys_newuname(struct new_utsname * name);
+	int ret = sys_newuname(name);
+
+	if (!ret)
+		if (copy_to_user(name->machine, "i686\0\0\0", 8))
+			ret = -EFAULT;
+	return ret;
+}
+
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
 
 /* In order to reduce some races, while at the same time doing additional
@@ -2721,7 +2813,7 @@
     __kernel_time_t32 dqb_btime;
     __kernel_time_t32 dqb_itime;
 };
-                                
+
 extern asmlinkage long sys_quotactl(int cmd, const char *special, int id,
 				   caddr_t addr);
 
@@ -2733,7 +2825,7 @@
 	struct dqblk d;
 	mm_segment_t old_fs;
 	char *spec;
-	
+
 	switch (cmds) {
 	case Q_GETQUOTA:
 		break;
@@ -2782,7 +2874,7 @@
 	mm_segment_t old_fs;
 	int ret;
 	char *filenam;
-	
+
 	if (!times)
 		return sys_utime(filename, NULL);
 	if (get_user (t.actime, &times->actime) ||
@@ -2792,7 +2884,7 @@
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
 		old_fs = get_fs();
-		set_fs (KERNEL_DS); 
+		set_fs (KERNEL_DS);
 		ret = sys_utime(filenam, &t);
 		set_fs (old_fs);
 		putname (filenam);
@@ -2869,18 +2961,18 @@
 }
 
 struct ncp_mount_data32 {
-        int version;
-        unsigned int ncp_fd;
-        __kernel_uid_t32 mounted_uid;
-        __kernel_pid_t32 wdog_pid;
-        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
-        unsigned int time_out;
-        unsigned int retry_count;
-        unsigned int flags;
-        __kernel_uid_t32 uid;
-        __kernel_gid_t32 gid;
-        __kernel_mode_t32 file_mode;
-        __kernel_mode_t32 dir_mode;
+	int version;
+	unsigned int ncp_fd;
+	__kernel_uid_t32 mounted_uid;
+	__kernel_pid_t32 wdog_pid;
+	unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+	unsigned int time_out;
+	unsigned int retry_count;
+	unsigned int flags;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_mode_t32 file_mode;
+	__kernel_mode_t32 dir_mode;
 };
 
 static void *
@@ -2901,12 +2993,12 @@
 }
 
 struct smb_mount_data32 {
-        int version;
-        __kernel_uid_t32 mounted_uid;
-        __kernel_uid_t32 uid;
-        __kernel_gid_t32 gid;
-        __kernel_mode_t32 file_mode;
-        __kernel_mode_t32 dir_mode;
+	int version;
+	__kernel_uid_t32 mounted_uid;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_mode_t32 file_mode;
+	__kernel_mode_t32 dir_mode;
 };
 
 static void *
@@ -3020,16 +3112,16 @@
 }
 
 struct sysinfo32 {
-        s32 uptime;
-        u32 loads[3];
-        u32 totalram;
-        u32 freeram;
-        u32 sharedram;
-        u32 bufferram;
-        u32 totalswap;
-        u32 freeswap;
-        unsigned short procs;
-        char _f[22];
+	s32 uptime;
+	u32 loads[3];
+	u32 totalram;
+	u32 freeram;
+	u32 sharedram;
+	u32 bufferram;
+	u32 totalswap;
+	u32 freeswap;
+	unsigned short procs;
+	char _f[22];
 };
 
 extern asmlinkage long sys_sysinfo(struct sysinfo *info);
@@ -3040,7 +3132,7 @@
 	struct sysinfo s;
 	int ret, err;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_sysinfo(&s);
 	set_fs (old_fs);
@@ -3059,7 +3151,7 @@
 		return -EFAULT;
 	return ret;
 }
-                
+
 extern asmlinkage long sys_sched_rr_get_interval(pid_t pid,
 						struct timespec *interval);
 
@@ -3069,7 +3161,7 @@
 	struct timespec t;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_sched_rr_get_interval(pid, &t);
 	set_fs (old_fs);
@@ -3088,7 +3180,7 @@
 	old_sigset_t s;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-	
+
 	if (set && get_user (s, set)) return -EFAULT;
 	set_fs (KERNEL_DS);
 	ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
@@ -3106,7 +3198,7 @@
 	old_sigset_t s;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-		
+
 	set_fs (KERNEL_DS);
 	ret = sys_sigpending(&s);
 	set_fs (old_fs);
@@ -3123,7 +3215,7 @@
 	sigset_t32 s32;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-		
+
 	set_fs (KERNEL_DS);
 	ret = sys_rt_sigpending(&s, sigsetsize);
 	set_fs (old_fs);
@@ -3234,7 +3326,7 @@
 	mm_segment_t old_fs = get_fs();
 	siginfo_t info;
 	siginfo_t32 info32;
-		
+
 	if (copy_from_user (&s32, uthese, sizeof(sigset_t32)))
 		return -EFAULT;
 	switch (_NSIG_WORDS) {
@@ -3270,7 +3362,7 @@
 	siginfo_t32 info32;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-	
+
 	if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
 		return -EFAULT;
 	/* XXX: Is this correct? */
@@ -3315,7 +3407,7 @@
 	uid_t a, b, c;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-		
+
 	set_fs (KERNEL_DS);
 	ret = sys_getresuid(&a, &b, &c);
 	set_fs (old_fs);
@@ -3354,12 +3446,12 @@
 
 asmlinkage long
 sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid,
-		__kernel_gid_t32 *sgid) 
+		__kernel_gid_t32 *sgid)
 {
 	gid_t a, b, c;
 	int ret;
 	mm_segment_t old_fs = get_fs();
-		
+
 	set_fs (KERNEL_DS);
 	ret = sys_getresgid(&a, &b, &c);
 	set_fs (old_fs);
@@ -3379,7 +3471,7 @@
 	gid_t gl[NGROUPS];
 	int ret, i;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	set_fs (KERNEL_DS);
 	ret = sys_getgroups(gidsetsize, gl);
 	set_fs (old_fs);
@@ -3398,13 +3490,13 @@
 	gid_t gl[NGROUPS];
 	int ret, i;
 	mm_segment_t old_fs = get_fs ();
-	
+
 	if ((unsigned) gidsetsize > NGROUPS)
 		return -EINVAL;
 	for (i = 0; i < gidsetsize; i++, grouplist++)
 		if (__get_user (gl[i], grouplist))
 			return -EFAULT;
-        set_fs (KERNEL_DS);
+	set_fs (KERNEL_DS);
 	ret = sys_setgroups(gidsetsize, gl);
 	set_fs (old_fs);
 	return ret;
@@ -3442,26 +3534,26 @@
 }
 
 struct msghdr32 {
-        u32               msg_name;
-        int               msg_namelen;
-        u32               msg_iov;
-        __kernel_size_t32 msg_iovlen;
-        u32               msg_control;
-        __kernel_size_t32 msg_controllen;
-        unsigned          msg_flags;
+	u32               msg_name;
+	int               msg_namelen;
+	u32               msg_iov;
+	__kernel_size_t32 msg_iovlen;
+	u32               msg_control;
+	__kernel_size_t32 msg_controllen;
+	unsigned          msg_flags;
 };
 
 struct cmsghdr32 {
-        __kernel_size_t32 cmsg_len;
-        int               cmsg_level;
-        int               cmsg_type;
+	__kernel_size_t32 cmsg_len;
+	int               cmsg_level;
+	int               cmsg_type;
 };
 
 /* Bleech... */
 #define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \
-        __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+	__cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
 #define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \
-        cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+	cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
 
 #define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
 
@@ -3479,7 +3571,7 @@
 
 __inline__ struct cmsghdr32 *
 __cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
-		struct cmsghdr32 *__cmsg, int __cmsg_len) 
+		struct cmsghdr32 *__cmsg, int __cmsg_len)
 {
 	struct cmsghdr32 * __ptr;
 
@@ -3541,7 +3633,7 @@
 	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
 	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
 	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
-	
+
 	return err;
 }
 
@@ -3588,7 +3680,7 @@
  */
 static int
 cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf,
-			    int stackbuf_size) 
+			    int stackbuf_size)
 {
 	struct cmsghdr32 *ucmsg;
 	struct cmsghdr *kcmsg, *kcmsg_base;
@@ -3812,7 +3904,7 @@
 		kcmsg32->cmsg_len = clen32;
 
 		ucmsg = (struct cmsghdr *) (((char *)ucmsg) +
-					    CMSG_ALIGN(clen64)); 
+					    CMSG_ALIGN(clen64));
 		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
 	}
 
@@ -3985,7 +4077,7 @@
 }
 
 extern asmlinkage long sys_init_module(const char *name_user,
-				      struct module *mod_user); 
+				      struct module *mod_user);
 
 /* Hey, when you're trying to init module, take time and prepare us a nice 64bit
  * module structure, even if from 32bit modutils... Why to pollute kernel... :))
@@ -4275,7 +4367,7 @@
 
 asmlinkage long
 sys32_query_module(char *name_user, int which, char *buf,
-		   __kernel_size_t32 bufsize, u32 ret) 
+		   __kernel_size_t32 bufsize, u32 ret)
 {
 	struct module *mod;
 	int err;
@@ -4340,7 +4432,7 @@
 	u32 value;
 	char name[60];
 };
-		 
+
 extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table);
 
 asmlinkage long
@@ -4349,7 +4441,7 @@
 	int len, i;
 	struct kernel_sym *tbl;
 	mm_segment_t old_fs;
-	
+
 	len = sys_get_kernel_syms(NULL);
 	if (!table) return len;
 	tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
@@ -4477,7 +4569,7 @@
 nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
 	int err;
-	
+
 	err = __get_user(karg->ca_version, &arg32->ca32_version);
 	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
 	err |= __get_user(karg->ca_svc.svc_nthreads,
@@ -4489,7 +4581,7 @@
 nfs_clnt32_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_client.cl_ident[0],
 			  &arg32->ca32_client.cl32_ident[0],
@@ -4513,7 +4605,7 @@
 nfs_exp32_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_export.ex_client[0],
 			  &arg32->ca32_export.ex32_client[0],
@@ -4589,7 +4681,7 @@
 nfs_getfh32_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_getfh.gf_addr,
 			  &arg32->ca32_getfh.gf32_addr,
@@ -4607,7 +4699,7 @@
 nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
 {
 	int err;
-	
+
 	err = copy_to_user(&res32->cr32_getfh,
 			&kres->cr_getfh,
 			sizeof(res32->cr32_getfh));
@@ -4772,19 +4864,6 @@
 }
 
 
-extern asmlinkage long sys_newuname(struct new_utsname * name);
-
-asmlinkage long
-sys32_newuname(struct new_utsname * name)
-{
-	int ret = sys_newuname(name);
-	
-	if (current->personality == PER_LINUX32 && !ret) {
-		ret = copy_to_user(name->machine, "sparc\0\0", 8);
-	}
-	return ret;
-}
-
 extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
 				    size_t count, loff_t pos);
 
@@ -4825,7 +4904,7 @@
 }
 
 extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset,
-				       size_t count); 
+				       size_t count);
 
 asmlinkage long
 sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count)
@@ -4833,17 +4912,17 @@
 	mm_segment_t old_fs = get_fs();
 	int ret;
 	off_t of;
-	
+
 	if (offset && get_user(of, offset))
 		return -EFAULT;
-		
+
 	set_fs(KERNEL_DS);
 	ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
 	set_fs(old_fs);
-	
+
 	if (!ret && offset && put_user(of, offset))
 		return -EFAULT;
-		
+
 	return ret;
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile
--- v2.4.3/linux/arch/ia64/kernel/Makefile	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/Makefile	Thu Apr  5 12:51:47 2001
@@ -11,19 +11,18 @@
 
 O_TARGET := kernel.o
 
-obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \
+export-objs := ia64_ksyms.o
+
+obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_sapic.o ivt.o \
 	 machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o	\
 	 signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
 obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o
 obj-$(CONFIG_IA64_DIG) += iosapic.o
 obj-$(CONFIG_IA64_PALINFO) += palinfo.o
+obj-$(CONFIG_IA64_EFIVARS) += efivars.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_SMP) += smp.o smpboot.o
 obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o
 obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
-
-export-objs := ia64_ksyms.o
-
-clean::
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c
--- v2.4.3/linux/arch/ia64/kernel/acpi.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/acpi.c	Thu Apr  5 12:51:47 2001
@@ -1,9 +1,9 @@
 /*
- * Advanced Configuration and Power Interface 
+ * Advanced Configuration and Power Interface
  *
- * Based on 'ACPI Specification 1.0b' February 2, 1999 and 
+ * Based on 'ACPI Specification 1.0b' February 2, 1999 and
  * 'IA-64 Extensions to ACPI Specification' Revision 0.6
- * 
+ *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 2000 Hewlett-Packard Co.
@@ -111,15 +111,15 @@
  * Identify usable CPU's and remember them for SMP bringup later.
  */
 static void __init
-acpi20_lsapic (char *p) 
+acpi20_lsapic (char *p)
 {
 	int add = 1;
 
 	acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p;
-	printk("      CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
+	printk("      CPU %.04x:%.04x: ", lsapic->eid, lsapic->id);
 
 	if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
-		printk("Disabled.\n");
+		printk("disabled.\n");
 		add = 0;
 	}
 
@@ -127,11 +127,14 @@
 	smp_boot_data.cpu_phys_id[total_cpus] = -1;
 #endif
 	if (add) {
-		printk("Available.\n");
 		available_cpus++;
+		printk("available");
 #ifdef CONFIG_SMP
 		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
-#endif /* CONFIG_SMP */
+		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
+			printk(" (BSP)");
+#endif
+		printk(".\n");
 	}
 	total_cpus++;
 }
@@ -199,7 +202,7 @@
 			printk("ACPI 2.0 MADT: LOCAL SAPIC\n");
 			acpi20_lsapic(p);
 			break;
-	
+
 		case ACPI20_ENTRY_IO_SAPIC:
 			iosapic = (acpi_entry_iosapic_t *) p;
 			if (iosapic_init)
@@ -233,7 +236,7 @@
 	end = p + (madt->header.length - sizeof(acpi_madt_t));
 
 	while (p < end) {
-		
+
 		switch (*p) {
 		case ACPI20_ENTRY_INT_SRC_OVERRIDE:
 			printk("ACPI 2.0 MADT: INT SOURCE Override\n");
@@ -251,7 +254,7 @@
 		available_cpus, total_cpus);
 }
 
-int __init 
+int __init
 acpi20_parse (acpi20_rsdp_t *rsdp20)
 {
 	acpi_xsdt_t *xsdt;
@@ -311,12 +314,12 @@
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
 		available_cpus = 1; /* We've got at least one of these, no? */
 	}
-	smp_boot_data.cpu_count = available_cpus;
+	smp_boot_data.cpu_count = total_cpus;
 #endif
 	return 1;
 }
 /*
- * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all 
+ * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all
  * platforms start supporting ACPI 2.0
  */
 
@@ -324,13 +327,13 @@
  * Identify usable CPU's and remember them for SMP bringup later.
  */
 static void __init
-acpi_lsapic (char *p) 
+acpi_lsapic (char *p)
 {
 	int add = 1;
 
 	acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p;
 
-	if ((lsapic->flags & LSAPIC_PRESENT) == 0) 
+	if ((lsapic->flags & LSAPIC_PRESENT) == 0)
 		return;
 
 	printk("      CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
@@ -388,7 +391,7 @@
 		      case ACPI_ENTRY_LOCAL_SAPIC:
 			acpi_lsapic(p);
 			break;
-	
+
 		      case ACPI_ENTRY_IO_SAPIC:
 			iosapic = (acpi_entry_iosapic_t *) p;
 			if (iosapic_init)
@@ -415,7 +418,7 @@
 	printk("      %d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
 }
 
-int __init 
+int __init
 acpi_parse (acpi_rsdp_t *rsdp)
 {
 	acpi_rsdt_t *rsdt;
@@ -433,9 +436,9 @@
 		return 0;
 	}
 
-	printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, 
+	printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id,
 	       rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff);
-	
+
 #ifdef CONFIG_ACPI_KERNEL_CONFIG
 	acpi_cf_init(rsdp);
 #endif
@@ -460,7 +463,7 @@
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
 		available_cpus = 1; /* We've got at least one of these, no? */
 	}
-	smp_boot_data.cpu_count = available_cpus;
+	smp_boot_data.cpu_count = total_cpus;
 #endif
 	return 1;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/brl_emu.c linux/arch/ia64/kernel/brl_emu.c
--- v2.4.3/linux/arch/ia64/kernel/brl_emu.c	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/kernel/brl_emu.c	Thu Apr  5 12:51:47 2001
@@ -1,6 +1,6 @@
 /*
  *  Emulation of the "brl" instruction for IA64 processors that
- *  don't support it in hardware. 
+ *  don't support it in hardware.
  *  Author: Stephan Zeisset, Intel Corp. <Stephan.Zeisset@intel.com>
  */
 
@@ -23,9 +23,9 @@
  *  of an and operation with the mask must be all 0's
  *  or all 1's for the address to be valid.
  */
-#define unimplemented_virtual_address(va) (					\
-	((va) & my_cpu_data.unimpl_va_mask) != 0 &&				\
-	((va) & my_cpu_data.unimpl_va_mask) != my_cpu_data.unimpl_va_mask	\
+#define unimplemented_virtual_address(va) (						\
+	((va) & local_cpu_data->unimpl_va_mask) != 0 &&					\
+	((va) & local_cpu_data->unimpl_va_mask) != local_cpu_data->unimpl_va_mask	\
 )
 
 /*
@@ -35,13 +35,13 @@
  *  address to be valid.
  */
 #define unimplemented_physical_address(pa) (		\
-	((pa) & my_cpu_data.unimpl_pa_mask) != 0	\
+	((pa) & local_cpu_data->unimpl_pa_mask) != 0	\
 )
 
 /*
- *  Handle an illegal operation fault that was caused by an 
+ *  Handle an illegal operation fault that was caused by an
  *  unimplemented "brl" instruction.
- *  If we are not successful (e.g because the illegal operation 
+ *  If we are not successful (e.g because the illegal operation
  *  wasn't caused by a "brl" after all), we return -1.
  *  If we are successful, we return either 0 or the address
  *  of a "fixup" function for manipulating preserved register
@@ -64,8 +64,8 @@
 	 *  Decode the instruction bundle.
 	 */
 
-        if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle)))
-                return rv; 
+	if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle)))
+		return rv;
 
 	next_ip = (unsigned long) regs->cr_iip + 16;
 
@@ -79,14 +79,14 @@
 	btype = ((bundle[1] >> 29) & 0x7);
 	qp = ((bundle[1] >> 23) & 0x3f);
 	offset = ((bundle[1] & 0x0800000000000000L) << 4)
-		| ((bundle[1] & 0x00fffff000000000L) >> 32) 
+		| ((bundle[1] & 0x00fffff000000000L) >> 32)
 		| ((bundle[1] & 0x00000000007fffffL) << 40)
 		| ((bundle[0] & 0xffff000000000000L) >> 24);
 
 	tmp_taken = regs->pr & (1L << qp);
 
 	switch(opcode) {
-		
+
 		case 0xC:
 			/*
 			 *  Long Branch.
@@ -169,7 +169,7 @@
 			 */
 			regs->cr_ifs = ((regs->cr_ifs & 0xffffffc00000007f)
 					- ((regs->cr_ifs >> 7) & 0x7f));
-				
+
 			break;
 
 		default:
@@ -180,7 +180,7 @@
 
 	}
 
-	regs->cr_iip += offset; 
+	regs->cr_iip += offset;
 	ia64_psr(regs)->ri = 0;
 
 	if (ia64_psr(regs)->it == 0)
@@ -188,7 +188,7 @@
 	else
 		unimplemented_address = unimplemented_virtual_address(regs->cr_iip);
 
-	if (unimplemented_address) { 
+	if (unimplemented_address) {
 		/*
 		 *  The target address contains unimplemented bits.
 		 */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c
--- v2.4.3/linux/arch/ia64/kernel/efi.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/kernel/efi.c	Thu Apr 12 12:16:35 2001
@@ -5,9 +5,9 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2000 Hewlett-Packard Co.
+ * Copyright (C) 1999-2001 Hewlett-Packard Co.
  * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1999-2001 Stephane Eranian <eranian@hpl.hp.com>
  *
  * All EFI Runtime Services are not implemented yet as EFI only
  * supports physical mode addressing on SoftSDV. This is to be fixed
@@ -16,9 +16,8 @@
  * Implemented EFI runtime services and virtual mode calls.  --davidm
  *
  * Goutham Rao: <goutham.rao@intel.com>
- * 	Skip non-WB memory and ignore empty memory ranges.
+ *	Skip non-WB memory and ignore empty memory ranges.
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -26,6 +25,7 @@
 
 #include <asm/efi.h>
 #include <asm/io.h>
+#include <asm/kregs.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 
@@ -128,9 +128,9 @@
 	efi_memory_desc_t *md;
 	u64 efi_desc_size, start, end;
 
-	efi_map_start = __va(ia64_boot_param.efi_memmap);
-	efi_map_end   = efi_map_start + ia64_boot_param.efi_memmap_size;
-	efi_desc_size = ia64_boot_param.efi_memdesc_size;
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
 
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
@@ -203,9 +203,9 @@
 	u64 mask, flags;
 	u64 vaddr;
 
-	efi_map_start = __va(ia64_boot_param.efi_memmap);
-	efi_map_end   = efi_map_start + ia64_boot_param.efi_memmap_size;
-	efi_desc_size = ia64_boot_param.efi_memdesc_size;
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
 
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
@@ -218,61 +218,48 @@
 			continue;
 		}
 		/*
-		 * We must use the same page size as the one used
-		 * for the kernel region when we map the PAL code.
-		 * This way, we avoid overlapping TRs if code is 
-		 * executed nearby. The Alt I-TLB installs 256MB
-		 * page sizes as defined for region 7.
+		 * The only ITLB entry in region 7 that is used is the one installed by
+		 * __start().  That entry covers a 64MB range.
 		 *
 		 * XXX Fixme: should be dynamic here (for page size)
 		 */
-		mask  = ~((1 << _PAGE_SIZE_256M)-1);
+		mask  = ~((1 << _PAGE_SIZE_64M) - 1);
 		vaddr = PAGE_OFFSET + md->phys_addr;
 
 		/*
-		 * We must check that the PAL mapping won't overlap
-		 * with the kernel mapping on ITR1. 
+		 * We must check that the PAL mapping won't overlap with the kernel
+		 * mapping.
 		 *
-		 * PAL code is guaranteed to be aligned on a power of 2
-		 * between 4k and 256KB.
-		 * Also from the documentation, it seems like there is an
-		 * implicit guarantee that you will need only ONE ITR to
-		 * map it. This implies that the PAL code is always aligned
-		 * on its size, i.e., the closest matching page size supported
-		 * by the TLB. Therefore PAL code is guaranteed never to cross
-		 * a 256MB unless it is bigger than 256MB (very unlikely!).
-		 * So for now the following test is enough to determine whether
-		 * or not we need a dedicated ITR for the PAL code.
+		 * PAL code is guaranteed to be aligned on a power of 2 between 4k and
+		 * 256KB.  Also from the documentation, it seems like there is an implicit
+		 * guarantee that you will need only ONE ITR to map it. This implies that
+		 * the PAL code is always aligned on its size, i.e., the closest matching
+		 * page size supported by the TLB. Therefore PAL code is guaranteed never
+		 * to cross a 64MB unless it is bigger than 64MB (very unlikely!).  So for
+		 * now the following test is enough to determine whether or not we need a
+		 * dedicated ITR for the PAL code.
 		 */
-		if ((vaddr & mask) == (PAGE_OFFSET & mask)) {
-			printk(__FUNCTION__ " : no need to install ITR for PAL Code\n");
+		if ((vaddr & mask) == (KERNEL_START & mask)) {
+			printk(__FUNCTION__ " : no need to install ITR for PAL code\n");
 			continue;
 		}
 
-	  	printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
+		printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
 		       smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12),
-		       vaddr & mask, (vaddr & mask) + 256*1024*1024);
+		       vaddr & mask, (vaddr & mask) + 64*1024*1024);
 
 		/*
 		 * Cannot write to CRx with PSR.ic=1
 		 */
 		ia64_clear_ic(flags);
-
-		/*
-		 * ITR0/DTR0: used for kernel code/data
-		 * ITR1/DTR1: used by HP simulator
-		 * ITR2/DTR2: map PAL code
-		 */
-		ia64_itr(0x1, 2, vaddr & mask,
-			 pte_val(mk_pte_phys(md->phys_addr,
-					     __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))),
-			 _PAGE_SIZE_256M);
+		ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask,
+			 pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), _PAGE_SIZE_64M);
 		local_irq_restore(flags);
-		ia64_srlz_i ();
+		ia64_srlz_i();
 	}
 }
 
-void __init 
+void __init
 efi_init (void)
 {
 	void *efi_map_start, *efi_map_end;
@@ -301,14 +288,14 @@
 	if (mem_limit != ~0UL)
 		printk("Ignoring memory above %luMB\n", mem_limit >> 20);
 
-	efi.systab = __va(ia64_boot_param.efi_systab);
+	efi.systab = __va(ia64_boot_param->efi_systab);
 
 	/*
 	 * Verify the EFI Table
- 	 */
-	if (efi.systab == NULL) 
+	 */
+	if (efi.systab == NULL)
 		panic("Woah! Can't find EFI system table.\n");
-	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) 
+	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
 		panic("Woah! EFI system table signature incorrect\n");
 	if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
 		printk("Warning: EFI system table major version mismatch: "
@@ -360,9 +347,9 @@
 	efi.get_next_high_mono_count = phys_get_next_high_mono_count;
 	efi.reset_system = phys_reset_system;
 
-	efi_map_start = __va(ia64_boot_param.efi_memmap);
-	efi_map_end   = efi_map_start + ia64_boot_param.efi_memmap_size;
-	efi_desc_size = ia64_boot_param.efi_memdesc_size;
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
 
 #if EFI_DEBUG
 	/* print EFI memory map: */
@@ -380,16 +367,7 @@
 #endif
 
 	efi_map_pal_code();
-
-#ifndef CONFIG_IA64_SOFTSDV_HACKS
-	/*
-	 * (Some) SoftSDVs seem to have a problem with this call.
-	 * Since it's mostly a performance optimization, just don't do
-	 * it for now...  --davidm 99/12/6
-	 */
 	efi_enter_virtual_mode();
-#endif
-
 }
 
 void
@@ -400,9 +378,9 @@
 	efi_status_t status;
 	u64 efi_desc_size;
 
-	efi_map_start = __va(ia64_boot_param.efi_memmap);
-	efi_map_end   = efi_map_start + ia64_boot_param.efi_memmap_size;
-	efi_desc_size = ia64_boot_param.efi_memdesc_size;
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
 
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
@@ -441,9 +419,9 @@
 	}
 
 	status = efi_call_phys(__va(runtime->set_virtual_address_map),
-			       ia64_boot_param.efi_memmap_size,
-			       efi_desc_size, ia64_boot_param.efi_memdesc_version,
-			       ia64_boot_param.efi_memmap);
+			       ia64_boot_param->efi_memmap_size,
+			       efi_desc_size, ia64_boot_param->efi_memdesc_version,
+			       ia64_boot_param->efi_memmap);
 	if (status != EFI_SUCCESS) {
 		printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status);
 		return;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/efi_stub.S linux/arch/ia64/kernel/efi_stub.S
--- v2.4.3/linux/arch/ia64/kernel/efi_stub.S	Fri Jul 14 16:08:11 2000
+++ linux/arch/ia64/kernel/efi_stub.S	Thu Apr  5 12:51:47 2001
@@ -33,13 +33,6 @@
 #include <asm/processor.h>
 #include <asm/asmmacro.h>
 
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
-	.text
-
 /*
  * Inputs:
  *	in0 = address of function descriptor of EFI routine to call
@@ -50,15 +43,15 @@
  */
 
 GLOBAL_ENTRY(efi_call_phys)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,5,7,0
 	ld8 r2=[in0],8			// load EFI function's entry point
 	mov loc0=rp
-	UNW(.body)
+	.body
 	;;
 	mov loc2=gp			// save global pointer
 	mov loc4=ar.rsc			// save RSE configuration
-	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	;;
 
 	ld8 gp=[in0]			// load EFI function's global pointer
@@ -80,7 +73,7 @@
 	mov out5=in6
 	mov out6=in7
 	br.call.sptk.few rp=b6		// call the EFI function
-.ret1:	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+.ret1:	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3
 	br.call.sptk.few rp=ia64_switch_mode // return to virtual mode
 .ret2:	mov ar.rsc=loc4			// restore RSE configuration
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/efivars.c linux/arch/ia64/kernel/efivars.c
--- v2.4.3/linux/arch/ia64/kernel/efivars.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/kernel/efivars.c	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,433 @@
+/*
+ * EFI Variables - efivars.c
+ *
+ * Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+ *
+ * This code takes all variables accessible from EFI runtime and
+ *  exports them via /proc
+ *
+ * Reads to /proc/efi/varname return an efi_variable_t structure.
+ * Writes to /proc/efi/varname must be an efi_variable_t structure.
+ * Writes with DataSize = 0 or Attributes = 0 deletes the variable.
+ * Writes with a new value in VariableName+VendorGuid creates
+ * a new variable.
+ *
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Changelog:
+ *
+ *  12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ *   Feedback received from Stephane Eranian incorporated.
+ *   efivar_write() checks copy_from_user() return value.
+ *   efivar_read/write() returns proper errno.
+ *   v0.02 release to linux-ia64@linuxia64.org
+ *
+ *  26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ *   v0.01 release to linux-ia64@linuxia64.org
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>		/* for capable() */
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/efi.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_SMP
+#include <linux/smp.h>
+#endif
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
+MODULE_DESCRIPTION("/proc interface to EFI Variables");
+
+#define EFIVARS_VERSION "0.02 2001-Mar-12"
+
+static int
+efivar_read(char *page, char **start, off_t off,
+	    int count, int *eof, void *data);
+static int
+efivar_write(struct file *file, const char *buffer,
+	     unsigned long count, void *data);
+
+
+/*
+ * The maximum size of VariableName + Data = 1024
+ * Therefore, it's reasonable to save that much
+ * space in each part of the structure,
+ * and we use a page for reading/writing.
+ */
+
+typedef struct _efi_variable_t {
+	efi_char16_t  VariableName[1024/sizeof(efi_char16_t)];
+	efi_guid_t    VendorGuid;
+	unsigned long DataSize;
+	__u8          Data[1024];
+	efi_status_t  Status;
+	__u32         Attributes;
+} __attribute__((packed)) efi_variable_t;
+
+
+typedef struct _efivar_entry_t {
+	efi_variable_t          var;
+	struct proc_dir_entry   *entry;
+	struct list_head        list;
+} efivar_entry_t;
+
+spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(efivar_list);
+static struct proc_dir_entry *efi_dir = NULL;
+
+#define efivar_entry(n) list_entry(n, efivar_entry_t, list)
+
+/* Return the number of unicode characters in data */
+static unsigned long
+utf8_strlen(efi_char16_t *data, unsigned long maxlength)
+{
+	unsigned long length = 0;
+	while (*data++ != 0 && length < maxlength)
+		length++;
+	return length;
+}
+
+/* Return the number of bytes is the length of this string */
+/* Note: this is NOT the same as the number of unicode characters */
+static inline unsigned long
+utf8_strsize(efi_char16_t *data, unsigned long maxlength)
+{
+	return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) *
+		sizeof(efi_char16_t);
+}
+
+
+static int
+proc_calc_metrics(char *page, char **start, off_t off,
+		  int count, int *eof, int len)
+{
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+
+static void
+uuid_unparse(efi_guid_t *guid, char *out)
+{
+	sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		guid->data1, guid->data2, guid->data3,
+		guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3],
+		guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+}
+
+
+
+
+
+/*
+ * efivar_create_proc_entry()
+ * Requires:
+ *    variable_name_size = number of bytes required to hold
+ *                         variable_name (not counting the NULL
+ *                         character at the end.
+ * Returns 1 on failure, 0 on success
+ */
+static int
+efivar_create_proc_entry(unsigned long variable_name_size,
+			 efi_char16_t *variable_name,
+			 efi_guid_t *vendor_guid)
+{
+
+	int i, short_name_size = variable_name_size /
+		sizeof(efi_char16_t) + 38;
+	char *short_name = kmalloc(short_name_size+1,
+				   GFP_KERNEL);
+	efivar_entry_t *new_efivar = kmalloc(sizeof(efivar_entry_t),
+					     GFP_KERNEL);
+	if (!short_name || !new_efivar)  {
+		if (short_name)        kfree(short_name);
+		if (new_efivar)        kfree(new_efivar);
+		return 1;
+	}
+	memset(short_name, 0, short_name_size+1);
+	memset(new_efivar, 0, sizeof(efivar_entry_t));
+
+	memcpy(new_efivar->var.VariableName, variable_name,
+	       variable_name_size);
+	memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
+
+	/* Convert Unicode to normal chars (assume top bits are 0),
+	   ala UTF-8 */
+	for (i=0; i<variable_name_size / sizeof(efi_char16_t); i++) {
+		short_name[i] = variable_name[i] & 0xFF;
+	}
+
+	/* This is ugly, but necessary to separate one vendor's
+	   private variables from another's.         */
+
+	*(short_name + strlen(short_name)) = '-';
+	uuid_unparse(vendor_guid, short_name + strlen(short_name));
+
+
+	/* Create the entry in proc */
+	new_efivar->entry = create_proc_entry(short_name, 0600, efi_dir);
+	kfree(short_name); short_name = NULL;
+	if (!new_efivar->entry) return 1;
+
+
+	new_efivar->entry->data = new_efivar;
+	new_efivar->entry->read_proc = efivar_read;
+	new_efivar->entry->write_proc = efivar_write;
+
+	list_add(&new_efivar->list, &efivar_list);
+
+
+	return 0;
+}
+
+
+
+/***********************************************************
+ * efivar_read()
+ * Requires:
+ * Modifies: page
+ * Returns: number of bytes written, or -EINVAL on failure
+ ***********************************************************/
+
+static int
+efivar_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = sizeof(efi_variable_t);
+	efivar_entry_t *efi_var = data;
+	efi_variable_t *var_data = (efi_variable_t *)page;
+
+	if (!page || !data) return -EINVAL;
+
+	spin_lock(&efivars_lock);
+	MOD_INC_USE_COUNT;
+
+	memcpy(var_data, &efi_var->var, len);
+
+	var_data->DataSize = 1024;
+	var_data->Status = efi.get_variable(var_data->VariableName,
+					    &var_data->VendorGuid,
+					    &var_data->Attributes,
+					    &var_data->DataSize,
+					    var_data->Data);
+
+	MOD_DEC_USE_COUNT;
+	spin_unlock(&efivars_lock);
+
+	return proc_calc_metrics(page, start, off, count, eof, len);
+}
+
+/***********************************************************
+ * efivar_write()
+ * Requires: data is an efi_setvariable_t data type,
+ *           properly filled in, possibly by a call
+ *           first to efivar_read().
+ *           Caller must have CAP_SYS_ADMIN
+ * Modifies: NVRAM
+ * Returns: var_data->DataSize on success, errno on failure
+ *
+ ***********************************************************/
+static int
+efivar_write(struct file *file, const char *buffer,
+	     unsigned long count, void *data)
+{
+	unsigned long strsize1, strsize2;
+	int found=0;
+	struct list_head *pos;
+	unsigned long size = sizeof(efi_variable_t);
+	efi_status_t status;
+	efivar_entry_t *efivar = data, *search_efivar = NULL;
+	efi_variable_t *var_data;
+	if (!data || count != size) {
+		printk(KERN_WARNING "efivars: improper struct of size 0x%lx passed.\n", count);
+		return -EINVAL;
+	}
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	spin_lock(&efivars_lock);
+	MOD_INC_USE_COUNT;
+
+	var_data = kmalloc(size, GFP_KERNEL);
+	if (!var_data) {
+		MOD_DEC_USE_COUNT;
+		spin_unlock(&efivars_lock);
+		return -ENOMEM;
+	}
+	if (copy_from_user(var_data, buffer, size)) {
+		MOD_DEC_USE_COUNT;
+		spin_unlock(&efivars_lock);
+		return -EFAULT;
+	}
+
+
+	/* Since the data ptr we've currently got is probably for
+	   a different variable find the right variable.
+	   This allows any properly formatted data structure to
+	   be written to any of the files in /proc/efi and it will work.
+	*/
+	list_for_each(pos, &efivar_list) {
+		search_efivar = efivar_entry(pos);
+		strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
+		strsize2 = utf8_strsize(var_data->VariableName, 1024);
+		if ( strsize1 == strsize2 &&
+		     !memcmp(&(search_efivar->var.VariableName),
+			     var_data->VariableName, strsize1) &&
+		     !efi_guidcmp(search_efivar->var.VendorGuid,
+				  var_data->VendorGuid)) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) efivar = search_efivar;
+
+	status = efi.set_variable(var_data->VariableName,
+				  &var_data->VendorGuid,
+				  var_data->Attributes,
+				  var_data->DataSize,
+				  var_data->Data);
+
+	if (status != EFI_SUCCESS) {
+		printk(KERN_WARNING "set_variable() failed: status=%lx\n", status);
+		kfree(var_data);
+		MOD_DEC_USE_COUNT;
+		spin_unlock(&efivars_lock);
+		return -EIO;
+	}
+
+
+	if (!var_data->DataSize || !var_data->Attributes) {
+		/* We just deleted the NVRAM variable */
+		remove_proc_entry(efivar->entry->name, efi_dir);
+		list_del(&efivar->list);
+		kfree(efivar);
+	}
+
+	/* If this is a new variable, set up the proc entry for it. */
+	if (!found) {
+		efivar_create_proc_entry(utf8_strsize(var_data->VariableName,
+						      1024),
+					 var_data->VariableName,
+					 &var_data->VendorGuid);
+	}
+
+	kfree(var_data);
+	MOD_DEC_USE_COUNT;
+	spin_unlock(&efivars_lock);
+	return size;
+}
+
+
+
+static int __init
+efivars_init(void)
+{
+
+	efi_status_t status;
+	efi_guid_t vendor_guid;
+	efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
+	unsigned long variable_name_size = 1024;
+
+	spin_lock(&efivars_lock);
+
+	printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
+
+	/* Per EFI spec, the maximum storage allocated for both
+	   the variable name and variable data is 1024 bytes.
+	*/
+
+	efi_dir = proc_mkdir("efi", NULL);
+
+	memset(variable_name, 0, 1024);
+
+	do {
+		variable_name_size=1024;
+
+		status = efi.get_next_variable(&variable_name_size,
+					       variable_name,
+					       &vendor_guid);
+
+
+		switch (status) {
+		case EFI_SUCCESS:
+			efivar_create_proc_entry(variable_name_size,
+						 variable_name,
+						 &vendor_guid);
+			break;
+		case EFI_NOT_FOUND:
+			break;
+		default:
+			printk(KERN_WARNING "get_next_variable: status=%lx\n", status);
+			status = EFI_NOT_FOUND;
+			break;
+		}
+
+	} while (status != EFI_NOT_FOUND);
+
+	kfree(variable_name);
+	spin_unlock(&efivars_lock);
+	return 0;
+}
+
+static void __exit
+efivars_exit(void)
+{
+	struct list_head *pos;
+	efivar_entry_t *efivar;
+
+	spin_lock(&efivars_lock);
+
+	list_for_each(pos, &efivar_list) {
+		efivar = efivar_entry(pos);
+		remove_proc_entry(efivar->entry->name, efi_dir);
+		list_del(&efivar->list);
+		kfree(efivar);
+	}
+	remove_proc_entry(efi_dir->name, NULL);
+	spin_unlock(&efivars_lock);
+
+}
+
+module_init(efivars_init);
+module_exit(efivars_exit);
+
+/*
+ * 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: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S
--- v2.4.3/linux/arch/ia64/kernel/entry.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/entry.S	Thu Apr  5 12:51:47 2001
@@ -3,8 +3,8 @@
  *
  * Kernel entry points.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
@@ -15,8 +15,6 @@
  * kernel stack. This allows us to handle interrupts without changing
  * to physical mode.
  *
- * ar.k4 is now used to hold last virtual map address
- * 
  * Jonathan Nickin	<nicklin@missioncriticallinux.com>
  * Patrick O'Rourke	<orourke@missioncriticallinux.com>
  * 11/07/2000
@@ -25,66 +23,84 @@
  * Global (preserved) predicate usage on syscall entry/exit path:
  *
  *	pKern:		See entry.h.
+ *	pUser:		See entry.h.
  *	pSys:		See entry.h.
  *	pNonSys:	!pSys
- *	p2:		(Alias of pKern!) True if any signals are pending.
  */
 
 #include <linux/config.h>
 
 #include <asm/cache.h>
 #include <asm/errno.h>
+#include <asm/kregs.h>
 #include <asm/offsets.h>
 #include <asm/processor.h>
 #include <asm/unistd.h>
 #include <asm/asmmacro.h>
 #include <asm/pgtable.h>
-	
-#include "entry.h"
 
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
+#include "minstate.h"
 
 	/*
 	 * execve() is special because in case of success, we need to
 	 * setup a null register window frame.
 	 */
 ENTRY(ia64_execve)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)
 	alloc loc1=ar.pfs,3,2,4,0
 	mov loc0=rp
-	UNW(.body)
+	.body
 	mov out0=in0			// filename
 	;;				// stop bit between alloc and call
 	mov out1=in1			// argv
 	mov out2=in2			// envp
 	add out3=16,sp			// regs
 	br.call.sptk.few rp=sys_execve
-.ret0:	cmp4.ge p6,p0=r8,r0
+.ret0:	cmp4.ge p6,p7=r8,r0
 	mov ar.pfs=loc1			// restore ar.pfs
-	;;
-(p6)	mov ar.pfs=r0			// clear ar.pfs in case of success
 	sxt4 r8=r8			// return 64-bit result
+	;;
+	stf.spill [sp]=f0
+(p6)	cmp.ne pKern,pUser=r0,r0	// a successful execve() lands us in user-mode...
 	mov rp=loc0
+(p6)	mov ar.pfs=r0			// clear ar.pfs on success
+(p7)	br.ret.sptk.few rp
 
+	/*
+	 * In theory, we'd have to zap this state only to prevent leaking of
+	 * security sensitive state (e.g., if current->dumpable is zero).  However,
+	 * this executes in less than 20 cycles even on Itanium, so it's not worth
+	 * optimizing for...).
+	 */
+	mov r4=0;		mov f2=f0;		mov b1=r0
+	mov r5=0;		mov f3=f0;		mov b2=r0
+	mov r6=0;		mov f4=f0;		mov b3=r0
+	mov r7=0;		mov f5=f0;		mov b4=r0
+	mov ar.unat=0;		mov f10=f0;		mov b5=r0
+	ldf.fill f11=[sp];	ldf.fill f12=[sp];	mov f13=f0
+	ldf.fill f14=[sp];	ldf.fill f15=[sp];	mov f16=f0
+	ldf.fill f17=[sp];	ldf.fill f18=[sp];	mov f19=f0
+	ldf.fill f20=[sp];	ldf.fill f21=[sp];	mov f22=f0
+	ldf.fill f23=[sp];	ldf.fill f24=[sp];	mov f25=f0
+	ldf.fill f26=[sp];	ldf.fill f27=[sp];	mov f28=f0
+	ldf.fill f29=[sp];	ldf.fill f30=[sp];	mov f31=f0
+	mov ar.lc=0
 	br.ret.sptk.few rp
 END(ia64_execve)
 
 GLOBAL_ENTRY(sys_clone2)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
 	alloc r16=ar.pfs,3,2,4,0
 	DO_SAVE_SWITCH_STACK
 	mov loc0=rp
 	mov loc1=r16				// save ar.pfs across do_fork
-	UNW(.body)
+	.body
 	mov out1=in1
 	mov out3=in2
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
 	mov out0=in0				// out0 = clone_flags
 	br.call.sptk.few rp=do_fork
-.ret1:	UNW(.restore sp)
+.ret1:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
 	mov ar.pfs=loc1
 	mov rp=loc0
@@ -92,43 +108,42 @@
 END(sys_clone2)
 
 GLOBAL_ENTRY(sys_clone)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
 	alloc r16=ar.pfs,2,2,4,0
 	DO_SAVE_SWITCH_STACK
 	mov loc0=rp
 	mov loc1=r16				// save ar.pfs across do_fork
-	UNW(.body)
+	.body
 	mov out1=in1
 	mov out3=0
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
 	mov out0=in0				// out0 = clone_flags
 	br.call.sptk.few rp=do_fork
-.ret2:	UNW(.restore sp)
+.ret2:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
 	mov ar.pfs=loc1
 	mov rp=loc0
 	br.ret.sptk.many rp
 END(sys_clone)
 
-#define KSTACK_TR	2
-
 /*
  * prev_task <- ia64_switch_to(struct task_struct *next)
  */
 GLOBAL_ENTRY(ia64_switch_to)
-	UNW(.prologue)
+	.prologue
 	alloc r16=ar.pfs,1,0,0,0
 	DO_SAVE_SWITCH_STACK
-	UNW(.body)
+	.body
 
 	adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13
-	mov r27=ar.k4
+	mov r27=IA64_KR(CURRENT_STACK)
 	dep r20=0,in0,61,3		// physical address of "current"
 	;;
 	st8 [r22]=sp			// save kernel stack pointer of old task
-	shr.u r26=r20,_PAGE_SIZE_256M
+	shr.u r26=r20,_PAGE_SIZE_64M
+	mov r16=1
 	;;
-	cmp.eq p7,p6=r26,r0		// check < 256M
+	cmp.ne p6,p7=r26,r16		// check >= 64M && < 128M
 	adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
 	;;
 	/*
@@ -142,50 +157,36 @@
 (p6)	ssm psr.ic			// if we we had to map, renable the psr.ic bit FIRST!!!
 	;;
 (p6)	srlz.d
-	mov ar.k6=r20			// copy "current" into ar.k6
+	mov IA64_KR(CURRENT)=r20	// update "current" application register
 	mov r8=r13			// return pointer to previously running task
 	mov r13=in0			// set "current" pointer
 	;;
 (p6)	ssm psr.i			// renable psr.i AFTER the ic bit is serialized
-	DO_LOAD_SWITCH_STACK( )
+	DO_LOAD_SWITCH_STACK
 
 #ifdef CONFIG_SMP
 	sync.i				// ensure "fc"s done by this CPU are visible on other CPUs
-#endif 
+#endif
 	br.ret.sptk.few rp		// boogie on out in new context
 
 .map:
 	rsm psr.i | psr.ic
-	movl r25=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX
+	movl r25=PAGE_KERNEL
 	;;
 	srlz.d
 	or r23=r25,r20			// construct PA | page properties
-	mov r25=_PAGE_SIZE_256M<<2
+	mov r25=_PAGE_SIZE_64M<<2
 	;;
 	mov cr.itir=r25
 	mov cr.ifa=in0			// VA of next task...
 	;;
-	mov r25=KSTACK_TR		// use tr entry #2...
-	mov ar.k4=r26			// remember last page we mapped...
+	mov r25=IA64_TR_CURRENT_STACK
+	mov IA64_KR(CURRENT_STACK)=r26	// remember last page we mapped...
 	;;
 	itr.d dtr[r25]=r23		// wire in new mapping...
 	br.cond.sptk.many .done
-	;;
 END(ia64_switch_to)
 
-#ifndef CONFIG_IA64_NEW_UNWIND
-	/*
-	 * Like save_switch_stack, but also save the stack frame that is active
-	 * at the time this function is called.
-	 */
-ENTRY(save_switch_stack_with_current_frame)
-	UNW(.prologue)
-	alloc r16=ar.pfs,0,0,0,0		// pass ar.pfs to save_switch_stack
-	DO_SAVE_SWITCH_STACK
-	br.ret.sptk.few rp
-END(save_switch_stack_with_current_frame)
-#endif /* !CONFIG_IA64_NEW_UNWIND */
-
 /*
  * Note that interrupts are enabled during save_switch_stack and
  * load_switch_stack.  This means that we may get an interrupt with
@@ -205,95 +206,108 @@
  *	- rp (b0) holds return address to save
  */
 GLOBAL_ENTRY(save_switch_stack)
-	UNW(.prologue)
-	UNW(.altrp b7)
+	.prologue
+	.altrp b7
 	flushrs			// flush dirty regs to backing store (must be first in insn group)
+	.save @priunat,r17
 	mov r17=ar.unat		// preserve caller's
-	adds r2=16,sp		// r2 = &sw->caller_unat
+	.body
+#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
+      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+	adds r3=80,sp
 	;;
-	mov r18=ar.fpsr		// preserve fpsr
-	mov ar.rsc=r0		// put RSE in mode: enforced lazy, little endian, pl 0
+	lfetch.fault.excl.nt1 [r3],128
+#endif
+	mov ar.rsc=0		// put RSE in mode: enforced lazy, little endian, pl 0
+#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
+      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+	adds r2=16+128,sp
 	;;
-	mov r19=ar.rnat
-	adds r3=24,sp		// r3 = &sw->ar_fpsr
+	lfetch.fault.excl.nt1 [r2],128
+	lfetch.fault.excl.nt1 [r3],128
+#endif
+	adds r14=SW(R4)+16,sp
+#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
+      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+	;;
+	lfetch.fault.excl [r2]
+	lfetch.fault.excl [r3]
+#endif
+	adds r15=SW(R5)+16,sp
 	;;
-	.savesp ar.unat,SW(CALLER_UNAT)
-	st8 [r2]=r17,16
-	.savesp ar.fpsr,SW(AR_FPSR)
-	st8 [r3]=r18,24
+	mov r18=ar.fpsr		// preserve fpsr
+	mov r19=ar.rnat
+	add r2=SW(F2)+16,sp	// r2 = &sw->f2
+.mem.offset 0,0; st8.spill [r14]=r4,16		// spill r4
+.mem.offset 8,0; st8.spill [r15]=r5,16		// spill r5
+	add r3=SW(F3)+16,sp	// r3 = &sw->f3
 	;;
-	UNW(.body)
 	stf.spill [r2]=f2,32
 	stf.spill [r3]=f3,32
 	mov r21=b0
+.mem.offset 0,0; st8.spill [r14]=r6,16		// spill r6
+.mem.offset 8,0; st8.spill [r15]=r7,16		// spill r7
+	mov r22=b1
 	;;
+	// since we're done with the spills, read and save ar.unat:
+	mov r29=ar.unat		// M-unit
+	mov r20=ar.bspstore	// M-unit
+	mov r23=b2
 	stf.spill [r2]=f4,32
 	stf.spill [r3]=f5,32
+	mov r24=b3
 	;;
+	st8 [r14]=r21,16	// save b0
+	st8 [r15]=r22,16	// save b1
+	mov r25=b4
 	stf.spill [r2]=f10,32
 	stf.spill [r3]=f11,32
-	mov r22=b1
+	mov r26=b5
 	;;
+	st8 [r14]=r23,16	// save b2
+	st8 [r15]=r24,16	// save b3
+	mov r21=ar.lc		// I-unit
 	stf.spill [r2]=f12,32
 	stf.spill [r3]=f13,32
-	mov r23=b2
 	;;
+	st8 [r14]=r25,16	// save b4
+	st8 [r15]=r26,16	// save b5
 	stf.spill [r2]=f14,32
 	stf.spill [r3]=f15,32
-	mov r24=b3
 	;;
+	st8 [r14]=r16		// save ar.pfs
+	st8 [r15]=r21		// save ar.lc
 	stf.spill [r2]=f16,32
 	stf.spill [r3]=f17,32
-	mov r25=b4
 	;;
 	stf.spill [r2]=f18,32
 	stf.spill [r3]=f19,32
-	mov r26=b5
 	;;
 	stf.spill [r2]=f20,32
 	stf.spill [r3]=f21,32
-	mov r17=ar.lc				// I-unit
 	;;
 	stf.spill [r2]=f22,32
 	stf.spill [r3]=f23,32
 	;;
 	stf.spill [r2]=f24,32
 	stf.spill [r3]=f25,32
+	add r14=SW(CALLER_UNAT)+16,sp
 	;;
 	stf.spill [r2]=f26,32
 	stf.spill [r3]=f27,32
+	add r15=SW(AR_FPSR)+16,sp
 	;;
 	stf.spill [r2]=f28,32
 	stf.spill [r3]=f29,32
-	;;
-	stf.spill [r2]=f30,32
-	stf.spill [r3]=f31,24
-	;;
-.mem.offset 0,0;	st8.spill [r2]=r4,16
-.mem.offset 8,0;	st8.spill [r3]=r5,16
-	;;
-.mem.offset 0,0;	st8.spill [r2]=r6,16
-.mem.offset 8,0;	st8.spill [r3]=r7,16
-	;;
-	st8 [r2]=r21,16		// save b0
-	st8 [r3]=r22,16		// save b1
-	/* since we're done with the spills, read and save ar.unat: */
-	mov r18=ar.unat		// M-unit
-	mov r20=ar.bspstore	// M-unit
-	;;
-	st8 [r2]=r23,16		// save b2
-	st8 [r3]=r24,16		// save b3
-	;;
-	st8 [r2]=r25,16		// save b4
-	st8 [r3]=r26,16		// save b5
-	;;
-	st8 [r2]=r16,16		// save ar.pfs
-	st8 [r3]=r17,16		// save ar.lc
+	st8 [r14]=r17		// save caller_unat
+	st8 [r15]=r18		// save fpsr
 	mov r21=pr
 	;;
-	st8 [r2]=r18,16		// save ar.unat
+	stf.spill [r2]=f30,(SW(AR_UNAT)-SW(F30))
+	stf.spill [r3]=f31,(SW(AR_RNAT)-SW(F31))
+	;;
+	st8 [r2]=r29,16		// save ar.unat
 	st8 [r3]=r19,16		// save ar.rnat
-	mov b7=r28
 	;;
 	st8 [r2]=r20		// save ar.bspstore
 	st8 [r3]=r21		// save predicate registers
@@ -303,16 +317,27 @@
 
 /*
  * load_switch_stack:
+ *	- "invala" MUST be done at call site (normally in DO_LOAD_SWITCH_STACK)
  *	- b7 holds address to return to
+ *	- must not touch r8-r11
  */
 ENTRY(load_switch_stack)
-	UNW(.prologue)
-	UNW(.altrp b7)
-	invala			// invalidate ALAT
-	UNW(.body)
-	adds r2=IA64_SWITCH_STACK_B0_OFFSET+16,sp	// get pointer to switch_stack.b0
-	mov ar.rsc=r0		// put RSE into enforced lazy mode
-	adds r3=IA64_SWITCH_STACK_B0_OFFSET+24,sp	// get pointer to switch_stack.b1
+	.prologue
+	.altrp b7
+	.body
+#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
+      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+
+	lfetch.fault.nt1 [sp]
+#endif
+	adds r2=SW(AR_BSPSTORE)+16,sp
+	adds r3=SW(AR_UNAT)+16,sp
+	mov ar.rsc=0						// put RSE into enforced lazy mode
+	adds r14=SW(CALLER_UNAT)+16,sp
+	adds r15=SW(AR_FPSR)+16,sp
+	;;
+	ld8 r27=[r2],(SW(B0)-SW(AR_BSPSTORE))	// bspstore
+	ld8 r29=[r3],(SW(B1)-SW(AR_UNAT))	// unat
 	;;
 	ld8 r21=[r2],16		// restore b0
 	ld8 r22=[r3],16		// restore b1
@@ -323,84 +348,77 @@
 	ld8 r25=[r2],16		// restore b4
 	ld8 r26=[r3],16		// restore b5
 	;;
-	ld8 r16=[r2],16		// restore ar.pfs
-	ld8 r17=[r3],16		// restore ar.lc
+	ld8 r16=[r2],(SW(PR)-SW(AR_PFS))	// ar.pfs
+	ld8 r17=[r3],(SW(AR_RNAT)-SW(AR_LC))	// ar.lc
 	;;
-	ld8 r18=[r2],16		// restore ar.unat
-	ld8 r19=[r3],16		// restore ar.rnat
-	mov b0=r21
+	ld8 r28=[r2]		// restore pr
+	ld8 r30=[r3]		// restore rnat
 	;;
-	ld8 r20=[r2]		// restore ar.bspstore
-	ld8 r21=[r3]		// restore predicate registers
-	mov ar.pfs=r16
+	ld8 r18=[r14],16	// restore caller's unat
+	ld8 r19=[r15],24	// restore fpsr
 	;;
-	mov ar.bspstore=r20
+	ldf.fill f2=[r14],32
+	ldf.fill f3=[r15],32
 	;;
-	loadrs			// invalidate stacked regs outside current frame
-	adds r2=16-IA64_SWITCH_STACK_SIZE,r2	// get pointer to switch_stack.caller_unat
-	;;			// stop bit for rnat dependency
-	mov ar.rnat=r19
-	mov ar.unat=r18		// establish unat holding the NaT bits for r4-r7
-	adds r3=16-IA64_SWITCH_STACK_SIZE,r3	// get pointer to switch_stack.ar_fpsr
+	ldf.fill f4=[r14],32
+	ldf.fill f5=[r15],32
 	;;
-	ld8 r18=[r2],16		// restore caller's unat
-	ld8 r19=[r3],24		// restore fpsr
-	mov ar.lc=r17
+	ldf.fill f10=[r14],32
+	ldf.fill f11=[r15],32
+	;;
+	ldf.fill f12=[r14],32
+	ldf.fill f13=[r15],32
 	;;
-	ldf.fill f2=[r2],32
-	ldf.fill f3=[r3],32
-	mov pr=r21,-1
+	ldf.fill f14=[r14],32
+	ldf.fill f15=[r15],32
 	;;
-	ldf.fill f4=[r2],32
-	ldf.fill f5=[r3],32
+	ldf.fill f16=[r14],32
+	ldf.fill f17=[r15],32
 	;;
-	ldf.fill f10=[r2],32
-	ldf.fill f11=[r3],32
+	ldf.fill f18=[r14],32
+	ldf.fill f19=[r15],32
+	mov b0=r21
+	;;
+	ldf.fill f20=[r14],32
+	ldf.fill f21=[r15],32
 	mov b1=r22
 	;;
-	ldf.fill f12=[r2],32
-	ldf.fill f13=[r3],32
+	ldf.fill f22=[r14],32
+	ldf.fill f23=[r15],32
 	mov b2=r23
 	;;
-	ldf.fill f14=[r2],32
-	ldf.fill f15=[r3],32
+	mov ar.bspstore=r27
+	mov ar.unat=r29		// establish unat holding the NaT bits for r4-r7
 	mov b3=r24
 	;;
-	ldf.fill f16=[r2],32
-	ldf.fill f17=[r3],32
+	ldf.fill f24=[r14],32
+	ldf.fill f25=[r15],32
 	mov b4=r25
 	;;
-	ldf.fill f18=[r2],32
-	ldf.fill f19=[r3],32
+	ldf.fill f26=[r14],32
+	ldf.fill f27=[r15],32
 	mov b5=r26
 	;;
-	ldf.fill f20=[r2],32
-	ldf.fill f21=[r3],32
-	;;
-	ldf.fill f22=[r2],32
-	ldf.fill f23=[r3],32
-	;;
-	ldf.fill f24=[r2],32
-	ldf.fill f25=[r3],32
-	;;
-	ldf.fill f26=[r2],32
-	ldf.fill f27=[r3],32
-	;;
-	ldf.fill f28=[r2],32
-	ldf.fill f29=[r3],32
+	ldf.fill f28=[r14],32
+	ldf.fill f29=[r15],32
+	mov ar.pfs=r16
 	;;
-	ldf.fill f30=[r2],32
-	ldf.fill f31=[r3],24
+	ldf.fill f30=[r14],32
+	ldf.fill f31=[r15],24
+	mov ar.lc=r17
 	;;
-	ld8.fill r4=[r2],16
-	ld8.fill r5=[r3],16
+	ld8.fill r4=[r14],16
+	ld8.fill r5=[r15],16
+	mov pr=r28,-1
 	;;
-	ld8.fill r6=[r2],16
-	ld8.fill r7=[r3],16
+	ld8.fill r6=[r14],16
+	ld8.fill r7=[r15],16
+
 	mov ar.unat=r18				// restore caller's unat
+	mov ar.rnat=r30				// must restore after bspstore but before rsc!
 	mov ar.fpsr=r19				// restore fpsr
 	mov ar.rsc=3				// put RSE back into eager mode, pl 0
-	br.cond.sptk.few b7
+	br.cond.sptk.many b7
 END(load_switch_stack)
 
 GLOBAL_ENTRY(__ia64_syscall)
@@ -415,17 +433,16 @@
 	br.ret.sptk.few rp
 END(__ia64_syscall)
 
-	//
-	// We invoke syscall_trace through this intermediate function to
-	// ensure that the syscall input arguments are not clobbered.  We
-	// also use it to preserve b6, which contains the syscall entry point.
-	//
+	/*
+	 * We invoke syscall_trace through this intermediate function to
+	 * ensure that the syscall input arguments are not clobbered.  We
+	 * also use it to preserve b6, which contains the syscall entry point.
+	 */
 GLOBAL_ENTRY(invoke_syscall_trace)
-#ifdef CONFIG_IA64_NEW_UNWIND
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,3,0,0
 	mov loc0=rp
-	UNW(.body)
+	.body
 	mov loc2=b6
 	;;
 	br.call.sptk.few rp=syscall_trace
@@ -433,33 +450,18 @@
 	mov ar.pfs=loc1
 	mov b6=loc2
 	br.ret.sptk.few rp
-#else /* !CONFIG_IA64_NEW_SYSCALL */
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
-	alloc loc1=ar.pfs,8,3,0,0
-	;;			// WAW on CFM at the br.call
-	mov loc0=rp
-	br.call.sptk.many rp=save_switch_stack_with_current_frame	// must preserve b6!!
-.ret4:	mov loc2=b6
-	br.call.sptk.few rp=syscall_trace
-.ret5:	adds sp=IA64_SWITCH_STACK_SIZE,sp	// drop switch_stack frame
-	mov rp=loc0
-	mov ar.pfs=loc1
-	mov b6=loc2
-	;;
-	br.ret.sptk.few rp
-#endif /* !CONFIG_IA64_NEW_SYSCALL */
 END(invoke_syscall_trace)
 
-	//
-	// Invoke a system call, but do some tracing before and after the call.
-	// We MUST preserve the current register frame throughout this routine
-	// because some system calls (such as ia64_execve) directly
-	// manipulate ar.pfs.
-	//
-	// Input:
-	//	r15 = syscall number
-	//	b6  = syscall entry point
-	//
+	/*
+	 * Invoke a system call, but do some tracing before and after the call.
+	 * We MUST preserve the current register frame throughout this routine
+	 * because some system calls (such as ia64_execve) directly
+	 * manipulate ar.pfs.
+	 *
+	 * Input:
+	 *	r15 = syscall number
+	 *	b6  = syscall entry point
+	 */
 	.global ia64_strace_leave_kernel
 
 GLOBAL_ENTRY(ia64_trace_syscall)
@@ -468,8 +470,8 @@
 .ret6:	br.call.sptk.few rp=b6			// do the syscall
 strace_check_retval:
 	cmp.lt p6,p0=r8,r0			// syscall failed?
-	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp	// r2 = &pt_regs.r8
-	adds r3=IA64_PT_REGS_R8_OFFSET+32,sp	// r3 = &pt_regs.r10
+	adds r2=PT(R8)+16,sp			// r2 = &pt_regs.r8
+	adds r3=PT(R10)+16,sp			// r3 = &pt_regs.r10
 	mov r10=0
 (p6)	br.cond.sptk.few strace_error		// syscall failed ->
 	;;					// avoid RAW on r10
@@ -492,28 +494,14 @@
 	br.cond.sptk.few strace_save_retval
 END(ia64_trace_syscall)
 
-/*
- * A couple of convenience macros to help implement/understand the state
- * restoration that happens at the end of ia64_ret_from_syscall.
- */
-#define rARPR		r31
-#define rCRIFS		r30
-#define rCRIPSR		r29
-#define rCRIIP		r28
-#define rARRSC		r27
-#define rARPFS		r26
-#define rARUNAT		r25
-#define rARRNAT		r24
-#define rARBSPSTORE	r23
-#define rKRBS		r22
-#define rB6		r21
-
 GLOBAL_ENTRY(ia64_ret_from_clone)
 	PT_REGS_UNWIND_INFO(0)
 #ifdef CONFIG_SMP
-	// In SMP mode, we need to call schedule_tail to complete the scheduling process.
-	// Called by ia64_switch_to after do_fork()->copy_thread().  r8 contains the
-	// address of the previously executing task.
+	/*
+	 * In SMP mode, we need to call invoke_schedule_tail to complete the scheduling process.
+	 * Called by ia64_switch_to after do_fork()->copy_thread().  r8 contains the
+	 * address of the previously executing task.
+	 */
 	br.call.sptk.few rp=invoke_schedule_tail
 .ret8:
 #endif
@@ -530,8 +518,8 @@
 GLOBAL_ENTRY(ia64_ret_from_syscall)
 	PT_REGS_UNWIND_INFO(0)
 	cmp.ge p6,p7=r8,r0			// syscall executed successfully?
-	adds r2=IA64_PT_REGS_R8_OFFSET+16,sp	// r2 = &pt_regs.r8
-	adds r3=IA64_PT_REGS_R8_OFFSET+32,sp	// r3 = &pt_regs.r10
+	adds r2=PT(R8)+16,sp			// r2 = &pt_regs.r8
+	adds r3=PT(R10)+16,sp			// r3 = &pt_regs.r10
 	;;
 	.mem.offset 0,0
 (p6)	st8.spill [r2]=r8	// store return value in slot for r8 and set unat bit
@@ -541,78 +529,57 @@
 END(ia64_ret_from_syscall)
 	// fall through
 GLOBAL_ENTRY(ia64_leave_kernel)
-	// check & deliver software interrupts:
-
 	PT_REGS_UNWIND_INFO(0)
-#ifdef CONFIG_SMP
-	adds r2=IA64_TASK_PROCESSOR_OFFSET,r13
-	movl r3=irq_stat		// softirq_active
-	;;
-	ld4 r2=[r2]
+	cmp.eq p16,p0=r0,r0			// set the "first_time" flag
+	movl r15=PERCPU_ADDR+IA64_CPU_SOFTIRQ_ACTIVE_OFFSET  // r15 = &cpu_data.softirq.active
 	;;
-	shl r2=r2,SMP_CACHE_SHIFT	// can't use shladd here...
+	ld8 r2=[r15]
+	movl r14=.restart
 	;;
-	add r3=r2,r3
-#else
-	movl r3=irq_stat		// softirq_active
+	lfetch.fault [sp]
+	shr.u r3=r2,32			// r3 = cpu_data.softirq.mask
+	MOVBR(.ret.sptk,rp,r14,.restart)
+.restart:
+	adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13
+	adds r18=IA64_TASK_SIGPENDING_OFFSET,r13
+#ifdef CONFIG_PERFMON
+	adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13
 #endif
 	;;
-	ld8 r2=[r3]		// r3 (softirq_active+softirq_mask) is guaranteed to be 8-byte aligned!
-	;;
-	shr r3=r2,32
+	ld8 r17=[r17]				// load current->need_resched
+	ld4 r18=[r18]				// load current->sigpending
+(p16)	and r2=r2,r3				// r2 <- (softirq.active & softirq.mask)
 	;;
-	and r2=r2,r3
+#ifdef CONFIG_PERFMON
+	ld8 r19=[r19]				// load current->task.pfm_notify
+#endif
+(p16)	cmp4.ne.unc p6,p0=r2,r0			// p6 <- (softirq.active & softirq.mask) != 0
+(pUser)	cmp.ne.unc p7,p0=r17,r0			// current->need_resched != 0?
 	;;
-	cmp4.ne p6,p7=r2,r0
-(p6)	br.call.spnt.many rp=invoke_do_softirq
-1:
-(pKern)	br.cond.dpnt.many restore_all	// yup -> skip check for rescheduling & signal delivery
-
-	// call schedule() until we find a task that doesn't have need_resched set:
-
-back_from_resched:
-	{ .mii
-	  adds r2=IA64_TASK_NEED_RESCHED_OFFSET,r13
-	  mov r3=ip
-	  adds r14=IA64_TASK_SIGPENDING_OFFSET,r13
-	}
+(pUser)	cmp.ne.unc p8,p0=r18,r0			// current->sigpending != 0?
+#ifdef CONFIG_PERFMON
+	cmp.ne p9,p0=r19,r0			// current->task.pfm_notify != 0?
+#endif
+	cmp.ne p16,p0=r0,r0			// clear the "first_time" flag
 	;;
-	ld8 r2=[r2]
-	ld4 r14=[r14]
-	mov rp=r3			// arrange for schedule() to return to back_from_resched
+# if __GNUC__ < 3
+(p6)	br.call.spnt.many b7=invoke_do_softirq
+# else
+(p6)	br.call.spnt.many b7=do_softirq
+# endif
+#ifdef CONFIG_PERFMON
+(p9)	br.call.spnt.many b7=pfm_overflow_notify
+#endif
+# if __GNUC__ < 3
+(p7)	br.call.spnt.many b7=invoke_schedule
+#else
+(p7)	br.call.spnt.many b7=schedule
+#endif
+	adds r2=PT(R8)+16,r12
+	adds r3=PT(R9)+16,r12
+(p8)	br.call.spnt.many b7=handle_signal_delivery	// check & deliver pending signals
 	;;
-	cmp.ne p6,p0=r2,r0
-	cmp.ne p2,p0=r14,r0		// NOTE: pKern is an alias for p2!!
-	srlz.d
-(p6)	br.call.spnt.many b6=invoke_schedule	// ignore return value
-2:
-	// check & deliver pending signals:
-(p2)	br.call.spnt.few rp=handle_signal_delivery
-.ret9:
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-	// Check for lost ticks
-	rsm psr.i
-	mov r2 = ar.itc
-	movl r14 = 1000			// latency tolerance
-	mov r3 = cr.itm
-	;;
-	sub r2 = r2, r3
-	;;
-	sub r2 = r2, r14
-	;;
-	cmp.ge p6,p7 = r2, r0
-(p6)	br.call.spnt.few rp=invoke_ia64_reset_itm
-.ret10:
-	;;
-	ssm psr.i
-#endif 
-restore_all:
-
 	// start restoring the state saved on the kernel stack (struct pt_regs):
-
-	adds r2=IA64_PT_REGS_R8_OFFSET+16,r12
-	adds r3=IA64_PT_REGS_R8_OFFSET+24,r12
-	;;
 	ld8.fill r8=[r2],16
 	ld8.fill r9=[r3],16
 	;;
@@ -643,6 +610,9 @@
 	ld8.fill r30=[r2],16
 	ld8.fill r31=[r3],16
 	;;
+	rsm psr.i | psr.ic	// initiate turning off of interrupts & interruption collection
+	invala			// invalidate ALAT
+	;;
 	ld8 r1=[r2],16		// ar.ccv
 	ld8 r13=[r3],16		// ar.fpsr
 	;;
@@ -658,14 +628,11 @@
 	mov ar.ccv=r1
 	mov ar.fpsr=r13
 	mov b0=r14
-	// turn off interrupts, interrupt collection
-	rsm psr.i | psr.ic
 	;;
-	srlz.i			// EAS 2.5
+	srlz.i			// ensure interrupts & interruption collection are off
 	mov b7=r15
 	;;
-	invala			// invalidate ALAT
-	bsw.0;;			// switch back to bank 0 (must be last in insn group)
+	bsw.0			// switch back to bank 0
 	;;
 #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
 	nop.i 0x0
@@ -683,17 +650,18 @@
 	;;
 	ld8 rCRIFS=[r16],16	// load cr.ifs
 	ld8 rARUNAT=[r17],16	// load ar.unat
+	cmp.eq p9,p0=r0,r0	// set p9 to indicate that we should restore cr.ifs
 	;;
 	ld8 rARPFS=[r16],16	// load ar.pfs
 	ld8 rARRSC=[r17],16	// load ar.rsc
 	;;
 	ld8 rARRNAT=[r16],16	// load ar.rnat (may be garbage)
-	ld8 rARBSPSTORE=[r17],16	// load ar.bspstore (may be garbage)
+	ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage)
 	;;
 	ld8 rARPR=[r16],16	// load predicates
 	ld8 rB6=[r17],16	// load b6
 	;;
-	ld8 r18=[r16],16	// load ar.rsc value for "loadrs"
+	ld8 r19=[r16],16	// load ar.rsc value for "loadrs"
 	ld8.fill r1=[r17],16	// load r1
 	;;
 	ld8.fill r2=[r16],16
@@ -701,62 +669,102 @@
 	;;
 	ld8.fill r12=[r16],16
 	ld8.fill r13=[r17],16
-	extr.u r19=rCRIPSR,32,2	// extract ps.cpl
 	;;
-	ld8.fill r14=[r16],16
-	ld8.fill r15=[r17],16
-	cmp.eq p6,p7=r0,r19	// are we returning to kernel mode? (psr.cpl==0)
+	ld8.fill r14=[r16]
+	ld8.fill r15=[r17]
+	shr.u r18=r19,16	// get byte size of existing "dirty" partition
 	;;
-	mov b6=rB6
-	mov ar.pfs=rARPFS
-(p6)	br.cond.dpnt.few skip_rbs_switch
-
+	mov r16=ar.bsp		// get existing backing store pointer
+	movl r17=PERCPU_ADDR+IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET
+	;;
+	ld4 r17=[r17]		// r17 = cpu_data->phys_stacked_size_p8
+(pKern)	br.cond.dpnt.few skip_rbs_switch
 	/*
 	 * Restore user backing store.
 	 *
 	 * NOTE: alloc, loadrs, and cover can't be predicated.
-	 *
-	 * XXX This needs some scheduling/tuning once we believe it
-	 *     really does work as intended.
 	 */
-	mov r16=ar.bsp			// get existing backing store pointer
 (pNonSys) br.cond.dpnt.few dont_preserve_current_frame
 	cover				// add current frame into dirty partition
 	;;
-	mov rCRIFS=cr.ifs		// fetch the cr.ifs value that "cover" produced
-	mov r17=ar.bsp			// get new backing store pointer
-	;;
-	sub r16=r17,r16			// calculate number of bytes that were added to rbs
+	mov r19=ar.bsp			// get new backing store pointer
+	sub r16=r16,r18			// krbs = old bsp - size of dirty partition
+	cmp.ne p9,p0=r0,r0		// clear p9 to skip restore of cr.ifs
 	;;
-	shl r16=r16,16			// shift additional frame size into position for loadrs
+	sub r19=r19,r16			// calculate total byte size of dirty partition
+	add r18=64,r18			// don't force in0-in7 into memory...
 	;;
-	add r18=r16,r18			// adjust the loadrs value
+	shl r19=r19,16			// shift size of dirty partition into loadrs position
 	;;
 dont_preserve_current_frame:
-	alloc r16=ar.pfs,0,0,0,0	// drop the current call frame (noop for syscalls)
-	;;
-	mov ar.rsc=r18			// load ar.rsc to be used for "loadrs"
-#ifdef CONFIG_IA32_SUPPORT
-	tbit.nz p6,p0=rCRIPSR,IA64_PSR_IS_BIT
+	/*
+	 * To prevent leaking bits between the kernel and user-space,
+	 * we must clear the stacked registers in the "invalid" partition here.
+	 * Not pretty, but at least it's fast (3.34 registers/cycle).
+	 * Architecturally, this loop could go at 4.67 registers/cycle, but that would
+	 * oversubscribe Itanium.
+	 */
+#	define pRecurse	p6
+#	define pReturn	p7
+#	define Nregs	10
+	alloc loc0=ar.pfs,2,Nregs-2,2,0
+	shr.u loc1=r18,9		// RNaTslots <= dirtySize / (64*8) + 1
+	sub r17=r17,r18			// r17 = (physStackedSize + 8) - dirtySize
+	;;
+	mov ar.rsc=r19			// load ar.rsc to be used for "loadrs"
+	shladd in0=loc1,3,r17
+	mov in1=0
+	;;
+	.align 32
+rse_clear_invalid:
+	// cycle 0
+ { .mii
+	alloc loc0=ar.pfs,2,Nregs-2,2,0
+	cmp.lt pRecurse,p0=Nregs*8,in0	// if more than Nregs regs left to clear, (re)curse
+	add out0=-Nregs*8,in0
+}{ .mfb
+	add out1=1,in1			// increment recursion count
+	nop.f 0
+	nop.b 0				// can't do br.call here because of alloc (WAW on CFM)
+	;;
+}{ .mfi	// cycle 1
+	mov loc1=0
+	nop.f 0
+	mov loc2=0
+}{ .mib
+	mov loc3=0
+	mov loc4=0
+(pRecurse) br.call.sptk.few b6=rse_clear_invalid
+
+}{ .mfi	// cycle 2
+	mov loc5=0
+	nop.f 0
+	cmp.ne pReturn,p0=r0,in1	// if recursion count != 0, we need to do a br.ret
+}{ .mib
+	mov loc6=0
+	mov loc7=0
+(pReturn) br.ret.sptk.few b6
+}
+#	undef pRecurse
+#	undef pReturn
+
+	alloc r17=ar.pfs,0,0,0,0	// drop current register frame
 	;;
-(p6)	mov ar.rsc=r0                   // returning to IA32 mode
-#endif
- 	;;
 	loadrs
 	;;
-	mov ar.bspstore=rARBSPSTORE
-	;;
-	mov ar.rnat=rARRNAT	// must happen with RSE in lazy mode
-
 skip_rbs_switch:
+	mov b6=rB6
+	mov ar.pfs=rARPFS
+(pUser)	mov ar.bspstore=rARBSPSTORE
+(p9)	mov cr.ifs=rCRIFS
+	mov cr.ipsr=rCRIPSR
+	mov cr.iip=rCRIIP
+	;;
+(pUser)	mov ar.rnat=rARRNAT	// must happen with RSE in lazy mode
 	mov ar.rsc=rARRSC
 	mov ar.unat=rARUNAT
-	mov cr.ifs=rCRIFS	// restore cr.ifs only if not a (synchronous) syscall
 	mov pr=rARPR,-1
-	mov cr.iip=rCRIIP
-	mov cr.ipsr=rCRIPSR
-	;;
-	rfi;;			// must be last instruction in an insn group
+	rfi
 END(ia64_leave_kernel)
 
 ENTRY(handle_syscall_error)
@@ -784,13 +792,13 @@
 	br.cond.sptk.many ia64_leave_kernel
 END(handle_syscall_error)
 
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
 	/*
 	 * Invoke schedule_tail(task) while preserving in0-in7, which may be needed
 	 * in case a system call gets restarted.
 	 */
 ENTRY(invoke_schedule_tail)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,2,1,0
 	mov loc0=rp
 	mov out0=r8				// Address of previous task
@@ -801,35 +809,24 @@
 	br.ret.sptk.many rp
 END(invoke_schedule_tail)
 
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-
-ENTRY(invoke_ia64_reset_itm)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
-	alloc loc1=ar.pfs,8,2,0,0
-	mov loc0=rp
-	;;
-	UNW(.body)
-	br.call.sptk.many rp=ia64_reset_itm
-.ret12:	;;
-	mov ar.pfs=loc1
-	mov rp=loc0
-	br.ret.sptk.many rp
-END(invoke_ia64_reset_itm)
-
-#endif /* CONFIG_IA64_SOFTSDV_HACKS */
+# endif /* CONFIG_SMP */
 
+#if __GNUC__ < 3
 	/*
 	 * Invoke do_softirq() while preserving in0-in7, which may be needed
-	 * in case a system call gets restarted.
+	 * in case a system call gets restarted.  Note that declaring do_softirq()
+	 * with asmlinkage() is NOT enough because that will only preserve as many
+	 * registers as there are formal arguments.
+	 *
+	 * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage
+	 *	renders all eight input registers (in0-in7) as "untouchable".
 	 */
 ENTRY(invoke_do_softirq)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,2,0,0
 	mov loc0=rp
 	;;
-	UNW(.body)
+	.body
 	br.call.sptk.few rp=do_softirq
 .ret13:	mov ar.pfs=loc1
 	mov rp=loc0
@@ -838,27 +835,33 @@
 
 	/*
 	 * Invoke schedule() while preserving in0-in7, which may be needed
-	 * in case a system call gets restarted.
+	 * in case a system call gets restarted.  Note that declaring schedule()
+	 * with asmlinkage() is NOT enough because that will only preserve as many
+	 * registers as there are formal arguments.
+	 *
+	 * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage
+	 *	renders all eight input registers (in0-in7) as "untouchable".
 	 */
 ENTRY(invoke_schedule)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,2,0,0
 	mov loc0=rp
 	;;
-	UNW(.body)
+	.body
 	br.call.sptk.few rp=schedule
 .ret14:	mov ar.pfs=loc1
 	mov rp=loc0
 	br.ret.sptk.many rp
 END(invoke_schedule)
 
-	//
-	// Setup stack and call ia64_do_signal.  Note that pSys and pNonSys need to
-	// be set up by the caller.  We declare 8 input registers so the system call
-	// args get preserved, in case we need to restart a system call.
-	//
+#endif /* __GNUC__ < 3 */
+
+	/*
+	 * Setup stack and call ia64_do_signal.  Note that pSys and pNonSys need to
+	 * be set up by the caller.  We declare 8 input registers so the system call
+	 * args get preserved, in case we need to restart a system call.
+	 */
 ENTRY(handle_signal_delivery)
-#ifdef CONFIG_IA64_NEW_UNWIND
 	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
 	mov r9=ar.unat
@@ -882,26 +885,9 @@
 	mov ar.unat=r9
 	mov ar.pfs=loc1
 	br.ret.sptk.many rp
-#else /* !CONFIG_IA64_NEW_UNWIND */
-	.prologue
-	alloc r16=ar.pfs,8,0,3,0 // preserve all eight input regs in case of syscall restart!
-	DO_SAVE_SWITCH_STACK
-	UNW(.body)
-
-	mov out0=0				// there is no "oldset"
-	adds out1=16,sp				// out1=&sigscratch
-	.pred.rel.mutex pSys, pNonSys
-(pSys)	mov out2=1				// out2==1 => we're in a syscall
-(pNonSys) mov out2=0				// out2==0 => not a syscall
-	br.call.sptk.few rp=ia64_do_signal
-.ret16:	// restore the switch stack (ptrace may have modified it)
-	DO_LOAD_SWITCH_STACK( )
-	br.ret.sptk.many rp
-#endif /* !CONFIG_IA64_NEW_UNWIND */
 END(handle_signal_delivery)
 
 GLOBAL_ENTRY(sys_rt_sigsuspend)
-#ifdef CONFIG_IA64_NEW_UNWIND
 	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
 	alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
 	mov r9=ar.unat
@@ -924,87 +910,43 @@
 	mov ar.unat=r9
 	mov ar.pfs=loc1
 	br.ret.sptk.many rp
-#else /* !CONFIG_IA64_NEW_UNWIND */
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2))
-	alloc r16=ar.pfs,2,0,3,0
-	DO_SAVE_SWITCH_STACK
-	UNW(.body)
-
-	mov out0=in0				// mask
-	mov out1=in1				// sigsetsize
-	adds out2=16,sp				// out1=&sigscratch
-	br.call.sptk.many rp=ia64_rt_sigsuspend
-.ret18:	// restore the switch stack (ptrace may have modified it)
-	DO_LOAD_SWITCH_STACK( )
-	br.ret.sptk.many rp
-#endif /* !CONFIG_IA64_NEW_UNWIND */
 END(sys_rt_sigsuspend)
 
 ENTRY(sys_rt_sigreturn)
-#ifdef CONFIG_IA64_NEW_UNWIND
-	.regstk 0,0,3,0	// inherited from gate.s:invoke_sighandler()
 	PT_REGS_UNWIND_INFO(0)
+	alloc r2=ar.pfs,0,0,1,0
 	.prologue
 	PT_REGS_SAVES(16)
 	adds sp=-16,sp
 	.body
-	cmp.eq pNonSys,p0=r0,r0			// sigreturn isn't a normal syscall...
+	cmp.eq pNonSys,pSys=r0,r0		// sigreturn isn't a normal syscall...
 	;;
 	adds out0=16,sp				// out0 = &sigscratch
 	br.call.sptk.few rp=ia64_rt_sigreturn
-.ret19:	adds sp=16,sp		// doesn't drop pt_regs, so don't mark it as restoring sp!
-	PT_REGS_UNWIND_INFO(0)	// instead, create a new body section with the smaller frame
+.ret19:	.restore sp 0
+	adds sp=16,sp
 	;;
 	ld8 r9=[sp]				// load new ar.unat
-	mov b7=r8
+	MOVBR(.sptk,b7,r8,ia64_leave_kernel)
 	;;
 	mov ar.unat=r9
 	br b7
-#else /* !CONFIG_IA64_NEW_UNWIND */
-	.regstk 0,0,3,0	// inherited from gate.s:invoke_sighandler()
-	PT_REGS_UNWIND_INFO(0)
-	UNW(.prologue)
-	UNW(.fframe IA64_PT_REGS_SIZE+IA64_SWITCH_STACK_SIZE)
-	UNW(.spillsp rp, PT(CR_IIP)+IA64_SWITCH_STACK_SIZE)
-	UNW(.spillsp ar.pfs, PT(CR_IFS)+IA64_SWITCH_STACK_SIZE)
-	UNW(.spillsp ar.unat, PT(AR_UNAT)+IA64_SWITCH_STACK_SIZE)
-	UNW(.spillsp pr, PT(PR)+IA64_SWITCH_STACK_SIZE)
-	adds sp=-IA64_SWITCH_STACK_SIZE,sp
-	cmp.eq pNonSys,p0=r0,r0			// sigreturn isn't a normal syscall...
-	;;
-	UNW(.body)
-
-	adds out0=16,sp				// out0 = &sigscratch
-	br.call.sptk.few rp=ia64_rt_sigreturn
-.ret20:	adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
-	;;
-	ld8 r9=[r3]			// load new ar.unat
-	mov b7=r8
-	;;
-	PT_REGS_UNWIND_INFO(0)
-	adds sp=IA64_SWITCH_STACK_SIZE,sp	// drop (dummy) switch-stack frame
-	mov ar.unat=r9
-	br b7
-#endif /* !CONFIG_IA64_NEW_UNWIND */
 END(sys_rt_sigreturn)
 
 GLOBAL_ENTRY(ia64_prepare_handle_unaligned)
 	//
-	// r16 = fake ar.pfs, we simply need to make sure 
+	// r16 = fake ar.pfs, we simply need to make sure
 	// privilege is still 0
 	//
-	PT_REGS_UNWIND_INFO(0)
-	mov r16=r0 				
-	UNW(.prologue)
+	mov r16=r0
+	.prologue
 	DO_SAVE_SWITCH_STACK
 	br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt
 .ret21:	.body
-	DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO(0))
+	DO_LOAD_SWITCH_STACK
 	br.cond.sptk.many rp			  // goes to ia64_leave_kernel
 END(ia64_prepare_handle_unaligned)
 
-#ifdef CONFIG_IA64_NEW_UNWIND
-
 	//
 	// unw_init_running(void (*callback)(info, arg), void *arg)
 	//
@@ -1050,8 +992,6 @@
 	br.ret.sptk.many rp
 END(unw_init_running)
 
-#endif
-
 	.rodata
 	.align 8
 	.globl sys_call_table
@@ -1229,7 +1169,7 @@
 	data8 sys_accept
 	data8 sys_getsockname			// 1195
 	data8 sys_getpeername
-	data8 sys_socketpair 
+	data8 sys_socketpair
 	data8 sys_send
 	data8 sys_sendto
 	data8 sys_recv				// 1200
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h
--- v2.4.3/linux/arch/ia64/kernel/entry.h	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/kernel/entry.h	Thu Apr  5 12:51:47 2001
@@ -1,65 +1,77 @@
+#include <linux/config.h>
+
+/* XXX fixme */
+#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
+# define MOVBR(type,br,gr,lbl)	mov br=gr
+#else
+# define MOVBR(type,br,gr,lbl)	mov##type br=gr,lbl
+#endif
+
 /*
  * Preserved registers that are shared between code in ivt.S and entry.S.  Be
  * careful not to step on these!
  */
 #define pKern		p2	/* will leave_kernel return to kernel-mode? */
+#define pUser		p3	/* will leave_kernel return to user-mode? */
 #define pSys		p4	/* are we processing a (synchronous) system call? */
 #define pNonSys		p5	/* complement of pSys */
 
-#define PT(f)		(IA64_PT_REGS_##f##_OFFSET + 16)
-#define SW(f)		(IA64_SWITCH_STACK_##f##_OFFSET + 16)
+#define PT(f)		(IA64_PT_REGS_##f##_OFFSET)
+#define SW(f)		(IA64_SWITCH_STACK_##f##_OFFSET)
 
-#define PT_REGS_SAVES(off)				\
-	UNW(.unwabi @svr4, 'i');			\
-	UNW(.fframe IA64_PT_REGS_SIZE+16+(off));	\
-	UNW(.spillsp rp, PT(CR_IIP)+(off));		\
-	UNW(.spillsp ar.pfs, PT(CR_IFS)+(off));		\
-	UNW(.spillsp ar.unat, PT(AR_UNAT)+(off));	\
-	UNW(.spillsp ar.fpsr, PT(AR_FPSR)+(off));	\
-	UNW(.spillsp pr, PT(PR)+(off));
+#define PT_REGS_SAVES(off)			\
+	.unwabi @svr4, 'i';			\
+	.fframe IA64_PT_REGS_SIZE+16+(off);	\
+	.spillsp rp, PT(CR_IIP)+16+(off);	\
+	.spillsp ar.pfs, PT(CR_IFS)+16+(off);	\
+	.spillsp ar.unat, PT(AR_UNAT)+16+(off);	\
+	.spillsp ar.fpsr, PT(AR_FPSR)+16+(off);	\
+	.spillsp pr, PT(PR)+16+(off);
 
 #define PT_REGS_UNWIND_INFO(off)		\
-	UNW(.prologue);				\
+	.prologue;				\
 	PT_REGS_SAVES(off);			\
-	UNW(.body)
+	.body
 
-#define SWITCH_STACK_SAVES(off)									  \
-	UNW(.savesp ar.unat,SW(CALLER_UNAT)+(off)); UNW(.savesp ar.fpsr,SW(AR_FPSR)+(off));	  \
-	UNW(.spillsp f2,SW(F2)+(off)); UNW(.spillsp f3,SW(F3)+(off));				  \
-	UNW(.spillsp f4,SW(F4)+(off)); UNW(.spillsp f5,SW(F5)+(off));				  \
-	UNW(.spillsp f16,SW(F16)+(off)); UNW(.spillsp f17,SW(F17)+(off));			  \
-	UNW(.spillsp f18,SW(F18)+(off)); UNW(.spillsp f19,SW(F19)+(off));			  \
-	UNW(.spillsp f20,SW(F20)+(off)); UNW(.spillsp f21,SW(F21)+(off));			  \
-	UNW(.spillsp f22,SW(F22)+(off)); UNW(.spillsp f23,SW(F23)+(off));			  \
-	UNW(.spillsp f24,SW(F24)+(off)); UNW(.spillsp f25,SW(F25)+(off));			  \
-	UNW(.spillsp f26,SW(F26)+(off)); UNW(.spillsp f27,SW(F27)+(off));			  \
-	UNW(.spillsp f28,SW(F28)+(off)); UNW(.spillsp f29,SW(F29)+(off));			  \
-	UNW(.spillsp f30,SW(F30)+(off)); UNW(.spillsp f31,SW(F31)+(off));			  \
-	UNW(.spillsp r4,SW(R4)+(off)); UNW(.spillsp r5,SW(R5)+(off));				  \
-	UNW(.spillsp r6,SW(R6)+(off)); UNW(.spillsp r7,SW(R7)+(off));				  \
-	UNW(.spillsp b0,SW(B0)+(off)); UNW(.spillsp b1,SW(B1)+(off));				  \
-	UNW(.spillsp b2,SW(B2)+(off)); UNW(.spillsp b3,SW(B3)+(off));				  \
-	UNW(.spillsp b4,SW(B4)+(off)); UNW(.spillsp b5,SW(B5)+(off));				  \
-	UNW(.spillsp ar.pfs,SW(AR_PFS)+(off)); UNW(.spillsp ar.lc,SW(AR_LC)+(off));		  \
-	UNW(.spillsp @priunat,SW(AR_UNAT)+(off));						  \
-	UNW(.spillsp ar.rnat,SW(AR_RNAT)+(off)); UNW(.spillsp ar.bspstore,SW(AR_BSPSTORE)+(off)); \
-	UNW(.spillsp pr,SW(PR)+(off))
+#define SWITCH_STACK_SAVES(off)							\
+	.savesp ar.unat,SW(CALLER_UNAT)+16+(off);				\
+	.savesp ar.fpsr,SW(AR_FPSR)+16+(off);					\
+	.spillsp f2,SW(F2)+16+(off); .spillsp f3,SW(F3)+16+(off);		\
+	.spillsp f4,SW(F4)+16+(off); .spillsp f5,SW(F5)+16+(off);		\
+	.spillsp f16,SW(F16)+16+(off); .spillsp f17,SW(F17)+16+(off);		\
+	.spillsp f18,SW(F18)+16+(off); .spillsp f19,SW(F19)+16+(off);		\
+	.spillsp f20,SW(F20)+16+(off); .spillsp f21,SW(F21)+16+(off);		\
+	.spillsp f22,SW(F22)+16+(off); .spillsp f23,SW(F23)+16+(off);		\
+	.spillsp f24,SW(F24)+16+(off); .spillsp f25,SW(F25)+16+(off);		\
+	.spillsp f26,SW(F26)+16+(off); .spillsp f27,SW(F27)+16+(off);		\
+	.spillsp f28,SW(F28)+16+(off); .spillsp f29,SW(F29)+16+(off);		\
+	.spillsp f30,SW(F30)+16+(off); .spillsp f31,SW(F31)+16+(off);		\
+	.spillsp r4,SW(R4)+16+(off); .spillsp r5,SW(R5)+16+(off);		\
+	.spillsp r6,SW(R6)+16+(off); .spillsp r7,SW(R7)+16+(off);		\
+	.spillsp b0,SW(B0)+16+(off); .spillsp b1,SW(B1)+16+(off);		\
+	.spillsp b2,SW(B2)+16+(off); .spillsp b3,SW(B3)+16+(off);		\
+	.spillsp b4,SW(B4)+16+(off); .spillsp b5,SW(B5)+16+(off);		\
+	.spillsp ar.pfs,SW(AR_PFS)+16+(off); .spillsp ar.lc,SW(AR_LC)+16+(off);	\
+	.spillsp @priunat,SW(AR_UNAT)+16+(off);					\
+	.spillsp ar.rnat,SW(AR_RNAT)+16+(off);					\
+	.spillsp ar.bspstore,SW(AR_BSPSTORE)+16+(off);				\
+	.spillsp pr,SW(PR)+16+(off))
 
 #define DO_SAVE_SWITCH_STACK			\
 	movl r28=1f;				\
 	;;					\
 	.fframe IA64_SWITCH_STACK_SIZE;		\
 	adds sp=-IA64_SWITCH_STACK_SIZE,sp;	\
-	mov b7=r28;				\
+	MOVBR(.ret.sptk,b7,r28,1f);		\
 	SWITCH_STACK_SAVES(0);			\
 	br.cond.sptk.many save_switch_stack;	\
 1:
 
-#define DO_LOAD_SWITCH_STACK(extra)		\
+#define DO_LOAD_SWITCH_STACK			\
 	movl r28=1f;				\
 	;;					\
-	mov b7=r28;				\
+	invala;					\
+	MOVBR(.ret.sptk,b7,r28,1f);		\
 	br.cond.sptk.many load_switch_stack;	\
-1:	UNW(.restore sp);			\
-	extra;					\
+1:	.restore sp;				\
 	adds sp=IA64_SWITCH_STACK_SIZE,sp
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c
--- v2.4.3/linux/arch/ia64/kernel/fw-emu.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/fw-emu.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * PAL & SAL emulation.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * For the HP simulator, this file gets include in boot/bootloader.c.
  * For SoftSDV, this file gets included in sys_softsdv.c.
@@ -22,7 +22,8 @@
 
 #define NUM_MEM_DESCS	2
 
-static char fw_mem[(  sizeof(efi_system_table_t)
+static char fw_mem[(  sizeof(struct ia64_boot_param)
+		    + sizeof(efi_system_table_t)
 		    + sizeof(efi_runtime_services_t)
 		    + 1*sizeof(efi_config_table_t)
 		    + sizeof(struct ia64_sal_systab)
@@ -151,6 +152,14 @@
 	movl r10=0x100000100		/* bus_ratio<<32 (1/256) */
 	movl r11=0x100000064		/* itc_ratio<<32 (1/100) */
 	;;
+1:	cmp.eq p6,p7=19,r28		/* PAL_RSE_INFO */
+(p7)	br.cond.sptk.few 1f
+	mov r8=0			/* status = 0 */
+	mov r9=96			/* num phys stacked */
+	mov r10=0			/* hints */
+	mov r11=0
+	br.cond.sptk.few rp
+
 1:	cmp.eq p6,p7=1,r28		/* PAL_CACHE_FLUSH */
 (p7)	br.cond.sptk.few 1f
 	mov r9=ar.lc
@@ -168,8 +177,7 @@
 	;;
 	mov ar.lc=r9
 	mov r8=r0
-1:
-	br.cond.sptk.few rp
+1:	br.cond.sptk.few rp
 
 stacked:
 	br.ret.sptk.few rp
@@ -249,13 +257,7 @@
 			 * or something platform specific?  The SAL
 			 * doc ain't exactly clear on this...
 			 */
-#if defined(CONFIG_IA64_SOFTSDV_HACKS)
-			r9 =   4000000;
-#elif defined(CONFIG_IA64_SDV)
-			r9 = 300000000;
-#else
 			r9 = 700000000;
-#endif
 			break;
 
 		      case SAL_FREQ_BASE_REALTIME_CLOCK:
@@ -332,7 +334,7 @@
 	return (void *) addr;
 }
 
-void
+struct ia64_boot_param *
 sys_fw_init (const char *args, int arglen)
 {
 	efi_system_table_t *efi_systab;
@@ -358,6 +360,7 @@
 	sal_systab  = (void *) cp; cp += sizeof(*sal_systab);
 	sal_ed      = (void *) cp; cp += sizeof(*sal_ed);
 	efi_memmap  = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
+	bp	    = (void *) cp; cp += sizeof(*bp);
 	cmd_line    = (void *) cp;
 
 	if (args) {
@@ -423,7 +426,7 @@
 	strcpy(sal_systab->product_id, "SN1");
 #endif
 
-	/* fill in an entry point: */	
+	/* fill in an entry point: */
 	sal_ed->type = SAL_DESC_ENTRY_POINT;
 	sal_ed->pal_proc = __pa(pal_desc[0]);
 	sal_ed->sal_proc = __pa(sal_desc[0]);
@@ -440,15 +443,15 @@
 	md->pad = 0;
 	md->phys_addr = 2*MB;
 	md->virt_addr = 0;
-	md->num_pages = (64*MB) >> 12;	/* 64MB (in 4KB pages) */
+	md->num_pages = (128*MB) >> 12;	/* 128MB (in 4KB pages) */
 	md->attribute = EFI_MEMORY_WB;
 
 	/* descriptor for firmware emulator: */
 	md = &efi_memmap[1];
-	md->type = EFI_RUNTIME_SERVICES_DATA;
+	md->type = EFI_PAL_CODE;
 	md->pad = 0;
 	md->phys_addr = 1*MB;
-	md->virt_addr = 0;
+	md->virt_addr = 1*MB;
 	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
 	md->attribute = EFI_MEMORY_WB;
 
@@ -468,7 +471,6 @@
 	md->attribute = EFI_MEMORY_WB;
 #endif
 
-	bp = id(ZERO_PAGE_ADDR);
 	bp->efi_systab = __pa(&fw_mem);
 	bp->efi_memmap = __pa(efi_memmap);
 	bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t);
@@ -479,6 +481,7 @@
 	bp->console_info.num_rows = 25;
 	bp->console_info.orig_x = 0;
 	bp->console_info.orig_y = 24;
-	bp->num_pci_vectors = 0;
 	bp->fpswa = 0;
+
+	return bp;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S
--- v2.4.3/linux/arch/ia64/kernel/gate.S	Fri Jul 14 16:08:11 2000
+++ linux/arch/ia64/kernel/gate.S	Thu Apr  5 12:51:47 2001
@@ -1,10 +1,9 @@
 /*
- * This file contains the code that gets mapped at the upper end of
- * each task's text region.  For now, it contains the signal
- * trampoline code only.
+ * This file contains the code that gets mapped at the upper end of each task's text
+ * region.  For now, it contains the signal trampoline code only.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <asm/asmmacro.h>
@@ -14,11 +13,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 
-	.psr abi64
-	.psr lsb
-	.lsb
-
-	.section __gate_section,"ax"
+	.section .text.gate,"ax"
 
 	.align PAGE_SIZE
 
@@ -51,28 +46,24 @@
 	 *   |            space              |
 	 *   +-------------------------------+ <-- sp
 	 *
-	 * The register stack looks _exactly_ the way it looked at the
-	 * time the signal occurred.  In other words, we're treading
-	 * on a potential mine-field: each incoming general register
-	 * may be a NaT value (includeing sp, in which case the process
-	 * ends up dying with a SIGSEGV).
+	 * The register stack looks _exactly_ the way it looked at the time the signal
+	 * occurred.  In other words, we're treading on a potential mine-field: each
+	 * incoming general register may be a NaT value (including sp, in which case the
+	 * process ends up dying with a SIGSEGV).
 	 *
-	 * The first need to do is a cover to get the registers onto
-	 * the backing store.  Once that is done, we invoke the signal
-	 * handler which may modify some of the machine state.  After
-	 * returning from the signal handler, we return control to the
-	 * previous context by executing a sigreturn system call.  A
-	 * signal handler may call the rt_sigreturn() function to
-	 * directly return to a given sigcontext.  However, the
-	 * user-level sigreturn() needs to do much more than calling
-	 * the rt_sigreturn() system call as it needs to unwind the
-	 * stack to restore preserved registers that may have been
-	 * saved on the signal handler's call stack.
+	 * The first need to do is a cover to get the registers onto the backing store.
+	 * Once that is done, we invoke the signal handler which may modify some of the
+	 * machine state.  After returning from the signal handler, we return control to
+	 * the previous context by executing a sigreturn system call.  A signal handler
+	 * may call the rt_sigreturn() function to directly return to a given sigcontext.
+	 * However, the user-level sigreturn() needs to do much more than calling the
+	 * rt_sigreturn() system call as it needs to unwind the stack to restore preserved
+	 * registers that may have been saved on the signal handler's call stack.
 	 *
 	 * On entry:
 	 *	r2	= signal number
 	 *	r3	= plabel of signal handler
-	 *	r15	= new register backing store (ignored)
+	 *	r15	= new register backing store
 	 *	[sp+16] = sigframe
 	 */
 
@@ -153,7 +144,7 @@
 
 ENTRY(setup_rbs)
 	flushrs					// must be first in insn
-	mov ar.rsc=r0				// put RSE into enforced lazy mode
+	mov ar.rsc=0				// put RSE into enforced lazy mode
 	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
 	mov r14=ar.rnat				// get rnat as updated by flushrs
@@ -167,7 +158,7 @@
 
 ENTRY(restore_rbs)
 	flushrs
-	mov ar.rsc=r0				// put RSE into enforced lazy mode
+	mov ar.rsc=0				// put RSE into enforced lazy mode
 	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
 	ld8 r14=[r16]				// get new rnat
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S
--- v2.4.3/linux/arch/ia64/kernel/head.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/head.S	Thu Apr  5 12:51:47 2001
@@ -5,8 +5,9 @@
  * to set up the kernel's global pointer and jump to the kernel
  * entry point.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Intel Corp.
@@ -18,16 +19,15 @@
 
 #include <asm/asmmacro.h>
 #include <asm/fpu.h>
-#include <asm/pal.h>
+#include <asm/kregs.h>
+#include <asm/mmu_context.h>
 #include <asm/offsets.h>
+#include <asm/pal.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
-	.psr abi64
-	.psr lsb
-	.lsb
-
 	.section __special_page_section,"ax"
 
 	.global empty_zero_page
@@ -38,29 +38,66 @@
 swapper_pg_dir:
 	.skip PAGE_SIZE
 
-	.global empty_bad_page
-empty_bad_page:
-	.skip PAGE_SIZE
-
-	.global empty_bad_pte_table
-empty_bad_pte_table:
-	.skip PAGE_SIZE
-
-	.global empty_bad_pmd_table
-empty_bad_pmd_table:
-	.skip PAGE_SIZE
-
 	.rodata
 halt_msg:
 	stringz "Halting kernel\n"
 
 	.text
 
+	.global start_ap
+
+	/*
+	 * Start the kernel.  When the bootloader passes control to _start(), r28
+	 * points to the address of the boot parameter area.  Execution reaches
+	 * here in physical mode.
+	 */
 GLOBAL_ENTRY(_start)
-	UNW(.prologue)
-	UNW(.save rp, r4)		// terminate unwind chain with a NULL rp
-	UNW(mov r4=r0)
-	UNW(.body)
+start_ap:
+	.prologue
+	.save rp, r4		// terminate unwind chain with a NULL rp
+	mov r4=r0
+	.body
+
+	/*
+	 * Initialize the region register for region 7 and install a translation register
+	 * that maps the kernel's text and data:
+	 */
+	rsm psr.i | psr.ic
+	mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (_PAGE_SIZE_64M << 2))
+	;;
+	srlz.i
+	mov r18=_PAGE_SIZE_64M<<2
+	movl r17=PAGE_OFFSET + 64*1024*1024
+	;;
+	mov rr[r17]=r16
+	mov cr.itir=r18
+	mov cr.ifa=r17
+	mov r16=IA64_TR_KERNEL
+	movl r18=(64*1024*1024 | PAGE_KERNEL)
+	;;
+	srlz.i
+	;;
+	itr.i itr[r16]=r18
+	;;
+	itr.d dtr[r16]=r18
+	;;
+	srlz.i
+
+	/*
+	 * Switch into virtual mode:
+	 */
+	movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN)
+	;;
+	mov cr.ipsr=r16
+	movl r17=1f
+	;;
+	mov cr.iip=r17
+	mov cr.ifs=r0
+	;;
+	rfi
+	;;
+1:	// now we are in virtual mode
+
 	// set IVT entry point---can't access I/O ports without it
 	movl r3=ia64_ivt
 	;;
@@ -74,7 +111,7 @@
 	;;
 
 #ifdef CONFIG_IA64_EARLY_PRINTK
-	mov r3=(6<<8) | (28<<2)
+	mov r3=(6<<8) | (_PAGE_SIZE_64M<<2)
 	movl r2=6<<61
 	;;
 	mov rr[r2]=r3
@@ -83,27 +120,32 @@
 	;;
 #endif
 
-#define isAP	p2	// are we booting an Application Processor (not the BSP)?
+#define isAP	p2	// are we an Application Processor?
+#define isBP	p3	// are we the Bootstrap Processor?
 
-	// Find the init_task for the currently booting CPU.  At poweron, and in
-	// UP mode, cpu_now_booting is 0
+	/*
+	 * Find the init_task for the currently booting CPU.  At poweron, and in
+	 * UP mode, cpu_now_booting is 0.
+	 */
 	movl r3=cpu_now_booting
  	;;
-	ld4 r3=[r3]
+	ld4 r3=[r3]		// r3 <- smp_processor_id()
 	movl r2=init_tasks
-	;; 
+	;;
 	shladd r2=r3,3,r2
 	;;
 	ld8 r2=[r2]
-	cmp4.ne isAP,p0=r3,r0	// p9 == true if this is an application processor (ap)
+	cmp4.ne isAP,isBP=r3,r0
 	;;			// RAW on r2
 	extr r3=r2,0,61		// r3 == phys addr of task struct
 	;;
 
-	// load the "current" pointer (r13) and ar.k6 with the current task 
+	// load the "current" pointer (r13) and ar.k6 with the current task
 	mov r13=r2
-	mov ar.k6=r3		// Physical address
-	;;
+	mov IA64_KR(CURRENT)=r3		// Physical address
+
+	// initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL)
+	mov IA64_KR(CURRENT_STACK)=1
 	/*
 	 * Reserve space at the top of the stack for "struct pt_regs".  Kernel threads
 	 * don't store interesting values in that structure, but the space still needs
@@ -113,14 +155,18 @@
 	 */
 	addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2
 	addl r2=IA64_RBS_OFFSET,r2	// initialize the RSE
-	mov ar.rsc=r0		// place RSE in enforced lazy mode
+	mov ar.rsc=0		// place RSE in enforced lazy mode
 	;;
-	mov ar.bspstore=r2	// establish the new RSE stack
+	loadrs			// clear the dirty partition
 	;;
-	loadrs			// load zero bytes from the register stack
+	mov ar.bspstore=r2	// establish the new RSE stack
 	;;
 	mov ar.rsc=0x3		// place RSE in eager mode
+
+(isBP)	dep r28=-1,r28,61,3	// make address virtual
+(isBP)	movl r2=ia64_boot_param
 	;;
+(isBP)	st8 [r2]=r28		// save the address of the boot param area passed by the bootloader
 
 #ifdef CONFIG_IA64_EARLY_PRINTK
 	.rodata
@@ -135,16 +181,12 @@
 1:	// force new bundle
 #endif /* CONFIG_IA64_EARLY_PRINTK */
 
-	alloc r2=ar.pfs,8,0,2,0
-	;;
 #ifdef CONFIG_SMP
 (isAP)	br.call.sptk.few rp=smp_callin
 .ret0:
 (isAP)	br.cond.sptk.few self
 #endif
 
-#undef isAP
-
 	// This is executed by the bootstrap processor (bsp) only:
 
 #ifdef CONFIG_IA64_FW_EMU
@@ -153,9 +195,11 @@
 .ret1:
 #endif
 	br.call.sptk.few rp=start_kernel
-.ret2:	addl r2=@ltoff(halt_msg),gp
+.ret2:	addl r3=@ltoff(halt_msg),gp
+	;;
+	alloc r2=ar.pfs,8,0,2,0
 	;;
-	ld8 out0=[r2]
+	ld8 out0=[r3]
 	br.call.sptk.few b0=console_print
 self:	br.sptk.few self		// endless loop
 END(_start)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c
--- v2.4.3/linux/arch/ia64/kernel/ia64_ksyms.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/ia64_ksyms.c	Thu Apr  5 12:51:47 2001
@@ -24,8 +24,11 @@
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strtok);
 
-#include <asm/hw_irq.h>
+#include <linux/irq.h>
 EXPORT_SYMBOL(isa_irq_to_vector_map);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
 
 #include <linux/in6.h>
 #include <asm/checksum.h>
@@ -40,10 +43,14 @@
 EXPORT_SYMBOL(__ia64_memcpy_toio);
 EXPORT_SYMBOL(__ia64_memset_c_io);
 
-#include <asm/irq.h>
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
+#include <asm/semaphore.h>
+EXPORT_SYMBOL_NOVERS(__down);
+EXPORT_SYMBOL_NOVERS(__down_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_trylock);
+EXPORT_SYMBOL_NOVERS(__up);
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
@@ -57,14 +64,20 @@
 EXPORT_SYMBOL(last_cli_ip);
 #endif
 
+#include <asm/pgalloc.h>
+
 #ifdef CONFIG_SMP
 
+EXPORT_SYMBOL(smp_flush_tlb_all);
+
 #include <asm/current.h>
 #include <asm/hardirq.h>
 EXPORT_SYMBOL(synchronize_irq);
 
 #include <asm/smp.h>
 EXPORT_SYMBOL(smp_call_function);
+EXPORT_SYMBOL(smp_call_function_single);
+EXPORT_SYMBOL(cpu_online_map);
 
 #include <linux/smp.h>
 EXPORT_SYMBOL(smp_num_cpus);
@@ -78,7 +91,11 @@
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 
-#endif
+#else /* !CONFIG_SMP */
+
+EXPORT_SYMBOL(__flush_tlb_all);
+
+#endif /* !CONFIG_SMP */
 
 #include <asm/uaccess.h>
 EXPORT_SYMBOL(__copy_user);
@@ -111,3 +128,12 @@
 
 extern unsigned long ia64_iobase;
 EXPORT_SYMBOL(ia64_iobase);
+
+#include <asm/pal.h>
+EXPORT_SYMBOL(ia64_pal_call_phys_stacked);
+EXPORT_SYMBOL(ia64_pal_call_phys_static);
+EXPORT_SYMBOL(ia64_pal_call_stacked);
+EXPORT_SYMBOL(ia64_pal_call_static);
+
+extern struct efi efi;
+EXPORT_SYMBOL(efi);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/iosapic.c linux/arch/ia64/kernel/iosapic.c
--- v2.4.3/linux/arch/ia64/kernel/iosapic.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/iosapic.c	Thu Apr  5 12:51:47 2001
@@ -11,7 +11,7 @@
  * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O APIC code.
  *				In particular, we now have separate handlers for edge
  *				and level triggered interrupts.
- * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation 
+ * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation
  *				PCI to vector mapping, shared PCI interrupts.
  * 00/10/27	D. Mosberger	Document things a bit more to make them more understandable.
  *				Clean up much of the old IOSAPIC cruft.
@@ -79,27 +79,27 @@
 static struct iosapic_irq {
 	char *addr;			/* base address of IOSAPIC */
 	unsigned char base_irq;		/* first irq assigned to this IOSAPIC */
-        char pin;			/* IOSAPIC pin (-1 => not an IOSAPIC irq) */
-	unsigned char dmode 	: 3;	/* delivery mode (see iosapic.h) */
+	char pin;			/* IOSAPIC pin (-1 => not an IOSAPIC irq) */
+	unsigned char dmode	: 3;	/* delivery mode (see iosapic.h) */
 	unsigned char polarity	: 1;	/* interrupt polarity (see iosapic.h) */
 	unsigned char trigger	: 1;	/* trigger mode (see iosapic.h) */
-} iosapic_irq[NR_IRQS];
+} iosapic_irq[IA64_NUM_VECTORS];
 
 /*
  * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector.  If no
  * entry exists, return -1.
  */
-static int 
+static int
 iosapic_irq_to_vector (int irq)
 {
 	int vector;
 
-	for (vector = 0; vector < NR_IRQS; ++vector)
+	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
 		if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq)
 			return vector;
 	return -1;
 }
-		
+
 /*
  * Map PCI pin to the corresponding IA-64 interrupt vector.  If no such mapping exists,
  * return -1.
@@ -137,14 +137,8 @@
 		 (dmode << IOSAPIC_DELIVERY_SHIFT) |
 		 vector);
 
-#ifdef CONFIG_IA64_AZUSA_HACKS
-	/* set Flush Disable bit */
-	if (addr != (char *) 0xc0000000fec00000)
-		low32 |= (1 << 17);
-#endif
-
 	/* dest contains both id and eid */
-	high32 = (dest << IOSAPIC_DEST_SHIFT);	
+	high32 = (dest << IOSAPIC_DEST_SHIFT);
 
 	writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT);
 	writel(high32, addr + IOSAPIC_WINDOW);
@@ -158,16 +152,17 @@
 	/* do nothing... */
 }
 
-static void 
-mask_irq (unsigned int vector)
+static void
+mask_irq (unsigned int irq)
 {
 	unsigned long flags;
 	char *addr;
 	u32 low32;
 	int pin;
+	ia64_vector vec = irq_to_vector(irq);
 
-	addr = iosapic_irq[vector].addr;
-	pin = iosapic_irq[vector].pin;
+	addr = iosapic_irq[vec].addr;
+	pin = iosapic_irq[vec].pin;
 
 	if (pin < 0)
 		return;			/* not an IOSAPIC interrupt! */
@@ -183,16 +178,17 @@
 	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
-static void 
-unmask_irq (unsigned int vector)
+static void
+unmask_irq (unsigned int irq)
 {
 	unsigned long flags;
 	char *addr;
 	u32 low32;
 	int pin;
+	ia64_vector vec = irq_to_vector(irq);
 
-	addr = iosapic_irq[vector].addr;
-	pin = iosapic_irq[vector].pin;
+	addr = iosapic_irq[vec].addr;
+	pin = iosapic_irq[vec].pin;
 	if (pin < 0)
 		return;			/* not an IOSAPIC interrupt! */
 
@@ -209,7 +205,7 @@
 
 
 static void
-iosapic_set_affinity (unsigned int vector, unsigned long mask)
+iosapic_set_affinity (unsigned int irq, unsigned long mask)
 {
 	printk("iosapic_set_affinity: not implemented yet\n");
 }
@@ -219,16 +215,18 @@
  */
 
 static unsigned int
-iosapic_startup_level_irq (unsigned int vector)
+iosapic_startup_level_irq (unsigned int irq)
 {
-	unmask_irq(vector);
+	unmask_irq(irq);
 	return 0;
 }
 
 static void
-iosapic_end_level_irq (unsigned int vector)
+iosapic_end_level_irq (unsigned int irq)
 {
-	writel(vector, iosapic_irq[vector].addr + IOSAPIC_EOI);
+	ia64_vector vec = irq_to_vector(irq);
+
+	writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI);
 }
 
 #define iosapic_shutdown_level_irq	mask_irq
@@ -252,9 +250,9 @@
  */
 
 static unsigned int
-iosapic_startup_edge_irq (unsigned int vector)
+iosapic_startup_edge_irq (unsigned int irq)
 {
-	unmask_irq(vector);
+	unmask_irq(irq);
 	/*
 	 * IOSAPIC simply drops interrupts pended while the
 	 * corresponding pin was masked, so we can't know if an
@@ -264,15 +262,16 @@
 }
 
 static void
-iosapic_ack_edge_irq (unsigned int vector)
+iosapic_ack_edge_irq (unsigned int irq)
 {
+	irq_desc_t *idesc = irq_desc(irq);
 	/*
 	 * Once we have recorded IRQ_PENDING already, we can mask the
 	 * interrupt for real. This prevents IRQ storms from unhandled
 	 * devices.
 	 */
-	if ((irq_desc[vector].status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
-		mask_irq(vector);
+	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
+		mask_irq(irq);
 }
 
 #define iosapic_enable_edge_irq		unmask_irq
@@ -291,7 +290,7 @@
 };
 
 static unsigned int
-iosapic_version (char *addr) 
+iosapic_version (char *addr)
 {
 	/*
 	 * IOSAPIC Version Register return 32 bit structure like:
@@ -335,6 +334,7 @@
 {
 	struct hw_interrupt_type *irq_type;
 	int i, irq, max_pin, vector;
+	irq_desc_t *idesc;
 	unsigned int ver;
 	char *addr;
 	static int first_time = 1;
@@ -342,18 +342,18 @@
 	if (first_time) {
 		first_time = 0;
 
-		for (vector = 0; vector < NR_IRQS; ++vector)
+		for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
 			iosapic_irq[vector].pin = -1;	/* mark as unused */
 
-		/* 
+		/*
 		 * Fetch the PCI interrupt routing table:
 		 */
 #ifdef CONFIG_ACPI_KERNEL_CONFIG
 		acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes);
 #else
 		pci_irq.route =
-			(struct pci_vector_struct *) __va(ia64_boot_param.pci_vectors);
-		pci_irq.num_routes = ia64_boot_param.num_pci_vectors;
+			(struct pci_vector_struct *) __va(ia64_boot_param->pci_vectors);
+		pci_irq.num_routes = ia64_boot_param->num_pci_vectors;
 #endif
 	}
 
@@ -361,8 +361,8 @@
 
 	ver = iosapic_version(addr);
 	max_pin = (ver >> 16) & 0xff;
-	
-	printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", 
+
+	printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n",
 	       (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin);
 
 	if (base_irq == 0)
@@ -385,20 +385,20 @@
 			       irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin,
 			       vector);
 #endif
-		  	irq_type = &irq_type_iosapic_edge;
-			if (irq_desc[vector].handler != irq_type) {
-				if (irq_desc[vector].handler != &no_irq_type)
+			irq_type = &irq_type_iosapic_edge;
+			idesc = irq_desc(vector);
+			if (idesc->handler != irq_type) {
+				if (idesc->handler != &no_irq_type)
 					printk("iosapic_init: changing vector 0x%02x from %s to "
-					       "%s\n", irq, irq_desc[vector].handler->typename,
+					       "%s\n", irq, idesc->handler->typename,
 					       irq_type->typename);
-				irq_desc[vector].handler = irq_type;
+				idesc->handler = irq_type;
 			}
 
 			/* program the IOSAPIC routing table: */
 			set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
 		}
 
-#ifndef CONFIG_IA64_SOFTSDV_HACKS
 	for (i = 0; i < pci_irq.num_routes; i++) {
 		irq = pci_irq.route[i].irq;
 
@@ -428,18 +428,17 @@
 		       iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector);
 # endif
 		irq_type = &irq_type_iosapic_level;
-		if (irq_desc[vector].handler != irq_type){
-			if (irq_desc[vector].handler != &no_irq_type)
+		idesc = irq_desc(vector);
+		if (idesc->handler != irq_type){
+			if (idesc->handler != &no_irq_type)
 				printk("iosapic_init: changing vector 0x%02x from %s to %s\n",
-				       vector, irq_desc[vector].handler->typename,
-				       irq_type->typename);
-			irq_desc[vector].handler = irq_type;
+				       vector, idesc->handler->typename, irq_type->typename);
+			idesc->handler = irq_type;
 		}
 
 		/* program the IOSAPIC routing table: */
 		set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
 	}
-#endif /* !CONFIG_IA64_SOFTSDV_HACKS */
 }
 
 void
@@ -492,7 +491,7 @@
 		 * Nothing to fixup
 		 * Fix out-of-range IRQ numbers
 		 */
-		if (dev->irq >= NR_IRQS)
+		if (dev->irq >= IA64_NUM_VECTORS)
 			dev->irq = 15;	/* Spurious interrupts */
 	}
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c
--- v2.4.3/linux/arch/ia64/kernel/irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/ia64/kernel/irq.c	Thu Apr  5 12:51:47 2001
@@ -63,7 +63,7 @@
 /*
  * Controller mappings for all interrupt sources:
  */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned =
 	{ [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
 
 static void register_irq_proc (unsigned int irq);
@@ -131,6 +131,7 @@
 {
 	int i, j;
 	struct irqaction * action;
+	irq_desc_t *idesc;
 	char *p = buf;
 
 	p += sprintf(p, "           ");
@@ -139,8 +140,9 @@
 	*p++ = '\n';
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
-		action = irq_desc[i].action;
-		if (!action) 
+		idesc = irq_desc(i);
+		action = idesc->action;
+		if (!action)
 			continue;
 		p += sprintf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
@@ -150,7 +152,7 @@
 			p += sprintf(p, "%10u ",
 				kstat.irqs[cpu_logical_map(j)][i]);
 #endif
-		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+		p += sprintf(p, " %14s", idesc->handler->typename);
 		p += sprintf(p, "  %s", action->name);
 
 		for (action=action->next; action; action = action->next)
@@ -193,10 +195,10 @@
 	printk("\n%s, CPU %d:\n", str, cpu);
 	printk("irq:  %d [",irqs_running());
 	for(i=0;i < smp_num_cpus;i++)
-		printk(" %d",local_irq_count(i));
+		printk(" %d",irq_count(i));
 	printk(" ]\nbh:   %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
 	for(i=0;i < smp_num_cpus;i++)
-		printk(" %d",local_bh_count(i));
+		printk(" %d",bh_count(i));
 
 	printk(" ]\nStack dumps:");
 #if defined(__ia64__)
@@ -224,7 +226,7 @@
 		esp &= ~(THREAD_SIZE-1);
 		esp += sizeof(struct task_struct);
 		show_stack((void*)esp);
- 	}
+	}
 #else
 	You lose...
 #endif
@@ -232,7 +234,7 @@
 	show_stack(NULL);
 	printk("\n");
 }
-	
+
 #define MAXCOUNT 100000000
 
 /*
@@ -266,7 +268,7 @@
 # endif
 #endif
 
-static inline void wait_on_irq(int cpu)
+static inline void wait_on_irq(void)
 {
 	int count = MAXCOUNT;
 
@@ -278,7 +280,7 @@
 		 * already executing in one..
 		 */
 		if (!irqs_running())
-			if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+			if (local_bh_count() || !spin_is_locked(&global_bh_lock))
 				break;
 
 		/* Duh, we have to loop. Release the lock to avoid deadlocks */
@@ -290,13 +292,13 @@
 				count = ~0;
 			}
 			__sti();
-			SYNC_OTHER_CORES(cpu);
+			SYNC_OTHER_CORES(smp_processor_id());
 			__cli();
 			if (irqs_running())
 				continue;
 			if (global_irq_lock)
 				continue;
-			if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
+			if (!local_bh_count() && spin_is_locked(&global_bh_lock))
 				continue;
 			if (!test_and_set_bit(0,&global_irq_lock))
 				break;
@@ -320,28 +322,28 @@
 	}
 }
 
-static inline void get_irqlock(int cpu)
+static inline void get_irqlock(void)
 {
 	if (test_and_set_bit(0,&global_irq_lock)) {
 		/* do we already hold the lock? */
-		if (cpu == global_irq_holder)
+		if (smp_processor_id() == global_irq_holder)
 			return;
 		/* Uhhuh.. Somebody else got it. Wait.. */
 		do {
 			do {
 			} while (test_bit(0,&global_irq_lock));
-		} while (test_and_set_bit(0,&global_irq_lock));		
+		} while (test_and_set_bit(0,&global_irq_lock));
 	}
-	/* 
+	/*
 	 * We also to make sure that nobody else is running
-	 * in an interrupt context. 
+	 * in an interrupt context.
 	 */
-	wait_on_irq(cpu);
+	wait_on_irq();
 
 	/*
 	 * Ok, finally..
 	 */
-	global_irq_holder = cpu;
+	global_irq_holder = smp_processor_id();
 }
 
 #define EFLAGS_IF_SHIFT 9
@@ -365,28 +367,24 @@
 #ifdef __ia64__
 	__save_flags(flags);
 	if (flags & IA64_PSR_I) {
-		int cpu = smp_processor_id();
 		__cli();
-		if (!local_irq_count(cpu))
-			get_irqlock(cpu);
+		if (!local_irq_count())
+			get_irqlock();
 	}
 #else
 	__save_flags(flags);
 	if (flags & (1 << EFLAGS_IF_SHIFT)) {
-		int cpu = smp_processor_id();
 		__cli();
-		if (!local_irq_count(cpu))
-			get_irqlock(cpu);
+		if (!local_irq_count())
+			get_irqlock();
 	}
 #endif
 }
 
 void __global_sti(void)
 {
-	int cpu = smp_processor_id();
-
-	if (!local_irq_count(cpu))
-		release_irqlock(cpu);
+	if (!local_irq_count())
+		release_irqlock(smp_processor_id());
 	__sti();
 }
 
@@ -414,7 +412,7 @@
 	retval = 2 + local_enabled;
 
 	/* check for global flags if we're not in an interrupt */
-	if (!local_irq_count(cpu)) {
+	if (!local_irq_count()) {
 		if (local_enabled)
 			retval = 1;
 		if (global_irq_holder == cpu)
@@ -456,9 +454,8 @@
 int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
 {
 	int status;
-	int cpu = smp_processor_id();
 
-	irq_enter(cpu, irq);
+	local_irq_enter(irq);
 
 	status = 1;	/* Force the "do bottom halves" bit */
 
@@ -474,7 +471,7 @@
 		add_interrupt_randomness(irq);
 	__cli();
 
-	irq_exit(cpu, irq);
+	local_irq_exit(irq);
 
 	return status;
 }
@@ -483,11 +480,11 @@
  * Generic enable/disable code: this just calls
  * down into the PIC-specific version for the actual
  * hardware disable after having gotten the irq
- * controller lock. 
+ * controller lock.
  */
 void inline disable_irq_nosync(unsigned int irq)
 {
-	irq_desc_t *desc = irq_desc + irq;
+	irq_desc_t *desc = irq_desc(irq);
 	unsigned long flags;
 
 	spin_lock_irqsave(&desc->lock, flags);
@@ -507,17 +504,17 @@
 	disable_irq_nosync(irq);
 
 #ifdef CONFIG_SMP
-	if (!local_irq_count(smp_processor_id())) {
+	if (!local_irq_count()) {
 		do {
 			barrier();
-		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+		} while (irq_desc(irq)->status & IRQ_INPROGRESS);
 	}
 #endif
 }
 
 void enable_irq(unsigned int irq)
 {
-	irq_desc_t *desc = irq_desc + irq;
+	irq_desc_t *desc = irq_desc(irq);
 	unsigned long flags;
 
 	spin_lock_irqsave(&desc->lock, flags);
@@ -541,26 +538,14 @@
 	spin_unlock_irqrestore(&desc->lock, flags);
 }
 
-void do_IRQ_per_cpu(unsigned long irq, struct pt_regs *regs)
-{
-	irq_desc_t *desc = irq_desc + irq;
-	int cpu = smp_processor_id();
-
-	kstat.irqs[cpu][irq]++;
-
-	desc->handler->ack(irq);
-	handle_IRQ_event(irq, regs, desc->action);
-	desc->handler->end(irq);
-}
-
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
 unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs)
-{	
-	/* 
+{
+	/*
 	 * We ack quickly, we don't want the irq controller
 	 * thinking we're snobs just because some other CPU has
 	 * disabled global interrupts (we have already done the
@@ -571,75 +556,82 @@
 	 * handled by some other CPU. (or is disabled)
 	 */
 	int cpu = smp_processor_id();
-	irq_desc_t *desc = irq_desc + irq;
+	irq_desc_t *desc = irq_desc(irq);
 	struct irqaction * action;
 	unsigned int status;
 
 	kstat.irqs[cpu][irq]++;
-	spin_lock(&desc->lock);
-	desc->handler->ack(irq);
-	/*
-	   REPLAY is when Linux resends an IRQ that was dropped earlier
-	   WAITING is used by probe to mark irqs that are being tested
-	   */
-	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
-	status |= IRQ_PENDING; /* we _want_ to handle it */
 
-	/*
-	 * If the IRQ is disabled for whatever reason, we cannot
-	 * use the action we have.
-	 */
-	action = NULL;
-	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-		action = desc->action;
-		status &= ~IRQ_PENDING; /* we commit to handling */
-		status |= IRQ_INPROGRESS; /* we are handling it */
-	}
-	desc->status = status;
+	if (desc->status & IRQ_PER_CPU) {
+		/* no locking required for CPU-local interrupts: */
+		desc->handler->ack(irq);
+		handle_IRQ_event(irq, regs, desc->action);
+		desc->handler->end(irq);
+	} else {
+		spin_lock(&desc->lock);
+		desc->handler->ack(irq);
+		/*
+		 * REPLAY is when Linux resends an IRQ that was dropped earlier
+		 * WAITING is used by probe to mark irqs that are being tested
+		 */
+		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+		status |= IRQ_PENDING; /* we _want_ to handle it */
 
-	/*
-	 * If there is no IRQ handler or it was disabled, exit early.
-	 * Since we set PENDING, if another processor is handling
-	 * a different instance of this same irq, the other processor
-	 * will take care of it.
-	 */
-	if (!action)
-		goto out;
+		/*
+		 * If the IRQ is disabled for whatever reason, we cannot
+		 * use the action we have.
+		 */
+		action = NULL;
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+			action = desc->action;
+			status &= ~IRQ_PENDING; /* we commit to handling */
+			status |= IRQ_INPROGRESS; /* we are handling it */
+		}
+		desc->status = status;
 
-	/*
-	 * Edge triggered interrupts need to remember
-	 * pending events.
-	 * This applies to any hw interrupts that allow a second
-	 * instance of the same irq to arrive while we are in do_IRQ
-	 * or in the handler. But the code here only handles the _second_
-	 * instance of the irq, not the third or fourth. So it is mostly
-	 * useful for irq hardware that does not mask cleanly in an
-	 * SMP environment.
-	 */
-	for (;;) {
+		/*
+		 * If there is no IRQ handler or it was disabled, exit early.
+		 * Since we set PENDING, if another processor is handling
+		 * a different instance of this same irq, the other processor
+		 * will take care of it.
+		 */
+		if (!action)
+			goto out;
+
+		/*
+		 * Edge triggered interrupts need to remember
+		 * pending events.
+		 * This applies to any hw interrupts that allow a second
+		 * instance of the same irq to arrive while we are in do_IRQ
+		 * or in the handler. But the code here only handles the _second_
+		 * instance of the irq, not the third or fourth. So it is mostly
+		 * useful for irq hardware that does not mask cleanly in an
+		 * SMP environment.
+		 */
+		for (;;) {
+			spin_unlock(&desc->lock);
+			handle_IRQ_event(irq, regs, action);
+			spin_lock(&desc->lock);
+
+			if (!(desc->status & IRQ_PENDING))
+				break;
+			desc->status &= ~IRQ_PENDING;
+		}
+		desc->status &= ~IRQ_INPROGRESS;
+	  out:
+		/*
+		 * The ->end() handler has to deal with interrupts which got
+		 * disabled while the handler was running.
+		 */
+		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
-		handle_IRQ_event(irq, regs, action);
-		spin_lock(&desc->lock);
-		
-		if (!(desc->status & IRQ_PENDING))
-			break;
-		desc->status &= ~IRQ_PENDING;
 	}
-	desc->status &= ~IRQ_INPROGRESS;
-out:
-	/*
-	 * The ->end() handler has to deal with interrupts which got
-	 * disabled while the handler was running.
-	 */
-	desc->handler->end(irq);
-	spin_unlock(&desc->lock);
-
 	return 1;
 }
 
-int request_irq(unsigned int irq, 
+int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
+		unsigned long irqflags,
 		const char * devname,
 		void *dev_id)
 {
@@ -655,7 +647,7 @@
 	 */
 	if (irqflags & SA_SHIRQ) {
 		if (!dev_id)
-			printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
+			printk("Bad boy: %s called us without a dev_id!\n", devname);
 	}
 #endif
 
@@ -681,7 +673,7 @@
 		kfree(action);
 	return retval;
 }
-		
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	irq_desc_t *desc;
@@ -691,7 +683,7 @@
 	if (irq >= NR_IRQS)
 		return;
 
-	desc = irq_desc + irq;
+	desc = irq_desc(irq);
 	spin_lock_irqsave(&desc->lock,flags);
 	p = &desc->action;
 	for (;;) {
@@ -739,16 +731,16 @@
 	unsigned long val;
 	unsigned long delay;
 
-	/* 
+	/*
 	 * something may have generated an irq long ago and we want to
-	 * flush such a longstanding irq before considering it as spurious. 
+	 * flush such a longstanding irq before considering it as spurious.
 	 */
 	for (i = NR_IRQS-1; i > 0; i--)  {
-		desc = irq_desc + i;
+		desc = irq_desc(i);
 
 		spin_lock_irq(&desc->lock);
-		if (!irq_desc[i].action) 
-			irq_desc[i].handler->startup(i);
+		if (!desc->action)
+			desc->handler->startup(i);
 		spin_unlock_irq(&desc->lock);
 	}
 
@@ -762,7 +754,7 @@
 	 * happened in the previous stage, it may have masked itself)
 	 */
 	for (i = NR_IRQS-1; i > 0; i--) {
-		desc = irq_desc + i;
+		desc = irq_desc(i);
 
 		spin_lock_irq(&desc->lock);
 		if (!desc->action) {
@@ -784,7 +776,7 @@
 	 */
 	val = 0;
 	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc_t *desc = irq_desc + i;
+		irq_desc_t *desc = irq_desc(i);
 		unsigned int status;
 
 		spin_lock_irq(&desc->lock);
@@ -816,7 +808,7 @@
 
 	mask = 0;
 	for (i = 0; i < 16; i++) {
-		irq_desc_t *desc = irq_desc + i;
+		irq_desc_t *desc = irq_desc(i);
 		unsigned int status;
 
 		spin_lock_irq(&desc->lock);
@@ -846,7 +838,7 @@
 	nr_irqs = 0;
 	irq_found = 0;
 	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc_t *desc = irq_desc + i;
+		irq_desc_t *desc = irq_desc(i);
 		unsigned int status;
 
 		spin_lock_irq(&desc->lock);
@@ -869,13 +861,12 @@
 	return irq_found;
 }
 
-/* this was setup_x86_irq but it seems pretty generic */
 int setup_irq(unsigned int irq, struct irqaction * new)
 {
 	int shared = 0;
 	unsigned long flags;
 	struct irqaction *old, **p;
-	irq_desc_t *desc = irq_desc + irq;
+	irq_desc_t *desc = irq_desc(irq);
 
 	/*
 	 * Some drivers like serial.c use request_irq() heavily,
@@ -986,7 +977,7 @@
 	int irq = (long) data, full_count = count, err;
 	unsigned long new_value;
 
-	if (!irq_desc[irq].handler->set_affinity)
+	if (!irq_desc(irq)->handler->set_affinity)
 		return -EIO;
 
 	err = parse_hex_value(buffer, count, &new_value);
@@ -1002,7 +993,7 @@
 #endif
 
 	irq_affinity[irq] = new_value;
-	irq_desc[irq].handler->set_affinity(irq, new_value);
+	irq_desc(irq)->handler->set_affinity(irq, new_value);
 
 	return full_count;
 }
@@ -1037,7 +1028,7 @@
 	struct proc_dir_entry *entry;
 	char name [MAX_NAMELEN];
 
-	if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type))
+	if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type))
 		return;
 
 	memset(name, 0, MAX_NAMELEN);
@@ -1079,9 +1070,8 @@
 	 * Create entries for all existing IRQs.
 	 */
 	for (i = 0; i < NR_IRQS; i++) {
-		if (irq_desc[i].handler == &no_irq_type)
+		if (irq_desc(i)->handler == &no_irq_type)
 			continue;
 		register_irq_proc(i);
 	}
 }
-
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c
--- v2.4.3/linux/arch/ia64/kernel/irq_ia64.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/ia64/kernel/irq_ia64.c	Thu Apr  5 12:51:47 2001
@@ -39,7 +39,7 @@
 #define IRQ_DEBUG	0
 
 /* default base addr of IPI table */
-unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IPI_DEFAULT_BASE_ADDR);	
+unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR);
 
 /*
  * Legacy IRQ to IA-64 vector translation table.
@@ -53,21 +53,23 @@
 int
 ia64_alloc_irq (void)
 {
-	static int next_irq = FIRST_DEVICE_IRQ;
+	static int next_irq = IA64_FIRST_DEVICE_VECTOR;
 
-	if (next_irq > LAST_DEVICE_IRQ)
+	if (next_irq > IA64_LAST_DEVICE_VECTOR)
 		/* XXX could look for sharable vectors instead of panic'ing... */
 		panic("ia64_alloc_irq: out of interrupt vectors!");
 	return next_irq++;
 }
 
+extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs);
+
 /*
  * That's where the IVT branches when we get an external
  * interrupt. This branches to the correct hardware IRQ handler via
  * function ptr.
  */
 void
-ia64_handle_irq (unsigned long vector, struct pt_regs *regs)
+ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
 {
 	unsigned long saved_tpr;
 
@@ -89,7 +91,7 @@
 			static unsigned char count;
 			static long last_time;
 
-			if (count > 5 && jiffies - last_time > 5*HZ)
+			if (jiffies - last_time > 5*HZ)
 				count = 0;
 			if (++count < 5) {
 				last_time = jiffies;
@@ -109,19 +111,10 @@
 	saved_tpr = ia64_get_tpr();
 	ia64_srlz_d();
 	do {
-		if (vector >= NR_IRQS) {
-			printk("handle_irq: invalid vector %lu\n", vector);
-			ia64_set_tpr(saved_tpr);
-			ia64_srlz_d();
-			return;
-		}
 		ia64_set_tpr(vector);
 		ia64_srlz_d();
 
-		if ((irq_desc[vector].status & IRQ_PER_CPU) != 0)
-			do_IRQ_per_cpu(vector, regs);
-		else
-			do_IRQ(vector, regs);
+		do_IRQ(local_vector_to_irq(vector), regs);
 
 		/*
 		 * Disable interrupts and send EOI:
@@ -130,7 +123,7 @@
 		ia64_set_tpr(saved_tpr);
 		ia64_eoi();
 		vector = ia64_get_ivr();
-	} while (vector != IA64_SPURIOUS_INT);
+	} while (vector != IA64_SPURIOUS_INT_VECTOR);
 }
 
 #ifdef CONFIG_SMP
@@ -144,33 +137,30 @@
 };
 #endif
 
+void
+register_percpu_irq (ia64_vector vec, struct irqaction *action)
+{
+	irq_desc_t *desc;
+	unsigned int irq;
+
+	for (irq = 0; irq < NR_IRQS; ++irq)
+		if (irq_to_vector(irq) == vec) {
+			desc = irq_desc(irq);
+			desc->status |= IRQ_PER_CPU;
+			desc->handler = &irq_type_ia64_sapic;
+			if (action)
+				setup_irq(irq, action);
+		}
+}
+
 void __init
 init_IRQ (void)
 {
-	/*
-	 * Disable all local interrupts
-	 */
-	ia64_set_itv(0, 1);
-	ia64_set_lrr0(0, 1);
-	ia64_set_lrr1(0, 1);
-
-	irq_desc[IA64_SPURIOUS_INT].handler = &irq_type_ia64_sapic;
+	register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
 #ifdef CONFIG_SMP
-	/* 
-	 * Configure the IPI vector and handler
-	 */
-	irq_desc[IPI_IRQ].status |= IRQ_PER_CPU;
-	irq_desc[IPI_IRQ].handler = &irq_type_ia64_sapic;
-	setup_irq(IPI_IRQ, &ipi_irqaction);
+	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 #endif
-
-	ia64_set_pmv(1 << 16);
-	ia64_set_cmcv(CMC_IRQ);			/* XXX fix me */
-
 	platform_irq_init();
-
-	/* clear TPR to enable all interrupt classes: */
-	ia64_set_tpr(0);
 }
 
 void
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S
--- v2.4.3/linux/arch/ia64/kernel/ivt.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/ivt.S	Thu Apr  5 12:51:47 2001
@@ -1,9 +1,9 @@
 /*
  * arch/ia64/kernel/ivt.S
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
  * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1998-2000 David Mosberger <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 David Mosberger <davidm@hpl.hp.com>
  *
  * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP
  * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB handler now uses virtual PT.
@@ -14,7 +14,7 @@
  *
  * External interrupts only use 1 entry. All others are internal interrupts
  *
- * The first 20 entries of the table contain 64 bundles each while the 
+ * The first 20 entries of the table contain 64 bundles each while the
  * remaining 48 entries contain only 16 bundles each.
  *
  * The 64 bundles are used to allow inlining the whole handler for critical
@@ -22,7 +22,7 @@
  *
  *  For each entry, the comment is as follows:
  *
- * 		// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51)
+ *		// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51)
  *  entry offset ----/     /         /                  /          /
  *  entry number ---------/         /                  /          /
  *  size of the entry -------------/                  /          /
@@ -37,7 +37,9 @@
 
 #include <linux/config.h>
 
+#include <asm/asmmacro.h>
 #include <asm/break.h>
+#include <asm/kregs.h>
 #include <asm/offsets.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -45,6 +47,22 @@
 #include <asm/system.h>
 #include <asm/unistd.h>
 
+#if 1
+# define PSR_DEFAULT_BITS	psr.ac
+#else
+# define PSR_DEFAULT_BITS	0
+#endif
+
+#if 0
+  /*
+   * This lets you track the last eight faults that occurred on the CPU.  Make sure ar.k2 isn't
+   * needed for something else before enabling this...
+   */
+# define DBG_FAULT(i)	mov r16=ar.k2;;	shl r16=r16,8;;	add r16=(i),r16;;mov ar.k2=r16
+#else
+# define DBG_FAULT(i)
+#endif
+
 #define MINSTATE_VIRT	/* needed by minstate.h */
 #include "minstate.h"
 
@@ -57,8 +75,8 @@
  * As we don't (hopefully) use the space available, we need to fill it with
  * nops. the parameter may be used for debugging and is representing the entry
  * number
- */ 
-#define BREAK_BUNDLE(a) 	break.m (a); \
+ */
+#define BREAK_BUNDLE(a)	break.m (a); \
 				break.i (a); \
 				break.i (a)
 /*
@@ -71,17 +89,15 @@
  */
 #define BREAK_BUNDLE8(a); BREAK_BUNDLE4(a); BREAK_BUNDLE4(a)
 
-	.psr abi64
-	.psr lsb
-	.lsb
-
-	.section __ivt_section,"ax"
+	.section .text.ivt,"ax"
 
 	.align 32768	// align on 32KB boundary
 	.global ia64_ivt
 ia64_ivt:
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47)
+ENTRY(vhpt_miss)
+	DBG_FAULT(0)
 	/*
 	 * The VHPT vector is invoked when the TLB entry for the virtual page table
 	 * is missing.  This happens only as a result of a previous
@@ -103,7 +119,7 @@
 	;;
 	rsm psr.dt				// use physical addressing for data
 	mov r31=pr				// save the predicate registers
-	mov r19=ar.k7				// get page table base address
+	mov r19=IA64_KR(PT_BASE)		// get page table base address
 	shl r21=r16,3				// shift bit 60 into sign bit
 	shr.u r17=r16,61			// get the region number into r17
 	;;
@@ -146,19 +162,21 @@
 (p6)	br.spnt.many page_fault			// handle bad address/page not present (page fault)
 	mov cr.ifa=r22
 
-	// Now compute and insert the TLB entry for the virtual page table.
-	// We never execute in a page table page so there is no need to set
-	// the exception deferral bit.
+	/*
+	 * Now compute and insert the TLB entry for the virtual page table.  We never
+	 * execute in a page table page so there is no need to set the exception deferral
+	 * bit.
+	 */
 	adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23
 	;;
 (p7)	itc.d r24
 	;;
 #ifdef CONFIG_SMP
-	//
-	// Re-check L2 and L3 pagetable.  If they changed, we may have received
-	// a ptc.g between reading the pagetable and the "itc".  If so,
-	// flush the entry we inserted and retry.
-	//
+	/*
+	 * Re-check L2 and L3 pagetable.  If they changed, we may have received a ptc.g
+	 * between reading the pagetable and the "itc".  If so, flush the entry we
+	 * inserted and retry.
+	 */
 	ld8 r25=[r21]				// read L3 PTE again
 	ld8 r26=[r17]				// read L2 entry again
 	;;
@@ -173,26 +191,29 @@
 
 	mov pr=r31,-1				// restore predicate registers
 	rfi
-	;;
+END(vhpt_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x0400 Entry 1 (size 64 bundles) ITLB (21)
+ENTRY(itlb_miss)
+	DBG_FAULT(1)
 	/*
 	 * The ITLB handler accesses the L3 PTE via the virtually mapped linear
 	 * page table.  If a nested TLB miss occurs, we switch into physical
 	 * mode, walk the page table, and then re-execute the L3 PTE read
 	 * and go on normally after that.
 	 */
-itlb_fault:
 	mov r16=cr.ifa				// get virtual address
 	mov r29=b0				// save b0
 	mov r31=pr				// save predicates
+itlb_fault:
 	mov r17=cr.iha				// get virtual address of L3 PTE
 	movl r30=1f				// load nested fault continuation point
 	;;
 1:	ld8 r18=[r17]				// read L3 PTE
 	;;
+	mov b0=r29
 	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
 (p6)	br.cond.spnt.many page_fault
 	;;
@@ -208,26 +229,29 @@
 #endif
 	mov pr=r31,-1
 	rfi
-	;;
+END(itlb_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x0800 Entry 2 (size 64 bundles) DTLB (9,48)
+ENTRY(dtlb_miss)
+	DBG_FAULT(2)
 	/*
 	 * The DTLB handler accesses the L3 PTE via the virtually mapped linear
 	 * page table.  If a nested TLB miss occurs, we switch into physical
 	 * mode, walk the page table, and then re-execute the L3 PTE read
 	 * and go on normally after that.
 	 */
-dtlb_fault:
 	mov r16=cr.ifa				// get virtual address
 	mov r29=b0				// save b0
 	mov r31=pr				// save predicates
+dtlb_fault:
 	mov r17=cr.iha				// get virtual address of L3 PTE
 	movl r30=1f				// load nested fault continuation point
 	;;
 1:	ld8 r18=[r17]				// read L3 PTE
 	;;
+	mov b0=r29
 	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
 (p6)	br.cond.spnt.many page_fault
 	;;
@@ -243,24 +267,27 @@
 #endif
 	mov pr=r31,-1
 	rfi
-	;;
+END(dtlb_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19)
+ENTRY(alt_itlb_miss)
+	DBG_FAULT(3)
 	mov r16=cr.ifa		// get address that caused the TLB miss
-	movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX
+	movl r17=PAGE_KERNEL
 	mov r21=cr.ipsr
 	mov r31=pr
 	;;
 #ifdef CONFIG_DISABLE_VHPT
 	shr.u r22=r16,61			// get the region number into r21
 	;;
-	cmp.gt p8,p0=6,r22			// user mode 
+	cmp.gt p8,p0=6,r22			// user mode
 	;;
 (p8)	thash r17=r16
 	;;
 (p8)	mov cr.iha=r17
+(p8)	mov r29=b0				// save b0
 (p8)	br.cond.dptk.many itlb_fault
 #endif
 	extr.u r23=r21,IA64_PSR_CPL0_BIT,2	// extract psr.cpl
@@ -277,13 +304,15 @@
 	itc.i r19		// insert the TLB entry
 	mov pr=r31,-1
 	rfi
-	;;
+END(alt_itlb_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46)
+ENTRY(alt_dtlb_miss)
+	DBG_FAULT(4)
 	mov r16=cr.ifa		// get address that caused the TLB miss
-	movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX
+	movl r17=PAGE_KERNEL
 	mov r20=cr.isr
 	mov r21=cr.ipsr
 	mov r31=pr
@@ -296,6 +325,7 @@
 (p8)	thash r17=r16
 	;;
 (p8)	mov cr.iha=r17
+(p8)	mov r29=b0				// save b0
 (p8)	br.cond.dptk.many dtlb_fault
 #endif
 	extr.u r23=r21,IA64_PSR_CPL0_BIT,2	// extract psr.cpl
@@ -316,70 +346,63 @@
 (p7)	itc.d r19		// insert the TLB entry
 	mov pr=r31,-1
 	rfi
-	;;
+END(alt_dtlb_miss)
 
 	//-----------------------------------------------------------------------------------
 	// call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address)
-page_fault:
+ENTRY(page_fault)
 	ssm psr.dt
 	;;
 	srlz.i
 	;;
 	SAVE_MIN_WITH_COVER
-	//
-	// Copy control registers to temporary registers, then turn on psr bits,
-	// then copy the temporary regs to the output regs.  We have to do this
-	// because the "alloc" can cause a mandatory store which could lead to
-	// an "Alt DTLB" fault which we can handle only if psr.ic is on.
-	//
-	mov r8=cr.ifa
-	mov r9=cr.isr
+	alloc r15=ar.pfs,0,0,3,0
+	mov out0=cr.ifa
+	mov out1=cr.isr
 	adds r3=8,r2				// set up second base pointer
 	;;
-	ssm psr.ic
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i					// guarantee that interrupt collection is enabled
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	movl r14=ia64_leave_kernel
 	;;
-	alloc r15=ar.pfs,0,0,3,0		// must be first in insn group
-	mov out0=r8
-	mov out1=r9
-	;;
 	SAVE_REST
 	mov rp=r14
 	;;
 	adds out2=16,r12			// out2 = pointer to pt_regs
 	br.call.sptk.many b6=ia64_do_page_fault	// ignore return address
-	;;
+END(page_fault)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45)
-	//
-	// In the absence of kernel bugs, we get here when the virtually mapped linear page
-	// table is accessed non-speculatively (e.g.,  in the Dirty-bit, Instruction
-	// Access-bit, or Data Access-bit faults).  If the DTLB entry for the virtual page
-	// table is missing, a nested TLB miss fault is triggered and control is transferred
-	// to this point.  When this happens, we lookup the pte for the faulting address
-	// by walking the page table in physical mode and return to the continuation point
-	// passed in register r30 (or call page_fault if the address is not mapped).
-	//
-	// Input:	r16:	faulting address
-	//		r29:	saved b0
-	//		r30:	continuation address
-	//		r31:	saved pr
-	//
-	// Output:	r17:	physical address of L3 PTE of faulting address
-	//		r29:	saved b0
-	//		r30:	continuation address
-	//		r31:	saved pr
-	//
-	// Clobbered:	b0, r18, r19, r21, psr.dt (cleared)
-	//
+ENTRY(nested_dtlb_miss)
+	/*
+	 * In the absence of kernel bugs, we get here when the virtually mapped linear
+	 * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction
+	 * Access-bit, or Data Access-bit faults).  If the DTLB entry for the virtual page
+	 * table is missing, a nested TLB miss fault is triggered and control is
+	 * transferred to this point.  When this happens, we lookup the pte for the
+	 * faulting address by walking the page table in physical mode and return to the
+	 * continuation point passed in register r30 (or call page_fault if the address is
+	 * not mapped).
+	 *
+	 * Input:	r16:	faulting address
+	 *		r29:	saved b0
+	 *		r30:	continuation address
+	 *		r31:	saved pr
+	 *
+	 * Output:	r17:	physical address of L3 PTE of faulting address
+	 *		r29:	saved b0
+	 *		r30:	continuation address
+	 *		r31:	saved pr
+	 *
+	 * Clobbered:	b0, r18, r19, r21, psr.dt (cleared)
+	 */
 	rsm psr.dt				// switch to using physical data addressing
-	mov r19=ar.k7				// get the page table base address
+	mov r19=IA64_KR(PT_BASE)		// get the page table base address
 	shl r21=r16,3				// shift bit 60 into sign bit
 	;;
 	shr.u r17=r16,61			// get the region number into r17
@@ -399,7 +422,6 @@
 	shr.u r18=r16,PMD_SHIFT			// shift L2 index into position
 	;;
 	ld8 r17=[r17]				// fetch the L1 entry (may be 0)
-	mov b0=r30
 	;;
 (p7)	cmp.eq p6,p7=r17,r0			// was L1 entry NULL?
 	dep r17=r18,r17,3,(PAGE_SHIFT-3)	// compute address of L2 page table entry
@@ -409,34 +431,41 @@
 	;;
 (p7)	cmp.eq.or.andcm p6,p7=r17,r0		// was L2 entry NULL?
 	dep r17=r19,r17,3,(PAGE_SHIFT-3)	// compute address of L3 page table entry
-	;;
 (p6)	br.cond.spnt.many page_fault
+	mov b0=r30
 	br.sptk.many b0				// return to continuation point
-	;;
+END(nested_dtlb_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24)
+ENTRY(ikey_miss)
+	DBG_FAULT(6)
 	FAULT(6)
+END(ikey_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51)
+ENTRY(dkey_miss)
+	DBG_FAULT(7)
 	FAULT(7)
+END(dkey_miss)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54)
-	//
-	// What we do here is to simply turn on the dirty bit in the PTE.  We need
-	// to update both the page-table and the TLB entry.  To efficiently access
-	// the PTE, we address it through the virtual page table.  Most likely, the
-	// TLB entry for the relevant virtual page table page is still present in
-	// the TLB so we can normally do this without additional TLB misses.
-	// In case the necessary virtual page table TLB entry isn't present, we take
-	// a nested TLB miss hit where we look up the physical address of the L3 PTE
-	// and then continue at label 1 below.
-	//
+ENTRY(dirty_bit)
+	DBG_FAULT(8)
+	/*
+	 * What we do here is to simply turn on the dirty bit in the PTE.  We need to
+	 * update both the page-table and the TLB entry.  To efficiently access the PTE,
+	 * we address it through the virtual page table.  Most likely, the TLB entry for
+	 * the relevant virtual page table page is still present in the TLB so we can
+	 * normally do this without additional TLB misses.  In case the necessary virtual
+	 * page table TLB entry isn't present, we take a nested TLB miss hit where we look
+	 * up the physical address of the L3 PTE and then continue at label 1 below.
+	 */
 	mov r16=cr.ifa				// get the address that caused the fault
 	movl r30=1f				// load continuation point in case of nested fault
 	;;
@@ -477,11 +506,13 @@
 #endif
 	mov pr=r31,-1				// restore pr
 	rfi
-	;;
+END(idirty_bit)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27)
+ENTRY(iaccess_bit)
+	DBG_FAULT(9)
 	// Like Entry 8, except for instruction access
 	mov r16=cr.ifa				// get the address that caused the fault
 	movl r30=1f				// load continuation point in case of nested fault
@@ -504,14 +535,14 @@
 	mov r28=ar.ccv				// save ar.ccv
 	;;
 1:	ld8 r18=[r17]
+	;;
 # if defined(CONFIG_IA32_SUPPORT) && \
     (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC))
-	//
-	// Erratum 85 (Access bit fault could be reported before page not present fault)
-	//   If the PTE is indicates the page is not present, then just turn this into a
-	//   page fault.
-	//
-	;;
+	/*
+	 * Erratum 85 (Access bit fault could be reported before page not present fault)
+	 *   If the PTE is indicates the page is not present, then just turn this into a
+	 *   page fault.
+	 */
 	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
 (p6)	br.sptk page_fault			// page wasn't present
 # endif
@@ -538,11 +569,11 @@
 	;;
 # if defined(CONFIG_IA32_SUPPORT) && \
     (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC))
-	//
-	// Erratum 85 (Access bit fault could be reported before page not present fault)
-	//   If the PTE is indicates the page is not present, then just turn this into a
-	//   page fault.
-	//
+	/*
+	 * Erratum 85 (Access bit fault could be reported before page not present fault)
+	 *   If the PTE is indicates the page is not present, then just turn this into a
+	 *   page fault.
+	 */
 	tbit.z p6,p0=r18,_PAGE_P_BIT		// page present bit cleared?
 (p6)	br.sptk page_fault			// page wasn't present
 # endif
@@ -554,11 +585,13 @@
 #endif /* !CONFIG_SMP */
 	mov pr=r31,-1
 	rfi
-	;;
+END(iaccess_bit)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55)
+ENTRY(daccess_bit)
+	DBG_FAULT(10)
 	// Like Entry 8, except for data access
 	mov r16=cr.ifa				// get the address that caused the fault
 	movl r30=1f				// load continuation point in case of nested fault
@@ -599,11 +632,13 @@
 	mov b0=r29				// restore b0
 	mov pr=r31,-1
 	rfi
-	;;
+END(daccess_bit)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33)
+ENTRY(break_fault)
+	DBG_FAULT(11)
 	mov r16=cr.iim
 	mov r17=__IA64_BREAK_SYSCALL
 	mov r31=pr		// prepare to save predicates
@@ -613,8 +648,7 @@
 
 	SAVE_MIN				// uses r31; defines r2:
 
-	// turn interrupt collection back on:
-	ssm psr.ic
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i					// guarantee that interrupt collection is enabled
 	cmp.eq pSys,pNonSys=r0,r0		// set pSys=1, pNonSys=0
@@ -667,12 +701,12 @@
 	;;
 	st8 [r16]=r18				// store new value for cr.isr
 
-(p8)	br.call.sptk.many b6=b6			// ignore this return addr 
+(p8)	br.call.sptk.many b6=b6			// ignore this return addr
 	br.call.sptk.many rp=ia64_trace_syscall	// rp will be overwritten (ignored)
 	// NOT REACHED
+END(break_fault)
 
-	.proc demine_args
-demine_args:
+ENTRY(demine_args)
 	alloc r2=ar.pfs,8,0,0,0
 	tnat.nz p8,p0=in0
 	tnat.nz p9,p0=in1
@@ -696,16 +730,18 @@
 (p14)	mov in6=-1
 (p15)	mov in7=-1
 	br.ret.sptk.many rp
-	.endp demine_args
+END(demine_args)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x3000 Entry 12 (size 64 bundles) External Interrupt (4)
+ENTRY(interrupt)
+	DBG_FAULT(12)
 	mov r31=pr		// prepare to save predicates
 	;;
 
 	SAVE_MIN_WITH_COVER	// uses r31; defines r2 and r3
-	ssm psr.ic		// turn interrupt collection
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	adds r3=8,r2		// set up second base pointer for SAVE_REST
 	srlz.i			// ensure everybody knows psr.ic is back on
@@ -721,41 +757,38 @@
 	;;
 	mov rp=r14
 	br.call.sptk.many b6=ia64_handle_irq
-	;;
+END(interrupt)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x3400 Entry 13 (size 64 bundles) Reserved
+	DBG_FAULT(13)
 	FAULT(13)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x3800 Entry 14 (size 64 bundles) Reserved
+	DBG_FAULT(14)
 	FAULT(14)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x3c00 Entry 15 (size 64 bundles) Reserved
+	DBG_FAULT(15)
 	FAULT(15)
 
-//
-//  Squatting in this space ...
-//
-//  This special case dispatcher for illegal operation faults
-//  allows preserved registers to be modified through a 
-//  callback function (asm only) that is handed back from
-//  the fault handler in r8. Up to three arguments can be
-//  passed to the callback function by returning an aggregate
-//  with the callback as its first element, followed by the
-//  arguments.
-//
-dispatch_illegal_op_fault:
+	/*
+	 * Squatting in this space ...
+	 *
+	 * This special case dispatcher for illegal operation faults allows preserved
+	 * registers to be modified through a callback function (asm only) that is handed
+	 * back from the fault handler in r8. Up to three arguments can be passed to the
+	 * callback function by returning an aggregate with the callback as its first
+	 * element, followed by the arguments.
+	 */
+ENTRY(dispatch_illegal_op_fault)
 	SAVE_MIN_WITH_COVER
-	//
-	// The "alloc" can cause a mandatory store which could lead to
-	// an "Alt DTLB" fault which we can handle only if psr.ic is on.
-	//
-	ssm psr.ic
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i		// guarantee that interrupt collection is enabled
 	;;
@@ -781,27 +814,30 @@
 	cmp.ne p6,p0=0,r8
 (p6)	br.call.dpnt b6=b6		// call returns to ia64_leave_kernel
 	br.sptk ia64_leave_kernel
-	;;
+END(dispatch_illegal_op_fault)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x4000 Entry 16 (size 64 bundles) Reserved
+	DBG_FAULT(16)
 	FAULT(16)
 
 #ifdef CONFIG_IA32_SUPPORT
 
-	// There is no particular reason for this code to be here, other than that
-	// there happens to be space here that would go unused otherwise.  If this
-	// fault ever gets "unreserved", simply moved the following code to a more
-	// suitable spot...
+	/*
+	 * There is no particular reason for this code to be here, other than that
+	 * there happens to be space here that would go unused otherwise.  If this
+	 * fault ever gets "unreserved", simply moved the following code to a more
+	 * suitable spot...
+	 */
 
 	// IA32 interrupt entry point
 
-dispatch_to_ia32_handler:
+ENTRY(dispatch_to_ia32_handler)
 	SAVE_MIN
 	;;
 	mov r14=cr.isr
-	ssm psr.ic
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i					// guarantee that interrupt collection is enabled
 	;;
@@ -812,7 +848,7 @@
 	;;
 	mov r15=0x80
 	shr r14=r14,16          // Get interrupt number
-	;; 
+	;;
 	cmp.ne p6,p0=r14,r15
 (p6)    br.call.dpnt.many b6=non_ia32_syscall
 
@@ -823,7 +859,7 @@
 	st8 [r15]=r8		// save orignal EAX in r1 (IA32 procs don't use the GP)
 	;;
 	alloc r15=ar.pfs,0,0,6,0	// must first in an insn group
-	;; 
+	;;
 	ld4 r8=[r14],8          // r8 == EAX (syscall number)
 	mov r15=222		// sys_vfork - last implemented system call
 	;;
@@ -842,10 +878,10 @@
 	;;
 	ld4 out4=[r14]           // R15 == edi
 	movl r16=ia32_syscall_table
-	;; 
+	;;
 (p6)    shladd r16=r8,3,r16     // Force ni_syscall if not valid syscall number
 	ld8 r2=[r2]		// r2 = current->ptrace
-	;; 
+	;;
 	ld8 r16=[r16]
 	tbit.z p8,p0=r2,PT_TRACESYS_BIT	// (current->ptrace & PT_TRACESYS) == 0?
 	;;
@@ -857,7 +893,7 @@
 	;;
 	br.call.sptk.many rp=ia32_trace_syscall	// rp will be overwritten (ignored)
 
-non_ia32_syscall:       
+non_ia32_syscall:
 	alloc r15=ar.pfs,0,0,2,0
 	mov out0=r14                            // interrupt #
 	add out1=16,sp                          // pointer to pt_regs
@@ -867,16 +903,17 @@
 	;;
 	mov rp=r15
 	br.ret.sptk.many rp
-	;;
+END(dispatch_to_ia32_handler)
 
 #endif /* CONFIG_IA32_SUPPORT */
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x4400 Entry 17 (size 64 bundles) Reserved
+	DBG_FAULT(17)
 	FAULT(17)
 
-non_syscall:
+ENTRY(non_syscall)
 	SAVE_MIN_WITH_COVER
 
 	// There is no particular reason for this code to be here, other than that
@@ -884,49 +921,45 @@
 	// fault ever gets "unreserved", simply moved the following code to a more
 	// suitable spot...
 
-	mov r8=cr.iim			// get break immediate (must be done while psr.ic is off)
+	alloc r14=ar.pfs,0,0,2,0
+	mov out0=cr.iim
+	add out1=16,sp
 	adds r3=8,r2			// set up second base pointer for SAVE_REST
 
-	// turn interrupt collection back on:
-	ssm psr.ic
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i				// guarantee that interrupt collection is enabled
 	;;
 (p15)	ssm psr.i			// restore psr.i
 	movl r15=ia64_leave_kernel
 	;;
-	alloc r14=ar.pfs,0,0,2,0
-	mov out0=r8			// break number
-	add out1=16,sp			// pointer to pt_regs
-	;;
 	SAVE_REST
 	mov rp=r15
 	;;
 	br.call.sptk.many b6=ia64_bad_break	// avoid WAW on CFM and ignore return addr
-	;;
+END(non_syscall)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x4800 Entry 18 (size 64 bundles) Reserved
+	DBG_FAULT(18)
 	FAULT(18)
 
-	// There is no particular reason for this code to be here, other than that
-	// there happens to be space here that would go unused otherwise.  If this
-	// fault ever gets "unreserved", simply moved the following code to a more
-	// suitable spot...
+	/*
+	 * There is no particular reason for this code to be here, other than that
+	 * there happens to be space here that would go unused otherwise.  If this
+	 * fault ever gets "unreserved", simply moved the following code to a more
+	 * suitable spot...
+	 */
 
-dispatch_unaligned_handler:
+ENTRY(dispatch_unaligned_handler)
 	SAVE_MIN_WITH_COVER
 	;;
-	//
-	// we can't have the alloc while psr.ic is cleared because 
-	// we might get a mandatory RSE (when you reach the end of the 
-	// rotating partition when doing the alloc) spill which could cause 
-	// a page fault on the kernel virtual address and the handler 
-	// wouldn't get the state to recover.
-	//
-	mov r15=cr.ifa
-	ssm psr.ic
+	alloc r14=ar.pfs,0,0,2,0		// now it's safe (must be first in insn group!)
+	mov out0=cr.ifa
+	adds out1=16,sp
+
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i					// guarantee that interrupt collection is enabled
 	;;
@@ -934,66 +967,53 @@
 	adds r3=8,r2				// set up second base pointer
 	;;
 	SAVE_REST
-	;;
-	alloc r14=ar.pfs,0,0,2,0		// now it's safe (must be first in insn group!)
-	;;					// avoid WAW on r14
 	movl r14=ia64_leave_kernel
-	mov out0=r15				// out0 = faulting address
-	adds out1=16,sp				// out1 = pointer to pt_regs
 	;;
 	mov rp=r14
 	br.sptk.many ia64_prepare_handle_unaligned
-	;;
+END(dispatch_unaligned_handler)
 
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x4c00 Entry 19 (size 64 bundles) Reserved
+	DBG_FAULT(19)
 	FAULT(19)
 
-	// There is no particular reason for this code to be here, other than that
-	// there happens to be space here that would go unused otherwise.  If this
-	// fault ever gets "unreserved", simply moved the following code to a more
-	// suitable spot...
+	/*
+	 * There is no particular reason for this code to be here, other than that
+	 * there happens to be space here that would go unused otherwise.  If this
+	 * fault ever gets "unreserved", simply moved the following code to a more
+	 * suitable spot...
+	 */
 
-dispatch_to_fault_handler:
-	//
-	// Input:
-	//	psr.ic:	off
-	//	r19:	fault vector number (e.g., 24 for General Exception)
-	//	r31:	contains saved predicates (pr)
-	//
+ENTRY(dispatch_to_fault_handler)
+	/*
+	 * Input:
+	 *	psr.ic:	off
+	 *	r19:	fault vector number (e.g., 24 for General Exception)
+	 *	r31:	contains saved predicates (pr)
+	 */
 	SAVE_MIN_WITH_COVER_R19
-	//
-	// Copy control registers to temporary registers, then turn on psr bits,
-	// then copy the temporary regs to the output regs.  We have to do this
-	// because the "alloc" can cause a mandatory store which could lead to
-	// an "Alt DTLB" fault which we can handle only if psr.ic is on.
-	//
-	mov r8=cr.isr
-	mov r9=cr.ifa
-	mov r10=cr.iim
-	mov r11=cr.itir
+	alloc r14=ar.pfs,0,0,5,0
+	mov out0=r15
+	mov out1=cr.isr
+	mov out2=cr.ifa
+	mov out3=cr.iim
+	mov out4=cr.itir
 	;;
-	ssm psr.ic
+	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
 	srlz.i					// guarantee that interrupt collection is enabled
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	adds r3=8,r2				// set up second base pointer for SAVE_REST
 	;;
-	alloc r14=ar.pfs,0,0,5,0		// must be first in insn group
-	mov out0=r15
-	mov out1=r8
-	mov out2=r9
-	mov out3=r10
-	mov out4=r11
-	;;
 	SAVE_REST
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
 	br.call.sptk.many b6=ia64_fault
-	;;
+END(dispatch_to_fault_handler)
 
 //
 // --- End of long entries, Beginning of short entries
@@ -1002,55 +1022,67 @@
 	.align 1024
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49)
+ENTRY(page_not_present)
+	DBG_FAULT(20)
 	mov r16=cr.ifa
 	rsm psr.dt
-	// The Linux page fault handler doesn't expect non-present pages to be in
-	// the TLB.  Flush the existing entry now, so we meet that expectation.
-	mov r17=_PAGE_SIZE_4K<<2
+	/*
+	 * The Linux page fault handler doesn't expect non-present pages to be in
+	 * the TLB.  Flush the existing entry now, so we meet that expectation.
+	 */
+	mov r17=PAGE_SHIFT<<2
 	;;
 	ptc.l r16,r17
 	;;
 	mov r31=pr
 	srlz.d
 	br.sptk.many page_fault
-	;;
+END(page_not_present)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52)
+ENTRY(key_permission)
+	DBG_FAULT(21)
 	mov r16=cr.ifa
 	rsm psr.dt
 	mov r31=pr
 	;;
 	srlz.d
 	br.sptk.many page_fault
-	;;
+END(key_permission)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26)
+ENTRY(iaccess_rights)
+	DBG_FAULT(22)
 	mov r16=cr.ifa
 	rsm psr.dt
 	mov r31=pr
 	;;
 	srlz.d
 	br.sptk.many page_fault
-	;;
+END(iaccess_rights)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53)
+ENTRY(daccess_rights)
+	DBG_FAULT(23)
 	mov r16=cr.ifa
 	rsm psr.dt
 	mov r31=pr
 	;;
 	srlz.d
 	br.sptk.many page_fault
-	;;
+END(daccess_rights)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39)
+ENTRY(general_exception)
+	DBG_FAULT(24)
 	mov r16=cr.isr
 	mov r31=pr
 	;;
@@ -1059,39 +1091,44 @@
 	;;
 	mov r19=24		// fault number
 	br.sptk.many dispatch_to_fault_handler
-	;;
+END(general_exception)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35)
+ENTRY(disabled_fp_reg)
+	DBG_FAULT(25)
 	rsm psr.dfh		// ensure we can access fph
 	;;
 	srlz.d
 	mov r31=pr
 	mov r19=25
 	br.sptk.many dispatch_to_fault_handler
-	;;
+END(disabled_fp_reg)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50)
+ENTRY(nat_consumption)
+	DBG_FAULT(26)
 	FAULT(26)
+END(nat_consumption)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5700 Entry 27 (size 16 bundles) Speculation (40)
-	//
-	// A [f]chk.[as] instruction needs to take the branch to
-	// the recovery code but this part of the architecture is
-	// not implemented in hardware on some CPUs, such as Itanium.
-	// Thus, in general we need to emulate the behavior.
-	// IIM contains the relative target (not yet sign extended).
-	// So after sign extending it we simply add it to IIP.
-	// We also need to reset the EI field of the IPSR to zero,
-	// i.e., the slot to restart into.
-	//
-	// cr.imm contains zero_ext(imm21)
-	//
+ENTRY(speculation_vector)
+	DBG_FAULT(27)
+	/*
+	 * A [f]chk.[as] instruction needs to take the branch to the recovery code but
+	 * this part of the architecture is not implemented in hardware on some CPUs, such
+	 * as Itanium.  Thus, in general we need to emulate the behavior.  IIM contains
+	 * the relative target (not yet sign extended).  So after sign extending it we
+	 * simply add it to IIP.  We also need to reset the EI field of the IPSR to zero,
+	 * i.e., the slot to restart into.
+	 *
+	 * cr.imm contains zero_ext(imm21)
+	 */
 	mov r18=cr.iim
 	;;
 	mov r17=cr.iip
@@ -1112,105 +1149,130 @@
 	;;
 
 	rfi				// and go back
-	;;
+END(speculation_vector)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5800 Entry 28 (size 16 bundles) Reserved
+	DBG_FAULT(28)
 	FAULT(28)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56)
+ENTRY(debug_vector)
+	DBG_FAULT(29)
 	FAULT(29)
+END(debug_vector)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57)
+ENTRY(unaligned_access)
+	DBG_FAULT(30)
 	mov r16=cr.ipsr
 	mov r31=pr		// prepare to save predicates
-	;;									
-	br.sptk.many dispatch_unaligned_handler
 	;;
+	br.sptk.many dispatch_unaligned_handler
+END(unaligned_access)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57)
+	DBG_FAULT(31)
 	FAULT(31)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64)
+	DBG_FAULT(32)
 	FAULT(32)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66)
+	DBG_FAULT(33)
 	FAULT(33)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Tranfer Trap (66)
+	DBG_FAULT(34)
 	FAULT(34)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68)
+	DBG_FAULT(35)
 	FAULT(35)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69)
+	DBG_FAULT(36)
 	FAULT(36)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6100 Entry 37 (size 16 bundles) Reserved
+	DBG_FAULT(37)
 	FAULT(37)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6200 Entry 38 (size 16 bundles) Reserved
+	DBG_FAULT(38)
 	FAULT(38)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6300 Entry 39 (size 16 bundles) Reserved
+	DBG_FAULT(39)
 	FAULT(39)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6400 Entry 40 (size 16 bundles) Reserved
+	DBG_FAULT(40)
 	FAULT(40)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6500 Entry 41 (size 16 bundles) Reserved
+	DBG_FAULT(41)
 	FAULT(41)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6600 Entry 42 (size 16 bundles) Reserved
+	DBG_FAULT(42)
 	FAULT(42)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6700 Entry 43 (size 16 bundles) Reserved
+	DBG_FAULT(43)
 	FAULT(43)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6800 Entry 44 (size 16 bundles) Reserved
+	DBG_FAULT(44)
 	FAULT(44)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77)
+ENTRY(ia32_exception)
+	DBG_FAULT(45)
 	FAULT(45)
+END(ia32_exception)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept  (30,31,59,70,71)
+ENTRY(ia32_intercept)
+	DBG_FAULT(46)
 #ifdef	CONFIG_IA32_SUPPORT
 	mov r31=pr
 	mov r16=cr.isr
@@ -1219,129 +1281,152 @@
 	mov r18=ar.eflag
 	mov r19=cr.iim		// old eflag value
 	;;
-	cmp.ne p2,p0=2,r17
-(p2)	br.cond.spnt 1f		// not a system flag fault
+	cmp.ne p6,p0=2,r17
+(p6)	br.cond.spnt 1f		// not a system flag fault
 	xor r16=r18,r19
 	;;
 	extr.u r17=r16,18,1	// get the eflags.ac bit
 	;;
-	cmp.eq p2,p0=0,r17
-(p2)	br.cond.spnt 1f		// eflags.ac bit didn't change
+	cmp.eq p6,p0=0,r17
+(p6)	br.cond.spnt 1f		// eflags.ac bit didn't change
 	;;
 	mov pr=r31,-1		// restore predicate registers
 	rfi
-	;;
+
 1:
 #endif	// CONFIG_IA32_SUPPORT
 	FAULT(46)
+END(ia32_intercept)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt  (74)
+ENTRY(ia32_interrupt)
+	DBG_FAULT(47)
 #ifdef CONFIG_IA32_SUPPORT
 	mov r31=pr
 	br.sptk.many dispatch_to_ia32_handler
-	;;
 #else
 	FAULT(47)
 #endif
+END(ia32_interrupt)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6c00 Entry 48 (size 16 bundles) Reserved
+	DBG_FAULT(48)
 	FAULT(48)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6d00 Entry 49 (size 16 bundles) Reserved
+	DBG_FAULT(49)
 	FAULT(49)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6e00 Entry 50 (size 16 bundles) Reserved
+	DBG_FAULT(50)
 	FAULT(50)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x6f00 Entry 51 (size 16 bundles) Reserved
+	DBG_FAULT(51)
 	FAULT(51)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7000 Entry 52 (size 16 bundles) Reserved
+	DBG_FAULT(52)
 	FAULT(52)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7100 Entry 53 (size 16 bundles) Reserved
+	DBG_FAULT(53)
 	FAULT(53)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7200 Entry 54 (size 16 bundles) Reserved
+	DBG_FAULT(54)
 	FAULT(54)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7300 Entry 55 (size 16 bundles) Reserved
+	DBG_FAULT(55)
 	FAULT(55)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7400 Entry 56 (size 16 bundles) Reserved
+	DBG_FAULT(56)
 	FAULT(56)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7500 Entry 57 (size 16 bundles) Reserved
+	DBG_FAULT(57)
 	FAULT(57)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7600 Entry 58 (size 16 bundles) Reserved
+	DBG_FAULT(58)
 	FAULT(58)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7700 Entry 59 (size 16 bundles) Reserved
+	DBG_FAULT(59)
 	FAULT(59)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7800 Entry 60 (size 16 bundles) Reserved
+	DBG_FAULT(60)
 	FAULT(60)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7900 Entry 61 (size 16 bundles) Reserved
+	DBG_FAULT(61)
 	FAULT(61)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7a00 Entry 62 (size 16 bundles) Reserved
+	DBG_FAULT(62)
 	FAULT(62)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7b00 Entry 63 (size 16 bundles) Reserved
+	DBG_FAULT(63)
 	FAULT(63)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7c00 Entry 64 (size 16 bundles) Reserved
+	DBG_FAULT(64)
 	FAULT(64)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7d00 Entry 65 (size 16 bundles) Reserved
+	DBG_FAULT(65)
 	FAULT(65)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7e00 Entry 66 (size 16 bundles) Reserved
+	DBG_FAULT(66)
 	FAULT(66)
 
 	.align 256
 /////////////////////////////////////////////////////////////////////////////////////////
 // 0x7f00 Entry 67 (size 16 bundles) Reserved
+	DBG_FAULT(67)
 	FAULT(67)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c
--- v2.4.3/linux/arch/ia64/kernel/mca.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/kernel/mca.c	Thu Apr 12 12:16:35 2001
@@ -1,16 +1,16 @@
 /*
- * File: 	mca.c
- * Purpose: 	Generic MCA handling layer
+ * File:	mca.c
+ * Purpose:	Generic MCA handling layer
  *
  * Updated for latest kernel
  * Copyright (C) 2000 Intel
  * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
- *  
+ *
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
  *
- * 00/03/29 C. Fleckenstein  Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, 
- *                           added min save state dump, added INIT handler. 
+ * 00/03/29 C. Fleckenstein  Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
+ *                           added min save state dump, added INIT handler.
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -28,7 +28,7 @@
 
 #include <asm/irq.h>
 
- 
+
 typedef struct ia64_fptr {
 	unsigned long fp;
 	unsigned long gp;
@@ -43,8 +43,8 @@
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
 
-static void			ia64_mca_cmc_vector_setup(int 		enable, 
-							  int_vector_t 	cmc_vector);
+static void			ia64_mca_cmc_vector_setup(int		enable,
+							  int_vector_t	cmc_vector);
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
@@ -77,7 +77,7 @@
  * console, then we would call the appropriate debug hooks here.
  */
 void
-init_handler_platform (struct pt_regs *regs) 
+init_handler_platform (struct pt_regs *regs)
 {
 	/* if a kernel debugger is available call it here else just dump the registers */
 	show_regs(regs);		/* dump the state info */
@@ -87,7 +87,7 @@
 log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc)
 {
 }
-	
+
 void
 ia64_mca_init_platform (void)
 {
@@ -131,7 +131,7 @@
 				tpmss_ptr++;  /* skip to next entry */
 				continue;
 			}
-		} 
+		}
 
 		printk("%5s=0x%16.16lx ",min_state_labels[i],*tpmss_ptr++);
 
@@ -142,7 +142,7 @@
 	/* hang city for now, until we include debugger or copy to ptregs to show: */
 	while (1);
 }
- 
+
 /*
  * ia64_mca_cmc_vector_setup
  *	Setup the correctable machine check vector register in the processor
@@ -154,14 +154,14 @@
  *	None
  */
 static void
-ia64_mca_cmc_vector_setup(int 		enable, 
-			  int_vector_t 	cmc_vector)
+ia64_mca_cmc_vector_setup(int		enable,
+			  int_vector_t	cmc_vector)
 {
 	cmcv_reg_t	cmcv;
 
-	cmcv.cmcv_regval 	= 0;
-	cmcv.cmcv_mask  	= enable;
-	cmcv.cmcv_vector 	= cmc_vector;
+	cmcv.cmcv_regval	= 0;
+	cmcv.cmcv_mask	= enable;
+	cmcv.cmcv_vector	= cmc_vector;
 	ia64_set_cmcv(cmcv.cmcv_regval);
 }
 
@@ -223,25 +223,27 @@
 	for(i = 0 ; i < IA64_MAXCPUS; i++)
 		ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
 
-	/* NOTE : The actual irqs for the rendez, wakeup and 
+	/* NOTE : The actual irqs for the rendez, wakeup and
 	 * cmc interrupts are requested in the platform-specific
 	 * mca initialization code.
 	 */
-	/* 
+	/*
 	 * Register the rendezvous spinloop and wakeup mechanism with SAL
 	 */
 
 	/* Register the rendezvous interrupt vector with SAL */
 	if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
 				   SAL_MC_PARAM_MECHANISM_INT,
-				   IA64_MCA_RENDEZ_INT_VECTOR,
-				   IA64_MCA_RENDEZ_TIMEOUT))
+				   IA64_MCA_RENDEZ_VECTOR,
+				   IA64_MCA_RENDEZ_TIMEOUT,
+				   0))
 		return;
 
 	/* Register the wakeup interrupt vector with SAL */
 	if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
 				   SAL_MC_PARAM_MECHANISM_INT,
-				   IA64_MCA_WAKEUP_INT_VECTOR,
+				   IA64_MCA_WAKEUP_VECTOR,
+				   0,
 				   0))
 		return;
 
@@ -249,17 +251,16 @@
 	/*
 	 * Setup the correctable machine check vector
 	 */
-	ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, 
-				  IA64_MCA_CMC_INT_VECTOR);
+	ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, IA64_CMC_VECTOR);
 
 	IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n");
 
-	ia64_mc_info.imi_mca_handler 		= __pa(ia64_os_mca_dispatch);
+	ia64_mc_info.imi_mca_handler		= __pa(ia64_os_mca_dispatch);
 	/*
 	 * XXX - disable SAL checksum by setting size to 0; should be
 	 *	__pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
 	 */
-	ia64_mc_info.imi_mca_handler_size	= 0; 
+	ia64_mc_info.imi_mca_handler_size	= 0;
 	/* Register the os mca handler with SAL */
 	if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
 				 ia64_mc_info.imi_mca_handler,
@@ -271,13 +272,13 @@
 
 	IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n");
 
-	/* 
+	/*
 	 * XXX - disable SAL checksum by setting size to 0, should be
-	 * IA64_INIT_HANDLER_SIZE 
+	 * IA64_INIT_HANDLER_SIZE
 	 */
-	ia64_mc_info.imi_monarch_init_handler 		= __pa(mon_init_ptr->fp);
+	ia64_mc_info.imi_monarch_init_handler		= __pa(mon_init_ptr->fp);
 	ia64_mc_info.imi_monarch_init_handler_size	= 0;
-	ia64_mc_info.imi_slave_init_handler 		= __pa(slave_init_ptr->fp);
+	ia64_mc_info.imi_slave_init_handler		= __pa(slave_init_ptr->fp);
 	ia64_mc_info.imi_slave_init_handler_size	= 0;
 
 	IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler);
@@ -296,7 +297,7 @@
 
 	IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n");
 
-	/* Initialize the areas set aside by the OS to buffer the 
+	/* Initialize the areas set aside by the OS to buffer the
 	 * platform/processor error states for MCA/INIT/CMC
 	 * handling.
 	 */
@@ -308,7 +309,7 @@
 	ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM);
 
 	ia64_mca_init_platform();
-	
+
 	IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n");
 
 #if defined(MCA_TEST)
@@ -321,9 +322,9 @@
 /*
  * ia64_mca_wakeup_ipi_wait
  *	Wait for the inter-cpu interrupt to be sent by the
- * 	monarch processor once it is done with handling the
+ *	monarch processor once it is done with handling the
  *	MCA.
- * Inputs 
+ * Inputs
  *	None
  * Outputs
  *	None
@@ -331,8 +332,8 @@
 void
 ia64_mca_wakeup_ipi_wait(void)
 {
-	int	irr_num = (IA64_MCA_WAKEUP_INT_VECTOR >> 6);
-	int	irr_bit = (IA64_MCA_WAKEUP_INT_VECTOR & 0x3f);
+	int	irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6);
+	int	irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f);
 	u64	irr = 0;
 
 	do {
@@ -356,7 +357,7 @@
 /*
  * ia64_mca_wakeup
  *	Send an inter-cpu interrupt to wake-up a particular cpu
- * 	and mark that cpu to be out of rendez.
+ *	and mark that cpu to be out of rendez.
  * Inputs
  *	cpuid
  * Outputs
@@ -365,9 +366,8 @@
 void
 ia64_mca_wakeup(int cpu)
 {
-	platform_send_ipi(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0);
+	platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
 	ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
-	
 }
 /*
  * ia64_mca_wakeup_all
@@ -390,10 +390,10 @@
 }
 /*
  * ia64_mca_rendez_interrupt_handler
- *	This is handler used to put slave processors into spinloop 
+ *	This is handler used to put slave processors into spinloop
  *	while the monarch processor does the mca handling and later
  *	wake each slave up once the monarch is done.
- * Inputs 
+ * Inputs
  *	None
  * Outputs
  *	None
@@ -403,7 +403,7 @@
 {
 	int flags, cpu = 0;
 	/* Mask all interrupts */
-        save_and_cli(flags);
+	save_and_cli(flags);
 
 #ifdef CONFIG_SMP
 	cpu = cpu_logical_id(hard_smp_processor_id());
@@ -414,7 +414,7 @@
 	 */
 	ia64_sal_mc_rendez();
 
-	/* Wait for the wakeup IPI from the monarch 
+	/* Wait for the wakeup IPI from the monarch
 	 * This waiting is done by polling on the wakeup-interrupt
 	 * vector bit in the processor's IRRs
 	 */
@@ -430,30 +430,30 @@
 /*
  * ia64_mca_wakeup_int_handler
  *	The interrupt handler for processing the inter-cpu interrupt to the
- * 	slave cpu which was spinning in the rendez loop.
+ *	slave cpu which was spinning in the rendez loop.
  *	Since this spinning is done by turning off the interrupts and
- *	polling on the wakeup-interrupt bit in the IRR, there is 
+ *	polling on the wakeup-interrupt bit in the IRR, there is
  *	nothing useful to be done in the handler.
  *  Inputs
  *	wakeup_irq	(Wakeup-interrupt bit)
  *	arg		(Interrupt handler specific argument)
  *	ptregs		(Exception frame at the time of the interrupt)
  *  Outputs
- *	
+ *
  */
 void
 ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
 {
-	
+
 }
 
 /*
  * ia64_return_to_sal_check
  *	This is function called before going back from the OS_MCA handler
- * 	to the OS_MCA dispatch code which finally takes the control back
- * 	to the SAL.
+ *	to the OS_MCA dispatch code which finally takes the control back
+ *	to the SAL.
  *	The main purpose of this routine is to setup the OS_MCA to SAL
- *	return state which can be used by the OS_MCA dispatch code 
+ *	return state which can be used by the OS_MCA dispatch code
  *	just before going back to SAL.
  * Inputs
  *	None
@@ -467,16 +467,16 @@
 	/* Copy over some relevant stuff from the sal_to_os_mca_handoff
 	 * so that it can be used at the time of os_mca_to_sal_handoff
 	 */
-	ia64_os_to_sal_handoff_state.imots_sal_gp = 
+	ia64_os_to_sal_handoff_state.imots_sal_gp =
 		ia64_sal_to_os_handoff_state.imsto_sal_gp;
 
-	ia64_os_to_sal_handoff_state.imots_sal_check_ra = 
+	ia64_os_to_sal_handoff_state.imots_sal_check_ra =
 		ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
 
 	/* For now ignore the MCA */
 	ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
 }
-/* 
+/*
  * ia64_mca_ucmc_handler
  *	This is uncorrectable machine check handler called from OS_MCA
  *	dispatch code which is in turn called from SAL_CHECK().
@@ -503,7 +503,7 @@
 
 	ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
 
-	/* 
+	/*
 	 * Do some error handling - Platform-specific mca handler is called at this point
 	 */
 
@@ -520,11 +520,11 @@
 	ia64_return_to_sal_check();
 }
 
-/* 
+/*
  * ia64_mca_cmc_int_handler
  *	This is correctable machine check interrupt handler.
  *	Right now the logs are extracted and displayed in a well-defined
- *	format. 
+ *	format.
  * Inputs
  *	None
  * Outputs
@@ -532,7 +532,7 @@
  */
 void
 ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
-{	
+{
 	/* Get the CMC processor log */
 	ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
 	/* Get the CMC platform log */
@@ -543,8 +543,7 @@
 	cmci_handler_platform(cmc_irq, arg, ptregs);
 
 	/* Clear the CMC SAL logs now that they have been saved in the OS buffer */
-	ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR);
-	ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM);
+	ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC);
 }
 
 /*
@@ -563,17 +562,17 @@
 static ia64_state_log_t	ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES];
 
 #define IA64_LOG_LOCK_INIT(it, sit)	spin_lock_init(&ia64_state_log[it][sit].isl_lock)
-#define IA64_LOG_LOCK(it, sit)	 	spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s)
-#define IA64_LOG_UNLOCK(it, sit) 	spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\
+#define IA64_LOG_LOCK(it, sit)		spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s)
+#define IA64_LOG_UNLOCK(it, sit)	spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\
 							       s)
 #define IA64_LOG_NEXT_INDEX(it, sit)	ia64_state_log[it][sit].isl_index
-#define IA64_LOG_CURR_INDEX(it, sit) 	1 - ia64_state_log[it][sit].isl_index
+#define IA64_LOG_CURR_INDEX(it, sit)	1 - ia64_state_log[it][sit].isl_index
 #define IA64_LOG_INDEX_INC(it, sit)	\
 	ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index
 #define IA64_LOG_INDEX_DEC(it, sit)	\
 	ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index
-#define IA64_LOG_NEXT_BUFFER(it, sit) 	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)]))
-#define IA64_LOG_CURR_BUFFER(it, sit) 	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)]))
+#define IA64_LOG_NEXT_BUFFER(it, sit)	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)]))
+#define IA64_LOG_CURR_BUFFER(it, sit)	(void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)]))
 
 /*
  * C portion of the OS INIT handler
@@ -582,7 +581,7 @@
  *
  * Inputs: pointer to pt_regs where processor info was saved.
  *
- * Returns: 
+ * Returns:
  *   0 if SAL must warm boot the System
  *   1 if SAL must retrun to interrupted context using PAL_MC_RESUME
  *
@@ -601,49 +600,48 @@
 	/* Get the INIT platform log */
 	ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
 
-#ifdef IA64_DUMP_ALL_PROC_INFO 
+#ifdef IA64_DUMP_ALL_PROC_INFO
 	ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
-#endif 
+#endif
 
-	/* 
+	/*
 	 * get pointer to min state save area
 	 *
 	 */
 	plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT,
 						       SAL_SUB_INFO_TYPE_PROCESSOR);
 	proc_ptr = &plog_ptr->devlog.proclog;
-	
+
 	ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs);
 
 	init_handler_platform(regs);              /* call platform specific routines */
 
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
-	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR);
-	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM);
+	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
 }
 
 /*
  * ia64_log_init
- * 	Reset the OS ia64 log buffer
- * Inputs 	:	info_type 	(SAL_INFO_TYPE_{MCA,INIT,CMC})
+ *	Reset the OS ia64 log buffer
+ * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
  *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
- * Outputs	: 	None
+ * Outputs	:	None
  */
 void
 ia64_log_init(int sal_info_type, int sal_sub_info_type)
 {
 	IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type);
 	IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0;
-	memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, 
+	memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0,
 	       sizeof(ia64_psilog_t) * IA64_MAX_LOGS);
 }
 
-/* 
+/*
  * ia64_log_get
- * 	Get the current MCA log from SAL and copy it into the OS log buffer.
- * Inputs 	:	info_type 	(SAL_INFO_TYPE_{MCA,INIT,CMC})
+ *	Get the current MCA log from SAL and copy it into the OS log buffer.
+ * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
  *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
- * Outputs	: 	None
+ * Outputs	:	None
  *
  */
 void
@@ -658,7 +656,7 @@
 	/* Get the process state information */
 	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type);
 
-	if (!(total_len=ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer)))
+	if (!(total_len=ia64_sal_get_state_info(sal_info_type,(u64 *)log_buffer)))
 		prfunc("ia64_mca_log_get : Getting processor log failed\n");
 
 	IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len);
@@ -669,21 +667,21 @@
 
 }
 
-/* 
+/*
  * ia64_log_clear
- * 	Clear the current MCA log from SAL and dpending on the clear_os_buffer flags
+ *	Clear the current MCA log from SAL and dpending on the clear_os_buffer flags
  *	clear the OS log buffer also
- * Inputs 	:	info_type 	(SAL_INFO_TYPE_{MCA,INIT,CMC})
+ * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
  *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
- *			clear_os_buffer 
+ *			clear_os_buffer
  *			prfunc		(print function)
- * Outputs	: 	None
+ * Outputs	:	None
  *
  */
 void
 ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc)
 {
-	if (ia64_sal_clear_state_info(sal_info_type, sal_sub_info_type))
+	if (ia64_sal_clear_state_info(sal_info_type))
 		prfunc("ia64_mca_log_get : Clearing processor log failed\n");
 
 	if (clear_os_buffer) {
@@ -698,7 +696,7 @@
 		memset(log_buffer, 0, sizeof(ia64_psilog_t));
 
 		IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type);
-	
+
 		IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type);
 	}
 
@@ -708,19 +706,19 @@
  * ia64_log_processor_regs_print
  *	Print the contents of the saved processor register(s) in the format
  *		<reg_prefix>[<index>] <value>
- *		
- * Inputs	:	regs 		(Register save buffer)
- *			reg_num 	(# of registers)
+ *
+ * Inputs	:	regs		(Register save buffer)
+ *			reg_num	(# of registers)
  *			reg_class	(application/banked/control/bank1_general)
  *			reg_prefix	(ar/br/cr/b1_gr)
- * Outputs	: 	None
+ * Outputs	:	None
  *
  */
 void
-ia64_log_processor_regs_print(u64 	*regs, 
-			      int 	reg_num,
-			      char 	*reg_class,
-			      char 	*reg_prefix,
+ia64_log_processor_regs_print(u64	*regs,
+			      int	reg_num,
+			      char	*reg_class,
+			      char	*reg_prefix,
 			      prfunc_t	prfunc)
 {
 	int i;
@@ -756,14 +754,14 @@
  * ia64_log_cache_check_info_print
  *	Display the machine check information related to cache error(s).
  * Inputs	:	i		(Multiple errors are logged, i - index of logged error)
- *			info		(Machine check info logged by the PAL and later 
+ *			info		(Machine check info logged by the PAL and later
  *					 captured by the SAL)
  *			target_addr	(Address which caused the cache error)
- * Outputs	: 	None
+ * Outputs	:	None
  */
-void 
-ia64_log_cache_check_info_print(int 			i, 
-				pal_cache_check_info_t 	info,
+void
+ia64_log_cache_check_info_print(int			i,
+				pal_cache_check_info_t	info,
 				u64			target_addr,
 				prfunc_t		prfunc)
 {
@@ -794,13 +792,13 @@
  * ia64_log_tlb_check_info_print
  *	Display the machine check information related to tlb error(s).
  * Inputs	:	i		(Multiple errors are logged, i - index of logged error)
- *			info		(Machine check info logged by the PAL and later 
+ *			info		(Machine check info logged by the PAL and later
  *					 captured by the SAL)
- * Outputs	: 	None
+ * Outputs	:	None
  */
 
 void
-ia64_log_tlb_check_info_print(int 			i,
+ia64_log_tlb_check_info_print(int			i,
 			      pal_tlb_check_info_t	info,
 			      prfunc_t			prfunc)
 {
@@ -826,16 +824,16 @@
  * ia64_log_bus_check_info_print
  *	Display the machine check information related to bus error(s).
  * Inputs	:	i		(Multiple errors are logged, i - index of logged error)
- *			info		(Machine check info logged by the PAL and later 
+ *			info		(Machine check info logged by the PAL and later
  *					 captured by the SAL)
  *			req_addr	(Address of the requestor of the transaction)
  *			resp_addr	(Address of the responder of the transaction)
  *			target_addr	(Address where the data was to be delivered to  or
  *					 obtained from)
- * Outputs	: 	None
+ * Outputs	:	None
  */
 void
-ia64_log_bus_check_info_print(int 			i,
+ia64_log_bus_check_info_print(int			i,
 			      pal_bus_check_info_t	info,
 			      u64			req_addr,
 			      u64			resp_addr,
@@ -868,9 +866,9 @@
  * ia64_log_processor_info_print
  *	Display the processor-specific information logged by PAL as a part
  *	of MCA or INIT or CMC.
- * Inputs 	:	lh	(Pointer of the sal log header which specifies the format
+ * Inputs	:	lh	(Pointer of the sal log header which specifies the format
  *				 of SAL state info as specified by the SAL spec).
- * Outputs	: 	None
+ * Outputs	:	None
  */
 void
 ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc)
@@ -892,29 +890,29 @@
 	}
 
 	/* Print branch register contents if valid */
-	if (slpi->slpi_valid.slpi_br) 
+	if (slpi->slpi_valid.slpi_br)
 		ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc);
 
 	/* Print control register contents if valid */
-	if (slpi->slpi_valid.slpi_cr) 
+	if (slpi->slpi_valid.slpi_cr)
 		ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc);
 
 	/* Print application register contents if valid */
-	if (slpi->slpi_valid.slpi_ar) 
+	if (slpi->slpi_valid.slpi_ar)
 		ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc);
 
 	/* Print region register contents if valid */
-	if (slpi->slpi_valid.slpi_rr) 
+	if (slpi->slpi_valid.slpi_rr)
 		ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc);
 
 	/* Print floating-point register contents if valid */
-	if (slpi->slpi_valid.slpi_fr) 
-		ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", 
+	if (slpi->slpi_valid.slpi_fr)
+		ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr",
 					      prfunc);
 
 	/* Print the cache check information if any*/
 	for (i = 0 ; i < MAX_CACHE_ERRORS; i++)
-		ia64_log_cache_check_info_print(i, 
+		ia64_log_cache_check_info_print(i,
 					slpi->slpi_cache_check_info[i].slpi_cache_check,
 					slpi->slpi_cache_check_info[i].slpi_target_address,
 						prfunc);
@@ -924,7 +922,7 @@
 
 	/* Print the bus check information if any*/
 	for (i = 0 ; i < MAX_BUS_ERRORS; i++)
-		ia64_log_bus_check_info_print(i, 
+		ia64_log_bus_check_info_print(i,
 					slpi->slpi_bus_check_info[i].slpi_bus_check,
 					slpi->slpi_bus_check_info[i].slpi_requestor_addr,
 					slpi->slpi_bus_check_info[i].slpi_responder_addr,
@@ -935,15 +933,15 @@
 
 /*
  * ia64_log_print
- * 	Display the contents of the OS error log information
- * Inputs 	:	info_type 	(SAL_INFO_TYPE_{MCA,INIT,CMC})
+ *	Display the contents of the OS error log information
+ * Inputs	:	info_type	(SAL_INFO_TYPE_{MCA,INIT,CMC})
  *			sub_info_type	(SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
- * Outputs	: 	None
+ * Outputs	:	None
  */
 void
 ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc)
 {
-	char 	*info_type, *sub_info_type;
+	char	*info_type, *sub_info_type;
 
 	switch(sal_info_type) {
 	case SAL_INFO_TYPE_MCA:
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S
--- v2.4.3/linux/arch/ia64/kernel/mca_asm.S	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/kernel/mca_asm.S	Thu Apr  5 12:51:47 2001
@@ -1,4 +1,4 @@
-// 
+//
 // assembly portion of the IA64 MCA handling
 //
 // Mods by cfleck to integrate into kernel build
@@ -8,6 +8,7 @@
 //		   kstack, switch modes, jump to C INIT handler
 //
 #include <linux/config.h>
+
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/mca_asm.h>
@@ -17,13 +18,9 @@
  * When we get an machine check, the kernel stack pointer is no longer
  * valid, so we need to set a new stack pointer.
  */
-#define	MINSTATE_PHYS	/* Make sure stack access is physical for MINSTATE */ 
+#define	MINSTATE_PHYS	/* Make sure stack access is physical for MINSTATE */
 
 #include "minstate.h"
-	
-	.psr abi64
-	.psr lsb
-	.lsb
 
 /*
  *	SAL_TO_OS_MCA_HANDOFF_STATE
@@ -35,26 +32,26 @@
  *		6. GR12 = Return address to location within SAL_CHECK
  */
 #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp)		\
-        movl	_tmp=ia64_sal_to_os_handoff_state;;	\
-        st8	[_tmp]=r1,0x08;;			\
-        st8	[_tmp]=r8,0x08;;			\
-        st8	[_tmp]=r9,0x08;;			\
-        st8	[_tmp]=r10,0x08;;			\
-        st8	[_tmp]=r11,0x08;;			\
-        st8	[_tmp]=r12,0x08;;
+	movl	_tmp=ia64_sal_to_os_handoff_state;;	\
+	st8	[_tmp]=r1,0x08;;			\
+	st8	[_tmp]=r8,0x08;;			\
+	st8	[_tmp]=r9,0x08;;			\
+	st8	[_tmp]=r10,0x08;;			\
+	st8	[_tmp]=r11,0x08;;			\
+	st8	[_tmp]=r12,0x08;;
 
 /*
  *	OS_MCA_TO_SAL_HANDOFF_STATE
  *		1. GR8 = OS_MCA status
  *		2. GR9 = SAL GP (physical)
  *		3. GR22 = New min state save area pointer
- */	
+ */
 #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp)	\
-        movl	_tmp=ia64_os_to_sal_handoff_state;;	\
+	movl	_tmp=ia64_os_to_sal_handoff_state;;	\
 	DATA_VA_TO_PA(_tmp);;				\
-        ld8	r8=[_tmp],0x08;;			\
-        ld8	r9=[_tmp],0x08;;			\
-        ld8	r22=[_tmp],0x08;;
+	ld8	r8=[_tmp],0x08;;			\
+	ld8	r9=[_tmp],0x08;;			\
+	ld8	r22=[_tmp],0x08;;
 
 /*
  *	BRANCH
@@ -65,9 +62,9 @@
  *		"ip" is the address of the instruction
  *	located at "from_label".
  *		"temp" is a scratch register like r2
- *		"adjust" needed for HP compiler. 
+ *		"adjust" needed for HP compiler.
  *	A screwup somewhere with constant arithmetic.
- */	
+ */
 #define BRANCH(to_label, temp, p, adjust)		\
 100:	(p)	mov		temp=ip;		\
 		;;					\
@@ -76,7 +73,7 @@
 	(p)	adds		temp=adjust,temp;	\
 		;;					\
 	(p)	mov		b1=temp	;		\
-	(p)	br		b1	
+	(p)	br		b1
 
 	.global ia64_os_mca_dispatch
 	.global ia64_os_mca_dispatch_end
@@ -88,11 +85,11 @@
 	.global	ia64_mca_stack
 	.global	ia64_mca_stackframe
 	.global	ia64_mca_bspstore
-	.global ia64_init_stack	
-			
+	.global ia64_init_stack
+
 	.text
 	.align 16
-	
+
 ia64_os_mca_dispatch:
 
 #if defined(MCA_TEST)
@@ -114,23 +111,23 @@
 	;;
 begin_os_mca_dump:
 	BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0)
-        ;;
+	;;
 ia64_os_mca_done_dump:
 
-	// Setup new stack frame for OS_MCA handling 
-        movl        r2=ia64_mca_bspstore		// local bspstore area location in r2
-        movl        r3=ia64_mca_stackframe		// save stack frame to memory in r3
-        rse_switch_context(r6,r3,r2);;                  // RSC management in this new context
-        movl        r12=ia64_mca_stack;;
+	// Setup new stack frame for OS_MCA handling
+	movl        r2=ia64_mca_bspstore		// local bspstore area location in r2
+	movl        r3=ia64_mca_stackframe		// save stack frame to memory in r3
+	rse_switch_context(r6,r3,r2);;                  // RSC management in this new context
+	movl        r12=ia64_mca_stack;;
 
 	// Enter virtual mode from physical mode
 	VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
 ia64_os_mca_virtual_begin:
 
 	// call our handler
-        movl		r2=ia64_mca_ucmc_handler;;
-        mov		b6=r2;;
-        br.call.sptk.few	b0=b6
+	movl		r2=ia64_mca_ucmc_handler;;
+	mov		b6=r2;;
+	br.call.sptk.few	b0=b6
 .ret0:
 	// Revert back to physical mode before going back to SAL
 	PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
@@ -144,42 +141,36 @@
 #endif	/* #if defined(MCA_TEST) */
 
 	// restore the original stack frame here
-        movl    r2=ia64_mca_stackframe               // restore stack frame from memory at r2
+	movl    r2=ia64_mca_stackframe               // restore stack frame from memory at r2
 	;;
 	DATA_VA_TO_PA(r2)
-        movl    r4=IA64_PSR_MC
+	movl    r4=IA64_PSR_MC
 	;;
-        rse_return_context(r4,r3,r2)                 // switch from interrupt context for RSE
-	
+	rse_return_context(r4,r3,r2)                 // switch from interrupt context for RSE
+
 	// let us restore all the registers from our PSI structure
-        mov		r8=gp
+	mov		r8=gp
 	;;
 begin_os_mca_restore:
 	BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0)
-        ;;
+	;;
 
 ia64_os_mca_done_restore:
 	;;
-#ifdef SOFTSDV
-	VIRTUAL_MODE_ENTER(r2,r3, vmode_enter, r4)
-vmode_enter:	
-	br.ret.sptk.few		b0	
-#else
 	// branch back to SALE_CHECK
 	OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2)
-        ld8		r3=[r2];;              
-        mov		b0=r3                       // SAL_CHECK return address
-        br		b0
-        ;;
-#endif /* #ifdef SOFTSDV */
-ia64_os_mca_dispatch_end:	
+	ld8		r3=[r2];;
+	mov		b0=r3                       // SAL_CHECK return address
+	br		b0
+	;;
+ia64_os_mca_dispatch_end:
 //EndMain//////////////////////////////////////////////////////////////////////
 
 
 //++
 // Name:
 //      ia64_os_mca_proc_state_dump()
-// 
+//
 // Stub Description:
 //
 //       This stub dumps the processor state during MCHK to a data area
@@ -188,223 +179,223 @@
 
 ia64_os_mca_proc_state_dump:
 // Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI
-        movl		r2=ia64_mca_proc_state_dump;;           // Os state dump area
+	movl		r2=ia64_mca_proc_state_dump;;           // Os state dump area
 
-// save ar.NaT 
-        mov		r5=ar.unat                  // ar.unat
+// save ar.NaT
+	mov		r5=ar.unat                  // ar.unat
 
 // save banked GRs 16-31 along with NaT bits
-        bsw.1;;
-        st8.spill	[r2]=r16,8;;
-        st8.spill	[r2]=r17,8;;
-        st8.spill	[r2]=r18,8;;
-        st8.spill	[r2]=r19,8;;
-        st8.spill	[r2]=r20,8;;
-        st8.spill	[r2]=r21,8;;
-        st8.spill	[r2]=r22,8;;
-        st8.spill	[r2]=r23,8;;
-        st8.spill	[r2]=r24,8;;
-        st8.spill	[r2]=r25,8;;
-        st8.spill	[r2]=r26,8;;
-        st8.spill	[r2]=r27,8;;
-        st8.spill	[r2]=r28,8;;
-        st8.spill	[r2]=r29,8;;
-        st8.spill	[r2]=r30,8;;
-        st8.spill	[r2]=r31,8;;
-
-        mov		r4=ar.unat;;
-        st8		[r2]=r4,8                // save User NaT bits for r16-r31
-        mov		ar.unat=r5                  // restore original unat
-        bsw.0;;
+	bsw.1;;
+	st8.spill	[r2]=r16,8;;
+	st8.spill	[r2]=r17,8;;
+	st8.spill	[r2]=r18,8;;
+	st8.spill	[r2]=r19,8;;
+	st8.spill	[r2]=r20,8;;
+	st8.spill	[r2]=r21,8;;
+	st8.spill	[r2]=r22,8;;
+	st8.spill	[r2]=r23,8;;
+	st8.spill	[r2]=r24,8;;
+	st8.spill	[r2]=r25,8;;
+	st8.spill	[r2]=r26,8;;
+	st8.spill	[r2]=r27,8;;
+	st8.spill	[r2]=r28,8;;
+	st8.spill	[r2]=r29,8;;
+	st8.spill	[r2]=r30,8;;
+	st8.spill	[r2]=r31,8;;
+
+	mov		r4=ar.unat;;
+	st8		[r2]=r4,8                // save User NaT bits for r16-r31
+	mov		ar.unat=r5                  // restore original unat
+	bsw.0;;
 
 //save BRs
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2                // duplicate r2 in r4
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2                // duplicate r2 in r4
 
-        mov		r3=b0
-        mov		r5=b1
-        mov		r7=b2;;
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;  
-
-        mov		r3=b3
-        mov		r5=b4
-        mov		r7=b5;;
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;  
-
-        mov		r3=b6
-        mov		r5=b7;;
-        st8		[r2]=r3,2*8
-        st8		[r4]=r5,2*8;;
+	mov		r3=b0
+	mov		r5=b1
+	mov		r7=b2;;
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=b3
+	mov		r5=b4
+	mov		r7=b5;;
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=b6
+	mov		r5=b7;;
+	st8		[r2]=r3,2*8
+	st8		[r4]=r5,2*8;;
 
 cSaveCRs:
 // save CRs
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2                // duplicate r2 in r4
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2                // duplicate r2 in r4
 
-        mov		r3=cr0                      // cr.dcr
-        mov		r5=cr1                      // cr.itm
-        mov		r7=cr2;;                    // cr.iva
-
-        st8		[r2]=r3,8*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;            // 48 byte rements
+	mov		r3=cr0                      // cr.dcr
+	mov		r5=cr1                      // cr.itm
+	mov		r7=cr2;;                    // cr.iva
+
+	st8		[r2]=r3,8*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;            // 48 byte rements
 
-        mov		r3=cr8;;                    // cr.pta
-        st8		[r2]=r3,8*8;;            // 64 byte rements
+	mov		r3=cr8;;                    // cr.pta
+	st8		[r2]=r3,8*8;;            // 64 byte rements
 
 // if PSR.ic=0, reading interruption registers causes an illegal operation fault
-        mov		r3=psr;;
-        tbit.nz.unc	p2,p0=r3,PSR_IC;;           // PSI Valid Log bit pos. test
-(p2)    st8		[r2]=r0,9*8+160             // increment by 168 byte inc.
-begin_skip_intr_regs:	
-	BRANCH(SkipIntrRegs,  r9, p2, 0x0)
-	;; 
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2                // duplicate r2 in r6
-        
-        mov		r3=cr16                     // cr.ipsr
-        mov		r5=cr17                     // cr.isr
-        mov		r7=r0;;                     // cr.ida => cr18
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;                                      
-
-        mov		r3=cr19                     // cr.iip
-        mov		r5=cr20                     // cr.idtr
-        mov		r7=cr21;;                   // cr.iitr
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;                                      
-
-        mov		r3=cr22                     // cr.iipa
-        mov		r5=cr23                     // cr.ifs
-        mov		r7=cr24;;                   // cr.iim
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;    
-                                          
-        mov		r3=cr25;;                   // cr.iha
-        st8		[r2]=r3,160;;               // 160 byte rement
+	mov		r3=psr;;
+	tbit.nz.unc	p6,p0=r3,PSR_IC;;           // PSI Valid Log bit pos. test
+(p6)    st8		[r2]=r0,9*8+160             // increment by 168 byte inc.
+begin_skip_intr_regs:
+	BRANCH(SkipIntrRegs,  r9, p6, 0x0)
+	;;
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2                // duplicate r2 in r6
+
+	mov		r3=cr16                     // cr.ipsr
+	mov		r5=cr17                     // cr.isr
+	mov		r7=r0;;                     // cr.ida => cr18
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=cr19                     // cr.iip
+	mov		r5=cr20                     // cr.idtr
+	mov		r7=cr21;;                   // cr.iitr
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=cr22                     // cr.iipa
+	mov		r5=cr23                     // cr.ifs
+	mov		r7=cr24;;                   // cr.iim
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=cr25;;                   // cr.iha
+	st8		[r2]=r3,160;;               // 160 byte rement
 
 SkipIntrRegs:
-        st8		[r2]=r0,168                 // another 168 byte .
+	st8		[r2]=r0,168                 // another 168 byte .
 
-        mov		r3=cr66;;                   // cr.lid
-        st8		[r2]=r3,40                  // 40 byte rement
+	mov		r3=cr66;;                   // cr.lid
+	st8		[r2]=r3,40                  // 40 byte rement
 
-        mov		r3=cr71;;                   // cr.ivr
-        st8		[r2]=r3,8
+	mov		r3=cr71;;                   // cr.ivr
+	st8		[r2]=r3,8
 
-        mov		r3=cr72;;                   // cr.tpr
-        st8		[r2]=r3,24                  // 24 byte increment
-    
-        mov		r3=r0;;                     // cr.eoi => cr75
-        st8		[r2]=r3,168                 // 168 byte inc.
-    
-        mov		r3=r0;;                     // cr.irr0 => cr96
-        st8		[r2]=r3,16               // 16 byte inc.
+	mov		r3=cr72;;                   // cr.tpr
+	st8		[r2]=r3,24                  // 24 byte increment
 
-        mov		r3=r0;;                     // cr.irr1 => cr98
-        st8		[r2]=r3,16               // 16 byte inc.
+	mov		r3=r0;;                     // cr.eoi => cr75
+	st8		[r2]=r3,168                 // 168 byte inc.
 
-        mov		r3=r0;;                     // cr.irr2 => cr100
-        st8		[r2]=r3,16               // 16 byte inc
+	mov		r3=r0;;                     // cr.irr0 => cr96
+	st8		[r2]=r3,16               // 16 byte inc.
 
-        mov		r3=r0;;                     // cr.irr3 => cr100
-        st8		[r2]=r3,16               // 16b inc.
+	mov		r3=r0;;                     // cr.irr1 => cr98
+	st8		[r2]=r3,16               // 16 byte inc.
 
-        mov		r3=r0;;                     // cr.itv => cr114
-        st8		[r2]=r3,16               // 16 byte inc.
+	mov		r3=r0;;                     // cr.irr2 => cr100
+	st8		[r2]=r3,16               // 16 byte inc
 
-        mov		r3=r0;;                     // cr.pmv => cr116
-        st8		[r2]=r3,8
+	mov		r3=r0;;                     // cr.irr3 => cr100
+	st8		[r2]=r3,16               // 16b inc.
 
-        mov		r3=r0;;                     // cr.lrr0 => cr117
-        st8		[r2]=r3,8
+	mov		r3=r0;;                     // cr.itv => cr114
+	st8		[r2]=r3,16               // 16 byte inc.
 
-        mov		r3=r0;;                     // cr.lrr1 => cr118
-        st8		[r2]=r3,8
+	mov		r3=r0;;                     // cr.pmv => cr116
+	st8		[r2]=r3,8
 
-        mov		r3=r0;;                     // cr.cmcv => cr119
-        st8		[r2]=r3,8*10;;
+	mov		r3=r0;;                     // cr.lrr0 => cr117
+	st8		[r2]=r3,8
+
+	mov		r3=r0;;                     // cr.lrr1 => cr118
+	st8		[r2]=r3,8
+
+	mov		r3=r0;;                     // cr.cmcv => cr119
+	st8		[r2]=r3,8*10;;
 
 cSaveARs:
 // save ARs
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2                // duplicate r2 in r6
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2                // duplicate r2 in r6
 
-        mov		r3=ar0                      // ar.kro
-        mov		r5=ar1                      // ar.kr1
-        mov		r7=ar2;;                    // ar.kr2
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;
-
-        mov		r3=ar3                      // ar.kr3                               
-        mov		r5=ar4                      // ar.kr4
-        mov		r7=ar5;;                    // ar.kr5
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;
-
-        mov		r3=ar6                      // ar.kr6
-        mov		r5=ar7                      // ar.kr7
-        mov		r7=r0;;                     // ar.kr8
-        st8		[r2]=r3,10*8
-        st8		[r4]=r5,10*8
-        st8		[r6]=r7,10*8;;           // rement by 72 bytes
+	mov		r3=ar0                      // ar.kro
+	mov		r5=ar1                      // ar.kr1
+	mov		r7=ar2;;                    // ar.kr2
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=ar3                      // ar.kr3
+	mov		r5=ar4                      // ar.kr4
+	mov		r7=ar5;;                    // ar.kr5
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
+
+	mov		r3=ar6                      // ar.kr6
+	mov		r5=ar7                      // ar.kr7
+	mov		r7=r0;;                     // ar.kr8
+	st8		[r2]=r3,10*8
+	st8		[r4]=r5,10*8
+	st8		[r6]=r7,10*8;;           // rement by 72 bytes
 
-        mov		r3=ar16                     // ar.rsc
+	mov		r3=ar16                     // ar.rsc
 	mov		ar16=r0			    // put RSE in enforced lazy mode
-        mov		r5=ar17                     // ar.bsp
+	mov		r5=ar17                     // ar.bsp
 	;;
-        mov		r7=ar18;;                   // ar.bspstore
-        st8		[r2]=r3,3*8
-        st8		[r4]=r5,3*8
-        st8		[r6]=r7,3*8;;
+	mov		r7=ar18;;                   // ar.bspstore
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-        mov		r3=ar19;;                   // ar.rnat
-        st8		[r2]=r3,8*13             // increment by 13x8 bytes
+	mov		r3=ar19;;                   // ar.rnat
+	st8		[r2]=r3,8*13             // increment by 13x8 bytes
 
-        mov		r3=ar32;;                   // ar.ccv
-        st8		[r2]=r3,8*4
+	mov		r3=ar32;;                   // ar.ccv
+	st8		[r2]=r3,8*4
 
-        mov		r3=ar36;;                   // ar.unat
-        st8		[r2]=r3,8*4
+	mov		r3=ar36;;                   // ar.unat
+	st8		[r2]=r3,8*4
 
-        mov		r3=ar40;;                   // ar.fpsr
-        st8		[r2]=r3,8*4
+	mov		r3=ar40;;                   // ar.fpsr
+	st8		[r2]=r3,8*4
 
-        mov		r3=ar44;;                   // ar.itc
-        st8		[r2]=r3,160                 // 160
+	mov		r3=ar44;;                   // ar.itc
+	st8		[r2]=r3,160                 // 160
 
-        mov		r3=ar64;;                   // ar.pfs
-        st8		[r2]=r3,8
+	mov		r3=ar64;;                   // ar.pfs
+	st8		[r2]=r3,8
 
-        mov		r3=ar65;;                   // ar.lc
-        st8		[r2]=r3,8
+	mov		r3=ar65;;                   // ar.lc
+	st8		[r2]=r3,8
+
+	mov		r3=ar66;;                   // ar.ec
+	st8		[r2]=r3
+	add		r2=8*62,r2               //padding
 
-        mov		r3=ar66;;                   // ar.ec
-        st8		[r2]=r3
-        add		r2=8*62,r2               //padding
-    
 // save RRs
-        mov		ar.lc=0x08-1
-        movl		r4=0x00;;
+	mov		ar.lc=0x08-1
+	movl		r4=0x00;;
 
 cStRR:
-        mov		r3=rr[r4];;
-        st8		[r2]=r3,8
-        add		r4=1,r4
-        br.cloop.sptk.few	cStRR
-        ;;
+	mov		r3=rr[r4];;
+	st8		[r2]=r3,8
+	add		r4=1,r4
+	br.cloop.sptk.few	cStRR
+	;;
 end_os_mca_dump:
 	BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10)
-        ;;
+	;;
 
 //EndStub//////////////////////////////////////////////////////////////////////
 
@@ -412,7 +403,7 @@
 //++
 // Name:
 //       ia64_os_mca_proc_state_restore()
-// 
+//
 // Stub Description:
 //
 //       This is a stub to restore the saved processor state during MCHK
@@ -421,225 +412,225 @@
 
 ia64_os_mca_proc_state_restore:
 
-// Restore bank1 GR16-31 
+// Restore bank1 GR16-31
 	movl		r2=ia64_mca_proc_state_dump	// Convert virtual address
 	;;						// of OS state dump area
 	DATA_VA_TO_PA(r2)				// to physical address
 	;;
 restore_GRs:                                    // restore bank-1 GRs 16-31
-        bsw.1;;
-        add		r3=16*8,r2;;                // to get to NaT of GR 16-31
-        ld8		r3=[r3];;
-        mov		ar.unat=r3;;                // first restore NaT
-
-        ld8.fill	r16=[r2],8;;
-        ld8.fill	r17=[r2],8;;
-        ld8.fill	r18=[r2],8;;
-        ld8.fill	r19=[r2],8;;
-        ld8.fill	r20=[r2],8;;
-        ld8.fill	r21=[r2],8;;
-        ld8.fill	r22=[r2],8;;
-        ld8.fill	r23=[r2],8;;
-        ld8.fill	r24=[r2],8;;
-        ld8.fill	r25=[r2],8;;
-        ld8.fill	r26=[r2],8;;
-        ld8.fill	r27=[r2],8;;
-        ld8.fill	r28=[r2],8;;
-        ld8.fill	r29=[r2],8;;
-        ld8.fill	r30=[r2],8;;
-        ld8.fill	r31=[r2],8;;
+	bsw.1;;
+	add		r3=16*8,r2;;                // to get to NaT of GR 16-31
+	ld8		r3=[r3];;
+	mov		ar.unat=r3;;                // first restore NaT
+
+	ld8.fill	r16=[r2],8;;
+	ld8.fill	r17=[r2],8;;
+	ld8.fill	r18=[r2],8;;
+	ld8.fill	r19=[r2],8;;
+	ld8.fill	r20=[r2],8;;
+	ld8.fill	r21=[r2],8;;
+	ld8.fill	r22=[r2],8;;
+	ld8.fill	r23=[r2],8;;
+	ld8.fill	r24=[r2],8;;
+	ld8.fill	r25=[r2],8;;
+	ld8.fill	r26=[r2],8;;
+	ld8.fill	r27=[r2],8;;
+	ld8.fill	r28=[r2],8;;
+	ld8.fill	r29=[r2],8;;
+	ld8.fill	r30=[r2],8;;
+	ld8.fill	r31=[r2],8;;
 
-        ld8		r3=[r2],8;;              // increment to skip NaT
-        bsw.0;;
+	ld8		r3=[r2],8;;              // increment to skip NaT
+	bsw.0;;
 
 restore_BRs:
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2;;              // duplicate r2 in r4
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2;;              // duplicate r2 in r4
 
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;  
-        mov		b0=r3
-        mov		b1=r5
-        mov		b2=r7;;
-
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;  
-        mov		b3=r3
-        mov		b4=r5
-        mov		b5=r7;;
-
-        ld8		r3=[r2],2*8
-        ld8		r5=[r4],2*8;;  
-        mov		b6=r3
-        mov		b7=r5;;
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		b0=r3
+	mov		b1=r5
+	mov		b2=r7;;
+
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		b3=r3
+	mov		b4=r5
+	mov		b5=r7;;
+
+	ld8		r3=[r2],2*8
+	ld8		r5=[r4],2*8;;
+	mov		b6=r3
+	mov		b7=r5;;
 
 restore_CRs:
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2;;              // duplicate r2 in r4
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2;;              // duplicate r2 in r4
 
-        ld8		r3=[r2],8*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;            // 48 byte increments
-        mov		cr0=r3                      // cr.dcr
-        mov		cr1=r5                      // cr.itm
-        mov		cr2=r7;;                    // cr.iva
+	ld8		r3=[r2],8*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;            // 48 byte increments
+	mov		cr0=r3                      // cr.dcr
+	mov		cr1=r5                      // cr.itm
+	mov		cr2=r7;;                    // cr.iva
 
-        ld8		r3=[r2],8*8;;            // 64 byte increments
+	ld8		r3=[r2],8*8;;            // 64 byte increments
 //      mov		cr8=r3                      // cr.pta
 
 
 // if PSR.ic=1, reading interruption registers causes an illegal operation fault
-        mov		r3=psr;;
-        tbit.nz.unc	p2,p0=r3,PSR_IC;;           // PSI Valid Log bit pos. test
-(p2)    st8		[r2]=r0,9*8+160             // increment by 160 byte inc.
-
-begin_rskip_intr_regs:	
-	BRANCH(rSkipIntrRegs, r9, p2, 0x0)
-	;; 
-
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2;;              // duplicate r2 in r4
-
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;
-        mov		cr16=r3                     // cr.ipsr
-        mov		cr17=r5                     // cr.isr is read only
+	mov		r3=psr;;
+	tbit.nz.unc	p6,p0=r3,PSR_IC;;           // PSI Valid Log bit pos. test
+(p6)    st8		[r2]=r0,9*8+160             // increment by 160 byte inc.
+
+begin_rskip_intr_regs:
+	BRANCH(rSkipIntrRegs, r9, p6, 0x0)
+	;;
+
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2;;              // duplicate r2 in r4
+
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		cr16=r3                     // cr.ipsr
+	mov		cr17=r5                     // cr.isr is read only
 //      mov		cr18=r7;;                   // cr.ida
 
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;
-        mov		cr19=r3                     // cr.iip
-        mov		cr20=r5                     // cr.idtr
-        mov		cr21=r7;;                   // cr.iitr
-
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;
-        mov		cr22=r3                     // cr.iipa
-        mov		cr23=r5                     // cr.ifs
-        mov		cr24=r7                     // cr.iim
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		cr19=r3                     // cr.iip
+	mov		cr20=r5                     // cr.idtr
+	mov		cr21=r7;;                   // cr.iitr
+
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		cr22=r3                     // cr.iipa
+	mov		cr23=r5                     // cr.ifs
+	mov		cr24=r7                     // cr.iim
 
-        ld8		r3=[r2],160;;               // 160 byte increment
-        mov		cr25=r3                     // cr.iha 
+	ld8		r3=[r2],160;;               // 160 byte increment
+	mov		cr25=r3                     // cr.iha
 
 rSkipIntrRegs:
-        ld8		r3=[r2],168;;               // another 168 byte inc.
+	ld8		r3=[r2],168;;               // another 168 byte inc.
 
-        ld8		r3=[r2],40;;                // 40 byte increment
-        mov		cr66=r3                     // cr.lid
+	ld8		r3=[r2],40;;                // 40 byte increment
+	mov		cr66=r3                     // cr.lid
 
-        ld8		r3=[r2],8;;
+	ld8		r3=[r2],8;;
 //      mov		cr71=r3                     // cr.ivr is read only
-        ld8		r3=[r2],24;;                // 24 byte increment
-        mov		cr72=r3                     // cr.tpr
-   
-        ld8		r3=[r2],168;;               // 168 byte inc.
+	ld8		r3=[r2],24;;                // 24 byte increment
+	mov		cr72=r3                     // cr.tpr
+
+	ld8		r3=[r2],168;;               // 168 byte inc.
 //      mov		cr75=r3                     // cr.eoi
-   
-        ld8		r3=[r2],16;;             // 16 byte inc.
+
+	ld8		r3=[r2],16;;             // 16 byte inc.
 //      mov		cr96=r3                     // cr.irr0 is read only
 
-        ld8		r3=[r2],16;;             // 16 byte inc.
+	ld8		r3=[r2],16;;             // 16 byte inc.
 //      mov		cr98=r3                     // cr.irr1 is read only
 
-        ld8		r3=[r2],16;;             // 16 byte inc
+	ld8		r3=[r2],16;;             // 16 byte inc
 //      mov		cr100=r3                    // cr.irr2 is read only
 
-        ld8		r3=[r2],16;;             // 16b inc.
+	ld8		r3=[r2],16;;             // 16b inc.
 //      mov		cr102=r3                    // cr.irr3 is read only
 
-        ld8		r3=[r2],16;;             // 16 byte inc.
+	ld8		r3=[r2],16;;             // 16 byte inc.
 //      mov		cr114=r3                    // cr.itv
 
-        ld8		r3=[r2],8;;
+	ld8		r3=[r2],8;;
 //      mov		cr116=r3                    // cr.pmv
-        ld8		r3=[r2],8;;
+	ld8		r3=[r2],8;;
 //      mov		cr117=r3                    // cr.lrr0
-        ld8		r3=[r2],8;;
+	ld8		r3=[r2],8;;
 //      mov		cr118=r3                    // cr.lrr1
-        ld8		r3=[r2],8*10;;
+	ld8		r3=[r2],8*10;;
 //      mov		cr119=r3                    // cr.cmcv
 
 restore_ARs:
-        add		r4=8,r2                  // duplicate r2 in r4
-        add		r6=2*8,r2;;              // duplicate r2 in r4
+	add		r4=8,r2                  // duplicate r2 in r4
+	add		r6=2*8,r2;;              // duplicate r2 in r4
 
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;
-        mov		ar0=r3                      // ar.kro
-        mov		ar1=r5                      // ar.kr1
-        mov		ar2=r7;;                    // ar.kr2
-
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;
-        mov		ar3=r3                      // ar.kr3                               
-        mov		ar4=r5                      // ar.kr4
-        mov		ar5=r7;;                    // ar.kr5
-
-        ld8		r3=[r2],10*8
-        ld8		r5=[r4],10*8
-        ld8		r7=[r6],10*8;;
-        mov		ar6=r3                      // ar.kr6
-        mov		ar7=r5                      // ar.kr7
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		ar0=r3                      // ar.kro
+	mov		ar1=r5                      // ar.kr1
+	mov		ar2=r7;;                    // ar.kr2
+
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
+	mov		ar3=r3                      // ar.kr3
+	mov		ar4=r5                      // ar.kr4
+	mov		ar5=r7;;                    // ar.kr5
+
+	ld8		r3=[r2],10*8
+	ld8		r5=[r4],10*8
+	ld8		r7=[r6],10*8;;
+	mov		ar6=r3                      // ar.kr6
+	mov		ar7=r5                      // ar.kr7
 //      mov		ar8=r6                      // ar.kr8
-        ;;
+	;;
 
-        ld8		r3=[r2],3*8
-        ld8		r5=[r4],3*8
-        ld8		r7=[r6],3*8;;
+	ld8		r3=[r2],3*8
+	ld8		r5=[r4],3*8
+	ld8		r7=[r6],3*8;;
 //      mov		ar16=r3                     // ar.rsc
 //      mov		ar17=r5                     // ar.bsp is read only
 	mov		ar16=r0			    // make sure that RSE is in enforced lazy mode
 	;;
-        mov		ar18=r7;;                   // ar.bspstore
+	mov		ar18=r7;;                   // ar.bspstore
 
-        ld8		r9=[r2],8*13;;
-        mov		ar19=r9                     // ar.rnat
+	ld8		r9=[r2],8*13;;
+	mov		ar19=r9                     // ar.rnat
 
 	mov		ar16=r3			    // ar.rsc
-        ld8		r3=[r2],8*4;;
-        mov		ar32=r3                     // ar.ccv
+	ld8		r3=[r2],8*4;;
+	mov		ar32=r3                     // ar.ccv
 
-        ld8		r3=[r2],8*4;;
-        mov		ar36=r3                     // ar.unat
+	ld8		r3=[r2],8*4;;
+	mov		ar36=r3                     // ar.unat
 
-        ld8		r3=[r2],8*4;;
-        mov		ar40=r3                     // ar.fpsr
+	ld8		r3=[r2],8*4;;
+	mov		ar40=r3                     // ar.fpsr
 
-        ld8		r3=[r2],160;;               // 160
+	ld8		r3=[r2],160;;               // 160
 //      mov		ar44=r3                     // ar.itc
 
-        ld8		r3=[r2],8;;
-        mov		ar64=r3                     // ar.pfs
+	ld8		r3=[r2],8;;
+	mov		ar64=r3                     // ar.pfs
+
+	ld8		r3=[r2],8;;
+	mov		ar65=r3                     // ar.lc
 
-        ld8		r3=[r2],8;;
-        mov		ar65=r3                     // ar.lc
+	ld8		r3=[r2];;
+	mov		ar66=r3                     // ar.ec
+	add		r2=8*62,r2;;             // padding
 
-        ld8		r3=[r2];;
-        mov		ar66=r3                     // ar.ec
-        add		r2=8*62,r2;;             // padding 
-    
 restore_RRs:
-        mov		r5=ar.lc
-        mov		ar.lc=0x08-1
-        movl		r4=0x00
+	mov		r5=ar.lc
+	mov		ar.lc=0x08-1
+	movl		r4=0x00
 cStRRr:
-        ld8		r3=[r2],8;;
+	ld8		r3=[r2],8;;
 //      mov		rr[r4]=r3                   // what are its access previledges?
-        add		r4=1,r4
-        br.cloop.sptk.few	cStRRr
-        ;;
-        mov		ar.lc=r5
+	add		r4=1,r4
+	br.cloop.sptk.few	cStRRr
+	;;
+	mov		ar.lc=r5
 	;;
 end_os_mca_restore:
 	BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20)
-	;; 
+	;;
 //EndStub//////////////////////////////////////////////////////////////////////
 
 // ok, the issue here is that we need to save state information so
@@ -647,16 +638,16 @@
 // In order to do this, our best bet is save the current state (plus
 // the state information obtain from the MIN_STATE_AREA) into a pt_regs
 // format.  This way we can pass it on in a useable format.
-//				
+//
 
 //
 // SAL to OS entry point for INIT on the monarch processor
-// This has been defined for registration purposes with SAL 
+// This has been defined for registration purposes with SAL
 // as a part of ia64_mca_init.
 //
 // When we get here, the follow registers have been
 // set by the SAL for our use
-//		
+//
 //		1. GR1 = OS INIT GP
 //		2. GR8 = PAL_PROC physical address
 //		3. GR9 = SAL_PROC physical address
@@ -665,14 +656,14 @@
 //			0 = Received INIT for event other than crash dump switch
 //			1 = Received wakeup at the end of an OS_MCA corrected machine check
 //			2 = Received INIT dude to CrashDump switch assertion
-//	
+//
 //		6. GR12 = Return address to location within SAL_INIT procedure
 
-				
+
 	.text
 	.align 16
-.global ia64_monarch_init_handler       
-.proc ia64_monarch_init_handler       
+.global ia64_monarch_init_handler
+.proc ia64_monarch_init_handler
 ia64_monarch_init_handler:
 
 #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND)
@@ -680,6 +671,7 @@
 	// work around SAL bug that sends all processors to monarch entry
 	//
 	mov	r17=cr.lid
+	// XXX fix me: this is wrong: hard_smp_processor_id() is a pair of lid/eid
 	movl	r18=__cpu_physical_id
 	;;
 	dep	r18=0,r18,61,3		// convert to physical address
@@ -694,7 +686,7 @@
 	;;
 #endif
 
-	
+
 //
 // ok, the first thing we do is stash the information
 // the SAL passed to os
@@ -706,8 +698,8 @@
 	;;
 	st8	[_tmp]=r1,0x08;;
 	st8	[_tmp]=r8,0x08;;
-	st8	[_tmp]=r9,0x08;;			
-	st8	[_tmp]=r10,0x08;;			
+	st8	[_tmp]=r9,0x08;;
+	st8	[_tmp]=r10,0x08;;
 	st8	[_tmp]=r11,0x08;;
 	st8	[_tmp]=r12,0x08;;
 
@@ -719,12 +711,12 @@
 	adds r3=8,r2				// set up second base pointer
 	;;
 	SAVE_REST
-	
+
 // ok, enough should be saved at this point to be dangerous, and  supply
 // information for a dump
 // We need to switch to Virtual mode before hitting the C functions.
 //
-// 
+//
 //
 	movl	r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN
 	mov	r3=psr	// get the current psr, minimum enabled at this point
@@ -739,7 +731,7 @@
 	rfi
 	;;
 IVirtual_Switch:
-	//	
+	//
 	// We should now be running virtual
 	//
 	// Lets call the C handler to get the rest of the state info
@@ -759,7 +751,7 @@
 
 //
 // SAL to OS entry point for INIT on the slave processor
-// This has been defined for registration purposes with SAL 
+// This has been defined for registration purposes with SAL
 // as a part of ia64_mca_init.
 //
 
@@ -767,10 +759,10 @@
 	.align 16
 .global ia64_slave_init_handler
 .proc ia64_slave_init_handler
-ia64_slave_init_handler:		
+ia64_slave_init_handler:
 
 
-slave_init_spin_me:	
+slave_init_spin_me:
 	br.sptk slave_init_spin_me
 	;;
 	.endp
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h
--- v2.4.3/linux/arch/ia64/kernel/minstate.h	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/minstate.h	Thu Apr  5 12:51:47 2001
@@ -29,20 +29,20 @@
  */
 #define MINSTATE_START_SAVE_MIN_VIRT								\
 	dep r1=-1,r1,61,3;				/* r1 = current (virtual) */		\
-(p7)	mov ar.rsc=r0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
+(pUser)	mov ar.rsc=0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
 	;;											\
-(p7)	addl rKRBS=IA64_RBS_OFFSET,r1;			/* compute base of RBS */		\
-(p7)	mov rARRNAT=ar.rnat;									\
+(pUser)	addl rKRBS=IA64_RBS_OFFSET,r1;			/* compute base of RBS */		\
+(pUser)	mov rARRNAT=ar.rnat;									\
 (pKern) mov r1=sp;					/* get sp  */				\
 	;;											\
-(p7)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1;	/* compute base of memory stack */	\
-(p7)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			\
+(pUser)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1;	/* compute base of memory stack */	\
+(pUser)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			\
 	;;											\
 (pKern) addl r1=-IA64_PT_REGS_SIZE,r1;			/* if in kernel mode, use sp (r12) */	\
-(p7)	mov ar.bspstore=rKRBS;				/* switch to kernel RBS */		\
+(pUser)	mov ar.bspstore=rKRBS;				/* switch to kernel RBS */		\
 	;;											\
-(p7)	mov r18=ar.bsp;										\
-(p7)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		\
+(pUser)	mov r18=ar.bsp;										\
+(pUser)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		\
 
 #define MINSTATE_END_SAVE_MIN_VIRT								\
 	or r13=r13,r14;		/* make `current' a kernel virtual address */			\
@@ -55,20 +55,20 @@
  */
 #define MINSTATE_START_SAVE_MIN_PHYS								\
 (pKern) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE;				\
-(p7)	mov ar.rsc=r0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
-(p7)	addl rKRBS=IA64_RBS_OFFSET,r1;		/* compute base of register backing store */	\
+(pUser)	mov ar.rsc=0;		/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
+(pUser)	addl rKRBS=IA64_RBS_OFFSET,r1;		/* compute base of register backing store */	\
 	;;											\
-(p7)	mov rARRNAT=ar.rnat;									\
+(pUser)	mov rARRNAT=ar.rnat;									\
 (pKern) dep r1=0,sp,61,3;				/* compute physical addr of sp	*/	\
-(p7)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1;	/* compute base of memory stack */	\
-(p7)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			\
-(p7)	dep rKRBS=-1,rKRBS,61,3;			/* compute kernel virtual addr of RBS */\
+(pUser)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1;	/* compute base of memory stack */	\
+(pUser)	mov rARBSPSTORE=ar.bspstore;			/* save ar.bspstore */			\
+(pUser)	dep rKRBS=-1,rKRBS,61,3;			/* compute kernel virtual addr of RBS */\
 	;;											\
 (pKern) addl r1=-IA64_PT_REGS_SIZE,r1;		/* if in kernel mode, use sp (r12) */		\
-(p7)	mov ar.bspstore=rKRBS;			/* switch to kernel RBS */			\
+(pUser)	mov ar.bspstore=rKRBS;			/* switch to kernel RBS */			\
 	;;											\
-(p7)	mov r18=ar.bsp;										\
-(p7)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		\
+(pUser)	mov r18=ar.bsp;										\
+(pUser)	mov ar.rsc=0x3;		/* set eager mode, pl 0, little-endian, loadrs=0 */		\
 
 #define MINSTATE_END_SAVE_MIN_PHYS								\
 	or r12=r12,r14;		/* make sp a kernel virtual address */				\
@@ -101,29 +101,30 @@
  *	r12 = kernel sp (kernel virtual address)
  *	r13 = points to current task_struct (kernel virtual address)
  *	p15 = TRUE if psr.i is set in cr.ipsr
- *	predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15:
+ *	predicate registers (other than p2, p3, and p15), b6, r3, r8, r9, r10, r11, r14, r15:
  *		preserved
  *
  * Note that psr.ic is NOT turned on by this macro.  This is so that
  * we can pass interruption state as arguments to a handler.
  */
-#define DO_SAVE_MIN(COVER,EXTRA)								  \
+#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA)							  \
 	mov rARRSC=ar.rsc;									  \
 	mov rARPFS=ar.pfs;									  \
 	mov rR1=r1;										  \
 	mov rARUNAT=ar.unat;									  \
 	mov rCRIPSR=cr.ipsr;									  \
-	mov rB6=b6;		/* rB6 = branch reg 6 */					  \
+	mov rB6=b6;				/* rB6 = branch reg 6 */			  \
 	mov rCRIIP=cr.iip;									  \
-	mov r1=ar.k6;		/* r1 = current (physical) */					  \
+	mov r1=IA64_KR(CURRENT);		/* r1 = current (physical) */			  \
+	COVER;											  \
 	;;											  \
 	invala;											  \
 	extr.u r16=rCRIPSR,32,2;		/* extract psr.cpl */				  \
 	;;											  \
-	cmp.eq pKern,p7=r0,r16;			/* are we in kernel mode already? (psr.cpl==0) */ \
+	cmp.eq pKern,pUser=r0,r16;		/* are we in kernel mode already? (psr.cpl==0) */ \
 	/* switch from user to kernel RBS: */							  \
-	COVER;											  \
 	;;											  \
+	SAVE_IFS;										  \
 	MINSTATE_START_SAVE_MIN									  \
 	;;											  \
 	mov r16=r1;					/* initialize first base pointer */	  \
@@ -135,7 +136,7 @@
 	;;											  \
 	st8 [r16]=rCRIFS,16;	/* save cr.ifs */						  \
 	st8 [r17]=rARUNAT,16;	/* save ar.unat */						  \
-(p7)	sub r18=r18,rKRBS;	/* r18=RSE.ndirty*8 */						  \
+(pUser)	sub r18=r18,rKRBS;	/* r18=RSE.ndirty*8 */						  \
 	;;											  \
 	st8 [r16]=rARPFS,16;	/* save ar.pfs */						  \
 	st8 [r17]=rARRSC,16;	/* save ar.rsc */						  \
@@ -143,8 +144,8 @@
 	;;			/* avoid RAW on r16 & r17 */					  \
 (pKern)	adds r16=16,r16;	/* skip over ar_rnat field */					  \
 (pKern)	adds r17=16,r17;	/* skip over ar_bspstore field */				  \
-(p7)	st8 [r16]=rARRNAT,16;	/* save ar.rnat */						  \
-(p7)	st8 [r17]=rARBSPSTORE,16;	/* save ar.bspstore */					  \
+(pUser)	st8 [r16]=rARRNAT,16;	/* save ar.rnat */						  \
+(pUser)	st8 [r17]=rARBSPSTORE,16;	/* save ar.bspstore */					  \
 	;;											  \
 	st8 [r16]=rARPR,16;	/* save predicates */						  \
 	st8 [r17]=rB6,16;	/* save b6 */							  \
@@ -171,7 +172,7 @@
 	;;											  \
 .mem.offset 0,0;		st8.spill [r16]=r10,16;						  \
 .mem.offset 8,0;		st8.spill [r17]=r11,16;						  \
-	mov r13=ar.k6;		/* establish `current' */					  \
+	mov r13=IA64_KR(CURRENT);	/* establish `current' */				  \
 	;;											  \
 	EXTRA;											  \
 	movl r1=__gp;		/* establish kernel global pointer */				  \
@@ -240,6 +241,6 @@
 # define STOPS
 #endif
 
-#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
-#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
-#define SAVE_MIN		DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
+#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) STOPS
+#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) STOPS
+#define SAVE_MIN		DO_SAVE_MIN(     , mov rCRIFS=r0, ) STOPS
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/pal.S linux/arch/ia64/kernel/pal.S
--- v2.4.3/linux/arch/ia64/kernel/pal.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/pal.S	Thu Apr  5 12:51:47 2001
@@ -14,11 +14,6 @@
 #include <asm/asmmacro.h>
 #include <asm/processor.h>
 
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 	.data
 pal_entry_point:
 	data8 ia64_pal_default_handler
@@ -58,7 +53,7 @@
  *
  */
 GLOBAL_ENTRY(ia64_pal_call_static)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)
 	alloc loc1 = ar.pfs,6,90,0,0
 	movl loc2 = pal_entry_point
 1:	{
@@ -73,7 +68,7 @@
 	;;
 	mov loc3 = psr
 	mov loc0 = rp
-	UNW(.body)
+	.body
 	mov r30 = in2
 
 (p6)	rsm psr.i | psr.ic
@@ -101,14 +96,14 @@
  * 	in2 - in3   Remaning PAL arguments
  */
 GLOBAL_ENTRY(ia64_pal_call_stacked)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
 	alloc loc1 = ar.pfs,5,4,87,0
 	movl loc2 = pal_entry_point
 
 	mov r28  = in0			// Index MUST be copied to r28
 	mov out0 = in0			// AND in0 of PAL function
 	mov loc0 = rp
-	UNW(.body)
+	.body
 	;;
 	ld8 loc2 = [loc2]		// loc2 <- entry point
 	mov out1 = in1
@@ -148,7 +143,7 @@
 
 
 GLOBAL_ENTRY(ia64_pal_call_phys_static)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)
 	alloc loc1 = ar.pfs,6,90,0,0
 	movl loc2 = pal_entry_point
 1:	{
@@ -156,7 +151,7 @@
 	  mov r8   = ip			// save ip to compute branch
 	  mov loc0 = rp			// save rp
 	}
-	UNW(.body)
+	.body
 	;;
 	ld8 loc2 = [loc2]		// loc2 <- entry point
 	mov r29  = in1			// first argument
@@ -171,7 +166,7 @@
 	dep.z r8=r8,0,61		// convert rp to physical
 	;;
 	mov b7 = loc2			// install target to branch reg
-	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	movl r16=PAL_PSR_BITS_TO_CLEAR
 	movl r17=PAL_PSR_BITS_TO_SET
 	;;
@@ -182,7 +177,7 @@
 .ret1:	mov rp = r8			// install return address (physical)
 	br.cond.sptk.few b7
 1:
-	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3			// r16= original psr
 	br.call.sptk.few rp=ia64_switch_mode // return to virtual mode
 .ret2:
@@ -204,7 +199,7 @@
  * 	in2 - in3   Remaning PAL arguments
  */
 GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
-	UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5))
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
 	alloc	loc1 = ar.pfs,5,5,86,0
 	movl	loc2 = pal_entry_point
 1:	{
@@ -224,7 +219,7 @@
 	mov loc4=ar.rsc			// save RSE configuration
 	dep.z loc2=loc2,0,61		// convert pal entry point to physical
 	;;
-	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	movl r16=PAL_PSR_BITS_TO_CLEAR
 	movl r17=PAL_PSR_BITS_TO_SET
 	;;
@@ -236,7 +231,7 @@
 .ret6:
 	br.call.sptk.many rp=b7		// now make the call
 .ret7:
-	mov ar.rsc=r0			// put RSE in enforced lazy, LE mode
+	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	mov r16=loc3			// r16= original psr
 	br.call.sptk.few rp=ia64_switch_mode	// return to virtual mode
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c
--- v2.4.3/linux/arch/ia64/kernel/palinfo.c	Fri Feb 16 15:53:08 2001
+++ linux/arch/ia64/kernel/palinfo.c	Thu Apr  5 12:51:47 2001
@@ -5,16 +5,13 @@
  * This code is based on specification of PAL as of the
  * Intel IA-64 Architecture Software Developer's Manual v1.0.
  *
- * 
+ *
  * Copyright (C) 2000 Hewlett-Packard Co
  * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
- * 
+ *
  * 05/26/2000	S.Eranian	initial release
  * 08/21/2000	S.Eranian	updated to July 2000 PAL specs
- *
- * ISSUES:
- *	- as of 2.2.9/2.2.12, the following values are still wrong
- *		PAL_VM_SUMMARY: key & rid sizes
+ * 02/05/2001   S.Eranian	fixed module support
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -36,12 +33,7 @@
 MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
 MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
 
-/*
- * Hope to get rid of this one in a near future
-*/
-#define IA64_PAL_VERSION_BUG		1
-
-#define PALINFO_VERSION "0.3"
+#define PALINFO_VERSION "0.4"
 
 #ifdef CONFIG_SMP
 #define cpu_is_online(i) (cpu_online_map & (1UL << i))
@@ -83,7 +75,7 @@
 	"Non-temporal, all levels",
 	"Reserved",
 	"Reserved",
-	"Reserved",	
+	"Reserved",
 	"Reserved"
 };
 
@@ -94,7 +86,7 @@
 	"Non-temporal, all levels",
 	"Reserved",
 	"Reserved",
-	"Reserved",	
+	"Reserved",
 	"Reserved"
 };
 
@@ -108,7 +100,7 @@
 #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *))
 
 /*
- * The current revision of the Volume 2 (July 2000) of 
+ * The current revision of the Volume 2 (July 2000) of
  * IA-64 Architecture Software Developer's Manual is wrong.
  * Table 4-10 has invalid information concerning the ma field:
  * Correct table is:
@@ -116,7 +108,7 @@
  *      bit 4 - 100 - UC
  *      bit 5 - 101 - UCE
  *      bit 6 - 110 - WC
- *      bit 7 - 111 - NatPage 
+ *      bit 7 - 111 - NatPage
  */
 static const char *mem_attrib[]={
 	"Write Back (WB)",		/* 000 */
@@ -136,7 +128,7 @@
  *
  * Input:
  *	- a pointer to a buffer to hold the string
- * 	- a 64-bit vector
+ *	- a 64-bit vector
  * Ouput:
  *	- a pointer to the end of the buffer
  *
@@ -163,7 +155,7 @@
  *
  * Input:
  *	- a pointer to a buffer to hold the string
- * 	- a 64-bit vector
+ *	- a 64-bit vector
  * Ouput:
  *	- a pointer to the end of the buffer
  *
@@ -181,7 +173,7 @@
 		if (i != 0 && (i%64) == 0) value = *++reg_info;
 
 		if ((value & 0x1) == 0 && skip == 0) {
-			if (begin  <= i - 2) 
+			if (begin  <= i - 2)
 				p += sprintf(p, "%d-%d ", begin, i-1);
 			else
 				p += sprintf(p, "%d ", i-1);
@@ -194,7 +186,7 @@
 		value >>=1;
 	}
 	if (begin > -1) {
-		if (begin < 127) 
+		if (begin < 127)
 			p += sprintf(p, "%d-127", begin);
 		else
 			p += sprintf(p, "127");
@@ -219,7 +211,7 @@
 		if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
 			p += sprintf(p,	"Power level %d:\n" \
 					"\tentry_latency       : %d cycles\n" \
-				 	"\texit_latency        : %d cycles\n" \
+					"\texit_latency        : %d cycles\n" \
 					"\tpower consumption   : %d mW\n" \
 					"\tCache+TLB coherency : %s\n", i,
 				halt_info[i].pal_power_mgmt_info_s.entry_latency,
@@ -233,7 +225,7 @@
 	return p - page;
 }
 
-static int 
+static int
 cache_info(char *page)
 {
 	char *p = page;
@@ -288,13 +280,13 @@
 
 			for(k=0; k < 8; k++ ) {
 				if ( cci.pcci_st_hints & 0x1) p += sprintf(p, "[%s]", cache_st_hints[k]);
-				cci.pcci_st_hints >>=1; 
+				cci.pcci_st_hints >>=1;
 			}
 			p += sprintf(p, "\n\tLoad hints     : ");
 
 			for(k=0; k < 8; k++ ) {
 				if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]);
-				cci.pcci_ld_hints >>=1; 
+				cci.pcci_ld_hints >>=1;
 			}
 			p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \
 					"\tTag LSB        : %d\n" \
@@ -384,7 +376,7 @@
 			ptce.stride[1]);
 
 	p += sprintf(p, "TC Levels                      : %d\n" \
-			"Unique TC(s)                   : %d\n", 
+			"Unique TC(s)                   : %d\n",
 			vm_info_1.pal_vm_info_1_s.num_tc_levels,
 			vm_info_1.pal_vm_info_1_s.max_unique_tcs);
 
@@ -392,7 +384,7 @@
 		for (j=2; j>0 ; j--) {
 			tc_pages = 0; /* just in case */
 
-		
+
 			/* even without unification, some levels may not be present */
 			if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
 				continue;
@@ -422,7 +414,7 @@
 	}
 	p += sprintf(p, "\n");
 
-	return p - page;	
+	return p - page;
 }
 
 
@@ -446,7 +438,7 @@
 
 		if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
 
-	 	p += sprintf(p, "%-32s : ", info_type[info]);
+		p += sprintf(p, "%-32s : ", info_type[info]);
 
 		p = bitregister_process(p, reg_info, 128);
 
@@ -458,8 +450,8 @@
 	p += sprintf(p, "RSE stacked physical registers   : %ld\n" \
 			"RSE load/store hints             : %ld (%s)\n",
 			phys_stacked,
-			hints.ph_data, 
-		     	hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
+			hints.ph_data,
+			hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
 
 	if (ia64_pal_debug_info(&iregs, &dregs)) return 0;
 
@@ -486,15 +478,15 @@
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	"Disable BINIT on processor time-out",
 	"Disable dynamic power management (DPM)",
-	"Disable coherency", 
-	"Disable cache", 
+	"Disable coherency",
+	"Disable cache",
 	"Enable CMCI promotion",
 	"Enable MCA to BINIT promotion",
 	"Enable MCA promotion",
 	"Enable BEER promotion"
 };
 
-	
+
 static int
 processor_info(char *page)
 {
@@ -508,7 +500,7 @@
 
 	for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) {
 		if ( ! *v ) continue;
-		p += sprintf(p, "%-40s : %s%s %s\n", *v, 
+		p += sprintf(p, "%-40s : %s%s %s\n", *v,
 				avail & 0x1 ? "" : "NotImpl",
 				avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "",
 				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
@@ -526,9 +518,9 @@
 	"Enable Half Transfer",
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	NULL, NULL, NULL, NULL, 
-	"Enable Cache Line Repl. Exclusive", 
-	"Enable Cache Line Repl. Shared", 
+	NULL, NULL, NULL, NULL,
+	"Enable Cache Line Repl. Exclusive",
+	"Enable Cache Line Repl. Shared",
 	"Disable Transaction Queuing",
 	"Disable Reponse Error Checking",
 	"Disable Bus Error Checking",
@@ -541,7 +533,7 @@
 	"Disable Bus Data Error Checking"
 };
 
-	
+
 static int
 bus_info(char *page)
 {
@@ -560,7 +552,7 @@
 
 	for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
 		if ( ! *v ) continue;
-		p += sprintf(p, "%-48s : %s%s %s\n", *v, 
+		p += sprintf(p, "%-48s : %s%s %s\n", *v,
 				avail & 0x1 ? "" : "NotImpl",
 				avail & 0x1 ? (status  & 0x1 ? "On" : "Off"): "",
 				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
@@ -568,62 +560,39 @@
 	return p - page;
 }
 
-
-/*
- * physical mode call for PAL_VERSION is working fine.
- * This function is meant to go away once PAL get fixed.
- */
-static inline s64 
-ia64_pal_version_phys(pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) 
-{	
-	struct ia64_pal_retval iprv;
-	PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0);
-	if (pal_min_version)
-		pal_min_version->pal_version_val = iprv.v0;
-	if (pal_cur_version)
-		pal_cur_version->pal_version_val = iprv.v1;
-	return iprv.status; 
-}
-
 static int
 version_info(char *page)
 {
-	s64 status;
 	pal_version_u_t min_ver, cur_ver;
 	char *p = page;
 
-#ifdef IA64_PAL_VERSION_BUG
-	/* The virtual mode call is buggy. But the physical mode call seems
-	 * to be ok. Until they fix virtual mode, we do physical.
-	 */
-	status = ia64_pal_version_phys(&min_ver, &cur_ver);
-#else
-	/* The system crashes if you enable this code with the wrong PAL 
-	 * code
+	/* The PAL_VERSION call is advertised as being able to support
+	 * both physical and virtual mode calls. This seems to be a documentation
+	 * bug rather than firmware bug. In fact, it does only support physical mode.
+	 * So now the code reflects this fact and the pal_version() has been updated
+	 * accordingly.
 	 */
-	status = ia64_pal_version(&min_ver, &cur_ver);
-#endif
-	if (status != 0) return 0;
+	if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0;
 
 	p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \
 			"PAL_A      : %x.%x.%x (min=%x.%x.%x)\n" \
 			"PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",
-	     		cur_ver.pal_version_s.pv_pal_vendor,
-	     		min_ver.pal_version_s.pv_pal_vendor,
+			cur_ver.pal_version_s.pv_pal_vendor,
+			min_ver.pal_version_s.pv_pal_vendor,
 
-	     		cur_ver.pal_version_s.pv_pal_a_model>>4,
-	     		cur_ver.pal_version_s.pv_pal_a_model&0xf,
-	     		cur_ver.pal_version_s.pv_pal_a_rev,
-	     		min_ver.pal_version_s.pv_pal_a_model>>4,
-	     		min_ver.pal_version_s.pv_pal_a_model&0xf,
-	     		min_ver.pal_version_s.pv_pal_a_rev,
-
-	     		cur_ver.pal_version_s.pv_pal_b_model>>4,
-	     		cur_ver.pal_version_s.pv_pal_b_model&0xf,
-	     		cur_ver.pal_version_s.pv_pal_b_rev,
-	     		min_ver.pal_version_s.pv_pal_b_model>>4,
-	     		min_ver.pal_version_s.pv_pal_b_model&0xf,
-	     		min_ver.pal_version_s.pv_pal_b_rev);
+			cur_ver.pal_version_s.pv_pal_a_model>>4,
+			cur_ver.pal_version_s.pv_pal_a_model&0xf,
+			cur_ver.pal_version_s.pv_pal_a_rev,
+			min_ver.pal_version_s.pv_pal_a_model>>4,
+			min_ver.pal_version_s.pv_pal_a_model&0xf,
+			min_ver.pal_version_s.pv_pal_a_rev,
+
+			cur_ver.pal_version_s.pv_pal_b_model>>4,
+			cur_ver.pal_version_s.pv_pal_b_model&0xf,
+			cur_ver.pal_version_s.pv_pal_b_rev,
+			min_ver.pal_version_s.pv_pal_b_model>>4,
+			min_ver.pal_version_s.pv_pal_b_model&0xf,
+			min_ver.pal_version_s.pv_pal_b_rev);
 
 	return p - page;
 }
@@ -650,7 +619,7 @@
 			"Counter width                 : %d bits\n" \
 			"Cycle event number            : %d\n" \
 			"Retired event number          : %d\n" \
-			"Implemented PMC               : ", 
+			"Implemented PMC               : ",
 			pm_info.pal_perf_mon_info_s.generic,
 			pm_info.pal_perf_mon_info_s.width,
 			pm_info.pal_perf_mon_info_s.cycles,
@@ -659,15 +628,15 @@
 	p = bitregister_process(p, pm_buffer, 256);
 
 	p += sprintf(p, "\nImplemented PMD               : ");
-	
+
 	p = bitregister_process(p, pm_buffer+4, 256);
 
 	p += sprintf(p, "\nCycles count capable          : ");
-	
+
 	p = bitregister_process(p, pm_buffer+8, 256);
 
 	p += sprintf(p, "\nRetired bundles count capable : ");
-	
+
 	p = bitregister_process(p, pm_buffer+12, 256);
 
 	p += sprintf(p, "\n");
@@ -683,7 +652,7 @@
 	u64 base;
 
 	if (ia64_pal_freq_base(&base) == -1)
-		p += sprintf(p, "Output clock            : not implemented\n"); 
+		p += sprintf(p, "Output clock            : not implemented\n");
 	else
 		p += sprintf(p, "Output clock            : %ld ticks/s\n", base);
 
@@ -762,7 +731,7 @@
 
 		if (ifa_reg->valid == 0) continue;
 
-		gr_reg   = (struct gr_reg *)tr_buffer;	
+		gr_reg   = (struct gr_reg *)tr_buffer;
 		itir_reg = (struct itir_reg *)&tr_buffer[1];
 		rid_reg  = (struct rid_reg *)&tr_buffer[3];
 
@@ -788,7 +757,7 @@
 				"\trid  : %x\n" \
 				"\tp    : %d\n" \
 				"\tma   : %d\n" \
-				"\td    : %d\n", 
+				"\td    : %d\n",
 				gr_reg->pl,
 				gr_reg->ar,
 				rid_reg->rid,
@@ -807,7 +776,7 @@
  */
 static palinfo_entry_t palinfo_entries[]={
 	{ "version_info",	version_info, },
-	{ "vm_info", 		vm_info, },
+	{ "vm_info",		vm_info, },
 	{ "cache_info",		cache_info, },
 	{ "power_info",		power_info, },
 	{ "register_info",	register_info, },
@@ -821,14 +790,14 @@
 #define NR_PALINFO_ENTRIES	(sizeof(palinfo_entries)/sizeof(palinfo_entry_t))
 
 /*
- * this array is used to keep track of the proc entries we create. This is 
+ * this array is used to keep track of the proc entries we create. This is
  * required in the module mode when we need to remove all entries. The procfs code
  * does not do recursion of deletion
  *
  * Notes:
  *	- first +1 accounts for the cpuN entry
  *	- second +1 account for toplevel palinfo
- * 
+ *
  */
 #define NR_PALINFO_PROC_ENTRIES	(NR_CPUS*(NR_PALINFO_ENTRIES+1)+1)
 
@@ -855,7 +824,7 @@
 #ifdef CONFIG_SMP
 
 /*
- * used to hold information about final function to call 
+ * used to hold information about final function to call
  */
 typedef struct {
 	palinfo_func_t	func;	/* pointer to function to call */
@@ -888,7 +857,7 @@
  *	0 : error or nothing to output
  *	otherwise how many bytes in the "page" buffer were written
  */
-static 
+static
 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
 {
 	palinfo_smp_data_t ptr;
@@ -908,7 +877,7 @@
 	return ptr.ret;
 }
 #else /* ! CONFIG_SMP */
-static 
+static
 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
 {
 	printk(__FUNCTION__" should not be called with non SMP kernel\n");
@@ -930,25 +899,25 @@
 	 * in SMP mode, we may need to call another CPU to get correct
 	 * information. PAL, by definition, is processor specific
 	 */
-	if (f->req_cpu == smp_processor_id()) 
+	if (f->req_cpu == smp_processor_id())
 		len = (*palinfo_entries[f->func_id].proc_read)(page);
 	else
 		len = palinfo_handle_smp(f, page);
 
-        if (len <= off+count) *eof = 1;
+	if (len <= off+count) *eof = 1;
 
-        *start = page + off;
-        len   -= off;
+	*start = page + off;
+	len   -= off;
 
-        if (len>count) len = count;
-        if (len<0) len = 0;
+	if (len>count) len = count;
+	if (len<0) len = 0;
 
 	MOD_DEC_USE_COUNT;
 
-        return len;
+	return len;
 }
 
-static int __init 
+static int __init
 palinfo_init(void)
 {
 #	define CPUSTR	"cpu%d"
@@ -979,7 +948,7 @@
 
 		for (j=0; j < NR_PALINFO_ENTRIES; j++) {
 			f.func_id = j;
-			*pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, 
+			*pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir,
 						palinfo_read_entry, (void *)f.value);
 		}
 		*pdir++ = cpu_dir;
@@ -994,9 +963,10 @@
 {
 	int i = 0;
 
-	/* remove all nodes: depth first pass */
+	/* remove all nodes: depth first pass. Could optimize this  */
 	for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) {
-		remove_proc_entry (palinfo_proc_entries[i]->name, NULL);
+		if (palinfo_proc_entries[i])
+			remove_proc_entry (palinfo_proc_entries[i]->name, NULL);
 	}
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c
--- v2.4.3/linux/arch/ia64/kernel/perfmon.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/perfmon.c	Fri Apr 13 15:29:37 2001
@@ -7,57 +7,39 @@
  * Modifications by Stephane Eranian, Hewlett-Packard Co.
  * Copyright (C) 1999 Ganesh Venkitachalam <venkitac@us.ibm.com>
  * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2000-2001 Stephane Eranian <eranian@hpl.hp.com>
  */
 
 #include <linux/config.h>
-
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+#include <linux/mm.h>
 
+#include <asm/bitops.h>
+#include <asm/efi.h>
 #include <asm/errno.h>
 #include <asm/hw_irq.h>
+#include <asm/page.h>
+#include <asm/pal.h>
+#include <asm/perfmon.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
+#include <asm/signal.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pal.h>
-
-/* Long blurb on how this works: 
- * We set dcr.pp, psr.pp, and the appropriate pmc control values with
- * this.  Notice that we go about modifying _each_ task's pt_regs to
- * set cr_ipsr.pp.  This will start counting when "current" does an
- * _rfi_. Also, since each task's cr_ipsr.pp, and cr_ipsr is inherited
- * across forks, we do _not_ need additional code on context
- * switches. On stopping of the counters we dont need to go about
- * changing every task's cr_ipsr back to where it wuz, because we can
- * just set pmc[0]=1. But we do it anyways becuase we will probably
- * add thread specific accounting later.
- *
- * The obvious problem with this is that on SMP systems, it is a bit
- * of work (when someone wants to do it:-)) - it would be easier if we
- * just added code to the context-switch path, but if we wanted to support
- * per-thread accounting, the context-switch path might be long unless 
- * we introduce a flag in the task_struct. Right now, the following code 
- * will NOT work correctly on MP (for more than one reason:-)).
- *
- * The short answer is that to make this work on SMP,  we would need 
- * to lock the run queue to ensure no context switches, send 
- * an IPI to each processor, and in that IPI handler, set processor regs,
- * and just modify the psr bit of only the _current_ thread, since we have 
- * modified the psr bit correctly in the kernel stack for every process 
- * which is not running. Also, we need pmd arrays per-processor, and 
- * the READ_PMD command will need to get values off of other processors. 
- * IPIs are the answer, irrespective of what the question is. Might 
- * crash on SMP systems without the lock_kernel().
- */
+#include <asm/delay.h> /* for ia64_get_itc() */
 
 #ifdef CONFIG_PERFMON
 
-#define MAX_PERF_COUNTER	4	/* true for Itanium, at least */
+#define PFM_VERSION		"0.2"
+#define PFM_SMPL_HDR_VERSION	1
+
 #define PMU_FIRST_COUNTER	4	/* first generic counter */
 
 #define PFM_WRITE_PMCS		0xa0
@@ -67,293 +49,1019 @@
 #define PFM_START		0xa4
 #define PFM_ENABLE		0xa5	/* unfreeze only */
 #define PFM_DISABLE		0xa6	/* freeze only */
-/* 
+#define PFM_RESTART		0xcf
+#define PFM_CREATE_CONTEXT	0xa7
+/*
  * Those 2 are just meant for debugging. I considered using sysctl() for
  * that but it is a little bit too pervasive. This solution is at least
  * self-contained.
  */
-#define PFM_DEBUG_ON		0xe0	
+#define PFM_DEBUG_ON		0xe0
 #define PFM_DEBUG_OFF		0xe1
 
+
+/*
+ * perfmon API flags
+ */
+#define PFM_FL_INHERIT_NONE	 0x00	/* never inherit a context across fork (default) */
+#define PFM_FL_INHERIT_ONCE	 0x01	/* clone pfm_context only once across fork() */
+#define PFM_FL_INHERIT_ALL	 0x02	/* always clone pfm_context across fork() */
+#define PFM_FL_SMPL_OVFL_NOBLOCK 0x04	/* do not block on sampling buffer overflow */
+#define PFM_FL_SYSTEMWIDE	 0x08	/* create a systemwide context */
+
+/*
+ * PMC API flags
+ */
+#define PFM_REGFL_OVFL_NOTIFY	1		/* send notification on overflow */
+
+/*
+ * Private flags and masks
+ */
+#define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
+
 #ifdef CONFIG_SMP
 #define cpu_is_online(i) (cpu_online_map & (1UL << i))
 #else
 #define cpu_is_online(i)	1
 #endif
 
-#define PMC_IS_IMPL(i)		(pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1))))
-#define PMD_IS_IMPL(i)  	(pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1))))
+#define PMC_IS_IMPL(i)		(i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1))))
+#define PMD_IS_IMPL(i)	(i < pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1))))
 #define PMD_IS_COUNTER(i)	(i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters))
 #define PMC_IS_COUNTER(i)	(i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters))
 
+/* This is the Itanium-specific PMC layout for counter config */
+typedef struct {
+	unsigned long pmc_plm:4;	/* privilege level mask */
+	unsigned long pmc_ev:1;		/* external visibility */
+	unsigned long pmc_oi:1;		/* overflow interrupt */
+	unsigned long pmc_pm:1;		/* privileged monitor */
+	unsigned long pmc_ig1:1;	/* reserved */
+	unsigned long pmc_es:7;		/* event select */
+	unsigned long pmc_ig2:1;	/* reserved */
+	unsigned long pmc_umask:4;	/* unit mask */
+	unsigned long pmc_thres:3;	/* threshold */
+	unsigned long pmc_ig3:1;	/* reserved (missing from table on p6-17) */
+	unsigned long pmc_ism:2;	/* instruction set mask */
+	unsigned long pmc_ig4:38;	/* reserved */
+} pmc_counter_reg_t;
+
+/* test for EAR/BTB configuration */
+#define PMU_DEAR_EVENT	0x67
+#define PMU_IEAR_EVENT	0x23
+#define PMU_BTB_EVENT	0x11
+
+#define PMC_IS_DEAR(a)		(((pmc_counter_reg_t *)(a))->pmc_es == PMU_DEAR_EVENT)
+#define PMC_IS_IEAR(a)		(((pmc_counter_reg_t *)(a))->pmc_es == PMU_IEAR_EVENT)
+#define PMC_IS_BTB(a)		(((pmc_counter_reg_t *)(a))->pmc_es == PMU_BTB_EVENT)
+
 /*
- * this structure needs to be enhanced
+ * This header is at the beginning of the sampling buffer returned to the user.
+ * It is exported as Read-Only at this point. It is directly followed with the
+ * first record.
  */
 typedef struct {
-	unsigned long	pfr_reg_num;	/* which register */
-	unsigned long	pfr_reg_value;	/* configuration (PMC) or initial value (PMD) */
-	unsigned long	pfr_reg_reset;	/* reset value on overflow (PMD) */
-	void		*pfr_smpl_buf;	/* pointer to user buffer for EAR/BTB */
-	unsigned long	pfr_smpl_size;	/* size of user buffer for EAR/BTB */
-	pid_t		pfr_notify_pid;	/* process to notify */
-	int		pfr_notify_sig;	/* signal for notification, 0=no notification */
-} perfmon_req_t;
+	int		hdr_version;		/* could be used to differentiate formats */
+	int		hdr_reserved;
+	unsigned long	hdr_entry_size;		/* size of one entry in bytes */
+	unsigned long	hdr_count;		/* how many valid entries */
+	unsigned long	hdr_pmds;		/* which pmds are recorded */
+} perfmon_smpl_hdr_t;
 
-#if 0
+/*
+ * Header entry in the buffer as a header as follows.
+ * The header is directly followed with the PMDS to saved in increasing index order:
+ * PMD4, PMD5, .... How many PMDs are present is determined by the tool which must
+ * keep track of it when generating the final trace file.
+ */
 typedef struct {
-	unsigned long pmu_reg_data;	/* generic PMD register */
-	unsigned long pmu_reg_num;	/* which register number */
-} perfmon_reg_t; 
-#endif
+	int		pid;		/* identification of process */
+	int		cpu;		/* which cpu was used */
+	unsigned long	rate;		/* initial value of this counter */
+	unsigned long	stamp;		/* timestamp */
+	unsigned long	ip;		/* where did the overflow interrupt happened */
+	unsigned long	regs;		/* which registers overflowed (up to 64)*/
+} perfmon_smpl_entry_t;
 
 /*
- * This structure is initialize at boot time and contains
+ * There is one such data structure per perfmon context. It is used to describe the
+ * sampling buffer. It is to be shared among siblings whereas the pfm_context isn't.
+ * Therefore we maintain a refcnt which is incremented on fork().
+ * This buffer is private to the kernel only the actual sampling buffer including its
+ * header are exposed to the user. This construct allows us to export the buffer read-write,
+ * if needed, without worrying about security problems.
+ */
+typedef struct {
+	atomic_t		psb_refcnt;	/* how many users for the buffer */
+	int			reserved;
+	void			*psb_addr;	/* points to location of first entry */
+	unsigned long		psb_entries;	/* maximum number of entries */
+	unsigned long		psb_size;	/* aligned size of buffer */
+	unsigned long		psb_index;	/* next free entry slot */
+	unsigned long		psb_entry_size;	/* size of each entry including entry header */
+	perfmon_smpl_hdr_t	*psb_hdr;	/* points to sampling buffer header */
+} pfm_smpl_buffer_desc_t;
+
+
+/*
+ * This structure is initialized at boot time and contains
  * a description of the PMU main characteristic as indicated
  * by PAL
  */
 typedef struct {
+	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
 	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
 	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
+	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
+	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
 	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
 } pmu_config_t;
 
+#define PERFMON_IS_DISABLED() pmu_conf.pfm_is_disabled
+
+typedef struct {
+	__u64		val;		/* virtual 64bit counter value */
+	__u64		ival;		/* initial value from user */
+	__u64		smpl_rval;	/* reset value on sampling overflow */
+	__u64		ovfl_rval;	/* reset value on overflow */
+	int		flags;		/* notify/do not notify */
+} pfm_counter_t;
+#define PMD_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
+
+/*
+ * perfmon context. One per process, is cloned on fork() depending on inheritance flags
+ */
+typedef struct {
+	unsigned int inherit:2;	/* inherit mode */
+	unsigned int noblock:1;	/* block/don't block on overflow with notification */
+	unsigned int system:1;	/* do system wide monitoring */
+	unsigned int frozen:1;	/* pmu must be kept frozen on ctxsw in */
+	unsigned int reserved:27;
+} pfm_context_flags_t;
+
+typedef struct pfm_context {
+
+	pfm_smpl_buffer_desc_t	*ctx_smpl_buf;		/* sampling buffer descriptor, if any */
+	unsigned long		ctx_dear_counter;	/* which PMD holds D-EAR */
+	unsigned long		ctx_iear_counter;	/* which PMD holds I-EAR */
+	unsigned long		ctx_btb_counter;	/* which PMD holds BTB */
+
+	pid_t			ctx_notify_pid;	/* who to notify on overflow */
+	int			ctx_notify_sig;	/* XXX: SIGPROF or other */
+	pfm_context_flags_t	ctx_flags;	/* block/noblock */
+	pid_t			ctx_creator;	/* pid of creator (debug) */
+	unsigned long		ctx_ovfl_regs;	/* which registers just overflowed (notification) */
+	unsigned long		ctx_smpl_regs;	/* which registers to record on overflow */
+
+	struct semaphore	ctx_restart_sem; /* use for blocking notification mode */
+
+	pfm_counter_t		ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */
+} pfm_context_t;
+
+#define ctx_fl_inherit	ctx_flags.inherit
+#define ctx_fl_noblock	ctx_flags.noblock
+#define ctx_fl_system	ctx_flags.system
+#define ctx_fl_frozen	ctx_flags.frozen
+
+#define CTX_IS_DEAR(c,n)	((c)->ctx_dear_counter == (n))
+#define CTX_IS_IEAR(c,n)	((c)->ctx_iear_counter == (n))
+#define CTX_IS_BTB(c,n)		((c)->ctx_btb_counter == (n))
+#define CTX_OVFL_NOBLOCK(c)	((c)->ctx_fl_noblock == 1)
+#define CTX_INHERIT_MODE(c)	((c)->ctx_fl_inherit)
+#define CTX_HAS_SMPL(c)		((c)->ctx_smpl_buf != NULL)
+
 static pmu_config_t pmu_conf;
 
 /* for debug only */
-static unsigned long pfm_debug=1;	/* 0= nodebug, >0= debug output on */
-#define DBprintk(a)	{\
-	if (pfm_debug >0) { printk a; } \
+static unsigned long pfm_debug=0;	/* 0= nodebug, >0= debug output on */
+#define DBprintk(a) \
+	do { \
+		if (pfm_debug >0) { printk(__FUNCTION__" "); printk a; } \
+	} while (0);
+
+static void perfmon_softint(unsigned long ignored);
+static void ia64_reset_pmu(void);
+
+DECLARE_TASKLET(pfm_tasklet, perfmon_softint, 0);
+
+/*
+ * structure used to pass information between the interrupt handler
+ * and the tasklet.
+ */
+typedef struct {
+	pid_t		to_pid;		/* which process to notify */
+	pid_t		from_pid;	/* which process is source of overflow */
+	int		sig;		/* with which signal */
+	unsigned long	bitvect;	/* which counters have overflowed */
+} notification_info_t;
+
+#define notification_is_invalid(i)	(i->to_pid < 2)
+
+/* will need to be cache line padded */
+static notification_info_t notify_info[NR_CPUS];
+
+/*
+ * We force cache line alignment to avoid false sharing
+ * given that we have one entry per CPU.
+ */
+static struct {
+	struct task_struct *owner;
+} ____cacheline_aligned pmu_owners[NR_CPUS];
+/* helper macros */
+#define SET_PMU_OWNER(t)	do { pmu_owners[smp_processor_id()].owner = (t); } while(0);
+#define PMU_OWNER()		pmu_owners[smp_processor_id()].owner
+
+/* for debug only */
+static struct proc_dir_entry *perfmon_dir;
+
+/*
+ * finds the number of PM(C|D) registers given
+ * the bitvector returned by PAL
+ */
+static unsigned long __init
+find_num_pm_regs(long *buffer)
+{
+	int i=3; /* 4 words/per bitvector */
+
+	/* start from the most significant word */
+	while (i>=0 && buffer[i] == 0 ) i--;
+	if (i< 0) {
+		printk(KERN_ERR "perfmon: No bit set in pm_buffer\n");
+		return 0;
+	}
+	return 1+ ia64_fls(buffer[i]) + 64 * i;
 }
 
+
 /*
- * could optimize to avoid cache line conflicts in SMP
+ * Generates a unique (per CPU) timestamp
+ */
+static inline unsigned long
+perfmon_get_stamp(void)
+{
+	/*
+	 * XXX: maybe find something more efficient
+	 */
+	return ia64_get_itc();
+}
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
  */
-static struct task_struct *pmu_owners[NR_CPUS];
+static inline unsigned long
+uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if (pte_present(pte)) {
+				ret = (unsigned long) page_address(pte_page(pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+			}
+		}
+	}
+	DBprintk(("uv2kva(%lx-->%lx)\n", adr, ret));
+	return ret;
+}
+
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long
+kvirt_to_pa(unsigned long adr)
+{
+	__u64 pa;
+	__asm__ __volatile__ ("tpa %0 = %1" : "=r"(pa) : "r"(adr) : "memory");
+	DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa));
+	return pa;
+}
+
+static void *
+rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr, page;
+
+	/* XXX: may have to revisit this part because
+	 * vmalloc() does not necessarily return a page-aligned buffer.
+	 * This maybe a security problem when mapped at user level
+	 */
+	mem=vmalloc(size);
+	if (mem) {
+		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+		adr=(unsigned long) mem;
+		while (size > 0) {
+			page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void
+rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr, page;
+
+	if (mem) {
+		adr=(unsigned long) mem;
+		while (size > 0) {
+			page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+static pfm_context_t *
+pfm_context_alloc(void)
+{
+	pfm_context_t *pfc;
+
+	/* allocate context descriptor */
+	pfc = vmalloc(sizeof(*pfc));
+	if (pfc) memset(pfc, 0, sizeof(*pfc));
+
+	return pfc;
+}
+
+static void
+pfm_context_free(pfm_context_t *pfc)
+{
+	if (pfc) vfree(pfc);
+}
 
 static int
-do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs)
+pfm_remap_buffer(unsigned long buf, unsigned long addr, unsigned long size)
 {
-        perfmon_req_t tmp;
-        int i;
+	unsigned long page;
 
-        switch (cmd) {
-		case PFM_WRITE_PMCS:          
-			/* we don't quite support this right now */
-			if (task != current) return -EINVAL;
+	while (size > 0) {
+		page = kvirt_to_pa(buf);
 
-			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
+		if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
+
+		addr  += PAGE_SIZE;
+		buf   += PAGE_SIZE;
+		size  -= PAGE_SIZE;
+	}
+	return 0;
+}
+
+/*
+ * counts the number of PMDS to save per entry.
+ * This code is generic enough to accomodate more than 64 PMDS when they become available
+ */
+static unsigned long
+pfm_smpl_entry_size(unsigned long *which, unsigned long size)
+{
+	unsigned long res = 0;
+	int i;
+
+	for (i=0; i < size; i++, which++) res += hweight64(*which);
+
+	DBprintk((" res=%ld\n", res));
+
+	return res;
+}
+
+/*
+ * Allocates the sampling buffer and remaps it into caller's address space
+ */
+static int
+pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long which_pmds, unsigned long entries, void **user_addr)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	unsigned long addr, size, regcount;
+	void *smpl_buf;
+	pfm_smpl_buffer_desc_t *psb;
+
+	regcount = pfm_smpl_entry_size(&which_pmds, 1);
+
+	/* note that regcount might be 0, in this case only the header for each
+	 * entry will be recorded.
+	 */
+
+	/*
+	 * 1 buffer hdr and for each entry a header + regcount PMDs to save
+	 */
+	size = PAGE_ALIGN(  sizeof(perfmon_smpl_hdr_t)
+			  + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64)));
+	/*
+	 * check requested size to avoid Denial-of-service attacks
+	 * XXX: may have to refine this test
+	 */
+	if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN;
+
+	/* find some free area in address space */
+	addr = get_unmapped_area(NULL, 0, size, 0, 0);
+	if (!addr) goto no_addr;
+
+	DBprintk((" entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, addr));
+
+	/* allocate vma */
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (!vma) goto no_vma;
+
+	/* XXX: see rvmalloc() for page alignment problem */
+	smpl_buf = rvmalloc(size);
+	if (smpl_buf == NULL) goto no_buffer;
+
+	DBprintk((" smpl_buf @%p\n", smpl_buf));
+
+	if (pfm_remap_buffer((unsigned long)smpl_buf, addr, size)) goto cant_remap;
+
+	/* allocate sampling buffer descriptor now */
+	psb = vmalloc(sizeof(*psb));
+	if (psb == NULL) goto no_buffer_desc;
+
+	/* start with something clean */
+	memset(smpl_buf, 0x0, size);
+
+	psb->psb_hdr	 = smpl_buf;
+	psb->psb_addr    = (char *)smpl_buf+sizeof(perfmon_smpl_hdr_t); /* first entry */
+	psb->psb_size    = size; /* aligned size */
+	psb->psb_index   = 0;
+	psb->psb_entries = entries;
+
+	atomic_set(&psb->psb_refcnt, 1);
+
+	psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64);
+
+	DBprintk((" psb @%p entry_size=%ld hdr=%p addr=%p\n", (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, (void *)psb->psb_addr));
+
+	/* initialize some of the fields of header */
+	psb->psb_hdr->hdr_version    = PFM_SMPL_HDR_VERSION;
+	psb->psb_hdr->hdr_entry_size = sizeof(perfmon_smpl_entry_t)+regcount*sizeof(u64);
+	psb->psb_hdr->hdr_pmds	     = which_pmds;
+
+	/* store which PMDS to record */
+	ctx->ctx_smpl_regs = which_pmds;
+
+	/* link to perfmon context */
+	ctx->ctx_smpl_buf  = psb;
+
+	/*
+	 * initialize the vma for the sampling buffer
+	 */
+	vma->vm_mm	  = mm;
+	vma->vm_start	  = addr;
+	vma->vm_end	  = addr + size;
+	vma->vm_flags	  = VM_READ|VM_MAYREAD;
+	vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */
+	vma->vm_ops	  = NULL;
+	vma->vm_pgoff	  = 0;
+	vma->vm_file	  = NULL;
+	vma->vm_raend	  = 0;
+
+	vma->vm_private_data = ctx;	/* link to pfm_context(not yet used) */
+
+	/*
+	 * now insert the vma in the vm list for the process
+	 */
+	insert_vm_struct(mm, vma);
+
+	mm->total_vm  += size >> PAGE_SHIFT;
+
+	/*
+	 * that's the address returned to the user
+	 */
+	*user_addr = (void *)addr;
+
+	return 0;
+
+	/* outlined error handling */
+no_addr:
+	DBprintk(("Cannot find unmapped area for size %ld\n", size));
+	return -ENOMEM;
+no_vma:
+	DBprintk(("Cannot allocate vma\n"));
+	return -ENOMEM;
+cant_remap:
+	DBprintk(("Can't remap buffer\n"));
+	rvfree(smpl_buf, size);
+no_buffer:
+	DBprintk(("Can't allocate sampling buffer\n"));
+	kmem_cache_free(vm_area_cachep, vma);
+	return -ENOMEM;
+no_buffer_desc:
+	DBprintk(("Can't allocate sampling buffer descriptor\n"));
+	kmem_cache_free(vm_area_cachep, vma);
+	rvfree(smpl_buf, size);
+	return -ENOMEM;
+}
+
+static int
+pfx_is_sane(pfreq_context_t *pfx)
+{
+	/* valid signal */
+	if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return 0;
+
+	/* cannot send to process 1, 0 means do not notify */
+	if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0;
+
+	/* asked for sampling, but nothing to record ! */
+	if (pfx->smpl_entries > 0 && pfm_smpl_entry_size(&pfx->smpl_regs, 1) == 0) return 0;
+
+	/* probably more to add here */
+
+
+	return 1;
+}
+
+static int
+pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req)
+{
+	pfm_context_t *ctx;
+	perfmon_req_t tmp;
+	void *uaddr = NULL;
+	int ret = -EFAULT;
+	int ctx_flags;
+
+	/* to go away */
+	if (flags) {
+		printk("perfmon: use context flags instead of perfmon() flags. Obsoleted API\n");
+	}
+
+	if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+	ctx_flags = tmp.pfr_ctx.flags;
+
+	/* not yet supported */
+	if (ctx_flags & PFM_FL_SYSTEMWIDE) return -EINVAL;
+
+	if (!pfx_is_sane(&tmp.pfr_ctx)) return -EINVAL;
+
+	ctx = pfm_context_alloc();
+	if (!ctx) return -ENOMEM;
+
+	/* record who the creator is (for debug) */
+	ctx->ctx_creator = task->pid;
+
+	ctx->ctx_notify_pid = tmp.pfr_ctx.notify_pid;
+	ctx->ctx_notify_sig = SIGPROF;	/* siginfo imposes a fixed signal */
+
+	if (tmp.pfr_ctx.smpl_entries) {
+		DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries));
+		if ((ret=pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, tmp.pfr_ctx.smpl_entries, &uaddr)) ) goto buffer_error;
+		tmp.pfr_ctx.smpl_vaddr = uaddr;
+	}
+	/* initialization of context's flags */
+	ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK;
+	ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0;
+	ctx->ctx_fl_system  = (ctx_flags & PFM_FL_SYSTEMWIDE) ? 1: 0;
+	ctx->ctx_fl_frozen  = 0;
+
+	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
+
+	if (copy_to_user(req, &tmp, sizeof(tmp))) goto buffer_error;
+
+	DBprintk((" context=%p, pid=%d notify_sig %d notify_pid=%d\n",(void *)ctx, task->pid, ctx->ctx_notify_sig, ctx->ctx_notify_pid));
+	DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system));
+
+	/* link with task */
+	task->thread.pfm_context = ctx;
+
+	return 0;
+
+buffer_error:
+	vfree(ctx);
+
+	return ret;
+}
+
+static void
+pfm_reset_regs(pfm_context_t *ctx)
+{
+	unsigned long mask = ctx->ctx_ovfl_regs;
+	int i, cnum;
+
+	DBprintk((" ovfl_regs=0x%lx\n", mask));
+	/*
+	 * now restore reset value on sampling overflowed counters
+	 */
+	for(i=0, cnum=PMU_FIRST_COUNTER; i < pmu_conf.max_counters; i++, cnum++, mask >>= 1) {
+		if (mask & 0x1) {
+			DBprintk((" reseting PMD[%d]=%lx\n", cnum, ctx->ctx_pmds[i].smpl_rval & pmu_conf.perf_ovfl_val));
+
+			/* upper part is ignored on rval */
+			ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval);
+		}
+	}
+}
+
+static int
+pfm_write_pmcs(struct task_struct *ta, perfmon_req_t *req, int count)
+{
+	struct thread_struct *th = &ta->thread;
+	pfm_context_t *ctx = th->pfm_context;
+	perfmon_req_t tmp;
+	unsigned long cnum;
+	int i;
+
+	/* XXX: ctx locking may be required here */
+
+	for (i = 0; i < count; i++, req++) {
+
+		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum = tmp.pfr_reg.reg_num;
+
+		/* XXX needs to check validity of the data maybe */
+		if (!PMC_IS_IMPL(cnum)) {
+			DBprintk((" invalid pmc[%ld]\n", cnum));
+			return -EINVAL;
+		}
+
+		if (PMC_IS_COUNTER(cnum)) {
+
+			/*
+			 * we keep track of EARS/BTB to speed up sampling later
+			 */
+			if (PMC_IS_DEAR(&tmp.pfr_reg.reg_value)) {
+				ctx->ctx_dear_counter = cnum;
+			} else if (PMC_IS_IEAR(&tmp.pfr_reg.reg_value)) {
+				ctx->ctx_iear_counter = cnum;
+			} else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) {
+				ctx->ctx_btb_counter = cnum;
+			}
+
+			if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY)
+				ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY;
+		}
+
+		ia64_set_pmc(cnum, tmp.pfr_reg.reg_value);
+			DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags));
+
+	}
+	/*
+	 * we have to set this here event hough we haven't necessarily started monitoring
+	 * because we may be context switched out
+	 */
+	th->flags |= IA64_THREAD_PM_VALID;
+
+	return 0;
+}
+
+static int
+pfm_write_pmds(struct task_struct *ta, perfmon_req_t *req, int count)
+{
+	struct thread_struct *th = &ta->thread;
+	pfm_context_t *ctx = th->pfm_context;
+	perfmon_req_t tmp;
+	unsigned long cnum;
+	int i;
+
+	/* XXX: ctx locking may be required here */
+
+	for (i = 0; i < count; i++, req++) {
+		int k;
+
+		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-			for (i = 0; i < count; i++, req++) {
-				copy_from_user(&tmp, req, sizeof(tmp));
+		cnum = tmp.pfr_reg.reg_num;
 
-				/* XXX needs to check validity of the data maybe */
+		k = cnum - PMU_FIRST_COUNTER;
 
-				if (!PMC_IS_IMPL(tmp.pfr_reg_num)) {
-					DBprintk((__FUNCTION__ " invalid pmc[%ld]\n", tmp.pfr_reg_num));
-					return -EINVAL;
-				}
-
-				/* XXX: for counters, need to some checks */
-				if (PMC_IS_COUNTER(tmp.pfr_reg_num)) {
-					current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].sig = tmp.pfr_notify_sig;
-					current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].pid = tmp.pfr_notify_pid;
-
-					DBprintk((__FUNCTION__" setting PMC[%ld] send sig %d to %d\n",tmp.pfr_reg_num, tmp.pfr_notify_sig, tmp.pfr_notify_pid));
-				}
-				ia64_set_pmc(tmp.pfr_reg_num, tmp.pfr_reg_value);
+		if (!PMD_IS_IMPL(cnum)) return -EINVAL;
 
-				DBprintk((__FUNCTION__" setting PMC[%ld]=0x%lx\n", tmp.pfr_reg_num, tmp.pfr_reg_value));
+		/* update virtualized (64bits) counter */
+		if (PMD_IS_COUNTER(cnum)) {
+			ctx->ctx_pmds[k].ival = tmp.pfr_reg.reg_value;
+			ctx->ctx_pmds[k].val  = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val;
+			ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset;
+			ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset;
+		}
+
+		/* writes to unimplemented part is ignored, so this is safe */
+		ia64_set_pmd(cnum, tmp.pfr_reg.reg_value);
+
+		/* to go away */
+		ia64_srlz_d();
+		DBprintk((" setting PMD[%ld]:  pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx\n",
+					cnum,
+					ctx->ctx_pmds[k].val,
+					ctx->ctx_pmds[k].ovfl_rval,
+					ctx->ctx_pmds[k].smpl_rval,
+					ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val));
+	}
+	/*
+	 * we have to set this here event hough we haven't necessarily started monitoring
+	 * because we may be context switched out
+	 */
+	th->flags |= IA64_THREAD_PM_VALID;
+
+	return 0;
+}
+
+static int
+pfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count)
+{
+	struct thread_struct *th = &ta->thread;
+	pfm_context_t *ctx = th->pfm_context;
+	unsigned long val=0;
+	perfmon_req_t tmp;
+	int i;
+
+	/*
+	 * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING
+	 * This is required when the monitoring has been stoppped by user of kernel.
+	 * If ity is still going on, then that's fine because we a re not gauranteed
+	 * to return an accurate value in this case
+	 */
+
+	/* XXX: ctx locking may be required here */
+
+	for (i = 0; i < count; i++, req++) {
+		int k;
+
+		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL;
+
+		k = tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER;
+
+		if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) {
+			if (ta == current){
+				val = ia64_get_pmd(tmp.pfr_reg.reg_num);
+			} else {
+				val = th->pmd[k];
 			}
+			val &= pmu_conf.perf_ovfl_val;
 			/*
-			 * we have to set this here event hough we haven't necessarily started monitoring
-			 * because we may be context switched out
+			 * lower part of .val may not be zero, so we must be an addition because of
+			 * residual count (see update_counters).
 			 */
-			current->thread.flags |= IA64_THREAD_PM_VALID;
-                	break;
+			val += ctx->ctx_pmds[k].val;
+		} else {
+			/* for now */
+			if (ta != current) return -EINVAL;
 
-		case PFM_WRITE_PMDS:
+			val = ia64_get_pmd(tmp.pfr_reg.reg_num);
+		}
+		tmp.pfr_reg.reg_value = val;
+
+		DBprintk((" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg.reg_num, val));
+
+		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+	}
+	return 0;
+}
+
+static int
+pfm_do_restart(struct task_struct *task)
+{
+	struct thread_struct *th = &task->thread;
+	pfm_context_t *ctx = th->pfm_context;
+	void *sem = &ctx->ctx_restart_sem;
+
+	if (task == current) {
+		DBprintk((" restartig self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
+
+		pfm_reset_regs(ctx);
+
+		/*
+		 * We ignore block/don't block because we never block
+		 * for a self-monitoring process.
+		 */
+		ctx->ctx_fl_frozen = 0;
+
+		if (CTX_HAS_SMPL(ctx)) {
+			ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0;
+			ctx->ctx_smpl_buf->psb_index = 0;
+		}
+
+		/* pfm_reset_smpl_buffers(ctx,th->pfm_ovfl_regs);*/
+
+		/* simply unfreeze */
+		ia64_set_pmc(0, 0);
+		ia64_srlz_d();
+
+		return 0;
+	}
+
+	/* check if blocking */
+	if (CTX_OVFL_NOBLOCK(ctx) == 0) {
+		DBprintk((" unblocking %d \n", task->pid));
+		up(sem);
+		return 0;
+	}
+
+	/*
+	 * in case of non blocking mode, then it's just a matter of
+	 * of reseting the sampling buffer (if any) index. The PMU
+	 * is already active.
+	 */
+
+	/*
+	 * must reset the header count first
+	 */
+	if (CTX_HAS_SMPL(ctx)) {
+		DBprintk((" resetting sampling indexes for %d \n", task->pid));
+		ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0;
+		ctx->ctx_smpl_buf->psb_index = 0;
+	}
+
+	return 0;
+}
+
+
+static int
+do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs)
+{
+	perfmon_req_t tmp;
+	struct thread_struct *th = &task->thread;
+	pfm_context_t *ctx = th->pfm_context;
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	switch (cmd) {
+		case PFM_CREATE_CONTEXT:
+			/* a context has already been defined */
+			if (ctx) return -EBUSY;
+
+			/* may be a temporary limitation */
+			if (task != current) return -EINVAL;
+
+			if (req == NULL || count != 1) return -EINVAL;
+
+			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
+
+			return pfm_context_create(task, flags, req);
+
+		case PFM_WRITE_PMCS:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
 			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-			for (i = 0; i < count; i++, req++) {
-				copy_from_user(&tmp, req, sizeof(tmp));
+			if (!ctx) {
+				DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid));
+				return -EINVAL;
+			}
+			return pfm_write_pmcs(task, req, count);
+
+		case PFM_WRITE_PMDS:
+			/* we don't quite support this right now */
+			if (task != current) return -EINVAL;
 
-				if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL;
+			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-				/* update virtualized (64bits) counter */
-				if (PMD_IS_COUNTER(tmp.pfr_reg_num)) {
-					current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val  = tmp.pfr_reg_value & ~pmu_conf.perf_ovfl_val;
-					current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval = tmp.pfr_reg_reset;
-				}
-				/* writes to unimplemented part is ignored, so this is safe */
-				ia64_set_pmd(tmp.pfr_reg_num, tmp.pfr_reg_value);
-				/* to go away */
-				ia64_srlz_d();
-				DBprintk((__FUNCTION__" setting PMD[%ld]:  pmod.val=0x%lx pmd=0x%lx rval=0x%lx\n", tmp.pfr_reg_num, current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val, ia64_get_pmd(tmp.pfr_reg_num),current->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].rval));
+			if (!ctx) {
+				DBprintk((" PFM_WRITE_PMDS: no context for task %d\n", task->pid));
+				return -EINVAL;
 			}
-			/*
-			 * we have to set this here event hough we haven't necessarily started monitoring
-			 * because we may be context switched out
-			 */
-			current->thread.flags |= IA64_THREAD_PM_VALID;
-                	break;
+			return pfm_write_pmds(task, req, count);
 
 		case PFM_START:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
-			pmu_owners[smp_processor_id()] = current;
+			if (!ctx) {
+				DBprintk((" PFM_START: no context for task %d\n", task->pid));
+				return -EINVAL;
+			}
+
+			SET_PMU_OWNER(current);
 
 			/* will start monitoring right after rfi */
 			ia64_psr(regs)->up = 1;
 
-			/* 
-		 	 * mark the state as valid.
-		 	 * this will trigger save/restore at context switch
-		 	 */
-			current->thread.flags |= IA64_THREAD_PM_VALID;
+			/*
+			 * mark the state as valid.
+			 * this will trigger save/restore at context switch
+			 */
+			th->flags |= IA64_THREAD_PM_VALID;
 
 			ia64_set_pmc(0, 0);
+			ia64_srlz_d();
 
-                	break;
+		break;
 
 		case PFM_ENABLE:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
-			pmu_owners[smp_processor_id()] = current;
+			if (!ctx) {
+				DBprintk((" PFM_ENABLE: no context for task %d\n", task->pid));
+				return -EINVAL;
+			}
+
+			/* reset all registers to stable quiet state */
+			ia64_reset_pmu();
+
+			/* make sure nothing starts */
+			ia64_psr(regs)->up = 0;
+			ia64_psr(regs)->pp = 0;
+
+			/* do it on the live register as well */
+			__asm__ __volatile__ ("rsm psr.pp|psr.pp;;"::: "memory");
+
+			SET_PMU_OWNER(current);
 
-			/* 
-		 	 * mark the state as valid.
-		 	 * this will trigger save/restore at context switch
-		 	 */
-			current->thread.flags |= IA64_THREAD_PM_VALID;
+			/*
+			 * mark the state as valid.
+			 * this will trigger save/restore at context switch
+			 */
+			th->flags |= IA64_THREAD_PM_VALID;
 
 			/* simply unfreeze */
 			ia64_set_pmc(0, 0);
+			ia64_srlz_d();
 			break;
 
 		case PFM_DISABLE:
 			/* we don't quite support this right now */
 			if (task != current) return -EINVAL;
 
-			/* simply unfreeze */
+			/* simply freeze */
 			ia64_set_pmc(0, 1);
 			ia64_srlz_d();
 			break;
 
-	        case PFM_READ_PMDS:
+		case PFM_READ_PMDS:
 			if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 			if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT;
 
-		/* This looks shady, but IMHO this will work fine. This is  
-		 * the sequence that I could come up with to avoid races
-		 * with the interrupt handler. See explanation in the 
-		 * following comment.
-		 */
-#if 0
-/* irrelevant with user monitors */
-		local_irq_save(flags);
-		__asm__ __volatile__("rsm psr.pp\n");
-		dcr = ia64_get_dcr();
-		dcr &= ~IA64_DCR_PP;
-		ia64_set_dcr(dcr);
-		local_irq_restore(flags);
-#endif
-		/*
-		 * We cannot write to pmc[0] to stop counting here, as
-		 * that particular instruction might cause an overflow
-		 * and the mask in pmc[0] might get lost. I'm _not_ 
-		 * sure of the hardware behavior here. So we stop
-		 * counting by psr.pp = 0. And we reset dcr.pp to
-		 * prevent an interrupt from mucking up psr.pp in the
-		 * meanwhile. Perfmon interrupts are pended, hence the
-		 * above code should be ok if one of the above instructions 
-		 * caused overflows, i.e the interrupt should get serviced
-		 * when we re-enabled interrupts. When I muck with dcr, 
-		 * is the irq_save/restore needed?
-		 */
-
-		for (i = 0; i < count; i++, req++) {
-			unsigned long val=0;
-
-			copy_from_user(&tmp, req, sizeof(tmp));
-
-			if (!PMD_IS_IMPL(tmp.pfr_reg_num)) return -EINVAL;
-
-			if (PMD_IS_COUNTER(tmp.pfr_reg_num)) {
-				if (task == current){
-					val = ia64_get_pmd(tmp.pfr_reg_num) & pmu_conf.perf_ovfl_val;
-				} else {
-					val = task->thread.pmd[tmp.pfr_reg_num - PMU_FIRST_COUNTER] & pmu_conf.perf_ovfl_val;
-				}
-				val += task->thread.pmu_counters[tmp.pfr_reg_num - PMU_FIRST_COUNTER].val;
-			} else {
-				/* for now */
-				if (task != current) return -EINVAL;
-
-				val = ia64_get_pmd(tmp.pfr_reg_num);
+			if (!ctx) {
+				DBprintk((" PFM_READ_PMDS: no context for task %d\n", task->pid));
+				return -EINVAL;
 			}
-			tmp.pfr_reg_value = val;
-
-DBprintk((__FUNCTION__" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg_num, val));
-
-			if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
-		}
-#if 0
-/* irrelevant with user monitors */
-		local_irq_save(flags);
-		__asm__ __volatile__("ssm psr.pp");
-		dcr = ia64_get_dcr();
-		dcr |= IA64_DCR_PP;
-		ia64_set_dcr(dcr);
-		local_irq_restore(flags);
-#endif
-                break;
+			return pfm_read_pmds(task, req, count);
 
 	      case PFM_STOP:
-		/* we don't quite support this right now */
-		if (task != current) return -EINVAL;
+			/* we don't quite support this right now */
+			if (task != current) return -EINVAL;
 
-		ia64_set_pmc(0, 1);
-		ia64_srlz_d();
+			ia64_set_pmc(0, 1);
+			ia64_srlz_d();
 
-		ia64_psr(regs)->up = 0;
+			ia64_psr(regs)->up = 0;
 
-		current->thread.flags &= ~IA64_THREAD_PM_VALID;
+			th->flags &= ~IA64_THREAD_PM_VALID;
 
-		pmu_owners[smp_processor_id()] = NULL;
+			SET_PMU_OWNER(NULL);
 
-#if 0
-/* irrelevant with user monitors */
-		local_irq_save(flags);
-		dcr = ia64_get_dcr();
-		dcr &= ~IA64_DCR_PP;
-		ia64_set_dcr(dcr);
-		local_irq_restore(flags);
-		ia64_psr(regs)->up = 0;
-#endif
-
-		break;
+			/* we probably will need some more cleanup here */
+			break;
 
 	      case PFM_DEBUG_ON:
-			printk(__FUNCTION__" debuggin on\n");
+			printk(" debugging on\n");
 			pfm_debug = 1;
 			break;
 
 	      case PFM_DEBUG_OFF:
-			printk(__FUNCTION__" debuggin off\n");
+			printk(" debugging off\n");
 			pfm_debug = 0;
 			break;
 
+	      case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */
+
+			if ((th->flags & IA64_THREAD_PM_VALID) == 0) {
+				printk(" PFM_RESTART not monitoring\n");
+				return -EINVAL;
+			}
+			if (!ctx) {
+				printk(" PFM_RESTART no ctx for %d\n", task->pid);
+				return -EINVAL;
+			}
+			if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) {
+				printk("task %d without pmu_frozen set\n", task->pid);
+				return -EINVAL;
+			}
+
+			return pfm_do_restart(task); /* we only look at first entry */
+
 	      default:
-		DBprintk((__FUNCTION__" UNknown command 0x%x\n", cmd));
-		return -EINVAL;
-		break;
-        }
-        return 0;
+			DBprintk((" UNknown command 0x%x\n", cmd));
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * XXX: do something better here
+ */
+static int
+perfmon_bad_permissions(struct task_struct *task)
+{
+	/* stolen from bad_signal() */
+	return (current->session != task->session)
+	    && (current->euid ^ task->suid) && (current->euid ^ task->uid)
+	    && (current->uid ^ task->suid) && (current->uid ^ task->uid);
 }
 
 asmlinkage int
@@ -361,8 +1069,16 @@
 {
 	struct pt_regs *regs = (struct pt_regs *) &stack;
 	struct task_struct *child = current;
-	int ret;
+	int ret = -ESRCH;
+
+	/* sanity check:
+	 *
+	 * ensures that we don't do bad things in case the OS
+	 * does not have enough storage to save/restore PMC/PMD
+	 */
+	if (PERFMON_IS_DISABLED()) return -ENOSYS;
 
+	/* XXX: pid interface is going away in favor of pfm context */
 	if (pid != current->pid) {
 		read_lock(&tasklist_lock);
 		{
@@ -370,37 +1086,245 @@
 			if (child)
 				get_task_struct(child);
 		}
-		if (!child) { 
-			read_unlock(&tasklist_lock);
-			return -ESRCH;
-		}
+
+		if (!child) goto abort_call;
+
+		ret = -EPERM;
+
+		if (perfmon_bad_permissions(child)) goto abort_call;
+
 		/*
 		 * XXX: need to do more checking here
 		 */
-		if (child->state != TASK_ZOMBIE) {
-			DBprintk((__FUNCTION__" warning process %d not in stable state %ld\n", pid, child->state));
+		if (child->state != TASK_ZOMBIE && child->state != TASK_STOPPED) {
+			DBprintk((" warning process %d not in stable state %ld\n", pid, child->state));
 		}
-	} 
+	}
 	ret = do_perfmonctl(child, cmd, flags, req, count, regs);
 
+abort_call:
 	if (child != current) read_unlock(&tasklist_lock);
 
 	return ret;
 }
 
 
-static inline int
-update_counters (u64 pmc0)
+/*
+ * This function is invoked on the exit path of the kernel. Therefore it must make sure
+ * it does does modify the caller's input registers (in0-in7) in case of entry by system call
+ * which can be restarted. That's why it's declared as a system call and all 8 possible args
+ * are declared even though not used.
+ */
+#if __GNUC__ >= 3
+void asmlinkage
+pfm_overflow_notify(void)
+#else
+void asmlinkage
+pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7)
+#endif
 {
-	unsigned long mask, i, cnum;
-	struct thread_struct *th;
-	struct task_struct *ta;
+	struct task_struct *task;
+	struct thread_struct *th = &current->thread;
+	pfm_context_t *ctx = current->thread.pfm_context;
+	struct siginfo si;
+	int ret;
 
-	if (pmu_owners[smp_processor_id()] == NULL) {
-		DBprintk((__FUNCTION__" Spurious overflow interrupt: PMU not owned\n"));
-		return 0;
+	/*
+	 * do some sanity checks first
+	 */
+	if (!ctx) {
+		printk("perfmon: process %d has no PFM context\n", current->pid);
+		return;
+	}
+	if (ctx->ctx_notify_pid < 2) {
+		printk("perfmon: process %d invalid notify_pid=%d\n", current->pid, ctx->ctx_notify_pid);
+		return;
+	}
+
+	DBprintk((" current=%d ctx=%p bv=0%lx\n", current->pid, (void *)ctx, ctx->ctx_ovfl_regs));
+	/*
+	 * NO matter what notify_pid is,
+	 * we clear overflow, won't notify again
+	 */
+	th->pfm_pend_notify = 0;
+
+	/*
+	 * When measuring in kernel mode and non-blocking fashion, it is possible to
+	 * get an overflow while executing this code. Therefore the state of pend_notify
+	 * and ovfl_regs can be altered. The important point is not to loose any notification.
+	 * It is fine to get called for nothing. To make sure we do collect as much state as
+	 * possible, update_counters() always uses |= to add bit to the ovfl_regs field.
+	 *
+	 * In certain cases, it is possible to come here, with ovfl_regs == 0;
+	 *
+	 * XXX: pend_notify and ovfl_regs could be merged maybe !
+	 */
+	if (ctx->ctx_ovfl_regs == 0) {
+		printk("perfmon: spurious overflow notification from pid %d\n", current->pid);
+		return;
 	}
-	
+	read_lock(&tasklist_lock);
+
+	task = find_task_by_pid(ctx->ctx_notify_pid);
+
+	if (task) {
+		si.si_signo    = ctx->ctx_notify_sig;
+		si.si_errno    = 0;
+		si.si_code     = PROF_OVFL; /* goes to user */
+		si.si_addr     = NULL;
+		si.si_pid      = current->pid; /* who is sending */
+		si.si_pfm_ovfl = ctx->ctx_ovfl_regs;
+
+		DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task));
+
+		/* must be done with tasklist_lock locked */
+		ret = send_sig_info(ctx->ctx_notify_sig, &si, task);
+		if (ret != 0) {
+			DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_pid, ret));
+			task = NULL; /* will cause return */
+		}
+	} else {
+		printk("perfmon: notify_pid %d not found\n", ctx->ctx_notify_pid);
+	}
+
+	read_unlock(&tasklist_lock);
+
+	/* now that we have released the lock handle error condition */
+	if (!task || CTX_OVFL_NOBLOCK(ctx)) {
+		/* we clear all pending overflow bits in noblock mode */
+		ctx->ctx_ovfl_regs = 0;
+		return;
+	}
+	DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid));
+
+	/*
+	 * may go through without blocking on SMP systems
+	 * if restart has been received already by the time we call down()
+	 */
+	ret = down_interruptible(&ctx->ctx_restart_sem);
+
+	DBprintk((" CPU%d %d after sleep ret=%d\n", smp_processor_id(), current->pid, ret));
+
+	/*
+	 * in case of interruption of down() we don't restart anything
+	 */
+	if (ret >= 0) {
+		/* we reactivate on context switch */
+		ctx->ctx_fl_frozen = 0;
+		/*
+		 * the ovfl_sem is cleared by the restart task and this is safe because we always
+		 * use the local reference
+		 */
+
+		pfm_reset_regs(ctx);
+
+		/* now we can clear this mask */
+		ctx->ctx_ovfl_regs = 0;
+
+		/*
+		 * Unlock sampling buffer and reset index atomically
+		 * XXX: not really needed when blocking
+		 */
+		if (CTX_HAS_SMPL(ctx)) {
+			ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0;
+			ctx->ctx_smpl_buf->psb_index = 0;
+		}
+
+		DBprintk((" CPU%d %d unfreeze PMU\n", smp_processor_id(), current->pid));
+
+		ia64_set_pmc(0, 0);
+		ia64_srlz_d();
+
+		/* state restored, can go back to work (user mode) */
+	}
+}
+
+static void
+perfmon_softint(unsigned long ignored)
+{
+	notification_info_t *info;
+	int my_cpu = smp_processor_id();
+	struct task_struct *task;
+	struct siginfo si;
+
+	info = notify_info+my_cpu;
+
+	DBprintk((" CPU%d current=%d to_pid=%d from_pid=%d bv=0x%lx\n", \
+		smp_processor_id(), current->pid, info->to_pid, info->from_pid, info->bitvect));
+
+	/* assumption check */
+	if (info->from_pid == info->to_pid) {
+		DBprintk((" Tasklet assumption error: from=%d tor=%d\n", info->from_pid, info->to_pid));
+		return;
+	}
+
+	if (notification_is_invalid(info)) {
+		DBprintk((" invalid notification information\n"));
+		return;
+	}
+
+	/* sanity check */
+	if (info->to_pid == 1) {
+		DBprintk((" cannot notify init\n"));
+		return;
+	}
+	/*
+	 * XXX: needs way more checks here to make sure we send to a task we have control over
+	 */
+	read_lock(&tasklist_lock);
+
+	task = find_task_by_pid(info->to_pid);
+
+	DBprintk((" after find %p\n", (void *)task));
+
+	if (task) {
+		int ret;
+
+		si.si_signo    = SIGPROF;
+		si.si_errno    = 0;
+		si.si_code     = PROF_OVFL; /* goes to user */
+		si.si_addr     =  NULL;
+		si.si_pid      = info->from_pid; /* who is sending */
+		si.si_pfm_ovfl = info->bitvect;
+
+		DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task));
+
+		/* must be done with tasklist_lock locked */
+		ret = send_sig_info(SIGPROF, &si, task);
+		if (ret != 0)
+			DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", info->to_pid, ret));
+
+		/* invalidate notification */
+		info->to_pid  = info->from_pid = 0;
+		info->bitvect = 0;
+	}
+
+	read_unlock(&tasklist_lock);
+
+	DBprintk((" after unlock %p\n", (void *)task));
+
+	if (!task) {
+		printk("perfmon: CPU%d cannot find process %d\n", smp_processor_id(), info->to_pid);
+	}
+}
+
+/*
+ * main overflow processing routine.
+ * it can be called from the interrupt path or explicitely during the context switch code
+ * Return:
+ *	0 : do not unfreeze the PMU
+ *	1 : PMU can be unfrozen
+ */
+static unsigned long
+update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs)
+{
+	unsigned long mask, i, cnum;
+	struct thread_struct *th;
+	pfm_context_t *ctx;
+	unsigned long bv = 0;
+	int my_cpu = smp_processor_id();
+	int ret = 1, buffer_is_full = 0;
+	int ovfl_is_smpl, can_notify, need_reset_pmd16=0;
 	/*
 	 * It is never safe to access the task for which the overflow interrupt is destinated
 	 * using the current variable as the interrupt may occur in the middle of a context switch
@@ -408,76 +1332,269 @@
 	 *
 	 * For monitoring, however, we do need to get access to the task which caused the overflow
 	 * to account for overflow on the counters.
+	 *
 	 * We accomplish this by maintaining a current owner of the PMU per CPU. During context
-	 * switch the ownership is changed in a way such that the reflected owner is always the 
+	 * switch the ownership is changed in a way such that the reflected owner is always the
 	 * valid one, i.e. the one that caused the interrupt.
 	 */
-	ta = pmu_owners[smp_processor_id()];
-	th = &pmu_owners[smp_processor_id()]->thread;
+
+	if (ta == NULL) {
+		DBprintk((" owners[%d]=NULL\n", my_cpu));
+		return 0x1;
+	}
+	th  = &ta->thread;
+	ctx = th->pfm_context;
 
 	/*
-	 * Don't think this could happen given first test. Keep as sanity check
+	 * XXX: debug test
+	 * Don't think this could happen given upfront tests
 	 */
 	if ((th->flags & IA64_THREAD_PM_VALID) == 0) {
-		DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d not using perfmon\n", ta->pid));
+		printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", ta->pid);
+		return 0x1;
+	}
+	if (!ctx) {
+		printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", ta->pid);
 		return 0;
 	}
 
 	/*
-	 * if PMU not frozen: spurious from previous context 
-	 * if PMC[0] = 0x1 : frozen but no overflow reported: leftover from previous context
-	 *
-	 * in either case we don't touch the state upon return from handler
+	 * sanity test. Should never happen
 	 */
-	if ((pmc0 & 0x1) == 0 || pmc0 == 0x1) { 
-		DBprintk((__FUNCTION__" Spurious overflow interrupt: process %d freeze=0\n",ta->pid));
-		return 0;
+	if ((pmc0 & 0x1 )== 0) {
+		printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", ta->pid, pmc0);
+		return 0x0;
 	}
 
-	mask = pmc0 >> 4;
+	mask = pmc0 >> PMU_FIRST_COUNTER;
 
-	for (i = 0, cnum = PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) {
+	DBprintk(("pmc0=0x%lx pid=%d\n", pmc0, ta->pid));
 
-		if (mask & 0x1) {
-			DBprintk((__FUNCTION__ " PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), th->pmu_counters[i].val)); 
-			
+	DBprintk(("ctx is in %s mode\n", CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK"));
+
+	if (CTX_HAS_SMPL(ctx)) {
+		pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf;
+		unsigned long *e, m, idx=0;
+		perfmon_smpl_entry_t *h;
+		int j;
+
+		idx = ia64_fetch_and_add(1, &psb->psb_index);
+		DBprintk((" trying to record index=%ld entries=%ld\n", idx, psb->psb_entries));
+
+		/*
+		 * XXX: there is a small chance that we could run out on index before resetting
+		 * but index is unsigned long, so it will take some time.....
+		 */
+		if (idx > psb->psb_entries) {
+			buffer_is_full = 1;
+			goto reload_pmds;
+		}
+
+		/* first entry is really entry 0, not 1 caused by fetch_and_add */
+		idx--;
+
+		h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size));
+
+		h->pid  = ta->pid;
+		h->cpu  = my_cpu;
+		h->rate = 0;
+		h->ip   = regs ? regs->cr_iip : 0x0; /* where did the fault happened */
+		h->regs = mask; /* which registers overflowed */
+
+		/* guaranteed to monotonically increase on each cpu */
+		h->stamp = perfmon_get_stamp();
+
+		e = (unsigned long *)(h+1);
+		/*
+		 * selectively store PMDs in increasing index number
+		 */
+		for (j=0, m = ctx->ctx_smpl_regs; m; m >>=1, j++) {
+			if (m & 0x1) {
+				if (PMD_IS_COUNTER(j))
+					*e =  ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val
+					    + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val);
+				else
+					*e = ia64_get_pmd(j); /* slow */
+				DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
+				e++;
+			}
+		}
+		/* make the new entry visible to user, needs to be atomic */
+		ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count);
+
+		DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count));
+
+		/* sampling buffer full ? */
+		if (idx == (psb->psb_entries-1)) {
+			bv = mask;
+			buffer_is_full = 1;
+
+			DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv));
+
+			if (!CTX_OVFL_NOBLOCK(ctx)) goto buffer_full;
 			/*
-			 * Because we somtimes (EARS/BTB) reset to a specific value, we cannot simply use 
-			 * val to count the number of times we overflowed. Otherwise we would loose the value
-			 * current in the PMD (which can be >0). So to make sure we don't loose
-			 * the residual counts we set val to contain full 64bits value of the counter.
+			 * here, we have a full buffer but we are in non-blocking mode
+			 * so we need to reloads overflowed PMDs with sampling reset values
+			 * and restart
 			 */
-			th->pmu_counters[i].val += 1+pmu_conf.perf_ovfl_val+(ia64_get_pmd(cnum) &pmu_conf.perf_ovfl_val);
+		}
+	}
+reload_pmds:
+	ovfl_is_smpl = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full;
+	can_notify   = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_pid;
 
-			/* writes to upper part are ignored, so this is safe */
-			ia64_set_pmd(cnum, th->pmu_counters[i].rval);
+	for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) {
+
+		if ((mask & 0x1) == 0) continue;
+
+		DBprintk((" PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), ctx->ctx_pmds[i].val));
 
-			DBprintk((__FUNCTION__ " pmod[%ld].val=0x%lx pmd=0x%lx\n", i, th->pmu_counters[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); 
+		/*
+		 * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use
+		 * val to count the number of times we overflowed. Otherwise we would loose the current value
+		 * in the PMD (which can be >0). So to make sure we don't loose
+		 * the residual counts we set val to contain full 64bits value of the counter.
+		 *
+		 * XXX: is this needed for EARS/BTB ?
+		 */
+		ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val
+				      + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val); /* slow */
+
+		DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val));
+
+		if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) {
+			DBprintk((" CPU%d should notify process %d with signal %d\n", my_cpu, ctx->ctx_notify_pid, ctx->ctx_notify_sig));
+			bv |= 1 << i;
+		} else {
+			DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum));
+			/*
+			 * In case no notification is requested, we reload the reset value right away
+			 * otherwise we wait until the notify_pid process has been called and has
+			 * has finished processing data. Check out pfm_overflow_notify()
+			 */
 
-			if (th->pmu_counters[i].pid != 0 && th->pmu_counters[i].sig>0) {
-				DBprintk((__FUNCTION__ " shouild notify process %d with signal %d\n",th->pmu_counters[i].pid, th->pmu_counters[i].sig)); 
+			/* writes to upper part are ignored, so this is safe */
+			if (ovfl_is_smpl) {
+				DBprintk((" CPU%d PMD[%ld] reloaded with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval));
+				ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval);
+			} else {
+				DBprintk((" CPU%d PMD[%ld] reloaded with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval));
+				ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval);
 			}
 		}
+		if (cnum == ctx->ctx_btb_counter) need_reset_pmd16=1;
 	}
-	return 1;
+	/*
+	 * In case of BTB, overflow
+	 * we need to reset the BTB index.
+	 */
+	if (need_reset_pmd16) {
+		DBprintk(("reset PMD16\n"));
+		ia64_set_pmd(16, 0);
+	}
+buffer_full:
+	/* see pfm_overflow_notify() on details for why we use |= here */
+	ctx->ctx_ovfl_regs  |= bv;
+
+	/* nobody to notify, return and unfreeze */
+	if (!bv) return 0x0;
+
+
+	if (ctx->ctx_notify_pid == ta->pid) {
+		struct siginfo si;
+
+		si.si_errno    = 0;
+		si.si_addr     = NULL;
+		si.si_pid      = ta->pid; /* who is sending */
+
+
+		si.si_signo    = ctx->ctx_notify_sig; /* is SIGPROF */
+		si.si_code     = PROF_OVFL; /* goes to user */
+		si.si_pfm_ovfl = bv;
+
+
+		/*
+		 * in this case, we don't stop the task, we let it go on. It will
+		 * necessarily go to the signal handler (if any) when it goes back to
+		 * user mode.
+		 */
+		DBprintk((" sending %d notification to self %d\n", si.si_signo, ta->pid));
+
+
+		/* this call is safe in an interrupt handler */
+		ret = send_sig_info(ctx->ctx_notify_sig, &si, ta);
+		if (ret != 0)
+			printk(" send_sig_info(process %d, SIGPROF)=%d\n", ta->pid, ret);
+		/*
+		 * no matter if we block or not, we keep PMU frozen and do not unfreeze on ctxsw
+		 */
+		ctx->ctx_fl_frozen = 1;
+
+	} else {
+#if 0
+			/*
+			 * The tasklet is guaranteed to be scheduled for this CPU only
+			 */
+			notify_info[my_cpu].to_pid   = ctx->notify_pid;
+			notify_info[my_cpu].from_pid = ta->pid; /* for debug only */
+			notify_info[my_cpu].bitvect  = bv;
+			/* tasklet is inserted and active */
+			tasklet_schedule(&pfm_tasklet);
+#endif
+			/*
+			 * stored the vector of overflowed registers for use in notification
+			 * mark that a notification/blocking is pending (arm the trap)
+			 */
+		th->pfm_pend_notify = 1;
+
+		/*
+		 * if we do block, then keep PMU frozen until restart
+		 */
+		if (!CTX_OVFL_NOBLOCK(ctx)) ctx->ctx_fl_frozen = 1;
+
+		DBprintk((" process %d notify ovfl_regs=0x%lx\n", ta->pid, bv));
+	}
+	/*
+	 * keep PMU frozen (and overflowed bits cleared) when we have to stop,
+	 * otherwise return a resume 'value' for PMC[0]
+	 *
+	 * XXX: maybe that's enough to get rid of ctx_fl_frozen ?
+	 */
+	DBprintk((" will return pmc0=0x%x\n",ctx->ctx_fl_frozen ? 0x1 : 0x0));
+	return ctx->ctx_fl_frozen ? 0x1 : 0x0;
 }
 
 static void
 perfmon_interrupt (int irq, void *arg, struct pt_regs *regs)
 {
-	/* unfreeze if not spurious */
-	if ( update_counters(ia64_get_pmc(0)) ) {
-		ia64_set_pmc(0, 0);
+	u64 pmc0;
+	struct task_struct *ta;
+
+	pmc0 = ia64_get_pmc(0); /* slow */
+
+	/*
+	 * if we have some pending bits set
+	 * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1
+	 */
+	if ((pmc0 & ~0x1) && (ta=PMU_OWNER())) {
+
+		/* assumes, PMC[0].fr = 1 at this point */
+		pmc0 = update_counters(ta, pmc0, regs);
+
+		/*
+		 * if pmu_frozen = 0
+		 *	pmc0 = 0 and we resume monitoring right away
+		 * else
+		 *	pmc0 = 0x1 frozen but all pending bits are cleared
+		 */
+		ia64_set_pmc(0, pmc0);
 		ia64_srlz_d();
+	} else {
+		printk("perfmon: Spurious PMU overflow interrupt: pmc0=0x%lx owner=%p\n", pmc0, (void *)PMU_OWNER());
 	}
 }
 
-static struct irqaction perfmon_irqaction = {
-	handler:	perfmon_interrupt,
-	flags:		SA_INTERRUPT,
-	name:		"perfmon"
-};
-
+/* for debug only */
 static int
 perfmon_proc_info(char *page)
 {
@@ -487,56 +1604,79 @@
 
 	p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off");
 	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_is_online(i)) 
-			p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i] ? pmu_owners[i]->pid: -1);
+		if (cpu_is_online(i))
+			p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: 0);
 	}
 	return p - page;
 }
 
+/* for debug only */
 static int
 perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	int len = perfmon_proc_info(page);
 
-        if (len <= off+count) *eof = 1;
+	if (len <= off+count) *eof = 1;
 
-        *start = page + off;
-        len   -= off;
+	*start = page + off;
+	len   -= off;
 
-        if (len>count) len = count;
-        if (len<0) len = 0;
+	if (len>count) len = count;
+	if (len<0) len = 0;
 
-        return len;
+	return len;
 }
 
-static struct proc_dir_entry *perfmon_dir;
+static struct irqaction perfmon_irqaction = {
+	handler:	perfmon_interrupt,
+	flags:		SA_INTERRUPT,
+	name:		"perfmon"
+};
 
 void __init
 perfmon_init (void)
 {
 	pal_perf_mon_info_u_t pm_info;
 	s64 status;
-	
-	irq_desc[PERFMON_IRQ].status |= IRQ_PER_CPU;
-	irq_desc[PERFMON_IRQ].handler = &irq_type_ia64_sapic;
-	setup_irq(PERFMON_IRQ, &perfmon_irqaction);
 
-	ia64_set_pmv(PERFMON_IRQ);
+	register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
+
+	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
 
-	printk("perfmon: Initialized vector to %u\n",PERFMON_IRQ);
+	pmu_conf.pfm_is_disabled = 1;
+
+	printk("perfmon: version %s\n", PFM_VERSION);
+	printk("perfmon: Interrupt vectored to %u\n", IA64_PERFMON_VECTOR);
 
 	if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) {
-		printk(__FUNCTION__ " pal call failed (%ld)\n", status);
+		printk("perfmon: PAL call failed (%ld)\n", status);
 		return;
-	} 
-	pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; 
-
-	/* XXX need to use PAL instead */
+	}
+	pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1;
 	pmu_conf.max_counters  = pm_info.pal_perf_mon_info_s.generic;
+	pmu_conf.num_pmds      = find_num_pm_regs(pmu_conf.impl_regs);
+	pmu_conf.num_pmcs      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
 
 	printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width);
 	printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val);
+	printk("perfmon: %ld PMC/PMD pairs\n", pmu_conf.max_counters);
+	printk("perfmon: %ld PMCs, %ld PMDs\n", pmu_conf.num_pmcs, pmu_conf.num_pmds);
+	printk("perfmon: Sampling format v%d\n", PFM_SMPL_HDR_VERSION);
+
+	/* sanity check */
+	if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) {
+		printk(KERN_ERR "perfmon: ERROR not enough PMC/PMD storage in kernel, perfmon is DISABLED\n");
+		return; /* no need to continue anyway */
+	}
+	/* we are all set */
+	pmu_conf.pfm_is_disabled = 0;
+
+	/*
+	 * Insert the tasklet in the list.
+	 * It is still disabled at this point, so it won't run
+	printk(__FUNCTION__" tasklet is %p state=%d, count=%d\n", &perfmon_tasklet, perfmon_tasklet.state, perfmon_tasklet.count);
+	 */
 
 	/*
 	 * for now here for debug purposes
@@ -547,7 +1687,7 @@
 void
 perfmon_init_percpu (void)
 {
-	ia64_set_pmv(PERFMON_IRQ);
+	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
 }
 
@@ -555,14 +1695,19 @@
  * XXX: for system wide this function MUST never be called
  */
 void
-ia64_save_pm_regs (struct task_struct *ta)
+pfm_save_regs (struct task_struct *ta)
 {
-	struct thread_struct *t = &ta->thread;
+	struct task_struct *owner;
+	struct thread_struct *t;
 	u64 pmc0, psr;
-	int i,j;
+	int i;
 
+	if (ta == NULL) {
+		panic(__FUNCTION__" task is NULL\n");
+	}
+	t = &ta->thread;
 	/*
-	 * We must maek sure that we don't loose any potential overflow
+	 * We must make sure that we don't loose any potential overflow
 	 * interrupt while saving PMU context. In this code, external
 	 * interrupts are always enabled.
 	 */
@@ -575,94 +1720,102 @@
 	/*
 	 * stop monitoring:
 	 * This is the only way to stop monitoring without destroying overflow
-	 * information in PMC[0..3].
+	 * information in PMC[0].
 	 * This is the last instruction which can cause overflow when monitoring
 	 * in kernel.
-	 * By now, we could still have an overflow interrupt in flight.
+	 * By now, we could still have an overflow interrupt in-flight.
 	 */
-	__asm__ __volatile__ ("rsm psr.up;;"::: "memory");
-	
+	__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+
+	/*
+	 * Mark the PMU as not owned
+	 * This will cause the interrupt handler to do nothing in case an overflow
+	 * interrupt was in-flight
+	 * This also guarantees that pmc0 will contain the final state
+	 * It virtually gives us full control over overflow processing from that point
+	 * on.
+	 * It must be an atomic operation.
+	 */
+	owner = PMU_OWNER();
+	SET_PMU_OWNER(NULL);
+
 	/*
 	 * read current overflow status:
 	 *
-	 * We may be reading stale information at this point, if we got interrupt
-	 * just before the read(pmc0) but that's all right. However, if we did
-	 * not get the interrupt before, this read reflects LAST state.
-	 *
+	 * we are guaranteed to read the final stable state
 	 */
-	pmc0 = ia64_get_pmc(0);
+	ia64_srlz_d();
+	pmc0 = ia64_get_pmc(0); /* slow */
 
 	/*
 	 * freeze PMU:
 	 *
 	 * This destroys the overflow information. This is required to make sure
 	 * next process does not start with monitoring on if not requested
-	 * (PSR.up may not be enough).
-	 *
-	 * We could still get an overflow interrupt by now. However the handler
-	 * will not do anything if is sees PMC[0].fr=1 but no overflow bits
-	 * are set. So PMU will stay in frozen state. This implies that pmc0
-	 * will still be holding the correct unprocessed information.
-	 *
 	 */
 	ia64_set_pmc(0, 1);
 	ia64_srlz_d();
 
 	/*
-	 * check for overflow bits set:
+	 * Check for overflow bits and proceed manually if needed
 	 *
-	 * If pmc0 reports PMU frozen, this means we have a pending overflow,
-	 * therefore we invoke the handler. Handler is reentrant with regards
-	 * to PMC[0] so it is safe to call it twice.
-	 *
-	 * IF pmc0 reports overflow, we need to reread current PMC[0] value
-	 * in case the handler was invoked right after the first pmc0 read.
-	 * it is was not invoked then pmc0==PMC[0], otherwise it's been invoked
-	 * and overflow information has been processed, so we don't need to call.
-	 *
-	 * Test breakdown:
-	 *	- pmc0 & ~0x1: test if overflow happened
-	 * 	- second part: check if current register reflects this as well.
-	 *
-	 * NOTE: testing for pmc0 & 0x1 is not enough has it would trigger call
-	 * when PM_VALID and PMU.fr which is common when setting up registers
-	 * just before actually starting monitors.
-	 *
-	 */
-	if ((pmc0 & ~0x1) && ((pmc0=ia64_get_pmc(0)) &~0x1) ) {
-		printk(__FUNCTION__" Warning: pmc[0]=0x%lx\n", pmc0);
-		update_counters(pmc0);
-		/* 
-		 * XXX: not sure that's enough. the next task may still get the
-		 * interrupt.
-		 */
+	 * It is safe to call the interrupt handler now because it does
+	 * not try to block the task right away. Instead it will set a
+	 * flag and let the task proceed. The blocking will only occur
+	 * next time the task exits from the kernel.
+	 */
+	if (pmc0 & ~0x1) {
+		if (owner != ta) printk(__FUNCTION__" owner=%p task=%p\n", (void *)owner, (void *)ta);
+		printk(__FUNCTION__" Warning: pmc[0]=0x%lx explicit call\n", pmc0);
+
+		pmc0 = update_counters(owner, pmc0, NULL);
+		/* we will save the updated version of pmc0 */
 	}
 
 	/*
 	 * restore PSR for context switch to save
 	 */
-	__asm__ __volatile__ ("mov psr.l=%0;;"::"r"(psr): "memory");
+	__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory");
+
 
 	/*
-	 * XXX: this will need to be extended beyong just counters
+	 * XXX needs further optimization.
+	 * Also must take holes into account
 	 */
-	for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) {
-		t->pmd[i] = ia64_get_pmd(j);
-		t->pmc[i] = ia64_get_pmc(j);
+	for (i=0; i< pmu_conf.num_pmds; i++) {
+		t->pmd[i] = ia64_get_pmd(i);
+	}
+
+	/* skip PMC[0], we handle it separately */
+	for (i=1; i< pmu_conf.num_pmcs; i++) {
+		t->pmc[i] = ia64_get_pmc(i);
 	}
+
 	/*
-	 * PMU is frozen, PMU context is saved: nobody owns the PMU on this CPU
-	 * At this point, we should not receive any pending interrupt from the 
-	 * 'switched out' task
+	 * Throughout this code we could have gotten an overflow interrupt. It is transformed
+	 * into a spurious interrupt as soon as we give up pmu ownership.
 	 */
-	pmu_owners[smp_processor_id()] = NULL;
 }
 
 void
-ia64_load_pm_regs (struct task_struct *ta)
+pfm_load_regs (struct task_struct *ta)
 {
 	struct thread_struct *t = &ta->thread;
-	int i,j;
+	pfm_context_t *ctx = ta->thread.pfm_context;
+	int i;
+
+	/*
+	 * XXX needs further optimization.
+	 * Also must take holes into account
+	 */
+	for (i=0; i< pmu_conf.num_pmds; i++) {
+		ia64_set_pmd(i, t->pmd[i]);
+	}
+
+	/* skip PMC[0] to avoid side effects */
+	for (i=1; i< pmu_conf.num_pmcs; i++) {
+		ia64_set_pmc(i, t->pmc[i]);
+	}
 
 	/*
 	 * we first restore ownership of the PMU to the 'soon to be current'
@@ -670,26 +1823,277 @@
 	 * of this function, we get an interrupt, we attribute it to the correct
 	 * task
 	 */
-	pmu_owners[smp_processor_id()] = ta;
+	SET_PMU_OWNER(ta);
+
+#if 0
+	/*
+	 * check if we had pending overflow before context switching out
+	 * If so, we invoke the handler manually, i.e. simulate interrupt.
+	 *
+	 * XXX: given that we do not use the tasklet anymore to stop, we can
+	 * move this back to the pfm_save_regs() routine.
+	 */
+	if (t->pmc[0] & ~0x1) {
+		/* freeze set in pfm_save_regs() */
+		DBprintk((" pmc[0]=0x%lx manual interrupt\n",t->pmc[0]));
+		update_counters(ta, t->pmc[0], NULL);
+	}
+#endif
 
 	/*
-	 * XXX: this will need to be extended beyong just counters 
+	 * unfreeze only when possible
 	 */
-	for (i=0,j=4; i< IA64_NUM_PMD_COUNTERS; i++,j++) {
-		ia64_set_pmd(j, t->pmd[i]);
-		ia64_set_pmc(j, t->pmc[i]);
+	if (ctx->ctx_fl_frozen == 0) {
+		ia64_set_pmc(0, 0);
+		ia64_srlz_d();
+	}
+}
+
+
+/*
+ * This function is called when a thread exits (from exit_thread()).
+ * This is a simplified pfm_save_regs() that simply flushes hthe current
+ * register state into the save area taking into account any pending
+ * overflow. This time no notification is sent because the taks is dying
+ * anyway. The inline processing of overflows avoids loosing some counts.
+ * The PMU is frozen on exit from this call and is to never be reenabled
+ * again for this task.
+ */
+void
+pfm_flush_regs (struct task_struct *ta)
+{
+	pfm_context_t *ctx;
+	u64 pmc0, psr, mask;
+	int i,j;
+
+	if (ta == NULL) {
+		panic(__FUNCTION__" task is NULL\n");
 	}
+	ctx = ta->thread.pfm_context;
+	if (ctx == NULL) {
+		panic(__FUNCTION__" no PFM ctx is NULL\n");
+	}
+	/*
+	 * We must make sure that we don't loose any potential overflow
+	 * interrupt while saving PMU context. In this code, external
+	 * interrupts are always enabled.
+	 */
+
+	/*
+	 * save current PSR: needed because we modify it
+	 */
+	__asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory");
+
+	/*
+	 * stop monitoring:
+	 * This is the only way to stop monitoring without destroying overflow
+	 * information in PMC[0].
+	 * This is the last instruction which can cause overflow when monitoring
+	 * in kernel.
+	 * By now, we could still have an overflow interrupt in-flight.
+	 */
+	__asm__ __volatile__ ("rsm psr.up;;"::: "memory");
+
+	/*
+	 * Mark the PMU as not owned
+	 * This will cause the interrupt handler to do nothing in case an overflow
+	 * interrupt was in-flight
+	 * This also guarantees that pmc0 will contain the final state
+	 * It virtually gives us full control on overflow processing from that point
+	 * on.
+	 * It must be an atomic operation.
+	 */
+	SET_PMU_OWNER(NULL);
+
+	/*
+	 * read current overflow status:
+	 *
+	 * we are guaranteed to read the final stable state
+	 */
+	ia64_srlz_d();
+	pmc0 = ia64_get_pmc(0); /* slow */
+
+	/*
+	 * freeze PMU:
+	 *
+	 * This destroys the overflow information. This is required to make sure
+	 * next process does not start with monitoring on if not requested
+	 */
+	ia64_set_pmc(0, 1);
+	ia64_srlz_d();
+
+	/*
+	 * restore PSR for context switch to save
+	 */
+	__asm__ __volatile__ ("mov psr.l=%0;;srlz.i;"::"r"(psr): "memory");
+
 	/*
-	 * unfreeze PMU
+	 * This loop flushes the PMD into the PFM context.
+	 * IT also processes overflow inline.
+	 *
+	 * IMPORTANT: No notification is sent at this point as the process is dying.
+	 * The implicit notification will come from a SIGCHILD or a return from a
+	 * waitpid().
+	 *
+	 * XXX: must take holes into account
 	 */
-	ia64_set_pmc(0, 0);
+	mask = pmc0 >> PMU_FIRST_COUNTER;
+	for (i=0,j=PMU_FIRST_COUNTER; i< pmu_conf.max_counters; i++,j++) {
+
+		/* collect latest results */
+		ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val;
+
+		/* take care of overflow inline */
+		if (mask & 0x1) {
+			ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
+			DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n",
+			j, ia64_get_pmd(j), ctx->ctx_pmds[i].val));
+		}
+	}
+}
+
+/*
+ * XXX: this routine is not very portable for PMCs
+ * XXX: make this routine able to work with non current context
+ */
+static void
+ia64_reset_pmu(void)
+{
+	int i;
+
+	/* PMU is frozen, no pending overflow bits */
+	ia64_set_pmc(0,1);
+
+	/* extra overflow bits + counter configs cleared */
+	for(i=1; i< PMU_FIRST_COUNTER + pmu_conf.max_counters ; i++) {
+		ia64_set_pmc(i,0);
+	}
+
+	/* opcode matcher set to all 1s */
+	ia64_set_pmc(8,~0);
+	ia64_set_pmc(9,~0);
+
+	/* I-EAR config cleared, plm=0 */
+	ia64_set_pmc(10,0);
+
+	/* D-EAR config cleared, PMC[11].pt must be 1 */
+	ia64_set_pmc(11,1 << 28);
+
+	/* BTB config. plm=0 */
+	ia64_set_pmc(12,0);
+
+	/* Instruction address range, PMC[13].ta must be 1 */
+	ia64_set_pmc(13,1);
+
+	/* clears all PMD registers */
+	for(i=0;i< pmu_conf.num_pmds; i++) {
+		if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0);
+	}
 	ia64_srlz_d();
 }
 
+/*
+ * task is the newly created task
+ */
+int
+pfm_inherit(struct task_struct *task)
+{
+	pfm_context_t *ctx = current->thread.pfm_context;
+	pfm_context_t *nctx;
+	struct thread_struct *th = &task->thread;
+	int i, cnum;
+
+	/*
+	 * takes care of easiest case first
+	 */
+	if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) {
+		DBprintk((" removing PFM context for %d\n", task->pid));
+		task->thread.pfm_context     = NULL;
+		task->thread.pfm_pend_notify = 0;
+		/* copy_thread() clears IA64_THREAD_PM_VALID */
+		return 0;
+	}
+	nctx = pfm_context_alloc();
+	if (nctx == NULL) return -ENOMEM;
+
+	/* copy content */
+	*nctx = *ctx;
+
+	if (ctx->ctx_fl_inherit == PFM_FL_INHERIT_ONCE) {
+		nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE;
+		DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid));
+	}
+
+	/* initialize counters in new context */
+	for(i=0, cnum= PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++) {
+		nctx->ctx_pmds[i].val = nctx->ctx_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
+		th->pmd[cnum]	      = nctx->ctx_pmds[i].ival & pmu_conf.perf_ovfl_val;
+
+	}
+	/* clear BTB index register */
+	th->pmd[16] = 0;
+
+	/* if sampling then increment number of users of buffer */
+	if (nctx->ctx_smpl_buf) {
+		atomic_inc(&nctx->ctx_smpl_buf->psb_refcnt);
+	}
+
+	nctx->ctx_fl_frozen = 0;
+	nctx->ctx_ovfl_regs = 0;
+	sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */
+
+	/* clear pending notification */
+	th->pfm_pend_notify = 0;
+
+	/* link with new task */
+	th->pfm_context     = nctx;
+
+	DBprintk((" nctx=%p for process %d\n", (void *)nctx, task->pid));
+
+	/*
+	 * the copy_thread routine automatically clears
+	 * IA64_THREAD_PM_VALID, so we need to reenable it, if it was used by the caller
+	 */
+	if (current->thread.flags & IA64_THREAD_PM_VALID) {
+		DBprintk(("  setting PM_VALID for %d\n", task->pid));
+		th->flags |= IA64_THREAD_PM_VALID;
+	}
+
+	return 0;
+}
+
+/* called from exit_thread() */
+void
+pfm_context_exit(struct task_struct *task)
+{
+	pfm_context_t *ctx = task->thread.pfm_context;
+
+	if (!ctx) {
+		DBprintk((" invalid context for %d\n", task->pid));
+		return;
+	}
+
+	/* check is we have a sampling buffer attached */
+	if (ctx->ctx_smpl_buf) {
+		pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf;
+
+		/* if only user left, then remove */
+		DBprintk((" pid %d: task %d sampling psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter));
+
+		if (atomic_dec_and_test(&psb->psb_refcnt) ) {
+			rvfree(psb->psb_hdr, psb->psb_size);
+			vfree(psb);
+			DBprintk((" pid %d: cleaning task %d sampling buffer\n", current->pid, task->pid ));
+		}
+	}
+	DBprintk((" pid %d: task %d pfm_context is freed @%p\n", current->pid, task->pid, (void *)ctx));
+	pfm_context_free(ctx);
+}
+
 #else /* !CONFIG_PERFMON */
 
-asmlinkage unsigned long
-sys_perfmonctl (int cmd, int count, void *ptr)
+asmlinkage int
+sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack)
 {
 	return -ENOSYS;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
--- v2.4.3/linux/arch/ia64/kernel/process.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/process.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Architecture-specific setup.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #define __KERNEL_SYSCALLS__	/* see <asm/unistd.h> */
 #include <linux/config.h>
@@ -20,6 +20,7 @@
 
 #include <asm/delay.h>
 #include <asm/efi.h>
+#include <asm/perfmon.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
@@ -27,8 +28,6 @@
 #include <asm/unwind.h>
 #include <asm/user.h>
 
-#ifdef CONFIG_IA64_NEW_UNWIND
-
 static void
 do_show_stack (struct unw_frame_info *info, void *arg)
 {
@@ -46,12 +45,9 @@
 	} while (unw_unwind(info) >= 0);
 }
 
-#endif
-
 void
 show_stack (struct task_struct *task)
 {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	if (!task)
 		unw_init_running(do_show_stack, 0);
 	else {
@@ -60,7 +56,6 @@
 		unw_init_from_blocked_task(&info, task);
 		do_show_stack(&info, 0);
 	}
-#endif
 }
 
 void
@@ -108,10 +103,8 @@
 			       ((i == sof - 1) || (i % 3) == 2) ? "\n" : " ");
 		}
 	}
-#ifdef CONFIG_IA64_NEW_UNWIND
 	if (!user_mode(regs))
 		show_stack(0);
-#endif
 }
 
 void __attribute__((noreturn))
@@ -147,7 +140,7 @@
 		ia64_save_debug_regs(&task->thread.dbr[0]);
 #ifdef CONFIG_PERFMON
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
-		ia64_save_pm_regs(task);
+		pfm_save_regs(task);
 #endif
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
 		ia32_save_state(&task->thread);
@@ -160,7 +153,7 @@
 		ia64_load_debug_regs(&task->thread.dbr[0]);
 #ifdef CONFIG_PERFMON
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
-		ia64_load_pm_regs(task);
+		pfm_load_regs(task);
 #endif
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
 		ia32_load_state(&task->thread);
@@ -210,6 +203,7 @@
 	struct switch_stack *child_stack, *stack;
 	extern char ia64_ret_from_clone;
 	struct pt_regs *child_ptregs;
+	int retval = 0;
 
 #ifdef CONFIG_SMP
 	/*
@@ -290,15 +284,17 @@
 	if (IS_IA32_PROCESS(ia64_task_regs(current)))
 		ia32_save_state(&p->thread);
 #endif
-	return 0;
+#ifdef CONFIG_PERFMON
+	if (current->thread.pfm_context)
+		retval = pfm_inherit(p);
+#endif
+	return retval;
 }
 
-#ifdef CONFIG_IA64_NEW_UNWIND
-
 void
 do_copy_regs (struct unw_frame_info *info, void *arg)
 {
-	unsigned long ar_bsp, ndirty, *krbs, addr, mask, sp, nat_bits = 0, ip;
+	unsigned long ar_bsp, addr, mask, sp, nat_bits = 0, ip, ar_rnat;
 	elf_greg_t *dst = arg;
 	struct pt_regs *pt;
 	char nat;
@@ -313,18 +309,18 @@
 	unw_get_sp(info, &sp);
 	pt = (struct pt_regs *) (sp + 16);
 
-	krbs = (unsigned long *) current + IA64_RBS_OFFSET/8;
-	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
-	ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty);
+	ar_bsp = ia64_get_user_bsp(current, pt);
 
 	/*
-	 * Write portion of RSE backing store living on the kernel
-	 * stack to the VM of the process.
+	 * Write portion of RSE backing store living on the kernel stack to the VM of the
+	 * process.
 	 */
 	for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8)
-		if (ia64_peek(pt, current, addr, &val) == 0)
+		if (ia64_peek(current, ar_bsp, addr, &val) == 0)
 			access_process_vm(current, addr, &val, sizeof(val), 1);
 
+	ia64_peek(current, ar_bsp, (long) ia64_rse_rnat_addr((long *) addr - 1), &ar_rnat);
+
 	/*
 	 * coredump format:
 	 *	r0-r31
@@ -361,7 +357,7 @@
 	 */
 	dst[46] = ar_bsp;
 	dst[47] = pt->ar_bspstore;
-	unw_get_ar(info, UNW_AR_RNAT, &dst[48]);
+	dst[48] = ar_rnat;
 	unw_get_ar(info, UNW_AR_CCV, &dst[49]);
 	unw_get_ar(info, UNW_AR_UNAT, &dst[50]);
 	unw_get_ar(info, UNW_AR_FPSR, &dst[51]);
@@ -391,91 +387,16 @@
 		memcpy(dst + 32, current->thread.fph, 96*16);
 }
 
-#endif /* CONFIG_IA64_NEW_UNWIND */
-
 void
 ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
 {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	unw_init_running(do_copy_regs, dst);
-#else
-	struct switch_stack *sw = ((struct switch_stack *) pt) - 1;
-	unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs, addr;
-
-	ar_ec = (sw->ar_pfs >> 52) & 0x3f;
-
-	cfm = pt->cr_ifs & ((1UL << 63) - 1);
-	if ((pt->cr_ifs & (1UL << 63)) == 0) {
-		/* if cr_ifs isn't valid, we got here through a syscall or a break */
-		cfm = sw->ar_pfs & ((1UL << 38) - 1);
-	}
-
-	krbs = (unsigned long *) current + IA64_RBS_OFFSET/8;
-	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
-	ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty);
-
-	/*
-	 * Write portion of RSE backing store living on the kernel
-	 * stack to the VM of the process.
-	 */
-	for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) {
-		long val;
-		if (ia64_peek(pt, current, addr, &val) == 0)
-			access_process_vm(current, addr, &val, sizeof(val), 1);
-	}
-
-	/*	r0-r31
-	 *	NaT bits (for r0-r31; bit N == 1 iff rN is a NaT)
-	 *	predicate registers (p0-p63)
-	 *	b0-b7
-	 *	ip cfm user-mask
-	 *	ar.rsc ar.bsp ar.bspstore ar.rnat
-	 *	ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec
-	 */
-	memset(dst, 0, sizeof(dst));	/* don't leak any "random" bits */
-
-	/* r0 is zero */   dst[ 1] =  pt->r1; dst[ 2] =  pt->r2; dst[ 3] = pt->r3;
-	dst[ 4] =  sw->r4; dst[ 5] =  sw->r5; dst[ 6] =  sw->r6; dst[ 7] = sw->r7;
-	dst[ 8] =  pt->r8; dst[ 9] =  pt->r9; dst[10] = pt->r10; dst[11] = pt->r11;
-	dst[12] = pt->r12; dst[13] = pt->r13; dst[14] = pt->r14; dst[15] = pt->r15;
-	memcpy(dst + 16, &pt->r16, 16*8);	/* r16-r31 are contiguous */
-
-	dst[32] = ia64_get_nat_bits(pt, sw);
-	dst[33] = pt->pr;
-
-	/* branch regs: */
-	dst[34] = pt->b0; dst[35] = sw->b1; dst[36] = sw->b2; dst[37] = sw->b3;
-	dst[38] = sw->b4; dst[39] = sw->b5; dst[40] = pt->b6; dst[41] = pt->b7;
-
-	dst[42] = pt->cr_iip + ia64_psr(pt)->ri;
-	dst[43] = pt->cr_ifs;
-	dst[44] = pt->cr_ipsr & IA64_PSR_UM;
-
-	dst[45] = pt->ar_rsc; dst[46] = ar_bsp; dst[47] = pt->ar_bspstore;  dst[48] = pt->ar_rnat;
-	dst[49] = pt->ar_ccv; dst[50] = pt->ar_unat; dst[51] = sw->ar_fpsr; dst[52] = pt->ar_pfs;
-	dst[53] = sw->ar_lc; dst[54] = (sw->ar_pfs >> 52) & 0x3f;
-#endif /* !CONFIG_IA64_NEW_UNWIND */
 }
 
 int
 dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
 {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	unw_init_running(do_dump_fpu, dst);
-#else
-	struct switch_stack *sw = ((struct switch_stack *) pt) - 1;
-
-	memset(dst, 0, sizeof (dst));	/* don't leak any "random" bits */
-
-	/* f0 is 0.0 */  /* f1 is 1.0 */  dst[2] = sw->f2; dst[3] = sw->f3;
-	dst[4] = sw->f4; dst[5] = sw->f5; dst[6] = pt->f6; dst[7] = pt->f7;
-	dst[8] = pt->f8; dst[9] = pt->f9;
-	memcpy(dst + 10, &sw->f10, 22*16);	/* f10-f31 are contiguous */
-
-	ia64_flush_fph(current);
-	if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0)
-		memcpy(dst + 32, current->thread.fph, 96*16);
-#endif
 	return 1;	/* f0-f31 are always valid so we always return 1 */
 }
 
@@ -523,6 +444,15 @@
 #endif
 }
 
+#ifdef CONFIG_PERFMON
+void
+release_thread (struct task_struct *task)
+{
+	if (task->thread.pfm_context)
+		pfm_context_exit(task);
+}
+#endif
+
 /*
  * Clean up state associated with current thread.  This is called when
  * the thread calls exit().
@@ -545,7 +475,7 @@
 		 * we garantee no race.  this call we also stop
 		 * monitoring
 		 */
-		ia64_save_pm_regs(current);
+		pfm_flush_regs(current);
 		/*
 		 * make sure that switch_to() will not save context again
 		 */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c
--- v2.4.3/linux/arch/ia64/kernel/ptrace.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/ia64/kernel/ptrace.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Kernel support for the ptrace() and syscall tracing interfaces.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Derived from the x86 and Alpha versions.  Most of the code in here
  * could actually be factored into a common set of routines.
@@ -22,6 +22,7 @@
 #include <asm/rse.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unwind.h>
 
 /*
  * Bits in the PSR that we allow ptrace() to change:
@@ -36,8 +37,6 @@
 	(IA64_PSR_UM | IA64_PSR_DB | IA64_PSR_IS | IA64_PSR_ID | IA64_PSR_DD | IA64_PSR_RI)
 #define IPSR_READ_MASK	IPSR_WRITE_MASK
 
-#ifdef CONFIG_IA64_NEW_UNWIND
-
 #define PTRACE_DEBUG	1
 
 #if PTRACE_DEBUG
@@ -97,57 +96,6 @@
 #	undef PUT_BITS
 }
 
-#else /* !CONFIG_IA64_NEW_UNWIND */
-
-/*
- * Collect the NaT bits for r1-r31 from sw->caller_unat and
- * sw->ar_unat and return a NaT bitset where bit i is set iff the NaT
- * bit of register i is set.
- */
-long
-ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw)
-{
-#	define GET_BITS(str, first, last, unat)						\
-	({										\
-		unsigned long bit = ia64_unat_pos(&str->r##first);			\
-		unsigned long mask = ((1UL << (last - first + 1)) - 1) << first;	\
-		(ia64_rotl(unat, first) >> bit) & mask;					\
-	})
-	unsigned long val;
-
-	val  = GET_BITS(pt,  1,  3, sw->caller_unat);
-	val |= GET_BITS(pt, 12, 15, sw->caller_unat);
-	val |= GET_BITS(pt,  8, 11, sw->caller_unat);
-	val |= GET_BITS(pt, 16, 31, sw->caller_unat);
-	val |= GET_BITS(sw,  4,  7, sw->ar_unat);
-	return val;
-
-#	undef GET_BITS
-}
-
-/*
- * Store the NaT bitset NAT in pt->caller_unat and sw->ar_unat.
- */
-void
-ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat)
-{
-#	define PUT_BITS(str, first, last, nat)					\
-	({									\
-		unsigned long bit = ia64_unat_pos(&str->r##first);		\
-		unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit;	\
-		(ia64_rotr(nat, first) << bit) & mask;				\
-	})
-	sw->caller_unat  = PUT_BITS(pt,  1,  3, nat);
-	sw->caller_unat |= PUT_BITS(pt, 12, 15, nat);
-	sw->caller_unat |= PUT_BITS(pt,  8, 11, nat);
-	sw->caller_unat |= PUT_BITS(pt, 16, 31, nat);
-	sw->ar_unat      = PUT_BITS(sw,  4,  7, nat);
-
-#	undef PUT_BITS
-}
-
-#endif /* !CONFIG_IA64_NEW_UNWIND */
-
 #define IA64_MLX_TEMPLATE	0x2
 #define IA64_MOVL_OPCODE	6
 
@@ -215,7 +163,7 @@
  * | slot01 | > child_regs->ar_rnat
  * +--------+ |
  * | slot02 | /				kernel rbs
- * +--------+ 				+--------+
+ * +--------+				+--------+
  *	    <- child_regs->ar_bspstore	| slot61 | <-- krbs
  * +- - - - +				+--------+
  *					| slot62 |
@@ -275,7 +223,7 @@
 		/* some bits need to be merged in from pt->ar_rnat */
 		kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1);
 		urnat = (pt->ar_rnat & ~kmask);
-	} 
+	}
 	if (rnat0_kaddr >= kbsp) {
 		rnat0 = sw->ar_rnat;
 	} else if (rnat0_kaddr > krbs) {
@@ -319,7 +267,7 @@
 		/* some bits need to be place in pt->ar_rnat: */
 		kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1);
 		pt->ar_rnat = (pt->ar_rnat & kmask) | (rnat & ~kmask);
-	} 
+	}
 	/*
 	 * Note: Section 11.1 of the EAS guarantees that bit 63 of an
 	 * rnat slot is ignored. so we don't have to clear it here.
@@ -342,9 +290,9 @@
 }
 
 long
-ia64_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long *val)
+ia64_peek (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long *val)
 {
-	unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr;
+	unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp;
 	struct switch_stack *child_stack;
 	struct pt_regs *child_regs;
 	size_t copied;
@@ -352,35 +300,22 @@
 
 	laddr = (unsigned long *) addr;
 	child_regs = ia64_task_regs(child);
-#ifdef CONFIG_IA64_NEW_UNWIND
 	child_stack = (struct switch_stack *) (child->thread.ksp + 16);
-#else
-	child_stack = (struct switch_stack *) child_regs - 1;
-#endif
 	bspstore = (unsigned long *) child_regs->ar_bspstore;
 	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-	krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore);
-	rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs);
-	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) {
+	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) {
 		/*
-		 * Attempt to read the RBS in an area that's actually
-		 * on the kernel RBS => read the corresponding bits in
-		 * the kernel RBS.
+		 * Attempt to read the RBS in an area that's actually on the kernel RBS =>
+		 * read the corresponding bits in the kernel RBS.
 		 */
 		if (ia64_rse_is_rnat_slot(laddr))
 			ret = get_rnat(child_regs, child_stack, krbs, laddr);
 		else {
-			regnum = ia64_rse_num_regs(bspstore, laddr);
-			laddr = ia64_rse_skip_regs(krbs, regnum);
-			if (regnum >= krbs_num_regs) {
+			if (laddr >= ubsp)
 				ret = 0;
-			} else {
-				if  ((unsigned long) laddr >= (unsigned long) high_memory) {
-					printk("yikes: trying to access long at %p\n",
-					       (void *) laddr);
-					return -EIO;
-				}
-				ret = *laddr;
+			else {
+				regnum = ia64_rse_num_regs(bspstore, laddr);
+				ret = *ia64_rse_skip_regs(krbs, regnum);
 			}
 		}
 	} else {
@@ -393,36 +328,28 @@
 }
 
 long
-ia64_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long val)
+ia64_poke (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long val)
 {
-	unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr;
+	unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp;
 	struct switch_stack *child_stack;
 	struct pt_regs *child_regs;
 
 	laddr = (unsigned long *) addr;
 	child_regs = ia64_task_regs(child);
-#ifdef CONFIG_IA64_NEW_UNWIND
 	child_stack = (struct switch_stack *) (child->thread.ksp + 16);
-#else
-	child_stack = (struct switch_stack *) child_regs - 1;
-#endif
 	bspstore = (unsigned long *) child_regs->ar_bspstore;
 	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-	krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore);
-	rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs);
-	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) {
+	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) {
 		/*
-		 * Attempt to write the RBS in an area that's actually
-		 * on the kernel RBS => write the corresponding bits
-		 * in the kernel RBS.
+		 * Attempt to write the RBS in an area that's actually on the kernel RBS
+		 * => write the corresponding bits in the kernel RBS.
 		 */
 		if (ia64_rse_is_rnat_slot(laddr))
 			put_rnat(child_regs, child_stack, krbs, laddr, val);
 		else {
-			regnum = ia64_rse_num_regs(bspstore, laddr);
-			laddr = ia64_rse_skip_regs(krbs, regnum);
-			if (regnum < krbs_num_regs) {
-				*laddr = val;
+			if (laddr < ubsp) {
+				regnum = ia64_rse_num_regs(bspstore, laddr);
+				*ia64_rse_skip_regs(krbs, regnum) = val;
 			}
 		}
 	} else if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) {
@@ -432,83 +359,76 @@
 }
 
 /*
- * Synchronize (i.e, write) the RSE backing store living in kernel
- * space to the VM of the indicated child process.
- *
- * If new_bsp is non-zero, the bsp will (effectively) be updated to
- * the new value upon resumption of the child process.  This is
- * accomplished by setting the loadrs value to zero and the bspstore
- * value to the new bsp value.
- *
- * When new_bsp and force_loadrs_to_zero are both 0, the register
- * backing store in kernel space is written to user space and the
- * loadrs and bspstore values are left alone.
- *
- * When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero),
- * loadrs is set to 0, and the bspstore value is set to the old bsp
- * value.  This will cause the stacked registers (r32 and up) to be
- * obtained entirely from the child's memory space rather than
- * from the kernel.  (This makes it easier to write code for
- * modifying the stacked registers in multi-threaded programs.)
- *
- * Note:  I had originally written this function without the
- * force_loadrs_to_zero parameter; it was written so that loadrs would
- * always be set to zero.  But I had problems with certain system
- * calls apparently causing a portion of the RBS to be zeroed.  (I
- * still don't understand why this was happening.) Anyway, it'd
- * definitely less intrusive to leave loadrs and bspstore alone if
- * possible.
+ * Calculate the user-level address that would have been in ar.bsp had the user executed a
+ * "cover" instruction right before entering the kernel.
  */
-static long
-sync_kernel_register_backing_store (struct task_struct *child,
-                                    long new_bsp,
-                                    int force_loadrs_to_zero)
+unsigned long
+ia64_get_user_bsp (struct task_struct *child, struct pt_regs *pt)
 {
-	unsigned long *krbs, bspstore, *kbspstore, bsp, rbs_end, addr, val;
-	long ndirty, ret = 0;
-	struct pt_regs *child_regs = ia64_task_regs(child);
-
-#ifdef CONFIG_IA64_NEW_UNWIND
+	unsigned long *krbs, *bspstore, cfm;
 	struct unw_frame_info info;
-	unsigned long cfm, sof;
-
-	unw_init_from_blocked_task(&info, child);
-	if (unw_unwind_to_user(&info) < 0)
-		return -1;
-
-	unw_get_bsp(&info, (unsigned long *) &kbspstore);
+	long ndirty;
 
 	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-	ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19));
-	bspstore = child_regs->ar_bspstore;
-	bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty);
-
-	cfm = child_regs->cr_ifs;
-	if (!(cfm & (1UL << 63)))
-		unw_get_cfm(&info, &cfm);
-	sof = (cfm & 0x7f);
-	rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, sof);
-#else
-	struct switch_stack *child_stack;
-	unsigned long krbs_num_regs;
+	bspstore = (unsigned long *) pt->ar_bspstore;
+	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
 
-	child_stack = (struct switch_stack *) child_regs - 1;
-	kbspstore = (unsigned long *) child_stack->ar_bspstore;
-	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-	ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19));
-	bspstore = child_regs->ar_bspstore;
-	bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty);
-	krbs_num_regs = ia64_rse_num_regs(krbs, kbspstore);
-	rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs);
-#endif
+	if ((long) pt->cr_ifs >= 0) {
+		/*
+		 * If bit 63 of cr.ifs is cleared, the kernel was entered via a system
+		 * call and we need to recover the CFM that existed on entry to the
+		 * kernel by unwinding the kernel stack.
+		 */
+		unw_init_from_blocked_task(&info, child);
+		if (unw_unwind_to_user(&info) == 0) {
+			unw_get_cfm(&info, &cfm);
+			ndirty += (cfm & 0x7f);
+		}
+	}
+	return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
+}
 
-	/* Return early if nothing to do */
-	if (bsp == new_bsp)
+/*
+ * Synchronize (i.e, write) the RSE backing store living in kernel space to the VM of the
+ * indicated child process.
+ *
+ * If new_bsp is non-zero, the bsp will (effectively) be updated to the new value upon
+ * resumption of the child process.  This is accomplished by setting the loadrs value to
+ * zero and the bspstore value to the new bsp value.
+ *
+ * When new_bsp and flush_user_rbs are both 0, the register backing store in kernel space
+ * is written to user space and the loadrs and bspstore values are left alone.
+ *
+ * When new_bsp is zero and flush_user_rbs is 1 (non-zero), loadrs is set to 0, and the
+ * bspstore value is set to the old bsp value.  This will cause the stacked registers (r32
+ * and up) to be obtained entirely from the child's memory space rather than from the
+ * kernel.  (This makes it easier to write code for modifying the stacked registers in
+ * multi-threaded programs.)
+ *
+ * Note: I had originally written this function without the flush_user_rbs parameter; it
+ * was written so that loadrs would always be set to zero.  But I had problems with
+ * certain system calls apparently causing a portion of the RBS to be zeroed.  (I still
+ * don't understand why this was happening.) Anyway, it'd definitely less intrusive to
+ * leave loadrs and bspstore alone if possible.
+ */
+static long
+sync_kernel_register_backing_store (struct task_struct *child, long user_bsp, long new_bsp,
+				    int flush_user_rbs)
+{
+	struct pt_regs *child_regs = ia64_task_regs(child);
+	unsigned long addr, val;
+	long ret;
+
+	/*
+	 * Return early if nothing to do.  Note that new_bsp will be zero if the caller
+	 * wants to force synchronization without changing bsp.
+	 */
+	if (user_bsp == new_bsp)
 		return 0;
 
 	/* Write portion of backing store living on kernel stack to the child's VM. */
-	for (addr = bspstore; addr < rbs_end; addr += 8) {
-		ret = ia64_peek(child_regs, child, addr, &val);
+	for (addr = child_regs->ar_bspstore; addr < user_bsp; addr += 8) {
+		ret = ia64_peek(child, user_bsp, addr, &val);
 		if (ret != 0)
 			return ret;
 		if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val))
@@ -516,27 +436,26 @@
 	}
 
 	if (new_bsp != 0) {
-		force_loadrs_to_zero = 1;
-		bsp = new_bsp;
+		flush_user_rbs = 1;
+		user_bsp = new_bsp;
 	}
 
-	if (force_loadrs_to_zero) {
+	if (flush_user_rbs) {
 		child_regs->loadrs = 0;
-		child_regs->ar_bspstore = bsp;
+		child_regs->ar_bspstore = user_bsp;
 	}
-
-	return ret;
+	return 0;
 }
 
 static void
-sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writable)
+sync_thread_rbs (struct task_struct *child, long bsp, struct mm_struct *mm, int make_writable)
 {
 	struct task_struct *p;
 	read_lock(&tasklist_lock);
 	{
 		for_each_task(p) {
 			if (p->mm == mm && p->state != TASK_RUNNING)
-				sync_kernel_register_backing_store(p, 0, make_writable);
+				sync_kernel_register_backing_store(p, bsp, 0, make_writable);
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -588,10 +507,6 @@
 	psr->dfh = 1;
 }
 
-#ifdef CONFIG_IA64_NEW_UNWIND
-
-#include <asm/unwind.h>
-
 static int
 access_fr (struct unw_frame_info *info, int regnum, int hi, unsigned long *data, int write_access)
 {
@@ -613,7 +528,7 @@
 static int
 access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access)
 {
-	unsigned long *ptr, *rbs, *bspstore, ndirty, regnum;
+	unsigned long *ptr, regnum, bsp, rnat_addr;
 	struct switch_stack *sw;
 	struct unw_frame_info info;
 	struct pt_regs *pt;
@@ -710,36 +625,16 @@
 		/* scratch state */
 		switch (addr) {
 		      case PT_AR_BSP:
+			bsp = ia64_get_user_bsp(child, pt);
 			if (write_access)
-				/* FIXME? Account for lack of ``cover'' in the syscall case */
-				return sync_kernel_register_backing_store(child, *data, 1);
+				return sync_kernel_register_backing_store(child, bsp, *data, 1);
 			else {
-				rbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-				bspstore = (unsigned long *) pt->ar_bspstore;
-				ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19));
-
-				/*
-				 * If we're in a system call, no ``cover'' was done.  So to
-				 * make things uniform, we'll add the appropriate displacement
-				 * onto bsp if we're in a system call.
-				 */
-				if (!(pt->cr_ifs & (1UL << 63))) {
-					struct unw_frame_info info;
-					unsigned long cfm;
-
-					unw_init_from_blocked_task(&info, child);
-					if (unw_unwind_to_user(&info) < 0)
-						return -1;
-
-					unw_get_cfm(&info, &cfm);
-					ndirty += cfm & 0x7f;
-				}
-				*data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
+				*data = bsp;
 				return 0;
 			}
 
 		      case PT_CFM:
-			if (pt->cr_ifs & (1UL << 63)) {
+			if ((long) pt->cr_ifs < 0) {
 				if (write_access)
 					pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL)
 						      | (*data & 0x3fffffffffUL));
@@ -770,7 +665,15 @@
 				*data = (pt->cr_ipsr & IPSR_READ_MASK);
 			return 0;
 
-		      		   case PT_R1:  case PT_R2:  case PT_R3:
+		      case PT_AR_RNAT:
+			bsp = ia64_get_user_bsp(child, pt);
+			rnat_addr = (long) ia64_rse_rnat_addr((long *) bsp - 1);
+			if (write_access)
+				return ia64_poke(child, bsp, rnat_addr, *data);
+			else
+				return ia64_peek(child, bsp, rnat_addr, data);
+
+				   case PT_R1:  case PT_R2:  case PT_R3:
 		      case PT_R8:  case PT_R9:  case PT_R10: case PT_R11:
 		      case PT_R12: case PT_R13: case PT_R14: case PT_R15:
 		      case PT_R16: case PT_R17: case PT_R18: case PT_R19:
@@ -781,7 +684,7 @@
 		      case PT_F6:  case PT_F6+8: case PT_F7: case PT_F7+8:
 		      case PT_F8:  case PT_F8+8: case PT_F9: case PT_F9+8:
 		      case PT_AR_BSPSTORE:
-		      case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT:
+		      case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS:
 		      case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR:
 			/* scratch register */
 			ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR);
@@ -799,7 +702,7 @@
 		if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
 			child->thread.flags |= IA64_THREAD_DBG_VALID;
 			memset(child->thread.dbr, 0, sizeof(child->thread.dbr));
-			memset(child->thread.ibr, 0, sizeof( child->thread.ibr));
+			memset(child->thread.ibr, 0, sizeof(child->thread.ibr));
 		}
 		if (addr >= PT_IBR) {
 			regnum = (addr - PT_IBR) >> 3;
@@ -830,173 +733,13 @@
 	return 0;
 }
 
-#else /* !CONFIG_IA64_NEW_UNWIND */
-
-static int
-access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access)
-{
-	unsigned long *ptr = NULL, *rbs, *bspstore, ndirty, regnum;
-	struct switch_stack *sw;
-	struct pt_regs *pt;
-
-	if ((addr & 0x7) != 0)
-		return -1;
-
-	if (addr < PT_F127+16) {
-		/* accessing fph */
-		if (write_access)
-			ia64_sync_fph(child);
-		else
-			ia64_flush_fph(child);
-		ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr);
-	} else if (addr < PT_F9+16) {
-		/* accessing switch_stack or pt_regs: */
-		pt = ia64_task_regs(child);
-		sw = (struct switch_stack *) pt - 1;
-
-		switch (addr) {
-		      case PT_NAT_BITS:
-			if (write_access)
-				ia64_put_nat_bits(pt, sw, *data);
-			else
-				*data = ia64_get_nat_bits(pt, sw);
-			return 0;
-
-		      case PT_AR_BSP:
-			if (write_access)
-				/* FIXME? Account for lack of ``cover'' in the syscall case */
-				return sync_kernel_register_backing_store(child, *data, 1);
-			else {
-				rbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-				bspstore = (unsigned long *) pt->ar_bspstore;
-				ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19));
-
-				/*
-				 * If we're in a system call, no ``cover'' was done.  So to
-				 * make things uniform, we'll add the appropriate displacement
-				 * onto bsp if we're in a system call.
-				 */
-				if (!(pt->cr_ifs & (1UL << 63)))
-					ndirty += sw->ar_pfs & 0x7f;
-				*data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
-				return 0;
-			}
-
-		      case PT_CFM:
-			if (write_access) {
-				if (pt->cr_ifs & (1UL << 63))
-					pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL)
-						      | (*data & 0x3fffffffffUL));
-				else
-					sw->ar_pfs = ((sw->ar_pfs & ~0x3fffffffffUL)
-						      | (*data & 0x3fffffffffUL));
-				return 0;
-			} else {
-				if ((pt->cr_ifs & (1UL << 63)) == 0)
-					*data = sw->ar_pfs;
-				else
-					/* return only the CFM */
-					*data = pt->cr_ifs & 0x3fffffffffUL;
-				return 0;
-			}
-
-		      case PT_CR_IPSR:
-			if (write_access)
-				pt->cr_ipsr = ((*data & IPSR_WRITE_MASK)
-					       | (pt->cr_ipsr & ~IPSR_WRITE_MASK));
-			else
-				*data = (pt->cr_ipsr & IPSR_READ_MASK);
-			return 0;
-
-		      case PT_AR_EC:
-			if (write_access)
-				sw->ar_pfs = (((*data & 0x3f) << 52)
-					      | (sw->ar_pfs & ~(0x3fUL << 52)));
-			else
-				*data = (sw->ar_pfs >> 52) & 0x3f;
-			break;
-
-		      case PT_R1: case PT_R2: case PT_R3:
-		      case PT_R4: case PT_R5: case PT_R6: case PT_R7:
-		      case PT_R8: case PT_R9: case PT_R10: case PT_R11:
-		      case PT_R12: case PT_R13: case PT_R14: case PT_R15:
-		      case PT_R16: case PT_R17: case PT_R18: case PT_R19:
-		      case PT_R20: case PT_R21: case PT_R22: case PT_R23:
-		      case PT_R24: case PT_R25: case PT_R26: case PT_R27:
-		      case PT_R28: case PT_R29: case PT_R30: case PT_R31:
-		      case PT_B0: case PT_B1: case PT_B2: case PT_B3:
-		      case PT_B4: case PT_B5: case PT_B6: case PT_B7:
-		      case PT_F2: case PT_F2+8: case PT_F3: case PT_F3+8:
-		      case PT_F4: case PT_F4+8: case PT_F5: case PT_F5+8:
-		      case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8:
-  		      case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8:
-		      case PT_F10: case PT_F10+8: case PT_F11: case PT_F11+8:
-		      case PT_F12: case PT_F12+8: case PT_F13: case PT_F13+8:
-		      case PT_F14: case PT_F14+8: case PT_F15: case PT_F15+8:
-		      case PT_F16: case PT_F16+8: case PT_F17: case PT_F17+8:
-		      case PT_F18: case PT_F18+8: case PT_F19: case PT_F19+8:
-  		      case PT_F20: case PT_F20+8: case PT_F21: case PT_F21+8:
-		      case PT_F22: case PT_F22+8: case PT_F23: case PT_F23+8: 
-		      case PT_F24: case PT_F24+8: case PT_F25: case PT_F25+8:
-		      case PT_F26: case PT_F26+8: case PT_F27: case PT_F27+8:
- 		      case PT_F28: case PT_F28+8: case PT_F29: case PT_F29+8:
-		      case PT_F30: case PT_F30+8: case PT_F31: case PT_F31+8:
-		      case PT_AR_BSPSTORE:
-		      case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT:
-		      case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR:
-		      case PT_AR_LC:
-			ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS);
-			break;
-
-		      default:
-			/* disallow accessing anything else... */
-			return -1;
-		}
-	} else {
-
-		/* access debug registers */
-
-		if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
-			child->thread.flags |= IA64_THREAD_DBG_VALID;
-			memset(child->thread.dbr, 0, sizeof child->thread.dbr);
-			memset(child->thread.ibr, 0, sizeof child->thread.ibr);
-		}
-		if (addr >= PT_IBR) {
-			regnum = (addr - PT_IBR) >> 3;
-			ptr = &child->thread.ibr[0];
-		} else {
-			regnum = (addr - PT_DBR) >> 3;
-			ptr = &child->thread.dbr[0];
-		}
-
-		if (regnum >= 8)
-			return -1;
-
-		ptr += regnum;
-
-		if (write_access)
-			/* don't let the user set kernel-level breakpoints... */
-			*ptr = *data & ~(7UL << 56);
-		else
-			*data = *ptr;
-		return 0;
-	}
-	if (write_access)
-		*ptr = *data;
-	else
-		*data = *ptr;
-	return 0;
-}
-
-#endif /* !CONFIG_IA64_NEW_UNWIND */
-
 asmlinkage long
 sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
 	    long arg4, long arg5, long arg6, long arg7, long stack)
 {
-	struct pt_regs *regs = (struct pt_regs *) &stack;
+	struct pt_regs *pt, *regs = (struct pt_regs *) &stack;
 	struct task_struct *child;
-	unsigned long flags;
+	unsigned long flags, bsp;
 	long ret;
 
 	lock_kernel();
@@ -1031,10 +774,10 @@
 		    (current->uid != child->euid) ||
 		    (current->uid != child->suid) ||
 		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+		    (current->gid != child->egid) ||
+		    (current->gid != child->sgid) ||
+		    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+		    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
 			goto out_tsk;
 		/* the same process cannot be attached many times */
 		if (child->ptrace & PT_PTRACED)
@@ -1065,10 +808,13 @@
 	if (child->p_pptr != current)
 		goto out_tsk;
 
+	pt = ia64_task_regs(child);
+
 	switch (request) {
 	      case PTRACE_PEEKTEXT:
 	      case PTRACE_PEEKDATA:		/* read word at location addr */
-	        if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
+		bsp = ia64_get_user_bsp(child, pt);
+		if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
 			struct mm_struct *mm;
 			long do_sync;
 
@@ -1079,9 +825,9 @@
 			}
 			task_unlock(child);
 			if (do_sync)
-				sync_thread_rbs(child, mm, 0);
+				sync_thread_rbs(child, bsp, mm, 0);
 		}
-		ret = ia64_peek(regs, child, addr, &data);
+		ret = ia64_peek(child, bsp, addr, &data);
 		if (ret == 0) {
 			ret = data;
 			regs->r8 = 0;	/* ensure "ret" is not mistaken as an error code */
@@ -1090,7 +836,8 @@
 
 	      case PTRACE_POKETEXT:
 	      case PTRACE_POKEDATA:		/* write the word at location addr */
-	        if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
+		bsp = ia64_get_user_bsp(child, pt);
+		if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
 			struct mm_struct *mm;
 			long do_sync;
 
@@ -1101,9 +848,9 @@
 			}
 			task_unlock(child);
 			if (do_sync)
-				sync_thread_rbs(child, mm, 1);
+				sync_thread_rbs(child, bsp, mm, 1);
 		}
-		ret = ia64_poke(regs, child, addr, data);
+		ret = ia64_poke(child, bsp, addr, data);
 		goto out_tsk;
 
 	      case PTRACE_PEEKUSR:		/* read the word at addr in the USER area */
@@ -1125,21 +872,19 @@
 
 	      case PTRACE_GETSIGINFO:
 		ret = -EIO;
-		if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t))
-		    || child->thread.siginfo == 0)
+		if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) || !child->thread.siginfo)
 			goto out_tsk;
-		copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t));
-		ret = 0;
+		ret = copy_siginfo_to_user((siginfo_t *) data, child->thread.siginfo);
 		goto out_tsk;
-		break;
+
 	      case PTRACE_SETSIGINFO:
 		ret = -EIO;
 		if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t))
 		    || child->thread.siginfo == 0)
 			goto out_tsk;
-		copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t));
-		ret = 0;
+		ret = copy_siginfo_from_user(child->thread.siginfo, (siginfo_t *) data);
 		goto out_tsk;
+
 	      case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
 	      case PTRACE_CONT:		/* restart after signal. */
 		ret = -EIO;
@@ -1152,8 +897,8 @@
 		child->exit_code = data;
 
 		/* make sure the single step/take-branch tra bits are not set: */
-		ia64_psr(ia64_task_regs(child))->ss = 0;
-		ia64_psr(ia64_task_regs(child))->tb = 0;
+		ia64_psr(pt)->ss = 0;
+		ia64_psr(pt)->tb = 0;
 
 		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
 		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
@@ -1173,8 +918,8 @@
 		child->exit_code = SIGKILL;
 
 		/* make sure the single step/take-branch tra bits are not set: */
-		ia64_psr(ia64_task_regs(child))->ss = 0;
-		ia64_psr(ia64_task_regs(child))->tb = 0;
+		ia64_psr(pt)->ss = 0;
+		ia64_psr(pt)->tb = 0;
 
 		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
 		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
@@ -1191,9 +936,9 @@
 
 		child->ptrace &= ~PT_TRACESYS;
 		if (request == PTRACE_SINGLESTEP) {
-			ia64_psr(ia64_task_regs(child))->ss = 1;
+			ia64_psr(pt)->ss = 1;
 		} else {
-			ia64_psr(ia64_task_regs(child))->tb = 1;
+			ia64_psr(pt)->tb = 1;
 		}
 		child->exit_code = data;
 
@@ -1219,8 +964,8 @@
 		write_unlock_irqrestore(&tasklist_lock, flags);
 
 		/* make sure the single step/take-branch tra bits are not set: */
-		ia64_psr(ia64_task_regs(child))->ss = 0;
-		ia64_psr(ia64_task_regs(child))->tb = 0;
+		ia64_psr(pt)->ss = 0;
+		ia64_psr(pt)->tb = 0;
 
 		/* Turn off flag indicating that the KRBS is sync'd with child's VM: */
 		child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/semaphore.c linux/arch/ia64/kernel/semaphore.c
--- v2.4.3/linux/arch/ia64/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/ia64/kernel/semaphore.c	Tue Apr 17 17:19:24 2001
@@ -155,180 +155,3 @@
 	spin_unlock_irqrestore(&semaphore_lock, flags);
 	return 1;
 }
-
-/*
- * Helper routines for rw semaphores.  These could be optimized some
- * more, but since they're off the critical path, I prefer clarity for
- * now...
- */
-
-/*
- * This gets called if we failed to acquire the lock, but we're biased
- * to acquire the lock by virtue of causing the count to change from 0
- * to -1.  Being biased, we sleep and attempt to grab the lock until
- * we succeed.  When this function returns, we own the lock.
- */
-static inline void
-down_read_failed_biased (struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->read_bias_granted)
-			schedule();
-	}
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/*
- * This gets called if we failed to acquire the lock and we are not
- * biased to acquire the lock.  We undo the decrement that was
- * done earlier, go to sleep, and then attempt to re-acquire the
- * lock afterwards.
- */
-static inline void
-down_read_failed (struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	/*
-	 * Undo the decrement we did in down_read() and check if we
-	 * need to wake up someone.
-	 */
-	__up_read(sem);
-
-	add_wait_queue(&sem->wait, &wait);
-	while (sem->count < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->count >= 0)
-			break;
-		schedule();
-	}
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/*
- * Wait for the lock to become unbiased.  Readers are non-exclusive.
- */
-void
-__down_read_failed (struct rw_semaphore *sem, long count)
-{
-	while (1) {
-		if (count == -1) {
-			down_read_failed_biased(sem);
-			return;
-		}
-		/* unbiased */
-		down_read_failed(sem);
-
-		count = ia64_fetch_and_add(-1, &sem->count);
-		if (count >= 0)
-			return;
-	}
-}
-
-static inline void
-down_write_failed_biased (struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	/* put ourselves at the end of the list */
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/*
-	 * If the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (sem->count >= 0)
-		wake_up(&sem->wait);
-}
-
-
-static inline void
-down_write_failed (struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (sem->count < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->count >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-
-/*
- * Wait for the lock to become unbiased.  Since we're a writer, we'll
- * make ourselves exclusive.
- */
-void
-__down_write_failed (struct rw_semaphore *sem, long count)
-{
-	long old_count;
-
-	while (1) {
-		if (count == -RW_LOCK_BIAS) {
-			down_write_failed_biased(sem);
-			return;
-		}
-		down_write_failed(sem);
-
-		do {
-			old_count = sem->count;
-			count = old_count - RW_LOCK_BIAS;
-		} while (cmpxchg_acq(&sem->count, old_count, count) != old_count);
-
-		if (count == 0)
-			return;
-	}
-}
-
-void
-__rwsem_wake (struct rw_semaphore *sem, long count)
-{
-	wait_queue_head_t *wq;
-
-	if (count == 0) {
-		/* wake a writer */
-		if (xchg(&sem->write_bias_granted, 1))
-			BUG();
-		wq = &sem->write_bias_wait;
-	} else {
-		/* wake reader(s) */
-		if (xchg(&sem->read_bias_granted, 1))
-			BUG();
-		wq = &sem->wait;
-	}
-	wake_up(wq);	/* wake up everyone on the wait queue */
-}
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c
--- v2.4.3/linux/arch/ia64/kernel/setup.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/setup.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Architecture-specific setup.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
  * Copyright (C) 1999 VA Linux Systems
@@ -42,16 +42,20 @@
 # include <linux/blk.h>
 #endif
 
+#if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
+# error "struct cpuinfo_ia64 too big!"
+#endif
+
 extern char _end;
 
 /* cpu_data[0] is data for the bootstrap processor: */
-struct cpuinfo_ia64 cpu_data[NR_CPUS];
+struct cpuinfo_ia64 cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section")));
 
 unsigned long ia64_cycles_per_usec;
-struct ia64_boot_param ia64_boot_param;
+struct ia64_boot_param *ia64_boot_param;
 struct screen_info screen_info;
 /* This tells _start which CPU is booting.  */
-int cpu_now_booting = 0;
+int cpu_now_booting;
 
 #ifdef CONFIG_SMP
 volatile unsigned long cpu_online_map;
@@ -119,14 +123,7 @@
 
 	unw_init();
 
-	/*
-	 * The secondary bootstrap loader passes us the boot
-	 * parameters at the beginning of the ZERO_PAGE, so let's
-	 * stash away those values before ZERO_PAGE gets cleared out.
-	 */
-	memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param));
-
-	*cmdline_p = __va(ia64_boot_param.command_line);
+	*cmdline_p = __va(ia64_boot_param->command_line);
 	strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
 	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';		/* for safety */
 
@@ -140,9 +137,8 @@
 	 * change APIs, they'd do things for the better.  Grumble...
 	 */
 	bootmap_start = PAGE_ALIGN(__pa(&_end));
-	if (ia64_boot_param.initrd_size)
-		bootmap_start = PAGE_ALIGN(bootmap_start
-					   + ia64_boot_param.initrd_size);
+	if (ia64_boot_param->initrd_size)
+		bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param->initrd_size);
 	bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);
 
 	efi_memmap_walk(free_available_memory, 0);
@@ -150,7 +146,7 @@
 	reserve_bootmem(bootmap_start, bootmap_size);
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	initrd_start = ia64_boot_param.initrd_start;
+	initrd_start = ia64_boot_param->initrd_start;
 
 	if (initrd_start) {
 		u64 start, size;
@@ -163,16 +159,16 @@
 			       "for initrd, please upgrade the loader\n");
 		else
 #endif
-			/* 
+			/*
 			 * The loader ONLY passes physical addresses
 			 */
 			initrd_start = (unsigned long)__va(initrd_start);
-		initrd_end = initrd_start+ia64_boot_param.initrd_size;
+		initrd_end = initrd_start+ia64_boot_param->initrd_size;
 		start      = initrd_start;
-		size       = ia64_boot_param.initrd_size;
+		size       = ia64_boot_param->initrd_size;
 
 		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
-		       (void *) initrd_start, ia64_boot_param.initrd_size);
+		       (void *) initrd_start, ia64_boot_param->initrd_size);
 
 		/*
 		 * The kernel end and the beginning of initrd can be
@@ -218,19 +214,19 @@
 	/* process SAL system table: */
 	ia64_sal_init(efi.sal_systab);
 
-#ifdef CONFIG_SMP
-	current->processor = 0;
-	cpu_physical_id(0) = hard_smp_processor_id();
-#endif
 	/*
 	 *  Set `iobase' to the appropriate address in region 6
 	 *    (uncached access range)
 	 */
-	__asm__ ("mov %0=ar.k0;;" : "=r"(ia64_iobase));
+	ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE);
 	ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET);
 
 	cpu_init();	/* initialize the bootstrap CPU */
 
+#ifdef CONFIG_SMP
+	cpu_physical_id(0) = hard_smp_processor_id();
+#endif
+
 #ifdef CONFIG_IA64_GENERIC
 	machvec_init(acpi_get_sysname());
 #endif
@@ -239,7 +235,7 @@
 	if (efi.acpi20) {
 		/* Parse the ACPI 2.0 tables */
 		acpi20_parse(efi.acpi20);
-	} else 
+	} else
 #endif
 	if (efi.acpi) {
 		/* Parse the ACPI tables */
@@ -259,8 +255,8 @@
 	ia64_mca_init();
 #endif
 
-	paging_init();
 	platform_setup(cmdline_p);
+	paging_init();
 }
 
 /*
@@ -325,7 +321,7 @@
 			     c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000,
 			     c->itc_freq / 1000000, c->itc_freq % 1000000,
 			     lpj*HZ/500000, (lpj*HZ/5000) % 100);
-        }
+	}
 	return p - buffer;
 }
 
@@ -362,8 +358,6 @@
 	for (i = 0; i < 5; ++i)
 		cpuid.bits[i] = ia64_get_cpuid(i);
 
-	memset(c, 0, sizeof(struct cpuinfo_ia64));
-
 	memcpy(c->vendor, cpuid.field.vendor, 16);
 	c->ppn = cpuid.field.ppn;
 	c->number = cpuid.field.number;
@@ -382,12 +376,6 @@
 	       smp_processor_id(), impl_va_msb + 1, phys_addr_size);
 	c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1));
 	c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
-
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-	/* BUG: SoftSDV doesn't support the cpuid registers. */
-	if (c->vendor[0] == '\0') 
-		memcpy(c->vendor, "Intel", 6);
-#endif
 }
 
 /*
@@ -397,12 +385,18 @@
 void
 cpu_init (void)
 {
-	extern void __init ia64_rid_init (void);
-	extern void __init ia64_tlb_init (void);
+	extern void __init ia64_mmu_init (void);
+	unsigned long num_phys_stacked;
 	pal_vm_info_2_u_t vmi;
 	unsigned int max_ctx;
 
-	identify_cpu(&my_cpu_data);
+	/*
+	 * We can't pass "local_cpu_data" do identify_cpu() because we haven't called
+	 * ia64_mmu_init() yet.  And we can't call ia64_mmu_init() first because it
+	 * depends on the data returned by identify_cpu().  We break the dependency by
+	 * accessing cpu_data[] the old way, through identity mapped space.
+	 */
+	identify_cpu(&cpu_data[smp_processor_id()]);
 
 	/* Clear the stack memory reserved for pt_regs: */
 	memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
@@ -415,22 +409,30 @@
 	ia64_set_dcr(  IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
 		     | IA64_DCR_DA | IA64_DCR_DD);
 #ifndef CONFIG_SMP
-	ia64_set_fpu_owner(0);		/* initialize ar.k5 */
+	ia64_set_fpu_owner(0);
 #endif
 
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
-	ia64_rid_init();
-	ia64_tlb_init();
+	ia64_mmu_init();
 
-#ifdef	CONFIG_IA32_SUPPORT
+#ifdef CONFIG_IA32_SUPPORT
 	/* initialize global ia32 state - CR0 and CR4 */
 	__asm__("mov ar.cflg = %0"
 		: /* no outputs */
 		: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0));
 #endif
 
+	/* disable all local interrupt sources: */
+	ia64_set_itv(1 << 16);
+	ia64_set_lrr0(1 << 16);
+	ia64_set_lrr1(1 << 16);
+	ia64_set_pmv(1 << 16);
+	ia64_set_cmcv(1 << 16);
+
+	/* clear TPR & XTP to enable all interrupt classes: */
+	ia64_set_tpr(0);
 #ifdef CONFIG_SMP
 	normal_xtp();
 #endif
@@ -439,7 +441,7 @@
 	if (ia64_pal_vm_summary(NULL, &vmi) == 0)
 		max_ctx = (1U << (vmi.pal_vm_info_2_s.rid_size - 3)) - 1;
 	else {
-		printk("ia64_rid_init: PAL VM summary failed, assuming 18 RID bits\n");
+		printk("cpu_init: PAL VM summary failed, assuming 18 RID bits\n");
 		max_ctx = (1U << 15) - 1;	/* use architected minimum */
 	}
 	while (max_ctx < ia64_ctx.max_ctx) {
@@ -447,4 +449,10 @@
 		if (cmpxchg(&ia64_ctx.max_ctx, old, max_ctx) == old)
 			break;
 	}
+
+	if (ia64_pal_rse_info(&num_phys_stacked, 0) != 0) {
+		printk ("cpu_init: PAL RSE info failed, assuming 96 physical stacked regs\n");
+		num_phys_stacked = 96;
+	}
+	local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c
--- v2.4.3/linux/arch/ia64/kernel/signal.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/signal.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Architecture-specific signal handling support.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Derived from i386 and Alpha versions.
  */
@@ -38,12 +38,8 @@
 #endif
 
 struct sigscratch {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	unsigned long scratch_unat;	/* ar.unat for the general registers saved in pt */
 	unsigned long pad;
-#else
-	struct switch_stack sw;
-#endif
 	struct pt_regs pt;
 };
 
@@ -52,7 +48,6 @@
 	struct sigcontext sc;
 };
 
-extern long sys_wait4 (int, int *, int, struct rusage *);
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
 long
@@ -141,11 +136,7 @@
 	ia64_psr(&scr->pt)->ri = ip & 0x3;
 	scr->pt.cr_ipsr = (scr->pt.cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM);
 
-#ifdef CONFIG_IA64_NEW_UNWIND
 	scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat);
-#else
-	ia64_put_nat_bits(&scr->pt, &scr->sw, nat);	/* restore the original scratch NaT bits */
-#endif
 
 	if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) {
 		struct ia64_psr *psr = ia64_psr(&scr->pt);
@@ -162,7 +153,7 @@
 int
 copy_siginfo_to_user (siginfo_t *to, siginfo_t *from)
 {
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+	if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
 	if (from->si_code < 0)
 		return __copy_to_user(to, from, sizeof(siginfo_t));
@@ -190,6 +181,11 @@
 			err |= __put_user(from->si_utime, &to->si_utime);
 			err |= __put_user(from->si_stime, &to->si_stime);
 			err |= __put_user(from->si_status, &to->si_status);
+		      case __SI_PROF >> 16:
+			err |= __put_user(from->si_uid, &to->si_uid);
+			err |= __put_user(from->si_pid, &to->si_pid);
+			err |= __put_user(from->si_pfm_ovfl, &to->si_pfm_ovfl);
+			break;
 		      default:
 			err |= __put_user(from->si_uid, &to->si_uid);
 			err |= __put_user(from->si_pid, &to->si_pid);
@@ -200,6 +196,43 @@
 	}
 }
 
+int
+copy_siginfo_from_user (siginfo_t *to, siginfo_t *from)
+{
+	if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t)))
+		return -EFAULT;
+	if (__copy_from_user(to, from, sizeof(siginfo_t)) != 0)
+		return -EFAULT;
+
+	if (SI_FROMUSER(to))
+		return 0;
+
+	to->si_code &= ~__SI_MASK;
+	if (to->si_code != 0) {
+		switch (to->si_signo) {
+		      case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGTRAP:
+			to->si_code |= __SI_FAULT;
+			break;
+
+		      case SIGCHLD:
+			to->si_code |= __SI_CHLD;
+			break;
+
+		      case SIGPOLL:
+			to->si_code |= __SI_POLL;
+			break;
+
+		      case SIGPROF:
+			to->si_code |= __SI_PROF;
+			break;
+
+		      default:
+			break;
+		}
+	}
+	return 0;
+}
+
 long
 ia64_rt_sigreturn (struct sigscratch *scr)
 {
@@ -212,19 +245,17 @@
 	sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc;
 
 	/*
-	 * When we return to the previously executing context, r8 and
-	 * r10 have already been setup the way we want them.  Indeed,
-	 * if the signal wasn't delivered while in a system call, we
-	 * must not touch r8 or r10 as otherwise user-level stat could
-	 * be corrupted.
+	 * When we return to the previously executing context, r8 and r10 have already
+	 * been setup the way we want them.  Indeed, if the signal wasn't delivered while
+	 * in a system call, we must not touch r8 or r10 as otherwise user-level state
+	 * could be corrupted.
 	 */
 	retval = (long) &ia64_leave_kernel;
 	if (current->ptrace & PT_TRACESYS)
 		/*
-		 * strace expects to be notified after sigreturn
-		 * returns even though the context to which we return
-		 * may not be in the middle of a syscall.  Thus, the
-		 * return-value that strace displays for sigreturn is
+		 * strace expects to be notified after sigreturn returns even though the
+		 * context to which we return may not be in the middle of a syscall.
+		 * Thus, the return-value that strace displays for sigreturn is
 		 * meaningless.
 		 */
 		retval = (long) &ia64_strace_leave_kernel;
@@ -301,11 +332,7 @@
 	 * preserved registers (r4-r7) are never being looked at by
 	 * the signal handler (registers r4-r7 are used instead).
 	 */
-#ifdef CONFIG_IA64_NEW_UNWIND
 	nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat);
-#else
-	nat = ia64_get_nat_bits(&scr->pt, &scr->sw);
-#endif
 
 	err  = __put_user(flags, &sc->sc_flags);
 
@@ -371,21 +398,11 @@
 	scr->pt.cr_iip = tramp_addr;
 	ia64_psr(&scr->pt)->ri = 0;			/* start executing in first slot */
 
-#ifdef CONFIG_IA64_NEW_UNWIND
 	/*
 	 * Note: this affects only the NaT bits of the scratch regs
 	 * (the ones saved in pt_regs), which is exactly what we want.
 	 */
 	scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */
-#else
-	/*
-	 * Note: this affects only the NaT bits of the scratch regs
-	 * (the ones saved in pt_regs), which is exactly what we want.
-	 * The NaT bits for the preserved regs (r4-r7) are in
-	 * sw->ar_unat iff this process is being PTRACED.
-	 */
-	scr->sw.caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */
-#endif
 
 #if DEBUG_SIG
 	printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n",
@@ -437,13 +454,8 @@
 }
 
 /*
- * Note that `init' is a special process: it doesn't get signals it
- * doesn't want to handle.  Thus you cannot kill init even with a
- * SIGKILL even by mistake.
- *
- * Note that we go through the signals twice: once to check the
- * signals that the kernel can handle, and then we build all the
- * user-level signal handling stack-frames in one go after that.
+ * Note that `init' is a special process: it doesn't get signals it doesn't want to
+ * handle.  Thus you cannot kill init even with a SIGKILL even by mistake.
  */
 long
 ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
@@ -454,9 +466,9 @@
 	long errno = scr->pt.r8;
 
 	/*
-	 * In the ia64_leave_kernel code path, we want the common case
-	 * to go fast, which is why we may in certain cases get here
-	 * from kernel mode. Just return without doing anything if so.
+	 * In the ia64_leave_kernel code path, we want the common case to go fast, which
+	 * is why we may in certain cases get here from kernel mode. Just return without
+	 * doing anything if so.
 	 */
 	if (!user_mode(&scr->pt))
 		return 0;
@@ -476,11 +488,10 @@
 #endif
 	if (scr->pt.r10 != -1) {
 		/*
-		 * A system calls has to be restarted only if one of
-		 * the error codes ERESTARTNOHAND, ERESTARTSYS, or
-		 * ERESTARTNOINTR is returned.  If r10 isn't -1 then
-		 * r8 doesn't hold an error code and we don't need to
-		 * restart the syscall, so we set in_syscall to zero.
+		 * A system calls has to be restarted only if one of the error codes
+		 * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned.  If r10
+		 * isn't -1 then r8 doesn't hold an error code and we don't need to
+		 * restart the syscall, so we can clear the "restart" flag here.
 		 */
 		restart = 0;
 	}
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c
--- v2.4.3/linux/arch/ia64/kernel/smp.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/smp.c	Thu Apr  5 12:51:47 2001
@@ -2,8 +2,8 @@
  * SMP Support
  *
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * 
+ * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
  * Lots of stuff stolen from arch/alpha/kernel/smp.c
  *
  *  00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy calibration on each CPU.
@@ -37,8 +37,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/page.h>
-#include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/sal.h>
@@ -50,9 +50,8 @@
 extern void machine_halt(void);
 extern void start_ap(void);
 
-extern int cpu_now_booting;			     /* Used by head.S to find idle task */
-extern volatile unsigned long cpu_online_map;	     /* Bitmap of available cpu's */
-extern struct cpuinfo_ia64 cpu_data[NR_CPUS];	     /* Duh... */
+extern int cpu_now_booting;			/* used by head.S to find idle task */
+extern volatile unsigned long cpu_online_map;	/* bitmap of available cpu's */
 
 struct smp_boot_data smp_boot_data __initdata;
 
@@ -60,18 +59,19 @@
 
 char __initdata no_int_routing;
 
+/* don't make this a CPU-local variable: it's used for IPIs, mostly...  */
+int __cpu_physical_id[NR_CPUS];			/* logical ID -> physical CPU ID map */
+
 unsigned char smp_int_redirect;			/* are INT and IPI redirectable by the chipset? */
-volatile int __cpu_physical_id[NR_CPUS] = { -1, };    /* Logical ID -> SAPIC ID */
-int smp_num_cpus = 1;		
-volatile int smp_threads_ready;			     /* Set when the idlers are all forked */
-cycles_t cacheflush_time;
-unsigned long ap_wakeup_vector = -1;		     /* External Int to use to wakeup AP's */
+int smp_num_cpus = 1;
+volatile int smp_threads_ready;			/* set when the idlers are all forked */
+unsigned long ap_wakeup_vector;			/* external Int to use to wakeup AP's */
 
 static volatile unsigned long cpu_callin_map;
 static volatile int smp_commenced;
 
-static int max_cpus = -1;			     /* Command line */
-static unsigned long ipi_op[NR_CPUS];
+static int max_cpus = -1;			/* command line */
+
 struct smp_call_struct {
 	void (*func) (void *info);
 	void *info;
@@ -99,7 +99,8 @@
  *	SMP mode to <NUM>.
  */
 
-static int __init nosmp(char *str)
+static int __init
+nosmp (char *str)
 {
 	max_cpus = 0;
 	return 1;
@@ -107,7 +108,8 @@
 
 __setup("nosmp", nosmp);
 
-static int __init maxcpus(char *str)
+static int __init
+maxcpus (char *str)
 {
 	get_option(&str, &max_cpus);
 	return 1;
@@ -116,7 +118,7 @@
 __setup("maxcpus=", maxcpus);
 
 static int __init
-nointroute(char *str)
+nointroute (char *str)
 {
 	no_int_routing = 1;
 	return 1;
@@ -125,21 +127,20 @@
 __setup("nointroute", nointroute);
 
 /*
- * Yoink this CPU from the runnable list... 
+ * Yoink this CPU from the runnable list...
  */
 void
-halt_processor(void) 
+halt_processor (void)
 {
-        clear_bit(smp_processor_id(), &cpu_online_map);
+	clear_bit(smp_processor_id(), &cpu_online_map);
 	max_xtp();
 	__cli();
-        for (;;)
+	for (;;)
 		;
-
 }
 
 static inline int
-pointer_lock(void *lock, void *data, int retry)
+pointer_lock (void *lock, void *data, int retry)
 {
 	volatile long *ptr = lock;
  again:
@@ -156,14 +157,13 @@
 }
 
 void
-handle_IPI(int irq, void *dev_id, struct pt_regs *regs) 
+handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
 {
-	int this_cpu = smp_processor_id();
-	unsigned long *pending_ipis = &ipi_op[this_cpu];
+	unsigned long *pending_ipis = &local_cpu_data->ipi_operation;
 	unsigned long ops;
 
 	/* Count this now; we may make a call that never returns. */
-	cpu_data[this_cpu].ipi_count++;
+	local_cpu_data->ipi_count++;
 
 	mb();	/* Order interrupt and bit testing. */
 	while ((ops = xchg(pending_ipis, 0)) != 0) {
@@ -173,16 +173,16 @@
 
 		which = ffz(~ops);
 		ops &= ~(1 << which);
-		
+
 		switch (which) {
 		case IPI_RESCHEDULE:
-			/* 
-			 * Reschedule callback.  Everything to be done is done by the 
-			 * interrupt return path.  
+			/*
+			 * Reschedule callback.  Everything to be done is done by the
+			 * interrupt return path.
 			 */
 			break;
-			
-		case IPI_CALL_FUNC: 
+
+		case IPI_CALL_FUNC:
 			{
 				struct smp_call_struct *data;
 				void (*func)(void *info);
@@ -203,7 +203,7 @@
 
 				/* Notify the sending CPU that the task is done.  */
 				mb();
-				if (wait) 
+				if (wait)
 					atomic_dec(&data->unfinished_count);
 			}
 			break;
@@ -214,7 +214,7 @@
 
 #ifndef CONFIG_ITANIUM_PTCG
 		case IPI_FLUSH_TLB:
-                {
+		{
 			extern unsigned long flush_start, flush_end, flush_nbits, flush_rid;
 			extern atomic_t flush_cpu_count;
 			unsigned long saved_rid = ia64_get_rr(flush_start);
@@ -223,6 +223,8 @@
 			unsigned long nbits = flush_nbits;
 
 			/*
+			 * Current CPU may be running with different RID so we need to
+			 * reload the RID of flushed address.
 			 * Current CPU may be running with different
 			 * RID so we need to reload the RID of flushed
 			 * address.  Purging the translation also
@@ -235,7 +237,7 @@
 				ia64_set_rr(flush_start, flush_rid);
 				ia64_srlz_d();
 			}
-			
+
 			do {
 				/*
 				 * Purge local TLB entries.
@@ -258,7 +260,8 @@
 #endif	/* !CONFIG_ITANIUM_PTCG */
 
 		default:
-			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
+			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
+			       smp_processor_id(), which);
 			break;
 		} /* Switch */
 	  } while (ops);
@@ -268,21 +271,21 @@
 }
 
 static inline void
-send_IPI_single (int dest_cpu, int op) 
+send_IPI_single (int dest_cpu, int op)
 {
-	
-	if (dest_cpu == -1) 
-                return;
-        
-	set_bit(op, &ipi_op[dest_cpu]);
-	platform_send_ipi(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0);
+
+	if (dest_cpu == -1)
+		return;
+
+	set_bit(op, &cpu_data[dest_cpu].ipi_operation);
+	platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
 }
 
 static inline void
-send_IPI_allbutself(int op)
+send_IPI_allbutself (int op)
 {
 	int i;
-	
+
 	for (i = 0; i < smp_num_cpus; i++) {
 		if (i != smp_processor_id())
 			send_IPI_single(i, op);
@@ -290,7 +293,7 @@
 }
 
 static inline void
-send_IPI_all(int op)
+send_IPI_all (int op)
 {
 	int i;
 
@@ -299,30 +302,42 @@
 }
 
 static inline void
-send_IPI_self(int op)
+send_IPI_self (int op)
 {
 	send_IPI_single(smp_processor_id(), op);
 }
 
 void
-smp_send_reschedule(int cpu)
+smp_send_reschedule (int cpu)
 {
 	send_IPI_single(cpu, IPI_RESCHEDULE);
 }
 
 void
-smp_send_stop(void)
+smp_send_stop (void)
 {
 	send_IPI_allbutself(IPI_CPU_STOP);
 }
 
 #ifndef CONFIG_ITANIUM_PTCG
+
 void
-smp_send_flush_tlb(void)
+smp_send_flush_tlb (void)
 {
 	send_IPI_allbutself(IPI_FLUSH_TLB);
 }
-#endif	/* !CONFIG_ITANIUM_PTCG */
+
+void
+smp_resend_flush_tlb(void)
+{
+	/*
+	 * Really need a null IPI but since this rarely should happen & since this code
+	 * will go away, lets not add one.
+	 */
+	send_IPI_allbutself(IPI_RESCHEDULE);
+}
+
+#endif /* !CONFIG_ITANIUM_PTCG */
 
 /*
  * Run a function on another CPU
@@ -347,7 +362,7 @@
 		printk(__FUNCTION__" trying to call self\n");
 		return -EBUSY;
 	}
-	
+
 	data.func = func;
 	data.info = info;
 	data.wait = wait;
@@ -392,7 +407,6 @@
  * Does not return until remote CPUs are nearly ready to execute <func>
  * or are or have executed.
  */
-
 int
 smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
 {
@@ -402,7 +416,7 @@
 
 	if (cpus == 0)
 		return 0;
-	
+
 	data.func = func;
 	data.info = info;
 	data.wait = wait;
@@ -425,7 +439,7 @@
 		int i;
 		for (i = 0; i < smp_num_cpus; i++) {
 			if (i != smp_processor_id())
-				platform_send_ipi(i, IPI_IRQ, IA64_IPI_DM_INT, 0);
+				platform_send_ipi(i, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
 		}
 		goto retry;
 #else
@@ -446,7 +460,7 @@
  * want to ensure all TLB's flushed before proceeding.
  */
 void
-smp_flush_tlb_all(void)
+smp_flush_tlb_all (void)
 {
 	smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1);
 	__flush_tlb_all();
@@ -456,21 +470,19 @@
  * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
  */
 static inline void __init
-smp_setup_percpu_timer(int cpuid)
+smp_setup_percpu_timer(void)
 {
-        cpu_data[cpuid].prof_counter = 1;
-        cpu_data[cpuid].prof_multiplier = 1;
+	local_cpu_data->prof_counter = 1;
+	local_cpu_data->prof_multiplier = 1;
 }
 
-void 
-smp_do_timer(struct pt_regs *regs)
+void
+smp_do_timer (struct pt_regs *regs)
 {
-        int cpu = smp_processor_id();
-        int user = user_mode(regs);
-	struct cpuinfo_ia64 *data = &cpu_data[cpu];
+	int user = user_mode(regs);
 
-        if (--data->prof_counter <= 0) {
-		data->prof_counter = data->prof_multiplier;
+	if (--local_cpu_data->prof_counter <= 0) {
+		local_cpu_data->prof_counter = local_cpu_data->prof_multiplier;
 		update_process_times(user);
 	}
 }
@@ -480,7 +492,7 @@
  * AP's start using C here.
  */
 void __init
-smp_callin (void) 
+smp_callin (void)
 {
 	extern void ia64_rid_init(void);
 	extern void ia64_init_itm(void);
@@ -493,12 +505,12 @@
 	if (test_and_set_bit(cpu, &cpu_online_map)) {
 		printk("CPU#%d already initialized!\n", cpu);
 		machine_halt();
-	}  
+	}
 
 	efi_map_pal_code();
 	cpu_init();
 
-	smp_setup_percpu_timer(cpu);
+	smp_setup_percpu_timer();
 
 	/* setup the CPU local timer tick */
 	ia64_init_itm();
@@ -506,15 +518,10 @@
 #ifdef CONFIG_PERFMON
 	perfmon_init_percpu();
 #endif
-
-	/* Disable all local interrupts */
-	ia64_set_lrr0(0, 1);	
-	ia64_set_lrr1(0, 1);	
-
 	local_irq_enable();		/* Interrupts have been off until now */
 
 	calibrate_delay();
-	my_cpu_data.loops_per_jiffy = loops_per_jiffy;
+	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
 
 	/* allow the master to continue */
 	set_bit(cpu, &cpu_callin_map);
@@ -531,8 +538,8 @@
  * path in which case the new idle task could get scheduled before we
  * had a chance to remove it from the run-queue...
  */
-static int __init 
-fork_by_hand(void)
+static int __init
+fork_by_hand (void)
 {
 	/*
 	 * Don't care about the usp and regs settings since we'll never
@@ -545,22 +552,22 @@
  * Bring one cpu online.  Return 0 if this fails for any reason.
  */
 static int __init
-smp_boot_one_cpu(int cpu)
+smp_boot_one_cpu (int cpu)
 {
 	struct task_struct *idle;
 	int cpu_phys_id = cpu_physical_id(cpu);
 	long timeout;
 
-	/* 
+	/*
 	 * Create an idle task for this CPU.  Note that the address we
 	 * give to kernel_thread is irrelevant -- it's going to start
 	 * where OS_BOOT_RENDEVZ vector in SAL says to start.  But
 	 * this gets all the other task-y sort of data structures set
-	 * up like we wish.   We need to pull the just created idle task 
-	 * off the run queue and stuff it into the init_tasks[] array.  
+	 * up like we wish.   We need to pull the just created idle task
+	 * off the run queue and stuff it into the init_tasks[] array.
 	 * Sheesh . . .
 	 */
-	if (fork_by_hand() < 0) 
+	if (fork_by_hand() < 0)
 		panic("failed fork for CPU 0x%x", cpu_phys_id);
 	/*
 	 * We remove it from the pidhash and the runqueue
@@ -571,7 +578,7 @@
 		panic("No idle process for CPU 0x%x", cpu_phys_id);
 	init_tasks[cpu] = idle;
 	del_from_runqueue(idle);
-        unhash_process(idle);
+	unhash_process(idle);
 
 	/* Schedule the first task manually.  */
 	idle->processor = cpu;
@@ -590,50 +597,41 @@
 		udelay(100);
 	}
 
-	printk(KERN_ERR "SMP: Processor 0x%x is stuck.\n", cpu_phys_id);
+	printk(KERN_ERR "SMP: CPU 0x%x is stuck\n", cpu_phys_id);
 	return 0;
 }
 
 
 
 /*
- * Called by smp_init bring all the secondaries online and hold them.  
- * XXX: this is ACPI specific; it uses "magic" variables exported from acpi.c 
- *      to 'discover' the AP's.  Blech.
+ * Called by smp_init bring all the secondaries online and hold them.
  */
 void __init
-smp_boot_cpus(void)
+smp_boot_cpus (void)
 {
 	int i, cpu_count = 1;
 	unsigned long bogosum;
 
-	/* Take care of some initial bookkeeping.  */
-	memset(&__cpu_physical_id, -1, sizeof(__cpu_physical_id));
-	memset(&ipi_op, 0, sizeof(ipi_op));
-
-	/* Setup BP mappings */
-	__cpu_physical_id[0] = hard_smp_processor_id();
-
 	/* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */
-	my_cpu_data.loops_per_jiffy = loops_per_jiffy;
+	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
 #if 0
 	smp_tune_scheduling();
 #endif
- 	smp_setup_percpu_timer(0);
+	smp_setup_percpu_timer();
 
 	if (test_and_set_bit(0, &cpu_online_map)) {
 		printk("CPU#%d already initialized!\n", smp_processor_id());
 		machine_halt();
-	}  
+	}
 	init_idle();
 
 	/* Nothing to do when told not to.  */
 	if (max_cpus == 0) {
-	        printk(KERN_INFO "SMP mode deactivated.\n");
+		printk(KERN_INFO "SMP mode deactivated.\n");
 		return;
 	}
 
-	if (max_cpus != -1) 
+	if (max_cpus != -1)
 		printk("Limiting CPUs to %d\n", max_cpus);
 
 	if (smp_boot_data.cpu_count > 1) {
@@ -650,7 +648,7 @@
 				continue;	/* failed */
 
 			cpu_count++; /* Count good CPUs only... */
-			/* 
+			/*
 			 * Bail if we've started as many CPUS as we've been told to.
 			 */
 			if (cpu_count == max_cpus)
@@ -663,10 +661,10 @@
 	}
 
 	bogosum = 0;
-        for (i = 0; i < NR_CPUS; i++) {
+	for (i = 0; i < NR_CPUS; i++) {
 		if (cpu_online_map & (1L << i))
 			bogosum += cpu_data[i].loops_per_jiffy;
-        }
+	}
 
 	printk(KERN_INFO "SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
 	       cpu_count, bogosum*HZ/500000, (bogosum*HZ/5000) % 100);
@@ -674,31 +672,31 @@
 	smp_num_cpus = cpu_count;
 }
 
-/* 
+/*
  * Called when the BP is just about to fire off init.
  */
-void __init 
-smp_commence(void)
+void __init
+smp_commence (void)
 {
 	smp_commenced = 1;
 }
 
 int __init
-setup_profiling_timer(unsigned int multiplier)
+setup_profiling_timer (unsigned int multiplier)
 {
-        return -EINVAL;
+	return -EINVAL;
 }
 
 /*
  * Assume that CPU's have been discovered by some platform-dependant
  * interface.  For SoftSDV/Lion, that would be ACPI.
  *
- * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP().
+ * Setup of the IPI irq handler is done in irq.c:init_IRQ().
  *
  * This also registers the AP OS_MC_REDVEZ address with SAL.
  */
 void __init
-init_smp_config(void)
+init_smp_config (void)
 {
 	struct fptr {
 		unsigned long fp;
@@ -708,14 +706,13 @@
 
 	/* Tell SAL where to drop the AP's.  */
 	ap_startup = (struct fptr *) start_ap;
-	sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
-				       __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 
-				       0, 0, 0);
+	sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, __pa(ap_startup->fp),
+				       __pa(ap_startup->gp), 0, 0, 0, 0);
 	if (sal_ret < 0) {
 		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret));
 		printk("     Forcing UP mode\n");
 		max_cpus = 0;
-		smp_num_cpus = 1; 
+		smp_num_cpus = 1;
 	}
 
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c
--- v2.4.3/linux/arch/ia64/kernel/smpboot.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/kernel/smpboot.c	Thu Apr  5 12:51:47 2001
@@ -1,74 +1,4 @@
 /*
- * SMP Support
- *
- * Application processor startup code, moved from smp.c to better support kernel profile
  */
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/smp.h>
-#include <linux/kernel_stat.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <asm/atomic.h>
-#include <asm/bitops.h>
-#include <asm/current.h>
-#include <asm/delay.h>
-#include <asm/efi.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/sal.h>
-#include <asm/system.h>
-#include <asm/unistd.h>
-
-/* 
- * SAL shoves the AP's here when we start them.  Physical mode, no kernel TR, 
- * no RRs set, better than even chance that psr is bogus.  Fix all that and 
- * call _start.  In effect, pretend to be lilo.
- *
- * Stolen from lilo_start.c.  Thanks David! 
- */
-void
-start_ap(void)
-{
-	extern void _start (void);
-	unsigned long flags;
-
-	/*
-	 * Install a translation register that identity maps the
-	 * kernel's 256MB page(s).
-	 */
-	ia64_clear_ic(flags);
-	ia64_set_rr(          0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2));
-	ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2));
-	ia64_srlz_d();
-	ia64_itr(0x3, 1, PAGE_OFFSET,
-		 pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))),
-		 _PAGE_SIZE_256M);
-	ia64_srlz_i();
-
-	flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | 
-		 IA64_PSR_BN);
-	
-	asm volatile ("movl r8 = 1f\n"
-		      ";;\n"
-		      "mov cr.ipsr=%0\n"
-		      "mov cr.iip=r8\n" 
-		      "mov cr.ifs=r0\n"
-		      ";;\n"
-		      "rfi;;"
-		      "1:\n"
-		      "movl r1 = __gp" :: "r"(flags) : "r8");
-	_start();
-}
-
-
+/* place holder... */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c
--- v2.4.3/linux/arch/ia64/kernel/sys_ia64.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/ia64/kernel/sys_ia64.c	Fri Apr 13 15:38:51 2001
@@ -22,16 +22,16 @@
 #define COLOR_ALIGN(addr)	(((addr) + SHMLBA - 1) & ~(SHMLBA - 1))
 
 unsigned long
-get_unmapped_area (unsigned long addr, unsigned long len)
+arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct * vmm;
 
 	if (len > RGN_MAP_LIMIT)
-		return 0;
+		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	if (current->thread.flags & IA64_THREAD_MAP_SHARED)
+	if (flags & MAP_SHARED)
 		addr = COLOR_ALIGN(addr);
 	else
 		addr = PAGE_ALIGN(addr);
@@ -39,17 +39,19 @@
 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
 		/* At this point:  (!vmm || addr < vmm->vm_end). */
 		if (TASK_SIZE - len < addr)
-			return 0;
+			return -ENOMEM;
 		if (rgn_offset(addr) + len > RGN_MAP_LIMIT)	/* no risk of overflow here... */
-			return 0;
+			return -ENOMEM;
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
 		addr = vmm->vm_end;
+		if (flags & MAP_SHARED)
+			addr = COLOR_ALIGN(addr);
 	}
 }
 
 asmlinkage long
-ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, 
+ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6,
 		  long arg7, long stack)
 {
 	struct pt_regs *regs = (struct pt_regs *) &stack;
@@ -197,15 +199,10 @@
 			return -EBADF;
 	}
 
-	if (flags & MAP_SHARED)
-		current->thread.flags |= IA64_THREAD_MAP_SHARED;
-
 	down_write(&current->mm->mmap_sem);
 	addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
 
-	current->thread.flags &= ~IA64_THREAD_MAP_SHARED;
-
 	if (file)
 		fput(file);
 	return addr;
@@ -246,15 +243,15 @@
 asmlinkage long
 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
 {
-        printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
-        return -ENOSYS;
+	printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
+	return -ENOSYS;
 }
 
 asmlinkage long
 sys_modify_ldt (long arg0, long arg1, long arg2, long arg3)
 {
-        printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
-        return -ENOSYS;
+	printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
+	return -ENOSYS;
 }
 
 asmlinkage unsigned long
@@ -392,7 +389,7 @@
 	}
 	return err;
 }
- 
+
 #endif
 
 #ifndef CONFIG_PCI
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c
--- v2.4.3/linux/arch/ia64/kernel/time.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/time.c	Thu Apr  5 12:51:47 2001
@@ -1,9 +1,9 @@
 /*
  * linux/arch/ia64/kernel/time.c
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
  * Copyright (C) 1998-2000 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 David Mosberger <davidm@hpl.hp.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  * Copyright (C) 1999-2000 VA Linux Systems
  * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
@@ -32,14 +32,6 @@
 
 #endif
 
-static struct {
-	unsigned long delta;
-	union {
-		unsigned long count;
-		unsigned char pad[SMP_CACHE_BYTES];
-	} next[NR_CPUS];
-} itm;
-
 static void
 do_profile (unsigned long ip)
 {
@@ -61,7 +53,7 @@
 			ip = prof_len - 1;
 
 		atomic_inc((atomic_t *) &prof_buffer[ip]);
-	} 
+	}
 }
 
 /*
@@ -82,7 +74,7 @@
 	unsigned long now = ia64_get_itc(), last_tick;
 	unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;
 
-	last_tick = (itm.next[smp_processor_id()].count - (lost+1)*itm.delta);
+	last_tick = (local_cpu_data->itm_next - (lost+1)*local_cpu_data->itm_delta);
 # if 1
 	if ((long) (now - last_tick) < 0) {
 		printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)!  No can do.\n",
@@ -91,7 +83,7 @@
 	}
 # endif
 	elapsed_cycles = now - last_tick;
-	return (elapsed_cycles*my_cpu_data.usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT;
+	return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT;
 #endif
 }
 
@@ -132,7 +124,7 @@
 	read_lock_irqsave(&xtime_lock, flags);
 	{
 		usec = gettimeoffset();
-	
+
 		sec = xtime.tv_sec;
 		usec += xtime.tv_usec;
 	}
@@ -150,10 +142,9 @@
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int cpu = smp_processor_id();
 	unsigned long new_itm;
 
-	new_itm = itm.next[cpu].count;
+	new_itm = local_cpu_data->itm_next;
 
 	if (!time_after(ia64_get_itc(), new_itm))
 		printk("Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
@@ -165,7 +156,7 @@
 		 * four so that we can use a prof_shift of 2 to get instruction-level
 		 * instead of just bundle-level accuracy.
 		 */
-		if (!user_mode(regs)) 
+		if (!user_mode(regs))
 			do_profile(regs->cr_iip + 4*ia64_psr(regs)->ri);
 
 #ifdef CONFIG_SMP
@@ -183,52 +174,50 @@
 			write_unlock(&xtime_lock);
 		}
 
-		new_itm += itm.delta;
-		itm.next[cpu].count = new_itm;
+		new_itm += local_cpu_data->itm_delta;
+		local_cpu_data->itm_next = new_itm;
 		if (time_after(new_itm, ia64_get_itc()))
 			break;
 	}
 
-	/*
-	 * If we're too close to the next clock tick for comfort, we
-	 * increase the saftey margin by intentionally dropping the
-	 * next tick(s).  We do NOT update itm.next accordingly
-	 * because that would force us to call do_timer() which in
-	 * turn would let our clock run too fast (with the potentially
-	 * devastating effect of losing monotony of time).
-	 */
-	while (!time_after(new_itm, ia64_get_itc() + itm.delta/2))
-		new_itm += itm.delta;
-	ia64_set_itm(new_itm);
-}
-
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-
-/*
- * Interrupts must be disabled before calling this routine.
- */
-void
-ia64_reset_itm (void)
-{
-	timer_interrupt(0, 0, ia64_task_regs(current));
+	do {
+	    /*
+	     * If we're too close to the next clock tick for comfort, we increase the
+	     * saftey margin by intentionally dropping the next tick(s).  We do NOT update
+	     * itm.next because that would force us to call do_timer() which in turn would
+	     * let our clock run too fast (with the potentially devastating effect of
+	     * losing monotony of time).
+	     */
+	    while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2))
+	      new_itm += local_cpu_data->itm_delta;
+	    ia64_set_itm(new_itm);
+	    /* double check, in case we got hit by a (slow) PMI: */
+	} while (time_after_eq(ia64_get_itc(), new_itm));
 }
 
-#endif
-
 /*
  * Encapsulate access to the itm structure for SMP.
  */
 void __init
-ia64_cpu_local_tick(void)
+ia64_cpu_local_tick (void)
 {
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-	ia64_set_itc(0);
-#endif
+	int cpu = smp_processor_id();
+	unsigned long shift = 0, delta;
 
 	/* arrange for the cycle counter to generate a timer interrupt: */
-	ia64_set_itv(TIMER_IRQ, 0);
-	itm.next[smp_processor_id()].count = ia64_get_itc() + itm.delta;
-	ia64_set_itm(itm.next[smp_processor_id()].count);
+	ia64_set_itv(IA64_TIMER_VECTOR);
+
+	delta = local_cpu_data->itm_delta;
+	/*
+	 * Stagger the timer tick for each CPU so they don't occur all at (almost) the
+	 * same time:
+	 */
+	if (cpu) {
+		unsigned long hi = 1UL << ia64_fls(cpu);
+		shift = (2*(cpu - hi) + 1) * delta/hi/2;
+	}
+	local_cpu_data->itm_next = ia64_get_itc() + delta + shift;
+	ia64_set_itm(local_cpu_data->itm_next);
 }
 
 void __init
@@ -258,33 +247,28 @@
 		itc_ratio.num = 3;
 		itc_ratio.den = 1;
 	}
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-	platform_base_freq = 10000000;
-	proc_ratio.num = 4; proc_ratio.den = 1;
-	itc_ratio.num  = 4; itc_ratio.den  = 1;
-#else
 	if (platform_base_freq < 40000000) {
 		printk("Platform base frequency %lu bogus---resetting to 75MHz!\n",
 		       platform_base_freq);
 		platform_base_freq = 75000000;
 	}
-#endif
 	if (!proc_ratio.den)
-		proc_ratio.num = 1;	/* avoid division by zero */
+		proc_ratio.den = 1;	/* avoid division by zero */
 	if (!itc_ratio.den)
-		itc_ratio.num = 1;	/* avoid division by zero */
+		itc_ratio.den = 1;	/* avoid division by zero */
 
-        itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
-        itm.delta = itc_freq / HZ;
-        printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n",
+	itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
+	local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
+	printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n",
 	       smp_processor_id(),
 	       platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
-               itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);
+	       itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);
 
-	my_cpu_data.proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
-	my_cpu_data.itc_freq = itc_freq;
-	my_cpu_data.cyc_per_usec = itc_freq / 1000000;
-	my_cpu_data.usec_per_cyc = (1000000UL << IA64_USEC_PER_CYC_SHIFT) / itc_freq;
+	local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
+	local_cpu_data->itc_freq = itc_freq;
+	local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000;
+	local_cpu_data->usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT)
+					+ itc_freq/2)/itc_freq;
 
 	/* Setup the CPU local timer tick */
 	ia64_cpu_local_tick();
@@ -299,11 +283,7 @@
 void __init
 time_init (void)
 {
-	/* we can't do request_irq() here because the kmalloc() would fail... */
-	irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU;
-	irq_desc[TIMER_IRQ].handler = &irq_type_ia64_sapic;
-	setup_irq(TIMER_IRQ, &timer_irqaction);
-
+	register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
 	efi_gettimeofday(&xtime);
 	ia64_init_itm();
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c
--- v2.4.3/linux/arch/ia64/kernel/traps.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/traps.c	Thu Apr  5 12:51:47 2001
@@ -7,8 +7,6 @@
  * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE
  */
 
-#define FPSWA_DEBUG	1
-
 /*
  * The fpu_fault() handler needs to be able to access and update all
  * floating point registers.  Those saved in pt_regs can be accessed
@@ -47,31 +45,10 @@
 void __init
 trap_init (void)
 {
-	printk("fpswa interface at %lx\n", ia64_boot_param.fpswa);
-	if (ia64_boot_param.fpswa) {
-#define OLD_FIRMWARE
-#ifdef OLD_FIRMWARE
-		/*
-		 * HACK to work around broken firmware.  This code
-		 * applies the label fixup to the FPSWA interface and
-		 * works both with old and new (fixed) firmware.
-		 */
-		unsigned long addr = (unsigned long) __va(ia64_boot_param.fpswa);
-		unsigned long gp_val = *(unsigned long *)(addr + 8);
-
-		/* go indirect and indexed to get table address */
-		addr = gp_val;
-		gp_val = *(unsigned long *)(addr + 8);
-
-		while (gp_val == *(unsigned long *)(addr + 8)) {
-			*(unsigned long *)addr |= PAGE_OFFSET;
-			*(unsigned long *)(addr + 8) |= PAGE_OFFSET;
-			addr += 16;
-		}
-#endif
+	printk("fpswa interface at %lx\n", ia64_boot_param->fpswa);
+	if (ia64_boot_param->fpswa)
 		/* FPSWA fixup: make the interface pointer a kernel virtual address: */
-		fpswa_interface = __va(ia64_boot_param.fpswa);
-	}
+		fpswa_interface = __va(ia64_boot_param->fpswa);
 }
 
 void
@@ -240,6 +217,7 @@
 {
 	fp_state_t fp_state;
 	fpswa_ret_t ret;
+#define FPSWA_BUG
 #ifdef FPSWA_BUG
 	struct ia64_fpreg f6_15[10];
 #endif
@@ -250,7 +228,7 @@
 	memset(&fp_state, 0, sizeof(fp_state_t));
 
 	/*
-	 * compute fp_state.  only FP registers f6 - f11 are used by the 
+	 * compute fp_state.  only FP registers f6 - f11 are used by the
 	 * kernel, so set those bits in the mask and set the low volatile
 	 * pointer to point to these registers.
 	 */
@@ -263,15 +241,15 @@
 	f6_15[1] = regs->f7;
 	f6_15[2] = regs->f8;
 	f6_15[3] = regs->f9;
- 	__asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4]));
- 	__asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5]));
- 	__asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6]));
- 	__asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7]));
- 	__asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8]));
- 	__asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9]));
+	__asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4]));
+	__asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5]));
+	__asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6]));
+	__asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7]));
+	__asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8]));
+	__asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9]));
 	fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15;
 #endif
-        /*
+	/*
 	 * unsigned long (*EFI_FPSWA) (
 	 *      unsigned long    trap_type,
 	 *	void             *Bundle,
@@ -287,12 +265,12 @@
 					(unsigned long *) isr, (unsigned long *) pr,
 					(unsigned long *) ifs, &fp_state);
 #ifdef FPSWA_BUG
- 	__asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4]));
- 	__asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5]));
- 	__asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6]));
- 	__asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7]));
- 	__asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8]));
- 	__asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9]));
+	__asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4]));
+	__asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5]));
+	__asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6]));
+	__asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7]));
+	__asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8]));
+	__asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9]));
 	regs->f6 = f6_15[0];
 	regs->f7 = f6_15[1];
 	regs->f8 = f6_15[2];
@@ -319,21 +297,20 @@
 	if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle)))
 		return -1;
 
-#ifdef FPSWA_DEBUG
-	if (fpu_swa_count > 5 && jiffies - last_time > 5*HZ)
+	if (jiffies - last_time > 5*HZ)
 		fpu_swa_count = 0;
 	if (++fpu_swa_count < 5) {
 		last_time = jiffies;
-		printk("%s(%d): floating-point assist fault at ip %016lx\n",
+		printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n",
 		       current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri);
 	}
-#endif
+
 	exception = fp_emulate(fp_fault, bundle, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
- 			       &regs->cr_ifs, regs);
+			       &regs->cr_ifs, regs);
 	if (fp_fault) {
 		if (exception == 0) {
 			/* emulation was successful */
- 			ia64_increment_ip(regs);
+			ia64_increment_ip(regs);
 		} else if (exception == -1) {
 			printk("handle_fpu_swa: fp_emulate() returned -1\n");
 			return -1;
@@ -392,7 +369,7 @@
 	struct siginfo si;
 	char buf[128];
 
-#ifdef CONFIG_IA64_BRL_EMU	
+#ifdef CONFIG_IA64_BRL_EMU
 	{
 		extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long);
 
@@ -431,7 +408,7 @@
 		"IA-64 Reserved Register/Field fault",
 		"Disabled Instruction Set Transition fault",
 		"Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault",
-		"Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", 
+		"Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12",
 		"Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
 	};
 
@@ -444,7 +421,7 @@
 		unsigned long n = vector;
 		char buf[32], *cp;
 
-		if (count > 5 && jiffies - last_time > 5*HZ)
+		if (jiffies - last_time > 5*HZ)
 			count = 0;
 
 		if (count++ < 5) {
@@ -502,7 +479,7 @@
 	      case 35: /* Taken Branch Trap */
 	      case 36: /* Single Step Trap */
 		switch (vector) {
-		      case 29: 
+		      case 29:
 			siginfo.si_code = TRAP_HWBKPT;
 #ifdef CONFIG_ITANIUM
 			/*
@@ -513,7 +490,7 @@
 			  ifa = regs->cr_iip;
 #endif
 			siginfo.si_addr = (void *) ifa;
-		        break;
+			break;
 		      case 35: siginfo.si_code = TRAP_BRANCH; break;
 		      case 36: siginfo.si_code = TRAP_TRACE; break;
 		}
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c
--- v2.4.3/linux/arch/ia64/kernel/unaligned.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/unaligned.c	Thu Apr  5 12:51:47 2001
@@ -1,12 +1,16 @@
 /*
  * Architecture-specific unaligned trap handling.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
  * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 2001/01/17	Add support emulation of unaligned kernel accesses.
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
+
 #include <asm/uaccess.h>
 #include <asm/rse.h>
 #include <asm/processor.h>
@@ -17,14 +21,28 @@
 #undef DEBUG_UNALIGNED_TRAP
 
 #ifdef DEBUG_UNALIGNED_TRAP
-#define DPRINT(a) { printk("%s, line %d: ", __FUNCTION__, __LINE__); printk a;}
+# define DPRINT(a...)	do { printk("%s.%u: ", __FUNCTION__, __LINE__); printk (a); } while (0)
+# define DDUMP(str,vp,len)	dump(str, vp, len)
+
+static void
+dump (const char *str, void *vp, size_t len)
+{
+	unsigned char *cp = vp;
+	int i;
+
+	printk("%s", str);
+	for (i = 0; i < len; ++i)
+		printk (" %02x", *cp++);
+	printk("\n");
+}
 #else
-#define DPRINT(a)
+# define DPRINT(a...)
+# define DDUMP(str,vp,len)
 #endif
 
 #define IA64_FIRST_STACKED_GR	32
 #define IA64_FIRST_ROTATING_FR	32
-#define SIGN_EXT9		__IA64_UL(0xffffffffffffff00)
+#define SIGN_EXT9		0xffffffffffffff00ul
 
 /*
  * For M-unit:
@@ -35,33 +53,34 @@
  * --------|------|---------|
  *     4   |   1  |    6    | = 11 bits
  * --------------------------
- * However bits [31:30] are not directly useful to distinguish between 
- * load/store so we can use [35:32] instead, which gives the following 
+ * However bits [31:30] are not directly useful to distinguish between
+ * load/store so we can use [35:32] instead, which gives the following
  * mask ([40:32]) using 9 bits. The 'e' comes from the fact that we defer
  * checking the m-bit until later in the load/store emulation.
  */
-#define IA64_OPCODE_MASK	0x1ef00000000
+#define IA64_OPCODE_MASK	0x1ef
+#define IA64_OPCODE_SHIFT	32
 
 /*
  * Table C-28 Integer Load/Store
- * 
+ *
  * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF
  *
- * ld8.fill, st8.fill  MUST be aligned because the RNATs are based on 
+ * ld8.fill, st8.fill  MUST be aligned because the RNATs are based on
  * the address (bits [8:3]), so we must failed.
  */
-#define LD_OP            0x08000000000
-#define LDS_OP           0x08100000000
-#define LDA_OP           0x08200000000
-#define LDSA_OP          0x08300000000
-#define LDBIAS_OP        0x08400000000
-#define LDACQ_OP         0x08500000000
+#define LD_OP            0x080
+#define LDS_OP           0x081
+#define LDA_OP           0x082
+#define LDSA_OP          0x083
+#define LDBIAS_OP        0x084
+#define LDACQ_OP         0x085
 /* 0x086, 0x087 are not relevant */
-#define LDCCLR_OP        0x08800000000
-#define LDCNC_OP         0x08900000000
-#define LDCCLRACQ_OP     0x08a00000000
-#define ST_OP            0x08c00000000
-#define STREL_OP         0x08d00000000
+#define LDCCLR_OP        0x088
+#define LDCNC_OP         0x089
+#define LDCCLRACQ_OP     0x08a
+#define ST_OP            0x08c
+#define STREL_OP         0x08d
 /* 0x08e,0x8f are not relevant */
 
 /*
@@ -73,38 +92,38 @@
 
 /*
  * Table C-30 Integer Load/Store +Imm
- * 
+ *
  * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF
  *
- * ld8.fill, st8.fill  must be aligned because the Nat register are based on 
+ * ld8.fill, st8.fill  must be aligned because the Nat register are based on
  * the address, so we must fail and the program must be fixed.
  */
-#define LD_IMM_OP            0x0a000000000
-#define LDS_IMM_OP           0x0a100000000
-#define LDA_IMM_OP           0x0a200000000
-#define LDSA_IMM_OP          0x0a300000000
-#define LDBIAS_IMM_OP        0x0a400000000
-#define LDACQ_IMM_OP         0x0a500000000
+#define LD_IMM_OP            0x0a0
+#define LDS_IMM_OP           0x0a1
+#define LDA_IMM_OP           0x0a2
+#define LDSA_IMM_OP          0x0a3
+#define LDBIAS_IMM_OP        0x0a4
+#define LDACQ_IMM_OP         0x0a5
 /* 0x0a6, 0xa7 are not relevant */
-#define LDCCLR_IMM_OP        0x0a800000000
-#define LDCNC_IMM_OP         0x0a900000000
-#define LDCCLRACQ_IMM_OP     0x0aa00000000
-#define ST_IMM_OP            0x0ac00000000
-#define STREL_IMM_OP         0x0ad00000000
+#define LDCCLR_IMM_OP        0x0a8
+#define LDCNC_IMM_OP         0x0a9
+#define LDCCLRACQ_IMM_OP     0x0aa
+#define ST_IMM_OP            0x0ac
+#define STREL_IMM_OP         0x0ad
 /* 0x0ae,0xaf are not relevant */
 
 /*
  * Table C-32 Floating-point Load/Store
  */
-#define LDF_OP           0x0c000000000
-#define LDFS_OP          0x0c100000000
-#define LDFA_OP          0x0c200000000
-#define LDFSA_OP         0x0c300000000
+#define LDF_OP           0x0c0
+#define LDFS_OP          0x0c1
+#define LDFA_OP          0x0c2
+#define LDFSA_OP         0x0c3
 /* 0x0c6 is irrelevant */
-#define LDFCCLR_OP       0x0c800000000
-#define LDFCNC_OP        0x0c900000000
+#define LDFCCLR_OP       0x0c8
+#define LDFCNC_OP        0x0c9
 /* 0x0cb is irrelevant  */
-#define STF_OP           0x0cc00000000
+#define STF_OP           0x0cc
 
 /*
  * Table C-33 Floating-point Load +Reg
@@ -116,17 +135,17 @@
 /*
  * Table C-34 Floating-point Load/Store +Imm
  */
-#define LDF_IMM_OP       0x0e000000000
-#define LDFS_IMM_OP      0x0e100000000
-#define LDFA_IMM_OP      0x0e200000000
-#define LDFSA_IMM_OP     0x0e300000000
+#define LDF_IMM_OP       0x0e0
+#define LDFS_IMM_OP      0x0e1
+#define LDFA_IMM_OP      0x0e2
+#define LDFSA_IMM_OP     0x0e3
 /* 0x0e6 is irrelevant */
-#define LDFCCLR_IMM_OP   0x0e800000000
-#define LDFCNC_IMM_OP    0x0e900000000
-#define STF_IMM_OP       0x0ec00000000
+#define LDFCCLR_IMM_OP   0x0e8
+#define LDFCNC_IMM_OP    0x0e9
+#define STF_IMM_OP       0x0ec
 
 typedef struct {
-	unsigned long  	 qp:6;	/* [0:5]   */
+	unsigned long	 qp:6;	/* [0:5]   */
 	unsigned long    r1:7;	/* [6:12]  */
 	unsigned long   imm:7;	/* [13:19] */
 	unsigned long    r3:7;	/* [20:26] */
@@ -170,7 +189,7 @@
 #define FR_IN_SW(x)	(fr_info[x] & 0x1)
 
 static u16 gr_info[32]={
-	0, 			/* r0 is read-only : WE SHOULD NEVER GET THIS */
+	0,			/* r0 is read-only : WE SHOULD NEVER GET THIS */
 
 	RPT(r1), RPT(r2), RPT(r3),
 
@@ -186,7 +205,7 @@
 };
 
 static u16 fr_info[32]={
-	0, 			/* constant : WE SHOULD NEVER GET THIS */
+	0,			/* constant : WE SHOULD NEVER GET THIS */
 	0,			/* constant : WE SHOULD NEVER GET THIS */
 
 	RSW(f2), RSW(f3), RSW(f4), RSW(f5),
@@ -255,162 +274,160 @@
 }
 
 static void
-set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
+set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
 {
-	struct switch_stack *sw = (struct switch_stack *)regs - 1;
-	unsigned long *kbs	= ((unsigned long *)current) + IA64_RBS_OFFSET/8;
+	struct switch_stack *sw = (struct switch_stack *) regs - 1;
+	unsigned long *bsp, *bspstore, *addr, *rnat_addr, *ubs_end;
+	unsigned long *kbs = (void *) current + IA64_RBS_OFFSET;
+	unsigned long rnats, nat_mask;
 	unsigned long on_kbs;
-	unsigned long *bsp, *bspstore, *addr, *ubs_end, *slot;
-	unsigned long rnats;
-	long nlocals;
+	long sof = (regs->cr_ifs) & 0x7f;
 
-	/*
-	 * cr_ifs=[rv:ifm], ifm=[....:sof(6)]
-	 * nlocal=number of locals (in+loc) register of the faulting function
-	 */
-	nlocals = (regs->cr_ifs) & 0x7f;
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f);
 
-	DPRINT(("sw.bsptore=%lx pt.bspstore=%lx\n", sw->ar_bspstore, regs->ar_bspstore));
-	DPRINT(("cr.ifs=%lx sof=%ld sol=%ld\n",
-		regs->cr_ifs, regs->cr_ifs &0x7f, (regs->cr_ifs>>7)&0x7f));
+	if ((r1 - 32) >= sof) {
+		/* this should never happen, as the "rsvd register fault" has higher priority */
+		DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
+		return;
+	}
 
-	on_kbs   = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore);
-	bspstore = (unsigned long *)regs->ar_bspstore;
+	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32));
+	if (addr >= kbs) {
+		/* the register is on the kernel backing store: easy... */
+		rnat_addr = ia64_rse_rnat_addr(addr);
+		if ((unsigned long) rnat_addr >= sw->ar_bspstore)
+			rnat_addr = &sw->ar_rnat;
+		nat_mask = 1UL << ia64_rse_slot_num(addr);
 
-	DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore)));
-	DPRINT(("kbs=%p nlocals=%ld\n", (void *) kbs, nlocals));
-	DPRINT(("bspstore next rnat slot %p\n",
-		(void *) ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore)));
-	DPRINT(("on_kbs=%ld rnats=%ld\n",
-		on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs));
+		*addr = val;
+		if (nat)
+			*rnat_addr |=  nat_mask;
+		else
+			*rnat_addr &= ~nat_mask;
+		return;
+	}
 
 	/*
-	 * See get_rse_reg() for an explanation on the following instructions
+	 * Avoid using user_mode() here: with "epc", we cannot use the privilege level to
+	 * infer whether the interrupt task was running on the kernel backing store.
 	 */
+	if (regs->r12 >= TASK_SIZE) {
+		DPRINT("ignoring kernel write to r%lu; register isn't on the RBS!", r1);
+		return;
+	}
+
+	bspstore = (unsigned long *) regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
-	bsp     = ia64_rse_skip_regs(ubs_end, -nlocals);
-	addr    = slot = ia64_rse_skip_regs(bsp, r1 - 32);
+	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
+	addr    = ia64_rse_skip_regs(bsp, r1 - 32);
 
-	DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n",
-		(void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr)));
+	DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
-	ia64_poke(regs, current, (unsigned long)addr, val);
+	ia64_poke(current, (unsigned long) ubs_end, (unsigned long) addr, val);
 
-	/*
-	 * addr will now contain the address of the RNAT for the register
-	 */
-	addr = ia64_rse_rnat_addr(addr);
+	rnat_addr = ia64_rse_rnat_addr(addr);
 
-	ia64_peek(regs, current, (unsigned long)addr, &rnats);
-	DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n",
-		(void *) addr, rnats, nat, rnats &ia64_rse_slot_num(slot)));
-	
-	if (nat) {
-		rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot);
-	} else {
-		rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot));
-	}
-	ia64_poke(regs, current, (unsigned long)addr, rnats);
+	ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
+	DPRINT("rnat @%p = 0x%lx nat=%d old nat=%ld\n",
+	       (void *) rnat_addr, rnats, nat, (rnats >> ia64_rse_slot_num(addr)) & 1);
 
-	DPRINT(("rnat changed to @%p = 0x%lx\n", (void *) addr, rnats));
+	nat_mask = 1UL << ia64_rse_slot_num(addr);
+	if (nat)
+		rnats |=  nat_mask;
+	else
+		rnats &= ~nat_mask;
+	ia64_poke(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats);
+
+	DPRINT("rnat changed to @%p = 0x%lx\n", (void *) rnat_addr, rnats);
 }
 
 
 static void
-get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat)
+get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat)
 {
-	struct switch_stack *sw = (struct switch_stack *)regs - 1;
-	unsigned long *kbs	= (unsigned long *)current + IA64_RBS_OFFSET/8;
+	struct switch_stack *sw = (struct switch_stack *) regs - 1;
+	unsigned long *bsp, *addr, *rnat_addr, *ubs_end, *bspstore;
+	unsigned long *kbs = (void *) current + IA64_RBS_OFFSET;
+	unsigned long rnats, nat_mask;
 	unsigned long on_kbs;
-	long nlocals;
-	unsigned long *bsp, *addr, *ubs_end, *slot, *bspstore;
-	unsigned long rnats;
+	long sof = (regs->cr_ifs) & 0x7f;
 
-	/*
-	 * cr_ifs=[rv:ifm], ifm=[....:sof(6)]
-	 * nlocals=number of local registers in the faulting function
-	 */
-	nlocals = (regs->cr_ifs) & 0x7f;
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f);
 
-	/*
-	 * save_switch_stack does a flushrs and saves bspstore.
-	 * on_kbs = actual number of registers saved on kernel backing store
-	 *          (taking into accound potential RNATs)
-	 *
-	 * Note that this number can be greater than nlocals if the dirty
-	 * parititions included more than one stack frame at the time we
-	 * switched to KBS
-	 */
-	on_kbs   = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore);
-	bspstore = (unsigned long *)regs->ar_bspstore;
+	if ((r1 - 32) >= sof) {
+		/* this should never happen, as the "rsvd register fault" has higher priority */
+		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+		return;
+	}
+
+	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32));
+	if (addr >= kbs) {
+		/* the register is on the kernel backing store: easy... */
+		*val = *addr;
+		if (nat) {
+			rnat_addr = ia64_rse_rnat_addr(addr);
+			if ((unsigned long) rnat_addr >= sw->ar_bspstore)
+				rnat_addr = &sw->ar_rnat;
+			nat_mask = 1UL << ia64_rse_slot_num(addr);
+			*nat = (*rnat_addr & nat_mask) != 0;
+		}
+		return;
+	}
 
 	/*
-	 * To simplify the logic, we calculate everything as if there was only
-	 * one backing store i.e., the user one (UBS). We let it to peek/poke
-	 * to figure out whether the register we're looking for really is
-	 * on the UBS or on KBS.
-	 *
-	 * regs->ar_bsptore = address of last register saved on UBS (before switch)
-	 *
-	 * ubs_end = virtual end of the UBS (if everything had been spilled there)
-	 *
-	 * We know that ubs_end is the point where the last register on the
-	 * stack frame we're interested in as been saved. So we need to walk
-	 * our way backward to figure out what the BSP "was" for that frame,
-	 * this will give us the location of r32. 
-	 *
-	 * bsp = "virtual UBS" address of r32 for our frame
-	 *
-	 * Finally, get compute the address of the register we're looking for
-	 * using bsp as our base (move up again).
-	 *
-	 * Please note that in our case, we know that the register is necessarily
-	 * on the KBS because we are only interested in the current frame at the moment
-	 * we got the exception i.e., bsp is not changed until we switch to KBS.
+	 * Avoid using user_mode() here: with "epc", we cannot use the privilege level to
+	 * infer whether the interrupt task was running on the kernel backing store.
 	 */
+	if (regs->r12 >= TASK_SIZE) {
+		DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
+		return;
+	}
+
+	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
-	bsp     = ia64_rse_skip_regs(ubs_end, -nlocals);
-	addr    = slot = ia64_rse_skip_regs(bsp, r1 - 32);
+	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
+	addr    = ia64_rse_skip_regs(bsp, r1 - 32);
 
-	DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n",
-		(void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr)));
-	
-	ia64_peek(regs, current, (unsigned long)addr, val);
+	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
-	/*
-	 * addr will now contain the address of the RNAT for the register
-	 */
-	addr = ia64_rse_rnat_addr(addr);
+	ia64_peek(current, (unsigned long) ubs_end, (unsigned long) addr, val);
 
-	ia64_peek(regs, current, (unsigned long)addr, &rnats);
-	DPRINT(("rnat @%p = 0x%lx\n", (void *) addr, rnats));
-	
-	if (nat)
-		*nat = rnats >> ia64_rse_slot_num(slot) & 0x1;
+	if (nat) {
+		rnat_addr = ia64_rse_rnat_addr(addr);
+		nat_mask = 1UL << ia64_rse_slot_num(addr);
+
+		DPRINT("rnat @%p = 0x%lx\n", (void *) rnat_addr, rnats);
+
+		ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
+		*nat = (rnats & nat_mask) != 0;
+	}
 }
 
 
 static void
-setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs)
+setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs)
 {
-	struct switch_stack *sw = (struct switch_stack *)regs -1;
+	struct switch_stack *sw = (struct switch_stack *) regs - 1;
 	unsigned long addr;
 	unsigned long bitmask;
 	unsigned long *unat;
 
-
 	/*
 	 * First takes care of stacked registers
 	 */
- 	if (regnum >= IA64_FIRST_STACKED_GR) {
+	if (regnum >= IA64_FIRST_STACKED_GR) {
 		set_rse_reg(regs, regnum, val, nat);
 		return;
 	}
 
 	/*
-	 * Using r0 as a target raises a General Exception fault which has 
-	 * higher priority than the Unaligned Reference fault.
-	 */ 
+	 * Using r0 as a target raises a General Exception fault which has higher priority
+	 * than the Unaligned Reference fault.
+	 */
 
 	/*
 	 * Now look at registers in [0-31] range and init correct UNAT
@@ -422,8 +439,8 @@
 		addr = (unsigned long)regs;
 		unat = &sw->caller_unat;
 	}
-	DPRINT(("tmp_base=%lx switch_stack=%s offset=%d\n",
-		addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum)));
+	DPRINT("tmp_base=%lx switch_stack=%s offset=%d\n",
+	       addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum));
 	/*
 	 * add offset from base of struct
 	 * and do it !
@@ -436,20 +453,20 @@
 	 * We need to clear the corresponding UNAT bit to fully emulate the load
 	 * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4
 	 */
-	bitmask   = __IA64_UL(1) << (addr >> 3 & 0x3f);
-	DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat));
+	bitmask   = 1UL << (addr >> 3 & 0x3f);
+	DPRINT("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat);
 	if (nat) {
 		*unat |= bitmask;
 	} else {
 		*unat &= ~bitmask;
 	}
-	DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat));
+	DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
 }
 
 #define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
 
 static void
-setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
+setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
 {
 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
 	unsigned long addr;
@@ -465,7 +482,7 @@
 	 *
 	 * For now, we are using approach (1).
 	 */
- 	if (regnum >= IA64_FIRST_ROTATING_FR) {
+	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_sync_fph(current);
 		current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval;
 	} else {
@@ -477,18 +494,18 @@
 		} else {
 			addr = (unsigned long)regs;
 		}
-		
-		DPRINT(("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum)));
+
+		DPRINT("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum));
 
 		addr += FR_OFFS(regnum);
 		*(struct ia64_fpreg *)addr = *fpval;
 
 		/*
-	 	 * mark the low partition as being used now
+		 * mark the low partition as being used now
 		 *
 		 * It is highly unlikely that this bit is not already set, but
 		 * let's do it for safety.
-	 	 */
+		 */
 		regs->cr_ipsr |= IA64_PSR_MFL;
 	}
 }
@@ -497,40 +514,40 @@
  * Those 2 inline functions generate the spilled versions of the constant floating point
  * registers which can be used with stfX
  */
-static inline void 
-float_spill_f0(struct ia64_fpreg *final)
+static inline void
+float_spill_f0 (struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("stf.spill [%0]=f0" :: "r"(final) : "memory");
 }
 
-static inline void 
-float_spill_f1(struct ia64_fpreg *final)
+static inline void
+float_spill_f1 (struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("stf.spill [%0]=f1" :: "r"(final) : "memory");
 }
 
 static void
-getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
+getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
 {
-	struct switch_stack *sw = (struct switch_stack *)regs -1;
+	struct switch_stack *sw = (struct switch_stack *) regs - 1;
 	unsigned long addr;
 
 	/*
-	 * From EAS-2.5: FPDisableFault has higher priority than 
-	 * Unaligned Fault. Thus, when we get here, we know the partition is 
+	 * From EAS-2.5: FPDisableFault has higher priority than
+	 * Unaligned Fault. Thus, when we get here, we know the partition is
 	 * enabled.
 	 *
 	 * When regnum > 31, the register is still live and we need to force a save
 	 * to current->thread.fph to get access to it.  See discussion in setfpreg()
 	 * for reasons and other ways of doing this.
 	 */
- 	if (regnum >= IA64_FIRST_ROTATING_FR) {
+	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_flush_fph(current);
 		*fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
 	} else {
 		/*
 		 * f0 = 0.0, f1= 1.0. Those registers are constant and are thus
-	 	 * not saved, we must generate their spilled form on the fly
+		 * not saved, we must generate their spilled form on the fly
 		 */
 		switch(regnum) {
 		case 0:
@@ -546,8 +563,8 @@
 			addr =  FR_IN_SW(regnum) ? (unsigned long)sw
 						 : (unsigned long)regs;
 
-			DPRINT(("is_sw=%d tmp_base=%lx offset=0x%x\n",
-				FR_IN_SW(regnum), addr, FR_OFFS(regnum)));
+			DPRINT("is_sw=%d tmp_base=%lx offset=0x%x\n",
+			       FR_IN_SW(regnum), addr, FR_OFFS(regnum));
 
 			addr  += FR_OFFS(regnum);
 			*fpval = *(struct ia64_fpreg *)addr;
@@ -557,12 +574,12 @@
 
 
 static void
-getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs)
+getreg (unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs)
 {
-	struct switch_stack *sw = (struct switch_stack *)regs -1;
+	struct switch_stack *sw = (struct switch_stack *) regs - 1;
 	unsigned long addr, *unat;
 
- 	if (regnum >= IA64_FIRST_STACKED_GR) {
+	if (regnum >= IA64_FIRST_STACKED_GR) {
 		get_rse_reg(regs, regnum, val, nat);
 		return;
 	}
@@ -588,7 +605,7 @@
 		unat = &sw->caller_unat;
 	}
 
-	DPRINT(("addr_base=%lx offset=0x%x\n", addr,  GR_OFFS(regnum)));
+	DPRINT("addr_base=%lx offset=0x%x\n", addr,  GR_OFFS(regnum));
 
 	addr += GR_OFFS(regnum);
 
@@ -602,16 +619,16 @@
 }
 
 static void
-emulate_load_updates(update_t type, load_store_t *ld, struct pt_regs *regs, unsigned long ifa)
-{		
+emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsigned long ifa)
+{
 	/*
-	 * IMPORTANT: 
+	 * IMPORTANT:
 	 * Given the way we handle unaligned speculative loads, we should
 	 * not get to this point in the code but we keep this sanity check,
 	 * just in case.
 	 */
-	if (ld->x6_op == 1 || ld->x6_op == 3) {
-		printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n");	
+	if (ld.x6_op == 1 || ld.x6_op == 3) {
+		printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n");
 		die_if_kernel("unaligned reference on specualtive load with register update\n",
 			      regs, 30);
 	}
@@ -624,18 +641,18 @@
 	if (type == UPD_IMMEDIATE) {
 		unsigned long imm;
 
-		/* 
-	 	 * Load +Imm: ldXZ r1=[r3],imm(9)
-	 	 *
+		/*
+		 * Load +Imm: ldXZ r1=[r3],imm(9)
+		 *
 		 *
-	   	 * form imm9: [13:19] contain the first 7 bits
-      		 */		 
-		imm = ld->x << 7 | ld->imm;
+		 * form imm9: [13:19] contain the first 7 bits
+		 */
+		imm = ld.x << 7 | ld.imm;
 
 		/*
 		 * sign extend (1+8bits) if m set
 		 */
-		if (ld->m) imm |= SIGN_EXT9;
+		if (ld.m) imm |= SIGN_EXT9;
 
 		/*
 		 * ifa == r3 and we know that the NaT bit on r3 was clear so
@@ -643,109 +660,79 @@
 		 */
 		ifa += imm;
 
-		setreg(ld->r3, ifa, 0, regs);
+		setreg(ld.r3, ifa, 0, regs);
 
-		DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa));
+		DPRINT("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld.x, ld.m, imm, ifa);
 
-	} else if (ld->m) {
+	} else if (ld.m) {
 		unsigned long r2;
 		int nat_r2;
 
 		/*
 		 * Load +Reg Opcode: ldXZ r1=[r3],r2
 		 *
-		 * Note: that we update r3 even in the case of ldfX.a 
+		 * Note: that we update r3 even in the case of ldfX.a
 		 * (where the load does not happen)
 		 *
 		 * The way the load algorithm works, we know that r3 does not
 		 * have its NaT bit set (would have gotten NaT consumption
-		 * before getting the unaligned fault). So we can use ifa 
+		 * before getting the unaligned fault). So we can use ifa
 		 * which equals r3 at this point.
 		 *
 		 * IMPORTANT:
-	 	 * The above statement holds ONLY because we know that we
+		 * The above statement holds ONLY because we know that we
 		 * never reach this code when trying to do a ldX.s.
-		 * If we ever make it to here on an ldfX.s then 
+		 * If we ever make it to here on an ldfX.s then
 		 */
-		getreg(ld->imm, &r2, &nat_r2, regs);
-		
+		getreg(ld.imm, &r2, &nat_r2, regs);
+
 		ifa += r2;
-		
+
 		/*
 		 * propagate Nat r2 -> r3
 		 */
-		setreg(ld->r3, ifa, nat_r2, regs);
+		setreg(ld.r3, ifa, nat_r2, regs);
 
-		DPRINT(("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld->imm, r2, ifa, nat_r2));
+		DPRINT("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld.imm, r2, ifa, nat_r2);
 	}
 }
 
 
 static int
-emulate_load_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
-	unsigned long val;
-	unsigned int len = 1<< ld->x6_sz;
-
-	/*
-	 * the macro supposes sequential access (which is the case)
-	 * if the first byte is an invalid address we return here. Otherwise
-	 * there is a guard page at the top of the user's address page and 
-	 * the first access would generate a NaT consumption fault and return
-	 * with a SIGSEGV, which is what we want.
-	 *
-	 * Note: the first argument is ignored 
-	 */
-	if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {
-		DPRINT(("verify area failed on %lx\n", ifa));
-		return -1;
-	}
+	unsigned int len = 1 << ld.x6_sz;
 
 	/*
 	 * r0, as target, doesn't need to be checked because Illegal Instruction
 	 * faults have higher priority than unaligned faults.
 	 *
-	 * r0 cannot be found as the base as it would never generate an 
+	 * r0 cannot be found as the base as it would never generate an
 	 * unaligned reference.
 	 */
 
 	/*
-	 * ldX.a we don't try to emulate anything but we must
-	 * invalidate the ALAT entry.
+	 * ldX.a we don't try to emulate anything but we must invalidate the ALAT entry.
 	 * See comment below for explanation on how we handle ldX.a
 	 */
-	if (ld->x6_op != 0x2) {
-		/*
-		 * we rely on the macros in unaligned.h for now i.e.,
-		 * we let the compiler figure out how to read memory gracefully.
-		 *
-		 * We need this switch/case because the way the inline function
-		 * works. The code is optimized by the compiler and looks like
-		 * a single switch/case.
-		 */
-		switch(len) {
-			case 2:
-				val = ia64_get_unaligned((void *)ifa, 2);
-				break;
-			case 4:
-				val = ia64_get_unaligned((void *)ifa, 4);
-				break;
-			case 8:
-				val = ia64_get_unaligned((void *)ifa, 8);
-				break;
-			default:
-				DPRINT(("unknown size: x6=%d\n", ld->x6_sz));
-				return -1;
-		}
+	if (ld.x6_op != 0x2) {
+		unsigned long val = 0;
 
-		setreg(ld->r1, val, 0, regs);
+		if (len != 2 && len != 4 && len != 8) {
+			DPRINT("unknown size: x6=%d\n", ld.x6_sz);
+			return -1;
+		}
+		/* this assumes little-endian byte-order: */
+		if (copy_from_user(&val, (void *) ifa, len))
+		    return -1;
+		setreg(ld.r1, val, 0, regs);
 	}
 
 	/*
 	 * check for updates on any kind of loads
 	 */
-	if (ld->op == 0x5 || ld->m)
-		emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
+	if (ld.op == 0x5 || ld.m)
+		emulate_load_updates(ld.op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
 
 	/*
 	 * handling of various loads (based on EAS2.4):
@@ -753,7 +740,6 @@
 	 * ldX.acq (ordered load):
 	 *	- acquire semantics would have been used, so force fence instead.
 	 *
-	 *
 	 * ldX.c.clr (check load and clear):
 	 *	- if we get to this handler, it's because the entry was not in the ALAT.
 	 *	  Therefore the operation reverts to a normal load
@@ -764,15 +750,15 @@
 	 * ldX.c.clr.acq (ordered check load and clear):
 	 *	- same as above for c.clr part. The load needs to have acquire semantics. So
 	 *	  we use the fence semantics which is stronger and thus ensures correctness.
-	 *	
+	 *
 	 * ldX.a (advanced load):
-	 *	- suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the 
-	 * 	  address doesn't match requested size alignement. This means that we would 
+	 *	- suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the
+	 *	  address doesn't match requested size alignement. This means that we would
 	 *	  possibly need more than one load to get the result.
 	 *
 	 *	  The load part can be handled just like a normal load, however the difficult
 	 *	  part is to get the right thing into the ALAT. The critical piece of information
-	 * 	  in the base address of the load & size. To do that, a ld.a must be executed,
+	 *	  in the base address of the load & size. To do that, a ld.a must be executed,
 	 *	  clearly any address can be pushed into the table by using ld1.a r1=[r3]. Now
 	 *	  if we use the same target register, we will be okay for the check.a instruction.
 	 *	  If we look at the store, basically a stX [r3]=r1 checks the ALAT  for any entry
@@ -791,7 +777,7 @@
 	 *		store & shift to temporary;
 	 *		ld1.a r1=[r3]
 	 *		store & shift to temporary;
-	 * 		r1=temporary
+	 *		r1=temporary
 	 *
 	 *	  So int this case, you would get the right value is r1 but the wrong info in
 	 *	  the ALAT.  Notice that you could do it in reverse to finish with address 3
@@ -815,7 +801,7 @@
 	 *	  So it's okay NOT to do any actual load on an unaligned ld.a. However the ALAT
 	 *	  must be invalidated for the register (so that's chck.a.*,ld.c.* don't pick up
 	 *	  a stale entry later) The register base update MUST also be performed.
-	 *	  
+	 *
 	 *	  Now what is the content of the register and its NaT bit in the case we don't
 	 *	  do the load ?  EAS2.4, says (in case an actual load is needed)
 	 *
@@ -828,40 +814,26 @@
 	 */
 
 	/*
-	 * when the load has the .acq completer then 
+	 * when the load has the .acq completer then
 	 * use ordering fence.
 	 */
-	if (ld->x6_op == 0x5 || ld->x6_op == 0xa)
+	if (ld.x6_op == 0x5 || ld.x6_op == 0xa)
 		mb();
 
 	/*
 	 * invalidate ALAT entry in case of advanced load
 	 */
-	if (ld->x6_op == 0x2)
-		invala_gr(ld->r1);
+	if (ld.x6_op == 0x2)
+		invala_gr(ld.r1);
 
 	return 0;
 }
 
 static int
-emulate_store_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
 	unsigned long r2;
-	unsigned int len = 1<< ld->x6_sz;
-	
-	/*
-	 * the macro supposes sequential access (which is the case)
-	 * if the first byte is an invalid address we return here. Otherwise
-	 * there is a guard page at the top of the user's address page and 
-	 * the first access would generate a NaT consumption fault and return
-	 * with a SIGSEGV, which is what we want.
-	 *
-	 * Note: the first argument is ignored 
-	 */
-	if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {
-		DPRINT(("verify area failed on %lx\n",ifa));
-		return -1;
-	}
+	unsigned int len = 1 << ld.x6_sz;
 
 	/*
 	 * if we get to this handler, Nat bits on both r3 and r2 have already
@@ -869,7 +841,7 @@
 	 *
 	 * extract the value to be stored
 	 */
-	getreg(ld->imm, &r2, 0, regs);
+	getreg(ld.imm, &r2, 0, regs);
 
 	/*
 	 * we rely on the macros in unaligned.h for now i.e.,
@@ -879,48 +851,43 @@
 	 * works. The code is optimized by the compiler and looks like
 	 * a single switch/case.
 	 */
-	DPRINT(("st%d [%lx]=%lx\n", len, ifa, r2));
+	DPRINT("st%d [%lx]=%lx\n", len, ifa, r2);
 
-	switch(len) {
-		case 2:
-			ia64_put_unaligned(r2, (void *)ifa, 2);
-			break;
-		case 4:
-			ia64_put_unaligned(r2, (void *)ifa, 4);
-			break;
-		case 8:
-			ia64_put_unaligned(r2, (void *)ifa, 8);
-			break;
-		default:
-			DPRINT(("unknown size: x6=%d\n", ld->x6_sz));
-			return -1;
+	if (len != 2 && len != 4 && len != 8) {
+		DPRINT("unknown size: x6=%d\n", ld.x6_sz);
+		return -1;
 	}
+
+	/* this assumes little-endian byte-order: */
+	if (copy_to_user((void *) ifa, &r2, len))
+		return -1;
+
 	/*
 	 * stX [r3]=r2,imm(9)
 	 *
 	 * NOTE:
-	 * ld->r3 can never be r0, because r0 would not generate an 
+	 * ld.r3 can never be r0, because r0 would not generate an
 	 * unaligned access.
 	 */
-	if (ld->op == 0x5) {
+	if (ld.op == 0x5) {
 		unsigned long imm;
 
 		/*
 		 * form imm9: [12:6] contain first 7bits
 		 */
-		imm = ld->x << 7 | ld->r1;
+		imm = ld.x << 7 | ld.r1;
 		/*
 		 * sign extend (8bits) if m set
 		 */
-		if (ld->m) imm |= SIGN_EXT9; 
+		if (ld.m) imm |= SIGN_EXT9;
 		/*
 		 * ifa == r3 (NaT is necessarily cleared)
 		 */
 		ifa += imm;
 
-		DPRINT(("imm=%lx r3=%lx\n", imm, ifa));
-	
-		setreg(ld->r3, ifa, 0, regs);
+		DPRINT("imm=%lx r3=%lx\n", imm, ifa);
+
+		setreg(ld.r3, ifa, 0, regs);
 	}
 	/*
 	 * we don't have alat_invalidate_multiple() so we need
@@ -931,7 +898,7 @@
 	/*
 	 * stX.rel: use fence instead of release
 	 */
-	if (ld->x6_op == 0xd)
+	if (ld.x6_op == 0xd)
 		mb();
 
 	return 0;
@@ -940,120 +907,108 @@
 /*
  * floating point operations sizes in bytes
  */
-static const unsigned short float_fsz[4]={
+static const unsigned char float_fsz[4]={
 	16, /* extended precision (e) */
 	8,  /* integer (8)            */
 	4,  /* single precision (s)   */
 	8   /* double precision (d)   */
 };
 
-static inline void 
-mem2float_extended(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+mem2float_extended (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldfe f6=[%0];; stf.spill [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-mem2float_integer(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+mem2float_integer (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldf8 f6=[%0];; stf.spill [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-mem2float_single(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+mem2float_single (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldfs f6=[%0];; stf.spill [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-mem2float_double(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+mem2float_double (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldfd f6=[%0];; stf.spill [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-float2mem_extended(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+float2mem_extended (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldf.fill f6=[%0];; stfe [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-float2mem_integer(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+float2mem_integer (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldf.fill f6=[%0];; stf8 [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-float2mem_single(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+float2mem_single (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldf.fill f6=[%0];; stfs [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
-static inline void 
-float2mem_double(struct ia64_fpreg *init, struct ia64_fpreg *final)
+static inline void
+float2mem_double (struct ia64_fpreg *init, struct ia64_fpreg *final)
 {
 	__asm__ __volatile__ ("ldf.fill f6=[%0];; stfd [%1]=f6"
 			      :: "r"(init), "r"(final) : "f6","memory");
 }
 
 static int
-emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
 	struct ia64_fpreg fpr_init[2];
 	struct ia64_fpreg fpr_final[2];
-	unsigned long len = float_fsz[ld->x6_sz];
+	unsigned long len = float_fsz[ld.x6_sz];
 
-	if (access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0) {
-		DPRINT(("verify area failed on %lx\n", ifa));
-		return -1;
-	}
 	/*
 	 * fr0 & fr1 don't need to be checked because Illegal Instruction
 	 * faults have higher priority than unaligned faults.
 	 *
-	 * r0 cannot be found as the base as it would never generate an 
+	 * r0 cannot be found as the base as it would never generate an
 	 * unaligned reference.
 	 */
 
-	/* 
+	/*
 	 * make sure we get clean buffers
 	 */
-	memset(&fpr_init,0, sizeof(fpr_init));
-	memset(&fpr_final,0, sizeof(fpr_final));
+	memset(&fpr_init, 0, sizeof(fpr_init));
+	memset(&fpr_final, 0, sizeof(fpr_final));
 
 	/*
 	 * ldfpX.a: we don't try to emulate anything but we must
 	 * invalidate the ALAT entry and execute updates, if any.
 	 */
-	if (ld->x6_op != 0x2) {
-		/*
-		 * does the unaligned access
-		 */
-		memcpy(&fpr_init[0], (void *)ifa, len);
-		memcpy(&fpr_init[1], (void *)(ifa+len), len);
+	if (ld.x6_op != 0x2) {
+		/* this assumes little-endian byte-order: */
 
-		DPRINT(("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld->r1, ld->imm, ld->x6_sz));
-#ifdef DEBUG_UNALIGNED_TRAP
-		{ int i; char *c = (char *)&fpr_init;
-			printk("fpr_init= ");
-			for(i=0; i < len<<1; i++ ) {
-				printk("%02x ", c[i]&0xff);
-			}
-			printk("\n");
-		}
-#endif
+		if (copy_from_user(&fpr_init[0], (void *) ifa, len)
+		    || copy_from_user(&fpr_init[1], (void *) (ifa + len), len))
+			return -1;
+
+		DPRINT("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld.r1, ld.imm, ld.x6_sz);
+		DDUMP("frp_init =", &fpr_init, 2*len);
 		/*
 		 * XXX fixme
-		 * Could optimize inlines by using ldfpX & 2 spills 
+		 * Could optimize inlines by using ldfpX & 2 spills
 		 */
-		switch( ld->x6_sz ) {
+		switch( ld.x6_sz ) {
 			case 0:
 				mem2float_extended(&fpr_init[0], &fpr_final[0]);
 				mem2float_extended(&fpr_init[1], &fpr_final[1]);
@@ -1071,15 +1026,7 @@
 				mem2float_double(&fpr_init[1], &fpr_final[1]);
 				break;
 		}
-#ifdef DEBUG_UNALIGNED_TRAP
-		{ int i; char *c = (char *)&fpr_final;
-			printk("fpr_final= ");
-			for(i=0; i < len<<1; i++ ) {
-				printk("%02x ", c[i]&0xff);
-			}
-			printk("\n");
-		}
-#endif
+		DDUMP("fpr_final =", &fpr_final, 2*len);
 		/*
 		 * XXX fixme
 		 *
@@ -1087,16 +1034,15 @@
 		 * use the storage from the saved context i.e., the actual final
 		 * destination (pt_regs, switch_stack or thread structure).
 		 */
-		setfpreg(ld->r1, &fpr_final[0], regs);
-		setfpreg(ld->imm, &fpr_final[1], regs);
+		setfpreg(ld.r1, &fpr_final[0], regs);
+		setfpreg(ld.imm, &fpr_final[1], regs);
 	}
 
 	/*
 	 * Check for updates: only immediate updates are available for this
 	 * instruction.
 	 */
-	if (ld->m) {
-
+	if (ld.m) {
 		/*
 		 * the immediate is implicit given the ldsz of the operation:
 		 * single: 8 (2x4) and for  all others it's 16 (2x8)
@@ -1104,57 +1050,45 @@
 		ifa += len<<1;
 
 		/*
-		 * IMPORTANT: 
+		 * IMPORTANT:
 		 * the fact that we force the NaT of r3 to zero is ONLY valid
 		 * as long as we don't come here with a ldfpX.s.
 		 * For this reason we keep this sanity check
 		 */
-		if (ld->x6_op == 1 || ld->x6_op == 3) {
-			printk(KERN_ERR "%s: register update on speculative load pair, error\n",
-			       __FUNCTION__);	
-		}
-
+		if (ld.x6_op == 1 || ld.x6_op == 3)
+			printk(KERN_ERR __FUNCTION__": register update on speculative load pair, "
+			       "error\n");
 
-		setreg(ld->r3, ifa, 0, regs);
+		setreg(ld.r3, ifa, 0, regs);
 	}
 
 	/*
 	 * Invalidate ALAT entries, if any, for both registers.
 	 */
-	if (ld->x6_op == 0x2) {
-		invala_fr(ld->r1);
-		invala_fr(ld->imm);
+	if (ld.x6_op == 0x2) {
+		invala_fr(ld.r1);
+		invala_fr(ld.imm);
 	}
 	return 0;
 }
 
 
 static int
-emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_load_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
 	struct ia64_fpreg fpr_init;
 	struct ia64_fpreg fpr_final;
-	unsigned long len = float_fsz[ld->x6_sz];
+	unsigned long len = float_fsz[ld.x6_sz];
 
 	/*
-	 * check for load pair because our masking scheme is not fine grain enough
-	if (ld->x == 1) return emulate_load_floatpair(ifa,ld,regs);
-	 */
-
-	if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {
-		DPRINT(("verify area failed on %lx\n", ifa));
-		return -1;
-	}
-	/*
 	 * fr0 & fr1 don't need to be checked because Illegal Instruction
 	 * faults have higher priority than unaligned faults.
 	 *
-	 * r0 cannot be found as the base as it would never generate an 
+	 * r0 cannot be found as the base as it would never generate an
 	 * unaligned reference.
 	 */
 
-
-	/* 
+	/*
 	 * make sure we get clean buffers
 	 */
 	memset(&fpr_init,0, sizeof(fpr_init));
@@ -1165,27 +1099,16 @@
 	 * invalidate the ALAT entry.
 	 * See comments in ldX for descriptions on how the various loads are handled.
 	 */
-	if (ld->x6_op != 0x2) {
-
-		/*
-		 * does the unaligned access
-		 */
-		memcpy(&fpr_init, (void *)ifa, len);
+	if (ld.x6_op != 0x2) {
+		if (copy_from_user(&fpr_init, (void *) ifa, len))
+			return -1;
 
-		DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz));
-#ifdef DEBUG_UNALIGNED_TRAP
-		{ int i; char *c = (char *)&fpr_init;
-			printk("fpr_init= ");
-			for(i=0; i < len; i++ ) {
-				printk("%02x ", c[i]&0xff);
-			}
-			printk("\n");
-		}
-#endif
+		DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz);
+		DDUMP("fpr_init =", &fpr_init, len);
 		/*
 		 * we only do something for x6_op={0,8,9}
 		 */
-		switch( ld->x6_sz ) {
+		switch( ld.x6_sz ) {
 			case 0:
 				mem2float_extended(&fpr_init, &fpr_final);
 				break;
@@ -1199,15 +1122,7 @@
 				mem2float_double(&fpr_init, &fpr_final);
 				break;
 		}
-#ifdef DEBUG_UNALIGNED_TRAP
-		{ int i; char *c = (char *)&fpr_final;
-			printk("fpr_final= ");
-			for(i=0; i < len; i++ ) {
-				printk("%02x ", c[i]&0xff);
-			}
-			printk("\n");
-		}
-#endif
+		DDUMP("fpr_final =", &fpr_final, len);
 		/*
 		 * XXX fixme
 		 *
@@ -1215,66 +1130,51 @@
 		 * use the storage from the saved context i.e., the actual final
 		 * destination (pt_regs, switch_stack or thread structure).
 		 */
-		setfpreg(ld->r1, &fpr_final, regs);
+		setfpreg(ld.r1, &fpr_final, regs);
 	}
 
 	/*
 	 * check for updates on any loads
 	 */
-	if (ld->op == 0x7 || ld->m)
-		emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
+	if (ld.op == 0x7 || ld.m)
+		emulate_load_updates(ld.op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
 
 	/*
 	 * invalidate ALAT entry in case of advanced floating point loads
 	 */
-	if (ld->x6_op == 0x2)
-		invala_fr(ld->r1);
+	if (ld.x6_op == 0x2)
+		invala_fr(ld.r1);
 
 	return 0;
 }
 
 
 static int
-emulate_store_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_store_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
 	struct ia64_fpreg fpr_init;
 	struct ia64_fpreg fpr_final;
-	unsigned long len = float_fsz[ld->x6_sz];
-	
-	/*
-	 * the macro supposes sequential access (which is the case)
-	 * if the first byte is an invalid address we return here. Otherwise
-	 * there is a guard page at the top of the user's address page and 
-	 * the first access would generate a NaT consumption fault and return
-	 * with a SIGSEGV, which is what we want.
-	 *
-	 * Note: the first argument is ignored 
-	 */
-	if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {
-		DPRINT(("verify area failed on %lx\n",ifa));
-		return -1;
-	}
+	unsigned long len = float_fsz[ld.x6_sz];
 
-	/* 
+	/*
 	 * make sure we get clean buffers
 	 */
 	memset(&fpr_init,0, sizeof(fpr_init));
 	memset(&fpr_final,0, sizeof(fpr_final));
 
-
 	/*
 	 * if we get to this handler, Nat bits on both r3 and r2 have already
 	 * been checked. so we don't need to do it
 	 *
 	 * extract the value to be stored
 	 */
-	getfpreg(ld->imm, &fpr_init, regs);
+	getfpreg(ld.imm, &fpr_init, regs);
 	/*
 	 * during this step, we extract the spilled registers from the saved
 	 * context i.e., we refill. Then we store (no spill) to temporary
 	 * aligned location
 	 */
-	switch( ld->x6_sz ) {
+	switch( ld.x6_sz ) {
 		case 0:
 			float2mem_extended(&fpr_init, &fpr_final);
 			break;
@@ -1288,56 +1188,40 @@
 			float2mem_double(&fpr_init, &fpr_final);
 			break;
 	}
-	DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz));
-#ifdef DEBUG_UNALIGNED_TRAP
-		{ int i; char *c = (char *)&fpr_init;
-			printk("fpr_init= ");
-			for(i=0; i < len; i++ ) {
-				printk("%02x ", c[i]&0xff);
-			}
-			printk("\n");
-		}
-		{ int i; char *c = (char *)&fpr_final;
-			printk("fpr_final= ");
-			for(i=0; i < len; i++ ) {
-				printk("%02x ", c[i]&0xff);
-			}
-			printk("\n");
-		}
-#endif
+	DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz);
+	DDUMP("fpr_init =", &fpr_init, len);
+	DDUMP("fpr_final =", &fpr_final, len);
 
-	/*
-	 * does the unaligned store
-	 */
-	memcpy((void *)ifa, &fpr_final, len);
+	if (copy_to_user((void *) ifa, &fpr_final, len))
+		return -1;
 
 	/*
 	 * stfX [r3]=r2,imm(9)
 	 *
 	 * NOTE:
-	 * ld->r3 can never be r0, because r0 would not generate an 
+	 * ld.r3 can never be r0, because r0 would not generate an
 	 * unaligned access.
 	 */
-	if (ld->op == 0x7) {
+	if (ld.op == 0x7) {
 		unsigned long imm;
 
 		/*
 		 * form imm9: [12:6] contain first 7bits
 		 */
-		imm = ld->x << 7 | ld->r1;
+		imm = ld.x << 7 | ld.r1;
 		/*
 		 * sign extend (8bits) if m set
 		 */
-		if (ld->m)
-			imm |= SIGN_EXT9; 
+		if (ld.m)
+			imm |= SIGN_EXT9;
 		/*
 		 * ifa == r3 (NaT is necessarily cleared)
 		 */
 		ifa += imm;
 
-		DPRINT(("imm=%lx r3=%lx\n", imm, ifa));
-	
-		setreg(ld->r3, ifa, 0, regs);
+		DPRINT("imm=%lx r3=%lx\n", imm, ifa);
+
+		setreg(ld.r3, ifa, 0, regs);
 	}
 	/*
 	 * we don't have alat_invalidate_multiple() so we need
@@ -1348,132 +1232,106 @@
 	return 0;
 }
 
-void
-ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs)
+/*
+ * Make sure we log the unaligned access, so that user/sysadmin can notice it and
+ * eventually fix the program.  However, we don't want to do that for every access so we
+ * pace it with jiffies.  This isn't really MP-safe, but it doesn't really have to be
+ * either...
+ */
+static int
+within_logging_rate_limit (void)
 {
-	static unsigned long unalign_count;
-	static long last_time;
+	static unsigned long count, last_time;
 
+	if (jiffies - last_time > 5*HZ)
+		count = 0;
+	if (++count < 5) {
+		last_time = jiffies;
+		return 1;
+	}
+	return 0;
+
+}
+
+void
+ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
+{
+	struct exception_fixup fix = { 0 };
 	struct ia64_psr *ipsr = ia64_psr(regs);
-	unsigned long *bundle_addr;
+	mm_segment_t old_fs = get_fs();
+	unsigned long bundle[2];
 	unsigned long opcode;
-	unsigned long op;
-	load_store_t *insn;
+	struct siginfo si;
+	union {
+		unsigned long l;
+		load_store_t insn;
+	} u;
 	int ret = -1;
 
+	if (ia64_psr(regs)->be) {
+		/* we don't support big-endian accesses */
+		die_if_kernel("big-endian unaligned accesses are not supported", regs, 0);
+		goto force_sigbus;
+	}
+
 	/*
-	 * Unaligned references in the kernel could come from unaligned
-	 *   arguments to system calls.  We fault the user process in
-	 *   these cases and panic the kernel otherwise (the kernel should
-	 *   be fixed to not make unaligned accesses).
+	 * Treat kernel accesses for which there is an exception handler entry the same as
+	 * user-level unaligned accesses.  Otherwise, a clever program could trick this
+	 * handler into reading an arbitrary kernel addresses...
 	 */
 	if (!user_mode(regs)) {
-		const struct exception_table_entry *fix;
-
+#ifdef GAS_HAS_LOCAL_TAGS
+		fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri);
+#else
 		fix = search_exception_table(regs->cr_iip);
-		if (fix) {
-			regs->r8 = -EFAULT;
-			if (fix->skip & 1) {
-				regs->r9 = 0;
-			}
-			regs->cr_iip += ((long) fix->skip) & ~15;
-			regs->cr_ipsr &= ~IA64_PSR_RI;	/* clear exception slot number */
-			return;
-		}
-		die_if_kernel("Unaligned reference while in kernel\n", regs, 30);
-		/* NOT_REACHED */
-	}
-	/*
-	 * For now, we don't support user processes running big-endian
-	 * which do unaligned accesses
-	 */
-	if (ia64_psr(regs)->be) {
-		struct siginfo si;
-
-		printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not "
-		       "yet supported\n",
-		       current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
-
-		si.si_signo = SIGBUS;
-		si.si_errno = 0;
-		si.si_code = BUS_ADRALN;
-		si.si_addr = (void *) ifa;
-		force_sig_info(SIGBUS, &si, current);
-		return;
-	}
-
-	if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) {
-		struct siginfo si;
-
-		si.si_signo = SIGBUS;
-		si.si_errno = 0;
-		si.si_code = BUS_ADRALN;
-		si.si_addr = (void *) ifa;
-		force_sig_info(SIGBUS, &si, current);
-		return;
+#endif
 	}
-
-	if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) {
-		/*
-		 * Make sure we log the unaligned access, so that
-		 * user/sysadmin can notice it and eventually fix the
-		 * program.
-		 *
-		 * We don't want to do that for every access so we
-		 * pace it with jiffies.
-		 */
-		if (unalign_count > 5 && jiffies - last_time > 5*HZ)
-			unalign_count = 0;
-		if (++unalign_count < 5) {
+	if (user_mode(regs) || fix.cont) {
+		if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0)
+			goto force_sigbus;
+
+		if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)
+		    && within_logging_rate_limit())
+		{
 			char buf[200];	/* comm[] is at most 16 bytes... */
 			size_t len;
 
-			last_time = jiffies;
-			len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, ip=0x%016lx\n\r",
-				      current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
+			len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, "
+				      "ip=0x%016lx\n\r", current->comm, current->pid,
+				      ifa, regs->cr_iip + ipsr->ri);
 			tty_write_message(current->tty, buf);
 			buf[len-1] = '\0';	/* drop '\r' */
-			printk("%s", buf);	/* guard against command names containing %s!! */
+			printk(KERN_WARNING "%s", buf);	/* watch for command names containing %s */
 		}
+	} else {
+		if (within_logging_rate_limit())
+			printk(KERN_WARNING "kernel unaligned access to 0x%016lx, ip=0x%016lx\n",
+			       ifa, regs->cr_iip + ipsr->ri);
+		set_fs(KERNEL_DS);
 	}
 
-	DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr));
-	DPRINT(("ISR.ei=%d ISR.sp=%d\n", ipsr->ri, ipsr->it));
+	DPRINT("iip=%lx ifa=%lx isr=%lx (ei=%d, sp=%d)\n",
+	       regs->cr_iip, ifa, regs->cr_ipsr, ipsr->ri, ipsr->it);
 
-	bundle_addr = (unsigned long *)(regs->cr_iip);
+	if (__copy_from_user(bundle, (void *) regs->cr_iip, 16))
+		goto failure;
 
 	/*
 	 * extract the instruction from the bundle given the slot number
 	 */
-	switch ( ipsr->ri ) {
-		case 0: op = *bundle_addr >> 5;
-			break;
-
-		case 1: op = *bundle_addr >> 46 | (*(bundle_addr+1) & 0x7fffff)<<18;
-			break;
-
-		case 2: op = *(bundle_addr+1) >> 23;
-		 	break;
+	switch (ipsr->ri) {
+	      case 0: u.l = (bundle[0] >>  5); break;
+	      case 1: u.l = (bundle[0] >> 46) | (bundle[1] << 18); break;
+	      case 2: u.l = (bundle[1] >> 23); break;
 	}
+	opcode = (u.l >> IA64_OPCODE_SHIFT) & IA64_OPCODE_MASK;
 
-	insn   = (load_store_t *)&op;
-	opcode = op & IA64_OPCODE_MASK;
-
-	DPRINT(("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d "
-		"ld.x6=0x%x ld.m=%d ld.op=%d\n",
-		opcode,
-		insn->qp,
-		insn->r1,
-		insn->imm,
-		insn->r3,
-		insn->x,
-		insn->hint,
-		insn->x6_sz,
-		insn->m,
-		insn->op));
+	DPRINT("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d "
+	       "ld.x6=0x%x ld.m=%d ld.op=%d\n", opcode, u.insn.qp, u.insn.r1, u.insn.imm,
+	       u.insn.r3, u.insn.x, u.insn.hint, u.insn.x6_sz, u.insn.m, u.insn.op);
 
 	/*
-  	 * IMPORTANT:
+	 * IMPORTANT:
 	 * Notice that the swictch statement DOES not cover all possible instructions
 	 * that DO generate unaligned references. This is made on purpose because for some
 	 * instructions it DOES NOT make sense to try and emulate the access. Sometimes it
@@ -1483,104 +1341,124 @@
 	 *	load/store:
 	 *		- ldX.spill
 	 *		- stX.spill
-	 * 	Reason: RNATs are based on addresses
+	 *	Reason: RNATs are based on addresses
 	 *
 	 *	synchronization:
 	 *		- cmpxchg
 	 *		- fetchadd
 	 *		- xchg
-	 * 	Reason: ATOMIC operations cannot be emulated properly using multiple 
-	 * 	        instructions.
+	 *	Reason: ATOMIC operations cannot be emulated properly using multiple
+	 *	        instructions.
 	 *
 	 *	speculative loads:
 	 *		- ldX.sZ
-	 *	Reason: side effects, code must be ready to deal with failure so simpler 
-	 * 		to let the load fail.
+	 *	Reason: side effects, code must be ready to deal with failure so simpler
+	 *		to let the load fail.
 	 * ---------------------------------------------------------------------------------
 	 * XXX fixme
 	 *
 	 * I would like to get rid of this switch case and do something
 	 * more elegant.
 	 */
-	switch(opcode) {
-		case LDS_OP:
-		case LDSA_OP:
-		case LDS_IMM_OP:
-		case LDSA_IMM_OP:
-		case LDFS_OP:
-		case LDFSA_OP:
-		case LDFS_IMM_OP:
-			/*
-			 * The instruction will be retried with defered exceptions
-			 * turned on, and we should get Nat bit installed
-			 *
-			 * IMPORTANT:
-			 * When PSR_ED is set, the register & immediate update
-			 * forms are actually executed even though the operation
-			 * failed. So we don't need to take care of this.
-			 */
-			DPRINT(("forcing PSR_ED\n"));
-			regs->cr_ipsr |= IA64_PSR_ED;
-			return;
-
-		case LD_OP:
-		case LDA_OP:
-		case LDBIAS_OP:
-		case LDACQ_OP:
-		case LDCCLR_OP:
-		case LDCNC_OP:
-		case LDCCLRACQ_OP:
-		case LD_IMM_OP:
-		case LDA_IMM_OP:
-		case LDBIAS_IMM_OP:
-		case LDACQ_IMM_OP:
-		case LDCCLR_IMM_OP:
-		case LDCNC_IMM_OP:
-		case LDCCLRACQ_IMM_OP:
-			ret = emulate_load_int(ifa, insn, regs);
-			break;
-		case ST_OP:
-		case STREL_OP:
-		case ST_IMM_OP:
-		case STREL_IMM_OP:
-			ret = emulate_store_int(ifa, insn, regs);
-			break;
-		case LDF_OP:
-		case LDFA_OP:
-		case LDFCCLR_OP:
-		case LDFCNC_OP:
-		case LDF_IMM_OP:
-		case LDFA_IMM_OP:
-		case LDFCCLR_IMM_OP:
-		case LDFCNC_IMM_OP:
-			ret = insn->x ? 
-			      emulate_load_floatpair(ifa, insn, regs):
-			      emulate_load_float(ifa, insn, regs);
-			break;
-		case STF_OP:
-		case STF_IMM_OP:
-			ret = emulate_store_float(ifa, insn, regs);
-	}
-
-	DPRINT(("ret=%d\n", ret));
-	if (ret) {
-		struct siginfo si;
-
-		si.si_signo = SIGBUS;
-		si.si_errno = 0;
-		si.si_code = BUS_ADRALN;
-		si.si_addr = (void *) ifa;
-	        force_sig_info(SIGBUS, &si, current);
-	} else {
+	switch (opcode) {
+	      case LDS_OP:
+	      case LDSA_OP:
+	      case LDS_IMM_OP:
+	      case LDSA_IMM_OP:
+	      case LDFS_OP:
+	      case LDFSA_OP:
+	      case LDFS_IMM_OP:
 		/*
-	 	 * given today's architecture this case is not likely to happen
-	 	 * because a memory access instruction (M) can never be in the 
-	 	 * last slot of a bundle. But let's keep it for  now.
-	 	 */
-		if (ipsr->ri == 2)
-			regs->cr_iip += 16;
-		ipsr->ri = ++ipsr->ri & 3;
-	}
+		 * The instruction will be retried with deferred exceptions turned on, and
+		 * we should get Nat bit installed
+		 *
+		 * IMPORTANT: When PSR_ED is set, the register & immediate update forms
+		 * are actually executed even though the operation failed. So we don't
+		 * need to take care of this.
+		 */
+		DPRINT("forcing PSR_ED\n");
+		regs->cr_ipsr |= IA64_PSR_ED;
+		goto done;
+
+	      case LD_OP:
+	      case LDA_OP:
+	      case LDBIAS_OP:
+	      case LDACQ_OP:
+	      case LDCCLR_OP:
+	      case LDCNC_OP:
+	      case LDCCLRACQ_OP:
+	      case LD_IMM_OP:
+	      case LDA_IMM_OP:
+	      case LDBIAS_IMM_OP:
+	      case LDACQ_IMM_OP:
+	      case LDCCLR_IMM_OP:
+	      case LDCNC_IMM_OP:
+	      case LDCCLRACQ_IMM_OP:
+		ret = emulate_load_int(ifa, u.insn, regs);
+		break;
+
+	      case ST_OP:
+	      case STREL_OP:
+	      case ST_IMM_OP:
+	      case STREL_IMM_OP:
+		ret = emulate_store_int(ifa, u.insn, regs);
+		break;
+
+	      case LDF_OP:
+	      case LDFA_OP:
+	      case LDFCCLR_OP:
+	      case LDFCNC_OP:
+	      case LDF_IMM_OP:
+	      case LDFA_IMM_OP:
+	      case LDFCCLR_IMM_OP:
+	      case LDFCNC_IMM_OP:
+		if (u.insn.x)
+			ret = emulate_load_floatpair(ifa, u.insn, regs);
+		else
+			ret = emulate_load_float(ifa, u.insn, regs);
+		break;
+
+	      case STF_OP:
+	      case STF_IMM_OP:
+		ret = emulate_store_float(ifa, u.insn, regs);
+		break;
+
+	      default:
+		goto failure;
+	}
+	DPRINT("ret=%d\n", ret);
+	if (ret)
+		goto failure;
+
+	if (ipsr->ri == 2)
+		/*
+		 * given today's architecture this case is not likely to happen because a
+		 * memory access instruction (M) can never be in the last slot of a
+		 * bundle. But let's keep it for now.
+		 */
+		regs->cr_iip += 16;
+	ipsr->ri = (ipsr->ri + 1) & 0x3;
+
+	DPRINT("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip);
+  done:
+	set_fs(old_fs);		/* restore original address limit */
+	return;
 
-	DPRINT(("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip));
+  failure:
+	/* something went wrong... */
+	if (!user_mode(regs)) {
+		if (fix.cont) {
+			handle_exception(regs, fix);
+			goto done;
+		}
+		die_if_kernel("error during unaligned kernel access\n", regs, ret);
+		/* NOT_REACHED */
+	}
+  force_sigbus:
+	si.si_signo = SIGBUS;
+	si.si_errno = 0;
+	si.si_code = BUS_ADRALN;
+	si.si_addr = (void *) ifa;
+	force_sig_info(SIGBUS, &si, current);
+	goto done;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c
--- v2.4.3/linux/arch/ia64/kernel/unwind.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/ia64/kernel/unwind.c	Thu Apr 12 12:16:35 2001
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 /*
  * This file implements call frame unwind support for the Linux
@@ -24,15 +24,12 @@
  *	o if both the unw.lock spinlock and a script's read-write lock must be
  *	  acquired, then the read-write lock must be acquired first.
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 
 #include <asm/unwind.h>
 
-#ifdef CONFIG_IA64_NEW_UNWIND
-
 #include <asm/delay.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
@@ -306,7 +303,7 @@
 		}
 	} else {
 		/* access a stacked register */
-		addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);
+		addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum - 32);
 		nat_addr = ia64_rse_rnat_addr(addr);
 		if ((unsigned long) addr < info->regstk.limit
 		    || (unsigned long) addr >= info->regstk.top)
@@ -660,7 +657,7 @@
 	 */
 	if (sr->any_spills) {
 		off = sr->spill_offset;
-		alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); 
+		alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31);
 		alloc_spill_area(&off,  8, sr->curr.reg + UNW_REG_B1, sr->curr.reg + UNW_REG_B5);
 		alloc_spill_area(&off,  8, sr->curr.reg + UNW_REG_R4, sr->curr.reg + UNW_REG_R7);
 	}
@@ -911,6 +908,10 @@
 	struct unw_reg_state *rs;
 
 	rs = alloc_reg_state();
+	if (!rs) {
+		printk("unwind: cannot stack!\n");
+		return;
+	}
 	memcpy(rs, &sr->curr, sizeof(*rs));
 	rs->label = label;
 	rs->next = sr->reg_state_list;
@@ -927,7 +928,7 @@
 	if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1))
 		return 0;
 	if (qp > 0) {
-		if ((sr->pr_val & (1UL << qp)) == 0) 
+		if ((sr->pr_val & (1UL << qp)) == 0)
 			return 0;
 		sr->pr_mask |= (1UL << qp);
 	}
@@ -944,7 +945,7 @@
 
 	r = sr->curr.reg + decode_abreg(abreg, 0);
 	r->where = UNW_WHERE_NONE;
-	r->when = sr->region_start + MIN((int)t, sr->region_len - 1);
+	r->when = UNW_WHEN_NEVER;
 	r->val = 0;
 }
 
@@ -1443,12 +1444,17 @@
 		 * sp has been restored and all values on the memory stack below
 		 * psp also have been restored.
 		 */
-		sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
 		sr.curr.reg[UNW_REG_PSP].val = 0;
+		sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
+		sr.curr.reg[UNW_REG_PSP].when = UNW_WHEN_NEVER;
 		for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)
 			if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10)
 			    || r->where == UNW_WHERE_SPREL)
+			{
+				r->val = 0;
 				r->where = UNW_WHERE_NONE;
+				r->when = UNW_WHEN_NEVER;
+			}
 	}
 
 	script->flags = sr.flags;
@@ -1477,7 +1483,7 @@
 			      case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break;
 			      case UNW_WHERE_NONE:
 				printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);
-				break; 
+				break;
 			      default:		     printk("BADWHERE(%d)", r->where); break;
 			}
 			printk("\t\t%d\n", r->when);
@@ -1604,7 +1610,9 @@
 
 		      case UNW_INSN_LOAD:
 #if UNW_DEBUG
-			if ((s[val] & (my_cpu_data.unimpl_va_mask | 0x7)) || s[val] < TASK_SIZE) {
+			if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0
+			    || s[val] < TASK_SIZE)
+			{
 				debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]);
 				break;
 			}
@@ -1636,7 +1644,7 @@
 	int have_write_lock = 0;
 	struct unw_script *scr;
 
-	if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
+	if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
 		/* don't let obviously bad addresses pollute the cache */
 		debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip);
 		info->rp_loc = 0;
@@ -1672,7 +1680,7 @@
 	unsigned long ip, pr, num_regs;
 	STAT(unsigned long start, flags;)
 	int retval;
-	
+
 	STAT(local_irq_save(flags); ++unw.stat.api.unwinds; start = ia64_get_itc());
 
 	prev_ip = info->ip;
@@ -1818,140 +1826,14 @@
 	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
 }
 
-#endif /* CONFIG_IA64_NEW_UNWIND */
-
 void
 unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t)
 {
 	struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16);
 
-#ifdef CONFIG_IA64_NEW_UNWIND
 	unw_init_frame_info(info, t, sw);
-#else
-	unsigned long sol, limit, top;
-
-	memset(info, 0, sizeof(*info));
-
-	sol = (sw->ar_pfs >> 7) & 0x7f;	/* size of locals */
-
-	limit = (unsigned long) t + IA64_RBS_OFFSET;
-	top   = sw->ar_bspstore;
-	if (top - (unsigned long) t >= IA64_STK_OFFSET)
-		top = limit;
-
-	info->regstk.limit = limit;
-	info->regstk.top   = top;
-	info->sw  = sw;
-	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
-	info->cfm_loc = &sw->ar_pfs;
-	info->ip  = sw->b0;
-#endif
 }
 
-void
-unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs)
-{
-#ifdef CONFIG_IA64_NEW_UNWIND
-	struct switch_stack *sw = (struct switch_stack *) regs - 1;
-
-	unw_init_frame_info(info, current, sw);
-	/* skip over interrupt frame: */
-	unw_unwind(info);
-#else
-	struct switch_stack *sw = (struct switch_stack *) regs - 1;
-	unsigned long sol, sof, *bsp, limit, top;
-
-	limit = (unsigned long) current + IA64_RBS_OFFSET;
-	top   = sw->ar_bspstore;
-	if (top - (unsigned long) current >= IA64_STK_OFFSET)
-		top = limit;
-
-	memset(info, 0, sizeof(*info));
-
-	sol = (sw->ar_pfs >> 7) & 0x7f;	/* size of frame */
-
-	/* this gives us the bsp top level frame (kdb interrupt frame): */
-	bsp = ia64_rse_skip_regs((unsigned long *) top, -sol);
-
-	/* now skip past the interrupt frame: */
-	sof = regs->cr_ifs & 0x7f;	/* size of frame */
-
-	info->regstk.limit = limit;
-	info->regstk.top   = top;
-	info->sw = sw;
-	info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof);
-	info->cfm_loc = &regs->cr_ifs;
-	info->ip  = regs->cr_iip;
-#endif
-}
-
-#ifndef CONFIG_IA64_NEW_UNWIND
-
-static unsigned long
-read_reg (struct unw_frame_info *info, int regnum, int *is_nat)
-{
-	unsigned long *addr, *rnat_addr, rnat;
-
-	addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);
-	if ((unsigned long) addr < info->regstk.limit
-	    || (unsigned long) addr >= info->regstk.top || ((long) addr & 0x7) != 0)
-	{
-		*is_nat = 1;
-		return 0xdeadbeefdeadbeef;
-	}
-	rnat_addr = ia64_rse_rnat_addr(addr);
-
-	if ((unsigned long) rnat_addr >= info->regstk.top)
-		rnat = info->sw->ar_rnat;
-	else
-		rnat = *rnat_addr;
-	*is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0;
-	return *addr;
-}
-
-/*
- * On entry, info->regstk.top should point to the register backing
- * store for r32.
- */
-int
-unw_unwind (struct unw_frame_info *info)
-{
-	unsigned long sol, cfm = *info->cfm_loc;
-	int is_nat;
-
-	sol = (cfm >> 7) & 0x7f;	/* size of locals */
-
-	/*
-	 * In general, we would have to make use of unwind info to
-	 * unwind an IA-64 stack, but for now gcc uses a special
-	 * convention that makes this possible without full-fledged
-	 * unwindo info.  Specifically, we expect "rp" in the second
-	 * last, and "ar.pfs" in the last local register, so the
-	 * number of locals in a frame must be at least two.  If it's
-	 * less than that, we reached the end of the C call stack.
-	 */
-	if (sol < 2)
-		return -1;
-
-	info->ip = read_reg(info, sol - 2, &is_nat);
-	if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)))
-		/* reject let obviously bad addresses */
-		return -1;
-
-	info->cfm_loc = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1);
-	cfm = read_reg(info, sol - 1, &is_nat);
-	if (is_nat)
-		return -1;
-
-	sol = (cfm >> 7) & 0x7f;
-
-	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol);
-	return 0;
-}
-#endif /* !CONFIG_IA64_NEW_UNWIND */
-
-#ifdef CONFIG_IA64_NEW_UNWIND
-
 static void
 init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base,
 		   unsigned long gp, void *table_start, void *table_end)
@@ -1979,7 +1861,7 @@
 		dprintk("unwind: ignoring attempt to insert empty unwind table\n");
 		return 0;
 	}
-	
+
 	table = kmalloc(sizeof(*table), GFP_USER);
 	if (!table)
 		return 0;
@@ -2052,12 +1934,10 @@
 
 	kfree(table);
 }
-#endif /* CONFIG_IA64_NEW_UNWIND */
 
 void
 unw_init (void)
 {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	extern int ia64_unw_start, ia64_unw_end, __gp;
 	extern void unw_hash_index_t_is_too_narrow (void);
 	long i, off;
@@ -2093,5 +1973,4 @@
 
 	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp,
 			  &ia64_unw_start, &ia64_unw_end);
-#endif /* CONFIG_IA64_NEW_UNWIND */
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile
--- v2.4.3/linux/arch/ia64/lib/Makefile	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/lib/Makefile	Thu Apr  5 12:51:47 2001
@@ -7,18 +7,18 @@
 
 L_TARGET = lib.a
 
+export-objs := io.o swiotlb.o
+
 obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
 	checksum.o clear_page.o csum_partial_copy.o copy_page.o				\
 	copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o	\
-	flush.o do_csum.o								\
+	flush.o io.o do_csum.o								\
 	swiotlb.o
 
 ifneq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y)
   obj-y += memcpy.o memset.o strlen.o
 endif
-
-export-objs += io.o
 
 IGNORE_FLAGS_OBJS =	__divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
 			__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S
--- v2.4.3/linux/arch/ia64/lib/clear_page.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/clear_page.S	Thu Apr  5 12:51:47 2001
@@ -6,29 +6,24 @@
  *
  * Inputs:
  *	in0:	address of page
- * 
+ *
  * Output:
  * 	none
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <asm/asmmacro.h>
 #include <asm/page.h>
 
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(clear_page)
-	UNW(.prologue)
+	.prologue
 	alloc r11=ar.pfs,1,0,0,0
-	UNW(.save ar.lc, r16)
+	.save ar.lc, r16
 	mov r16=ar.lc		// slow
 
-	UNW(.body)
+	.body
 
 	mov r17=PAGE_SIZE/32-1	// -1 = repeat/until
 	;;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S
--- v2.4.3/linux/arch/ia64/lib/clear_user.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/clear_user.S	Thu Apr  5 12:51:47 2001
@@ -6,8 +6,8 @@
  *	in1:	length of buffer in bytes
  * Outputs:
  *	r8:	number of bytes that didn't get cleared due to a fault
- * 
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
+ *
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  */
 
@@ -51,27 +51,12 @@
 //	have side effects (same thing for writing).
 //
 
-// The label comes first because our store instruction contains a comma
-// and confuse the preprocessor otherwise
-//
-#define EX(y,x...)				\
-	.section __ex_table,"a";		\
-	data4 @gprel(99f);			\
-	data4 y-99f;				\
-	.previous;				\
-99:	x
-
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(__do_clear_user)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
- 	alloc	saved_pfs=ar.pfs,2,0,0,0
+	.prologue
+	.save ar.pfs, saved_pfs
+	alloc	saved_pfs=ar.pfs,2,0,0,0
 	cmp.eq p6,p0=r0,len		// check for zero length
-	UNW(.save ar.lc, saved_lc)
+	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc		// preserve ar.lc (slow)
 	.body
 	;;				// avoid WAW on CFM
@@ -80,7 +65,7 @@
 (p6)	br.ret.spnt.few rp
 	;;
 	cmp.lt p6,p0=16,len		// if len > 16 then long memset
-	mov ar.lc=tmp			// initialize lc for small count 
+	mov ar.lc=tmp			// initialize lc for small count
 (p6)	br.cond.dptk.few long_do_clear
 	;;				// WAR on ar.lc
 	//
@@ -91,7 +76,7 @@
 	// the various counters compared to how long the loop is supposed
 	// to last on average does not make this solution viable.
 	//
-1:	
+1:
 	EX( .Lexit1, st1 [buf]=r0,1 )
 	adds len=-1,len			// countdown length using len
 	br.cloop.dptk.few 1b
@@ -99,7 +84,7 @@
 	//
 	// .Lexit4: comes from byte by byte loop
 	//	    len contains bytes left
-.Lexit1:			
+.Lexit1:
 	mov ret0=len			// faster than using ar.lc
 	mov ar.lc=saved_lc
 	br.ret.sptk.few rp		// end of short clear_user
@@ -110,7 +95,7 @@
 	// so we focus on alignment (no branches required)
 	//
 	// The use of len/len2 for countdown of the number of bytes left
-	// instead of ret0 is due to the fact that the exception code 
+	// instead of ret0 is due to the fact that the exception code
 	// changes the values of r8.
 	//
 long_do_clear:
@@ -131,10 +116,10 @@
 	EX( .Lexit3, (p6) st8 [buf]=r0,8 )	// 8-byte aligned
 (p6)	adds len=-8,len;;
 	shr.u cnt=len,4		// number of 128-bit (2x64bit) words
-	;;	
+	;;
 	cmp.eq p6,p0=r0,cnt
 	adds tmp=-1,cnt
-(p6)	br.cond.dpnt.few .dotail 	// we have less than 16 bytes left
+(p6)	br.cond.dpnt.few .dotail	// we have less than 16 bytes left
 	;;
 	adds buf2=8,buf			// setup second base pointer
 	mov ar.lc=tmp
@@ -143,32 +128,30 @@
 	//
 	// 16bytes/iteration core loop
 	//
-	// The second store can never generate a fault because 
+	// The second store can never generate a fault because
 	// we come into the loop only when we are 16-byte aligned.
 	// This means that if we cross a page then it will always be
 	// in the first store and never in the second.
 	//
-	// 
+	//
 	// We need to keep track of the remaining length. A possible (optimistic)
-	// way would be to ue ar.lc and derive how many byte were left by
+	// way would be to use ar.lc and derive how many byte were left by
 	// doing : left= 16*ar.lc + 16.  this would avoid the addition at
-	// every iteration. 
+	// every iteration.
 	// However we need to keep the synchronization point. A template
 	// M;;MB does not exist and thus we can keep the addition at no
 	// extra cycle cost (use a nop slot anyway). It also simplifies the
 	// (unlikely)  error recovery code
 	//
 
-2:					
-
-	EX(.Lexit3, st8 [buf]=r0,16 )
+2:	EX(.Lexit3, st8 [buf]=r0,16 )
 	;;				// needed to get len correct when error
 	st8 [buf2]=r0,16
-	adds len=-16,len		
+	adds len=-16,len
 	br.cloop.dptk.few 2b
 	;;
 	mov ar.lc=saved_lc
-	// 
+	//
 	// tail correction based on len only
 	//
 	// We alternate the use of len3,len2 to allow parallelism and correct
@@ -176,14 +159,14 @@
 	// The addition of len2/len3 does not cost anything more compared to
 	// the regular memset as we had empty slots.
 	//
-.dotail:				
+.dotail:
 	mov len2=len			// for parallelization of error handling
 	mov len3=len
-	tbit.nz p6,p0=len,3	
+	tbit.nz p6,p0=len,3
 	;;
 	EX( .Lexit2, (p6) st8 [buf]=r0,8 )	// at least 8 bytes
 (p6)	adds len3=-8,len2
-	tbit.nz p7,p6=len,2	
+	tbit.nz p7,p6=len,2
 	;;
 	EX( .Lexit2, (p7) st4 [buf]=r0,4 )	// at least 4 bytes
 (p7)	adds len2=-4,len3
@@ -207,8 +190,8 @@
 	//
 	//
 	// .Lexit2:
-	// 	if p6 -> coming from st8 or st2 : len2 contains what's left
-	// 	if p7 -> coming from st4 or st1 : len3 contains what's left
+	//	if p6 -> coming from st8 or st2 : len2 contains what's left
+	//	if p7 -> coming from st4 or st1 : len3 contains what's left
 	// We must restore lc/pr even though might not have been used.
 .Lexit2:
 	.pred.rel "mutex", p6, p7
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S
--- v2.4.3/linux/arch/ia64/lib/copy_page.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/copy_page.S	Thu Apr  5 12:51:47 2001
@@ -3,14 +3,14 @@
  * Optimized version of the standard copy_page() function
  *
  * Based on comments from ddd. Try not to overflow write buffer.
- * 
+ *
  * Inputs:
- * 	in0:	address of target page
+ *	in0:	address of target page
  *	in1:	address of source page
  * Output:
- * 	no return value
+ *	no return value
  *
- * Copyright (C) 1999 Hewlett-Packard Co
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  */
 #include <asm/asmmacro.h>
@@ -28,28 +28,23 @@
 #define tgt1		r22
 #define tgt2		r23
 
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(copy_page)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
+	.prologue
+	.save ar.pfs, saved_pfs
 	alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7)
 
 	.rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH]
 	.rotp p[PIPE_DEPTH]
 
-	UNW(.save ar.lc, saved_lc)
+	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc	// save ar.lc ahead of time
-	UNW(.save pr, saved_pr)
+	.save pr, saved_pr
 	mov saved_pr=pr		// rotating predicates are preserved
 				// resgisters we must save.
-	UNW(.body)
+	.body
 
-	mov src1=in1		// initialize 1st stream source 
-	adds src2=8,in1		// initialize 2nd stream source 
+	mov src1=in1		// initialize 1st stream source
+	adds src2=8,in1		// initialize 2nd stream source
 	mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page
 				  // -1 is because br.ctop is repeat/until
 
@@ -72,7 +67,7 @@
 	//
 	// The initialization of the prolog is done via the predicate registers:
 	// the choice of EPI DEPENDS on the depth of the pipeline (n).
-	// When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 
+	// When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62
 	// are then shifted right at every iteration,
 	// Thus by initializing pr16=1 and the rest to 0 before the loop
 	// we get EPI=1 after n iterations.
@@ -87,7 +82,7 @@
 				// stores but no loads anymore
 	;;
 	mov pr=saved_pr,0xffffffffffff0000	// restore predicates
-	mov ar.pfs=saved_pfs	// restore ar.ec 
+	mov ar.pfs=saved_pfs	// restore ar.ec
 	mov ar.lc=saved_lc	// restore saved lc
 	br.ret.sptk.few rp	// bye...
 END(copy_page)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S
--- v2.4.3/linux/arch/ia64/lib/copy_user.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/ia64/lib/copy_user.S	Thu Apr  5 12:51:47 2001
@@ -12,41 +12,25 @@
  *
  * Inputs:
  *	in0	address of source buffer
- * 	in1	address of destination buffer
+ *	in1	address of destination buffer
  *	in2	number of bytes to copy
  *
- * Outputs: 
- * 	ret0	0 in case of success. The number of bytes NOT copied in
- * 		case of error.
+ * Outputs:
+ *	ret0	0 in case of success. The number of bytes NOT copied in
+ *		case of error.
  *
  * Copyright (C) 2000 Hewlett-Packard Co
  * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
  *
  * Fixme:
  *	- handle the case where we have more than 16 bytes and the alignment
- * 	  are different.
+ *	  are different.
  *	- more benchmarking
- * 	- fix extraneous stop bit introduced by the EX() macro.
+ *	- fix extraneous stop bit introduced by the EX() macro.
  */
 
 #include <asm/asmmacro.h>
 
-// The label comes first because our store instruction contains a comma
-// and confuse the preprocessor otherwise
-//
-#undef DEBUG
-#ifdef DEBUG
-#define EX(y,x...)				\
-99:	x
-#else
-#define EX(y,x...)				\
-	.section __ex_table,"a";		\
-	data4 @gprel(99f);			\
-	data4 y-99f;				\
-	.previous;				\
-99:	x
-#endif
-
 //
 // Tuneable parameters
 //
@@ -85,13 +69,10 @@
 #define enddst		r29
 #define endsrc		r30
 #define saved_pfs	r31
- 	.text
- 	.psr	abi64
- 	.psr	lsb
 
 GLOBAL_ENTRY(__copy_user)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
+	.prologue
+	.save ar.pfs, saved_pfs
 	alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7)
 
 	.rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH]
@@ -102,16 +83,16 @@
 
 	;;			// RAW of cfm when len=0
 	cmp.eq p8,p0=r0,len	// check for zero length
-	UNW(.save ar.lc, saved_lc)
+	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc	// preserve ar.lc (slow)
 (p8)	br.ret.spnt.few rp	// empty mempcy()
 	;;
 	add enddst=dst,len	// first byte after end of source
 	add endsrc=src,len	// first byte after end of destination
-	UNW(.save pr, saved_pr)
+	.save pr, saved_pr
 	mov saved_pr=pr		// preserve predicates
 
-	UNW(.body)
+	.body
 
 	mov dst1=dst		// copy because of rotation
 	mov ar.ec=PIPE_DEPTH
@@ -119,7 +100,7 @@
 
 	mov src1=src		// copy because of rotation
 	mov ar.lc=len2		// initialize lc for small count
-	cmp.lt p10,p7=COPY_BREAK,len	// if len > COPY_BREAK then long copy 
+	cmp.lt p10,p7=COPY_BREAK,len	// if len > COPY_BREAK then long copy
 
 	xor tmp=src,dst		// same alignment test prepare
 (p10)	br.cond.dptk.few long_copy_user
@@ -128,9 +109,8 @@
 	// Now we do the byte by byte loop with software pipeline
 	//
 	// p7 is necessarily false by now
-1:				
+1:
 	EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
-
 	EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
 	br.ctop.dptk.few 1b
 	;;
@@ -148,10 +128,10 @@
 	and src2=0x7,src1				// src offset
 	and dst2=0x7,dst1				// dst offset
 	;;
-	// The basic idea is that we copy byte-by-byte at the head so 
-	// that we can reach 8-byte alignment for both src1 and dst1. 
-	// Then copy the body using software pipelined 8-byte copy, 
-	// shifting the two back-to-back words right and left, then copy 
+	// The basic idea is that we copy byte-by-byte at the head so
+	// that we can reach 8-byte alignment for both src1 and dst1.
+	// Then copy the body using software pipelined 8-byte copy,
+	// shifting the two back-to-back words right and left, then copy
 	// the tail by copying byte-by-byte.
 	//
 	// Fault handling. If the byte-by-byte at the head fails on the
@@ -162,18 +142,18 @@
 	// handled simply by failure_in_pipe1.
 	//
 	// The case p14 represents the source has more bytes in the
-	// the first word (by the shifted part), whereas the p15 needs to 
-	// copy some bytes from the 2nd word of the source that has the 
+	// the first word (by the shifted part), whereas the p15 needs to
+	// copy some bytes from the 2nd word of the source that has the
 	// tail of the 1st of the destination.
 	//
 
 	//
-	// Optimization. If dst1 is 8-byte aligned (not rarely), we don't need 
-	// to copy the head to dst1, to start 8-byte copy software pipleline. 
+	// Optimization. If dst1 is 8-byte aligned (not rarely), we don't need
+	// to copy the head to dst1, to start 8-byte copy software pipleline.
 	// We know src1 is not 8-byte aligned in this case.
 	//
 	cmp.eq p14,p15=r0,dst2
-(p15)	br.cond.spnt.few 1f				
+(p15)	br.cond.spnt.few 1f
 	;;
 	sub t1=8,src2
 	mov t2=src2
@@ -182,10 +162,10 @@
 	sub len1=len,t1					// set len1
 	;;
 	sub lshift=64,rshift
-	;; 
+	;;
 	br.cond.spnt.few word_copy_user
-	;; 
-1:			
+	;;
+1:
 	cmp.leu	p14,p15=src2,dst2
 	sub t1=dst2,src2
 	;;
@@ -196,30 +176,29 @@
 	;;
 	// For the case p14, we don't need to copy the shifted part to
 	// the 1st word of destination.
-	sub t2=8,t1	
+	sub t2=8,t1
 (p14)	sub word1=word1,t1
 	;;
 	sub len1=len,word1				// resulting len
 (p15)	shl rshift=t1,3					// in bits
 (p14)	shl rshift=t2,3
-	;; 
+	;;
 (p14)	sub len1=len1,t1
 	adds cnt=-1,word1
-	;; 
+	;;
 	sub lshift=64,rshift
 	mov ar.ec=PIPE_DEPTH
 	mov pr.rot=1<<16	// p16=true all others are false
 	mov ar.lc=cnt
-	;; 
-2:	
+	;;
+2:
 	EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1)
-	;; 
 	EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
 	br.ctop.dptk.few 2b
 	;;
-	clrrrb	
-	;; 
-word_copy_user:		
+	clrrrb
+	;;
+word_copy_user:
 	cmp.gtu p9,p0=16,len1
 (p9)	br.cond.spnt.few 4f		// if (16 > len1) skip 8-byte copy
 	;;
@@ -227,7 +206,7 @@
 	;;
 	adds cnt=-1,cnt
 	;;
-	.pred.rel "mutex", p14, p15	
+	.pred.rel "mutex", p14, p15
 (p14)	sub src1=src1,t2
 (p15)	sub src1=src1,t1
 	//
@@ -237,23 +216,23 @@
 	mov ar.lc=cnt
 	mov ar.ec=PIPE_DEPTH
 	mov pr.rot=1<<16	// p16=true all others are false
-	;; 
+	;;
 3:
 	//
-	// The pipleline consists of 3 stages:	
+	// The pipleline consists of 3 stages:
 	// 1 (p16):	Load a word from src1
 	// 2 (EPI_1):	Shift right pair, saving to tmp
 	// 3 (EPI):	Store tmp to dst1
 	//
-	// To make it simple, use at least 2 (p16) loops to set up val1[n] 
+	// To make it simple, use at least 2 (p16) loops to set up val1[n]
 	// because we need 2 back-to-back val1[] to get tmp.
 	// Note that this implies EPI_2 must be p18 or greater.
-	// 
+	//
 
 #define EPI_1		p[PIPE_DEPTH-2]
 #define SWITCH(pred, shift)	cmp.eq pred,p0=shift,rshift
 #define CASE(pred, shift)	\
-	(pred)	br.cond.spnt.few copy_user_bit##shift	
+	(pred)	br.cond.spnt.few copy_user_bit##shift
 #define BODY(rshift)							\
 copy_user_bit##rshift:							\
 1:									\
@@ -267,11 +246,11 @@
 	//
 	// Since the instruction 'shrp' requires a fixed 128-bit value
 	// specifying the bits to shift, we need to provide 7 cases
-	// below. 
+	// below.
 	//
 	SWITCH(p6, 8)
 	SWITCH(p7, 16)
-	SWITCH(p8, 24)	
+	SWITCH(p8, 24)
 	SWITCH(p9, 32)
 	SWITCH(p10, 40)
 	SWITCH(p11, 48)
@@ -289,40 +268,40 @@
 	BODY(16)
 	BODY(24)
 	BODY(32)
-	BODY(40)		
+	BODY(40)
 	BODY(48)
 	BODY(56)
-	;; 
-.diff_align_do_tail:	
-	.pred.rel "mutex", p14, p15		
+	;;
+.diff_align_do_tail:
+	.pred.rel "mutex", p14, p15
 (p14)	sub src1=src1,t1
-(p14)	adds dst1=-8,dst1			
+(p14)	adds dst1=-8,dst1
 (p15)	sub dst1=dst1,t1
-	;; 
-4:	
+	;;
+4:
 	// Tail correction.
 	//
 	// The problem with this piplelined loop is that the last word is not
-	// loaded and thus parf of the last word written is not correct. 
+	// loaded and thus parf of the last word written is not correct.
 	// To fix that, we simply copy the tail byte by byte.
-	
+
 	sub len1=endsrc,src1,1
 	clrrrb
-	;; 
+	;;
 	mov ar.ec=PIPE_DEPTH
 	mov pr.rot=1<<16	// p16=true all others are false
 	mov ar.lc=len1
 	;;
-5:		
+5:
 	EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
-	
 	EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
 	br.ctop.dptk.few 5b
 	;;
+	mov ar.lc=saved_lc
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.pfs=saved_pfs
 	br.ret.dptk.few rp
-	
+
 	//
 	// Beginning of long mempcy (i.e. > 16 bytes)
 	//
@@ -353,6 +332,7 @@
 	// we have never executed the ld1, therefore st1 is not executed.
 	//
 	EX(failure_in1,(p8) ld4 val2[0]=[src1],4)	// 4-byte aligned
+	;;
 	EX(failure_out,(p6) st1 [dst1]=val1[0],1)
 	tbit.nz p9,p0=src1,3
 	;;
@@ -369,12 +349,12 @@
 	shr.u cnt=len1,4		// number of 128-bit (2x64bit) words
 	;;
 	EX(failure_out, (p9) st8 [dst1]=val2[1],8)
-	tbit.nz p6,p0=len1,3	
+	tbit.nz p6,p0=len1,3
 	cmp.eq p7,p0=r0,cnt
 	adds tmp=-1,cnt			// br.ctop is repeat/until
 (p7)	br.cond.dpnt.few .dotail	// we have less than 16 bytes left
 	;;
-	adds src2=8,src1	
+	adds src2=8,src1
 	adds dst2=8,dst1
 	mov ar.lc=tmp
 	;;
@@ -395,12 +375,12 @@
 	// No matter where we come from (loop or test) the src1 pointer
 	// is 16 byte aligned AND we have less than 16 bytes to copy.
 	//
-.dotail:			
+.dotail:
 	EX(failure_in1,(p6) ld8 val1[0]=[src1],8)	// at least 8 bytes
 	tbit.nz p7,p0=len1,2
 	;;
 	EX(failure_in1,(p7) ld4 val1[1]=[src1],4)	// at least 4 bytes
- 	tbit.nz p8,p0=len1,1
+	tbit.nz p8,p0=len1,1
 	;;
 	EX(failure_in1,(p8) ld2 val2[0]=[src1],2)	// at least 2 bytes
 	tbit.nz p9,p0=len1,0
@@ -430,7 +410,7 @@
 	//
 	//	  In the same loop iteration, the dst1 pointer does not directly
 	//	  reflect where the faulty load was.
-	//	  
+	//
 	//	- pipeline effect
 	//	  When you get a fault on load, you may have valid data from
 	//	  previous loads not yet store in transit. Such data must be
@@ -442,7 +422,7 @@
 	//	- we don't disrupt the pipeline, i.e. data in transit in
 	//	  the software pipeline will be eventually move to memory.
 	//	  We simply replace the load with a simple mov and keep the
-	//	  pipeline going. We can't really do this inline because 
+	//	  pipeline going. We can't really do this inline because
 	//	  p16 is always reset to 1 when lc > 0.
 	//
 failure_in_pipe1:
@@ -459,7 +439,7 @@
 
 	//
 	// This is the case where the byte by byte copy fails on the load
-	// when we copy the head. We need to finish the pipeline and copy 
+	// when we copy the head. We need to finish the pipeline and copy
 	// zeros for the rest of the destination. Since this happens
 	// at the top we still need to fill the body and tail.
 failure_in_pipe2:
@@ -471,7 +451,7 @@
 	;;
 	sub len=enddst,dst1,1		// precompute len
 	br.cond.dptk.few failure_in1bis
-	;; 
+	;;
 
 	//
 	// Here we handle the head & tail part when we check for alignment.
@@ -482,7 +462,7 @@
 	//
 	// However some simplifications are possible given the way
 	// things work.
-	// 
+	//
 	// 1) HEAD
 	// Theory of operation:
 	//
@@ -506,23 +486,23 @@
 	//
 	// Key point:
 	//	- if you fail on 1, 2, 4 then you have never executed any smaller
-	//	  size loads, e.g. failing ld4 means no ld1 nor ld2 executed 
+	//	  size loads, e.g. failing ld4 means no ld1 nor ld2 executed
 	//	  before.
 	//
 	// This allows us to simplify the cleanup code, because basically you
 	// only have to worry about "pending" stores in the case of a failing
-	// ld8(). Given the way the code is written today, this means only 
+	// ld8(). Given the way the code is written today, this means only
 	// worry about st2, st4. There we can use the information encapsulated
 	// into the predicates.
-	// 
+	//
 	// Other key point:
-	// 	- if you fail on the ld8 in the head, it means you went straight
+	//	- if you fail on the ld8 in the head, it means you went straight
 	//	  to it, i.e. 8byte alignment within an unexisting page.
 	// Again this comes from the fact that if you crossed just for the ld8 then
 	// you are 8byte aligned but also 16byte align, therefore you would
 	// either go for the 16byte copy loop OR the ld8 in the tail part.
 	// The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible
-	// because it would mean you had 15bytes to copy in which case you 
+	// because it would mean you had 15bytes to copy in which case you
 	// would have defaulted to the byte by byte copy.
 	//
 	//
@@ -533,18 +513,18 @@
 	// Key point:
 	// This means that we either:
 	//		- are right on a page boundary
-	//	OR 
-	//		- are at more than 16 bytes from a page boundary with 
+	//	OR
+	//		- are at more than 16 bytes from a page boundary with
 	//		  at most 15 bytes to copy: no chance of crossing.
 	//
 	// This allows us to assume that if we fail on a load we haven't possibly
-	// executed any of the previous (tail) ones, so we don't need to do 
-	// any stores. For instance, if we fail on ld2, this means we had 
+	// executed any of the previous (tail) ones, so we don't need to do
+	// any stores. For instance, if we fail on ld2, this means we had
 	// 2 or 3 bytes left to copy and we did not execute the ld8 nor ld4.
 	//
-	// This means that we are in a situation similar the a fault in the 
-	// head part. That's nice! 
-	// 
+	// This means that we are in a situation similar the a fault in the
+	// head part. That's nice!
+	//
 failure_in1:
 //	sub ret0=enddst,dst1	// number of bytes to zero, i.e. not copied
 //	sub len=enddst,dst1,1
@@ -563,7 +543,7 @@
 	;;
 5:
 	st1 [dst1]=r0,1
-	br.cloop.dptk.few 5b	
+	br.cloop.dptk.few 5b
 	;;
 skip_loop:
 	mov pr=saved_pr,0xffffffffffff0000
@@ -574,7 +554,7 @@
 	//
 	// Here we simply restart the loop but instead
 	// of doing loads we fill the pipeline with zeroes
-	// We can't simply store r0 because we may have valid 
+	// We can't simply store r0 because we may have valid
 	// data in transit in the pipeline.
 	// ar.lc and ar.ec are setup correctly at this point
 	//
@@ -593,7 +573,7 @@
 	;;
 	cmp.ne p6,p0=dst1,enddst	// Do we need to finish the tail ?
 	sub len=enddst,dst1,1		// precompute len
-(p6)	br.cond.dptk.few failure_in1bis	
+(p6)	br.cond.dptk.few failure_in1bis
 	;;
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
@@ -610,13 +590,13 @@
 	;;
 	cmp.ne p6,p0=dst1,enddst	// Do we need to finish the tail ?
 	sub len=enddst,dst1,1		// precompute len
-(p6)	br.cond.dptk.few failure_in1bis	
+(p6)	br.cond.dptk.few failure_in1bis
 	;;
 	mov pr=saved_pr,0xffffffffffff0000
 	mov ar.lc=saved_lc
 	mov ar.pfs=saved_pfs
 	br.ret.dptk.few rp
-	
+
 	//
 	// handling of failures on stores: that's the easy part
 	//
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/csum_partial_copy.c linux/arch/ia64/lib/csum_partial_copy.c
--- v2.4.3/linux/arch/ia64/lib/csum_partial_copy.c	Sun Feb  6 18:42:40 2000
+++ linux/arch/ia64/lib/csum_partial_copy.c	Thu Apr  5 12:51:47 2001
@@ -1,6 +1,6 @@
 /*
  * Network Checksum & Copy routine
- * 
+ *
  * Copyright (C) 1999 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
@@ -107,22 +107,18 @@
 do_csum_partial_copy_from_user (const char *src, char *dst, int len,
 				unsigned int psum, int *errp)
 {
-	const unsigned char *psrc = src;
 	unsigned long result;
-	int cplen = len;
-	int r = 0;
 
 	/* XXX Fixme
-	 * for now we separate the copy from checksum for obvious 
+	 * for now we separate the copy from checksum for obvious
 	 * alignment difficulties. Look at the Alpha code and you'll be
 	 * scared.
 	 */
 
-	while ( cplen-- ) r |=__get_user(*dst++,psrc++);
-
-	if ( r && errp ) *errp = r;
+	if (__copy_from_user(dst, src, len) != 0 && errp)
+		*errp = -EFAULT;
 
-	result = do_csum(src, len);
+	result = do_csum(dst, len);
 
 	/* add in old sum, and carry.. */
 	result += psum;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S
--- v2.4.3/linux/arch/ia64/lib/do_csum.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/do_csum.S	Thu Apr  5 12:51:47 2001
@@ -7,8 +7,8 @@
  * Inputs:
  *	in0: address of buffer to checksum (char *)
  *	in1: length of the buffer (int)
- * 
- * Copyright (C) 1999 Hewlett-Packard Co
+ *
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
  */
@@ -39,7 +39,7 @@
 //	This version avoids synchronization in the core loop by also using a
 //	pipeline for the accumulation of the checksum in result[].
 //
-//	 p[]     
+//	 p[]
 //	|---|
 //     0|   | r32 : new value loaded in pipeline
 //	|---|
@@ -50,7 +50,7 @@
 //     3|   | r35 : previous value added to checksum (previous iteration)
 //      |---|
 //
-//	result[] 
+//	result[]
 //	|---|
 //     0|   | r36 : new checksum
 //	|---|
@@ -68,7 +68,7 @@
 //	- Maybe another algorithm which would take care of the folding at the
 //	  end in a different manner
 //	- Work with people more knowledgeable than me on the network stack
-//	  to figure out if we could not split the function depending on the 
+//	  to figure out if we could not split the function depending on the
 //	  type of packet or alignment we get. Like the ip_fast_csum() routine
 //	  where we know we have at least 20bytes worth of data to checksum.
 //	- Look at RFCs about checksums to see whether or not we can do better
@@ -94,17 +94,11 @@
 #define buf		in0
 #define len		in1
 
-
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 // unsigned long do_csum(unsigned char *buf,int len)
 
 GLOBAL_ENTRY(do_csum)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
+	.prologue
+	.save ar.pfs, saved_pfs
 	alloc saved_pfs=ar.pfs,2,8,0,8
 
 	.rotr p[4], result[3]
@@ -126,7 +120,7 @@
 	;;
 	and lastoff=7,tmp1	// how many bytes off for last element
 	andcm last=tmp2,tmp3	// address of word containing last byte
-	UNW(.save pr, saved_pr)
+	.save pr, saved_pr
 	mov saved_pr=pr		// preserve predicates (rotation)
 	;;
 	sub tmp3=last,first	// tmp3=distance from first to last
@@ -144,14 +138,14 @@
 	;;
 
 	shl tmp1=tmp1,3		// number of bits
-	shl hmask=hmask,tmp2 	// build head mask, mask off [0,firstoff[
+	shl hmask=hmask,tmp2	// build head mask, mask off [0,firstoff[
 	;;
 	shr.u tmask=tmask,tmp1	// build tail mask, mask off ]8,lastoff]
-	UNW(.save ar.lc, saved_lc)
+	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc	// save lc
 	;;
 
-	UNW(.body)
+	.body
 
 (p8)	and hmask=hmask,tmask	// apply tail mask to head mask if 1 word only
 (p9)	and p[1]=lastval,tmask	// mask last it as appropriate
@@ -163,7 +157,7 @@
 	;;
 	// XXX Fixme: not very nice initialization here
 	//
-	// Setup loop control registers: 
+	// Setup loop control registers:
 	//
 	// tmp3=0 (1 word)   : lc=0, ec=2, p16=F
 	// tmp3=1 (2 words)  : lc=0, ec=3, p16=F
@@ -227,7 +221,7 @@
 	add ret0=tmp1,tmp2
 	mov pr=saved_pr,0xffffffffffff0000
 	;;
-	// if buf was odd then swap bytes 
+	// if buf was odd then swap bytes
 	mov ar.pfs=saved_pfs		// restore ar.ec
 (p10)	mux1 ret0=ret0,@rev		// reverse word
 	;;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/flush.S linux/arch/ia64/lib/flush.S
--- v2.4.3/linux/arch/ia64/lib/flush.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/lib/flush.S	Thu Apr  5 12:51:47 2001
@@ -1,30 +1,25 @@
 /*
  * Cache flushing routines.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <asm/asmmacro.h>
 #include <asm/page.h>
 
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 	/*
 	 * flush_icache_range(start,end)
 	 *	Must flush range from start to end-1 but nothing else (need to
 	 *	be careful not to touch addresses that may be unmapped).
 	 */
 GLOBAL_ENTRY(flush_icache_range)
-	UNW(.prologue)
+	.prologue
 	alloc r2=ar.pfs,2,0,0,0
 	sub r8=in1,in0,1
 	;;
 	shr.u r8=r8,5			// we flush 32 bytes per iteration
-	UNW(.save ar.lc, r3)
-	mov r3=ar.lc			// save ar.lc	
+	.save ar.lc, r3
+	mov r3=ar.lc			// save ar.lc
 	;;
 
 	.body
@@ -38,7 +33,7 @@
 	sync.i
 	;;
 	srlz.i
-	;;	
+	;;
 	mov ar.lc=r3			// restore ar.lc
 	br.ret.sptk.many rp
 END(flush_icache_range)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/idiv64.S linux/arch/ia64/lib/idiv64.S
--- v2.4.3/linux/arch/ia64/lib/idiv64.S	Mon Oct  9 17:54:56 2000
+++ linux/arch/ia64/lib/idiv64.S	Thu Apr  5 12:51:47 2001
@@ -37,28 +37,29 @@
 #define NAME		PASTE(PASTE(__,SGN),PASTE(OP,di3))
 
 GLOBAL_ENTRY(NAME)
-	UNW(.prologue)
+	.prologue
 	.regstk 2,0,0,0
 	// Transfer inputs to FP registers.
 	setf.sig f8 = in0
 	setf.sig f9 = in1
-	UNW(.fframe 16)
-	UNW(.save.f 0x20)
+	;;
+	.fframe 16
+	.save.f 0x20
 	stf.spill [sp] = f17,-16
 
 	// Convert the inputs to FP, to avoid FP software-assist faults.
 	INT_TO_FP(f8, f8)
 	;;
 
-	UNW(.save.f 0x10)
+	.save.f 0x10
 	stf.spill [sp] = f16
-	UNW(.body)
+	.body
 	INT_TO_FP(f9, f9)
 	;;
 	frcpa.s1 f17, p6 = f8, f9	// y0 = frcpa(b)
 	;;
 (p6)	fmpy.s1 f7 = f8, f17		// q0 = a*y0
-(p6)	fnma.s1 f6 = f9, f17, f1	// e0 = -b*y0 + 1 
+(p6)	fnma.s1 f6 = f9, f17, f1	// e0 = -b*y0 + 1
 	;;
 (p6)	fma.s1 f16 = f7, f6, f7		// q1 = q0*e0 + q0
 (p6)	fmpy.s1 f7 = f6, f6		// e1 = e0*e0
@@ -70,7 +71,7 @@
 (p6)	fma.s1 f6 = f17, f6, f17	// y1 = y0*e0 + y0
 	;;
 (p6)	fma.s1 f6 = f6, f7, f6		// y2 = y1*e1 + y1
-(p6)	fnma.s1 f7 = f9, f16, f8	// r = -b*q2 + a 
+(p6)	fnma.s1 f7 = f9, f16, f8	// r = -b*q2 + a
 	;;
 #ifdef MODULO
 	setf.sig f8 = in0		// f8 = a
@@ -78,7 +79,7 @@
 #endif
 (p6)	fma.s1 f17 = f7, f6, f16	// q3 = r*y2 + q2
 	;;
-	UNW(.restore sp)
+	.restore sp
 	ldf.fill f16 = [sp], 16
 	FP_TO_INT(f17, f17)		// q = trunc(q3)
 	;;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/memcpy.S linux/arch/ia64/lib/memcpy.S
--- v2.4.3/linux/arch/ia64/lib/memcpy.S	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/lib/memcpy.S	Thu Apr  5 12:51:47 2001
@@ -68,19 +68,19 @@
 	 * the more general copy routine handling arbitrary
 	 * sizes/alignment etc.
 	 */
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
+	.prologue
+	.save ar.pfs, saved_pfs
 	alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot
-	UNW(.save ar.lc, saved_lc)
+	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc
 	or t0=in0,in1
 	;;
 
 	or t0=t0,in2
-	UNW(.save pr, saved_pr)
+	.save pr, saved_pr
 	mov saved_pr=pr
 
-	UNW(.body)
+	.body
 
 	cmp.eq p6,p0=in2,r0	// zero length?
 	mov retval=in0		// return dst
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/memset.S linux/arch/ia64/lib/memset.S
--- v2.4.3/linux/arch/ia64/lib/memset.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/memset.S	Thu Apr  5 12:51:47 2001
@@ -3,14 +3,13 @@
  * Optimized version of the standard memset() function
  *
  * Return: none
- *         
  *
  * Inputs:
  *	in0:	address of buffer
  * 	in1:	byte value to use for storing
  *	in2:	length of the buffer
  *
- * Copyright (C) 1999 Hewlett-Packard Co
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  */
 
@@ -31,20 +30,16 @@
 #define saved_lc	r20
 #define tmp		r21
 
- 	.text
- 	.psr	abi64
- 	.psr	lsb
-
 GLOBAL_ENTRY(memset)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
- 	alloc	saved_pfs=ar.pfs,3,0,0,0	// cnt is sink here
+	.prologue
+	.save ar.pfs, saved_pfs
+ 	alloc saved_pfs=ar.pfs,3,0,0,0	// cnt is sink here
 	cmp.eq p8,p0=r0,len	// check for zero length
-	UNW(.save ar.lc, saved_lc)
+	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc	// preserve ar.lc (slow)
-	;; 
+	;;
 
-	UNW(.body)
+	.body
 
 	adds tmp=-1,len		// br.ctop is repeat/until
 	tbit.nz p6,p0=buf,0	// odd alignment
@@ -82,7 +77,7 @@
 (p6)	st8 [buf]=val,8		// 8-byte aligned
 (p6)	adds len=-8,len;;
 	shr.u cnt=len,4		// number of 128-bit (2x64bit) words
-	;;	
+	;;
 	cmp.eq p6,p0=r0,cnt
 	adds tmp=-1,cnt
 (p6)	br.cond.dpnt.few .dotail // we have less than 16 bytes left
@@ -96,10 +91,10 @@
 	br.cloop.dptk.few 2b
 	;;
 .dotail:			// tail correction based on len only
-	tbit.nz p6,p0=len,3	
+	tbit.nz p6,p0=len,3
 	;;
 (p6)	st8 [buf]=val,8		// at least 8 bytes
-	tbit.nz p6,p0=len,2	
+	tbit.nz p6,p0=len,2
 	;;
 (p6)	st4 [buf]=val,4		// at least 4 bytes
 	tbit.nz p6,p0=len,1
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S
--- v2.4.3/linux/arch/ia64/lib/strlen.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/ia64/lib/strlen.S	Thu Apr  5 12:51:47 2001
@@ -5,12 +5,12 @@
  *
  * Inputs:
  *	in0	address of string
- * 
- * Outputs: 
- * 	ret0	the number of characters in the string (0 if empty string)
- *         	does not count the \0
  *
- * Copyright (C) 1999 Hewlett-Packard Co
+ * Outputs:
+ *	ret0	the number of characters in the string (0 if empty string)
+ *	does not count the \0
+ *
+ * Copyright (C) 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
  * 09/24/99 S.Eranian add speculation recovery code
@@ -30,7 +30,7 @@
 //	  string may not be 8-byte aligned. In this case we load the 8byte
 //	  quantity which includes the start of the string and mask the unused
 //	  bytes with 0xff to avoid confusing czx.
-//	  We use speculative loads and software pipelining to hide memory 
+//	  We use speculative loads and software pipelining to hide memory
 //	  latency and do read ahead safely. This way we defer any exception.
 //
 //	  Because we don't want the kernel to be relying on particular
@@ -42,7 +42,7 @@
 //	  The fact that speculation may fail can be caused, for instance, by
 //	  the DCR.dm bit being set. In this case TLB misses are deferred, i.e.,
 //	  a NaT bit will be set if the translation is not present. The normal
-//	  load, on the other hand, will cause the translation to be inserted 
+//	  load, on the other hand, will cause the translation to be inserted
 //	  if the mapping exists.
 //
 //	  It should be noted that we execute recovery code only when we need
@@ -50,22 +50,22 @@
 //	  recovery code on pure read ahead data.
 //
 // Remarks:
-//	- the cmp r0,r0 is used as a fast way to initialize a predicate 
+//	- the cmp r0,r0 is used as a fast way to initialize a predicate
 //	  register to 1. This is required to make sure that we get the parallel
 //	  compare correct.
 //
 //	- we don't use the epilogue counter to exit the loop but we need to set
 //	  it to zero beforehand.
 //
-//	- after the loop we must test for Nat values because neither the 
+//	- after the loop we must test for Nat values because neither the
 //	  czx nor cmp instruction raise a NaT consumption fault. We must be
-//	  careful not to look too far for a Nat for which we don't care. 
+//	  careful not to look too far for a Nat for which we don't care.
 //	  For instance we don't need to look at a NaT in val2 if the zero byte
 //	  was in val1.
 //
 //	- Clearly performance tuning is required.
 //
-// 
+//
 //
 #define saved_pfs	r11
 #define	tmp		r10
@@ -78,15 +78,9 @@
 #define val1		r22
 #define val2		r23
 
-
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(strlen)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
+	.prologue
+	.save ar.pfs, saved_pfs
 	alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8
 
 	.rotr v[2], w[2]	// declares our 4 aliases
@@ -94,11 +88,11 @@
 	extr.u tmp=in0,0,3	// tmp=least significant 3 bits
 	mov orig=in0		// keep trackof initial byte address
 	dep src=0,in0,0,3	// src=8byte-aligned in0 address
-	UNW(.save pr, saved_pr)
+	.save pr, saved_pr
 	mov saved_pr=pr		// preserve predicates (rotation)
 	;;
 
-	UNW(.body)
+	.body
 
 	ld8 v[1]=[src],8	// must not speculate: can fail here
 	shl tmp=tmp,3		// multiply by 8bits/byte
@@ -115,8 +109,8 @@
 	or v[1]=v[1],mask	// now we have a safe initial byte pattern
 	;;
 1:
-	ld8.s v[0]=[src],8	// speculatively load next 
-	czx1.r val1=v[1]	// search 0 byte from right 
+	ld8.s v[0]=[src],8	// speculatively load next
+	czx1.r val1=v[1]	// search 0 byte from right
 	czx1.r val2=w[1]	// search 0 byte from right following 8bytes
 	;;
 	ld8.s w[0]=[src],8	// speculatively load next to next
@@ -132,11 +126,7 @@
 	//	- there must be a better way of doing the test
 	//
 	cmp.eq  p8,p9=8,val1	// p6 = val1 had zero (disambiguate)
-#ifdef notyet
 	tnat.nz p6,p7=val1	// test NaT on val1
-#else
-	tnat.z p7,p6=val1	// test NaT on val1
-#endif
 (p6)	br.cond.spnt.few recover// jump to recovery if val1 is NaT
 	;;
 	//
@@ -154,7 +144,7 @@
 	sub tmp=8,val1		// which byte in word
 	mov pr=saved_pr,0xffffffffffff0000
 	;;
-	sub ret0=ret0,tmp	// adjust 
+	sub ret0=ret0,tmp	// adjust
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
 	br.ret.sptk.few rp	// end of normal execution
 
@@ -167,8 +157,8 @@
 	//
 	// IMPORTANT:
 	// Please note that in the case of strlen() as opposed to strlen_user()
-	// we don't use the exception mechanism, as this function is not 
-	// supposed to fail. If that happens it means we have a bug and the 
+	// we don't use the exception mechanism, as this function is not
+	// supposed to fail. If that happens it means we have a bug and the
 	// code will cause of kernel fault.
 	//
 	// XXX Fixme
@@ -187,7 +177,7 @@
 2:
 (p6)	ld8 val=[base],8	// will fail if unrecoverable fault
 	;;
-	czx1.r val1=val		// search 0 byte from right 
+	czx1.r val1=val		// search 0 byte from right
 	;;
 	cmp.eq p6,p0=8,val1	// val1==8 ?
 (p6)	br.wtop.dptk.few 2b	// loop until p6 == 0
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S
--- v2.4.3/linux/arch/ia64/lib/strlen_user.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/ia64/lib/strlen_user.S	Thu Apr  5 12:51:47 2001
@@ -6,9 +6,9 @@
  *
  * Outputs:
  *	ret0	0 in case of fault, strlen(buffer)+1 otherwise
- * 
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
  * 01/19/99 S.Eranian heavily enhanced version (see details below)
@@ -24,8 +24,8 @@
 //	- length of string + 1
 //	- 0 in case an exception is raised
 //
-// This is an enhanced version of the basic strlen_user. it includes a 
-// combination of compute zero index (czx), parallel comparisons, speculative 
+// This is an enhanced version of the basic strlen_user. it includes a
+// combination of compute zero index (czx), parallel comparisons, speculative
 // loads and loop unroll using rotating registers.
 //
 // General Ideas about the algorithm:
@@ -34,7 +34,7 @@
 //	  string may not be 8-byte aligned. In this case we load the 8byte
 //	  quantity which includes the start of the string and mask the unused
 //	  bytes with 0xff to avoid confusing czx.
-//	  We use speculative loads and software pipelining to hide memory 
+//	  We use speculative loads and software pipelining to hide memory
 //	  latency and do read ahead safely. This way we defer any exception.
 //
 //	  Because we don't want the kernel to be relying on particular
@@ -45,7 +45,7 @@
 //	  The fact that speculation may fail can be caused, for instance, by
 //	  the DCR.dm bit being set. In this case TLB misses are deferred, i.e.,
 //	  a NaT bit will be set if the translation is not present. The normal
-//	  load, on the other hand, will cause the translation to be inserted 
+//	  load, on the other hand, will cause the translation to be inserted
 //	  if the mapping exists.
 //
 //	  It should be noted that we execute recovery code only when we need
@@ -53,30 +53,21 @@
 //	  recovery code on pure read ahead data.
 //
 // Remarks:
-//	- the cmp r0,r0 is used as a fast way to initialize a predicate 
+//	- the cmp r0,r0 is used as a fast way to initialize a predicate
 //	  register to 1. This is required to make sure that we get the parallel
 //	  compare correct.
 //
 //	- we don't use the epilogue counter to exit the loop but we need to set
 //	  it to zero beforehand.
 //
-//	- after the loop we must test for Nat values because neither the 
+//	- after the loop we must test for Nat values because neither the
 //	  czx nor cmp instruction raise a NaT consumption fault. We must be
-//	  careful not to look too far for a Nat for which we don't care. 
+//	  careful not to look too far for a Nat for which we don't care.
 //	  For instance we don't need to look at a NaT in val2 if the zero byte
 //	  was in val1.
 //
 //	- Clearly performance tuning is required.
 //
-// 
-//
-
-#define EX(y,x...)				\
-	.section __ex_table,"a";		\
-	data4 @gprel(99f);			\
-	data4 y-99f;				\
-	.previous;				\
-99:	x
 
 #define saved_pfs	r11
 #define	tmp		r10
@@ -89,15 +80,9 @@
 #define val1		r22
 #define val2		r23
 
-
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(__strlen_user)
-	UNW(.prologue)
-	UNW(.save ar.pfs, saved_pfs)
+	.prologue
+	.save ar.pfs, saved_pfs
 	alloc saved_pfs=ar.pfs,11,0,0,8
 
 	.rotr v[2], w[2]	// declares our 4 aliases
@@ -105,7 +90,7 @@
 	extr.u tmp=in0,0,3	// tmp=least significant 3 bits
 	mov orig=in0		// keep trackof initial byte address
 	dep src=0,in0,0,3	// src=8byte-aligned in0 address
-	UNW(.save pr, saved_pr)
+	.save pr, saved_pr
 	mov saved_pr=pr		// preserve predicates (rotation)
 	;;
 
@@ -127,8 +112,8 @@
 	or v[1]=v[1],mask	// now we have a safe initial byte pattern
 	;;
 1:
-	ld8.s v[0]=[src],8	// speculatively load next 
-	czx1.r val1=v[1]	// search 0 byte from right 
+	ld8.s v[0]=[src],8	// speculatively load next
+	czx1.r val1=v[1]	// search 0 byte from right
 	czx1.r val2=w[1]	// search 0 byte from right following 8bytes
 	;;
 	ld8.s w[0]=[src],8	// speculatively load next to next
@@ -144,11 +129,7 @@
 	//	- there must be a better way of doing the test
 	//
 	cmp.eq  p8,p9=8,val1	// p6 = val1 had zero (disambiguate)
-#ifdef notyet
 	tnat.nz p6,p7=val1	// test NaT on val1
-#else
-	tnat.z p7,p6=val1	// test NaT on val1
-#endif
 (p6)	br.cond.spnt.few recover// jump to recovery if val1 is NaT
 	;;
 	//
@@ -193,7 +174,7 @@
 2:
 	EX(.Lexit1, (p6) ld8 val=[base],8)
 	;;
-	czx1.r val1=val		// search 0 byte from right 
+	czx1.r val1=val		// search 0 byte from right
 	;;
 	cmp.eq p6,p0=8,val1	// val1==8 ?
 (p6)	br.wtop.dptk.few 2b	// loop until p6 == 0
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/strncpy_from_user.S linux/arch/ia64/lib/strncpy_from_user.S
--- v2.4.3/linux/arch/ia64/lib/strncpy_from_user.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/strncpy_from_user.S	Thu Apr  5 12:51:47 2001
@@ -8,9 +8,9 @@
  *	in2:	length of buffer in bytes
  * Outputs:
  *	r8:	-EFAULT in case of fault or number of bytes copied if no fault
- * 
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 00/03/06 D. Mosberger Fixed to return proper return value (bug found by
  *			 by Andreas Schwab <schwab@suse.de>).
@@ -18,18 +18,6 @@
 
 #include <asm/asmmacro.h>
 
-#define EX(x...)				\
-99:	x;					\
-	.section __ex_table,"a";		\
-	data4 @gprel(99b);			\
-	data4 .Lexit-99b;			\
-	.previous
-
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(__strncpy_from_user)
 	alloc r2=ar.pfs,3,0,0,0
 	mov r8=0
@@ -41,15 +29,16 @@
 
 	// XXX braindead copy loop---this needs to be optimized
 .Loop1:
-	EX(ld1 r8=[in1],1;; st1 [in0]=r8,1; cmp.ne p6,p7=r8,r0)
+	EX(.Lexit, ld1 r8=[in1],1)
+	;;
+	EX(.Lexit, st1 [in0]=r8,1)
+	cmp.ne p6,p7=r8,r0
 	;;
 (p6)	cmp.ne.unc p8,p0=in1,r10
 (p8)	br.cond.dpnt.few .Loop1
 	;;
 (p6)	mov r8=in2		// buffer filled up---return buffer length
 (p7)	sub r8=in1,r9,1		// return string length (excluding NUL character)
-	br.ret.sptk.few rp
-
-.Lexit:
+[.Lexit:]
 	br.ret.sptk.few rp
 END(__strncpy_from_user)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/strnlen_user.S linux/arch/ia64/lib/strnlen_user.S
--- v2.4.3/linux/arch/ia64/lib/strnlen_user.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/strnlen_user.S	Thu Apr  5 12:51:47 2001
@@ -8,41 +8,28 @@
  *	in1:	string length limit N
  * Outputs:
  *	r8:	0 in case of fault, strlen(buffer)+1 otherwise
- * 
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <asm/asmmacro.h>
 
-/* If a fault occurs, r8 gets set to -EFAULT and r9 gets cleared.  */
-#define EX(x...)				\
-	.section __ex_table,"a";		\
-	data4 @gprel(99f);			\
-	data4 (.Lexit-99f)|1;			\
-	.previous				\
-99:	x;
-
-	.text
-	.psr abi64
-	.psr lsb
-	.lsb
-
 GLOBAL_ENTRY(__strnlen_user)
-	UNW(.prologue)
+	.prologue
 	alloc r2=ar.pfs,2,0,0,0
-	UNW(.save ar.lc, r16)
+	.save ar.lc, r16
 	mov r16=ar.lc			// preserve ar.lc
 
-	UNW(.body)
+	.body
 
 	add r3=-1,in1
 	;;
 	mov ar.lc=r3
 	mov r9=0
-
+	;;
 	// XXX braindead strlen loop---this needs to be optimized
 .Loop1:
-	EX(ld1 r8=[in0],1)
+	EXCLR(.Lexit, ld1 r8=[in0],1)
 	add r9=1,r9
 	;;
 	cmp.eq p6,p0=r8,r0
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/lib/swiotlb.c linux/arch/ia64/lib/swiotlb.c
--- v2.4.3/linux/arch/ia64/lib/swiotlb.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/lib/swiotlb.c	Thu Apr  5 12:51:47 2001
@@ -11,6 +11,7 @@
  */
 
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -50,14 +51,14 @@
 static unsigned int io_tlb_index;
 
 /*
- * We need to save away the original address corresponding to a mapped entry for the sync 
+ * We need to save away the original address corresponding to a mapped entry for the sync
  * operations.
  */
 static unsigned char **io_tlb_orig_addr;
 
 /*
  * Protect the above data structures in the map and unmap calls
- */ 
+ */
 static spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED;
 
 static int __init
@@ -132,7 +133,7 @@
 	{
 		wrap = index = ALIGN(io_tlb_index, stride);
 
-		if (index >= io_tlb_nslabs) 
+		if (index >= io_tlb_nslabs)
 			wrap = index = 0;
 
 		do {
@@ -164,12 +165,12 @@
 		} while (index != wrap);
 
 		/*
-		 * XXX What is a suitable recovery mechanism here?  We cannot 
+		 * XXX What is a suitable recovery mechanism here?  We cannot
 		 * sleep because we are called from with in interrupts!
 		 */
 		panic("map_single: could not allocate software IO TLB (%ld bytes)", size);
-found:
 	}
+  found:
 	spin_unlock_irqrestore(&io_tlb_lock, flags);
 
 	/*
@@ -199,9 +200,9 @@
 	 */
 	if ((direction == PCI_DMA_FROMDEVICE) || (direction == PCI_DMA_BIDIRECTIONAL))
 		/*
- 	 	 * bounce... copy the data back into the original buffer * and delete the
- 	 	 * bounce buffer.
- 	 	 */
+		 * bounce... copy the data back into the original buffer * and delete the
+		 * bounce buffer.
+		 */
 		memcpy(buffer, dma_addr, size);
 
 	/*
@@ -236,9 +237,9 @@
 	char *buffer = io_tlb_orig_addr[index];
 
 	/*
-  	 * bounce... copy the data back into/from the original buffer
+	 * bounce... copy the data back into/from the original buffer
 	 * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ?
- 	 */
+	 */
 	if (direction == PCI_DMA_FROMDEVICE)
 		memcpy(buffer, dma_addr, size);
 	else if (direction == PCI_DMA_TODEVICE)
@@ -298,8 +299,8 @@
 		 */
 		return pci_addr;
 
-	/* 
-	 * get a bounce buffer: 
+	/*
+	 * get a bounce buffer:
 	 */
 	pci_addr = virt_to_phys(map_single(hwdev, ptr, size, direction));
 
@@ -325,12 +326,8 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-#if 0
-		set_bit(PG_arch_1, virt_to_page(pg_addr));
-#else
-		if (!VALID_PAGE(virt_to_page(pg_addr)))
-			printk("Invalid addr %lx!!!\n", pg_addr);
-#endif
+		struct page *page = virt_to_page(pg_addr);
+		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
 }
@@ -454,3 +451,14 @@
 {
 	return virt_to_phys(sg->address);
 }
+
+EXPORT_SYMBOL(swiotlb_init);
+EXPORT_SYMBOL(swiotlb_map_single);
+EXPORT_SYMBOL(swiotlb_unmap_single);
+EXPORT_SYMBOL(swiotlb_map_sg);
+EXPORT_SYMBOL(swiotlb_unmap_sg);
+EXPORT_SYMBOL(swiotlb_sync_single);
+EXPORT_SYMBOL(swiotlb_sync_sg);
+EXPORT_SYMBOL(swiotlb_dma_address);
+EXPORT_SYMBOL(swiotlb_alloc_consistent);
+EXPORT_SYMBOL(swiotlb_free_consistent);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/mm/extable.c linux/arch/ia64/mm/extable.c
--- v2.4.3/linux/arch/ia64/mm/extable.c	Sun Feb  6 18:42:40 2000
+++ linux/arch/ia64/mm/extable.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Kernel exception handling table support.  Derived from arch/alpha/mm/extable.c.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>
@@ -43,14 +43,22 @@
         return 0;
 }
 
-register unsigned long gp __asm__("gp");
+#ifndef CONFIG_MODULE
+register unsigned long main_gp __asm__("gp");
+#endif
 
-const struct exception_table_entry *
+struct exception_fixup
 search_exception_table (unsigned long addr)
 {
+	const struct exception_table_entry *entry;
+	struct exception_fixup fix = { 0 };
+
 #ifndef CONFIG_MODULE
 	/* There is only the kernel to search.  */
-	return search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp);
+	entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - main_gp);
+	if (entry)
+		fix.cont = entry->cont + main_gp;
+	return fix;
 #else
 	struct exception_table_entry *ret;
 	/* The kernel is the last "module" -- no need to treat it special. */
@@ -59,10 +67,22 @@
 	for (mp = module_list; mp ; mp = mp->next) {
 		if (!mp->ex_table_start)
 			continue;
-		ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp);
-		if (ret)
-			return ret;
+		entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp);
+		if (entry) {
+			fix.cont = entry->cont + mp->gp;
+			return fix;
+		}
 	}
-	return 0;
 #endif
+	return fix;
+}
+
+void
+handle_exception (struct pt_regs *regs, struct exception_fixup fix)
+{
+	regs->r8 = -EFAULT;
+	if (fix.cont & 4)
+		regs->r9 = 0;
+	regs->cr_iip = (long) fix.cont & ~0xf;
+	ia64_psr(regs)->ri = fix.cont & 0x3;		/* set continuation slot number */
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c
--- v2.4.3/linux/arch/ia64/mm/fault.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/ia64/mm/fault.c	Thu Apr  5 12:51:47 2001
@@ -47,7 +47,7 @@
 ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs)
 {
 	struct mm_struct *mm = current->mm;
-	const struct exception_table_entry *fix;
+	struct exception_fixup fix;
 	struct vm_area_struct *vma, *prev_vma;
 	struct siginfo si;
 	int signal = SIGSEGV;
@@ -163,14 +163,13 @@
 		return;
 	}
 
+#ifdef GAS_HAS_LOCAL_TAGS
+	fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri);
+#else
 	fix = search_exception_table(regs->cr_iip);
-	if (fix) {
-		regs->r8 = -EFAULT;
-		if (fix->skip & 1) {
-			regs->r9 = 0;
-		}
-		regs->cr_iip += ((long) fix->skip) & ~15;
-		regs->cr_ipsr &= ~IA64_PSR_RI;	/* clear exception slot number */
+#endif
+	if (fix.cont) {
+		handle_exception(regs, fix);
 		return;
 	}
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c
--- v2.4.3/linux/arch/ia64/mm/init.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/mm/init.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Initialize MMU support.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -23,116 +23,33 @@
 #include <asm/pgalloc.h>
 #include <asm/sal.h>
 #include <asm/system.h>
+#include <asm/uaccess.h>
 
 /* References to section boundaries: */
 extern char _stext, _etext, _edata, __init_begin, __init_end;
 
-/*
- * These are allocated in head.S so that we get proper page alignment.
- * If you change the size of these then change head.S as well.
- */
-extern char empty_bad_page[PAGE_SIZE];
-extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD];
-extern pte_t empty_bad_pte_table[PTRS_PER_PTE];
-
 extern void ia64_tlb_init (void);
 
-static unsigned long totalram_pages;
-
-/*
- * Fill in empty_bad_pmd_table with entries pointing to
- * empty_bad_pte_table and return the address of this PMD table.
- */
-static pmd_t *
-get_bad_pmd_table (void)
-{
-	pmd_t v;
-	int i;
-
-	pmd_set(&v, empty_bad_pte_table);
+unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
 
-	for (i = 0; i < PTRS_PER_PMD; ++i)
-		empty_bad_pmd_table[i] = v;
-
-	return empty_bad_pmd_table;
-}
-
-/*
- * Fill in empty_bad_pte_table with PTEs pointing to empty_bad_page
- * and return the address of this PTE table.
- */
-static pte_t *
-get_bad_pte_table (void)
-{
-	pte_t v;
-	int i;
-
-	set_pte(&v, pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)));
-
-	for (i = 0; i < PTRS_PER_PTE; ++i)
-		empty_bad_pte_table[i] = v;
-
-	return empty_bad_pte_table;
-}
-
-void
-__handle_bad_pgd (pgd_t *pgd)
-{
-	pgd_ERROR(*pgd);
-	pgd_set(pgd, get_bad_pmd_table());
-}
-
-void
-__handle_bad_pmd (pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-	pmd_set(pmd, get_bad_pte_table());
-}
-
-/*
- * Allocate and initialize an L3 directory page and set
- * the L2 directory entry PMD to the newly allocated page.
- */
-pte_t*
-get_pte_slow (pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			/* everything A-OK */
-			clear_page(pte);
-			pmd_set(pmd, pte);
-			return pte + offset;
-		}
-		pmd_set(pmd, get_bad_pte_table());
-		return NULL;
-	}
-	free_page((unsigned long) pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
+static unsigned long totalram_pages;
 
 int
 do_check_pgt_cache (int low, int high)
 {
 	int freed = 0;
 
-        if (pgtable_cache_size > high) {
-                do {
-                        if (pgd_quicklist)
-                                free_page((unsigned long)get_pgd_fast()), ++freed;
-                        if (pmd_quicklist)
-                                free_page((unsigned long)get_pmd_fast()), ++freed;
-                        if (pte_quicklist)
-                                free_page((unsigned long)get_pte_fast()), ++freed;
-                } while (pgtable_cache_size > low);
-        }
-        return freed;
+	if (pgtable_cache_size > high) {
+		do {
+			if (pgd_quicklist)
+				free_page((unsigned long)pgd_alloc_one_fast()), ++freed;
+			if (pmd_quicklist)
+				free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed;
+			if (pte_quicklist)
+				free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed;
+		} while (pgtable_cache_size > low);
+	}
+	return freed;
 }
 
 /*
@@ -188,12 +105,12 @@
 {
 	/*
 	 * EFI uses 4KB pages while the kernel can use 4KB  or bigger.
-	 * Thus EFI and the kernel may have different page sizes. It is 
-	 * therefore possible to have the initrd share the same page as 
-	 * the end of the kernel (given current setup). 
+	 * Thus EFI and the kernel may have different page sizes. It is
+	 * therefore possible to have the initrd share the same page as
+	 * the end of the kernel (given current setup).
 	 *
 	 * To avoid freeing/using the wrong page (kernel sized) we:
-	 * 	- align up the beginning of initrd
+	 *	- align up the beginning of initrd
 	 *	- keep the end untouched
 	 *
 	 *  |             |
@@ -201,8 +118,8 @@
 	 *  |             |
 	 *  |             |
 	 *  |             | 9000
-	 *  |/////////////| 
-	 *  |/////////////| 
+	 *  |/////////////|
+	 *  |/////////////|
 	 *  |=============| 8000
 	 *  |///INITRD////|
 	 *  |/////////////|
@@ -211,9 +128,9 @@
 	 *  |KKKKKKKKKKKKK|
 	 *  |=============| 6000
 	 *  |KKKKKKKKKKKKK|
-	 *  |KKKKKKKKKKKKK| 
+	 *  |KKKKKKKKKKKKK|
 	 *  K=kernel using 8KB pages
-	 * 
+	 *
 	 * In this example, we must free page 8000 ONLY. So we must align up
 	 * initrd_start and keep initrd_end as is.
 	 */
@@ -286,52 +203,59 @@
 		       page_address(page));
 
 	pgd = pgd_offset_k(address);		/* note: this is NOT pgd_offset()! */
-	pmd = pmd_alloc(pgd, address);
-	if (!pmd) {
-		__free_page(page);
-		panic("Out of memory.");
-		return 0;
-	}
-	pte = pte_alloc(pmd, address);
-	if (!pte) {
-		__free_page(page);
-		panic("Out of memory.");
-		return 0;
-	}
-	if (!pte_none(*pte)) {
-		pte_ERROR(*pte);
-		__free_page(page);
-		return 0;
+
+	spin_lock(&init_mm.page_table_lock);
+	{
+		pmd = pmd_alloc(&init_mm, pgd, address);
+		if (!pmd)
+			goto out;
+		pte = pte_alloc(&init_mm, pmd, address);
+		if (!pte)
+			goto out;
+		if (!pte_none(*pte)) {
+			pte_ERROR(*pte);
+			goto out;
+		}
+		flush_page_to_ram(page);
+		set_pte(pte, mk_pte(page, PAGE_GATE));
 	}
-	flush_page_to_ram(page);
-	set_pte(pte, mk_pte(page, PAGE_GATE));
+  out:	spin_unlock(&init_mm.page_table_lock);
 	/* no need for flush_tlb */
 	return page;
 }
 
 void __init
-ia64_rid_init (void)
+ia64_mmu_init (void)
 {
 	unsigned long flags, rid, pta, impl_va_bits;
+	extern void __init tlb_init (void);
 #ifdef CONFIG_DISABLE_VHPT
 #	define VHPT_ENABLE_BIT	0
 #else
 #	define VHPT_ENABLE_BIT	1
 #endif
 
-	/* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */
+	/*
+	 * Set up the kernel identity mapping for regions 6 and 5.  The mapping for region
+	 * 7 is setup up in _start().
+	 */
 	ia64_clear_ic(flags);
 
 	rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET);
-	ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2));
-
-	rid = ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET);
-	ia64_set_rr(PAGE_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2));
+	ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_64M << 2));
 
 	rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START);
 	ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1);
 
+	/* ensure rr6 is up-to-date before inserting the PERCPU_ADDR translation: */
+	ia64_srlz_d();
+
+	ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
+		 pte_val(mk_pte_phys(__pa(&cpu_data[smp_processor_id()]), PAGE_KERNEL)),
+		 PAGE_SHIFT);
+
 	__restore_flags(flags);
+	ia64_srlz_i();
 
 	/*
 	 * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped
@@ -356,7 +280,7 @@
 #	define vmlpt_bits		(impl_va_bits - PAGE_SHIFT + pte_bits)
 #	define POW2(n)			(1ULL << (n))
 
-	impl_va_bits = ffz(~my_cpu_data.unimpl_va_mask);
+	impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61)));
 
 	if (impl_va_bits < 51 || impl_va_bits > 61)
 		panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1);
@@ -374,6 +298,8 @@
 	 * enabled.
 	 */
 	ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT);
+
+	ia64_tlb_init();
 }
 
 /*
@@ -390,7 +316,7 @@
 
 	memset(zones_size, 0, sizeof(zones_size));
 
-	max_dma = (PAGE_ALIGN(MAX_DMA_ADDRESS) >> PAGE_SHIFT);
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 	if (max_low_pfn < max_dma)
 		zones_size[ZONE_DMA] = max_low_pfn;
 	else {
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c
--- v2.4.3/linux/arch/ia64/mm/tlb.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/mm/tlb.c	Thu Apr  5 12:51:47 2001
@@ -1,11 +1,11 @@
 /*
  * TLB support routines.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
- * 08/02/00 A. Mallick <asit.k.mallick@intel.com>	
- *		Modified RID allocation for SMP 
+ * 08/02/00 A. Mallick <asit.k.mallick@intel.com>
+ *		Modified RID allocation for SMP
  *          Goutham Rao <goutham.rao@intel.com>
  *              IPI based ptc implementation and A-step IPI implementation.
  */
@@ -41,7 +41,7 @@
 };
 
 /*
- * Seralize usage of ptc.g 
+ * Seralize usage of ptc.g
  */
 spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see <asm/pgtable.h> */
 
@@ -49,7 +49,7 @@
 
 #include <linux/irq.h>
 
-unsigned long 	flush_end, flush_start, flush_nbits, flush_rid;
+unsigned long	flush_end, flush_start, flush_nbits, flush_rid;
 atomic_t flush_cpu_count;
 
 /*
@@ -71,7 +71,7 @@
 	if (!(flags & IA64_PSR_I)) {
 		saved_tpr = ia64_get_tpr();
 		ia64_srlz_d();
-		ia64_set_tpr(IPI_IRQ - 16);
+		ia64_set_tpr(IA64_IPI_VECTOR - 16);
 		ia64_srlz_d();
 		local_irq_enable();
 	}
@@ -97,13 +97,14 @@
 	/*
 	 * Wait for other CPUs to finish purging entries.
 	 */
-#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC))
+#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)
 	{
+		extern void smp_resend_flush_tlb (void);
 		unsigned long start = ia64_get_itc();
+
 		while (atomic_read(&flush_cpu_count) > 0) {
-			if ((ia64_get_itc() - start) > 40000UL) {
-				atomic_set(&flush_cpu_count, smp_num_cpus - 1);
-				smp_send_flush_tlb();
+			if ((ia64_get_itc() - start) > 400000UL) {
+				smp_resend_flush_tlb();
 				start = ia64_get_itc();
 			}
 		}
@@ -148,7 +149,7 @@
 		if (tsk_context == ia64_ctx.next) {
 			if (++ia64_ctx.next >= ia64_ctx.limit) {
 				/* empty range: reset the range limit and start over */
-				if (ia64_ctx.next > max_ctx) 
+				if (ia64_ctx.next > max_ctx)
 					ia64_ctx.next = 300;
 				ia64_ctx.limit = max_ctx + 1;
 				goto repeat;
@@ -166,11 +167,11 @@
 {
 	unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
 
-	addr    = my_cpu_data.ptce_base;
-	count0  = my_cpu_data.ptce_count[0];
-	count1  = my_cpu_data.ptce_count[1];
-	stride0 = my_cpu_data.ptce_stride[0];
-	stride1 = my_cpu_data.ptce_stride[1];
+	addr    = local_cpu_data->ptce_base;
+	count0  = local_cpu_data->ptce_count[0];
+	count1  = local_cpu_data->ptce_count[1];
+	stride0 = local_cpu_data->ptce_stride[0];
+	stride1 = local_cpu_data->ptce_stride[1];
 
 	local_irq_save(flags);
 	for (i = 0; i < count0; ++i) {
@@ -249,11 +250,11 @@
 	ia64_ptce_info_t ptce_info;
 
 	ia64_get_ptce(&ptce_info);
-	my_cpu_data.ptce_base = ptce_info.base;
-	my_cpu_data.ptce_count[0] = ptce_info.count[0];
-	my_cpu_data.ptce_count[1] = ptce_info.count[1];
-	my_cpu_data.ptce_stride[0] = ptce_info.stride[0];
-	my_cpu_data.ptce_stride[1] = ptce_info.stride[1];
+	local_cpu_data->ptce_base = ptce_info.base;
+	local_cpu_data->ptce_count[0] = ptce_info.count[0];
+	local_cpu_data->ptce_count[1] = ptce_info.count[1];
+	local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
+	local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
 
 	__flush_tlb_all();		/* nuke left overs from bootstrapping... */
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/Makefile linux/arch/ia64/sn/Makefile
--- v2.4.3/linux/arch/ia64/sn/Makefile	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/Makefile	Thu Apr  5 12:51:47 2001
@@ -8,12 +8,11 @@
 EXTRA_CFLAGS	:= -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \
 		   -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \
 		   -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \
-		   -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO
+		   -DNEW_INTERRUPTS
 all: sn.a
 
 O_TARGET        = sn.a
-O_HEADERS       =
-O_OBJS          = sn1/sn1.a
+obj-y           = sn1/sn1.a
 
 clean::
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/fprom/Makefile linux/arch/ia64/sn/fprom/Makefile
--- v2.4.3/linux/arch/ia64/sn/fprom/Makefile	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/fprom/Makefile	Thu Apr  5 12:51:47 2001
@@ -13,6 +13,7 @@
 LIB     = ../../lib/lib.a
 
 OBJ=fpromasm.o main.o  fw-emu.o fpmem.o
+obj-y=fprom
 
 fprom: $(OBJ)
 	$(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/fprom/fw-emu.c linux/arch/ia64/sn/fprom/fw-emu.c
--- v2.4.3/linux/arch/ia64/sn/fprom/fw-emu.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/fprom/fw-emu.c	Thu Apr 12 12:16:35 2001
@@ -8,6 +8,7 @@
  * Copyright (C) 2000 Silicon Graphics, Inc.
  * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com)
  */
+
 #include <asm/efi.h>
 #include <asm/pal.h>
 #include <asm/sal.h>
@@ -62,6 +63,7 @@
 func_ptr_t	ap_entry;
 
 
+static efi_runtime_services_t    *efi_runtime_p;
 static char fw_mem[(  sizeof(efi_system_table_t)
 		    + sizeof(efi_runtime_services_t)
 		    + NUM_EFI_DESCS*sizeof(efi_config_table_t)
@@ -88,8 +90,8 @@
 	.text
 	.proc pal_emulator_static
 pal_emulator_static:
-	mov r8=-1
-	cmp.eq p6,p7=6,r28		/* PAL_PTCE_INFO */
+	mov r8=-1;;
+	cmp.eq p6,p7=6,r28;;		/* PAL_PTCE_INFO */
 (p7)	br.cond.sptk.few 1f
 	;;
 	mov r8=0			/* status = 0 */
@@ -98,20 +100,20 @@
 	movl r11=0x1000000000002000	/* stride[0], stride[1] */
 	br.cond.sptk.few rp
 
-1:	cmp.eq p6,p7=14,r28		/* PAL_FREQ_RATIOS */
-(p7)	br.cond.sptk.few 1f
+1:	cmp.eq p6,p7=14,r28;;		/* PAL_FREQ_RATIOS */
+(p7)	br.cond.sptk.few 1f;;
 	mov r8=0			/* status = 0 */
 	movl r9 =0x100000064		/* proc_ratio (1/100) */
 	movl r10=0x100000100		/* bus_ratio<<32 (1/256) */
 	movl r11=0x10000000a		/* itc_ratio<<32 (1/100) */
 
-1:	cmp.eq p6,p7=22,r28		/* PAL_MC_DRAIN */
-(p7)	br.cond.sptk.few 1f
+1:	cmp.eq p6,p7=22,r28;;		/* PAL_MC_DRAIN */
+(p7)	br.cond.sptk.few 1f;;
 	mov r8=0
 	br.cond.sptk.few rp
 
-1:	cmp.eq p6,p7=23,r28		/* PAL_MC_EXPECTED */
-(p7)	br.cond.sptk.few 1f
+1:	cmp.eq p6,p7=23,r28;;		/* PAL_MC_EXPECTED */
+(p7)	br.cond.sptk.few 1f;;
 	mov r8=0
 	br.cond.sptk.few rp
 
@@ -256,6 +258,36 @@
 	_fp->gp = __fwtab_pa(base_nasid, _fp->gp);
 }
 
+void
+fix_virt_function_pointer(void *fptr)
+{
+        func_ptr_t      *fp;
+
+        fp = fptr;
+        fp->pc = fp->pc | PAGE_OFFSET;
+        fp->gp = fp->gp | PAGE_OFFSET;
+}
+
+
+int
+efi_set_virtual_address_map(void)
+{
+        efi_runtime_services_t            *runtime;
+
+        runtime = efi_runtime_p;
+        fix_virt_function_pointer((void*)runtime->get_time);
+        fix_virt_function_pointer((void*)runtime->set_time);
+        fix_virt_function_pointer((void*)runtime->get_wakeup_time);
+        fix_virt_function_pointer((void*)runtime->set_wakeup_time);
+        fix_virt_function_pointer((void*)runtime->set_virtual_address_map);
+        fix_virt_function_pointer((void*)runtime->get_variable);
+        fix_virt_function_pointer((void*)runtime->get_next_variable);
+        fix_virt_function_pointer((void*)runtime->set_variable);
+        fix_virt_function_pointer((void*)runtime->get_next_high_mono_count);
+        fix_virt_function_pointer((void*)runtime->reset_system);
+        return EFI_SUCCESS;;
+}
+
 
 void
 sys_fw_init (const char *args, int arglen, int bsp)
@@ -305,7 +337,7 @@
 
 	cp = fw_mem;
 	efi_systab  = (void *) cp; cp += sizeof(*efi_systab);
-	efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
+	efi_runtime_p = efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
 	efi_tables  = (void *) cp; cp += NUM_EFI_DESCS*sizeof(*efi_tables);
 	sal_systab  = (void *) cp; cp += sizeof(*sal_systab);
 	sal_ed      = (void *) cp; cp += sizeof(*sal_ed);
@@ -354,7 +386,7 @@
 	efi_runtime->set_time = __fwtab_pa(base_nasid, &efi_unimplemented);
 	efi_runtime->get_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented);
 	efi_runtime->set_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented);
-	efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_success);
+	efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_set_virtual_address_map);
 	efi_runtime->get_variable = __fwtab_pa(base_nasid, &efi_unimplemented);
 	efi_runtime->get_next_variable = __fwtab_pa(base_nasid, &efi_unimplemented);
 	efi_runtime->set_variable = __fwtab_pa(base_nasid, &efi_unimplemented);
@@ -370,10 +402,11 @@
 	fix_function_pointer(&efi_get_time);
 	fix_function_pointer(&efi_success);
 	fix_function_pointer(&efi_reset_system);
+	fix_function_pointer(&efi_set_virtual_address_map);
 
 	/* fill in the ACPI system table: */
 	memcpy(acpi_systab->signature, "RSD PTR ", 8);
-	acpi_systab->rsdt = (acpi_rsdt_t*)__fwtab_pa(base_nasid, acpi_rsdt);
+	acpi_systab->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt);
 
 	memcpy(acpi_rsdt->header.signature, "RSDT",4);
 	acpi_rsdt->header.length = sizeof(acpi_rsdt_t);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/Makefile linux/arch/ia64/sn/io/Makefile
--- v2.4.3/linux/arch/ia64/sn/io/Makefile	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/Makefile	Thu Apr  5 12:51:47 2001
@@ -18,15 +18,15 @@
 EXTRA_CFLAGS	:= -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \
 		   -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \
 		   -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \
-		   -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO
+		   -DNEW_INTERRUPTS
 O_TARGET := sgiio.o
-O_OBJS   := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \
-		klgraph_hack.o io.o hubdev.o \
+obj-y   := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \
+		klgraph_hack.o io.o hubdev.o huberror.o \
 		hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \
 		module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \
-		ml_SN_intr.o ip37.o \
+		ml_SN_intr.o ip37.o pciba.o \
 		ml_iograph.o hcl_util.o cdl.o \
 		mem_refcnt.o devsupport.o alenlist.o pci_bus_cvlink.o \
-		eeprom.o pci.o pci_dma.o l1.o l1_command.o
+		eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/alenlist.c linux/arch/ia64/sn/io/alenlist.c
--- v2.4.3/linux/arch/ia64/sn/io/alenlist.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/alenlist.c	Thu Apr  5 12:51:47 2001
@@ -201,8 +201,8 @@
 int alenlist_count=0;		/* Currently allocated Lists */
 int alenlist_chunk_count = 0;	/* Currently allocated chunks */
 int alenlist_cursor_count = 0;	/* Currently allocate cursors */
-#define INCR_COUNT(ptr) atomicAddInt((ptr), 1);
-#define DECR_COUNT(ptr) atomicAddInt((ptr), -1);
+#define INCR_COUNT(ptr) atomic_inc((ptr));
+#define DECR_COUNT(ptr) atomic_dec((ptr));
 #else
 #define INCR_COUNT(ptr)
 #define DECR_COUNT(ptr)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/cdl.c linux/arch/ia64/sn/io/cdl.c
--- v2.4.3/linux/arch/ia64/sn/io/cdl.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/cdl.c	Thu Apr  5 12:51:47 2001
@@ -67,7 +67,7 @@
 void
 cdl_del(cdl_p reg)
 {
-	printk("SGI IO INFRASTRUCTURE - cdl_del not supported.\n");
+	return;
 }
 
 /*
@@ -77,7 +77,7 @@
   Do nothing.
  */
 int
-cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags)
+cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags, cdl_drv_f *func)
 {
     return 0;
 }
@@ -86,11 +86,9 @@
  * cdl_del_driver: Not supported.
  */
 void
-cdl_del_driver(cdl_p reg,
-	       char *prefix)
+cdl_del_driver(cdl_p reg, char *prefix, cdl_drv_f *func)
 {
-
-	printk("SGI IO INFRASTRUCTURE - cdl_del_driver not supported.\n");
+	return;
 }
 
 /*
@@ -106,7 +104,7 @@
  */
 int
 cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, 
-	       devfs_handle_t connpt)
+	       devfs_handle_t connpt, int drv_flags)
 {
 	int i;
 	
@@ -123,27 +121,12 @@
 			if (sgi_infrastructure_drivers[i].attach) {
 			    return(sgi_infrastructure_drivers[i].attach(connpt));
 			}
-#ifdef BRINGUP
-			/*
-			 * XXX HACK ALERT bypassing fops for now..
-			 */
-			else {
-			    printk("cdl_add_connpt: NEED FOPS FOR OUR DRIVERS!!\n");
-			    printk("cdl_add_connpt: part_num= 0x%x  mfg_num= 0x%x\n",
-				part_num, mfg_num);
-			    return(-1);
-			}
-#endif /* BRINGUP */
 		} else {
 			continue;
 		}
-
-		printk("**** cdl_add_connpt: driver not found for part_num %d mfg_num %d ****\n", part_num, mfg_num);
-
-		return(-1);
 	}	
-	if ( (i == MAX_SGI_IO_INFRA_DRVR) ) 
-		printk("**** cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x ****\n", part_num, mfg_num);
+
+	/* printk("WARNING: cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x\n", part_num, mfg_num); */
 
 	return (0);
 }
@@ -151,11 +134,11 @@
 /*
  * cdl_del_connpt: Not implemented.
  */
-void
-cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt)
+int
+cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt, int drv_flags)
 {
 
-	printk("SGI IO INFRASTRUCTURE - cdl_del_cdl_del_connpt not supported.\n");
+	return(0);
 }
 
 /*
@@ -166,65 +149,54 @@
 	    char *prefix,
 	    cdl_iter_f * func)
 {
-
-	printk("SGI IO INFRASTRUCTURE - cdl_iterate not supported.\n");
+	return;
 }
 
 async_attach_t 
 async_attach_new(void)
 {
 
-	printk("SGI IO INFRASTRUCTURE - async_attach_new not supported.\n");
 	return(0);
 }
 
 void 
 async_attach_free(async_attach_t aa)
 {
-	printk("SGI IO INFRASTRUCTURE - async_attach_free not supported.\n");
+	return;
 }
 
 async_attach_t 
 async_attach_get_info(devfs_handle_t vhdl)
 {
 
-	printk("SGI IO INFRASTRUCTURE - async_attach_get_info not supported.\n");
 	return(0);
 }
 
 void            
 async_attach_add_info(devfs_handle_t vhdl, async_attach_t aa)
 {
-	printk("SGI IO INFRASTRUCTURE - async_attach_add_info not supported.\n");
+	return;
 
 }
 
 void            
 async_attach_del_info(devfs_handle_t vhdl)
 {
-
-	printk("SGI IO INFRASTRUCTURE - async_attach_del_info not supported.\n");
-
+	return;
 }
 
 void async_attach_signal_start(async_attach_t aa)
 {
-
-	printk("SGI IO INFRASTRUCTURE - async_attach_signal_start not supported.\n");
-
+	return;
 }
 
 void async_attach_signal_done(async_attach_t aa)
 {
-
-	printk("SGI IO INFRASTRUCTURE - async_attach_signal_done not supported.\n");
-
+	return;
 }
 
 void async_attach_waitall(async_attach_t aa)
 {
-
-	printk("SGI IO INFRASTRUCTURE - async_attach_waitall not supported.\n");
-
+	return;
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/devsupport.c linux/arch/ia64/sn/io/devsupport.c
--- v2.4.3/linux/arch/ia64/sn/io/devsupport.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/devsupport.c	Thu Apr  5 12:51:47 2001
@@ -1,5 +1,3 @@
-#define ilvt_t int
-
 /* $Id$
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -28,7 +26,7 @@
 /* =====Generic iobus support===== */
 
 /* String table to hold names of interrupts. */
-#ifdef notyet
+#ifdef LATER
 static struct string_table device_desc_string_table;
 #endif
 
@@ -36,7 +34,7 @@
 static void
 device_desc_init(void)
 {
-#ifdef notyet
+#ifdef LATER
 	string_table_init(&device_desc_string_table);
 #endif
 	FIXME("device_desc_init");
@@ -47,7 +45,7 @@
 static device_desc_t
 device_desc_alloc(void)
 {
-#ifdef notyet
+#ifdef LATER
 	device_desc_t device_desc;
 
 	device_desc = (device_desc_t)kmem_zalloc(sizeof(struct device_desc_s), 0);
@@ -69,7 +67,7 @@
 void
 device_desc_free(device_desc_t device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	if (!(device_desc->flags & D_IS_ASSOC)) /* sanity */
 		kfree(device_desc);
 #endif
@@ -79,7 +77,7 @@
 device_desc_t
 device_desc_dup(devfs_handle_t dev)
 {
-#ifdef notyet
+#ifdef LATER
 	device_desc_t orig_device_desc, new_device_desc;
 
 
@@ -111,7 +109,7 @@
 device_desc_t	
 device_desc_default_get(devfs_handle_t dev)
 {
-#ifdef notyet
+#ifdef LATER
 	graph_error_t rc;
 	device_desc_t device_desc;
 
@@ -130,7 +128,7 @@
 void		
 device_desc_default_set(devfs_handle_t dev, device_desc_t new_device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	graph_error_t rc;
 	device_desc_t old_device_desc = NULL;
 
@@ -164,7 +162,7 @@
 devfs_handle_t
 device_desc_intr_target_get(device_desc_t device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	return(device_desc->intr_target);
 #else
 	FIXME("device_desc_intr_target_get");
@@ -175,7 +173,7 @@
 int
 device_desc_intr_policy_get(device_desc_t device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	return(device_desc->intr_policy);
 #else
 	FIXME("device_desc_intr_policy_get");
@@ -186,7 +184,7 @@
 ilvl_t
 device_desc_intr_swlevel_get(device_desc_t device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	return(device_desc->intr_swlevel);
 #else
 	FIXME("device_desc_intr_swlevel_get");
@@ -197,7 +195,7 @@
 char *
 device_desc_intr_name_get(device_desc_t device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	return(device_desc->intr_name);
 #else
 	FIXME("device_desc_intr_name_get");
@@ -208,7 +206,7 @@
 int
 device_desc_flags_get(device_desc_t device_desc)
 {
-#ifdef notyet
+#ifdef LATER
 	return(device_desc->flags);
 #else
 	FIXME("device_desc_flags_get");
@@ -240,7 +238,7 @@
 void
 device_desc_intr_name_set(device_desc_t device_desc, char *name)
 {
-#ifdef notyet
+#ifdef LATER
 	if ( device_desc != (device_desc_t)0 )
 		device_desc->intr_name = string_table_insert(&device_desc_string_table, name);
 #else
@@ -325,7 +323,7 @@
 static void
 dev_admin_registry_init(dev_admin_registry_t *registry)
 {
-#ifdef notyet
+#ifdef LATER
 	if ( registry != (dev_admin_registry_t *)0 )
 		DEV_ADMIN_REGISTRY_INITLOCK(&registry->reg_lock,
 				    "dev_admin_registry_lock");
@@ -349,7 +347,7 @@
 		       char			*name,
 		       char			*val)
 {
-#ifdef notyet
+#ifdef LATER
 	dev_admin_list_t	*reg_entry;
 	dev_admin_list_t	*scan = 0;
 
@@ -404,7 +402,7 @@
 static char *
 dev_admin_registry_find(dev_admin_registry_t *registry,char *name)
 {
-#ifdef notyet
+#ifdef LATER
 	dev_admin_list_t	*scan = 0;
 	
 	DEV_ADMIN_REGISTRY_RDLOCK(&registry->reg_lock);
@@ -433,7 +431,7 @@
 device_admin_info_get(devfs_handle_t	dev_vhdl,
 		      char		*info_lbl)
 {
-#ifdef notyet
+#ifdef LATER
 	char		*info = 0;
 
 	/* return value need not be GRAPH_SUCCESS as the labelled
@@ -460,7 +458,7 @@
 		      char		*dev_info_lbl,
 		      char		*dev_info_val)
 {
-#ifdef notyet
+#ifdef LATER
 	graph_error_t		rv;
 	arbitrary_info_t	old_info;
 
@@ -570,7 +568,7 @@
 device_driver_admin_info_get(char		*driver_prefix,
 			     char		*driver_info_lbl)
 {
-#ifdef notyet
+#ifdef LATER
 	device_driver_t driver;
 
 	driver = device_driver_get(driver_prefix);
@@ -592,7 +590,7 @@
 			     char		*driver_info_lbl,
 			     char		*driver_info_val)
 {
-#ifdef notyet
+#ifdef LATER
 	device_driver_t driver;
 
 	driver = device_driver_get(driver_prefix);
@@ -623,7 +621,7 @@
 void
 device_admin_table_init(void)
 {
-#ifdef notyet
+#ifdef LATER
 	extended_dev_admin_table_size = 0;
 	mrinit(&extended_dev_admin_table_lock,
 	       "extended_dev_admin_table_lock");
@@ -638,7 +636,7 @@
 void
 device_admin_table_update(char *name,char *label,char *value)
 {
-#ifdef notyet
+#ifdef LATER
 	dev_admin_info_t	*p;
 
 	mrupdate(&extended_dev_admin_table_lock);
@@ -678,7 +676,7 @@
 void
 device_driver_admin_table_init(void)
 {
-#ifdef notyet
+#ifdef LATER
 	extended_drv_admin_table_size = 0;
 	mrinit(&extended_drv_admin_table_lock,
 	       "extended_drv_admin_table_lock");
@@ -693,7 +691,7 @@
 void
 device_driver_admin_table_update(char *name,char *label,char *value)
 {
-#ifdef notyet
+#ifdef LATER
 	dev_admin_info_t	*p;
 
 	mrupdate(&extended_dev_admin_table_lock);
@@ -730,7 +728,7 @@
 void
 device_admin_info_update(devfs_handle_t	dev_vhdl)
 {
-#ifdef notyet
+#ifdef LATER
 	int			i = 0;
 	dev_admin_info_t	*scan;
 	devfs_handle_t		scan_vhdl;
@@ -779,7 +777,7 @@
 void
 device_driver_admin_info_update(device_driver_t	driver)
 {
-#ifdef notyet
+#ifdef LATER
 	int			i = 0;
 	dev_admin_info_t	*scan;
 
@@ -823,7 +821,7 @@
 */
 
 #define DEVICE_DRIVER_HASH_SIZE 32
-#ifdef notyet
+#ifdef LATER
 lock_t device_driver_lock[DEVICE_DRIVER_HASH_SIZE];
 device_driver_t device_driver_hash[DEVICE_DRIVER_HASH_SIZE];
 static struct string_table driver_prefix_string_table;
@@ -835,7 +833,7 @@
 void
 device_driver_init(void)
 {
-#ifdef notyet
+#ifdef LATER
 	int i;
 	extern void alenlist_init(void);
 	extern void hwgraph_init(void);
@@ -849,7 +847,7 @@
 	string_table_init(&driver_prefix_string_table);
 
 	for (i=0; i<DEVICE_DRIVER_HASH_SIZE; i++) {
-		spinlock_init(&device_driver_lock[i], "devdrv");
+		spin_lock_init(&device_driver_lock[i]);
 		device_driver_hash[i] = NULL;
 	}
 
@@ -877,7 +875,7 @@
 static int
 driver_prefix_hash(char *prefix)
 {
-#ifdef notyet
+#ifdef LATER
 	int accum = 0;
 	char nextchar;
 
@@ -903,10 +901,10 @@
 device_driver_t
 device_driver_alloc(char *prefix)
 {
-#ifdef notyet
+#ifdef LATER
 	int which_hash;
 	device_driver_t new_driver;
-	int s;
+	unsigned long s;
 		
 	which_hash = driver_prefix_hash(prefix);
 
@@ -964,9 +962,9 @@
 void
 device_driver_free(device_driver_t driver)
 {
-#ifdef notyet
+#ifdef LATER
 	int which_hash;
-	int s;
+	unsigned long s;
 
 	if (!driver)
 		return;
@@ -1027,10 +1025,10 @@
 device_driver_t
 device_driver_get(char *prefix)
 {
-#ifdef notyet
+#ifdef LATER
 	int which_hash;
 	device_driver_t drvscan;
-	int s;
+	unsigned long s;
 
 	if (prefix == NULL)
 		return(NULL);
@@ -1060,7 +1058,7 @@
 device_driver_t
 device_driver_getbydev(devfs_handle_t device)
 {
-#ifdef notyet
+#ifdef LATER
 	struct bdevsw *my_bdevsw;
 	struct cdevsw *my_cdevsw;
 
@@ -1093,7 +1091,7 @@
 			struct bdevsw *my_bdevsw,
 			struct cdevsw *my_cdevsw)
 {
-#ifdef notyet
+#ifdef LATER
 	int i;
 
 	if (!driver)
@@ -1194,7 +1192,7 @@
 void 
 device_info_set(devfs_handle_t device, void *info)
 {
-#ifdef notyet
+#ifdef LATER
 	hwgraph_fastinfo_set(device, (arbitrary_info_t)info);
 #endif
 	FIXME("device_info_set");
@@ -1207,7 +1205,7 @@
 void *
 device_info_get(devfs_handle_t device)
 {
-#ifdef notyet
+#ifdef LATER
 	return((void *)hwgraph_fastinfo_get(device));
 #else
 	FIXME("device_info_get");
@@ -1222,7 +1220,7 @@
 int
 device_driver_sysgen_thread_pri_get(char *dev_prefix)
 {
-#ifdef notyet
+#ifdef LATER
 	int pri;
 	char *pri_s;
 	char *class;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/eeprom.c linux/arch/ia64/sn/io/eeprom.c
--- v2.4.3/linux/arch/ia64/sn/io/eeprom.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/eeprom.c	Thu Apr  5 12:51:47 2001
@@ -53,7 +53,6 @@
 #include <asm/sn/labelcl.h>
 #include <asm/sn/eeprom.h>
 #include <asm/sn/ksys/i2c.h>
-#include <asm/sn/cmn_err.h>
 /* #include <sys/SN/SN1/ip27log.h> */
 #include <asm/sn/router.h>
 #include <asm/sn/module.h>
@@ -949,6 +948,7 @@
 #else
     char msg[BRL1_QSIZE]; 	    /* message buffer */
     int len;              	    /* number of bytes used in message buffer */
+    int resp;                       /* l1 response code */
     int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */
     int offset = 0;		    /* current offset into spd record */
     char *spd_p = spd->bytes;	    /* "thumb" for writing to spd */
@@ -981,11 +981,26 @@
 	}
 
 	/* check response */
-	if( sc_interpret_resp( msg, 5, 
+	if( (resp = sc_interpret_resp( msg, 5, 
 			       L1_ARG_INT, &spd_len,
-			       L1_ARG_UNKNOWN, &len, spd_p ) < 0 )
+			       L1_ARG_UNKNOWN, &len, spd_p )) < 0 )
 	{
-	    return( EEP_L1 );
+            /*
+             * translate l1 response code to eeprom.c error codes:
+             * The L1 response will be L1_RESP_NAVAIL if the spd
+             * can't be read (i.e. the spd isn't physically there). It will
+             * return L1_RESP_INVAL if the spd exists, but fails the checksum
+             * test because the eeprom wasn't programmed, programmed incorrectly,
+             * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present,
+             * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is
+             * invalid.
+             */
+            if(resp == L1_RESP_INVAL) {
+                resp = EEP_BAD_CHECKSUM;
+            } else {
+                resp = EEP_L1;
+            }
+            return( resp );
 	}
 
 	if( spd_len > EEPROM_CHUNKSIZE )
@@ -1201,7 +1216,9 @@
 #else
     int r;
     uint64_t uid = 0;
+#ifdef LOG_GETENV
     char uid_str[32];
+#endif
     int l1_compt, subch;
 
     if ( IS_RUNNING_ON_SIMULATOR() )
@@ -1228,6 +1245,13 @@
     if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
 	return EEP_L1;
 
+    if((component & C_DIMM) == C_DIMM) {
+        l1_compt = L1_EEP_DIMM(component & COMPT_MASK);
+        r = read_spd(scp,subch,l1_compt, buf->spd);
+        sc_close(scp,subch);
+        return(r);
+    }
+
     switch( component )
     {
       case C_BRICK:
@@ -1252,13 +1276,6 @@
 	l1_compt = L1_EEP_PIMM( component & COMPT_MASK );
 	break;
 
-      case C_DIMM:
-	/* one of the DIMMs */
-	l1_compt = L1_EEP_DIMM( component & COMPT_MASK );
-	r = read_spd( scp, subch, l1_compt, buf->spd );
-	sc_close( scp, subch );
-	return r;
-
       default:
 	/* unsupported board type */
 	sc_close( scp, subch );
@@ -1297,8 +1314,7 @@
 	scp = get_l1sc();
     }
     else {
-	elsc_t *get_elsc(void);
-	scp = get_elsc();
+	scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
     }
 
     return _cbrick_eeprom_read( buf, scp, component );
@@ -1333,8 +1349,7 @@
 	scp = get_l1sc();
     }
     else {
-	elsc_t *get_elsc(void);
-	scp = get_elsc();
+	scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
     }
 
     if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 )
@@ -1350,9 +1365,11 @@
 
 	if( r != EEP_OK ) {
 	    sc_close( scp, subch );
-#ifdef BRINGUP /* Once EEPROMs are universally available, remove this */
+	/*
+	 * Whenever we no longer need to test on hardware
+	 * that does not have EEPROMS, then this can be removed.
+	 */
 	    r = fake_an_eeprom_record( buf, component, rtc_time() );
-#endif /* BRINGUP */
 	    return r;
 	}
 	break;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hcl.c linux/arch/ia64/sn/io/hcl.c
--- v2.4.3/linux/arch/ia64/sn/io/hcl.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/hcl.c	Thu Apr  5 12:51:47 2001
@@ -30,6 +30,7 @@
 #define HCL_TEMP_NAME_LEN 44 
 #define HCL_VERSION "1.0"
 devfs_handle_t hwgraph_root = NULL;
+devfs_handle_t linux_busnum = NULL;
 
 /*
  * Debug flag definition.
@@ -41,7 +42,9 @@
 static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE;
 #endif
 static unsigned int hcl_debug = HCL_DEBUG_NONE;
+#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
 static unsigned int boot_options = OPTION_NONE;
+#endif
 
 /*
  * Some Global definitions.
@@ -49,6 +52,12 @@
 spinlock_t hcl_spinlock;
 devfs_handle_t hcl_handle = NULL;
 
+invplace_t invplace_none = {
+	GRAPH_VERTEX_NONE,
+	GRAPH_VERTEX_PLACE_NONE,
+	NULL
+};
+
 /*
  * HCL device driver.
  * The purpose of this device driver is to provide a facility 
@@ -98,6 +107,7 @@
 }
 
 struct file_operations hcl_fops = {
+	(struct module *)0,
 	NULL,		/* lseek - default */
 	NULL,		/* read - general block-dev read */
 	NULL,		/* write - general block-dev write */
@@ -110,9 +120,9 @@
 	hcl_close,	/* release */
 	NULL,		/* fsync */
 	NULL,		/* fasync */
-	NULL,		/* check_media_change */
-	NULL,		/* revalidate */
-	NULL		/* lock */
+	NULL,		/* lock */
+	NULL,		/* readv */
+	NULL,		/* writev */
 };
 
 
@@ -134,13 +144,15 @@
 	extern struct string_table label_string_table;
 	int rv = 0;
 
+#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
 	printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n",
 		HCL_NAME, HCL_VERSION);
-#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
+
 	hcl_debug = hcl_debug_init;
 	printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME, hcl_debug);
-#endif
 	printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options);
+#endif
+
 	spin_lock_init(&hcl_spinlock);
 
 	/*
@@ -148,7 +160,7 @@
 	 */
 	rv = hwgraph_path_add(NULL, "hw", &hwgraph_root);
 	if (rv)
-		printk ("init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv);
+		printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv);
 
 	/*
 	 * Create the hcl driver to support inventory entry manipulations.
@@ -171,6 +183,15 @@
 	 */
 	string_table_init(&label_string_table);
 
+	/*
+	 * Create the directory that links Linux bus numbers to our Xwidget.
+	 */
+	rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum);
+	if (linux_busnum == NULL) {
+		panic("HCL: Unable to create hw/linux/busnum\n");
+		return(0);
+	}
+
 	return(0);
 
 }
@@ -190,7 +211,6 @@
 {
     while ( (*str != '\0') && !isspace (*str) )
     {
-	printk("HCL: Boot time parameter %s\n", str);
 #ifdef CONFIG_HCL_DEBUG
         if (strncmp (str, "all", 3) == 0) {
             hcl_debug_init |= HCL_DEBUG_ALL;
@@ -445,7 +465,7 @@
 		/*
 		 * We need to clean up!
 		 */
-		printk("HCL: Unable to set the connect point to it's parent 0x%p\n",
+		printk(KERN_WARNING "HCL: Unable to set the connect point to it's parent 0x%p\n",
 			new_devfs_handle);
 	}
 
@@ -561,19 +581,44 @@
 {
 
 	char *path;
+	char *s1;
+	char *index;
 	int name_start;
 	devfs_handle_t handle = NULL;
 	int rv;
+	int i, count;
 
 	path = kmalloc(1024, GFP_KERNEL);
+	memset(path, 0x0, 1024);
+	name_start = devfs_generate_path (from, path, 1024);
+	s1 = &path[name_start];
+	count = 0;
+	while (1) {
+		index = strstr (s1, "/");
+		if (index) {
+			count++;
+			s1 = ++index;
+		} else {
+			count++;
+			break;
+		}
+	}
+
+	memset(path, 0x0, 1024);
 	name_start = devfs_generate_path (to, path, 1024);
 
+	for (i = 0; i < count; i++) {
+		strcat(path,"../");
+	}
+
+	strcat(path, &path[name_start]);
+
 	/*
 	 * Otherwise, just create a symlink to the vertex.
 	 * In this case the vertex was previous created with a REAL pathname.
 	 */
 	rv = devfs_mk_symlink (from, (const char *)name, 
-			       DEVFS_FL_DEFAULT, (const char *)&path[name_start],
+			       DEVFS_FL_DEFAULT, path,
 			       &handle, NULL);
 
 	name_start = devfs_generate_path (handle, path, 1024);
@@ -744,7 +789,6 @@
 		*placeptr = which_place + 1;
 		if (curr && name) {
 			tempname = devfs_get_name(*target, &namelen);
-			printk("hwgraph_edge_get_next: Component name = %s, length = %d\n", tempname, namelen);
 			if (tempname && namelen)
 				strcpy(name, tempname);
 		}
@@ -1335,7 +1379,7 @@
 		return(DEVNAME_UNKNOWN);
 }
 
-#ifdef IRIX
+#ifdef LATER
 /*
 ** Return the compact node id of the node that ultimately "owns" the specified
 ** vertex.  In order to do this, we walk back through masters and connect points
@@ -1440,7 +1484,7 @@
 
   return (mem_vhdl);
 }
-#endif /* IRIX */
+#endif /* LATER */
 
 
 /*
@@ -1454,7 +1498,7 @@
 {
 	devfs_handle_t xx = NULL;
 
-	printk("FIXME: hwgraph_char_device_add() called. Use hwgraph_register.\n");
+	printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n");
 	*devhdl = xx;	// Must set devhdl
 	return(GRAPH_SUCCESS);
 }
@@ -1462,14 +1506,13 @@
 graph_error_t
 hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr)
 {
-	printk("FIXME: hwgraph_edge_remove\n");
+	printk("WARNING: hwgraph_edge_remove NOT supported.\n");
 	return(GRAPH_ILLEGAL_REQUEST);
 }
 
 graph_error_t
 hwgraph_vertex_unref(devfs_handle_t vhdl)
 {
-	printk("FIXME: hwgraph_vertex_unref\n");
 	return(GRAPH_ILLEGAL_REQUEST);
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hcl_util.c linux/arch/ia64/sn/io/hcl_util.c
--- v2.4.3/linux/arch/ia64/sn/io/hcl_util.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/hcl_util.c	Thu Apr  5 12:51:47 2001
@@ -137,6 +137,20 @@
 	}
 }
 
+/*
+** If the specified device represents a CPU, return its cpuid;
+** otherwise, return CPU_NONE.
+*/
+cpuid_t
+cpuvertex_to_cpuid(devfs_handle_t vhdl)
+{
+	arbitrary_info_t cpuid = CPU_NONE;
+
+	(void)labelcl_info_get_LBL(vhdl, INFO_LBL_CPUID, NULL, &cpuid);
+
+	return((cpuid_t)cpuid);
+}
+
 
 /*
 ** dev_to_name converts a devfs_handle_t into a canonical name.  If the devfs_handle_t
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hubdev.c linux/arch/ia64/sn/io/hubdev.c
--- v2.4.3/linux/arch/ia64/sn/io/hubdev.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/hubdev.c	Thu Apr  5 12:51:47 2001
@@ -31,7 +31,7 @@
 void
 hubdev_init(void)
 {
-	mutex_init(&hubdev_callout_mutex, MUTEX_DEFAULT, "hubdev");
+	mutex_init(&hubdev_callout_mutex);
         hubdev_callout_list = NULL;
 }
         
@@ -45,9 +45,9 @@
         callout =  (hubdev_callout_t *)kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP);
         ASSERT(callout);
         
-	mutex_lock(&hubdev_callout_mutex, PZERO);
+	mutex_lock(&hubdev_callout_mutex);
         /*
-         * Insert at the front of the list
+         * Insert at the end of the list
          */
         callout->fp = hubdev_callout_list;
         hubdev_callout_list = callout;
@@ -62,7 +62,7 @@
         
         ASSERT(attach_method);
    
-	mutex_lock(&hubdev_callout_mutex, PZERO);
+	mutex_lock(&hubdev_callout_mutex);
         /*
          * Remove registry element containing attach_method
          */
@@ -86,7 +86,7 @@
         hubdev_callout_t *p;
         int errcode;
 
-	mutex_lock(&hubdev_callout_mutex, PZERO);
+	mutex_lock(&hubdev_callout_mutex);
         
         for (p = hubdev_callout_list; p != NULL; p = p->fp) {
                 ASSERT(p->attach_method);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/huberror.c linux/arch/ia64/sn/io/huberror.c
--- v2.4.3/linux/arch/ia64/sn/io/huberror.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/sn/io/huberror.c	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,475 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2000 by Alan Mayer
+ */
+
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/smp.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/nodemask.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/synergy.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+
+extern void hubni_eint_init(cnodeid_t cnode);
+extern void hubii_eint_init(cnodeid_t cnode);
+extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep);
+extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs);
+
+extern int maxcpus;
+
+#define HUB_ERROR_PERIOD        (120 * HZ)      /* 2 minutes */
+
+
+void
+hub_error_clear(nasid_t nasid)
+{
+	int i;
+	hubreg_t idsr;
+	int sn;
+
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_PEND, -1);
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_A_CLR, -1);
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_B_CLR, -1);
+		REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_0, 0);
+		REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_1, 0);
+	}
+
+	REMOTE_HUB_L(nasid, MD_DIR_ERROR_CLR);
+	REMOTE_HUB_L(nasid, MD_MEM_ERROR_CLR);
+	REMOTE_HUB_L(nasid, MD_MISC1_ERROR_CLR);
+	REMOTE_HUB_L(nasid, MD_PROTOCOL_ERR_CLR);
+
+    /*
+     * Make sure spurious write response errors are cleared
+     * (values are from hub_set_prb())
+     */
+    for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) {
+        iprb_t prb;
+
+	prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)));
+
+        /* Clear out some fields */
+        prb.iprb_ovflow = 1;
+        prb.iprb_bnakctr = 0;
+        prb.iprb_anakctr = 0;
+
+	/*
+	 * PIO reads in fire-and-forget mode on bedrock 1.0 don't
+	 * frob the credit count properly, making the responses appear
+	 * spurious.  So don't use fire-and-forget mode.  Bug 761802.
+	 */
+        prb.iprb_ff = 0;        /* disable fire-and-forget mode by default */
+
+        prb.iprb_xtalkctr = 3;  /* approx. PIO credits for the widget */
+
+        REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval);
+    }
+
+    REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1);
+    idsr = REMOTE_HUB_L(nasid, IIO_IIDSR);
+    REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK)));
+
+    REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR);
+    /* No need to clear NI_PORT_HEADER regs; they are continually overwritten*/
+
+    REMOTE_HUB_S(nasid, LB_ERROR_MASK_CLR, -1);
+    REMOTE_HUB_S(nasid, LB_ERROR_HDR1, 0);
+
+    /* Clear XB error regs, in order */
+    for (i = 0;
+         i <= XB_FIRST_ERROR_CLEAR - XB_POQ0_ERROR_CLEAR;
+         i += sizeof(hubreg_t)) {
+        REMOTE_HUB_S(nasid, XB_POQ0_ERROR_CLEAR + i, 0);
+    }
+}
+
+
+/*
+ * Function	: hub_error_init
+ * Purpose	: initialize the error handling requirements for a given hub.
+ * Parameters	: cnode, the compact nodeid.
+ * Assumptions	: Called only once per hub, either by a local cpu. Or by a 
+ *			remote cpu, when this hub is headless.(cpuless)
+ * Returns	: None
+ */
+
+void
+hub_error_init(cnodeid_t cnode)
+{
+	nasid_t nasid;
+
+    nasid = cnodeid_to_nasid(cnode);
+    hub_error_clear(nasid);
+
+#ifdef ajm
+    if (cnode == 0) {
+	/*
+	 * Allocate log for storing the node specific error info
+	 */
+	for (i = 0; i < numnodes; i++) {
+	    kl_error_log[i]  = kmem_zalloc_node(sizeof(sn0_error_log_t), 
+						KM_NOSLEEP, i);
+	    hub_err_count[i] = kmem_zalloc_node(sizeof(hub_errcnt_t),
+						VM_DIRECT | KM_NOSLEEP, i);
+	    ASSERT_ALWAYS(kl_error_log[i] && hub_err_count[i]);
+	}
+    }
+
+    /*
+     * Assumption: There will be only one cpu who will initialize
+     * a hub. we need to setup the ii and each pi error interrupts.
+     * The SN1 hub (bedrock) has two PI, one for up to two processors.
+     */
+
+    if (cpuid_to_cnodeid(smp_processor_id()) == cnode) { 
+	int generic_intr_mask = PI_ERR_GENERIC; /* These interrupts are sent to only 1 CPU per NODE */
+
+	ASSERT_ALWAYS(kl_error_log[cnode]);
+	ASSERT_ALWAYS(hub_err_count[cnode]);
+	MD_ERR_LOG_INIT(kl_error_log[cnode]);
+
+	/* One for each CPU */
+	recover_error_init(RECOVER_ERROR_TABLE(cnode, 0));
+	recover_error_init(RECOVER_ERROR_TABLE(cnode, 1));
+	recover_error_init(RECOVER_ERROR_TABLE(cnode, 2));
+	recover_error_init(RECOVER_ERROR_TABLE(cnode, 3));
+
+	/*
+	 * Setup error intr masks.
+	 */
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		int cpuA_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_A);
+		int cpuB_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_B);
+
+		if (cpuA_present) {
+			if (cpuB_present) {		/* A && B */
+	    			REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A,
+					(PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_A|generic_intr_mask));
+	    			REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B,
+					(PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_B));
+
+			} else {			/* A && !B */
+	    			REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A,
+					(PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_A|generic_intr_mask));
+			}
+			generic_intr_mask = 0;
+		} else {
+			if (cpuB_present) {		/* !A && B */
+	    			REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B,
+					(PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_B|generic_intr_mask));
+				generic_intr_mask = 0;
+
+			} else {			/* !A && !B */
+				/* nothing to set up */
+			}
+		}
+	}
+
+	/*
+	 * Turn off UNCAC_UNCORR interrupt in the masks. Anyone interested
+	 * in these errors will peek at the int pend register to see if its
+	 * set.
+	 */ 
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_A);
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, (misc & ~PI_ERR_UNCAC_UNCORR_A));
+		misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_B);
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, (misc & ~PI_ERR_UNCAC_UNCORR_B));
+	}
+
+	/*
+	 * enable all error indicators to turn on, in case of errors.
+	 *
+	 * This is not good on single cpu node boards.
+	 **** LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL);
+	 */
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_A_CLR, 0);
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_B_CLR, 0);
+	}
+
+	/* Set up stack for each present processor */
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_A)) {
+	    	SN0_ERROR_LOG(cnode)->el_spool_cur_addr[0] =
+			SN0_ERROR_LOG(cnode)->el_spool_last_addr[0] =
+		    	REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A);
+		}
+	    
+		if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) {
+	    	SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] =
+			SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] =
+		    	REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B);
+		}
+	}
+
+
+	PI_SPOOL_SIZE_BYTES = 
+	    ERR_STACK_SIZE_BYTES(REMOTE_HUB_L(nasid, PI_ERR_STACK_SIZE));
+
+#ifdef BRINGUP
+/* BRINGUP: The following code looks like a check to make sure
+the prom set up the error spool correctly for 2 processors.  I
+don't think it is needed.  */
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) {
+			__psunsigned_t addr_a = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A);
+			__psunsigned_t addr_b = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B);
+			if ((addr_a & ~0xff) == (addr_b & ~0xff)) {
+			    REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STACK_ADDR_B, 	
+					addr_b + PI_SPOOL_SIZE_BYTES);
+	
+			    SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] =
+				SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] =
+				    REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B);
+	
+		    }
+		}
+	}
+#endif /* BRINGUP */
+
+	/* programming our own hub. Enable error_int_pend intr.
+	 * If both present, CPU A takes CPU b's error interrupts and any
+	 * generic ones. CPU B takes CPU A error ints.
+	 */
+	if (cause_intr_connect (SRB_ERR_IDX,
+				(intr_func_t)(hubpi_eint_handler),
+				SR_ALL_MASK|SR_IE)) {
+	    cmn_err(ERR_WARN, 
+		    "hub_error_init: cause_intr_connect failed on %d", cnode);
+	}
+    }
+    else {
+	/* programming remote hub. The only valid reason that this
+	 * is called will be on headless hubs. No interrupts 
+	 */
+	for(sn=0; sn<NUM_SUBNODES; sn++) {
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, 0); /* not necessary */
+		REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, 0); /* not necessary */
+	}
+    }
+#endif /* ajm */
+    /*
+     * Now setup the hub ii and ni error interrupt handler.
+     */
+
+    hubii_eint_init(cnode);
+    hubni_eint_init(cnode);
+
+#ifdef ajm
+    /*** XXX FIXME XXX resolve the following***/
+    /* INT_PEND1 bits set up for one hub only:
+     *	SHUTDOWN_INTR
+     *	MD_COR_ERR_INTR
+     *  COR_ERR_INTR_A and COR_ERR_INTR_B should be sent to the
+     *  appropriate CPU only.
+     */
+
+    if (cnode == 0) {
+	    error_consistency_check.eps_state = 0;
+	    error_consistency_check.eps_cpuid = -1;
+	    spinlock_init(&error_consistency_check.eps_lock, "error_dump_lock");
+    }
+#endif
+
+    nodepda->huberror_ticks = HUB_ERROR_PERIOD;
+    return;
+}
+
+/*
+ * Function	: hubii_eint_init
+ * Parameters	: cnode
+ * Purpose	: to initialize the hub iio error interrupt.
+ * Assumptions	: Called once per hub, by the cpu which will ultimately
+ *			handle this interrupt.
+ * Returns	: None.
+ */
+
+
+void
+hubii_eint_init(cnodeid_t cnode)
+{
+    int			bit, rv;
+    ii_iidsr_u_t    	hubio_eint;
+    hubinfo_t		hinfo; 
+    cpuid_t		intr_cpu;
+    devfs_handle_t 	hub_v;
+    ii_ilcsr_u_t	ilcsr;
+
+    hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode);
+    ASSERT_ALWAYS(hub_v);
+    hubinfo_get(hub_v, &hinfo);
+
+    ASSERT(hinfo);
+    ASSERT(hinfo->h_cnodeid == cnode);
+
+    ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR);
+
+    if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) {
+	/* 
+	 * HUB II link is not up. 
+	 * Just disable LLP, and don't connect any interrupts.
+	 */
+	ilcsr.ii_ilcsr_fld_s.i_llp_en = 0;
+	REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval);
+	return;
+    }
+    /* Select a possible interrupt target where there is a free interrupt
+     * bit and also reserve the interrupt bit for this IO error interrupt
+     */
+    intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v,
+			      "HUB IO error interrupt",&bit);
+    if (intr_cpu == CPU_NONE) {
+	printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode);
+	return;
+    }
+	
+    rv = intr_connect_level(intr_cpu, bit, 0,(intr_func_t)(NULL),
+			    (void *)(long)hub_v, NULL);
+    synergy_intr_connect(bit, intr_cpu);
+    request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, NULL, (void *)hub_v);
+    ASSERT_ALWAYS(rv >= 0);
+    hubio_eint.ii_iidsr_regval = 0;
+    hubio_eint.ii_iidsr_fld_s.i_enable = 1;
+    hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/
+    hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode);
+    hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu);
+    REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval);
+
+}
+
+void
+hubni_eint_init(cnodeid_t cnode)
+{
+    int intr_bit;
+    cpuid_t targ;
+
+
+    if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE)
+	return;
+
+	/* The prom chooses which cpu gets these interrupts, but we
+	*  don't know which one it chose.  We will register all of the 
+	*  cpus to be sure.  This only costs us an irqaction per cpu.
+	*/
+    for (; targ < CPUS_PER_NODE; targ++) {
+	if (!cpu_enabled(targ) ) continue;
+	/* connect the INTEND1 bits. */
+	for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) {
+		intr_connect_level(targ, intr_bit, II_ERRORINT, NULL, NULL, NULL);
+	}
+	request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, NULL, NULL);
+	/* synergy masks are initialized in the prom to enable all interrupts. */
+	/* We'll just leave them that way, here, for these interrupts. */
+    }
+}
+
+
+/*ARGSUSED*/
+void
+hubii_eint_handler (int irq, void *arg, struct pt_regs *ep)
+{
+    devfs_handle_t	hub_v;
+    hubinfo_t		hinfo; 
+    ii_wstat_u_t	wstat;
+    hubreg_t		idsr;
+
+	panic("Hubii interrupt\n");
+#ifdef ajm
+    /*
+     * If the NI has a problem, everyone has a problem.  We shouldn't
+     * even attempt to handle other errors when an NI error is present.
+     */
+    if (check_ni_errors()) {
+	hubni_error_handler("II interrupt", 1);
+	/* NOTREACHED */
+    }
+
+    /* two levels of casting avoids compiler warning.!! */
+    hub_v = (devfs_handle_t)(long)(arg); 
+    ASSERT(hub_v);
+
+    hubinfo_get(hub_v, &hinfo);
+    
+    /* 
+     * Identify the reason for error. 
+     */
+    wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT);
+
+    if (wstat.ii_wstat_fld_s.w_crazy) {
+	char	*reason;
+	/*
+	 * We can do a couple of things here. 
+	 * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check
+	 * which of these caused the CRAZY bit to be set. 
+	 * You may be able to check if the Link is up really.
+	 */
+	if (wstat.ii_wstat_fld_s.w_tx_mx_rty)
+		reason = "Micro Packet Retry Timeout";
+	else if (wstat.ii_wstat_fld_s.w_xt_tail_to)
+		reason = "Crosstalk Tail Timeout";
+	else if (wstat.ii_wstat_fld_s.w_xt_crd_to)
+		reason = "Crosstalk Credit Timeout";
+	else {
+		hubreg_t	hubii_imem;
+		/*
+		 * Check if widget 0 has been marked as shutdown, or
+		 * if BTE 0/1 has been marked.
+		 */
+		hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM);
+		if (hubii_imem & IIO_IMEM_W0ESD)
+			reason = "Hub Widget 0 has been Shutdown";
+		else if (hubii_imem & IIO_IMEM_B0ESD)
+			reason = "BTE 0 has been shutdown";
+		else if (hubii_imem & IIO_IMEM_B1ESD)
+			reason = "BTE 1 has been shutdown";
+		else	reason = "Unknown";
+	
+	}
+	/*
+	 * Note: we may never be able to print this, if the II talking
+	 * to Xbow which hosts the console is dead. 
+	 */
+	printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", 
+		hinfo->h_cnodeid, reason);
+    }
+
+    /* 
+     * It's a toss as to which one among PRB/CRB to check first. 
+     * Current decision is based on the severity of the errors. 
+     * IO CRB errors tend to be more severe than PRB errors.
+     *
+     * It is possible for BTE errors to have been handled already, so we
+     * may not see any errors handled here. 
+     */
+    (void)hubiio_crb_error_handler(hub_v, hinfo);
+    (void)hubiio_prb_error_handler(hub_v, hinfo);
+    /*
+     * If we reach here, it indicates crb/prb handlers successfully
+     * handled the error. So, re-enable II to send more interrupt
+     * and return.
+     */
+    REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff);
+    idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK;
+    REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr);
+#endif /* ajm */
+}
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/hubspc.c linux/arch/ia64/sn/io/hubspc.c
--- v2.4.3/linux/arch/ia64/sn/io/hubspc.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/hubspc.c	Thu Apr  5 12:51:47 2001
@@ -61,7 +61,7 @@
 }cpuprom_info_t;
 
 static cpuprom_info_t	*cpuprom_head;
-lock_t	cpuprom_spinlock;
+spinlock_t	cpuprom_spinlock;
 #define	PROM_LOCK()	mutex_spinlock(&cpuprom_spinlock)
 #define	PROM_UNLOCK(s)	mutex_spinunlock(&cpuprom_spinlock, (s))
 
@@ -72,7 +72,7 @@
 prominfo_add(devfs_handle_t hub, devfs_handle_t prom)
 {
 	cpuprom_info_t	*info;
-	int	s;
+	unsigned long	s;
 
 	info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL);
 	ASSERT(info);
@@ -89,7 +89,7 @@
 void
 prominfo_del(devfs_handle_t prom)
 {
-	int	s;
+	unsigned long	s;
 	cpuprom_info_t	*info;
 	cpuprom_info_t	**prev;
 
@@ -111,7 +111,7 @@
 devfs_handle_t
 prominfo_nodeget(devfs_handle_t prom)
 {
-	int	s;
+	unsigned long	s;
 	cpuprom_info_t	*info;
 
 	s = PROM_LOCK();
@@ -297,7 +297,7 @@
 	printf("hubspc_init: Completed\n");
 #endif	/* HUBSPC_DEBUG */
 	/* Initialize spinlocks */
-	spinlock_init(&cpuprom_spinlock, "promlist");
+	mutex_spinlock_init(&cpuprom_spinlock);
 }
 
 /* ARGSUSED */
@@ -312,12 +312,6 @@
                 break;
 
         case HUBSPC_PROM:
-		/* Check if the user has proper access rights to 
-		 * read/write the prom space.
-		 */
-                if (!cap_able(CAP_DEVICE_MGT)) {
-                        errcode = EPERM;
-                }                
                 break;
 
         default:
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/invent.c linux/arch/ia64/sn/io/invent.c
--- v2.4.3/linux/arch/ia64/sn/io/invent.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/invent.c	Thu Apr  5 12:51:47 2001
@@ -61,6 +61,9 @@
  * These two routines are intended to prevent the caller from having to know
  * the internal structure of the inventory table.
  *
+ * The caller of get_next_inventory is supposed to call start_scan_invent
+ * before the irst call to get_next_inventory, and the caller is required
+ * to call end_scan_invent after the last call to get_next_inventory.
  */
 inventory_t *
 get_next_inventory(invplace_t *place)
@@ -74,11 +77,15 @@
 		 * We've exhausted inventory items on the last device.
 		 * Advance to next device.
 		 */
+		place->invplace_inv = NULL; /* Start from beginning invent on this device */
 		rv = hwgraph_vertex_get_next(&device, &place->invplace_vplace);
-		if (rv != LABELCL_SUCCESS)
+		if (rv == LABELCL_SUCCESS) {
+			place->invplace_vhdl = device;
+		}
+		else {
+			place->invplace_vhdl = GRAPH_VERTEX_NONE;
 			return(NULL);
-		place->invplace_vhdl = device;
-		place->invplace_inv = NULL; /* Start from beginning invent on this device */
+		}
 	}
 
 	return(pinv);
@@ -91,6 +98,23 @@
 	return sizeof(inventory_t);
 }
 
+/* Must be called prior to first call to get_next_inventory */
+void
+start_scan_inventory(invplace_t *iplace)
+{
+	*iplace = INVPLACE_NONE;
+}
+
+/* Must be called after last call to get_next_inventory */
+void
+end_scan_inventory(invplace_t *iplace)
+{
+	devfs_handle_t vhdl = iplace->invplace_vhdl;
+	if (vhdl != GRAPH_VERTEX_NONE)
+		hwgraph_vertex_unref(vhdl);
+	*iplace = INVPLACE_NONE; /* paranoia */
+}
+
 /*
  * Hardware inventory scanner.
  *
@@ -106,11 +130,13 @@
 
 	ie = 0;
 	rc = 0;
-	while ( (ie = (inventory_t *)get_next_inventory(&iplace)) ) {
+	start_scan_inventory(&iplace);
+	while ((ie = (inventory_t *)get_next_inventory(&iplace))) {
 		rc = (*fun)(ie, arg);
 		if (rc)
 			break;
 	}
+	end_scan_inventory(&iplace);
 	return rc;
 }
 
@@ -127,6 +153,7 @@
 {
 	invplace_t iplace =  { NULL,NULL, NULL };
 
+	start_scan_inventory(&iplace);
 	while ((pinv = (inventory_t *)get_next_inventory(&iplace)) != NULL) {
 		if (class != -1 && pinv->inv_class != class)
 			continue;
@@ -146,6 +173,7 @@
 			continue;
 		break;
 	}
+	end_scan_inventory(&iplace);
 
 	return(pinv);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/io.c linux/arch/ia64/sn/io/io.c
--- v2.4.3/linux/arch/ia64/sn/io/io.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/io.c	Thu Apr 12 12:16:35 2001
@@ -13,7 +13,6 @@
 #include <linux/slab.h>
 #include <asm/sn/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/iobus.h>
 #include <asm/sn/iograph.h>
 #include <asm/param.h>
@@ -33,11 +32,6 @@
 
 extern xtalk_provider_t hub_provider;
 
-#ifndef CONFIG_IA64_SGI_IO
-/* Global variables */
-extern pdaindr_t       pdaindr[MAXCPUS];
-#endif
-
 /*
  * Perform any initializations needed to support hub-based I/O.
  * Called once during startup.
@@ -45,7 +39,7 @@
 void
 hubio_init(void)
 {
-#if 0
+#ifdef	LATER
 	/* This isn't needed unless we port the entire sio driver ... */
         extern void early_brl1_port_init( void );
 	early_brl1_port_init();
@@ -101,17 +95,14 @@
 		hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW;
 		IIO_ITTE_DISABLE(nasid, bigwin);
 	}
-#ifdef	BRINGUP
 	hub_set_piomode(nasid, HUB_PIO_CONVEYOR);
-#else
-	/* Set all the xwidgets in fire-and-forget mode
-	 * by default
-	 */
-	hub_set_piomode(nasid, HUB_PIO_FIRE_N_FORGET);
-#endif	/* BRINGUP */
 
-	sv_init(&hubinfo->h_bwwait, SV_FIFO, "bigwin");
-	spinlock_init(&hubinfo->h_bwlock, "bigwin");
+	mutex_spinlock_init(&hubinfo->h_bwlock);
+/*
+ * If this lock can be acquired from interrupts or bh's, add SV_INTS or SV_BHS,
+ * respectively, to the flags here.
+ */
+	sv_init(&hubinfo->h_bwwait, &hubinfo->h_bwlock, SV_ORDER_FIFO | SV_MON_SPIN); 
 }
 
 /* 
@@ -143,7 +134,7 @@
 	int bigwin, free_bw_index;
 	nasid_t nasid;
 	volatile hubreg_t junk;
-	int s;
+	unsigned long s;
 
 	/* sanity check */
 	if (byte_count_max > byte_count)
@@ -222,7 +213,7 @@
 				goto done;
 			}
 
-			sv_wait(&hubinfo->h_bwwait, PZERO, &hubinfo->h_bwlock, s);
+			sv_wait(&hubinfo->h_bwwait, 0, 0);
 			goto tryagain;
 		}
 	}
@@ -282,7 +273,7 @@
 	devfs_handle_t hubv;
 	hubinfo_t hubinfo;
 	nasid_t nasid;
-	int s;
+	unsigned long s;
 
 	/* 
 	 * Small windows are permanently mapped to corresponding widgets,
@@ -463,9 +454,9 @@
 	    if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
 		vhdl = dmamap->hdma_xtalk_info.xd_dev;
 #if defined(SUPPORT_PRINTING_V_FORMAT)
-		cmn_err(CE_WARN, "%v: hub_dmamap_addr re-uses dmamap.\n",vhdl);
+		PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl);
 #else
-		cmn_err(CE_WARN, "0x%p: hub_dmamap_addr re-uses dmamap.\n", &vhdl);
+		PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl);
 #endif
 	    }
 	} else {
@@ -496,9 +487,9 @@
 	    if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
 		vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
 #if defined(SUPPORT_PRINTING_V_FORMAT)
-		cmn_err(CE_WARN,"%v: hub_dmamap_list re-uses dmamap\n",vhdl);
+		PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl);
 #else
-		cmn_err(CE_WARN,"0x%p: hub_dmamap_list re-uses dmamap\n", &vhdl);
+		PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl);
 #endif
 	    }
 	} else {
@@ -525,9 +516,9 @@
 	    if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
 		vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
 #if defined(SUPPORT_PRINTING_V_FORMAT)
-		cmn_err(CE_WARN, "%v: hub_dmamap_done already done with dmamap\n",vhdl);
+		PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl);
 #else
-		cmn_err(CE_WARN, "0x%p: hub_dmamap_done already done with dmamap\n", &vhdl);
+		PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl);
 #endif
 	    }
 	}
@@ -629,16 +620,17 @@
  * Allocate resources required for an interrupt as specified in dev_desc.
  * Returns a hub interrupt handle on success, or 0 on failure.
  */
-hub_intr_t
-hub_intr_alloc(	devfs_handle_t dev,		/* which crosstalk device */
-		device_desc_t dev_desc,		/* device descriptor */
-		devfs_handle_t owner_dev)		/* owner of this interrupt, if known */
+static hub_intr_t
+do_hub_intr_alloc(devfs_handle_t dev,		/* which crosstalk device */
+		  device_desc_t dev_desc,	/* device descriptor */
+		  devfs_handle_t owner_dev,	/* owner of this interrupt, if known */
+		  int uncond_nothread)		/* unconditionally non-threaded */
 {
-	cpuid_t cpu;			/* cpu to receive interrupt */
+	cpuid_t cpu = (cpuid_t)0;			/* cpu to receive interrupt */
         int cpupicked = 0;
 	int bit;			/* interrupt vector */
 	/*REFERENCED*/
-	int intr_resflags;
+	int intr_resflags = 0;
 	hub_intr_t intr_hdl;
 	cnodeid_t nodeid;		/* node to receive interrupt */
 	/*REFERENCED*/
@@ -665,7 +657,7 @@
 		intr_swlevel = device_desc_intr_swlevel_get(dev_desc);
 		if (dev_desc->flags & D_INTR_ISERR) {
 			intr_resflags = II_ERRORINT;
-		} else if (!(dev_desc->flags & D_INTR_NOTHREAD)) {
+		} else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) {
 			intr_resflags = II_THREADED;
 		} else {
 			/* Neither an error nor a thread. */
@@ -673,7 +665,8 @@
 		}
 	} else {
 		intr_swlevel = default_intr_pri;
-		intr_resflags = II_THREADED;
+		if (!uncond_nothread)
+			intr_resflags = II_THREADED;
 	}
 
 	/* XXX - Need to determine if the interrupt should be threaded. */
@@ -692,13 +685,11 @@
 	/* At this point we SHOULD have a valid cpu */
 	if (cpu == CPU_NONE) {
 #if defined(SUPPORT_PRINTING_V_FORMAT)
-		cmn_err(CE_WARN, 
-			"%v hub_intr_alloc could not allocate interrupt\n",
+		PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n",
 			owner_dev);
 #else
-		cmn_err(CE_WARN, 
-			"0x%p hub_intr_alloc could not allocate interrupt\n",
-			&owner_dev);
+		PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n",
+			owner_dev);
 #endif
 		return(0);
 
@@ -714,15 +705,13 @@
 					 owner_dev, intr_name);
 		if (bit < 0) {
 #if defined(SUPPORT_PRINTING_V_FORMAT)
-			cmn_err(CE_WARN,
-				"Could not reserve an interrupt bit for cpu "
+			PRINT_WARNING("Could not reserve an interrupt bit for cpu "
 				" %d and dev %v\n",
 				cpu,owner_dev);
 #else
-			cmn_err(CE_WARN,
-				"Could not reserve an interrupt bit for cpu "
+			PRINT_WARNING("Could not reserve an interrupt bit for cpu "
 				" %d and dev 0x%x\n",
-				cpu, &owner_dev);
+				cpu, owner_dev);
 #endif
 				
 			return(0);
@@ -751,8 +740,6 @@
 	xtalk_info->xi_dev = dev;
 	xtalk_info->xi_vector = bit;
 	xtalk_info->xi_addr = xtalk_addr;
-	xtalk_info->xi_flags =  (intr_resflags == II_THREADED) ?
-				0 : XTALK_INTR_NOTHREAD;
 
 	/*
 	 * Regardless of which CPU we ultimately interrupt, a given crosstalk
@@ -779,6 +766,31 @@
 	return(intr_hdl);
 }
 
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Returns a hub interrupt handle on success, or 0 on failure.
+ */
+hub_intr_t
+hub_intr_alloc(	devfs_handle_t dev,		/* which crosstalk device */
+		device_desc_t dev_desc,		/* device descriptor */
+		devfs_handle_t owner_dev)		/* owner of this interrupt, if known */
+{
+	return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0));
+}
+
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Uncondtionally request non-threaded, regardless of what the device
+ * descriptor might say.
+ * Returns a hub interrupt handle on success, or 0 on failure.
+ */
+hub_intr_t
+hub_intr_alloc_nothd(devfs_handle_t dev,		/* which crosstalk device */
+		device_desc_t dev_desc,		/* device descriptor */
+		devfs_handle_t owner_dev)		/* owner of this interrupt, if known */
+{
+	return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1));
+}
 
 /*
  * Free resources consumed by intr_alloc.
@@ -1001,7 +1013,7 @@
 {
 	iprb_t prb;
 	int prb_offset;
-#ifdef IRIX
+#ifdef LATER
 	extern int force_fire_and_forget;
 	extern volatile int ignore_conveyor_override;
 
@@ -1063,7 +1075,7 @@
 	int direct_connect;
 	hubii_wcr_t ii_wcr;
 	int prbnum;
-	int s, cons_lock = 0;
+	int cons_lock = 0;
 
 	ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID);
 	if (nasid == get_console_nasid()) {
@@ -1098,15 +1110,6 @@
 		hub_setup_prb(nasid, prbnum, 3, conveyor);
 	}
 
-#ifdef IRIX
-	/*
-	 * In direct connect mode, disable access to all widgets but 0.
-	 * Later, the prom will do this for us.
-	 */
-	if (direct_connect)
-		ii_iowa = 1;
-#endif
-
 	REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa);
 
 	if (cons_lock)
@@ -1151,7 +1154,8 @@
 	devfs_handle_t		hub_vhdl    = xwidget_info_master_get(widget_info);
 	hubinfo_t		hub_info = 0;
 	nasid_t			nasid;
-	int			s,rv;
+	unsigned long		s;
+	int			rv;
 
 	/* Use the nasid from the hub info hanging off the hub vertex
 	 * and widget number from the widget vertex
@@ -1178,7 +1182,7 @@
 	devfs_handle_t		hub_vhdl    = xwidget_info_master_get(widget_info);
 	hubinfo_t		hub_info = 0;
 	nasid_t			nasid;
-	int			s;
+	unsigned long			s;
 
 	/* Use the nasid from the hub info hanging off the hub vertex
 	 * and widget number from the widget vertex
@@ -1201,7 +1205,7 @@
 	devfs_handle_t		hub_vhdl    = xwidget_info_master_get(widget_info);
 	hubinfo_t		hub_info = 0;
 	nasid_t			nasid;
-	int			s;
+	unsigned long		s;
 
 	/* Use the nasid from the hub info hanging off the hub vertex
 	 * and widget number from the widget vertex
@@ -1253,25 +1257,23 @@
 	ii_iowa 	= REMOTE_HUB_L(nasid, IIO_IOWA);
 
 #if defined(SUPPORT_PRINTING_V_FORMAT)
-	cmn_err(CE_CONT, "Inquiry Info for %v\n", xconn);
+	printk("Inquiry Info for %v\n", xconn);
 #else
-	cmn_err(CE_CONT, "Inquiry Info for 0x%p\n", &xconn);
+	printk("Inquiry Info for 0x%x\n", xconn);
 #endif
 
-	cmn_err(CE_CONT,"\tDevices shutdown [ ");
+	printk("\tDevices shutdown [ ");
 
 	for (d = 0 ; d <= 7 ; d++)
 		if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d))))
-			cmn_err(CE_CONT, " %d", d);
+			printk(" %d", d);
 
-	cmn_err(CE_CONT,"]\n");
+	printk("]\n");
 
-	cmn_err(CE_CONT,
-		"\tInbound access ? %s\n",
+	printk("\tInbound access ? %s\n",
 		ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no");
 
-	cmn_err(CE_CONT,
-		"\tOutbound access ? %s\n",
+	printk("\tOutbound access ? %s\n",
 		ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no");
 
 }
@@ -1300,6 +1302,7 @@
 	(xtalk_dmalist_drain_f *)	hub_dmalist_drain,
 
 	(xtalk_intr_alloc_f *)		hub_intr_alloc,
+	(xtalk_intr_alloc_f *)		hub_intr_alloc_nothd,
 	(xtalk_intr_free_f *)		hub_intr_free,
 	(xtalk_intr_connect_f *)	hub_intr_connect,
 	(xtalk_intr_disconnect_f *)	hub_intr_disconnect,
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ip37.c linux/arch/ia64/sn/io/ip37.c
--- v2.4.3/linux/arch/ia64/sn/io/ip37.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/ip37.c	Thu Apr  5 12:51:47 2001
@@ -30,10 +30,6 @@
 		
 	ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR);
 
-	printk("hub_widget_id: Found Hub Widget ID 0x%x from Register 0x%p\n", ii_wcr.wcr_fields_s.wcr_widget_id, REMOTE_HUB_ADDR(nasid, IIO_WCR));
-
-	printk("hub_widget_id: Found Hub Widget 0x%lx wcr_reg_value 0x%lx\n", REMOTE_HUB_L(nasid,IIO_WCR), ii_wcr.wcr_reg_value);
-
 	return ii_wcr.wcr_fields_s.wcr_widget_id;
 }
 
@@ -64,8 +60,6 @@
 get_hub_chiprev(nasid_t nasid)
 {
 
-	printk("get_hub_chiprev: Hub Chip Rev 0x%lx\n",
-		(REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK) >> LRI_REV_SHFT);
 	return ((REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK)
 		                                         >> LRI_REV_SHFT);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/klconflib.c linux/arch/ia64/sn/io/klconflib.c
--- v2.4.3/linux/arch/ia64/sn/io/klconflib.c	Fri Feb 16 16:02:34 2001
+++ linux/arch/ia64/sn/io/klconflib.c	Thu Apr  5 12:51:47 2001
@@ -82,7 +82,7 @@
 		}
 		index = j;
 		if (index == KLCF_NUM_COMPS(brd)) {
-			printf("find_component: Bad pointer: 0x%p\n", kli);
+			DBG("find_component: Bad pointer: 0x%p\n", kli);
 			return (klinfo_t *)NULL;
 		}
 		index++;	/* next component */
@@ -152,11 +152,6 @@
 	return (lboard_t *)NULL;
 }
 
-#ifndef CONFIG_IA64_SGI_IO
-#define tolower(c)	(isupper(c) ? (c) - 'A' + 'a' : (c))
-#define toupper(c)	(islower(c) ? (c) - 'a' + 'A' : (c))
-#endif
-
 
 /*
  * Convert a NIC name to a name for use in the hardware graph.
@@ -205,10 +200,6 @@
             !strncmp(new_name, "mio", 3) || 
 	    !strncmp(new_name, "media_io", 8))
 		strcpy(new_name, "baseio");
-#if !defined(CONFIG_SGI_IP35) && !defined(CONFIG_IA64_SGI_SN1) && !defined(CONFIG_IA64_GENERIC)
-	else if (!strncmp(new_name, "ip29", 4))
-		strcpy(new_name,SN00_MOTHERBOARD);
-#endif
 	else if (!strncmp(new_name, "divo", 4))
 		strcpy(new_name, "divo") ;
 
@@ -284,11 +275,11 @@
 
 	/*
  	 * PV # 540860
-	 * If the name is not 'baseio' or SN00 MOTHERBOARD
+	 * If the name is not 'baseio' 
 	 * get the lowest of all the names in the nic string.
 	 * This is needed for boards like divo, which can have
 	 * a bunch of daughter cards, but would like to be called
-	 * divo. We could do this for baseio and SN00 MOTHERBOARD
+	 * divo. We could do this for baseio 
  	 * but it has some special case names that we would not
  	 * like to disturb at this point.
 	 */
@@ -355,11 +346,7 @@
 	/*
 	 * look for boards that might contain an xbow or xbridge
 	 */
-#if SN0
-	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8);
-#else
-	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_PBRICK_XBOW);
-#endif
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW);
 	if (brd == NULL) return 0;
 		
 	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
@@ -369,7 +356,7 @@
 	if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link))
 	    return 0;
 
-	printf("xbow_port_io_enabled:  brd 0x%p xbow_p 0x%p \n", brd, xbow_p);
+	DBG("xbow_port_io_enabled:  brd 0x%p xbow_p 0x%p \n", brd, xbow_p);
 
 	return 1;
 }
@@ -395,6 +382,9 @@
 			if (brd->brd_type == KLTYPE_META_ROUTER) {
 				board_name = EDGE_LBL_META_ROUTER;
 				hasmetarouter++;
+			} else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) {
+				board_name = EDGE_LBL_REPEATER_ROUTER;
+				hasmetarouter++;
 			} else
 				board_name = EDGE_LBL_ROUTER;
 			break;
@@ -420,22 +410,17 @@
 			
 	modnum = brd->brd_module;
 
-#if defined(SN0)
-	slot = brd->brd_slot;
-	get_slotname(slot, slot_name);
-
-	ASSERT(modnum >= 0);
-
-	sprintf(path, "%H/" EDGE_LBL_SLOT "/%s/%s", 
-		modnum, slot_name, board_name);
-#else
 	ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE);
-#ifdef BRINGUP /* fix IP35 hwgraph */
-	sprintf(path, EDGE_LBL_MODULE "/%x/%s", modnum, board_name);
+#ifdef __ia64
+	{
+		char	buffer[16];
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF);
+		sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name);
+	}
 #else
 	sprintf(path, "%H/%s", modnum, board_name);
 #endif
-#endif
 }
 
 /*
@@ -455,172 +440,8 @@
 }
 
 
-#ifndef CONFIG_IA64_SGI_IO
-#if 1
-/*
- *  find_gfxpipe(#)
- *
- *  XXXmacko
- *  This is only used by graphics drivers, and should be moved
- *  over to gfx/kern/graphics/SN0 as soon as it's convenient.
- */
-static klgfx_t *graphics_pipe_list = NULL;
-static devfs_handle_t hwgraph_all_gfxids = GRAPH_VERTEX_NONE;
-
-void
-setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum)
-{
-	char idbuf[8];
-	extern graph_hdl_t hwgraph;
-
-	graph_info_add_LBL(hwgraph, vhdl, INFO_LBL_GFXID, INFO_DESC_EXPORT, 
-		(arbitrary_info_t)pipenum);
-	if (hwgraph_all_gfxids == GRAPH_VERTEX_NONE)
-		hwgraph_path_add(hwgraph_root, EDGE_LBL_GFX, &hwgraph_all_gfxids);
-	sprintf(idbuf, "%d", pipenum);
-	hwgraph_edge_add(hwgraph_all_gfxids, vhdl, idbuf);
-
-}
-#endif
-
-/* 
- * find the pipenum'th logical graphics pipe (KLCLASS_GFX)
- */
-lboard_t *
-find_gfxpipe(int pipenum)
-{
-        gda_t           *gdap;
-        cnodeid_t       cnode;
-        nasid_t         nasid;
-        lboard_t        *lb;
-	klgfx_t		*kg,**pkg;
-	int		i;
-
-        gdap = (gda_t *)GDA_ADDR(get_nasid());
-        if (gdap->g_magic != GDA_MAGIC)
-        	return NULL;
-
-	if (!graphics_pipe_list) {
-		/* for all nodes */
-        	for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
-                	nasid = gdap->g_nasidtable[cnode];
-                	if (nasid == INVALID_NASID)
-                        	continue;
-			lb = KL_CONFIG_INFO(nasid) ;
-			while (lb = find_lboard_class(lb, KLCLASS_GFX)) {
-				moduleid_t kgm, pkgm;
-				int	kgs, pkgs;
-
-#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP)
-				printf("find_gfxpipe(): PIPE: %s mod %M slot %d\n",lb?lb->brd_name:"!LBRD",
-					lb->brd_module,lb->brd_slot);
-#endif
-				/* insert lb into list */
-				if (!(kg = (klgfx_t*)find_first_component(lb,KLSTRUCT_GFX))) {
-					lb = KLCF_NEXT(lb);
-					continue;
-				}
-				/* set moduleslot now that we have brd_module set */
-				kg->moduleslot = (lb->brd_module << 8) | SLOTNUM_GETSLOT(lb->brd_slot);
-				/* make sure board has device flag set */
-				kg->gfx_info.flags |= KLINFO_DEVICE;
-				if (kg->cookie < KLGFX_COOKIE) {
-				    kg->gfx_next_pipe = NULL;
-				    kg->cookie = KLGFX_COOKIE;
-				}
-
-				kgm = kg->moduleslot>>8;
-				kgs = kg->moduleslot&0xff;
-				pkg = &graphics_pipe_list;
-				while (*pkg) {
-					pkgm = (*pkg)->moduleslot>>8;
-					pkgs = (*pkg)->moduleslot&0xff;
-
-					if (!(MODULE_CMP(kgm, pkgm) > 0 ||
-					      (MODULE_CMP(kgm, pkgm) == 0 &&
-					       kgs > pkgs)))
-					    break;
-
-					pkg = &(*pkg)->gfx_next_pipe;
-				}
-				kg->gfx_next_pipe = *pkg;
-				*pkg = kg;
-				lb = KLCF_NEXT(lb);
-			}
-		}
-#ifdef FIND_GFXPIPE_DEBUG
-		i = 0;
-		kg = graphics_pipe_list;
-		while (kg) {
-			lboard_t *lb;
-#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-			lb = find_lboard_class(KL_CONFIG_INFO(kg->gfx_info.nasid), KLCLASS_GFX);
-#else
-#error Need to figure out how to find graphics boards ...
-#endif
-#if defined(SUPPORT_PRINTING_M_FORMAT)
-			printf("find_gfxpipe(): %s pipe %d mod %M slot %d\n",lb?lb->brd_name:"!LBRD",i,
-				(kg->moduleslot>>8),(kg->moduleslot&0xff));
-#else
-			printf("find_gfxpipe(): %s pipe %d mod 0x%x slot %d\n",lb?lb->brd_name:"!LBRD",i,
-				(kg->moduleslot>>8),(kg->moduleslot&0xff));
-#endif
-			kg = kg->gfx_next_pipe;
-			i++;
-		}
-#endif
-        }
-
-	i = 0;
-	kg = graphics_pipe_list;
-	while (kg && (i < pipenum)) {
-		kg = kg->gfx_next_pipe;
-		i++;
-		}
-
-	if (!kg) return NULL;
-
-#if defined(SN0)
-	return find_lboard_modslot(KL_CONFIG_INFO(kg->gfx_info.nasid),
-				(kg->moduleslot>>8),
-				SLOTNUM_XTALK_CLASS|(kg->moduleslot&0xff));
-#elif defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-	return find_lboard_class(KL_CONFIG_INFO(kg->gfx_info.nasid), KLCLASS_GFX);
-#else
-#error Need to figure out how to find graphics boards ...
-#endif
-}
-#endif
-
-
 #define MHZ	1000000
 
-#ifndef CONFIG_IA64_SGI_IO
-uint
-cpu_cycles_adjust(uint orig_cycles)
-{
-	klcpu_t *acpu;
-	uint speed;
-
-	acpu  = nasid_slice_to_cpuinfo(get_nasid(), get_slice());
-
-	if (acpu == NULL) return orig_cycles;
-
-	/*
-	 * cpu cycles seem to be half of the real value, hack and mult by 2
-	 * for now.
-	 */
-	speed = (orig_cycles * 2) / MHZ;
-
-	/*
-	 * if the cpu thinks its running at some random speed nowhere close 
-	 * the programmed speed, do nothing.
-	 */
-	if ((speed < (acpu->cpu_speed - 2)) || (speed > (acpu->cpu_speed + 2)))
-	    return orig_cycles;
-	return (acpu->cpu_speed * MHZ/2);
-}
-#endif /* CONFIG_IA64_SGI_IO */
 
 /* Get the canonical hardware graph name for the given pci component
  * on the given io board.
@@ -633,9 +454,6 @@
 	moduleid_t 	modnum;
 	slotid_t 	slot;
 	char 		board_name[20];
-#ifdef SN0
-	char 		slot_name[SLOTNUM_MAXLENGTH];
-#endif
 
 	ASSERT(brd);
 
@@ -646,13 +464,7 @@
 	 * into a string 
 	 */
 	slot = brd->brd_slot;
-#ifdef SN0
-	get_slotname(slot, slot_name);
-
-	ASSERT(modnum >= 0);
-#else
 	ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE);
-#endif
 
 	/* Get the io board name  */
 	if (!brd || (brd->brd_sversion < 2)) {
@@ -662,18 +474,10 @@
 	}
 
 	/* Give out the canonical  name of the pci device*/
-#ifdef SN0
-	sprintf(name, 
-		"/hw/"EDGE_LBL_MODULE "/%M/"EDGE_LBL_SLOT"/%s/%s/"
-		EDGE_LBL_PCI"/%d", 
-		modnum, slot_name, board_name,KLCF_BRIDGE_W_ID(component));
-#elif defined (CONFIG_SGI_IP35)  || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 	sprintf(name, 
 		"/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/"
 		EDGE_LBL_PCI"/%d", 
 		modnum, board_name,KLCF_BRIDGE_W_ID(component));
-#endif
-	
 }
 
 /*
@@ -894,90 +698,6 @@
 }
 
 #include "asm/sn/sn_private.h"
-#ifndef CONFIG_IA64_SGI_IO
-/*
- * Given a physical address get the name of memory dimm bank
- * in a hwgraph name format.
- */
-void
-membank_pathname_get(paddr_t paddr,char *name)
-{
-	cnodeid_t	cnode;
-	char		slotname[SLOTNUM_MAXLENGTH];
-
-	cnode = paddr_cnode(paddr);
-	/* Make sure that we have a valid name buffer */
-	if (!name)
-		return;
-
-	name[0] = 0;
-	/* Make sure that the cnode is valid */
-	if ((cnode == CNODEID_NONE) || (cnode > numnodes))
-		return;
-	/* Given a slotid(class:type) get the slotname */
-#if defined (SN0)
-	get_slotname(NODE_SLOTID(cnode),slotname);
-	sprintf(name,
-		"/hw/"EDGE_LBL_MODULE"/%M/"EDGE_LBL_SLOT"/%s/"EDGE_LBL_NODE
-		"/"EDGE_LBL_MEMORY"/dimm_bank/%d",
-		NODE_MODULEID(cnode),slotname,paddr_dimm(paddr));
-#elif defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-	sprintf(name,
-		"/dev/hw/"EDGE_LBL_MODULE"/%M/"EDGE_LBL_NODE
-		"/"EDGE_LBL_MEMORY"/dimm_bank/%d",
-		NODE_MODULEID(cnode),paddr_dimm(paddr));
-#endif
-}
-
-
-
-int
-membank_check_mixed_hidensity(nasid_t nasid)
-{
-	lboard_t *brd;
-	klmembnk_t *mem;
-	int min_size = 1024, max_size = 0;
-	int bank, mem_size;
-
-	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
-	ASSERT(brd);
-
-	mem = (klmembnk_t *)find_first_component(brd, KLSTRUCT_MEMBNK);
-	ASSERT(mem);
-
-
-	for (mem_size = 0, bank = 0; bank < MD_MEM_BANKS; bank++) {
-		mem_size = KLCONFIG_MEMBNK_SIZE(mem, bank);
-		if (mem_size < min_size)
-		    min_size = mem_size;
-		if (mem_size > max_size)
-		    max_size = mem_size;
-	}
-	
-	if ((max_size == 512) && (max_size != min_size))
-	    return 1;
-
-	return 0;
-}
-
-
-int
-mem_mixed_hidensity_banks(void)
-{
-	cnodeid_t cnode;
-	nasid_t nasid;
-
-	for (cnode = 0; cnode < maxnodes; cnode++) {
-		nasid = COMPACT_TO_NASID_NODEID(cnode);
-		if (nasid == INVALID_NASID)
-		    continue;
-		if (membank_check_mixed_hidensity(nasid))
-		    return 1;
-	}
-	return 0;
-
-}
-#endif /* CONFIG_IA64_SGI_IO */
 
 xwidgetnum_t
 nodevertex_widgetnum_get(devfs_handle_t node_vtx)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/klgraph.c linux/arch/ia64/sn/io/klgraph.c
--- v2.4.3/linux/arch/ia64/sn/io/klgraph.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/klgraph.c	Thu Apr  5 12:51:47 2001
@@ -23,18 +23,15 @@
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/agent.h>
-#ifdef CONFIG_IA64_SGI_IO
 #include <asm/sn/kldir.h>
-#endif
 #include <asm/sn/gda.h> 
 #include <asm/sn/klconfig.h>
 #include <asm/sn/router.h>
 #include <asm/sn/xtalk/xbow.h>
 #include <asm/sn/hcl_util.h>
 
-#define KLGRAPH_DEBUG 1
+/* #define KLGRAPH_DEBUG 1 */
 #ifdef KLGRAPH_DEBUG
 #define GRPRINTF(x)	printk x
 #define CE_GRPANIC	CE_PANIC
@@ -48,25 +45,6 @@
 extern char arg_maxnodes[];
 extern int maxnodes;
 
-#ifndef BRINGUP
-/*
- * Gets reason for diagval using table lookup.
- */
-static char*
-get_diag_string(uint diagcode)
-{
-  int num_entries;
-  int i;
-  num_entries = sizeof(diagval_map) / sizeof(diagval_t);
-  for (i = 0; i < num_entries; i++){
-    if ((unchar)diagval_map[i].dv_code == (unchar)diagcode)
-      return diagval_map[i].dv_msg;
-  }
-  return "Unknown";
-}
-
-#endif /* ndef BRINGUP */
-
 
 /*
  * Support for verbose inventory via hardware graph. 
@@ -105,7 +83,7 @@
 		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
 	baseio_inventory->im_type = INV_IO6PROM;
 	/* Read the io6prom revision from the nvram */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	nvram_prom_version_get(&version,&revision);
 #endif
 	/* Store the revision info  in the inventory */
@@ -169,7 +147,7 @@
 	(void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
 	rc = device_master_set(myhubv, node_vertex);
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	/*
 	 * Activate when we support hub stats.
 	 */
@@ -178,8 +156,7 @@
 #endif
 
 	if (rc != GRAPH_SUCCESS) {
-		cmn_err(CE_WARN,
-			"klhwg_add_hub: Can't add hub info label 0x%p, code %d",
+		PRINT_WARNING("klhwg_add_hub: Can't add hub info label 0x%p, code %d",
 			myhubv, rc);
 	}
 
@@ -187,15 +164,12 @@
 
 #ifndef BRINGUP
 	init_hub_stats(cnode, NODEPDA(cnode));
-#endif /* ndef BRINGUP */
-
-#ifndef CONFIG_IA64_SGI_IO
 	sndrv_attach(myhubv);
 #else
 	/*
 	 * Need to call our driver to do the attach?
 	 */
-	printk("klhwg_add_hub: Need to add code to do the attach.\n");
+	FIXME("klhwg_add_hub: Need to add code to do the attach.\n");
 #endif
 }
 
@@ -350,7 +324,7 @@
 		rps_invent->ir_gen.ig_flag = INVENT_ENABLED;
 }
 
-#endif /* ndef BRINGUP */
+#endif /* BRINGUP */
 
 void
 klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
@@ -366,7 +340,7 @@
 
 #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC)
 	if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),
-				KLTYPE_PBRICK_XBOW)) == NULL)
+				KLTYPE_IOBRICK_XBOW)) == NULL)
 			return;
 #endif
 
@@ -380,7 +354,7 @@
 	    == NULL)
 	    return;
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	/*
 	 * We cannot support this function in devfs .. see below where 
 	 * we use hwgraph_path_add() to create this vertex with a known 
@@ -390,21 +364,19 @@
 	ASSERT(err == GRAPH_SUCCESS);
 
 	xswitch_vertex_init(xbow_v);
-#endif /* !CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
 		if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
 		    continue;
 
 		hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
-		printk("klhwg_add_xbow: Found xbow port type hub hub_nasid %d widgetnum %d\n", hub_nasid, widgetnum);
 		if (hub_nasid == INVALID_NASID) {
-			cmn_err(CE_WARN, "hub widget %d, skipping xbow graph\n", widgetnum);
+			PRINT_WARNING("hub widget %d, skipping xbow graph\n", widgetnum);
 			continue;
 		}
 
 		hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
-		printk("klhwg_add_xbow: cnode %d cnode %d\n", nasid_to_compact_node[0], nasid_to_compact_node[1]);
 
 		if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
 			continue;
@@ -412,21 +384,18 @@
 			
 		hubv = cnodeid_to_vertex(hub_cnode);
 
-#ifdef CONFIG_IA64_SGI_IO
-		printk("klhwg_add_xbow: Hub Vertex found = %p hub_cnode %d\n", hubv, hub_cnode);
 		err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
                 if (err != GRAPH_SUCCESS) {
                         if (err == GRAPH_DUP)
-                                cmn_err(CE_WARN, "klhwg_add_xbow: Check for "
+                                PRINT_WARNING("klhwg_add_xbow: Check for "
                                         "working routers and router links!");
 
-                        cmn_err(CE_GRPANIC, "klhwg_add_xbow: Failed to add "
+                        PRINT_PANIC("klhwg_add_xbow: Failed to add "
                                 "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p),"
                                 "error %d\n",
                                 hubv, hubv, xbow_v, xbow_v, err);
                 }
 		xswitch_vertex_init(xbow_v); 
-#endif
 
 		NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
 
@@ -443,14 +412,14 @@
 		GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
 			hub_nasid, EDGE_LBL_XTALK, hubv));
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 		err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK);
 		if (err != GRAPH_SUCCESS) {
 			if (err == GRAPH_DUP)
-				cmn_err(CE_WARN, "klhwg_add_xbow: Check for "
+				PRINT_WARNING("klhwg_add_xbow: Check for "
 					"working routers and router links!");
 
-			cmn_err(CE_GRPANIC, "klhwg_add_xbow: Failed to add "
+			PRINT_PANIC("klhwg_add_xbow: Failed to add "
 				"edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), "
 				"error %d\n",
 				hubv, hubv, xbow_v, xbow_v, err);
@@ -488,9 +457,8 @@
 			path_buffer, hwgraph_root));
 		rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
 
-		printk("klhwg_add_node: rv = %d graph success %d node_vertex 0x%p\n", rv, GRAPH_SUCCESS, node_vertex);
 		if (rv != GRAPH_SUCCESS)
-			cmn_err(CE_PANIC, "Node vertex creation failed.  "
+			PRINT_PANIC("Node vertex creation failed.  "
 					  "Path == %s",
 				path_buffer);
 
@@ -504,11 +472,8 @@
 		if(!board_disabled) {
 			mark_nodevertex_as_node(node_vertex,
 					    cnode + board_disabled * numnodes);
-			printk("klhwg_add_node: node_vertex %p, cnode %d numnodes %d\n", node_vertex, cnode, numnodes);
 
 			s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
-			printk("klhwg_add_node: s %s\n", s);
-
 			NODEPDA(cnode)->hwg_node_name =
 						kmalloc(strlen(s) + 1,
 						GFP_KERNEL);
@@ -581,7 +546,7 @@
 			rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
 
 			if (rv != GRAPH_SUCCESS)
-				cmn_err(CE_PANIC, "Router vertex creation "
+				PRINT_PANIC("Router vertex creation "
 						  "failed.  Path == %s",
 					path_buffer);
 
@@ -629,12 +594,11 @@
 			return;
 
 	if (rc != GRAPH_SUCCESS)
-		cmn_err(CE_WARN, "Can't find router: %s", path_buffer);
+		PRINT_WARNING("Can't find router: %s", path_buffer);
 
 	/* We don't know what to do with multiple router components */
 	if (brd->brd_numcompts != 1) {
-		cmn_err(CE_PANIC,
-			"klhwg_connect_one_router: %d cmpts on router\n",
+		PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
 			brd->brd_numcompts);
 		return;
 	}
@@ -668,7 +632,7 @@
 		if (rc != GRAPH_SUCCESS) {
 			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
 				continue;
-			cmn_err(CE_PANIC, "Can't find router: %s", dest_path);
+			PRINT_PANIC("Can't find router: %s", dest_path);
 		}
 		GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
 			  path_buffer, port, dest_path));
@@ -685,7 +649,7 @@
 		}
 
 		if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
-			cmn_err(CE_GRPANIC, "Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
+			PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
 				path_buffer, dest_path, dest_hndl, rc);
 		
 	}
@@ -768,7 +732,7 @@
 		rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
 
 		if (rc != GRAPH_SUCCESS)
-			cmn_err(CE_WARN, "Can't find hub: %s", path_buffer);
+			PRINT_WARNING("Can't find hub: %s", path_buffer);
 
 		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
 				hub->hub_port.port_nasid,
@@ -782,7 +746,7 @@
 		if (rc != GRAPH_SUCCESS) {
 			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
 				continue;
-			cmn_err(CE_PANIC, "Can't find board: %s", dest_path);
+			PRINT_PANIC("Can't find board: %s", dest_path);
 		} else {
 		
 
@@ -792,7 +756,7 @@
 			rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT);
 
 			if (rc != GRAPH_SUCCESS)
-				cmn_err(CE_GRPANIC, "Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
+				PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
 				path_buffer, dest_path, dest_hndl, rc);
 
 		}
@@ -815,7 +779,7 @@
 					 */
 	char		device_name[MAXDEVNAME];
 	
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	device_admin_table_init();
 #endif
 	for(cnode = 0; cnode < numnodes; cnode++) {
@@ -853,7 +817,7 @@
 				device_component_canonical_name_get(board,
 							    component,
 							    device_name);
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 				device_admin_table_update(device_name,
 							  ADMIN_LBL_DISABLED,
 							  "yes");
@@ -877,13 +841,20 @@
 	char		name[128];
 	devfs_handle_t	vhdl;
 	int		rc;
+	char		buffer[16];
 
 	/* Add devices under each module */
 
 	for (cm = 0; cm < nummodules; cm++) {
 		/* Use module as module vertex fastinfo */
 
+#ifdef __ia64
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
+		sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
+#else
 		sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id);
+#endif
 
 		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
 		ASSERT(rc == GRAPH_SUCCESS);
@@ -893,9 +864,15 @@
 
 		/* Add system controller */
 
+#ifdef __ia64
+		sprintf(name,
+			EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
+			buffer);
+#else
 		sprintf(name,
 			EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1,
 			modules[cm]->id);
+#endif
 
 		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
 		ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
@@ -905,7 +882,7 @@
 				     INFO_LBL_ELSC,
 				     (arbitrary_info_t) (__psint_t) 1);
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 		sndrv_attach(vhdl);
 #else
 		/*
@@ -923,13 +900,10 @@
 	gda_t		*gdap;
 	cnodeid_t	cnode;
 
-#ifdef SIMULATED_KLGRAPH
-	//gdap = 0xa800000000011000;
-	gdap = (gda_t *)0xe000000000011000;
-	printk("klhwg_add_all_nodes: SIMULATED_KLGRAPH FIXME: gdap= 0x%p\n", gdap);
-#else
-	gdap = GDA;
-#endif /* SIMULATED_KLGRAPH */
+	gdap = (gda_t *)0xe000000000002400;
+
+	FIXME("klhwg_add_all_nodes: FIX GDA\n");
+
 	for (cnode = 0; cnode < numnodes; cnode++) {
 		ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID);
 		klhwg_add_node(hwgraph_root, cnode, gdap);
@@ -938,12 +912,7 @@
 	for (cnode = 0; cnode < numnodes; cnode++) {
 		ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID);
 
-#ifndef CONFIG_IA64_SGI_IO
 		klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]);
-#else
-		printk("klhwg_add_all_nodes: Fix me by getting real nasid\n");
-		klhwg_add_xbow(cnode, 0);
-#endif
 	}
 
 	/*
@@ -959,7 +928,7 @@
 	 * routers in the system.
 	 */
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	router_guardians_set(hwgraph_root);
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/klgraph_hack.c linux/arch/ia64/sn/io/klgraph_hack.c
--- v2.4.3/linux/arch/ia64/sn/io/klgraph_hack.c	Fri Feb 16 16:02:34 2001
+++ linux/arch/ia64/sn/io/klgraph_hack.c	Thu Apr 12 12:16:35 2001
@@ -15,7 +15,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <asm/sn/sgi.h>
@@ -35,55 +34,6 @@
 extern void clear_ii_error(void);
 #endif /* BRINGUP */
 
-void
-simulated_BW0_init(void)
-{
-
-	unsigned long *cnode0_hub;
-	unsigned long hub_widget = 0x1000000;
-	unsigned long hub_offset = 0x800000;
-	unsigned long hub_reg_base = 0;
-	extern void * vmalloc(unsigned long);
-
-	memset(&nasid_to_compact_node[0], 0, sizeof(cnodeid_t) * MAX_NASIDS);
-
-	BW0 = vmalloc(0x10000000);
-	if (BW0 == NULL) {
-		printk("Darn it .. cannot create space for Big Window 0\n");
-	}
-	printk("BW0: Start Address %p\n", BW0);
-	
-	memset(BW0+(0x10000000 - 8), 0xf, 0x8);
-
-	printk("BW0: Last WORD address %p has value 0x%lx\n", (char *)(BW0 +(0x10000000 - 8)), *(long *)(BW0 +(0x10000000 - 8)));
-
-	printk("XWIDGET 8 Address = 0x%p\n", (unsigned long *)(NODE_SWIN_BASE(0, 8)) ); 
-
-	/*
-	 * Do some HUB Register Hack ..
-	 */
-	hub_reg_base = (unsigned long)BW0 + hub_widget + hub_offset;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WID); *cnode0_hub = 0x1c110049;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WSTAT); *cnode0_hub = 0x0;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_WCR); *cnode0_hub = 0x401b;
-	printk("IIO_WCR address = 0x%p\n", cnode0_hub);
-
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILAPR); *cnode0_hub = 0xffffffffffffffff;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILAPO); *cnode0_hub = 0x0;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IOWA); *cnode0_hub = 0xff01;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIWA); *cnode0_hub = 0xff01;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIDEM); *cnode0_hub = 0xffffffffffffffff;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILCSR); *cnode0_hub = 0x3fc03ff640a;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ILLR); *cnode0_hub = 0x0;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IIDSR); *cnode0_hub = 0x1000040;
-#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IGFX0); *cnode0_hub = 0x0;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_IGFX1); *cnode0_hub = 0x0;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ISCR0); *cnode0_hub = 0x23d;
-        cnode0_hub = (unsigned long *)(hub_reg_base + IIO_ISCR1); *cnode0_hub = 0x0;
-#endif	/* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */
-}
-
 #define SYNERGY_WIDGET          ((char *)0xc0000e0000000000)
 #define SYNERGY_SWIZZLE         ((char *)0xc0000e0000000400)
 #define HUBREG                  ((char *)0xc0000a0001e00000)
@@ -136,10 +86,10 @@
 	klxbow_t	*klxbow_ptr;
 	klinfo_t	*klinfo_ptr;
 	klcomp_t	*klcomp_ptr;
+#if 0
 	uint64_t	*tmp;
 	volatile u32	*tmp32;
 
-#if 0
 	/* Preset some values */
 	/* Write IOERR clear to clear the CRAZY bit in the status */
 	tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff;
@@ -164,7 +114,6 @@
 	*tmp32 = 0xba98;
 	tmp32 = (volatile u32 *)0xc0000a000f000288L;
 	*tmp32 = 0xba98;
-#endif
 
 printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc0000a0001e00000, *( (volatile uint64_t *)0xc0000a0001e00000) );
 
@@ -181,6 +130,7 @@
 
 printk("Xbow ID Address 0x%p Value 0x%x\n", (uint64_t *)0xc000020000000004, *( (volatile uint32_t *)0xc000020000000004) );
 
+#endif
 
 	if ( test )
 		test_io_regs();
@@ -210,9 +160,8 @@
 	 */
 	linux_klcfg = (kl_config_hdr_t *)0xe000000000030000;
 	if (linux_klcfg->ch_magic == 0xbeedbabe) {
-		printk("Linux Kernel Booted from Disk\n");
+		return;
 	} else {
-		printk("Linux Kernel Booted from PROM\n");
 		linux_klcfg = kl_hdr_ptr;
 	}
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/l1.c linux/arch/ia64/sn/io/l1.c
--- v2.4.3/linux/arch/ia64/sn/io/l1.c	Tue Mar  6 19:44:35 2001
+++ linux/arch/ia64/sn/io/l1.c	Thu Apr  5 12:51:47 2001
@@ -34,6 +34,7 @@
 #include <linux/types.h>
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/iograph.h>
 #include <asm/sn/invent.h>
@@ -42,7 +43,6 @@
 #include <asm/sn/labelcl.h>
 #include <asm/sn/eeprom.h>
 #include <asm/sn/ksys/i2c.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/router.h>
 #include <asm/sn/module.h>
 #include <asm/sn/ksys/l1.h>
@@ -51,6 +51,20 @@
 
 #include <asm/sn/sn1/uart16550.h>
 
+/*
+ * Delete this when atomic_clear is part of atomic.h.
+ */
+static __inline__ int
+atomic_clear (int i, atomic_t *v)
+{
+	__s32 old, new;
+
+	do {
+		old = atomic_read(v);
+		new = old & ~i;
+	} while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old);
+	return new;
+}
 
 #if defined(EEPROM_DEBUG)
 #define db_printf(x) printk x
@@ -73,6 +87,7 @@
 /* location of uart receive/xmit data register */
 #define L1_UART_BASE(n)	((ulong)REMOTE_HSPEC_ADDR((n), HSPEC_UART_0))
 #define LOCAL_HUB	LOCAL_HUB_ADDR
+#define LOCK_HUB	REMOTE_HUB_ADDR
 
 #define ADDR_L1_REG(n, r)	\
     (L1_UART_BASE(n) | ( (r) << 3 ))
@@ -84,21 +99,10 @@
     ( SD(ADDR_L1_REG((n), (r)), (v)) )
 
 
-/* Avoid conflicts with symmon...*/
-#define CONS_HW_LOCK(x)
-#define CONS_HW_UNLOCK(x)
-
-#define L1_CONS_HW_LOCK(sc)	CONS_HW_LOCK(sc->uart == BRL1_LOCALUART)
-#define L1_CONS_HW_UNLOCK(sc)	CONS_HW_UNLOCK(sc->uart == BRL1_LOCALUART)
-
-#if DEBUG
-static int debuglock_ospl; /* For CONS_HW_LOCK macro */
-#endif
-
 /* UART-related #defines */
 
 #define UART_BAUD_RATE		57600
-#define UART_FIFO_DEPTH		16
+#define UART_FIFO_DEPTH		0xf0
 #define UART_DELAY_SPAN		10
 #define UART_PUTC_TIMEOUT	50000
 #define UART_INIT_TIMEOUT	100000
@@ -146,6 +150,9 @@
 	    _xyz[0] = _b[_i++];			\
 	}
 #else	/* BIG_ENDIAN */
+
+extern char *bcopy(const char * src, char * dest, int count);
+
 #define COPY_INT_TO_BUFFER(_b, _i, _n)			\
 	{						\
 		bcopy((char *)&_n, _b, sizeof(_n));	\
@@ -165,13 +172,148 @@
 	}
 #endif	/* LITTLE_ENDIAN */
 
-int atomicAddInt(int *int_ptr, int value);
-int atomicClearInt(int *int_ptr, int value);
 void kmem_free(void *where, int size);
 
 #define BCOPY(x,y,z)	memcpy(y,x,z)
 
-extern char *bcopy(const char * src, char * dest, int count);
+/*
+ * Console locking defines and functions.
+ *
+ */
+
+#ifdef BRINGUP
+#define FORCE_CONSOLE_NASID
+#endif
+
+#define HUB_LOCK		16
+
+#define PRIMARY_LOCK_TIMEOUT    10000000
+#define HUB_LOCK_REG(n)         LOCK_HUB(n, MD_PERF_CNT0)
+
+#define SET_BITS(reg, bits)     SD(reg, LD(reg) |  (bits))
+#define CLR_BITS(reg, bits)     SD(reg, LD(reg) & ~(bits))
+#define TST_BITS(reg, bits)     ((LD(reg) & (bits)) != 0)
+
+#define HUB_TEST_AND_SET(n)	LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ))
+#define HUB_CLEAR(n)		SD(LOCK_HUB(n,LB_SCRATCH_REG3),0)
+
+#define RTC_TIME_MAX		((rtc_time_t) ~0ULL)
+
+
+/*
+ * primary_lock
+ *
+ *   Allows CPU's 0-3  to mutually exclude the hub from one another by
+ *   obtaining a blocking lock.  Does nothing if only one CPU is active.
+ *
+ *   This lock should be held just long enough to set or clear a global
+ *   lock bit.  After a relatively short timeout period, this routine
+ *   figures something is wrong, and steals the lock. It does not set
+ *   any other CPU to "dead".
+ */
+inline void
+primary_lock(nasid_t nasid)
+{
+	rtc_time_t          expire;
+
+	expire = rtc_time() + PRIMARY_LOCK_TIMEOUT;
+
+	while (HUB_TEST_AND_SET(nasid)) {
+		if (rtc_time() > expire) {
+			HUB_CLEAR(nasid);
+		}
+	}
+}
+
+/*
+ * primary_unlock (internal)
+ *
+ *   Counterpart to primary_lock
+ */
+
+inline void
+primary_unlock(nasid_t nasid)
+{
+	HUB_CLEAR(nasid);
+}
+
+/*
+ * hub_unlock
+ *
+ *   Counterpart to hub_lock_timeout and hub_lock
+ */
+
+inline void
+hub_unlock(nasid_t nasid, int level)
+{
+	uint64_t mask = 1ULL << level;
+
+	primary_lock(nasid);
+	CLR_BITS(HUB_LOCK_REG(nasid), mask);
+	primary_unlock(nasid);
+}
+
+/*
+ * hub_lock_timeout
+ *
+ *   Uses primary_lock to implement multiple lock levels.
+ *
+ *   There are 20 lock levels from 0 to 19 (limited by the number of bits
+ *   in HUB_LOCK_REG).  To prevent deadlock, multiple locks should be
+ *   obtained in order of increasingly higher level, and released in the
+ *   reverse order.
+ *
+ *   A timeout value of 0 may be used for no timeout.
+ *
+ *   Returns 0 if successful, -1 if lock times out.
+ */
+
+inline int
+hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout)
+{
+	uint64_t mask = 1ULL << level;
+	rtc_time_t expire = (timeout ?  rtc_time() + timeout : RTC_TIME_MAX);
+	int done    = 0;
+
+	while (! done) {
+		while (TST_BITS(HUB_LOCK_REG(nasid), mask)) {
+			if (rtc_time() > expire)
+				return -1;
+		}
+
+		primary_lock(nasid);
+
+		if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) {
+			SET_BITS(HUB_LOCK_REG(nasid), mask);
+			done = 1;
+		}
+		primary_unlock(nasid);
+	}
+	return 0;
+}
+
+
+#define LOCK_TIMEOUT	(0x1500000 * 1) /* 0x1500000 is ~30 sec */
+
+inline void
+lock_console(nasid_t nasid)
+{
+	int ret;
+
+	ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT);
+	if ( ret != 0 ) {
+		/* timeout */
+		hub_unlock(nasid, HUB_LOCK);
+		/* If the 2nd lock fails, just pile ahead.... */
+		hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT);
+	}
+}
+
+inline void
+unlock_console(nasid_t nasid)
+{
+	hub_unlock(nasid, HUB_LOCK);
+}
 
 
 int 
@@ -189,7 +331,7 @@
     UART_DELAY( delay_span );
 }
 
-#define UART_PUTC_READY(n)	(READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE)
+#define UART_PUTC_READY(n)      ( (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) && (READ_L1_UART_REG((n), REG_MSR) & MSR_CTS) )
 
 static int
 uart_putc( l1sc_t *sc ) 
@@ -198,6 +340,10 @@
     /* need a delay to avoid dropping chars */
     UART_DELAY(57);
 #endif
+#ifdef FORCE_CONSOLE_NASID
+    /* We need this for the console write path _elscuart_flush() -> brl1_send() */
+    sc->nasid = 0;
+#endif
     WRITE_L1_UART_REG( sc->nasid, REG_DAT,
 		       sc->send[sc->sent] );
     return UART_SUCCESS;
@@ -210,6 +356,10 @@
     u_char lsr_reg = 0;
     nasid_t nasid = sc->nasid;
 
+#ifdef FORCE_CONSOLE_NASID
+    nasid = sc->nasid = 0;
+#endif
+
     if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & 
 	(LSR_RCA | LSR_PARERR | LSR_FRMERR) ) 
     {
@@ -246,7 +396,8 @@
 	}
     }
 
-    L1_CONS_HW_LOCK( sc );
+    if ( sc->uart == BRL1_LOCALUART )
+	lock_console(nasid);
 
     WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB );
 	uart_delay( UART_DELAY_SPAN );
@@ -271,17 +422,17 @@
     WRITE_L1_UART_REG( nasid, REG_FCR,
 	FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO );
 
-    L1_CONS_HW_UNLOCK( sc );
+    if ( sc->uart == BRL1_LOCALUART )
+	unlock_console(nasid);
 }
 
+/* This requires the console lock */
 static void
 uart_intr_enable( l1sc_t *sc, u_char mask )
 {
     u_char lcr_reg, icr_reg;
     nasid_t nasid = sc->nasid;
 
-    L1_CONS_HW_LOCK(sc);
-
     /* make sure that the DLAB bit in the LCR register is 0
      */
     lcr_reg = READ_L1_UART_REG( nasid, REG_LCR );
@@ -293,18 +444,15 @@
     icr_reg = READ_L1_UART_REG( nasid, REG_ICR );
     icr_reg |= mask;
     WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ );
-
-    L1_CONS_HW_UNLOCK(sc);
 }
 
+/* This requires the console lock */
 static void
 uart_intr_disable( l1sc_t *sc, u_char mask )
 {
     u_char lcr_reg, icr_reg;
     nasid_t nasid = sc->nasid;
 
-    L1_CONS_HW_LOCK(sc);
-
     /* make sure that the DLAB bit in the LCR register is 0
      */
     lcr_reg = READ_L1_UART_REG( nasid, REG_LCR );
@@ -316,8 +464,6 @@
     icr_reg = READ_L1_UART_REG( nasid, REG_ICR );
     icr_reg &= mask;
     WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ );
-
-    L1_CONS_HW_UNLOCK(sc);
 }
 
 #define uart_enable_xmit_intr(sc) \
@@ -353,15 +499,9 @@
 	}						\
     }
 
-#ifdef SABLE
-#define RTR_UART_PUTC_TIMEOUT	0
-#define RTR_UART_DELAY_SPAN	0
-#define RTR_UART_INIT_TIMEOUT	0
-#else
 #define RTR_UART_PUTC_TIMEOUT	UART_PUTC_TIMEOUT*10
 #define RTR_UART_DELAY_SPAN	UART_DELAY_SPAN
 #define RTR_UART_INIT_TIMEOUT	UART_INIT_TIMEOUT*10
-#endif
 
 static int
 rtr_uart_putc( l1sc_t *sc )
@@ -370,7 +510,11 @@
     nasid_t nasid = sc->nasid;
     net_vec_t path = sc->uart;
     rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT;
-    
+
+#ifdef FORCE_CONSOLE_NASID
+    /* We need this for the console write path _elscuart_flush() -> brl1_send() */
+    nasid = sc->nasid = 0;
+#endif
     c = (sc->send[sc->sent] & 0xffULL);
     
     while( 1 ) 
@@ -399,6 +543,10 @@
     nasid_t nasid = sc->nasid;
     net_vec_t path = sc->uart;
 
+#ifdef FORCE_CONSOLE_NASID
+    nasid = sc->nasid = 0;
+#endif
+
     READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
     if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) )
     {
@@ -468,28 +616,6 @@
 
     return 0;
 }
-    
-	
-
-/*********************************************************************
- * locking macros 
- */
-
-#define L1SC_SEND_LOCK(l,pl)						\
-     { if( (l)->uart == BRL1_LOCALUART )				\
-	 (pl) = mutex_spinlock_spl( &((l)->send_lock), spl7 ); }
-
-#define L1SC_SEND_UNLOCK(l,pl)				\
-     { if( (l)->uart == BRL1_LOCALUART )		\
-	 mutex_spinunlock( &((l)->send_lock), (pl)); }
-
-#define L1SC_RECV_LOCK(l,pl)						\
-     { if( (l)->uart == BRL1_LOCALUART )				\
-	 (pl) = mutex_spinlock_spl( &((l)->recv_lock), spl7 ); }
-
-#define L1SC_RECV_UNLOCK(l,pl)				\
-     { if( (l)->uart == BRL1_LOCALUART )		\
-	 mutex_spinunlock( &((l)->recv_lock), (pl)); }
 
 
 /*********************************************************************
@@ -501,60 +627,17 @@
  *
  */
 
-
 #ifdef SPINLOCKS_WORK
-#define SUBCH_LOCK(sc,pl) \
-     (pl) = mutex_spinlock_spl( &((sc)->subch_lock), spl7 )
-#define SUBCH_UNLOCK(sc,pl) \
-     mutex_spinunlock( &((sc)->subch_lock), (pl) )
-
-#define SUBCH_DATA_LOCK(sbch,pl) \
-     (pl) = mutex_spinlock_spl( &((sbch)->data_lock), spl7 )
-#define SUBCH_DATA_UNLOCK(sbch,pl) \
-     mutex_spinunlock( &((sbch)->data_lock), (pl) )
+#define SUBCH_LOCK(sc)			spin_lock_irq( &((sc)->subch_lock) )
+#define SUBCH_UNLOCK(sc)		spin_unlock_irq( &((sc)->subch_lock) )
+#define SUBCH_DATA_LOCK(sbch) 		spin_lock_irq( &((sbch)->data_lock) )
+#define SUBCH_DATA_UNLOCK(sbch)		spin_unlock_irq( &((sbch)->data_lock) )
 #else
-#define SUBCH_LOCK(sc,pl) 
-#define SUBCH_UNLOCK(sc,pl)
-#define SUBCH_DATA_LOCK(sbch,pl)
-#define SUBCH_DATA_UNLOCK(sbch,pl)
-#endif	/* SPINLOCKS_WORK */
-
-/*
- * set a function to be called for subchannel ch in the event of
- * a transmission low-water interrupt from the uart
- */
-void
-subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func )
-{
-    int pl;
-    L1SC_SEND_LOCK( sc, pl );
-    sc->subch[ch].tx_notify = func;
-    
-    /* some upper layer is asking to be notified of low-water, but if the 
-     * send buffer isn't already in use, we're going to need to get the
-     * interrupts going on the uart...
-     */
-    if( func && !sc->send_in_use )
-	uart_enable_xmit_intr( sc );
-    L1SC_SEND_UNLOCK(sc, pl );
-}
-
-/*
- * set a function to be called for subchannel ch when data is received
- */
-void
-subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func )
-{
-#ifdef SPINLOCKS_WORK
-    int pl;
+#define SUBCH_LOCK(sc)
+#define SUBCH_UNLOCK(sc)
+#define SUBCH_DATA_LOCK(sbch)
+#define SUBCH_DATA_UNLOCK(sbch)
 #endif
-    brl1_sch_t *subch = &(sc->subch[ch]);
-
-    SUBCH_DATA_LOCK( subch, pl );
-    sc->subch[ch].rx_notify = func;
-    SUBCH_DATA_UNLOCK( subch, pl );
-}
-
 
 
 /* get_myid is an internal function that reads the PI_CPU_NUM
@@ -680,21 +763,18 @@
 /* timeouts */
 #define BRL1_INIT_TIMEOUT	500000
 
-extern l1sc_t * get_elsc( void );
-
 /*
  * brl1_discard_packet is a dummy "receive callback" used to get rid
  * of packets we don't want
  */
 void brl1_discard_packet( l1sc_t *sc, int ch )
 {
-    int pl;
     brl1_sch_t *subch = &sc->subch[ch];
     sc_cq_t *q = subch->iqp;
-    SUBCH_DATA_LOCK( subch, pl );
+    SUBCH_DATA_LOCK( subch );
     q->opos = q->ipos;
-    atomicClearInt( &(subch->packet_arrived), ~((unsigned)0) );
-    SUBCH_DATA_UNLOCK( subch, pl );
+    atomic_clear( &(subch->packet_arrived), ~((unsigned)0) );
+    SUBCH_DATA_UNLOCK( subch );
 }
 
 
@@ -720,18 +800,14 @@
      */
     if( sc->uart == BRL1_LOCALUART ) 
     {
-	CONS_HW_LOCK(1);
 	if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) )
-//	    sc->fifo_space = UART_FIFO_DEPTH;
-	    sc->fifo_space = 1000;
+	    sc->fifo_space = UART_FIFO_DEPTH;
 	
 	while( (sc->sent < sc->send_len) && (sc->fifo_space) ) {
 	    uart_putc( sc );
 	    sc->fifo_space--;
 	    sc->sent++;
 	}
-
-	CONS_HW_UNLOCK(1);
     }
 
     else
@@ -770,7 +846,6 @@
 	    }
 	}
     }
-    
     return sc->sent;
 }
 
@@ -786,20 +861,25 @@
  * until our message has been completely transmitted.
  */
 
-int
+static int
 brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait )
 {
-    int pl;
     int index;
     int pkt_len = 0;
     unsigned short crc = INIT_CRC;
     char *send_ptr = sc->send;
 
-    L1SC_SEND_LOCK(sc, pl);
+#ifdef BRINGUP
+    /* We want to be sure that we are sending the entire packet before returning */
+    wait = 1;
+#endif
+    if ( sc->uart == BRL1_LOCALUART )
+	lock_console(sc->nasid);
 
     if( sc->send_in_use ) {
 	if( !wait ) {
-	    L1SC_SEND_UNLOCK(sc, pl);
+    	    if ( sc->uart == BRL1_LOCALUART )
+	    	unlock_console(sc->nasid);
 	    return 0; /* couldn't send anything; wait for buffer to drain */
 	}
 	else {
@@ -880,61 +960,12 @@
 	/* enable low-water interrupts so buffer will be drained */
 	uart_enable_xmit_intr(sc);
     }
-    L1SC_SEND_UNLOCK(sc, pl);
+    if ( sc->uart == BRL1_LOCALUART )
+	unlock_console(sc->nasid);
     return len;
 }
 
 
-/* brl1_send_cont is intended to be called as an interrupt service
- * routine.  It sends until the UART won't accept any more characters,
- * or until an error is encountered (in which case we surrender the
- * send buffer and give up trying to send the packet).  Once the
- * last character in the packet has been sent, this routine releases
- * the send buffer and calls any previously-registered "low-water"
- * output routines.
- */
-int
-brl1_send_cont( l1sc_t *sc )
-{
-    int pl;
-    int done = 0;
-    brl1_notif_t callups[BRL1_NUM_SUBCHANS];
-    brl1_notif_t *callup;
-    brl1_sch_t *subch;
-    int index;
-
-    L1SC_SEND_LOCK(sc, pl);
-    brl1_send_chars( sc );
-    done = (sc->sent == sc->send_len);
-    if( done ) {
-
-	sc->send_in_use = 0;
-	uart_disable_xmit_intr(sc);
-
-	/* collect pointers to callups *before* unlocking */
-	subch = sc->subch;
-	callup = callups;
-	for( index = 0; index < BRL1_NUM_SUBCHANS; index++ ) {
-	    *callup = subch->tx_notify;
-	    subch++;
-	    callup++;
-	}
-    }
-    L1SC_SEND_UNLOCK(sc, pl);
-
-    if( done ) {
-	/* call any upper layer that's asked for low-water notification */
-	callup = callups;
-	for( index = 0; index < BRL1_NUM_SUBCHANS; index++ ) {
-	    if( *callup )
-		(*(*callup))( sc, index );
-	    callup++;
-	}
-    }
-    return 0;
-}
-
-
 /* internal function -- used by brl1_receive to read a character 
  * from the uart and check whether errors occurred in the process.
  */
@@ -1039,14 +1070,16 @@
 {
     int result;		/* value to be returned by brl1_receive */
     int c;		/* most-recently-read character	     	*/
-    int pl;		/* priority level for UART receive lock */
     int done;		/* set done to break out of recv loop	*/
     sc_cq_t *q;		/* pointer to queue we're working with	*/
 
     result = BRL1_NO_MESSAGE;
 
-    L1SC_RECV_LOCK( sc, pl );
-    L1_CONS_HW_LOCK( sc );
+#ifdef FORCE_CONSOLE_NASID
+    sc->nasid = 0;
+#endif
+    if ( sc->uart == BRL1_LOCALUART )
+	lock_console(sc->nasid);
 
     done = 0;
     while( !done )
@@ -1171,7 +1204,6 @@
 		unsigned short crc;	/* holds the crc as we calculate it */
 		int i;			/* index variable */
 		brl1_sch_t *subch;      /* subchannel for received packet */
-		int sch_pl;		/* cookie for subchannel lock */
 		brl1_notif_t callup;	/* "data ready" callup */
 
 		/* whatever else may happen, we've seen a flag and we're
@@ -1226,7 +1258,7 @@
 
 		/* get the subchannel and lock it */
 		subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]);
-		SUBCH_DATA_LOCK( subch, sch_pl );
+		SUBCH_DATA_LOCK( subch );
 		
 		/* if this isn't a console packet, we need to record
 		 * a length byte
@@ -1242,16 +1274,16 @@
 		/* notify subchannel owner that there's something
 		 * on the queue for them
 		 */
-		atomicAddInt( &(subch->packet_arrived), 1);
+		atomic_inc(&(subch->packet_arrived));
 		callup = subch->rx_notify;
-		SUBCH_DATA_UNLOCK( subch, sch_pl );
+		SUBCH_DATA_UNLOCK( subch );
 
 		if( callup ) {
-		    L1_CONS_HW_UNLOCK( sc );
-		    L1SC_RECV_UNLOCK( sc, pl );
+		    if ( sc->uart == BRL1_LOCALUART )
+			unlock_console(sc->nasid);
 		    (*callup)( sc, SUBCH(LAST_HDR_GET(sc)) );
-		    L1SC_RECV_LOCK( sc, pl );
-		    L1_CONS_HW_LOCK( sc );
+		    if ( sc->uart == BRL1_LOCALUART )
+			lock_console(sc->nasid);
 		}
 		continue;	/* go back for more! */
 	    }
@@ -1320,8 +1352,8 @@
 	} /* end of switch( STATE_GET(sc) ) */
     } /* end of while(!done) */
     
-    L1_CONS_HW_UNLOCK( sc );
-    L1SC_RECV_UNLOCK(sc, pl);
+    if ( sc->uart == BRL1_LOCALUART )
+	unlock_console(sc->nasid);
 
     return result;
 }	    
@@ -1338,6 +1370,9 @@
     brl1_sch_t *subch;
 
     bzero( sc, sizeof( *sc ) );
+#ifdef FORCE_CONSOLE_NASID
+    nasid = (nasid_t)0;
+#endif
     sc->nasid = nasid;
     sc->uart = uart;
     sc->getc_f = (uart == BRL1_LOCALUART ? uart_getc : rtr_uart_getc);
@@ -1351,9 +1386,9 @@
     /* assign processor TTY channels */
     for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) {
 	subch->use = BRL1_SUBCH_RSVD;
-	subch->packet_arrived = 0;
-	spinlock_init( &(subch->data_lock), NULL );
-	sv_init( &(subch->arrive_sv), SV_FIFO, NULL );
+	subch->packet_arrived = ATOMIC_INIT(0);
+	spin_lock_init( &(subch->data_lock) );
+	sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ );
 	subch->tx_notify = NULL;
 	/* (for now, drop elscuart packets in the kernel) */
 	subch->rx_notify = brl1_discard_packet;
@@ -1364,9 +1399,9 @@
      * processor's individual TTY channel has been assigned)
      */
     subch->use = BRL1_SUBCH_RSVD;
-    subch->packet_arrived = 0;
-    spinlock_init( &(subch->data_lock), NULL );
-    sv_init( &(subch->arrive_sv), SV_FIFO, NULL );
+    subch->packet_arrived = ATOMIC_INIT(0);
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ );
     subch->tx_notify = NULL;
     if( sc->uart == BRL1_LOCALUART ) {
 	subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
@@ -1387,7 +1422,7 @@
      */
     for( ; i < 0x10; i++, subch++ ) {
 	subch->use = BRL1_SUBCH_FREE;
-	subch->packet_arrived = 0;
+	subch->packet_arrived = ATOMIC_INIT(0);
 	subch->tx_notify = NULL;
 	subch->rx_notify = brl1_discard_packet;
 	subch->iqp = &sc->garbage_q;
@@ -1396,7 +1431,7 @@
     /* remaining subchannels are free */
     for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) {
 	subch->use = BRL1_SUBCH_FREE;
-	subch->packet_arrived = 0;
+	subch->packet_arrived = ATOMIC_INIT(0);
 	subch->tx_notify = NULL;
 	subch->rx_notify = brl1_discard_packet;
 	subch->iqp = &sc->garbage_q;
@@ -1404,9 +1439,7 @@
 
     /* initialize synchronization structures
      */
-    spinlock_init( &(sc->send_lock), NULL );
-    spinlock_init( &(sc->recv_lock), NULL );
-    spinlock_init( &(sc->subch_lock), NULL );
+    spin_lock_init( &(sc->subch_lock) );
 
     if( sc->uart == BRL1_LOCALUART ) {
 	uart_init( sc, UART_BAUD_RATE );
@@ -1423,146 +1456,46 @@
 	extern int elsc_module_get(l1sc_t *);
 
 	sc->modid = elsc_module_get( sc );
-	sc->modid = 
-	    (sc->modid < 0 ? INVALID_MODULE : sc->modid);
-
+	sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid);
 	sc->verbose = 1;
     }
 }
 
 
-/*********************************************************************
- * These are interrupt-related functions used in the kernel to service
- * the L1.
- */
-
-/*
- * brl1_intrd is the function which is called in a loop by the
- * xthread that services L1 interrupts.
- */
-#ifdef IRIX
-void
-brl1_intrd( struct eframe_s *ep )
-{
-    u_char isr_reg;
-    l1sc_t *sc = get_elsc();
-
-    isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
-
-    while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) {
-
-	if( isr_reg & ISR_RxRDY ) {
-	    brl1_receive(sc);
-	}
-	if( (isr_reg & ISR_TxRDY) || 
-	    (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) 
-	{
-	    brl1_send_cont(sc);
-	}
-	isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
-    }
-
-    /* uart interrupts were blocked at bedrock when the interrupt
-     * was initially answered; reenable them now
-     */
-    intr_unblock_bit( sc->intr_cpu, UART_INTR );
-    ep = ep; /* placate the compiler */
-}
-#endif
-
-
-
-/* brl1_intr is called directly from the uart interrupt; after it runs, the
- * interrupt "daemon" xthread is signalled to continue.
- */
-#ifdef IRIX
-void
-brl1_intr( struct eframe_s *ep )
-{
-    /* Disable the UART interrupt, giving the xthread time to respond.
-     * When the daemon (xthread) finishes doing its thing, it will
-     * unblock the interrupt.
-     */
-    intr_block_bit( get_elsc()->intr_cpu, UART_INTR );
-    ep = ep; /* placate the compiler */
-}
-
-
-/* set up uart interrupt handling for this node's uart
- */
-void
-brl1_connect_intr( l1sc_t *sc )
-{
-    cpuid_t last_cpu;
-
-    sc->intr_cpu = nodepda->node_first_cpu;
-
-    if( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK,
-			   (intr_func_t)brl1_intrd, 0, 
-			   (intr_func_t)brl1_intr) )
-	cmn_err(CE_PANIC, "brl1_connect_intr: Can't connect UART interrupt.");
-
-    uart_enable_recv_intr( sc );
-}
-#endif	/* IRIX */
-
-#ifdef SABLE
-/* this function is called periodically to generate fake interrupts
- * and allow brl1_intrd to send/receive characters
- */
-void
-hubuart_service( void )
-{
-    l1sc_t *sc = get_elsc();
-    /* note that we'll lose error state by reading the lsr_reg.
-     * This is probably ok in the frictionless domain of sable.
-     */
-    int lsr_reg;
-    nasid_t nasid = sc->nasid;
-    lsr_reg = READ_L1_UART_REG( nasid, REG_LSR );
-    if( lsr_reg & (LSR_RCA | LSR_XSRE) ) {
-        REMOTE_HUB_PI_SEND_INTR(0, 0, UART_INTR);
-    }
-}
-#endif /* SABLE */
-
-
-/*********************************************************************
- * The following function allows the kernel to "go around" the
- * uninitialized l1sc structure to allow console output during
- * early system startup.
- */
-
 /* These are functions to use from serial_in/out when in protocol
- * mode to send and receive uart control regs.
+ * mode to send and receive uart control regs. These are external
+ * interfaces into the protocol driver.
  */
 void
-brl1_send_control(int offset, int value)
+l1_control_out(int offset, int value)
 {
-	nasid_t nasid = get_nasid();
+	nasid_t nasid = 0; //(get_elsc())->nasid;
 	WRITE_L1_UART_REG(nasid, offset, value); 
 }
 
 int
-brl1_get_control(int offset)
+l1_control_in(int offset)
 {
-	nasid_t nasid = get_nasid();
+	nasid_t nasid = 0; //(get_elsc())->nasid;
 	return(READ_L1_UART_REG(nasid, offset)); 
 }
 
 #define PUTCHAR(ch) \
     { \
-        while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE) );  \
+        while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \
+                (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \
         WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \
     }
 
 int
-brl1_send_console_packet( char *str, int len )
+l1_serial_out( char *str, int len )
 {
     int sent = len;
     char crc_char;
     unsigned short crc = INIT_CRC;
-    nasid_t nasid = get_nasid();
+    nasid_t nasid = 0; //(get_elsc())->nasid;
+
+    lock_console(nasid);
 
     PUTCHAR( BRL1_FLAG_CH );
     PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM );
@@ -1598,9 +1531,18 @@
     PUTCHAR( crc_char );
     PUTCHAR( BRL1_FLAG_CH );
 
+    unlock_console(nasid);
     return sent - len;
 }
 
+int
+l1_serial_in(void)
+{
+	static int l1_cons_getc( l1sc_t *sc );
+
+	return(l1_cons_getc(get_elsc()));
+}
+
 
 /*********************************************************************
  * l1_cons functions
@@ -1612,7 +1554,7 @@
  *
  */
 
-int
+static int
 l1_cons_poll( l1sc_t *sc )
 {
     /* in case this gets called before the l1sc_t structure for the module_t
@@ -1623,13 +1565,13 @@
 	return 0;
     }
 
-    if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) {
+    if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) {
 	return 1;
     }
 
     brl1_receive( sc );
 
-    if( sc->subch[SC_CONS_SYSTEM].packet_arrived ) {
+    if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) {
 	return 1;
     }
     return 0;
@@ -1638,13 +1580,11 @@
 
 /* pull a character off of the system console queue (if one is available)
  */
-int
+static int
 l1_cons_getc( l1sc_t *sc )
 {
     int c;
-#ifdef SPINLOCKS_WORK
-    int pl;
-#endif
+
     brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);
     sc_cq_t *q = subch->iqp;
 
@@ -1652,16 +1592,16 @@
 	return 0;
     }
 
-    SUBCH_DATA_LOCK( subch, pl );
+    SUBCH_DATA_LOCK( subch );
     if( cq_empty( q ) ) {
-	subch->packet_arrived = 0;
-	SUBCH_DATA_UNLOCK( subch, pl );
+	atomic_set(&subch->packet_arrived, 0);
+	SUBCH_DATA_UNLOCK( subch );
 	return 0;
     }
     cq_rem( q, c );
     if( cq_empty( q ) )
-	subch->packet_arrived = 0;
-    SUBCH_DATA_UNLOCK( subch, pl );
+	atomic_set(&subch->packet_arrived, 0);
+    SUBCH_DATA_UNLOCK( subch );
 
     return c;
 }
@@ -1672,106 +1612,15 @@
 void
 l1_cons_init( l1sc_t *sc )
 {
-#ifdef SPINLOCKS_WORK
-    int pl;
-#endif
     brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);
 
-    SUBCH_DATA_LOCK( subch, pl );
-    subch->packet_arrived = 0;
+    SUBCH_DATA_LOCK( subch );
+    atomic_set(&subch->packet_arrived, 0);
     cq_init( subch->iqp );
-    SUBCH_DATA_UNLOCK( subch, pl );
-}
-
-
-/*
- * Write a message to the L1 on the system console subchannel.
- *
- * Danger: don't use a non-zero value for the wait parameter unless you're
- * someone important (like a kernel error message).
- */
-int
-l1_cons_write( l1sc_t *sc, char *msg, int len, int wait )
-{
-    return( brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ) );
-}
-
-
-/* 
- * Read as many characters from the system console receive queue as are
- * available there (up to avail bytes).
- */
-int
-l1_cons_read( l1sc_t *sc, char *buf, int avail )
-{
-    int pl;
-    int before_wrap, after_wrap;
-    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);
-    sc_cq_t *q = subch->iqp;
-
-    if( !(subch->packet_arrived) )
-	return 0;
-
-    SUBCH_DATA_LOCK( subch, pl );
-    if( q->opos > q->ipos ) {
-	before_wrap = BRL1_QSIZE - q->opos;
-	if( before_wrap >= avail ) {
-	    before_wrap = avail;
-	    after_wrap = 0;
-	}
-	else {
-	    avail -= before_wrap;
-	    after_wrap = q->ipos;
-	    if( after_wrap > avail )
-		after_wrap = avail;
-	}
-    }
-    else {
-	before_wrap = q->ipos - q->opos;
-	if( before_wrap > avail )
-	    before_wrap = avail;
-	after_wrap = 0;
-    }
-
-
-    BCOPY( q->buf + q->opos, buf, before_wrap  );
-    if( after_wrap )
-        BCOPY( q->buf, buf + before_wrap, after_wrap  );
-    q->opos = ((q->opos + before_wrap + after_wrap) % BRL1_QSIZE);
-
-    subch->packet_arrived = 0;
-    SUBCH_DATA_UNLOCK( subch, pl );
-
-    return( before_wrap + after_wrap );
-}
-	
-
-/*
- * Install a callback function for the system console subchannel 
- * to allow an upper layer to be notified when the send buffer 
- * has been emptied.
- */
-void
-l1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func )
-{
-    subch_set_tx_notify( sc, SC_CONS_SYSTEM, func );
-}
-
-
-/*
- * Install a callback function for the system console subchannel
- * to allow an upper layer to be notified when a packet has been
- * received.
- */
-void
-l1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func )
-{
-    subch_set_rx_notify( sc, SC_CONS_SYSTEM, func );
+    SUBCH_DATA_UNLOCK( subch );
 }
 
 
-
-
 /*********************************************************************
  * The following functions and definitions implement the "message"-
  * style interface to the L1 system controller.
@@ -1795,7 +1644,9 @@
 sc_data_ready( l1sc_t *sc, int ch )
 {
     brl1_sch_t *subch = &(sc->subch[ch]);
+    SUBCH_DATA_LOCK( subch );
     sv_signal( &(subch->arrive_sv) );
+    SUBCH_DATA_UNLOCK( subch );
 }
 
 /* sc_open reserves a subchannel to send a request to the L1 (the
@@ -1810,10 +1661,9 @@
      * subchannel assignment.
      */
     int ch;
-    int pl;
     brl1_sch_t *subch;
 
-    SUBCH_LOCK( sc, pl );
+    SUBCH_LOCK( sc );
 
     /* Look for a free subchannel. Subchannels 0-15 are reserved
      * for other purposes.
@@ -1826,17 +1676,17 @@
 
     if( ch == BRL1_NUM_SUBCHANS ) {
         /* there were no subchannels available! */
-        SUBCH_UNLOCK( sc, pl );
+        SUBCH_UNLOCK( sc );
         return SC_NSUBCH;
     }
 
     subch->use = BRL1_SUBCH_RSVD;
-    SUBCH_UNLOCK( sc, pl );
+    SUBCH_UNLOCK( sc );
 
-    subch->packet_arrived = 0;
+    atomic_set(&subch->packet_arrived, 0);
     subch->target = target;
-    sv_init( &(subch->arrive_sv), SV_FIFO, NULL );
-    spinlock_init( &(subch->data_lock), NULL );
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */);
     subch->tx_notify = NULL;
     subch->rx_notify = sc_data_ready;
     subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
@@ -1854,27 +1704,28 @@
 sc_close( l1sc_t *sc, int ch )
 {
     brl1_sch_t *subch;
-    int pl;
 
-    SUBCH_LOCK( sc, pl );
+    SUBCH_LOCK( sc );
     subch = &(sc->subch[ch]);
     if( subch->use != BRL1_SUBCH_RSVD ) {
         /* we're trying to close a subchannel that's not open */
         return SC_NOPEN;
     }
 
-    subch->packet_arrived = 0;
+    atomic_set(&subch->packet_arrived, 0);
     subch->use = BRL1_SUBCH_FREE;
 
+    SUBCH_DATA_LOCK( subch );
     sv_broadcast( &(subch->arrive_sv) );
     sv_destroy( &(subch->arrive_sv) );
-    spinlock_destroy( &(subch->data_lock) );
+    SUBCH_DATA_UNLOCK( subch );
+    spin_lock_destroy( &(subch->data_lock) );
 
     ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) );
     kmem_free( subch->iqp, sizeof(sc_cq_t) );
     subch->iqp = &sc->garbage_q;
 
-    SUBCH_UNLOCK( sc, pl );
+    SUBCH_UNLOCK( sc );
 
     return SC_SUCCESS;
 }
@@ -2248,7 +2099,7 @@
     else {
 	q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1));
     }
-    atomicAddInt( &(subch->packet_arrived), -1 );
+    atomic_dec(&(subch->packet_arrived));
 }
 
 
@@ -2263,7 +2114,6 @@
 int
 sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block )
 {
-    int pl;             /* lock cookie */
     int is_msg = 0;
     brl1_sch_t *subch = &(sc->subch[ch]);
 
@@ -2278,7 +2128,7 @@
         /* kick the next lower layer and see if it pulls anything in
          */
 	brl1_receive( sc );
-	is_msg = subch->packet_arrived;
+	is_msg = atomic_read(&subch->packet_arrived);
 
     } while( block && !is_msg && (rtc_time() < exp_time) );
 
@@ -2287,9 +2137,9 @@
 	return( SC_NMSG );
     }
 
-    SUBCH_DATA_LOCK( subch, pl );
+    SUBCH_DATA_LOCK( subch );
     subch_pull_msg( subch, msg, len );
-    SUBCH_DATA_UNLOCK( subch, pl );
+    SUBCH_DATA_UNLOCK( subch );
 
     return( SC_SUCCESS );
 }
@@ -2305,17 +2155,16 @@
 int
 sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block )
 {
-    int pl;             /* lock cookie */
     int is_msg = 0;
     brl1_sch_t *subch = &(sc->subch[ch]);
 
     do {
-	SUBCH_DATA_LOCK(subch, pl);
-	is_msg = subch->packet_arrived;
+	SUBCH_DATA_LOCK(subch);
+	is_msg = atomic_read(&subch->packet_arrived);
 	if( !is_msg && block ) {
 	    /* wake me when you've got something */
 	    subch->rx_notify = sc_data_ready;
-	    sv_wait( &(subch->arrive_sv), 0, &(subch->data_lock), pl );
+	    sv_wait( &(subch->arrive_sv), 0, 0);
 	    if( subch->use == BRL1_SUBCH_FREE ) {
 		/* oops-- somebody closed our subchannel while we were
 		 * sleeping!
@@ -2329,12 +2178,12 @@
 
     if( !is_msg ) {
 	/* no message and we didn't care to wait for one */
-	SUBCH_DATA_UNLOCK( subch, pl );
+	SUBCH_DATA_UNLOCK( subch );
 	return( SC_NMSG );
     }
 
     subch_pull_msg( subch, msg, len );
-    SUBCH_DATA_UNLOCK( subch, pl );
+    SUBCH_DATA_UNLOCK( subch );
 
     return( SC_SUCCESS );
 }
@@ -2388,12 +2237,12 @@
     }
     
     /* block on sc_recv_* */
-#ifdef notyet
+#ifdef LATER
     if( sc->uart == BRL1_LOCALUART ) {
 	return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) );
     }
     else
-#endif
+#endif	/* LATER */
     {
 	return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );
     }
@@ -2438,12 +2287,12 @@
 {
     brl1_sch_t *subch = &(sc->subch[ch]);
 
-    if( subch->packet_arrived )
+    if( atomic_read(&subch->packet_arrived) )
 	return 1;
 
     brl1_receive( sc );
 
-    if( subch->packet_arrived )
+    if( atomic_read(&subch->packet_arrived) )
 	return 1;
 
     return 0;
@@ -2461,6 +2310,9 @@
 /* sc_dispatch_env_event handles events sent from the system control
  * network's environmental monitor tasks.
  */
+
+#ifdef LINUX_KERNEL_THREADS
+
 static void
 sc_dispatch_env_event( uint code, int argc, char *args, int maxlen )
 {
@@ -2512,18 +2364,16 @@
 	for( ;
 	     i < j && ((args[i] == 0xd) || (args[i] == 0xa));
 	     i++ );
-	
-	/* write the event to syslog */
-#ifdef IRIX
-	cmn_err_tag( ESPcode, CE_WARN, &(args[i]) );
-#endif
     }
 }
+#endif	/* LINUX_KERNEL_THREADS */
 
 
 /* sc_event waits for events to arrive from the system controller, and
  * prints appropriate messages to the syslog.
  */
+
+#ifdef LINUX_KERNEL_THREADS
 static void
 sc_event( l1sc_t *sc, int ch )
 {
@@ -2544,7 +2394,7 @@
 	 */
 	result = sc_recv_intr( sc, ch, event, &event_len, 1 );
 	if( result != SC_SUCCESS ) {
-	    cmn_err( CE_WARN, "Error receiving sysctl event on nasid %d\n",
+	    PRINT_WARNING("Error receiving sysctl event on nasid %d\n",
 		     sc->nasid );
 	}
 	else {
@@ -2588,13 +2438,13 @@
 	
     }			
 }
+#endif	/* LINUX_KERNEL_THREADS */
 
 /* sc_listen sets up a service thread to listen for incoming events.
  */
 void
 sc_listen( l1sc_t *sc )
 {
-    int pl;
     int result;
     brl1_sch_t *subch;
 
@@ -2602,24 +2452,26 @@
     int         len;    /* length of message being sent */
     int         ch;     /* system controller subchannel used */
 
+#ifdef LINUX_KERNEL_THREADS
     extern int msc_shutdown_pri;
+#endif
 
     /* grab the designated "event subchannel" */
-    SUBCH_LOCK( sc, pl );
+    SUBCH_LOCK( sc );
     subch = &(sc->subch[BRL1_EVENT_SUBCH]);
     if( subch->use != BRL1_SUBCH_FREE ) {
-	SUBCH_UNLOCK( sc, pl );
-	cmn_err( CE_WARN, "sysctl event subchannel in use! "
+	SUBCH_UNLOCK( sc );
+	PRINT_WARNING("sysctl event subchannel in use! "
 		 "Not monitoring sysctl events.\n" );
 	return;
     }
     subch->use = BRL1_SUBCH_RSVD;
-    SUBCH_UNLOCK( sc, pl );
+    SUBCH_UNLOCK( sc );
 
-    subch->packet_arrived = 0;
+    atomic_set(&subch->packet_arrived, 0);
     subch->target = BRL1_LOCALUART;
-    sv_init( &(subch->arrive_sv), SV_FIFO, NULL );
-    spinlock_init( &(subch->data_lock), NULL );
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */);
     subch->tx_notify = NULL;
     subch->rx_notify = sc_data_ready;
     subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
@@ -2670,7 +2522,7 @@
 	
 err_return:
     /* there was a problem; complain */
-    cmn_err( CE_WARN, "failed to set sysctl event-monitoring subchannel.  "
+    PRINT_WARNING("failed to set sysctl event-monitoring subchannel.  "
 	     "Sysctl events will not be monitored.\n" );
 }
 
@@ -2825,7 +2677,7 @@
 int
 _elscuart_readc( l1sc_t *sc )
 {
-    int c, pl;
+    int c;
     sc_cq_t *q;
     brl1_sch_t *subch;
 
@@ -2833,32 +2685,32 @@
 	subch = &(sc->subch[ SC_CONS_SYSTEM ]);
 	q = subch->iqp;
 	
-	SUBCH_DATA_LOCK( subch, pl );
+	SUBCH_DATA_LOCK( subch );
         if( !cq_empty( q ) ) {
             cq_rem( q, c );
 	    if( cq_empty( q ) ) {
-		subch->packet_arrived = 0;
+		atomic_set(&subch->packet_arrived, 0);
 	    }
-	    SUBCH_DATA_UNLOCK( subch, pl );
+	    SUBCH_DATA_UNLOCK( subch );
             return c;
         }
-	SUBCH_DATA_UNLOCK( subch, pl );
+	SUBCH_DATA_UNLOCK( subch );
     }
 
     subch = &(sc->subch[ L1_ELSCUART_SUBCH(get_myid()) ]);
     q = subch->iqp;
 
-    SUBCH_DATA_LOCK( subch, pl );
+    SUBCH_DATA_LOCK( subch );
     if( cq_empty( q ) ) {
-	SUBCH_DATA_UNLOCK( subch, pl );
+	SUBCH_DATA_UNLOCK( subch );
         return -1;
     }
 
     cq_rem( q, c );
     if( cq_empty ( q ) ) {
-	subch->packet_arrived = 0;
+	atomic_set(&subch->packet_arrived, 0);
     }
-    SUBCH_DATA_UNLOCK( subch, pl );
+    SUBCH_DATA_UNLOCK( subch );
 
     return c;
 }
@@ -2918,6 +2770,7 @@
 #else
     char ver[BRL1_QSIZE];
     extern int elsc_version( l1sc_t *, char * );
+
     if ( IS_RUNNING_ON_SIMULATOR() )
     	return 0;
     return( elsc_version(sc, ver) >= 0 );
@@ -2932,43 +2785,13 @@
 void
 _elscuart_init( l1sc_t *sc )
 {
-    int pl;
     brl1_sch_t *subch = &sc->subch[L1_ELSCUART_SUBCH(get_myid())];
 
-    SUBCH_DATA_LOCK(subch, pl);
+    SUBCH_DATA_LOCK(subch);
 
-    subch->packet_arrived = 0;
+    atomic_set(&subch->packet_arrived, 0);
     cq_init( subch->iqp );
     cq_init( &sc->oq[MAP_OQ(L1_ELSCUART_SUBCH(get_myid()))] );
 
-    SUBCH_DATA_UNLOCK(subch, pl);
-}
-
-
-#ifdef IRIX
-
-/* elscuart_syscon_listen causes the processor on which it's
- * invoked to "listen" to the system console subchannel (that
- * is, subchannel 4) for console input.
- */
-void
-elscuart_syscon_listen( l1sc_t *sc )
-{
-    int pl;
-    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);
-
-    /* if we're already listening, don't bother */
-    if( sc->cons_listen )
-        return;
-
-    SUBCH_DATA_LOCK( subch, pl );
-
-    subch->use = BRL1_SUBCH_RSVD;
-    subch->packet_arrived = 0;
-
-    SUBCH_DATA_UNLOCK( subch, pl );
-
-
-    sc->cons_listen = 1;
+    SUBCH_DATA_UNLOCK(subch);
 }
-#endif	/* IRIX */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/l1_command.c linux/arch/ia64/sn/io/l1_command.c
--- v2.4.3/linux/arch/ia64/sn/io/l1_command.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/l1_command.c	Thu Apr  5 12:51:47 2001
@@ -18,7 +18,6 @@
 #include <asm/sn/labelcl.h>
 #include <asm/sn/eeprom.h>
 #include <asm/sn/ksys/i2c.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/router.h>
 #include <asm/sn/module.h>
 #include <asm/sn/ksys/l1.h>
@@ -68,7 +67,6 @@
 
 #define SC_COMMAND sc_command
 
-
 /*
  * elsc_init
  *
@@ -206,6 +204,7 @@
     return -1;
 }
 
+
 /*
  * Command Set
  */
@@ -312,6 +311,7 @@
     return 0;
 }
 
+
 /*
  * elsc_rack_bay_get fills in the two int * arguments with the
  * rack number and bay number of the L1 being addressed
@@ -447,8 +447,9 @@
 
     /* construct module ID from rack and slot info */
 
-    if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0)
+    if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) {
 	return ret;
+    }
 
     /* report unset location info. with a special, otherwise invalid modid */
     if (rnum == 0 && bay == 0)
@@ -935,6 +936,7 @@
     return cbrick_uid_get( e->nasid, nic );
 }
 
+
 int _elsc_hbt(elsc_t *e, int ival, int rdly)
 {
     e = e;
@@ -958,11 +960,12 @@
 
     /* fill in msg with the opcode & params */
     bzero( msg, BRL1_QSIZE );
-    subch = sc_open( sc, L1_ADDR_LOCAL );
 
-    L1_BUILD_ADDR( &target, compt, rack, bay, L1_ADDR_TASK_CMD );
+    L1_BUILD_ADDR( &target, compt, rack, bay, 0 );
+    subch = sc_open( sc, target );
+
     if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
-				 target, L1_REQ_EXEC_CMD, 2,
+				 L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2,
 				 L1_ARG_ASCII, cmd )) < 0 )
     {
 	sc_close( sc, subch );
@@ -970,7 +973,7 @@
     }
 		   
     /* send the request to the L1 */
-    if( sc_command( sc, subch, msg, msg, &len ) < 0 )
+    if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 )
     {
 	sc_close( sc, subch );
 	return( ELSC_ERROR_CMD_SEND );
@@ -988,6 +991,38 @@
     return 0;
 }
 
+/*
+ * sc_power_down
+ *
+ * Shuts down the c-brick associated with sc, and any attached I/O bricks
+ * or other c-bricks (won't go through r-bricks).
+ */
+
+int sc_power_down(l1sc_t *sc)
+{
+    return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, 
+			      L1_ADDR_BAY_LOCAL, "* pwr d" );
+}
+
+
+/*
+ * sc_power_down_all
+ *
+ * Works similarly to sc_power_down, except that the request is sent to the
+ * closest L2 and EVERYBODY gets turned off.
+ */
+
+int sc_power_down_all(l1sc_t *sc)
+{
+    if( nodepda->num_routers > 0 ) {
+	return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, 
+				  L1_ADDR_BAY_LOCAL, "* pwr d" );
+    }
+    else {
+	return sc_power_down( sc );
+    }
+}
+
 
 /*
  * Routines for reading the R-brick's L1
@@ -1115,10 +1150,6 @@
     if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0)
         return ret;
 
-    /* report unset location info. with a special, otherwise invalid modid */
-    if (rnum == 0 && bay == 0)
-        return MODULE_NOT_SET;
-
     if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
         return ELSC_ERROR_MODULE;
 
@@ -1203,28 +1234,101 @@
  */
 
 int
-iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up )
+iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code )
 {
-    char cmd[BRL1_QSIZE];
-    unsigned rack, bay, brick_type;
-    if( iobrick_rack_bay_type_get( sc, &rack, &bay, &brick_type ) < 0 )
+#if 0 /* The "bedrock request" method of performing this function
+       * seems to be broken in the L1, so for now use the command-
+       * interpreter method
+       */
+
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCALIO );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 req_code, 4,
+				 L1_ARG_INT, bus,
+				 L1_ARG_INT, slot )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
 	return( ELSC_ERROR_CMD_SEND );
-    sprintf( cmd, "pci %d %d %s", bus, slot,
-	     (up ? "u" : "d") );
-    return( sc_command_interp
-	    ( sc, L1_ADDR_TYPE_L1, rack, bay, cmd ) );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+
+#else
+    char cmd[64];
+    char *fxn;
+
+    switch( req_code )
+    {
+    case L1_REQ_PCI_UP:
+	fxn = "u";
+	break;
+    case L1_REQ_PCI_DOWN:
+	fxn = "d";
+	break;
+    case L1_REQ_PCI_RESET:
+	fxn = "rst";
+	break;
+    default:
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    if( slot == -1 ) 
+	sprintf( cmd, "pci %d %s", bus, fxn );
+    else
+        sprintf( cmd, "pci %d %d %s", bus, slot, fxn );
+	
+    return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK,
+	L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd );
+#endif
+}
+				 
+int
+iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up )
+{
+    return iobrick_pci_pwr( sc, bus, slot, up );
 }
 
 int
 iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up )
 {
-    char cmd[BRL1_QSIZE];
-    unsigned rack, bay, brick_type;
-    if( iobrick_rack_bay_type_get( sc, &rack, &bay, &brick_type ) < 0 )
-	return( ELSC_ERROR_CMD_SEND );
-    sprintf( cmd, "pci %d %s", bus, (up ? "u" : "d") );
-    return( sc_command_interp
-	    ( sc, L1_ADDR_TYPE_L1, rack, bay, cmd ) );
+    return iobrick_pci_pwr( sc, bus, -1, up );
+}
+
+
+int
+iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot )
+{
+    return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET );
+}
+
+int
+iobrick_pci_bus_rst( l1sc_t *sc, int bus )
+{
+    return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET );
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/labelcl.c linux/arch/ia64/sn/io/labelcl.c
--- v2.4.3/linux/arch/ia64/sn/io/labelcl.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/labelcl.c	Thu Apr  5 12:51:47 2001
@@ -286,7 +286,7 @@
 		if (!strcmp(info_name, old_label_list[i].name)) {
 			/* Not allowed to add duplicate labelled info names. */
 			kfree(new_label_list);
-			printk("labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de);
+			printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de);
 			return(-1);
 		}
 		new_label_list[i] = old_label_list[i]; /* structure copy */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/mem_refcnt.c linux/arch/ia64/sn/io/mem_refcnt.c
--- v2.4.3/linux/arch/ia64/sn/io/mem_refcnt.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/mem_refcnt.c	Thu Apr 12 12:16:35 2001
@@ -9,7 +9,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/invent.h>
 #include <asm/sn/hcl.h>
@@ -58,15 +57,8 @@
 mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp)
 {
         cnodeid_t node;
-#ifndef CONFIG_IA64_SGI_SN1
-	extern int numnodes;
-#endif
-        
-        ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS );
 
-        if (!cap_able(CAP_MEMORY_MGT)) {
-                return (EPERM);
-        }
+        ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS );
 
         node = master_node_get(*devp);
 
@@ -97,9 +89,6 @@
         int errcode;
         char* buffer;
         size_t blen;
-#ifndef CONFIG_IA64_SGI_SN1
-	extern int numnodes;
-#endif
         
         ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(dev) == HUBSPC_REFCOUNTERS );
 
@@ -186,7 +175,7 @@
                 
                 rcb.rcb_cnodeid = node;
                 rcb.rcb_granularity = MD_PAGE_SIZE;
-#ifdef notyet
+#ifdef LATER
                 rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node);
                 rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node);
 #endif
@@ -209,7 +198,7 @@
                 ASSERT(nslots <= MAX_MEM_SLOTS);
                 for (s = 0; s < nslots; s++) {
                         slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s));
-#ifdef notyet
+#ifdef LATER
                         slot[s].size  = (uint64_t)ctob(slot_getsize(node, s));
 #else
                         slot[s].size  = (uint64_t)1;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ml_SN_init.c linux/arch/ia64/sn/io/ml_SN_init.c
--- v2.4.3/linux/arch/ia64/sn/io/ml_SN_init.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/ml_SN_init.c	Thu Apr  5 12:51:47 2001
@@ -45,25 +45,8 @@
 
 extern xwidgetnum_t hub_widget_id(nasid_t);
 
-#ifndef CONFIG_IA64_SGI_IO
-#if defined (IP27)
-short		cputype = CPU_IP27;
-#elif defined (IP33)
-short		cputype = CPU_IP33;
-#elif defined (IP35)
-short		cputype = CPU_IP35;
-#else
-#error <BOMB! define new cputype here >
-#endif
-#endif /* CONFIG_IA64_SGI_IO */
-
 static int	fine_mode = 0;
 
-#ifndef CONFIG_IA64_SGI_IO
-/* Global variables */
-pdaindr_t	pdaindr[MAXCPUS];
-#endif
-
 static cnodemask_t	hub_init_mask;	/* Mask of cpu in a node doing init */
 static volatile cnodemask_t hub_init_done_mask;
 					/* Node mask where we wait for
@@ -101,7 +84,7 @@
 		master_nasid = get_nasid();
 		set_master_bridge_base();
 		FIXME("mlreset: Enable when we support ioc3 ..");
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 		if (get_console_nasid() == master_nasid) 
 			/* Set up the IOC3 */
 			ioc3_mlreset((ioc3_cfg_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->config_base,
@@ -113,7 +96,7 @@
 		nvram_baseinit();
 
 		fine_mode = is_fine_dirmode();
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 		/* We're the master processor */
 		master_procid = smp_processor_id();
@@ -125,7 +108,7 @@
 		 */
 		ASSERT_ALWAYS(master_nasid == get_nasid());
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 
 	/*
 	 * Activate when calias is implemented.
@@ -155,7 +138,7 @@
 				((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
 				(0 << IIO_ITTE_WIDGET_SHIFT)));
 		}
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 		/* Set up the hub initialization mask and init the lock */
 		CNODEMASK_CLRALL(hub_init_mask);
@@ -169,7 +152,7 @@
 		/* Initialize Hub Pseudodriver Management */
 		hubdev_init();
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 		/*
 		 * Our IO system doesn't require cache writebacks.  Set some
 		 * variables appropriately.
@@ -192,7 +175,7 @@
                  * keep redundant PROM code in memory.
                  */
 		he_arcs_set_vectors();
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 	} else { /* slave != 0 */
 		/*
@@ -216,8 +199,10 @@
 
 	extern void router_map_init(nodepda_t *);
 	extern void router_queue_init(nodepda_t *,cnodeid_t);
+	extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int);
+
 #if defined(DEBUG)
-	extern lock_t		intr_dev_targ_map_lock;
+	extern spinlock_t	intr_dev_targ_map_lock;
 	extern uint64_t 	intr_dev_targ_map_size;
 
 	/* Initialize the lock to access the device - target cpu mapping
@@ -229,7 +214,7 @@
 		 * There is always a cnode 0 present.
 		 */
 		intr_dev_targ_map_size = 0;
-		init_spinlock(&intr_dev_targ_map_lock,"dtmap_lock",0);
+		spin_lock_init(&intr_dev_targ_map_lock);
 	}
 #endif	/* DEBUG */
 	/* Allocate per-node platform-dependent data */
@@ -241,8 +226,6 @@
 	hubinfo->h_cnodeid = node;
 	hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node);
 
-	printk("init_platform_nodepda: hubinfo 0x%p, &hubinfo->h_crblock 0x%p\n", hubinfo, &hubinfo->h_crblock);
-
 	spin_lock_init(&hubinfo->h_crblock);
 
 	hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid);
@@ -265,21 +248,18 @@
 	for (sn=0; sn<NUM_SUBNODES; sn++) {
 		SNPDA(npda,sn)->prof_count = 0;
 		SNPDA(npda,sn)->next_prof_timeout = 0;
-// ajm
-#ifndef CONFIG_IA64_SGI_IO
 		intr_init_vecblk(npda, node, sn);
-#endif
 	}
 
 	npda->vector_unit_busy = 0;
 
 	spin_lock_init(&npda->vector_lock);
-	init_MUTEX_LOCKED(&npda->xbow_sema); /* init it locked? */
+	mutex_init_locked(&npda->xbow_sema); /* init it locked? */
 	spin_lock_init(&npda->fprom_lock);
 
 	spin_lock_init(&npda->node_utlbswitchlock);
 	npda->ni_error_print = 0;
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	if (need_utlbmiss_patch) {
 		npda->node_need_utlbmiss_patch = 1;
 		npda->node_utlbmiss_patched = 1;
@@ -299,7 +279,7 @@
 		npda->nasid_mask[nasid / 8] |= (1 << nasid % 8);
 	}
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	npda->node_first_cpu = get_cnode_cpu(node);
 #endif
 
@@ -324,7 +304,7 @@
 	 * may not be guaranteed shared memory at that time
 	 * which precludes depending on a global dump stack
 	 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	npda->dump_stack = (uint64_t *)kmem_zalloc_node(DUMP_STACK_SIZE,VM_NOSLEEP,
 							  node);
 	ASSERT_ALWAYS(npda->dump_stack);
@@ -334,7 +314,7 @@
 	 * both the cpus on a node to proceed with nmi
 	 * handling.
 	 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	npda->dump_count = 0;
 
 	/* Setup the (module,slot) --> nic mapping for all the routers
@@ -356,7 +336,7 @@
 		npda->node_bte_info[i] = (bteinfo_t *)NULL;
 	}
 #endif
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 }
 
 /* XXX - Move the interrupt stuff to intr.c ? */
@@ -369,13 +349,15 @@
 void init_platform_pda(cpuid_t cpu)
 {
 	hub_intmasks_t *intmasks;
+#ifdef	LATER
 	cpuinfo_t cpuinfo;
+#endif
 	int i;
 	cnodeid_t	cnode;
 	synergy_da_t	*sda;
 	int	which_synergy;
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	/* Allocate per-cpu platform-dependent data */
 	cpuinfo = (cpuinfo_t)kmem_alloc_node(sizeof(struct cpuinfo_s), GFP_ATOMIC, cputocnode(cpu));
 	ASSERT_ALWAYS(cpuinfo);
@@ -390,7 +372,7 @@
 	// intmasks = &ppda->p_intmasks;
 	intmasks = &sda->s_intmasks;
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	ASSERT_ALWAYS(&ppda->p_nodepda);
 #endif
 
@@ -400,15 +382,15 @@
 
 	/* Set up pointer to the vector block in the nodepda. */
 	/* (Cant use SUBNODEPDA - not working yet) */
-	intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cputosubnode(cpu)].intr_dispatch0;
-	intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cputosubnode(cpu)].intr_dispatch1;
+	intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch0;
+	intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch1;
 
 	/* Clear INT_PEND1 masks. */
 	for (i = 0; i < N_INTPEND1_MASKS; i++)
 		intmasks->intpend1_masks[i] = 0;
 
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	/* Don't read the routers unless we're the master. */
 	ppda->p_routertick = 0;
 #endif
@@ -419,7 +401,7 @@
 #error "need protect_hub_calias, protect_nmi_handler_data"
 #endif
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 /*
  * For now, just protect the first page (exception handlers). We
  * may want to protect more stuff later.
@@ -433,13 +415,6 @@
 	for (i = 0; i < MAX_REGIONS; i++) {
 		if (i == nasid_to_region(nasid))
 			continue;
-#ifndef BRINGUP
-		/* Protect the exception handlers. */
-		*(__psunsigned_t *)BDPRT_ENTRY(pa, i) = MD_PROT_NO;
-
-		/* Protect the ARCS SPB. */
-		*(__psunsigned_t *)BDPRT_ENTRY(pa + 4096, i) = MD_PROT_NO;
-#endif
 	}
 }
 
@@ -455,15 +430,12 @@
 	for (i = 0; i < MAX_REGIONS; i++) {
 		if (i == nasid_to_region(nasid))
 			continue;
-#ifndef BRINGUP
-		*(__psunsigned_t *)BDPRT_ENTRY(pa, i) = MD_PROT_NO;
-#endif
 	}
 }
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 
-#ifdef IRIX
+#ifdef LATER
 /*
  * Protect areas of memory that we access uncached by marking them as
  * poisoned so the T5 can't read them speculatively and erroneously
@@ -492,7 +464,7 @@
 				CACHE_ERR_AREA_SIZE, 1);
 #error "SN1 not handled correctly"
 }
-#endif	/* IRIX */
+#endif	/* LATER */
 
 /*
  * per_hub_init
@@ -509,15 +481,10 @@
 	ii_icmr_u_t	ii_icmr;
 	ii_ibcr_u_t	ii_ibcr;
 #endif
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	int i;
 #endif
 
-#ifdef SIMULATED_KLGRAPH
-	compact_to_nasid_node[0] = 0;
-	nasid_to_compact_node[0] = 0;
-	FIXME("per_hub_init: SIMULATED_KLCONFIG: compact_to_nasid_node[0] = 0\n");
-#endif /* SIMULATED_KLGRAPH */
 	nasid = COMPACT_TO_NASID_NODEID(cnode);
 
 	ASSERT(nasid != INVALID_NASID);
@@ -546,15 +513,26 @@
 	if (!done) {
 		npdap = NODEPDA(cnode);
 
+#if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
+		/* initialize per-node synergy perf instrumentation */
+		npdap->synergy_perf_enabled = 0; /* off by default */
+		npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED;
+		npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT;
+		npdap->synergy_inactive_intervals = 0;
+		npdap->synergy_active_intervals = 0;
+		npdap->synergy_perf_data = NULL;
+		npdap->synergy_perf_first = NULL;
+#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */
+
 		npdap->hub_chip_rev = get_hub_chiprev(nasid);
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 		for (i = 0; i < CPUS_PER_NODE; i++) {
 			cpu = cnode_slice_to_cpuid(cnode, i);
 			if (!cpu_enabled(cpu))
 			    SET_CPU_LEDS(nasid, i, 0xf);
 		}
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* SN1 specific */
 
@@ -582,7 +560,6 @@
 #endif /* SN0_HWDEBUG */
 
 
-#ifndef CONFIG_IA64_SGI_IO
 
 		/* Reserve all of the hardwired interrupt levels. */
 		intr_reserve_hardwired(cnode);
@@ -590,6 +567,7 @@
 		/* Initialize error interrupts for this hub. */
 		hub_error_init(cnode);
 
+#ifdef LATER
 		/* Set up correctable memory/directory ECC error interrupt. */
 		install_eccintr(cnode);
 
@@ -599,7 +577,7 @@
 		/* Enable RT clock interrupts */
 		hub_rtc_init(cnode);
 		hub_migrintr_init(cnode); /* Enable migration interrupt */
-#endif
+#endif	/* LATER */
 
 		spin_lock(&hub_mask_lock);
 		CNODEMASK_SETB(hub_init_done_mask, cnode);
@@ -609,9 +587,14 @@
 		/*
 		 * Wait for the other CPU to complete the initialization.
 		 */
-		while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0)
+		while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) {
+			/*
+			 * On SNIA64 we should never get here ..
+			 */
+			printk("WARNING: per_hub_init: Should NEVER get here!\n");
 			/* LOOP */
 			;
+		}
 	}
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ml_SN_intr.c linux/arch/ia64/sn/io/ml_SN_intr.c
--- v2.4.3/linux/arch/ia64/sn/io/ml_SN_intr.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/ml_SN_intr.c	Thu Apr 12 12:16:35 2001
@@ -34,6 +34,8 @@
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/xtalk/xtalk.h>
 #include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+
 
 #if DEBUG_INTR_TSTAMP_DEBUG
 #include <sys/debug.h>
@@ -65,6 +67,8 @@
 
 extern cnodeid_t master_node_get(devfs_handle_t vhdl);
 
+extern snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs);
+
 
 #define INTR_LOCK(vecblk) \
      (s = mutex_spinlock(&(vecblk)->vector_lock))
@@ -99,7 +103,7 @@
 void
 intr_stray(void *lvl)
 {
-    printk("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid());
+    PRINT_WARNING("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid());
 }
 
 #if defined(DEBUG)
@@ -119,7 +123,7 @@
 
 intr_dev_targ_map_t 	intr_dev_targ_map[MAX_DEVICES];
 uint64_t		intr_dev_targ_map_size;
-lock_t			intr_dev_targ_map_lock;
+spinlock_t		intr_dev_targ_map_lock;
 
 /* Print out the device - target cpu mapping.
  * This routine is used only in the idbg command
@@ -220,7 +224,7 @@
 
 	    }
 
-	spinlock_init(&vecblk->vector_lock, "ivecb");
+	mutex_spinlock_init(&vecblk->vector_lock);
 
 	vecblk->vector_count = 0;    
 	for (i = 0; i < CPUS_PER_SUBNODE; i++)
@@ -254,7 +258,7 @@
 {
     intr_vecblk_t	*vecblk;
     hub_intmasks_t 	*hub_intmasks;
-    int s;
+    unsigned long s;
     int rv = 0;
     int ip;
     synergy_da_t	*sda;
@@ -283,8 +287,7 @@
     INTR_LOCK(vecblk);
 
     if (bit <= -1) {
-	// bit = 0;
-	bit = 7;  /* First available on SNIA */
+	bit = 0;
 	ASSERT(reserve == II_RESERVE);
 	/* Choose any available level */
 	for (; bit < N_INTPEND_BITS; bit++) {
@@ -449,9 +452,9 @@
 {
     intr_vecblk_t	*vecblk;
     hubreg_t		*intpend_masks;
-    int s;
     int rv = 0;
     int ip;
+    unsigned long s;
 
     ASSERT(bit < N_INTPEND_BITS * 2);
 
@@ -530,7 +533,7 @@
 {
     intr_vecblk_t	*vecblk;
     hubreg_t		*intpend_masks;
-    int s;
+    unsigned long s;
     int rv = 0;
     int ip;
 
@@ -582,8 +585,8 @@
 do_intr_block_bit(cpuid_t cpu, int bit, int block)
 {
 	intr_vecblk_t *vecblk;
-	int s;
 	int ip;
+	unsigned long s;
 	hubreg_t *intpend_masks;
 	volatile hubreg_t mask_value;
 	volatile hubreg_t *mask_reg;
@@ -671,7 +674,6 @@
 		int local_cpu_num;
 
 		cpu = cnode_slice_to_cpuid(cnode, slice);
-		cpu = cpu_logical_id(cpu);
 		if (cpu == CPU_NONE)
 			continue;
 
@@ -711,7 +713,7 @@
 }
 
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 /*
  * Convert a subnode vertex into a (cnodeid, which_subnode) pair.
  * Return 0 on success, non-zero on failure.
@@ -736,7 +738,7 @@
 	return(0); /* success */
 }
 
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 /* Make it easy to identify subnode vertices in the hwgraph */
 void
@@ -755,13 +757,14 @@
 }
 
 
-#ifndef CONFIG_IA64_SGI_IO
 /*
  * Given a device descriptor, extract interrupt target information and
  * choose an appropriate CPU.  Return CPU_NONE if we can't make sense
  * out of the target information.
  * TBD: Should this be considered platform-independent code?
  */
+
+#ifdef	LATER
 static cpuid_t
 intr_target_from_desc(device_desc_t dev_desc, int favor_subnode)
 {
@@ -799,10 +802,10 @@
 cpuchosen:
 	return(cpuid);
 }
-#endif /* CONFIG_IA64_SGI_IO */
+#endif	/* LATER */
 
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 /*
  * Check if we had already visited this candidate cnode
  */
@@ -824,7 +827,7 @@
 	return(visited_cnodes);
 }
 
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 
 
@@ -915,7 +918,7 @@
 {
 	cpuid_t		cpuid;				/* possible intr targ*/
 	cnodeid_t 	candidate;			/* possible canidate */
-#ifndef BRINGUP
+#ifdef LATER
 	cnodeid_t	visited_cnodes[MAX_NASIDS], 	/* nodes seen so far */
 		        center,				/* node we are on */
 		        candidate;			/* possible canidate */
@@ -926,10 +929,10 @@
 							 */
 		        maxradius = physmem_maxradius();
 	void		*rv;
-#endif /* BRINGUP */
+#endif /* LATER */
 	int		which_subnode = SUBNODE_ANY;
 
-#if CONFIG_IA64_SGI_IO /* SN1 + pcibr Addressing Limitation */
+/* SN1 + pcibr Addressing Limitation */
 	{
 	devfs_handle_t pconn_vhdl;
 	pcibr_soft_t pcibr_soft;
@@ -962,9 +965,8 @@
 		}
 	}
 	}
-#endif /* CONFIG_IA64_SGI_IO */
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	/* 
 	 * If an interrupt target was specified for this
 	 * interrupt allocation, try to use it.
@@ -998,7 +1000,7 @@
 		 */
 
 	}
-#endif  /* CONFIG_IA64_SGI_IO */
+#endif  /* LATER */
 	
 	/* Check if we can find a valid interrupt target candidate on
 	 * the master node for the device.
@@ -1019,7 +1021,7 @@
 			intr_unreserve_level(cpuid, *resp_bit);
 	}
 
-	printk("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n",
+	PRINT_WARNING("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n",
 		master_node_get(dev),(long) owner_dev, (unsigned long)owner_dev);
 
 	/* Fall through into the default algorithm
@@ -1076,10 +1078,11 @@
 #else  /* BRINGUP */
 	{
 	// Do a stupid round-robin assignment of the node.
-		static cnodeid_t last_node = 0;
+		static cnodeid_t last_node = -1;
 
-		if (last_node > numnodes) last_node = 0;
-		for (candidate = last_node; candidate <= numnodes; candidate++) {
+		if (last_node >= numnodes) last_node = 0;
+		for (candidate = last_node + 1; candidate != last_node; candidate++) {
+			if (candidate == numnodes) candidate = 0;
 			cpuid = intr_bit_reserve_test(CPU_NONE,
 					      which_subnode,
 					      candidate,
@@ -1091,18 +1094,18 @@
 
 			if (cpuid != CPU_NONE) {
 				if (cpu_on_subnode(cpuid, which_subnode)) {
-					last_node++;
+					last_node = candidate;
 					return(cpuid);	/* got a valid interrupt target */
 				}
 				else
 					intr_unreserve_level(cpuid, *resp_bit);
 			}
-			last_node++;
 		}
+		last_node = candidate;
 	}
 #endif
 
-	printk("Cannot target interrupts to any close node: %ld (0x%lx)\n",
+	PRINT_WARNING("Cannot target interrupts to any close node: %ld (0x%lx)\n",
 		(long)owner_dev, (unsigned long)owner_dev);
 
 	/* In the worst case try to allocate interrupt bits on the
@@ -1127,7 +1130,7 @@
 			intr_unreserve_level(cpuid, *resp_bit);
 	}
 
-	printk("Cannot target interrupts: %ld (0x%lx)\n",
+	PRINT_WARNING("Cannot target interrupts: %ld (0x%lx)\n",
 		(long)owner_dev, (unsigned long)owner_dev);
 
 	return(CPU_NONE);	/* Should never get here */
@@ -1515,6 +1518,7 @@
 	}
 }
 
+#endif /* BRINGUP */
 
 struct hardwired_intr_s {
 	signed char level;
@@ -1525,17 +1529,9 @@
 	{ INT_PEND0_BASELVL + GFX_INTR_A,	0, 	"Gfx A" },
 	{ INT_PEND0_BASELVL + GFX_INTR_B,	0, 	"Gfx B" },
 	{ INT_PEND0_BASELVL + PG_MIG_INTR,	II_THREADED, "Migration" },
-#if defined(SN1) && !defined(DIRECT_L1_CONSOLE)
 	{ INT_PEND0_BASELVL + UART_INTR,	II_THREADED, "Bedrock/L1" },
-#else
-	{ INT_PEND0_BASELVL + UART_INTR,	0,	"Hub I2C" },
-#endif
 	{ INT_PEND0_BASELVL + CC_PEND_A,	0,	"Crosscall A" },
 	{ INT_PEND0_BASELVL + CC_PEND_B,	0,	"Crosscall B" },
-	{ INT_PEND0_BASELVL + MSC_MESG_INTR,	II_THREADED, "MSC Message" },
-	{ INT_PEND0_BASELVL + CPU_ACTION_A,	0,	"CPU Action A" },
-	{ INT_PEND0_BASELVL + CPU_ACTION_B,	0,	"CPU Action B" },
-	{ INT_PEND1_BASELVL + IO_ERROR_INTR,	II_ERRORINT, "IO Error" },
 	{ INT_PEND1_BASELVL + CLK_ERR_INTR,	II_ERRORINT, "Clock Error" },
 	{ INT_PEND1_BASELVL + COR_ERR_INTR_A,	II_ERRORINT, "Correctable Error A" },
 	{ INT_PEND1_BASELVL + COR_ERR_INTR_B,	II_ERRORINT, "Correctable Error B" },
@@ -1546,13 +1542,11 @@
 	{ INT_PEND1_BASELVL + MSC_PANIC_INTR,	II_ERRORINT, "MSC Panic" },
 	{ INT_PEND1_BASELVL + LLP_PFAIL_INTR_A,	II_ERRORINT, "LLP Pfail WAR" },
 	{ INT_PEND1_BASELVL + LLP_PFAIL_INTR_B,	II_ERRORINT, "LLP Pfail WAR" },
-#ifdef SN1
 	{ INT_PEND1_BASELVL + NACK_INT_A,	0, "CPU A Nack count == NACK_CMP" },
 	{ INT_PEND1_BASELVL + NACK_INT_B,	0, "CPU B Nack count == NACK_CMP" },
 	{ INT_PEND1_BASELVL + LB_ERROR,		0, "Local Block Error" },
 	{ INT_PEND1_BASELVL + XB_ERROR,		0, "Local XBar Error" },
-#endif /* SN1 */	
-	{ -1, 0, (char *)NULL}
+	{ -1, 0, (char *)NULL},
 };
 
 /*
@@ -1567,7 +1561,13 @@
 	int i;
 	char subnode_done[NUM_SUBNODES];
 
-	cpu = cnodetocpu(cnode);
+	// cpu = cnodetocpu(cnode);
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		if (cpuid_to_cnodeid(cpu) == cnode) {
+			break;
+		}
+	}
+	if (cpu == smp_num_cpus) cpu = CPU_NONE;
 	if (cpu == CPU_NONE) {
 		printk("Node %d has no CPUs", cnode);
 		return;
@@ -1576,7 +1576,7 @@
 	for (i=0; i<NUM_SUBNODES; i++)
 		subnode_done[i] = 0;
 
-	for (; cpu<maxcpus && cpu_enabled(cpu) && cputocnode(cpu) == cnode; cpu++) {
+	for (; cpu<smp_num_cpus && cpu_enabled(cpu) && cpuid_to_cnodeid(cpu) == cnode; cpu++) {
 		int which_subnode = cpuid_to_subnode(cpu);
 		if (subnode_done[which_subnode])
 			continue;
@@ -1594,7 +1594,6 @@
 	}
 }
 
-#endif /* BRINGUP */
 
 /*
  * Check and clear interrupts.
@@ -1612,7 +1611,7 @@
 		for (i = 0; i < N_INTPEND_BITS; i++) {
 			if (bits & (1 << i)) {
 #ifdef INTRDEBUG
-				printk( "Nasid %d interrupt bit %d set in %s",
+				PRINT_WARNING("Nasid %d interrupt bit %d set in %s",
 					nasid, i, name);
 #endif
 				LOCAL_HUB_CLR_INTR(base_level + i);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ml_iograph.c linux/arch/ia64/sn/io/ml_iograph.c
--- v2.4.3/linux/arch/ia64/sn/io/ml_iograph.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/ml_iograph.c	Thu Apr 12 12:16:35 2001
@@ -32,6 +32,13 @@
 
 extern int maxnodes;
 
+/* #define IOGRAPH_DEBUG */
+#ifdef IOGRAPH_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* IOGRAPH_DEBUG */
+
 /* #define PROBE_TEST */
 
 /* At most 2 hubs can be connected to an xswitch */
@@ -44,7 +51,7 @@
  * xswitch vertex is created.
  */
 typedef struct xswitch_vol_s {
-	struct semaphore xswitch_volunteer_mutex;
+	mutex_t xswitch_volunteer_mutex;
 	int		xswitch_volunteer_count;
 	devfs_handle_t	xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
 } *xswitch_vol_t;
@@ -56,7 +63,7 @@
 	int rc;
 
 	xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
-	init_MUTEX(&xvolinfo->xswitch_volunteer_mutex);
+	mutex_init(&xvolinfo->xswitch_volunteer_mutex);
 	xvolinfo->xswitch_volunteer_count = 0;
 	rc = hwgraph_info_add_LBL(xswitch, 
 			INFO_LBL_XSWITCH_VOL,
@@ -78,7 +85,7 @@
 	rc = hwgraph_info_remove_LBL(xswitch, 
 				INFO_LBL_XSWITCH_VOL,
 				(arbitrary_info_t *)&xvolinfo);
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
 #endif
 
@@ -97,64 +104,26 @@
 				INFO_LBL_XSWITCH_VOL, 
 				(arbitrary_info_t *)&xvolinfo);
 	if (xvolinfo == NULL) {
-#ifndef CONFIG_IA64_SGI_IO
-	    if (!is_headless_node_vertex(master))
-		cmn_err(CE_WARN, 
-			"volunteer for widgets: vertex %v has no info label",
+#ifdef LATER
+	    if (!is_headless_node_vertex(master)) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		PRINT_WARNING("volunteer for widgets: vertex %v has no info label",
+			xswitch);
+#else
+		PRINT_WARNING("volunteer for widgets: vertex 0x%x has no info label",
 			xswitch);
 #endif
+	    }
+#endif	/* LATER */
 	    return;
 	}
 
-#ifndef CONFIG_IA64_SGI_IO
-	mutex_lock(&xvolinfo->xswitch_volunteer_mutex, PZERO);
-#endif
+	mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
 	ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
 	xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
 	xvolinfo->xswitch_volunteer_count++;
-#ifndef CONFIG_IA64_SGI_IO
 	mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
-#endif
-}
-
-#ifndef	BRINGUP
-/* 
- * The "ideal fixed assignment" of 12 IO slots to 4 node slots.
- * At index N is the node slot number of the node board that should
- * ideally control the widget in IO slot N.  Note that if there is
- * only one node board on a given xbow, it will control all of the
- * devices on that xbow regardless of these defaults.
- *
- * 	N1 controls IO slots IO1, IO3, IO5	(upper left)
- * 	N3 controls IO slots IO2, IO4, IO6	(upper right)
- * 	N2 controls IO slots IO7, IO9, IO11	(lower left)
- * 	N4 controls IO slots IO8, IO10, IO12	(lower right)
- *
- * This makes assignments predictable and easily controllable.
- * TBD: Allow administrator to override these defaults.
- */
-static slotid_t ideal_assignment[] = {
-	-1,	/* IO0 -->non-existent */
-	1,	/* IO1 -->N1 */
-	3,	/* IO2 -->N3 */
-	1,	/* IO3 -->N1 */
-	3,	/* IO4 -->N3 */
-	1,	/* IO5 -->N1 */
-	3,	/* IO6 -->N3 */
-	2,	/* IO7 -->N2 */
-	4,	/* IO8 -->N4 */
-	2,	/* IO9 -->N2 */
-	4,	/* IO10-->N4 */
-	2,	/* IO11-->N2 */
-	4	/* IO12-->N4 */
-};
-
-static int
-is_ideal_assignment(slotid_t hubslot, slotid_t ioslot)
-{
-	return(ideal_assignment[ioslot] == hubslot);
 }
-#endif /* ifndef BRINGUP */
 
 extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
 
@@ -166,15 +135,12 @@
 static void
 assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
 {
+	int curr_volunteer, num_volunteer;
+	xwidgetnum_t widgetnum;
 	xswitch_info_t xswitch_info;
 	xswitch_vol_t xvolinfo = NULL;
-	xwidgetnum_t widgetnum;
-	int curr_volunteer, num_volunteer;
 	nasid_t nasid;
 	hubinfo_t hubinfo;
-#ifndef BRINGUP
-	int xbownum;
-#endif
 
 	hubinfo_get(hubv, &hubinfo);
 	nasid = hubinfo->h_nasid;
@@ -186,13 +152,19 @@
 				INFO_LBL_XSWITCH_VOL, 
 				(arbitrary_info_t *)&xvolinfo);
 	if (xvolinfo == NULL) {
-#ifndef CONFIG_IA64_SGI_IO
-	    if (!is_headless_node_vertex(hubv))
-		cmn_err(CE_WARN, 
-			"assign_widgets_to_volunteers:vertex %v has "
+#ifdef LATER
+	    if (!is_headless_node_vertex(hubv)) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		PRINT_WARNING("assign_widgets_to_volunteers:vertex %v has "
+			" no info label",
+			xswitch);
+#else
+		PRINT_WARNING("assign_widgets_to_volunteers:vertex 0x%x has "
 			" no info label",
 			xswitch);
 #endif
+	    }
+#endif	/* LATER */
 	    return;
 	}
 
@@ -206,10 +178,6 @@
 		xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
 	}
 
-#ifndef	BRINGUP
-	xbownum = get_node_crossbow(nasid);
-#endif /* ifndef BRINGUP */
-
 	/*
 	 * TBD: Use administrative information to alter assignment of
 	 * widgets to hubs.
@@ -239,29 +207,12 @@
 				if (nasid == get_console_nasid())
 					goto do_assignment;
 			}
-#ifndef CONFIG_IA64_SGI_IO
-			cmn_err(CE_PANIC,
-				"Nasid == %d, console nasid == %d",
+#ifdef LATER
+			PRINT_PANIC("Nasid == %d, console nasid == %d",
 				nasid, get_console_nasid());
 #endif
 		}
 
-#ifndef	BRINGUP
-		/*
-		 * Try to do the "ideal" assignment if IO slots to nodes.
-		 */
-		for (i=0; i<num_volunteer; i++) {
-			hubv = xvolinfo->xswitch_volunteer[i];
-			hubinfo_get(hubv, &hubinfo);
-			nasid = hubinfo->h_nasid;
-			if (is_ideal_assignment(SLOTNUM_GETSLOT(get_node_slotid(nasid)),
-						SLOTNUM_GETSLOT(get_widget_slotnum(xbownum, widgetnum)))) {
-
-				goto do_assignment;
-				
-			}
-		}
-#endif /* ifndef BRINGUP */
 
 		/*
 		 * Do a round-robin assignment among the volunteer nodes.
@@ -301,13 +252,13 @@
 	for(cnode = 0; cnode < numnodes; cnode++) {
 		nasid = COMPACT_TO_NASID_NODEID(cnode);
 		board = (lboard_t *)KL_CONFIG_INFO(nasid);
-		printk("iograph_early_init: Found board 0x%p\n", board);
+		DBG("iograph_early_init: Found board 0x%p\n", board);
 
 		/* Check out all the board info stored on a node */
 		while(board) {
 			board->brd_graph_link = GRAPH_VERTEX_NONE;
 			board = KLCF_NEXT(board);
-			printk("iograph_early_init: Found board 0x%p\n", board);
+			DBG("iograph_early_init: Found board 0x%p\n", board);
 
 
 		}
@@ -316,7 +267,7 @@
 	hubio_init();
 }
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 /* There is an identical definition of this in os/scheduler/runq.c */
 #define INIT_COOKIE(cookie) cookie.must_run = 0; cookie.cpu = PDA_RUNANYWHERE
 /*
@@ -363,12 +314,11 @@
 {
 	restoremustrun(cookie);
 }
-static sema_t io_init_sema;
-
-#endif	/* !CONFIG_IA64_SGI_IO */
-
-struct semaphore io_init_sema;
+#endif	/* LATER */
 
+#ifdef LINUX_KERNEL_THREADS
+static struct semaphore io_init_sema;
+#endif
 
 /*
  * Let boot processor know that we're done initializing our node's IO
@@ -378,9 +328,11 @@
 static void
 io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
 {
-#ifndef CONFIG_IA64_SGI_IO
 	/* Let boot processor know that we're done. */
+#ifdef LINUX_KERNEL_THREADS
 	up(&io_init_sema);
+#endif
+#ifdef LATER
 	/* This is for the setnoderun done when the io_init thread
 	 * started 
 	 */
@@ -420,17 +372,12 @@
 		 * We're able to read from a widget because our hub's 
 		 * WIDGET_ID was set up earlier.
 		 */
-#ifdef	BRINGUP
 		widgetreg_t widget_id = *(volatile widgetreg_t *)
 			(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
 
-		printk("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
+		DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
 		(volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
 
-#else	/* !BRINGUP */
-		widgetreg_t widget_id = XWIDGET_ID_READ(nasid, 0);
-#endif	/* BRINGUP */
-
 		hwid->part_num = XWIDGET_PART_NUM(widget_id);
 		hwid->rev_num = XWIDGET_REV_NUM(widget_id);
 		hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
@@ -438,8 +385,6 @@
 		/* TBD: link reset */
 	} else {
 
-		panic("\n\n**** early_probe_for_widget: Hub Vertex 0x%p is DOWN llp_csr_reg 0x%x ****\n\n", hubv, llp_csr_reg);
-
 		hwid->part_num = XWIDGET_PART_NUM_NONE;
 		hwid->rev_num = XWIDGET_REV_NUM_NONE;
 		hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
@@ -499,8 +444,9 @@
 	moduleid_t		module;
 	slotid_t		slot;
 	lboard_t		*board = NULL;
+	char			buffer[16];
 	
-	printk("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
+	DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
 	/*
 	 * Verify that xswitchv is indeed an attached xswitch.
 	 */
@@ -546,8 +492,8 @@
 		 * but I don't feel like figuring out vhdl right now..
 		 * and I know for a fact the answer is 0x2d000049 
 		 */
-		printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
-		printk("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049));
+		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
+		DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049));
 		if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) {
 #else
 		if (nasid_has_xbridge(nasid)) {
@@ -557,8 +503,18 @@
 				module,
 				KLTYPE_IOBRICK);
 
-			if (board)
-				printk("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
+DBG("io_xswitch_widget_init: Board 0x%p\n", board);
+{
+		lboard_t dummy;
+
+			if (board) {
+				DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
+			} else {
+				DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
+				board = &dummy;
+			}
+				
+}
 
 			/*
 			 * BRINGUP
@@ -568,11 +524,16 @@
 
 #ifdef SUPPORT_PRINTING_M_FORMAT
 			sprintf(pathname, EDGE_LBL_MODULE "/%M/"
-#else
-			sprintf(pathname, EDGE_LBL_MODULE "/%x/"
-#endif
 				"%cbrick" "/%s/%d",
 				NODEPDA(cnode)->module_id,
+				
+#else
+			memset(buffer, 0, 16);
+			format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
+			sprintf(pathname, EDGE_LBL_MODULE "/%s/"
+				"%cbrick" "/%s/%d",
+				buffer,
+#endif
 #ifdef BRINGUP
 
 				(board->brd_type == KLTYPE_IBRICK) ? 'I' :
@@ -584,7 +545,7 @@
 				EDGE_LBL_XTALK, widgetnum);
 		} 
 		
-		printk("io_xswitch_widget_init: path= %s\n", pathname);
+		DBG("io_xswitch_widget_init: path= %s\n", pathname);
 		rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
 		
 		ASSERT(rc == GRAPH_SUCCESS);
@@ -612,7 +573,7 @@
 			module 	= NODEPDA(cnode)->module_id;
 
 #ifdef XBRIDGE_REGS_SIM
-			printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
+			DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
 			if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) {
 #else
 			if (nasid_has_xbridge(nasid)) {
@@ -647,16 +608,21 @@
 			 	 */
 #ifdef SUPPORT_PRINTING_M_FORMAT
 				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+                                                EDGE_LBL_SLOT "/%s/%s",
+                                        NODEPDA(cnode)->module_id,
+                                        slotname, new_name);
 #else
-				sprintf(pathname, EDGE_LBL_MODULE "/%x/"
-#endif
+				memset(buffer, 0, 16);
+				format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
+				sprintf(pathname, EDGE_LBL_MODULE "/%s/"
 					  	EDGE_LBL_SLOT "/%s/%s",
-					NODEPDA(cnode)->module_id,
+					buffer,
 					slotname, new_name);
+#endif
 			}
 
 			rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
-			printk("io_xswitch_widget_init: (2) path= %s\n", pathname);
+			DBG("io_xswitch_widget_init: (2) path= %s\n", pathname);
 		        /*
 		         * This is a weird ass code needed for error injection
 		         * purposes.
@@ -666,7 +632,7 @@
 			klhwg_baseio_inventory_add(widgetv,cnode);
 		}
 		sprintf(name, "%d", widgetnum);
-		printk("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
+		DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
 		rc = hwgraph_edge_add(xswitchv, widgetv, name);
 		
 		/*
@@ -683,7 +649,7 @@
 		 */
 #ifdef XBRIDGE_REGS_SIM
 		widget_id = 0x2d000049;
-		printk("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n");
+		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n");
 #else
 		widget_id = XWIDGET_ID_READ(nasid, widgetnum);
 #endif /* XBRIDGE_REGS_SIM */
@@ -715,21 +681,13 @@
 
 	aa = async_attach_new();
 	
-	printk("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
+	DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
 
 	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
 	     widgetnum++) {
-#ifdef BRINGUP
-		if (widgetnum != 0xe) 
-			io_xswitch_widget_init(xswitchv,
-				       cnodeid_to_vertex(cnode),
-				       widgetnum, aa);
-
-#else
 		io_xswitch_widget_init(xswitchv,
 				       cnodeid_to_vertex(cnode),
 				       widgetnum, aa);
-#endif /* BRINGUP */
 	}
 	/* 
 	 * Wait for parallel attach threads, if any, to complete.
@@ -798,9 +756,12 @@
 #endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */
 		}
 		if (board == NULL) {
-#ifndef CONFIG_IA64_SGI_IO
-			cmn_err(CE_WARN,
-				"Could not find PROM info for vertex %v, "
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+			PRINT_WARNING("Could not find PROM info for vertex %v, "
+				"FRU analyzer may fail",
+				vhdl);
+#else
+			PRINT_WARNING("Could not find PROM info for vertex 0x%x, "
 				"FRU analyzer may fail",
 				vhdl);
 #endif
@@ -828,16 +789,13 @@
 	hubinfo_t hubinfo;
 	int is_xswitch;
 	nodepda_t	*npdap;
-#ifndef CONFIG_IA64_SGI_IO
-	sema_t 		*peer_sema = 0;
-#else
 	struct semaphore *peer_sema = 0;
-#endif
 	uint32_t	widget_partnum;
 	nodepda_router_info_t *npda_rip;
 	cpu_cookie_t	c = 0;
+	extern int hubdev_docallouts(devfs_handle_t);
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	/* Try to execute on the node that we're initializing. */
 	c = setnoderun(cnodeid);
 #endif
@@ -851,13 +809,11 @@
 	 * form /hw/module/%M/slot/%d/node
 	 */
 	hubv = cnodeid_to_vertex(cnodeid);
-	printk("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
+	DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
 
 	ASSERT(hubv != GRAPH_VERTEX_NONE);
 
-#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
 	hubdev_docallouts(hubv);
-#endif
 
 	/*
 	 * Set up the dependent routers if we have any.
@@ -877,10 +833,10 @@
 	/*
 	 * Read mfg info on this hub
 	 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n");
 	HUB_VERTEX_MFG_INFO(hubv);
-#endif /* CONFIG_IA64_SGI_IO */
+#endif /* LATER */
 
 	/* 
 	 * If nothing connected to this hub's xtalk port, we're done.
@@ -892,7 +848,7 @@
 			int index;
 
 			for (index = 0; index < 600; index++)
-				printk("Interfering with device probing!!!\n");
+				DBG("Interfering with device probing!!!\n");
 		}
 #endif
 		/* io_init_done takes cpu cookie as 2nd argument 
@@ -900,8 +856,8 @@
 		 * at the start of this thread 
 		 */
 		
-		printk("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
-		io_init_done(cnodeid,c);
+		DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
+		return;
 		/* NOTREACHED */
 	}
 
@@ -931,13 +887,13 @@
 
 	(void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
 
-	printk("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
+	DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
 
 	ASSERT(switchv != GRAPH_VERTEX_NONE);
 
 	(void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
 
-	printk("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
+	DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
 
 	/*
 	 * We need to find the widget id and update the basew_id field
@@ -951,7 +907,7 @@
 				widget_partnum == XBRIDGE_WIDGET_PART_NUM){
 		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
 
-		printk("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
+		DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
 
 	} else if (widget_partnum == XBOW_WIDGET_PART_NUM ||
 				widget_partnum == XXBOW_WIDGET_PART_NUM) {
@@ -959,7 +915,7 @@
 		 * Xbow control register does not have the widget ID field.
 		 * So, hard code the widget ID to be zero.
 		 */
-		printk("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
+		DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
 		npdap->basew_id = 0;
 
 #if defined(BRINGUP)
@@ -982,7 +938,7 @@
 		char widname[10];
 		sprintf(widname, "%x", npdap->basew_id);
 		(void)hwgraph_path_add(switchv, widname, &widgetv);
-		printk("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
+		DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
 		ASSERT(widgetv != GRAPH_VERTEX_NONE);
 	}
 	
@@ -1043,13 +999,13 @@
 
 		/* Signal that we're done */
 		if (peer_sema) {
-			up(peer_sema);
+			mutex_unlock(peer_sema);
 		}
 		
 	}
 	else {
 	    /* Wait 'til master is done assigning widgets. */
-	    down(&npdap->xbow_sema);
+	    mutex_lock(&npdap->xbow_sema);
 	}
 
 #ifdef PROBE_TEST
@@ -1057,7 +1013,7 @@
 		int index;
 
 		for (index = 0; index < 500; index++)
-			printk("Interfering with device probing!!!\n");
+			DBG("Interfering with device probing!!!\n");
 	}
 #endif
 	/* Now both nodes can safely inititialize widgets */
@@ -1070,15 +1026,12 @@
 	 */
 	io_init_done(cnodeid,c);
 
-	printk("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
+	DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
 }
 
 
 #define IOINIT_STKSZ	(16 * 1024)
 
-#ifndef CONFIG_IA64_SGI_IO
-#include <sys/sn/iograph.h>
-#endif
 #define __DEVSTR1 	"/../.master/"
 #define __DEVSTR2 	"/target/"
 #define __DEVSTR3 	"/lun/0/disk/partition/"
@@ -1145,6 +1098,7 @@
 		{"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
 		{"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
 		{"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
+		{"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
 		{NULL, -1} /* must be last */
 	};
 
@@ -1181,11 +1135,7 @@
 }
 
 
-#ifndef CONFIG_IA64_SGI_IO
-#include <sys/asm/sn/ioerror_handling.h>
-#else
 #include <asm/sn/ioerror_handling.h>
-#endif
 extern devfs_handle_t 	ioc3_console_vhdl_get(void);
 devfs_handle_t		sys_critical_graph_root = GRAPH_VERTEX_NONE;
 
@@ -1203,7 +1153,7 @@
 	int			slot;
 	devfs_handle_t		baseio_console_conn;
 
-	printk("sys_critical_graph_init: FIXME.\n");
+	DBG("sys_critical_graph_init: FIXME.\n");
 	baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
 
 	if (baseio_console_conn == NULL) {
@@ -1303,7 +1253,7 @@
 	devfs_handle_t		console_vhdl, pci_vhdl, enet_vhdl;
 
 
-	printk("baseio_ctlr_num_set; FIXME\n");
+	DBG("baseio_ctlr_num_set; FIXME\n");
 	console_vhdl = ioc3_console_vhdl_get();
 	if (console_vhdl == GRAPH_VERTEX_NONE)
 		return;
@@ -1384,10 +1334,8 @@
 	else {
 		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0);
 	}
-#ifndef CONFIG_IA64_SGI_IO
 	if (rtn_val)
-		cmn_err(CE_WARN, "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
-#endif
+		PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
 
 	if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && 
 	    (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) {
@@ -1406,10 +1354,8 @@
 		/* nothing in slot 5 or 7 */
 		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0);
 	}
-#ifndef CONFIG_IA64_SGI_IO
 	if (rtn_val)
-		cmn_err(CE_WARN, "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
-#endif
+		PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
 }
 
 
@@ -1423,17 +1369,18 @@
 	/* Governor on init threads..bump up when safe 
 	 * (beware many devfs races) 
 	 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	int io_init_node_threads = 2;	
 #endif
 	cnodeid_t cnodeid, active;
 
-	init_MUTEX(&io_init_sema);
-
+#ifdef LINUX_KERNEL_THREADS
+	sema_init(&io_init_sema, 0);
+#endif
 
 	active = 0;
 	for (cnodeid = 0; cnodeid < maxnodes; cnodeid++) {
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LINUX_KERNEL_THREADS
 		char thread_name[16];
 		extern int io_init_pri;
 
@@ -1448,20 +1395,17 @@
 			io_init_pri, KT_PS, (st_func_t *)io_init_node,
 			(void *)(long)cnodeid, 0, 0, 0);
 #else
-                printk("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
+                DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
                 io_init_node(cnodeid);
 
-		printk("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
-
-#endif /* !CONFIG_IA64_SGI_IO */
+		DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
 
+#endif /* LINUX_KERNEL_THREADS */
 
+#ifdef LINUX_KERNEL_THREADS
 		/* Limit how many nodes go at once, to not overload hwgraph */
 		/* TBD: Should timeout */
-#ifdef AA_DEBUG
-		printk("started thread for cnode %d\n", cnodeid);
-#endif
-#ifdef LINUX_KERNEL_THREADS
+		DBG("started thread for cnode %d\n", cnodeid);
 		active++;
 		if (io_init_node_threads && 
 			active >= io_init_node_threads) {
@@ -1476,9 +1420,9 @@
 
 	while (active > 0) {
 #ifdef AA_DEBUG
-	    printk("waiting, %d still active\n", active);
+	    DBG("waiting, %d still active\n", active);
 #endif
-	    sema(&io_init_sema);
+	    down(&io_init_sema);
 	    active--;
 	}
 
@@ -1534,22 +1478,22 @@
 		int i;
 		int viable_found = 0;
 
-		printk("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
-		printk("prom \"root\" variables of the form dksXdXsX.\n");
-		printk("To use another disk you must use the full hardware graph path\n\n");
-		printk("Possible controller numbers for use in 'dksXdXsX' on this system: ");
+		DBG("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
+		DBG("prom \"root\" variables of the form dksXdXsX.\n");
+		DBG("To use another disk you must use the full hardware graph path\n\n");
+		DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
 		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
 			if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
-				printk("%d ", i);
+				DBG("%d ", i);
 				viable_found=1;
 			}
 		}
 		if (viable_found)
-			printk("\n");
+			DBG("\n");
 		else
-			printk("none found!\n");
+			DBG("none found!\n");
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 		if (kdebug)
 			debug("ring");
 #endif
@@ -1579,4 +1523,132 @@
 	*tmp2++ = '/';
 	strcpy(tmp2, EDGE_LBL_BLOCK);
 	strcpy(devnm,tmpnm);
+}
+
+static
+struct io_brick_map_s io_brick_tab[] = {
+
+/* Ibrick widget number to PCI bus number map */
+  {
+        'I',                                    /* Ibrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+     {  0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        0,                                      /* 0xc            */
+        0,                                      /* 0xd            */
+        2,                                      /* 0xe            */
+        1                                       /* 0xf            */
+     }
+  },
+
+/* Pbrick widget number to PCI bus number map */
+  {
+        'P',                                    /* Pbrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+     {  0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        2,                                      /* 0x8            */
+        1,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        5,                                      /* 0xc            */
+        6,                                      /* 0xd            */
+        4,                                      /* 0xe            */
+        3                                       /* 0xf            */
+     }
+  },
+
+/* Xbrick widget to XIO slot map */
+  {
+        'X',                                    /* Xbrick type    */ 
+    /*  XIO Slot #                                 Widget #       */
+     {  0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        1,                                      /* 0x8            */
+        2,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        3,                                      /* 0xc            */
+        4,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        0                                       /* 0xf            */
+     }
+  }
+};
+
+/*
+ * Use the brick's type to map a widget number to a meaningful int
+ */
+int
+io_brick_map_widget(char brick_type, int widget_num)
+{
+        int num_bricks, i;
+
+        /* Calculate number of bricks in table */
+        num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
+
+        /* Look for brick prefix in table */
+        for (i = 0; i < num_bricks; i++) {
+               if (brick_type == io_brick_tab[i].ibm_type)
+                       return(io_brick_tab[i].ibm_map_wid[widget_num]);
+        }
+
+        return 0;
+
+}
+
+/*
+ * Use the device's vertex to map the device's widget to a meaningful int
+ */
+int
+io_path_map_widget(devfs_handle_t vertex)
+{
+        char hw_path_name[MAXDEVNAME];
+        char *wp, *bp, *sp = NULL;
+        int  widget_num;
+	long atoi(char *);
+	int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
+
+
+        /* Get the full path name of the vertex */
+        if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
+                                                     MAXDEVNAME))
+                return 0;
+
+        /* Find the widget number in the path name */
+        wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
+        if (wp == NULL)
+                return 0;
+        widget_num = atoi(wp+7);
+        if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
+                return 0;
+
+        /* Find "brick" in the path name */
+        bp = strstr(hw_path_name, "brick");
+        if (bp == NULL)
+                return 0;
+
+        /* Find preceding slash */
+        sp = bp;
+        while (sp > hw_path_name) {
+                sp--;
+                if (*sp == '/')
+                        break;
+        }
+
+        /* Invalid if no preceding slash */
+        if (!sp)
+                return 0;
+
+        /* Bump slash pointer to "brick" prefix */
+        sp++;
+        /*
+         * Verify "brick" prefix length;  valid exaples:
+         * 'I' from "/Ibrick"
+         * 'P' from "/Pbrick"
+         * 'X' from "/Xbrick"
+         */
+         if ((bp - sp) != 1)
+                return 0;
+
+        return (io_brick_map_widget(*sp, widget_num));
+
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/module.c linux/arch/ia64/sn/io/module.c
--- v2.4.3/linux/arch/ia64/sn/io/module.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/module.c	Thu Apr 12 12:16:35 2001
@@ -9,13 +9,11 @@
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/invent.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/xtalk/xbow.h>
 #include <asm/sn/pci/bridge.h>
 #include <asm/sn/klconfig.h>
@@ -24,12 +22,17 @@
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/xtalk/xswitch.h>
 #include <asm/sn/nodepda.h>
+#include <asm/sn/sn_cpuid.h>
 
 
-#define LDEBUG	1	
+/* #define LDEBUG	1	*/
 
-#define DPRINTF		if (LDEBUG) printk
+#ifdef LDEBUG
+#define DPRINTF		printk
 #define printf		printk
+#else
+#define DPRINTF(x...)
+#endif
 
 module_t	       *modules[MODULE_MAX];
 int			nummodules;
@@ -100,8 +103,6 @@
 {
     int			i;
 
-    DPRINTF("module_lookup: id=%d\n", id);
-
     for (i = 0; i < nummodules; i++)
 	if (modules[i]->id == id) {
 	    DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
@@ -125,29 +126,29 @@
 {
     module_t	       *m;
     int			i;
+    char		buffer[16];
 
-    DPRINTF("module_add_node: id=%x node=%d\n", id, n);
+#ifdef __ia64
+    memset(buffer, 0, 16);
+    format_module_id(buffer, id, MODULE_FORMAT_BRIEF);
+    DPRINTF("module_add_node: id=%s node=%d\n", buffer, n);
+#endif
 
     if ((m = module_lookup(id)) == 0) {
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n);
 #else
 	m = kmalloc(sizeof (module_t), GFP_KERNEL);
 	memset(m, 0 , sizeof(module_t));
-	printk("Module nodecnt = %d\n", m->nodecnt); 
 #endif
 	ASSERT_ALWAYS(m);
 
-	DPRINTF("module_add_node: m=0x%p\n", m);
-
 	m->id = id;
 	spin_lock_init(&m->lock);
 
-	init_MUTEX_LOCKED(&m->thdcnt);
+	mutex_init_locked(&m->thdcnt);
 
-printk("Set elsc to 0x%p on node %d\n", &m->elsc, get_nasid());
-
-set_elsc(&m->elsc);
+// set_elsc(&m->elsc);
 	elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n));
 	spin_lock_init(&m->elsclock);
 
@@ -162,8 +163,7 @@
 
     m->nodes[m->nodecnt++] = n;
 
-printk("module_add_node: module %x now has %d nodes\n", id, m->nodecnt);
-    DPRINTF("module_add_node: module %x now has %d nodes\n", id, m->nodecnt);
+    DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt);
 
     return m;
 }
@@ -172,6 +172,7 @@
 {
     lboard_t	       *board;
     klmod_serial_num_t *comp;
+    char * bcopy(const char * src, char * dest, int count);
 
     board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
 			KLTYPE_MIDPLANE8);
@@ -204,14 +205,8 @@
     if (m->snum_valid)
 	return 1;
     else {
-#ifndef CONFIG_IA64_SGI_IO
-	cmn_err(CE_WARN | CE_MAINTENANCE,
-		"Invalid serial number for module %d, "
-		"possible missing or invalid NIC.", m->id);
-#else
-	printk("Invalid serial number for module %d, "
+	DPRINTF("Invalid serial number for module %d, "
 		"possible missing or invalid NIC.", m->id);
-#endif
 	return 0;
     }
 }
@@ -246,32 +241,12 @@
 	    nserial);
 
     if (nserial == 0)
-	cmn_err(CE_WARN, "No serial number found.");
+	PRINT_WARNING("io_module_init: No serial number found.\n");
 }
 
-#ifdef BRINGUP
-elsc_t *Elsc[100];
-
-void
-set_elsc(elsc_t *p)
-{
-      Elsc[get_nasid()] = p;
-}
-#endif
-
 elsc_t *get_elsc(void)
 {
-#ifdef BRINGUP
-return(Elsc[get_nasid()]);
-#else
-	if ( NODEPDA(get_nasid())->module == (module_t *)0 ) {
-		printf("get_elsc() for nasd %d fails\n", get_nasid());
-//		return((elsc_t *)0);
-	}
-	return &NODEPDA(get_nasid())->module->elsc;
-
-//	return &NODEPDA(NASID_TO_COMPACT_NODEID(0))->module->elsc;
-#endif
+	return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc;
 }
 
 int
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pci.c linux/arch/ia64/sn/io/pci.c
--- v2.4.3/linux/arch/ia64/sn/io/pci.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/pci.c	Thu Apr  5 12:51:47 2001
@@ -14,7 +14,6 @@
 #include <linux/pci.h>
 #include <asm/sn/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/iobus.h>
 #include <asm/sn/iograph.h>
 #include <asm/param.h>
@@ -250,18 +249,9 @@
 pci_fixup_ioc3(struct pci_dev *d)
 {
         int 		i;
-	int 		slot;
-	unsigned long 	res = 0;
-	unsigned int 	val, size;
-	int 		ret;
-	u_short 	command;
+	unsigned int 	size;
 
-	devfs_handle_t 	device_vertex;
 	devfs_handle_t	bridge_vhdl = pci_bus_to_vertex(d->bus->number);
-	pcibr_soft_t 	pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl);
-	devfs_handle_t  xconn_vhdl = pcibr_soft->bs_conn;
-	bridge_t 	*bridge = pcibr_soft->bs_base;
-	bridgereg_t 	devreg;
 
         /* IOC3 only decodes 0x20 bytes of the config space, reading
 	 * beyond that is relatively benign but writing beyond that
@@ -271,7 +261,7 @@
 	 *       currently we hack this with special code in 
 	 *	 sgi_pci_intr_support()
 	 */
-        printk("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name);
+        DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name);
 
 	/* I happen to know from the spec that the ioc3 needs only 0xfffff 
 	 * The standard pci trick of writing ~0 to the baddr and seeing
@@ -296,7 +286,9 @@
 	 * DEV_DIRECT bit.  This will not work if IOC3 is not on Slot 
 	 * 4.
 	 */
-	*(volatile u32 *)0xc0000a000f000220 |= 0x90000;
+	DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220);
+
+ 	*(volatile u32 *)0xc0000a000f000220 |= 0x90000; 
 
         d->subsystem_vendor = 0;
         d->subsystem_device = 0;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pci_bus_cvlink.c linux/arch/ia64/sn/io/pci_bus_cvlink.c
--- v2.4.3/linux/arch/ia64/sn/io/pci_bus_cvlink.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/pci_bus_cvlink.c	Thu Apr 12 12:16:35 2001
@@ -16,7 +16,6 @@
 #include <asm/sn/types.h>
 #include <asm/sn/hack.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/iobus.h>
 #include <asm/sn/iograph.h>
 #include <asm/param.h>
@@ -32,23 +31,32 @@
 #include <asm/sn/xtalk/xtalkaddrs.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/io.h>
-#include <asm/sn/pci/pci_bus_cvlink.h>
 
 #include <asm/sn/pci/pciio.h>
 // #include <sys/ql.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
 extern int bridge_rev_b_data_check_disable;
+#include <asm/sn/pci/pci_bus_cvlink.h>
 
 #define MAX_PCI_XWIDGET 256
-devfs_handle_t busnum_to_xwidget[MAX_PCI_XWIDGET];
+devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET];
 nasid_t busnum_to_nid[MAX_PCI_XWIDGET];
+void * busnum_to_atedmamaps[MAX_PCI_XWIDGET];
 unsigned char num_bridges;
 static int done_probing = 0;
 
 static int pci_bus_map_create(devfs_handle_t xtalk);
 devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn);
 
+#define SN1_IOPORTS_UNIT 256
+#define MAX_IOPORTS 0xffff
+#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN1_IOPORTS_UNIT)
+struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS];
+unsigned long sn1_allocate_ioports(unsigned long pci_address);
+
+
+
 /*
  * pci_bus_cvlink_init() - To be called once during initialization before 
  *	SGI IO Infrastructure init is called.
@@ -56,9 +64,13 @@
 void
 pci_bus_cvlink_init(void)
 {
-
-	memset(busnum_to_xwidget, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET);
+	memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET);
 	memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET);
+
+	memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET);
+
+	memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs));
+
 	num_bridges = 0;
 }
 
@@ -70,27 +82,13 @@
 pci_bus_to_vertex(unsigned char busnum)
 {
 
-	devfs_handle_t	xwidget;
 	devfs_handle_t	pci_bus = NULL;
 
 
 	/*
 	 * First get the xwidget vertex.
 	 */
-	xwidget = busnum_to_xwidget[busnum];
-	if (!xwidget)
-		return (NULL);
-
-	/*
-	 * Use devfs to get the pci vertex from xwidget.
-	 */
-	if (hwgraph_traverse(xwidget, EDGE_LBL_PCI, &pci_bus) != GRAPH_SUCCESS) {
-		if (!pci_bus) {
-			printk("pci_bus_to_vertex: Cannot find pci bus for given bus number %d\n", busnum);
-			return (NULL);
-		}
-	}
-
+	pci_bus = busnum_to_pcibr_vhdl[busnum];
 	return(pci_bus);
 }
 
@@ -138,7 +136,6 @@
 
 	if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) {
 		if (!device_vertex) {
-			printk("devfn_to_vertex: Unable to get slot&func %s from pci vertex 0x%p\n", name, pci_bus);
 			return(NULL);
 		}
 	}
@@ -175,6 +172,61 @@
 }
 
 /*
+ * sn1_allocate_ioports() - This routine provides the allocation and 
+ *	mappings between Linux style IOPORTs management.
+ *
+ *	For simplicity sake, SN1 will allocate IOPORTs in chunks of 
+ *	256bytes .. irrespective of what the card desires.  This may 
+ *	have to change when we understand how to deal with legacy ioports 
+ *	which are hardcoded in some drivers e.g. SVGA.
+ *
+ *	Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers.
+ *	It will remain so.  The IO Infrastructure will continue to map 
+ *	IO Resource just like IRIX.  When this is done, we map IOPORT 
+ *	chunks to these resources.  The Linux drivers will see and use real 
+ *	IOPORT numbers.  The various IOPORT access macros e.g. inb/outb etc. 
+ *	does the munging of these IOPORT numbers to make a Uncache Virtual 
+ *	Address.  This address via the tlb entries generates the PCI Address 
+ *	allocated by the SN1 IO Infrastructure Layer.
+ */
+static unsigned long sn1_ioport_num = 0x100; /* Reserve room for Legacy stuff */
+unsigned long
+sn1_allocate_ioports(unsigned long pci_address)
+{
+	
+	unsigned long ioport_index;
+
+	/*
+	 * Just some idiot checking ..
+	 */
+	if ( sn1_ioport_num > 0xffff ) {
+		printk("sn1_allocate_ioports: No more IO PORTS available\n");
+		return(-1);
+	}
+
+	/*
+	 * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's
+	 * Manual for details.
+	 */
+	ioport_index = sn1_ioport_num / SN1_IOPORTS_UNIT;
+	ioports_to_tlbs[ioport_index].ppn = pci_address;
+	ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */
+	ioports_to_tlbs[ioport_index].ma = 5; /* Memory Attributes */
+	ioports_to_tlbs[ioport_index].a = 0; /* Set Data Access Bit Fault */
+	ioports_to_tlbs[ioport_index].d = 0; /* Dirty Bit */
+	ioports_to_tlbs[ioport_index].pl = 3;/* Privilege Level - All levels can R/W*/
+	ioports_to_tlbs[ioport_index].ar = 2; /* Access Rights - R/W only*/
+	ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */
+	ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */
+
+	printk("sn1_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index].ppn);
+	
+	sn1_ioport_num += SN1_IOPORTS_UNIT;
+
+	return(sn1_ioport_num - SN1_IOPORTS_UNIT);
+}
+
+/*
  * sn1_pci_fixup() - This routine is called when platform_pci_fixup() is 
  *	invoked at the end of pcibios_init() to link the Linux pci 
  *	infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c
@@ -189,6 +241,11 @@
 	struct pci_dev *device_dev = NULL;
 	struct sn1_widget_sysdata *widget_sysdata;
 	struct sn1_device_sysdata *device_sysdata;
+	unsigned long ioport;
+	pciio_intr_t intr_handle;
+	int cpuid, bit;
+	devfs_handle_t *device_vertex;
+	pciio_intr_line_t lines;
 	extern void sn1_pci_find_bios(void);
 
 
@@ -204,7 +261,6 @@
         devfs_handle_t  bridge_vhdl = pci_bus_to_vertex(0);
         pcibr_soft_t    pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl);
 	bridge_t        *bridge = pcibr_soft->bs_base;
-printk("Before Changing PIO Map Address:\n");
         printk("pci_fixup_ioc3: Before devreg fixup\n");
         printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg);
         printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg);
@@ -280,16 +336,11 @@
 			size = device_dev->resource[idx].end -
 				device_dev->resource[idx].start;
 			if (size) {
-res = 0;
-res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4);
-printk("Before pciio_pio_addr Base address %d = 0x%lx\n", idx, res);
-
-				printk(" Changing device %d:%d resource start address from 0x%lx", 
-				PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn),
-				device_dev->resource[idx].start);
-				device_dev->resource[idx].start = 
-				(unsigned long)pciio_pio_addr(vhdl, 0, 
-					PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM);
+				res = 0;
+				res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4);
+				device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM);
+
+/* printk("sn1_pci_fixup: Mapped Address = 0x%p size = 0x%x\n", device_dev->resource[idx].start, size); */
 			}
 			else
 				continue;
@@ -304,13 +355,14 @@
 				device_dev->resource[idx].start & 0xfffff7ffffffffff;
 			device_dev->resource[idx].end = 
 				device_dev->resource[idx].end & 0xfffff7ffffffffff;
-			printk(" to 0x%lx\n", device_dev->resource[idx].start);
-res = 0;
-res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4);
-printk("After pciio_pio_addr Base address %d = 0x%lx\n", idx, res);
-
-			if (device_dev->resource[idx].flags & IORESOURCE_IO)
+			res = 0;
+			res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4);
+			if (device_dev->resource[idx].flags & IORESOURCE_IO) {
 				cmd |= PCI_COMMAND_IO;
+				ioport = sn1_allocate_ioports(device_dev->resource[idx].start);
+				/* device_dev->resource[idx].start = ioport; */
+				/* device_dev->resource[idx].end = ioport + SN1_IOPORTS_UNIT */
+			}
 			else if (device_dev->resource[idx].flags & IORESOURCE_MEM)
 				cmd |= PCI_COMMAND_MEMORY;
 		}
@@ -319,9 +371,6 @@
 		 */
 		size = device_dev->resource[PCI_ROM_RESOURCE].end -
 			device_dev->resource[PCI_ROM_RESOURCE].start;
-		printk(" Changing device %d:%d ROM resource start address from 0x%lx", 
-			PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn),
-			device_dev->resource[PCI_ROM_RESOURCE].start);
 		device_dev->resource[PCI_ROM_RESOURCE].start =
 			(unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, 
 				size, 0, PCIIO_BYTE_STREAM);
@@ -341,24 +390,26 @@
 					   /* bit gets dropped .. no harm */
 		pci_write_config_word(device_dev, PCI_COMMAND, cmd);
 
-		printk("  to 0x%lx\n", device_dev->resource[PCI_ROM_RESOURCE].start);
+		pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, &lines);
+#ifdef BRINGUP
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+			device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+				lines = 1;
+		}
 
-		/*
-		 * Set the irq correctly.
-		 * Bits 7:3 = slot
-		 * Bits 2:0 = function
-		 *
-		 * In the IRQ we will have:
-		 *	Bits 24:16 = bus number
-		 *	Bits 15:8 = slot|func number
-		 */
-		irq = 0;
-		irq = (irq | (device_dev->devfn << 8));
-		irq = (irq | ( (device_dev->bus->number & 0xff) << 16) );
+#endif
+ 
+		device_sysdata = (struct sn1_device_sysdata *)device_dev->sysdata;
+		device_vertex = device_sysdata->vhdl;
+ 
+		intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex);
+
+		bit = intr_handle->pi_irq;
+		cpuid = intr_handle->pi_cpu;
+		irq = bit_pos_to_irq(bit);
+		irq = irq + (cpuid << 8);
+		pciio_intr_connect(intr_handle, NULL, NULL, NULL);
 		device_dev->irq = irq;
-printk("sn1_pci_fixup: slot= %d  fn= %d  vendor= 0x%x  device= 0x%x  irq= 0x%x\n",
-PCI_SLOT(device_dev->devfn),PCI_FUNC(device_dev->devfn),device_dev->vendor,
-device_dev->device, device_dev->irq);
 
 	}
 #endif	/* REAL_HARDWARE */
@@ -369,7 +420,6 @@
         pcibr_soft_t    pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl);
         bridge_t        *bridge = pcibr_soft->bs_base;
 
-printk("After Changing PIO Map Address:\n");
         printk("pci_fixup_ioc3: Before devreg fixup\n");
         printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg);
         printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg);
@@ -386,6 +436,25 @@
 
 /*
  * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job.
+ *
+ *	Linux PCI Bus numbers are assigned from lowest module_id numbers
+ *	(rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to 
+ *	HUB_WIDGET_ID_MIN:
+ *		widgetnum 15 gets lower Bus Number than widgetnum 14 etc.
+ *
+ *	Given 2 modules 001c01 and 001c02 we get the following mappings:
+ *		001c01, widgetnum 15 = Bus number 0
+ *		001c01, widgetnum 14 = Bus number 1
+ *		001c02, widgetnum 15 = Bus number 3
+ *		001c02, widgetnum 14 = Bus number 4
+ *		etc.
+ *
+ * The rational for starting Bus Number 0 with Widget number 15 is because 
+ * the system boot disks are always connected via Widget 15 Slot 0 of the 
+ * I-brick.  Linux creates /dev/sd* devices(naming) strating from Bus Number 0 
+ * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest 
+ * module id(Master Cnode) of the system.
+ *	
  */
 static int 
 pci_bus_map_create(devfs_handle_t xtalk)
@@ -402,10 +471,21 @@
 	/*
 	 * Loop throught this vertex and get the Xwidgets ..
 	 */
-	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+	for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) {
+        {
+                int pos;
+                char dname[256];
+                pos = devfs_generate_path(xtalk, dname, 256);
+                printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+        }
+
 		sprintf(pathname, "%d", widgetnum);
 		xwidget = NULL;
 		
+		/*
+		 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+		 *	     /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device
+		 */
 		rv = hwgraph_traverse(xtalk, pathname, &xwidget);
 		if ( (rv != GRAPH_SUCCESS) ) {
 			if (!xwidget)
@@ -425,25 +505,35 @@
 		 * Should not be any race here ...
 		 */
 		num_bridges++;
-		busnum_to_xwidget[num_bridges - 1] = xwidget;
+		busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
 
 		/*
 		 * Get the master node and from there get the NASID.
 		 */
 		master_node_vertex = device_master_get(xwidget);
 		if (!master_node_vertex) {
-			printk(" **** pci_bus_map_create: Unable to get .master for vertex 0x%p **** \n", xwidget);
+			printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", xwidget);
 		}
 	
 		hubinfo_get(master_node_vertex, &hubinfo);
 		if (!hubinfo) {
-			printk(" **** pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p ****\n", master_node_vertex);
+			printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", master_node_vertex);
 			return(1);
 		} else {
 			busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
 		}
 
-		printk("pci_bus_map_create: Found Hub nasid %d PCI Xwidget 0x%p  widgetnum= %d\n", hubinfo->h_nasid, xwidget, widgetnum);
+		/*
+		 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+		 */
+		busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+			sizeof(struct sn1_dma_maps_s) * 512, GFP_KERNEL);
+		if (!busnum_to_atedmamaps[num_bridges - 1])
+			printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, xwidget);
+
+		memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+			sizeof(struct sn1_dma_maps_s) * 512);
+
 	}
 
         return(0);
@@ -468,6 +558,9 @@
 	graph_vertex_place_t placeptr = EDGE_PLACE_WANT_REAL_EDGES;
 	int rv = 0;
 	char name[256];
+	int master_iobrick;
+	moduleid_t iobrick_id;
+	int i;
 
 	/*
 	 * Iterate throught each xtalk links in the system ..
@@ -480,42 +573,48 @@
 	devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module");
 
 	/*
-	 * Loop throught this directory "/devfs/hw/module/" and get each 
-	 * of it's entry.
-	 */
-	while (1) {
-	
-		/* Get vertex of component /dev/hw/<module_number> */
-		memset((char *)name, '0', 256);
-		module_comp = NULL;
-		rv = hwgraph_edge_get_next(devfs_hdl, (char *)name, &module_comp, (uint *)&placeptr);
-		if ((rv == 0) && (module_comp)) {
-			/* Found a valid entry */
-			node = NULL;
-			rv = hwgraph_edge_get(module_comp, "node", &node);
-
-		} else {
-			printk("pci_bus_to_hcl_cvlink: No more Module Component.\n");
-			return(0);
+	 * To provide consistent(not persistent) device naming, we need to start 
+	 * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 
+	 * with an attached I-Brick.  Find the master_iobrick.
+	 */
+	master_iobrick = -1;
+	for (i = 0; i < nummodules; i++) {
+		moduleid_t iobrick_id; 
+		iobrick_id = iobrick_module_get(&modules[i]->elsc);
+		if (iobrick_id > 0) { /* Valid module id */
+			if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) {
+				master_iobrick = i;
+				break;
+			}
 		}
+	}
 
-		if ( (rv != 0) || (!node) ){
-			printk("pci_bus_to_hcl_cvlink: Module Component does not have node vertex.\n");
-			continue;
-		} else {
-			xtalk = NULL;
-			rv = hwgraph_edge_get(node, "xtalk", &xtalk);
-			if ( (rv != 0) || (xtalk == NULL) ){
-				printk("pci_bus_to_hcl_cvlink: Node has no xtalk vertex.\n");
-				continue;
-			}
+	/*
+	 * The master_iobrick gets bus 0 and 1.
+	 */
+	if (master_iobrick >= 0) {
+		memset(name, 0, 256);
+		format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF);
+		strcat(name, "/node/xtalk");
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+		
+	/*
+	 * Now go do the rest of the modules, starting from the C-Brick with the lowest 
+	 * module id, remembering to skip the master_iobrick, which was done above.
+	 */
+	for (i = 0; i < nummodules; i++) {
+		if (i == master_iobrick) {
+			continue; /* Did the master_iobrick already. */
 		}
 
-		printk("pci_bus_to_hcl_cvlink: Found Module %s node vertex = 0x%p xtalk vertex = 0x%p\n", name, node, xtalk);
-		/*
-		 * Call routine to get the existing PCI Xwidget and create
-		 * the convenience link from "/devfs/hw/pci_bus/.."
-		 */
+		memset(name, 0, 256);
+		format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF);
+		strcat(name, "/node/xtalk");
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
 		pci_bus_map_create(xtalk);
 	}
 
@@ -539,10 +638,8 @@
 	struct sn1_widget_sysdata *widget_sysdata;
 	struct sn1_device_sysdata *device_sysdata;
 
-	printk("sgi_pci_intr_support: Called with requested_irq 0x%x\n", requested_irq);
-
 	if (!dev_desc || !bus_vertex || !device_vertex) {
-		printk("sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex);
+		printk("WARNING: sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex);
 		return(-1);
 	}
 
@@ -577,15 +674,11 @@
 	if (pci_dev->vendor == PCI_VENDOR_ID_SGI &&
 	    pci_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
 		*lines = 1;
-		printk("%s : IOC3 HACK: lines= %d\n", __FUNCTION__, *lines);
 	}
 #endif /* BRINGUP */
 
 	/* Not supported currently */
 	*dev_desc = NULL;
-
-	printk("sgi_pci_intr_support: Device Descriptor 0x%p, Bus Vertex 0x%p, Interrupt Pins 0x%x, Device Vertex 0x%p\n", *dev_desc, *bus_vertex, *lines, *device_vertex);
-
 	return(0);
 
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pci_dma.c linux/arch/ia64/sn/io/pci_dma.c
--- v2.4.3/linux/arch/ia64/sn/io/pci_dma.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/pci_dma.c	Thu Apr 12 12:16:35 2001
@@ -21,9 +21,6 @@
 #ifndef _LANGUAGE_C
 #define _LANGUAGE_C 99
 #endif
-#ifndef CONFIG_IA64_SGI_IO
-#define CONFIG_IA64_SGI_IO 99
-#endif
 
 #include <asm/io.h>
 #include <asm/sn/sgi.h>
@@ -32,9 +29,9 @@
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
 #include <asm/sn/iobus.h>
-#include <asm/sn/pci/pci_bus_cvlink.h>
 #include <asm/sn/types.h>
 #include <asm/sn/alenlist.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
 
 /*
  * this is REALLY ugly, blame it on gcc's lame inlining that we
@@ -43,13 +40,69 @@
 #if LANGUAGE_C == 99
 #undef LANGUAGE_C
 #endif
-#if _LANGUAGE_C == 99
-#undef _LANGUAGE_C
-#endif
 #if CONFIG_IA64_SGI_IO == 99
 #undef CONFIG_IA64_SGI_IO
 #endif
 
+pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t);
+struct sn1_dma_maps_s *find_sn1_dma_map(dma_addr_t, unsigned char);
+extern devfs_handle_t busnum_to_pcibr_vhdl[];
+extern nasid_t busnum_to_nid[];
+extern void * busnum_to_atedmamaps[];
+
+/*
+ * Get a free pciio_dmamap_t entry.
+ */
+pciio_dmamap_t
+get_free_pciio_dmamap(devfs_handle_t pci_bus)
+{
+	int i;
+	struct sn1_dma_maps_s *sn1_dma_map = NULL;
+
+	/*
+	 * Darn, we need to get the maps allocated for this bus.
+	 */
+	for (i=0; i<512; i++) {
+		if (busnum_to_pcibr_vhdl[i] == pci_bus) {
+			sn1_dma_map = busnum_to_atedmamaps[i];
+		}
+	}
+
+	/*
+	 * Now get a free dmamap entry from this list.
+	 */
+	for (i=0; i<512; i++, sn1_dma_map++) {
+		if (!sn1_dma_map->dma_addr) {
+			sn1_dma_map->dma_addr = -1;
+			return( (pciio_dmamap_t) sn1_dma_map );
+		}
+	}
+
+printk("get_pciio_dmamap: Unable to find a free dmamap\n");
+	return(NULL);
+
+}
+
+struct sn1_dma_maps_s *
+find_sn1_dma_map(dma_addr_t dma_addr, unsigned char busnum)
+{
+
+	struct sn1_dma_maps_s *sn1_dma_map = NULL;
+	int i;
+
+	sn1_dma_map = busnum_to_atedmamaps[busnum];
+
+	for (i=0; i<512; i++, sn1_dma_map++) {
+		if (sn1_dma_map->dma_addr == dma_addr) {
+			return( sn1_dma_map );
+		}
+	}
+
+printk("find_pciio_dmamap: Unable find the corresponding dma map\n");
+	return(NULL);
+
+}
+
 /*
  * sn1 platform specific pci_alloc_consistent()
  *
@@ -74,7 +127,7 @@
 	device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata;
 	vhdl = device_sysdata->vhdl;
 
-        if ( ret = (void *)__get_free_pages(gfp, get_order(size)) ) {
+        if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) {
 		memset(ret, 0, size);
 	} else {
 		return(NULL);
@@ -142,6 +195,8 @@
 	dma_addr_t dma_addr;
 	paddr_t temp_ptr;
 	struct sn1_device_sysdata *device_sysdata;
+	pciio_dmamap_t dma_map;
+
 
 
 	if (direction == PCI_DMA_NONE)
@@ -153,7 +208,7 @@
 	device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata;
 	vhdl = device_sysdata->vhdl;
 	for (i = 0; i < nents; i++, sg++) {
-		sg->orig_address = sg->address;
+		sg->orig_address = (char *)NULL;
 		dma_addr = 0;
 		temp_ptr = (paddr_t) __pa(sg->address);
 
@@ -166,7 +221,6 @@
 				PCIBR_BARRIER | PCIIO_BYTE_STREAM |
 				PCIIO_DMA_CMD | PCIIO_DMA_A64 );
 			sg->address = (char *)dma_addr;
-/* printk("pci_map_sg: 64Bits hwdev %p DMA Address 0x%p alt_address 0x%p orig_address 0x%p length 0x%x\n", hwdev, sg->address, sg->alt_address, sg->orig_address, sg->length); */
 			continue;
 		}
 
@@ -180,17 +234,28 @@
 				PCIIO_DMA_CMD);
 			if (dma_addr) {
 				sg->address = (char *)dma_addr;
-/* printk("pci_map_single: 32Bit direct pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */
 				continue;
-			} else {
-				/*
-				 * We need to map this request by using ATEs.
-				 */
-				printk("pci_map_single: 32Bits DMA Page Map support not available yet!");
-				BUG();
-
 			}
+
 		}
+
+		/*
+		 * It is a 32bit card and we cannot do Direct mapping.
+		 * Let's 32Bit Page map the request.
+		 */
+		dma_map = NULL;
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, 
+				PCIBR_BARRIER | PCIIO_BYTE_STREAM |
+				PCIIO_DMA_CMD);
+		if (!dma_map) {
+			printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n");
+			BUG();
+		}
+		dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length);
+		/* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */
+		sg->address = (char *)dma_addr;
+		sg->orig_address = (char *)dma_map;
+		
 	}
 
 	return nents;
@@ -206,13 +271,25 @@
 sn1_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
 	int i;
+	struct sn1_dma_maps_s *sn1_dma_map;
+
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
+
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != sg->address) {
+		if (sg->orig_address) {
+			/*
+			 * We maintain the DMA Map pointer in sg->orig_address if 
+			 * it is ever allocated.
+			 */
 			/* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */
-			sg->address = sg->orig_address;
+			/* sg->address = sg->orig_address; */
+			sg->address = (char *)-1;
+			sn1_dma_map = (struct sn1_dma_maps_s *)sg->orig_address;
+			pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map);
+			pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map);
+			sn1_dma_map->dma_addr = 0;
 			sg->orig_address = 0;
 		}
 }
@@ -234,24 +311,20 @@
 	dma_addr_t dma_addr;
 	paddr_t temp_ptr;
 	struct sn1_device_sysdata *device_sysdata;
+	pciio_dmamap_t dma_map = NULL;
+	struct sn1_dma_maps_s *sn1_dma_map;
 
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
-	if (IS_PCI32L(hwdev)) {
-		/*
-		 * SNIA64 cannot support DMA Addresses smaller than 32 bits.
-		 */
-		return ((dma_addr_t) NULL);
-	}
 
 	/*
 	 * find vertex for the device
 	 */
 	device_sysdata = (struct sn1_device_sysdata *)hwdev->sysdata;
 	vhdl = device_sysdata->vhdl;
-/* printk("pci_map_single: Called vhdl = 0x%p ptr = 0x%p size = %d\n", vhdl, ptr, size); */
+
 	/*
 	 * Call our dmamap interface
 	 */
@@ -266,7 +339,6 @@
 			temp_ptr, size,
 			PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD
 			| PCIIO_DMA_A64 );
-/* printk("pci_map_single: 64Bit pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */
 		return (dma_addr);
 	}
 
@@ -281,14 +353,7 @@
 			temp_ptr, size,
 			PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
 		if (dma_addr) {
-/* printk("pci_map_single: 32Bit direct pciio_dmatrans_addr pcidev %p returns dma_addr 0x%lx\n", hwdev, dma_addr); */
 			return (dma_addr);
-		} else {
-			/*
-			 * We need to map this request by using ATEs.
-			 */
-			printk("pci_map_single: 32Bits DMA Page Map support not available yet!");
-			BUG();
 		}
 	}
 
@@ -297,23 +362,56 @@
 		 * SNIA64 cannot support DMA Addresses smaller than 32 bits.
 		 */
 		return ((dma_addr_t) NULL);
+        }
+
+	/*
+	 * It is a 32bit card and we cannot do Direct mapping.
+	 * Let's 32Bit Page map the request.
+	 */
+	dma_map = NULL;
+	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIBR_BARRIER | 
+			PCIIO_BYTE_STREAM | PCIIO_DMA_CMD);
+	if (!dma_map) {
+		printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n");
+		BUG();
 	}
 
-	return ((dma_addr_t) NULL);
+	dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size);
+	/* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, 
+		temp_ptr, dma_addr); */
+	sn1_dma_map = (struct sn1_dma_maps_s *)dma_map;
+	sn1_dma_map->dma_addr = dma_addr;
 
+	return ((dma_addr_t)dma_addr);
 }
 
 void
 sn1_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
+
+	struct sn1_dma_maps_s *sn1_dma_map = NULL;
+
         if (direction == PCI_DMA_NONE)
-                BUG();
-        /* Nothing to do */
+		BUG();
+
+	/*
+	 * Get the sn1_dma_map entry.
+	 */
+	if (IS_PCI32_MAPPED(dma_addr))
+		sn1_dma_map = find_sn1_dma_map(dma_addr, hwdev->bus->number);
+
+	if (sn1_dma_map) {
+		pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map);
+		pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map);
+		sn1_dma_map->dma_addr = (dma_addr_t)NULL;
+	}
+
 }
 
 void
 sn1_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
+	
         if (direction == PCI_DMA_NONE)
                 BUG();
         /* Nothing to do */
@@ -330,5 +428,5 @@
 unsigned long
 sn1_dma_address (struct scatterlist *sg)
 {
-	return (sg->address);
+	return ((unsigned long)sg->address);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pciba.c linux/arch/ia64/sn/io/pciba.c
--- v2.4.3/linux/arch/ia64/sn/io/pciba.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/sn/io/pciba.c	Thu Apr 12 12:16:35 2001
@@ -0,0 +1,1716 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2000 by Colin Ngam
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_defs.h>
+#include <asm/sn/prio.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/ioc3.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/sn1/bedrock.h>
+#include <asm/sn/sn_private.h>
+#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
+#include <asm/sn/sn1/hubio.h>
+#include <asm/sn/sn1/hubio_next.h>
+#endif
+
+#define copyin(_a, _b, _c)	copy_from_user(_b, _a, _c)
+
+#ifndef	DEBUG_PCIBA
+#define	DEBUG_PCIBA		0
+#endif
+
+/* v_mapphys does not percolate page offset back. */
+#define	PCIBA_ALIGN_CHECK	1
+
+#include <asm/sn/pci/pciba.h>
+
+/* grab an unused space code for "User DMA" space */
+#ifndef	PCIBA_SPACE_UDMA
+#define	PCIBA_SPACE_UDMA	(14)
+#endif
+
+#if DEBUG_REFCT
+extern int		hwgraph_vertex_refct(vertex_hdl_t);
+#endif
+extern int		pci_user_dma_max_pages;
+
+#define NEW(ptr)	(ptr = kmem_zalloc(sizeof (*(ptr)), KM_SLEEP))
+#define DEL(ptr)	(kfree(ptr))
+
+/* Oops -- no standard "pci address" type! */
+typedef uint64_t        pciaddr_t;
+
+/* ================================================================
+ *            driver types
+ */
+typedef struct pciba_slot_s *pciba_slot_t;
+typedef struct pciba_comm_s *pciba_comm_t;
+typedef struct pciba_soft_s *pciba_soft_t;
+typedef struct pciba_map_s *pciba_map_t, **pciba_map_h;
+typedef struct pciba_dma_s *pciba_dma_t, **pciba_dma_h;
+typedef struct pciba_bus_s *pciba_bus_t;
+
+#define	TRACKED_SPACES	16
+struct pciba_comm_s {
+    devfs_handle_t	    conn;
+    pciba_bus_t             bus;
+    int			    refct;
+    pciba_soft_t	    soft[TRACKED_SPACES][2];
+    struct semaphore        lock;
+    pciba_dma_t             dmap;
+};
+
+/* pciba_soft: device_info() for all openables */
+struct pciba_soft_s {
+    pciba_comm_t	    comm;
+    devfs_handle_t          vhdl;
+    int			    refct;
+    pciio_space_t           space;
+    size_t                  size;
+    pciio_space_t           iomem;
+    pciaddr_t               base;
+    unsigned		    flags;
+};
+
+#define	pciba_soft_get(v)	(pciba_soft_t)hwgraph_fastinfo_get(v)
+#define	pciba_soft_set(v,i)	hwgraph_fastinfo_set(v,(arbitrary_info_t)(i))
+
+#define	pciba_soft_lock(soft)	down(&soft->comm->lock)
+#define	pciba_soft_unlock(soft)	up(&soft->comm->lock)
+
+/* pciba_map: data describing a mapping.
+ * (ie. a user mmap request)
+ */
+struct pciba_map_s {
+    pciba_map_t             next;
+#ifdef LATER
+    uthread_t              *uthread;
+#endif
+    __psunsigned_t          handle;
+    uvaddr_t                uvaddr;
+    size_t                  size;
+    pciio_piomap_t          map;
+    pciio_space_t           space;
+    pciaddr_t               base;
+    unsigned		    flags;
+};
+
+/* pciba_dma: data describing a DMA mapping.
+ */
+struct pciba_dma_s {
+    pciba_dma_t             next;
+    iopaddr_t               paddr;	/* starting phys addr */
+    caddr_t                 kaddr;	/* starting kern addr */
+    pciio_dmamap_t          map;	/* mapping resources (ugh!) */
+    pciaddr_t               daddr;	/* starting pci addr */
+    size_t                  pages;	/* size of block in pages */
+    size_t                  bytes;	/* size of block in bytes */
+    __psunsigned_t          handle;	/* mapping handle */
+};
+
+/* pciba_bus: common bus info for all openables
+ * descended from the same master vertex.
+ */
+struct pciba_bus_s {
+    struct semaphore        lock;
+    pciba_map_t             maps;	/* stack of mappings */
+    int			    refct;
+};
+
+#define	pciba_bus_lock(bus)	down(&bus->lock)
+#define	pciba_bus_unlock(bus)	up(&bus->lock)
+
+typedef union ioctl_arg_buffer_u {
+    char                    data[IOCPARM_MASK + 1];
+    uint8_t                 uc;
+    uint16_t                us;
+    uint32_t                ui;
+    uint64_t                ud;
+    caddr_t                 ca;
+#if ULI
+    struct uliargs          uli;
+    struct uliargs32	    uli32;
+#endif
+} ioctl_arg_buffer_t;
+
+/* ================================================================
+ *            driver variables
+ */
+char                   *pciba_mversion = "mload version 7.0";
+int                     pciba_devflag = 0x1 |
+                                        0x200 |
+                                        0x400;
+
+/* this counts the reasons why we can not
+ * currently unload this driver.
+ */
+atomic_t                pciba_prevent_unload = ATOMIC_INIT(0);
+
+#if DEBUG_PCIBA
+static struct reg_values space_v[] =
+{
+    {PCIIO_SPACE_NONE, "none"},
+    {PCIIO_SPACE_ROM, "ROM"},
+    {PCIIO_SPACE_IO, "I/O"},
+    {PCIIO_SPACE_MEM, "MEM"},
+    {PCIIO_SPACE_MEM32, "MEM(32)"},
+    {PCIIO_SPACE_MEM64, "MEM(64)"},
+    {PCIIO_SPACE_CFG, "CFG"},
+    {PCIIO_SPACE_WIN(0), "WIN(0)"},
+    {PCIIO_SPACE_WIN(1), "WIN(1)"},
+    {PCIIO_SPACE_WIN(2), "WIN(2)"},
+    {PCIIO_SPACE_WIN(3), "WIN(3)"},
+    {PCIIO_SPACE_WIN(4), "WIN(4)"},
+    {PCIIO_SPACE_WIN(5), "WIN(5)"},
+    {PCIBA_SPACE_UDMA, "UDMA"},
+    {PCIIO_SPACE_BAD, "BAD"},
+    {0}
+};
+
+static struct reg_desc  space_desc[] =
+{
+    {0xFF, 0, "space", 0, space_v},
+    {0}
+};
+#endif
+
+char                    pciba_edge_lbl_base[] = "base";
+char                    pciba_edge_lbl_cfg[] = "config";
+char                    pciba_edge_lbl_dma[] = "dma";
+char                    pciba_edge_lbl_intr[] = "intr";
+char                    pciba_edge_lbl_io[] = "io";
+char                    pciba_edge_lbl_mem[] = "mem";
+char                    pciba_edge_lbl_rom[] = "rom";
+char                   *pciba_edge_lbl_win[6] =
+{"0", "1", "2", "3", "4", "5"};
+
+#define	PCIBA_EDGE_LBL_BASE	pciba_edge_lbl_base
+#define	PCIBA_EDGE_LBL_CFG	pciba_edge_lbl_cfg
+#define	PCIBA_EDGE_LBL_DMA	pciba_edge_lbl_dma
+#define	PCIBA_EDGE_LBL_INTR	pciba_edge_lbl_intr
+#define	PCIBA_EDGE_LBL_IO	pciba_edge_lbl_io
+#define	PCIBA_EDGE_LBL_MEM	pciba_edge_lbl_mem
+#define	PCIBA_EDGE_LBL_ROM	pciba_edge_lbl_rom
+#define	PCIBA_EDGE_LBL_WIN(n)	pciba_edge_lbl_win[n]
+
+#define	PCIBA_EDGE_LBL_FLIP	pciba_edge_lbl_flip
+
+static char             pciba_info_lbl_bus[] = "pciba_bus";
+
+#define	PCIBA_INFO_LBL_BUS	pciba_info_lbl_bus
+
+struct file_operations pciba_fops = {
+	owner:	THIS_MODULE,
+	llseek: NULL,
+	read: NULL,
+	write: NULL,
+	readdir: NULL,
+	poll: NULL,
+	ioctl: NULL,
+	mmap: NULL,
+	open: NULL,
+	flush: NULL,
+	release: NULL,
+	fsync: NULL,
+	fasync: NULL,
+	lock: NULL,
+	readv: NULL,
+	writev: NULL
+};
+	
+/* ================================================================
+ *            function table of contents
+ */
+
+void                    pciba_init(void);
+int                     pciba_attach(devfs_handle_t);
+
+static void		pciba_sub_attach(pciba_comm_t,
+					 pciio_space_t, pciio_space_t, pciaddr_t,
+					 devfs_handle_t, devfs_handle_t, char *);
+
+static pciba_bus_t      pciba_find_bus(devfs_handle_t, int);
+#ifdef LATER
+static void             pciba_map_push(pciba_bus_t, pciba_map_t);
+static pciba_map_t      pciba_map_pop_hdl(pciba_bus_t, __psunsigned_t);
+static void             pciba_sub_detach(devfs_handle_t, char *);
+static pciio_iter_f     pciba_unload_me;
+#endif
+
+int                     pciba_unload(void);
+int                     pciba_unreg(void);
+int                     pciba_detach(devfs_handle_t);
+
+int                     pciba_open(dev_t *, int, int, struct cred *);
+int                     pciba_close(dev_t);
+int                     pciba_read(dev_t, cred_t *);
+int                     pciba_write(dev_t, cred_t *);
+int                     pciba_ioctl(dev_t, int, void *, int, cred_t *, int *);
+
+int                     pciba_map(dev_t, vhandl_t *, off_t, size_t, uint32_t);
+int                     pciba_unmap(dev_t, vhandl_t *);
+
+#if ULI
+void                    pciba_clearuli(struct uli *);
+static intr_func_f      pciba_intr;
+#endif /* Undef as it gets implemented */
+
+/* ================================================================
+ *            driver load, register, and setup
+ */
+void
+pciba_init(void)
+{
+
+	/*
+	 * What do we need to do here?
+	 */
+#if DEBUG_PCIBA
+    printk("pciba_init()\n");
+#endif
+}
+
+#ifdef LATER
+#if HWG_PERF_CHECK && IP30 && !DEBUG
+void
+pciba_timeout(void *arg1, void *arg2)
+{
+    struct semaphore       *semap = (sema_t *) arg1;
+    unsigned long          *cvalp = (unsigned long *) arg2;
+
+    if (cvalp)
+	cvalp[0] = RAW_COUNT();
+    if (semap)
+	up(semap);
+}
+
+volatile unsigned long  cNval[1];
+struct semaphore        tsema;
+
+void
+pciba_timeout_test(void)
+{
+    unsigned long           c0val, cval;
+    toid_t                  tid;
+
+    extern void             hwg_hprint(unsigned long, char *);
+
+    sema_init(&tsema, 0);
+
+    cNval[0] = 0;
+    c0val = RAW_COUNT();
+    tid = timeout((void (*)()) pciba_timeout, (void *) 0, 1, (void *) cNval);
+    DELAY(1000000);
+    cval = cNval[0];
+    if (cval == 0) {
+	untimeout(tid);
+	PRINT_ALERT("pciba: one-tick timeout did not happen in a second\n");
+	return;
+    }
+    cval = cval - c0val;
+    hwg_hprint(cval, "timeout(1)");
+
+    cNval[0] = 0;
+    c0val = RAW_COUNT();
+    tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, 2, (void *) cNval);
+
+    /* FIXME : this probably needs to be down_interruptible() */
+
+    if (down(&tsema) < 0) {	/* wait for the pciba_timeout */
+	untimeout(tid);
+	PRINT_WARNING("pciba: timeout(2) time check aborted\n");
+	return;
+    }
+    cval = cNval[0];
+    if (cval == 0) {
+	untimeout(tid);
+	PRINT_WARNING("pciba: timeout(2) time not logged\n");
+	return;
+    }
+    cval = cval - c0val;
+    hwg_hprint(cval, "timeout(2)");
+
+    cNval[0] = 0;
+    c0val = RAW_COUNT();
+    tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, HZ, (void *) cNval);
+
+    /* FIXME : this probably needs to be down_interruptible() */
+
+    if (down(&tsema) < 0) {	/* wait for the pciba_timeout */
+	untimeout(tid);
+	PRINT_WARNING("pciba: timeout(HZ) time check aborted\n");
+	return;
+    }
+    cval = cNval[0];
+    if (cval == 0) {
+	untimeout(tid);
+	PRINT_WARNING("pciba: timeout(HZ) time not logged\n");
+	return;
+    }
+    cval = cval - c0val;
+    hwg_hprint(cval, "timeout(HZ)");
+
+    printk("verifying untimeout() cancells ...\n");
+    cNval[0] = 0;
+    tid = timeout((void (*)()) pciba_timeout, (void *) 0, 2, (void *) cNval);
+    untimeout(tid);
+    DELAY(1000000);
+    cval = cNval[0];
+    if (cval != 0) {
+	PRINT_ALERT("pciba: unable to cancel two-tick timeout\n");
+	cval -= c0val;
+	hwg_hprint(cval, "CANCELLED timeout(2)");
+    }
+}
+#endif
+
+int
+pciba_reg(void)
+{
+#if DEBUG_PCIBA
+    printk("pciba_reg()\n");
+#endif
+    pciio_driver_register(-1, -1, "pciba_", 0);
+
+#if HWG_PERF_CHECK && IP30 && !DEBUG
+    printk("%s %d\n", __FUNCTION__, __LINE__);
+pciba_timeout_test();
+#endif
+
+#if DEBUG_REFCT
+    {
+	char	       *cname = "pciba";
+	char	       *dname = "ptv";
+	char           *cpath0 = "node/xtalk/15";
+	char           *uname0 = "0";
+	char           *cpath1 = "node/xtalk/13";
+	char           *uname1 = "1";
+	devfs_handle_t conn;
+	devfs_handle_t conv;
+	devfs_handle_t vhdl;
+	int		ret;
+
+	printk("pciba refct tests:\n");
+
+#define	SHOWREF(vhdl,func)	printk("ref=%d\t%s\t(%d) %v\n", hwgraph_vertex_refct(vhdl), #func, vhdl, vhdl);
+
+	if (GRAPH_SUCCESS != (ret = hwgraph_path_add(hwgraph_root, cname, &conv)))
+	    printk("\tunable to create conv (ret=%d)\n", ret);
+	else {						SHOWREF(conv, hwgraph_path_add);
+	    if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn)))
+		printk("\tunable to find %s (ret=%d)\n", cpath0, ret);
+	    else {					SHOWREF(conn, hwgraph_traverse);
+		if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl)))
+		    printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret);
+		else {					SHOWREF(vhdl, hwgraph_char_device_add);
+		    hwgraph_chmod(vhdl, 0666);		SHOWREF(vhdl, hwgraph_chmod);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname0)))
+			printk("unable to create %v/%s (ret=%d)\n", conn, uname0, vhdl, ret);
+		    else				SHOWREF(vhdl, hwgraph_edge_add);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl)))
+			printk("unable to unref %v\n", vhdl);
+		    else				SHOWREF(vhdl, hwgraph_vertex_unref);
+		}
+		if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn)))
+		    printk("unable to unref %v\n", conn);
+		else					SHOWREF(conn, hwgraph_vertex_unref);
+	    }
+ 
+	    if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn)))
+		printk("\tunable to find %s (ret=%d)\n", cpath1, ret);
+	    else {					SHOWREF(conn, hwgraph_traverse);
+		if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl)))
+		    printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret);
+		else {					SHOWREF(vhdl, hwgraph_char_device_add);
+		    hwgraph_chmod(vhdl, 0666);		SHOWREF(vhdl, hwgraph_chmod);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname1)))
+			printk("unable to create %v/%s (ret=%d)\n", conn, uname1, vhdl, ret);
+		    else				SHOWREF(vhdl, hwgraph_edge_add);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl)))
+			printk("unable to unref %v\n", vhdl);
+		    else				SHOWREF(vhdl, hwgraph_vertex_unref);
+		}
+		if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn)))
+		    printk("unable to unref %v\n", conn);
+		else					SHOWREF(conn, hwgraph_vertex_unref);
+	    }
+ 
+	    if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn)))
+		printk("\tunable to find %s (ret=%d)\n", cpath0, ret);
+	    else {					SHOWREF(conn, hwgraph_traverse);
+		if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl)))
+		    printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret);
+		else {					SHOWREF(vhdl, hwgraph_traverse);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname0, NULL)))
+			printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname0, ret);
+		    else				SHOWREF(vhdl, hwgraph_edge_remove);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL)))
+			printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret);
+		    else				SHOWREF(vhdl, hwgraph_edge_remove);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl)))
+			printk("unable to unref %v\n", vhdl);
+		    else				SHOWREF(vhdl, hwgraph_vertex_unref);
+		    if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl)))
+			printk("\tvertex %d destroyed OK\n", vhdl);
+		    else				SHOWREF(vhdl, hwgraph_vertex_destroy);
+		}
+		if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn)))
+		    printk("unable to unref %v\n", conn);
+		else					SHOWREF(conn, hwgraph_vertex_unref);
+	    }
+
+	    if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn)))
+		printk("\tunable to find %s (ret=%d)\n", cpath1, ret);
+	    else {					SHOWREF(conn, hwgraph_traverse);
+		if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl)))
+		    printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret);
+		else {					SHOWREF(vhdl, hwgraph_traverse);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname1, NULL)))
+			printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname1, ret);
+		    else				SHOWREF(vhdl, hwgraph_edge_remove);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL)))
+			printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret);
+		    else				SHOWREF(vhdl, hwgraph_edge_remove);
+		    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl)))
+			printk("unable to unref %v\n", vhdl);
+		    else				SHOWREF(vhdl, hwgraph_vertex_unref);
+		    if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl)))
+			printk("\tvertex %d destroyed OK\n", vhdl);
+		    else				SHOWREF(vhdl, hwgraph_vertex_destroy);
+		}
+		if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn)))
+		    printk("unable to unref %v\n", conn);
+		else					SHOWREF(conn, hwgraph_vertex_unref);
+	    }
+
+	    if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(hwgraph_root, cname, NULL)))
+		printk("\tunable to remove edge %v/%s (ret=%d)\n", hwgraph_root, cname, ret);
+	    else				SHOWREF(conv, hwgraph_edge_remove);
+	    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conv)))
+		printk("unable to unref %v\n", conv);
+	    else					SHOWREF(conv, hwgraph_vertex_unref);
+	    if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(conv)))
+		printk("\tvertex %d destroyed OK\n", conv);
+	    else					SHOWREF(conv, hwgraph_vertex_destroy);
+	}
+    }
+#endif
+
+    return 0;
+}
+
+#endif
+int
+pciba_attach(devfs_handle_t hconn)
+{
+#if defined(PCIIO_SLOT_NONE)
+    pciio_info_t            info = pciio_info_get(hconn);
+    pciio_slot_t            slot = pciio_info_slot_get(info);
+#endif
+    pciba_comm_t	    comm;
+    pciba_bus_t             bus;
+    int                     ht;
+    devfs_handle_t	    hbase;
+    devfs_handle_t          gconn;
+    devfs_handle_t          gbase;
+    int                     win;
+    int                     wins;
+    pciio_space_t           space;
+    pciaddr_t               base;
+
+    int                     iwins;
+    int                     mwins;
+
+#if DEBUG_PCIBA
+    printk("pciba_attach(%p)\n", hconn);
+#endif
+
+    /* Pick up "dualslot guest" vertex,
+     * which gets all functionality except
+     * config space access.
+     */
+    if ((GRAPH_SUCCESS !=
+	 hwgraph_traverse(hconn, ".guest", &gconn)) ||
+	(hconn == gconn))
+	gconn = GRAPH_VERTEX_NONE;
+
+    bus = pciba_find_bus(hconn, 1);
+    bus->refct ++;
+
+    /* set up data common to all pciba openables
+     * on this connection point.
+     */
+    NEW(comm);
+    comm->conn = hconn;
+    comm->bus = bus;
+    comm->refct = 0;
+    sema_init(&comm->lock, 1);
+
+#if !defined(PCIIO_SLOT_NONE)
+    if (bus->refct == 1)
+#else
+    if (slot == PCIIO_SLOT_NONE)
+#endif
+    {
+	pciio_info_t            pciio_info;
+	devfs_handle_t          master;
+
+	pciio_info = pciio_info_get(hconn);
+	master = pciio_info_master_get(pciio_info);
+
+	pciba_sub_attach(comm, PCIIO_SPACE_IO, PCIIO_SPACE_IO, 0, master, master, PCIBA_EDGE_LBL_IO);
+	pciba_sub_attach(comm, PCIIO_SPACE_MEM, PCIIO_SPACE_MEM, 0, master, master, PCIBA_EDGE_LBL_MEM);
+#if defined(PCIIO_SLOT_NONE)
+	return 0;
+#endif
+    }
+
+    ht = 0x7F & pciio_config_get(hconn, PCI_CFG_HEADER_TYPE, 1);
+
+    wins = ((ht == 0x00) ? 6 :
+	    (ht == 0x01) ? 2 :
+	    0);
+
+    mwins = iwins = 0;
+
+    hbase = GRAPH_VERTEX_NONE;
+    gbase = GRAPH_VERTEX_NONE;
+
+    for (win = 0; win < wins; win++) {
+
+	base = pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win), 4);
+	if (base & 1) {
+	    space = PCIIO_SPACE_IO;
+	    base &= 0xFFFFFFFC;
+	} else if ((base & 7) == 4) {
+	    space = PCIIO_SPACE_MEM;
+	    base &= 0xFFFFFFF0;
+	    base |= ((pciaddr_t) pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win + 1), 4)) << 32;
+	} else {
+	    space = PCIIO_SPACE_MEM;
+	    base &= 0xFFFFFFF0;
+	}
+
+	if (!base)
+	    break;
+
+#if PCIBA_ALIGN_CHECK
+	if (base & (_PAGESZ - 1)) {
+#if DEBUG_PCIBA
+	    PRINT_WARNING("%p pciba: BASE%d not page aligned!\n"
+		    "\tmmap this window at offset 0x%x via \".../pci/%s\"\n",
+		    hconn, win, base,
+		    (space == PCIIO_SPACE_IO) ? "io" : "mem");
+#endif
+	    continue;			/* next window */
+	}
+#endif
+
+	if ((hbase == GRAPH_VERTEX_NONE) &&
+	    ((GRAPH_SUCCESS !=
+	      hwgraph_path_add(hconn, PCIBA_EDGE_LBL_BASE, &hbase)) ||
+	     (hbase == GRAPH_VERTEX_NONE)))
+	    break;			/* no base vertex, no more windows. */
+
+	if ((gconn != GRAPH_VERTEX_NONE) &&
+	    (gbase == GRAPH_VERTEX_NONE) &&
+	    ((GRAPH_SUCCESS !=
+	      hwgraph_path_add(gconn, PCIBA_EDGE_LBL_BASE, &gbase)) ||
+	     (gbase == GRAPH_VERTEX_NONE)))
+	    break;			/* no base vertex, no more windows. */
+
+	pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hbase, gbase, PCIBA_EDGE_LBL_WIN(win));
+
+	if (space == PCIIO_SPACE_IO) {
+	    if (!iwins++) {
+		pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_IO);
+	    }
+	} else {
+	    if (!mwins++) {
+		pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_MEM);
+	    }
+	}
+
+	if ((base & 7) == 4)
+	    win++;
+    }
+
+    pciba_sub_attach(comm, PCIIO_SPACE_CFG, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_CFG);
+    pciba_sub_attach(comm, PCIBA_SPACE_UDMA, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_DMA);
+#if ULI
+    pciba_sub_attach(comm, PCIIO_SPACE_NONE, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_INTR);
+#endif
+
+    /* XXX should ignore if device is an IOC3 */
+    if (ht == 0x01)
+	base = pciio_config_get(hconn, PCI_EXPANSION_ROM+8, 4);
+    else
+	base = pciio_config_get(hconn, PCI_EXPANSION_ROM, 4);
+
+    base &= 0xFFFFF000;
+
+    if (base) {
+	if (base & (_PAGESZ - 1))
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	    PRINT_WARNING("%v pciba: ROM is 0x%x\n"
+		    "\tnot page aligned, mmap will be difficult\n",
+		    hconn, base);
+#else
+	    PRINT_WARNING("0x%x pciba: ROM is 0x%x\n"
+		    "\tnot page aligned, mmap will be difficult\n",
+		    hconn, base);
+#endif
+	pciba_sub_attach(comm, PCIIO_SPACE_ROM, PCIIO_SPACE_MEM, base, hconn, gconn, PCIBA_EDGE_LBL_ROM);
+    }
+
+#if !FICUS	/* FICUS shorts the refct by one on path_add */
+    if (hbase != GRAPH_VERTEX_NONE)
+	hwgraph_vertex_unref(hbase);
+
+    if (gbase != GRAPH_VERTEX_NONE)
+	hwgraph_vertex_unref(gbase);
+#endif
+
+    return 0;
+}
+
+static void
+pciba_sub_attach2(pciba_comm_t comm,
+		  pciio_space_t space,
+		  pciio_space_t iomem,
+		  pciaddr_t base,
+		  devfs_handle_t from,
+		  char *name,
+		  char *suf,
+		  unsigned bigend)
+{
+    char		nbuf[128];
+    pciba_soft_t            soft;
+    devfs_handle_t	handle = NULL;
+
+    if (suf && *suf) {
+	strcpy(nbuf, name);
+	name = nbuf;
+	strcat(name, suf);
+    }
+
+#if DEBUG_PCIBA
+    printk("pciba_sub_attach2 %p/%s %p at %p[%x]\n",
+	   from, name, space, space_desc, iomem, space_desc, base, from, name);
+#endif
+
+    if (space < TRACKED_SPACES)
+	if ((soft = comm->soft[space][bigend]) != NULL) {
+	    soft->refct ++;
+	    hwgraph_edge_add(from, soft->vhdl, name);
+	    return;
+	}
+
+    NEW(soft);
+    if (!soft)
+	return;
+
+    soft->comm = comm;
+    soft->space = space;
+    soft->size = 0;
+    soft->iomem = iomem;
+    soft->base = base;
+    soft->refct = 1;
+
+    if (space == PCIIO_SPACE_NONE)
+	soft->flags = 0;
+    else if (bigend)
+	soft->flags = PCIIO_BYTE_STREAM;
+    else
+	soft->flags = PCIIO_WORD_VALUES;
+
+    handle = hwgraph_register(from, name,
+		0, DEVFS_FL_AUTO_DEVNUM,
+		0, 0,
+		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+		&pciba_fops, NULL);
+    soft->vhdl = handle;
+    pciba_soft_set(soft->vhdl, soft);
+    if (space < TRACKED_SPACES)
+	comm->soft[space][bigend] = soft;
+    comm->refct ++;
+}
+
+static void
+pciba_sub_attach1(pciba_comm_t comm,
+		  pciio_space_t space,
+		  pciio_space_t iomem,
+		  pciaddr_t base,
+		  devfs_handle_t hfrom,
+		  devfs_handle_t gfrom,
+		  char *name,
+		  char *suf,
+		  unsigned bigend)
+{
+    pciba_sub_attach2(comm, space, iomem, base, hfrom, name, suf, bigend);
+    if ((gfrom != GRAPH_VERTEX_NONE) && (gfrom != hfrom))
+	pciba_sub_attach2(comm, space, iomem, base, gfrom, name, suf, bigend);
+}
+
+static void
+pciba_sub_attach(pciba_comm_t comm,
+		 pciio_space_t space,
+		 pciio_space_t iomem,
+		 pciaddr_t base,
+		 devfs_handle_t hfrom,
+		 devfs_handle_t gfrom,
+		 char *name)
+{
+    pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, NULL, 0);
+    if (iomem != PCIIO_SPACE_NONE) {
+	pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_le", 0);
+	pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_be", 1);
+    }
+}
+
+#ifdef LATER
+static void
+pciba_reload_me(devfs_handle_t pconn_vhdl)
+{
+    devfs_handle_t            vhdl;
+
+#if DEBUG_PCIBA
+    printf("pciba_reload_me(%v)\n", pconn_vhdl);
+#endif
+
+    if (GRAPH_SUCCESS !=
+	hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &vhdl))
+	return;
+
+    hwgraph_vertex_unref(vhdl);
+}
+#endif	/* LATER */
+
+static                  pciba_bus_t
+pciba_find_bus(devfs_handle_t pconn, int cflag)
+{
+    pciio_info_t            pciio_info;
+    devfs_handle_t          master;
+    arbitrary_info_t        ainfo;
+    pciba_bus_t             bus;
+
+    pciio_info = pciio_info_get(pconn);
+    master = pciio_info_master_get(pciio_info);
+
+    if (GRAPH_SUCCESS ==
+	hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo))
+	return (pciba_bus_t) ainfo;
+
+    if (!cflag)
+	return 0;
+
+    NEW(bus);
+    if (!bus)
+	return 0;
+
+    sema_init(&bus->lock, 1);
+
+    ainfo = (arbitrary_info_t) bus;
+    hwgraph_info_add_LBL(master, PCIBA_INFO_LBL_BUS, ainfo);
+    hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo);
+    if ((pciba_bus_t) ainfo != bus)
+	DEL(bus);
+#if DEBUG_PCIBA
+    else
+	printk("pcbia_find_bus: new bus at %p\n", master);
+#endif
+
+    return (pciba_bus_t) ainfo;
+}
+
+#ifdef LATER
+static void
+pciba_map_push(pciba_bus_t bus, pciba_map_t map)
+{
+#if DEBUG_PCIBA
+    printk("pciba_map_push(bus=0x%x, map=0x%x, hdl=0x%x\n",
+	   bus, map, map->handle);
+#endif
+    pciba_bus_lock(bus);
+    map->next = bus->maps;
+    bus->maps = map;
+    pciba_bus_unlock(bus);
+}
+
+static                  pciba_map_t
+pciba_map_pop_hdl(pciba_bus_t bus, __psunsigned_t handle)
+{
+    pciba_map_h             hdl;
+    pciba_map_t             map;
+
+    pciba_bus_lock(bus);
+    for (hdl = &bus->maps; map = *hdl; hdl = &map->next)
+	if (map->handle == handle) {
+	    *hdl = map->next;
+	    break;
+	}
+    pciba_bus_unlock(bus);
+#if DEBUG_PCIBA
+    printk("pciba_map_pop_va(bus=0x%x, handle=0x%x) returns map=0x%x\n",
+	   bus, handle, map);
+#endif
+    return map;
+}
+
+/* ================================================================
+ *            driver teardown, unregister and unload
+ */
+int
+pciba_unload(void)
+{
+#if DEBUG_PCIBA
+    printk("pciba_unload()\n");
+#endif
+
+    if (atomic_read(&pciba_prevent_unload))
+	return -1;
+
+    pciio_iterate("pciba_", pciba_unload_me);
+
+    return 0;
+}
+
+int
+pciba_unreg(void)
+{
+
+#if DEBUG_PCIBA
+    printf("pciba_unreg()\n");
+#endif
+
+    if (atomic_read(&pciba_prevent_unload))
+	return -1;
+
+    pciio_driver_unregister("pciba_");
+    return 0;
+}
+
+int
+pciba_detach(devfs_handle_t conn)
+{
+    devfs_handle_t          base;
+    pciba_bus_t             bus;
+    devfs_handle_t          gconn;
+    devfs_handle_t          gbase;
+
+    pciio_info_t            pciio_info;
+    devfs_handle_t          master;
+    arbitrary_info_t        ainfo;
+    int			    ret;
+
+#if DEBUG_PCIBA
+    printf("pciba_detach(%v)\n", conn);
+#endif
+
+    if ((GRAPH_SUCCESS !=
+	 hwgraph_traverse(conn, ".guest", &gconn)) ||
+	(conn == gconn))
+	gconn = GRAPH_VERTEX_NONE;
+
+    if (gconn != GRAPH_VERTEX_NONE) {
+	pciba_sub_detach(gconn, PCIBA_EDGE_LBL_CFG);
+	pciba_sub_detach(gconn, PCIBA_EDGE_LBL_DMA);
+	pciba_sub_detach(gconn, PCIBA_EDGE_LBL_ROM);
+#if ULI
+	pciba_sub_detach(gconn, PCIBA_EDGE_LBL_INTR);
+#endif
+	if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &gbase)) {
+	    pciba_sub_detach(gconn, PCIBA_EDGE_LBL_MEM);
+	    pciba_sub_detach(gconn, PCIBA_EDGE_LBL_IO);
+	    pciba_sub_detach(gbase, "0");
+	    pciba_sub_detach(gbase, "1");
+	    pciba_sub_detach(gbase, "2");
+	    pciba_sub_detach(gbase, "3");
+	    pciba_sub_detach(gbase, "4");
+	    pciba_sub_detach(gbase, "5");
+	    hwgraph_vertex_unref(gbase);
+	    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(gbase))) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/base) failed (%d)",
+			conn, ret);
+#else
+		PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)",
+			conn, ret);
+#endif
+#if DEBUG_REFCT
+		printk("\tretained refct %d\n", hwgraph_vertex_refct(gbase));
+#endif
+	    }
+	}
+    }
+
+    pciba_sub_detach(conn, PCIBA_EDGE_LBL_CFG);
+    pciba_sub_detach(conn, PCIBA_EDGE_LBL_DMA);
+    pciba_sub_detach(conn, PCIBA_EDGE_LBL_ROM);
+#if ULI
+    pciba_sub_detach(conn, PCIBA_EDGE_LBL_INTR);
+#endif
+
+    if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &base)) {
+	pciba_sub_detach(conn, PCIBA_EDGE_LBL_MEM);
+	pciba_sub_detach(conn, PCIBA_EDGE_LBL_IO);
+	pciba_sub_detach(base, "0");
+	pciba_sub_detach(base, "1");
+	pciba_sub_detach(base, "2");
+	pciba_sub_detach(base, "3");
+	pciba_sub_detach(base, "4");
+	pciba_sub_detach(base, "5");
+	hwgraph_vertex_unref(base);
+	if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(base))) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	    PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(%v/base) failed (%d)",
+		    conn, ret);
+#else
+	    PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)",
+		    conn, ret);
+#endif
+#if DEBUG_REFCT
+	    printk("\tretained refct %d\n", hwgraph_vertex_refct(base));
+#endif
+	}
+    }
+
+    bus = pciba_find_bus(conn, 0);
+    if (bus && !--(bus->refct)) {
+
+	pciio_info = pciio_info_get(conn);
+
+	master = pciio_info_master_get(pciio_info);
+
+	pciba_sub_detach(master, PCIBA_EDGE_LBL_IO);
+	pciba_sub_detach(master, PCIBA_EDGE_LBL_MEM);
+	pciba_sub_detach(master, PCIBA_EDGE_LBL_CFG);
+	hwgraph_info_remove_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo);
+
+#if DEBUG_PCIBA
+	printf("pcbia_detach: DEL(bus) at %v\n", master);
+#endif
+	DEL(bus);
+    } 
+
+    return 0;
+}
+
+static void
+pciba_sub_detach1(devfs_handle_t conn,
+		  char *name,
+		  char *suf)
+{
+    devfs_handle_t         vhdl;
+    pciba_soft_t            soft;
+    pciba_comm_t	    comm;
+    int			    ret;
+    char		nbuf[128];
+
+    if (suf && *suf) {
+	strcpy(nbuf, name);
+	name = nbuf;
+	strcat(name, suf);
+    }
+
+    if ((GRAPH_SUCCESS == hwgraph_edge_remove(conn, name, &vhdl)) &&
+	((soft = pciba_soft_get(vhdl)) != NULL)) {
+#if DEBUG_PCIBA
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	prink("pciba_sub_detach(%v,%s)\n", conn, name);
+#else
+	prink("pciba_sub_detach(0x%x,%s)\n", conn, name);
+#endif
+#endif
+
+	hwgraph_vertex_unref(soft->vhdl);
+#if DEBUG_REFCT
+	printk("\tadjusted refct %d (soft ref: %d)\n",
+		hwgraph_vertex_refct(vhdl),
+		soft->refct);
+#endif
+	if (!--(soft->refct)) {
+	    comm = soft->comm;
+	    if (!--(comm->refct)) {
+		DEL(comm);
+	    }
+	    pciba_soft_set(vhdl, 0);
+	    DEL(soft);
+
+	    hwgraph_vertex_unref(vhdl);
+	    if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(vhdl))) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/%s) failed (%d)",
+			conn, name, ret);
+#else
+		PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/%s) failed (%d)",
+			conn, name, ret);
+#endif
+#if DEBUG_REFCT
+		printk("\tretained refct %d\n", hwgraph_vertex_refct(vhdl));
+#endif
+	    }
+	}
+    }
+}
+
+static void
+pciba_sub_detach(devfs_handle_t conn,
+		 char *name)
+{
+    pciba_sub_detach1(conn, name, "");
+    pciba_sub_detach1(conn, name, "_le");
+    pciba_sub_detach1(conn, name, "_be");
+}
+
+static void
+pciba_unload_me(devfs_handle_t pconn_vhdl)
+{
+    devfs_handle_t         c_vhdl;
+
+#if DEBUG_PCIBA
+    printf("pciba_unload_me(%v)\n", pconn_vhdl);
+#endif
+
+    if (GRAPH_SUCCESS !=
+	hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &c_vhdl))
+	return;
+
+    hwgraph_vertex_unref(c_vhdl);
+}
+
+/* ================================================================
+ *            standard unix entry points
+ */
+
+/*ARGSUSED */
+int
+pciba_open(dev_t *devp, int flag, int otyp, struct cred *crp)
+{
+
+#if DEBUG_PCIBA
+    printf("pciba_open(%V)\n", *devp);
+#endif
+    return 0;
+}
+
+/*ARGSUSED */
+int
+pciba_close(dev_t dev)
+{
+    devfs_handle_t         vhdl = dev_to_vhdl(dev);
+    pciba_soft_t            soft = pciba_soft_get(vhdl);
+
+#if DEBUG_PCIBA
+    printf("pciba_close(%V)\n", dev);
+#endif
+
+    /* if there is pending DMA for this device, hit the
+     * device over the head with a baseball bat and
+     * release the system memory resources.
+     */
+    if (soft && soft->comm->dmap) {
+	pciba_dma_t             next;
+	pciba_dma_t             dmap;
+
+	pciba_soft_lock(soft);
+	if (dmap = soft->comm->dmap) {
+	    soft->comm->dmap = 0;
+
+	    pciio_reset(soft->comm->conn);
+
+	    do {
+		if (!dmap->kaddr)
+		    break;
+		if (!dmap->paddr)
+		    break;
+		if (dmap->bytes < NBPP)
+		    break;
+		next = dmap->next;
+		kvpfree(dmap->kaddr, dmap->bytes / NBPP);
+		dmap->paddr = 0;
+		dmap->bytes = 0;
+		DEL(dmap);
+	    } while (dmap = next);
+	}
+	pciba_soft_unlock(soft);
+    }
+    return 0;
+}
+
+/* ARGSUSED */
+int
+pciba_read(dev_t dev, cred_t *crp)
+{
+#if DEBUG_PCIBA
+    printf("pciba_read(%V)\n", dev);
+#endif
+
+    return EINVAL;
+}
+
+/* ARGSUSED */
+int
+pciba_write(dev_t dev, cred_t *crp)
+{
+#if DEBUG_PCIBA
+    printf("pciba_write(%V)\n", dev);
+#endif
+
+    return EINVAL;
+}
+
+/*ARGSUSED */
+int
+pciba_ioctl(dev_t dev, int cmd, void *uarg, int mode, cred_t *crp, int *rvalp)
+{
+    devfs_handle_t          vhdl;
+    pciba_soft_t            soft;
+    pciio_space_t           space;
+    ioctl_arg_buffer_t      arg;
+    int                     psize;
+    int                     err = 0;
+
+#if ULI
+    char		    abi = get_current_abi();
+    pciio_intr_t            intr=0;
+    device_desc_t           desc;
+    cpuid_t                 intrcpu;
+    unsigned                lines;
+    struct uli             *uli = 0;
+#endif
+    unsigned                flags;
+    void                   *kaddr = 0;
+    iopaddr_t               paddr;
+    pciba_dma_h             dmah;
+    pciba_dma_t             dmap = 0;
+    pciio_dmamap_t          dmamap = 0;
+    size_t                  bytes;
+    int                     pages;
+    pciaddr_t               daddr;
+
+#if DEBUG_PCIBA
+    printf("pciba_ioctl(%V,0x%x)\n", dev, cmd);
+#endif
+
+    psize = (cmd >> 16) & IOCPARM_MASK;
+
+#if ULI
+    ASSERT(sizeof(struct uliargs) > 8);	/* prevent CFG access conflict */
+    ASSERT(sizeof(struct uliargs) <= IOCPARM_MASK);
+#endif
+
+    arg.ca = uarg;
+
+    if ((psize > 0) && (cmd & (IOC_OUT | IOC_IN))) {
+	if (psize > sizeof(arg))
+	    err = EINVAL;		/* "bad parameter size */
+	else {
+	    if (cmd & IOC_OUT)
+		bzero(arg.data, psize);
+	    if ((cmd & IOC_IN) &&
+		(copyin(uarg, arg.data, psize) < 0))
+		err = EFAULT;		/* "parameter copyin failed" */
+	}
+    }
+    vhdl = dev_to_vhdl(dev);
+    soft = pciba_soft_get(vhdl);
+    space = soft->space;
+
+    if (err == 0) {
+	err = EINVAL;			/* "invalid ioctl for this vertex" */
+	switch (space) {
+#if ULI
+	case PCIIO_SPACE_NONE:		/* the "intr" vertex */
+	    /* PCIIOCSETULI: set up user interrupts.
+	     */
+	    lines = cmd & 15;
+	    if (ABI_IS_64BIT(abi)) {
+		if (cmd != PCIIOCSETULI(lines)) {
+		    err = EINVAL;		/* "invalid ioctl for this vertex" */
+		    break;
+		}
+	    }
+	    else {
+		struct uliargs uliargs;
+
+		if (cmd != PCIIOCSETULI32(lines)) {
+		    err = EINVAL;		/* "invalid ioctl for this vertex" */
+		    break;
+		}
+		
+		uliargs32_to_uliargs(&arg.uli32, &uliargs);
+		arg.uli = uliargs;
+	    }
+	    desc = device_desc_dup(soft->comm->conn);
+	    device_desc_flags_set(desc, (device_desc_flags_get(desc) |
+					 D_INTR_NOTHREAD));
+	    device_desc_intr_swlevel_set(desc, INTR_SWLEVEL_NOTHREAD_DEFAULT);
+	    device_desc_intr_name_set(desc, "PCIBA");
+	    device_desc_default_set(soft->comm->conn, desc);
+
+	    /* When designating interrupts, the slot number
+	     * is taken from the connection point.
+	     * Bits 0..3 are used to select INTA..INTD; more
+	     * than one bit can be specified. These should
+	     * be constructed using PCIIO_INTR_LINE_[ABCD].
+	     */
+	    intr = pciio_intr_alloc
+		(soft->comm->conn, desc, lines, soft->vhdl);
+	    if (intr == 0) {
+		err = ENOMEM;		/* "insufficient resources" */
+		break;
+	    }
+	    intrcpu = cpuvertex_to_cpuid(pciio_intr_cpu_get(intr));
+
+	    if (err = new_uli(&arg.uli, &uli, intrcpu)) {
+		break;			/* "unable to set up ULI" */
+	    }
+	    atomic_inc(&pciba_prevent_unload);
+
+	    pciio_intr_connect(intr, pciba_intr, uli, (void *) 0);
+
+	    /* NOTE: don't set the teardown function
+	     * until the interrupt is connected.
+	     */
+	    uli->teardownarg1 = (__psint_t) intr;
+	    uli->teardown = pciba_clearuli;
+
+	    arg.uli.id = uli->index;
+
+	    if (!ABI_IS_64BIT(abi)) {
+		struct uliargs32 uliargs32;
+		uliargs_to_uliargs32(&arg.uli, &uliargs32);
+		arg.uli32 = uliargs32;
+	    }
+
+	    err = 0;
+	    break;
+#endif
+
+	case PCIBA_SPACE_UDMA:		/* the "dma" vertex */
+
+	    switch (cmd) {
+
+	    case PCIIOCDMAALLOC:
+		/* PCIIOCDMAALLOC: allocate a chunk of physical
+		 * memory and set it up for DMA. Return the
+		 * PCI address that gets to it.
+		 * NOTE: this allocates memory local to the
+		 * CPU doing the ioctl, not local to the
+		 * device that will be doing the DMA.
+		 */
+
+		if (!_CAP_ABLE(CAP_DEVICE_MGT)) {
+		    err = EPERM;
+		    break;
+		}
+		/* separate the halves of the incoming parameter */
+		flags = arg.ud >> 32;
+		bytes = arg.ud & 0xFFFFFFFF;
+
+#if DEBUG_PCIBA
+		printf("pciba: user wants 0x%x bytes of DMA, flags 0x%x\n",
+		       bytes, flags);
+#endif
+
+		/* round up the requested size to the next highest page */
+		pages = (bytes + NBPP - 1) / NBPP;
+
+		/* make sure the requested size is something reasonable */
+		if (pages > pci_user_dma_max_pages) {
+#if DEBUG_PCIBA
+		    printf("pciba: request for too much buffer space\n");
+#endif
+		    err = EINVAL;
+		    break;		/* "request for too much buffer space" */
+		}
+		/* "correct" number of bytes */
+		bytes = pages * NBPP;
+
+		/* allocate the space */
+		/* XXX- force to same node as the device? */
+		/* XXX- someday, we want to handle user buffers,
+		 *    and noncontiguous pages, but this will
+		 *      require either fancy mapping or handing
+		 *      a list of blocks back to the user. For
+		 *      now, just tell users to allocate a lot of
+		 *      individual single-pages and manage their
+		 *      scatter-gather manually.
+		 */
+		kaddr = kvpalloc(pages, VM_DIRECT | KM_NOSLEEP, 0);
+		if (kaddr == 0) {
+#if DEBUG_PCIBA
+		    printf("pciba: unable to get %d contiguous pages\n", pages);
+#endif
+		    err = EAGAIN;	/* "insufficient resources, try again later" */
+		    break;
+		}
+#if DEBUG_PCIBA
+		printf("pciba: kaddr is 0x%x\n", kaddr);
+#endif
+		paddr = kvtophys(kaddr);
+
+		daddr = pciio_dmatrans_addr
+		    (soft->comm->conn, 0, paddr, bytes, flags);
+		if (daddr == 0) {	/* "no direct path available" */
+#if DEBUG_PCIBA
+		    printf("pciba: dmatrans failed, trying dmamap\n");
+#endif
+		    dmamap = pciio_dmamap_alloc
+			(soft->comm->conn, 0, bytes, flags);
+		    if (dmamap == 0) {
+#if DEBUG_PCIBA
+			printf("pciba: unable to allocate dmamap\n");
+#endif
+			err = ENOMEM;
+			break;		/* "out of mapping resources" */
+		    }
+		    daddr = pciio_dmamap_addr
+			(dmamap, paddr, bytes);
+		    if (daddr == 0) {
+#if DEBUG_PCIBA
+			printf("pciba: dmamap_addr failed\n");
+#endif
+			err = EINVAL;
+			break;		/* "can't get there from here" */
+		    }
+		}
+#if DEBUG_PCIBA
+		printf("pciba: daddr is 0x%x\n", daddr);
+#endif
+		NEW(dmap);
+		if (!dmap) {
+		    err = ENOMEM;
+		    break;		/* "no memory available" */
+		}
+		dmap->bytes = bytes;
+		dmap->pages = pages;
+		dmap->paddr = paddr;
+		dmap->kaddr = kaddr;
+		dmap->map = dmamap;
+		dmap->daddr = daddr;
+		dmap->handle = 0;
+
+#if DEBUG_PCIBA
+		printf("pciba: dmap 0x%x contains va 0x%x bytes 0x%x pa 0x%x pages 0x%x daddr 0x%x\n",
+		       dmap, kaddr, bytes, paddr, pages, daddr);
+#endif
+
+		arg.ud = dmap->daddr;
+
+		err = 0;
+		break;
+
+	    case PCIIOCDMAFREE:
+		/* PCIIOCDMAFREE: Find the chunk of
+		 * User DMA memory, and release its
+		 * resources back to the system.
+		 */
+
+		if (!_CAP_ABLE(CAP_DEVICE_MGT)) {
+		    err = EPERM;	/* "you can't do that" */
+		    break;
+		}
+		if (soft->comm->dmap == NULL) {
+		    err = EINVAL;	/* "no User DMA to free" */
+		    break;
+		}
+		/* find the request. */
+		daddr = arg.ud;
+		err = EINVAL;		/* "block not found" */
+		pciba_soft_lock(soft);
+		for (dmah = &soft->comm->dmap; dmap = *dmah; dmah = &dmap->next) {
+		    if (dmap->daddr == daddr) {
+			if (dmap->handle != 0) {
+			    dmap = 0;	/* don't DEL this dmap! */
+			    err = EINVAL;	/* "please unmap first" */
+			    break;		/* break outa for loop. */
+			}
+			*dmah = dmap->next;
+
+			if (dmamap = dmap->map) {
+			    pciio_dmamap_free(dmamap);
+			    dmamap = 0;	/* don't free it twice! */
+			}
+			kvpfree(dmap->kaddr, dmap->bytes / NBPP);
+			DEL(dmap);
+			dmap = 0;	/* don't link this back into the list! */
+			err = 0;	/* "all done" */
+			break;		/* break outa for loop. */
+		    }
+		}
+		pciba_soft_unlock(soft);
+		break;		/* break outa case PCIIOCDMAFREE: */
+	    }
+	    break;		/* break outa case PCIBA_SPACE_UDMA: */
+
+	case PCIIO_SPACE_CFG:
+
+	    /* PCIIOCCFG{RD,WR}: read and/or write
+	     * PCI configuration space. If both,
+	     * the read happens first (this becomes
+	     * a swap operation, atomic with respect
+	     * to other updates through this path).
+	     *
+	     * Should be *last* IOCTl command checked,
+	     * so other patterns can nip useless codes
+	     * out of the space this decodes.
+	     */
+	    err = EINVAL;
+	    if ((psize > 0) || (psize <= 8) &&
+		(((cmd & 0xFF) + psize) <= 256) &&
+		(cmd & (IOC_IN | IOC_OUT))) {
+
+		uint64_t                rdata;
+		uint64_t                wdata;
+		int                     shft;
+
+		shft = 64 - (8 * psize);
+
+		wdata = arg.ud >> shft;
+
+		pciba_soft_lock(soft);
+
+		if (cmd & IOC_OUT)
+		    rdata = pciio_config_get(soft->comm->conn, cmd & 0xFFFF, psize);
+		if (cmd & IOC_IN)
+		    pciio_config_set(soft->comm->conn, cmd & 0xFFFF, psize, wdata);
+
+		pciba_soft_unlock(soft);
+
+		arg.ud = rdata << shft;
+		err = 0;
+		break;
+	    }
+	    break;
+	}
+    }
+    /* done: come here if all went OK.
+     */
+    if ((err == 0) &&
+	((cmd & IOC_OUT) && (psize > 0)) &&
+	copyout(arg.data, uarg, psize))
+	err = EFAULT;
+
+    /* This gets delayed until after the copyout so we
+     * do not free the dmap on a copyout error, or
+     * alternately end up with a dangling allocated
+     * buffer that the user never got back.
+     */
+    if ((err == 0) && dmap) {
+	pciba_soft_lock(soft);
+	dmap->next = soft->comm->dmap;
+	soft->comm->dmap = dmap;
+	pciba_soft_unlock(soft);
+    }
+    if (err) {
+	/* Things went badly. Clean up.
+	 */
+#if ULI
+	if (intr) {
+	    pciio_intr_disconnect(intr);
+	    pciio_intr_free(intr);
+	}
+	if (uli)
+	    free_uli(uli);
+#endif
+	if (dmap) {
+	    if (dmap->map && (dmap->map != dmamap))
+		pciio_dmamap_free(dmap->map);
+	    DEL(dmap);
+	}
+	if (dmamap)
+	    pciio_dmamap_free(dmamap);
+	if (kaddr)
+	    kvpfree(kaddr, pages);
+    }
+    return *rvalp = err;
+}
+
+/* ================================================================
+ *            mapping support
+ */
+
+/*ARGSUSED */
+int
+pciba_map(dev_t dev, vhandl_t *vt,
+	  off_t off, size_t len, uint32_t prot)
+{
+    devfs_handle_t          vhdl = dev_to_vhdl(dev);
+    pciba_soft_t            soft = pciba_soft_get(vhdl);
+    devfs_handle_t          conn = soft->comm->conn;
+    pciio_space_t           space = soft->space;
+    size_t                  pages = (len + NBPP - 1) / NBPP;
+    pciio_piomap_t          pciio_piomap = 0;
+    caddr_t                 kaddr;
+    pciba_map_t             map;
+    pciba_dma_t             dmap;
+
+#if DEBUG_PCIBA
+    printf("pciba_map(%V,vt=0x%x)\n", dev, vt);
+#endif
+
+    if (space == PCIBA_SPACE_UDMA) {
+	pciba_soft_lock(soft);
+
+	for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) {
+	    if (off == dmap->daddr) {
+		if (pages != dmap->pages) {
+		    pciba_soft_unlock(soft);
+		    return EINVAL;	/* "size mismatch" */
+		}
+		v_mapphys(vt, dmap->kaddr, dmap->bytes);
+		dmap->handle = v_gethandle(vt);
+		pciba_soft_unlock(soft);
+#if DEBUG_PCIBA
+		printf("pciba: mapped dma at kaddr 0x%x via handle 0x%x\n",
+		       dmap->kaddr, dmap->handle);
+#endif
+		return 0;
+	    }
+	}
+	pciba_soft_unlock(soft);
+	return EINVAL;			/* "block not found" */
+    }
+    if (soft->iomem == PCIIO_SPACE_NONE)
+	return EINVAL;			/* "mmap not supported" */
+
+    kaddr = (caddr_t) pciio_pio_addr
+	(conn, 0, space, off, len, &pciio_piomap, soft->flags | PCIIO_FIXED );
+
+#if DEBUG_PCIBA
+    printf("pciba: mapped %R[0x%x..0x%x] via map 0x%x to kaddr 0x%x\n",
+	   space, space_desc, off, off + len - 1, pciio_piomap, kaddr);
+#endif
+
+    if (kaddr == NULL)
+	return EINVAL;			/* "you can't get there from here" */
+
+    NEW(map);
+    if (map == NULL) {
+	if (pciio_piomap)
+	    pciio_piomap_free(pciio_piomap);
+	return ENOMEM;			/* "unable to get memory resources */
+    }
+#ifdef LATER
+    map->uthread = curuthread;
+#endif
+    map->handle = v_gethandle(vt);
+    map->uvaddr = v_getaddr(vt);
+    map->map = pciio_piomap;
+    map->space = soft->iomem;
+    map->base = soft->base + off;
+    map->size = len;
+    pciba_map_push(soft->comm->bus, map);
+
+    /* Inform the system of the correct
+     * kvaddr corresponding to the thing
+     * that is being mapped.
+     */
+    v_mapphys(vt, kaddr, len);
+
+    return 0;
+}
+
+/*ARGSUSED */
+int
+pciba_unmap(dev_t dev, vhandl_t *vt)
+{
+    devfs_handle_t         vhdl = dev_to_vhdl(dev);
+    pciba_soft_t            soft = pciba_soft_get(vhdl);
+    pciba_bus_t             bus = soft->comm->bus;
+    pciba_map_t             map;
+    __psunsigned_t          handle = v_gethandle(vt);
+
+#if DEBUG_PCIBA
+    printf("pciba_unmap(%V,vt=%x)\n", dev, vt);
+#endif
+
+    /* If this is a userDMA buffer,
+     * make a note that it has been unmapped
+     * so it can be released.
+     */
+    if (soft->comm->dmap) {
+	pciba_dma_t             dmap;
+
+	pciba_soft_lock(soft);
+	for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next)
+	    if (handle == dmap->handle) {
+		dmap->handle = 0;
+		pciba_soft_unlock(soft);
+#if DEBUG_PCIBA
+		printf("pciba: unmapped dma at kaddr 0x%x via handle 0x%x\n",
+		       dmap->kaddr, handle);
+#endif
+		return 0;		/* found userPCI */
+	    }
+	pciba_soft_unlock(soft);
+    }
+    map = pciba_map_pop_hdl(bus, handle);
+    if (map == NULL)
+	return EINVAL;			/* no match */
+
+    if (map->map)
+	pciio_piomap_free(map->map);
+    DEL(map);
+
+    return (0);				/* all done OK */
+}
+
+#if ULI
+void
+pciba_clearuli(struct uli *uli)
+{
+    pciio_intr_t            intr = (pciio_intr_t) uli->teardownarg1;
+
+#if DEBUG_PCIBA
+    printf("pciba_clearuli(0x%x)\n", uli);
+#endif
+
+    pciio_intr_disconnect(intr);
+    pciio_intr_free(intr);
+    atomic_dec(&pciba_prevent_unload);
+}
+
+void
+pciba_intr(intr_arg_t arg)
+{
+    struct uli             *uli = (struct uli *) arg;
+    int                     ulinum = uli->index;
+
+    extern void frs_handle_uli(void);
+
+    if (ulinum >= 0 && ulinum < MAX_ULIS) {
+	    uli_callup(ulinum);
+
+	    if (private.p_frs_flags)
+		    frs_handle_uli();
+    }
+}
+#endif
+#endif /* LATER - undef as we implement each routine */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pcibr.c linux/arch/ia64/sn/io/pcibr.c
--- v2.4.3/linux/arch/ia64/sn/io/pcibr.c	Tue Mar  6 19:44:35 2001
+++ linux/arch/ia64/sn/io/pcibr.c	Thu Apr 12 12:16:35 2001
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
@@ -22,7 +23,6 @@
 #include <asm/sn/invent.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
-#include <asm/sn/cmn_err.h>
 #include <asm/sn/xtalk/xwidget.h>
 #include <asm/sn/pci/bridge.h>
 #include <asm/sn/pci/pciio.h>
@@ -41,6 +41,14 @@
 #include <asm/sn/sn1/hubio_next.h>
 #endif
 
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
+#undef PCIBR_ATE_DEBUG
 #if defined(BRINGUP)
 #if 0
 #define DEBUG 1	 /* To avoid lots of bad printk() formats leave off */
@@ -54,6 +62,24 @@
 #define	LOCAL		static
 #endif
 
+/*
+ * Macros related to the Lucent USS 302/312 usb timeout workaround.  It
+ * appears that if the lucent part can get into a retry loop if it sees a
+ * DAC on the bus during a pio read retry.  The loop is broken after about
+ * 1ms, so we need to set up bridges holding this part to allow at least
+ * 1ms for pio.
+ */
+
+#define USS302_TIMEOUT_WAR
+
+#ifdef USS302_TIMEOUT_WAR
+#include <asm/sn/io.h>
+#define LUCENT_USBHC_VENDOR_ID_NUM	0x11c1
+#define LUCENT_USBHC302_DEVICE_ID_NUM	0x5801
+#define LUCENT_USBHC312_DEVICE_ID_NUM	0x5802
+#define USS302_BRIDGE_TIMEOUT_HLD	4
+#endif
+
 #define PCIBR_LLP_CONTROL_WAR
 #if defined (PCIBR_LLP_CONTROL_WAR)
 int                     pcibr_llp_control_war_cnt;
@@ -69,6 +95,7 @@
 
 int                     pcibr_devflag = D_MP;
 
+#ifdef LATER
 #define F(s,n)		{ 1l<<(s),-(s), n }
 
 struct reg_desc         bridge_int_status_desc[] =
@@ -246,6 +273,7 @@
     {0}
 };
 #endif
+#endif	/* LATER */
 
 /* kbrick widgetnum-to-bus layout */
 int p_busnum[MAX_PORT_NUM] = {                  /* widget#      */
@@ -275,8 +303,8 @@
  * CPU to a particular IO device are synched before the start of the next
  * set of PIO operations to the same device.
  */
-#define pcibr_lock(pcibr_soft)		io_splock(pcibr_soft->bs_lock)
-#define pcibr_unlock(pcibr_soft, s)	io_spunlock(pcibr_soft->bs_lock,s)
+#define pcibr_lock(pcibr_soft)		io_splock(&pcibr_soft->bs_lock)
+#define pcibr_unlock(pcibr_soft,s)	io_spunlock(&pcibr_soft->bs_lock,s)
 
 #if PCIBR_SOFT_LIST
 typedef struct pcibr_list_s *pcibr_list_p;
@@ -302,6 +330,31 @@
 extern int      hub_device_flags_set(devfs_handle_t       widget_dev,
                                      hub_widget_flags_t flags);
 #endif
+extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t);
+
+/*
+ * This is the file operation table for the pcibr driver.
+ * As each of the functions are implemented, put the 
+ * appropriate function name below.
+ */
+struct file_operations pcibr_fops = {
+        owner:  THIS_MODULE,
+        llseek: NULL,
+        read: NULL,
+        write: NULL,
+        readdir: NULL,
+        poll: NULL,
+        ioctl: NULL,
+        mmap: NULL,
+        open: NULL,
+        flush: NULL,
+        release: NULL,
+        fsync: NULL,
+        fasync: NULL,
+        lock: NULL,
+        readv: NULL,
+        writev: NULL
+};
 
 extern devfs_handle_t hwgraph_root;
 extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl);
@@ -317,7 +370,7 @@
 extern struct map *rmallocmap(uint64_t mapsiz);
 extern void rmfreemap(struct map *mp);
 extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr);
-extern void cmn_err_tag(int seqnumber, register int level, char *fmt, ...);
+extern int io_path_map_widget(devfs_handle_t vertex);
 
 
 
@@ -363,17 +416,13 @@
 
 void                    pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
 
-#ifndef BRINGUP
 LOCAL int               pcibr_init_ext_ate_ram(bridge_t *);
-#endif
 LOCAL int               pcibr_ate_alloc(pcibr_soft_t, int);
 LOCAL void              pcibr_ate_free(pcibr_soft_t, int, int);
 
 LOCAL pcibr_info_t      pcibr_info_get(devfs_handle_t);
 LOCAL pcibr_info_t      pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
 LOCAL void		pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
-LOCAL int		pcibr_device_attach(devfs_handle_t,pciio_slot_t);
-LOCAL int		pcibr_device_detach(devfs_handle_t,pciio_slot_t);
 LOCAL iopaddr_t         pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned);
 
 pcibr_piomap_t          pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);
@@ -411,7 +460,7 @@
 
 devfs_handle_t            pcibr_intr_cpu_get(pcibr_intr_t);
 void                    pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
-void                    pcibr_intr_list_func(intr_arg_t);
+void                    pcibr_intr_func(intr_arg_t);
 
 LOCAL void              print_bridge_errcmd(uint32_t, char *);
 
@@ -450,21 +499,32 @@
 void			pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *);
 void                    pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t);
 void                    pcibr_hints_handsoff(devfs_handle_t);
-void                    pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t);
+void                    pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong);
 
-LOCAL int		pcibr_slot_reset(devfs_handle_t,pciio_slot_t);
 LOCAL int		pcibr_slot_info_init(devfs_handle_t,pciio_slot_t);
 LOCAL int		pcibr_slot_info_free(devfs_handle_t,pciio_slot_t);
+
+#ifdef LATER
+LOCAL int	        pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t,
+                                               pcibr_slot_info_resp_t);
+LOCAL void       	pcibr_slot_func_info_return(pcibr_info_h, int,
+                                                    pcibr_slot_func_info_resp_t);
+#endif	/* LATER */
+
 LOCAL int		pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t);
 LOCAL int		pcibr_slot_device_init(devfs_handle_t, pciio_slot_t);
 LOCAL int		pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t);
 LOCAL int		pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
-LOCAL int		pcibr_slot_call_device_attach(devfs_handle_t,pciio_slot_t);
-LOCAL int		pcibr_slot_call_device_detach(devfs_handle_t,pciio_slot_t);
+LOCAL int		pcibr_slot_call_device_attach(devfs_handle_t,
+						      pciio_slot_t, int);
+LOCAL int		pcibr_slot_call_device_detach(devfs_handle_t,
+						      pciio_slot_t, int);
 
-int			pcibr_slot_powerup(devfs_handle_t,pciio_slot_t);
-int			pcibr_slot_shutdown(devfs_handle_t,pciio_slot_t);
-int			pcibr_slot_inquiry(devfs_handle_t,pciio_slot_t);		
+LOCAL int               pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int);
+LOCAL int 		pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t);
+#ifdef LATER
+LOCAL int		pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t);
+#endif
 
 /* =====================================================================
  *    RRB management
@@ -754,7 +814,7 @@
     int                     final_vchan0;
     int                     final_vchan1;
     int                     avail_rrbs;
-    unsigned                s;
+    unsigned long           s;
     int                     error;
 
     /*
@@ -930,7 +990,7 @@
     pciio_info_t            pciio_info;
     pciio_slot_t            pciio_slot;
     pcibr_soft_t            pcibr_soft;
-    unsigned                s;
+    unsigned long           s;
     int                     error = -1;
 
     if ((pciio_info = pciio_info_get(pconn_vhdl)) &&
@@ -978,11 +1038,7 @@
 		     int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4)
 {
     devfs_handle_t            pcibr_vhdl;
-#ifdef colin
-    pcibr_soft_t            pcibr_soft;
-#else
-    pcibr_soft_t	pcibr_soft = NULL;
-#endif
+    pcibr_soft_t            pcibr_soft = NULL;
     bridge_t               *bridge = NULL;
 
     uint32_t              rrb_setting = 0;
@@ -991,7 +1047,7 @@
     int                     dev_rrbs[4];
     int                     virt[4];
     int                     i, j;
-    unsigned                s;
+    unsigned long           s;
 
     if (GRAPH_SUCCESS ==
 	hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) {
@@ -1089,7 +1145,7 @@
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
-    unsigned                s;
+    unsigned long           s;
     reg_p                   rrbp;
     unsigned                rrbm;
     int                     i;
@@ -1141,7 +1197,7 @@
     bridgereg_t             badd32;
     bridgereg_t             badd64;
     bridgereg_t             fix;
-    unsigned                s;
+    unsigned long           s;
     bridgereg_t             xmask;
 
     xmask = mask;
@@ -1203,29 +1259,16 @@
     /* Generic macro flags
      */
     if (flags & PCIIO_DMA_DATA) {
-#ifdef colin
-	new = new
-	    & ~BRIDGE_DEV_BARRIER	/* barrier off */
-	    | BRIDGE_DEV_PREF;		/* prefetch on */
-#else
 	new = (new
             & ~BRIDGE_DEV_BARRIER)      /* barrier off */
             | BRIDGE_DEV_PREF;          /* prefetch on */
-#endif
 
     }
     if (flags & PCIIO_DMA_CMD) {
-#ifdef colin
-	new = new
-	    & ~BRIDGE_DEV_PREF		/* prefetch off */
-	    & ~BRIDGE_DEV_WRGA_BITS	/* write gather off */
-	    | BRIDGE_DEV_BARRIER;	/* barrier on */
-#else
         new = ((new
             & ~BRIDGE_DEV_PREF)         /* prefetch off */
             & ~BRIDGE_DEV_WRGA_BITS)    /* write gather off */
             | BRIDGE_DEV_BARRIER;       /* barrier on */
-#endif
     }
     /* Generic detail flags
      */
@@ -1297,13 +1340,8 @@
 	     * but the alternative is not allowing
 	     * the new stream at all.
 	     */
-#ifdef colin
-	    if (fix = bad & (BRIDGE_DEV_PRECISE |
-			     BRIDGE_DEV_BARRIER)) {
-#else
             if ( (fix = bad & (BRIDGE_DEV_PRECISE |
                              BRIDGE_DEV_BARRIER)) ){
-#endif
 		bad &= ~fix;
 		/* don't change these bits if
 		 * they are already set in "old"
@@ -1317,13 +1355,8 @@
 	     * but the alternative is not allowing
 	     * the new stream at all.
 	     */
-#ifdef colin
-	    if (fix = bad & (BRIDGE_DEV_WRGA_BITS |
-			     BRIDGE_DEV_PREF)) {
-#else
 	    if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS |
-			     BRIDGE_DEV_PREF)) ){
-#endif
+			     BRIDGE_DEV_PREF)) ) {
 		bad &= ~fix;
 		/* don't change these bits if
 		 * we wanted to turn them on.
@@ -1379,7 +1412,7 @@
 		     bridgereg_t mask)
 {
     pcibr_soft_slot_t       slotp;
-    unsigned                s;
+    unsigned long           s;
 
     slotp = &pcibr_soft->bs_slot[slot];
 
@@ -1403,7 +1436,7 @@
               pciio_slot_t slot)
 {
     bridge_t               *bridge;
-    unsigned                s;
+    unsigned long          s;
     volatile uint32_t     wrf;
     s = pcibr_lock(pcibr_soft);
     bridge = pcibr_soft->bs_base;
@@ -1429,14 +1462,14 @@
 {
     int                     rv;
     bridgereg_t             old_enable, new_enable;
+    int badaddr_val(volatile void *, int, volatile void *);
+
 
     old_enable = bridge->b_int_enable;
     new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
 
     bridge->b_int_enable = new_enable;
 
-#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-#if defined(BRINGUP)
 	/*
 	 * The xbridge doesn't clear b_err_int_view unless
 	 * multi-err is cleared...
@@ -1445,8 +1478,6 @@
 	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
 	    }
-#endif	/* BRINGUP */
-#endif	/* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */
 
     if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
 	bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
@@ -1454,8 +1485,6 @@
     }
     rv = badaddr_val((void *) cfg, 4, valp);
 
-#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-#if defined(BRINGUP)
 	/*
 	 * The xbridge doesn't set master timeout in b_int_status
 	 * here.  Fortunately it's in error_interrupt_view.
@@ -1465,8 +1494,6 @@
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
 		rv = 1;		/* unoccupied slot */
 	    }
-#endif	/* BRINGUP */
-#endif /* CONFIG_SGI_IP35 */
 
     bridge->b_int_enable = old_enable;
     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
@@ -1514,10 +1541,6 @@
 int
 pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
 {
-#ifndef CONFIG_IA64_SGI_IO
-    if (!_CAP_CRABLE((uint64_t)credp, (uint64_t)CAP_DEVICE_MGT))
-	return EPERM;
-#endif
     return 0;
 }
 
@@ -1630,42 +1653,10 @@
 
     return slot;
 }
+
 /*==========================================================================
  *	BRIDGE PCI SLOT RELATED IOCTLs
  */
-/*
- * pcibr_slot_powerup
- *	Software initialize the pci slot.
- */
-int
-pcibr_slot_powerup(devfs_handle_t pcibr_vhdl,pciio_slot_t slot)
-{
-    /* Check for the valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
-	return(EINVAL);
-
-    if (pcibr_device_attach(pcibr_vhdl,slot))
-	return(EINVAL);
-
-    return(0);
-}
-/*
- * pcibr_slot_shutdown
- *	Software shutdown the pci slot
- */
-int
-pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl,pciio_slot_t slot)
-{
-    /* Check for valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
-	return(EINVAL);
-
-    if (pcibr_device_detach(pcibr_vhdl,slot))
-	return(EINVAL);
-
-    return(0);
-}
-
 char *pci_space_name[] = {"NONE", 
 			  "ROM",
 			  "IO",
@@ -1683,177 +1674,163 @@
 			  "",
 			  "BAD"};
 
+
+#ifdef LATER
+
 void
-pcibr_slot_func_info_print(pcibr_info_h pcibr_infoh, int func, int verbose)
+pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh,
+                            int func,
+                            pcibr_slot_func_info_resp_t funcp)
 {
-    pcibr_info_t	pcibr_info = pcibr_infoh[func];
-    char		name[MAXDEVNAME];
-    int			win;
-    
-    if (!pcibr_info)
-	return;
+    pcibr_info_t                 pcibr_info = pcibr_infoh[func];
+    int                          win;
 
+    funcp->resp_f_status = 0;
+
+    if (!pcibr_info) {
+        return;
+    }
+
+    funcp->resp_f_status |= FUNC_IS_VALID;
 #ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(name, "%v", pcibr_info->f_vertex);
-#endif
-    if (!verbose) {
-	printk("\tSlot Name : %s\n",name);
-    } else {
-	printk("\tPER-SLOT FUNCTION INFO\n");
-#ifdef SUPPORT_PRINTING_V_FORMAT
-	sprintf(name, "%v", pcibr_info->f_vertex);
+    sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
+#else
+    sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex);
 #endif
-	printk("\tSlot Name : %s\n",name);
-	printk("\tPCI Bus : %d ",pcibr_info->f_bus);
-	printk("Slot : %d ", pcibr_info->f_slot);
-	printk("Function : %d\n", pcibr_info->f_func);
+
+    if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
+        funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
+    }
+
+    funcp->resp_f_bus = pcibr_info->f_bus;
+    funcp->resp_f_slot = pcibr_info->f_slot;
+    funcp->resp_f_func = pcibr_info->f_func;
 #ifdef SUPPORT_PRINTING_V_FORMAT
-	sprintf(name, "%v", pcibr_info->f_master);
+    sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
+#else
+    sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master);
 #endif
-	printk("\tBus provider : %s\n",name);
-	printk("\tProvider Fns : 0x%p ", pcibr_info->f_pops);
-	printk("Error Handler : 0x%p Arg 0x%p\n", 
-		pcibr_info->f_efunc,pcibr_info->f_einfo);
+    funcp->resp_f_pops = pcibr_info->f_pops;
+    funcp->resp_f_efunc = pcibr_info->f_efunc;
+    funcp->resp_f_einfo = pcibr_info->f_einfo;
+
+    funcp->resp_f_vendor = pcibr_info->f_vendor;
+    funcp->resp_f_device = pcibr_info->f_device;
+
+    for(win = 0 ; win < 6 ; win++) {
+        funcp->resp_f_window[win].resp_w_base =
+                                  pcibr_info->f_window[win].w_base;
+        funcp->resp_f_window[win].resp_w_size =
+                                  pcibr_info->f_window[win].w_size;
+        sprintf(funcp->resp_f_window[win].resp_w_space,
+                "%s",
+                pci_space_name[pcibr_info->f_window[win].w_space]);
     }
-    printk("\tVendorId : 0x%x " , pcibr_info->f_vendor);
-    printk("DeviceId : 0x%x\n", pcibr_info->f_device);
 
-    printk("\n\tBase Register Info\n");
-    printk("\t\tReg#\tBase\t\tSize\t\tSpace\n");
-    for(win = 0 ; win < 6 ; win++) 
-	printk("\t\t%d\t0x%lx\t%s0x%lx\t%s%s\n",
-		win,
-		pcibr_info->f_window[win].w_base,
-		pcibr_info->f_window[win].w_base >= 0x100000 ? "": "\t",
-		pcibr_info->f_window[win].w_size,
-		pcibr_info->f_window[win].w_size >= 0x100000 ? "": "\t",
-		pci_space_name[pcibr_info->f_window[win].w_space]);
-
-    printk("\t\t7\t0x%x\t%s0x%x\t%sROM\n", 
-	    pcibr_info->f_rbase,
-	    pcibr_info->f_rbase > 0x100000 ? "" : "\t",
-	    pcibr_info->f_rsize,
-	    pcibr_info->f_rsize > 0x100000 ? "" : "\t");
+    funcp->resp_f_rbase = pcibr_info->f_rbase;
+    funcp->resp_f_rsize = pcibr_info->f_rsize;
 
-    printk("\n\tInterrupt Bit Map\n");
-    printk("\t\tPCI Int#\tBridge Pin#\n");
-    for (win = 0 ; win < 4; win++)
-	printk("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]);
-    printk("\n");
-}
+    for (win = 0 ; win < 4; win++) {
+        funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win];
+    }
 
+    funcp->resp_f_att_det_error = pcibr_info->f_att_det_error;
 
-void
-pcibr_slot_info_print(pcibr_soft_t 	pcibr_soft, 
-		      pciio_slot_t 	slot, 
-		      int	   	verbose)
-{
-    pcibr_soft_slot_t	pss;
-    char		slot_conn_name[MAXDEVNAME];
-    int			func;
-    bridge_t		*bridge = pcibr_soft->bs_base;
-    bridgereg_t		b_resp;
-    reg_p		b_respp;
-    int			dev;
-    bridgereg_t		b_int_device;
-    bridgereg_t		b_int_host;
-    bridgereg_t		b_int_enable;
-    int			pin = 0;
-    int			int_bits = 0;
+}
+
+int
+pcibr_slot_info_return(pcibr_soft_t             pcibr_soft,
+                       pciio_slot_t             slot,
+                       pcibr_slot_info_resp_t   respp)
+{
+    pcibr_soft_slot_t            pss;
+    int                          func;
+    bridge_t                    *bridge = pcibr_soft->bs_base;
+    reg_p                        b_respp;
+    pcibr_slot_info_resp_t       slotp;
+    pcibr_slot_func_info_resp_t  funcp;
+
+    slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP);
+    if (slotp == NULL) {
+        return(ENOMEM);
+    }
 
     pss = &pcibr_soft->bs_slot[slot];
     
     printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot);
 
-    if (verbose) {
-	printk("\tHost Present ? %s ", pss->has_host ? "yes" : "no");
-	printk("\tHost Slot : %d\n",pss->host_slot);
+    slotp->resp_has_host = pss->has_host;
+    slotp->resp_host_slot = pss->host_slot;
 #ifdef SUPPORT_PRINTING_V_FORMAT
-	sprintf(slot_conn_name, "%v", pss->slot_conn);
+    sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
+#else
+    sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn);
 #endif
-	printk("\tSlot Conn : %s\n",slot_conn_name);	
-	printk("\t#Functions : %d\n",pss->bss_ninfo);
+    slotp->resp_slot_status = pss->slot_status;
+    slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
+
+    if (is_sys_critical_vertex(pss->slot_conn)) {
+        slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
     }
-    for (func = 0; func < pss->bss_ninfo; func++)
-	pcibr_slot_func_info_print(pss->bss_infos,func, verbose);
-    printk("\tDevio[Space:%s,Base:0x%lx,Shadow:0x%x]\n",
-	    pci_space_name[pss->bss_devio.bssd_space],
-	    pss->bss_devio.bssd_base,
-	    pss->bss_device);
-
-    if (verbose) {
-	printk("\tUsage counts : pmu %d d32 %d d64 %d\n",
-		pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr);
-    
-	printk("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x"
-		"d32_base 0x%x d32_flags 0x%x\n",
-		(unsigned int)pss->bss_d64_base, pss->bss_d64_flags,
-		(unsigned int)pss->bss_d32_base, pss->bss_d32_flags);
-    
-	printk("\tExt ATEs active ? %s", 
-		pss->bss_ext_ates_active ? "yes" : "no");
-	printk(" Command register : 0x%p ", pss->bss_cmd_pointer);
-	printk(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow);
+
+    slotp->resp_bss_ninfo = pss->bss_ninfo;
+
+    for (func = 0; func < pss->bss_ninfo; func++) {
+        funcp = &(slotp->resp_func[func]);
+        pcibr_slot_func_info_return(pss->bss_infos, func, funcp);
     }
 
-    printk("\tSoft RRB Info[Valid %d+%d, Reserved %d]\n",
-	    pcibr_soft->bs_rrb_valid[slot],
-	    pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-	    pcibr_soft->bs_rrb_res[slot]);
+    sprintf(slotp->resp_bss_devio_bssd_space, "%s",
+            pci_space_name[pss->bss_devio.bssd_space]);
+    slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base;
+    slotp->resp_bss_device = pss->bss_device;
 
+    slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr;
+    slotp->resp_bss_d32_uctr = pss->bss_d32_uctr;
+    slotp->resp_bss_d64_uctr = pss->bss_d64_uctr;
 
-    if (slot & 1)
-	b_respp = &bridge->b_odd_resp;
-    else
-	b_respp = &bridge->b_even_resp;
+    slotp->resp_bss_d64_base = pss->bss_d64_base;
+    slotp->resp_bss_d64_flags = pss->bss_d64_flags;
+    slotp->resp_bss_d32_base = pss->bss_d32_base;
+    slotp->resp_bss_d32_flags = pss->bss_d32_flags;
 
-    b_resp = *b_respp;
+    slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active);
 
-    printk("\n\tBridge RRB Info\n");
-    printk("\t\tRRB#\tVirtual\n");
-    for (dev = 0; dev < 8; dev++) {
-	if ((b_resp & BRIDGE_RRB_EN) &&
-	    (b_resp & BRIDGE_RRB_PDEV) == (slot >> 1))
-	    printk( "\t\t%d\t%s\n", 
-		    dev,
-		    (b_resp & BRIDGE_RRB_VDEV) ? "yes" : "no");
-	b_resp >>= 4;
-	    
-    }
-    b_int_device = bridge->b_int_device;
-    b_int_enable = bridge->b_int_enable;
+    slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
+    slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
 
-    printk("\n\tBridge Interrupt Info\n"
-	    "\t\tInt_device 0x%x\n\t\tInt_enable 0x%x "
-	    "\n\t\tEnabled pin#s for this slot: ",
-	    b_int_device,
-	    b_int_enable);
+    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
+    slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
+                                                      PCIBR_RRB_SLOT_VIRTUAL];
+    slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
 
-    while (b_int_device) {
-	if (((b_int_device & 7) == slot) &&
-	    (b_int_enable & (1 << pin))) {
-	    int_bits |= (1 << pin);
-	    printk("%d ", pin); 
-	}
-	pin++;
-	b_int_device >>= 3;
+    if (slot & 1) {
+        b_respp = &bridge->b_odd_resp;
+    } else {
+        b_respp = &bridge->b_even_resp;
     }
 
-    if (!int_bits)
-	printk("NONE ");
+    slotp->resp_b_resp = *b_respp;
 
-    b_int_host = bridge->b_int_addr[slot].addr;
+    slotp->resp_b_int_device = bridge->b_int_device;
+    slotp->resp_b_int_enable = bridge->b_int_enable;
+    slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
 
-    printk("\n\t\tInt_host_addr 0x%x\n",
-	    b_int_host);
-    
+    if (COPYOUT(slotp, respp, sizeof(*respp))) {
+        return(EFAULT);
+    }
+
+    kmem_free(slotp, sizeof(*slotp));
+
+    return(0);
 }
 
-int verbose = 0;
 /*
- * pcibr_slot_inquiry
- *	Print information about the pci slot maintained by the infrastructure.
- *	Current information displayed
+ * pcibr_slot_query
+ *	Return information about the PCI slot maintained by the infrastructure.
+ *	Information is requested in the request structure.
+ *
+ *      Information returned in the response structure:
  *		Slot hwgraph name
  *		Vendor/Device info
  *		Base register info
@@ -1861,7 +1838,6 @@
  *		Devio register
  *		Software RRB info
  *		RRB register info
- *	In verbose mode following additional info is displayed
  *		Host/Gues info
  *		PCI Bus #,slot #, function #
  *		Slot provider hwgraph name
@@ -1872,28 +1848,76 @@
  *		External SSRAM workaround info
  */
 int
-pcibr_slot_inquiry(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
+pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp)
 {
-    pcibr_soft_t	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+    pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+    pciio_slot_t            slot = reqp->req_slot;
+    pciio_slot_t            tmp_slot;
+    pcibr_slot_info_resp_t  respp = (pcibr_slot_info_resp_t) reqp->req_respp;
+    int                     size = reqp->req_size;
+    int                     error;
 
     /* Make sure that we are dealing with a bridge device vertex */
-    if (!pcibr_soft)
-	return(EINVAL);
+    if (!pcibr_soft) {
+        return(EINVAL);
+    }
 
-    /* Make sure that we have a valid pci slot number or PCIIO_SLOT_NONE */
-    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE))
-	return(EINVAL);
+    /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
+    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
+        return(EINVAL);
+    }
 
-    /* Print information for the requested pci slot */
+#ifdef LATER
+    /* Do not allow a query of a slot in a shoehorn */
+    if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
+       return(EPERM);
+    }
+#endif
+
+    /* Return information for the requested PCI slot */
     if (slot != PCIIO_SLOT_NONE) {
-	pcibr_slot_info_print(pcibr_soft,slot,verbose);
-	return(0);
+        if (size < sizeof(*respp)) {
+            return(EINVAL);
+        }
+
+        /* Acquire read access to the slot */
+        mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO);
+
+        error = pcibr_slot_info_return(pcibr_soft, slot, respp);
+
+        /* Release the slot lock */
+        mrunlock(pcibr_soft->bs_slot[slot].slot_lock);
+
+        return(error);
     }
-    /* Print information for all the slots */
-    for (slot = 0; slot < 8; slot++)
-	pcibr_slot_info_print(pcibr_soft, slot,verbose);
-    return(0);
+
+    /* Return information for all the slots */
+    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
+
+        if (size < sizeof(*respp)) {
+            return(EINVAL);
+        }
+
+        /* Acquire read access to the slot */
+        mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO);
+
+        error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
+
+        /* Release the slot lock */
+        mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock);
+
+        if (error) {
+            return(error);
+        }
+
+        ++respp;
+        size -= sizeof(*respp);
+    }
+
+    return(error);
 }
+#endif	/* LATER */
+
 
 /*ARGSUSED */
 int
@@ -1905,7 +1929,7 @@
 	    int *rvalp)
 {
     devfs_handle_t            pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev);
-#ifdef colin
+#ifdef LATER
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 #endif
     int                     error = 0;
@@ -1913,7 +1937,7 @@
     hwgraph_vertex_unref(pcibr_vhdl);
 
     switch (cmd) {
-#ifdef colin
+#ifdef LATER
     case GIOCSETBW:
 	{
 	    grio_ioctl_info_t       info;
@@ -1969,7 +1993,6 @@
 		pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW);
 	    break;
 	}
-#endif /* colin */
 
     case PCIBR_SLOT_POWERUP:
 	{
@@ -1985,31 +2008,33 @@
 	    break;
 	}
     case PCIBR_SLOT_SHUTDOWN:
-	{
-	    pciio_slot_t	slot;
-
 	    if (!cap_able(CAP_DEVICE_MGT)) {
 		error = EPERM;
 		break;
 	    }
 
 	    slot = (pciio_slot_t)(uint64_t)arg;
-	    error = pcibr_slot_shutdown(pcibr_vhdl,slot);
+	    error = pcibr_slot_powerup(pcibr_vhdl,slot);
 	    break;
 	}
-    case PCIBR_SLOT_INQUIRY:
+    case PCIBR_SLOT_QUERY:
 	{
-	    pciio_slot_t	slot;
+	    struct pcibr_slot_info_req_s        req;
 
 	    if (!cap_able(CAP_DEVICE_MGT)) {
 		error = EPERM;
 		break;
 	    }
 
-	    slot = (pciio_slot_t)(uint64_t)arg;
-	    error = pcibr_slot_inquiry(pcibr_vhdl,slot);
+            if (COPYIN(arg, &req, sizeof(req))) {
+                error = EFAULT;
+                break;
+            }
+
+            error = pcibr_slot_query(pcibr_vhdl, &req);
 	    break;
 	}
+#endif	/* LATER */
     default:
 	break;
 
@@ -2055,7 +2080,6 @@
 	*free_basep = last + 1;		/* keep upper chunk */
 }
 
-#ifdef IRIX
 /* Convert from ssram_bits in control register to number of SSRAM entries */
 #define ATE_NUM_ENTRIES(n) _ate_info[n]
 
@@ -2070,14 +2094,12 @@
 
 #define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int))
 #define ATE_PROBE_VALUE 0x0123456789abcdefULL
-#endif	/* IRIX */
 
 /*
  * Determine the size of this bridge's external mapping SSRAM, and set
  * the control register appropriately to reflect this size, and initialize
  * the external SSRAM.
  */
-#ifndef BRINGUP
 LOCAL int
 pcibr_init_ext_ate_ram(bridge_t *bridge)
 {
@@ -2087,9 +2109,6 @@
     bridgereg_t             old_enable, new_enable;
     int                     s;
 
-    if (is_xbridge(bridge))
-	return 0;
-
     /* Probe SSRAM to determine its size. */
     old_enable = bridge->b_int_enable;
     new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
@@ -2116,11 +2135,9 @@
      */
 
     s = splhi();
-#ifdef colin
     bridge->b_wid_control = (bridge->b_wid_control
 	& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
 	| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
-#endif
     bridge->b_wid_control;		/* inval addr bug war */
     splx(s);
 
@@ -2139,7 +2156,6 @@
 
     return (num_entries);
 }
-#endif	/* !BRINGUP */
 
 /*
  * Allocate "count" contiguous Bridge Address Translation Entries
@@ -2155,6 +2171,7 @@
     int                     index = 0;
 
     index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count);
+/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */
 
     if (!index && pcibr_soft->bs_ext_ate_map)
 	index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count);
@@ -2174,6 +2191,8 @@
     /* note the "+1" since rmalloc handles 1..n but
      * we start counting ATEs at zero.
      */
+/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */
+
     rmfree((index < pcibr_soft->bs_int_ate_size)
 	   ? pcibr_soft->bs_int_ate_map
 	   : pcibr_soft->bs_ext_ate_map,
@@ -2233,8 +2252,6 @@
 	/*
 	 * Record the info in the sparse func info space.
 	 */
-printk("pcibr_device_info_new: slot= %d  func= %d  bss_ninfo= %d  pcibr_info= 0x%p\n", slot, func, pcibr_soft->bs_slot[slot].bss_ninfo, pcibr_info);
-
 	if (func < pcibr_soft->bs_slot[slot].bss_ninfo)
 	    pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info;
     }
@@ -2281,7 +2298,7 @@
     slotp->bss_d32_flags = 0;
 
     /* Clear out shadow info necessary for the external SSRAM workaround */
-    slotp->bss_ext_ates_active = 0;
+    slotp->bss_ext_ates_active = ATOMIC_INIT(0);
     slotp->bss_cmd_pointer = 0;
     slotp->bss_cmd_shadow = 0;
 
@@ -2336,55 +2353,10 @@
 	   pcibr_soft->bs_spinfo.pci_mem_last);
 
 /*
- * pcibr_slot_reset
- *	Reset the pci device in the particular slot .
- */
-int
-pcibr_slot_reset(devfs_handle_t pcibr_vhdl,pciio_slot_t slot)
-{
-	pcibr_soft_t		pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-	bridge_t		*bridge;
-	bridgereg_t		ctrlreg,tmp;
-	volatile bridgereg_t	*wrb_flush;
-
-	if (!PCIBR_VALID_SLOT(slot))
-		return(1);
-
-	if (!pcibr_soft)
-		return(1);
-
-	/* Enable the DMA operations from this device of the xtalk widget
-	 * (PCI host bridge in this case).
-	 */
-	xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot);
-	/* Set the reset slot bit in the bridge's wid control register
-	 * to reset the pci slot 
-	 */
-	bridge = pcibr_soft->bs_base;
-	/* Read the bridge widget control and clear out the reset pin
-	 * bit for the corresponding slot. 
-	 */
-	tmp = ctrlreg = bridge->b_wid_control;
-	tmp &= ~BRIDGE_CTRL_RST_PIN(slot); 
-	bridge->b_wid_control = tmp;
-	tmp = bridge->b_wid_control;
-	/* Restore the old control register back.
-	 * NOTE : pci card gets reset when the reset pin bit
-	 * changes from 0 (set above) to 1 (going to be set now).
-	 */
-	bridge->b_wid_control = ctrlreg;
-
-	/* Flush the write buffers if any !! */
-	wrb_flush = &(bridge->b_wr_req_buf[slot].reg);
-	while (*wrb_flush);
-
-	return(0);
-}
-/*
  * pcibr_slot_info_init
  *	Probe for this slot and see if it is populated.
- *	If it is populated initialize the generic pci infrastructural
- * 	information associated with this particular pci device.
+ *	If it is populated initialize the generic PCI infrastructural
+ * 	information associated with this particular PCI device.
  */
 int
 pcibr_slot_info_init(devfs_handle_t 	pcibr_vhdl,
@@ -2401,6 +2373,9 @@
     pciio_vendor_id_t       vendor;
     pciio_device_id_t       device;
     unsigned                htype;
+#if !defined(CONFIG_IA64_SGI_SN1)
+    int			    nbars;
+#endif
     cfg_p                   wptr;
     int                     win;
     pciio_space_t           space;
@@ -2416,40 +2391,41 @@
     /* Get the basic software information required to proceed */
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     if (!pcibr_soft)
-	return(1);
+	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
     if (!PCIBR_VALID_SLOT(slot))
-	return(1);
-
-    slotp = &pcibr_soft->bs_slot[slot];
-
-    /* Load the current values of allocated pci address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
+	return(EINVAL);
 
-    /* If we have a host slot (eg:- IOC3 has 2 pci slots and the initialization
+    /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization
      * is done by the host slot then we are done.
      */
-    if (pcibr_soft->bs_slot[slot].has_host)
-	return(0);
+    if (pcibr_soft->bs_slot[slot].has_host) {
+	return(0);    
+    }
+
+    /* Check for a slot with any system critical functions */
+    if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
+        return(EPERM);
+
+    /* Load the current values of allocated PCI address spaces */
+    PCI_ADDR_SPACE_LIMITS_LOAD();
     
     /* Try to read the device-id/vendor-id from the config space */
     cfgw = bridge->b_type0_cfg_dev[slot].l;
 
-#ifdef BRINGUP
-    if (slot < 3  || slot == 7) 
-	return (0);
-    else
-#endif /* BRINGUP */
-    if (pcibr_probe_slot(bridge, cfgw, &idword))
-	return(0);
+    if (pcibr_probe_slot(bridge, cfgw, &idword)) 
+	return(ENODEV);
+
+    slotp = &pcibr_soft->bs_slot[slot];
+    slotp->slot_status |= SLOT_POWER_UP;
 
     vendor = 0xFFFF & idword;
     /* If the vendor id is not valid then the slot is not populated
      * and we are done.
      */
-    if (vendor == 0xFFFF)
-	return(0);			/* next slot */
+    if (vendor == 0xFFFF) 
+	return(ENODEV);			
     
     device = 0xFFFF & (idword >> 16);
     htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
@@ -2503,7 +2479,13 @@
 	if (htype != 0x00) {
 	    PRINT_WARNING("%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
 		    pcibr_soft->bs_name, slot, func, htype);
+#if defined(CONFIG_IA64_SGI_SN1)
 	    continue;
+#else
+	    nbars = 2;
+	} else {
+	    nbars = PCI_CFG_BASE_ADDRS;
+#endif
 	}
 #if DEBUG && ATTACH_DEBUG
 	PRINT_NOTICE( 
@@ -2516,13 +2498,17 @@
 	conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);
 	if (func == 0)
 	    slotp->slot_conn = conn_vhdl;
-	
+
 	cmd_reg = cfgw[PCI_CFG_COMMAND / 4];
 	
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-
-	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) {
+#if defined(CONFIG_IA64_SGI_SN1)
+	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win)
+#else
+	for (win = 0; win < nbars; ++win)
+#endif
+	{
 	    iopaddr_t               base, mask, code;
 	    size_t                  size;
 
@@ -2573,9 +2559,9 @@
 	    base = wptr[((win*4)^4)/4];
 #else
 	    base = wptr[win];
-#endif /* LITTLE_ENDIAN */
+#endif
 
-	    if (base & 1) {
+	    if (base & PCI_BA_IO_SPACE) {
 		/* BASE is in I/O space. */
 		space = PCIIO_SPACE_IO;
 		mask = -4;
@@ -2590,7 +2576,7 @@
 		/* BASE is in MEM space. */
 		space = PCIIO_SPACE_MEM;
 		mask = -16;
-		code = base & 15;
+		code = base & PCI_BA_MEM_LOCATION;	/* extract BAR type */
 		base = base & mask;
 		if (base == 0) {
 		    ;		/* not assigned */
@@ -2697,37 +2683,30 @@
 	}				/* next win */
     }				/* next func */
 
-    /* Store back the values for allocated pci address spaces */
+    /* Store back the values for allocated PCI address spaces */
     PCI_ADDR_SPACE_LIMITS_STORE();
     return(0);
 }					
 
 /*
  * pcibr_slot_info_free
- *	Remove all the pci infrastructural information associated
- * 	with a particular pci device.
+ *	Remove all the PCI infrastructural information associated
+ * 	with a particular PCI device.
  */
 int
-pcibr_slot_info_free(devfs_handle_t 	pcibr_vhdl,
-		     pciio_slot_t	slot)
+pcibr_slot_info_free(devfs_handle_t pcibr_vhdl,
+                     pciio_slot_t slot)
 {
     pcibr_soft_t	pcibr_soft;
     pcibr_info_h	pcibr_infoh;
     int			nfunc;
-#if defined(PCI_HOTSWAP_DEBUG)
-    cfg_p		cfgw;
-    bridge_t		*bridge;
-    int			win;
-    cfg_p		wptr;
-#endif /* PCI_HOTSWAP_DEBUG */
-
-    
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+
     if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
+	return(EINVAL);
 
-#if defined(PCI_HOTSWAP_DEBUG)
+#if !defined(CONFIG_IA64_SGI_SN1)
     /* Clean out all the base registers */
     bridge = pcibr_soft->bs_base;
     cfgw = bridge->b_type0_cfg_dev[slot].l;
@@ -2739,7 +2718,7 @@
 #else
 	wptr[win] = 0;
 #endif  /* LITTLE_ENDIAN */
-#endif /* PCI_HOTSWAP_DEBUG */
+#endif	/* !CONFIG_IA64_SGI_SN1 */
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
 
@@ -2750,13 +2729,12 @@
     pcibr_soft->bs_slot[slot].bss_ninfo = 0;
 
     return(0);
-    
-
 }
+
 int as_debug = 0;
 /*
  * pcibr_slot_addr_space_init
- *	Reserve chunks of pci address space as required by 
+ *	Reserve chunks of PCI address space as required by 
  * 	the base registers in the card.
  */
 int
@@ -2772,38 +2750,40 @@
     iopaddr_t		pci_hi_fb, pci_hi_fl;
     size_t              align;
     iopaddr_t           mask;
+    int		    	nbars;
     int		       	nfunc;
     int			func;
     int			win;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+
     if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
+	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
 
-    /* Get the current values for the allocated pci address spaces */
+    /* Get the current values for the allocated PCI address spaces */
     PCI_ADDR_SPACE_LIMITS_LOAD();
 
     if (as_debug)
-#ifdef colin
+#ifdef LATER
     PCI_ADDR_SPACE_LIMITS_PRINT();
 #endif
     /* allocate address space,
      * for windows that have not been
      * previously assigned.
      */
-
-    if (pcibr_soft->bs_slot[slot].has_host)
+    if (pcibr_soft->bs_slot[slot].has_host) {
 	return(0);
+    }
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     if (nfunc < 1)
-	return(0);
+	return(EINVAL);
 
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
     if (!pcibr_infoh)
-	return(0);
+	return(EINVAL);
 
     /*
      * Try to make the DevIO windows not
@@ -2842,7 +2822,16 @@
 	cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) {
+#if defined(CONFIG_IA64_SGI_SN1)
+	nbars = PCI_CFG_BASE_ADDRS;
+#else
+	if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0)
+	    nbars = 2;
+	else
+	    nbars = PCI_CFG_BASE_ADDRS;
+#endif
+
+	for (win = 0; win < nbars; ++win) {
 
 	    space = pcibr_info->f_window[win].w_space;
 	    base = pcibr_info->f_window[win].w_base;
@@ -2908,7 +2897,9 @@
 	    pcibr_info->f_window[win].w_base = base;
 #ifdef LITTLE_ENDIAN
 	    wptr[((win*4)^4)/4] = base;
+#if DEBUG && PCI_DEBUG
 		printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base);
+#endif
 #else
 	    wptr[win] = base;
 #endif  /* LITTLE_ENDIAN */
@@ -2976,7 +2967,22 @@
 	 * be sure are set.
 	 */
 	pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE;
-	pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE;
+
+	/*
+	 * The Adaptec 1160 FC Controller WAR #767995:
+	 * The part incorrectly ignores the upper 32 bits of a 64 bit
+	 * address when decoding references to it's registers so to
+	 * keep it from responding to a bus cycle that it shouldn't
+	 * we only use I/O space to get at it's registers.  Don't
+	 * enable memory space accesses on that PCI device.
+	 */
+	#define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */
+	#define FCADP_DEVID 0x1160  /* Adaptec 1160 Device ID from fcadp.h */
+
+	if ((pcibr_info->f_vendor != FCADP_VENDID) ||
+	    (pcibr_info->f_device != FCADP_DEVID))
+	    pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE;
+
 	pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER;
 
 	pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4;
@@ -2991,28 +2997,30 @@
 	
     }				/* next func */
 
-    /* Now that we have allocated new chunks of pci address spaces to this
+    /* Now that we have allocated new chunks of PCI address spaces to this
      * card we need to update the bookkeeping values which indicate
-     * the current pci address space allocations.
+     * the current PCI address space allocations.
      */
     PCI_ADDR_SPACE_LIMITS_STORE();
     return(0);
 }
+
 /*
  * pcibr_slot_device_init
- * 	Setup the device register in the bridge for this pci slot.
+ * 	Setup the device register in the bridge for this PCI slot.
  */
 int
-pcibr_slot_device_init(devfs_handle_t 	pcibr_vhdl,
-		       pciio_slot_t    	slot)
+pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,
+		       pciio_slot_t slot)
 {
-    pcibr_soft_t	pcibr_soft;
+    pcibr_soft_t	 pcibr_soft;
     bridge_t		*bridge;
-    bridgereg_t		devreg;
+    bridgereg_t		 devreg;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+
     if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
+	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
 
@@ -3036,13 +3044,13 @@
 #if DEBUG && PCI_DEBUG
     printk("pcibr: PCI space allocation done.\n");
 #endif
-	
+
     return(0);
 }
 
 /*
  * pcibr_slot_guest_info_init
- *	Setup the host/guest relations for a pci slot.
+ *	Setup the host/guest relations for a PCI slot.
  */
 int
 pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl,
@@ -3056,7 +3064,7 @@
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
     if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
+	return(EINVAL);
 
     slotp = &pcibr_soft->bs_slot[slot];
 
@@ -3103,17 +3111,17 @@
 
     return(0);
 }
+
 /*
  * pcibr_slot_initial_rrb_alloc
  *	Allocate a default number of rrbs for this slot on 
- * 	the two channels. This is dictated by the rrb allocation
+ * 	the two channels.  This is dictated by the rrb allocation
  * 	strategy routine defined per platform.
  */
 
 int
-pcibr_slot_initial_rrb_alloc(devfs_handle_t 	pcibr_vhdl,
-			     pciio_slot_t	slot)
-
+pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl,
+			     pciio_slot_t slot)
 {
     pcibr_soft_t	pcibr_soft;
     pcibr_info_h	pcibr_infoh;
@@ -3123,16 +3131,17 @@
     int			r;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+
     if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
+	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
 
-
     /* How may RRBs are on this slot?
      */
     c0 = do_pcibr_rrb_count_valid(bridge, slot);
     c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL);
+
 #if PCIBR_RRB_DEBUG
     printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1);
 #endif
@@ -3149,7 +3158,7 @@
 	    do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1);
 	pcibr_soft->bs_rrb_valid[slot] = 0x1000;
 	pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000;
-	return(0);
+	return(ENODEV);
     }
 
     pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1;
@@ -3173,17 +3182,19 @@
 	    pcibr_soft->bs_rrb_res[slot]);
     printk("\n");
 #endif
+
     return(0);
 }
 
 /*
  * pcibr_slot_call_device_attach
- *	This calls the associated driver attach routine for the pci
+ *	This calls the associated driver attach routine for the PCI
  * 	card in this slot.
  */
 int
-pcibr_slot_call_device_attach(devfs_handle_t	pcibr_vhdl,
-			      pciio_slot_t	slot)
+pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl,
+			      pciio_slot_t slot,
+			      int          drv_flags)
 {
     pcibr_soft_t	pcibr_soft;
     pcibr_info_h	pcibr_infoh;
@@ -3192,14 +3203,19 @@
     int			func;
     devfs_handle_t	xconn_vhdl,conn_vhdl;
     int			nfunc;
+    int                 error_func;
+    int                 error_slot = 0;
+    int                 error = ENODEV;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+
     if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
+	return(EINVAL);
 
 
-    if (pcibr_soft->bs_slot[slot].has_host)
-        return(0);
+    if (pcibr_soft->bs_slot[slot].has_host) {
+        return(EPERM);
+    }
     
     xconn_vhdl = pcibr_soft->bs_conn;
     aa = async_attach_get_info(xconn_vhdl);
@@ -3207,8 +3223,6 @@
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
 
-    printk("\npcibr_slot_call_device_attach: link 0x%p pci bus 0x%p slot %d\n", xconn_vhdl, pcibr_vhdl, slot);
-
     for (func = 0; func < nfunc; ++func) {
 
 	pcibr_info = pcibr_infoh[func];
@@ -3221,51 +3235,77 @@
 
 	conn_vhdl = pcibr_info->f_vertex;
 
-	/* If the pci device has been disabled in the prom,
+	/* If the PCI device has been disabled in the prom,
 	 * do not set it up for driver attach. NOTE: usrpci
 	 * and pciba will not "see" this connection point!
 	 */
 	if (device_admin_info_get(conn_vhdl, ADMIN_LBL_DISABLED)) {
 #ifdef SUPPORT_PRINTING_V_FORMAT
-	    PRINT_WARNING( "pcibr_slot_call_device_attach: %v disabled\n", 
+	    PRINT_WARNING("pcibr_slot_call_device_attach: %v disabled\n", 
 		    conn_vhdl);
 #endif
 	    continue;
 	}
+#ifdef LATER
+	/*
+	 * Activate if and when we support cdl.
+	 */
 	if (aa)
 	    async_attach_add_info(conn_vhdl, aa);
-	pciio_device_attach(conn_vhdl);
-    }				/* next func */
+#endif	/* LATER */
 
-    printk("\npcibr_slot_call_device_attach: DONE\n");
+	error_func = pciio_device_attach(conn_vhdl, drv_flags);
 
-    return(0);
+        pcibr_info->f_att_det_error = error_func;
+
+	if (error_func)
+	    error_slot = error_func;
+
+        error = error_slot;
+
+    }				/* next func */
+
+    if (error) {
+	if ((error != ENODEV) && (error != EUNATCH))
+	    pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT;
+    } else {
+        pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
+    }
+        
+    return(error);
 }
+
 /*
  * pcibr_slot_call_device_detach
- *	This calls the associated driver detach routine for the pci
+ *	This calls the associated driver detach routine for the PCI
  * 	card in this slot.
  */
 int
-pcibr_slot_call_device_detach(devfs_handle_t	pcibr_vhdl,
-			      pciio_slot_t	slot)
+pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl,
+			      pciio_slot_t slot,
+			      int          drv_flags)
 {
     pcibr_soft_t	pcibr_soft;
     pcibr_info_h	pcibr_infoh;
     pcibr_info_t	pcibr_info;
     int			func;
-    devfs_handle_t	conn_vhdl;
+    devfs_handle_t	conn_vhdl = GRAPH_VERTEX_NONE;
     int			nfunc;
-    int			ndetach = 1;
+    int                 error_func;
+    int                 error_slot = 0;
+    int                 error = ENODEV;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-	return(1);
 
+    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host)
-        return(0);
-    
+        return(EPERM);
+
+    /* Make sure that we do not detach a system critical function vertex */
+    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
+        return(EPERM);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
@@ -3281,94 +3321,120 @@
 	    continue;
 
 	conn_vhdl = pcibr_info->f_vertex;
-	
-	/* Make sure that we do not detach a system critical device
-	 * vertex.
-	 */
-	if (is_sys_critical_vertex(conn_vhdl)) {
-#ifdef SUPPORT_PRINTING_V_FORMAT
-	    PRINT_WARNING( "%v is a system critical device vertex\n",
-		    conn_vhdl);
-#endif
-	    continue;
-	}
-	
-	ndetach = 0;
-	pciio_device_detach(conn_vhdl);
+
+	error_func = pciio_device_detach(conn_vhdl, drv_flags);
+
+        pcibr_info->f_att_det_error = error_func;
+
+	if (error_func)
+	    error_slot = error_func;
+
+	error = error_slot;
+
     }				/* next func */
 
+    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 
-    return(ndetach);
+    if (error) {
+	if ((error != ENODEV) && (error != EUNATCH))
+            pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT;
+    } else {
+        if (conn_vhdl != GRAPH_VERTEX_NONE) 
+            pcibr_device_unregister(conn_vhdl);
+        pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
+    }
+        
+    return(error);
 }
 
 /*
- * pcibr_device_attach
+ * pcibr_slot_detach
  *	This is a place holder routine to keep track of all the
- *	slot-specific initialization that needs to be done.
- *	This is usually called when we want to initialize a new
- * 	pci card on the bus.
+ *	slot-specific freeing that needs to be done.
  */
 int
-pcibr_device_attach(devfs_handle_t 	pcibr_vhdl,
-		    pciio_slot_t	slot)
+pcibr_slot_detach(devfs_handle_t pcibr_vhdl,
+		  pciio_slot_t slot,
+		  int          drv_flags)
 {
-    return (
-	    /* Reset the slot */
-	    pcibr_slot_reset(pcibr_vhdl,slot)			||
-	    /* FInd out what is out there */
-	    pcibr_slot_info_init(pcibr_vhdl,slot)		||
-
-	    /* Set up the address space for this slot in the pci land */
-	    pcibr_slot_addr_space_init(pcibr_vhdl,slot) 	||
-
-	    /* Setup the device register */
-	    pcibr_slot_device_init(pcibr_vhdl, slot)		||
-
-	    /* Setup host/guest relations */
-	    pcibr_slot_guest_info_init(pcibr_vhdl,slot)		||
-
-	    /* Initial RRB management */
-	    pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot)	||
-
-	    /* Call the device attach */
-	    pcibr_slot_call_device_attach(pcibr_vhdl,slot)
-	    );
+    int		  error;
+    
+    /* Call the device detach function */
+    error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags));
+    return (error);
 
 }
+
 /*
- * pcibr_device_detach
- *	This is a place holder routine to keep track of all the
- *	slot-specific freeing that needs to be done.
+ * pcibr_is_slot_sys_critical
+ *      Check slot for any functions that are system critical.
+ *      Return 1 if any are system critical or 0 otherwise.
+ *
+ *      This function will always return 0 when called by 
+ *      pcibr_attach() because the system critical vertices 
+ *      have not yet been set in the hwgraph.
  */
 int
-pcibr_device_detach(devfs_handle_t 	pcibr_vhdl,
-		    pciio_slot_t	slot)
+pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl,
+                      pciio_slot_t slot)
 {
-    
-    /* Call the device detach */
-    return (pcibr_slot_call_device_detach(pcibr_vhdl,slot));
+    pcibr_soft_t        pcibr_soft;
+    pcibr_info_h        pcibr_infoh;
+    pcibr_info_t        pcibr_info;
+    devfs_handle_t        conn_vhdl = GRAPH_VERTEX_NONE;
+    int                 nfunc;
+    int                 func;
+
+    pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+        return(0);
+
+    nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
+    pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
+
+    for (func = 0; func < nfunc; ++func) {
+
+        pcibr_info = pcibr_infoh[func];
+        if (!pcibr_info)
+            continue;
+
+        if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
+            continue;
+
+        conn_vhdl = pcibr_info->f_vertex;
+        if (is_sys_critical_vertex(conn_vhdl)) { 
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+            PRINT_WARNING("%v is a system critical device vertex\n", conn_vhdl);
+#else
+            PRINT_WARNING("%p is a system critical device vertex\n", conn_vhdl);
+#endif
+            return(1); 
+        }
+
+    }
 
+    return(0);
 }
+
 /*
  * pcibr_device_unregister
- *	This frees up any hardware resources reserved for this pci device
- * 	and removes any pci infrastructural information setup for it.
- *	This is usually used at the time of shutting down of the pci card.
+ *	This frees up any hardware resources reserved for this PCI device
+ * 	and removes any PCI infrastructural information setup for it.
+ *	This is usually used at the time of shutting down of the PCI card.
  */
-void
+int
 pcibr_device_unregister(devfs_handle_t pconn_vhdl)
 {
-    pciio_info_t	pciio_info;
-    devfs_handle_t	pcibr_vhdl;
-    pciio_slot_t	slot;
-    pcibr_soft_t	pcibr_soft;
+    pciio_info_t	 pciio_info;
+    devfs_handle_t	 pcibr_vhdl;
+    pciio_slot_t	 slot;
+    pcibr_soft_t	 pcibr_soft;
     bridge_t		*bridge;
+    int			 error_call;
+    int			 error = 0;
 
     pciio_info = pciio_info_get(pconn_vhdl);
 
-    /* Detach the pciba name space */
-    pciio_device_detach(pconn_vhdl);
-
     pcibr_vhdl = pciio_info_master_get(pciio_info);
     slot = pciio_info_slot_get(pciio_info);
 
@@ -3382,19 +3448,31 @@
     pcibr_rrb_flush(pconn_vhdl);
 
     /* Free the rrbs allocated to this slot */
-    do_pcibr_rrb_free(bridge, slot, 
-		      pcibr_soft->bs_rrb_valid[slot] +
-		      pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]);
+    error_call = do_pcibr_rrb_free(bridge, slot, 
+		                   pcibr_soft->bs_rrb_valid[slot] +
+		                   pcibr_soft->bs_rrb_valid[slot + 
+                                   PCIBR_RRB_SLOT_VIRTUAL]);
 
+    if (error_call)
+        error = ERANGE;
 
     pcibr_soft->bs_rrb_valid[slot] = 0;
     pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0;
     pcibr_soft->bs_rrb_res[slot] = 0;
 
     /* Flush the write buffers !! */
-    (void)pcibr_wrb_flush(pconn_vhdl);
+    error_call = pcibr_wrb_flush(pconn_vhdl);
+
+    if (error_call)
+        error = error_call;
+
     /* Clear the information specific to the slot */
-    (void)pcibr_slot_info_free(pcibr_vhdl, slot);
+    error_call = pcibr_slot_info_free(pcibr_vhdl, slot);
+
+    if (error_call)
+        error = error_call;
+
+    return(error);
     
 }
 
@@ -3467,6 +3545,7 @@
 	return (rv == GRAPH_SUCCESS);
 }
 
+
 /*
  *    pcibr_attach: called every time the crosstalk
  *      infrastructure is asked to initialize a widget
@@ -3502,11 +3581,15 @@
     iopaddr_t               pci_hi_fb, pci_hi_fl;
 
     int                     spl_level;
+#ifdef LATER
     char		    *nicinfo = (char *)0;
+#endif
 
 #if PCI_FBBE
     int                     fast_back_to_back_enable;
 #endif
+    l1sc_t		    *scp;
+    nasid_t		    nasid;
 
     async_attach_t          aa = NULL;
 
@@ -3542,8 +3625,6 @@
 	NeedXbridgeSwap = 1;
 #endif
 
-	printk("pcibr_attach: Called with vertex 0x%p, b_wid_stat 0x%x, gio 0x%x\n",xconn_vhdl, bridge->b_wid_stat, BRIDGE_STAT_PCI_GIO_N);
-
     /*
      * Create the vertex for the PCI bus, which we
      * will also use to hold the pcibr_soft and
@@ -3558,8 +3639,14 @@
     rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl);
     ASSERT(rc == GRAPH_SUCCESS);
 
-    rc = hwgraph_char_device_add(pcibr_vhdl, EDGE_LBL_CONTROLLER, "pcibr_", &ctlr_vhdl);
-    ASSERT(rc == GRAPH_SUCCESS);
+    ctlr_vhdl = NULL;
+    ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER,
+                0, DEVFS_FL_AUTO_DEVNUM,
+                0, 0,
+                S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+                &pcibr_fops, NULL);
+
+    ASSERT(ctlr_vhdl != NULL);
 
     /*
      * decode the nic, and hang its stuff off our
@@ -3606,6 +3693,10 @@
 	pcibr_soft->bs_xbridge = 0;
     }
 
+    nasid = NASID_GET(bridge);
+    scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
+    pcibr_soft->bs_l1sc = scp;
+    pcibr_soft->bs_moduleid = iobrick_module_get(scp);
     pcibr_soft->bsi_err_intr = 0;
 
     /* Bridges up through REV C
@@ -3660,7 +3751,7 @@
     /*
      * Init bridge lock.
      */
-    spinlock_init(&pcibr_soft->bs_lock, "pcibr_loc");
+    spin_lock_init(&pcibr_soft->bs_lock);
 
     /*
      * If we have one, process the hints structure.
@@ -3691,12 +3782,18 @@
 	pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE;
 	pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET;
 	pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET;
-	pcibr_soft->bs_slot[slot].bss_ext_ates_active = 0;
+	pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0);
     }
 
     for (ibit = 0; ibit < 8; ++ibit) {
 	pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0;
-	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_list = 0;
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft;
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL;
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = 
+							&(bridge->b_int_status);
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0;
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0;
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0;
     }
 
     /*
@@ -3733,7 +3830,7 @@
 	iopaddr_t               xbase;
 	xwidgetnum_t            xport;
 	iopaddr_t               offset;
-	int                     num_entries;
+	int                     num_entries = 0;
 	int                     entry;
 	cnodeid_t		cnodeid;
 	nasid_t			nasid;
@@ -3801,10 +3898,6 @@
 
 	    dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT;
 
-#ifdef IRIX
-	    dirmap |= BRIDGE_DIRMAP_RMF_64;
-#endif
-
 	    if (xbase)
 		dirmap |= BRIDGE_DIRMAP_OFF & xbase;
 	    else if (offset >= (512 << 20))
@@ -3855,15 +3948,10 @@
 	 * recomparing against BRIDGE_INTERNAL_ATES every
 	 * time.
 	 */
-#ifdef BRINGUP
-	/*
-	 * 082799: for some reason pcibr_init_ext_ate_ram is causing
-	 * a Data Bus Error.  It should be zero anyway so just force it.
-	 */
-	num_entries = 0;
-#else
-	num_entries = pcibr_init_ext_ate_ram(bridge);
-#endif
+	if (is_xbridge(bridge))
+		num_entries = 0;
+	else
+		num_entries = pcibr_init_ext_ate_ram(bridge);
 
 	/* we always have 128 ATEs (512 for Xbridge) inside the chip
 	 * even if disabled for debugging.
@@ -3947,7 +4035,6 @@
 
     pcibr_soft->bsi_err_intr = xtalk_intr;
 
-#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
     /*
      * On IP35 with XBridge, we do some extra checks in pcibr_setwidint
      * in order to work around some addressing limitations.  In order
@@ -3955,9 +4042,6 @@
      * start from a known clean state.
      */
     pcibr_clearwidint(bridge);
-#endif
-
-    printk("pribr_attach:  FIXME Error Interrupt not registered\n");
 
     xtalk_intr_connect(xtalk_intr,
 		       (intr_func_t) pcibr_error_intr_handler,
@@ -4054,13 +4138,13 @@
     }
 #endif
 
-#ifdef IRIX
+#ifdef LATER
     /* If the bridge has been reset then there is no need to reset
      * the individual PCI slots.
      */
     for (slot = 0; slot < 8; ++slot)  
 	/* Reset all the slots */
-	(void)pcibr_slot_reset(pcibr_vhdl,slot);
+	(void)pcibr_slot_reset(pcibr_vhdl, slot);
 #endif
 
     for (slot = 0; slot < 8; ++slot)
@@ -4075,6 +4159,7 @@
 	/* Setup the device register */
 	(void)pcibr_slot_device_init(pcibr_vhdl, slot);
 
+#ifndef __ia64
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
     for (slot = 0; slot < 8; ++slot)  
 	/* Set up convenience links */
@@ -4082,6 +4167,7 @@
 		if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */
 			pcibr_bus_cnvlink(pcibr_info->f_vertex, slot);
 #endif
+#endif
 
     for (slot = 0; slot < 8; ++slot)  
 	/* Setup host/guest relations */
@@ -4091,12 +4177,34 @@
 	/* Initial RRB management */
 	(void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot);
 
-#ifdef dagum
     /* driver attach routines should be called out from generic linux code */
     for (slot = 0; slot < 8; ++slot)  
 	/* Call the device attach */
-	(void)pcibr_slot_call_device_attach(pcibr_vhdl,slot);
-#endif /* dagum */
+	(void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0);
+
+    /*
+     * Each Pbrick PCI bus only has slots 1 and 2.   Similarly for
+     * widget 0xe on Ibricks.  Allocate RRB's accordingly.
+     */
+    if (pcibr_soft->bs_moduleid > 0) {
+	switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) {
+	case 'p':		/* Pbrick */
+		do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
+		do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8);
+		break;
+	case 'i':		/* Ibrick */
+	  	/* port 0xe on the Ibrick only has slots 1 and 2 */
+		if (pcibr_soft->bs_xid == 0xe) {
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8);
+		}
+		else {
+		    	/* allocate one RRB for the serial port */
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1);
+		}
+		break;
+	} /* switch */
+    }
 
 #ifdef LATER
     if (strstr(nicinfo, XTALK_PCI_PART_NUM)) {
@@ -4119,13 +4227,13 @@
 #endif
     }
 #else
-	printk("pcibr_attach: FIXME to call do_pcibr_rrb_autoalloc nicinfo 0x%p\n", nicinfo);
+	FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n");
 #endif
 
     if (aa)
 	    async_attach_add_info(noslot_conn, aa);
 
-    pciio_device_attach(noslot_conn);
+    pciio_device_attach(noslot_conn, 0);
 
 
     /* 
@@ -4166,14 +4274,14 @@
 	printk("pcibr_device_detach called for %p/%d\n",
 		pcibr_vhdl,slot);
 #endif
-	pcibr_device_detach(pcibr_vhdl, slot);
+	pcibr_slot_detach(pcibr_vhdl, slot, 0);
     }
 
     /* Unregister the no-slot connection point */
     pciio_device_info_unregister(pcibr_vhdl,
 				 &(pcibr_soft->bs_noslot_info->f_c));
 
-    spinlock_destroy(&pcibr_soft->bs_lock);
+    spin_lock_destroy(&pcibr_soft->bs_lock);
     kfree(pcibr_soft->bs_name);
     
     /* Error handler gets unregistered when the widget info is 
@@ -4264,7 +4372,7 @@
     size_t                  msize;	/* size of devio(x) mapped area on PCI */
     size_t                  mmask;	/* addr bits stored in Device(x) */
 
-    unsigned                s;
+    unsigned long           s;
 
     s = pcibr_lock(pcibr_soft);
 
@@ -4327,7 +4435,7 @@
 	if (wspace == PCIIO_SPACE_NONE)
 	    goto done;
 
-	/* get pci base and size */
+	/* get PCI base and size */
 	wbase = pcibr_info->f_window[bar].w_base;
 	wsize = pcibr_info->f_window[bar].w_size;
 
@@ -4587,7 +4695,7 @@
     pcibr_piomap_t          pcibr_piomap;
     iopaddr_t               xio_addr;
     xtalk_piomap_t          xtalk_piomap;
-    unsigned                s;
+    unsigned long           s;
 
     /* Make sure that the req sizes are non-zero */
     if ((req_size < 1) || (req_size_max < 1))
@@ -4631,7 +4739,7 @@
     pcibr_piomap->bp_pciaddr = pci_addr;
     pcibr_piomap->bp_mapsz = req_size;
     pcibr_piomap->bp_soft = pcibr_soft;
-    pcibr_piomap->bp_toc[0] = 0;
+    pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0);
 
     if (mapptr) {
 	s = pcibr_lock(pcibr_soft);
@@ -4733,7 +4841,7 @@
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
 
     pciio_piospace_t        piosp;
-    int                     s;
+    unsigned long           s;
 
     iopaddr_t              *pciaddr, *pcilast;
     iopaddr_t               start_addr;
@@ -4751,7 +4859,7 @@
     /*
      * First look if a previously allocated chunk exists.
      */
-    if ((piosp = pcibr_info->f_piospace) != (pciio_piospace_t)0) {
+    if ((piosp = pcibr_info->f_piospace)) {
 	/*
 	 * Look through the list for a right sized free chunk.
 	 */
@@ -4825,7 +4933,7 @@
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
 
     pciio_piospace_t        piosp;
-    int                     s;
+    unsigned long           s;
     char                    name[1024];
 
     /*
@@ -4901,7 +5009,7 @@
     iopaddr_t               attributes = 0;
 
     /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */
-#ifdef IRIX
+#ifdef LATER
     ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64));
 #endif
 
@@ -5031,7 +5139,16 @@
     /* merge in forced flags */
     flags |= pcibr_soft->bs_dma_flags;
 
+#ifdef IRIX
     NEWf(pcibr_dmamap, flags);
+#else
+    /*
+     * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc()
+     * can be called within an interrupt thread.
+     */
+    pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl);
+#endif
+
     if (!pcibr_dmamap)
 	return 0;
 
@@ -5162,7 +5279,7 @@
 	    pcibr_dmamap->bd_pci_addr =
 		PCI32_MAPPED_BASE + IOPGSIZE * ate_index;
 	    /*
-	     * for xbridge the byte-swap bit == bit 29 of pci address
+	     * for xbridge the byte-swap bit == bit 29 of PCI address
 	     */
 	    if (pcibr_soft->bs_xbridge) {
 		    if (flags & PCIIO_BYTE_STREAM)
@@ -5201,7 +5318,7 @@
 		bridge_t               *bridge = pcibr_soft->bs_base;
 		volatile unsigned      *cmd_regp;
 		unsigned                cmd_reg;
-		unsigned                s;
+		unsigned long           s;
 
 		pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM;
 
@@ -5239,20 +5356,15 @@
     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
     pciio_slot_t            slot = pcibr_dmamap->bd_slot;
 
-#ifdef IRIX
     unsigned                flags = pcibr_dmamap->bd_flags;
-#endif
 
     /* Make sure that bss_ext_ates_active
      * is properly kept up to date.
      */
-#ifdef IRIX
+
     if (PCIBR_DMAMAP_BUSY & flags)
 	if (PCIBR_DMAMAP_SSRAM & flags)
-	    atomicAddInt(&(pcibr_soft->
-			   bs_slot[slot].
-			   bss_ext_ates_active), -1);
-#endif
+	    atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active));
 
     xtalk_dmamap_free(pcibr_dmamap->bd_xtalk);
 
@@ -5265,7 +5377,9 @@
 		       pcibr_dmamap->bd_ate_count);
 	pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS);
     }
+#ifdef IRIX
     DEL(pcibr_dmamap);
+#endif
 }
 
 /*
@@ -5325,7 +5439,6 @@
 /* We are starting to get more complexity
  * surrounding writing ATEs, so pull
  * the writing code into this new function.
- * XXX mail ranga@engr for IP27 prom!
  */
 
 #if PCIBR_FREEZE_TIME
@@ -5342,13 +5455,13 @@
 	   unsigned *cmd_regs)
 {
     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
-#ifdef IRIX
+#ifdef LATER
     int                     dma_slot = pcibr_dmamap->bd_slot;
 #endif
     int                     ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM;
     int                     slot;
 
-    unsigned                s;
+    unsigned long           s;
     unsigned                cmd_reg;
     volatile unsigned      *cmd_lwa;
     unsigned                cmd_lwd;
@@ -5371,27 +5484,22 @@
      */
     s = pcibr_lock(pcibr_soft);
 
-#ifdef IRIX
+#ifdef LATER
     /* just in case pcibr_dmamap_done was not called */
     if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) {
 	pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY;
 	if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM)
-	    atomicAddInt(&(pcibr_soft->
-			   bs_slot[dma_slot].
-			   bss_ext_ates_active), -1);
+	    atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));
 	xtalk_dmamap_done(pcibr_dmamap->bd_xtalk);
     }
-#endif
+#endif	/* LATER */
 #if PCIBR_FREEZE_TIME
     *freeze_time_ptr = get_timestamp();
 #endif
 
     cmd_lwa = 0;
     for (slot = 0; slot < 8; ++slot)
-	if (pcibr_soft->
-	    bs_slot[slot].
-	    bss_ext_ates_active) {
-
+	if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
 	    cmd_reg = pcibr_soft->
 		bs_slot[slot].
 		bss_cmd_shadow;
@@ -5418,9 +5526,7 @@
 
 	    /* Flush all the write buffers in the bridge */
 	    for (slot = 0; slot < 8; ++slot)
-		    if (pcibr_soft->
-			bs_slot[slot].
-			bss_ext_ates_active) {
+		    if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
 			    /* Flush the write buffer associated with this
 			     * PCI device which might be using dma map RAM.
 			     */
@@ -5462,9 +5568,7 @@
 	 unsigned s)
 {
     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
-#ifdef IRIX
     int                     dma_slot = pcibr_dmamap->bd_slot;
-#endif
     int                     slot;
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM;
@@ -5486,11 +5590,7 @@
 	    bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg;
 
     pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY;
-#ifdef IRIX
-    atomicAddInt(&(pcibr_soft->
-		   bs_slot[dma_slot].
-		   bss_ext_ates_active), 1);
-#endif
+    atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));
 
 #if PCIBR_FREEZE_TIME
     freeze_time = get_timestamp() - freeze_time_start;
@@ -5685,11 +5785,7 @@
 		  unsigned flags)
 {
     pcibr_soft_t            pcibr_soft;
-#ifdef IRIX
-    bridge_t               *bridge;
-#else
     bridge_t               *bridge=NULL;
-#endif
 
     unsigned                al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0;
     int                     inplace = flags & PCIIO_INPLACE;
@@ -5699,19 +5795,11 @@
     size_t                  length;
     iopaddr_t               offset;
     unsigned                direct64;
-#ifdef IRIX
-    int                     ate_index;
-    int                     ate_count;
-    int                     ate_total = 0;
-    bridge_ate_p            ate_ptr;
-    bridge_ate_t            ate_proto;
-#else
     int                     ate_index = 0;
     int                     ate_count = 0;
     int                     ate_total = 0;
     bridge_ate_p            ate_ptr = (bridge_ate_p)0;
     bridge_ate_t            ate_proto = (bridge_ate_t)0;
-#endif
     bridge_ate_t            ate_prev;
     bridge_ate_t            ate;
     alenaddr_t              xio_addr;
@@ -5899,16 +5987,12 @@
      * between _addr/_list and _done, but Hub does.
      */
 
-#ifdef IRIX
     if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) {
 	pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY;
 
 	if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM)
-	    atomicAddInt(&(pcibr_dmamap->bd_soft->
-			   bs_slot[pcibr_dmamap->bd_slot].
-			   bss_ext_ates_active), -1);
+	    atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active));
     }
-#endif
 
     xtalk_dmamap_done(pcibr_dmamap->bd_xtalk);
 }
@@ -6332,11 +6416,7 @@
 	 */
 	if (xio_port == pcibr_soft->bs_xid) {
 	    pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size);
-#ifdef IRIX
-	    if (pci_addr == NULL)
-#else
 	    if ( (pci_addr == (alenaddr_t)NULL) )
-#endif
 		goto fail;
 	} else if (direct64) {
 	    ASSERT(xio_port != 0);
@@ -6371,11 +6451,7 @@
 	}
     }
 
-#ifdef IRIX
-    if (relbits)
-#else
     if (relbits) {
-#endif
 	if (direct64) {
 	    slotp->bss_d64_flags = flags;
 	    slotp->bss_d64_base = pci_base;
@@ -6383,9 +6459,7 @@
 	    slotp->bss_d32_flags = flags;
 	    slotp->bss_d32_base = pci_base;
 	}
-#ifndef IRIX
     }
-#endif
     if (!inplace)
 	alenlist_done(xtalk_alenlist);
 
@@ -6480,26 +6554,155 @@
     return bbits;
 }
 
-#ifdef IRIX
+
+/*
+ *	Get the next wrapper pointer queued in the interrupt circular buffer.
+ */
+#ifdef KERNEL_THREADS
+pcibr_intr_wrap_t
+pcibr_wrap_get(pcibr_intr_cbuf_t cbuf)
+{
+    pcibr_intr_wrap_t	wrap;
+
+	if (cbuf->ib_in == cbuf->ib_out)
+	    PRINT_PANIC("pcibr intr circular buffer empty, cbuf=0x%x, ib_in=ib_out=%d\n",
+		cbuf, cbuf->ib_out);
+
+	wrap = cbuf->ib_cbuf[cbuf->ib_out++];
+	cbuf->ib_out = cbuf->ib_out % IBUFSIZE;
+	return(wrap);
+}
+
+/* 
+ *	Queue a wrapper pointer in the interrupt circular buffer.
+ */
+void
+pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf)
+{
+	int	in;
+	unsigned long	s;
+
+	/*
+	 * Multiple CPUs could be executing this code simultaneously
+	 * if a handler has registered multiple interrupt lines and
+	 * the interrupts are directed to different CPUs.
+	 */
+	s = mutex_spinlock(&cbuf->ib_lock);
+	in = (cbuf->ib_in + 1) % IBUFSIZE;
+	if (in == cbuf->ib_out) 
+	    PRINT_PANIC("pcibr intr circular buffer full, cbuf=0x%x, ib_in=%d\n",
+		cbuf, cbuf->ib_in);
+
+	cbuf->ib_cbuf[cbuf->ib_in] = wrap;
+	cbuf->ib_in = in;
+	mutex_spinunlock(&cbuf->ib_lock, s);
+	return;
+}
+#endif	/* KERNEL_THREADS */
+
+/*
+ *	There are end cases where a deadlock can occur if interrupt 
+ *	processing completes and the Bridge b_int_status bit is still set.
+ *
+ *	One scenerio is if a second PCI interrupt occurs within 60ns of
+ *	the previous interrupt being cleared. In this case the Bridge
+ *	does not detect the transition, the Bridge b_int_status bit
+ *	remains set, and because no transition was detected no interrupt
+ *	packet is sent to the Hub/Heart.
+ *
+ *	A second scenerio is possible when a b_int_status bit is being
+ *	shared by multiple devices:
+ *						Device #1 generates interrupt
+ *						Bridge b_int_status bit set
+ *						Device #2 generates interrupt
+ *		interrupt processing begins
+ *		  ISR for device #1 runs and
+ *			clears interrupt
+ *						Device #1 generates interrupt
+ *		  ISR for device #2 runs and
+ *			clears interrupt
+ *						(b_int_status bit still set)
+ *		interrupt processing completes
+ *		  
+ *	Interrupt processing is now complete, but an interrupt is still
+ *	outstanding for Device #1. But because there was no transition of
+ *	the b_int_status bit, no interrupt packet will be generated and
+ *	a deadlock will occur.
+ *
+ *	To avoid these deadlock situations, this function is used
+ *	to check if a specific Bridge b_int_status bit is set, and if so,
+ *	cause the setting of the corresponding interrupt bit.
+ *
+ *	On a XBridge (IP35), we do this by writing the appropriate Bridge Force 
+ *	Interrupt register.
+ */
+void
+pcibr_force_interrupt(pcibr_intr_wrap_t wrap)
+{
+	unsigned	bit;
+	pcibr_soft_t    pcibr_soft = wrap->iw_soft;
+	bridge_t       *bridge = pcibr_soft->bs_base;
+	cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl);
+
+	bit = wrap->iw_intr;
+
+	if (pcibr_soft->bs_xbridge) {
+	    bridge->b_force_pin[bit].intr = 1;
+	} else if ((1 << bit) & *wrap->iw_stat) {
+	    cpuid_t	    cpu;
+	    unsigned        intr_bit;
+	    xtalk_intr_t    xtalk_intr =
+				pcibr_soft->bs_intr[bit].bsi_xtalk_intr;
+
+	    intr_bit = (short) xtalk_intr_vector_get(xtalk_intr);
+	    cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
+	    REMOTE_CPU_SEND_INTR(cpu, intr_bit);
+	}
+}
+
 /* Wrapper for pcibr interrupt threads. */
+#ifdef KERNEL_THREADS
 static void
 pcibr_intrd(pcibr_intr_t intr)
 {
+    pcibr_intr_wrap_t	wrap;
+
 	/* Called on each restart */
 	ASSERT(cpuid() == intr->bi_mustruncpu);
 
 #ifdef ITHREAD_LATENCY
-	xthread_update_latstats(intr->bi_tinfo->thd_latstats);
+	xthread_update_latstats(intr->bi_tinfo.thd_latstats);
 #endif /* ITHREAD_LATENCY */
 
 	ASSERT(intr->bi_func != NULL);
 	intr->bi_func(intr->bi_arg);		/* Invoke the interrupt handler */
 
+	/*
+	 * The pcibr_intrd thread needs access to the wrapper struct
+	 * specific to the current interrupt it is processing. Because
+	 * multiple calls/wakeups to the thread could be queued, each
+	 * potentially from a different interrupt line (PCIIO_INTR_LINE_A,
+	 * etc), multiple wrapper struct pointers need to be queued. This 
+	 * is done via a circular buffer of wrapper struct pointers. 
+	 */
+	wrap = pcibr_wrap_get(&intr->bi_ibuf);
+
+	/* 
+	 * The interrupt handler has completed. Now decrement the running
+	 * count tracking the number of handlers still running for this line.
+	 * If this was the last handler to complete (i.e., iw_hdlrcnt == 0),
+	 * avoid a potential deadlock condition and ensure that another
+	 * interrupt will occur if the Bridge b_int_status bit is still
+	 * set. 
+	 */
+	atomicAddInt(&(wrap->iw_hdlrcnt), -1);
+	if (wrap->iw_hdlrcnt == 0)
+		pcibr_force_interrupt(wrap);
+
 	ipsema(&intr->bi_tinfo.thd_isync);	/* Sleep 'till next interrupt */
 	/* NOTREACHED */
 }
 
-
 static void
 pcibr_intrd_start(pcibr_intr_t intr)
 {
@@ -6519,14 +6722,16 @@
 	char thread_name[32];
 
 	sprintf(thread_name, "pcibr_intrd[0x%x]", bridge_levels);
+	thread_name[IT_NAMELEN-1] = '\0';
 
 	/* XXX need to adjust priority whenever an interrupt is connected */
+	intr->bi_tinfo.thd_pri = intr_swlevel;
 	atomicSetInt(&intr->bi_tinfo.thd_flags, THD_ISTHREAD | THD_REG);
 	xthread_setup(thread_name, intr_swlevel, &intr->bi_tinfo,
 			(xt_func_t *)pcibr_intrd_start,
 			(void *)intr);
 }
-#endif	/* IRIX */
+#endif	/* KERNEL_THREADS */
 
 
 
@@ -6542,13 +6747,16 @@
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
     bridge_t               *bridge = pcibr_soft->bs_base;
-    int                     is_threaded;
+    int                     is_threaded = 0;
+#ifdef KERNEL_THREADS
+    cpuid_t		    mustruncpu = CPU_NONE;
+    cpuid_t		    old_intrcpu = CPU_NONE;
+#endif
     int                     thread_swlevel;
 
     xtalk_intr_t           *xtalk_intr_p;
     pcibr_intr_t           *pcibr_intr_p;
     pcibr_intr_list_t      *intr_list_p;
-    pcibr_intr_wrap_t      *intr_wrap_p;
 
     unsigned                pcibr_int_bits;
     unsigned                pcibr_int_bit;
@@ -6557,7 +6765,6 @@
     pcibr_intr_t            pcibr_intr;
     pcibr_intr_list_t       intr_entry;
     pcibr_intr_list_t       intr_list;
-    pcibr_intr_wrap_t       intr_wrap;
     bridgereg_t             int_dev;
 
 #if DEBUG && INTR_DEBUG
@@ -6576,9 +6783,29 @@
 	return NULL;
 
     if (dev_desc) {
+	cpuid_t intr_target_from_desc(device_desc_t, int);
+
+#ifdef KERNEL_THREADS
 	is_threaded = !(device_desc_flags_get(dev_desc) & D_INTR_NOTHREAD);
-	if (is_threaded)
+	if (is_threaded) {
+	    /*
+	     * If the device descriptor contains interrupt target info,
+	     * save the CPU requested. This is the CPU the pcibr_intrd
+	     * thread will be set to run on. 
+	     *
+	     * We need to get the interrupt target info at this time, because
+	     * the original intr_target value can be overwritten, as part of
+	     * the xtalk_intr_alloc_nothd() call, with the actual interrupt CPU.
+	     * This can be different than the requested CPU if the lower layers
+	     * could not direct the hardware interrupt to the requested CPU. 
+	     * Regardless of which CPU processes the hardware interrupt, the 
+	     * ISR thread will still be setup to run on the CPU originally 
+	     * requested.
+	     */
+		mustruncpu = intr_target_from_desc(dev_desc, SUBNODE_ANY);
 		thread_swlevel = device_desc_intr_swlevel_get(dev_desc);
+	}
+#endif	/* KERNEL_THREADS */
     } else {
 	extern int default_intr_pri;
 
@@ -6594,6 +6821,11 @@
     pcibr_intr->bi_arg = 0;		/* unset until connect */
     pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD;
     pcibr_intr->bi_mustruncpu = CPU_NONE;
+#ifdef KERNEL_THREADS
+    pcibr_intr->bi_ibuf.ib_in = 0;
+    pcibr_intr->bi_ibuf.ib_out = 0;
+#endif
+    mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock);
 
     pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines);
 
@@ -6626,7 +6858,17 @@
 		 *    single Bridge. (IP35-specific code forces this, and we
 		 *    verify in pcibr_setwidint.)
 		 */
-		xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, owner_dev);
+
+		/*
+		 * All code dealing with threaded PCI interrupt handlers
+		 * is located at the pcibr level. Because of this,
+		 * we always want the lower layers (hub/heart_intr_alloc, 
+		 * intr_level_connect) to treat us as non-threaded so we
+		 * don't set up a duplicate threaded environment. We make
+		 * this happen by calling a special xtalk interface.
+		 */
+		xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, 
+			owner_dev);
 #if DEBUG && INTR_DEBUG
 		printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr);
 #endif
@@ -6690,32 +6932,64 @@
 		}
 	    }
 
-	    /*
-	     * For threaded drivers, set the interrupt thread to run wherever
-	     * the interrupt is targeted.
-	     */
-#ifdef notyet
+#ifdef KERNEL_THREADS
 	    if (is_threaded) {
-		cpuid_t old_mustrun = pcibr_intr->bi_mustruncpu;
-		pcibr_intr->bi_mustruncpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
-		ASSERT(pcibr_intr->bi_mustruncpu >= 0);
+		cpuid_t intrcpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
 
 		/*
-		 * This is possible, but very unlikely: It means that 2 (or more) interrupts
-		 * originating on a single Bridge and used by a single device were unable to
-		 * find sufficient xtalk interrupt resources that would allow them all to be
-		 * handled by the same CPU.  If someone tries to target lots of interrupts to
-		 * a single CPU, we might hit this case.  Things should still operate correctly,
-		 * but it's a sub-optimal configuration.
+		 * It is possible that 2 (or more) interrupts originating on a
+		 * single Bridge and used by a single device were assigned to
+		 * different CPUs. If this occurs issue a warning message for
+		 * this sub-optimal configuration. There are two ways this 
+		 * could happen:
+		 *
+		 *  - There were insufficient xtalk interrupt resources to
+		 *    allow all interrupts to be assigned to the same CPU.
+		 *    This is an unlikely case, but could happen if someone
+		 *    tries to target a lot of interrupts to a single CPU.
+		 *
+		 * - If there is no device descriptor associated with this
+		 *   device, the xtalk/hub/heart layers will not know to
+		 *   assign the same CPU to any additional interrupts this
+		 *   driver has specified, and will perform the normal load
+		 *   leveling of interrupts across CPUs.
+		 *   (The lower layers store the CPU assigned to the first
+		 *   interrupt in the device desc, if present, and then when
+		 *   called again for additional interrupts for the same device,
+		 *   use this information to assign the same CPU to these
+		 *   interrupts.)
 		 */
-		if ((old_mustrun != CPU_NONE) && (old_mustrun != pcibr_intr->bi_mustruncpu)) {
-#ifdef SUPPORT_PRINTING_V_FORMAT
-			PRINT_WARNING( "Conflict on where to schedule interrupts for %v\n", pconn_vhdl);
+		if ((old_intrcpu != CPU_NONE) && (old_intrcpu != intrcpu)) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+			PRINT_WARNING("Conflict on where to schedule interrupts for %v\n", pconn_vhdl);
+#else
+			PRINT_WARNING("Conflict on where to schedule interrupts for 0x%x\n", pconn_vhdl);
 #endif
-			PRINT_WARNING( "(on cpu %d or on cpu %d)\n", old_mustrun, pcibr_intr->bi_mustruncpu);
+			PRINT_WARNING("(on cpu %d or on cpu %d), cpu %d used\n", old_intrcpu, intrcpu, intrcpu);
+		}
+		if (old_intrcpu == CPU_NONE)
+			old_intrcpu = intrcpu;
+	    /*
+	     * For threaded drivers, set the interrupt thread to run wherever
+	     * the interrupt is targeted, or where requested in the dev_desc.
+	     */
+		if (mustruncpu != CPU_NONE) {
+			pcibr_intr->bi_mustruncpu = mustruncpu;
+			if (mustruncpu != intrcpu) {
+				PRINT_WARNING("Request to target PCI interrupts to CPU %d could not\n"
+                		"      be satisfied, CPU %d used. However, interrupt thread\n"
+                		"      pcibr_intrd will run on CPU %d as requested.\n"
+                		"      %v (0x%x)\n",
+                		mustruncpu, intrcpu, mustruncpu, owner_dev,
+				owner_dev);
+			}
+		} else {
+			pcibr_intr->bi_mustruncpu = intrcpu;
 		}
+		ASSERT(pcibr_intr->bi_mustruncpu >= 0);
+
 	    }
-#endif
+#endif	/* KERNEL_THREADS */
 
 	    pcibr_intr->bi_ibits |= 1 << pcibr_int_bit;
 
@@ -6723,8 +6997,20 @@
 	    intr_entry->il_next = NULL;
 	    intr_entry->il_intr = pcibr_intr;
 	    intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg);
+	    intr_list_p = 
+		&pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
+#if DEBUG && INTR_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	    printk("0x%x: Bridge bit %d wrap=0x%x\n",
+		pconn_vhdl, pcibr_int_bit,
+		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
+#else
+	    printk("%v: Bridge bit %d wrap=0x%x\n",
+		pconn_vhdl, pcibr_int_bit,
+		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
+#endif
+#endif
 
-	    intr_list_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_list;
 	    if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
 		/* we are the first interrupt on this bridge bit.
 		 */
@@ -6751,29 +7037,12 @@
 	    intr_list_p = &intr_list->il_next;
 	    if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
 		/* we are the new second interrupt on this bit.
-		 * switch to local wrapper.
 		 */
+		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1;
 #if DEBUG && INTR_DEBUG
 		printk("%v INT 0x%x (bridge bit %d) is new SECOND\n",
 			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
 #endif
-		NEW(intr_wrap);
-		intr_wrap->iw_soft = pcibr_soft;
-		intr_wrap->iw_stat = &(bridge->b_int_status);
-		intr_wrap->iw_intr = 1 << pcibr_int_bit;
-		intr_wrap->iw_list = intr_list;
-		intr_wrap_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
-		if (!compare_and_swap_ptr((void **) intr_wrap_p, NULL, intr_wrap)) {
-		    /* someone else set up the wrapper.
-		     */
-		    DEL(intr_wrap);
-		    continue;
-#if DEBUG && INTR_DEBUG
-		} else {
-		    printk("%v bridge bit %d wrapper state created\n",
-			    pconn_vhdl, pcibr_int_bit);
-#endif
-		}
 		continue;
 	    }
 	    while (1) {
@@ -6807,13 +7076,13 @@
 	}
     }
 
-#ifdef IRIX
+#ifdef KERNEL_THREADS
     if (is_threaded) {
 	/* Set pcibr_intr->bi_tinfo */
 	pcibr_thread_setup(pcibr_intr, pcibr_int_bits, thread_swlevel);
 	ASSERT(!(pcibr_intr->bi_flags & PCIIO_INTR_CONNECTED));
     }
-#endif
+#endif	/* KERNEL_THREADS */
 
 #if DEBUG && INTR_DEBUG
     printk("%v pcibr_intr_alloc complete\n", pconn_vhdl);
@@ -6832,13 +7101,13 @@
     pcibr_soft_t            pcibr_soft = pcibr_intr->bi_soft;
     unsigned                pcibr_int_bit;
     pcibr_intr_list_t       intr_list;
-    pcibr_intr_wrap_t	    intr_wrap;
+    int			    intr_shared;
     xtalk_intr_t	    *xtalk_intrp;
 
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) {
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
 	    for (intr_list = 
-		     pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_list;
+		     pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
 		 intr_list != NULL;
 		 intr_list = intr_list->il_next)
 		if (compare_and_swap_ptr((void **) &intr_list->il_intr, 
@@ -6852,10 +7121,11 @@
 	    /* If this interrupt line is not being shared between multiple
 	     * devices release the xtalk interrupt resources.
 	     */
-	    intr_wrap = 
-		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
+	    intr_shared = 
+		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared;
 	    xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
-	    if ((intr_wrap == NULL) && (*xtalk_intrp)) {
+
+	    if ((!intr_shared) && (*xtalk_intrp)) {
 
 		bridge_t 	*bridge = pcibr_soft->bs_base;
 		bridgereg_t	int_dev;
@@ -6900,7 +7170,7 @@
     unsigned                pcibr_int_bits = pcibr_intr->bi_ibits;
     unsigned                pcibr_int_bit;
     bridgereg_t             b_int_enable;
-    unsigned                s;
+    unsigned long           s;
 
     if (pcibr_intr == NULL)
 	return -1;
@@ -6924,59 +7194,29 @@
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
 	    pcibr_intr_wrap_t       intr_wrap;
 	    xtalk_intr_t            xtalk_intr;
-	    int                    *setptr;
 
 	    xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
 
-	    /* if we have no wrap structure,
-	     * tell xtalk to deliver the interrupt
-	     * directly to the client.
+	    intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
+	    /*
+	     * If this interrupt line is being shared and the connect has
+	     * already been done, no need to do it again.
 	     */
-	    intr_wrap = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
-	    if (intr_wrap == NULL) {
-		xtalk_intr_connect(xtalk_intr,
-				   (intr_func_t) intr_func,
-				   (intr_arg_t) intr_arg,
-				   (xtalk_intr_setfunc_t) pcibr_setpciint,
-				   (void *) &(bridge->b_int_addr[pcibr_int_bit].addr),
-				   thread);
-#if DEBUG && INTR_DEBUG
-		printk("%v bridge bit %d routed by xtalk\n",
-			pcibr_intr->bi_dev, pcibr_int_bit);
-#endif
+	    if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected)
 		continue;
-	    }
-
-	    setptr = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set;
-	    if (*setptr)
-		continue;
-
 
-	    /* We have a wrap structure, so we're sharing a Bridge interrupt level */
-
-	    xtalk_intr_disconnect(xtalk_intr); /* Disconnect old interrupt */
 
 	    /*
-		If the existing xtalk_intr was allocated without the NOTHREAD flag,
-		we need to allocate a new one that's NOTHREAD, and connect to the
-		new one.   pcibr_intr_list_func expects to run at interrupt level
-		rather than in a thread.  With today's devices, this can't happen,
-		so let's punt on writing the code till we need it (probably never).
-		Instead, just ASSERT that we're a NOTHREAD xtalk_intr.
-	    */
-#ifdef IRIX
-	    ASSERT_ALWAYS(!(pcibr_intr->bi_flags & PCIIO_INTR_NOTHREAD) ||
-			xtalk_intr_flags_get(xtalk_intr) & XTALK_INTR_NOTHREAD);
-#endif
-
-	    /* Use the wrapper dispatch function to handle shared Bridge interrupts */
+	     * Use the pcibr wrapper function to handle all Bridge interrupts
+	     * regardless of whether the interrupt line is shared or not.
+	     */
 	    xtalk_intr_connect(xtalk_intr,
-			       pcibr_intr_list_func,
+				pcibr_intr_func,
 			       (intr_arg_t) intr_wrap,
 			       (xtalk_intr_setfunc_t) pcibr_setpciint,
 			       (void *) &(bridge->b_int_addr[pcibr_int_bit].addr),
 			       0);
-	    *setptr = 1;
+	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1;
 
 #if DEBUG && INTR_DEBUG
 	    printk("%v bridge bit %d wrapper connected\n",
@@ -7001,9 +7241,9 @@
     bridge_t               *bridge = pcibr_soft->bs_base;
     unsigned                pcibr_int_bits = pcibr_intr->bi_ibits;
     unsigned                pcibr_int_bit;
-    pcibr_intr_wrap_t       intr_wrap;
+    pcibr_intr_wrap_t	    intr_wrap;
     bridgereg_t             b_int_enable;
-    unsigned                s;
+    unsigned long           s;
 
     /* Stop calling the function. Now.
      */
@@ -7021,7 +7261,7 @@
      */
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
 	if ((pcibr_int_bits & (1 << pcibr_int_bit)) &&
-	    (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set))
+	    (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared))
 	    pcibr_int_bits &= ~(1 << pcibr_int_bit);
     if (!pcibr_int_bits)
 	return;
@@ -7035,26 +7275,32 @@
 
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
-	    /* if we have set up the share wrapper,
+	    /* if the interrupt line is now shared,
 	     * do not disconnect it.
 	     */
-	    if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_wrap_set)
+	    if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
 		continue;
 
 	    xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr);
+	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0;
+
+#if DEBUG && INTR_DEBUG
+	    printk("%s: xtalk disconnect done for Bridge bit %d\n",
+		pcibr_soft->bs_name, pcibr_int_bit);
+#endif
 
-	    /* if we have a share wrapper state,
+	    /* if we are sharing the interrupt line,
 	     * connect us up; this closes the hole
-	     * where the connection of the wrapper
+	     * where the another pcibr_intr_alloc()
 	     * was in progress as we disconnected.
 	     */
-	    intr_wrap = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
-	    if (intr_wrap == NULL) 
+	    intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
+	    if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
 		continue;
 
 
 	    xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr,
-			       pcibr_intr_list_func,
+			       pcibr_intr_func,
 			       (intr_arg_t) intr_wrap,
 			       (xtalk_intr_setfunc_t) pcibr_setpciint,
 			       (void *) &(bridge->b_int_addr[pcibr_int_bit].addr),
@@ -7168,7 +7414,7 @@
 	bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK;
 
     } else {
-	/* routing a pci device interrupt.
+	/* routing a PCI device interrupt.
 	 * targ and low 38 bits of addr must
 	 * be the same as the already set
 	 * value for the widget error interrupt.
@@ -7187,46 +7433,71 @@
     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
 }
 
+
+/*
+ * pcibr_intr_func()
+ *
+ * This is the pcibr interrupt "wrapper" function that is called,
+ * in interrupt context, to initiate the interrupt handler(s) registered
+ * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded 
+ * handlers will be called directly, and threaded handlers will have their 
+ * thread woken up.
+ */
 void
-pcibr_intr_list_func(intr_arg_t arg)
+pcibr_intr_func(intr_arg_t arg)
 {
     pcibr_intr_wrap_t       wrap = (pcibr_intr_wrap_t) arg;
-    reg_p                   statp = wrap->iw_stat;
-    bridgereg_t             mask = wrap->iw_intr;
     reg_p                   wrbf;
-    pcibr_intr_list_t       list;
-    pcibr_intr_t            intr;
     intr_func_t             func;
+    pcibr_intr_t            intr;
+    pcibr_intr_list_t       list;
     int                     clearit;
-    int                     thread_count = 0;
+#ifdef KERNEL_THREADS
+    int			    do_nonthreaded = 0;
+    int			    do_threaded = 1;
+    int			    is_threaded = 0;
+#else
+    int			    do_nonthreaded = 1;
+    int			    do_threaded = 0;
+    int			    is_threaded = 0;
+#endif
+    int			    nonthreaded_count = 0;
+    int			    x = 0;
+
+	/*
+	 * If any handler is still running from a previous interrupt
+	 * just return. If there's a need to call the handler(s) again,
+	 * another interrupt will be generated either by the device or by
+	 * pcibr_force_interrupt().
+	 */
+
+	if (wrap->iw_hdlrcnt) {
+		return;
+	}
 
     /*
-     * Loop until either
-     * 1) All interrupts have been removed by direct-called interrupt handlers OR
-     * 2) We've woken up at least one interrupt thread that will presumably clear
-     *    Bridge interrupt bits
+     * Call all interrupt handlers registered.
+     * First, the pcibr_intrd threads for any threaded handlers will be
+     * awoken, then any non-threaded handlers will be called sequentially.
      */
 	
-    while ((!thread_count) && (mask & *statp)) {
 	clearit = 1;
-	for (list = wrap->iw_list;
-	     list != NULL;
-	     list = list->il_next) {
-	    if ((intr = list->il_intr) &&
-		(intr->bi_flags & PCIIO_INTR_CONNECTED)) {
-    		int is_threaded;
+	while (do_threaded || do_nonthreaded) {
+	    for (list = wrap->iw_list; list != NULL; list = list->il_next) {
+		if ((intr = list->il_intr) &&
+		    (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
 
-		ASSERT(intr->bi_func);
+		    ASSERT(intr->bi_func);
 
 		/*
 		 * This device may have initiated write
 		 * requests since the bridge last saw
 		 * an edge on this interrupt input; flushing
-		 * the buffer here should help but may not
-		 * be sufficient if we get more requests after
-		 * the flush, followed by the card deciding
-		 * it wants service, before the interrupt
-		 * handler checks to see if things need
+		 * the buffer prior to invoking the handler
+		 * should help but may not be sufficient if we 
+		 * get more requests after the flush, followed
+		 * by the card deciding it wants service, before
+		 * the interrupt handler checks to see if things need
 		 * to be done.
 		 *
 		 * There is a similar race condition if
@@ -7238,28 +7509,96 @@
 		 * has completed, but before observing the
 		 * contents of memory?
 		 */
-#ifdef IRIX
-		if (wrbf = list->il_wrbf)
+
+#ifdef KERNEL_THREADS
+		    is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD);
+		    if (!is_threaded) {
+			nonthreaded_count++;
+		    }
+
+		    if ((do_threaded) && (is_threaded)) {
+			/* Only need to flush write buffers if sharing */
+
+			if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) {
+			    if (x = *wrbf)	/* write request buffer flush */
+#ifdef SUPPORT_PRINTING_V_FORMAT
+				PRINT_ALERT("pcibr_intr_func %v: \n"
+				    "write buffer flush failed, wrbf=0x%x\n", 
+				    list->il_intr->bi_dev, wrbf);
 #else
-		if ((wrbf = list->il_wrbf))
+				PRINT_ALERT("pcibr_intr_func 0x%x: \n"
+				    "write buffer flush failed, wrbf=0x%x\n", 
+				    list->il_intr->bi_dev, wrbf);
 #endif
-		    (void) *wrbf;	/* write request buffer flush */
+			}
+
+			/*
+			 * Keep a running count of the number of interrupt
+			 * handlers that have yet to complete. 
+			 */
+			atomicAddInt(&(wrap->iw_hdlrcnt), 1);
+
+			/* 
+			 * Prior to waking up pcibr_intrd, a pointer to the 
+			 * wrapper struct corresponding to the interrupt taken
+			 * needs to be queued in the interrupt circular buffer.
+			 * The pcibr_intrd thread needs the wrapper pointer in
+			 * order to decrement the handler count (iw_hdlrcnt).
+			 */
+			pcibr_wrap_put(wrap, &intr->bi_ibuf);
+#ifdef ITHREAD_LATENCY
+			xthread_set_istamp(intr->bi_tinfo.thd_latstats);
+#endif /* ITHREAD_LATENCY */
+		     	up(&intr->bi_tinfo.thd_isync); 
+		    } else
+#endif	/* KERNEL_THREADS */
+			if ((do_nonthreaded) && (!is_threaded)) {
+			/* Non-threaded. 
+			 * Call the interrupt handler at interrupt level
+			 */
 
-		is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD);
+			/* Only need to flush write buffers if sharing */
 
-		if (is_threaded) {
-			thread_count++;
-#ifdef IRIX
-			icvsema(&intr->bi_tinfo.thd_isync, intr->bi_tinfo.thd_pri,
-				NULL, NULL, NULL);
+			if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) {
+			    if ((x = *wrbf))	/* write request buffer flush */
+#ifdef SUPPORT_PRINTING_V_FORMAT
+				PRINT_ALERT("pcibr_intr_func %v: \n"
+				    "write buffer flush failed, wrbf=0x%x\n", 
+				    list->il_intr->bi_dev, wrbf);
+#else
+				PRINT_ALERT("pcibr_intr_func %p: \n"
+				    "write buffer flush failed, wrbf=0x%x\n", 
+				    list->il_intr->bi_dev, wrbf);
 #endif
-		} else {
-			/* Non-threaded.  Call the interrupt handler at interrupt level */
+			}
+
 			func = intr->bi_func;
 			func(intr->bi_arg);
+		    }
+
+		    clearit = 0;
 		}
+	    }
+
+	    if (do_threaded) {
+		/* 
+		 * All threaded handlers have been called;
+		 * next do non-threaded, if any.
+		 */
+		do_threaded = 0;
 
-		clearit = 0;
+		if (nonthreaded_count)
+			do_nonthreaded = 1;
+	    } else {
+		do_nonthreaded = 0;
+		/*
+		 * If the non-threaded handler was the last to complete,
+		 * (i.e., no threaded handlers still running) force an
+		 * interrupt to avoid a potential deadlock situation.
+		 */
+		if (wrap->iw_hdlrcnt == 0) {
+			pcibr_force_interrupt(wrap);
+		}
 	    }
 	}
 
@@ -7275,7 +7614,8 @@
 	    pcibr_soft_t            pcibr_soft = wrap->iw_soft;
 	    bridge_t               *bridge = pcibr_soft->bs_base;
 	    bridgereg_t             b_int_enable;
-	    unsigned                s;
+	    bridgereg_t		    mask = 1 << wrap->iw_intr;
+	    unsigned long           s;
 
 	    s = pcibr_lock(pcibr_soft);
 	    b_int_enable = bridge->b_int_enable;
@@ -7285,7 +7625,6 @@
 	    pcibr_unlock(pcibr_soft, s);
 	    return;
 	}
-    }
 }
 
 /* =====================================================================
@@ -7403,7 +7742,7 @@
 		bridge->b_pci_err_lower);
     }
     if (int_status & BRIDGE_ISR_ERROR_FATAL) {
-	cmn_err_tag(14, (int)CE_PANIC, "PCI Bridge Error interrupt killed the system");
+	PRINT_PANIC("PCI Bridge Error interrupt killed the system");
 	/*NOTREACHED */
     } else {
 	PRINT_ALERT( "Non-fatal Error in Bridge..");
@@ -7491,10 +7830,8 @@
 				soft->bs_slot[slot].bss_window[win].bssw_base;
 			else if (map->bp_space == PCIIO_SPACE_ROM)
 			    base += pcibr_info->f_rbase;
-#ifdef IRIX
 			if ((pci_addr >= base) && (pci_addr < (base + size)))
-			    atomicAddInt(map->bp_toc, 1);
-#endif
+			    atomic_inc(map->bp_toc);
 		    }
 		}
 	    }
@@ -7532,34 +7869,8 @@
     bridgereg_t             err_status;
     int                     i;
 
-#if defined(SN0_HWDEBUG)
-    extern int		    la_trigger_nasid1;
-    extern int		    la_trigger_nasid2;
-    extern long		    la_trigger_val;
-#endif
-
     /* REFERENCED */
     bridgereg_t             disable_errintr_mask = 0;
-#ifdef IRIX
-    int 		    rv;
-#else
-    int                     rv = 0;
-#endif
-    int 		    error_code = IOECODE_DMA | IOECODE_READ;
-    ioerror_mode_t 	    mode = MODE_DEVERROR;
-    ioerror_t 	            ioe;
-
-#if defined(SN0_HWDEBUG)
-   /*
-    * trigger points for logic analyzer. Used to debug the DMA timeout
-    * note that 0xcafe is added to the trigger values to avoid false
-    * triggers when la_trigger_val shows up in a cacheline as data
-    */
-   if (la_trigger_nasid1 != -1) 
-	REMOTE_HUB_PI_S(la_trigger_nasid1, 0, PI_CPU_NUM, la_trigger_val + 0xcafe);
-   if (la_trigger_nasid2 != -1) 
-	REMOTE_HUB_PI_S(la_trigger_nasid2, 0, PI_CPU_NUM, la_trigger_val + 0xcafe);
-#endif
 
 #if PCIBR_SOFT_LIST
     /* IP27 seems to be handing us junk.
@@ -7635,7 +7946,7 @@
 
 		bs_estat->bs_errcount_total++;
 
-#ifdef IRIX
+#ifdef LATER
 		current_tick = lbolt;
 #else
 		current_tick = 0;
@@ -7777,7 +8088,7 @@
     if ((err_status & BRIDGE_ISR_INVLD_ADDR) &&
 	((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower))
 	 == (BRIDGE_INT_RST_STAT & 0xff0))) {
-#ifdef IRIX
+#ifdef LATER
 	if (kdebug)
 	    PRINT_NOTICE( "%s bridge: ignoring llp/control address interrupt",
 		    pcibr_soft->bs_name);
@@ -7787,32 +8098,6 @@
     }
 #endif				/* PCIBR_LLP_CONTROL_WAR */
 
-    /* Check if this is the RESP_XTALK_ERROR interrupt. 
-     * This can happen due to a failed DMA READ operation.
-     */
-    if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) {
-	/* Phase 1 : Look at the error state in the bridge and further
-	 * down in the device layers.
-	 */
-#if defined(CONFIG_SGI_IO_ERROR_HANDLING)
-	(void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP);
-#endif
-	IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid);
-	(void)pcibr_error_handler((error_handler_arg_t)pcibr_soft,
-				  error_code,
-				  mode,
-				  &ioe);
-	/* Phase 2 : Perform the action agreed upon in phase 1.
-	 */
-#if defined(CONFIG_SGI_IO_ERROR_HANDLING)
-	(void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION);
-#endif
-	rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
-				 error_code,
-				 mode,
-				 &ioe);
-    }
-    if (rv != IOERROR_HANDLED) {
 #ifdef	DEBUG
 	if (err_status & BRIDGE_ISR_ERROR_DUMP)
 	    pcibr_error_dump(pcibr_soft);
@@ -7822,7 +8107,7 @@
 	    pcibr_error_dump(pcibr_soft);
 	}
 #endif
-    }
+
     /*
      * We can't return without re-enabling the interrupt, since
      * it would cause problems for devices like IOC3 (Lost
@@ -7853,11 +8138,7 @@
 		  iopaddr_t *offsetp,
 		  pciio_function_t *funcp)
 {
-#ifdef IRIX
-    int                     s, f, w;
-#else
     int                     s, f=0, w;
-#endif
     iopaddr_t               base;
     size_t                  size;
     pciio_piospace_t        piosp;
@@ -8082,7 +8363,7 @@
  * decodes the PCI specific portions -- we count on our
  * callers to dump the raw IOE data.
  */
-#ifdef colin
+#ifdef LATER
 #define BEM_ADD_IOE(ioe)						\
 	do {								\
 	    if (IOERROR_FIELDVALID(ioe, busspace)) {			\
@@ -8165,7 +8446,7 @@
      * and need to construct the slot/space/offset.
      */
 
-#ifdef colin
+#ifdef LATER
     bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr);
 #else
     bad_xaddr = -1;
@@ -8207,7 +8488,7 @@
 	if (x > 1)
 	    x--;
 	/* x is which devio reg; no guarantee
-	 * pci slot x will be responding.
+	 * PCI slot x will be responding.
 	 * still need to figure out who decodes
 	 * space/offset on the bus.
 	 */
@@ -8253,7 +8534,7 @@
 
     if ((slot == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) {
 	/* we've got a space/offset but not which
-	 * pci slot decodes it. Check through our
+	 * PCI slot decodes it. Check through our
 	 * notions of which devices decode where.
 	 *
 	 * Yes, this "duplicates" some logic in
@@ -8353,9 +8634,7 @@
 		wx = PCIIO_SPACE_MEM;
 	    wl = wb + ws;
 	    if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) {
-#ifdef IRIX
-		atomicAddInt(map->bp_toc, 1);
-#endif
+		atomic_inc(map->bp_toc);
 		if (slot == PCIIO_SLOT_NONE) {
 		    slot = cs;
 		    space = map->bp_space;
@@ -8369,7 +8648,7 @@
 
     if (space != PCIIO_SPACE_NONE) {
 	if (slot != PCIIO_SLOT_NONE) {
-#ifdef IRIX
+#ifdef LATER
 	    if (func != PCIIO_FUNC_NONE)
 		IOERROR_SETVALUE(ioe, widgetdev, 
 				 pciio_widgetdev_create(slot,func));
@@ -8451,10 +8730,10 @@
      * error interrupt is due to read/write error..
      */
 
-    /* We know the xtalk addr, the raw pci bus space,
-     * the raw pci bus address, the decoded pci bus
+    /* We know the xtalk addr, the raw PCI bus space,
+     * the raw PCI bus address, the decoded PCI bus
      * space, the offset within that space, and the
-     * decoded pci slot (which may be "PCIIO_SLOT_NONE" if no slot
+     * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot
      * is known to be involved).
      */
 
@@ -8506,7 +8785,7 @@
 	    BEM_ADD_VAR(raw_paddr);
 	    if (IOERROR_FIELDVALID(ioe, widgetdev)) {
 
-#ifdef colin
+#ifdef LATER
 		slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, 
 								 widgetdev));
 		func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, 
@@ -8545,7 +8824,7 @@
 	 *      Need a way to ensure we don't inadvertently clear some
 	 *      other errors.
 	 */
-#ifdef IRIX
+#ifdef LATER
 	if (IOERROR_FIELDVALID(ioe, widgetdev))
 	    pcibr_device_disable(pcibr_soft, 
 				 pciio_widgetdev_slot_get(
@@ -8586,7 +8865,7 @@
      * Look up the address, in the bridge error registers, and
      * take appropriate action
      */
-#ifdef colin
+#ifdef LATER
     ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid);
     ASSERT(bridge);
 #endif
@@ -8618,7 +8897,7 @@
 
     retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);
     if (retval != IOERROR_HANDLED)
-#ifdef colin
+#ifdef LATER
 	pcibr_device_disable(pcibr_soft, 
 			     pciio_widgetdev_slot_get(
 				      IOERROR_GETVALUE(ioe,widgetdev)));
@@ -8690,7 +8969,7 @@
 
     retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);
 
-#ifdef IRIX
+#ifdef LATER
     if (retval != IOERROR_HANDLED) {
 	pcibr_device_disable(pcibr_soft, 
 			     pciio_widgetdev_slot_get(
@@ -8722,22 +9001,8 @@
 {
     pcibr_soft_t            pcibr_soft;
     int                     retval = IOERROR_BADERRORCODE;
-    devfs_handle_t	    xconn_vhdl,pcibr_vhdl;
-#if defined(CONFIG_SGI_IO_ERROR_HANDLING)
-    error_state_t	    e_state;
-#endif
-    pcibr_soft = (pcibr_soft_t) einfo;
-
-    xconn_vhdl = pcibr_soft->bs_conn;
-    pcibr_vhdl = pcibr_soft->bs_vhdl;
 
-#if defined(CONFIG_SGI_IO_ERROR_HANDLING)
-    e_state = error_state_get(xconn_vhdl);
-    
-    if (error_state_set(pcibr_vhdl, e_state) == 
-	ERROR_RETURN_CODE_CANNOT_SET_STATE)
-	return(IOERROR_UNHANDLED);
-#endif
+    pcibr_soft = (pcibr_soft_t) einfo;
 
     /* If we are in the action handling phase clean out the error state
      * on the xswitch.
@@ -8844,7 +9109,7 @@
     bridge_t               *bridge = pcibr_soft->bs_base;
     bridgereg_t             ctlreg;
     unsigned                cfgctl[8];
-    unsigned                s;
+    unsigned long           s;
     int                     f, nf;
     pcibr_info_h            pcibr_infoh;
     pcibr_info_t            pcibr_info;
@@ -8869,11 +9134,7 @@
 	/* XXX delay? */
 
 	for (f = 0; f < nf; ++f)
-#ifdef IRIX
-	    if (pcibr_info = pcibr_infoh[f])
-#else
 	    if ((pcibr_info = pcibr_infoh[f]))
-#endif
 		for (win = 0; win < 6; ++win)
 		    if (pcibr_info->f_window[win].w_base != 0)
 			bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] =
@@ -8901,7 +9162,7 @@
     pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridgereg_t             devreg;
-    unsigned                s;
+    unsigned long           s;
 
     /*
      * Bridge supports hardware swapping; so we can always
@@ -8944,7 +9205,7 @@
 			pciio_slot_t pciio_slot,
 			pciio_priority_t device_prio)
 {
-    int                     s;
+    unsigned long           s;
     int                    *counter;
     bridgereg_t             rtbits = 0;
     bridgereg_t             devreg;
@@ -8966,9 +9227,9 @@
      * XXX- Bug in Rev B Bridge Si:
      * Symptom: Prefetcher starts operating incorrectly. This happens
      * due to corruption of the address storage ram in the prefetcher
-     * when a non-real time pci request is pulled and a real-time one is
+     * when a non-real time PCI request is pulled and a real-time one is
      * put in it's place. Workaround: Use only a single arbitration ring
-     * on pci bus. GBR and RR can still be uniquely used per
+     * on PCI bus. GBR and RR can still be uniquely used per
      * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C.
      */
 
@@ -8983,18 +9244,12 @@
     s = pcibr_lock(pcibr_soft);
     devreg = pcibr_soft->bs_slot[pciio_slot].bss_device;
     if (device_prio == PCI_PRIO_HIGH) {
-#ifdef IRIX
-	if (++*counter == 1)
-#else
 	if ((++*counter == 1)) {
-#endif
 	    if (rtbits)
 		devreg |= rtbits;
 	    else
 		rc = PRIO_FAIL;
-#ifndef IRIX
 	}
-#endif
     } else if (device_prio == PCI_PRIO_LOW) {
 	if (*counter <= 0)
 	    rc = PRIO_FAIL;
@@ -9082,15 +9337,11 @@
 
     if (set || clr) {
 	bridgereg_t             devreg;
-	unsigned                s;
+	unsigned long           s;
 
 	s = pcibr_lock(pcibr_soft);
 	devreg = pcibr_soft->bs_slot[pciio_slot].bss_device;
-#ifdef IRIX
-	devreg = devreg & ~clr | set;
-#else
 	devreg = (devreg & ~clr) | set;
-#endif
 	if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	    bridge_t               *bridge = pcibr_soft->bs_base;
 
@@ -9146,13 +9397,9 @@
 
     pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
 
-    if ( (pcibr_soft_t)0 != pcibr_soft ) {
-	bridge = pcibr_soft->bs_base;
-	if ( (bridge_t *)0 != bridge ) {
-		cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l;
-	}
-    }
+    bridge = pcibr_soft->bs_base;
 
+    cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l;
 
     return cfgbase;
 }
@@ -9215,7 +9462,7 @@
     case 3:
 	if (reg & 1) {
 	    CB(cfgbase, reg) = value;
-	    CS(cfgbase, reg + 1) = value >> 8;
+	    CS(cfgbase, (reg + 1)) = value >> 8;
 	} else {
 	    CS(cfgbase, reg) = value;
 	    CB(cfgbase, reg + 2) = value >> 16;
@@ -9266,6 +9513,16 @@
 
     (pciio_error_devenable_f *) pcibr_error_devenable,
     (pciio_error_extract_f *) pcibr_error_extract,
+
+#ifdef LATER
+    (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback,
+    (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback,
+#else
+    (pciio_driver_reg_callback_f *) 0,
+    (pciio_driver_unreg_callback_f *) 0,
+#endif
+    (pciio_device_unregister_f 	*) pcibr_device_unregister,
+    (pciio_dma_enabled_f		*) pcibr_dma_enabled,
 };
 
 LOCAL                   pcibr_hints_t
@@ -9299,7 +9556,7 @@
     return (pcibr_hints_t) ainfo;
 
 abnormal_exit:
-#ifdef IRIX
+#ifdef LATER
     printf("SHOULD NOT BE HERE\n");
 #endif
     DEL(hint);
@@ -9417,12 +9674,7 @@
 	if (ainfo == (arbitrary_info_t) subdevp)
 	    return;
 	DEL(subdevp);
-#ifdef IRIX
-	if (ainfo == NULL)
-#else
-	if (ainfo == (arbitrary_info_t) NULL)
-#endif
-	{
+	if (ainfo == (arbitrary_info_t) NULL) {
 #if DEBUG
 	    printk("pcibr_hints_subdevs: null subdevs ptr at\n"
 		    "\t%p\n", pconn_vhdl);
@@ -9438,7 +9690,7 @@
 }
 
 
-#ifdef colin
+#ifdef LATER
 
 #include <sys/idbg.h>
 #include <sys/idbgentry.h>
@@ -9531,7 +9783,7 @@
 	    pss->bss_d32_base, pss->bss_d32_flags);
     
     qprintf("\tExt ATEs active ? %s", 
-	    pss->bss_ext_ates_active ? "yes" : "no");
+	    atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no");
     qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer);
     qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow);
 
@@ -9559,7 +9811,7 @@
 	qprintf("Invalid ips %d\n",ips);
 }
 
-#endif /* colin */
+#endif /* LATER */
 
 int
 pcibr_dma_enabled(devfs_handle_t pconn_vhdl)
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/pciio.c linux/arch/ia64/sn/io/pciio.c
--- v2.4.3/linux/arch/ia64/sn/io/pciio.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/pciio.c	Thu Apr  5 12:51:47 2001
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/slab.h>
 #include <asm/sn/sgi.h>
+#include <asm/sn/xtalk/xbow.h>	/* Must be before iograph.h to get MAX_PORT_NUM */
 #include <asm/sn/iograph.h>
 #include <asm/sn/invent.h>
 #include <asm/sn/hcl.h>
@@ -23,6 +24,7 @@
 #include <asm/sn/ioerror_handling.h>
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/pci/pciio_private.h>
+#include <asm/sn/sn_sal.h>
 
 #define DEBUG_PCIIO
 #undef DEBUG_PCIIO	/* turn this on for yet more console output */
@@ -38,28 +40,30 @@
 int
 badaddr_val(volatile void *addr, int len, volatile void *ptr)
 {
+	int ret = 0;
+	volatile void *new_addr;
+
 	switch (len) {
-		case 4: *(volatile u32*)ptr = *(((volatile u32*)(((u64) addr)^4)));
-		default: printk("FIXME: argh fix badaddr_val\n");
+		case 4:
+			new_addr = (void *)(((u64) addr)^4);
+			ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr);
+			break;
+		default:
+			printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len);
 	}
-	/* no such thing as a bad addr .... */
-	return(0);
-}
 
+	if (ret < 0)
+		panic("badaddr_val: unexpected status (%d) in probing", ret);
+	return(ret);
 
-void
-cmn_err_tag(int seqnumber, register int level, char *fmt, ...)
-{
 }
 
+
 nasid_t
 get_console_nasid(void)
 {
-#ifdef IRIX
+	extern nasid_t console_nasid;
 	return console_nasid;
-#else
-	return 0;
-#endif
 }
 
 int
@@ -208,8 +212,8 @@
 void			pciio_device_info_free(pciio_info_t);
 devfs_handle_t		pciio_device_info_register(devfs_handle_t, pciio_info_t);
 void			pciio_device_info_unregister(devfs_handle_t, pciio_info_t);
-int                     pciio_device_attach(devfs_handle_t);
-int			pciio_device_detach(devfs_handle_t);
+int                     pciio_device_attach(devfs_handle_t, int);
+int			pciio_device_detach(devfs_handle_t, int);
 void                    pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
 
 int                     pciio_reset(devfs_handle_t);
@@ -234,13 +238,30 @@
     pciio_info_t            card_info;
     pciio_provider_t       *provider_fns;
 
-    card_info = pciio_info_get(dev);
-    ASSERT(card_info != NULL);
+    /*
+     * We're called with two types of vertices, one is
+     * the bridge vertex (ends with "pci") and the other is the
+     * pci slot vertex (ends with "pci/[0-8]").  For the first type
+     * we need to get the provider from the PFUNCS label.  For
+     * the second we get it from fastinfo/c_pops.
+     */
+    provider_fns = pciio_provider_fns_get(dev);
+    if (provider_fns == NULL) {
+	card_info = pciio_info_get(dev);
+	if (card_info != NULL) {
+		provider_fns = pciio_info_pops_get(card_info);
+	}
+    }
+
+    if (provider_fns == NULL)
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	PRINT_PANIC("%v: provider_fns == NULL", dev);
+#else
+	PRINT_PANIC("0x%x: provider_fns == NULL", dev);
+#endif
 
-    provider_fns = pciio_info_pops_get(card_info);
-    ASSERT(provider_fns != NULL);
+    return provider_fns;
 
-    return (provider_fns);
 }
 
 #define DEV_FUNC(dev,func)	pciio_to_provider_fns(dev)->func
@@ -672,15 +693,21 @@
     error_state_t	    e_state;
 #endif
 
-#ifdef IRIX
 #if DEBUG && ERROR_DEBUG
-    cmn_err(CE_CONT, "%v: pciio_error_handler\n", pciio_vhdl);
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: pciio_error_handler\n", pciio_vhdl);
+#else
+    printk("0x%x: pciio_error_handler\n", pciio_vhdl);
 #endif
 #endif
 
-    IOERR_PRINTF(cmn_err(CE_NOTE,
-			 "%v: PCI Bus Error: Error code: %d Error mode: %d\n",
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    IOERR_PRINTF(printk("%v: PCI Bus Error: Error code: %d Error mode: %d\n",
 			 pciio_vhdl, error_code, mode));
+#else
+    IOERR_PRINTF(printk("0x%x: PCI Bus Error: Error code: %d Error mode: %d\n",
+			 pciio_vhdl, error_code, mode));
+#endif
 
     /* If there is an error handler sitting on
      * the "no-slot" connection point, give it
@@ -715,7 +742,7 @@
 	 * widgetdev is a 4byte value encoded as slot in the higher order
 	 * 2 bytes and function in the lower order 2 bytes.
 	 */
-#ifdef IRIX
+#ifdef LATER
 	slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioerror, widgetdev));
 #else
 	slot = 0;
@@ -732,9 +759,12 @@
 #if defined(CONFIG_SGI_IO_ERROR_HANDLING)
 		e_state = error_state_get(pciio_vhdl);
 
+
 		if (e_state == ERROR_STATE_ACTION)
 		    (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE);
 
+
+
 		if (error_state_set(pconn_vhdl,e_state) ==
 		    ERROR_RETURN_CODE_CANNOT_SET_STATE)
 		    return(IOERROR_UNHANDLED);
@@ -825,12 +855,18 @@
     ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE));
 
 #if DEBUG
-    cmn_err(CE_ALERT,
-	    "%v: pciio_endian_set is going away.\n"
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    PRINT_ALERT("%v: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#else
+    PRINT_ALERT("0x%x: pciio_endian_set is going away.\n"
 	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
 	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
 	    dev);
 #endif
+#endif
 
     return DEV_FUNC(dev, endian_set)
 	(dev, device_end, desired_end);
@@ -1027,8 +1063,6 @@
 	(pciio_info->c_fingerprint != pciio_info_fingerprint)) {
 #endif /* BRINGUP */
 
-	printk("pciio_info_get: Found fastinfo 0x%p but wrong fingerprint %s\n", pciio_info,
-	pciio_info->c_fingerprint);
 	return((pciio_info_t)-1); /* Should panic .. */
     }
 	
@@ -1198,7 +1232,11 @@
 pciio_attach(devfs_handle_t pciio)
 {
 #if DEBUG && ATTACH_DEBUG
-    cmn_err(CE_CONT, "%v: pciio_attach\n", pciio);
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: pciio_attach\n", pciio);
+#else
+    printk("0x%x: pciio_attach\n", pciio);
+#endif
 #endif
     return 0;
 }
@@ -1220,11 +1258,7 @@
 {
     arbitrary_info_t        ainfo;
 
-#ifdef IRIX
-    hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, &ainfo);
-#else
     hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo);
-#endif
 }
 
 /*
@@ -1258,7 +1292,7 @@
 
     return cdl_add_driver(pciio_registry,
 			  vendor_id, device_id,
-			  driver_prefix, flags);
+			  driver_prefix, flags, NULL);
 }
 
 /*
@@ -1274,7 +1308,33 @@
      */
     ASSERT(pciio_registry != NULL);
 
-    cdl_del_driver(pciio_registry, driver_prefix);
+    cdl_del_driver(pciio_registry, driver_prefix, NULL);
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being registered.
+ */
+void
+pciio_driver_reg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being unregistered.
+ */
+void
+pciio_driver_unreg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
 }
 
 /*
@@ -1307,7 +1367,6 @@
 		pciio_vendor_id_t vendor_id,
 		pciio_device_id_t device_id)
 {
-
     return pciio_device_info_register
 	(connectpt, pciio_device_info_new (NULL, master, slot, func,
 					   vendor_id, device_id));
@@ -1366,8 +1425,6 @@
 			    pciio_info->c_slot,
 			    pciio_info->c_func);
 
-    printk("pciio_device_info_register: connectpt 0x%p, pciio_info 0x%p\n", connectpt, pciio_info);
-
     if (GRAPH_SUCCESS !=
 	hwgraph_path_add(connectpt, name, &pconn))
 	return pconn;
@@ -1379,7 +1436,9 @@
 	int pos;
 	char dname[256];
 	pos = devfs_generate_path(pconn, dname, 256);
+#ifdef DEBUG_PCIIO
 	printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]);
+#endif
     }
 #endif /* BRINGUP */
 
@@ -1421,6 +1480,7 @@
     /* Remove the link to our pci provider */
     hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL);
 
+
     hwgraph_vertex_unref(pconn);
     hwgraph_vertex_destroy(pconn);
     
@@ -1447,18 +1507,21 @@
 static void
 pciio_device_inventory_remove(devfs_handle_t pconn_vhdl)
 {
-#ifdef IRIX
+#ifdef LATER
     hwgraph_inventory_remove(pconn_vhdl,-1,-1,-1,-1,-1);
 #endif
 }
 
 /*ARGSUSED */
 int
-pciio_device_attach(devfs_handle_t pconn)
+pciio_device_attach(devfs_handle_t pconn,
+		    int          drv_flags)
 {
     pciio_info_t            pciio_info;
     pciio_vendor_id_t       vendor_id;
     pciio_device_id_t       device_id;
+    int pciba_attach(devfs_handle_t);
+
 
     pciio_device_inventory_add(pconn);
     pciio_info = pciio_info_get(pconn);
@@ -1466,8 +1529,6 @@
     vendor_id = pciio_info->c_vendor;
     device_id = pciio_info->c_device;
 
-    printk("pciio_device_attach: Function 0x%p, vendor 0x%x, device_id %x\n", pconn, vendor_id, device_id);
-
     /* we don't start attaching things until
      * all the driver init routines (including
      * pciio_init) have been called; so we
@@ -1475,12 +1536,17 @@
      */
     ASSERT(pciio_registry != NULL);
 
-    return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn));
+    /*
+     * Since pciba is not called from cdl routines .. call it here.
+     */
+    pciba_attach(pconn);
 
+    return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));
 }
 
 int
-pciio_device_detach(devfs_handle_t pconn)
+pciio_device_detach(devfs_handle_t pconn,
+		    int          drv_flags)
 {
     pciio_info_t            pciio_info;
     pciio_vendor_id_t       vendor_id;
@@ -1499,10 +1565,9 @@
      */
     ASSERT(pciio_registry != NULL);
 
-    cdl_del_connpt(pciio_registry, vendor_id, device_id, pconn);
+    return(cdl_del_connpt(pciio_registry, vendor_id, device_id,
+		          pconn, drv_flags));
 
-    return(0);
-    
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/sgi_if.c linux/arch/ia64/sn/io/sgi_if.c
--- v2.4.3/linux/arch/ia64/sn/io/sgi_if.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/sgi_if.c	Thu Apr  5 12:51:47 2001
@@ -21,8 +21,6 @@
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/slotnum.h>
 
-#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name);
-
 void *
 kmem_zalloc(size_t size, int flag)
 {
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/sgi_io_init.c linux/arch/ia64/sn/io/sgi_io_init.c
--- v2.4.3/linux/arch/ia64/sn/io/sgi_io_init.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/sgi_io_init.c	Thu Apr  5 12:51:47 2001
@@ -79,13 +79,8 @@
 void
 sgi_master_io_infr_init(void)
 {
-#ifdef Colin
-	/*
-	 * Simulate Big Window 0.
-	 * Only when we build for lutsen etc. ..
-	 */
-	simulated_BW0_init();
-#endif
+	int cnode;
+	extern int maxnodes;
 
 	/*
 	 * Do any early init stuff .. einit_tbl[] etc.
@@ -122,7 +117,9 @@
 	sn_mp_setup();
 
 	DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n");
-	per_hub_init(0); /* Need to get and send in actual cnode number */
+	for (cnode = 0; cnode < maxnodes; cnode++) {
+		per_hub_init(cnode);
+	}
 
 	/* We can do headless hub cnodes here .. */
 
@@ -188,7 +185,7 @@
 	/* Emulate cboot() .. */
 	mlreset(1); /* This is a slave cpu */
 
-	per_hub_init(0); /* Need to get and send in actual cnode number */
+	// per_hub_init(0); /* Need to get and send in actual cnode number */
 
 	/* Done */
 }
@@ -212,12 +209,8 @@
 	 * do not currently support yet .. just a hack for now.
 	 */
 #ifdef NUMA_BASE
-	DBG("sn_mp_setup(): maxnodes= %d  numnodes= %d\n", maxnodes,numnodes);
         maxnodes = numnodes;
-#ifdef SIMULATED_KLGRAPH
-	maxnodes = 1;
-	numnodes = 1;
-#endif /* SIMULATED_KLGRAPH */
+	DBG("sn_mp_setup(): maxnodes= %d  numnodes= %d\n", maxnodes,numnodes);
         printk("sn_mp_setup(): Allocating backing store for *Nodepdaindr[%2d] \n",
                 maxnodes);
 
@@ -259,6 +252,14 @@
 	 *      ml/SN/promif.c
 	 */
 
+#ifdef CONFIG_IA64_SGI_SN1
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		/* Skip holes in CPU space */
+		if (cpu_enabled(cpu)) {
+			init_platform_pda(cpu);
+		}
+	}
+#endif
 	for (cnode = 0; cnode < maxnodes; cnode++) {
 		/*
 		 * Set up platform-dependent nodepda fields.
@@ -267,29 +268,7 @@
 		 */
 		DBG("sn_mp_io_setup: calling init_platform_nodepda(%2d)\n",cnode);
 		init_platform_nodepda(Nodepdaindr[cnode], cnode);
-
-		/*
-		 * This routine clears the Hub's Interrupt registers.
-		 */
-#ifndef CONFIG_IA64_SGI_IO
-		/*
-		 * We need to move this intr_clear_all() routine 
-		 * from SN/intr.c to a more appropriate file.
-		 * Talk to Al Mayer.
-		 */
-                intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
-#endif
 	}
-
-#ifdef CONFIG_IA64_SGI_IO
-	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
-		/* Skip holes in CPU space */
-		if (cpu_enabled(cpu)) {
-			init_platform_pda(cpu);
-		}
-	}
-#endif
-
 	/*
 	 * Initialize platform-dependent vertices in the hwgraph:
 	 *	module
@@ -309,4 +288,26 @@
 	klhwg_add_all_modules(hwgraph_root);
 	DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n");
 	klhwg_add_all_nodes(hwgraph_root);
+
+
+	for (cnode = 0; cnode < maxnodes; cnode++) {
+
+		/*
+		 * This routine clears the Hub's Interrupt registers.
+		 */
+#ifdef CONFIG_IA64_SGI_SN1
+		/*
+		 * We need to move this intr_clear_all() routine 
+		 * from SN/intr.c to a more appropriate file.
+		 * Talk to Al Mayer.
+		 */
+                intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
+		/* now init the hub */
+	//	per_hub_init(cnode);
+#endif
+	}
+
+#if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
+	synergy_perf_init();
+#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/sgi_io_sim.c linux/arch/ia64/sn/io/sgi_io_sim.c
--- v2.4.3/linux/arch/ia64/sn/io/sgi_io_sim.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/sgi_io_sim.c	Thu Apr  5 12:51:47 2001
@@ -17,9 +17,6 @@
 #include <asm/sn/sn_private.h>
 #include <asm/sn/synergy.h>
 
-cnodeid_t nasid_to_compact_node[MAX_NASIDS];
-nasid_t compact_to_nasid_node[MAX_COMPACT_NODES];
-cnodeid_t cpuid_to_compact_node[MAXCPUS];
 cpuid_t         master_procid = 0;
 int maxnodes;
 char arg_maxnodes[4];
@@ -42,12 +39,6 @@
         return (strlen(s) != 0);
 }
 
-
-void pciba_init(void)
-{
-	FIXME("pciba_init : no-op\n");
-}
-
 void xbmon_init(void)
 {
 	FIXME("xbmon_init : no-op\n");
@@ -82,7 +73,7 @@
  * Routines provided by ml/SN/promif.c.
  */
 static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL;
-static nasid_t console_nasid;
+nasid_t console_nasid;
 static char console_wid;
 static char console_pcislot;
 
@@ -90,19 +81,12 @@
 set_master_bridge_base(void)
 {
 
-#ifdef SIMULATED_KLGRAPH
-	printk("set_master_bridge_base: SIMULATED_KLGRAPH FIXME hardwired master.\n");
-	console_nasid = 0;
-	console_wid = 0x8;
-	console_pcislot = 0x2;
-#else
         console_nasid = KL_CONFIG_CH_CONS_INFO(master_nasid)->nasid;
         console_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base);
         console_pcislot = KL_CONFIG_CH_CONS_INFO(master_nasid)->npci;
-#endif /* SIMULATED_KLGRAPH */
-
         master_bridge_base = (__psunsigned_t)NODE_SWIN_BASE(console_nasid,
                                                             console_wid);
+	FIXME("WARNING: set_master_bridge_base: NON NASID 0 DOES NOT WORK\n");
 }
 
 int
@@ -133,21 +117,6 @@
         } else {
                 return 0;
         }
-}
-
-cnodeid_t
-nasid_to_compact_nodeid(nasid_t nasid)
-{
-        ASSERT(nasid >= 0 && nasid < MAX_NASIDS);
-        return nasid_to_compact_node[nasid];
-}
-
-nasid_t
-compact_to_nasid_nodeid(cnodeid_t cnode)
-{
-        ASSERT(cnode >= 0 && cnode <= MAX_COMPACT_NODES);
-        ASSERT(compact_to_nasid_node[cnode] >= 0);
-        return compact_to_nasid_node[cnode];
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/stubs.c linux/arch/ia64/sn/io/stubs.c
--- v2.4.3/linux/arch/ia64/sn/io/stubs.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/stubs.c	Thu Apr  5 12:51:47 2001
@@ -31,8 +31,6 @@
 int force_fire_and_forget;
 int ignore_conveyor_override;
 
-#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name);
-
 devfs_handle_t dummy_vrtx;	/* Needed for cpuid_to_vertex() in hack.h */
 
 
@@ -105,32 +103,6 @@
 	return((zone_t *)0);
 }
 
-uint64_t
-rmalloc(struct map *mp, size_t size)
-{
-	FIXME("rmalloc : returns NULL");
-	return((uint64_t)0);
-}
-
-void
-rmfree(struct map *mp, size_t size, uint64_t a)
-{
-	FIXME("rmfree : no-op");
-}
-
-struct map *
-rmallocmap(uint64_t mapsiz)
-{
-	FIXME("rmallocmap : returns NULL");
-	return((struct map *)0);
-}
-
-void
-rmfreemap(struct map *mp)
-{
-	FIXME("rmfreemap : no-op");
-}
-
 int
 compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr)
 {
@@ -170,40 +142,6 @@
 ioc3_console_vhdl_get(void)
 	{FIXME("ioc3_console_vhdl_get"); return( (devfs_handle_t)-1);}
 
-
-#if 0
-#define io_splock(l) 1
-#define io_spunlock(l,s)
-
-#define spinlock_destroy(a)     /* needed by pcibr_detach() */
-#define mutex_spinlock(a) 0
-#define mutex_spinunlock(a,b)
-#define mutex_init(a,b,c)               ;
-#define mutex_lock(a,b)                 ;
-#define mutex_unlock(a)                 ;
-#define dev_to_vhdl(dev) 0
-#define get_timestamp() 0
-#define us_delay(a)
-#define v_mapphys(a,b,c) 0
-#define splhi()  0
-#define splx(s)
-#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name);
-#endif /* 0 */
-
-int
-cap_able(uint64_t x)
-{
-	FIXME("cap_able : returns 1");
-	return(1);
-}
-
-int
-cap_able_cred(uint64_t a, uint64_t b)
-{
-	FIXME("cap_able_cred : returns 1");
-	return(1);
-}
-
 void
 nic_vmc_check(devfs_handle_t vhdl, char *nicinfo)
 {
@@ -236,21 +174,5 @@
               uint64_t value)
 {
 	FIXME("vector_write_node\n");
-	return(0);
-}
-
-int
-atomicAddInt(int *int_ptr, int value)
-{
-//	FIXME("atomicAddInt : simple add\n");
-	*int_ptr += value;
-	return(0);
-}
-
-int
-atomicClearInt(int *int_ptr, int value)
-{
-	FIXME("atomicClearInt : simple clear\n");
-	*int_ptr &= ~value;
 	return(0);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/xbow.c linux/arch/ia64/sn/io/xbow.c
--- v2.4.3/linux/arch/ia64/sn/io/xbow.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/ia64/sn/io/xbow.c	Thu Apr 12 12:16:35 2001
@@ -9,7 +9,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <asm/sn/sgi.h>
@@ -17,19 +16,18 @@
 #include <asm/sn/invent.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
+#include <asm/sn/hack.h>
 #include <asm/sn/pci/bridge.h>
 #include <asm/sn/xtalk/xtalk_private.h>
 
-#define DEBUG		1
-#define XBOW_DEBUG	1
+/* #define DEBUG		1 */
+/* #define XBOW_DEBUG	1 */
 
 
 /*
  * Files needed to get the device driver entry points
  */
 
-/* #include <asm/cred.h> */
-
 #include <asm/sn/xtalk/xbow.h>
 #include <asm/sn/xtalk/xtalk.h>
 #include <asm/sn/xtalk/xswitch.h>
@@ -66,7 +64,7 @@
     xbow_perf_t             xbow_perfcnt[XBOW_PERF_COUNTERS];
     xbow_perf_link_t        xbow_perflink[MAX_XBOW_PORTS];
     xbow_link_status_t      xbow_link_status[MAX_XBOW_PORTS];
-    lock_t                  xbow_perf_lock;
+    spinlock_t              xbow_perf_lock;
     int                     link_monitor;
     widget_cfg_t	   *wpio[MAX_XBOW_PORTS];	/* cached PIO pointer */
 
@@ -74,7 +72,7 @@
      * destination port since contention happens there.
      * Implicit mapping from xbow ports (8..f) -> (0..7) array indices.
      */
-    lock_t		    xbow_bw_alloc_lock;		/* bw allocation lock */
+    spinlock_t		    xbow_bw_alloc_lock;		/* bw allocation lock */
     unsigned long long	    bw_hiwm[MAX_XBOW_PORTS];	/* hiwater mark values */
     unsigned long long      bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */
 };
@@ -118,15 +116,8 @@
 
 int                     xbow_disable_llp_monitor(devfs_handle_t);
 int                     xbow_enable_llp_monitor(devfs_handle_t);
-
-#ifdef IRIX
-int			xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
-				unsigned long long, unsigned long long);
-#else
 int                     xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
                                 unsigned long long, unsigned long long);
-#endif
-
 
 xswitch_reset_link_f    xbow_reset_link;
 
@@ -237,7 +228,11 @@
     int			    xbow_num;
 	
 #if DEBUG && ATTACH_DEBUG
-    cmn_err(CE_CONT, "%v: xbow_attach\n", conn);
+#if defined(SUPPORT_PRINTING_V_FORMAT
+    printk("%v: xbow_attach\n", conn);
+#else
+    printk("0x%x: xbow_attach\n", conn);
+#endif
 #endif
 
     /*
@@ -261,7 +256,9 @@
      * of our connection point.
      */
     busv = hwgraph_connectpt_get(conn);
+#if DEBUG && ATTACH_DEBUG
     printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow);
+#endif
 
     ASSERT(busv != GRAPH_VERTEX_NONE);
 
@@ -283,8 +280,7 @@
                         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
                         /* &hcl_fops */ (void *)&vhdl, NULL);
     if (!vhdl) {
-        printk("xbow_attach: Unable to create char device for xbow conn
-0x%p\n",
+        printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n",
                 conn);
     }
 
@@ -306,11 +302,7 @@
     /* Add xbow number as a suffix to the hwgraph name of the xbow.
      * This is helpful while looking at the error/warning messages.
      */
-#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
     xbow_num = 0;
-#else
-    xbow_num = xswitch_id_get(busv);
-#endif
 
     /*
      * get the name of this xbow vertex and keep the info.
@@ -341,7 +333,7 @@
      * Crossbow is DOWNREV: these chips are not good
      * to have around, and the operator should be told.
      */
-#ifdef IRIX
+#ifdef	LATER
 #if !DEBUG
     if (
 #if SHOW_REVS
@@ -349,8 +341,7 @@
 #endif	/* SHOW_REVS */
 	   (rev < XBOW_REV_1_1))
 #endif	/* !DEBUG  */
-	cmn_err((rev < XBOW_REV_1_1) ? CE_WARN : CE_CONT,
-		"%sCrossbow ASIC: rev %s (code=%d) at %s%s",
+	printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s",
 		(rev < XBOW_REV_1_1) ? "DOWNREV " : "",
 		(rev == XBOW_REV_1_0) ? "1.0" :
 		(rev == XBOW_REV_1_1) ? "1.1" :
@@ -362,14 +353,13 @@
 		"unknown",
 		rev, soft->name,
 		(rev < XBOW_REV_1_1) ? "" : "\n");
-#endif	/* IRIX */
-
-    spinlock_init(&soft->xbow_perf_lock, "xbow_perf_lock");
+#endif	/* LATER */
+    mutex_spinlock_init(&soft->xbow_perf_lock);
     soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a;
     soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b;
 
     /* Initialization for GBR bw allocation */
-    spinlock_init(&soft->xbow_bw_alloc_lock, "xbow_bw_alloc_lock");
+    mutex_spinlock_init(&soft->xbow_bw_alloc_lock);
 
 #define	XBOW_8_BIT_PORT_BW_MAX		(400 * 1000 * 1000)	/* 400 MB/s */
 #define XBOW_16_BIT_PORT_BW_MAX		(800 * 1000 * 1000)	/* 800 MB/s */
@@ -403,7 +393,7 @@
     xwidget_error_register(conn, xbow_error_handler, soft);
 
 #else
-    printk("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n");
+    FIXME("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n");
 #endif /* LATER */
 
     /*
@@ -479,8 +469,6 @@
 int
 xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
 {
-    if (!_CAP_CRABLE((uint64_t)credp, CAP_DEVICE_MGT))
-	return EPERM;
     return 0;
 
 }
@@ -525,28 +513,9 @@
 	char		devname[MAXDEVNAME];
 	xwidget_info_t	xwidget_info;
 	int		i;
-#if IP27
-	cnodeid_t	cnodeid = CNODEID_NONE;
-#endif
 
 	vertex_to_name(dev, devname, MAXDEVNAME);
 
-#if IP30
-	/* If there is a ".connection" edge from this vertex,
-	 * then it must be "/hw/node" vertex. Return the widget
-	 * number for heart: 8.
-	 */
-	if (hwgraph_edge_get(dev, EDGE_LBL_CONN, &tdev) ==
-			GRAPH_SUCCESS) {
-		return ((xwidgetnum_t) 8);
-	}
-#elif IP27
-	if ((cnodeid = nodevertex_to_cnodeid(dev)) != CNODEID_NONE) {
-		ASSERT(cnodeid < maxnodes);
-		return(hub_widget_id(COMPACT_TO_NASID_NODEID(cnodeid)));
-	}
-#endif
-
 	/* If this is a pci controller vertex, traverse up using
 	 * the ".." links to get to the widget.
 	 */
@@ -601,7 +570,7 @@
     ASSERT_ALWAYS(rc != 0);
 #endif
     switch (cmd) {
-#ifdef IRIX
+#ifdef LATER
     case XBOWIOC_PERF_ENABLE:
     case XBOWIOC_PERF_DISABLE:
 	{
@@ -630,7 +599,7 @@
 	}
 #endif
 
-#ifdef IRIX
+#ifdef LATER
     case XBOWIOC_PERF_GET:
 	{
 	    xbow_perf_link_t       *xbow_perf_cnt;
@@ -652,10 +621,6 @@
 #endif
 
     case XBOWIOC_LLP_ERROR_ENABLE:
-	if (!_CAP_CRABLE((uint64_t)cr, CAP_DEVICE_MGT)) {
-	    error = EPERM;
-	    break;
-	}
 	if ((error = xbow_enable_llp_monitor(vhdl)) != 0)
 	    error = EINVAL;
 
@@ -663,16 +628,12 @@
 
     case XBOWIOC_LLP_ERROR_DISABLE:
 
-	if (!_CAP_CRABLE((uint64_t)cr, CAP_DEVICE_MGT)) {
-	    error = EPERM;
-	    break;
-	}
 	if ((error = xbow_disable_llp_monitor(vhdl)) != 0)
 	    error = EINVAL;
 
 	break;
 
-#ifdef IRIX
+#ifdef LATER
     case XBOWIOC_LLP_ERROR_GET:
 	{
 	    xbow_link_status_t     *xbow_llp_status;
@@ -693,17 +654,12 @@
 	}
 #endif
 
-#ifdef IRIX
+#ifdef LATER
     case GIOCSETBW:
 	{
 	    grio_ioctl_info_t info;
 	    xwidgetnum_t src_widgetnum, dest_widgetnum;
 
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
 	    if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
 		error = EFAULT;
 		break;
@@ -863,14 +819,14 @@
     xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
 }
 
-#define	XEM_ADD_STR(s)		cmn_err(CE_CONT, "%s", (s))
-#define	XEM_ADD_NVAR(n,v)	cmn_err(CE_CONT, "\t%20s: 0x%x\n", (n), (v))
+#define	XEM_ADD_STR(s)		printk("%s", (s))
+#define	XEM_ADD_NVAR(n,v)	printk("\t%20s: 0x%x\n", (n), (v))
 #define	XEM_ADD_VAR(v)		XEM_ADD_NVAR(#v,(v))
 #define XEM_ADD_IOEF(n) 	if (IOERROR_FIELDVALID(ioe,n))		    \
 				    XEM_ADD_NVAR("ioe." #n,		    \
 						 IOERROR_GETVALUE(ioe,n))
 
-#ifdef IRIX
+#ifdef LATER
 static void
 xem_add_ioe(ioerror_t *ioe)
 {
@@ -891,7 +847,7 @@
 }
 
 #define XEM_ADD_IOE()	(xem_add_ioe(ioe))
-#endif	/* IRIX */
+#endif	/* LATER */
 
 int                     xbow_xmit_retry_errors = 0;
 
@@ -971,7 +927,6 @@
 static void
 xbow_errintr_handler(intr_arg_t arg)
 {
-#ifdef IRIX
     ioerror_t               ioe[1];
     xbow_soft_t             soft = (xbow_soft_t) arg;
     xbow_t                 *xbow = soft->base;
@@ -1065,9 +1020,8 @@
 		    xwidget_vhdl = xbow_widget_lookup(soft->busv,port);
 		    xwidget_name = xwidget_name_get(xwidget_vhdl);
 
-#ifdef IRIX
-		    cmn_err(CE_CONT,
-			    "%s port %X[%s] XIO Bus Error",
+#ifdef	LATER
+		    printk("%s port %X[%s] XIO Bus Error",
 			    soft->name, port, xwidget_name);
 		    if (link_status & XB_STAT_MULTI_ERR)
 			XEM_ADD_STR("\tMultiple Errors\n");
@@ -1089,8 +1043,7 @@
 			XEM_ADD_STR("\tMaximum Request Timeout\n");
 		    if (link_status & XB_STAT_SRC_TOUT_ERR)
 			XEM_ADD_STR("\tSource Timeout Error\n");
-#endif
-
+#endif	/* LATER */
 		    {
 			int                     other_port;
 
@@ -1130,8 +1083,7 @@
 			| XB_WID_STAT_XTALK_ERR
 			| XB_WID_STAT_REG_ACC_ERR)) {
 
-	    cmn_err(CE_CONT,
-		    "%s Port 0 XIO Bus Error",
+	    printk("%s Port 0 XIO Bus Error",
 		    soft->name);
 	    if (wid_stat & XB_WID_STAT_MULTI_ERR)
 		XEM_ADD_STR("\tMultiple Error\n");
@@ -1150,9 +1102,8 @@
 	XEM_ADD_VAR(wid_err_upper);
 	XEM_ADD_VAR(wid_err_lower);
 	XEM_ADD_VAR(wid_err_addr);
-	cmn_err_tag(8, CE_PANIC, "XIO Bus Error");
+	PRINT_PANIC("XIO Bus Error");
     }
-#endif
 }
 #endif	/* LATER */
 
@@ -1180,7 +1131,6 @@
 		      ioerror_mode_t mode,
 		      ioerror_t *ioerror)
 {
-#ifdef IRIX
     int                     retval = IOERROR_WIDGETLEVEL;
 
     xbow_soft_t             soft = (xbow_soft_t) einfo;
@@ -1204,7 +1154,7 @@
     busv = soft->busv;
 
 #if DEBUG && ERROR_DEBUG
-    cmn_err(CE_CONT, "%s: xbow_error_handler\n", soft->name, busv);
+    printk("%s: xbow_error_handler\n", soft->name, busv);
 #endif
 
     port = IOERROR_GETVALUE(ioerror, widgetnum);
@@ -1217,14 +1167,12 @@
 	    return IOERROR_HANDLED;
 
 	if (error_code & IOECODE_DMA) {
-	    cmn_err(CE_ALERT,
-		    "DMA error blamed on Crossbow at %s\n"
+	    PRINT_ALERT("DMA error blamed on Crossbow at %s\n"
 		    "\tbut Crosbow never initiates DMA!",
 		    soft->name);
 	}
 	if (error_code & IOECODE_PIO) {
-	    cmn_err(CE_ALERT,
-		    "PIO Error on XIO Bus %s\n"
+	    PRINT_ALERt("PIO Error on XIO Bus %s\n"
 		    "\tattempting to access XIO controller\n"
 		    "\twith offset 0x%X",
 		    soft->name,
@@ -1258,14 +1206,12 @@
 	    return IOERROR_HANDLED;
 
 	if (error_code & IOECODE_DMA) {
-	    cmn_err(CE_ALERT,
-		    "DMA error blamed on XIO port at %s/%d\n"
+	    PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n"
 		    "\tbut Crossbow does not support that port",
 		    soft->name, port);
 	}
 	if (error_code & IOECODE_PIO) {
-	    cmn_err(CE_ALERT,
-		    "PIO Error on XIO Bus %s\n"
+	    PRINT_ALERT("PIO Error on XIO Bus %s\n"
 		    "\tattempting to access XIO port %d\n"
 		    "\t(which Crossbow does not support)"
 		    "\twith offset 0x%X",
@@ -1309,14 +1255,12 @@
 	    return IOERROR_HANDLED;
 
 	if (error_code & IOECODE_DMA) {
-	    cmn_err(CE_ALERT,
-		    "DMA error blamed on XIO port at %s/%d\n"
+	    PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n"
 		    "\tbut there is no device connected there.",
 		    soft->name, port);
 	}
 	if (error_code & IOECODE_PIO) {
-	    cmn_err(CE_ALERT,
-		    "PIO Error on XIO Bus %s\n"
+	    PRINT_ALERT("PIO Error on XIO Bus %s\n"
 		    "\tattempting to access XIO port %d\n"
 		    "\t(which has no device connected)"
 		    "\twith offset 0x%X",
@@ -1349,16 +1293,14 @@
 	if (mode == MODE_DEVPROBE)
 	    return IOERROR_HANDLED;
 
-	cmn_err(CE_ALERT,
-		"%s%sError on XIO Bus %s port %d",
+	PRINT_ALERT("%s%sError on XIO Bus %s port %d",
 		(error_code & IOECODE_DMA) ? "DMA " : "",
 		(error_code & IOECODE_PIO) ? "PIO " : "",
 		soft->name, port);
 
 	if ((error_code & IOECODE_PIO) &&
 	    (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
-	    cmn_err(CE_CONT,
-		    "\tAccess attempted to offset 0x%X\n",
+	    printk("\tAccess attempted to offset 0x%X\n",
 		    IOERROR_GETVALUE(ioerror, xtalkaddr));
 	}
 	if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD)
@@ -1393,16 +1335,14 @@
     if (retval == IOERROR_UNHANDLED) {
 	retval = IOERROR_PANIC;
 
-	cmn_err(CE_ALERT,
-		"%s%sError on XIO Bus %s port %d",
+	PRINT_ALERT("%s%sError on XIO Bus %s port %d",
 		(error_code & IOECODE_DMA) ? "DMA " : "",
 		(error_code & IOECODE_PIO) ? "PIO " : "",
 		soft->name, port);
 
 	if ((error_code & IOECODE_PIO) &&
 	    (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
-	    cmn_err(CE_CONT,
-		    "\tAccess attempted to offset 0x%X\n",
+	    printk("\tAccess attempted to offset 0x%X\n",
 		    IOERROR_GETVALUE(ioerror, xtalkaddr));
 	}
     }
@@ -1428,7 +1368,6 @@
      */
 
     return retval;
-#endif /* IRIX */
 }
 
 #endif	/* LATER */
@@ -1440,7 +1379,8 @@
     xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
     xbow_perf_link_t       *xbow_plink = xbow_soft->xbow_perflink;
     xbow_perfcount_t        perf_reg;
-    int                     link, s, i;
+    unsigned long           s;
+    int                     link, i;
 
     for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) {
 	if (xbow_perf->xp_mode == XBOW_MONITOR_NONE)
@@ -1460,7 +1400,7 @@
     }
     /* Do port /mode multiplexing here */
 
-#ifdef IRIX
+#ifdef LATER
     (void) timeout(xbow_update_perf_counters,
 		   (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT);
 #endif
@@ -1484,7 +1424,8 @@
     xbow_linkctrl_t         xbow_link_ctrl;
     xbow_t                 *xbow = xbow_soft->base;
     xbow_perfcount_t        perf_reg;
-    int                     s, i;
+    unsigned long           s;
+    int                     i;
 
     link -= BASE_XBOW_PORT;
     if ((link < 0) || (link >= MAX_XBOW_PORTS))
@@ -1525,7 +1466,7 @@
     *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val;
     xbow_perf->xp_current = perf_reg.xb_perf.count;
 
-#ifdef IRIX
+#ifdef LATER
     (void) timeout(xbow_update_perf_counters,
 		   (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT);
 #endif
@@ -1578,13 +1519,13 @@
 	    aux_sts.xb_aux_linkstatus.tx_retry_cnt;
 
 	if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {
-#ifdef IRIX
-	    cmn_err(CE_WARN, "link %d[%s]: bad status 0x%x\n",
+#ifdef	LATER
+	    PRINT_WARNING("link %d[%s]: bad status 0x%x\n",
 		    link, xwidget_name, lnk_sts.linkstatus);
 #endif
 	}
     }
-#ifdef IRIX
+#ifdef LATER
     if (xbow_soft->link_monitor)
 	(void) timeout(xbow_update_llp_status,
 		       (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT);
@@ -1611,7 +1552,7 @@
 {
     xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
 
-#ifdef IRIX
+#ifdef LATER
     (void) timeout(xbow_update_llp_status,
 		   (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT);
 #endif
@@ -1690,7 +1631,7 @@
     int                     i;
     xb_linkregs_t          *link;
 
-#ifdef IRIX
+#ifdef LATER
     if (dev_is_vertex((devfs_handle_t) regs)) {
 	devfs_handle_t            vhdl = (devfs_handle_t) regs;
 	xbow_soft_t             soft = xbow_soft_get(vhdl);
@@ -1702,7 +1643,7 @@
 	xbow = (xbow_t *) regs;
     }
 
-#ifdef IRIX
+#ifdef LATER
     qprintf("Printing xbow registers starting at 0x%x\n", xbow);
     qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n",
 	    xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper,
@@ -1716,7 +1657,7 @@
 
     for (i = 8; i <= 0xf; i++) {
 	link = &xbow->xb_link(i);
-#ifdef IRIX
+#ifdef LATER
 	qprintf("Link %d registers\n", i);
 	qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n",
 		link->link_control, link->link_status,
@@ -1795,7 +1736,7 @@
     xbow_soft_t             soft = xbow_soft_get(vhdl);
     volatile xbowreg_t     *xreg;
     xbowreg_t               mask;
-    int                     s;
+    unsigned long           s;
     int                     error = 0;
     bandwidth_t             old_bw_BYTES, req_bw_BYTES;
     xbowreg_t               old_xreg;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/xswitch.c linux/arch/ia64/sn/io/xswitch.c
--- v2.4.3/linux/arch/ia64/sn/io/xswitch.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/io/xswitch.c	Thu Apr  5 12:51:47 2001
@@ -88,13 +88,15 @@
 
     xswitch_info = (xswitch_info_t)
 	hwgraph_fastinfo_get(xwidget);
-#ifdef IRIX
+#ifdef	LATER
     if ((xswitch_info != NULL) &&
 	(xswitch_info->fingerprint != xswitch_info_fingerprint))
-	cmn_err(CE_PANIC, "%v xswitch_info_get bad fingerprint", xwidget);
+#ifdef SUPPORT_PRINTING_V_FORMAT
+	PRINT_PANIC("%v xswitch_info_get bad fingerprint", xwidget);
+#else
+	PRINT_PANIC("%x xswitch_info_get bad fingerprint", xwidget);
 #endif
-
-    printk("xswitch_info_get: xwidget 0x%p xswitch_info 0x%p\n", xwidget, xswitch_info);
+#endif	/* LATER */
 
     return (xswitch_info);
 }
@@ -118,9 +120,9 @@
 xswitch_info_vhdl_get(xswitch_info_t xswitch_info,
 		      xwidgetnum_t port)
 {
-#ifdef IRIX
+#ifdef	LATER
     if (xswitch_info == NULL)
-	cmn_err(CE_PANIC, "xswitch_info_vhdl_get: null xswitch_info");
+	PRINT_PANIC("xswitch_info_vhdl_get: null xswitch_info");
 #endif
 
 #if XSWITCH_CENSUS_PORT_MIN
@@ -196,8 +198,6 @@
 					       GRAPH_VERTEX_NONE);
 	}
 	xswitch_info_set(xwidget, xswitch_info);
-	printk("xswitch_info_new: xswitch_info_set xwidget 0x%p, xswitch_info 0x%p\n",
-		xwidget, xswitch_info);
     }
     return xswitch_info;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/xtalk.c linux/arch/ia64/sn/io/xtalk.c
--- v2.4.3/linux/arch/ia64/sn/io/xtalk.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/ia64/sn/io/xtalk.c	Thu Apr 12 12:16:35 2001
@@ -9,7 +9,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/iobus.h>
@@ -71,6 +70,7 @@
 void			xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t);
 void			xtalk_dmalist_drain(devfs_handle_t, alenlist_t);
 xtalk_intr_t            xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t);
+xtalk_intr_t            xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t);
 void                    xtalk_intr_free(xtalk_intr_t);
 int                     xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *, void *);
 void                    xtalk_intr_disconnect(xtalk_intr_t);
@@ -318,7 +318,7 @@
 			       unsigned flags)
 {
 #if DEBUG
-    cmn_err(CE_PANIC, "null_xtalk_early_piotrans_addr");
+    PRINT_PANIC("null_xtalk_early_piotrans_addr");
 #endif
     return NULL;
 }
@@ -439,6 +439,19 @@
 	(dev, dev_desc, owner_dev);
 }
 
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Unconditionally setup resources to be non-threaded.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc_nothd(devfs_handle_t dev,	/* which Crosstalk device */
+		 	device_desc_t dev_desc,	/* device descriptor */
+		 	devfs_handle_t owner_dev)	/* owner of this interrupt */
+{
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd)
+	(dev, dev_desc, owner_dev);
+}
 
 /*
  * Free resources consumed by intr_alloc.
@@ -527,7 +540,11 @@
     xwidget_info_t          xwidget_info;
 
 #if DEBUG && ERROR_DEBUG
-    cmn_err(CE_CONT, "%v: xtalk_error_handler\n", xconn);
+#ifdef SUPPORT_PRINTING_V_FORMAT
+    printk("%v: xtalk_error_handler\n", xconn);
+#else
+    printk("%x: xtalk_error_handler\n", xconn);
+#endif
 #endif
 
     xwidget_info = xwidget_info_get(xconn);
@@ -549,9 +566,13 @@
 	(mode == MODE_DEVREENABLE))
 	return IOERROR_HANDLED;
 
-#ifdef IRIX
-    cmn_err(CE_WARN, "Xbow at %v encountered Fatal error", xconn);
+#ifdef	LATER
+#ifdef SUPPORT_PRINTING_V_FORMAT
+    PRINT_WARNING("Xbow at %v encountered Fatal error", xconn);
+#else
+    PRINT_WARNING("Xbow at %x encountered Fatal error", xconn);
 #endif
+#endif	/* LATER */
     ioerror_dump("xtalk", error_code, mode, ioerror);
 
     return IOERROR_UNHANDLED;
@@ -648,13 +669,6 @@
     return (xtalk_intr->xi_sfarg);
 }
 
-
-int
-xtalk_intr_flags_get(xtalk_intr_t xtalk_intr)
-{
-	return(xtalk_intr->xi_flags);
-}
-
 /****** Generic crosstalk pio interfaces ******/
 devfs_handle_t
 xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap)
@@ -726,11 +740,15 @@
     widget_info = (xwidget_info_t)
 	hwgraph_fastinfo_get(xwidget);
 
-#ifdef IRIX
+#ifdef	LATER
     if ((widget_info != NULL) &&
 	(widget_info->w_fingerprint != widget_info_fingerprint))
-	cmn_err(CE_PANIC, "%v bad xwidget_info", xwidget);
+#ifdef SUPPORT_PRINTING_V_FORMAT
+	PRINT_PANIC("%v bad xwidget_info", xwidget);
+#else
+	PRINT_PANIC("%x bad xwidget_info", xwidget);
 #endif
+#endif	/* LATER */
 
     return (widget_info);
 }
@@ -894,7 +912,7 @@
 
     return cdl_add_driver(xtalk_registry,
 			  part_num, mfg_num,
-			  driver_prefix, flags);
+			  driver_prefix, flags, NULL);
 }
 
 /*
@@ -910,7 +928,7 @@
      */
     ASSERT(xtalk_registry != NULL);
 
-    cdl_del_driver(xtalk_registry, driver_prefix);
+    cdl_del_driver(xtalk_registry, driver_prefix, NULL);
 }
 
 /*
@@ -963,7 +981,6 @@
      * long as we have it, we can use it elsewhere.
      */
     s = dev_to_name(widget,devnm,MAXDEVNAME);
-    printk("xwidget_register: dev_to_name widget id 0x%p, s = %s\n", widget, s);
     widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
     strcpy(widget_info->w_name,s);
     
@@ -985,7 +1002,8 @@
     if (aa)
 	    async_attach_add_info(widget, aa);
 
-    return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, widget);
+    return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                          widget, 0);
 }
 
 /*
@@ -1009,8 +1027,8 @@
     
     hwid = &(widget_info->w_hwid);
 
-    cdl_del_connpt(xtalk_registry, hwid->part_num, 
-		   hwid->mfg_num, widget);
+    cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                   widget, 0);
 
     /* Clean out the xwidget information */
     (void)kfree(widget_info->w_name);
@@ -1051,7 +1069,7 @@
 
     xswitch_reset_link(xwidget);
     info = xwidget_info_get(xwidget);
-#ifdef IRIX
+#ifdef LATER
     ASSERT_ALWAYS(info != NULL);
 #endif
 
@@ -1083,26 +1101,7 @@
 	ASSERT(info != NULL);
 	return(xwidget_info_name_get(info));
 }
-/*
- * xtalk_device_powerup
- *	Reset and initialize the specified xtalk widget
- */
-int 
-xtalk_device_powerup(devfs_handle_t xbus_vhdl, xwidgetnum_t widget)
-{
-#ifndef CONFIG_IA64_SGI_IO
-	extern void	io_xswitch_widget_init(devfs_handle_t,
-					       devfs_handle_t,
-					       xwidgetnum_t,
-					       async_attach_t);
-	io_xswitch_widget_init(xbus_vhdl, 
-			       hwgraph_connectpt_get(xbus_vhdl),
-			       widget,
-			       NULL);
-#endif	/* CONFIG_IA64_SGI_IO */
-	
-	return(0);
-}
+
 /*
  * xtalk_device_shutdown
  *	Disable  the specified xtalk widget and clean out all the software
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/Makefile linux/arch/ia64/sn/sn1/Makefile
--- v2.4.3/linux/arch/ia64/sn/sn1/Makefile	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/sn1/Makefile	Thu Apr  5 12:51:47 2001
@@ -8,7 +8,7 @@
 EXTRA_CFLAGS	:= -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \
 		   -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \
 		   -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \
-		   -DNEW_INTERRUPTS -DCONFIG_IA64_SGI_IO
+		   -DNEW_INTERRUPTS
 
 .S.s:
 	$(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $<
@@ -18,18 +18,13 @@
 all: sn1.a
 
 O_TARGET        = sn1.a
-O_HEADERS       =
-O_OBJS          = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \
-		discontig.o
 
-ifeq ($(CONFIG_IA64_SGI_AUTOTEST),y)
-O_OBJS          += llsc4.o
-endif
+obj-y          = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \
+		discontig.o probe.o error.o sv.o
 
-
-ifeq ($(CONFIG_IA64_GENERIC),y)
-O_OBJS		+= machvec.o
-endif
+obj-$(CONFIG_IA64_SGI_AUTOTEST)	+= llsc4.o
+obj-$(CONFIG_IA64_GENERIC)	+= machvec.o
+obj-$(CONFIG_MODULES)		+= sn1_ksyms.o
 
 clean::
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/discontig.c linux/arch/ia64/sn/sn1/discontig.c
--- v2.4.3/linux/arch/ia64/sn/sn1/discontig.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/sn1/discontig.c	Thu Apr  5 12:51:47 2001
@@ -139,35 +139,6 @@
 	dump_bootmem_info() ;
 }
 
-void __init
-discontig_paging_init(void)
-{
-	int i;
-	unsigned long max_dma, zones_size[MAX_NR_ZONES];
-	void dump_node_data(void);
-
-        max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-	for (i = 0; i < numnodes; i++) {
-	       extern void free_unused_memmap_node(int);
-               unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT;
-               unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT;
-               memset(zones_size, 0, sizeof(zones_size));
-
-               if ((startpfn + numpfn) < max_dma) {
-                       zones_size[ZONE_DMA] = numpfn;
-               } else if (startpfn > max_dma) {
-                       zones_size[ZONE_NORMAL] = numpfn;
-               } else {
-                       zones_size[ZONE_DMA] = (max_dma - startpfn);
-                       zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA];
-               }
-               free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn<<PAGE_SHIFT, 0);
-	       free_unused_memmap_node(i);
-	}
-	dump_node_data();
-}
-
-
 void
 dump_node_data(void)
 {
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/error.c linux/arch/ia64/sn/sn1/error.c
--- v2.4.3/linux/arch/ia64/sn/sn1/error.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/sn/sn1/error.c	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,149 @@
+
+
+/*
+ * SN1 Platform specific error Support
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Copyright (C) 2001 Alan Mayer (ajm@sgi.com)
+ */
+
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/ptrace.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/smp.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/sn1/bedrock.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/addrs.h>
+
+void
+snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) {
+	unsigned long long intpend_val;
+	unsigned long long bit;
+
+	switch (irq) {
+	case SGI_UART_IRQ:
+		// This isn't really an error interrupt.  We're just
+		// here because we have to do something with them.
+		// This is probably wrong, and this code will be
+		// removed.
+		intpend_val = LOCAL_HUB_L(PI_INT_PEND0);
+		if ( (bit = ~(1L<<GFX_INTR_A)) ==
+			(intpend_val & ~(1L<<GFX_INTR_A)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			return;
+		}
+		if ( (bit = ~(1L<<GFX_INTR_B)) ==
+			(intpend_val & ~(1L<<GFX_INTR_B)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			return;
+		}
+		if ( (bit = ~(1L<<PG_MIG_INTR)) ==
+			(intpend_val & ~(1L<<PG_MIG_INTR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			return;
+		}
+		if ( (bit = ~(1L<<UART_INTR)) ==
+			(intpend_val & ~(1L<<UART_INTR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			return;
+		}
+		if ( (bit = ~(1L<<CC_PEND_A)) ==
+			(intpend_val & ~(1L<<CC_PEND_A)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			return;
+		}
+		if ( (bit = ~(1L<<CC_PEND_B)) ==
+			(intpend_val & ~(1L<<CC_PEND_B)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			return;
+		}
+		printk("Received SGI_UART_IRQ (65), but no intpend0 bits were set???\n");
+		return;
+	case SGI_HUB_ERROR_IRQ:
+		// These are mostly error interrupts of various
+		// sorts.  We need to do more than panic here, but
+		// what the heck, this is bring up.
+		intpend_val = LOCAL_HUB_L(PI_INT_PEND1);
+		
+		if ( (bit = ~(1L<<XB_ERROR)) ==
+			(intpend_val & ~(1L<<XB_ERROR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED XB_ERROR on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<LB_ERROR)) ==
+			(intpend_val & ~(1L<<LB_ERROR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED LB_ERROR on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<NACK_INT_A)) ==
+			(intpend_val & ~(1L<<NACK_INT_A)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED NACK_INT_A on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<NACK_INT_B)) ==
+			(intpend_val & ~(1L<<NACK_INT_B)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED NACK_INT_B on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<CLK_ERR_INTR)) ==
+			(intpend_val & ~(1L<<CLK_ERR_INTR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED CLK_ERR_INTR on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<COR_ERR_INTR_A)) ==
+			(intpend_val & ~(1L<<COR_ERR_INTR_A)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED COR_ERR_INTR_A on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<COR_ERR_INTR_B)) ==
+			(intpend_val & ~(1L<<COR_ERR_INTR_B)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED COR_ERR_INTR_B on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<MD_COR_ERR_INTR)) ==
+			(intpend_val & ~(1L<<MD_COR_ERR_INTR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED MD_COR_ERR_INTR on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<NI_ERROR_INTR)) ==
+			(intpend_val & ~(1L<<NI_ERROR_INTR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED NI_ERROR_INTR on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		if ( (bit = ~(1L<<MSC_PANIC_INTR)) ==
+			(intpend_val & ~(1L<<MSC_PANIC_INTR)) ) {
+			LOCAL_HUB_CLR_INTR(bit);
+			panic("RECEIVED MSC_PANIC_INTR on cpu %d, cnode %d\n",
+				smp_processor_id(), 
+				cpuid_to_cnodeid(smp_processor_id()));
+		}
+		printk("Received SGI_XB_ERROR_IRQ (182) but no intpend1 bits are set???\n");
+		return;
+	default:
+		printk("Received invalid irq in snia_error_intr_handler()/n");
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/iomv.c linux/arch/ia64/sn/sn1/iomv.c
--- v2.4.3/linux/arch/ia64/sn/sn1/iomv.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/sn1/iomv.c	Thu Apr  5 12:51:47 2001
@@ -25,11 +25,8 @@
  		 * for accessing registers in bedrock local block
  		 * (so we don't do port&0xfff)
  		 */
-		if (port == 0x1f6 || port == 0x1f7
-			|| port == 0x3f6 || port == 0x3f7
-			|| port == 0x1f0 || port == 0x1f1
-			|| port == 0x1f3 || port == 0x1f4
-			|| port == 0x1f2 || port == 0x1f5)  {
+		if (port >= 0x1f0 && port <= 0x1f7 ||
+			port == 0x3f6 || port == 0x3f7) {
 			io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000;
 			addr = io_base | ((port >> 2) << 12) | (port & 0xfff);
 		} else {
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/irq.c linux/arch/ia64/sn/sn1/irq.c
--- v2.4.3/linux/arch/ia64/sn/sn1/irq.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/sn1/irq.c	Thu Apr  5 12:51:47 2001
@@ -4,11 +4,13 @@
  * Copyright (C) 2000   Silicon Graphics
  * Copyright (C) 2000   Jack Steiner (steiner@sgi.com)
  * Copyright (C) 2000   Alan Mayer (ajm@sgi.com)
+ * Copyright (C) 2000   Kanoj Sarcar (kanoj@sgi.com)
  */
 
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <asm/current.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
@@ -30,28 +32,23 @@
 #include <asm/sn/sn1/arch.h>
 #include <asm/sn/synergy.h>
 
+#define IRQ_BIT_OFFSET 64
 
-int bit_pos_to_irq(int bit);
-int irq_to_bit_pos(int irq);
-void add_interrupt_randomness(int irq);
-void * kmalloc(size_t size, int flags);
-void kfree(const void *);
-int sgi_pci_intr_support (unsigned int, device_desc_t *, devfs_handle_t *, pciio_intr_line_t *, devfs_handle_t *);
-pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
-int request_irq(unsigned int, void (*)(int, void *, struct pt_regs *), unsigned long, const char *, void *);
-
-/* This should be dynamically allocated, at least part of it. */
-/* For the time being, though, we'll statically allocate it */
-/* because kmalloc hasn't been initiallized at the time this */
-/* array is initiallized.  One way to do it would be to statically */
-/* allocate the data for node 0, then let other nodes, as they */
-/* need it, dynamically allocate their own data space. */
-
-struct sn1_cnode_action_list *sn1_node_actions[MAX_COMPACT_NODES];
-struct sn1_cnode_action_list sn1_actions[MAX_COMPACT_NODES][256];
+int bit_pos_to_irq(int bit)
+{
+	if (bit > 118)
+		bit = 118;
+	return (bit + IRQ_BIT_OFFSET);
+}
 
+static inline int irq_to_bit_pos(int irq)
+{
+	int bit = irq - IRQ_BIT_OFFSET;
 
-extern int numnodes;
+	if (bit > 63)
+		bit -= 64;
+	return bit;
+}
 
 static unsigned int
 sn1_startup_irq(unsigned int irq)
@@ -82,6 +79,10 @@
 static void
 sn1_end_irq(unsigned int irq)
 {
+	int bit;
+
+	bit = irq_to_bit_pos(irq);
+	LOCAL_HUB_CLR_INTR(bit);
 }
 
 static void
@@ -89,38 +90,6 @@
 {
 }
 
-
-static void
-sn1_handle_irq(int irq, void *dummy, struct pt_regs *regs)
-{
-	int bit, cnode;
-	struct sn1_cnode_action_list *alp;
-	struct sn1_intr_action *ap;
-	void (*handler)(int, void *, struct pt_regs *);
-	unsigned long flags = 0;
-	int cpuid = smp_processor_id();
-
-
-	bit = irq_to_bit_pos(irq);
-	LOCAL_HUB_CLR_INTR(bit);
-	cnode = cpuid_to_cnodeid(cpuid);
-	alp = sn1_node_actions[cnode];
-	ap = alp[irq].action_list;
-	if (ap == NULL) {
-		return;
-	}
-	while (ap) {
-		flags |= ap->flags;
-		handler = ap->handler;
-		(*handler)(irq,ap->intr_arg,regs);
-		ap = ap->next;
-	}
-	if ((flags & SA_SAMPLE_RANDOM) != 0)
-                add_interrupt_randomness(irq);
-
-        return;
-}
-
 struct hw_interrupt_type irq_type_sn1 = {
         "sn1_irq",
         sn1_startup_irq,
@@ -132,134 +101,83 @@
         sn1_set_affinity_irq
 };
 
-struct irqaction sn1_irqaction = {
-	sn1_handle_irq,
-	0,
-	0,
-	NULL,
-	NULL,
-	NULL,
-};
 
 void
 sn1_irq_init (void)
 {
-	int i,j;
+	int i;
 
 	for (i = 0; i <= NR_IRQS; ++i) {
-		if (irq_desc[i].handler == &no_irq_type) {
-			irq_desc[i].handler = &irq_type_sn1;
-			if (i >=71 && i <= 181) {
-				irq_desc[i].action = &sn1_irqaction;
-			}
-		}
-	}
-
-	for (i = 0; i < numnodes; i++) {
-		sn1_node_actions[i] = sn1_actions[i];
-		memset(sn1_node_actions[i], 0,
-			sizeof(struct sn1_cnode_action_list) *
-			(IA64_MAX_VECTORED_IRQ + 1));
-		for (j=0; j<IA64_MAX_VECTORED_IRQ+1; j++) {
-			spin_lock_init(&sn1_node_actions[i][j].action_list_lock);
+		if (idesc_from_vector(i)->handler == &no_irq_type) {
+			idesc_from_vector(i)->handler = &irq_type_sn1;
 		}
 	}
 }
 
 
-int          
-sn1_request_irq (unsigned int requested_irq, void (*handler)(int, void *, struct pt_regs *),
-             unsigned long irqflags, const char * devname, void *dev_id)
-{ 
-	devfs_handle_t curr_dev;
-	devfs_handle_t dev;
-	pciio_intr_t intr_handle;
-	pciio_intr_line_t line;
-	device_desc_t dev_desc;
-        int cpuid, bit, cnode;
-	struct sn1_intr_action *ap, *new_ap;
-	struct sn1_cnode_action_list *alp;
-	int irq;
-
-	if ( (requested_irq & 0xff) == 0 ) {
-		int ret;
-
-		sgi_pci_intr_support(requested_irq,
-			&dev_desc, &dev, &line, &curr_dev);
-		intr_handle = pciio_intr_alloc(curr_dev, NULL, line, curr_dev);
-		bit = intr_handle->pi_irq;
-		cpuid = intr_handle->pi_cpu;
-		irq = bit_pos_to_irq(bit);
-		cnode = cpuid_to_cnodeid(cpuid);
-		new_ap = (struct sn1_intr_action *)kmalloc(
-			sizeof(struct sn1_intr_action), GFP_KERNEL);
-		irq_desc[irq].status = 0;
-		new_ap->handler = handler;
-		new_ap->intr_arg = dev_id;
-		new_ap->flags = irqflags;
-		new_ap->next = NULL;
-		alp = sn1_node_actions[cnode];
-
-		spin_lock(&alp[irq].action_list_lock);
-		ap = alp[irq].action_list;
-		/* check action list for "share" consistency */
-		while (ap){
-			if (!(ap->flags & irqflags & SA_SHIRQ) ) {
-				return(-EBUSY);
-				spin_unlock(&alp[irq].action_list_lock);
-			}
-			ap = ap->next;
-		}
-		ap = alp[irq].action_list;
-		if (ap) {
-			while (ap->next) {
-				ap = ap->next;
-			}
-			ap->next = new_ap;
-		} else {
-			alp[irq].action_list = new_ap;
-		}
-		ret = pciio_intr_connect(intr_handle, (intr_func_t)handler, dev_id, NULL);
-		if (ret) { /* connect failed, undo what we did. */
-			new_ap = alp[irq].action_list;
-			if (new_ap == ap) {
-				alp[irq].action_list = NULL;
-				kfree(ap);
-			} else {
-				while (new_ap->next && new_ap->next != ap) {
-					new_ap = new_ap->next;
-				}
-				if (new_ap->next == ap) {
-					new_ap->next = ap->next;
-					kfree(ap);
-				}
-			}
-		}
-			
-		spin_unlock(&alp[irq].action_list_lock);
-		return(ret);
-	} else {
-		return(request_irq(requested_irq, handler, irqflags, devname, dev_id));
-	}
-}
 
-#if !defined(CONFIG_IA64_SGI_IO)
+#if !defined(CONFIG_IA64_SGI_SN1)
 void
 sn1_pci_fixup(int arg)
 {
 }
 #endif
 
-int
-bit_pos_to_irq(int bit) {
-#define BIT_TO_IRQ 64
+#ifdef CONFIG_PERCPU_IRQ
+
+extern irq_desc_t irq_descX[NR_IRQS];
+irq_desc_t *irq_desc_ptr[NR_CPUS] = { irq_descX };
+
+/*
+ * Each slave AP allocates its own irq table.
+ */
+int __init cpu_irq_init(void)
+{
+	irq_desc_ptr[smp_processor_id()] = (irq_desc_t *)kmalloc(sizeof(irq_descX), GFP_KERNEL);
+	if (irq_desc_ptr[smp_processor_id()] == 0)
+		return(-1);
+	memcpy(irq_desc_ptr[smp_processor_id()], irq_desc_ptr[0], 
+							sizeof(irq_descX));
+	return(0);
+}
+
+/*
+ * This can also allocate the irq tables for the other cpus, specifically
+ * on their nodes.
+ */
+int __init master_irq_init(void)
+{
+	return(0);
+}
+
+/*
+ * The input is an ivt level.
+ */
+irq_desc_t *idesc_from_vector(unsigned int ivnum)
+{
+	return(irq_desc_ptr[smp_processor_id()] + ivnum);
+}
 
-        return bit + BIT_TO_IRQ;
+/*
+ * The input is a "soft" level, that we encoded in.
+ */
+irq_desc_t *idesc_from_irq(unsigned int irq)
+{
+	return(irq_desc_ptr[irq >> 8] + (irq & 0xff));
 }
 
-int
-irq_to_bit_pos(int irq) {
-#define IRQ_TO_BIT 64
+unsigned int ivector_from_irq(unsigned int irq)
+{
+	return(irq & 0xff);
+}
 
-        return irq - IRQ_TO_BIT;
+/*
+ * This should return the Linux irq # for the i/p vector on the
+ * i/p cpu. We currently do not track this.
+ */
+unsigned int irq_from_cpuvector(int cpunum, unsigned int vector)
+{
+	return (vector);
 }
+
+#endif /* CONFIG_PERCPU_IRQ */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/llsc4.c linux/arch/ia64/sn/sn1/llsc4.c
--- v2.4.3/linux/arch/ia64/sn/sn1/llsc4.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/sn1/llsc4.c	Thu Apr  5 12:51:47 2001
@@ -35,6 +35,15 @@
 static int	inttest=0;
 #endif
 
+#ifdef IA64_SEMFIX_INSN
+#undef IA64_SEMFIX_INSN
+#endif
+#ifdef IA64_SEMFIX
+#undef IA64_SEMFIX
+#endif
+# define IA64_SEMFIX_INSN
+# define IA64_SEMFIX    ""
+
 
 /*
  * Test parameter table for AUTOTEST
@@ -46,22 +55,22 @@
 } autotest_table_t;
 
 autotest_table_t autotest_table[] = {
-	{1000000,	2,	0x2b4		},
-	{1000000,	16,	0,		},
-	{1000000,	16,	4,		},
-	{1000000,	128,	0x44		},
-	{1000000,	128,	0x84		},
-	{1000000,	128,	0x200		},
-	{1000000,	128,	0x204		},
-	{1000000,	128,	0x2b4		},
-	{1000000,	2,	8*MB+0x2b4	},
-	{1000000,	16,	8*MB+0		},
-	{1000000,	16,	8*MB+4		},
-	{1000000,	128,	8*MB+0x44	},
-	{1000000,	128,	8*MB+0x84	},
-	{1000000,	128,	8*MB+0x200	},
-	{1000000,	128,	8*MB+0x204	},
-	{1000000,	128,	8*MB+0x2b4	},
+	{5000000,	2,	0x2b4		},
+	{5000000,	16,	0,		},
+	{5000000,	16,	4,		},
+	{5000000,	128,	0x44		},
+	{5000000,	128,	0x84		},
+	{5000000,	128,	0x200		},
+	{5000000,	128,	0x204		},
+	{5000000,	128,	0x2b4		},
+	{5000000,	2,	8*MB+0x2b4	},
+	{5000000,	16,	8*MB+0		},
+	{5000000,	16,	8*MB+4		},
+	{5000000,	128,	8*MB+0x44	},
+	{5000000,	128,	8*MB+0x84	},
+	{5000000,	128,	8*MB+0x200	},
+	{5000000,	128,	8*MB+0x204	},
+	{5000000,	128,	8*MB+0x2b4	},
 	{0}};
 
 /*
@@ -134,20 +143,21 @@
 static void Speedo(void);
 
 int autotest_enabled=0;
-static int autotest_explicit_flush=0;
 static int llsctest_number=-1;
 static int errstop_enabled=0;
 static int fail_enabled=0;
 static int selective_trigger=0;
+static int dump_block_addrs_opt=0;
+static uint errlock=0;
 
 static int __init autotest_enable(char *str)
 {
         autotest_enabled = 1;
 	return 1;
 }
-static int __init set_llscxflush(char *str)
+static int __init set_llscblkadr(char *str)
 {
-	autotest_explicit_flush = 1;
+	dump_block_addrs_opt = 1;
 	return 1;
 }
 static int __init set_llscselt(char *str)
@@ -179,55 +189,39 @@
 	printk ("  Test options:\n");
 	printk ("     llsctest=<n>\t%d\tTest number to run (all = -1)\n", llsctest_number);
 	printk ("     llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off");
-	printk ("     llscxflush  \t%s\tEnable explicit FC in test\n", autotest_explicit_flush ? "on" : "off");
 	printk ("     llscfail    \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off");
 	printk ("     llscselt    \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off");
+	printk ("     llscblkadr  \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off");
+	printk ("  SEMFIX: %s\n", IA64_SEMFIX);
 	printk ("\n");
 }
 __setup("autotest", autotest_enable);
 __setup("llsctest=", set_llsctest);
 __setup("llscerrstop", set_llscerrstop);
-__setup("llscxflush", set_llscxflush);
 __setup("llscfail", set_llscfail);
 __setup("llscselt", set_llscselt);
+__setup("llscblkadr", set_llscblkadr);
 
 
-extern inline void
-flush_buddy(void *p)
-{
-	long	lp;
-
-	if (autotest_explicit_flush)  {
-		lp = (long)p;
-		lp ^= 0x40;
-		asm volatile ("fc %0" :: "r"(lp) : "memory");
-		ia64_sync_i();
-		ia64_srlz_d();
-	}
-}
-
-static int
+extern inline int
 set_lock(uint *lock, uint id)
 {
 	uint	old;
-	flush_buddy(lock);
 	old = cmpxchg_acq(lock, 0, id);
 	return (old == 0);
 }
 
-static int
+extern inline int
 clr_lock(uint *lock, uint id)
 {
 	uint	old;
-	flush_buddy(lock);
 	old = cmpxchg_rel(lock, id, 0);
 	return (old == id);
 }
 
-static void
+extern inline void
 zero_lock(uint *lock)
 {
-	flush_buddy(lock);
 	*lock = 0;
 }
 
@@ -322,7 +316,6 @@
 					return 1;
 				}
 				if (correct_errors) {
-					flush_buddy(privp);
 					tp->private[linei] = *privp;
 				}
 				errs++;
@@ -343,7 +336,6 @@
 				errs++;
 			}
 			pval++;
-			flush_buddy(privp);
 			*privp = pval;
 			tp->private[linei] = pval;
 			break;
@@ -425,9 +417,7 @@
 				errs++;
 			}
 
-			flush_buddy(sharep);
 			*sharep = lockpat;
-			flush_buddy(sharecopy);
 			*sharecopy = lockpat;
 
 
@@ -471,7 +461,7 @@
 static int
 rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int linei, int exp, int found, int stillbad)
 {
-	int		cpu;
+	int		cpu, i;
 	long 		synerr;
 	int		selt;
 
@@ -487,6 +477,11 @@
 	}
 
 	spin(1);
+	i = 100;
+	while (i && set_lock(&errlock, 1) != 1) {
+		spin(1);
+		i--;
+	}
 	printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n",
 	    msg, k_testnumber, thread, linei, pass, pass, jiffies, exp, found);
 
@@ -512,6 +507,7 @@
 		printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr);
 	spin(2);
 	printk("\n\n");
+	clr_lock(&errlock, 1);
 
 	if (errstop_enabled) {
 		local_irq_disable();
@@ -639,8 +635,10 @@
 		testnumber = llsctest_number;
 	} else {
 		testnumber++;
-		if (autotest_table[testnumber].passes == 0)
+		if (autotest_table[testnumber].passes == 0) {
 			testnumber = 0;
+			dump_block_addrs_opt = 0;
+		}
 	}
 	k_passes = autotest_table[testnumber].passes;
 	k_linepad = autotest_table[testnumber].linepad;
@@ -704,6 +702,22 @@
 }
 
 static void
+dump_block_addrs(void)
+{
+	int	i;
+
+	printk("LLSC TestNumber %ld\n", k_testnumber);
+
+	for (i=0; i<k_linecount; i++) {
+		printk("  %lx", blocks[i]);
+		if (i%4 == 3)
+			printk("\n");
+	}
+	printk("\n");
+}
+
+
+static void
 set_thread_state(int cpuid, int state)
 {
 	if (k_threadprivate[cpuid]->threadstate == TS_KILLED) {
@@ -717,6 +731,7 @@
 build_mem_map(unsigned long start, unsigned long end, void *arg)
 {
 	long	lstart;
+	long	align = 8*MB;
 	/*
 	 * HACK - skip the kernel on the first node 
 	 */
@@ -731,9 +746,11 @@
 	while (lstart > start && (!PageReserved(virt_to_page(lstart-PAGE_SIZE)) && virt_to_page(lstart-PAGE_SIZE)->count.counter == 0))
 		lstart -= PAGE_SIZE;
 
-	printk ("     memmap: start 0x%lx, end 0x%lx\n", lstart, end);
+	lstart = (lstart + align -1) /align * align;
+	end = end / align * align;
 	if (lstart >= end)
 		return 0;
+	printk ("     memmap: start 0x%lx, end 0x%lx\n", lstart, end);
 
 	memmap[memmapx].vstart = lstart;
 	memmap[memmapx].vend = end;
@@ -812,6 +829,8 @@
 		if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT;
 		k_linecount = k_linecount & ~1;
 		setup_block_addresses();
+		if (dump_block_addrs_opt)
+			dump_block_addrs();
 
 		k_currentpass = pass++;
 		k_go = ST_RUN;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/machvec.c linux/arch/ia64/sn/sn1/machvec.c
--- v2.4.3/linux/arch/ia64/sn/sn1/machvec.c	Fri Aug 11 19:09:06 2000
+++ linux/arch/ia64/sn/sn1/machvec.c	Thu Apr  5 12:51:47 2001
@@ -1,2 +1,18 @@
 #define MACHVEC_PLATFORM_NAME	sn1
 #include <asm/machvec_init.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+void*
+sn1_mk_io_addr_MACRO
+
+dma_addr_t
+sn1_pci_map_single_MACRO
+
+int
+sn1_pci_map_sg_MACRO
+
+unsigned long
+sn1_virt_to_phys_MACRO
+
+void *
+sn1_phys_to_virt_MACRO
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/mm.c linux/arch/ia64/sn/sn1/mm.c
--- v2.4.3/linux/arch/ia64/sn/sn1/mm.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/sn1/mm.c	Thu Apr  5 12:51:47 2001
@@ -1,7 +1,7 @@
 /*
- * Copyright, 2000, Silicon Graphics.
+ * Copyright, 2000-2001, Silicon Graphics.
  * Copyright Srinivasa Thirumalachar (sprasad@engr.sgi.com)
- * Copyright 2000 Kanoj Sarcar (kanoj@sgi.com)
+ * Copyright 2000-2001 Kanoj Sarcar (kanoj@sgi.com)
  */
 
 #include <linux/config.h>
@@ -11,32 +11,23 @@
 #include <asm/efi.h>
 #include <asm/sn/mmzone_sn1.h>
 
-#       define MIN(a,b)         ((a) < (b) ? (a) : (b))
-#       define MAX(a,b)         ((a) > (b) ? (a) : (b))
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#define MAX(a,b)	((a) > (b) ? (a) : (b))
+
+#define DONE_NOTHING	0
+#define DONE_FINDING	1
+#define DONE_BUILDING	2
 
-/*
- * Note that the nodemem[] data structure does not support arbitrary
- * memory types and memory descriptors inside the node. For example, 
- * you can not have multiple efi-mem-type segments in the node and
- * expect the OS not to use specific mem-types. Currently, the 
- * assumption is that "start" is the start of virtual/physical memory 
- * on the node. PROM can reserve some memory _only_ at the beginning. 
- * This is tracked via the "usable" field, that maintains where the 
- * os can start using memory from on a node (ie end of PROM memory).
- * setup_node_bootmem() is passed the above "usable" value, and is
- * expected to make bootmem calls that ensure lower memory is not used.
- * Note that the bootmem for a node is initialized on the entire node, 
- * without regards to any holes - then we reserve the holes in 
- * setup_sn1_bootmem(), to make sure the holes are not handed out by
- * alloc_bootmem, as well as the corresponding mem_map entries are not
- * considered allocatable by the page_alloc routines.
- */
 struct nodemem_s {
-        u64     start ;
-        u64     end   ;
-        u64 	hole[SN1_MAX_BANK_PER_NODE] ;
-	u64	usable;
-} nodemem[MAXNODES] ;
+        u64     start;	/* start of kernel usable memory */
+        u64     end;	/* end of kernel usable memory */
+	u64	mtot;	/* total kernel usable memory */
+	u64	done;	/* state of bootmem initialization */
+	u64	bstart;	/* where should the bootmem area be */
+	u64	bsize;	/* bootmap size */
+        u64 	hole[SN1_MAX_BANK_PER_NODE];
+} nodemem[MAXNODES];
+
 static int nodemem_valid = 0;
 
 static int __init
@@ -46,7 +37,7 @@
         unsigned long count = 0;
 
 	if (start >= end)
-		return 0 ;
+		return 0;
 
 	/*
 	 * Get the memmap ptrs to the start and end of the holes.
@@ -54,31 +45,33 @@
 	 * Can we do virt_to_page(end), if end is on the next node?
 	 */
 
-	page = virt_to_page(start-1);
-	page++ ;
-	pageend = virt_to_page(end) ;
+	page = virt_to_page(start - 1);
+	page++;
+	pageend = virt_to_page(end);
 
 	printk("hpage=0x%lx, hpageend=0x%lx\n", (u64)page, (u64)pageend) ;
 	free_bootmem_node(NODE_DATA(nid), __pa(page), (u64)pageend - (u64)page);
 
-	return count ;
+	return count;
 }
 
-void
+static void __init
 free_unused_memmap_node(int nid)
 {
-	u64	i = 0 ;
-	u64	holestart = -1 ;
+	u64	i = 0;
+	u64	holestart = -1;
+	u64	start = nodemem[nid].start;
 
+	start = ((start >> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT);
 	do {
-		holestart = nodemem[nid].hole[i] ;
-		i++ ;
+		holestart = nodemem[nid].hole[i];
+		i++;
 		while ((i < SN1_MAX_BANK_PER_NODE) && 
-			(nodemem[nid].hole[i] == (u64)-1))
-			i++ ;
+					(nodemem[nid].hole[i] == (u64)-1))
+			i++;
 		if (i < SN1_MAX_BANK_PER_NODE)
 			free_unused_memmap_hole(nid, holestart, 
-				nodemem[nid].start + (i<<SN1_BANK_ADDR_SHIFT));
+				start + (i<<SN1_BANK_ADDR_SHIFT));
 	} while (i<SN1_MAX_BANK_PER_NODE);
 }
 
@@ -98,7 +91,6 @@
 		cnodeid = NASID_TO_CNODEID(nasid);
 		bankid = GetBankId(__pa(vaddr));
 		nodemem[cnodeid].start = MIN(nodemem[cnodeid].start, vaddr);
-		nodemem[cnodeid].usable = MIN(nodemem[cnodeid].usable, vaddr);
 		nvaddr = (unsigned long)__va((unsigned long)(++nasid) << 
 							SN1_NODE_ADDR_SHIFT);
 		nodemem[cnodeid].end = MAX(nodemem[cnodeid].end, MIN(end, nvaddr));
@@ -118,11 +110,14 @@
 pgtbl_size_ok(int nid)
 {
 	unsigned long numpfn, bank0size, nodesize ;
+	unsigned long start = nodemem[nid].start;
+
+	start = ((start >> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT);
 	
-	nodesize 	= nodemem[nid].end - nodemem[nid].start ;
+	nodesize 	= nodemem[nid].end - start ;
 	numpfn 		= nodesize >> PAGE_SHIFT;
 
-	bank0size 	= nodemem[nid].hole[0] - nodemem[nid].start ;
+	bank0size 	= nodemem[nid].hole[0] - start ;
 	/* If nid == master node && no kernel text replication */
 	bank0size      -= 0xA00000 ;	/* Kernel text + stuff */
 	bank0size      -= ((numpfn + 7) >> 3);
@@ -163,198 +158,198 @@
 
 #ifdef CONFIG_DISCONTIGMEM
 
-extern bootmem_data_t 	bdata[] ;
-static int	 	curnodeid ;
+extern bootmem_data_t bdata[];
 
+/*
+ * This assumes there will be a hole in kernel-usable memory between nodes
+ * (due to prom). The memory descriptors invoked via efi_memmap_walk are 
+ * in increasing order. It tries to identify first suitable free area to 
+ * put the bootmem for the node in. When presented with the md holding
+ * the kernel, it only searches at the end of the kernel area.
+ */
 static int __init
-setup_node_bootmem(unsigned long start, unsigned long end, unsigned long nodefree)
+find_node_bootmem(unsigned long start, unsigned long end, void *arg)
 {
+	int nasid = GetNasId(__pa(start));
+	int cnodeid = NASID_TO_CNODEID(nasid);
+	unsigned long nodesize;
 	extern char _end;
-	int i;
-	unsigned long kernelend = PAGE_ALIGN((unsigned long)(&_end));
-	unsigned long pkernelend = __pa(kernelend);
-	unsigned long bootmap_start, bootmap_size;
-	unsigned long pstart, pend;
-
-	pstart = __pa(start) ;
-	pend   = __pa(end) ;
-
-	/* If we are past a node mem boundary, on simulated dig numa
-	 * increment current node id. */
-
-	curnodeid = NASID_TO_CNODEID(GetNasId(pstart)) ;
-
-       /*
-        * Make sure we are being passed page aligned addresses.
-        */
-	if ((start & (PAGE_SIZE - 1)) || (end & (PAGE_SIZE - 1)))
-               panic("setup_node_bootmem:align");
+	unsigned long kaddr = (unsigned long)&_end;
 
-
-	/* For now, just go to the lower CHUNK alignment so that 
-	 * chunktonid of 0-8MB and other lower mem pages get initted. */
-
-	pstart &= CHUNKMASK ;
-	pend = (pend+CHUNKSZ-1) & CHUNKMASK;
-
-	/* If pend == 0, both addrs below 8 MB, special case it
-	 * FIX: CHUNKNUM(pend-1) broken if pend == 0 
-	 * both addrs within 8MB */
-
-	if (pend == 0) {
-		chunktonid[0] = 0;
-		return 0;
-	}
-
-	/* Fill up the chunktonid array first. */
-
-        for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend-1); i++)
-               chunktonid[i] = curnodeid;
-
-	/* This check is bogus for now till MAXCHUNKS is properly
-	 * defined to say if it includes holes or not. */
-
-	if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || 
-		(PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) {
-		printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end));
+	/*
+	 * Track memory available to kernel.
+	 */
+	nodemem[cnodeid].mtot += ((end - start) >> PAGE_SHIFT);
+	if (nodemem[cnodeid].done != DONE_NOTHING)
 		return(0);
-	}
+	nodesize = nodemem[cnodeid].end - ((nodemem[cnodeid].start >> 
+				SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT);
+	nodesize >>= PAGE_SHIFT;
 
-	/* This routine gets called many times in node 0.
-	 * The first one to reach here would be the one after
-	 * kernelend to end of first node. */
-
-	NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]);
-
-	if (curnodeid == 0) {
-		/* for master node, forcibly assign these values
-		 * This gets called many times on dig but we
-		 * want these exact values 
-		 * Also on softsdv, the memdesc for 0 is missing */
-		NODE_START(curnodeid) = PAGE_OFFSET;
-		NODE_SIZE(curnodeid) = (end - PAGE_OFFSET);
-	} else {
-		/* This gets called only once for non zero nodes
-		 * If it does not, then NODE_STARt should be 
-		 * LOCAL_BASE(nid) */
+	/*
+	 * Adjust limits for the md holding the kernel.
+	 */
+	if ((start < kaddr) && (end > kaddr))
+		start = PAGE_ALIGN(kaddr);
 
-		NODE_START(curnodeid) = start;
-		NODE_SIZE(curnodeid) = (end - start);
+	/*
+	 * We need space for mem_map, bootmem map plus a few more pages
+	 * to satisfy alloc_bootmems out of node 0.
+	 */
+	if ((end - start) > ((nodesize * sizeof(struct page)) + (nodesize/8)
+						+ (10 * PAGE_SIZE))) {
+		nodemem[cnodeid].bstart = start;
+		nodemem[cnodeid].done = DONE_FINDING;
 	}
+	return(0);
+}
 
-	/* if end < kernelend do not do anything below this */
-	if (pend < pkernelend)
-		return 0 ;
+/*
+ * This assumes there will be a hole in kernel-usable memory between nodes
+ * (due to prom). The memory descriptors invoked via efi_memmap_walk are 
+ * in increasing order.
+ */
+static int __init
+build_node_bootmem(unsigned long start, unsigned long end, void *arg)
+{
+	int nasid = GetNasId(__pa(start));
+	int curnodeid = NASID_TO_CNODEID(nasid);
+	int i;
+	unsigned long pstart, pend;
+	extern char _end, _stext;
+	unsigned long kaddr = (unsigned long)&_end;
 
-       /*
-        * Handle the node that contains kernel text/data. It would
-        * be nice if the loader loads the kernel at a "chunk", ie
-        * not in memory that the kernel will ignore (else free_initmem
-        * has to worry about not freeing memory that the kernel ignores).
-        * Note that we assume the space from the node start to
-        * KERNEL_START can not hold all the bootmem data, but from kernel
-        * end to node end can.
-        */
-
-	/* TBD: This may be bogus in light of the above check. */
-
-	if ((pstart < pkernelend) && (pend >= pkernelend)) {
-               bootmap_start = pkernelend;
-	} else {
-               bootmap_start = __pa(start);    /* chunk & page aligned */
+	if (nodemem[curnodeid].done == DONE_FINDING) {
+		/*
+		 * This is where we come to know the node is present.
+		 * Do node wide tasks.
+		 */
+		nodemem[curnodeid].done = DONE_BUILDING;
+		NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]);
+
+		/*
+	 	 * Update the chunktonid array as a node wide task. There
+		 * are too many smalls mds on first node to do this per md.
+	 	 */
+		pstart = __pa(nodemem[curnodeid].start);
+		pend = __pa(nodemem[curnodeid].end);
+		pstart &= CHUNKMASK;
+		pend = (pend + CHUNKSZ - 1) & CHUNKMASK;
+		/* Possible check point to enforce minimum node size */
+		if (nodemem[curnodeid].bstart == -1) {
+			printk("No valid bootmem area on node %d\n", curnodeid);
+			while(1);
+		}
+		for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend - 1); i++)
+			chunktonid[i] = curnodeid;
+		if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || 
+				(PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) {
+			printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end));
+			return(0);
+		}
+
+		/*
+		 * NODE_START and NODE_SIZE determine the physical range
+		 * on the node that mem_map array needs to be set up for.
+		 */
+		NODE_START(curnodeid) = ((nodemem[curnodeid].start >> 
+				SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT);
+		NODE_SIZE(curnodeid) = (nodemem[curnodeid].end - 
+							NODE_START(curnodeid));
+
+        	nodemem[curnodeid].bsize = 
+			init_bootmem_node(NODE_DATA(curnodeid),
+			(__pa(nodemem[curnodeid].bstart) >> PAGE_SHIFT),
+			(__pa((nodemem[curnodeid].start >> SN1_NODE_ADDR_SHIFT)
+			<< SN1_NODE_ADDR_SHIFT) >> PAGE_SHIFT),
+			(__pa(nodemem[curnodeid].end) >> PAGE_SHIFT));
+
+	} else if (nodemem[curnodeid].done == DONE_NOTHING) {
+		printk("build_node_bootmem: node %d weirdness\n", curnodeid);
+		while(1);		/* Paranoia */
 	}
 
 	/*
-	 * Low memory is reserved for PROM use on SN1. The current node
-	 * memory model is [PROM mem ... kernel ... free], where the 
-	 * first two components are optional on a node.
+	 * Free the entire md.
 	 */
-	if (bootmap_start < __pa(nodefree))
-		bootmap_start = __pa(nodefree);
-
-/* XXX TBD */
-/* For curnodeid of 0, this gets called many times because of many
- * < 8MB segments. start gets bumped each time. We want to fix it
- * to 0 now. 
- */
-	if (curnodeid == 0)
-		start=PAGE_OFFSET;
-/*
- * This makes sure that in free_area_init_core - paging_init
- * idx is the entire node page range and for loop goes thro
- * all pages. test_bit for kernel pages should remain reserved
- * because free available mem takes care of kernel_start and end
- */
-
-        bootmap_size = init_bootmem_node(NODE_DATA(curnodeid),
-			(bootmap_start >> PAGE_SHIFT),
-			(__pa(start) >> PAGE_SHIFT), (__pa(end) >> PAGE_SHIFT));
+	free_bootmem_node(NODE_DATA(curnodeid), __pa(start), (end - start));
 
-	free_bootmem_node(NODE_DATA(curnodeid), bootmap_start + bootmap_size,
-				__pa(end) - (bootmap_start + bootmap_size));
+	/*
+	 * Reclaim back the bootmap and kernel areas.
+	 */
+	if ((start <= nodemem[curnodeid].bstart) && (end >
+						nodemem[curnodeid].bstart))
+		reserve_bootmem_node(NODE_DATA(curnodeid),
+		    __pa(nodemem[curnodeid].bstart), nodemem[curnodeid].bsize);
+	if ((start <= kaddr) && (end > kaddr))
+		reserve_bootmem_node(NODE_DATA(curnodeid),
+		    __pa(&_stext), (&_end - &_stext));
 
 	return(0);
 }
 
-void
+void __init
 setup_sn1_bootmem(int maxnodes)
 {
         int     i;
 
-        for (i=0;i<MAXNODES;i++) {
-                nodemem[i].usable = nodemem[i].start = -1 ;
-                nodemem[i].end   = 0 ;
-		memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole)) ;
+        for (i = 0; i < MAXNODES; i++) {
+                nodemem[i].start = nodemem[i].bstart = -1;
+                nodemem[i].end = nodemem[i].bsize = nodemem[i].mtot = 0;
+		nodemem[i].done = DONE_NOTHING;
+		memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole));
         }
-        efi_memmap_walk(build_nodemem_map, 0) ;
+        efi_memmap_walk(build_nodemem_map, 0);
 
-	/*
-	 * Run thru all the nodes, adjusting their starts. This is needed
-	 * because efi_memmap_walk() might not process certain mds that 
-	 * are marked reserved for PROM at node low memory.
-	 */
-	for (i = 0; i < maxnodes; i++)
-		nodemem[i].start = ((nodemem[i].start >> SN1_NODE_ADDR_SHIFT) <<
-					SN1_NODE_ADDR_SHIFT);
-	nodemem_valid = 1 ;
+	nodemem_valid = 1;
 
-	/* After building the nodemem map, check if the page table
+	/* 
+	 * After building the nodemem map, check if the node memmap
 	 * will fit in the first bank of each node. If not change
-	 * the node end addr till it fits. We dont want to do this
-	 * in mm/page_alloc.c
+	 * the node end addr till it fits.
  	 */
 
-        for (i=0;i<maxnodes;i++)
-		check_pgtbl_size(i) ;
-
-        for (i=0;i<maxnodes;i++)
-                setup_node_bootmem(nodemem[i].start, nodemem[i].end, nodemem[i].usable);
+        for (i = 0; i < maxnodes; i++)
+		check_pgtbl_size(i);
 
-	/*
-	 * Mark the holes as reserved, so the corresponding mem_map
-	 * entries will not be marked allocatable in free_all_bootmem*().
-	 */
-	for (i = 0; i < maxnodes; i++) {
-		int j = 0 ;
-		u64 holestart = -1 ;
-
-		do {
-			holestart = nodemem[i].hole[j++];
-			while ((j < SN1_MAX_BANK_PER_NODE) && 
-					(nodemem[i].hole[j] == (u64)-1))
-				j++;
-			if (j < SN1_MAX_BANK_PER_NODE)
-				reserve_bootmem_node(NODE_DATA(i), 
-					__pa(holestart), (nodemem[i].start + 
-					((long)j <<  SN1_BANK_ADDR_SHIFT) - 
-					 holestart));
-		} while (j < SN1_MAX_BANK_PER_NODE);
-	}
+	dump_nodemem_map(maxnodes);
 
-	dump_nodemem_map(maxnodes) ;
+	efi_memmap_walk(find_node_bootmem, 0);
+	efi_memmap_walk(build_node_bootmem, 0);
 }
 #endif
 
+void __init
+discontig_paging_init(void)
+{
+	int i;
+	unsigned long max_dma, zones_size[MAX_NR_ZONES], holes_size[MAX_NR_ZONES];
+	extern void dump_node_data(void);
+
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	for (i = 0; i < numnodes; i++) {
+		unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT;
+		unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT;
+		memset(zones_size, 0, sizeof(zones_size));
+		memset(holes_size, 0, sizeof(holes_size));
+		holes_size[ZONE_DMA] = numpfn - nodemem[i].mtot;
+
+		if ((startpfn + numpfn) < max_dma) {
+			zones_size[ZONE_DMA] = numpfn;
+		} else if (startpfn > max_dma) {
+			zones_size[ZONE_NORMAL] = numpfn;
+			panic("discontig_paging_init: %d\n", i);
+		} else {
+			zones_size[ZONE_DMA] = (max_dma - startpfn);
+			zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA];
+			panic("discontig_paging_init: %d\n", i);
+		}
+		free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn<<PAGE_SHIFT, holes_size);
+		free_unused_memmap_node(i);
+	}
+	dump_node_data();
+}
+
 /*
  * This used to be invoked from an SN1 specific hack in efi_memmap_walk.
  * It tries to ignore banks which the kernel is ignoring because bank 0 
@@ -386,10 +381,10 @@
 	int	i,j;
 
         printk("NODEMEM_S info ....\n") ;
-        printk("Node         start                end                 usable\n");
+        printk("Node         start                end\n");
         for (i=0;i<maxnodes;i++) {
-                printk("%d      0x%lx   0x%lx   0x%lx\n",
-                       i, nodemem[i].start, nodemem[i].end, nodemem[i].usable);
+                printk("%d      0x%lx   0x%lx\n",
+                       i, nodemem[i].start, nodemem[i].end);
                 printk("Holes -> ") ;
                 for (j=0;j<SN1_MAX_BANK_PER_NODE;j++)
                         printk("0x%lx ", nodemem[i].hole[j]) ;
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/probe.c linux/arch/ia64/sn/sn1/probe.c
--- v2.4.3/linux/arch/ia64/sn/sn1/probe.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/sn/sn1/probe.c	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,62 @@
+/*
+ * Platform dependent support for IO probing.
+ *
+ * Copyright (C) 2000   Silicon Graphics
+ * Copyright (C) 2000   Jack Steiner (steiner@sgi.com)
+ */
+
+#include <asm/sn/sn_sal.h>
+
+/*
+ * ia64_sn_probe_io_slot
+ *	This function will probe a physical address to determine if
+ *	the address can be read. If reading the address causes a BUS
+ *	error, an error is returned. If the probe succeeds, the contents 
+ *	of the memory location is returned.
+ *
+ *   Calling sequence:
+ *		ia64_probe_io_slot(paddr, size, data_ptr)
+ *
+ *   Input:
+ *	paddr		Physical address to probe
+ *	size		Number bytes to read (1,2,4,8)
+ *	data_ptr	Address to store value read by probe
+ *		          (-1 returned if probe fails)
+ *
+ *   Output:
+ *	Status
+ *		 0 - probe successful
+ *		 1 - probe failed (generated MCA)
+ *		 2 - Bad arg
+ *		<0 - PAL error
+ */
+
+
+u64
+ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr)
+{
+	struct ia64_sal_retval isrv;
+
+	SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0);
+
+	if (data_ptr) {
+		switch (size) {
+			case 1:
+				*((u8*)data_ptr) = (u8)isrv.v0;
+				break;
+			case 2:
+				*((u16*)data_ptr) = (u16)isrv.v0;
+				break;
+			case 4:
+				*((u32*)data_ptr) = (u32)isrv.v0;
+				break;
+			case 8:
+				*((u64*)data_ptr) = (u64)isrv.v0;
+				break;
+			default:
+				isrv.status = 2;	
+		}
+	}
+
+	return isrv.status;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/setup.c linux/arch/ia64/sn/sn1/setup.c
--- v2.4.3/linux/arch/ia64/sn/sn1/setup.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/sn1/setup.c	Thu Apr  5 12:51:47 2001
@@ -15,12 +15,30 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/serial.h>
 
 #include <asm/sn/mmzone_sn1.h>
 #include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/machvec.h>
 #include <asm/system.h>
 #include <asm/processor.h>
+#include <asm-ia64/sn/arch.h>
+#include <asm-ia64/sn/addrs.h>
+
+
+/*
+ * This is the address of the RRegs in the HSpace of the global
+ * master.  It is used by a hack in serial.c (serial_[in|out],
+ * printk.c (early_printk), and kdb_io.c to put console output on that
+ * node's Bedrock UART.  It is initialized here to 0, so that
+ * early_printk won't try to access the UART before
+ * master_node_bedrock_address is properly calculated.
+ */
+u64 master_node_bedrock_address = 0UL;
+
+static void sn_fix_ivt_for_partitioned_system(void);
+
 
 /*
  * The format of "screen_info" is strange, and due to early i386-setup
@@ -58,31 +76,169 @@
 #endif
 }
 
+#if defined(BRINGUP) && defined(CONFIG_IA64_EARLY_PRINTK)
+void __init
+early_sn1_setup(void)
+{
+	master_node_bedrock_address = 
+		(u64)REMOTE_HSPEC_ADDR(get_nasid(), 0);
+	printk("early_sn1_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address);
+}
+#endif /* BRINGUP && CONFIG_IA64_EARLY_PRINTK */
+
 void __init
 sn1_setup(char **cmdline_p)
 {
-	extern void init_sn1_smp_config(void);
+#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
+	struct serial_struct req;
+#endif
+
+	MAX_DMA_ADDRESS = PAGE_OFFSET + 0x10000000000UL;
+	master_node_bedrock_address = 
+		(u64)REMOTE_HSPEC_ADDR(get_nasid(), 0);
+	printk("sn1_setup: setting master_node_bedrock_address to 0x%lx\n",
+		   master_node_bedrock_address);
+
+#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
+	/*
+	 * We do early_serial_setup() to clean out the rs-table[] from the
+	 * statically compiled in version.
+	 */
+	memset(&req, 0, sizeof(struct serial_struct));
+	req.line = 0;
+	req.baud_base = 124800;
+	req.port = 0;
+	req.port_high = 0;
+	req.irq = 0;
+	req.flags = (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST);
+	req.io_type = SERIAL_IO_MEM;
+	req.hub6 = 0;
+	req.iomem_base = (u8 *)(master_node_bedrock_address + 0x80);
+	req.iomem_reg_shift = 3;
+	req.type = 0;
+	req.xmit_fifo_size = 0;
+	req.custom_divisor = 0;
+	req.closing_wait = 0;
+	early_serial_setup(&req);
+#endif /* CONFIG_SERIAL && !CONFIG_SERIAL_SGI_L1_PROTOCOL */
+
 	ROOT_DEV = to_kdev_t(0x0301);		/* default to first IDE drive */
+	sn_fix_ivt_for_partitioned_system();
 
-	init_sn1_smp_config();
-#ifdef ZZZ
-#if !defined (CONFIG_IA64_SOFTSDV_HACKS)
-        /*
-         * Program the timer to deliver timer ticks.  0x40 is the I/O port
-         * address of PIT counter 0, 0x43 is the I/O port address of the
-         * PIT control word.
-         */
-        request_region(0x40,0x20,"timer");
-        outb(0x34, 0x43);            /* Control word */
-        outb(LATCH & 0xff , 0x40);   /* LSB */
-        outb(LATCH >> 8, 0x40);      /* MSB */
-        printk("PIT: LATCH at 0x%x%x for %d HZ\n", LATCH >> 8, LATCH & 0xff, HZ);
-#endif
-#endif
 #ifdef CONFIG_SMP
 	init_smp_config();
 #endif
 	screen_info = sn1_screen_info;
+}
+
+
+/* 
+ * sn_fix_ivt_for_partitioned_system
+ *
+ * This is an ugly hack that is needed for partitioned systems.
+ *
+ * On a partitioned system, most partitions do NOT have a physical address 0.
+ * Unfortunately, the exception handling code in ivt.S has a couple of physical
+ * addresses of kernel structures hardcoded into "movl" instructions.
+ * These addresses are correct on partition 0 only. On all other partitions,
+ * the addresses must be changed to reference the correct address.
+ *
+ * This routine scans the ivt code and replaces the hardcoded addresses with 
+ * the correct address.
+ *
+ * Note that we could have made the ivt.S code dynamically determine the correct
+ * address but this would add code to performance critical pathes. This option
+ * was rejected.
+ */
+
+#define TEMP_mlx	4		/* template type that contains movl instruction */
+#define TEMP_mlX	5		/* template type that contains movl instruction */
+
+typedef union {				/* Instruction encoding for movl instruction */
+	struct {
+		unsigned long	qp:6;
+		unsigned long	r1:7;
+		unsigned long	imm7b:7;
+		unsigned long	vc:1;
+		unsigned long	ic:1;
+		unsigned long	imm5c:5;
+		unsigned long	imm9d:9;
+		unsigned long	i:1;
+		unsigned long	op:4;
+		unsigned long	fill:23;
+	} b;
+	unsigned long	l;
+} movl_instruction_t;
+
+#define MOVL_OPCODE	6
+#define MOVL_ARG(a,b)	(((long)a.i<<63) | ((long)b<<22) | ((long)a.ic<<21) | \
+			((long)a.imm5c<<16) | ((long)a.imm9d<<7) | ((long)a.imm7b))
+
+typedef struct {				/* Instruction bundle */
+	unsigned long template:5;
+	unsigned long ins2:41;
+	unsigned long ins1l:18;
+	unsigned long ins1u:23;
+	unsigned long ins0:41;
+} instruction_bundle_t;
+
+
+static void __init
+sn_fix_ivt_for_partitioned_system(void)
+{
+	extern int		ia64_ivt;
+	instruction_bundle_t	*p, *pend;
+	movl_instruction_t	ins0, ins1, ins2;
+	long			new_ins1, phys_offset;
+	unsigned long		val;
+
+	/*
+	 * Setup to scan the ivt code.
+	 */
+	p = (instruction_bundle_t*)&ia64_ivt;
+	pend = p + 0x8000/sizeof(instruction_bundle_t);
+	phys_offset = __pa(p) & ~0x1ffffffffUL;
+
+	/*
+	 * Hunt for movl instructions that contain the node 0 physical address 
+	 * of "SWAPPER_PGD_ADDR".  These addresses must be relocated to reference the 
+	 * actual node that the kernel is loaded on.
+	 */
+	for (; p < pend; p++) {
+		if (p->template != TEMP_mlx && p->template != TEMP_mlX)
+			continue;
+		ins0.l =  p->ins0;
+		if (ins0.b.op != MOVL_OPCODE)
+			continue;
+		ins1.l =  ((long)p->ins1u<<18) | p->ins1l;
+		ins2.l =  p->ins2;
+		val = MOVL_ARG(ins0.b, ins1.l);
+
+		/*
+		 * Test for correct address. SWAPPER_PGD_ADDR will
+		 * always be a node 0 virtual address. Note that we cant
+		 * use the __pa or __va macros here since they may contain
+		 * debug code that gets fooled here.
+		 */
+		if ((PAGE_OFFSET | val)  != SWAPPER_PGD_ADDR)
+			continue;
+
+		/*
+		 * We found an instruction that needs to be fixed. The following
+		 * inserts the NASID of the ivt into the movl instruction.
+		 */
+		new_ins1 = ins1.l | (phys_offset>>22);
+		p->ins1l = new_ins1 & 0x3ffff;
+		p->ins1u = (new_ins1>>18) & 0x7fffff;
+		ia64_fc(p);
+	}
+
+	/*
+	 * Do necessary serialization.
+	 */
+	ia64_sync_i();
+	ia64_srlz_i();
+
 }
 
 int
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/smp.c linux/arch/ia64/sn/sn1/smp.c
--- v2.4.3/linux/arch/ia64/sn/sn1/smp.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/sn1/smp.c	Thu Apr  5 12:51:47 2001
@@ -124,10 +124,10 @@
 
 #ifdef CONFIG_SMP
 
+#ifdef PTC_NOTYET
 static void __init
 process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain)
 {
-#ifdef PTC_NOTYET
 	ia64_sal_ptc_domain_proc_entry_t	*pe;
 	int 					i, sapicid, cpuid;
 
@@ -138,7 +138,6 @@
 		sn_sapicid_info[cpuid].domain = domain;
 		sn_sapicid_info[cpuid].sapicid = sapicid;
 	}
-#endif
 }
 
 
@@ -153,6 +152,7 @@
 		process_sal_ptc_domain_info(di, i);	
 	}
 }
+#endif
 
 
 void __init
@@ -179,7 +179,7 @@
 {
 
 #ifdef PTC_NOTYET
-	sn_sapicid_info[0].sapicid = hard_processor_sapicid();
+	sn_sapicid_info[0].sapicid = hard_smp_processor_id();
 #endif
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/sn1_asm.S linux/arch/ia64/sn/sn1/sn1_asm.S
--- v2.4.3/linux/arch/ia64/sn/sn1/sn1_asm.S	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/sn1/sn1_asm.S	Thu Apr  5 12:51:47 2001
@@ -4,3 +4,146 @@
  * Copyright (C) 2000 Jack Steiner (steiner@sgi.com)
  */
 
+#include <linux/config.h>
+#ifdef CONFIG_IA64_SGI_AUTOTEST
+
+// Testing only.
+// Routine will cause MCAs
+//   zzzmsa(n)
+//      n=0 MCA via duplicate TLB dropin
+//      n=0 MCA via read of garbage address
+//
+
+#define ITIR(key, ps)           ((key<<8) | (ps<<2))
+#define TLB_PAGESIZE            28                      // Use 256MB pages for now.
+
+                        .global zzzmca
+                        .proc   zzzmca
+zzzmca:
+                        alloc   loc4       = ar.pfs,2,8,1,0;;
+                        cmp.ne  p6,p0=r32,r0;;
+                        movl    r2=0x2dead
+                        movl    r3=0x3dead
+                        movl    r15=0x15dead
+                        movl    r16=0x16dead
+                        movl    r31=0x31dead
+                        movl    loc0=0x34beef
+                        movl    loc1=0x35beef
+                        movl    loc2=0x36beef
+                        movl    loc3=0x37beef
+                        movl    out0=0x42beef
+
+                        movl    r20=0x32feed;;
+                        mov     ar32=r20
+                        movl    r20=0x36feed;;
+                        mov     ar36=r20
+                        movl    r20=0x65feed;;
+                        mov     ar65=r20
+                        movl    r20=0x66feed;;
+                        mov     ar66=r20
+
+(p6)                    br.cond.sptk    1f
+
+                        rsm      0x2000;;
+                        srlz.d;
+                        mov      r11      = 1
+                        mov      r3       = ITIR(0,TLB_PAGESIZE);;
+                        mov      cr.itir  = r3
+                        mov      r10      = 0;;
+                        itr.d    dtr[r11] = r10;;
+                        mov      r11      = 2
+
+                        itr.d    dtr[r11] = r10;;
+                        br      9f
+
+1:                      movl    r8=0xfe00000048;;
+                        ld8     r9=[r8];;
+                        mf
+                        mf.a
+                        srlz.d
+
+9:                      mov     ar.pfs=loc4
+                        br.ret.sptk     rp
+
+                        .endp   zzzmca
+
+                        .global zzzspec
+                        .proc   zzzspec
+zzzspec:
+			mov	r8=r32
+			movl	r9=0xe000000000000000
+			movl	r10=0x4000;;
+			ld8.s	r16=[r8];;
+			ld8.s	r17=[r9];;
+			add	r8=r8,r10;;
+			ld8.s	r18=[r8];;
+			add	r8=r8,r10;;
+			ld8.s	r19=[r8];;
+			add	r8=r8,r10;;
+			ld8.s	r20=[r8];;
+			mov	r8=r0
+			tnat.nz	p6,p0=r16
+			tnat.nz	p7,p0=r17
+			tnat.nz	p8,p0=r18
+			tnat.nz	p9,p0=r19
+			tnat.nz	p10,p0=r20;;
+		(p6)	dep	r8=-1,r8,0,1;;
+		(p7)	dep	r8=-1,r8,1,1;;
+		(p8)	dep	r8=-1,r8,2,1;;
+		(p9)	dep	r8=-1,r8,3,1;;
+		(p10)	dep	r8=-1,r8,4,1;;
+                        br.ret.sptk     rp
+                        .endp   zzzspec
+
+                        .global zzzspec2
+                        .proc   zzzspec2
+zzzspec2:
+			cmp.eq	p6,p7=r2,r2
+			movl	r16=0xc0000a0001000020
+			;;
+			mf
+			;;
+			ld8	r9=[r16]
+		(p6)	br.spnt	1f
+			ld8	r10=[r32]
+			;;
+		1:	mf.a
+			mf
+
+			ld8	r9=[r16];;
+			cmp.ne	p6,p7=r9,r16
+		(p6)	br.spnt	1f
+			ld8	r10=[r32]
+			;;
+		1:	mf.a
+			mf
+
+			ld8	r9=[r33];;
+			cmp.ne	p6,p7=r9,r33
+		(p6)	br.spnt	1f
+			ld8	r10=[r32]
+			;;
+		1:	mf.a
+			mf
+
+			tpa	r23=r32
+			add	r20=512,r33
+			add	r21=1024,r33;;
+			ld8	r9=[r20]
+			ld8	r10=[r21];;
+			nop.i	0
+			{ .mib
+			nop.m 0
+			cmp.ne	p6,p7=r10,r33
+		(p6)	br.spnt	1f
+			}
+			ld8	r10=[r32]
+			;;
+		1:	mf.a
+			mf
+			br.ret.sptk     rp
+
+                        .endp   zzzspec
+
+#endif
+
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/sn1_ksyms.c linux/arch/ia64/sn/sn1/sn1_ksyms.c
--- v2.4.3/linux/arch/ia64/sn/sn1/sn1_ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/sn/sn1/sn1_ksyms.c	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,39 @@
+/* 
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2000 Jesse Barnes (jbarnes@sgi.com)
+ */
+
+
+/*
+ * Architecture-specific kernel symbols
+ */
+
+#include <linux/module.h>
+
+#include <asm/machvec.h>
+
+/*
+ * I/O routines
+ */
+EXPORT_SYMBOL(sn1_outb);
+EXPORT_SYMBOL(sn1_outl);
+EXPORT_SYMBOL(sn1_outw);
+EXPORT_SYMBOL(sn1_inw);
+EXPORT_SYMBOL(sn1_inb);
+EXPORT_SYMBOL(sn1_inl);
+
+/*
+ * other stuff (more to be added later, cleanup then)
+ */
+EXPORT_SYMBOL(sn1_pci_map_sg);
+EXPORT_SYMBOL(sn1_pci_unmap_sg);
+EXPORT_SYMBOL(sn1_pci_alloc_consistent);
+EXPORT_SYMBOL(sn1_pci_free_consistent);
+EXPORT_SYMBOL(sn1_dma_address);
+
+#include <linux/mm.h>
+EXPORT_SYMBOL(alloc_pages);
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/sv.c linux/arch/ia64/sn/sn1/sv.c
--- v2.4.3/linux/arch/ia64/sn/sn1/sv.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/sn/sn1/sv.c	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,551 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.  All rights reserved
+ *
+ * This implemenation of synchronization variables is heavily based on
+ * one done by Steve Lord <lord@sgi.com>
+ *
+ * Paul Cassella <pwc@sgi.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/semaphore.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/current.h>
+
+#include <asm/sn/sv.h>
+
+/* Define this to have sv_test() run some simple tests.
+   kernel_thread() must behave as expected when this is called.  */
+#undef RUN_SV_TEST
+
+#define DEBUG
+
+/* Set up some macros so sv_wait(), sv_signal(), and sv_broadcast()
+   can sanity check interrupt state on architectures where we know
+   how. */
+#ifdef DEBUG
+ #define SV_DEBUG_INTERRUPT_STATE
+ #ifdef __mips64
+  #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x1) != 0)
+  #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x1) == 0)
+  #define SV_INTERRUPT_TEST_WORKERS 31
+ #elif defined(__ia64)
+  #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x4000) != 0)
+  #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x4000) == 0)
+  #define SV_INTERRUPT_TEST_WORKERS 4 /* simulator's slow */
+ #else
+  #undef  SV_DEBUG_INTERRUPT_STATE
+  #define SV_INTERRUPT_TEST_WORKERS 4 /* reasonable? default. */
+ #endif /* __mips64 */
+#endif /* DEBUG */
+
+
+/* XXX FIXME hack hack hack.  Our mips64 tree is from before the
+   switch to WQ_FLAG_EXCLUSIVE, and our ia64 tree is from after it. */
+#ifdef TASK_EXCLUSIVE
+  #undef EXCLUSIVE_IN_QUEUE
+#else
+  #define EXCLUSIVE_IN_QUEUE
+  #define TASK_EXCLUSIVE 0 /* for the set_current_state() in sv_wait() */
+#endif
+
+
+static inline void sv_lock(sv_t *sv) {
+	spin_lock(&sv->sv_lock);
+}
+
+static inline void sv_unlock(sv_t *sv) {
+	spin_unlock(&sv->sv_lock);
+}
+
+/* up() is "extern inline", so we can't pass its address to sv_wait.
+   Use this function's address instead. */
+static void up_wrapper(struct semaphore *sem) {
+	up(sem);
+}
+
+/* spin_unlock() is sometimes a macro. */
+static void spin_unlock_wrapper(spinlock_t *s) {
+	spin_unlock(s);
+}
+
+/* XXX Perhaps sv_wait() should do the switch() each time and avoid
+   the extra indirection and the need for the _wrapper functions? */
+
+static inline void sv_set_mon_type(sv_t *sv, int type) {
+	switch (type) {
+	case SV_MON_SPIN:
+		sv->sv_mon_unlock_func =
+		  (sv_mon_unlock_func_t)spin_unlock_wrapper;
+		break;
+	case SV_MON_SEMA:
+		sv->sv_mon_unlock_func =
+		  (sv_mon_unlock_func_t)up_wrapper;
+		if(sv->sv_flags & SV_INTS) {
+			printk(KERN_ERR "sv_set_mon_type: The monitor lock "
+			       "cannot be shared with interrupts if it is a "
+			       "semaphore!\n");
+			BUG();
+		}
+		if(sv->sv_flags & SV_BHS) {
+			printk(KERN_ERR "sv_set_mon_type: The monitor lock "
+			       "cannot be shared with bottom-halves if it is "
+			       "a semaphore!\n");
+			BUG();
+		}
+		break;
+#if 0 
+	/*
+	 * If needed, and will need to think about interrupts.  This
+	 * may be needed, for example, if someone wants to use sv's
+	 * with something like dev_base; writers need to hold two
+	 * locks. 
+	 */
+	case SV_MON_CUSTOM: 
+		{
+		struct sv_mon_custom *c = lock;
+		sv->sv_mon_unlock_func = c->sv_mon_unlock_func;
+		sv->sv_mon_lock        = c->sv_mon_lock;
+		break;
+		}
+#endif
+		
+	default:
+		printk(KERN_ERR "sv_set_mon_type: unknown type %d (0x%x)! "
+		       "(flags 0x%x)\n", type, type, sv->sv_flags);
+		BUG();
+		break;
+	}
+	sv->sv_flags |= type;
+}
+
+static inline void sv_set_ord(sv_t *sv, int ord) {
+	if (!ord)
+		ord = SV_ORDER_DEFAULT;
+
+	if (ord != SV_ORDER_FIFO && ord != SV_ORDER_LIFO) {
+		printk(KERN_EMERG "sv_set_ord: unknown order %d (0x%x)! ",
+		       ord, ord);
+		BUG();
+	}
+
+	sv->sv_flags |= ord;
+}
+
+void sv_init(sv_t *sv, sv_mon_lock_t *lock, int flags) 
+{
+	int ord = flags & SV_ORDER_MASK;
+	int type = flags & SV_MON_MASK;
+
+	/* Copy all non-order, non-type flags */
+	sv->sv_flags = (flags & ~(SV_ORDER_MASK | SV_MON_MASK));
+
+	if((sv->sv_flags & (SV_INTS | SV_BHS)) == (SV_INTS | SV_BHS)) {
+	  printk(KERN_ERR "sv_init: do not set both SV_INTS and SV_BHS, only SV_INTS.\n");
+	  BUG();
+	}
+
+	sv_set_ord(sv, ord);
+	sv_set_mon_type(sv, type);
+
+	/* If lock is NULL, we'll get it from sv_wait_compat() (and
+           ignore it in sv_signal() and sv_broadcast()). */
+	sv->sv_mon_lock = lock;
+
+	spin_lock_init(&sv->sv_lock);
+	init_waitqueue_head(&sv->sv_waiters);
+}
+
+/*
+ * The associated lock must be locked on entry.  It is unlocked on return.
+ *
+ * Return values:
+ *
+ * n < 0 : interrupted,  -n jiffies remaining on timeout, or -1 if timeout == 0
+ * n = 0 : timeout expired
+ * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0
+ */
+signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout) 
+{
+	DECLARE_WAITQUEUE( wait, current );
+	unsigned long flags;
+	signed long ret = 0;
+
+#ifdef SV_DEBUG_INTERRUPT_STATE
+	{
+	unsigned long flags;
+	__save_flags(flags);
+
+	if(sv->sv_flags & SV_INTS) {
+		if(SV_TEST_INTERRUPTS_ENABLED(flags)) {
+			printk(KERN_ERR "sv_wait: SV_INTS and interrupts "
+			       "enabled (flags: 0x%lx)\n", flags);
+			BUG();
+		}
+	} else {
+		if (SV_TEST_INTERRUPTS_DISABLED(flags)) {
+			printk(KERN_WARNING "sv_wait: !SV_INTS and interrupts "
+			       "disabled! (flags: 0x%lx)\n", flags);
+		}
+	}
+	}
+#endif  /* SV_DEBUG_INTERRUPT_STATE */
+
+	sv_lock(sv);
+
+	sv->sv_mon_unlock_func(sv->sv_mon_lock);
+
+	/* Add ourselves to the wait queue and set the state before
+	 * releasing the sv_lock so as to avoid racing with the
+	 * wake_up() in sv_signal() and sv_broadcast(). 
+	 */
+
+	/* don't need the _irqsave part, but there is no wq_write_lock() */
+	wq_write_lock_irqsave(&sv->sv_waiters.lock, flags);
+
+#ifdef EXCLUSIVE_IN_QUEUE
+	wait.flags |= WQ_FLAG_EXCLUSIVE;
+#endif
+
+	switch(sv->sv_flags & SV_ORDER_MASK) {
+	case SV_ORDER_FIFO:
+		__add_wait_queue_tail(&sv->sv_waiters, &wait);
+		break;
+	case SV_ORDER_FILO:
+		__add_wait_queue(&sv->sv_waiters, &wait);
+		break;
+	default:
+		printk(KERN_ERR "sv_wait: unknown order!  (sv: 0x%p, flags: 0x%x)\n",
+					sv, sv->sv_flags);
+		BUG();
+	}
+	wq_write_unlock_irqrestore(&sv->sv_waiters.lock, flags);
+
+	if(sv_wait_flags & SV_WAIT_SIG)
+		set_current_state(TASK_EXCLUSIVE | TASK_INTERRUPTIBLE  );
+	else
+		set_current_state(TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE);
+
+	spin_unlock(&sv->sv_lock);
+
+	if(sv->sv_flags & SV_INTS)
+		local_irq_enable();
+	else if(sv->sv_flags & SV_BHS)
+		local_bh_enable();
+
+	if (timeout)
+		ret = schedule_timeout(timeout);
+	else
+		schedule();
+
+	if(current->state != TASK_RUNNING) /* XXX Is this possible? */ {
+		printk(KERN_ERR "sv_wait: state not TASK_RUNNING after "
+		       "schedule().\n");
+		set_current_state(TASK_RUNNING);
+	}
+
+	remove_wait_queue(&sv->sv_waiters, &wait);
+
+	/* Return cases:
+	   - woken by a sv_signal/sv_broadcast
+	   - woken by a signal
+	   - woken by timeout expiring
+	*/
+
+	/* XXX This isn't really accurate; we may have been woken
+           before the signal anyway.... */
+	if(signal_pending(current))
+		return timeout ? -ret : -1;
+	return timeout ? ret : 1;
+}
+
+
+void sv_signal(sv_t *sv) 
+{
+	/* If interrupts can acquire this lock, they can also acquire the
+	   sv_mon_lock, which we must already have to have called this, so
+	   interrupts must be disabled already.  If interrupts cannot
+	   contend for this lock, we don't have to worry about it. */
+
+#ifdef SV_DEBUG_INTERRUPT_STATE
+	if(sv->sv_flags & SV_INTS) {
+		unsigned long flags;
+		__save_flags(flags);
+		if(SV_TEST_INTERRUPTS_ENABLED(flags))
+			printk(KERN_ERR "sv_signal: SV_INTS and "
+			"interrupts enabled! (flags: 0x%lx)\n", flags);
+	}
+#endif /* SV_DEBUG_INTERRUPT_STATE */
+
+	sv_lock(sv);
+	wake_up(&sv->sv_waiters);
+	sv_unlock(sv);
+}
+
+void sv_broadcast(sv_t *sv) 
+{
+#ifdef SV_DEBUG_INTERRUPT_STATE
+	if(sv->sv_flags & SV_INTS) {
+		unsigned long flags;
+		__save_flags(flags);
+		if(SV_TEST_INTERRUPTS_ENABLED(flags))
+			printk(KERN_ERR "sv_broadcast: SV_INTS and "
+			       "interrupts enabled! (flags: 0x%lx)\n", flags);
+	}
+#endif /* SV_DEBUG_INTERRUPT_STATE */
+
+	sv_lock(sv);
+	wake_up_all(&sv->sv_waiters);
+	sv_unlock(sv);
+}
+
+void sv_destroy(sv_t *sv) 
+{
+	if(!spin_trylock(&sv->sv_lock)) {
+		printk(KERN_ERR "sv_destroy: someone else has sv 0x%p locked!\n", sv);
+		BUG();
+	}
+
+	/* XXX Check that the waitqueue is empty? 
+	       Mark the sv destroyed?
+	*/
+}
+
+
+#ifdef RUN_SV_TEST
+
+static DECLARE_MUTEX_LOCKED(talkback);
+static DECLARE_MUTEX_LOCKED(sem);
+sv_t sv;
+sv_t sv_filo;
+
+static int sv_test_1_w(void *arg) 
+{
+	printk("sv_test_1_w: acquiring spinlock 0x%p...\n", arg);
+
+	spin_lock((spinlock_t*)arg);
+	printk("sv_test_1_w: spinlock acquired, waking sv_test_1_s.\n");
+
+	up(&sem);
+
+	printk("sv_test_1_w: sv_spin_wait()'ing.\n");
+
+	sv_spin_wait(&sv, arg);
+
+	printk("sv_test_1_w: talkback.\n");
+	up(&talkback);
+
+	printk("sv_test_1_w: exiting.\n");
+	return 0;
+}
+
+static int sv_test_1_s(void *arg) 
+{
+	printk("sv_test_1_s: waiting for semaphore.\n");
+	down(&sem);
+	printk("sv_test_1_s: semaphore acquired.  Acquiring spinlock.\n");
+	spin_lock((spinlock_t*)arg);
+	printk("sv_test_1_s: spinlock acquired.  sv_signaling.\n");
+	sv_signal(&sv);
+	printk("sv_test_1_s: talkback.\n");
+	up(&talkback);
+	printk("sv_test_1_s: exiting.\n");
+	return 0;
+
+}
+
+static int count;
+static DECLARE_MUTEX(monitor);
+
+static int sv_test_2_w(void *arg) 
+{
+	int dummy = count++;
+	sv_t *sv = (sv_t *)arg;
+
+	down(&monitor);
+	up(&talkback);
+	printk("sv_test_2_w: thread %d started, sv_waiting.\n", dummy);
+	sv_sema_wait(sv, &monitor);
+	printk("sv_test_2_w: thread %d woken, exiting.\n", dummy);
+	up(&sem);
+	return 0;
+}
+
+static int sv_test_2_s_1(void *arg) 
+{
+	int i;
+	sv_t *sv = (sv_t *)arg;
+
+	down(&monitor);
+	for(i = 0; i < 3; i++) {
+		printk("sv_test_2_s_1: waking one thread.\n");
+		sv_signal(sv);
+		down(&sem);
+	}
+
+	printk("sv_test_2_s_1: signaling and broadcasting again.  Nothing should happen.\n");
+	sv_signal(sv);
+	sv_broadcast(sv);
+	sv_signal(sv);
+	sv_broadcast(sv);
+
+	printk("sv_test_2_s_1: talkbacking.\n");
+	up(&talkback);
+	up(&monitor);
+	return 0;
+}
+
+static int sv_test_2_s(void *arg) 
+{
+	int i;
+	sv_t *sv = (sv_t *)arg;
+
+	down(&monitor);
+	for(i = 0; i < 3; i++) {
+		printk("sv_test_2_s: waking one thread (should be %d.)\n", i);
+		sv_signal(sv);
+		down(&sem);
+	}
+
+	printk("sv_test_3_s: waking remaining threads with broadcast.\n");
+	sv_broadcast(sv);
+	for(; i < 10; i++)
+		down(&sem);
+
+	printk("sv_test_3_s: sending talkback.\n");
+	up(&talkback);
+
+	printk("sv_test_3_s: exiting.\n");
+	up(&monitor);
+	return 0;
+}
+
+
+static void big_test(sv_t *sv) 
+{
+	int i;
+
+	count = 0;
+
+	for(i = 0; i < 3; i++) {
+		printk("big_test: spawning thread %d.\n", i);
+		kernel_thread(sv_test_2_w, sv, 0);
+		down(&talkback);
+	}
+
+	printk("big_test: spawning first wake-up thread.\n");
+	kernel_thread(sv_test_2_s_1, sv, 0);
+
+	down(&talkback);
+	printk("big_test: talkback happened.\n");
+
+
+	for(i = 3; i < 13; i++) {
+		printk("big_test: spawning thread %d.\n", i);
+		kernel_thread(sv_test_2_w, sv, 0);
+		down(&talkback);
+	}
+
+	printk("big_test: spawning wake-up thread.\n");
+	kernel_thread(sv_test_2_s, sv, 0);
+
+	down(&talkback);
+}
+
+sv_t int_test_sv;
+spinlock_t int_test_spin = SPIN_LOCK_UNLOCKED;
+int int_test_ready;
+static int irqtestcount;
+
+static int interrupt_test_worker(void *unused) 
+{
+	int id = ++irqtestcount;
+	int it = 0;
+			unsigned long flags, flags2;
+
+	printk("ITW: thread %d started.\n", id);
+
+	while(1) {
+		__save_flags(flags2);
+		if(jiffies % 3) {
+			printk("ITW %2d %5d: irqsaving          (%lx)\n", id, it, flags2);
+			spin_lock_irqsave(&int_test_spin, flags);
+		} else {
+			printk("ITW %2d %5d: spin_lock_irqing   (%lx)\n", id, it, flags2);
+			spin_lock_irq(&int_test_spin);
+		}
+
+		__save_flags(flags2);
+		printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2);
+		sv_wait(&int_test_sv, 0, 0);
+
+		__save_flags(flags2);
+		printk("ITW %2d %5d: wait finished      (%lx), pausing\n", id, it, flags2);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(jiffies & 0xf);
+		if(current->state != TASK_RUNNING)
+		  printk("ITW:  current->state isn't RUNNING after schedule!\n");
+		it++;
+	}
+}
+
+static void interrupt_test(void) 
+{
+	int i;
+
+	printk("interrupt_test: initing sv.\n");
+	sv_init(&int_test_sv, &int_test_spin, SV_MON_SPIN | SV_INTS);
+
+	for(i = 0; i < SV_INTERRUPT_TEST_WORKERS; i++) {
+		printk("interrupt_test: starting test thread %d.\n", i);
+		kernel_thread(interrupt_test_worker, 0, 0);
+	}
+	printk("interrupt_test: done with init part.\n");
+	int_test_ready = 1;
+}
+
+int sv_test(void) 
+{
+	spinlock_t s = SPIN_LOCK_UNLOCKED;
+
+	sv_init(&sv, &s, SV_MON_SPIN);
+	printk("sv_test: starting sv_test_1_w.\n");
+	kernel_thread(sv_test_1_w, &s, 0);
+	printk("sv_test: starting sv_test_1_s.\n");
+	kernel_thread(sv_test_1_s, &s, 0);
+
+	printk("sv_test: waiting for talkback.\n");
+	down(&talkback); down(&talkback);
+	printk("sv_test: talkback happened, sv_destroying.\n");
+	sv_destroy(&sv);
+
+	count = 0;
+
+	printk("sv_test: beginning big_test on sv.\n");
+
+	sv_init(&sv, &monitor, SV_MON_SEMA);
+	big_test(&sv);
+	sv_destroy(&sv);
+
+	printk("sv_test: beginning big_test on sv_filo.\n");
+	sv_init(&sv_filo, &monitor, SV_MON_SEMA | SV_ORDER_FILO);
+	big_test(&sv_filo);
+	sv_destroy(&sv_filo);
+
+	interrupt_test();
+
+	printk("sv_test: done.\n");
+	return 0;
+}
+
+__initcall(sv_test);
+
+#endif /* RUN_SV_TEST */
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/synergy.c linux/arch/ia64/sn/sn1/synergy.c
--- v2.4.3/linux/arch/ia64/sn/sn1/synergy.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/sn/sn1/synergy.c	Thu Apr  5 12:51:47 2001
@@ -8,9 +8,12 @@
 
 
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
 
 #include <asm/ptrace.h>
 #include <linux/devfs_fs_kernel.h>
@@ -26,8 +29,6 @@
 void setclear_mask_a(int irq, int cpuid, int set);
 void * kmalloc(size_t size, int flags);
 
-extern struct sn1_cnode_action_list *sn1_node_actions[];
-
 
 void
 synergy_intr_alloc(int bit, int cpuid) {
@@ -40,9 +41,7 @@
 {
 	int irq;
 	unsigned is_b;
-int nasid;
 
-nasid = cpuid_to_nasid(cpuid);
 	irq = bit_pos_to_irq(bit);
 
 	is_b = (cpuid_to_slice(cpuid)) & 1;
@@ -202,3 +201,229 @@
 		REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);
 	}
 }
+
+#if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
+
+/*
+ * Synergy perf registers. Multiplexed via timer_interrupt
+ */
+static struct proc_dir_entry *synergy_perf_proc = NULL;
+
+/*
+ * read handler for /proc/synergy
+ */
+static int
+synergy_perf_read_proc (char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+	cnodeid_t       cnode;
+	nodepda_t       *npdap;
+	synergy_perf_t	*p;
+	int		len = 0;
+
+	len += sprintf(page+len, "# cnode module slot event synergy-A synergy-B\n");
+
+	/* walk the event list for each node */
+	for (cnode=0; cnode < numnodes; cnode++) {
+		npdap = NODEPDA(cnode);
+		if (npdap->synergy_perf_enabled == 0) {
+			len += sprintf(page+len, "# DISABLED\n");
+			break;
+		}
+
+		spin_lock_irq(&npdap->synergy_perf_lock);
+		for (p = npdap->synergy_perf_first; p;) {
+			uint64_t cnt_a=0, cnt_b=0;
+
+			if (p->intervals > 0) {
+				cnt_a = p->counts[0] * npdap->synergy_active_intervals / p->intervals;
+				cnt_b = p->counts[1] * npdap->synergy_active_intervals / p->intervals;
+			}
+
+			len += sprintf(page+len, "%d %d %d %12lx %lu %lu\n",
+				(int)cnode, (int)npdap->module_id, (int)npdap->slotdesc,
+				p->modesel, cnt_a, cnt_b);
+
+			p = p->next;
+			if (p == npdap->synergy_perf_first)
+				break;
+		}
+		spin_unlock_irq(&npdap->synergy_perf_lock);
+	}
+
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+
+	return len;
+}
+
+static int
+synergy_perf_append(uint64_t modesel)
+{
+	int		cnode;
+	nodepda_t       *npdap;
+	synergy_perf_t	*p;
+	int		err = 0;
+
+	/* bit 45 is enable */
+	modesel |= (1UL << 45);
+
+	for (cnode=0; cnode < numnodes; cnode++) {
+		/* for each node, insert a new synergy_perf entry */
+		if ((npdap = NODEPDA(cnode)) == NULL) {
+			printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, nodepda);
+			continue;
+		}
+
+		/* XX use kmem_alloc_node() when it is implemented */
+		p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL);
+		if (p == NULL)
+			err = -ENOMEM;
+		else {
+			memset(p, 0, sizeof(synergy_perf_t));
+			p->modesel = modesel;
+			if (npdap->synergy_perf_data == NULL) {
+				/* circular list */
+				p->next = p;
+				npdap->synergy_perf_data = p;
+				npdap->synergy_perf_first = p;
+			}
+			else {
+				/*
+				 * Jumble up the insertion order so we get better sampling.
+				 * Once the list is complete, "first" stays the same so the
+				 * reporting order is consistent.
+				 */
+				p->next = npdap->synergy_perf_first->next;
+				npdap->synergy_perf_first->next = p;
+				npdap->synergy_perf_first = p->next;
+			}
+		}
+	}
+
+	return err;
+}
+
+static int
+synergy_perf_write_proc (struct file *file, const char *buffer,
+                                unsigned long count, void *data)
+{
+	int		cnode;
+	nodepda_t       *npdap;
+	uint64_t	modesel;
+	char		cmd[64];
+	extern long	atoi(char *);
+    
+	if (count == sizeof(uint64_t)) {
+	    if (copy_from_user(&modesel, buffer, sizeof(uint64_t)))
+		    return -EFAULT;
+	    synergy_perf_append(modesel);
+	}
+	else {
+	    if (copy_from_user(cmd, buffer, count < sizeof(cmd) ? count : sizeof(cmd)))
+		    return -EFAULT;
+	    if (strncmp(cmd, "enable", 6) == 0) {
+		/* enable counting */
+		for (cnode=0; cnode < numnodes; cnode++) {
+			npdap = NODEPDA(cnode);
+			npdap->synergy_perf_enabled = 1;
+		}
+		printk("NOTICE: synergy perf counting enabled\n");
+	    }
+	    else
+	    if (strncmp(cmd, "disable", 7) == 0) {
+		/* disable counting */
+		for (cnode=0; cnode < numnodes; cnode++) {
+			npdap = NODEPDA(cnode);
+			npdap->synergy_perf_enabled = 0;
+		}
+		printk("NOTICE: synergy perf counting disabled\n");
+	    }
+	    else
+	    if (strncmp(cmd, "frequency", 9) == 0) {
+		/* set the update frequency (timer-interrupts per update) */
+		int freq;
+
+		if (count < 12)
+			return -EINVAL;
+		freq = atoi(cmd + 10);
+		if (freq <= 0 || freq > 100)
+			return -EINVAL;
+		for (cnode=0; cnode < numnodes; cnode++) {
+			npdap = NODEPDA(cnode);
+			npdap->synergy_perf_freq = (uint64_t)freq;
+		}
+		printk("NOTICE: synergy perf freq set to %d\n", freq);
+	    }
+	    else
+		return -EINVAL;
+	}
+	
+	return count;
+}
+
+void
+synergy_perf_update(int cpu)
+{
+	nasid_t		nasid;
+	cnodeid_t       cnode = cpuid_to_cnodeid(cpu);
+	struct nodepda_s *npdap;
+	extern struct nodepda_s *nodepda;
+
+	if (nodepda == NULL || (npdap=NODEPDA(cnode)) == NULL || npdap->synergy_perf_enabled == 0 ||
+		npdap->synergy_perf_data == NULL) {
+		/* I/O not initialized, or not enabled, or no events to monitor */
+		return;
+	}
+
+	if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) {
+		/* don't multiplex on every timer interrupt */
+		return;
+	}
+
+	/*
+	 * Read registers for last interval and increment counters.
+	 * Hold the per-node synergy_perf_lock so concurrent readers get
+	 * consistent values.
+	 */
+	spin_lock_irq(&npdap->synergy_perf_lock);
+
+	nasid = cpuid_to_nasid(cpu);
+	npdap->synergy_active_intervals++;
+	npdap->synergy_perf_data->intervals++;
+
+	npdap->synergy_perf_data->counts[0] += 0xffffffffffUL &
+		REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A);
+
+	npdap->synergy_perf_data->counts[1] += 0xffffffffffUL &
+		REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B);
+
+	/* skip to next in circular list */
+	npdap->synergy_perf_data = npdap->synergy_perf_data->next;
+
+	spin_unlock_irq(&npdap->synergy_perf_lock);
+
+	/* set the counter 0 selection modes for both A and B */
+	REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel);
+	REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel);
+
+	/* and reset the counter registers to zero */
+	REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL);
+	REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL);
+}
+
+void
+synergy_perf_init(void)
+{
+        if ((synergy_perf_proc = create_proc_entry("synergy", 0644, NULL)) != NULL) {
+                synergy_perf_proc->read_proc = synergy_perf_read_proc;
+                synergy_perf_proc->write_proc = synergy_perf_write_proc;
+                printk("markgw: synergy_perf_init()\n");
+        }
+}
+
+#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */
+
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/tools/print_offsets.awk linux/arch/ia64/tools/print_offsets.awk
--- v2.4.3/linux/arch/ia64/tools/print_offsets.awk	Fri Jul 14 16:08:12 2000
+++ linux/arch/ia64/tools/print_offsets.awk	Thu Apr  5 12:51:47 2001
@@ -28,6 +28,10 @@
 	inside_table = 0
 }
 
+/.*[.]rodata/ {
+	inside_table = 0
+}
+
 {
 	if (inside_table) {
 		if ($1 == "//") getline;
@@ -61,7 +65,7 @@
 	inside_table = 1
 }
 
-/tab#:/ {
+/tab\#:/ {
 	inside_table = 1
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c
--- v2.4.3/linux/arch/ia64/tools/print_offsets.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/tools/print_offsets.c	Thu Apr  5 12:51:47 2001
@@ -1,8 +1,8 @@
 /*
  * Utility to generate asm-ia64/offsets.h.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Note that this file has dual use: when building the kernel
  * natively, the file is translated into a binary and executed.  When
@@ -45,9 +45,8 @@
     { "IA64_PT_REGS_SIZE",		sizeof (struct pt_regs) },
     { "IA64_SWITCH_STACK_SIZE",		sizeof (struct switch_stack) },
     { "IA64_SIGINFO_SIZE",		sizeof (struct siginfo) },
-#ifdef CONFIG_IA64_NEW_UNWIND
+    { "IA64_CPU_SIZE",			sizeof (struct cpuinfo_ia64) },
     { "UNW_FRAME_INFO_SIZE",		sizeof (struct unw_frame_info) },
-#endif
     { "", 0 },			/* spacer */
     { "IA64_TASK_PTRACE_OFFSET",	offsetof (struct task_struct, ptrace) },
     { "IA64_TASK_SIGPENDING_OFFSET",	offsetof (struct task_struct, sigpending) },
@@ -58,6 +57,9 @@
 #ifdef CONFIG_IA32_SUPPORT
     { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) },
 #endif
+#ifdef CONFIG_PERFMON
+    { "IA64_TASK_PFM_NOTIFY_OFFSET",	offsetof(struct task_struct, thread.pfm_pend_notify) },
+#endif
     { "IA64_TASK_PID_OFFSET",		offsetof (struct task_struct, pid) },
     { "IA64_TASK_MM_OFFSET",		offsetof (struct task_struct, mm) },
     { "IA64_PT_REGS_CR_IPSR_OFFSET",	offsetof (struct pt_regs, cr_ipsr) },
@@ -157,6 +159,11 @@
     { "IA64_SIGCONTEXT_FR6_OFFSET",	offsetof (struct sigcontext, sc_fr[6]) },
     { "IA64_CLONE_VFORK",		CLONE_VFORK },
     { "IA64_CLONE_VM",			CLONE_VM },
+    { "IA64_CPU_IRQ_COUNT_OFFSET",	offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) },
+    { "IA64_CPU_BH_COUNT_OFFSET",	offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) },
+    { "IA64_CPU_SOFTIRQ_ACTIVE_OFFSET",		offsetof (struct cpuinfo_ia64, softirq.active) },
+    { "IA64_CPU_SOFTIRQ_MASK_OFFSET",		offsetof (struct cpuinfo_ia64, softirq.mask) },
+    { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET",	offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) },
 };
 
 static const char *tabs = "\t\t\t\t\t\t\t\t\t\t";
diff -u --recursive --new-file v2.4.3/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S
--- v2.4.3/linux/arch/ia64/vmlinux.lds.S	Fri Aug 11 19:09:06 2000
+++ linux/arch/ia64/vmlinux.lds.S	Thu Apr  5 12:51:47 2001
@@ -5,10 +5,18 @@
 
 OUTPUT_FORMAT("elf64-ia64-little")
 OUTPUT_ARCH(ia64)
-ENTRY(_start)
+ENTRY(phys_start)
 SECTIONS
 {
+  /* Sections to be discarded */
+  /DISCARD/ : {
+	*(.text.exit)
+	*(.data.exit)
+	*(.exitcall.exit)
+	}
+
   v = PAGE_OFFSET;	/* this symbol is here to make debugging easier... */
+  phys_start = _start - PAGE_OFFSET;
 
   . = KERNEL_START;
 
@@ -16,11 +24,11 @@
   _stext = .;
   .text : AT(ADDR(.text) - PAGE_OFFSET)
     {
-	*(__ivt_section)
+	*(.text.ivt)
 	/* these are not really text pages, but the zero page needs to be in a fixed location: */
 	*(__special_page_section)
 	__start_gate_section = .;
-	*(__gate_section)
+	*(.text.gate)
 	__stop_gate_section = .;
 	*(.text)
     }
@@ -34,7 +42,7 @@
 
   /* Read-only data */
 
-  __gp = ALIGN(8) + 0x200000;
+  __gp = ALIGN(16) + 0x200000;	/* gp must be 16-byte aligned for exc. table */
 
   /* Global data */
   _data = .;
@@ -60,13 +68,19 @@
 	{ *(__ksymtab) }
   __stop___ksymtab = .;
 
-  /* Unwind table */
+  __start___kallsyms = .;	/* All kernel symbols for debugging */
+  __kallsyms : AT(ADDR(__kallsyms) - PAGE_OFFSET)
+	{ *(__kallsyms) }
+  __stop___kallsyms = .;
+
+  /* Unwind info & table: */
+  .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET)
+	{ *(.IA_64.unwind_info*) }
+  . = ALIGN(8);
   ia64_unw_start = .;
   .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET)
-	{ *(.IA_64.unwind) }
+	{ *(.IA_64.unwind*) }
   ia64_unw_end = .;
-  .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET)
-	{ *(.IA_64.unwind_info) }
 
   .rodata : AT(ADDR(.rodata) - PAGE_OFFSET)
 	{ *(.rodata) }
@@ -129,13 +143,6 @@
 	{ *(.bss) *(COMMON) }
   . = ALIGN(64 / 8);
   _end = .;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-	*(.text.exit)
-	*(.data.exit)
-	*(.exitcall.exit)
-	}
 
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.4.3/linux/arch/m68k/amiga/config.c	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/amiga/config.c	Fri Apr 13 20:26:07 2001
@@ -769,20 +769,6 @@
     return 0;
 }
 
-void dbprintf(const char *fmt , ...)
-{
-	static char buf[1024];
-	va_list args;
-	extern void console_print (const char *str);
-	extern int vsprintf(char * buf, const char * fmt, va_list args);
-
-	va_start(args, fmt);
-	vsprintf(buf, fmt, args);
-	va_end(args);
-
-	console_print (buf);
-}
-
 static NORET_TYPE void amiga_reset( void )
     ATTRIB_NORET;
 
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.4.3/linux/arch/m68k/config.in	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/config.in	Tue Apr 17 17:19:25 2001
@@ -4,6 +4,8 @@
 #
 
 define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_name "Linux/68k Kernel Configuration"
 
@@ -487,8 +489,10 @@
    fi
 fi
 if [ "$CONFIG_APOLLO" = "y" ]; then
-   bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
+   bool 'Support for DN serial port (dummy)' CONFIG_DN_SERIAL
    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
+
+   define_tristate CONFIG_SERIAL $CONFIG_DN_SERIAL
 fi 
 bool 'Support for user serial device modules' CONFIG_USERIAL
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/ifpsp060/src/fpsp.S linux/arch/m68k/ifpsp060/src/fpsp.S
--- v2.4.3/linux/arch/m68k/ifpsp060/src/fpsp.S	Tue Mar  6 19:44:35 2001
+++ linux/arch/m68k/ifpsp060/src/fpsp.S	Fri Apr  6 10:42:47 2001
@@ -19594,7 +19594,7 @@
 # in the data register file. If it's actually out in memory, use one of	#
 # the mem_read() routines to fetch it. If the mem_read() access returns	#
 # a failing value, exit through the special facc_in() routine which	#
-# will create an acess error exception frame from the current exception #
+# will create an access error exception frame from the current exception #
 # frame.								#
 # 	Immediate data and regular data accesses are separated because 	#
 # if an immediate data access fails, the resulting fault status		#
@@ -24608,7 +24608,7 @@
 # made out of the current exception stack frame. 			#
 #	So, we first call restore() which makes sure that any updated	#
 # -(an)+ register gets returned to its pre-exception value and then	#
-# we change the stack to an acess error stack frame.			#
+# we change the stack to an access error stack frame.			#
 #									#
 #########################################################################
 
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/ifpsp060/src/pfpsp.S linux/arch/m68k/ifpsp060/src/pfpsp.S
--- v2.4.3/linux/arch/m68k/ifpsp060/src/pfpsp.S	Tue Mar  6 19:44:36 2001
+++ linux/arch/m68k/ifpsp060/src/pfpsp.S	Fri Apr  6 10:42:48 2001
@@ -14568,7 +14568,7 @@
 # made out of the current exception stack frame. 			#
 #	So, we first call restore() which makes sure that any updated	#
 # -(an)+ register gets returned to its pre-exception value and then	#
-# we change the stack to an acess error stack frame.			#
+# we change the stack to an access error stack frame.			#
 #									#
 #########################################################################
 
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/kernel/semaphore.c linux/arch/m68k/kernel/semaphore.c
--- v2.4.3/linux/arch/m68k/kernel/semaphore.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -130,111 +130,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	__up_read(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-                if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	current->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-}
-
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-}
-
-void rwsem_wake_writer(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.4.3/linux/arch/m68k/kernel/setup.c	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/kernel/setup.c	Fri Apr 13 20:26:07 2001
@@ -39,10 +39,6 @@
 #include <linux/blk.h>
 #endif
 
-#ifndef CONFIG_AMIGA
-#define dbprintf	printk
-#endif
-
 unsigned long m68k_machtype;
 unsigned long m68k_cputype;
 unsigned long m68k_fputype;
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/mm/motorola.c linux/arch/m68k/mm/motorola.c
--- v2.4.3/linux/arch/m68k/mm/motorola.c	Mon Aug  7 21:02:27 2000
+++ linux/arch/m68k/mm/motorola.c	Fri Apr  6 10:42:48 2001
@@ -286,6 +286,7 @@
 }
 
 extern char __init_begin, __init_end;
+extern unsigned long totalram_pages;
 
 void free_initmem(void)
 {
@@ -296,6 +297,7 @@
 		virt_to_page(addr)->flags &= ~(1 << PG_reserved);
 		set_page_count(virt_to_page(addr), 1);
 		free_page(addr);
+		totalram_pages++;
 	}
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.4.3/linux/arch/m68k/q40/config.c	Tue Mar  6 19:44:36 2001
+++ linux/arch/m68k/q40/config.c	Fri Apr  6 10:42:48 2001
@@ -238,7 +238,7 @@
     mach_max_dma_address = 32*1024*1024;   /* no DMA at all, but ide-scsi requires it.. */
 
 
-/* userfull for early debugging stages writes kernel messages into SRAM */
+/* useful for early debugging stages - writes kernel messages into SRAM */
 
     if (!strncmp( m68k_debug_device,"mem",3 ))
       {
diff -u --recursive --new-file v2.4.3/linux/arch/mips/Makefile linux/arch/mips/Makefile
--- v2.4.3/linux/arch/mips/Makefile	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/Makefile	Fri Apr 13 20:26:07 2001
@@ -17,8 +17,10 @@
 #
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 tool-prefix	= mipsel-linux-
+output-format	= elf32-littlemips
 else
 tool-prefix	= mips-linux-
+output-format	= elf32-bigmips
 endif
 
 ifdef CONFIG_CROSSCOMPILE
@@ -26,16 +28,16 @@
 endif
 
 #
-# The ELF GCC uses -G0 -mabicalls -fpic as default.  We don't need PIC
-# code in the kernel since it only slows down the whole thing.  For the
-# old GCC these options are just the defaults.  At some point we might
-# make use of global pointer optimizations.
+# GCC uses -G0 -mabicalls -fpic as default.  We don't want PIC in the kernel
+# code since it only slows down the whole thing.  At some point we might make
+# use of global pointer optimizations but their use of $28 conflicts with
+# the current pointer optimization.
 #
 # The DECStation requires an ECOFF kernel for remote booting, other MIPS
 # machines may also.  Since BFD is incredibly buggy with respect to
 # crossformat linking we rely on the elf2ecoff tool for format conversion.
 #
-CFLAGS		+= -G 0 -mno-abicalls -fno-pic
+GCCFLAGS	:= -G 0 -mno-abicalls -fno-pic
 LINKFLAGS	+= -static -G 0
 MODFLAGS	+= -mlong-calls
 
@@ -47,37 +49,63 @@
 # CPU-dependent compiler/assembler options for optimization.
 #
 ifdef CONFIG_CPU_R3000
-CFLAGS		:= $(CFLAGS) -mcpu=r3000 -mips1
+GCCFLAGS	+= -mcpu=r3000 -mips1
+endif
+ifdef CONFIG_CPU_R3912
+GCCFLAGS	+= -mcpu=r3000 -mips1
 endif
 ifdef CONFIG_CPU_R6000
-CFLAGS		:= $(CFLAGS) -mcpu=r6000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r6000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R4300
-CFLAGS		:= $(CFLAGS) -mcpu=r4300 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r4300 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R4X00
-CFLAGS		:= $(CFLAGS) -mcpu=r4600 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r4600 -mips2 -Wa,--trap
+endif
+ifdef CONFIG_CPU_MIPS32
+GCCFLAGS	+= -mcpu=r4600 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R5000
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
+endif
+ifdef CONFIG_CPU_R5432
+GCCFLAGS        += -mcpu=r8000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_NEVADA
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap -mmad
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap -mmad
+endif
+ifdef CONFIG_CPU_RM7000
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R8000
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
 endif
 ifdef CONFIG_CPU_R10000
-CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS	+= -mcpu=r8000 -mips2 -Wa,--trap
 endif
 
+ifdef CONFIG_MIPS_FPU_EMULATOR
+CORE_FILES	+=arch/mips/math-emu/fpu_emulator.o
+SUBDIRS		+=arch/mips/math-emu
+endif
+
+#
+# The pipe options is bad for my low-mem machine
+# Uncomment this if you want this.
+#
+GCCFLAGS	+= -pipe
+
+CFLAGS		:= -I $(TOPDIR)/include/asm/gcc $(CFLAGS) $(GCCFLAGS)
+AFLAGS		+= $(GCCFLAGS)
+
 #
 # Board-dependent options and extra files
 #
 ifdef CONFIG_ALGOR_P4032
 CORE_FILES    += arch/mips/algor/algor.o
 SUBDIRS       += arch/mips/algor
-#LOADADDR      += 0x80000000
+LOADADDR      += 0x80000000
 endif
 
 #
@@ -90,6 +118,18 @@
 LOADADDR      += 0x80040000
 endif
 
+ifdef CONFIG_MIPS_ATLAS
+LIBS          += arch/mips/mips-boards/atlas/atlas.o arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS       += arch/mips/mips-boards/generic arch/mips/mips-boards/atlas
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_MALTA
+LIBS          += arch/mips/mips-boards/malta/malta.o arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS       += arch/mips/mips-boards/malta arch/mips/mips-boards/generic
+LOADADDR      += 0x80100000
+endif
+
 #
 # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
 #
@@ -100,12 +140,6 @@
 LOADADDR      += 0x80080000
 endif
 
-ifdef CONFIG_COBALT_MICRO_SERVER
-ARCHIVES      += arch/mips/cobalt/cobalt.o
-SUBDIRS       += arch/mips/cobalt
-LOADADDR      += 0x80000000
-endif
-
 ifdef CONFIG_SNI_RM200_PCI
 CORE_FILES    += arch/mips/sni/sni.o
 SUBDIRS       += arch/mips/sni arch/mips/arc
@@ -114,7 +148,8 @@
 endif
 
 ifdef CONFIG_SGI_IP22
-LIBS          += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a
+CORE_FILES    += arch/mips/sgi/kernel/ip22-kern.o
+LIBS          += arch/mips/arc/arclib.a
 SUBDIRS       += arch/mips/sgi/kernel arch/mips/arc
 #
 # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
@@ -152,28 +187,74 @@
 endif
 
 #
-# Choosing incompatible machines durings configuration will result in
-# error messages during linking.  Select a default linkscript if
-# none has been choosen above.
 #
-ifndef LINKSCRIPT
-ifndef CONFIG_CPU_LITTLE_ENDIAN
-LINKSCRIPT    = arch/mips/ld.script.big
-else
-LINKSCRIPT    = arch/mips/ld.script.little
+# NEC DDB Vrc-5476
+#
+ifdef CONFIG_DDB5476
+SUBDIRS       += arch/mips/ddb5476
+LIBS          += arch/mips/ddb5476/ddb5476.a
+LOADADDR      += 0x80080000
 endif
+
+#
+# Galileo EV64120 Board
+#
+ifdef CONFIG_MIPS_EV64120
+LIBS          += arch/mips/galileo-boards/ev64120/ev64120.o
+SUBDIRS       += arch/mips/galileo-boards/ev64120
+LOADADDR      += 0x80100000
 endif
-LINKFLAGS     += -T $(word 1,$(LINKSCRIPT))
 
-ifdef LOADADDR
-LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
+#
+# Galileo EV96100 Board
+#
+ifdef CONFIG_MIPS_EV96100
+LIBS          += arch/mips/galileo-boards/ev96100/ev96100.o arch/mips/galileo-boards/generic/galboards.o
+SUBDIRS       += arch/mips/galileo-boards/generic arch/mips/galileo-boards/ev96100
+LOADADDR      += 0x80100000
 endif
 
 #
-# The pipe options is bad for my low-mem machine
-# Uncomment this if you want this.
+# Momentum Ocelot board
+#
+ifdef CONFIG_MOMENCO_OCELOT
+LIBS          += arch/mips/gt64120/common/gt64120.o arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o
+SUBDIRS       += arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot
+LOADADDR      += 0x80100000
+endif
+
 #
-CFLAGS		+= -pipe
+# Philips Nino
+#
+ifdef CONFIG_NINO
+CORE_FILES    += arch/mips/philips/nino/nino.o \
+		 arch/mips/philips/drivers/drivers.o
+SUBDIRS       += arch/mips/philips/nino arch/mips/philips/drivers
+LOADADDR      += 0x80000000
+endif
+
+#
+# ITE 8172 eval board with QED 5231 CPU
+#
+ifdef CONFIG_MIPS_ITE8172
+LIBS		+= arch/mips/ite-boards/qed-4n-s01b/ite.o		     \
+		   arch/mips/ite-boards/generic/it8172.o
+SUBDIRS		+= arch/mips/ite-boards/generic				     \
+		   arch/mips/ite-boards/qed-4n-s01b
+LOADADDR	+= 0x80100000
+endif
+
+#
+# Choosing incompatible machines durings configuration will result in
+# error messages during linking.  Select a default linkscript if
+# none has been choosen above.
+#
+vmlinux: arch/$(ARCH)/ld.script
+
+arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile
+	sed -e 's/@@OUTPUT_FORMAT@@/$(output-format)/' \
+	    -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@
+LINKFLAGS	+= -T arch/$(ARCH)/ld.script
 
 HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
 
@@ -197,8 +278,18 @@
 	$(ORIONBOOT) orionboot
 endif
 
+ifdef CONFIG_MIPS_EV64120
+GALILEOBOOT = $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120
+
+gboot: vmlinux
+	$(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120/compressed 
+endif
+
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
+vmlinux.ecoff: vmlinux
+	@$(MAKEBOOT) $@
+
 zImage: vmlinux
 	@$(MAKEBOOT) zImage
 
@@ -209,7 +300,7 @@
 
 archclean:
 	@$(MAKEBOOT) clean
-	$(MAKE) -C arch/$(ARCH)/kernel clean
+	rm -f arch/$(ARCH)/ld.script
 	$(MAKE) -C arch/$(ARCH)/tools clean
 	$(MAKE) -C arch/mips/baget clean
 
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/Makefile linux/arch/mips/arc/Makefile
--- v2.4.3/linux/arch/mips/arc/Makefile	Sat May 13 08:29:14 2000
+++ linux/arch/mips/arc/Makefile	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
 #
 # Makefile for the SGI arcs prom monitor library routines
 # under Linux.
@@ -10,7 +9,10 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 L_TARGET = arclib.a
-L_OBJS  = console.o init.o printf.o memory.o tree.o env.o cmdline.o misc.o \
-	  time.o file.o identify.o
+
+obj-y		+= console.o init.o memory.o tree.o env.o cmdline.o misc.o \
+		   time.o file.o identify.o
+
+obj-$(CONFIG_ARC_CONSOLE)   += arc_con.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/arc_con.c linux/arch/mips/arc/arc_con.c
--- v2.4.3/linux/arch/mips/arc/arc_con.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/arc_con.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,69 @@
+/*
+ * Wrap-around code for a console using the
+ * ARC io-routines.
+ *
+ * Copyright (c) 1998 Harald Koerfgen 
+ */
+
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+
+extern char prom_getchar (void);
+extern void prom_printf (char *, ...);
+
+static void prom_console_write(struct console *co, const char *s,
+			       unsigned count)
+{
+	unsigned i;
+
+	/*
+	 *    Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		if (*s == 10)
+			prom_printf("%c", 13);
+		prom_printf("%c", *s++);
+	}
+}
+
+static int prom_console_wait_key(struct console *co)
+{
+	return prom_getchar();
+}
+
+static int __init prom_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+static kdev_t prom_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console arc_cons = {
+	"ttyS",
+	prom_console_write,
+	NULL,
+	prom_console_device,
+	prom_console_wait_key,
+	NULL,
+	prom_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *    Register console.
+ */
+
+void __init arc_console_init(void)
+{
+	register_console(&arc_cons);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/cmdline.c linux/arch/mips/arc/cmdline.c
--- v2.4.3/linux/arch/mips/arc/cmdline.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/arc/cmdline.c	Fri Apr 13 20:26:07 2001
@@ -2,8 +2,6 @@
  * cmdline.c: Kernel command line creation using ARCS argc/argv.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -12,9 +10,9 @@
 #include <asm/sgialib.h>
 #include <asm/bootinfo.h>
 
-/* #define DEBUG_CMDLINE */
+#undef DEBUG_CMDLINE
 
-char arcs_cmdline[CL_SIZE];
+char arcs_cmdline[COMMAND_LINE_SIZE];
 
 char * __init prom_getcmdline(void)
 {
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/console.c linux/arch/mips/arc/console.c
--- v2.4.3/linux/arch/mips/arc/console.c	Mon Feb 28 07:18:20 2000
+++ linux/arch/mips/arc/console.c	Fri Apr 13 20:26:07 2001
@@ -1,50 +1,99 @@
 /*
- * console.c: SGI arcs console code.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  *
  * Copyright (C) 1996 David S. Miller (dm@sgi.com)
  * Compability with board caches, Ulf Carlsson
- *
- * $Id: console.c,v 1.3 1999/10/09 00:00:57 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <asm/sgialib.h>
 #include <asm/bcache.h>
+#include <linux/console.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+
+#ifdef CONFIG_ARC_CONSOLE
+#define __init
+#endif
 
-/* The romvec is not compatible with board caches.  Thus we disable it during
- * romvec action.  Since r4xx0.c is always compiled and linked with your kernel,
- * this shouldn't cause any harm regardless what MIPS processor you have.
+/*
+ * IP22 boardcache is not compatible with board caches.  Thus we disable it
+ * during romvec action.  Since r4xx0.c is always compiled and linked with your
+ * kernel, this shouldn't cause any harm regardless what MIPS processor you
+ * have.
  *
- * The romvec write and read functions seem to interfere with the serial lines
+ * The ARC write and read functions seem to interfere with the serial lines
  * in some way. You should be careful with them.
  */
-extern struct bcache_ops *bcops;
 
-#ifdef CONFIG_SGI_PROM_CONSOLE
-void prom_putchar(char c)
-#else
 void __init prom_putchar(char c)
-#endif
 {
 	long cnt;
 	char it = c;
 
-	bcops->bc_disable();
+	bc_disable();
 	romvec->write(1, &it, 1, &cnt);
-	bcops->bc_enable();
+	bc_enable();
 }
 
-#ifdef CONFIG_SGI_PROM_CONSOLE
-char prom_getchar(void)
-#else
 char __init prom_getchar(void)
-#endif
 {
 	long cnt;
 	char c;
 
-	bcops->bc_disable();
+	bc_disable();
 	romvec->read(0, &c, 1, &cnt);
-	bcops->bc_enable();
+	bc_enable();
+
 	return c;
+}
+
+static char ppbuf[1024];
+
+void __init prom_printf(char *fmt, ...)
+{
+	va_list args;
+	char ch, *bptr;
+	int i;
+
+	va_start(args, fmt);
+	i = vsprintf(ppbuf, fmt, args);
+
+	bptr = ppbuf;
+
+	while ((ch = *(bptr++)) != 0) {
+		if (ch == '\n')
+			prom_putchar('\r');
+
+		prom_putchar(ch);
+	}
+	va_end(args);
+}
+
+static void
+arc_console_write(struct console *con, const char *s, unsigned n)
+{
+	prom_printf("%s", s);
+}
+
+static kdev_t 
+arc_console_dev(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console arc_prom_console = {
+    name:	"prom",
+    write:	arc_console_write,
+    device:	arc_console_dev,
+    flags:	CON_PRINTBUFFER,
+    index:	-1,
+};
+
+__init void arc_setup_console(void)
+{
+	register_console(&arc_prom_console);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/identify.c linux/arch/mips/arc/identify.c
--- v2.4.3/linux/arch/mips/arc/identify.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/arc/identify.c	Fri Apr 13 20:26:07 2001
@@ -6,8 +6,6 @@
  * This code is based on arch/mips/sgi/kernel/system.c, which is
  * 
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -19,50 +17,51 @@
 #include <asm/bootinfo.h>
 
 struct smatch {
-    char *name;
-    int group;
-    int type;
-    int flags;
+	char *name;
+	int group;
+	int type;
+	int flags;
 };
 
 static struct smatch mach_table[] = {
-    { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS },
-    { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 },
-    { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 },
-    { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 }
+	{"SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS},
+	{"Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0},
+	{"PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0},
+	{"RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0}
 };
 
 int prom_flags;
 
-static struct smatch * __init string_to_mach(char *s)
+static struct smatch *__init string_to_mach(char *s)
 {
-    int i;
-    
-    for (i = 0; i < sizeof (mach_table); i++) {
-	if(!strcmp(s, mach_table[i].name))
-	    return &mach_table[i];
-    }
-    prom_printf("\nYeee, could not determine architecture type <%s>\n", s);
-    prom_printf("press a key to reboot\n");
-    prom_getchar();
-    romvec->imode();
-    return NULL;
+	int i;
+
+	for (i = 0; i < sizeof(mach_table); i++) {
+		if (!strcmp(s, mach_table[i].name))
+			return &mach_table[i];
+	}
+	prom_printf("\nYeee, could not determine architecture type <%s>\n",
+		    s);
+	prom_printf("press a key to reboot\n");
+	prom_getchar();
+	romvec->imode();
+	return NULL;
 }
 
 void __init prom_identify_arch(void)
 {
-    pcomponent *p;
-    struct smatch *mach;
-    
-    /* The root component tells us what machine architecture we
-     * have here.
-     */
-    p = prom_getchild(PROM_NULL_COMPONENT);
-    printk("ARCH: %s\n", p->iname);
-    mach = string_to_mach(p->iname);
-
-    mips_machgroup = mach->group;
-    mips_machtype = mach->type;
-    prom_flags = mach->flags;
-}
+	pcomponent *p;
+	struct smatch *mach;
 
+	/*
+	 * The root component tells us what machine architecture we
+	 * have here.
+	 */
+	p = prom_getchild(PROM_NULL_COMPONENT);
+	printk("ARCH: %s\n", p->iname);
+	mach = string_to_mach(p->iname);
+
+	mips_machgroup = mach->group;
+	mips_machtype = mach->type;
+	prom_flags = mach->flags;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/init.c linux/arch/mips/arc/init.c
--- v2.4.3/linux/arch/mips/arc/init.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/arc/init.c	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.5 2000/03/07 15:45:27 ralf Exp $
+/*
  * This file is subject to the terms and conditions of the GNU General Public+ 
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -23,7 +23,9 @@
 
 extern void prom_testtree(void);
 
-int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
+extern void arc_setup_console(void);
+
+void __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
 {
 	struct linux_promblock *pb;
 
@@ -33,7 +35,20 @@
 	prom_argv = argv;
 	prom_envp = envp;
 
-	if(pb->magic != 0x53435241) {
+#if 0
+	/* arc_printf should not use prom_printf as soon as we free
+	 * the prom buffers - This horribly breaks on Indys with framebuffer
+	 * as it simply stops after initialising swap - On the Indigo2 serial
+	 * console you will get A LOT illegal instructions - Only enable
+	 * this for early init crashes - This also brings up artefacts of
+	 * printing everything twice on serial console and on GFX Console
+	 * this has the effect of having the prom printing everything
+	 * in the small rectangle and the kernel printing around.
+	 */
+
+	arc_setup_console();
+#endif
+	if (pb->magic != 0x53435241) {
 		prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic);
 		while(1)
 			;
@@ -55,5 +70,4 @@
 		romvec->imode();
 	}
 #endif
-	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/memory.c linux/arch/mips/arc/memory.c
--- v2.4.3/linux/arch/mips/arc/memory.c	Mon Aug  7 21:02:27 2000
+++ linux/arch/mips/arc/memory.c	Fri Apr 13 20:26:07 2001
@@ -3,8 +3,6 @@
  *           given to us from the ARCS firmware.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: memory.c,v 1.10 2000/01/27 23:21:57 ralf Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -47,31 +45,25 @@
 	"LoadedProgram",
 	"FirmwareTemporary",
 	"FirmwarePermanent",
-	"FreeContigiuous"
+	"FreeContiguous"
 };
 #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc]
 #endif
 
-static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS];
-
-#define MEMTYPE_DONTUSE   0
-#define MEMTYPE_PROM      1
-#define MEMTYPE_FREE      2
-
 static inline int memtype_classify_arcs (union linux_memtypes type)
 {
 	switch (type.arcs) {
 	case arcs_fcontig:
 	case arcs_free:
-		return MEMTYPE_FREE;
+		return BOOT_MEM_RAM;
 	case arcs_atmp:
-		return MEMTYPE_PROM;
+		return BOOT_MEM_ROM_DATA;
 	case arcs_eblock:
 	case arcs_rvpage:
 	case arcs_bmem:
 	case arcs_prog:
 	case arcs_aperm:
-		return MEMTYPE_DONTUSE;
+		return BOOT_MEM_RESERVED;
 	default:
 		BUG();
 	}
@@ -83,15 +75,15 @@
 	switch (type.arc) {
 	case arc_free:
 	case arc_fcontig:
-		return MEMTYPE_FREE;
+		return BOOT_MEM_RAM;
 	case arc_atmp:
-		return MEMTYPE_PROM;
+		return BOOT_MEM_ROM_DATA;
 	case arc_eblock:
 	case arc_rvpage:
 	case arc_bmem:
 	case arc_prog:
 	case arc_aperm:
-		return MEMTYPE_DONTUSE;
+		return BOOT_MEM_RESERVED;
 	default:
 		BUG();
 	}
@@ -106,50 +98,13 @@
 	return memtype_classify_arc(type);
 }
 
-static inline unsigned long find_max_low_pfn(void)
-{
-	struct prom_pmemblock *p, *highest;
-	unsigned long pfn;
-
-	p = pblocks;
-	highest = 0;
-	while (p->size != 0) {
-		if (!highest || p->base > highest->base)
-			highest = p;
-		p++;
-	}
-
-	pfn = (highest->base + highest->size) >> PAGE_SHIFT;
-#ifdef DEBUG
-	prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn);
-#endif
-	return pfn;
-}
-
-static inline struct prom_pmemblock *find_largest_memblock(void)
-{
-	struct prom_pmemblock *p, *largest;
-
-	p = pblocks;
-	largest = 0;
-	while (p->size != 0) {
-		if (!largest || p->size > largest->size)
-			largest = p;
-		p++;
-	}
-
-	return largest;
-}
-
 void __init prom_meminit(void)
 {
-	struct prom_pmemblock *largest;
-	unsigned long bootmap_size;
 	struct linux_mdesc *p;
-	int totram;
-	int i = 0;
 
 #ifdef DEBUG
+	int i = 0;
+
 	prom_printf("ARCS MEMORY DESCRIPTOR dump:\n");
 	p = ArcGetMemoryDescriptor(PROM_NULL_MDESC);
 	while(p) {
@@ -160,77 +115,36 @@
 	}
 #endif
 
-	totram = 0;
-	i = 0;
 	p = PROM_NULL_MDESC;
 	while ((p = ArcGetMemoryDescriptor(p))) {
-		pblocks[i].type = prom_memtype_classify(p->type);
-		pblocks[i].base = p->base << PAGE_SHIFT;
-		pblocks[i].size = p->pages << PAGE_SHIFT;
-
-		switch (pblocks[i].type) {
-		case MEMTYPE_FREE:
-			totram += pblocks[i].size;
-#ifdef DEBUG
-			prom_printf("free_chunk[%d]: base=%08lx size=%x\n",
-				    i, pblocks[i].base,
-				    pblocks[i].size);
-#endif
-			i++;
-			break;
-		case MEMTYPE_PROM:
-#ifdef DEBUG
-			prom_printf("prom_chunk[%d]: base=%08lx size=%x\n",
-				    i, pblocks[i].base,
-				    pblocks[i].size);
-#endif
-			i++;
-			break;
-		default:
-			break;
-		}
-	}
-	pblocks[i].size = 0;
-
-	max_low_pfn = find_max_low_pfn();
-
-	largest = find_largest_memblock();
-	bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn);
+		unsigned long base, size;
+		long type;
 
-	for (i = 0; pblocks[i].size; i++)
-		if (pblocks[i].type == MEMTYPE_FREE)
-			free_bootmem(pblocks[i].base, pblocks[i].size);
+		base = p->base << PAGE_SHIFT;
+		size = p->pages << PAGE_SHIFT;
+		type = prom_memtype_classify(p->type);
 
-	/* This test is simpleminded.  It will fail if the bootmem bitmap
-	   falls into multiple adjacent ARC memory areas.  */
-	if (bootmap_size > largest->size) {
-		prom_printf("CRITIAL: overwriting PROM data.\n");
-		BUG();
+		add_memory_region(base, size, type);
 	}
-
-	/* Reserve the memory bootmap itself */
-	reserve_bootmem(largest->base, bootmap_size);
-
-	printk("PROMLIB: Total free ram %dK / %dMB.\n",
-	       totram >> 10, totram >> 20);
 }
 
 void __init
 prom_free_prom_memory (void)
 {
-	struct prom_pmemblock *p;
 	unsigned long freed = 0;
 	unsigned long addr;
+	int i;
 
-	for (p = pblocks; p->size != 0; p++) {
-		if (p->type != MEMTYPE_PROM)
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
 			continue;
 
-		addr = PAGE_OFFSET + p->base;
-		while (addr < p->base + p->size) {
-			ClearPageReserved(virt_to_page(addr));
-			set_page_count(virt_to_page(addr), 1);
-			free_page(addr);
+		addr = boot_mem_map.map[i].addr;
+		while (addr < boot_mem_map.map[i].addr
+			      + boot_mem_map.map[i].size) {
+			ClearPageReserved(virt_to_page(__va(addr)));
+			set_page_count(virt_to_page(__va(addr)), 1);
+			free_page((unsigned long)__va(addr));
 			addr += PAGE_SIZE;
 			freed += PAGE_SIZE;
 		}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/misc.c linux/arch/mips/arc/misc.c
--- v2.4.3/linux/arch/mips/arc/misc.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/arc/misc.c	Fri Apr 13 20:26:07 2001
@@ -1,5 +1,4 @@
-/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $
- *
+/*
  * misc.c: Miscellaneous ARCS PROM routines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -13,13 +12,12 @@
 #include <asm/bootinfo.h>
 #include <asm/system.h>
 
-extern unsigned long mips_cputype;
 extern void *sgiwd93_host;
 extern void reset_wd33c93(void *instance);
 
 void prom_halt(void)
 {
-	bcops->bc_disable();
+	bc_disable();
 	cli();
 #if CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
@@ -29,7 +27,7 @@
 
 void prom_powerdown(void)
 {
-	bcops->bc_disable();
+	bc_disable();
 	cli();
 #if CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
@@ -40,7 +38,7 @@
 /* XXX is this a soft reset basically? XXX */
 void prom_restart(void)
 {
-	bcops->bc_disable();
+	bc_disable();
 	cli();
 #if CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
@@ -50,7 +48,7 @@
 
 void prom_reboot(void)
 {
-	bcops->bc_disable();
+	bc_disable();
 	cli();
 #if CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
@@ -60,7 +58,7 @@
 
 void prom_imode(void)
 {
-	bcops->bc_disable();
+	bc_disable();
 	cli();
 #if CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
diff -u --recursive --new-file v2.4.3/linux/arch/mips/arc/printf.c linux/arch/mips/arc/printf.c
--- v2.4.3/linux/arch/mips/arc/printf.c	Mon Feb 28 07:18:20 2000
+++ linux/arch/mips/arc/printf.c	Wed Dec 31 16:00:00 1969
@@ -1,40 +0,0 @@
-/*
- * printf.c: Putting things on the screen using SGI arcs
- *           PROM facilities.
- *
- * Copyright (C) 1996 David S. Miller (dm@sgi.com)
- *
- * $Id: printf.c,v 1.3 1999/10/09 00:00:57 ralf Exp $
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/sgialib.h>
-
-static char ppbuf[1024];
-
-#ifdef CONFIG_SGI_PROM_CONSOLE
-void prom_printf(char *fmt, ...)
-#else
-void __init prom_printf(char *fmt, ...)
-#endif
-{
-	va_list args;
-	char ch, *bptr;
-	int i;
-
-	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
-	va_end(args);
-	return;
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/baget/Makefile linux/arch/mips/baget/Makefile
--- v2.4.3/linux/arch/mips/baget/Makefile	Sat May 13 08:29:14 2000
+++ linux/arch/mips/baget/Makefile	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.3 1999/08/13 17:07:26 harald Exp $
 #
 # Makefile for the Baget specific kernel interface routines
 # under Linux.
@@ -12,22 +11,12 @@
 all: baget.a 
 
 O_TARGET := baget.a
-O_OBJS   := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o
 
-ifeq ($(CONFIG_SERIAL),y)
-	OX_OBJS += vacserial.o
-else
-	ifeq ($(CONFIG_SERIAL),m)
-		MX_OBJS += vacserial.o
-	endif
-endif
-ifeq ($(CONFIG_VAC_RTC),y)
-	OX_OBJS += vacrtc.o
-else
-	ifeq ($(CONFIG_VAC_RTC),m)
-		MX_OBJS += vacrtc.o
-	endif
-endif
+export-objs		:= vacserial.o vacrtc.o
+obj-y			:= baget.o print.o setup.o time.o irq.o bagetIRQ.o \
+			   reset.o wbflush.o
+obj-$(CONFIG_SERIAL)	+= vacserial.o
+obj-$(CONFIG_VAC_RTC)	+= vacrtc.o
 
 bagetIRQ.o : bagetIRQ.S
 	$(CC) $(CFLAGS) -c -o $@ $<
diff -u --recursive --new-file v2.4.3/linux/arch/mips/baget/prom/Makefile linux/arch/mips/baget/prom/Makefile
--- v2.4.3/linux/arch/mips/baget/prom/Makefile	Sat May 13 08:29:14 2000
+++ linux/arch/mips/baget/prom/Makefile	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,4 @@
-# $Id$
+#
 # Makefile for the Baget/MIPS prom emulator library routines.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,9 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-O_TARGET := bagetlib.a
-O_OBJS   := init.o
+L_TARGET := bagetlib.a
 
-all: 	$(O_TARGET)
+obj-y	:= init.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.4.3/linux/arch/mips/config.in	Thu Nov 16 12:51:28 2000
+++ linux/arch/mips/config.in	Tue Apr 17 17:19:25 2001
@@ -28,6 +28,9 @@
 bool 'Support for SGI IP22' CONFIG_SGI_IP22
 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
 
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
 #
 # Select some configuration options automatically for certain systems.
 #
@@ -329,7 +332,10 @@
 #   if [ "$CONFIG_ACCESSBUS" = "y" ]; then
 #      bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE
 #   fi
-   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+   bool 'Enhanced Real Time Clock Support' CONFIG_MIPS_RTC
+
+   define_tristate CONFIG_RTC $CONFIG_MIPS_RTC
+
    endmenu
 fi
 
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/Makefile linux/arch/mips/ddb5074/Makefile
--- v2.4.3/linux/arch/mips/ddb5074/Makefile	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/Makefile	Fri Apr 13 20:26:07 2001
@@ -8,8 +8,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 #
-# $Id$
-#
 
 .S.s:
 	$(CPP) $(CFLAGS) $< -o $*.s
@@ -17,6 +15,7 @@
 	$(CC) $(CFLAGS) -c $< -o $*.o
 
 O_TARGET = ddb5074.a
-O_OBJS  = setup.o irq.o time.o prom.o pci.o pci-dma.o int-handler.o nile4.o
+
+obj-y	:= setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/int-handler.S linux/arch/mips/ddb5074/int-handler.S
--- v2.4.3/linux/arch/mips/ddb5074/int-handler.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/int-handler.S	Fri Apr 13 20:26:07 2001
@@ -7,54 +7,50 @@
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id: int-handler.S,v 1.1 2000/01/26 00:07:44 ralf Exp $
  */
-
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 
-	/* A lot of complication here is taken away because:
-	 *
-	 * 1) We handle one interrupt and return, sitting in a loop
-	 *    and moving across all the pending IRQ bits in the cause
-	 *    register is _NOT_ the answer, the common case is one
-	 *    pending IRQ so optimize in that direction.
-	 *
-	 * 2) We need not check against bits in the status register
-	 *    IRQ mask, that would make this routine slow as hell.
-	 *
-	 * 3) Linux only thinks in terms of all IRQs on or all IRQs
-	 *    off, nothing in between like BSD spl() brain-damage.
-	 *
-	 * Furthermore, the IRQs on the INDY look basically (barring
-	 * software IRQs which we don't use at all) like:
-	 *
-	 *	MIPS IRQ	Source
-	 *      --------        ------
-	 *             0	Software (ignored)
-	 *             1        Software (ignored)
-	 *             2        Local IRQ level zero
-	 *             3        Local IRQ level one
-	 *             4        8254 Timer zero
-	 *             5        8254 Timer one
-	 *             6        Bus Error
-	 *             7        R4k timer (what we use)
-	 *
-	 * We handle the IRQ according to _our_ priority which is:
-	 *
-	 * Highest ----     R4k Timer
-	 *                  Local IRQ zero
-	 *                  Local IRQ one
-	 *                  Bus Error
-	 *                  8254 Timer zero
-	 * Lowest  ----     8254 Timer one
-	 *
-	 * then we just return, if multiple IRQs are pending then
-	 * we will just take another exception, big deal.
-	 */
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ *    common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ *    would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ *    between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the INDY look basically (barring software IRQs
+ * which we don't use at all) like:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        Local IRQ level zero
+ *             3        Local IRQ level one
+ *             4        8254 Timer zero
+ *             5        8254 Timer one
+ *             6        Bus Error
+ *             7        R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ----     R4k Timer
+ *                  Local IRQ zero
+ *                  Local IRQ one
+ *                  Bus Error
+ *                  8254 Timer zero
+ * Lowest  ----     8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
 
 	.text
 	.set	noreorder
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/irq.c linux/arch/mips/ddb5074/irq.c
--- v2.4.3/linux/arch/mips/ddb5074/irq.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/irq.c	Fri Apr 13 20:26:07 2001
@@ -3,10 +3,7 @@
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $
  */
-
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/signal.h>
@@ -14,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -27,7 +25,7 @@
 
 extern asmlinkage void ddbIRQ(void);
 extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
-extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
+extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
 
 
 void no_action(int cpl, void *dev_id, struct pt_regs *regs)
@@ -55,177 +53,174 @@
 
 static void m1543_irq_setup(void)
 {
-    /*
-     *  The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13.  Not all
-     *  the possible IO sources in the M1543 are in use by us.  We will
-     *  use the following mapping:
-     *
-     *	    IRQ1  - keyboard (default set by M1543)
-     *	    IRQ3  - reserved for UART B (default set by M1543) (note that
-     *		    the schematics for the DDB Vrc-5074 board seem to 
-     *		    indicate that IRQ3 is connected to the DS1386 
-     *		    watchdog timer interrupt output so we might have 
-     *		    a conflict)
-     *	    IRQ4  - reserved for UART A (default set by M1543)
-     *	    IRQ5  - parallel (default set by M1543)
-     *	    IRQ8  - DS1386 time of day (RTC) interrupt
-     *	    IRQ12 - mouse
-     */
- 
-    /*
-     *  Assing mouse interrupt to IRQ12 
-     */
-
-    /* Enter configuration mode */
-    outb(0x51, M1543_PNP_CONFIG);
-    outb(0x23, M1543_PNP_CONFIG);
-
-    /* Select logical device 7 (Keyboard) */
-    outb(0x07, M1543_PNP_INDEX);
-    outb(0x07, M1543_PNP_DATA);
-
-    /* Select IRQ12 */
-    outb(0x72, M1543_PNP_INDEX);
-    outb(0x0c, M1543_PNP_DATA);
-
-    /* Leave configration mode */
-    outb(0xbb, M1543_PNP_CONFIG);
+	/*
+	 *  The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13.  Not all
+	 *  the possible IO sources in the M1543 are in use by us.  We will
+	 *  use the following mapping:
+	 *
+	 *      IRQ1  - keyboard (default set by M1543)
+	 *      IRQ3  - reserved for UART B (default set by M1543) (note that
+	 *              the schematics for the DDB Vrc-5074 board seem to 
+	 *              indicate that IRQ3 is connected to the DS1386 
+	 *              watchdog timer interrupt output so we might have 
+	 *              a conflict)
+	 *      IRQ4  - reserved for UART A (default set by M1543)
+	 *      IRQ5  - parallel (default set by M1543)
+	 *      IRQ8  - DS1386 time of day (RTC) interrupt
+	 *      IRQ12 - mouse
+	 */
+
+	/*
+	 *  Assing mouse interrupt to IRQ12 
+	 */
+
+	/* Enter configuration mode */
+	outb(0x51, M1543_PNP_CONFIG);
+	outb(0x23, M1543_PNP_CONFIG);
+
+	/* Select logical device 7 (Keyboard) */
+	outb(0x07, M1543_PNP_INDEX);
+	outb(0x07, M1543_PNP_DATA);
+
+	/* Select IRQ12 */
+	outb(0x72, M1543_PNP_INDEX);
+	outb(0x0c, M1543_PNP_DATA);
+
+	/* Leave configration mode */
+	outb(0xbb, M1543_PNP_CONFIG);
 
 
-    /* Initialize the 8259 PIC in the M1543 */
-    i8259_init();
+	/* Initialize the 8259 PIC in the M1543 */
+	i8259_init();
 
-    /* Enable the interrupt cascade */
-    nile4_enable_irq(NILE4_INT_INTE);
+	/* Enable the interrupt cascade */
+	nile4_enable_irq(NILE4_INT_INTE);
 
-    request_region(M1543_PNP_CONFIG, 2, "M1543 config");
-    request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR");
+	request_region(M1543_PNP_CONFIG, 2, "M1543 config");
+	request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR");
 }
 
 static void nile4_irq_setup(void)
 {
-    int i;
+	int i;
 
-    /* Map all interrupts to CPU int #0 */
-    nile4_map_irq_all(0);
+	/* Map all interrupts to CPU int #0 */
+	nile4_map_irq_all(0);
 
-    /* PCI INTA#-E# must be level triggered */
-    nile4_set_pci_irq_level_or_edge(0, 1);
-    nile4_set_pci_irq_level_or_edge(1, 1);
-    nile4_set_pci_irq_level_or_edge(2, 1);
-    nile4_set_pci_irq_level_or_edge(3, 1);
-    nile4_set_pci_irq_level_or_edge(4, 1);
-
-    /* PCI INTA#-D# must be active low, INTE# must be active high */
-    nile4_set_pci_irq_polarity(0, 0);
-    nile4_set_pci_irq_polarity(1, 0);
-    nile4_set_pci_irq_polarity(2, 0);
-    nile4_set_pci_irq_polarity(3, 0);
-    nile4_set_pci_irq_polarity(4, 1);
+	/* PCI INTA#-E# must be level triggered */
+	nile4_set_pci_irq_level_or_edge(0, 1);
+	nile4_set_pci_irq_level_or_edge(1, 1);
+	nile4_set_pci_irq_level_or_edge(2, 1);
+	nile4_set_pci_irq_level_or_edge(3, 1);
+	nile4_set_pci_irq_level_or_edge(4, 1);
+
+	/* PCI INTA#-D# must be active low, INTE# must be active high */
+	nile4_set_pci_irq_polarity(0, 0);
+	nile4_set_pci_irq_polarity(1, 0);
+	nile4_set_pci_irq_polarity(2, 0);
+	nile4_set_pci_irq_polarity(3, 0);
+	nile4_set_pci_irq_polarity(4, 1);
 
-    for (i = 0; i < 16; i++)
-	nile4_clear_irq(i);
+	for (i = 0; i < 16; i++)
+		nile4_clear_irq(i);
 
-    /* Enable CPU int #0 */
-    nile4_enable_irq_output(0);
+	/* Enable CPU int #0 */
+	nile4_enable_irq_output(0);
 
-    request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4");
+	request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4");
 }
 
 
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
  */
-
-static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL };
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
 
 
 void disable_irq(unsigned int irq_nr)
 {
-    if (is_i8259_irq(irq_nr))
-	i8259_disable_irq(irq_nr);
-    else
-	nile4_disable_irq(irq_to_nile4(irq_nr));
+	if (is_i8259_irq(irq_nr))
+		i8259_disable_irq(irq_nr);
+	else
+		nile4_disable_irq(irq_to_nile4(irq_nr));
 }
 
 void enable_irq(unsigned int irq_nr)
 {
-    if (is_i8259_irq(irq_nr))
-	i8259_enable_irq(irq_nr);
-    else
-	nile4_enable_irq(irq_to_nile4(irq_nr));
+	if (is_i8259_irq(irq_nr))
+		i8259_enable_irq(irq_nr);
+	else
+		nile4_enable_irq(irq_to_nile4(irq_nr));
 }
 
 int table[16] = { 0, };
 
 void ddb_local0_irqdispatch(struct pt_regs *regs)
 {
-    u32 mask;
-    int nile4_irq;
+	u32 mask;
+	int nile4_irq;
 #if 1
-    volatile static int nesting = 0;
-    if (nesting++ == 0)
-	ddb5074_led_d3(1);
-    ddb5074_led_hex(nesting < 16 ? nesting : 15);
+	volatile static int nesting = 0;
+	if (nesting++ == 0)
+		ddb5074_led_d3(1);
+	ddb5074_led_hex(nesting < 16 ? nesting : 15);
 #endif
 
-    mask = nile4_get_irq_stat(0);
-    nile4_clear_irq_mask(mask);
+	mask = nile4_get_irq_stat(0);
+	nile4_clear_irq_mask(mask);
 
-    /* Handle the timer interrupt first */
-    if (mask & (1<<NILE4_INT_GPT)) {
-	nile4_disable_irq(NILE4_INT_GPT);
-	do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
-	nile4_enable_irq(NILE4_INT_GPT);
-	mask &= ~(1<<NILE4_INT_GPT);
-    }
-    for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
-	if (mask & 1) {
-	    nile4_disable_irq(nile4_irq);
-	    if (nile4_irq == NILE4_INT_INTE) {
-		int i8259_irq = nile4_i8259_iack();
-		i8259_do_irq(i8259_irq, regs);
-	    } else
-		do_IRQ(nile4_to_irq(nile4_irq), regs);
-	    nile4_enable_irq(nile4_irq);
+	/* Handle the timer interrupt first */
+	if (mask & (1 << NILE4_INT_GPT)) {
+		nile4_disable_irq(NILE4_INT_GPT);
+		do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
+		nile4_enable_irq(NILE4_INT_GPT);
+		mask &= ~(1 << NILE4_INT_GPT);
 	}
-
+	for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
+		if (mask & 1) {
+			nile4_disable_irq(nile4_irq);
+			if (nile4_irq == NILE4_INT_INTE) {
+				int i8259_irq = nile4_i8259_iack();
+				i8259_do_irq(i8259_irq, regs);
+			} else
+				do_IRQ(nile4_to_irq(nile4_irq), regs);
+			nile4_enable_irq(nile4_irq);
+		}
 #if 1
-    if (--nesting == 0)
-	ddb5074_led_d3(0);
-    ddb5074_led_hex(nesting < 16 ? nesting : 15);
+	if (--nesting == 0)
+		ddb5074_led_d3(0);
+	ddb5074_led_hex(nesting < 16 ? nesting : 15);
 #endif
 }
 
 void ddb_local1_irqdispatch(void)
 {
-    printk("ddb_local1_irqdispatch called\n");
+	printk("ddb_local1_irqdispatch called\n");
 }
 
 void ddb_buserror_irq(void)
 {
-    printk("ddb_buserror_irq called\n");
+	printk("ddb_buserror_irq called\n");
 }
 
 void ddb_8254timer_irq(void)
 {
-    printk("ddb_8254timer_irq called\n");
+	printk("ddb_8254timer_irq called\n");
 }
 
 void __init ddb_irq_setup(void)
 {
 #ifdef CONFIG_REMOTE_DEBUG
-    if (remote_debug)
-	set_debug_traps();
-    breakpoint(); /* you may move this line to whereever you want :-) */
+	if (remote_debug)
+		set_debug_traps();
+	breakpoint();		/* you may move this line to whereever you want :-) */
 #endif
-    request_region(0x20, 0x20, "pic1");
-    request_region(0xa0, 0x20, "pic2");
-    i8259_setup_irq(2, &irq2);
+	request_region(0x20, 0x20, "pic1");
+	request_region(0xa0, 0x20, "pic2");
+	i8259_setup_irq(2, &irq2);
 
-    nile4_irq_setup();
-    m1543_irq_setup();
+	nile4_irq_setup();
+	m1543_irq_setup();
 
-    set_except_vector(0, ddbIRQ);
+	set_except_vector(0, ddbIRQ);
 }
-
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/nile4.c linux/arch/mips/ddb5074/nile4.c
--- v2.4.3/linux/arch/mips/ddb5074/nile4.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/nile4.c	Fri Apr 13 20:26:07 2001
@@ -3,292 +3,290 @@
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id$
  */
-
 #include <linux/kernel.h>
 #include <linux/types.h>
+
 #include <asm/nile4.h>
 
 
-    /*
-     *  Physical Device Address Registers
-     *
-     *  Note: 32 bit addressing only!
-     */
-
-void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, int on_memory_bus,
-		    int visible)
-{
-    u32 maskbits;
-    u32 widthbits;
-
-    if (pdar > NILE4_BOOTCS || (pdar & 7)) {
-	printk("nile4_set_pdar: invalid pdar %d\n", pdar);
-	return;
-    }
-    if (pdar == NILE4_INTCS && size != 0x00200000) {
-	printk("nile4_set_pdar: INTCS size must be 2 MB\n");
-	return;
-    }
-    switch (size) {
-#if 0	/* We don't support 4 GB yet */
+/*
+ *  Physical Device Address Registers
+ *
+ *  Note: 32 bit addressing only!
+ */
+void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width,
+		    int on_memory_bus, int visible)
+{
+	u32 maskbits;
+	u32 widthbits;
+
+	if (pdar > NILE4_BOOTCS || (pdar & 7)) {
+		printk("nile4_set_pdar: invalid pdar %d\n", pdar);
+		return;
+	}
+	if (pdar == NILE4_INTCS && size != 0x00200000) {
+		printk("nile4_set_pdar: INTCS size must be 2 MB\n");
+		return;
+	}
+	switch (size) {
+#if 0				/* We don't support 4 GB yet */
 	case 0x100000000:	/* 4 GB */
-	    maskbits = 4;
-	    break;
+		maskbits = 4;
+		break;
 #endif
 	case 0x80000000:	/* 2 GB */
-	    maskbits = 5;
-	    break;
+		maskbits = 5;
+		break;
 	case 0x40000000:	/* 1 GB */
-	    maskbits = 6;
-	    break;
+		maskbits = 6;
+		break;
 	case 0x20000000:	/* 512 MB */
-	    maskbits = 7;
-	    break;
+		maskbits = 7;
+		break;
 	case 0x10000000:	/* 256 MB */
-	    maskbits = 8;
-	    break;
+		maskbits = 8;
+		break;
 	case 0x08000000:	/* 128 MB */
-	    maskbits = 9;
-	    break;
+		maskbits = 9;
+		break;
 	case 0x04000000:	/* 64 MB */
-	    maskbits = 10;
-	    break;
+		maskbits = 10;
+		break;
 	case 0x02000000:	/* 32 MB */
-	    maskbits = 11;
-	    break;
+		maskbits = 11;
+		break;
 	case 0x01000000:	/* 16 MB */
-	    maskbits = 12;
-	    break;
+		maskbits = 12;
+		break;
 	case 0x00800000:	/* 8 MB */
-	    maskbits = 13;
-	    break;
+		maskbits = 13;
+		break;
 	case 0x00400000:	/* 4 MB */
-	    maskbits = 14;
-	    break;
+		maskbits = 14;
+		break;
 	case 0x00200000:	/* 2 MB */
-	    maskbits = 15;
-	    break;
-	case 0:			/* OFF */
-	    maskbits = 0;
-	    break;
+		maskbits = 15;
+		break;
+	case 0:		/* OFF */
+		maskbits = 0;
+		break;
 	default:
-	    printk("nile4_set_pdar: unsupported size %p\n", (void *)size);
-	    return;
-    }
-    switch (width) {
+		printk("nile4_set_pdar: unsupported size %p\n", (void *) size);
+		return;
+	}
+	switch (width) {
 	case 8:
-	    widthbits = 0;
-	    break;
+		widthbits = 0;
+		break;
 	case 16:
-	    widthbits = 1;
-	    break;
+		widthbits = 1;
+		break;
 	case 32:
-	    widthbits = 2;
-	    break;
+		widthbits = 2;
+		break;
 	case 64:
-	    widthbits = 3;
-	    break;
+		widthbits = 3;
+		break;
 	default:
-	    printk("nile4_set_pdar: unsupported width %d\n", width);
-	    return;
-    }
-    nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
-    		      (visible ? 0x20 : 0) | (widthbits << 6) |
-		      (phys & 0xffe00000));
-    nile4_out32(pdar+4, 0);
-    /*
-     *  When programming a PDAR, the register should be read immediately after
-     *  writing it. This ensures that address decoders are properly configured.
-     */
-    (void)nile4_in32(pdar);
-    (void)nile4_in32(pdar+4);
+		printk("nile4_set_pdar: unsupported width %d\n", width);
+		return;
+	}
+	nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
+		    (visible ? 0x20 : 0) | (widthbits << 6) |
+		    (phys & 0xffe00000));
+	nile4_out32(pdar + 4, 0);
+	/*
+	 * When programming a PDAR, the register should be read immediately
+	 * after writing it. This ensures that address decoders are properly
+	 * configured.
+	 */
+	nile4_in32(pdar);
+	nile4_in32(pdar + 4);
 }
 
 
-    /*
-     *  PCI Master Registers
-     *
-     *  Note: 32 bit addressing only!
-     */
-
+/*
+ *  PCI Master Registers
+ *
+ *  Note: 32 bit addressing only!
+ */
 void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
 {
-    if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
-	printk("nile4_set_pmr: invalid pmr %d\n", pmr);
-	return;
-    }
-    switch (type) {
+	if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
+		printk("nile4_set_pmr: invalid pmr %d\n", pmr);
+		return;
+	}
+	switch (type) {
 	case NILE4_PCICMD_IACK:	/* PCI Interrupt Acknowledge */
 	case NILE4_PCICMD_IO:	/* PCI I/O Space */
 	case NILE4_PCICMD_MEM:	/* PCI Memory Space */
 	case NILE4_PCICMD_CFG:	/* PCI Configuration Space */
-	    break;
+		break;
 	default:
-	    printk("nile4_set_pmr: invalid type %d\n", type);
-	    return;
-    }
-    nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
-    nile4_out32(pmr+4, 0);
+		printk("nile4_set_pmr: invalid type %d\n", type);
+		return;
+	}
+	nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
+	nile4_out32(pmr + 4, 0);
 }
 
 
-    /*
-     *  Interrupt Programming
-     */
-
+/*
+ *  Interrupt Programming
+ */
 void nile4_map_irq(int nile4_irq, int cpu_irq)
 {
-    u32 offset, t;
+	u32 offset, t;
 
-    offset = NILE4_INTCTRL;
-    if (nile4_irq >= 8) {
-	offset += 4;
-	nile4_irq -= 8;
-    }
-    t = nile4_in32(offset);
-    t &= ~(7 << (nile4_irq*4));
-    t |= cpu_irq << (nile4_irq*4);
-    nile4_out32(offset, t);
+	offset = NILE4_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = nile4_in32(offset);
+	t &= ~(7 << (nile4_irq * 4));
+	t |= cpu_irq << (nile4_irq * 4);
+	nile4_out32(offset, t);
 }
 
 void nile4_map_irq_all(int cpu_irq)
 {
-    u32 all, t;
-    
-    all = cpu_irq;
-    all |= all << 4;
-    all |= all << 8;
-    all |= all << 16;
-    t = nile4_in32(NILE4_INTCTRL);
-    t &= 0x88888888;
-    t |= all;
-    nile4_out32(NILE4_INTCTRL, t);
-    t = nile4_in32(NILE4_INTCTRL+4);
-    t &= 0x88888888;
-    t |= all;
-    nile4_out32(NILE4_INTCTRL+4, t);
+	u32 all, t;
+
+	all = cpu_irq;
+	all |= all << 4;
+	all |= all << 8;
+	all |= all << 16;
+	t = nile4_in32(NILE4_INTCTRL);
+	t &= 0x88888888;
+	t |= all;
+	nile4_out32(NILE4_INTCTRL, t);
+	t = nile4_in32(NILE4_INTCTRL + 4);
+	t &= 0x88888888;
+	t |= all;
+	nile4_out32(NILE4_INTCTRL + 4, t);
 }
 
 void nile4_enable_irq(int nile4_irq)
 {
-    u32 offset, t;
+	u32 offset, t;
 
-    offset = NILE4_INTCTRL;
-    if (nile4_irq >= 8) {
-	offset += 4;
-	nile4_irq -= 8;
-    }
-    t = nile4_in32(offset);
-    t |= 8 << (nile4_irq*4);
-    nile4_out32(offset, t);
+	offset = NILE4_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = nile4_in32(offset);
+	t |= 8 << (nile4_irq * 4);
+	nile4_out32(offset, t);
 }
 
 void nile4_disable_irq(int nile4_irq)
 {
-    u32 offset, t;
+	u32 offset, t;
 
-    offset = NILE4_INTCTRL;
-    if (nile4_irq >= 8) {
-	offset += 4;
-	nile4_irq -= 8;
-    }
-    t = nile4_in32(offset);
-    t &= ~(8 << (nile4_irq*4));
-    nile4_out32(offset, t);
+	offset = NILE4_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = nile4_in32(offset);
+	t &= ~(8 << (nile4_irq * 4));
+	nile4_out32(offset, t);
 }
 
 void nile4_disable_irq_all(void)
 {
-    nile4_out32(NILE4_INTCTRL, 0);
-    nile4_out32(NILE4_INTCTRL+4, 0);
+	nile4_out32(NILE4_INTCTRL, 0);
+	nile4_out32(NILE4_INTCTRL + 4, 0);
 }
 
 u16 nile4_get_irq_stat(int cpu_irq)
 {
-    return nile4_in16(NILE4_INTSTAT0+cpu_irq*2);
+	return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2);
 }
 
 void nile4_enable_irq_output(int cpu_irq)
 {
-    u32 t;
+	u32 t;
 
-    t = nile4_in32(NILE4_INTSTAT1+4);
-    t |= 1 << (16+cpu_irq);
-    nile4_out32(NILE4_INTSTAT1, t);
+	t = nile4_in32(NILE4_INTSTAT1 + 4);
+	t |= 1 << (16 + cpu_irq);
+	nile4_out32(NILE4_INTSTAT1, t);
 }
 
 void nile4_disable_irq_output(int cpu_irq)
 {
-    u32 t;
+	u32 t;
 
-    t = nile4_in32(NILE4_INTSTAT1+4);
-    t &= ~(1 << (16+cpu_irq));
-    nile4_out32(NILE4_INTSTAT1, t);
+	t = nile4_in32(NILE4_INTSTAT1 + 4);
+	t &= ~(1 << (16 + cpu_irq));
+	nile4_out32(NILE4_INTSTAT1, t);
 }
 
 void nile4_set_pci_irq_polarity(int pci_irq, int high)
 {
-    u32 t;
+	u32 t;
 
-    t = nile4_in32(NILE4_INTPPES);
-    if (high)
-	t &= ~(1 << (pci_irq*2));
-    else
-	t |= 1 << (pci_irq*2);
-    nile4_out32(NILE4_INTPPES, t);
+	t = nile4_in32(NILE4_INTPPES);
+	if (high)
+		t &= ~(1 << (pci_irq * 2));
+	else
+		t |= 1 << (pci_irq * 2);
+	nile4_out32(NILE4_INTPPES, t);
 }
 
 void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
 {
-    u32 t;
+	u32 t;
 
-    t = nile4_in32(NILE4_INTPPES);
-    if (level)
-	t |= 2 << (pci_irq*2);
-    else
-	t &= ~(2 << (pci_irq*2));
-    nile4_out32(NILE4_INTPPES, t);
+	t = nile4_in32(NILE4_INTPPES);
+	if (level)
+		t |= 2 << (pci_irq * 2);
+	else
+		t &= ~(2 << (pci_irq * 2));
+	nile4_out32(NILE4_INTPPES, t);
 }
 
 void nile4_clear_irq(int nile4_irq)
 {
-    nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
+	nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
 }
 
 void nile4_clear_irq_mask(u32 mask)
 {
-    nile4_out32(NILE4_INTCLR, mask);
+	nile4_out32(NILE4_INTCLR, mask);
 }
 
 u8 nile4_i8259_iack(void)
 {
-    u8 irq;
+	u8 irq;
 
-    /* Set window 0 for interrupt acknowledge */
-    nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
-    irq = *(volatile u8 *)NILE4_PCI_IACK_BASE;
-    /* Set window 0 for PCI I/O space */
-    nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
-    return irq;
+	/* Set window 0 for interrupt acknowledge */
+	nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
+	irq = *(volatile u8 *) NILE4_PCI_IACK_BASE;
+	/* Set window 0 for PCI I/O space */
+	nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+	return irq;
 }
 
 #if 0
 void nile4_dump_irq_status(void)
 {
-    printk("CPUSTAT = %p:%p\n", (void *)nile4_in32(NILE4_CPUSTAT+4),
-    				(void *)nile4_in32(NILE4_CPUSTAT));
-    printk("INTCTRL = %p:%p\n", (void *)nile4_in32(NILE4_INTCTRL+4),
-    				(void *)nile4_in32(NILE4_INTCTRL));
-    printk("INTSTAT0 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT0+4),
-    				(void *)nile4_in32(NILE4_INTSTAT0));
-    printk("INTSTAT1 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT1+4),
-    				(void *)nile4_in32(NILE4_INTSTAT1));
-    printk("INTCLR = %p:%p\n", (void *)nile4_in32(NILE4_INTCLR+4),
-    				(void *)nile4_in32(NILE4_INTCLR));
-    printk("INTPPES = %p:%p\n", (void *)nile4_in32(NILE4_INTPPES+4),
-    				(void *)nile4_in32(NILE4_INTPPES));
+	printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4),
+	       (void *) nile4_in32(NILE4_CPUSTAT));
+	printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4),
+	       (void *) nile4_in32(NILE4_INTCTRL));
+	printk("INTSTAT0 = %p:%p\n",
+	       (void *) nile4_in32(NILE4_INTSTAT0 + 4),
+	       (void *) nile4_in32(NILE4_INTSTAT0));
+	printk("INTSTAT1 = %p:%p\n",
+	       (void *) nile4_in32(NILE4_INTSTAT1 + 4),
+	       (void *) nile4_in32(NILE4_INTSTAT1));
+	printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4),
+	       (void *) nile4_in32(NILE4_INTCLR));
+	printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4),
+	       (void *) nile4_in32(NILE4_INTPPES));
 }
 #endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/pci-dma.c linux/arch/mips/ddb5074/pci-dma.c
--- v2.4.3/linux/arch/mips/ddb5074/pci-dma.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/pci-dma.c	Wed Dec 31 16:00:00 1969
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2000   Ani Joshi <ajoshi@unixbox.com>
- *
- *
- * Dynamic DMA mapping support.
- *
- * swiped from i386, and cloned for MIPS by Geert.
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t *dma_handle)
-{
-	void *ret;
-	int gfp = GFP_ATOMIC;
-
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
-		gfp |= GFP_DMA;
-	ret = (void *)__get_free_pages(gfp, get_order(size));
-
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_bus(ret);
-	}
-	return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-	free_pages((unsigned long)vaddr, get_order(size));
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/pci.c linux/arch/mips/ddb5074/pci.c
--- v2.4.3/linux/arch/mips/ddb5074/pci.c	Mon Nov 27 17:51:34 2000
+++ linux/arch/mips/ddb5074/pci.c	Fri Apr 13 20:26:07 2001
@@ -4,313 +4,325 @@
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Albert Dorofeev <albert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $
  */
-
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
-#include <asm-mips/nile4.h>
+
+#include <asm/nile4.h>
 
 
 static u32 nile4_pre_pci_access0(int slot_num)
 {
-    u32 pci_addr = 0;
-    u32 virt_addr = NILE4_PCI_CFG_BASE;
+	u32 pci_addr = 0;
+	u32 virt_addr = NILE4_PCI_CFG_BASE;
 
-    /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */
-    nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, 0);
-    if (slot_num > 2)
-	pci_addr = 0x00040000 << slot_num;
-    else
-	virt_addr += 0x00040000 << slot_num;
-    nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
-    return virt_addr;
+	/* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */
+	nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0,
+		       0);
+	if (slot_num > 2)
+		pci_addr = 0x00040000 << slot_num;
+	else
+		virt_addr += 0x00040000 << slot_num;
+	nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
+	return virt_addr;
 }
 
 static void nile4_post_pci_access0(void)
 {
-    /* Set window 1 back to address 8000000 - 64 bit - 128 MB (PCI IO space) */
-    nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 64,
-    		   1, 1);
-    nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+	/*
+	 * Set window 1 back to address 8000000 - 64 bit - 128 MB
+	 * (PCI IO space)
+	 */
+	nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE),
+		       0x08000000, 64, 1, 1);
+	nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
 }
 
 
-static int nile4_pci_read_config_dword( struct pci_dev *dev,
-				int where, u32 *val)
+static int nile4_pci_read_config_dword(struct pci_dev *dev,
+				       int where, u32 * val)
 {
-    int slot_num, func_num;
-    u32 base;
-
-    /*
-     *  For starters let's do configuration cycle 0 only (one bus only)
-     */
-    if (dev->bus->number)
-	return PCIBIOS_FUNC_NOT_SUPPORTED;
+	int slot_num, func_num;
+	u32 base;
 
-    slot_num = PCI_SLOT(dev->devfn);
-    func_num = PCI_FUNC(dev->devfn);
-    if (slot_num == 5) {
 	/*
-	 *  This is Nile 4 and it will crash if we access it like other
-	 *   devices
+	 *  For starters let's do configuration cycle 0 only (one bus only)
 	 */
-	*val = nile4_in32(NILE4_PCI_BASE + where);
+	if (dev->bus->number)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	slot_num = PCI_SLOT(dev->devfn);
+	func_num = PCI_FUNC(dev->devfn);
+	if (slot_num == 5) {
+		/*
+		 * This is Nile 4 and it will crash if we access it like other
+		 * devices
+		 */
+		*val = nile4_in32(NILE4_PCI_BASE + where);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	base = nile4_pre_pci_access0(slot_num);
+	*val =
+	    *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc)));
+	nile4_post_pci_access0();
 	return PCIBIOS_SUCCESSFUL;
-    }
-    base = nile4_pre_pci_access0(slot_num);
-    *val = *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc)));
-    nile4_post_pci_access0();
-    return PCIBIOS_SUCCESSFUL;
 }
 
 static int nile4_pci_write_config_dword(struct pci_dev *dev, int where,
 					u32 val)
 {
-    int slot_num, func_num;
-    u32 base;
+	int slot_num, func_num;
+	u32 base;
 
-    /*
-     *  For starters let's do configuration cycle 0 only (one bus only)
-     */
-    if (dev->bus->number)
-	return PCIBIOS_FUNC_NOT_SUPPORTED;
-
-    slot_num = PCI_SLOT(dev->devfn);
-    func_num = PCI_FUNC(dev->devfn);
-    if (slot_num == 5) {
 	/*
-	 *  This is Nile 4 and it will crash if we access it like other
-	 *   devices
+	 * For starters let's do configuration cycle 0 only (one bus only)
 	 */
-	nile4_out32(NILE4_PCI_BASE + where, val);
+	if (dev->bus->number)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	slot_num = PCI_SLOT(dev->devfn);
+	func_num = PCI_FUNC(dev->devfn);
+	if (slot_num == 5) {
+		/*
+		 * This is Nile 4 and it will crash if we access it like other
+		 * devices
+		 */
+		nile4_out32(NILE4_PCI_BASE + where, val);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	base = nile4_pre_pci_access0(slot_num);
+	*((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))) =
+	    val;
+	nile4_post_pci_access0();
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_word(struct pci_dev *dev, int where,
+				      u16 * val)
+{
+	int status;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 2)
+		result >>= 16;
+	*val = result & 0xffff;
 	return PCIBIOS_SUCCESSFUL;
-    }
-    base = nile4_pre_pci_access0(slot_num);
-    *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))) = val;
-    nile4_post_pci_access0();
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int nile4_pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
-{
-    int status;
-    u32 result;
-
-    status = nile4_pci_read_config_dword(dev, where, &result);
-    if (status != PCIBIOS_SUCCESSFUL)
-	return status;
-    if (where & 2)
-	result >>= 16;
-    *val = result & 0xffff;
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
-{
-    int status;
-    u32 result;
-
-    status = nile4_pci_read_config_dword(dev, where, &result);
-    if (status != PCIBIOS_SUCCESSFUL)
-	return status;
-    if (where & 1)
-	result >>= 8;
-    if (where & 2)
-	result >>= 16;
-    *val = result & 0xff;
-    return PCIBIOS_SUCCESSFUL;
-}
-
-static int nile4_pci_write_config_word(struct pci_dev *dev, int where, u16 val)
-{
-    int status, shift = 0;
-    u32 result;
-
-    status = nile4_pci_read_config_dword(dev, where, &result);
-    if (status != PCIBIOS_SUCCESSFUL)
-	return status;
-    if (where & 2)
-	shift += 16;
-    result &= ~(0xffff << shift);
-    result |= val << shift;
-    return nile4_pci_write_config_dword(dev, where, result);
-}
-
-static int nile4_pci_write_config_byte( struct pci_dev *dev, int where, u8 val)
-{
-    int status, shift = 0;
-    u32 result;
-
-    status = nile4_pci_read_config_dword(dev, where, &result);
-    if (status != PCIBIOS_SUCCESSFUL)
-	return status;
-    if (where & 2)
-	shift += 16;
-    if (where & 1)
-	shift += 8;
-    result &= ~(0xff << shift);
-    result |= val << shift;
-    return nile4_pci_write_config_dword(dev, where, result);
+}
+
+static int nile4_pci_read_config_byte(struct pci_dev *dev, int where,
+				      u8 * val)
+{
+	int status;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 1)
+		result >>= 8;
+	if (where & 2)
+		result >>= 16;
+	*val = result & 0xff;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_word(struct pci_dev *dev, int where,
+				       u16 val)
+{
+	int status, shift = 0;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 2)
+		shift += 16;
+	result &= ~(0xffff << shift);
+	result |= val << shift;
+	return nile4_pci_write_config_dword(dev, where, result);
+}
+
+static int nile4_pci_write_config_byte(struct pci_dev *dev, int where,
+				       u8 val)
+{
+	int status, shift = 0;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 2)
+		shift += 16;
+	if (where & 1)
+		shift += 8;
+	result &= ~(0xff << shift);
+	result |= val << shift;
+	return nile4_pci_write_config_dword(dev, where, result);
 }
 
 struct pci_ops nile4_pci_ops = {
-    nile4_pci_read_config_byte,
-    nile4_pci_read_config_word,
-    nile4_pci_read_config_dword,
-    nile4_pci_write_config_byte,
-    nile4_pci_write_config_word,
-    nile4_pci_write_config_dword
+	nile4_pci_read_config_byte,
+	nile4_pci_read_config_word,
+	nile4_pci_read_config_dword,
+	nile4_pci_write_config_byte,
+	nile4_pci_write_config_word,
+	nile4_pci_write_config_dword
 };
 
 struct {
-    struct resource ram;
-    struct resource flash;
-    struct resource isa_io;
-    struct resource pci_io;
-    struct resource isa_mem;
-    struct resource pci_mem;
-    struct resource nile4;
-    struct resource boot;
+	struct resource ram;
+	struct resource flash;
+	struct resource isa_io;
+	struct resource pci_io;
+	struct resource isa_mem;
+	struct resource pci_mem;
+	struct resource nile4;
+	struct resource boot;
 } ddb5074_resources = {
-    { "RAM", 0x00000000, 0x03ffffff,
-      IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
-    { "Flash ROM", 0x04000000, 0x043fffff },
-    { "Nile4 ISA I/O", 0x06000000, 0x060fffff },
-    { "Nile4 PCI I/O", 0x06100000, 0x07ffffff },
-    { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM },
-    { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM },
-    { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff,
-      IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
-    { "Boot ROM", 0x1fc00000, 0x1fffffff }
+	{ "RAM", 0x00000000, 0x03ffffff,
+	  IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64},
+	{ "Flash ROM", 0x04000000, 0x043fffff},
+	{ "Nile4 ISA I/O", 0x06000000, 0x060fffff},
+	{ "Nile4 PCI I/O", 0x06100000, 0x07ffffff},
+	{ "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM},
+	{ "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM},
+	{ "Nile4 ctrl", 0x1fa00000, 0x1fbfffff,
+	  IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64},
+	{ "Boot ROM", 0x1fc00000, 0x1fffffff}
 };
 
 static void __init ddb5074_pci_fixup(void)
 {
-    struct pci_dev *dev;
+	struct pci_dev *dev;
 
-    pci_for_each_dev(dev) {
-	if (dev->vendor == PCI_VENDOR_ID_NEC &&
-	    dev->device == PCI_DEVICE_ID_NEC_NILE4) {
-	    /*
-	     *  The first 64-bit PCI base register should point to the Nile4
-	     *  control registers. Unfortunately this isn't the case, so we fix
-	     *  it ourselves. This allows the serial driver to find the UART.
-	     */
-	    dev->resource[0] = ddb5074_resources.nile4;
-	    request_resource(&iomem_resource, &dev->resource[0]);
-	    /*
-	     *  The second 64-bit PCI base register points to the first memory
-	     *  bank. Unfortunately the address is wrong, so we fix it (again).
-	     */
-	    dev->resource[2] = ddb5074_resources.ram;
-	    request_resource(&iomem_resource, &dev->resource[2]);
-	} else if (dev->vendor == PCI_VENDOR_ID_AL &&
-		   dev->device == PCI_DEVICE_ID_AL_M7101) {
-	    /*
-	     *  It's nice to have the LEDs on the GPIO pins available for
-	     *  debugging
-	     */
-	    extern struct pci_dev *pci_pmu;
-	    u8 t8;
-
-	    pci_pmu = dev;		/* for LEDs D2 and D3 */
-	    /* Program the lines for LEDs D2 and D3 to output */
-	    nile4_pci_read_config_byte(dev, 0x7d, &t8);
-	    t8 |= 0xc0;
-	    nile4_pci_write_config_byte(dev, 0x7d, t8);
-	    /* Turn LEDs D2 and D3 off */
-	    nile4_pci_read_config_byte(dev, 0x7e, &t8);
-	    t8 |= 0xc0;
-	    nile4_pci_write_config_byte(dev, 0x7e, t8);
+	pci_for_each_dev(dev) {
+		if (dev->vendor == PCI_VENDOR_ID_NEC &&
+		    dev->device == PCI_DEVICE_ID_NEC_NILE4) {
+			/*
+			 * The first 64-bit PCI base register should point to
+			 * the Nile4 control registers. Unfortunately this
+			 * isn't the case, so we fix it ourselves. This allows
+			 * the serial driver to find the UART.
+			 */
+			dev->resource[0] = ddb5074_resources.nile4;
+			request_resource(&iomem_resource,
+					 &dev->resource[0]);
+			/*
+			 * The second 64-bit PCI base register points to the
+			 * first memory bank. Unfortunately the address is
+			 * wrong, so we fix it (again).
+			 */
+			dev->resource[2] = ddb5074_resources.ram;
+			request_resource(&iomem_resource,
+					 &dev->resource[2]);
+		} else if (dev->vendor == PCI_VENDOR_ID_AL
+			   && dev->device == PCI_DEVICE_ID_AL_M7101) {
+			/*
+			 * It's nice to have the LEDs on the GPIO pins
+			 * available for debugging
+			 */
+			extern struct pci_dev *pci_pmu;
+			u8 t8;
+
+			pci_pmu = dev;	/* for LEDs D2 and D3 */
+			/* Program the lines for LEDs D2 and D3 to output */
+			nile4_pci_read_config_byte(dev, 0x7d, &t8);
+			t8 |= 0xc0;
+			nile4_pci_write_config_byte(dev, 0x7d, t8);
+			/* Turn LEDs D2 and D3 off */
+			nile4_pci_read_config_byte(dev, 0x7e, &t8);
+			t8 |= 0xc0;
+			nile4_pci_write_config_byte(dev, 0x7e, t8);
+		}
 	}
-    }
 }
 
 static void __init pcibios_fixup_irqs(void)
 {
-    struct pci_dev *dev;
-    int slot_num;
+	struct pci_dev *dev;
+	int slot_num;
 
-    pci_for_each_dev(dev) {
-	slot_num = PCI_SLOT(dev->devfn);
-	switch (slot_num) {
-	    case 0:
-		dev->irq = nile4_to_irq(NILE4_INT_INTE);
-		break;
-	    case 1:
-		dev->irq = nile4_to_irq(NILE4_INT_INTA);
-		break;
-	    case 2:	/* slot 1 */
-		dev->irq = nile4_to_irq(NILE4_INT_INTA);
-		break;
-	    case 3:	/* slot 2 */
-		dev->irq = nile4_to_irq(NILE4_INT_INTB);
-		break;
-	    case 4:	/* slot 3 */
-		dev->irq = nile4_to_irq(NILE4_INT_INTC);
-		break;
-	    case 5:
-		/*
-		 * Fixup so the serial driver can use the UART
-		 */
-		dev->irq = nile4_to_irq(NILE4_INT_UART);
-		break;
-	    case 13:
-		dev->irq = nile4_to_irq(NILE4_INT_INTE);
-		break;
-	    default:
-		break;
+	pci_for_each_dev(dev) {
+		slot_num = PCI_SLOT(dev->devfn);
+		switch (slot_num) {
+		case 0:
+			dev->irq = nile4_to_irq(NILE4_INT_INTE);
+			break;
+		case 1:
+			dev->irq = nile4_to_irq(NILE4_INT_INTA);
+			break;
+		case 2:	/* slot 1 */
+			dev->irq = nile4_to_irq(NILE4_INT_INTA);
+			break;
+		case 3:	/* slot 2 */
+			dev->irq = nile4_to_irq(NILE4_INT_INTB);
+			break;
+		case 4:	/* slot 3 */
+			dev->irq = nile4_to_irq(NILE4_INT_INTC);
+			break;
+		case 5:
+			/*
+			 * Fixup so the serial driver can use the UART
+			 */
+			dev->irq = nile4_to_irq(NILE4_INT_UART);
+			break;
+		case 13:
+			dev->irq = nile4_to_irq(NILE4_INT_INTE);
+			break;
+		default:
+			break;
+		}
 	}
-    }
 }
 
 void __init pcibios_init(void)
 {
-    printk("PCI: Probing PCI hardware\n");
-    ioport_resource.end = 0x1ffffff;		/*  32 MB */
-    iomem_resource.end = 0x1fffffff;		/* 512 MB */
-    /* `ram' and `nile4' are requested through the Nile4 pci_dev */
-    request_resource(&iomem_resource, &ddb5074_resources.flash);
-    request_resource(&iomem_resource, &ddb5074_resources.isa_io);
-    request_resource(&iomem_resource, &ddb5074_resources.pci_io);
-    request_resource(&iomem_resource, &ddb5074_resources.isa_mem);
-    request_resource(&iomem_resource, &ddb5074_resources.pci_mem);
-    request_resource(&iomem_resource, &ddb5074_resources.boot);
-
-    pci_scan_bus(0, &nile4_pci_ops, NULL);
-    ddb5074_pci_fixup();
-    pci_assign_unassigned_resources();
-    pcibios_fixup_irqs();
+	printk("PCI: Probing PCI hardware\n");
+	ioport_resource.end = 0x1ffffff;	/*  32 MB */
+	iomem_resource.end = 0x1fffffff;	/* 512 MB */
+	/* `ram' and `nile4' are requested through the Nile4 pci_dev */
+	request_resource(&iomem_resource, &ddb5074_resources.flash);
+	request_resource(&iomem_resource, &ddb5074_resources.isa_io);
+	request_resource(&iomem_resource, &ddb5074_resources.pci_io);
+	request_resource(&iomem_resource, &ddb5074_resources.isa_mem);
+	request_resource(&iomem_resource, &ddb5074_resources.pci_mem);
+	request_resource(&iomem_resource, &ddb5074_resources.boot);
+
+	pci_scan_bus(0, &nile4_pci_ops, NULL);
+	ddb5074_pci_fixup();
+	pci_assign_unassigned_resources();
+	pcibios_fixup_irqs();
 }
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
-    bus->resource[1] = &ddb5074_resources.pci_mem;
+	bus->resource[1] = &ddb5074_resources.pci_mem;
 }
 
-char *pcibios_setup (char *str)
+char *pcibios_setup(char *str)
 {
-    return str;
+	return str;
 }
 
 void __init pcibios_update_irq(struct pci_dev *dev, int irq)
 {
-    pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
 void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
 				      struct pbus_set_ranges_data *ranges)
 {
-    ranges->io_start -= bus->resource[0]->start;
-    ranges->io_end -= bus->resource[0]->start;
-    ranges->mem_start -= bus->resource[1]->start;
-    ranges->mem_end -= bus->resource[1]->start;
+	ranges->io_start -= bus->resource[0]->start;
+	ranges->io_end -= bus->resource[0]->start;
+	ranges->mem_start -= bus->resource[1]->start;
+	ranges->mem_end -= bus->resource[1]->start;
 }
 
 int pcibios_enable_resources(struct pci_dev *dev)
@@ -323,15 +335,15 @@
 	 *  Don't touch the Nile 4
 	 */
 	if (dev->vendor == PCI_VENDOR_ID_NEC &&
-	    dev->device == PCI_DEVICE_ID_NEC_NILE4)
-	    return 0;
+	    dev->device == PCI_DEVICE_ID_NEC_NILE4) return 0;
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
-	for(idx=0; idx<6; idx++) {
+	for (idx = 0; idx < 6; idx++) {
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
-			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			printk(KERN_ERR "PCI: Device %s not available because "
+			       "of resource collisions\n", dev->slot_name);
 			return -EINVAL;
 		}
 		if (r->flags & IORESOURCE_IO)
@@ -340,7 +352,8 @@
 			cmd |= PCI_COMMAND_MEMORY;
 	}
 	if (cmd != old_cmd) {
-		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		printk("PCI: Enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
 	return 0;
@@ -348,7 +361,7 @@
 
 int pcibios_enable_device(struct pci_dev *dev)
 {
-    return pcibios_enable_resources(dev);
+	return pcibios_enable_resources(dev);
 }
 
 void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
@@ -359,18 +372,23 @@
 
 	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
 	if (resource < 6) {
-		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+		reg = PCI_BASE_ADDRESS_0 + 4 * resource;
 	} else if (resource == PCI_ROM_RESOURCE) {
 		res->flags |= PCI_ROM_ADDRESS_ENABLE;
 		reg = dev->rom_base_reg;
 	} else {
-		/* Somebody might have asked allocation of a non-standard resource */
+		/*
+		 * Somebody might have asked allocation of a non-standard
+		 * resource
+		 */
 		return;
 	}
-	
+
 	pci_write_config_dword(dev, reg, new);
 	pci_read_config_dword(dev, reg, &check);
-	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+	if ((new ^ check) &
+	    ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
+	     PCI_BASE_ADDRESS_MEM_MASK)) {
 		printk(KERN_ERR "PCI: Error while updating region "
 		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
 		       new, check);
@@ -400,5 +418,4 @@
 }
 
 
-struct pci_fixup pcibios_fixups[] = {};
-
+struct pci_fixup pcibios_fixups[] = { };
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/prom.c linux/arch/mips/ddb5074/prom.c
--- v2.4.3/linux/arch/mips/ddb5074/prom.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/prom.c	Fri Apr 13 20:26:07 2001
@@ -3,58 +3,32 @@
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id: prom.c,v 1.1 2000/01/26 00:07:44 ralf Exp $
  */
-
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
+
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 
 
-char arcs_cmdline[CL_SIZE];
-
-extern char _end;
-
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
+char arcs_cmdline[COMMAND_LINE_SIZE];
 
 void __init prom_init(const char *s)
 {
-    int i = 0;
-    unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size;
+	int i = 0;
 
-//  _serinit();
+	if (s != (void *) -1)
+		while (*s && i < sizeof(arcs_cmdline) - 1)
+			arcs_cmdline[i++] = *s++;
+	arcs_cmdline[i] = '\0';
 
-    if (s != (void *)-1)
-	while (*s && i < sizeof(arcs_cmdline)-1)
-	    arcs_cmdline[i++] = *s++;
-    arcs_cmdline[i] = '\0';
-
-    mips_machgroup = MACH_GROUP_NEC_DDB;
-    mips_machtype = MACH_NEC_DDB5074;
-    /* 64 MB non-upgradable */
-    mem_size = 64 << 20;
-
-    free_start = PHYSADDR(PFN_ALIGN(&_end));
-    free_end = mem_size;
-    start_pfn = PFN_UP((unsigned long)&_end);
-
-    /* Register all the contiguous memory with the bootmem allocator
-       and free it.  Be careful about the bootmem freemap.  */
-    bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT);
-
-    /* Free the entire available memory after the _end symbol.  */
-    free_start += bootmap_size;
-    free_bootmem(free_start, free_end-free_start);
-}
+	mips_machgroup = MACH_GROUP_NEC_DDB;
+	mips_machtype = MACH_NEC_DDB5074;
 
-void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
-{
+	/* 64 MB non-upgradable */
+	add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
 }
 
 void __init prom_free_prom_memory(void)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/setup.c linux/arch/mips/ddb5074/setup.c
--- v2.4.3/linux/arch/mips/ddb5074/setup.c	Sun Jul  9 22:18:15 2000
+++ linux/arch/mips/ddb5074/setup.c	Fri Apr 13 20:26:07 2001
@@ -3,10 +3,7 @@
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id: setup.c,v 1.1 2000/01/26 00:07:44 ralf Exp $
  */
-
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kbd_ll.h>
@@ -42,85 +39,83 @@
 extern struct ide_ops std_ide_ops;
 extern struct rtc_ops ddb_rtc_ops;
 
-static void (*back_to_prom)(void) = (void (*)(void))0xbfc00000;
+static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
 
 static void ddb_machine_restart(char *command)
 {
-    u32 t;
+	u32 t;
 
-    /* PCI cold reset */
-    t = nile4_in32(NILE4_PCICTRL+4);
-    t |= 0x40000000;
-    nile4_out32(NILE4_PCICTRL+4, t);
-    /* CPU cold reset */
-    t = nile4_in32(NILE4_CPUSTAT);
-    t |= 1;
-    nile4_out32(NILE4_CPUSTAT, t);
-    /* Call the PROM */
-    back_to_prom();
+	/* PCI cold reset */
+	t = nile4_in32(NILE4_PCICTRL + 4);
+	t |= 0x40000000;
+	nile4_out32(NILE4_PCICTRL + 4, t);
+	/* CPU cold reset */
+	t = nile4_in32(NILE4_CPUSTAT);
+	t |= 1;
+	nile4_out32(NILE4_CPUSTAT, t);
+	/* Call the PROM */
+	back_to_prom();
 }
 
 static void ddb_machine_halt(void)
 {
-    printk("DDB Vrc-5074 halted.\n");
-    do {} while (1);
+	printk("DDB Vrc-5074 halted.\n");
+	do {
+	} while (1);
 }
 
 static void ddb_machine_power_off(void)
 {
-    printk("DDB Vrc-5074 halted. Please turn off the power.\n");
-    do {} while (1);
+	printk("DDB Vrc-5074 halted. Please turn off the power.\n");
+	do {
+	} while (1);
 }
 
 extern void ddb_irq_setup(void);
 
-void (*board_time_init)(struct irqaction *irq);
+void (*board_time_init) (struct irqaction * irq);
 
 
 static void __init ddb_time_init(struct irqaction *irq)
 {
-    /* set the clock to 1 Hz */
-    nile4_out32(NILE4_T2CTRL, 1000000);
-    /* enable the General-Purpose Timer */
-    nile4_out32(NILE4_T2CTRL+4, 0x00000001);
-    /* reset timer */
-    nile4_out32(NILE4_T2CNTR, 0);
-    /* enable interrupt */
-    nile4_enable_irq(NILE4_INT_GPT);
-    i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
-    set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+	/* set the clock to 1 Hz */
+	nile4_out32(NILE4_T2CTRL, 1000000);
+	/* enable the General-Purpose Timer */
+	nile4_out32(NILE4_T2CTRL + 4, 0x00000001);
+	/* reset timer */
+	nile4_out32(NILE4_T2CNTR, 0);
+	/* enable interrupt */
+	nile4_enable_irq(NILE4_INT_GPT);
+	i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
+	change_cp0_status(ST0_IM,
+		          IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
 }
 
 void __init ddb_setup(void)
 {
-    extern int panic_timeout;
+	extern int panic_timeout;
 
-    irq_setup = ddb_irq_setup;
-    mips_io_port_base = NILE4_PCI_IO_BASE;
-    isa_slot_offset = NILE4_PCI_MEM_BASE;
-    request_region(0x00, 0x20, "dma1");
-    request_region(0x40, 0x20, "timer");
-    request_region(0x70, 0x10, "rtc");
-    request_region(0x80, 0x10, "dma page reg");
-    request_region(0xc0, 0x20, "dma2");
-    board_time_init = ddb_time_init;
-
-    _machine_restart = ddb_machine_restart;
-    _machine_halt = ddb_machine_halt;
-    _machine_power_off = ddb_machine_power_off;
+	irq_setup = ddb_irq_setup;
+	mips_io_port_base = NILE4_PCI_IO_BASE;
+	isa_slot_offset = NILE4_PCI_MEM_BASE;
+	request_region(0x00, 0x20, "dma1");
+	request_region(0x40, 0x20, "timer");
+	request_region(0x70, 0x10, "rtc");
+	request_region(0x80, 0x10, "dma page reg");
+	request_region(0xc0, 0x20, "dma2");
+	board_time_init = ddb_time_init;
+
+	_machine_restart = ddb_machine_restart;
+	_machine_halt = ddb_machine_halt;
+	_machine_power_off = ddb_machine_power_off;
 
 #ifdef CONFIG_BLK_DEV_IDE
-    ide_ops = &std_ide_ops;
+	ide_ops = &std_ide_ops;
 #endif
-    rtc_ops = &ddb_rtc_ops;
+	rtc_ops = &ddb_rtc_ops;
 
-    /* Reboot on panic */
-    panic_timeout = 180;
-}
-
-int __init page_is_ram(unsigned long pagenr)
-{
-    return 1;
+	/* Reboot on panic */
+	panic_timeout = 180;
 }
 
 
@@ -133,12 +128,12 @@
 #define NS16550_BASE		(NILE4_PCI_IO_BASE+0x03f8)
 static inline u8 ns16550_in(u32 reg)
 {
-    return *(volatile u8 *)(NS16550_BASE+reg);
+	return *(volatile u8 *) (NS16550_BASE + reg);
 }
 
 static inline void ns16550_out(u32 reg, u8 val)
 {
-    *(volatile u8 *)(NS16550_BASE+reg) = val;
+	*(volatile u8 *) (NS16550_BASE + reg) = val;
 }
 #endif
 
@@ -168,87 +163,84 @@
 void _serinit(void)
 {
 #if USE_NILE4_SERIAL
-    ns16550_out(NS16550_LCR, 0x80);
-    ns16550_out(NS16550_DLM, 0x00);
-    ns16550_out(NS16550_DLL, 0x36);	/* 9600 baud */
-    ns16550_out(NS16550_LCR, 0x00);
-    ns16550_out(NS16550_LCR, 0x03);
-    ns16550_out(NS16550_FCR, 0x47);
+	ns16550_out(NS16550_LCR, 0x80);
+	ns16550_out(NS16550_DLM, 0x00);
+	ns16550_out(NS16550_DLL, 0x36);	/* 9600 baud */
+	ns16550_out(NS16550_LCR, 0x00);
+	ns16550_out(NS16550_LCR, 0x03);
+	ns16550_out(NS16550_FCR, 0x47);
 #else
-    /* done by PMON */
+	/* done by PMON */
 #endif
 }
 
 void _putc(char c)
 {
-    while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
-    ns16550_out(NS16550_THR, c);
-    if (c == '\n') {
 	while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
-	ns16550_out(NS16550_THR, '\r');
-    }
+	ns16550_out(NS16550_THR, c);
+	if (c == '\n') {
+		while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+		ns16550_out(NS16550_THR, '\r');
+	}
 }
 
 void _puts(const char *s)
 {
-    char c;
-    while ((c = *s++))
-	_putc(c);
+	char c;
+	while ((c = *s++))
+		_putc(c);
 }
 
 char _getc(void)
 {
-    while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
-    return ns16550_in(NS16550_RBR);
+	while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
+	return ns16550_in(NS16550_RBR);
 }
 
 int _testc(void)
 {
-    return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
+	return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
 }
 
 
-    /*
-     *  Hexadecimal 7-segment LED
-     */
-
+/*
+ *  Hexadecimal 7-segment LED
+ */
 void ddb5074_led_hex(int hex)
 {
-    outb(hex, 0x80);
+	outb(hex, 0x80);
 }
 
 
-    /*
-     *  LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
-     */
-
+/*
+ *  LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
+ */
 struct pci_dev *pci_pmu = NULL;
 
 void ddb5074_led_d2(int on)
 {
-    u8 t;
+	u8 t;
 
-    if (pci_pmu) {
-	pci_read_config_byte(pci_pmu, 0x7e, &t);
-	if (on)
-	    t &= 0x7f;
-	else
-	    t |= 0x80;
-	pci_write_config_byte(pci_pmu, 0x7e, t);
-    }
+	if (pci_pmu) {
+		pci_read_config_byte(pci_pmu, 0x7e, &t);
+		if (on)
+			t &= 0x7f;
+		else
+			t |= 0x80;
+		pci_write_config_byte(pci_pmu, 0x7e, t);
+	}
 }
 
 void ddb5074_led_d3(int on)
 {
-    u8 t;
+	u8 t;
 
-    if (pci_pmu) {
-	pci_read_config_byte(pci_pmu, 0x7e, &t);
-	if (on)
-	    t &= 0xbf;
-	else
-	    t |= 0x40;
-	pci_write_config_byte(pci_pmu, 0x7e, t);
-    }
+	if (pci_pmu) {
+		pci_read_config_byte(pci_pmu, 0x7e, &t);
+		if (on)
+			t &= 0xbf;
+		else
+			t |= 0x40;
+		pci_write_config_byte(pci_pmu, 0x7e, t);
+	}
 }
-
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5074/time.c linux/arch/mips/ddb5074/time.c
--- v2.4.3/linux/arch/mips/ddb5074/time.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/ddb5074/time.c	Fri Apr 13 20:26:07 2001
@@ -3,33 +3,30 @@
  *
  *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
  *                     Sony Software Development Center Europe (SDCE), Brussels
- *
- *  $Id*
  */
-
 #include <linux/init.h>
 #include <asm/mc146818rtc.h>
 
 static unsigned char ddb_rtc_read_data(unsigned long addr)
 {
-    outb_p(addr, RTC_PORT(0));
-    return inb_p(RTC_PORT(1));
+	outb_p(addr, RTC_PORT(0));
+
+	return inb_p(RTC_PORT(1));
 }
 
 static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
 {
-    outb_p(addr, RTC_PORT(0));
-    outb_p(data, RTC_PORT(1));
+	outb_p(addr, RTC_PORT(0));
+	outb_p(data, RTC_PORT(1));
 }
 
 static int ddb_rtc_bcd_mode(void)
 {
-    return 1;
+	return 1;
 }
 
 struct rtc_ops ddb_rtc_ops = {
-    ddb_rtc_read_data,
-    ddb_rtc_write_data,
-    ddb_rtc_bcd_mode
+	ddb_rtc_read_data,
+	ddb_rtc_write_data,
+	ddb_rtc_bcd_mode
 };
-
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/Makefile linux/arch/mips/ddb5476/Makefile
--- v2.4.3/linux/arch/mips/ddb5476/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,23 @@
+#
+# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines
+# under Linux.
+#
+# 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 in the main makefile...
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET = ddb5476.a
+
+obj-y				+= setup.o irq.o time.o prom.o pci.o \
+				   int-handler.o nile4.o
+obj-$(CONFIG_REMOTE_DEBUG)	+= dbg_io.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/dbg_io.c linux/arch/mips/ddb5476/dbg_io.c
--- v2.4.3/linux/arch/mips/ddb5476/dbg_io.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/dbg_io.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,125 @@
+
+#include <linux/config.h>
+
+#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG))
+
+/* --- CONFIG --- */
+
+/* we need uint32 uint8 */
+/* #include "types.h" */
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+/* --- END OF CONFIG --- */
+
+#define         UART16550_BAUD_2400             2400
+#define         UART16550_BAUD_4800             4800
+#define         UART16550_BAUD_9600             9600
+#define         UART16550_BAUD_19200            19200
+#define         UART16550_BAUD_38400            38400
+#define         UART16550_BAUD_57600            57600
+#define         UART16550_BAUD_115200           115200
+
+#define         UART16550_PARITY_NONE           0
+#define         UART16550_PARITY_ODD            0x08
+#define         UART16550_PARITY_EVEN           0x18
+#define         UART16550_PARITY_MARK           0x28
+#define         UART16550_PARITY_SPACE          0x38
+
+#define         UART16550_DATA_5BIT             0x0
+#define         UART16550_DATA_6BIT             0x1
+#define         UART16550_DATA_7BIT             0x2
+#define         UART16550_DATA_8BIT             0x3
+
+#define         UART16550_STOP_1BIT             0x0
+#define         UART16550_STOP_2BIT             0x4
+
+/* ----------------------------------------------------- */
+
+/* === CONFIG === */
+
+/* [jsun] we use the second serial port for kdb */
+#define         BASE                    0xa60002f8
+#define         MAX_BAUD                115200
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define         OFS_RCV_BUFFER          0
+#define         OFS_TRANS_HOLD          0
+#define         OFS_SEND_BUFFER         0
+#define         OFS_INTR_ENABLE         1
+#define         OFS_INTR_ID             2
+#define         OFS_DATA_FORMAT         3
+#define         OFS_LINE_CONTROL        3
+#define         OFS_MODEM_CONTROL       4
+#define         OFS_RS232_OUTPUT        4
+#define         OFS_LINE_STATUS         5
+#define         OFS_MODEM_STATUS        6
+#define         OFS_RS232_INPUT         6
+#define         OFS_SCRATCH_PAD         7
+
+#define         OFS_DIVISOR_LSB         0
+#define         OFS_DIVISOR_MSB         1
+
+
+/* memory-mapped read/write of the port */
+#define         UART16550_READ(y)    (*((volatile uint8*)(BASE + y)))
+#define         UART16550_WRITE(y, z)  ((*((volatile uint8*)(BASE + y))) = z)
+
+void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+	/* disable interrupts */
+	UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+	/* set up buad rate */
+	{
+		uint32 divisor;
+
+		/* set DIAB bit */
+		UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+		/* set divisor */
+		divisor = MAX_BAUD / baud;
+		UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+		UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
+
+		/* clear DIAB bit */
+		UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+	}
+
+	/* set data format */
+	UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+static int remoteDebugInitialized = 0;
+
+uint8 getDebugChar(void)
+{
+	if (!remoteDebugInitialized) {
+		remoteDebugInitialized = 1;
+		debugInit(UART16550_BAUD_38400,
+			  UART16550_DATA_8BIT,
+			  UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+	}
+
+	while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+	return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+int putDebugChar(uint8 byte)
+{
+	if (!remoteDebugInitialized) {
+		remoteDebugInitialized = 1;
+		debugInit(UART16550_BAUD_9600,
+			  UART16550_DATA_8BIT,
+			  UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+	}
+
+	while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
+	UART16550_WRITE(OFS_SEND_BUFFER, byte);
+	return 1;
+}
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/int-handler.S linux/arch/mips/ddb5476/int-handler.S
--- v2.4.3/linux/arch/mips/ddb5476/int-handler.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/int-handler.S	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,125 @@
+/*
+ *  arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
+ *
+ *  Based on arch/mips/sgi/kernel/indyIRQ.S
+ *
+ *  Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ *    common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ *    would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ *    between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the INDY look basically (barring software IRQs
+ * which we don't use at all) like:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        Local IRQ level zero
+ *             3        Local IRQ level one
+ *             4        8254 Timer zero
+ *             5        8254 Timer one
+ *             6        Bus Error
+ *             7        R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ----     R4k Timer
+ *                  Local IRQ zero
+ *                  Local IRQ one
+ *                  Bus Error
+ *                  8254 Timer zero
+ * Lowest  ----     8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+	.text
+	.set	noreorder
+	.set	noat
+	.align	5
+	NESTED(ddbIRQ, PT_SIZE, sp)
+	SAVE_ALL
+	CLI
+	.set	at
+	mfc0	s1, CP0_CAUSE		# get irq mask
+
+#if 1
+	mfc0	t2,CP0_STATUS		# get enabled interrupts
+	and	s0, s1, t2		# isolate allowed ones
+#endif
+	/* First we check for r4k counter/timer IRQ. */
+	andi	a0, s0, CAUSEF_IP2	# delay slot, check local level zero
+	beq	a0, zero, 1f
+	 andi	a0, s0, CAUSEF_IP3	# delay slot, check local level one
+
+	/* Wheee, local level zero interrupt. */
+	jal	ddb_local0_irqdispatch
+	 move	a0, sp			# delay slot
+
+	j	ret_from_irq
+	 nop				# delay slot
+
+1:
+	beq	a0, zero, 1f
+	 andi	a0, s0, CAUSEF_IP6	# delay slot, check bus error
+
+	/* Wheee, local level one interrupt. */
+	move	a0, sp
+	jal	ddb_local1_irqdispatch
+	 nop
+
+	j	ret_from_irq
+	 nop
+
+1:
+	beq	a0, zero, 1f
+	 nop
+
+	/* Wheee, an asynchronous bus error... */
+	move	a0, sp
+	jal	ddb_buserror_irq
+	 nop
+
+	j	ret_from_irq
+	 nop
+
+1:
+	/* Here by mistake?  This is possible, what can happen
+	 * is that by the time we take the exception the IRQ
+	 * pin goes low, so just leave if this is the case.
+	 */
+	andi	a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
+	beq	a0, zero, 1f
+
+	/* Must be one of the 8254 timers... */
+	move	a0, sp
+	jal	ddb_8254timer_irq
+	 nop
+1:
+	/* phamtom interrupt */
+	move 	a0, s1
+	jal	ddb_phantom_irq
+	nop
+	j	ret_from_irq
+	nop
+	END(ddbIRQ)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/irq.c linux/arch/mips/ddb5476/irq.c
--- v2.4.3/linux/arch/mips/ddb5476/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/irq.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,251 @@
+/*
+ *  arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ptrace.h>
+#include <asm/nile4.h>
+
+extern void __init i8259_init(void);
+extern void i8259_disable_irq(unsigned int irq_nr);
+extern void i8259_enable_irq(unsigned int irq_nr);
+
+extern asmlinkage void ddbIRQ(void);
+extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
+extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
+
+
+void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+
+#define M1543_PNP_CONFIG	0x03f0	/* PnP Config Port */
+#define M1543_PNP_INDEX		0x03f0	/* PnP Index Port */
+#define M1543_PNP_DATA		0x03f1	/* PnP Data Port */
+
+#define M1543_PNP_ALT_CONFIG	0x0370	/* Alternative PnP Config Port */
+#define M1543_PNP_ALT_INDEX	0x0370	/* Alternative PnP Index Port */
+#define M1543_PNP_ALT_DATA	0x0371	/* Alternative PnP Data Port */
+
+#define M1543_INT1_MASTER_CTRL	0x0020	/* INT_1 (master) Control Register */
+#define M1543_INT1_MASTER_MASK	0x0021	/* INT_1 (master) Mask Register */
+
+#define M1543_INT1_SLAVE_CTRL	0x00a0	/* INT_1 (slave) Control Register */
+#define M1543_INT1_SLAVE_MASK	0x00a1	/* INT_1 (slave) Mask Register */
+
+#define M1543_INT1_MASTER_ELCR	0x04d0	/* INT_1 (master) Edge/Level Control */
+#define M1543_INT1_SLAVE_ELCR	0x04d1	/* INT_1 (slave) Edge/Level Control */
+
+static struct {
+	struct resource m1543_config;
+	struct resource pic_elcr;
+} m1543_ioport = {
+	{ "M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG + 1,
+	  IORESOURCE_BUSY},
+	{ "pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR + 1,
+	  IORESOURCE_BUSY}
+};
+
+static void m1543_irq_setup(void)
+{
+	/*
+	 *  The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13.  Not all
+	 *  the possible IO sources in the M1543 are in use by us.  We will
+	 *  use the following mapping:
+	 *
+	 *      IRQ1  - keyboard (default set by M1543)
+	 *      IRQ3  - reserved for UART B (default set by M1543) (note that
+	 *              the schematics for the DDB Vrc-5476 board seem to 
+	 *              indicate that IRQ3 is connected to the DS1386 
+	 *              watchdog timer interrupt output so we might have 
+	 *              a conflict)
+	 *      IRQ4  - reserved for UART A (default set by M1543)
+	 *      IRQ5  - parallel (default set by M1543)
+	 *      IRQ8  - DS1386 time of day (RTC) interrupt
+	 *      IRQ9  - USB (hardwired in ddb_setup)
+	 *      IRQ10 - PMU (hardwired in ddb_setup)
+	 *      IRQ12 - mouse
+	 *      IRQ14,15 - IDE controller (need to be confirmed, jsun)
+	 */
+
+	/*
+	 *  Assing mouse interrupt to IRQ12 
+	 */
+
+	/* Enter configuration mode */
+	outb(0x51, M1543_PNP_CONFIG);
+	outb(0x23, M1543_PNP_CONFIG);
+
+	/* Select logical device 7 (Keyboard) */
+	outb(0x07, M1543_PNP_INDEX);
+	outb(0x07, M1543_PNP_DATA);
+
+	/* Select IRQ12 */
+	outb(0x72, M1543_PNP_INDEX);
+	outb(0x0c, M1543_PNP_DATA);
+
+	/* Leave configration mode */
+	outb(0xbb, M1543_PNP_CONFIG);
+
+
+	/* Initialize the 8259 PIC in the M1543 */
+	i8259_init();
+
+	/* Enable the interrupt cascade from M1543 */
+	nile4_enable_irq(NILE4_INT_INTC);
+
+	/* request io ports */
+	if (request_resource(&ioport_resource, &m1543_ioport.m1543_config)
+	    || request_resource(&ioport_resource, &m1543_ioport.pic_elcr)) {
+		printk("m1543_irq_setup : requesting io ports failed.\n");
+		for (;;);
+	}
+}
+
+static void nile4_irq_setup(void)
+{
+	int i;
+
+	/* Map all interrupts to CPU int #0 */
+	nile4_map_irq_all(0);
+
+	/* PCI INTA#-E# must be level triggered */
+	nile4_set_pci_irq_level_or_edge(0, 1);
+	nile4_set_pci_irq_level_or_edge(1, 1);
+	nile4_set_pci_irq_level_or_edge(2, 1);
+	nile4_set_pci_irq_level_or_edge(3, 1);
+
+	/* PCI INTA#, B#, D# must be active low, INTC# must be active high */
+	nile4_set_pci_irq_polarity(0, 0);
+	nile4_set_pci_irq_polarity(1, 0);
+	nile4_set_pci_irq_polarity(2, 1);
+	nile4_set_pci_irq_polarity(3, 0);
+
+	for (i = 0; i < 16; i++)
+		nile4_clear_irq(i);
+
+	/* Enable CPU int #0 */
+	nile4_enable_irq_output(0);
+
+	/* memory resource acquire in ddb_setup */
+}
+
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
+
+
+void disable_irq(unsigned int irq_nr)
+{
+	if (is_i8259_irq(irq_nr))
+		i8259_disable_irq(irq_nr);
+	else
+		nile4_disable_irq(irq_to_nile4(irq_nr));
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	if (is_i8259_irq(irq_nr))
+		i8259_enable_irq(irq_nr);
+	else
+		nile4_enable_irq(irq_to_nile4(irq_nr));
+}
+
+int table[16] = { 0, };
+
+void ddb_local0_irqdispatch(struct pt_regs *regs)
+{
+	u32 mask;
+	int nile4_irq;
+#if 0
+	volatile static int nesting = 0;
+	if (nesting++ == 0)
+		ddb5476_led_d3(1);
+	ddb5476_led_hex(nesting < 16 ? nesting : 15);
+#endif
+
+	mask = nile4_get_irq_stat(0);
+	nile4_clear_irq_mask(mask);
+
+	/* Handle the timer interrupt first */
+	if (mask & (1 << NILE4_INT_GPT)) {
+		nile4_disable_irq(NILE4_INT_GPT);
+		do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
+		nile4_enable_irq(NILE4_INT_GPT);
+		mask &= ~(1 << NILE4_INT_GPT);
+	}
+	for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
+		if (mask & 1) {
+			nile4_disable_irq(nile4_irq);
+			if (nile4_irq == NILE4_INT_INTC) {
+				int i8259_irq = nile4_i8259_iack();
+				i8259_do_irq(i8259_irq, regs);
+			} else {
+				do_IRQ(nile4_to_irq(nile4_irq), regs);
+			}
+			nile4_enable_irq(nile4_irq);
+		}
+#if 0
+	if (--nesting == 0)
+		ddb5476_led_d3(0);
+	ddb5476_led_hex(nesting < 16 ? nesting : 15);
+#endif
+}
+
+void ddb_local1_irqdispatch(void)
+{
+	printk("ddb_local1_irqdispatch called\n");
+}
+
+void ddb_buserror_irq(void)
+{
+	printk("ddb_buserror_irq called\n");
+}
+
+void ddb_8254timer_irq(void)
+{
+	printk("ddb_8254timer_irq called\n");
+}
+
+void ddb_phantom_irq(unsigned long cause)
+{
+	printk("phantom interrupts detected : \n");
+	printk("\tcause \t\t0x%08x\n", cause);
+	printk("\tcause reg\t0x%08x\n",
+	       read_32bit_cp0_register(CP0_CAUSE));
+	printk("\tstatus reg\t0x%08x\n",
+	       read_32bit_cp0_register(CP0_STATUS));
+}
+
+void __init ddb_irq_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+	printk("Wait for gdb client connection ...\n");
+	set_debug_traps();
+	breakpoint();		/* you may move this line to whereever you want :-) */
+#endif
+	i8259_setup_irq(2, &irq2);
+
+	nile4_irq_setup();
+	m1543_irq_setup();
+
+	/* we pin #0 - #4 (no internal timer) */
+	change_cp0_status(ST0_IM,
+	                  IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+
+	set_except_vector(0, ddbIRQ);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/nile4.c linux/arch/mips/ddb5476/nile4.c
--- v2.4.3/linux/arch/mips/ddb5476/nile4.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/nile4.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,293 @@
+/*
+ *  arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/nile4.h>
+
+
+/*
+ *  Physical Device Address Registers
+ *
+ *  Note: 32 bit addressing only!
+ */
+void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width,
+		    int on_memory_bus, int visible)
+{
+	u32 maskbits;
+	u32 widthbits;
+
+	if (pdar > NILE4_BOOTCS || (pdar & 7)) {
+		printk("nile4_set_pdar: invalid pdar %d\n", pdar);
+		return;
+	}
+	if (pdar == NILE4_INTCS && size != 0x00200000) {
+		printk("nile4_set_pdar: INTCS size must be 2 MB\n");
+		return;
+	}
+	switch (size) {
+#if 0				/* We don't support 4 GB yet */
+	case 0x100000000:	/* 4 GB */
+		maskbits = 4;
+		break;
+#endif
+	case 0x80000000:	/* 2 GB */
+		maskbits = 5;
+		break;
+	case 0x40000000:	/* 1 GB */
+		maskbits = 6;
+		break;
+	case 0x20000000:	/* 512 MB */
+		maskbits = 7;
+		break;
+	case 0x10000000:	/* 256 MB */
+		maskbits = 8;
+		break;
+	case 0x08000000:	/* 128 MB */
+		maskbits = 9;
+		break;
+	case 0x04000000:	/* 64 MB */
+		maskbits = 10;
+		break;
+	case 0x02000000:	/* 32 MB */
+		maskbits = 11;
+		break;
+	case 0x01000000:	/* 16 MB */
+		maskbits = 12;
+		break;
+	case 0x00800000:	/* 8 MB */
+		maskbits = 13;
+		break;
+	case 0x00400000:	/* 4 MB */
+		maskbits = 14;
+		break;
+	case 0x00200000:	/* 2 MB */
+		maskbits = 15;
+		break;
+	case 0:		/* OFF */
+		maskbits = 0;
+		break;
+	default:
+		printk("nile4_set_pdar: unsupported size %p\n",
+		       (void *) size);
+		return;
+	}
+	switch (width) {
+	case 8:
+		widthbits = 0;
+		break;
+	case 16:
+		widthbits = 1;
+		break;
+	case 32:
+		widthbits = 2;
+		break;
+	case 64:
+		widthbits = 3;
+		break;
+	default:
+		printk("nile4_set_pdar: unsupported width %d\n", width);
+		return;
+	}
+	nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
+		    (visible ? 0x20 : 0) | (widthbits << 6) |
+		    (phys & 0xffe00000));
+	nile4_out32(pdar + 4, 0);
+	/*
+	 * When programming a PDAR, the register should be read immediately
+	 * after writing it. This ensures that address decoders are properly
+	 * configured.
+	 */
+	nile4_in32(pdar);
+	nile4_in32(pdar + 4);
+}
+
+
+/*
+ *  PCI Master Registers
+ *
+ *  Note: 32 bit addressing only!
+ */
+void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
+{
+	if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
+		printk("nile4_set_pmr: invalid pmr %d\n", pmr);
+		return;
+	}
+	switch (type) {
+	case NILE4_PCICMD_IACK:	/* PCI Interrupt Acknowledge */
+	case NILE4_PCICMD_IO:	/* PCI I/O Space */
+	case NILE4_PCICMD_MEM:	/* PCI Memory Space */
+	case NILE4_PCICMD_CFG:	/* PCI Configuration Space */
+		break;
+	default:
+		printk("nile4_set_pmr: invalid type %d\n", type);
+		return;
+	}
+	nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
+	nile4_out32(pmr + 4, 0);
+}
+
+
+/*
+ *  Interrupt Programming
+ */
+void nile4_map_irq(int nile4_irq, int cpu_irq)
+{
+	u32 offset, t;
+
+	offset = NILE4_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = nile4_in32(offset);
+	t &= ~(7 << (nile4_irq * 4));
+	t |= cpu_irq << (nile4_irq * 4);
+	nile4_out32(offset, t);
+}
+
+void nile4_map_irq_all(int cpu_irq)
+{
+	u32 all, t;
+
+	all = cpu_irq;
+	all |= all << 4;
+	all |= all << 8;
+	all |= all << 16;
+	t = nile4_in32(NILE4_INTCTRL);
+	t &= 0x88888888;
+	t |= all;
+	nile4_out32(NILE4_INTCTRL, t);
+	t = nile4_in32(NILE4_INTCTRL + 4);
+	t &= 0x88888888;
+	t |= all;
+	nile4_out32(NILE4_INTCTRL + 4, t);
+}
+
+void nile4_enable_irq(int nile4_irq)
+{
+	u32 offset, t;
+
+	offset = NILE4_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = nile4_in32(offset);
+	t |= 8 << (nile4_irq * 4);
+	nile4_out32(offset, t);
+}
+
+void nile4_disable_irq(int nile4_irq)
+{
+	u32 offset, t;
+
+	offset = NILE4_INTCTRL;
+	if (nile4_irq >= 8) {
+		offset += 4;
+		nile4_irq -= 8;
+	}
+	t = nile4_in32(offset);
+	t &= ~(8 << (nile4_irq * 4));
+	nile4_out32(offset, t);
+}
+
+void nile4_disable_irq_all(void)
+{
+	nile4_out32(NILE4_INTCTRL, 0);
+	nile4_out32(NILE4_INTCTRL + 4, 0);
+}
+
+u16 nile4_get_irq_stat(int cpu_irq)
+{
+	return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2);
+}
+
+void nile4_enable_irq_output(int cpu_irq)
+{
+	u32 t;
+
+	t = nile4_in32(NILE4_INTSTAT1 + 4);
+	t |= 1 << (16 + cpu_irq);
+	nile4_out32(NILE4_INTSTAT1, t);
+}
+
+void nile4_disable_irq_output(int cpu_irq)
+{
+	u32 t;
+
+	t = nile4_in32(NILE4_INTSTAT1 + 4);
+	t &= ~(1 << (16 + cpu_irq));
+	nile4_out32(NILE4_INTSTAT1, t);
+}
+
+void nile4_set_pci_irq_polarity(int pci_irq, int high)
+{
+	u32 t;
+
+	t = nile4_in32(NILE4_INTPPES);
+	if (high)
+		t &= ~(1 << (pci_irq * 2));
+	else
+		t |= 1 << (pci_irq * 2);
+	nile4_out32(NILE4_INTPPES, t);
+}
+
+void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
+{
+	u32 t;
+
+	t = nile4_in32(NILE4_INTPPES);
+	if (level)
+		t |= 2 << (pci_irq * 2);
+	else
+		t &= ~(2 << (pci_irq * 2));
+	nile4_out32(NILE4_INTPPES, t);
+}
+
+void nile4_clear_irq(int nile4_irq)
+{
+	nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
+}
+
+void nile4_clear_irq_mask(u32 mask)
+{
+	nile4_out32(NILE4_INTCLR, mask);
+}
+
+u8 nile4_i8259_iack(void)
+{
+	u8 irq;
+
+	/* Set window 0 for interrupt acknowledge */
+	nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
+	irq = *(volatile u8 *) NILE4_PCI_IACK_BASE;
+	/* Set window 0 for PCI I/O space */
+	nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+	return irq;
+}
+
+#if 0
+void nile4_dump_irq_status(void)
+{
+	printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4),
+	       (void *) nile4_in32(NILE4_CPUSTAT));
+	printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4),
+	       (void *) nile4_in32(NILE4_INTCTRL));
+	printk("INTSTAT0 = %p:%p\n",
+	       (void *) nile4_in32(NILE4_INTSTAT0 + 4),
+	       (void *) nile4_in32(NILE4_INTSTAT0));
+	printk("INTSTAT1 = %p:%p\n",
+	       (void *) nile4_in32(NILE4_INTSTAT1 + 4),
+	       (void *) nile4_in32(NILE4_INTSTAT1));
+	printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4),
+	       (void *) nile4_in32(NILE4_INTCLR));
+	printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4),
+	       (void *) nile4_in32(NILE4_INTPPES));
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/pci.c linux/arch/mips/ddb5476/pci.c
--- v2.4.3/linux/arch/mips/ddb5476/pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/pci.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,495 @@
+/*
+ *  arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Albert Dorofeev <albert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+
+#include <asm-mips/nile4.h>
+
+
+static u32 nile4_pre_pci_access0(int slot_num)
+{
+	u32 pci_addr = 0;
+	u32 virt_addr = NILE4_PCI_CFG_BASE;
+
+	/* work around the bug for Vrc5476 */
+	if (slot_num == 13)
+		return NILE4_BASE + NILE4_PCI_BASE;
+
+	/* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */
+	nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0,
+		       0);
+
+	// [jsun] we start scanning from addr:10, 
+	// with 128M we can go up to addr:26 (slot 16)
+	if (slot_num <= 16) {
+		virt_addr += 0x00000400 << slot_num;
+	} else {
+		/* for high slot, we have to set higher PCI base addr */
+		pci_addr = 0x00000400 << slot_num;
+	}
+	nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
+	return virt_addr;
+}
+
+static void nile4_post_pci_access0(void)
+{
+	/*
+	 * Set window 1 back to address 08000000 - 32 bit - 128 MB
+	 * (PCI IO space)
+	 */
+	nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE),
+		       0x08000000, 32, 1, 1);
+	// nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+	nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000);
+}
+
+
+static int nile4_pci_read_config_dword(struct pci_dev *dev,
+				       int where, u32 * val)
+{
+	int slot_num, func_num;
+	u32 base;
+	u32 addr;
+
+	/*
+	 *  Do we need to generate type 1 configure transaction?
+	 */
+	if (dev->bus->number) {
+		/* FIXME - not working yet */
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+		/*
+		 * the largest type 1 configuration addr is 16M, < 256M
+		 * config space
+		 */
+		slot_num = 0;
+		addr =
+		    (dev->bus->number << 16) | (dev->devfn <
+						8) | where | 1;
+	} else {
+		slot_num = PCI_SLOT(dev->devfn);
+		func_num = PCI_FUNC(dev->devfn);
+		addr = (func_num << 8) + where;
+	}
+
+	base = nile4_pre_pci_access0(slot_num);
+	*val = *(volatile u32 *) (base + addr);
+	nile4_post_pci_access0();
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_dword(struct pci_dev *dev, int where,
+					u32 val)
+{
+	int slot_num, func_num;
+	u32 base;
+	u32 addr;
+
+	/*
+	 *  Do we need to generate type 1 configure transaction?
+	 */
+	if (dev->bus->number) {
+		/* FIXME - not working yet */
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+		/* the largest type 1 configuration addr is 16M, < 256M config space */
+		slot_num = 0;
+		addr =
+		    (dev->bus->number << 16) | (dev->devfn <
+						8) | where | 1;
+	} else {
+		slot_num = PCI_SLOT(dev->devfn);
+		func_num = PCI_FUNC(dev->devfn);
+		addr = (func_num << 8) + where;
+	}
+
+	base = nile4_pre_pci_access0(slot_num);
+	*(volatile u32 *) (base + addr) = val;
+	nile4_post_pci_access0();
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_word(struct pci_dev *dev, int where,
+				      u16 * val)
+{
+	int status;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 2)
+		result >>= 16;
+	*val = result & 0xffff;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_byte(struct pci_dev *dev, int where,
+				      u8 * val)
+{
+	int status;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 1)
+		result >>= 8;
+	if (where & 2)
+		result >>= 16;
+	*val = result & 0xff;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_word(struct pci_dev *dev, int where,
+				       u16 val)
+{
+	int status, shift = 0;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 2)
+		shift += 16;
+	result &= ~(0xffff << shift);
+	result |= val << shift;
+	return nile4_pci_write_config_dword(dev, where & ~3, result);
+}
+
+static int nile4_pci_write_config_byte(struct pci_dev *dev, int where,
+				       u8 val)
+{
+	int status, shift = 0;
+	u32 result;
+
+	status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+	if (status != PCIBIOS_SUCCESSFUL)
+		return status;
+	if (where & 2)
+		shift += 16;
+	if (where & 1)
+		shift += 8;
+	result &= ~(0xff << shift);
+	result |= val << shift;
+	return nile4_pci_write_config_dword(dev, where & ~3, result);
+}
+
+struct pci_ops nile4_pci_ops = {
+	nile4_pci_read_config_byte,
+	nile4_pci_read_config_word,
+	nile4_pci_read_config_dword,
+	nile4_pci_write_config_byte,
+	nile4_pci_write_config_word,
+	nile4_pci_write_config_dword
+};
+
+struct {
+	struct resource ram;
+	struct resource flash;
+	struct resource isa_io;
+	struct resource pci_io;
+	struct resource isa_mem;
+	struct resource pci_mem;
+	struct resource nile4;
+	struct resource boot;
+} ddb5476_resources = {
+	// { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
+	{
+	"RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM}, {
+	"Flash ROM", 0x04000000, 0x043fffff}, {
+	"Nile4 ISA I/O", 0x06000000, 0x060fffff}, {
+	"Nile4 PCI I/O", 0x06100000, 0x07ffffff}, {
+	"Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, {
+	"Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM},
+	    // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
+	{
+	"Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM}, {
+	"Boot ROM", 0x1fc00000, 0x1fffffff}
+};
+
+struct resource M5229_resources[5] = {
+	{"M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO},
+	{"M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO},
+	{"M5229 BAR2", 0x170, 0x173, IORESOURCE_IO},
+	{"M5229 BAR3", 0x374, 0x377, IORESOURCE_IO},
+	{"M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO}
+};
+
+static void __init ddb5476_pci_fixup(void)
+{
+	struct pci_dev *dev;
+
+	pci_for_each_dev(dev) {
+		if (dev->vendor == PCI_VENDOR_ID_NEC &&
+		    dev->device == PCI_DEVICE_ID_NEC_VRC5476) {
+			/*
+			 * The first 64-bit PCI base register should point to
+			 * the Nile4 control registers. Unfortunately this
+			 * isn't the case, so we fix it ourselves. This allows
+			 * the serial driver to find the UART.
+			 */
+			dev->resource[0] = ddb5476_resources.nile4;
+			request_resource(&iomem_resource,
+					 &dev->resource[0]);
+			/*
+			 * The second 64-bit PCI base register points to the
+			 * first memory bank. Unfortunately the address is
+			 * wrong, so we fix it (again).
+			 */
+
+			/* [jsun] We cannot request the resource anymore,
+			 * because kernel/setup.c has already reserved "System 
+			 * RAM" resource at the same spot.  
+			 * The fundamental problem here is that PCI host 
+			 * controller should not put system RAM mapping in BAR
+			 * and make subject to PCI resource assignement.
+			 * Current fix is a total hack.  We set parent to 1 so
+                         * so that PCI resource assignement code is fooled to 
+                         * think the resource is assigned, and will not attempt
+                         * to mess with it.
+			 */
+			dev->resource[2] = ddb5476_resources.ram;
+			if (request_resource(&iomem_resource,
+			                     &dev->resource[2]) ) {
+				dev->resource[2].parent = 0x1;
+                        }
+
+		} else if (dev->vendor == PCI_VENDOR_ID_AL
+			   && dev->device == PCI_DEVICE_ID_AL_M7101) {
+			/*
+			 * It's nice to have the LEDs on the GPIO pins
+			 * available for debugging
+			 */
+			extern struct pci_dev *pci_pmu;
+			u8 t8;
+
+			pci_pmu = dev;	/* for LEDs D2 and D3 */
+			/* Program the lines for LEDs D2 and D3 to output */
+			nile4_pci_read_config_byte(dev, 0x7d, &t8);
+			t8 |= 0xc0;
+			nile4_pci_write_config_byte(dev, 0x7d, t8);
+			/* Turn LEDs D2 and D3 off */
+			nile4_pci_read_config_byte(dev, 0x7e, &t8);
+			t8 |= 0xc0;
+			nile4_pci_write_config_byte(dev, 0x7e, t8);
+		} else if (dev->vendor == PCI_VENDOR_ID_AL &&
+			   dev->device == 0x5229) {
+			int i;
+			for (i = 0; i < 5; i++) {
+				dev->resource[i] = M5229_resources[i];
+				request_resource(&ioport_resource,
+						 &dev->resource[i]);
+			}
+		}
+	}
+}
+
+static void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev;
+	int slot_num;
+
+	pci_for_each_dev(dev) {
+		slot_num = PCI_SLOT(dev->devfn);
+		switch (slot_num) {
+		case 3:	/* re-programmed to USB */
+			dev->irq = 9;	/* hard-coded; see irq.c */
+			break;
+		case 4:	/* re-programmed to PMU */
+			dev->irq = 10;	/* hard-coded; see irq.c */
+			break;
+		case 6:	/* on-board pci-pci bridge */
+			dev->irq = 0xff;
+			break;
+		case 7:	/* on-board ether */
+			dev->irq = nile4_to_irq(NILE4_INT_INTB);
+			break;
+		case 8:	/* ISA-PCI bridge  */
+			dev->irq = nile4_to_irq(NILE4_INT_INTC);
+			break;
+		case 9:	/* ext slot #3 */
+			dev->irq = nile4_to_irq(NILE4_INT_INTD);
+			break;
+		case 10:	/* ext slot #4 */
+			dev->irq = nile4_to_irq(NILE4_INT_INTA);
+			break;
+		case 13:	/* Vrc5476 */
+			dev->irq = 0xff;
+			break;
+		case 14:	/* HD controller, M5229 */
+			dev->irq = 14;
+			break;
+		default:
+			printk
+			    ("JSUN : in pcibios_fixup_irqs - unkown slot %d\n",
+			     slot_num);
+			panic
+			    ("JSUN : in pcibios_fixup_irqs - unkown slot.\n");
+		}
+	}
+}
+
+void __init pcibios_init(void)
+{
+	printk("PCI: Emulate bios initialization \n");
+	/* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */
+	*(long *) (NILE4_BASE + NILE4_BAR0) = 0x8;
+
+	printk("PCI: Probing PCI hardware\n");
+	ioport_resource.end = 0x1ffffff;	/*  32 MB */
+	iomem_resource.end = 0x1fffffff;	/* 512 MB */
+
+	/* `ram' and `nile4' are requested through the Nile4 pci_dev */
+	request_resource(&iomem_resource, &ddb5476_resources.flash);
+	request_resource(&iomem_resource, &ddb5476_resources.isa_io);
+	request_resource(&iomem_resource, &ddb5476_resources.pci_io);
+	request_resource(&iomem_resource, &ddb5476_resources.isa_mem);
+	request_resource(&iomem_resource, &ddb5476_resources.pci_mem);
+	request_resource(&iomem_resource, &ddb5476_resources.boot);
+
+	pci_scan_bus(0, &nile4_pci_ops, NULL);
+	ddb5476_pci_fixup();
+	pci_assign_unassigned_resources();
+	pcibios_fixup_irqs();
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	/* [jsun] we don't know how to fix sub-buses yet */
+	if (bus->number == 0) {
+		bus->resource[1] = &ddb5476_resources.pci_mem;
+	}
+}
+
+char *pcibios_setup(char *str)
+{
+	return str;
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
+				      struct pbus_set_ranges_data *ranges)
+{
+	/*
+	 * our caller figure out range by going through the dev structures.  
+	 * I guess this is the place to fix things up if the bus is using a 
+	 * different view of the addressing space.
+	 */
+
+#if 0	/*  original DDB5074 code */
+	   if (bus->number == 0) {
+	   ranges->io_start -= bus->resource[0]->start;
+	   ranges->io_end -= bus->resource[0]->start;
+	   ranges->mem_start -= bus->resource[1]->start;
+	   ranges->mem_end -= bus->resource[1]->start;
+	   }
+#endif
+}
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	/*
+	 *  Don't touch the Nile 4
+	 */
+	if (dev->vendor == PCI_VENDOR_ID_NEC &&
+	    dev->device == PCI_DEVICE_ID_NEC_VRC5476) return 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because "
+			       "of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	return pcibios_enable_resources(dev);
+}
+
+void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			     struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+
+	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4 * resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/*
+		 * Somebody might have asked allocation of a non-standard
+		 * resource
+		 */
+		return;
+	}
+
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) &
+	    ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
+	     PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size)
+{
+	struct pci_dev *dev = data;
+
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		/* We need to avoid collisions with `mirrored' VGA ports
+		   and other strange ISA hardware, so we always want the
+		   addresses kilobyte aligned.  */
+		if (size > 0x100) {
+			printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+			       " (%ld bytes)\n", dev->slot_name,
+			       dev->resource - res, size);
+		}
+
+		start = (start + 1024 - 1) & ~(1024 - 1);
+		res->start = start;
+	}
+}
+
+struct pci_fixup pcibios_fixups[] = { {0} };
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/prom.c linux/arch/mips/ddb5476/prom.c
--- v2.4.3/linux/arch/mips/ddb5476/prom.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/prom.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,43 @@
+/*
+ *  arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ *
+ *   	Jun Sun - modified for DDB5476.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+
+/* [jsun@junsun.net] PMON passes arguments in C main() style */
+void __init prom_init(int argc, const char **arg)
+{
+	int i;
+
+	/* arg[0] is "g", the rest is boot parameters */
+	arcs_cmdline[0] = '\0';
+	for (i = 1; i < argc; i++) {
+		if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
+		    >= sizeof(arcs_cmdline))
+			break;
+		strcat(arcs_cmdline, arg[i]);
+		strcat(arcs_cmdline, " ");
+	}
+
+	mips_machgroup = MACH_GROUP_NEC_DDB;
+	mips_machtype = MACH_NEC_DDB5476;
+	/* 64 MB non-upgradable */
+	add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/setup.c linux/arch/mips/ddb5476/setup.c
--- v2.4.3/linux/arch/mips/ddb5476/setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/setup.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,375 @@
+/*
+ *  arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/pc_keyb.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/addrspace.h>
+#include <asm/bcache.h>
+#include <asm/keyboard.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/gdb-stub.h>
+#include <asm/nile4.h>
+
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE)
+extern void console_setup(char *);
+#endif
+
+extern struct ide_ops std_ide_ops;
+extern struct rtc_ops ddb_rtc_ops;
+extern struct kbd_ops std_kbd_ops;
+
+static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
+
+static void ddb_machine_restart(char *command)
+{
+	u32 t;
+
+	/* PCI cold reset */
+	t = nile4_in32(NILE4_PCICTRL + 4);
+	t |= 0x40000000;
+	nile4_out32(NILE4_PCICTRL + 4, t);
+	/* CPU cold reset */
+	t = nile4_in32(NILE4_CPUSTAT);
+	t |= 1;
+	nile4_out32(NILE4_CPUSTAT, t);
+	/* Call the PROM */
+	back_to_prom();
+}
+
+static void ddb_machine_halt(void)
+{
+	printk("DDB Vrc-5476 halted.\n");
+	while (1);
+}
+
+static void ddb_machine_power_off(void)
+{
+	printk("DDB Vrc-5476 halted. Please turn off the power.\n");
+	while (1);
+}
+
+extern void ddb_irq_setup(void);
+
+void (*board_time_init) (struct irqaction * irq);
+
+
+static void __init ddb_time_init(struct irqaction *irq)
+{
+	/* set the clock to 1 Hz */
+	nile4_out32(NILE4_T2CTRL, 1000000);
+	/* enable the General-Purpose Timer */
+	nile4_out32(NILE4_T2CTRL + 4, 0x00000001);
+	/* reset timer */
+	nile4_out32(NILE4_T2CNTR, 0);
+	/* enable interrupt */
+	nile4_enable_irq(NILE4_INT_GPT);
+	i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
+}
+
+static struct {
+	struct resource dma1;
+	struct resource pic1;
+	struct resource timer;
+	struct resource rtc;
+	struct resource dma_page_reg;
+	struct resource pic2;
+	struct resource dma2;
+} ddb5476_ioport = {
+	{
+	"dma1", 0x00, 0x1f, IORESOURCE_BUSY}, {
+	"pic1", 0x20, 0x3f, IORESOURCE_BUSY}, {
+	"timer", 0x40, 0x5f, IORESOURCE_BUSY}, {
+	"rtc", 0x70, 0x7f, IORESOURCE_BUSY}, {
+	"dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, {
+	"pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, {
+	"dma2", 0xc0, 0xdf, IORESOURCE_BUSY}
+};
+
+static struct {
+	struct resource nile4;
+} ddb5476_iomem = {
+	{ "Nile 4", NILE4_BASE, NILE4_BASE + NILE4_SIZE - 1, IORESOURCE_BUSY}
+};
+
+void __init ddb_setup(void)
+{
+	extern int panic_timeout;
+
+	irq_setup = ddb_irq_setup;
+	mips_io_port_base = NILE4_PCI_IO_BASE;
+	isa_slot_offset = NILE4_PCI_MEM_BASE;
+	board_time_init = ddb_time_init;
+
+	_machine_restart = ddb_machine_restart;
+	_machine_halt = ddb_machine_halt;
+	_machine_power_off = ddb_machine_power_off;
+
+	/* request io port/mem resources  */
+	if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) ||
+	    request_resource(&ioport_resource, &ddb5476_ioport.pic1) ||
+	    request_resource(&ioport_resource, &ddb5476_ioport.timer) ||
+	    request_resource(&ioport_resource, &ddb5476_ioport.rtc) ||
+	    request_resource(&ioport_resource,
+			     &ddb5476_ioport.dma_page_reg)
+	    || request_resource(&ioport_resource, &ddb5476_ioport.pic2)
+	    || request_resource(&ioport_resource, &ddb5476_ioport.dma2)
+	    || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) {
+		printk
+		    ("ddb_setup - requesting oo port resources failed.\n");
+		for (;;);
+	}
+#ifdef CONFIG_BLK_DEV_IDE
+	ide_ops = &std_ide_ops;
+#endif
+	rtc_ops = &ddb_rtc_ops;
+
+#ifdef CONFIG_PC_KEYB
+	kbd_ops = &std_kbd_ops;
+#endif
+
+	/* Reboot on panic */
+	panic_timeout = 180;
+
+	/* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */
+	/* *(long*)0xbfa00218 = 0x8; */
+
+#ifdef CONFIG_FB
+	conswitchp = &dummy_con;
+#endif
+
+
+	/* board initialization stuff - non-fundamental, but need to be set
+	 * before kernel runs */
+
+	/* setup I/O space */
+	nile4_set_pdar(NILE4_PCIW0,
+		       PHYSADDR(NILE4_PCI_IO_BASE), 0x02000000, 32, 0, 0);
+	nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+
+	/* map config space to 0xa8000000, 128MB */
+	nile4_set_pdar(NILE4_PCIW1,
+		       PHYSADDR(NILE4_PCI_CFG_BASE), 0x08000000, 32, 0, 0);
+	nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, 0x0);
+
+	/* ----- M1543 PCI setup ------ */
+
+	/* we know M1543 PCI-ISA controller is at addr:18 */
+	/* xxxx1010 makes USB at addr:13 and PMU at addr:14 */
+	*(volatile unsigned char *) 0xa8040072 &= 0xf0;
+	*(volatile unsigned char *) 0xa8040072 |= 0xa;
+
+	/* setup USB interrupt to IRQ 9, (bit 0:3 - 0001)
+	 * no IOCHRDY signal, (bit 7 - 1)
+	 * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1)
+	 * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0)
+	 */
+	*(unsigned char *) 0xa8040074 = 0xc1;
+
+	/* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011)
+	 * SCI routing to IRQ 13 disabled (bit 7 - 1)
+	 * SCI interrupt level to edge conversion bypassed (bit 4 - 0)
+	 */
+	*(unsigned char *) 0xa8040076 = 0x83;
+
+	/* setup IDE controller
+	 * enable IDE controller (bit 6 - 1)
+	 * IDE IDSEL to be addr:24 (bit 4:5 - 11)
+	 * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0)
+	 * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0)
+	 * primary IRQ is 14, secondary is 15 (bit 1:0 - 01
+	 */
+	// *(unsigned char*)0xa8040058 = 0x71;
+	// *(unsigned char*)0xa8040058 = 0x79;
+	// *(unsigned char*)0xa8040058 = 0x74;              // use SIRQ, primary tri-state
+	*(unsigned char *) 0xa8040058 = 0x75;	// primary tri-state
+
+#if 0
+	/* this is not necessary if M5229 does not use SIRQ */
+	*(unsigned char *) 0xa8040044 = 0x0d;	// primary to IRQ 14
+	*(unsigned char *) 0xa8040075 = 0x0d;	// secondary to IRQ 14
+#endif
+
+	/* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */
+	/* M5229 IDSEL is addr:24; see above setting */
+	*(unsigned char *) 0xa9000050 |= 0x1;
+
+	/* enable bus master (bit 2)  and IO decoding  (bit 0) */
+	*(unsigned char *) 0xa9000004 |= 0x5;
+
+	/* enable native, copied from arch/ppc/k2boot/head.S */
+	/* TODO - need volatile, need to be portable */
+	*(unsigned char *) 0xa9000009 = 0xff;
+
+	/* ----- end of M1543 PCI setup ------ */
+
+	/* ----- reset on-board ether chip  ------ */
+	*((volatile u32 *) 0xa8020004) |= 1;	/* decode I/O */
+	*((volatile u32 *) 0xa8020010) = 0;	/* set BAR address */
+
+	/* send reset command */
+	*((volatile u32 *) 0xa6000000) = 1;	/* do a soft reset */
+
+	/* disable ether chip */
+	*((volatile u32 *) 0xa8020004) = 0;	/* disable any decoding */
+
+	/* put it into sleep */
+	*((volatile u32 *) 0xa8020040) = 0x80000000;
+
+	/* ----- end of reset on-board ether chip  ------ */
+
+	/* ----- set pci window 1 to pci memory space -------- */
+	nile4_set_pdar(NILE4_PCIW1,
+		       PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 32, 0, 0);
+	// nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+	nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000);
+
+}
+
+#define USE_NILE4_SERIAL	0
+
+#if USE_NILE4_SERIAL
+#define ns16550_in(reg)		nile4_in8((reg)*8)
+#define ns16550_out(reg, val)	nile4_out8((reg)*8, (val))
+#else
+#define NS16550_BASE		(NILE4_PCI_IO_BASE+0x03f8)
+static inline u8 ns16550_in(u32 reg)
+{
+	return *(volatile u8 *) (NS16550_BASE + reg);
+}
+
+static inline void ns16550_out(u32 reg, u8 val)
+{
+	*(volatile u8 *) (NS16550_BASE + reg) = val;
+}
+#endif
+
+#define NS16550_RBR		0
+#define NS16550_THR		0
+#define NS16550_DLL		0
+#define NS16550_IER		1
+#define NS16550_DLM		1
+#define NS16550_FCR		2
+#define NS16550_IIR		2
+#define NS16550_LCR		3
+#define NS16550_MCR		4
+#define NS16550_LSR		5
+#define NS16550_MSR		6
+#define NS16550_SCR		7
+
+#define NS16550_LSR_DR		0x01	/* Data ready */
+#define NS16550_LSR_OE		0x02	/* Overrun */
+#define NS16550_LSR_PE		0x04	/* Parity error */
+#define NS16550_LSR_FE		0x08	/* Framing error */
+#define NS16550_LSR_BI		0x10	/* Break */
+#define NS16550_LSR_THRE	0x20	/* Xmit holding register empty */
+#define NS16550_LSR_TEMT	0x40	/* Xmitter empty */
+#define NS16550_LSR_ERR		0x80	/* Error */
+
+
+void _serinit(void)
+{
+#if USE_NILE4_SERIAL
+	ns16550_out(NS16550_LCR, 0x80);
+	ns16550_out(NS16550_DLM, 0x00);
+	ns16550_out(NS16550_DLL, 0x36);	/* 9600 baud */
+	ns16550_out(NS16550_LCR, 0x00);
+	ns16550_out(NS16550_LCR, 0x03);
+	ns16550_out(NS16550_FCR, 0x47);
+#else
+	/* done by PMON */
+#endif
+}
+
+void _putc(char c)
+{
+	while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+	ns16550_out(NS16550_THR, c);
+	if (c == '\n') {
+		while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+		ns16550_out(NS16550_THR, '\r');
+	}
+}
+
+void _puts(const char *s)
+{
+	char c;
+
+	while ((c = *s++))
+		_putc(c);
+}
+
+char _getc(void)
+{
+	while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
+
+	return ns16550_in(NS16550_RBR);
+}
+
+int _testc(void)
+{
+	return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
+}
+
+
+/*
+ *  Hexadecimal 7-segment LED
+ */
+void ddb5476_led_hex(int hex)
+{
+	outb(hex, 0x80);
+}
+
+
+/*
+ *  LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
+ */
+struct pci_dev *pci_pmu = NULL;
+
+void ddb5476_led_d2(int on)
+{
+	u8 t;
+
+	if (pci_pmu) {
+		pci_read_config_byte(pci_pmu, 0x7e, &t);
+		if (on)
+			t &= 0x7f;
+		else
+			t |= 0x80;
+		pci_write_config_byte(pci_pmu, 0x7e, t);
+	}
+}
+
+void ddb5476_led_d3(int on)
+{
+	u8 t;
+
+	if (pci_pmu) {
+		pci_read_config_byte(pci_pmu, 0x7e, &t);
+		if (on)
+			t &= 0xbf;
+		else
+			t |= 0x40;
+		pci_write_config_byte(pci_pmu, 0x7e, t);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/time.c linux/arch/mips/ddb5476/time.c
--- v2.4.3/linux/arch/mips/ddb5476/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ddb5476/time.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,32 @@
+/*
+ *  arch/mips/ddb5074/time.c -- Timer routines
+ *
+ *  Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *                     Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/init.h>
+
+#include <asm/mc146818rtc.h>
+
+static unsigned char ddb_rtc_read_data(unsigned long addr)
+{
+	outb_p(addr, RTC_PORT(0));
+	return inb_p(RTC_PORT(1));
+}
+
+static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
+{
+	outb_p(addr, RTC_PORT(0));
+	outb_p(data, RTC_PORT(1));
+}
+
+static int ddb_rtc_bcd_mode(void)
+{
+	return 1;
+}
+
+struct rtc_ops ddb_rtc_ops = {
+	ddb_rtc_read_data,
+	ddb_rtc_write_data,
+	ddb_rtc_bcd_mode
+};
diff -u --recursive --new-file v2.4.3/linux/arch/mips/dec/Makefile linux/arch/mips/dec/Makefile
--- v2.4.3/linux/arch/mips/dec/Makefile	Thu Feb 24 22:52:30 2000
+++ linux/arch/mips/dec/Makefile	Fri Apr 13 20:26:07 2001
@@ -7,30 +7,20 @@
 #
 
 .S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
+	$(CPP) $(AFLAGS) $< -o $@
 .S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+	$(CC) $(AFLAGS) -c $< -o $@
 
-all: dec.o
 O_TARGET := dec.o
-O_OBJS	 := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o
 
-ifdef CONFIG_PROM_CONSOLE
-O_OBJS   += promcon.o
-endif
+all: dec.o
 
-ifdef CONFIG_SERIAL
-O_OBJS   += serial.o
-endif
+export-objs := wbflush.o
+obj-y	 := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o
 
-ifeq ($(CONFIG_MODULES),y)
- OX_OBJS  = wbflush.o
-else
- O_OBJS   += wbflush.o
-endif
+obj-$(CONFIG_PROM_CONSOLE)	+= promcon.o
+obj-$(CONFIG_SERIAL)		+= serial.o
 
 int-handler.o:	int-handler.S
-
-clean:
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/dec/boot/Makefile linux/arch/mips/dec/boot/Makefile
--- v2.4.3/linux/arch/mips/dec/boot/Makefile	Fri Jun 25 17:40:12 1999
+++ linux/arch/mips/dec/boot/Makefile	Fri Apr 13 20:26:07 2001
@@ -18,7 +18,8 @@
 all: dec_boot.o
 
 O_TARGET := dec_boot.o
-O_OBJS	 := decstation.o
+
+obj-y	 := decstation.o
 
 clean:
 	rm -f nbImage
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.4.3/linux/arch/mips/defconfig	Sun Mar  4 14:30:18 2001
+++ linux/arch/mips/defconfig	Fri Apr 13 20:26:07 2001
@@ -16,16 +16,17 @@
 # CONFIG_COBALT_MICRO_SERVER is not set
 # CONFIG_DECSTATION is not set
 # CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 CONFIG_SGI_IP22=y
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 CONFIG_ARC32=y
 CONFIG_PC_KEYB=y
 CONFIG_SGI=y
 # CONFIG_ISA is not set
+# CONFIG_EISA is not set
 # CONFIG_PCI is not set
 
 #
@@ -84,17 +85,23 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
@@ -111,10 +118,8 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -131,6 +136,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -152,6 +158,7 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 CONFIG_SR_EXTRA_DEVS=2
@@ -192,14 +199,14 @@
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -229,6 +236,8 @@
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -283,8 +292,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -299,11 +306,13 @@
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
@@ -334,6 +343,11 @@
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-cobalt linux/arch/mips/defconfig-cobalt
--- v2.4.3/linux/arch/mips/defconfig-cobalt	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/defconfig-cobalt	Fri Apr 13 20:26:07 2001
@@ -17,18 +17,18 @@
 CONFIG_COBALT_28=y
 # CONFIG_DECSTATION is not set
 # CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
-# CONFIG_ISA is not set
 CONFIG_COBALT_27=y
 CONFIG_COBALT_LCD=y
 CONFIG_COBALT_SERIAL=y
 CONFIG_PCI=y
 # CONFIG_ISA is not set
+# CONFIG_EISA is not set
 
 #
 # Loadable module support
@@ -85,22 +85,26 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_BOOT is not set
-# CONFIG_AUTODETECT_RAID is not set
 CONFIG_BLK_DEV_RAM=m
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
 # Networking options
 #
 # CONFIG_PACKET is not set
@@ -112,13 +116,11 @@
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 CONFIG_IP_MROUTE=y
 # CONFIG_IP_PIMSM_V1 is not set
 # CONFIG_IP_PIMSM_V2 is not set
-CONFIG_IP_ALIAS=y
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -130,13 +132,13 @@
 #
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
-# CONFIG_SPX is not set
 CONFIG_ATALK=m
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -171,6 +173,7 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 CONFIG_SR_EXTRA_DEVS=2
@@ -194,15 +197,14 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-# CONFIG_AIC7XXX_PROC_STATS is not set
 CONFIG_AIC7XXX_RESET_DELAY=5
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # 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_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
@@ -214,8 +216,6 @@
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_NCR53C8XX=y
 # CONFIG_SCSI_SYM53C8XX is not set
@@ -233,6 +233,8 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
@@ -265,6 +267,7 @@
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
 
 #
@@ -277,6 +280,7 @@
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
@@ -284,8 +288,9 @@
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_YELLOWFIN is not set
 # CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -326,6 +331,7 @@
 CONFIG_ISDN_PPP=y
 CONFIG_ISDN_PPP_VJ=y
 CONFIG_ISDN_MPP=y
+# CONFIG_ISDN_PPP_BSDCOMP is not set
 CONFIG_ISDN_AUDIO=y
 # CONFIG_ISDN_TTY_FAX is not set
 
@@ -353,6 +359,7 @@
 # CONFIG_HISAX_NO_LLC is not set
 # CONFIG_HISAX_NO_KEYPAD is not set
 CONFIG_HISAX_1TR6=y
+# CONFIG_HISAX_NI1 is not set
 
 #
 #   HiSax supported cards
@@ -374,6 +381,7 @@
 # CONFIG_HISAX_SPORTSTER is not set
 # CONFIG_HISAX_MIC is not set
 # CONFIG_HISAX_NETJET is not set
+# CONFIG_HISAX_NETJET_U is not set
 # CONFIG_HISAX_NICCY is not set
 # CONFIG_HISAX_ISURF is not set
 # CONFIG_HISAX_HSTSAPHIR is not set
@@ -383,6 +391,7 @@
 # CONFIG_HISAX_HFC_PCI is not set
 # CONFIG_HISAX_W6692 is not set
 # CONFIG_HISAX_HFC_SX is not set
+# CONFIG_HISAX_SEDLBAUER_CS is not set
 
 #
 # Active ISDN cards
@@ -393,8 +402,8 @@
 # CONFIG_ISDN_DRV_ACT2000 is not set
 # CONFIG_ISDN_DRV_EICON is not set
 # CONFIG_ISDN_CAPI is not set
-# CONFIG_ISDN_CAPI_MIDDLEWARE is not set
 # CONFIG_HYSDN is not set
+# CONFIG_HYSDN_CAPI is not set
 
 #
 # Old CD-ROM drivers (not SCSI, not IDE)
@@ -425,6 +434,10 @@
 # Joysticks
 #
 # CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -434,11 +447,6 @@
 # CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 CONFIG_RTC=y
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -447,8 +455,13 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
 # CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
 
 #
 # File systems
@@ -456,6 +469,8 @@
 CONFIG_QUOTA=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -503,6 +518,7 @@
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
@@ -510,8 +526,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -520,6 +534,7 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
 CONFIG_NLS=y
 
 #
@@ -569,6 +584,11 @@
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-ddb5476 linux/arch/mips/defconfig-ddb5476
--- v2.4.3/linux/arch/mips/defconfig-ddb5476	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/defconfig-ddb5476	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,541 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MOMENCO_OCELOT is not set
+CONFIG_DDB5476=y
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_I8259=y
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_PC_KEYB=y
+CONFIG_ROTTEN_IRQ=y
+CONFIG_EISA=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+CONFIG_CPU_R5432=y
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_WB is not set
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_FPU_EMULATOR=y
+CONFIG_KCORE_ELF=y
+CONFIG_ELF_KERNEL=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PM is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NATSEMI is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-decstation linux/arch/mips/defconfig-decstation
--- v2.4.3/linux/arch/mips/defconfig-decstation	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/defconfig-decstation	Fri Apr 13 20:26:07 2001
@@ -16,13 +16,14 @@
 # CONFIG_COBALT_MICRO_SERVER is not set
 CONFIG_DECSTATION=y
 # CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_ISA is not set
+# CONFIG_EISA is not set
 # CONFIG_PCI is not set
 
 #
@@ -80,17 +81,23 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
@@ -107,10 +114,8 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -127,6 +132,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -148,6 +154,7 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 # 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
 
@@ -170,6 +177,7 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -186,14 +194,14 @@
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -224,6 +232,8 @@
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -278,8 +288,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -294,17 +302,24 @@
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_SGI_PARTITION is not set
 CONFIG_ULTRIX_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-ip22 linux/arch/mips/defconfig-ip22
--- v2.4.3/linux/arch/mips/defconfig-ip22	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/defconfig-ip22	Fri Apr 13 20:26:07 2001
@@ -16,16 +16,17 @@
 # CONFIG_COBALT_MICRO_SERVER is not set
 # CONFIG_DECSTATION is not set
 # CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 CONFIG_SGI_IP22=y
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 CONFIG_ARC32=y
 CONFIG_PC_KEYB=y
 CONFIG_SGI=y
 # CONFIG_ISA is not set
+# CONFIG_EISA is not set
 # CONFIG_PCI is not set
 
 #
@@ -84,17 +85,23 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
@@ -111,10 +118,8 @@
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -131,6 +136,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -152,6 +158,7 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 CONFIG_SR_EXTRA_DEVS=2
@@ -175,6 +182,7 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -191,14 +199,14 @@
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -228,6 +236,8 @@
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -282,8 +292,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -298,11 +306,13 @@
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
@@ -333,6 +343,11 @@
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-it8172 linux/arch/mips/defconfig-it8172
--- v2.4.3/linux/arch/mips/defconfig-it8172	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/defconfig-it8172	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,569 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SNI_RM200_PCI is not set
+CONFIG_MIPS_ITE8172=y
+# CONFIG_IT8172_REVC is not set
+CONFIG_QTRONIX_KEYBOARD=y
+CONFIG_IT8172_CIR=y
+# CONFIG_IT8172_SCR0 is not set
+# CONFIG_IT8172_SCR1 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_PCI=y
+CONFIG_IT8712=y
+CONFIG_PC_KEYB=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_I8259 is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_RM7000 is not set
+CONFIG_CPU_NEVADA=y
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_WB is not set
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_FPU_EMULATOR=y
+CONFIG_KCORE_ELF=y
+CONFIG_ELF_KERNEL=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+CONFIG_PCI_NAMES=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# RAM/ROM Device Drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_MTDRAM is not set
+
+#
+# Linearly Mapped Flash Device Drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_JEDEC is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=8000000
+CONFIG_MTD_PHYSMAP_LEN=2000000
+CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+
+#
+# Drivers for chip mappings
+#
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_VMAX is not set
+
+#
+# User modules and translation layers for MTD devices
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+# CONFIG_UNIX is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_IT8172=y
+CONFIG_IT8172_TUNING=y
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_IDE_CHIPSETS=y
+
+#
+# Note: most of these also require special kernel boot parameters
+#
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_BLK_DEV_PDC4030 is not set
+# CONFIG_BLK_DEV_QD6580 is not set
+# CONFIG_BLK_DEV_UMC8672 is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PM is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+CONFIG_8139TOO=y
+# CONFIG_RTL8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_MIPS_FPE_MODULE is not set
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-orion linux/arch/mips/defconfig-orion
--- v2.4.3/linux/arch/mips/defconfig-orion	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/defconfig-orion	Fri Apr 13 20:26:07 2001
@@ -16,13 +16,14 @@
 # CONFIG_COBALT_MICRO_SERVER is not set
 # CONFIG_DECSTATION is not set
 # CONFIG_DDB5074 is not set
-CONFIG_ORION=y
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_SGI_IP22 is not set
 # CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 # CONFIG_ISA is not set
+# CONFIG_EISA is not set
 # CONFIG_PCI is not set
 
 #
@@ -79,18 +80,24 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
@@ -113,6 +120,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET_AUNUDP is not set
 # CONFIG_ECONET_NATIVE is not set
 # CONFIG_WAN_ROUTER is not set
@@ -180,6 +188,10 @@
 # Joysticks
 #
 # CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -189,11 +201,6 @@
 # CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -202,8 +209,13 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
 # CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
 
 #
 # File systems
@@ -211,6 +223,8 @@
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -265,6 +279,7 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
@@ -276,6 +291,11 @@
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/mips/defconfig-rm200 linux/arch/mips/defconfig-rm200
--- v2.4.3/linux/arch/mips/defconfig-rm200	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/defconfig-rm200	Fri Apr 13 20:26:07 2001
@@ -16,16 +16,17 @@
 # CONFIG_COBALT_MICRO_SERVER is not set
 # CONFIG_DECSTATION is not set
 # CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_SGI_IP22 is not set
 CONFIG_SNI_RM200_PCI=y
+# CONFIG_MCA is not set
 # CONFIG_SBUS is not set
 CONFIG_ARC32=y
 CONFIG_PCI=y
 CONFIG_ISA=y
 CONFIG_PC_KEYB=y
+CONFIG_EISA=y
 
 #
 # Loadable module support
@@ -88,17 +89,23 @@
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
@@ -113,10 +120,8 @@
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -133,6 +138,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -211,6 +217,10 @@
 # Joysticks
 #
 # CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -220,11 +230,6 @@
 # CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 CONFIG_RTC=y
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -233,8 +238,13 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
 # CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
 
 #
 # File systems
@@ -242,6 +252,8 @@
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -296,8 +308,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -312,11 +322,13 @@
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
@@ -339,6 +351,11 @@
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/Makefile linux/arch/mips/ite-boards/generic/Makefile
--- v2.4.3/linux/arch/mips/ite-boards/generic/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,36 @@
+#
+#  Copyright 2000 MontaVista Software Inc.
+#  Author: MontaVista Software, Inc.
+#     	ppopov@mvista.com or support@mvista.com
+#
+# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
+#
+# 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).
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+all: it8172.o
+
+O_TARGET := it8172.o
+
+obj-y := it8172_rtc.o it8172_setup.o irq.o int-handler.o pmon_prom.o time.o lpc.o puts.o reset.o
+
+ifdef CONFIG_PCI
+obj-y += it8172_pci.o
+endif
+
+ifdef CONFIG_IT8172_CIR
+obj-y += it8172_cir.o 
+endif
+
+ifdef CONFIG_REMOTE_DEBUG
+ obj-y += dbg_io.o             
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/dbg_io.c linux/arch/mips/ite-boards/generic/dbg_io.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/dbg_io.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/dbg_io.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,127 @@
+
+#include <linux/config.h>
+
+#ifdef CONFIG_REMOTE_DEBUG
+
+/* --- CONFIG --- */
+
+/* we need uint32 uint8 */
+/* #include "types.h" */
+typedef         unsigned char uint8;
+typedef         unsigned int  uint32;
+
+/* --- END OF CONFIG --- */
+
+#define         UART16550_BAUD_2400             2400
+#define         UART16550_BAUD_4800             4800
+#define         UART16550_BAUD_9600             9600
+#define         UART16550_BAUD_19200            19200
+#define         UART16550_BAUD_38400            38400
+#define         UART16550_BAUD_57600            57600
+#define         UART16550_BAUD_115200           115200
+
+#define         UART16550_PARITY_NONE           0
+#define         UART16550_PARITY_ODD            0x08
+#define         UART16550_PARITY_EVEN           0x18
+#define         UART16550_PARITY_MARK           0x28
+#define         UART16550_PARITY_SPACE          0x38
+
+#define         UART16550_DATA_5BIT             0x0
+#define         UART16550_DATA_6BIT             0x1
+#define         UART16550_DATA_7BIT             0x2
+#define         UART16550_DATA_8BIT             0x3
+
+#define         UART16550_STOP_1BIT             0x0
+#define         UART16550_STOP_2BIT             0x4
+
+/* ----------------------------------------------------- */
+
+/* === CONFIG === */
+
+/* [stevel] we use the IT8712 serial port for kgdb */
+#define	DEBUG_BASE  0xB40003F8 /* 8712 serial port 1 base address */
+#define MAX_BAUD    115200
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define         OFS_RCV_BUFFER          0
+#define         OFS_TRANS_HOLD          0
+#define         OFS_SEND_BUFFER         0
+#define         OFS_INTR_ENABLE         1
+#define         OFS_INTR_ID             2
+#define         OFS_DATA_FORMAT         3
+#define         OFS_LINE_CONTROL        3
+#define         OFS_MODEM_CONTROL       4
+#define         OFS_RS232_OUTPUT        4
+#define         OFS_LINE_STATUS         5
+#define         OFS_MODEM_STATUS        6
+#define         OFS_RS232_INPUT         6
+#define         OFS_SCRATCH_PAD         7
+
+#define         OFS_DIVISOR_LSB         0
+#define         OFS_DIVISOR_MSB         1
+
+
+/* memory-mapped read/write of the port */
+#define UART16550_READ(y)    (*((volatile uint8*)(DEBUG_BASE + y)))
+#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z)
+
+void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+    /* disable interrupts */
+    UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+    /* set up buad rate */
+    { 
+        uint32 divisor;
+       
+        /* set DIAB bit */
+        UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+        
+        /* set divisor */
+        divisor = MAX_BAUD / baud;
+        UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+        UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8);
+
+        /* clear DIAB bit */
+        UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+    }
+
+    /* set data format */
+    UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+static int remoteDebugInitialized = 0;
+
+uint8 getDebugChar(void)
+{
+    if (!remoteDebugInitialized) {
+	remoteDebugInitialized = 1;
+	debugInit(UART16550_BAUD_115200,
+		  UART16550_DATA_8BIT,
+		  UART16550_PARITY_NONE,
+		  UART16550_STOP_1BIT);
+    }
+
+    while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+    return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+int putDebugChar(uint8 byte)
+{
+    if (!remoteDebugInitialized) {
+	remoteDebugInitialized = 1;
+	debugInit(UART16550_BAUD_115200,
+		  UART16550_DATA_8BIT,
+		  UART16550_PARITY_NONE,
+		  UART16550_STOP_1BIT);
+    }
+
+    while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0);
+    UART16550_WRITE(OFS_SEND_BUFFER, byte);
+    return 1;
+}
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/int-handler.S linux/arch/mips/ite-boards/generic/int-handler.S
--- v2.4.3/linux/arch/mips/ite-boards/generic/int-handler.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/int-handler.S	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,61 @@
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+	.text
+	.set    macro
+	.set    noat
+	.align	5
+
+NESTED(it8172_IRQ, PT_SIZE, sp)
+	SAVE_ALL
+	CLI				# Important: mark KERNEL mode !
+
+        /* We're working with 'reorder' set at this point. */
+	/*
+	 * Get pending interrupts
+	 */
+
+	mfc0	t0,CP0_CAUSE		# get pending interrupts
+	mfc0	t1,CP0_STATUS		# get enabled interrupts
+	and	t0,t1			# isolate allowed ones
+
+	andi	t0,0xff00		# isolate pending bits
+        beqz    t0, 3f                  # spurious interrupt
+
+        andi    a0, t0, CAUSEF_IP7
+        beq     a0, zero, 1f
+        move    a0, sp
+        jal     mips_timer_interrupt
+	j	ret_from_irq
+        nop
+        
+1:
+        andi    a0, t0, CAUSEF_IP2      # the only int we expect at this time
+        beq     a0, zero, 3f           
+	move	a0,sp  
+	jal	it8172_hw0_irqdispatch
+
+	mfc0	t0,CP0_STATUS		# disable interrupts
+	ori	t0,1
+	xori	t0,1
+	mtc0	t0,CP0_STATUS
+        nop
+        nop
+        nop
+	
+	la      a1, ret_from_irq
+	jr	a1
+        nop
+	
+3:	
+	move a0, sp
+	jal	mips_spurious_interrupt
+        nop
+	la      a1, ret_from_irq
+	jr	a1
+        nop
+
+END(it8172_IRQ)
+
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/irq.c linux/arch/mips/ite-boards/generic/irq.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/irq.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,540 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	ITE 8172G interrupt/setup routines.
+ *
+ * Copyright 2000,2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.com
+ *
+ * Part of this file was derived from Carsten Langgaard's 
+ * arch/mips/mips-boards/atlas/atlas_int.c.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/serial_reg.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_int.h>
+#include <asm/it8172/it8172_dbg.h>
+
+#undef DEBUG_IRQ
+#ifdef DEBUG_IRQ
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void breakpoint(void);
+#endif
+
+/* revisit */
+#define EXT_IRQ0_TO_IP 2 /* IP 2 */
+#define EXT_IRQ5_TO_IP 7 /* IP 7 */
+
+extern void set_debug_traps(void);
+extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
+extern asmlinkage void it8172_IRQ(void);
+irq_cpustat_t irq_stat [NR_CPUS];
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+irq_desc_t irq_desc[NR_IRQS];
+irq_desc_t *irq_desc_base=&irq_desc[0];
+
+struct it8172_intc_regs volatile *it8172_hw0_icregs
+	= (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
+
+/* Function for careful CP0 interrupt mask access */
+static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
+{
+        unsigned long status = read_32bit_cp0_register(CP0_STATUS);
+        status &= ~((clr_mask & 0xFF) << 8);
+        status |=   (set_mask & 0xFF) << 8;
+        write_32bit_cp0_register(CP0_STATUS, status);
+}
+
+static inline void mask_irq(unsigned int irq_nr)
+{
+        modify_cp0_intmask(irq_nr, 0);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+        modify_cp0_intmask(0, irq_nr);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+        unsigned long flags;
+
+        save_and_cli(flags);
+        mask_irq(irq_nr);
+        restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+        save_and_cli(flags);
+        unmask_irq(irq_nr);
+        restore_flags(flags);
+}
+
+
+void disable_it8172_irq(unsigned int irq_nr)
+{
+	unsigned short mask;
+
+	DPRINTK("disable_it8172_irq %d\n", irq_nr);
+
+	if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
+		/* LPC interrupt */
+		DPRINTK("disable, before lpc_mask  %x\n", it8172_hw0_icregs->lpc_mask);
+		it8172_hw0_icregs->lpc_mask |= (1 << (irq_nr - IT8172_LPC_IRQ_BASE));
+		DPRINTK("disable, after lpc_mask  %x\n", it8172_hw0_icregs->lpc_mask);
+	}
+	else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
+		/* Local Bus interrupt */
+		DPRINTK("before lb_mask  %x\n", it8172_hw0_icregs->lb_mask);
+		it8172_hw0_icregs->lb_mask |= (1 << (irq_nr - IT8172_LB_IRQ_BASE));
+		DPRINTK("after lb_mask  %x\n", it8172_hw0_icregs->lb_mask);
+	}
+	else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
+		/* PCI and other interrupts */
+		DPRINTK("before pci_mask  %x\n", it8172_hw0_icregs->pci_mask);
+		it8172_hw0_icregs->pci_mask |= (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
+		DPRINTK("after pci_mask  %x\n", it8172_hw0_icregs->pci_mask);
+	}
+	else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
+		/* NMI interrupts */
+		DPRINTK("before nmi_mask  %x\n", it8172_hw0_icregs->nmi_mask);
+		it8172_hw0_icregs->nmi_mask |= (1 << (irq_nr - IT8172_NMI_IRQ_BASE));
+		DPRINTK("after nmi_mask  %x\n", it8172_hw0_icregs->nmi_mask);
+	}
+	else {
+		panic("disable_it8172_irq: bad irq %d\n", irq_nr);
+	}
+}
+
+
+void enable_it8172_irq(unsigned int irq_nr)
+{
+	DPRINTK("enable_it8172_irq %d\n", irq_nr);
+	if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
+		/* LPC interrupt */
+		DPRINTK("enable, before lpc_mask  %x\n", it8172_hw0_icregs->lpc_mask);
+		it8172_hw0_icregs->lpc_mask &= ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE));
+		DPRINTK("enable, after lpc_mask  %x\n", it8172_hw0_icregs->lpc_mask);
+	}
+	else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
+		/* Local Bus interrupt */
+		DPRINTK("before lb_mask  %x\n", it8172_hw0_icregs->lb_mask);
+		it8172_hw0_icregs->lb_mask &= ~(1 << (irq_nr - IT8172_LB_IRQ_BASE));
+		DPRINTK("after lb_mask  %x\n", it8172_hw0_icregs->lb_mask);
+	}
+	else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
+		/* PCI and other interrupts */
+		DPRINTK("before pci_mask  %x\n", it8172_hw0_icregs->pci_mask);
+		it8172_hw0_icregs->pci_mask &= ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
+		DPRINTK("after pci_mask  %x\n", it8172_hw0_icregs->pci_mask);
+	}
+	else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
+		/* NMI interrupts */
+		DPRINTK("before nmi_mask  %x\n", it8172_hw0_icregs->nmi_mask);
+		it8172_hw0_icregs->nmi_mask &= ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE));
+		DPRINTK("after nmi_mask  %x\n", it8172_hw0_icregs->nmi_mask);
+	}
+	else {
+		panic("enable_it8172_irq: bad irq %d\n", irq_nr);
+	}
+}
+
+static unsigned int startup_ite_irq(unsigned int irq)
+{
+	enable_it8172_irq(irq);
+	return 0; 
+}
+
+#define shutdown_ite_irq	disable_it8172_irq
+#define mask_and_ack_ite_irq    disable_it8172_irq
+
+static void end_ite_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_it8172_irq(irq);
+}
+
+static struct hw_interrupt_type it8172_irq_type = {
+	"ITE8172",
+	startup_ite_irq,
+	shutdown_ite_irq,
+	enable_it8172_irq,
+	disable_it8172_irq,
+	mask_and_ack_ite_irq,
+	end_ite_irq,
+	NULL
+};
+
+
+int get_irq_list(char *buf)
+{
+        int i, len = 0, j;
+        struct irqaction * action;
+
+        len += sprintf(buf+len, "           ");
+        for (j=0; j<smp_num_cpus; j++)
+                len += sprintf(buf+len, "CPU%d       ",j);
+        *(char *)(buf+len++) = '\n';
+
+        for (i = 0 ; i < NR_IRQS ; i++) {
+                action = irq_desc[i].action;
+                if ( !action || !action->handler )
+                        continue;
+                len += sprintf(buf+len, "%3d: ", i);		
+                len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+                if ( irq_desc[i].handler )		
+                        len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
+                else
+                        len += sprintf(buf+len, "  None      ");
+                len += sprintf(buf+len, "    %s",action->name);
+                for (action=action->next; action; action = action->next) {
+                        len += sprintf(buf+len, ", %s", action->name);
+                }
+                len += sprintf(buf+len, "\n");
+        }
+        len += sprintf(buf+len, "BAD: %10lu\n", spurious_count);
+        return len;
+}
+
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+	struct irqaction *action;
+	int cpu;
+
+	cpu = smp_processor_id();
+	irq_enter(cpu, irq);
+
+	kstat.irqs[cpu][irq]++;
+#if 0
+	if (irq_desc[irq].handler && irq_desc[irq].handler->ack) {
+	//	printk("invoking ack handler\n");
+		irq_desc[irq].handler->ack(irq);
+	}
+#endif
+
+	action = irq_desc[irq].action;
+
+	if (action && action->handler)
+	{
+		//mask_irq(1<<irq);
+		//printk("action->handler %x\n", action->handler);
+		disable_it8172_irq(irq);
+		//if (!(action->flags & SA_INTERRUPT)) __sti(); /* reenable ints */
+		do { 
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+		} while ( action );
+		//__cli(); /* disable ints */
+		if (irq_desc[irq].handler)
+		{
+		}
+		//unmask_irq(1<<irq);
+		enable_it8172_irq(irq);
+	}
+	else
+	{
+		spurious_count++;
+		printk("Unhandled interrupt %d, cause %x, disabled\n", 
+				(unsigned)irq, (unsigned)regs->cp0_cause);
+		disable_it8172_irq(irq);
+		//disable_irq(1<<irq);
+	}
+	irq_exit(cpu, irq);
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+	unsigned long irqflags, const char * devname, void *dev_id)
+{
+        struct irqaction *old, **p, *action;
+        unsigned long flags;
+
+        /*
+         * IP0 and IP1 are software interrupts. IP7 is typically the timer interrupt.
+	 *
+	 * The ITE QED-4N-S01B board has one single interrupt line going from
+	 * the system controller to the CPU. It's connected to the CPU external
+	 * irq pin 1, which is IP2.  The interrupt numbers are listed in it8172_int.h;
+	 * the ISA interrupts are numbered from 0 to 15, and the rest go from
+	 * there.  
+         */
+
+	//printk("request_irq: %d handler %x\n", irq, handler);
+        if (irq >= NR_IRQS) 
+                return -EINVAL;
+
+        if (!handler)
+        {
+                /* Free */
+                for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
+                {
+                        /* Found it - now free it */
+                        save_flags(flags);
+                        cli();
+                        *p = action->next;
+			disable_it8172_irq(irq);
+                        //disable_irq(1<<irq);
+                        restore_flags(flags);
+                        kfree(action);
+                        return 0;
+                }
+                return -ENOENT;
+        }
+        
+        action = (struct irqaction *)
+                kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+        if (!action)
+                return -ENOMEM;
+        memset(action, 0, sizeof(struct irqaction));
+        
+        save_flags(flags);
+        cli();
+        
+        action->handler = handler;
+        action->flags = irqflags;					
+        action->mask = 0;
+        action->name = devname;
+        action->dev_id = dev_id;
+        action->next = NULL;
+
+        p = &irq_desc[irq].action;
+        
+        if ((old = *p) != NULL) {
+                /* Can't share interrupts unless both agree to */
+                if (!(old->flags & action->flags & SA_SHIRQ))
+                        return -EBUSY;
+                /* add new interrupt at end of irq queue */
+                do {
+                        p = &old->next;
+                        old = *p;
+                } while (old);
+        }
+        *p = action;
+	enable_it8172_irq(irq);
+        restore_flags(flags);	
+#if 0
+	printk("request_irq: status %x cause %x\n", 
+			read_32bit_cp0_register(CP0_STATUS), read_32bit_cp0_register(CP0_CAUSE));
+#endif
+        return 0;
+}
+		
+void free_irq(unsigned int irq, void *dev_id)
+{
+        request_irq(irq, NULL, 0, NULL, dev_id);
+}
+
+void enable_cpu_timer(void)
+{
+	enable_irq(1<<EXT_IRQ5_TO_IP); /* timer interrupt */
+}
+
+unsigned long probe_irq_on (void)
+{
+        return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+        return 0;
+}
+
+
+void __init init_IRQ(void)
+{
+	int i;
+
+        memset(irq_desc, 0, sizeof(irq_desc));
+        set_except_vector(0, it8172_IRQ);
+
+	/* mask all interrupts */
+	it8172_hw0_icregs->lb_mask  = 0xffff;
+	it8172_hw0_icregs->lpc_mask = 0xffff;
+	it8172_hw0_icregs->pci_mask = 0xffff;
+	it8172_hw0_icregs->nmi_mask = 0xffff;
+
+	/* make all interrupts level triggered */
+	it8172_hw0_icregs->lb_trigger  = 0;
+	it8172_hw0_icregs->lpc_trigger = 0;
+	it8172_hw0_icregs->pci_trigger = 0;
+	it8172_hw0_icregs->nmi_trigger = 0;
+
+	/* active level setting */
+	/* uart, keyboard, and mouse are active high */
+	it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000);
+	it8172_hw0_icregs->lb_level |= 0x20;
+
+	/* keyboard and mouse are edge triggered */
+	it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000); 
+
+
+#if 0
+	// Enable this piece of code to make internal USB interrupt
+	// edge triggered.
+	it8172_hw0_icregs->pci_trigger |= 
+		(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
+	it8172_hw0_icregs->pci_level &= 
+		~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
+#endif
+
+	for (i = 0; i <= IT8172_INT_END; i++) {
+		irq_desc[i].status	= IRQ_DISABLED;
+		irq_desc[i].action	= 0;
+		irq_desc[i].depth	= 1;
+		irq_desc[i].handler	= &it8172_irq_type;
+	}
+
+	/*
+	 * Enable external int line 2
+	 * All ITE interrupts are masked for now.
+	 */
+	enable_irq(1<<EXT_IRQ0_TO_IP);
+	//change_cp0_status(ST0_IM, IE_IRQ2);
+
+#ifdef CONFIG_REMOTE_DEBUG
+	/* If local serial I/O used for debug port, enter kgdb at once */
+	puts("Waiting for kgdb to connect...");
+	set_debug_traps();
+	breakpoint(); 
+#endif
+}
+
+void mips_spurious_interrupt(struct pt_regs *regs)
+{
+#if 1
+	return;
+#else
+	unsigned long status, cause;
+
+	printk("got spurious interrupt\n");
+	status = read_32bit_cp0_register(CP0_STATUS);
+	cause = read_32bit_cp0_register(CP0_CAUSE);
+	printk("status %x cause %x\n", status, cause);
+	printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr);
+//	while(1);
+#endif
+}
+
+void it8172_hw0_irqdispatch(struct pt_regs *regs)
+{
+	int irq;
+	unsigned short intstatus, status;
+
+	intstatus = it8172_hw0_icregs->intstatus;
+	if (intstatus & 0x8) {
+		panic("Got NMI interrupt\n");
+	}
+	else if (intstatus & 0x4) {
+		/* PCI interrupt */
+		irq = 0;
+		status = it8172_hw0_icregs->pci_req;
+		while (!(status & 0x1)) {
+			irq++;
+			status >>= 1;
+		}
+		irq += IT8172_PCI_DEV_IRQ_BASE;
+		//printk("pci int %d\n", irq);
+	}
+	else if (intstatus & 0x1) {
+		/* Local Bus interrupt */
+		irq = 0;
+		status = it8172_hw0_icregs->lb_req;
+		while (!(status & 0x1)) {
+			irq++;
+			status >>= 1;
+		}
+		irq += IT8172_LB_IRQ_BASE;
+		//printk("lb int %d\n", irq);
+	}
+	else if (intstatus & 0x2) {
+		/* LPC interrupt */
+		/* Since some lpc interrupts are edge triggered,
+		 * we could lose an interrupt this way because
+		 * we acknowledge all ints at onces. Revisit.
+		 */
+		status = it8172_hw0_icregs->lpc_req;
+		it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */
+		irq = 0;
+		while (!(status & 0x1)) {
+			irq++;
+			status >>= 1;
+		}
+		irq += IT8172_LPC_IRQ_BASE;
+		//printk("LPC int %d\n", irq);
+	}
+	else {
+		return;
+	}
+	do_IRQ(irq, regs);
+}
+
+void show_pending_irqs(void)
+{
+	fputs("intstatus:  ");
+	put32(it8172_hw0_icregs->intstatus);
+	puts("");
+
+	fputs("pci_req:  ");
+	put32(it8172_hw0_icregs->pci_req);
+	puts("");
+
+	fputs("lb_req:  ");
+	put32(it8172_hw0_icregs->lb_req);
+	puts("");
+
+	fputs("lpc_req:  ");
+	put32(it8172_hw0_icregs->lpc_req);
+	puts("");
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_cir.c linux/arch/mips/ite-boards/generic/it8172_cir.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_cir.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/it8172_cir.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,171 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172 Consumer IR port generic routines.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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_IT8172_CIR
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_cir.h>
+
+
+volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = {
+	(volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)),
+	(volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))};
+
+
+/*
+ * Initialize Consumer IR Port.
+ */
+int cir_port_init(struct cir_port *cir)
+{
+	int port = cir->port;
+	unsigned char data;
+
+	/* set baud rate */
+	cir_regs[port]->bdlr = cir->baud_rate & 0xff;
+	cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff;
+
+	/* set receiver control register */
+	cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr));
+
+	/* set carrier frequency register */
+	cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs));
+
+	/* set fifo threshold */
+	data = cir_regs[port]->mstcr & 0xf3;
+	data |= CIR_SET_FIFO_TL(cir->fifo_tl);
+	cir_regs[port]->mstcr = data;
+
+	clear_fifo(cir);
+	enable_receiver(cir);
+	disable_rx_demodulation(cir);
+
+	set_rx_active(cir);
+	int_enable(cir);
+	rx_int_enable(cir);
+
+	return 0;
+}
+
+
+void clear_fifo(struct cir_port *cir)
+{
+	cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR;
+}
+
+void enable_receiver(struct cir_port *cir)
+{
+	cir_regs[cir->port]->rcr |= CIR_RXEN;
+}
+
+void disable_receiver(struct cir_port *cir)
+{
+	cir_regs[cir->port]->rcr &= ~CIR_RXEN;
+}
+
+void enable_rx_demodulation(struct cir_port *cir)
+{
+	cir_regs[cir->port]->rcr |= CIR_RXEND;
+}
+
+void disable_rx_demodulation(struct cir_port *cir)
+{
+	cir_regs[cir->port]->rcr &= ~CIR_RXEND;
+}
+
+void set_rx_active(struct cir_port *cir)
+{
+	cir_regs[cir->port]->rcr |= CIR_RXACT;
+}
+
+void int_enable(struct cir_port *cir)
+{
+	cir_regs[cir->port]->ier |= CIR_IEC;
+}
+
+void rx_int_enable(struct cir_port *cir)
+{
+	cir_regs[cir->port]->ier |= CIR_RDAIE;
+}
+
+void dump_regs(struct cir_port *cir)
+{
+	printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n",
+	cir_regs[cir->port]->mstcr,
+	cir_regs[cir->port]->ier,
+	cir_regs[cir->port]->iir,
+	cir_regs[cir->port]->cfr,
+	cir_regs[cir->port]->rcr,
+	cir_regs[cir->port]->tcr,
+	cir_regs[cir->port]->tfsr,
+	cir_regs[cir->port]->rfsr);
+
+	while (cir_regs[cir->port]->iir & CIR_RDAI) {
+		printk("data %x\n", cir_regs[cir->port]->dr);
+	}
+}
+
+void dump_reg_addr(struct cir_port *cir)
+{
+	printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n",
+	(unsigned)&cir_regs[cir->port]->dr,
+	(unsigned)&cir_regs[cir->port]->mstcr,
+	(unsigned)&cir_regs[cir->port]->ier,
+	(unsigned)&cir_regs[cir->port]->iir,
+	(unsigned)&cir_regs[cir->port]->cfr,
+	(unsigned)&cir_regs[cir->port]->rcr,
+	(unsigned)&cir_regs[cir->port]->tcr,
+	(unsigned)&cir_regs[cir->port]->bdlr,
+	(unsigned)&cir_regs[cir->port]->bdhr,
+	(unsigned)&cir_regs[cir->port]->tfsr,
+	(unsigned)&cir_regs[cir->port]->rfsr);
+}
+
+int cir_get_rx_count(struct cir_port *cir)
+{
+	return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK;
+}
+
+char cir_read_data(struct cir_port *cir)
+{
+	return cir_regs[cir->port]->dr;
+}
+
+char get_int_status(struct cir_port *cir)
+{
+	return cir_regs[cir->port]->iir;
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_pci.c linux/arch/mips/ite-boards/generic/it8172_pci.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/it8172_pci.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,276 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172 system controller specific pci support.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+#undef DEBUG
+#undef DEBUG_CONFIG_CYCLES
+
+static int
+it8172_pcibios_config_access(unsigned char access_type, struct pci_dev *dev,
+                           unsigned char where, u32 *data)
+{
+	/* 
+	 * config cycles are on 4 byte boundary only
+	 */
+	unsigned char bus = dev->bus->number;
+	unsigned char dev_fn = dev->devfn;
+
+#ifdef DEBUG_CONFIG_CYCLES
+	printk("it config: type %d dev %x bus %d dev_fn %x data %x\n",
+			access_type, dev, bus, dev_fn, *data);
+
+#endif
+
+	/* Setup address */
+	IT_WRITE(IT_CONFADDR, (bus << IT_BUSNUM_SHF) | 
+			(dev_fn << IT_FUNCNUM_SHF) | (where & ~0x3));
+
+
+	if (access_type == PCI_ACCESS_WRITE) {
+		IT_WRITE(IT_CONFDATA, *data);
+	} 
+	else {
+		IT_READ(IT_CONFDATA, *data);
+	}
+
+	/*
+	 * Revisit: check for master or target abort.
+	 */
+	return 0;
+
+
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly.  Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int
+it8172_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val)
+{
+	u32 data = 0;
+
+	if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+		return -1;
+
+	*val = (data >> ((where & 3) << 3)) & 0xff;
+#ifdef DEBUG
+        printk("cfg read byte: bus %d dev_fn %x where %x: val %x\n", 
+                dev->bus->number, dev->devfn, where, *val);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+it8172_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val)
+{
+	u32 data = 0;
+
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+	       return -1;
+
+	*val = (data >> ((where & 3) << 3)) & 0xffff;
+#ifdef DEBUG
+        printk("cfg read word: bus %d dev_fn %x where %x: val %x\n", 
+                dev->bus->number, dev->devfn, where, *val);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+it8172_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val)
+{
+	u32 data = 0;
+
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	
+	if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+		return -1;
+
+	*val = data;
+#ifdef DEBUG
+        printk("cfg read dword: bus %d dev_fn %x where %x: val %x\n", 
+                dev->bus->number, dev->devfn, where, *val);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+it8172_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val)
+{
+	u32 data = 0;
+       
+	if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+		return -1;
+
+	data = (data & ~(0xff << ((where & 3) << 3))) |
+	       (val << ((where & 3) << 3));
+
+	if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+		return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+it8172_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val)
+{
+        u32 data = 0;
+
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+       
+        if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+	       return -1;
+
+	data = (data & ~(0xffff << ((where & 3) << 3))) | 
+	       (val << ((where & 3) << 3));
+
+	if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+	       return -1;
+
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+it8172_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+	       return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops it8172_pci_ops = {
+	it8172_pcibios_read_config_byte,
+        it8172_pcibios_read_config_word,
+	it8172_pcibios_read_config_dword,
+	it8172_pcibios_write_config_byte,
+	it8172_pcibios_write_config_word,
+	it8172_pcibios_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+
+	printk("PCI: Probing PCI hardware on host bus 0.\n");
+	pci_scan_bus(0, &it8172_pci_ops, NULL);
+}
+
+int __init
+pcibios_enable_device(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+
+void __init
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+    printk("pcibios_align_resource\n");
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+	/* Nothing to do for now.  */
+
+	return str;
+}
+
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                        struct resource *res, int resource)
+{
+	unsigned long where, size;
+	u32 reg;
+
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	size = res->end - res->start;
+	pci_read_config_dword(dev, where, &reg);
+	reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+	pci_write_config_dword(dev, where, reg);
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	printk("pcibios_fixup_bus\n");
+}
+#endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_rtc.c linux/arch/mips/ite-boards/generic/it8172_rtc.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_rtc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/it8172_rtc.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.com
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * RTC routines for ITE8172 MC146818-compatible rtc chip.
+ *
+ */
+#include <asm/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <asm/it8172/it8172.h>
+
+#define IT8172_RTC_ADR_REG  (IT8172_PCI_IO_BASE + IT_RTC_BASE)
+#define IT8172_RTC_DAT_REG  (IT8172_RTC_ADR_REG + 1)
+
+static volatile char *rtc_adr_reg = KSEG1ADDR((volatile char *)IT8172_RTC_ADR_REG);
+static volatile char *rtc_dat_reg = KSEG1ADDR((volatile char *)IT8172_RTC_DAT_REG);
+
+unsigned char it8172_rtc_read_data(unsigned long addr)
+{
+	unsigned char retval;
+
+	*rtc_adr_reg = addr;
+	retval =  *rtc_dat_reg;
+	return retval;
+}
+
+void it8172_rtc_write_data(unsigned char data, unsigned long addr)
+{
+	*rtc_adr_reg = addr;
+	*rtc_dat_reg = data;
+}
+
+static int it8172_rtc_bcd_mode(void)
+{
+	return 0;
+}
+
+struct rtc_ops it8172_rtc_ops = {
+	&it8172_rtc_read_data,
+	&it8172_rtc_write_data,
+	&it8172_rtc_bcd_mode
+};
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/it8172_setup.c linux/arch/mips/ite-boards/generic/it8172_setup.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/it8172_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/it8172_setup.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,310 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172/QED5231 board setup.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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/sched.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/mc146818rtc.h>
+#include <linux/serial_reg.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/it8172/it8172.h>
+#include <asm/it8712.h>
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+extern struct rtc_ops it8172_rtc_ops;
+extern struct resource ioport_resource;
+extern unsigned long mips_io_port_base;
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+extern struct ide_ops *ide_ops;
+#endif
+#ifdef CONFIG_PC_KEYB
+extern struct kbd_ops std_kbd_ops;
+int init_8712_keyboard(void);
+#endif
+
+extern int SearchIT8712(void);
+extern void InitLPCInterface(void);
+extern char * __init prom_getcmdline(void);
+extern void it8172_restart(void);
+extern void it8172_halt(void);
+extern void it8172_power_off(void);
+
+#ifdef CONFIG_IT8172_REVC
+struct {
+    struct resource ram;
+    struct resource pci_mem;
+    struct resource pci_io;
+    struct resource flash;
+    struct resource boot;
+} it8172_resources = {
+    { "RAM",           0,          0,          IORESOURCE_MEM }, /* to be initted */
+    { "PCI Mem",       0x10000000, 0x13FFFFFF, IORESOURCE_MEM },
+    { "PCI I/O",       0x14000000, 0x17FFFFFF                 },
+    { "Flash",         0x08000000, 0x0CFFFFFF                 },
+    { "Boot ROM",      0x1FC00000, 0x1FFFFFFF                 }
+};
+#else
+struct {
+    struct resource ram;
+    struct resource pci_mem0;
+    struct resource pci_mem1;
+    struct resource pci_io;
+    struct resource pci_mem2;
+    struct resource pci_mem3;
+    struct resource flash;
+    struct resource boot;
+} it8172_resources = {
+    { "RAM",           0,          0,          IORESOURCE_MEM }, /* to be initted */
+    { "PCI Mem0",      0x0C000000, 0x0FFFFFFF, IORESOURCE_MEM },
+    { "PCI Mem1",      0x10000000, 0x13FFFFFF, IORESOURCE_MEM },
+    { "PCI I/O",       0x14000000, 0x17FFFFFF                 },
+    { "PCI Mem2",      0x1A000000, 0x1BFFFFFF, IORESOURCE_MEM },
+    { "PCI Mem3",      0x1C000000, 0x1FBFFFFF, IORESOURCE_MEM },
+    { "Flash",         0x08000000, 0x0CFFFFFF                 },
+    { "Boot ROM",      0x1FC00000, 0x1FFFFFFF                 }
+};
+#endif
+
+
+void __init it8172_init_ram_resource(unsigned long memsize)
+{
+	it8172_resources.ram.end = memsize;
+}
+
+void __init it8172_setup(void)
+{
+#ifdef CONFIG_BLK_DEV_IT8172
+	unsigned short dsr;
+#endif
+	char *argptr;
+
+	argptr = prom_getcmdline();
+#ifdef CONFIG_SERIAL_CONSOLE
+	if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) {
+		strcpy(serial_console, "ttyS0,115200");
+		console_setup(serial_console, NULL);
+	}
+#endif	  
+
+	rtc_ops = &it8172_rtc_ops;
+
+	_machine_restart = it8172_restart;
+	_machine_halt = it8172_halt;
+	_machine_power_off = it8172_power_off;
+
+	/*
+	* IO/MEM resources. 
+	*
+	* revisit this area.
+	*/
+	mips_io_port_base = KSEG1;
+	ioport_resource.start = it8172_resources.pci_io.start;
+	ioport_resource.end = it8172_resources.pci_io.end;
+#ifdef CONFIG_IT8172_REVC
+	iomem_resource.start = it8172_resources.pci_mem.start;
+	iomem_resource.end = it8172_resources.pci_mem.end;
+#else
+	iomem_resource.start = it8172_resources.pci_mem0.start;
+	iomem_resource.end = it8172_resources.pci_mem3.end;
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+#endif
+
+#ifdef CONFIG_BLK_DEV_IT8172
+	/*
+	 * Pull IDE device out of standby mode.
+	 */
+	IT_IO_READ16(IT_PM_DSR, dsr);
+	dsr &= ~IT_PM_DSR_IDESB;
+	IT_IO_WRITE16(IT_PM_DSR, dsr);
+
+	ide_ops = &std_ide_ops;
+#endif
+
+#ifdef CONFIG_FB
+    conswitchp = &dummy_con;
+#endif
+
+	InitLPCInterface();
+
+#ifdef CONFIG_MIPS_ITE8172
+	if (SearchIT8712()) {
+		printk("Found IT8712 Super IO\n");
+		// enable IT8712 serial port
+		LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */
+		LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */
+#ifdef CONFIG_PC_KEYB
+		if (init_8712_keyboard()) {
+			printk("Unable to initialize keyboard\n");
+			LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */
+		}
+		else {
+			LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */
+			LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2);
+			LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3);
+
+			LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */
+
+			LPCSetConfig(0x4, 0x30, 0x1);
+			LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80);
+
+			if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) || 
+					(LPCGetConfig(LDN_MOUSE, 0x30) == 0)) 
+				printk("Error: keyboard or mouse not enabled\n");
+
+			kbd_ops = &std_kbd_ops;
+		}
+#endif
+	}
+	else {
+		printk("IT8712 Super IO not found\n");
+	}
+#endif
+
+#ifdef CONFIG_IT8172_CIR
+	{
+		unsigned long data;
+		//printk("Enabling CIR0\n");
+		IT_IO_READ16(IT_PM_DSR, data);
+		data &= ~IT_PM_DSR_CIR0SB;
+		IT_IO_WRITE16(IT_PM_DSR, data);
+		//printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data));
+	}
+#endif
+#ifdef CONFIG_IT8172_SCR0
+	{
+		unsigned i; 
+		/* Enable Smart Card Reader 0 */
+		/* First power it up */
+		IT_IO_READ16(IT_PM_DSR, i);
+		i &= ~IT_PM_DSR_SCR0SB;
+		IT_IO_WRITE16(IT_PM_DSR, i);
+		/* Then initialize its registers */
+		outb(( IT_SCR_SFR_GATE_UART_OFF     << IT_SCR_SFR_GATE_UART_BIT
+		      |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
+		      |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
+		      |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
+		      |IT_SCR_SFR_ENABLE_ON         << IT_SCR_SFR_ENABLE_BIT),
+		     IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR);
+		outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
+		     IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR);
+	}
+#endif /* CONFIG_IT8172_SCR0 */
+#ifdef CONFIG_IT8172_SCR1
+	{
+		unsigned i; 
+		/* Enable Smart Card Reader 1 */
+		/* First power it up */
+		IT_IO_READ16(IT_PM_DSR, i);
+		i &= ~IT_PM_DSR_SCR1SB;
+		IT_IO_WRITE16(IT_PM_DSR, i);
+		/* Then initialize its registers */
+		outb(( IT_SCR_SFR_GATE_UART_OFF     << IT_SCR_SFR_GATE_UART_BIT
+		      |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
+		      |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
+		      |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
+		      |IT_SCR_SFR_ENABLE_ON         << IT_SCR_SFR_ENABLE_BIT),
+		     IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR);
+		outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
+		     IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR);
+	}
+#endif /* CONFIG_IT8172_SCR1 */
+}
+
+
+#ifdef CONFIG_PC_KEYB
+/*
+ * According to the ITE Special BIOS Note for waking up the 
+ * keyboard controller...
+ */
+int init_8712_keyboard()
+{
+	unsigned int cmd_port = 0x14000064;
+	unsigned int data_port = 0x14000060;
+	unsigned char data;
+	int i;
+
+	printk("8712 keyboard init");
+
+	outb(0xaa, cmd_port); /* send self-test cmd */
+	i = 0;
+	while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */
+		i++;
+		if (i > 0xffffff)
+			return 1;
+	}
+
+	data = inb(data_port);
+	outb(0xcb, cmd_port); /* set ps2 mode */
+	while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+		i++;
+		if (i > 0xffffff)
+			return 1;
+	}
+	outb(0x01, data_port);
+	while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+		i++;
+		if (i > 0xffffff)
+			return 1;
+	}
+
+	outb(0x60, cmd_port); /* write 8042 command byte */
+	while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+		i++;
+		if (i > 0xffffff)
+			return 1;
+	}
+	outb(0x45, data_port); /* at interface, keyboard enabled, system flag */
+	while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+		i++;
+		if (i > 0xffffff)
+			return 1;
+	}
+
+	outb(0xae, cmd_port); /* enable interface */
+	return 0;
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/lpc.c linux/arch/mips/ite-boards/generic/lpc.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/lpc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/lpc.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,144 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	ITE Semi IT8712 Super I/O functions.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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 <asm/io.h>
+#include <asm/types.h>
+#include <asm/it8712.h>
+#include <asm/it8172/it8172.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+void LPCEnterMBPnP()
+{
+	int i;
+	unsigned char key[4] = {0x87, 0x01, 0x55, 0x55};
+
+	for (i = 0; i<4; i++)
+		outb(key[i], LPC_KEY_ADDR);
+
+}
+
+void LPCExitMBPnP()
+{
+	outb(0x02, LPC_KEY_ADDR);
+	outb(0x02, LPC_DATA_ADDR);
+}
+
+void LPCSetConfig(char LdnNumber, char Index, char data)
+{
+	LPCEnterMBPnP();				// Enter IT8712 MB PnP mode
+	outb(0x07, LPC_KEY_ADDR);
+	outb(LdnNumber, LPC_DATA_ADDR);
+	outb(Index, LPC_KEY_ADDR);	
+	outb(data, LPC_DATA_ADDR);
+	LPCExitMBPnP();
+}
+
+char LPCGetConfig(char LdnNumber, char Index)
+{
+	char rtn;
+
+	LPCEnterMBPnP();				// Enter IT8712 MB PnP mode
+	outb(0x07, LPC_KEY_ADDR);
+	outb(LdnNumber, LPC_DATA_ADDR);
+	outb(Index, LPC_KEY_ADDR);	
+	rtn = inb(LPC_DATA_ADDR);
+	LPCExitMBPnP();
+	return rtn;
+}
+
+int SearchIT8712()
+{
+	unsigned char Id1, Id2;
+	unsigned short Id;
+
+	LPCEnterMBPnP();
+	outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */
+	Id1 = inb(LPC_DATA_ADDR);
+	outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */
+	Id2 = inb(LPC_DATA_ADDR);
+	Id = (Id1 << 8) | Id2;
+	LPCExitMBPnP();
+	if (Id == 0x8712) 
+		return TRUE;
+	else
+		return FALSE;
+}
+
+void InitLPCInterface()
+{
+	unsigned char bus, dev_fn;
+	unsigned long data;
+
+	bus = 0;
+	dev_fn = 1<<3 | 4; 
+
+
+	/* pci cmd, SERR# Enable */
+	IT_WRITE(IT_CONFADDR,  
+		 (bus         << IT_BUSNUM_SHF)   |
+		 (dev_fn      << IT_FUNCNUM_SHF) |
+		 ((0x4 / 4) << IT_REGNUM_SHF));
+	IT_READ(IT_CONFDATA, data);
+	data |= 0x0100;
+	IT_WRITE(IT_CONFADDR,  
+		 (bus         << IT_BUSNUM_SHF)   |
+		 (dev_fn      << IT_FUNCNUM_SHF) |
+		 ((0x4 / 4) << IT_REGNUM_SHF));
+	IT_WRITE(IT_CONFDATA, data);
+
+	/* setup serial irq control register */
+	IT_WRITE(IT_CONFADDR,  
+		 (bus         << IT_BUSNUM_SHF)   |
+		 (dev_fn      << IT_FUNCNUM_SHF) |
+		 ((0x48 / 4) << IT_REGNUM_SHF));
+	IT_READ(IT_CONFDATA, data);
+	data  = (data & 0xffff00ff) | 0xc400;
+	IT_WRITE(IT_CONFADDR,  
+		 (bus         << IT_BUSNUM_SHF)   |
+		 (dev_fn      << IT_FUNCNUM_SHF) |
+		 ((0x48 / 4) << IT_REGNUM_SHF));
+	IT_WRITE(IT_CONFDATA, data);
+
+
+	/* Enable I/O Space Subtractive Decode */
+	/* default 0x4C is 0x3f220000 */
+	IT_WRITE(IT_CONFADDR,  
+		 (bus         << IT_BUSNUM_SHF)   |
+		 (dev_fn      << IT_FUNCNUM_SHF) |
+		 ((0x4C / 4) << IT_REGNUM_SHF));
+	IT_WRITE(IT_CONFDATA, 0x3f2200f3);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/pmon_prom.c linux/arch/mips/ite-boards/generic/pmon_prom.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/pmon_prom.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/pmon_prom.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,138 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *    PROM library initialisation code, assuming a version of
+ *    pmon is the boot code.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's 
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+/* #define DEBUG_CMDLINE */
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+typedef struct
+{
+    char *name;
+/*    char *val; */
+}t_env_var;
+
+
+char * __init prom_getcmdline(void)
+{
+	return &(arcs_cmdline[0]);
+}
+
+void  __init prom_init_cmdline(void)
+{
+	char *cp;
+	int actr;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	cp = &(arcs_cmdline[0]);
+	while(actr < prom_argc) {
+	        strcpy(cp, prom_argv[actr]);
+		cp += strlen(prom_argv[actr]);
+		*cp++ = ' ';
+		actr++;
+	}
+	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+		--cp;
+	*cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+	/*
+	 * Return a pointer to the given environment variable.
+	 * Environment variables are stored in the form of "memsize=64".
+	 */
+
+	t_env_var *env = (t_env_var *)prom_envp;
+	int i;
+
+	i = strlen(envname);
+
+	while(env->name) {
+		if(strncmp(envname, env->name, i) == 0) {
+			return(env->name + strlen(envname) + 1);
+		}
+		env++;
+	}
+	return(NULL);
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+	if(c >= '0' && c <= '9')
+	return c - '0';
+	if(c >= 'a' && c <= 'f')
+	return c - 'a' + 10;
+	return 0; /* foo */
+}
+
+int __init page_is_ram(unsigned long pagenr)
+{
+    return 1;
+}
+
+void prom_free_prom_memory (void)
+{
+}
+
+unsigned long __init prom_get_memsize(void)
+{
+	char *memsize_str;
+	unsigned int memsize;
+
+	memsize_str = prom_getenv("memsize");
+	if (!memsize_str) {
+		printk("memsize unknown: setting to 32MB\n");
+		memsize = 32; 
+	} else {
+#ifdef DEBUG
+		printk("prom_memsize: %s\n", memsize_str);
+#endif
+		memsize = simple_strtol(memsize_str, NULL, 0);
+	}
+	return memsize;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/puts.c linux/arch/mips/ite-boards/generic/puts.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/puts.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/puts.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,144 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Low level uart routines to directly access a 16550 uart.
+ *
+ * Copyright 2000,2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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/types.h>
+
+#define SERIAL_BASE   0xB4011800 /* it8172 */
+#define SER_CMD       5
+#define SER_DATA      0x00
+#define TX_BUSY       0x20
+
+#define TIMEOUT       0xffff
+#undef SLOW_DOWN
+
+static const char digits[16] = "0123456789abcdef";
+static volatile unsigned char * const com1 = (unsigned char *)SERIAL_BASE;
+
+
+#ifdef SLOW_DOWN
+static inline void slow_down()
+{
+    int k;
+    for (k=0; k<10000; k++);
+}
+#else
+#define slow_down()
+#endif
+
+void
+putch(const unsigned char c)
+{
+    unsigned char ch;
+    int i = 0;
+
+    do {
+        ch = com1[SER_CMD];
+        slow_down();
+        i++;
+        if (i>TIMEOUT) {
+            break;
+        }
+    } while (0 == (ch & TX_BUSY));
+    com1[SER_DATA] = c;
+}
+
+void
+puts(unsigned char *cp)
+{
+    unsigned char ch;
+    int i = 0;
+
+    while (*cp) {
+        do {
+             ch = com1[SER_CMD];
+            slow_down();
+            i++;
+            if (i>TIMEOUT) {
+                break;
+            }
+        } while (0 == (ch & TX_BUSY));
+        com1[SER_DATA] = *cp++;
+    }
+    putch('\r');
+    putch('\n');
+}
+
+void
+fputs(unsigned char *cp)
+{
+    unsigned char ch;
+    int i = 0;
+
+    while (*cp) {
+
+        do {
+             ch = com1[SER_CMD];
+             slow_down();
+            i++;
+            if (i>TIMEOUT) {
+                break;
+            }
+        } while (0 == (ch & TX_BUSY));
+        com1[SER_DATA] = *cp++;
+    }
+}
+
+
+void
+put64(uint64_t ul)
+{
+    int cnt;
+    unsigned ch;
+
+    cnt = 16;            /* 16 nibbles in a 64 bit long */
+    putch('0');
+    putch('x');
+    do {
+        cnt--;
+        ch = (unsigned char)(ul >> cnt * 4) & 0x0F;
+                putch(digits[ch]);
+    } while (cnt > 0);
+}
+
+void
+put32(unsigned u)
+{
+    int cnt;
+    unsigned ch;
+
+    cnt = 8;            /* 8 nibbles in a 32 bit long */
+    putch('0');
+    putch('x');
+    do {
+        cnt--;
+        ch = (unsigned char)(u >> cnt * 4) & 0x0F;
+                putch(digits[ch]);
+    } while (cnt > 0);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/reset.c linux/arch/mips/ite-boards/generic/reset.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/reset.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/reset.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,61 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	ITE 8172 reset routines.
+ *
+ * Copyright (C) 1997, 2001 Ralf Baechle
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+
+void it8172_restart(char *command)
+{
+	set_cp0_status(ST0_BEV | ST0_ERL);
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+	flush_cache_all();
+	write_32bit_cp0_register(CP0_WIRED, 0);
+	__asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+}
+
+void it8172_halt(void)
+{
+	printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+	while (1)
+		__asm__(".set\tmips3\n\t"
+	                "wait\n\t"
+			".set\tmips0");
+}
+
+void it8172_power_off(void)
+{
+	it8172_halt();
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/generic/time.c linux/arch/mips/ite-boards/generic/time.c
--- v2.4.3/linux/arch/mips/ite-boards/generic/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/generic/time.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,378 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Setting up the clock on the MIPS boards.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/it8172/it8172_int.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+extern void enable_cpu_timer(void);
+extern volatile unsigned long wall_jiffies;
+extern rwlock_t xtime_lock;
+
+unsigned long missed_heart_beats = 0;
+static long last_rtc_update = 0;
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur;    /* What counter should be at next timer irq */
+static unsigned int timer_tick_count=0;
+
+static inline void ack_r4ktimer(unsigned long newval)
+{
+	write_32bit_cp0_register(CP0_COMPARE, newval);
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ *      sets the minutes. Usually you won't notice until after reboot!
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned char save_control, save_freq_select;
+
+	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+	cmos_minutes = CMOS_READ(RTC_MINUTES);
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;		/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		CMOS_WRITE(real_seconds,RTC_SECONDS);
+		CMOS_WRITE(real_minutes,RTC_MINUTES);
+	} else {
+		printk(KERN_WARNING
+		       "set_rtc_mmss: can't update from %d to %d\n",
+		       cmos_minutes, real_minutes);
+ 		retval = -1;
+	}
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	return retval;
+}
+
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around.  This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+void mips_timer_interrupt(struct pt_regs *regs)
+{
+	if (r4k_offset == 0)
+		goto null;
+
+	do {
+		kstat.irqs[0][MIPS_CPU_TIMER_IRQ]++;
+		do_timer(regs);
+
+		/* Historical comment/code:
+ 		 * RTC time of day s updated approx. every 11 
+ 		 * minutes.  Because of how the numbers work out 
+ 		 * we need to make absolutely sure we do this update
+ 		 * within 500ms before the * next second starts, 
+ 		 * thus the following code.
+ 		 */
+		read_lock(&xtime_lock);
+		if ((time_status & STA_UNSYNC) == 0 
+		    && xtime.tv_sec > last_rtc_update + 660 
+		    && xtime.tv_usec >= 500000 - (tick >> 1) 
+		    && xtime.tv_usec <= 500000 + (tick >> 1))
+			if (set_rtc_mmss(xtime.tv_sec) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else {
+				/* do it again in 60 s */
+	    			last_rtc_update = xtime.tv_sec - 600; 
+			}
+		read_unlock(&xtime_lock);
+
+		r4k_cur += r4k_offset;
+		ack_r4ktimer(r4k_cur);
+
+	} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
+	         - r4k_cur) < 0x7fffffff);
+
+	return;
+
+null:
+	ack_r4ktimer(0);
+}
+
+/* 
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick. 
+ * Use the RTC to calculate offset.
+ */
+static unsigned long __init cal_r4koff(void)
+{
+	unsigned long count;
+	unsigned int flags;
+
+	__save_and_cli(flags);
+
+	/* Start counter exactly on falling edge of update flag */
+	while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+	/* Start r4k counter. */
+	write_32bit_cp0_register(CP0_COUNT, 0);
+
+	/* Read counter exactly on falling edge of update flag */
+	while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+	count = read_32bit_cp0_register(CP0_COUNT);
+
+	/* restore interrupts */
+	__restore_flags(flags);
+		
+	return (count / HZ);
+}
+
+static unsigned long __init get_mips_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned char save_control;
+
+	save_control = CMOS_READ(RTC_CONTROL);
+
+	/* Freeze it. */
+	CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
+
+	/* Read regs. */
+	sec = CMOS_READ(RTC_SECONDS);
+	min = CMOS_READ(RTC_MINUTES);
+	hour = CMOS_READ(RTC_HOURS);
+
+	if (!(save_control & RTC_24H))
+	{
+		if ((hour & 0xf) == 0xc)
+		        hour &= 0x80;
+	        if (hour & 0x80)
+		        hour = (hour & 0xf) + 12;     
+	}
+	day = CMOS_READ(RTC_DAY_OF_MONTH);
+	mon = CMOS_READ(RTC_MONTH);
+	year = CMOS_READ(RTC_YEAR);
+
+	/* Unfreeze clock. */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+
+	if ((year += 1900) < 1970)
+	        year += 100;
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+void __init time_init(void)
+{
+        unsigned int est_freq, flags;
+
+        /* Set Data mode - binary. */ 
+        CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
+
+	printk("calculating r4koff... ");
+	r4k_offset = cal_r4koff();
+	printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+	est_freq = 2*r4k_offset*HZ;	
+	est_freq += 5000;    /* round */
+	est_freq -= est_freq%10000;
+	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 
+	       (est_freq%1000000)*100/1000000);
+	r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+
+	write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
+
+	enable_cpu_timer();
+
+	/* Read time from the RTC chipset. */
+	write_lock_irqsave (&xtime_lock, flags);
+	xtime.tv_sec = get_mips_time();
+	xtime.tv_usec = 0;
+	write_unlock_irqrestore(&xtime_lock, flags);
+}
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+
+/* Cycle counter value at the previous timer interrupt.. */
+
+static unsigned int timerhi = 0, timerlo = 0;
+
+/*
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+
+	/* Last jiffy when do_fast_gettimeoffset() was called. */
+	static unsigned long last_jiffies=0;
+	unsigned long quotient;
+
+	/*
+	 * Cached "1/(clocks per usec)*2^32" value.
+	 * It has to be recalculated once each jiffy.
+	 */
+	static unsigned long cached_quotient=0;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (tmp && last_jiffies != tmp) {
+		last_jiffies = tmp;
+		__asm__(".set\tnoreorder\n\t"
+			".set\tnoat\n\t"
+			".set\tmips3\n\t"
+			"lwu\t%0,%2\n\t"
+			"dsll32\t$1,%1,0\n\t"
+			"or\t$1,$1,%0\n\t"
+			"ddivu\t$0,$1,%3\n\t"
+			"mflo\t$1\n\t"
+			"dsll32\t%0,%4,0\n\t"
+			"nop\n\t"
+			"ddivu\t$0,%0,$1\n\t"
+			"mflo\t%0\n\t"
+			".set\tmips0\n\t"
+			".set\tat\n\t"
+			".set\treorder"
+			:"=&r" (quotient)
+			:"r" (timerhi),
+			 "m" (timerlo),
+			 "r" (tmp),
+			 "r" (USECS_PER_JIFFY)
+			:"$1");
+		cached_quotient = quotient;
+	}
+
+	/* Get last timer tick in absolute kernel time */
+	count = read_32bit_cp0_register(CP0_COUNT);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+
+	__asm__("multu\t%1,%2\n\t"
+		"mfhi\t%0"
+		:"=r" (res)
+		:"r" (count),
+		 "r" (quotient));
+
+	/*
+ 	 * Due to possible jiffies inconsistencies, we need to check 
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY-1;
+
+	return res;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned int flags;
+
+	read_lock_irqsave (&xtime_lock, flags);
+	*tv = xtime;
+	tv->tv_usec += do_fast_gettimeoffset();
+
+	/*
+	 * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
+	 * is nonzero if the timer bottom half hasnt executed yet.
+	 */
+	if (jiffies - wall_jiffies)
+		tv->tv_usec += USECS_PER_JIFFY;
+
+	read_unlock_irqrestore (&xtime_lock, flags);
+
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	write_lock_irq (&xtime_lock);
+
+	/* This is revolting. We need to set the xtime.tv_usec correctly.
+	 * However, the value in this location is is value at the last tick.
+	 * Discover what correction gettimeofday would have done, and then
+	 * undo it!
+	 */
+	tv->tv_usec -= do_fast_gettimeoffset();
+
+	if (tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+
+	xtime = *tv;
+	time_adjust = 0;		/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+
+	write_unlock_irq (&xtime_lock);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/Makefile linux/arch/mips/ite-boards/qed-4n-s01b/Makefile
--- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/qed-4n-s01b/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,37 @@
+#
+#  Copyright 2000 MontaVista Software Inc.
+#  Author: MontaVista Software, Inc.
+#     	ppopov@mvista.com or support@mvista.com
+#
+# Makefile for the ITE 8172 (qed-4n-s01b) board, board
+# specific files.
+#
+# 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).
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+all: ite.o
+
+O_TARGET := ite.o
+
+obj-y := init.o 
+
+ifdef CONFIG_PCI
+obj-y += pci_fixup.o
+endif
+
+ifdef CONFIG_BLK_DEV_INITRD
+obj-y += le_ramdisk.o
+endif
+
+
+dep:
+	$(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/README linux/arch/mips/ite-boards/qed-4n-s01b/README
--- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/README	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/qed-4n-s01b/README	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,2 @@
+This is an ITE (www.iteusa.com) eval board for the ITE 8172G
+system controller, with a QED 5231 CPU.
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/init.c linux/arch/mips/ite-boards/qed-4n-s01b/init.c
--- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/init.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/qed-4n-s01b/init.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,87 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172/QED5231 board setup.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_dbg.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+extern char _end;
+extern void  __init prom_init_cmdline(void);
+extern unsigned long __init prom_get_memsize(void);
+extern void __init it8172_init_ram_resource(unsigned long memsize);
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
+
+
+int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
+{
+	unsigned long mem_size, free_start, free_end, bootmap_size;
+	unsigned long pcicr;
+
+	prom_argc = argc;
+	prom_argv = argv;
+	prom_envp = envp;
+
+	puts("ITE board running...");
+
+	mips_machgroup = MACH_GROUP_ITE;
+	mips_machtype = MACH_QED_4N_S01B;  /* ITE board name/number */
+
+	prom_init_cmdline();
+	mem_size = prom_get_memsize();
+
+	printk("Memory size: %dMB\n", (unsigned)mem_size);
+
+	mem_size <<= 20; /* MB */
+
+	/*
+	 * make the entire physical memory visible to pci bus masters
+	 */
+	IT_READ(IT_MC_PCICR, pcicr);
+	pcicr &= ~0x1f; 
+	pcicr |= (mem_size - 1) >> 22;
+	IT_WRITE(IT_MC_PCICR, pcicr);
+
+	it8172_init_ram_resource(mem_size);
+	add_memory_region(0, 20 << 20, BOOT_MEM_RAM);
+
+	return 0;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c
--- v2.4.3/linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,197 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Board specific pci fixups.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+#include <asm/it8172/it8172_int.h>
+
+void __init board_int_line_fixup(struct pci_dev *dev)     
+{
+	unsigned int slot, func;
+	unsigned char pin;
+        const int internal_func_irqs[7] = {
+            IT8172_AC97_IRQ,
+            IT8172_DMA_IRQ,
+            IT8172_CDMA_IRQ,
+            IT8172_USB_IRQ,
+            IT8172_BRIDGE_MASTER_IRQ,
+            IT8172_IDE_IRQ,
+            IT8172_MC68K_IRQ
+        };
+
+#ifdef DEBUG
+	printk("board_int_line_fixup bus %d\n", dev->bus->number);
+#endif
+	if (dev->bus->number != 0)
+		return;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
+#ifdef DEBUG
+	pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
+#endif
+
+	slot = PCI_SLOT(dev->devfn);
+        func = PCI_FUNC(dev->devfn);
+
+	switch (slot) {
+                case 0x01:
+                    /*
+                     * Internal device 1 is actually 7 different internal
+                     * devices on the IT8172G (a multi-function device).
+                     */
+                    if (func < 7)
+                        dev->irq = internal_func_irqs[func];
+                    break;
+		case 0x10:
+			switch (pin) {
+				case 1: /* pin A */
+					dev->irq = IT8172_PCI_INTA_IRQ;
+					break;
+				case 2: /* pin B */
+					dev->irq = IT8172_PCI_INTB_IRQ;
+					break;
+				case 3: /* pin C */
+					dev->irq = IT8172_PCI_INTC_IRQ;
+					break;
+				case 4: /* pin D */
+					dev->irq = IT8172_PCI_INTD_IRQ;
+					break;
+				default:
+					dev->irq = 0xff; 
+					break;
+
+			}
+			break;
+		case 0x11:
+			switch (pin) {
+				case 1: /* pin A */
+					dev->irq = IT8172_PCI_INTA_IRQ;
+					break;
+				case 2: /* pin B */
+					dev->irq = IT8172_PCI_INTB_IRQ;
+					break;
+				case 3: /* pin C */
+					dev->irq = IT8172_PCI_INTC_IRQ;
+					break;
+				case 4: /* pin D */
+					dev->irq = IT8172_PCI_INTD_IRQ;
+					break;
+				default:
+					dev->irq = 0xff; 
+					break;
+
+			}
+			break;
+		case 0x12:
+			switch (pin) {
+				case 1: /* pin A */
+					dev->irq = IT8172_PCI_INTB_IRQ;
+					break;
+				case 2: /* pin B */
+					dev->irq = IT8172_PCI_INTC_IRQ;
+					break;
+				case 3: /* pin C */
+					dev->irq = IT8172_PCI_INTD_IRQ;
+					break;
+				case 4: /* pin D */
+					dev->irq = IT8172_PCI_INTA_IRQ;
+					break;
+				default:
+					dev->irq = 0xff; 
+					break;
+
+			}
+			break;
+		case 0x13:
+			switch (pin) {
+				case 1: /* pin A */
+					dev->irq = IT8172_PCI_INTC_IRQ;
+					break;
+				case 2: /* pin B */
+					dev->irq = IT8172_PCI_INTD_IRQ;
+					break;
+				case 3: /* pin C */
+					dev->irq = IT8172_PCI_INTA_IRQ;
+					break;
+				case 4: /* pin D */
+					dev->irq = IT8172_PCI_INTB_IRQ;
+					break;
+				default:
+					dev->irq = 0xff; 
+					break;
+
+			}
+			break;
+		case 0x14:
+			switch (pin) {
+				case 1: /* pin A */
+					dev->irq = IT8172_PCI_INTD_IRQ;
+					break;
+				case 2: /* pin B */
+					dev->irq = IT8172_PCI_INTA_IRQ;
+					break;
+				case 3: /* pin C */
+					dev->irq = IT8172_PCI_INTB_IRQ;
+					break;
+				case 4: /* pin D */
+					dev->irq = IT8172_PCI_INTC_IRQ;
+					break;
+				default:
+					dev->irq = 0xff; 
+					break;
+
+			}
+			break;
+		default:
+			return;
+	}
+
+#ifdef DEBUG
+	printk("irq fixup: slot %d, vendor %x, int line %d, int number %d\n",
+			slot, vendor, pin, dev->irq);
+#endif
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, board_int_line_fixup },
+	{ 0 }
+};
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/jazz/Makefile linux/arch/mips/jazz/Makefile
--- v2.4.3/linux/arch/mips/jazz/Makefile	Sat May 13 08:29:14 2000
+++ linux/arch/mips/jazz/Makefile	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.5 1999/01/03 17:50:47 ralf Exp $
 #
 # Makefile for the Jazz family specific parts of the kernel
 #
@@ -8,17 +7,17 @@
 #
 
 .S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
+	$(CPP) $(CFLAGS) $< -o $@
 .S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
+	$(CC) $(CFLAGS) -c $< -o $@
 
 all: jazz.o
+
 O_TARGET := jazz.o
-O_OBJS	 := int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o floppy-jazz.o \
-	    kbd-jazz.o
 
-int-handler.o: int-handler.S
+obj-y	 := int-handler.o irq.o jazzdma.o reset.o rtc-jazz.o setup.o \
+	    floppy-jazz.o kbd-jazz.o
 
-clean:
+int-handler.o: int-handler.S
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/branch.c linux/arch/mips/kernel/branch.c
--- v2.4.3/linux/arch/mips/kernel/branch.c	Wed Dec 10 10:31:09 1997
+++ linux/arch/mips/kernel/branch.c	Fri Apr 13 20:26:07 2001
@@ -5,15 +5,19 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 1997 by Ralf Baechle
+ * Copyright (C) 1996, 97, 2000 by Ralf Baechle
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/branch.h>
+#include <asm/cpu.h>
 #include <asm/inst.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+#include <asm/processor.h>
 
 /*
  * Compute the return address and do emulate branch simulation, if required.
@@ -65,7 +69,7 @@
 		switch (insn.i_format.rt) {
 	 	case bltz_op:
 		case bltzl_op:
-			if (regs->regs[insn.i_format.rs] < 0)
+			if ((long)regs->regs[insn.i_format.rs] < 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -74,7 +78,7 @@
 
 		case bgez_op:
 		case bgezl_op:
-			if (regs->regs[insn.i_format.rs] >= 0)
+			if ((long)regs->regs[insn.i_format.rs] >= 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -84,7 +88,7 @@
 		case bltzal_op:
 		case bltzall_op:
 			regs->regs[31] = epc + 8;
-			if (regs->regs[insn.i_format.rs] < 0)
+			if ((long)regs->regs[insn.i_format.rs] < 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -94,7 +98,7 @@
 		case bgezal_op:
 		case bgezall_op:
 			regs->regs[31] = epc + 8;
-			if (regs->regs[insn.i_format.rs] >= 0)
+			if ((long)regs->regs[insn.i_format.rs] >= 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -142,7 +146,7 @@
 	case blez_op: /* not really i_format */
 	case blezl_op:
 		/* rt field assumed to be zero */
-		if (regs->regs[insn.i_format.rs] <= 0)
+		if ((long)regs->regs[insn.i_format.rs] <= 0)
 			epc = epc + 4 + (insn.i_format.simmediate << 2);
 		else
 			epc += 8;
@@ -152,7 +156,7 @@
 	case bgtz_op:
 	case bgtzl_op:
 		/* rt field assumed to be zero */
-		if (regs->regs[insn.i_format.rs] > 0)
+		if ((long)regs->regs[insn.i_format.rs] > 0)
 			epc = epc + 4 + (insn.i_format.simmediate << 2);
 		else
 			epc += 8;
@@ -163,6 +167,11 @@
 	 * And now the FPA/cp1 branch instructions.
 	 */
 	case cop1_op:
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+		if(!(mips_cpu.options & MIPS_CPU_FPU))
+			fcr31 = current->thread.fpu.soft.sr;
+		else
+#endif
 		asm ("cfc1\t%0,$31":"=r" (fcr31));
 		bit = (insn.i_format.rt >> 2);
 		bit += (bit != 0);
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.4.3/linux/arch/mips/kernel/process.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips/kernel/process.c	Fri Apr 13 20:26:07 2001
@@ -1,12 +1,12 @@
-/* $Id: process.c,v 1.18 2000/01/29 01:41:59 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994 - 1999 by Ralf Baechle and others.
+ * Copyright (C) 1994 - 2000 by Ralf Baechle and others.
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -21,6 +21,7 @@
 #include <linux/a.out.h>
 
 #include <asm/bootinfo.h>
+#include <asm/cpu.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/mipsregs.h>
@@ -55,7 +56,7 @@
 {
 	/* Forget lazy fpu state */
 	if (last_task_used_math == current) {
-		set_cp0_status(ST0_CU1, ST0_CU1);
+		set_cp0_status(ST0_CU1);
 		__asm__ __volatile__("cfc1\t$0,$31");
 		last_task_used_math = NULL;
 	}
@@ -65,7 +66,7 @@
 {
 	/* Forget lazy fpu state */
 	if (last_task_used_math == current) {
-		set_cp0_status(ST0_CU1, ST0_CU1);
+		set_cp0_status(ST0_CU1);
 		__asm__ __volatile__("cfc1\t$0,$31");
 		last_task_used_math = NULL;
 	}
@@ -81,9 +82,13 @@
 
 	childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
 
-	if (last_task_used_math == current) {
-		set_cp0_status(ST0_CU1, ST0_CU1);
-		save_fp(p);
+	if (last_task_used_math == current)
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+		if (mips_cpu.options & MIPS_CPU_FPU)
+#endif
+	{
+			set_cp0_status(ST0_CU1);
+			save_fp(p);
 	}
 	/* set up new TSS. */
 	childregs = (struct pt_regs *) childksp - 1;
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.4.3/linux/arch/mips/kernel/ptrace.c	Sun Jul  9 22:18:15 2000
+++ linux/arch/mips/kernel/ptrace.c	Fri Apr 13 20:26:07 2001
@@ -1,14 +1,16 @@
-/* $Id: ptrace.c,v 1.17 1999/09/28 22:25:47 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Copyright (C) 1992 Ross Biro
  * Copyright (C) Linus Torvalds
- * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
  * Copyright (C) 1996 David S. Miller
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999 MIPS Technologies, Inc.
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -24,6 +26,8 @@
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
 
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
@@ -131,13 +135,22 @@
 			break;
 		case FPR_BASE ... FPR_BASE + 31:
 			if (child->used_math) {
+			        unsigned long long *fregs
+					= (unsigned long long *)
+					    &child->thread.fpu.hard.fp_regs[0];
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+			    if(!(mips_cpu.options & MIPS_CPU_FPU)) {
+				    fregs = (unsigned long long *)
+					&child->thread.fpu.soft.regs[0];
+			    } else 
+#endif
 				if (last_task_used_math == child) {
 					enable_cp1();
 					save_fp(child);
 					disable_cp1();
 					last_task_used_math = NULL;
 				}
-				tmp = child->thread.fpu.hard.fp_regs[addr - 32];
+				tmp = (unsigned long) fregs[(addr - 32)];
 			} else {
 				tmp = -1;	/* FP not yet used  */
 			}
@@ -158,6 +171,11 @@
 			tmp = regs->lo;
 			break;
 		case FPC_CSR:
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+			if(!(mips_cpu.options & MIPS_CPU_FPU))
+				tmp = child->thread.fpu.soft.sr;
+			else
+#endif
 			tmp = child->thread.fpu.hard.control;
 			break;
 		case FPC_EIR: {	/* implementation / version register */
@@ -198,9 +216,17 @@
 			regs->regs[addr] = data;
 			break;
 		case FPR_BASE ... FPR_BASE + 31: {
-			unsigned int *fregs;
+			unsigned long long *fregs;
+			fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0];
 			if (child->used_math) {
-				if (last_task_used_math == child) {
+				if (last_task_used_math == child)
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+				    if(!(mips_cpu.options & MIPS_CPU_FPU)) {
+					fregs = (unsigned long long *)
+					    &child->thread.fpu.soft.regs[0];
+				    } else
+#endif
+				{
 					enable_cp1();
 					save_fp(child);
 					disable_cp1();
@@ -213,7 +239,6 @@
 				       sizeof(child->thread.fpu.hard));
 				child->thread.fpu.hard.control = 0;
 			}
-			fregs = child->thread.fpu.hard.fp_regs;
 			fregs[addr - FPR_BASE] = data;
 			break;
 		}
@@ -227,6 +252,11 @@
 			regs->lo = data;
 			break;
 		case FPC_CSR:
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+			if(!(mips_cpu.options & MIPS_CPU_FPU)) 
+				child->thread.fpu.soft.sr = data;
+			else
+#endif
 			child->thread.fpu.hard.control = data;
 			break;
 		default:
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/r2300_fpu.S linux/arch/mips/kernel/r2300_fpu.S
--- v2.4.3/linux/arch/mips/kernel/r2300_fpu.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/kernel/r2300_fpu.S	Fri Apr 13 20:26:07 2001
@@ -1,7 +1,4 @@
-/* $Id: r2300_fpu.S,v 1.6 1999/08/09 19:43:14 harald Exp $
- *
- * r2300_fpu.S: Save/restore floating point context for signal handlers.
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -30,7 +27,7 @@
 	.set	noreorder
 	.set	mips1
 	/* Save floating point context */
-LEAF(save_fp_context)
+LEAF(_save_fp_context)
 	li	v0, 0					# assume success
 	cfc1	t1,fcr31
 	EX(swc1	$f0,(SC_FPREGS+0)(a0))
@@ -65,13 +62,13 @@
 	EX(swc1	$f29,(SC_FPREGS+232)(a0))
 	EX(swc1	$f30,(SC_FPREGS+240)(a0))
 	EX(swc1	$f31,(SC_FPREGS+248)(a0))
-	EX(sw	t1,SC_FPC_CSR(a0))
+	EX(sw	t1,(SC_FPC_CSR)(a0))
 	cfc1	t0,$0				# implementation/version
 	jr	ra
 	.set	nomacro
-	 EX(sw	t0,SC_FPC_EIR(a0))
+	 EX(sw	t0,(SC_FPC_EIR)(a0))
 	.set	macro
-	END(save_fp_context)
+	END(_save_fp_context)
 
 /*
  * Restore FPU state:
@@ -82,9 +79,9 @@
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
-LEAF(restore_fp_context)
+LEAF(_restore_fp_context)
 	li	v0, 0					# assume success
-	EX(lw t0,SC_FPC_CSR(a0))
+	EX(lw t0,(SC_FPC_CSR)(a0))
 	EX(lwc1	$f0,(SC_FPREGS+0)(a0))
 	EX(lwc1	$f1,(SC_FPREGS+8)(a0))
 	EX(lwc1	$f2,(SC_FPREGS+16)(a0))
@@ -119,7 +116,7 @@
 	EX(lwc1	$f31,(SC_FPREGS+248)(a0))
 	jr	ra
 	 ctc1	t0,fcr31
-	END(restore_fp_context)
+	END(_restore_fp_context)
 
 	.type	fault@function
 	.ent	fault
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/r2300_switch.S linux/arch/mips/kernel/r2300_switch.S
--- v2.4.3/linux/arch/mips/kernel/r2300_switch.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/kernel/r2300_switch.S	Fri Apr 13 20:26:07 2001
@@ -9,7 +9,7 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
  * Further modifications to make this work:
- * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 1998-2000 Harald Koerfgen
  */
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
@@ -30,13 +30,11 @@
 	.align	5
 
 /*
- * task_struct *r4xx0_resume(task_struct *prev,
- *                           task_struct *next)
+ * task_struct *resume(task_struct *prev,
+ *                     task_struct *next)
  */
 LEAF(resume)
-	.set	reorder
 	mfc0	t1, CP0_STATUS
-	.set	noreorder
 	sw	t1, THREAD_STATUS(a0)
 	CPU_SAVE_NONSCRATCH(a0)
 	sw	ra, THREAD_REG31(a0)
@@ -57,8 +55,10 @@
 	and	a2, a3
 	or	a2, t1
 	mtc0	a2, CP0_STATUS
+	.set	noreorder
 	jr	ra
 	 move	v0, a0
+	.set	reorder
 	END(resume)
 
 /*
@@ -74,19 +74,16 @@
 	or	t0, t3
 	mtc0	t0, CP0_STATUS
 
+	.set	noreorder
 	beqz	a0, 2f				# Save floating point state
 	 nor	t3, zero, t3
 	.set	reorder
 	lw	t1, ST_OFF(a0)			# last thread looses fpu
-	.set	noreorder
 	and	t1, t3
 	sw	t1, ST_OFF(a0)
-	swc1	$f0, (THREAD_FPU + 0x00)(a0)
 	FPU_SAVE_SINGLE(a0, t1)			# clobbers t1
 
 2:
-	lwc1	$f0, (THREAD_FPU + 0x00)($28)
-	.set	reorder
 	FPU_RESTORE_SINGLE($28, t0)		# clobbers t0
 	jr	ra
 	END(lazy_fpu_switch)
@@ -94,14 +91,20 @@
 /*
  * Save a thread's fp context.
  */
-	.set	noreorder
 LEAF(save_fp)
 	FPU_SAVE_SINGLE(a0, t1)			# clobbers t1
 	jr	ra
-	 swc1	$f0, (THREAD_FPU + 0x00)(a0)
 	END(save_fp)
 
 /*
+ * Restore a thread's fp context.
+ */
+LEAF(restore_fp)
+	FPU_RESTORE_SINGLE(a0, t1)		# clobbers t1
+	jr	ra
+	END(restore_fp)
+
+/*
  * Load the FPU with signalling NANS.  This bit pattern we're using has
  * the property that no matter wether considered as single or as double
  * precission represents signaling NANS.
@@ -153,6 +156,8 @@
 	mtc1	t0, $f28
 	mtc1	t0, $f29
 	mtc1	t0, $f30
+	.set	noreorder
 	jr	ra
 	 mtc1	t0, $f31
+	.set	reorder
 	END(init_fpu)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/r4k_fpu.S linux/arch/mips/kernel/r4k_fpu.S
--- v2.4.3/linux/arch/mips/kernel/r4k_fpu.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/kernel/r4k_fpu.S	Fri Apr 13 20:26:07 2001
@@ -1,15 +1,15 @@
-/* $Id: r4k_fpu.S,v 1.8 1999/09/28 22:25:47 ralf Exp $
- *
- * r4k_fpu.S: Save/restore floating point context for signal handlers.
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 1998 by Ralf Baechle
+ * Copyright (C) 1996, 1998, 2000 by Ralf Baechle
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ *  Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.
  */
 #include <asm/asm.h>
 #include <asm/errno.h>
@@ -19,7 +19,7 @@
 #include <asm/regdef.h>
 
 #define EX(a,b)							\
-9:	a,##b;							\
+9:	a,b;							\
 	.section __ex_table,"a";				\
 	PTR	9b, fault;					\
 	.previous
@@ -27,7 +27,7 @@
 	.set	noreorder
 	.set	mips3
 	/* Save floating point context */
-LEAF(save_fp_context)
+LEAF(_save_fp_context)
 	li	v0, 0					# assume success
 	cfc1	t1,fcr31
 
@@ -55,7 +55,7 @@
 	.set	nomacro
 	 EX(sw	t0,SC_FPC_EIR(a0))
 	.set	macro
-	END(save_fp_context)
+	END(_save_fp_context)
 
 /*
  * Restore FPU state:
@@ -66,7 +66,7 @@
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
-LEAF(restore_fp_context)
+LEAF(_restore_fp_context)
 	li	v0, 0					# assume success
 	EX(lw	t0,SC_FPC_CSR(a0))
 
@@ -92,7 +92,7 @@
 	EX(ldc1	$f30,(SC_FPREGS+240)(a0))
 	jr	ra
 	 ctc1	t0,fcr31
-	END(restore_fp_context)
+	END(_restore_fp_context)
 
 	.type	fault@function
 	.ent	fault
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S
--- v2.4.3/linux/arch/mips/kernel/r4k_misc.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/kernel/r4k_misc.S	Fri Apr 13 20:26:07 2001
@@ -7,6 +7,13 @@
  * Multi-cpu abstraction and reworking:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  */
+/**************************************************************************
+ *  14 Nov, 2000.
+ *  Made support for MIPS32 CPUs.
+ *
+ *  Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *************************************************************************/
 #include <asm/asm.h>
 #include <asm/current.h>
 #include <asm/offset.h>
@@ -102,7 +109,6 @@
 	sw	pte, (ptr);
 
 	.set	noreorder
-	.set	mips3
 
 /*
  * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
@@ -147,7 +153,9 @@
 	 tlbwi
 1:
 	nop
+	.set	mips3	
 	eret
+	.set	mips0
 #endif
 
 nopage_tlbl:
@@ -169,7 +177,9 @@
 	 tlbwi
 1:
 	nop
+	.set	mips3	
 	eret
+	.set	mips0
 #endif
 
 nopage_tlbs:
@@ -201,7 +211,9 @@
 	 tlbwi
 1:
 	nop
+	.set	mips3
 	eret
+	.set	mips0
 #endif
 
 nowrite_mod:
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/r4k_switch.S linux/arch/mips/kernel/r4k_switch.S
--- v2.4.3/linux/arch/mips/kernel/r4k_switch.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/kernel/r4k_switch.S	Fri Apr 13 20:26:07 2001
@@ -9,6 +9,14 @@
  * Copyright (C) 1994, 1995, 1996, by Andreas Busse
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
+/**************************************************************************
+ *  13 Nov, 2000.
+ *  Made support for MIPS32 CPUs and restoring of fp registers.
+ *
+ *  Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *************************************************************************/
+	
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
@@ -24,8 +32,6 @@
 
 #include <asm/asmmacro.h>
 
-	.set	mips3
-
 /*
  * task_struct *r4xx0_resume(task_struct *prev, task_struct *next)
  */
@@ -95,6 +101,14 @@
 	END(save_fp)
 
 /*
+ * Restore a thread's fp context.
+ */
+LEAF(restore_fp)
+	FPU_RESTORE_DOUBLE(a0, t1)		# clobbers t1
+	jr	ra
+	END(restore_fp)
+
+/*
  * Load the FPU with signalling NANS.  This bit pattern we're using has
  * the property that no matter whether considered as single or as double
  * precision represents signaling NANS.
@@ -105,6 +119,7 @@
 #define FPU_DEFAULT  0x00000000
 
 LEAF(init_fpu)
+	.set	mips3
 	mfc0	t0, CP0_STATUS
 	li	t1, 0x20000000
 	or	t0, t1
@@ -135,3 +150,4 @@
 	 dmtc1	t0, $f30
 	.set	reorder
 	END(init_fpu)
+
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/r6000_fpu.S linux/arch/mips/kernel/r6000_fpu.S
--- v2.4.3/linux/arch/mips/kernel/r6000_fpu.S	Sat May 13 08:29:14 2000
+++ linux/arch/mips/kernel/r6000_fpu.S	Fri Apr 13 20:26:07 2001
@@ -9,8 +9,6 @@
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -21,7 +19,7 @@
 	.set	noreorder
 	.set	mips2
 	/* Save floating point context */
-	LEAF(save_fp_context)
+	LEAF(_save_fp_context)
 	mfc0	t0,CP0_STATUS
 	sll	t0,t0,2
 	bgez	t0,1f
@@ -49,7 +47,7 @@
 	 sw	t0,SC_FPC_CSR(a0)
 1:	jr	ra
 	 nop
-	END(save_fp_context)
+	END(_save_fp_context)
 
 /* Restore FPU state:
  *  - fp gp registers
@@ -59,7 +57,7 @@
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
-	LEAF(restore_fp_context)
+	LEAF(_restore_fp_context)
 	mfc0	t0,CP0_STATUS
 	sll	t0,t0,2
 
@@ -86,4 +84,4 @@
 	 ctc1	t0,fcr31
 1:	jr	ra
 	 nop
-	END(restore_fp_context)
+	END(_restore_fp_context)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/semaphore.c linux/arch/mips/kernel/semaphore.c
--- v2.4.3/linux/arch/mips/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/mips/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -127,112 +127,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-/*
- * RW Semaphores
- */
-void
-__down_read(struct rw_semaphore *sem, int count)
-{
-	DOWN_VAR;
-
- retry_down:
-	if (count < 0) {
-		/* Wait for the lock to become unbiased.  Readers
-		   are non-exclusive.  */
-		
-		/* This takes care of granting the lock.  */
-		up_read(sem);
-
-		add_wait_queue(&sem->wait, &wait);
-		while (atomic_read(&sem->count) < 0) {
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&sem->count) >= 0)
-				break;
-			schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_dec_return(&sem->count);
-		if (count <= 0)
-			goto retry_down;
-	} else {
-		add_wait_queue(&sem->wait, &wait);
-
-		while (1) {
-			if (test_and_clear_bit(0, &sem->granted))
-				break;
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if ((sem->granted & 1) == 0)
-				schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-	}
-}
-
-void
-__down_write(struct rw_semaphore *sem, int count)
-{
-	DOWN_VAR;
-
- retry_down:
-	if (count + RW_LOCK_BIAS < 0) {
-		up_write(sem);
-
-		add_wait_queue_exclusive(&sem->wait, &wait);
-	
-		while (atomic_read(&sem->count) < 0) {
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
-				break;
-			schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-		if (count != 0)
-			goto retry_down;
-	} else {
-		/* Put ourselves at the end of the list.  */
-		add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
-		while (1) {
-			if (test_and_clear_bit(1, &sem->granted))
-				break;
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if ((sem->granted & 2) == 0)
-				schedule();
-		}
-
-		remove_wait_queue(&sem->write_bias_wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		/* If the lock is currently unbiased, awaken the sleepers.
-		   FIXME: This wakes up the readers early in a bit of a
-		   stampede -> bad!  */
-		if (atomic_read(&sem->count) >= 0)
-			wake_up(&sem->wait);
-	}
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
-	if (readers) {
-		if (test_and_set_bit(0, &sem->granted))
-			BUG();
-		wake_up(&sem->wait);
-	} else {
-		if (test_and_set_bit(1, &sem->granted))
-			BUG();
-		wake_up(&sem->write_bias_wait);
-	}
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c
--- v2.4.3/linux/arch/mips/kernel/setup.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips/kernel/setup.c	Fri Apr 13 20:26:07 2001
@@ -4,8 +4,9 @@
  * for more details.
  *
  * Copyright (C) 1995  Linus Torvalds
- * Copyright (C) 1995, 1996, 1997, 1998  Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000  Ralf Baechle
  * Copyright (C) 1996  Stoned Elipot
+ * Copyright (C) 2000  Maciej W. Rozycki
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -36,10 +37,10 @@
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
+#include <asm/cpu.h>
 #include <asm/io.h>
 #include <asm/stackframe.h>
 #include <asm/system.h>
-#include <asm/cpu.h>
 #ifdef CONFIG_SGI_IP22
 #include <asm/sgialib.h>
 #endif
@@ -152,64 +153,171 @@
 #endif
 }
 
+/* declaration of the global struct */
+struct mips_cpu mips_cpu = {PRID_IMP_UNKNOWN, CPU_UNKNOWN, 0, 0, 0,
+			    {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}};
+
+/* Shortcut for assembler access to mips_cpu.options */
+int *cpuoptions = &mips_cpu.options;
+
+#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
+		| MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
+
 static inline void cpu_probe(void)
 {
-	unsigned int prid = read_32bit_cp0_register(CP0_PRID);
-	switch(prid & 0xff00) {
+	unsigned long config1;
+
+	mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
+	switch (mips_cpu.processor_id & 0xff00) {
 	case PRID_IMP_R2000:
-		mips_cputype = CPU_R2000;
+		mips_cpu.cputype = CPU_R2000;
+		mips_cpu.isa_level = MIPS_CPU_ISA_I;
+		mips_cpu.options = MIPS_CPU_TLB;
+		mips_cpu.tlbsize = 64;
 		break;
 	case PRID_IMP_R3000:
-		if((prid & 0xff) == PRID_REV_R3000A)
-			if(cpu_has_confreg())
-				mips_cputype = CPU_R3081E;
+		if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
+			if (cpu_has_confreg())
+				mips_cpu.cputype = CPU_R3081E;
 			else
-				mips_cputype = CPU_R3000A;
+				mips_cpu.cputype = CPU_R3000A;
 		else
-			 mips_cputype = CPU_R3000;
+			 mips_cpu.cputype = CPU_R3000;
+		mips_cpu.isa_level = MIPS_CPU_ISA_I;
+		mips_cpu.options = MIPS_CPU_TLB;
+		mips_cpu.tlbsize = 64;
 		break;
 	case PRID_IMP_R4000:
-		if((prid & 0xff) == PRID_REV_R4400)
-			mips_cputype = CPU_R4400SC;
+		if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
+			mips_cpu.cputype = CPU_R4400SC;
 		else
-			mips_cputype = CPU_R4000SC;
+			mips_cpu.cputype = CPU_R4000SC;
+		mips_cpu.isa_level = MIPS_CPU_ISA_III;
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		                   MIPS_CPU_WATCH | MIPS_CPU_VCE;
+		mips_cpu.tlbsize = 48;
 		break;
 	case PRID_IMP_R4600:
-		mips_cputype = CPU_R4600;
+		mips_cpu.cputype = CPU_R4600;
+		mips_cpu.isa_level = MIPS_CPU_ISA_III;
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+		mips_cpu.tlbsize = 48;
 		break;
+/*
+ * This processor doesn't have an MMU, so it's not "real easy" to
+ * run Linux on it. It is left purely for documentation.
+ *
 	case PRID_IMP_R4650:
-		mips_cputype = CPU_R4650;
+		mips_cpu.cputype = CPU_R4650;
+		mips_cpu.isa_level = MIPS_CPU_ISA_III;
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+		mips_cpu.tlbsize = 48;
+		break;
+ */
+	case PRID_IMP_R3912:
+		mips_cpu.cputype = CPU_R3912;
+		mips_cpu.isa_level = MIPS_CPU_ISA_I;
+		mips_cpu.options = MIPS_CPU_TLB;
+		mips_cpu.tlbsize = 32;
 		break;
 	case PRID_IMP_R4700:
-		mips_cputype = CPU_R4700;
+		mips_cpu.cputype = CPU_R4700;
+		mips_cpu.isa_level = MIPS_CPU_ISA_III;
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
+		mips_cpu.tlbsize = 48;
 		break;
 	case PRID_IMP_R5000:
-		mips_cputype = CPU_R5000;
+		mips_cpu.cputype = CPU_R5000;
+		mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
+		mips_cpu.tlbsize = 48;
+		break;
+	case PRID_IMP_R5432:
+	        mips_cpu.cputype = CPU_R5432;
+		mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
+		mips_cpu.tlbsize = 48;
 		break;
 	case PRID_IMP_NEVADA:
-		mips_cputype = CPU_NEVADA;
+		mips_cpu.cputype = CPU_NEVADA;
+		mips_cpu.isa_level = MIPS_CPU_ISA_IV; 
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 
+		                   MIPS_CPU_DIVEC;
+		mips_cpu.tlbsize = 48;
+		mips_cpu.icache.ways = 2;
+		mips_cpu.dcache.ways = 2;
 		break;
 	case PRID_IMP_R6000:
-		mips_cputype = CPU_R6000;
+		mips_cpu.cputype = CPU_R6000;
+		mips_cpu.isa_level = MIPS_CPU_ISA_II;
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+		mips_cpu.tlbsize = 32;
 		break;
 	case PRID_IMP_R6000A:
-		mips_cputype = CPU_R6000A;
+		mips_cpu.cputype = CPU_R6000A;
+		mips_cpu.isa_level = MIPS_CPU_ISA_II;
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+		mips_cpu.tlbsize = 32;
+		break;
+	case PRID_IMP_RM7000:
+		mips_cpu.cputype = CPU_RM7000;
+	        mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
 		break;
 	case PRID_IMP_R8000:
-		mips_cputype = CPU_R8000;
+		mips_cpu.cputype = CPU_R8000;
+	        mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		                   MIPS_CPU_FPU | MIPS_CPU_32FPR;
+		mips_cpu.tlbsize = 384;      /* has wierd TLB: 3-way x 128 */
 		break;
 	case PRID_IMP_R10000:
-		mips_cputype = CPU_R10000;
-		break;
-	case PRID_IMP_RM7000:
-		mips_cputype = CPU_R5000;
+		mips_cpu.cputype = CPU_R10000;
+		mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
+		                   MIPS_CPU_FPU | MIPS_CPU_32FPR | 
+		                   MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
+		mips_cpu.tlbsize = 64;
+		break;
+#ifdef CONFIG_CPU_MIPS32
+	case PRID_IMP_4KC:
+		mips_cpu.cputype = CPU_4KC;
+		mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
+		                   MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | 
+		                   MIPS_CPU_DIVEC | MIPS_CPU_WATCH;
+		config1 = read_mips32_cp0_config1();
+		if (config1 & (1 << 3))
+		        mips_cpu.options |= MIPS_CPU_WATCH;
+		if (config1 & (1 << 2))
+		        mips_cpu.options |= MIPS_CPU_MIPS16;
+		if (config1 & 1)
+		        mips_cpu.options |= MIPS_CPU_FPU;
+		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
+		break;
+	case PRID_IMP_5KC:
+		mips_cpu.cputype = CPU_5KC;
+		mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | 
+		                   MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | 
+		                   MIPS_CPU_DIVEC | MIPS_CPU_WATCH;
+		config1 = read_mips32_cp0_config1();
+		if (config1 & (1 << 3))
+		        mips_cpu.options |= MIPS_CPU_WATCH;
+		if (config1 & (1 << 2))
+		        mips_cpu.options |= MIPS_CPU_MIPS16;
+		if (config1 & 1)
+		        mips_cpu.options |= MIPS_CPU_FPU;
+		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
 		break;
+#endif
 	default:
-		mips_cputype = CPU_UNKNOWN;
+		mips_cpu.cputype = CPU_UNKNOWN;
 	}
 }
 
-asmlinkage void __init init_arch(int argc, char **argv, char **envp, int *prom_vec)
+asmlinkage void __init
+init_arch(int argc, char **argv, char **envp, int *prom_vec)
 {
 	unsigned int s;
 
@@ -232,18 +340,13 @@
 	 */
 	loadmmu();
 
-	/* Disable coprocessors */
+	/* Disable coprocessors and set FPU for 16 FPRs */
 	s = read_32bit_cp0_register(CP0_STATUS);
-	s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX);
+	s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR);
 	s |= ST0_CU0;
 	write_32bit_cp0_register(CP0_STATUS, s);
 
-	/*
-	 * Main should never return here, but
-	 * just in case, we know what happens.
-	 */
-	for(;;)
-		start_kernel();
+	start_kernel();
 }
 
 static void __init default_irq_setup(void)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v2.4.3/linux/arch/mips/kernel/signal.c	Wed Jan 24 15:20:59 2001
+++ linux/arch/mips/kernel/signal.c	Fri Apr 13 20:26:07 2001
@@ -31,8 +31,9 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
-extern asmlinkage int save_fp_context(struct sigcontext *sc);
-extern asmlinkage int restore_fp_context(struct sigcontext *sc);
+
+extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
+extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
 
 extern asmlinkage void syscall_trace(void);
 
@@ -74,12 +75,12 @@
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-asmlinkage inline int
-sys_sigsuspend(struct pt_regs regs)
+save_static_function(sys_sigsuspend);
+static_unused int
+_sys_sigsuspend(struct pt_regs regs)
 {
 	sigset_t *uset, saveset, newset;
 
-	save_static(&regs);
 	uset = (sigset_t *) regs.regs[4];
 	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
 		return -EFAULT;
@@ -101,14 +102,14 @@
 	}
 }
 
-asmlinkage int
-sys_rt_sigsuspend(struct pt_regs regs)
+
+save_static_function(sys_rt_sigsuspend);
+static_unused int
+_sys_rt_sigsuspend(struct pt_regs regs)
 {
 	sigset_t *unewset, saveset, newset;
         size_t sigsetsize;
 
-	save_static(&regs);
-
 	/* XXX Don't preclude handling different sized sigset_t's.  */
 	sigsetsize = regs.regs[5];
 	if (sigsetsize != sizeof(sigset_t))
@@ -353,7 +354,7 @@
 	err |= __put_user(owned_fp, &sc->sc_ownedfp);
 
 	if (current->used_math) {	/* fp is active.  */
-		set_cp0_status(ST0_CU1, ST0_CU1);
+		set_cp0_status(ST0_CU1);
 		err |= save_fp_context(sc);
 		last_task_used_math = NULL;
 		regs->cp0_status &= ~ST0_CU1;
diff -u --recursive --new-file v2.4.3/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
--- v2.4.3/linux/arch/mips/kernel/traps.c	Sun Dec  3 17:48:19 2000
+++ linux/arch/mips/kernel/traps.c	Fri Apr 13 20:26:07 2001
@@ -7,6 +7,9 @@
  * Modified for R3000 by Paul M. Antoine, 1995, 1996
  * Complete output from die() by Ulf Carlsson, 1998
  * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -16,12 +19,15 @@
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 
+#include <asm/bootinfo.h>
 #include <asm/branch.h>
+#include <asm/cpu.h>
 #include <asm/cachectl.h>
+#include <asm/inst.h>
 #include <asm/jazz.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/bootinfo.h>
+#include <asm/siginfo.h>
 #include <asm/watch.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -51,13 +57,15 @@
 extern asmlinkage void handle_tr(void);
 extern asmlinkage void handle_fpe(void);
 extern asmlinkage void handle_watch(void);
+extern asmlinkage void handle_mcheck(void);
 extern asmlinkage void handle_reserved(void);
 
+extern int fpu_emulator_cop1Handler(int, struct pt_regs *);
+
 static char *cpu_names[] = CPU_NAMES;
 
 char watch_available = 0;
 char dedicated_iv_available = 0;
-char vce_available = 0;
 
 void (*ibe_board_handler)(struct pt_regs *regs);
 void (*dbe_board_handler)(struct pt_regs *regs);
@@ -308,9 +316,11 @@
  */
 void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
-	unsigned long pc;
-	unsigned int insn;
-	extern void simfp(unsigned int);
+
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+	if(!(mips_cpu.options & MIPS_CPU_FPU))
+		panic("Floating Point Exception with No FPU");
+#endif
 
 #ifdef CONFIG_MIPS_FPE_MODULE
 	if (fpe_handler != NULL) {
@@ -318,12 +328,52 @@
 		return;
 	}
 #endif
-	if (fcr31 & 0x20000) {
+
+	if (fcr31 & FPU_CSR_UNI_X) {
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+		extern void save_fp(struct task_struct *);
+		extern void restore_fp(struct task_struct *);
+		int sig;
+		/*
+	 	 * Unimplemented operation exception.  If we've got the
+	 	 * Full software emulator on-board, let's use it...
+		 *
+		 * Force FPU to dump state into task/thread context.
+		 * We're moving a lot of data here for what is probably
+		 * a single instruction, but the alternative is to 
+		 * pre-decode the FP register operands before invoking
+		 * the emulator, which seems a bit extreme for what
+		 * should be an infrequent event.
+		 */
+		save_fp(current);
+	
+		/* Run the emulator */
+		sig = fpu_emulator_cop1Handler(0, regs);
+
+		/* 
+		 * We can't allow the emulated instruction to leave the
+		 * Unimplemented Operation bit set in the FCR31 fp-register.
+		 */
+		current->thread.fpu.soft.sr &= ~FPU_CSR_UNI_X;
+
+		/* Restore the hardware register state */
+		restore_fp(current);
+
+		/* If something went wrong, signal */
+		if (sig)
+			force_sig(sig, current);
+#else
+		/* Else use mini-emulator */
+
+		extern void simfp(int);
+		unsigned long pc;
+		unsigned int insn;
+
 		/* Retry instruction with flush to zero ...  */
 		if (!(fcr31 & (1<<24))) {
 			printk("Setting flush to zero for %s.\n",
 			       current->comm);
-			fcr31 &= ~0x20000;
+			fcr31 &= ~FPU_CSR_UNI_X;
 			fcr31 |= (1<<24);
 			__asm__ __volatile__(
 				"ctc1\t%0,$31"
@@ -332,20 +382,26 @@
 			return;
 		}
 		pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0);
-		if (get_user(insn, (unsigned int *)pc)) {
+		if(pc & 0x80000000) insn = *(unsigned int *)pc;
+		else if (get_user(insn, (unsigned int *)pc)) {
 			/* XXX Can this happen?  */
 			force_sig(SIGSEGV, current);
 		}
 
 		printk(KERN_DEBUG "Unimplemented exception for insn %08x at 0x%08lx in %s.\n",
 		       insn, regs->cp0_epc, current->comm);
-		simfp(insn);
+		simfp(MIPSInst(insn));
+		compute_return_epc(regs);
+#endif /* CONFIG_MIPS_FPU_EMULATOR */
+
+		return;
 	}
 
 	if (compute_return_epc(regs))
 		return;
-	//force_sig(SIGFPE, current);
-	printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm);
+
+	force_sig(SIGFPE, current);
+	printk(KERN_DEBUG "Sent send SIGFPE to %s\n", current->comm);
 }
 
 static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
@@ -382,12 +438,28 @@
 	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
 	 * insns, even for break codes that indicate arithmetic failures.
 	 * Weird ...)
+	 * But should we continue the brokenness???  --macro
 	 */
-	force_sig(SIGTRAP, current);
+	switch (bcode) {
+	case 6:
+	case 7:
+		if (bcode == 7)
+			info.si_code = FPE_INTDIV;
+		else
+			info.si_code = FPE_INTOVF;
+		info.si_signo = SIGFPE;
+		info.si_errno = 0;
+		info.si_addr = (void *)compute_return_epc(regs);
+		force_sig_info(SIGFPE, &info, current);
+		break;
+	default:
+		force_sig(SIGTRAP, current);
+	}
 }
 
 void do_tr(struct pt_regs *regs)
 {
+	siginfo_t info;
 	unsigned int opcode, bcode;
 
 	if (get_insn_opcode(regs, &opcode))
@@ -398,8 +470,23 @@
 	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
 	 * insns, even for break codes that indicate arithmetic failures.
 	 * Weird ...)
+	 * But should we continue the brokenness???  --macro
 	 */
-	force_sig(SIGTRAP, current);
+	switch (bcode) {
+	case 6:
+	case 7:
+		if (bcode == 7)
+			info.si_code = FPE_INTDIV;
+		else
+			info.si_code = FPE_INTOVF;
+		info.si_signo = SIGFPE;
+		info.si_errno = 0;
+		info.si_addr = (void *)compute_return_epc(regs);
+		force_sig_info(SIGFPE, &info, current);
+		break;
+	default:
+		force_sig(SIGTRAP, current);
+	}
 }
 
 #if !defined(CONFIG_CPU_HAS_LLSC)
@@ -520,10 +607,32 @@
 	unsigned int cpid;
 	extern void lazy_fpu_switch(void*);
 	extern void init_fpu(void);
-
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+	void fpu_emulator_init_fpu(void);
+	int sig;
+#endif
 	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
 	if (cpid != 1)
 		goto bad_cid;
+
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+	if(!(mips_cpu.options & MIPS_CPU_FPU)) {
+	    if (last_task_used_math != current) {
+		if(!current->used_math) {
+		    fpu_emulator_init_fpu();
+		    current->used_math = 1;
+		}
+	    }
+	    sig = fpu_emulator_cop1Handler(0, regs);
+	    last_task_used_math = current;
+	    if(sig) {
+		force_sig(sig, current);
+	    }
+	    return;
+	}
+#else
+	if(!(mips_cpu.options & MIPS_CPU_FPU)) goto bad_cid;
+#endif
 
 	regs->cp0_status |= ST0_CU1;
 	if (last_task_used_math == current)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile
--- v2.4.3/linux/arch/mips/lib/Makefile	Tue Dec  5 23:15:12 2000
+++ linux/arch/mips/lib/Makefile	Fri Apr 13 20:26:07 2001
@@ -9,26 +9,23 @@
 
 L_TARGET = lib.a
 
-L_OBJS	= csum_partial.o csum_partial_copy.o \
-          rtc-std.o rtc-no.o memcpy.o memset.o  watch.o\
-          strlen_user.o strncpy_user.o strnlen_user.o
+obj-y				+= csum_partial.o csum_partial_copy.o \
+				   rtc-std.o rtc-no.o memcpy.o memset.o \
+				   watch.o strlen_user.o strncpy_user.o \
+				   strnlen_user.o
 
 ifdef CONFIG_CPU_R3000
-  L_OBJS += r3k_dump_tlb.o 
+  obj-y	+= r3k_dump_tlb.o 
 else
-  L_OBJS += dump_tlb.o 
+  ifdef CONFIG_CPU_R3912
+    obj-y	+= r3k_dump_tlb.o 
+  else
+    obj-y	+= dump_tlb.o 
+  endif
 endif
 
-ifdef CONFIG_BLK_DEV_FD
-  L_OBJS += floppy-no.o floppy-std.o
-endif
-
-ifdef CONFIG_IDE
-  L_OBJS += ide-std.o ide-no.o
-endif
-
-ifdef CONFIG_PC_KEYB
-  L_OBJS += kbd-std.o kbd-no.o
-endif
+obj-$(CONFIG_BLK_DEV_FD)	+= floppy-no.o floppy-std.o
+obj-$(CONFIG_IDE)		+= ide-std.o ide-no.o
+obj-$(CONFIG_PC_KEYB)		+= kbd-std.o kbd-no.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/lib/kbd-std.c linux/arch/mips/lib/kbd-std.c
--- v2.4.3/linux/arch/mips/lib/kbd-std.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/lib/kbd-std.c	Fri Apr 13 20:26:07 2001
@@ -8,6 +8,7 @@
  *
  * Copyright (C) 1998, 1999 by Ralf Baechle
  */
+#include <linux/config.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/pc_keyb.h>
@@ -19,11 +20,17 @@
 
 static void std_kbd_request_region(void)
 {
+#ifdef CONFIG_MIPS_ITE8172
+	printk("std_kbd_request_region\n");
+	request_region(0x14000060, 16, "keyboard");
+#else
 	request_region(0x60, 16, "keyboard");
+#endif
 }
 
 static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *))
 {
+	printk("std_kbd_request_irq\n");
 	return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL);
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/Makefile linux/arch/mips/math-emu/Makefile
--- v2.4.3/linux/arch/mips/math-emu/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,24 @@
+#
+# Makefile for the Linux/MIPS kernel FPU emulation.
+#
+# 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).
+#
+
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+EXTRA_ASFLAGS = -mips2 -mcpu=r4000
+
+O_TARGET:= fpu_emulator.o
+
+obj-y	:= cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
+	   ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \
+	   dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \
+	   dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
+	   sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
+	   sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
+	   dp_sqrt.o sp_sqrt.o kernel_linkage.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/cp1emu.c linux/arch/mips/math-emu/cp1emu.c
--- v2.4.3/linux/arch/mips/math-emu/cp1emu.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/cp1emu.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,1811 @@
+/*
+ * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
+ * 
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * A complete emulator for MIPS coprocessor 1 instructions.  This is
+ * required for #float(switch) or #float(trap), where it catches all
+ * COP1 instructions via the "CoProcessor Unusable" exception.  
+ *
+ * More surprisingly it is also required for #float(ieee), to help out
+ * the hardware fpu at the boundaries of the IEEE-754 representation
+ * (denormalised values, infinities, underflow, etc).  It is made
+ * quite nasty because emulation of some non-COP1 instructions is
+ * required, e.g. in branch delay slots.
+ * 
+ * Notes: 
+ *  1) the IEEE754 library (-le) performs the actual arithmetic;
+ *  2) if you know that you won't have an fpu, then you'll get much 
+ *     better performance by compiling with -msoft-float!  */
+
+/**************************************************************************
+ *  Nov 7, 2000
+ *  Massive changes to integrate with Linux kernel.
+ *
+ *  Replace use of kernel data area with use of user stack 
+ *  for execution of instructions in branch delay slots.
+ *
+ *  Replace use of static kernel variables with thread_struct elements.
+ *
+ *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000  MIPS Technologies, Inc.  All rights reserved.
+ *************************************************************************/
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/asm.h>
+#include <asm/branch.h>
+#include <asm/byteorder.h>
+#include <asm/inst.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+#include <asm/fpu_emulator.h>
+
+#include "ieee754.h"
+
+/* Strap kernel emulator for full MIPS IV emulation */
+
+#ifdef __mips
+#undef __mips
+#endif
+#define __mips 4
+
+typedef void *vaddr_t;
+
+/* Function which emulates the instruction in a branch delay slot. */
+
+static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t);
+
+/* Function which emulates a floating point instruction. */
+
+static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
+	 mips_instruction);
+
+#if __mips >= 4 && __mips != 32
+static int fpux_emu(struct pt_regs *,
+		    struct mips_fpu_soft_struct *, mips_instruction);
+#endif
+
+/* Further private data for which no space exists in mips_fpu_soft_struct */
+
+struct mips_fpu_emulator_private fpuemuprivate;
+
+/* Control registers */
+
+#define FPCREG_RID	0	/* $0  = revision id */
+#define FPCREG_CSR	31	/* $31 = csr */
+
+/* Convert Mips rounding mode (0..3) to IEEE library modes. */
+static const unsigned char ieee_rm[4] = {
+	IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD
+};
+
+#if __mips >= 4
+/* convert condition code register number to csr bit */
+static const unsigned int fpucondbit[8] = {
+	FPU_CSR_COND0,
+	FPU_CSR_COND1,
+	FPU_CSR_COND2,
+	FPU_CSR_COND3,
+	FPU_CSR_COND4,
+	FPU_CSR_COND5,
+	FPU_CSR_COND6,
+	FPU_CSR_COND7
+};
+#endif
+
+
+
+/* 
+ * Redundant with logic already in kernel/branch.c,
+ * embedded in compute_return_epc.  At some point,
+ * a single subroutine should be used across both
+ * modules.
+ */
+static int isBranchInstr(mips_instruction * i)
+{
+	switch (MIPSInst_OPCODE(*i)) {
+	case spec_op:
+		switch (MIPSInst_FUNC(*i)) {
+		case jalr_op:
+		case jr_op:
+			return 1;
+		}
+		break;
+
+	case bcond_op:
+		switch (MIPSInst_RT(*i)) {
+		case bltz_op:
+		case bgez_op:
+		case bltzl_op:
+		case bgezl_op:
+		case bltzal_op:
+		case bgezal_op:
+		case bltzall_op:
+		case bgezall_op:
+			return 1;
+		}
+		break;
+
+	case j_op:
+	case jal_op:
+	case jalx_op:
+	case beq_op:
+	case bne_op:
+	case blez_op:
+	case bgtz_op:
+	case beql_op:
+	case bnel_op:
+	case blezl_op:
+	case bgtzl_op:
+		return 1;
+
+	case cop0_op:
+	case cop1_op:
+	case cop2_op:
+	case cop1x_op:
+		if (MIPSInst_RS(*i) == bc_op)
+			return 1;
+		break;
+	}
+
+	return 0;
+}
+
+#define REG_TO_VA (vaddr_t)
+#define VA_TO_REG (unsigned long)
+
+static unsigned long
+mips_get_word(struct pt_regs *xcp, void *va, int *perr)
+{
+	unsigned long temp;
+
+	if (!user_mode(xcp)) {
+		*perr = 0;
+		return (*(unsigned long *) va);
+	} else {
+		/* Use kernel get_user() macro */
+		*perr = (int) get_user(temp, (unsigned long *) va);
+		return temp;
+	}
+}
+
+static unsigned long long
+mips_get_dword(struct pt_regs *xcp, void *va, int *perr)
+{
+	unsigned long long temp;
+
+	if (!user_mode(xcp)) {
+		*perr = 0;
+		return (*(unsigned long long *) va);
+	} else {
+		/* Use kernel get_user() macro */
+		*perr = (int) get_user(temp, (unsigned long long *) va);
+		return temp;
+	}
+}
+
+static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val)
+{
+	if (!user_mode(xcp)) {
+		*(unsigned long *) va = val;
+		return 0;
+	} else {
+		/* Use kernel get_user() macro */
+		return (int) put_user(val, (unsigned long *) va);
+	}
+}
+
+static int mips_put_dword(struct pt_regs *xcp, void *va, long long val)
+{
+	if (!user_mode(xcp)) {
+		*(unsigned long long *) va = val;
+		return 0;
+	} else {
+		/* Use kernel get_user() macro */
+		return (int) put_user(val, (unsigned long long *) va);
+	}
+}
+
+
+/*
+ * In the Linux kernel, we support selection of FPR format on the
+ * basis of the Status.FR bit.  This does imply that, if a full 32
+ * FPRs are desired, there needs to be a flip-flop that can be written
+ * to one at that bit position.  In any case, normal MIPS ABI uses
+ * only the even FPRs (Status.FR = 0).
+ */
+
+#define CP0_STATUS_FR_SUPPORT
+
+/*
+ * Emulate the single floating point instruction pointed at by EPC.
+ * Two instructions if the instruction is in a branch delay slot.
+ */
+
+static int
+cop1Emulate(int xcptno, struct pt_regs *xcp,
+	    struct mips_fpu_soft_struct *ctx)
+{
+	mips_instruction ir;
+	vaddr_t emulpc;
+	vaddr_t contpc;
+	unsigned int cond;
+	int err = 0;
+
+
+	ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err);
+	if (err) {
+		fpuemuprivate.stats.errors++;
+		return SIGBUS;
+	}
+
+	/* XXX NEC Vr54xx bug workaround */
+	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
+		xcp->cp0_cause &= ~CAUSEF_BD;
+
+	if (xcp->cp0_cause & CAUSEF_BD) {
+		/*
+		 * The instruction to be emulated is in a branch delay slot
+		 * which means that we have to  emulate the branch instruction
+		 * BEFORE we do the cop1 instruction. 
+		 *
+		 * This branch could be a COP1 branch, but in that case we
+		 * would have had a trap for that instruction, and would not
+		 * come through this route.
+		 *
+		 * Linux MIPS branch emulator operates on context, updating the
+		 * cp0_epc.
+		 */
+		emulpc = REG_TO_VA(xcp->cp0_epc + 4);	/* Snapshot emulation target */
+
+		if (__compute_return_epc(xcp)) {
+#ifdef CP1DBG
+			printk("failed to emulate branch at %p\n",
+				    REG_TO_VA(xcp->cp0_epc));
+#endif
+			return SIGILL;;
+		}
+		ir = mips_get_word(xcp, emulpc, &err);
+		if (err) {
+			fpuemuprivate.stats.errors++;
+			return SIGBUS;
+		}
+		contpc = REG_TO_VA xcp->cp0_epc;
+	} else {
+		emulpc = REG_TO_VA xcp->cp0_epc;
+		contpc = REG_TO_VA xcp->cp0_epc + 4;
+	}
+
+      emul:
+	fpuemuprivate.stats.emulated++;
+	switch (MIPSInst_OPCODE(ir)) {
+#ifdef CP0_STATUS_FR_SUPPORT
+		/* R4000+ 64-bit fpu registers */
+#ifndef SINGLE_ONLY_FPU
+	case ldc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			int ft = MIPSInst_RT(ir);
+			if (!(xcp->cp0_status & ST0_FR))
+				ft &= ~1;
+			ctx->regs[ft] = mips_get_dword(xcp, va, &err);
+			fpuemuprivate.stats.loads++;
+			if (err) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+		}
+		break;
+
+	case sdc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			int ft = MIPSInst_RT(ir);
+			if (!(xcp->cp0_status & ST0_FR))
+				ft &= ~1;
+			fpuemuprivate.stats.stores++;
+			if (mips_put_dword(xcp, va, ctx->regs[ft])) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+		}
+		break;
+#endif
+
+	case lwc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			fpureg_t val;
+			int ft = MIPSInst_RT(ir);
+			fpuemuprivate.stats.loads++;
+			val = mips_get_word(xcp, va, &err);
+			if (err) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+			if (xcp->cp0_status & ST0_FR) {
+				/* load whole register */
+				ctx->regs[ft] = val;
+			} else if (ft & 1) {
+				/* load to m.s. 32 bits */
+#ifdef SINGLE_ONLY_FPU
+				/* illegal register in single-float mode */
+				return SIGILL;
+#else
+				ctx->regs[(ft & ~1)] &= 0xffffffff;
+				ctx->regs[(ft & ~1)] |= val << 32;
+#endif
+			} else {
+				/* load to l.s. 32 bits */
+				ctx->regs[ft] &= ~0xffffffffLL;
+				ctx->regs[ft] |= val;
+			}
+		}
+		break;
+
+	case swc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			unsigned int val;
+			int ft = MIPSInst_RT(ir);
+			fpuemuprivate.stats.stores++;
+			if (xcp->cp0_status & ST0_FR) {
+				/* store whole register */
+				val = ctx->regs[ft];
+			} else if (ft & 1) {
+#ifdef SINGLE_ONLY_FPU
+				/* illegal register in single-float mode */
+				return SIGILL;
+#else
+				/* store from m.s. 32 bits */
+				val = ctx->regs[(ft & ~1)] >> 32;
+#endif
+			} else {
+				/* store from l.s. 32 bits */
+				val = ctx->regs[ft];
+			}
+			if (mips_put_word(xcp, va, val)) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+		}
+		break;
+#else				/* old 32-bit fpu registers */
+	case lwc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			ctx->regs[MIPSInst_RT(ir)] =
+			    mips_get_word(xcp, va, &err);
+			fpuemuprivate.stats.loads++;
+			if (err) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+		}
+		break;
+
+	case swc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			fpuemuprivate.stats.stores++;
+			if (mips_put_word
+			    (xcp, va, ctx->regs[MIPSInst_RT(ir)])) {
+				fpuemuprivate.stats.errors++;
+				return SIGBUS;
+			}
+		}
+		break;
+	case ldc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			unsigned int rt = MIPSInst_RT(ir) & ~1;
+			int errs = 0;
+			fpuemuprivate.stats.loads++;
+#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
+			ctx->regs[rt + 1] =
+			    mips_get_word(xcp, va + 0, &err);
+			errs += err;
+			ctx->regs[rt + 0] =
+			    mips_get_word(xcp, va + 4, &err);
+			errs += err;
+#else
+			ctx->regs[rt + 0] =
+			    mips_get_word(xcp, va + 0, &err);
+			errs += err;
+			ctx->regs[rt + 1] =
+			    mips_get_word(xcp, va + 4, &err);
+			errs += err;
+#endif
+			if (err)
+				return SIGBUS;
+		}
+		break;
+
+	case sdc1_op:
+		{
+			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+			    + MIPSInst_SIMM(ir);
+			unsigned int rt = MIPSInst_RT(ir) & ~1;
+			fpuemuprivate.stats.stores++;
+#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
+			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1]))
+				return SIGBUS;
+			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0]))
+				return SIGBUS;
+#else
+			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0]))
+				return SIGBUS;
+			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1]))
+				return SIGBUS;
+#endif
+		}
+		break;
+#endif
+
+	case cop1_op:
+		switch (MIPSInst_RS(ir)) {
+
+#ifdef CP0_STATUS_FR_SUPPORT
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+		case dmfc_op:
+			/* copregister fs -> gpr[rt] */
+			if (MIPSInst_RT(ir) != 0) {
+				int fs = MIPSInst_RD(ir);
+				if (!(xcp->cp0_status & ST0_FR))
+					fs &= ~1;
+				xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
+			}
+			break;
+
+		case dmtc_op:
+			/* copregister fs <- rt */
+			{
+				fpureg_t value;
+				int fs = MIPSInst_RD(ir);
+				if (!(xcp->cp0_status & ST0_FR))
+					fs &= ~1;
+				value =
+				    (MIPSInst_RT(ir) ==
+				     0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
+				ctx->regs[fs] = value;
+			}
+			break;
+#endif
+
+		case mfc_op:
+			/* copregister rd -> gpr[rt] */
+			if (MIPSInst_RT(ir) != 0) {
+				/* default value from l.s. 32 bits */
+				int value = ctx->regs[MIPSInst_RD(ir)];
+				if (MIPSInst_RD(ir) & 1) {
+#ifdef SINGLE_ONLY_FPU
+					/* illegal register in single-float mode */
+					return SIGILL;
+#else
+					if (!(xcp->cp0_status & ST0_FR)) {
+						/* move from m.s. 32 bits */
+						value =
+						    ctx->
+						    regs[MIPSInst_RD(ir) &
+							 ~1] >> 32;
+					}
+#endif
+				}
+				xcp->regs[MIPSInst_RT(ir)] = value;
+			}
+			break;
+
+		case mtc_op:
+			/* copregister rd <- rt */
+			{
+				fpureg_t value;
+				if (MIPSInst_RT(ir) == 0)
+					value = 0;
+				else
+					value =
+					    (unsigned int) xcp->
+					    regs[MIPSInst_RT(ir)];
+				if (MIPSInst_RD(ir) & 1) {
+#ifdef SINGLE_ONLY_FPU
+					/* illegal register in single-float mode */
+					return SIGILL;
+#else
+					if (!(xcp->cp0_status & ST0_FR)) {
+						/* move to m.s. 32 bits */
+						ctx->
+						    regs[
+							 (MIPSInst_RD(ir) &
+							  ~1)] &=
+						    0xffffffff;
+						ctx->
+						    regs[
+							 (MIPSInst_RD(ir) &
+							  ~1)] |=
+						    value << 32;
+						break;
+					}
+#endif
+				}
+				/* move to l.s. 32 bits */
+				ctx->regs[MIPSInst_RD(ir)] &=
+				    ~0xffffffffLL;
+				ctx->regs[MIPSInst_RD(ir)] |= value;
+			}
+			break;
+#else
+
+		case mfc_op:
+			/* copregister rd -> gpr[rt] */
+			if (MIPSInst_RT(ir) != 0) {
+				unsigned value =
+				    ctx->regs[MIPSInst_RD(ir)];
+				xcp->regs[MIPSInst_RT(ir)] = value;
+			}
+			break;
+
+		case mtc_op:
+			/* copregister rd <- rt */
+			{
+				unsigned value;
+				value =
+				    (MIPSInst_RT(ir) ==
+				     0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
+				ctx->regs[MIPSInst_RD(ir)] = value;
+			}
+			break;
+#endif
+
+		case cfc_op:
+			/* cop control register rd -> gpr[rt] */
+			{
+				unsigned value;
+
+				if (MIPSInst_RD(ir) == FPCREG_CSR) {
+					value = ctx->sr;
+#ifdef CSRTRACE
+					printk
+					    ("%p gpr[%d]<-csr=%08x\n",
+					     REG_TO_VA(xcp->cp0_epc),
+					     MIPSInst_RT(ir), value);
+#endif
+				} else if (MIPSInst_RD(ir) == FPCREG_RID)
+					value = 0;
+				else
+					value = 0;
+				if (MIPSInst_RT(ir))
+					xcp->regs[MIPSInst_RT(ir)] = value;
+			}
+			break;
+
+		case ctc_op:
+			/* copregister rd <- rt */
+			{
+				unsigned value;
+
+				if (MIPSInst_RT(ir) == 0)
+					value = 0;
+				else
+					value = xcp->regs[MIPSInst_RT(ir)];
+
+				/* we only have one writable control reg
+				 */
+				if (MIPSInst_RD(ir) == FPCREG_CSR) {
+#ifdef CSRTRACE
+					printk
+					    ("%p gpr[%d]->csr=%08x\n",
+					     REG_TO_VA(xcp->cp0_epc),
+					     MIPSInst_RT(ir), value);
+#endif
+					ctx->sr = value;
+					/* copy new rounding mode to ieee library state! */
+					ieee754_csr.rm =
+					    ieee_rm[value & 0x3];
+				}
+			}
+			break;
+
+		case bc_op:
+			if (xcp->cp0_cause & CAUSEF_BD) {
+				return SIGILL;
+			}
+			{
+				int likely = 0;
+
+#if __mips >= 4
+				cond =
+				    ctx->
+				    sr & fpucondbit[MIPSInst_RT(ir) >> 2];
+#else
+				cond = ctx->sr & FPU_CSR_COND;
+#endif
+				switch (MIPSInst_RT(ir) & 3) {
+				case bcfl_op:
+					likely = 1;
+				case bcf_op:
+					cond = !cond;
+					break;
+				case bctl_op:
+					likely = 1;
+				case bct_op:
+					break;
+				default:
+					/* thats an illegal instruction */
+					return SIGILL;
+				}
+
+				xcp->cp0_cause |= CAUSEF_BD;
+				if (cond) {
+					/* branch taken: emulate dslot instruction */
+					xcp->cp0_epc += 4;
+					contpc =
+					    REG_TO_VA xcp->cp0_epc +
+					    (MIPSInst_SIMM(ir) << 2);
+
+					ir =
+					    mips_get_word(xcp,
+							  REG_TO_VA(xcp->
+								    cp0_epc),
+							  &err);
+					if (err) {
+						fpuemuprivate.stats.
+						    errors++;
+						return SIGBUS;
+					}
+
+					switch (MIPSInst_OPCODE(ir)) {
+					case lwc1_op:
+					case swc1_op:
+#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU)
+					case ldc1_op:
+					case sdc1_op:
+#endif
+					case cop1_op:
+#if __mips >= 4 && __mips != 32
+					case cop1x_op:
+#endif
+						/* its one of ours */
+						goto emul;
+#if __mips >= 4
+					case spec_op:
+						if (MIPSInst_FUNC(ir) ==
+						    movc_op) goto emul;
+						break;
+#endif
+					}
+
+					/* single step the non-cp1 instruction in the dslot */
+					return mips_dsemul(xcp, ir,
+							   contpc);
+				} else {
+					/* branch not taken */
+					if (likely)
+						/* branch likely nullifies dslot if not taken */
+						xcp->cp0_epc += 4;
+					/* else continue & execute dslot as normal insn */
+				}
+			}
+			break;
+
+		default:
+			if (!(MIPSInst_RS(ir) & 0x10)) {
+				return SIGILL;
+			}
+			/* a real fpu computation instruction */
+			{
+				int sig;
+				if ((sig = fpu_emu(xcp, ctx, ir)))
+					return sig;
+			}
+		}
+		break;
+
+#if __mips >= 4 && __mips != 32
+	case cop1x_op:
+		{
+			int sig;
+			if ((sig = fpux_emu(xcp, ctx, ir)))
+				return sig;
+		}
+		break;
+#endif
+
+#if __mips >= 4
+	case spec_op:
+		if (MIPSInst_FUNC(ir) != movc_op)
+			return SIGILL;
+		cond = fpucondbit[MIPSInst_RT(ir) >> 2];
+		if (((ctx->sr & cond) != 0) !=
+		    ((MIPSInst_RT(ir) & 1) != 0)) return 0;
+		xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
+		break;
+#endif
+
+	default:
+		return SIGILL;
+	}
+
+	/* we did it !! */
+	xcp->cp0_epc = VA_TO_REG(contpc);
+	xcp->cp0_cause &= ~CAUSEF_BD;
+	return 0;
+}
+
+/*
+ * Emulate the arbritrary instruction ir at xcp->cp0_epc.  Required when
+ * we have to emulate the instruction in a COP1 branch delay slot.  Do
+ * not change cp0_epc due to the instruction
+ *
+ * According to the spec:
+ * 1) it shouldnt be a branch :-)
+ * 2) it can be a COP instruction :-(
+ * 3) if we are tring to run a protected memory space we must take
+ *    special care on memory access instructions :-(
+ */
+
+/*
+ * "Trampoline" return routine to catch exception following
+ *  execution of delay-slot instruction execution.
+ */
+
+int do_dsemulret(struct pt_regs *xcp)
+{
+#ifdef DSEMUL_TRACE
+	printk("desemulret\n");
+#endif
+	/* Set EPC to return to post-branch instruction */
+	xcp->cp0_epc = current->thread.dsemul_epc;
+	/*
+	 * Clear the state that got us here.
+	 */
+	current->thread.dsemul_aerpc = (unsigned long) 0;
+
+	return 0;
+}
+
+
+#define AdELOAD 0x8c000001	/* lw $0,1($0) */
+
+static int
+mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc)
+{
+	mips_instruction *dsemul_insns;
+	mips_instruction forcetrap;
+	extern asmlinkage void handle_dsemulret(void);
+
+	if (ir == 0) {		/* a nop is easy */
+		xcp->cp0_epc = VA_TO_REG(cpc);
+		return 0;
+	}
+#ifdef DSEMUL_TRACE
+	printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc);
+#endif
+
+	/* 
+	 * The strategy is to push the instruction onto the user stack 
+	 * and put a trap after it which we can catch and jump to 
+	 * the required address any alternative apart from full 
+	 * instruction emulation!!.
+	 */
+	dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3);
+	dsemul_insns -= 3;	/* Two instructions, plus one for luck ;-) */
+	/* Verify that the stack pointer is not competely insane */
+	if (verify_area
+	    (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2))
+		return SIGBUS;
+
+	if (mips_put_word(xcp, &dsemul_insns[0], ir)) {
+		fpuemuprivate.stats.errors++;
+		return (SIGBUS);
+	}
+
+	/* 
+	 * Algorithmics used a system call instruction, and
+	 * borrowed that vector.  MIPS/Linux version is a bit
+	 * more heavyweight in the interests of portability and
+	 * multiprocessor support.  We flag the thread for special
+	 * handling in the unaligned access handler and force an
+	 * address error excpetion.
+	 */
+
+	/* If one is *really* paranoid, one tests for a bad stack pointer */
+	if ((xcp->regs[29] & 0x3) == 0x3)
+		forcetrap = AdELOAD - 1;
+	else
+		forcetrap = AdELOAD;
+
+	if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) {
+		fpuemuprivate.stats.errors++;
+		return (SIGBUS);
+	}
+
+	/* Set thread state to catch and handle the exception */
+	current->thread.dsemul_epc = (unsigned long) cpc;
+	current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1];
+	xcp->cp0_epc = VA_TO_REG & dsemul_insns[0];
+
+	/* What we'd really like to do is just flush the line(s) of the */
+	/* icache containing the dsemulret instructions, but there's no */
+	/* mechanism to do this yet...  */
+	flush_cache_all();
+	return SIGILL;		/* force out of emulation loop */
+}
+
+/* 
+ * Conversion table from MIPS compare ops 48-63
+ * cond = ieee754dp_cmp(x,y,IEEE754_UN);
+ */
+static const unsigned char cmptab[8] = {
+	0,					/* cmp_0 (sig) cmp_sf */
+	IEEE754_CUN,				/* cmp_un (sig) cmp_ngle */
+	IEEE754_CEQ,				/* cmp_eq (sig) cmp_seq */
+	IEEE754_CEQ | IEEE754_CUN,		/* cmp_ueq (sig) cmp_ngl  */
+	IEEE754_CLT,				/* cmp_olt (sig) cmp_lt */
+	IEEE754_CLT | IEEE754_CUN,		/* cmp_ult (sig) cmp_nge */
+	IEEE754_CLT | IEEE754_CEQ,		/* cmp_ole (sig) cmp_le */
+	IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
+};
+
+#define SIFROMREG(si,x)	((si) = ctx->regs[x])
+#define SITOREG(si,x)	(ctx->regs[x] = (int)(si))
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#define DIFROMREG(di,x)	((di) = ctx->regs[x])
+#define DITOREG(di,x)	(ctx->regs[x] = (di))
+#endif
+
+#define SPFROMREG(sp,x)	((sp).bits = ctx->regs[x])
+#define SPTOREG(sp,x)	(ctx->regs[x] = (sp).bits)
+
+#ifdef CP0_STATUS_FR_SUPPORT
+#define DPFROMREG(dp,x)	((dp).bits = \
+			ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)])
+#define DPTOREG(dp,x)	(ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\
+			= (dp).bits)
+#else
+/* Beware: MIPS COP1 doubles are always little_word endian in registers */
+#define DPFROMREG(dp,x)	\
+  ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x])
+#define DPTOREG(dp,x) \
+  (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32)
+#endif
+
+#if __mips >= 4 && __mips != 32
+
+/*
+ * Additional MIPS4 instructions
+ */
+
+static ieee754dp fpemu_dp_recip(ieee754dp d)
+{
+	return ieee754dp_div(ieee754dp_one(0), d);
+}
+
+static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
+{
+	return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
+}
+
+static ieee754sp fpemu_sp_recip(ieee754sp s)
+{
+	return ieee754sp_div(ieee754sp_one(0), s);
+}
+
+static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
+{
+	return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
+}
+
+
+static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+	return ieee754dp_add(ieee754dp_mul(s, t), r);
+}
+
+static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+	return ieee754dp_sub(ieee754dp_mul(s, t), r);
+}
+
+static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+	return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r));
+}
+
+static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+	return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r));
+}
+
+
+static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+	return ieee754sp_add(ieee754sp_mul(s, t), r);
+}
+
+static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+	return ieee754sp_sub(ieee754sp_mul(s, t), r);
+}
+
+static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+	return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r));
+}
+
+static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+	return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r));
+}
+
+static int
+fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
+	 mips_instruction ir)
+{
+	unsigned rcsr = 0;	/* resulting csr */
+
+	fpuemuprivate.stats.cp1xops++;
+
+	switch (MIPSInst_FMA_FFMT(ir)) {
+	case s_fmt:		/* 0 */
+		{
+			ieee754sp(*handler) (ieee754sp, ieee754sp,
+					     ieee754sp);
+			ieee754sp fd, fr, fs, ft;
+
+			switch (MIPSInst_FUNC(ir)) {
+			case lwxc1_op:
+				{
+					void *va =
+					    REG_TO_VA(xcp->
+						      regs[MIPSInst_FR(ir)]
+						      +
+						      xcp->
+						      regs[MIPSInst_FT
+							   (ir)]);
+					fpureg_t val;
+					int err = 0;
+					val = mips_get_word(xcp, va, &err);
+					if (err) {
+						fpuemuprivate.stats.
+						    errors++;
+						return SIGBUS;
+					}
+					if (xcp->cp0_status & ST0_FR) {
+						/* load whole register */
+						ctx->
+						    regs[MIPSInst_FD(ir)] =
+						    val;
+					} else if (MIPSInst_FD(ir) & 1) {
+						/* load to m.s. 32 bits */
+#if defined(SINGLE_ONLY_FPU)
+						/* illegal register in single-float mode */
+						return SIGILL;
+#else
+						ctx->
+						    regs[
+							 (MIPSInst_FD(ir) &
+							  ~1)] &=
+						    0xffffffff;
+						ctx->
+						    regs[
+							 (MIPSInst_FD(ir) &
+							  ~1)] |=
+						    val << 32;
+#endif
+					} else {
+						/* load to l.s. 32 bits */
+						ctx->
+						    regs[MIPSInst_FD(ir)]
+						    &= ~0xffffffffLL;
+						ctx->
+						    regs[MIPSInst_FD(ir)]
+						    |= val;
+					}
+				}
+				break;
+
+			case swxc1_op:
+				{
+					void *va =
+					    REG_TO_VA(xcp->
+						      regs[MIPSInst_FR(ir)]
+						      +
+						      xcp->
+						      regs[MIPSInst_FT
+							   (ir)]);
+					unsigned int val;
+					if (xcp->cp0_status & ST0_FR) {
+						/* store whole register */
+						val =
+						    ctx->
+						    regs[MIPSInst_FS(ir)];
+					} else if (MIPSInst_FS(ir) & 1) {
+#if defined(SINGLE_ONLY_FPU)
+						/* illegal register in single-float mode */
+						return SIGILL;
+#else
+						/* store from m.s. 32 bits */
+						val =
+						    ctx->
+						    regs[
+							 (MIPSInst_FS(ir) &
+							  ~1)] >> 32;
+#endif
+					} else {
+						/* store from l.s. 32 bits */
+						val =
+						    ctx->
+						    regs[MIPSInst_FS(ir)];
+					}
+					if (mips_put_word(xcp, va, val)) {
+						fpuemuprivate.stats.
+						    errors++;
+						return SIGBUS;
+					}
+				}
+				break;
+
+			case madd_s_op:
+				handler = fpemu_sp_madd;
+				goto scoptop;
+			case msub_s_op:
+				handler = fpemu_sp_msub;
+				goto scoptop;
+			case nmadd_s_op:
+				handler = fpemu_sp_nmadd;
+				goto scoptop;
+			case nmsub_s_op:
+				handler = fpemu_sp_nmsub;
+				goto scoptop;
+
+			      scoptop:
+				SPFROMREG(fr, MIPSInst_FR(ir));
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				SPFROMREG(ft, MIPSInst_FT(ir));
+				fd = (*handler) (fr, fs, ft);
+				SPTOREG(fd, MIPSInst_FD(ir));
+
+			      copcsr:
+				if (ieee754_cxtest(IEEE754_INEXACT))
+					rcsr |=
+					    FPU_CSR_INE_X | FPU_CSR_INE_S;
+				if (ieee754_cxtest(IEEE754_UNDERFLOW))
+					rcsr |=
+					    FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+				if (ieee754_cxtest(IEEE754_OVERFLOW))
+					rcsr |=
+					    FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+				if (ieee754_cxtest
+				    (IEEE754_INVALID_OPERATION)) rcsr |=
+					    FPU_CSR_INV_X | FPU_CSR_INV_S;
+
+				ctx->sr =
+				    (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
+				if ((ctx->sr >> 5) & ctx->
+				    sr & FPU_CSR_ALL_E) {
+		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
+					return SIGFPE;
+				}
+
+				break;
+
+			default:
+				return SIGILL;
+			}
+		}
+		break;
+
+#if !defined(SINGLE_ONLY_FPU)
+	case d_fmt:		/* 1 */
+		{
+			ieee754dp(*handler) (ieee754dp, ieee754dp,
+					     ieee754dp);
+			ieee754dp fd, fr, fs, ft;
+
+			switch (MIPSInst_FUNC(ir)) {
+			case ldxc1_op:
+				{
+					void *va =
+					    REG_TO_VA(xcp->
+						      regs[MIPSInst_FR(ir)]
+						      +
+						      xcp->
+						      regs[MIPSInst_FT
+							   (ir)]);
+					int err = 0;
+					ctx->regs[MIPSInst_FD(ir)] =
+					    mips_get_dword(xcp, va, &err);
+					if (err) {
+						fpuemuprivate.stats.
+						    errors++;
+						return SIGBUS;
+					}
+				}
+				break;
+
+			case sdxc1_op:
+				{
+					void *va =
+					    REG_TO_VA(xcp->
+						      regs[MIPSInst_FR(ir)]
+						      +
+						      xcp->
+						      regs[MIPSInst_FT
+							   (ir)]);
+					if (mips_put_dword
+					    (xcp, va,
+					     ctx->regs[MIPSInst_FS(ir)])) {
+						fpuemuprivate.stats.
+						    errors++;
+						return SIGBUS;
+					}
+				}
+				break;
+
+			case madd_d_op:
+				handler = fpemu_dp_madd;
+				goto dcoptop;
+			case msub_d_op:
+				handler = fpemu_dp_msub;
+				goto dcoptop;
+			case nmadd_d_op:
+				handler = fpemu_dp_nmadd;
+				goto dcoptop;
+			case nmsub_d_op:
+				handler = fpemu_dp_nmsub;
+				goto dcoptop;
+
+			      dcoptop:
+				DPFROMREG(fr, MIPSInst_FR(ir));
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				DPFROMREG(ft, MIPSInst_FT(ir));
+				fd = (*handler) (fr, fs, ft);
+				DPTOREG(fd, MIPSInst_FD(ir));
+				goto copcsr;
+
+			default:
+				return SIGILL;
+			}
+		}
+		break;
+#endif
+
+	case 0x7:		/* 7 */
+		{
+			if (MIPSInst_FUNC(ir) != pfetch_op) {
+				return SIGILL;
+			}
+			/* ignore prefx operation */
+		}
+		break;
+
+	default:
+		return SIGILL;
+	}
+
+	return 0;
+}
+#endif
+
+
+
+/*
+ * Emulate a single COP1 arithmetic instruction.
+ */
+static int
+fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
+	mips_instruction ir)
+{
+	int rfmt;		/* resulting format */
+	unsigned rcsr = 0;	/* resulting csr */
+	unsigned cond;
+	union {
+		ieee754dp d;
+		ieee754sp s;
+		int w;
+#if __mips64
+		long long l;
+#endif
+	} rv;			/* resulting value */
+
+	fpuemuprivate.stats.cp1ops++;
+	switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
+
+	case s_fmt:{		/* 0 */
+		ieee754sp(*handler) ();
+
+		switch (MIPSInst_FUNC(ir)) {
+			/* binary ops */
+		case fadd_op:
+			handler = ieee754sp_add;
+			goto scopbop;
+		case fsub_op:
+			handler = ieee754sp_sub;
+			goto scopbop;
+		case fmul_op:
+			handler = ieee754sp_mul;
+			goto scopbop;
+		case fdiv_op:
+			handler = ieee754sp_div;
+			goto scopbop;
+
+			/* unary  ops */
+#if __mips >= 2 || __mips64
+		case fsqrt_op:
+			handler = ieee754sp_sqrt;
+			goto scopuop;
+#endif
+#if __mips >= 4 && __mips != 32
+		case frsqrt_op:
+			handler = fpemu_sp_rsqrt;
+			goto scopuop;
+		case frecip_op:
+			handler = fpemu_sp_recip;
+			goto scopuop;
+#endif
+#if __mips >= 4
+		case fmovc_op:
+			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
+			if (((ctx->sr & cond) != 0) !=
+			    ((MIPSInst_FT(ir) & 1) != 0))
+				return 0;
+			SPFROMREG(rv.s, MIPSInst_FS(ir));
+			break;
+		case fmovz_op:
+			if (xcp->regs[MIPSInst_FT(ir)] != 0)
+				return 0;
+			SPFROMREG(rv.s, MIPSInst_FS(ir));
+			break;
+		case fmovn_op:
+			if (xcp->regs[MIPSInst_FT(ir)] == 0)
+				return 0;
+			SPFROMREG(rv.s, MIPSInst_FS(ir));
+			break;
+#endif
+		case fabs_op:
+			handler = ieee754sp_abs;
+			goto scopuop;
+		case fneg_op:
+			handler = ieee754sp_neg;
+			goto scopuop;
+		case fmov_op:
+			/* an easy one */
+			SPFROMREG(rv.s, MIPSInst_FS(ir));
+			break;
+			/* binary op on handler */
+scopbop:
+			{
+				ieee754sp fs, ft;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				SPFROMREG(ft, MIPSInst_FT(ir));
+
+				rv.s = (*handler) (fs, ft);
+				goto copcsr;
+			}
+scopuop:
+			{
+				ieee754sp fs;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				rv.s = (*handler) (fs);
+				goto copcsr;
+			}
+copcsr:
+			if (ieee754_cxtest(IEEE754_INEXACT))
+				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
+			if (ieee754_cxtest(IEEE754_UNDERFLOW))
+				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+			if (ieee754_cxtest(IEEE754_OVERFLOW))
+				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+			if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
+				rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
+			if (ieee754_cxtest
+				(IEEE754_INVALID_OPERATION)) rcsr |=
+					    FPU_CSR_INV_X | FPU_CSR_INV_S;
+				break;
+
+				/* unary conv ops */
+		case fcvts_op:
+			return SIGILL;	/* not defined */
+		case fcvtd_op:
+#if defined(SINGLE_ONLY_FPU)
+			return SIGILL;	/* not defined */
+#else
+			{
+				ieee754sp fs;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				rv.d = ieee754dp_fsp(fs);
+				rfmt = d_fmt;
+				goto copcsr;
+			}
+#endif
+		case fcvtw_op:
+			{
+				ieee754sp fs;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				rv.w = ieee754sp_tint(fs);
+				rfmt = w_fmt;
+				goto copcsr;
+			}
+
+#if __mips >= 2 || __mips64
+		case fround_op:
+		case ftrunc_op:
+		case fceil_op:
+		case ffloor_op:
+			{
+				unsigned int oldrm = ieee754_csr.rm;
+				ieee754sp fs;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+				rv.w = ieee754sp_tint(fs);
+				ieee754_csr.rm = oldrm;
+				rfmt = w_fmt;
+				goto copcsr;
+			}
+#endif			/* __mips >= 2 */
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+		case fcvtl_op:
+			{
+				ieee754sp fs;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				rv.l = ieee754sp_tlong(fs);
+				rfmt = l_fmt;
+				goto copcsr;
+			}
+
+		case froundl_op:
+		case ftruncl_op:
+		case fceill_op:
+		case ffloorl_op:
+			{
+				unsigned int oldrm = ieee754_csr.rm;
+				ieee754sp fs;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+				rv.l = ieee754sp_tlong(fs);
+				ieee754_csr.rm = oldrm;
+				rfmt = l_fmt;
+				goto copcsr;
+			}
+#endif /* __mips64 && !fpu(single) */
+
+		default:
+			if (MIPSInst_FUNC(ir) >= fcmp_op) {
+				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
+				ieee754sp fs, ft;
+
+				SPFROMREG(fs, MIPSInst_FS(ir));
+				SPFROMREG(ft, MIPSInst_FT(ir));
+				rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]);
+				rfmt = -1;
+				if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION))
+					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+				} else {
+					return SIGILL;
+				}
+				break;
+			}
+			break;
+		}
+
+#if !defined(SINGLE_ONLY_FPU)
+	case d_fmt: {
+		ieee754dp(*handler) ();
+
+		switch (MIPSInst_FUNC(ir)) {
+			/* binary ops */
+		case fadd_op:
+			handler = ieee754dp_add;
+			goto dcopbop;
+		case fsub_op:
+			handler = ieee754dp_sub;
+			goto dcopbop;
+		case fmul_op:
+			handler = ieee754dp_mul;
+			goto dcopbop;
+		case fdiv_op:
+			handler = ieee754dp_div;
+			goto dcopbop;
+
+			/* unary  ops */
+#if __mips >= 2 || __mips64
+		case fsqrt_op:
+			handler = ieee754dp_sqrt;
+			goto dcopuop;
+#endif
+#if __mips >= 4 && __mips != 32
+		case frsqrt_op:
+			handler = fpemu_dp_rsqrt;
+			goto dcopuop;
+		case frecip_op:
+			handler = fpemu_dp_recip;
+			goto dcopuop;
+#endif
+#if __mips >= 4
+		case fmovc_op:
+			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
+			if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0))
+				return 0;
+			DPFROMREG(rv.d, MIPSInst_FS(ir));
+			break;
+		case fmovz_op:
+			if (xcp->regs[MIPSInst_FT(ir)] != 0)
+				return 0;
+			DPFROMREG(rv.d, MIPSInst_FS(ir));
+			break;
+		case fmovn_op:
+			if (xcp->regs[MIPSInst_FT(ir)] == 0)
+				return 0;
+			DPFROMREG(rv.d, MIPSInst_FS(ir));
+			break;
+#endif
+		case fabs_op:
+			handler = ieee754dp_abs;
+			goto dcopuop;
+		case fneg_op:
+			handler = ieee754dp_neg;
+			goto dcopuop;
+		case fmov_op:
+			/* an easy one */
+			DPFROMREG(rv.d, MIPSInst_FS(ir));
+			break;
+
+			/* binary op on handler */
+dcopbop:
+			{
+				ieee754dp fs, ft;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				DPFROMREG(ft, MIPSInst_FT(ir));
+
+				rv.d = (*handler) (fs, ft);
+				goto copcsr;
+			}
+dcopuop:
+			{
+				ieee754dp fs;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				rv.d = (*handler) (fs);
+				goto copcsr;
+			}
+
+		/* unary conv ops */
+		case fcvts_op:
+			{
+				ieee754dp fs;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				rv.s = ieee754sp_fdp(fs);
+				rfmt = s_fmt;
+				goto copcsr;
+			}
+		case fcvtd_op:
+			return SIGILL;	/* not defined */
+		case fcvtw_op:
+			{
+				ieee754dp fs;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				rv.w = ieee754dp_tint(fs);	/* wrong */
+				rfmt = w_fmt;
+				goto copcsr;
+			}
+
+#if __mips >= 2 || __mips64
+		case fround_op:
+		case ftrunc_op:
+		case fceil_op:
+		case ffloor_op:
+			{
+				unsigned int oldrm = ieee754_csr.rm;
+				ieee754dp fs;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+				rv.w = ieee754dp_tint(fs);
+				ieee754_csr.rm = oldrm;
+				rfmt = w_fmt;
+				goto copcsr;
+			}
+#endif
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+		case fcvtl_op:
+			{
+				ieee754dp fs;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				rv.l = ieee754dp_tlong(fs);
+				rfmt = l_fmt;
+				goto copcsr;
+			}
+
+		case froundl_op:
+		case ftruncl_op:
+		case fceill_op:
+		case ffloorl_op:
+			{
+				unsigned int oldrm = ieee754_csr.rm;
+				ieee754dp fs;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+				rv.l = ieee754dp_tlong(fs);
+				ieee754_csr.rm = oldrm;
+				rfmt = l_fmt;
+				goto copcsr;
+			}
+#endif /* __mips >= 3 && !fpu(single) */
+
+		default:
+			if (MIPSInst_FUNC(ir) >= fcmp_op) {
+				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
+				ieee754dp fs, ft;
+
+				DPFROMREG(fs, MIPSInst_FS(ir));
+				DPFROMREG(ft, MIPSInst_FT(ir));
+				rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]);
+				rfmt = -1;
+				if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION))
+					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+			} else {
+				return SIGILL;
+			}
+			break;
+		}
+		break;
+	}
+#endif				/* !defined(SINGLE_ONLY_FPU) */
+
+	case w_fmt: {
+		switch (MIPSInst_FUNC(ir)) {
+		case fcvts_op:
+			/* convert word to single precision real */
+			rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]);
+			rfmt = s_fmt;
+			goto copcsr;
+#if !defined(SINGLE_ONLY_FPU)
+		case fcvtd_op:
+			/* convert word to double precision real */
+			rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]);
+			rfmt = d_fmt;
+			goto copcsr;
+#endif
+		default:
+			return SIGILL;
+		}
+		break;
+	}
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+	case l_fmt: {
+		switch (MIPSInst_FUNC(ir)) {
+		case fcvts_op:
+			/* convert long to single precision real */
+			rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]);
+			rfmt = s_fmt;
+			goto copcsr;
+		case fcvtd_op:
+			/* convert long to double precision real */
+			rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]);
+			rfmt = d_fmt;
+			goto copcsr;
+		default:
+			return SIGILL;
+		}
+		break;
+	}
+#endif
+
+	default:
+		return SIGILL;
+	}
+
+	/*
+	 * Update the fpu CSR register for this operation.
+	 * If an exception is required, generate a tidy SIGFPE exception,
+	 * without updating the result register.
+	 * Note: cause exception bits do not accumulate, they are rewritten
+	 * for each op; only the flag/sticky bits accumulate.
+	 */
+	ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
+	if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) {
+		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
+		return SIGFPE;
+	}
+
+	/* 
+	 * Now we can safely write the result back to the register file.
+	 */
+	switch (rfmt) {
+	case -1: {
+#if __mips >= 4
+		cond = fpucondbit[MIPSInst_FD(ir) >> 2];
+#else
+		cond = FPU_CSR_COND;
+#endif
+		if (rv.w)
+			ctx->sr |= cond;
+		else
+			ctx->sr &= ~cond;
+		break;
+	}
+#if !defined(SINGLE_ONLY_FPU)
+	case d_fmt:
+		DPTOREG(rv.d, MIPSInst_FD(ir));
+		break;
+#endif
+	case s_fmt:
+		SPTOREG(rv.s, MIPSInst_FD(ir));
+		break;
+	case w_fmt:
+		SITOREG(rv.w, MIPSInst_FD(ir));
+		break;
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+	case l_fmt:
+		DITOREG(rv.l, MIPSInst_FD(ir));
+		break;
+#endif
+	default:
+		return SIGILL;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Emulate the floating point instruction at EPC, and continue
+ * to run until we hit a non-fp instruction, or a backward
+ * branch.  This cuts down dramatically on the per instruction 
+ * exception overhead.
+ */
+int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp)
+{
+	struct mips_fpu_soft_struct *ctx = &current->thread.fpu.soft;
+	unsigned long oldepc, prevepc;
+	unsigned int insn;
+	int sig = 0;
+	int err = 0;
+
+	oldepc = xcp->cp0_epc;
+	do {
+		prevepc = xcp->cp0_epc;
+		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
+		if (err) {
+			fpuemuprivate.stats.errors++;
+			return SIGBUS;
+		}
+		if (insn != 0)
+			sig = cop1Emulate(xcptno, xcp, ctx);
+		else
+			xcp->cp0_epc += 4;	/* skip nops */
+	} while (xcp->cp0_epc > prevepc && sig == 0);
+
+	/* SIGILL indicates a non-fpu instruction */
+	if (sig == SIGILL && xcp->cp0_epc != oldepc)
+		/* but if epc has advanced, then ignore it */
+		sig = 0;
+
+	return sig;
+}
+
+
+#ifdef NOTDEF
+/*
+ * Patch up the hardware fpu state when an f.p. exception occurs.  
+ */
+static int cop1Patcher(int xcptno, struct pt_regs *xcp)
+{
+	struct mips_fpu_soft_struct *ctx = &current->thread.fpu.soft;
+	unsigned sr;
+	int sig;
+
+	/* reenable Cp1, else fpe_save() will get nested exception */
+	sr = mips_bissr(ST0_CU1);
+
+	/* get fpu registers and status, then clear pending exceptions */
+	fpe_save(ctx);
+	fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X);
+
+	/* get current rounding mode for IEEE library, and emulate insn */
+	ieee754_csr.rm = ieee_rm[ctx->sr & 0x3];
+	sig = cop1Emulate(xcptno, xcp, ctx);
+
+	/* don't return with f.p. exceptions pending */
+	ctx->sr &= ~FPU_CSR_ALL_X;
+	fpe_restore(ctx);
+
+	mips_setsr(sr);
+	return sig;
+}
+
+void _cop1_init(int emulate)
+{
+	extern int _nofpu;
+
+	if (emulate) {
+		/* 
+		 * Install cop1 emulator to handle "coprocessor unusable" exception
+		 */
+		xcption(XCPTCPU, cop1Handler);
+		fpuemuactive = 1;	/* tell dbg.c that we are in charge */
+		_nofpu = 0;	/* tell setjmp() it "has" an fpu */
+	} else {
+		/* 
+		 * Install cop1 emulator for floating point exceptions only,
+		 * i.e. denormalised results, underflow, overflow etc, which
+		 * must be emulated in s/w.
+		 */
+#ifdef 1
+		/* r4000 or above use dedicate exception */
+		xcption(XCPTFPE, cop1Patcher);
+#else
+		/* r3000 et al use interrupt */
+		extern int _sbd_getfpuintr(void);
+		int intno = _sbd_getfpuintr();
+		intrupt(intno, cop1Patcher, 0);
+		mips_bissr(SR_IM0 << intno);
+#endif
+
+#if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU)
+		/* For R4640/R4650 compiled *without* the -msingle-float flag,
+		   then we share responsibility: the h/w handles the single
+		   precision operations, and the trap emulator handles the
+		   double precision. We set fpuemuactive so that dbg.c first
+		   fetches the s/w state before saving the h/w state. */
+		fpuemuactive = 1;
+		{
+			int i;
+			/* initialise the unused d.p high order words to be NaN */
+			for (i = 0; i < 32; i++)
+				current->thread.fpu.soft.regs[i] =
+				    0x7ff80bad00000000LL;
+		}
+#endif				/* (r4640 || r4650) && !fpu(single) */
+	}
+}
+#endif
+
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_add.c linux/arch/mips/math-emu/dp_add.c
--- v2.4.3/linux/arch/mips/math-emu/dp_add.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_add.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,186 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
+{
+	COMPXDP;
+	COMPYDP;
+
+	EXPLODEXDP;
+	EXPLODEYDP;
+
+	CLEARCX;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(y, "add", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754dp_nanxcpt(x, "add", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754dp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Inifity handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		if (xs == ys)
+			return x;
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+		return x;
+
+		/* Zero handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+		if (xs == ys)
+			return x;
+		else
+			return ieee754dp_zero(ieee754_csr.rm ==
+					      IEEE754_RD);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		return x;
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		DPDNORMX;
+
+		/* FALL THROUGH */
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		DPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		DPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	assert(xm & DP_HIDDEN_BIT);
+	assert(ym & DP_HIDDEN_BIT);
+
+	/* provide guard,round and stick bit space */
+	xm <<= 3;
+	ym <<= 3;
+
+	if (xe > ye) {
+		/* have to shift y fraction right to align
+		 */
+		int s = xe - ye;
+		ym = XDPSRS(ym, s);
+		ye += s;
+	} else if (ye > xe) {
+		/* have to shift x fraction right to align
+		 */
+		int s = ye - xe;
+		xm = XDPSRS(xm, s);
+		xe += s;
+	}
+	assert(xe == ye);
+	assert(xe <= DP_EMAX);
+
+	if (xs == ys) {
+		/* generate 28 bit result of adding two 27 bit numbers
+		 * leaving result in xm,xs,xe
+		 */
+		xm = xm + ym;
+		xe = xe;
+		xs = xs;
+
+		if (xm >> (DP_MBITS + 1 + 3)) {	/* carry out */
+			xm = XDPSRS1(xm);
+			xe++;
+		}
+	} else {
+		if (xm >= ym) {
+			xm = xm - ym;
+			xe = xe;
+			xs = xs;
+		} else {
+			xm = ym - xm;
+			xe = xe;
+			xs = ys;
+		}
+		if (xm == 0)
+			return ieee754dp_zero(ieee754_csr.rm ==
+					      IEEE754_RD);
+
+		/* normalize to rounding precision */
+		while ((xm >> (DP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+
+	}
+	DPNORMRET2(xs, xe, xm, "add", x, y);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_cmp.c linux/arch/mips/math-emu/dp_cmp.c
--- v2.4.3/linux/arch/mips/math-emu/dp_cmp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_cmp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,58 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp)
+{
+	CLEARCX;
+
+	if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) {
+		if (cmp & IEEE754_CUN)
+			return 1;
+		if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
+			if (SETCX(IEEE754_INVALID_OPERATION))
+				return ieee754si_xcpt(0, "fcmpf", x);
+		}
+		return 0;
+	} else {
+		long long int vx = x.bits;
+		long long int vy = y.bits;
+
+		if (vx < 0)
+			vx = -vx ^ DP_SIGN_BIT;
+		if (vy < 0)
+			vy = -vy ^ DP_SIGN_BIT;
+
+		if (vx < vy)
+			return (cmp & IEEE754_CLT) != 0;
+		else if (vx == vy)
+			return (cmp & IEEE754_CEQ) != 0;
+		else
+			return (cmp & IEEE754_CGT) != 0;
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_div.c linux/arch/mips/math-emu/dp_div.c
--- v2.4.3/linux/arch/mips/math-emu/dp_div.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_div.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,160 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
+{
+	COMPXDP;
+	COMPYDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+	EXPLODEYDP;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(y, "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754dp_nanxcpt(x, "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754dp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Infinity handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+		return ieee754dp_zero(xs ^ ys);
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+		return ieee754dp_inf(xs ^ ys);
+
+		/* Zero handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		SETCX(IEEE754_ZERO_DIVIDE);
+		return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+		return ieee754dp_zero(xs == ys ? 0 : 1);
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		DPDNORMX;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		DPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		DPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	assert(xm & DP_HIDDEN_BIT);
+	assert(ym & DP_HIDDEN_BIT);
+
+	/* provide rounding space */
+	xm <<= 3;
+	ym <<= 3;
+
+	{
+		/* now the dirty work */
+
+		unsigned long long rm = 0;
+		int re = xe - ye;
+		unsigned long long bm;
+
+		for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) {
+			if (xm >= ym) {
+				xm -= ym;
+				rm |= bm;
+				if (xm == 0)
+					break;
+			}
+			xm <<= 1;
+		}
+		rm <<= 1;
+		if (xm)
+			rm |= 1;	/* have remainder, set sticky */
+
+		assert(rm);
+
+		/* normalise rm to rounding precision ?
+		 */
+		while ((rm >> (DP_MBITS + 3)) == 0) {
+			rm <<= 1;
+			re--;
+		}
+
+		DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_fint.c linux/arch/mips/math-emu/dp_fint.c
--- v2.4.3/linux/arch/mips/math-emu/dp_fint.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_fint.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,78 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_fint(int x)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	if (x == 0)
+		return ieee754dp_zero(0);
+	if (x == 1 || x == -1)
+		return ieee754dp_one(x < 0);
+	if (x == 10 || x == -10)
+		return ieee754dp_ten(x < 0);
+
+	xs = (x < 0);
+	if (xs) {
+		if (x == (1 << 31))
+			xm = ((unsigned) 1 << 31);	/* max neg can't be safely negated */
+		else
+			xm = -x;
+	} else {
+		xm = x;
+	}
+
+#if 1
+	/* normalize - result can never be inexact or overflow */
+	xe = DP_MBITS;
+	while ((xm >> DP_MBITS) == 0) {
+		xm <<= 1;
+		xe--;
+	}
+	return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+#else
+	/* normalize */
+	xe = DP_MBITS + 3;
+	while ((xm >> (DP_MBITS + 3)) == 0) {
+		xm <<= 1;
+		xe--;
+	}
+	DPNORMRET1(xs, xe, xm, "fint", x);
+#endif
+}
+
+ieee754dp ieee754dp_funs(unsigned int u)
+{
+	if ((int) u < 0)
+		return ieee754dp_add(ieee754dp_1e31(),
+				     ieee754dp_fint(u & ~(1 << 31)));
+	return ieee754dp_fint(u);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_flong.c linux/arch/mips/math-emu/dp_flong.c
--- v2.4.3/linux/arch/mips/math-emu/dp_flong.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_flong.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,76 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_flong(long long x)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	if (x == 0)
+		return ieee754dp_zero(0);
+	if (x == 1 || x == -1)
+		return ieee754dp_one(x < 0);
+	if (x == 10 || x == -10)
+		return ieee754dp_ten(x < 0);
+
+	xs = (x < 0);
+	if (xs) {
+		if (x == (1ULL << 63))
+			xm = (1ULL << 63);	/* max neg can't be safely negated */
+		else
+			xm = -x;
+	} else {
+		xm = x;
+	}
+
+	/* normalize */
+	xe = DP_MBITS + 3;
+	if (xm >> (DP_MBITS + 1 + 3)) {
+		/* shunt out overflow bits */
+		while (xm >> (DP_MBITS + 1 + 3)) {
+			XDPSRSX1();
+		}
+	} else {
+		/* normalize in grs extended double precision */
+		while ((xm >> (DP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+	}
+	DPNORMRET1(xs, xe, xm, "dp_flong", x);
+}
+
+ieee754dp ieee754dp_fulong(unsigned long long u)
+{
+	if ((long long) u < 0)
+		return ieee754dp_add(ieee754dp_1e63(),
+				     ieee754dp_flong(u & ~(1ULL << 63)));
+	return ieee754dp_flong(u);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_frexp.c linux/arch/mips/math-emu/dp_frexp.c
--- v2.4.3/linux/arch/mips/math-emu/dp_frexp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_frexp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,53 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+/* close to ieeep754dp_logb 
+*/
+ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr)
+{
+	COMPXDP;
+	CLEARCX;
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_INF:
+	case IEEE754_CLASS_ZERO:
+		*eptr = 0;
+		return x;
+	case IEEE754_CLASS_DNORM:
+		DPDNORMX;
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	*eptr = xe + 1;
+	return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_fsp.c linux/arch/mips/math-emu/dp_fsp.c
--- v2.4.3/linux/arch/mips/math-emu/dp_fsp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_fsp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,70 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_fsp(ieee754sp x)
+{
+	COMPXSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_SNAN:
+		return ieee754dp_nanxcpt(builddp(xs,
+						 DP_EMAX + 1 + DP_EBIAS,
+						 ((unsigned long long) xm
+						  << (DP_MBITS -
+						      SP_MBITS))), "fsp",
+					 x);
+	case IEEE754_CLASS_INF:
+		return ieee754dp_inf(xs);
+	case IEEE754_CLASS_ZERO:
+		return ieee754dp_zero(xs);
+	case IEEE754_CLASS_DNORM:
+		/* normalize */
+		while ((xm >> SP_MBITS) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+
+	/* CANT possibly overflow,underflow, or need rounding
+	 */
+
+	/* drop the hidden bit */
+	xm &= ~SP_HIDDEN_BIT;
+
+	return builddp(xs, xe + DP_EBIAS,
+		       (unsigned long long) xm << (DP_MBITS - SP_MBITS));
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_logb.c linux/arch/mips/math-emu/dp_logb.c
--- v2.4.3/linux/arch/mips/math-emu/dp_logb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_logb.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,54 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_logb(ieee754dp x)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+		return ieee754dp_nanxcpt(x, "logb", x);
+	case IEEE754_CLASS_QNAN:
+		return x;
+	case IEEE754_CLASS_INF:
+		return ieee754dp_inf(0);
+	case IEEE754_CLASS_ZERO:
+		return ieee754dp_inf(1);
+	case IEEE754_CLASS_DNORM:
+		DPDNORMX;
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	return ieee754dp_fint(xe);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_modf.c linux/arch/mips/math-emu/dp_modf.c
--- v2.4.3/linux/arch/mips/math-emu/dp_modf.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_modf.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,80 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+/* modf function is always exact for a finite number
+*/
+ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_INF:
+	case IEEE754_CLASS_ZERO:
+		*ip = x;
+		return x;
+	case IEEE754_CLASS_DNORM:
+		/* far to small */
+		*ip = ieee754dp_zero(xs);
+		return x;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	if (xe < 0) {
+		*ip = ieee754dp_zero(xs);
+		return x;
+	}
+	if (xe >= DP_MBITS) {
+		*ip = x;
+		return ieee754dp_zero(xs);
+	}
+	/* generate ipart mantissa by clearing bottom bits 
+	 */
+	*ip = builddp(xs, xe + DP_EBIAS,
+		      ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) &
+		      ~DP_HIDDEN_BIT);
+
+	/* generate fpart mantissa by clearing top bits
+	 * and normalizing (must be able to normalize)
+	 */
+	xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe));
+	if (xm == 0)
+		return ieee754dp_zero(xs);
+
+	while ((xm >> DP_MBITS) == 0) {
+		xm <<= 1;
+		xe--;
+	}
+	return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_mul.c linux/arch/mips/math-emu/dp_mul.c
--- v2.4.3/linux/arch/mips/math-emu/dp_mul.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_mul.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,180 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
+{
+	COMPXDP;
+	COMPYDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+	EXPLODEYDP;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(y, "mul", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754dp_nanxcpt(x, "mul", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754dp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Infinity handeling */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		return ieee754dp_inf(xs ^ ys);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		return ieee754dp_zero(xs ^ ys);
+
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		DPDNORMX;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		DPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		DPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	/* rm = xm * ym, re = xe+ye basicly */
+	assert(xm & DP_HIDDEN_BIT);
+	assert(ym & DP_HIDDEN_BIT);
+	{
+		int re = xe + ye;
+		int rs = xs ^ ys;
+		unsigned long long rm;
+
+		/* shunt to top of word */
+		xm <<= 64 - (DP_MBITS + 1);
+		ym <<= 64 - (DP_MBITS + 1);
+
+		/* multiply 32bits xm,ym to give high 32bits rm with stickness
+		 */
+
+		/* 32 * 32 => 64 */
+#define DPXMULT(x,y)	((unsigned long long)(x) * (unsigned long long)y)
+
+		{
+			unsigned lxm = xm;
+			unsigned hxm = xm >> 32;
+			unsigned lym = ym;
+			unsigned hym = ym >> 32;
+			unsigned long long lrm;
+			unsigned long long hrm;
+
+			lrm = DPXMULT(lxm, lym);
+			hrm = DPXMULT(hxm, hym);
+
+			{
+				unsigned long long t = DPXMULT(lxm, hym);
+				{
+					unsigned long long at =
+					    lrm + (t << 32);
+					hrm += at < lrm;
+					lrm = at;
+				}
+				hrm = hrm + (t >> 32);
+			}
+
+			{
+				unsigned long long t = DPXMULT(hxm, lym);
+				{
+					unsigned long long at =
+					    lrm + (t << 32);
+					hrm += at < lrm;
+					lrm = at;
+				}
+				hrm = hrm + (t >> 32);
+			}
+			rm = hrm | (lrm != 0);
+		}
+
+		/*
+		 * sticky shift down to normal rounding precision
+		 */
+		if ((signed long long) rm < 0) {
+			rm =
+			    (rm >> (64 - (DP_MBITS + 1 + 3))) |
+			    ((rm << (DP_MBITS + 1 + 3)) != 0);
+			re++;
+		} else {
+			rm =
+			    (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) |
+			    ((rm << (DP_MBITS + 1 + 3 + 1)) != 0);
+		}
+		assert(rm & (DP_HIDDEN_BIT << 3));
+		DPNORMRET2(rs, re, rm, "mul", x, y);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_scalb.c linux/arch/mips/math-emu/dp_scalb.c
--- v2.4.3/linux/arch/mips/math-emu/dp_scalb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_scalb.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,58 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_scalb(ieee754dp x, int n)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+		return ieee754dp_nanxcpt(x, "scalb", x, n);
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_INF:
+	case IEEE754_CLASS_ZERO:
+		return x;
+	case IEEE754_CLASS_DNORM:
+		DPDNORMX;
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
+}
+
+
+ieee754dp ieee754dp_ldexp(ieee754dp x, int n)
+{
+	return ieee754dp_scalb(x, n);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_simple.c linux/arch/mips/math-emu/dp_simple.c
--- v2.4.3/linux/arch/mips/math-emu/dp_simple.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_simple.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,66 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+int ieee754dp_finite(ieee754dp x)
+{
+	return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS;
+}
+
+ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y)
+{
+	CLEARCX;
+	DPSIGN(x) = DPSIGN(y);
+	return x;
+}
+
+
+ieee754dp ieee754dp_neg(ieee754dp x)
+{
+	CLEARCX;
+
+	if (ieee754dp_isnan(x))	/* but not infinity */
+		return ieee754dp_nanxcpt(x, "neg", x);
+
+	/* quick fix up */
+	DPSIGN(x) ^= 1;
+	return x;
+}
+
+
+ieee754dp ieee754dp_abs(ieee754dp x)
+{
+	CLEARCX;
+
+	if (ieee754dp_isnan(x))	/* but not infinity */
+		return ieee754dp_nanxcpt(x, "abs", x);
+
+	/* quick fix up */
+	DPSIGN(x) = 0;
+	return x;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_sqrt.c linux/arch/mips/math-emu/dp_sqrt.c
--- v2.4.3/linux/arch/mips/math-emu/dp_sqrt.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_sqrt.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,167 @@
+/* IEEE754 floating point arithmetic
+ * double precision square root
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+static const struct ieee754dp_konst knan = {
+#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
+	0, 0, DP_EBIAS + DP_EMAX + 1, 0
+#else
+	0, DP_EBIAS + DP_EMAX + 1, 0, 0
+#endif
+};
+
+#define nan	((ieee754dp)knan)
+
+static const unsigned table[] = {
+	0, 1204, 3062, 5746, 9193, 13348, 18162, 23592,
+	29598, 36145, 43202, 50740, 58733, 67158, 75992,
+	85215, 83599, 71378, 60428, 50647, 41945, 34246,
+	27478, 21581, 16499, 12183, 8588, 5674, 3403,
+	1742, 661, 130
+};
+
+ieee754dp ieee754dp_sqrt(ieee754dp x)
+{
+	struct ieee754_csr oldcsr;
+	ieee754dp y, z, t;
+	unsigned scalx, yh;
+	COMPXDP;
+
+	EXPLODEXDP;
+
+	/* x == INF or NAN? */
+	switch (xc) {
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_SNAN:
+		/* sqrt(Nan) = Nan */
+		return ieee754dp_nanxcpt(x, "sqrt");
+	case IEEE754_CLASS_ZERO:
+		/* sqrt(0) = 0 */
+		return x;
+	case IEEE754_CLASS_INF:
+		if (xs)
+			/* sqrt(-Inf) = Nan */
+			return ieee754dp_nanxcpt(nan, "sqrt");
+		/* sqrt(+Inf) = Inf */
+		return x;
+	case IEEE754_CLASS_DNORM:
+		DPDNORMX;
+		/* fall through */
+	case IEEE754_CLASS_NORM:
+		if (xs)
+			/* sqrt(-x) = Nan */
+			return ieee754dp_nanxcpt(nan, "sqrt");
+		break;
+	}
+
+	/* save old csr; switch off INX enable & flag; set RN rounding */
+	oldcsr = ieee754_csr;
+	ieee754_csr.mx &= ~IEEE754_INEXACT;
+	ieee754_csr.sx &= ~IEEE754_INEXACT;
+	ieee754_csr.rm = IEEE754_RN;
+
+	/* adjust exponent to prevent overflow */
+	scalx = 0;
+	if (xe > 512) {		/* x > 2**-512? */
+		xe -= 512;	/* x = x / 2**512 */
+		scalx += 256;
+	} else if (xe < -512) {	/* x < 2**-512? */
+		xe += 512;	/* x = x * 2**512 */
+		scalx -= 256;
+	}
+
+	y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+
+	/* magic initial approximation to almost 8 sig. bits */
+	yh = y.bits >> 32;
+	yh = (yh >> 1) + 0x1ff80000;
+	yh = yh - table[(yh >> 15) & 31];
+	y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff);
+
+	/* Heron's rule once with correction to improve to ~18 sig. bits */
+	/* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */
+	t = ieee754dp_div(x, y);
+	y = ieee754dp_add(y, t);
+	y.bits -= 0x0010000600000000LL;
+	y.bits &= 0xffffffff00000000LL;
+
+	/* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
+	/* t=y*y; z=t;  pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
+	z = t = ieee754dp_mul(y, y);
+	t.parts.bexp += 0x001;
+	t = ieee754dp_add(t, z);
+	z = ieee754dp_mul(ieee754dp_sub(x, z), y);
+
+	/* t=z/(t+x) ;  pt[n0]+=0x00100000; y+=t; */
+	t = ieee754dp_div(z, ieee754dp_add(t, x));
+	t.parts.bexp += 0x001;
+	y = ieee754dp_add(y, t);
+
+	/* twiddle last bit to force y correctly rounded */
+
+	/* set RZ, clear INEX flag */
+	ieee754_csr.rm = IEEE754_RZ;
+	ieee754_csr.sx &= ~IEEE754_INEXACT;
+
+	/* t=x/y; ...chopped quotient, possibly inexact */
+	t = ieee754dp_div(x, y);
+
+	if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) {
+
+		if (!(ieee754_csr.sx & IEEE754_INEXACT))
+			/* t = t-ulp */
+			t.bits -= 1;
+
+		/* add inexact to result status */
+		oldcsr.cx |= IEEE754_INEXACT;
+		oldcsr.sx |= IEEE754_INEXACT;
+
+		switch (oldcsr.rm) {
+		case IEEE754_RP:
+			y.bits += 1;
+			/* drop through */
+		case IEEE754_RN:
+			t.bits += 1;
+			break;
+		}
+
+		/* y=y+t; ...chopped sum */
+		y = ieee754dp_add(y, t);
+
+		/* adjust scalx for correctly rounded sqrt(x) */
+		scalx -= 1;
+	}
+
+	/* py[n0]=py[n0]+scalx; ...scale back y */
+	y.parts.bexp += scalx;
+
+	/* restore rounding mode, possibly set inexact */
+	ieee754_csr = oldcsr;
+
+	return y;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_sub.c linux/arch/mips/math-emu/dp_sub.c
--- v2.4.3/linux/arch/mips/math-emu/dp_sub.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_sub.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,193 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
+{
+	COMPXDP;
+	COMPYDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+	EXPLODEYDP;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754dp_nanxcpt(y, "sub", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754dp_nanxcpt(x, "sub", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754dp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Inifity handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		if (xs != ys)
+			return x;
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+		return ieee754dp_inf(ys ^ 1);
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+		return x;
+
+		/* Zero handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+		if (xs != ys)
+			return x;
+		else
+			return ieee754dp_zero(ieee754_csr.rm ==
+					      IEEE754_RD);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		return x;
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+		/* quick fix up */
+		DPSIGN(y) ^= 1;
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		DPDNORMX;
+		/* FAAL THOROUGH */
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		/* normalize ym,ye */
+		DPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		/* normalize xm,xe */
+		DPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	/* flip sign of y and handle as add */
+	ys ^= 1;
+
+	assert(xm & DP_HIDDEN_BIT);
+	assert(ym & DP_HIDDEN_BIT);
+
+
+	/* provide guard,round and stick bit dpace */
+	xm <<= 3;
+	ym <<= 3;
+
+	if (xe > ye) {
+		/* have to shift y fraction right to align
+		 */
+		int s = xe - ye;
+		ym = XDPSRS(ym, s);
+		ye += s;
+	} else if (ye > xe) {
+		/* have to shift x fraction right to align
+		 */
+		int s = ye - xe;
+		xm = XDPSRS(xm, s);
+		xe += s;
+	}
+	assert(xe == ye);
+	assert(xe <= DP_EMAX);
+
+	if (xs == ys) {
+		/* generate 28 bit result of adding two 27 bit numbers
+		 */
+		xm = xm + ym;
+		xe = xe;
+		xs = xs;
+
+		if (xm >> (DP_MBITS + 1 + 3)) {	/* carry out */
+			xm = XDPSRS1(xm);	/* shift preserving sticky */
+			xe++;
+		}
+	} else {
+		if (xm >= ym) {
+			xm = xm - ym;
+			xe = xe;
+			xs = xs;
+		} else {
+			xm = ym - xm;
+			xe = xe;
+			xs = ys;
+		}
+		if (xm == 0)
+			if (ieee754_csr.rm == IEEE754_RD)
+				return ieee754dp_zero(1);	/* round negative inf. => sign = -1 */
+			else
+				return ieee754dp_zero(0);	/* other round modes   => sign = 1 */
+
+		/* normalize to rounding precision 
+		 */
+		while ((xm >> (DP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+	}
+	DPNORMRET2(xs, xe, xm, "sub", x, y);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_tint.c linux/arch/mips/math-emu/dp_tint.c
--- v2.4.3/linux/arch/mips/math-emu/dp_tint.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_tint.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,88 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include <linux/kernel.h>
+#include "ieee754dp.h"
+
+int ieee754dp_tint(ieee754dp x)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754si_xcpt(ieee754si_indef(), "fixdp", x);
+	case IEEE754_CLASS_INF:
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754si_xcpt(ieee754si_indef(), "fixdp", x);
+	case IEEE754_CLASS_ZERO:
+		return 0;
+	case IEEE754_CLASS_DNORM:	/* much to small */
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754si_xcpt(0, "fixdp", x);
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	if (xe >= 31) {
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754si_xcpt(ieee754si_indef(), "fix", x);
+	}
+	if (xe < 0) {
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754si_xcpt(0, "fix", x);
+	}
+	/* oh gawd */
+	if (xe > DP_MBITS) {
+		xm <<= xe - DP_MBITS;
+	} else if (xe < DP_MBITS) {
+		/* XXX no rounding 
+		 */
+		xm >>= DP_MBITS - xe;
+	}
+	if (xs)
+		return -xm;
+	else
+		return xm;
+}
+
+
+unsigned int ieee754dp_tuns(ieee754dp x)
+{
+	ieee754dp hb = ieee754dp_1e31();
+
+	/* what if x < 0 ?? */
+	if (ieee754dp_lt(x, hb))
+		return (unsigned) ieee754dp_tint(x);
+
+	return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) |
+	    ((unsigned) 1 << 31);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/dp_tlong.c linux/arch/mips/math-emu/dp_tlong.c
--- v2.4.3/linux/arch/mips/math-emu/dp_tlong.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/dp_tlong.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,141 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+long long ieee754dp_tlong(ieee754dp x)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+	case IEEE754_CLASS_INF:
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+	case IEEE754_CLASS_ZERO:
+		return 0;
+	case IEEE754_CLASS_DNORM:	/* much too small */
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754di_xcpt(0, "dp_tlong", x);
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	if (xe >= 63) {
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+	}
+	if (xe < 0) {
+		if (ieee754_csr.rm == IEEE754_RU) {
+			if (xs) {	/* Negative  */
+				return 0x0000000000000000LL;
+			} else {	/* Positive */
+				return 0x0000000000000001LL;
+			}
+		} else if (ieee754_csr.rm == IEEE754_RD) {
+			if (xs) {	/* Negative , return -1 */
+				return 0xffffffffffffffffLL;
+			} else {	/* Positive */
+				return 0x0000000000000000LL;
+			}
+		} else {
+			SETCX(IEEE754_UNDERFLOW);
+			return ieee754di_xcpt(0, "dp_tlong", x);
+		}
+	}
+	/* oh gawd */
+	if (xe > DP_MBITS) {
+		xm <<= xe - DP_MBITS;
+	} else if (xe < DP_MBITS) {
+		unsigned long long residue;
+		unsigned long long mask = 0;
+		int i;
+		int round;
+		int sticky;
+		int odd;
+
+		/* compute mask */
+		for (i = 0; i < DP_MBITS - xe; i++) {
+			mask = mask << 1;
+			mask = mask | 0x1;
+		}
+		residue = (xm & mask) << (64 - (DP_MBITS - xe));
+		round =
+		    ((0x8000000000000000LL & residue) !=
+		     0x0000000000000000LL);
+		sticky =
+		    ((0x7fffffffffffffffLL & residue) !=
+		     0x0000000000000000LL);
+
+		xm >>= DP_MBITS - xe;
+
+		odd = ((xm & 0x1) != 0x0000000000000000LL);
+
+		/* Do the rounding */
+		if (!round && sticky) {
+			if ((ieee754_csr.rm == IEEE754_RU && !xs)
+			    || (ieee754_csr.rm == IEEE754_RD && xs)) {
+				xm++;
+			}
+		} else if (round && !sticky) {
+			if ((ieee754_csr.rm == IEEE754_RU && !xs)
+			    || (ieee754_csr.rm == IEEE754_RD && xs)
+			    || (ieee754_csr.rm == IEEE754_RN && odd)) {
+				xm++;
+			}
+		} else if (round && sticky) {
+			if ((ieee754_csr.rm == IEEE754_RU && !xs)
+			    || (ieee754_csr.rm == IEEE754_RD && xs)
+			    || (ieee754_csr.rm == IEEE754_RN)) {
+				xm++;
+			}
+		}
+	}
+	if (xs)
+		return -xm;
+	else
+		return xm;
+}
+
+
+unsigned long long ieee754dp_tulong(ieee754dp x)
+{
+	ieee754dp hb = ieee754dp_1e63();
+
+	/* what if x < 0 ?? */
+	if (ieee754dp_lt(x, hb))
+		return (unsigned long long) ieee754dp_tlong(x);
+
+	return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) |
+	    (1ULL << 63);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754.c linux/arch/mips/math-emu/ieee754.c
--- v2.4.3/linux/arch/mips/math-emu/ieee754.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,138 @@
+/* ieee754 floating point arithmetic
+ * single and double precision
+ *
+ * BUGS
+ * not much dp done
+ * doesnt generate IEEE754_INEXACT
+ *
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754int.h"
+
+#define DP_EBIAS	1023
+#define DP_EMIN		(-1022)
+#define DP_EMAX		1023
+
+#define SP_EBIAS	127
+#define SP_EMIN		(-126)
+#define SP_EMAX		127
+
+/* indexed by class */
+const char *const ieee754_cname[] = {
+	"Normal",
+	"Zero",
+	"Denormal",
+	"Infinity",
+	"QNaN",
+	"SNaN",
+};
+
+/* the control status register 
+*/
+struct ieee754_csr ieee754_csr;
+
+/* special constants
+*/
+
+
+#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
+#define SPSTR(s,b,m) {m,b,s}
+#define DPSTR(s,b,mh,ml) {ml,mh,b,s}
+#endif
+
+#ifdef __MIPSEB__
+#define SPSTR(s,b,m) {s,b,m}
+#define DPSTR(s,b,mh,ml) {s,b,mh,ml}
+#endif
+
+const struct ieee754dp_konst __ieee754dp_spcvals[] = {
+	DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0),	/* + zero   */
+	DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0),	/* - zero   */
+	DPSTR(0, DP_EBIAS, 0, 0),	/* + 1.0   */
+	DPSTR(1, DP_EBIAS, 0, 0),	/* - 1.0   */
+	DPSTR(0, 3 + DP_EBIAS, 0x40000, 0),	/* + 10.0   */
+	DPSTR(1, 3 + DP_EBIAS, 0x40000, 0),	/* - 10.0   */
+	DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0),	/* + infinity */
+	DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0),	/* - infinity */
+	DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0),	/* + indef quiet Nan */
+	DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF),	/* + max */
+	DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF),	/* - max */
+	DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0),	/* + min normal */
+	DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0),	/* - min normal */
+	DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1),	/* + min denormal */
+	DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1),	/* - min denormal */
+	DPSTR(0, 31 + DP_EBIAS, 0, 0),	/* + 1.0e31 */
+	DPSTR(0, 63 + DP_EBIAS, 0, 0),	/* + 1.0e63 */
+};
+
+const struct ieee754sp_konst __ieee754sp_spcvals[] = {
+	SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0),	/* + zero   */
+	SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0),	/* - zero   */
+	SPSTR(0, SP_EBIAS, 0),	/* + 1.0   */
+	SPSTR(1, SP_EBIAS, 0),	/* - 1.0   */
+	SPSTR(0, 3 + SP_EBIAS, 0x200000),	/* + 10.0   */
+	SPSTR(1, 3 + SP_EBIAS, 0x200000),	/* - 10.0   */
+	SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0),	/* + infinity */
+	SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0),	/* - infinity */
+	SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000),	/* + indef quiet Nan  */
+	SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF),	/* + max normal */
+	SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF),	/* - max normal */
+	SPSTR(0, SP_EMIN + SP_EBIAS, 0),	/* + min normal */
+	SPSTR(1, SP_EMIN + SP_EBIAS, 0),	/* - min normal */
+	SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1),	/* + min denormal */
+	SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1),	/* - min denormal */
+	SPSTR(0, 31 + SP_EBIAS, 0),	/* + 1.0e31 */
+	SPSTR(0, 63 + SP_EBIAS, 0),	/* + 1.0e63 */
+};
+
+
+int ieee754si_xcpt(int r, const char *op, ...)
+{
+	struct ieee754xctx ax;
+
+	if (!TSTX())
+		return r;
+	ax.op = op;
+	ax.rt = IEEE754_RT_SI;
+	ax.rv.si = r;
+	va_start(ax.ap, op);
+	ieee754_xcpt(&ax);
+	return ax.rv.si;
+}
+
+long long ieee754di_xcpt(long long r, const char *op, ...)
+{
+	struct ieee754xctx ax;
+
+	if (!TSTX())
+		return r;
+	ax.op = op;
+	ax.rt = IEEE754_RT_DI;
+	ax.rv.di = r;
+	va_start(ax.ap, op);
+	ieee754_xcpt(&ax);
+	return ax.rv.di;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754.h linux/arch/mips/math-emu/ieee754.h
--- v2.4.3/linux/arch/mips/math-emu/ieee754.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,490 @@
+/* single and double precision fp ops
+ * missing extended precision.
+*/
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+/**************************************************************************
+ *  Nov 7, 2000
+ *  Modification to allow integration with Linux kernel 
+ *
+ *  Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+
+#ifdef __KERNEL__
+/* Going from Algorithmics to Linux native environment, add this */
+#include <linux/types.h>
+
+/* 
+ * Not very pretty, but the Linux kernel's normal va_list definition 
+ * does not allow it to be used as a structure element, as it is here.
+ */
+#ifndef _STDARG_H
+#include <stdarg.h>
+#endif
+
+#else
+
+/* Note that __KERNEL__ is taken to mean Linux kernel */
+
+#if #system(OpenBSD)
+#include <machine/types.h>
+#endif
+#include <machine/endian.h>
+
+#endif				/* __KERNEL__ */
+
+#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
+struct ieee754dp_konst {
+	unsigned mantlo:32;
+	unsigned manthi:20;
+	unsigned bexp:11;
+	unsigned sign:1;
+};
+struct ieee754sp_konst {
+	unsigned mant:23;
+	unsigned bexp:8;
+	unsigned sign:1;
+};
+
+typedef union _ieee754dp {
+	struct ieee754dp_konst oparts;
+	struct {
+		unsigned long long mant:52;
+		unsigned int bexp:11;
+		unsigned int sign:1;
+	} parts;
+	unsigned long long bits;
+	double d;
+} ieee754dp;
+
+typedef union _ieee754sp {
+	struct ieee754sp_konst parts;
+	float f;
+	unsigned long bits;
+} ieee754sp;
+#endif
+
+#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
+struct ieee754dp_konst {
+	unsigned sign:1;
+	unsigned bexp:11;
+	unsigned manthi:20;
+	unsigned mantlo:32;
+};
+typedef union _ieee754dp {
+	struct ieee754dp_konst oparts;
+	struct {
+		unsigned int sign:1;
+		unsigned int bexp:11;
+		unsigned long long mant:52;
+	} parts;
+	double d;
+	unsigned long long bits;
+} ieee754dp;
+
+struct ieee754sp_konst {
+	unsigned sign:1;
+	unsigned bexp:8;
+	unsigned mant:23;
+};
+
+typedef union _ieee754sp {
+	struct ieee754sp_konst parts;
+	float f;
+	unsigned long bits;
+} ieee754sp;
+#endif
+
+/*
+ * single precision (often aka float)
+*/
+int ieee754sp_finite(ieee754sp x);
+int ieee754sp_class(ieee754sp x);
+
+ieee754sp ieee754sp_abs(ieee754sp x);
+ieee754sp ieee754sp_neg(ieee754sp x);
+ieee754sp ieee754sp_scalb(ieee754sp x, int);
+ieee754sp ieee754sp_logb(ieee754sp x);
+
+/* x with sign of y */
+ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y);
+
+ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y);
+ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y);
+ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y);
+ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y);
+
+ieee754sp ieee754sp_fint(int x);
+ieee754sp ieee754sp_funs(unsigned x);
+ieee754sp ieee754sp_flong(long long x);
+ieee754sp ieee754sp_fulong(unsigned long long x);
+ieee754sp ieee754sp_fdp(ieee754dp x);
+
+int ieee754sp_tint(ieee754sp x);
+unsigned int ieee754sp_tuns(ieee754sp x);
+long long ieee754sp_tlong(ieee754sp x);
+unsigned long long ieee754sp_tulong(ieee754sp x);
+
+int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop);
+/*
+ * basic sp math
+ */
+ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip);
+ieee754sp ieee754sp_frexp(ieee754sp x, int *exp);
+ieee754sp ieee754sp_ldexp(ieee754sp x, int exp);
+
+ieee754sp ieee754sp_ceil(ieee754sp x);
+ieee754sp ieee754sp_floor(ieee754sp x);
+ieee754sp ieee754sp_trunc(ieee754sp x);
+
+ieee754sp ieee754sp_sqrt(ieee754sp x);
+
+/*
+ * double precision (often aka double)
+*/
+int ieee754dp_finite(ieee754dp x);
+int ieee754dp_class(ieee754dp x);
+
+/* x with sign of y */
+ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y);
+
+ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y);
+ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y);
+ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y);
+ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y);
+
+ieee754dp ieee754dp_abs(ieee754dp x);
+ieee754dp ieee754dp_neg(ieee754dp x);
+ieee754dp ieee754dp_scalb(ieee754dp x, int);
+
+/* return exponent as integer in floating point format 
+ */
+ieee754dp ieee754dp_logb(ieee754dp x);
+
+ieee754dp ieee754dp_fint(int x);
+ieee754dp ieee754dp_funs(unsigned x);
+ieee754dp ieee754dp_flong(long long x);
+ieee754dp ieee754dp_fulong(unsigned long long x);
+ieee754dp ieee754dp_fsp(ieee754sp x);
+
+ieee754dp ieee754dp_ceil(ieee754dp x);
+ieee754dp ieee754dp_floor(ieee754dp x);
+ieee754dp ieee754dp_trunc(ieee754dp x);
+
+int ieee754dp_tint(ieee754dp x);
+unsigned int ieee754dp_tuns(ieee754dp x);
+long long ieee754dp_tlong(ieee754dp x);
+unsigned long long ieee754dp_tulong(ieee754dp x);
+
+int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop);
+/*
+ * basic sp math
+ */
+ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip);
+ieee754dp ieee754dp_frexp(ieee754dp x, int *exp);
+ieee754dp ieee754dp_ldexp(ieee754dp x, int exp);
+
+ieee754dp ieee754dp_ceil(ieee754dp x);
+ieee754dp ieee754dp_floor(ieee754dp x);
+ieee754dp ieee754dp_trunc(ieee754dp x);
+
+ieee754dp ieee754dp_sqrt(ieee754dp x);
+
+
+
+/* 5 types of floating point number 
+*/
+#define IEEE754_CLASS_NORM	0x00
+#define IEEE754_CLASS_ZERO	0x01
+#define IEEE754_CLASS_DNORM	0x02
+#define IEEE754_CLASS_INF	0x03
+#define IEEE754_CLASS_SNAN	0x04
+#define IEEE754_CLASS_QNAN	0x05
+extern const char *const ieee754_cname[];
+
+/* exception numbers */
+#define IEEE754_INEXACT			0x01
+#define IEEE754_UNDERFLOW		0x02
+#define IEEE754_OVERFLOW		0x04
+#define IEEE754_ZERO_DIVIDE		0x08
+#define IEEE754_INVALID_OPERATION	0x10
+
+/* cmp operators
+*/
+#define IEEE754_CLT	0x01
+#define IEEE754_CEQ	0x02
+#define IEEE754_CGT	0x04
+#define IEEE754_CUN	0x08
+
+/* rounding mode 
+*/
+#define IEEE754_RN	0	/* round to nearest */
+#define IEEE754_RZ	1	/* round toward zero  */
+#define IEEE754_RD	2	/* round toward -Infinity */
+#define IEEE754_RU	3	/* round toward +Infinity */
+
+/* other naming */
+#define IEEE754_RM	IEEE754_RD
+#define IEEE754_RP	IEEE754_RU
+
+/* "normal" comparisons
+*/
+static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y)
+{
+	return ieee754sp_cmp(x, y, IEEE754_CEQ);
+}
+
+static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y)
+{
+	return ieee754sp_cmp(x, y,
+			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
+}
+
+static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y)
+{
+	return ieee754sp_cmp(x, y, IEEE754_CLT);
+}
+
+static __inline int ieee754sp_le(ieee754sp x, ieee754sp y)
+{
+	return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
+}
+
+static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y)
+{
+	return ieee754sp_cmp(x, y, IEEE754_CGT);
+}
+
+
+static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y)
+{
+	return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
+}
+
+static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y)
+{
+	return ieee754dp_cmp(x, y, IEEE754_CEQ);
+}
+
+static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y)
+{
+	return ieee754dp_cmp(x, y,
+			     IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
+}
+
+static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y)
+{
+	return ieee754dp_cmp(x, y, IEEE754_CLT);
+}
+
+static __inline int ieee754dp_le(ieee754dp x, ieee754dp y)
+{
+	return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
+}
+
+static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y)
+{
+	return ieee754dp_cmp(x, y, IEEE754_CGT);
+}
+
+static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y)
+{
+	return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
+}
+
+
+/* like strtod
+*/
+ieee754dp ieee754dp_fstr(const char *s, char **endp);
+char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af);
+
+
+/* the control status register 
+*/
+struct ieee754_csr {
+	unsigned pad:13;
+	unsigned noq:1;		/* set 1 for no quiet NaN's */
+	unsigned nod:1;		/* set 1 for no denormalised numbers */
+	unsigned cx:5;		/* exceptions this operation */
+	unsigned mx:5;		/* exception enable  mask */
+	unsigned sx:5;		/* exceptions total */
+	unsigned rm:2;		/* current rounding mode */
+};
+extern struct ieee754_csr ieee754_csr;
+
+static __inline unsigned ieee754_getrm(void)
+{
+	return (ieee754_csr.rm);
+}
+static __inline unsigned ieee754_setrm(unsigned rm)
+{
+	return (ieee754_csr.rm = rm);
+}
+
+/*
+ * get current exceptions
+ */
+static __inline unsigned ieee754_getcx(void)
+{
+	return (ieee754_csr.cx);
+}
+
+/* test for current exception condition 
+ */
+static __inline int ieee754_cxtest(unsigned n)
+{
+	return (ieee754_csr.cx & n);
+}
+
+/*
+ * get sticky exceptions
+ */
+static __inline unsigned ieee754_getsx(void)
+{
+	return (ieee754_csr.sx);
+}
+
+/* clear sticky conditions
+*/
+static __inline unsigned ieee754_clrsx(void)
+{
+	return (ieee754_csr.sx = 0);
+}
+
+/* test for sticky exception condition 
+ */
+static __inline int ieee754_sxtest(unsigned n)
+{
+	return (ieee754_csr.sx & n);
+}
+
+/* debugging */
+ieee754sp ieee754sp_dump(char *s, ieee754sp x);
+ieee754dp ieee754dp_dump(char *s, ieee754dp x);
+
+#define IEEE754_SPCVAL_PZERO	0
+#define IEEE754_SPCVAL_NZERO	1
+#define IEEE754_SPCVAL_PONE	2
+#define IEEE754_SPCVAL_NONE	3
+#define IEEE754_SPCVAL_PTEN	4
+#define IEEE754_SPCVAL_NTEN	5
+#define IEEE754_SPCVAL_PINFINITY	6
+#define IEEE754_SPCVAL_NINFINITY	7
+#define IEEE754_SPCVAL_INDEF	8
+#define IEEE754_SPCVAL_PMAX	9	/* +max norm */
+#define IEEE754_SPCVAL_NMAX	10	/* -max norm */
+#define IEEE754_SPCVAL_PMIN	11	/* +min norm */
+#define IEEE754_SPCVAL_NMIN	12	/* +min norm */
+#define IEEE754_SPCVAL_PMIND	13	/* +min denorm */
+#define IEEE754_SPCVAL_NMIND	14	/* +min denorm */
+#define IEEE754_SPCVAL_P1E31	15	/* + 1.0e31 */
+#define IEEE754_SPCVAL_P1E63	16	/* + 1.0e63 */
+
+extern const struct ieee754dp_konst __ieee754dp_spcvals[];
+extern const struct ieee754sp_konst __ieee754sp_spcvals[];
+#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals)
+#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals)
+
+/* return infinity with given sign
+*/
+#define ieee754dp_inf(sn)	\
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
+#define ieee754dp_zero(sn) \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
+#define ieee754dp_one(sn) \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
+#define ieee754dp_ten(sn) \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
+#define ieee754dp_indef() \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754dp_max(sn) \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
+#define ieee754dp_min(sn) \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
+#define ieee754dp_mind(sn) \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
+#define ieee754dp_1e31() \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31])
+#define ieee754dp_1e63() \
+  (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63])
+
+#define ieee754sp_inf(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
+#define ieee754sp_zero(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
+#define ieee754sp_one(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
+#define ieee754sp_ten(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
+#define ieee754sp_indef() \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754sp_max(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
+#define ieee754sp_min(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
+#define ieee754sp_mind(sn) \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
+#define ieee754sp_1e31() \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31])
+#define ieee754sp_1e63() \
+  (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
+
+/* indefinite integer value 
+*/
+#define ieee754si_indef()	INT_MIN
+#ifdef LONG_LONG_MIN
+#define ieee754di_indef()	LONG_LONG_MIN
+#else
+#define ieee754di_indef()	(-9223372036854775807LL-1)
+#endif
+
+/* IEEE exception context, passed to handler */
+struct ieee754xctx {
+	const char *op;		/* operation name */
+	int rt;			/* result type */
+	union {
+		ieee754sp sp;	/* single precision */
+		ieee754dp dp;	/* double precision */
+#ifdef IEEE854_XP
+		ieee754xp xp;	/* extended precision */
+#endif
+		int si;		/* standard signed integer (32bits) */
+		long long di;	/* extended signed integer (64bits) */
+	} rv;			/* default result format implied by op */
+	va_list ap;
+};
+
+/* result types for xctx.rt */
+#define IEEE754_RT_SP	0
+#define IEEE754_RT_DP	1
+#define IEEE754_RT_XP	2
+#define IEEE754_RT_SI	3
+#define IEEE754_RT_DI	4
+
+extern void ieee754_xcpt(struct ieee754xctx *xcp);
+
+/* compat */
+#define ieee754dp_fix(x)	ieee754dp_tint(x)
+#define ieee754sp_fix(x)	ieee754sp_tint(x)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754d.c linux/arch/mips/math-emu/ieee754d.c
--- v2.4.3/linux/arch/mips/math-emu/ieee754d.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754d.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,142 @@
+/* some debug functions
+*/
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+/**************************************************************************
+ *  Nov 7, 2000
+ *  Modified to build and operate in Linux kernel environment. 
+ *
+ *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+
+#include "ieee754.h"
+
+#define DP_EBIAS	1023
+#define DP_EMIN		(-1022)
+#define DP_EMAX		1023
+#define DP_FBITS	52
+
+#define SP_EBIAS	127
+#define SP_EMIN		(-126)
+#define SP_EMAX		127
+#define SP_FBITS	23
+
+#define DP_MBIT(x)	((unsigned long long)1 << (x))
+#define DP_HIDDEN_BIT	DP_MBIT(DP_FBITS)
+#define DP_SIGN_BIT	DP_MBIT(63)
+
+
+#define SP_MBIT(x)	((unsigned long)1 << (x))
+#define SP_HIDDEN_BIT	SP_MBIT(SP_FBITS)
+#define SP_SIGN_BIT	SP_MBIT(31)
+
+
+#define SPSIGN(sp)	(sp.parts.sign)
+#define SPBEXP(sp)	(sp.parts.bexp)
+#define SPMANT(sp)	(sp.parts.mant)
+
+#define DPSIGN(dp)	(dp.parts.sign)
+#define DPBEXP(dp)	(dp.parts.bexp)
+#define DPMANT(dp)	(dp.parts.mant)
+
+ieee754dp ieee754dp_dump(char *m, ieee754dp x)
+{
+	int i;
+
+	printk("%s", m);
+	printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32),
+	       (unsigned) x.bits);
+	printk("\t=");
+	switch (ieee754dp_class(x)) {
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_SNAN:
+		printk("Nan %c", DPSIGN(x) ? '-' : '+');
+		for (i = DP_FBITS - 1; i >= 0; i--)
+			printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
+		break;
+	case IEEE754_CLASS_INF:
+		printk("%cInfinity", DPSIGN(x) ? '-' : '+');
+		break;
+	case IEEE754_CLASS_ZERO:
+		printk("%cZero", DPSIGN(x) ? '-' : '+');
+		break;
+	case IEEE754_CLASS_DNORM:
+		printk("%c0.", DPSIGN(x) ? '-' : '+');
+		for (i = DP_FBITS - 1; i >= 0; i--)
+			printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
+		printk("e%d", DPBEXP(x) - DP_EBIAS);
+		break;
+	case IEEE754_CLASS_NORM:
+		printk("%c1.", DPSIGN(x) ? '-' : '+');
+		for (i = DP_FBITS - 1; i >= 0; i--)
+			printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
+		printk("e%d", DPBEXP(x) - DP_EBIAS);
+		break;
+	default:
+		printk("Illegal/Unknown IEEE754 value class");
+	}
+	printk("\n");
+	return x;
+}
+
+ieee754sp ieee754sp_dump(char *m, ieee754sp x)
+{
+	int i;
+
+	printk("%s=", m);
+	printk("<%08x>\n", (unsigned) x.bits);
+	printk("\t=");
+	switch (ieee754sp_class(x)) {
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_SNAN:
+		printk("Nan %c", SPSIGN(x) ? '-' : '+');
+		for (i = SP_FBITS - 1; i >= 0; i--)
+			printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
+		break;
+	case IEEE754_CLASS_INF:
+		printk("%cInfinity", SPSIGN(x) ? '-' : '+');
+		break;
+	case IEEE754_CLASS_ZERO:
+		printk("%cZero", SPSIGN(x) ? '-' : '+');
+		break;
+	case IEEE754_CLASS_DNORM:
+		printk("%c0.", SPSIGN(x) ? '-' : '+');
+		for (i = SP_FBITS - 1; i >= 0; i--)
+			printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
+		printk("e%d", SPBEXP(x) - SP_EBIAS);
+		break;
+	case IEEE754_CLASS_NORM:
+		printk("%c1.", SPSIGN(x) ? '-' : '+');
+		for (i = SP_FBITS - 1; i >= 0; i--)
+			printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
+		printk("e%d", SPBEXP(x) - SP_EBIAS);
+		break;
+	default:
+		printk("Illegal/Unknown IEEE754 value class");
+	}
+	printk("\n");
+	return x;
+}
+
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754dp.c linux/arch/mips/math-emu/ieee754dp.c
--- v2.4.3/linux/arch/mips/math-emu/ieee754dp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754dp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,197 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+int ieee754dp_class(ieee754dp x)
+{
+	COMPXDP;
+	EXPLODEXDP;
+	return xc;
+}
+
+int ieee754dp_isnan(ieee754dp x)
+{
+	return ieee754dp_class(x) >= IEEE754_CLASS_SNAN;
+}
+
+int ieee754dp_issnan(ieee754dp x)
+{
+	assert(ieee754dp_isnan(x));
+	if (ieee754_csr.noq)
+		return 1;
+	return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1));
+}
+
+
+ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...)
+{
+	struct ieee754xctx ax;
+	if (!TSTX())
+		return r;
+
+	ax.op = op;
+	ax.rt = IEEE754_RT_DP;
+	ax.rv.dp = r;
+	va_start(ax.ap, op);
+	ieee754_xcpt(&ax);
+	return ax.rv.dp;
+}
+
+ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...)
+{
+	struct ieee754xctx ax;
+
+	assert(ieee754dp_isnan(r));
+
+	if (!ieee754dp_issnan(r))	/* QNAN does not cause invalid op !! */
+		return r;
+
+	if (!SETCX(IEEE754_INVALID_OPERATION)) {
+		/* not enabled convert to a quiet NaN */
+		if (ieee754_csr.noq)
+			return r;
+		DPMANT(r) |= DP_MBIT(DP_MBITS - 1);
+		return r;
+	}
+
+	ax.op = op;
+	ax.rt = 0;
+	ax.rv.dp = r;
+	va_start(ax.ap, op);
+	ieee754_xcpt(&ax);
+	return ax.rv.dp;
+}
+
+ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y)
+{
+	assert(ieee754dp_isnan(x));
+	assert(ieee754dp_isnan(y));
+
+	if (DPMANT(x) > DPMANT(y))
+		return x;
+	else
+		return y;
+}
+
+
+/* generate a normal/denormal number with over,under handeling
+ * sn is sign
+ * xe is an unbiased exponent
+ * xm is 3bit extended precision value.
+ */
+ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm)
+{
+	assert(xm);		/* we dont gen exact zeros (probably should) */
+
+	assert((xm >> (DP_MBITS + 1 + 3)) == 0);	/* no execess */
+	assert(xm & (DP_HIDDEN_BIT << 3));
+
+	if (xe < DP_EMIN) {
+		/* strip lower bits */
+		int es = DP_EMIN - xe;
+
+		if (ieee754_csr.nod) {
+			SETCX(IEEE754_UNDERFLOW);
+			return ieee754dp_zero(sn);
+		}
+
+		/* sticky right shift es bits 
+		 */
+		xm = XDPSRS(xm, es);
+		xe += es;
+
+		assert((xm & (DP_HIDDEN_BIT << 3)) == 0);
+		assert(xe == DP_EMIN);
+	}
+	if (xm & (DP_MBIT(3) - 1)) {
+		SETCX(IEEE754_INEXACT);
+		/* inexact must round of 3 bits 
+		 */
+		switch (ieee754_csr.rm) {
+		case IEEE754_RZ:
+			break;
+		case IEEE754_RN:
+			xm += 0x3 + ((xm >> 3) & 1);
+			/* xm += (xm&0x8)?0x4:0x3 */
+			break;
+		case IEEE754_RU:	/* toward +Infinity */
+			if (!sn)	/* ?? */
+				xm += 0x8;
+			break;
+		case IEEE754_RD:	/* toward -Infinity */
+			if (sn)	/* ?? */
+				xm += 0x8;
+			break;
+		}
+		/* adjust exponent for rounding add overflowing 
+		 */
+		if (xm >> (DP_MBITS + 3 + 1)) {	/* add causes mantissa overflow */
+			xm >>= 1;
+			xe++;
+		}
+	}
+	/* strip grs bits */
+	xm >>= 3;
+
+	assert((xm >> (DP_MBITS + 1)) == 0);	/* no execess */
+	assert(xe >= DP_EMIN);
+
+	if (xe > DP_EMAX) {
+		SETCX(IEEE754_OVERFLOW);
+		/* -O can be table indexed by (rm,sn) */
+		switch (ieee754_csr.rm) {
+		case IEEE754_RN:
+			return ieee754dp_inf(sn);
+		case IEEE754_RZ:
+			return ieee754dp_max(sn);
+		case IEEE754_RU:	/* toward +Infinity */
+			if (sn == 0)
+				return ieee754dp_inf(0);
+			else
+				return ieee754dp_max(1);
+		case IEEE754_RD:	/* toward -Infinity */
+			if (sn == 0)
+				return ieee754dp_max(0);
+			else
+				return ieee754dp_inf(1);
+		}
+	}
+	/* gen norm/denorm/zero */
+
+	if ((xm & DP_HIDDEN_BIT) == 0) {
+		/* we underflow (tiny/zero) */
+		assert(xe == DP_EMIN);
+		SETCX(IEEE754_UNDERFLOW);
+		return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
+	} else {
+		assert((xm >> (DP_MBITS + 1)) == 0);	/* no execess */
+		assert(xm & DP_HIDDEN_BIT);
+
+		return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754dp.h linux/arch/mips/math-emu/ieee754dp.h
--- v2.4.3/linux/arch/mips/math-emu/ieee754dp.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754dp.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,83 @@
+/* 
+ * IEEE754 floating point
+ * double precision internal header file
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754int.h"
+
+#define assert(expr) ((void)0)
+
+/* 3bit extended double precision sticky right shift */
+#define XDPSRS(v,rs)	\
+  ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0))
+
+#define XDPSRSX1() \
+  (xe++, (xm = (xm >> 1) | (xm & 1)))
+
+#define XDPSRS1(v)	\
+  (((v) >> 1) | ((v) & 1))
+
+/* convert denormal to normalized with extended exponent */
+#define DPDNORMx(m,e) \
+  while( (m >> DP_MBITS) == 0) { m <<= 1; e--; }
+#define DPDNORMX	DPDNORMx(xm,xe)
+#define DPDNORMY	DPDNORMx(ym,ye)
+
+static __inline ieee754dp builddp(int s, int bx, unsigned long long m)
+{
+	ieee754dp r;
+
+	assert((s) == 0 || (s) == 1);
+	assert((bx) >= DP_EMIN - 1 + DP_EBIAS
+	       && (bx) <= DP_EMAX + 1 + DP_EBIAS);
+	assert(((m) >> DP_MBITS) == 0);
+
+	r.parts.sign = s;
+	r.parts.bexp = bx;
+	r.parts.mant = m;
+	return r;
+}
+
+extern int ieee754dp_isnan(ieee754dp);
+extern int ieee754dp_issnan(ieee754dp);
+extern int ieee754si_xcpt(int, const char *, ...);
+extern long long ieee754di_xcpt(long long, const char *, ...);
+extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...);
+extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...);
+extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp);
+extern ieee754dp ieee754dp_format(int, int, unsigned long long);
+
+
+#define DPNORMRET2(s,e,m,name,a0,a1) \
+{ \
+    ieee754dp V = ieee754dp_format(s,e,m); \
+    if(TSTX()) \
+      return ieee754dp_xcpt(V,name,a0,a1); \
+    else \
+      return V; \
+}
+
+#define DPNORMRET1(s,e,m,name,a0)  DPNORMRET2(s,e,m,name,a0,a0)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754int.h linux/arch/mips/math-emu/ieee754int.h
--- v2.4.3/linux/arch/mips/math-emu/ieee754int.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754int.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,135 @@
+/* 
+ * IEEE754 floating point
+ * common internal header file
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754.h"
+
+#define DP_EBIAS	1023
+#define DP_EMIN		(-1022)
+#define DP_EMAX		1023
+#define DP_MBITS	52
+
+#define SP_EBIAS	127
+#define SP_EMIN		(-126)
+#define SP_EMAX		127
+#define SP_MBITS	23
+
+#define DP_MBIT(x)	((unsigned long long)1 << (x))
+#define DP_HIDDEN_BIT	DP_MBIT(DP_MBITS)
+#define DP_SIGN_BIT	DP_MBIT(63)
+
+#define SP_MBIT(x)	((unsigned long)1 << (x))
+#define SP_HIDDEN_BIT	SP_MBIT(SP_MBITS)
+#define SP_SIGN_BIT	SP_MBIT(31)
+
+
+#define SPSIGN(sp)	(sp.parts.sign)
+#define SPBEXP(sp)	(sp.parts.bexp)
+#define SPMANT(sp)	(sp.parts.mant)
+
+#define DPSIGN(dp)	(dp.parts.sign)
+#define DPBEXP(dp)	(dp.parts.bexp)
+#define DPMANT(dp)	(dp.parts.mant)
+
+#define CLPAIR(x,y)	((x)*6+(y))
+
+#define CLEARCX	\
+  (ieee754_csr.cx = 0)
+
+#define SETCX(x) \
+  (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x),ieee754_csr.mx & (x))
+
+#define TSTX()	\
+	(ieee754_csr.cx & ieee754_csr.mx)
+
+
+#define COMPXSP \
+  unsigned xm; int xe; int xs; int xc
+
+#define COMPYSP \
+  unsigned ym; int ye; int ys; int yc
+
+#define EXPLODESP(v,vc,vs,ve,vm) \
+{\
+    vs = SPSIGN(v);\
+    ve = SPBEXP(v);\
+    vm = SPMANT(v);\
+    if(ve == SP_EMAX+1+SP_EBIAS){\
+	if(vm == 0)\
+	  vc = IEEE754_CLASS_INF;\
+	else if(vm & SP_MBIT(SP_MBITS-1)) \
+	  vc = IEEE754_CLASS_QNAN;\
+	else \
+	  vc = IEEE754_CLASS_SNAN;\
+    } else if(ve == SP_EMIN-1+SP_EBIAS) {\
+	if(vm) {\
+	    ve = SP_EMIN;\
+	    vc = IEEE754_CLASS_DNORM;\
+	} else\
+	  vc = IEEE754_CLASS_ZERO;\
+    } else {\
+	ve -= SP_EBIAS;\
+	vm |= SP_HIDDEN_BIT;\
+	vc = IEEE754_CLASS_NORM;\
+    }\
+}
+#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm)
+#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym)
+
+
+#define COMPXDP \
+unsigned long long xm; int xe; int xs; int xc
+
+#define COMPYDP \
+unsigned long long ym; int ye; int ys; int yc
+
+#define EXPLODEDP(v,vc,vs,ve,vm) \
+{\
+    vm = DPMANT(v);\
+    vs = DPSIGN(v);\
+    ve = DPBEXP(v);\
+    if(ve == DP_EMAX+1+DP_EBIAS){\
+	if(vm == 0)\
+	  vc = IEEE754_CLASS_INF;\
+	else if(vm & DP_MBIT(DP_MBITS-1)) \
+	  vc = IEEE754_CLASS_QNAN;\
+	else \
+	  vc = IEEE754_CLASS_SNAN;\
+    } else if(ve == DP_EMIN-1+DP_EBIAS) {\
+	if(vm) {\
+	    ve = DP_EMIN;\
+	    vc = IEEE754_CLASS_DNORM;\
+	} else\
+	  vc = IEEE754_CLASS_ZERO;\
+    } else {\
+	ve -= DP_EBIAS;\
+	vm |= DP_HIDDEN_BIT;\
+	vc = IEEE754_CLASS_NORM;\
+    }\
+}
+#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm)
+#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754m.c linux/arch/mips/math-emu/ieee754m.c
--- v2.4.3/linux/arch/mips/math-emu/ieee754m.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754m.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,56 @@
+/*
+ * floor, trunc, ceil
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754.h"
+
+ieee754dp ieee754dp_floor(ieee754dp x)
+{
+	ieee754dp i;
+
+	if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
+		return ieee754dp_sub(i, ieee754dp_one(0));
+	else
+		return i;
+}
+
+ieee754dp ieee754dp_ceil(ieee754dp x)
+{
+	ieee754dp i;
+
+	if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
+		return ieee754dp_add(i, ieee754dp_one(0));
+	else
+		return i;
+}
+
+ieee754dp ieee754dp_trunc(ieee754dp x)
+{
+	ieee754dp i;
+
+	(void) ieee754dp_modf(x, &i);
+	return i;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754sp.c linux/arch/mips/math-emu/ieee754sp.c
--- v2.4.3/linux/arch/mips/math-emu/ieee754sp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754sp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,197 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+int ieee754sp_class(ieee754sp x)
+{
+	COMPXSP;
+	EXPLODEXSP;
+	return xc;
+}
+
+int ieee754sp_isnan(ieee754sp x)
+{
+	return ieee754sp_class(x) >= IEEE754_CLASS_SNAN;
+}
+
+int ieee754sp_issnan(ieee754sp x)
+{
+	assert(ieee754sp_isnan(x));
+	if (ieee754_csr.noq)
+		return 1;
+	return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1));
+}
+
+
+ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...)
+{
+	struct ieee754xctx ax;
+
+	if (!TSTX())
+		return r;
+
+	ax.op = op;
+	ax.rt = IEEE754_RT_SP;
+	ax.rv.sp = r;
+	va_start(ax.ap, op);
+	ieee754_xcpt(&ax);
+	return ax.rv.sp;
+}
+
+ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...)
+{
+	struct ieee754xctx ax;
+
+	assert(ieee754sp_isnan(r));
+
+	if (!ieee754sp_issnan(r))	/* QNAN does not cause invalid op !! */
+		return r;
+
+	if (!SETCX(IEEE754_INVALID_OPERATION)) {
+		/* not enabled convert to a quiet NaN */
+		if (ieee754_csr.noq)
+			return r;
+		SPMANT(r) |= SP_MBIT(SP_MBITS - 1);
+		return r;
+	}
+
+	ax.op = op;
+	ax.rt = 0;
+	ax.rv.sp = r;
+	va_start(ax.ap, op);
+	ieee754_xcpt(&ax);
+	return ax.rv.sp;
+}
+
+ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y)
+{
+	assert(ieee754sp_isnan(x));
+	assert(ieee754sp_isnan(y));
+
+	if (SPMANT(x) > SPMANT(y))
+		return x;
+	else
+		return y;
+}
+
+
+/* generate a normal/denormal number with over,under handeling
+ * sn is sign
+ * xe is an unbiased exponent
+ * xm is 3bit extended precision value.
+ */
+ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
+{
+	assert(xm);		/* we dont gen exact zeros (probably should) */
+
+	assert((xm >> (SP_MBITS + 1 + 3)) == 0);	/* no execess */
+	assert(xm & (SP_HIDDEN_BIT << 3));
+
+	if (xe < SP_EMIN) {
+		/* strip lower bits */
+		int es = SP_EMIN - xe;
+
+		if (ieee754_csr.nod) {
+			SETCX(IEEE754_UNDERFLOW);
+			return ieee754sp_zero(sn);
+		}
+
+		/* sticky right shift es bits 
+		 */
+		SPXSRSXn(es);
+
+		assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
+		assert(xe == SP_EMIN);
+	}
+	if (xm & (SP_MBIT(3) - 1)) {
+		SETCX(IEEE754_INEXACT);
+		/* inexact must round of 3 bits 
+		 */
+		switch (ieee754_csr.rm) {
+		case IEEE754_RZ:
+			break;
+		case IEEE754_RN:
+			xm += 0x3 + ((xm >> 3) & 1);
+			/* xm += (xm&0x8)?0x4:0x3 */
+			break;
+		case IEEE754_RU:	/* toward +Infinity */
+			if (!sn)	/* ?? */
+				xm += 0x8;
+			break;
+		case IEEE754_RD:	/* toward -Infinity */
+			if (sn)	/* ?? */
+				xm += 0x8;
+			break;
+		}
+		/* adjust exponent for rounding add overflowing 
+		 */
+		if (xm >> (SP_MBITS + 1 + 3)) {	/* add causes mantissa overflow */
+			xm >>= 1;
+			xe++;
+		}
+	}
+	/* strip grs bits */
+	xm >>= 3;
+
+	assert((xm >> (SP_MBITS + 1)) == 0);	/* no execess */
+	assert(xe >= SP_EMIN);
+
+	if (xe > SP_EMAX) {
+		SETCX(IEEE754_OVERFLOW);
+		/* -O can be table indexed by (rm,sn) */
+		switch (ieee754_csr.rm) {
+		case IEEE754_RN:
+			return ieee754sp_inf(sn);
+		case IEEE754_RZ:
+			return ieee754sp_max(sn);
+		case IEEE754_RU:	/* toward +Infinity */
+			if (sn == 0)
+				return ieee754sp_inf(0);
+			else
+				return ieee754sp_max(1);
+		case IEEE754_RD:	/* toward -Infinity */
+			if (sn == 0)
+				return ieee754sp_max(0);
+			else
+				return ieee754sp_inf(1);
+		}
+	}
+	/* gen norm/denorm/zero */
+
+	if ((xm & SP_HIDDEN_BIT) == 0) {
+		/* we underflow (tiny/zero) */
+		assert(xe == SP_EMIN);
+		SETCX(IEEE754_UNDERFLOW);
+		return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
+	} else {
+		assert((xm >> (SP_MBITS + 1)) == 0);	/* no execess */
+		assert(xm & SP_HIDDEN_BIT);
+
+		return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754sp.h linux/arch/mips/math-emu/ieee754sp.h
--- v2.4.3/linux/arch/mips/math-emu/ieee754sp.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754sp.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,89 @@
+/* 
+ * IEEE754 floating point
+ * double precision internal header file
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754int.h"
+
+#define assert(expr) ((void)0)
+
+/* 3bit extended single precision sticky right shift */
+#define SPXSRSXn(rs) \
+  (xe += rs, \
+   xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0))
+
+#define SPXSRSX1() \
+  (xe++, (xm = (xm >> 1) | (xm & 1)))
+
+#define SPXSRSYn(rs) \
+   (ye+=rs, \
+    ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0))
+
+#define SPXSRSY1() \
+   (ye++, (ym = (ym >> 1) | (ym & 1)))
+
+/* convert denormal to normalized with extended exponent */
+#define SPDNORMx(m,e) \
+  while( (m >> SP_MBITS) == 0) { m <<= 1; e--; }
+#define SPDNORMX	SPDNORMx(xm,xe)
+#define SPDNORMY	SPDNORMx(ym,ye)
+
+static __inline ieee754sp buildsp(int s, int bx, unsigned m)
+{
+	ieee754sp r;
+
+	assert((s) == 0 || (s) == 1);
+	assert((bx) >= SP_EMIN - 1 + SP_EBIAS
+	       && (bx) <= SP_EMAX + 1 + SP_EBIAS);
+	assert(((m) >> SP_MBITS) == 0);
+
+	r.parts.sign = s;
+	r.parts.bexp = bx;
+	r.parts.mant = m;
+
+	return r;
+}
+
+extern int ieee754sp_isnan(ieee754sp);
+extern int ieee754sp_issnan(ieee754sp);
+extern int ieee754si_xcpt(int, const char *, ...);
+extern long long ieee754di_xcpt(long long, const char *, ...);
+extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...);
+extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...);
+extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp);
+extern ieee754sp ieee754sp_format(int, int, unsigned);
+
+
+#define SPNORMRET2(s,e,m,name,a0,a1) \
+{ \
+    ieee754sp V = ieee754sp_format(s,e,m); \
+    if(TSTX()) \
+      return ieee754sp_xcpt(V,name,a0,a1); \
+    else \
+      return V; \
+}
+
+#define SPNORMRET1(s,e,m,name,a0)  SPNORMRET2(s,e,m,name,a0,a0)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/ieee754xcpt.c linux/arch/mips/math-emu/ieee754xcpt.c
--- v2.4.3/linux/arch/mips/math-emu/ieee754xcpt.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/ieee754xcpt.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,48 @@
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+/**************************************************************************
+ *  Nov 7, 2000
+ *  Added preprocessor hacks to map to Linux kernel diagnostics. 
+ *
+ *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *************************************************************************/
+
+#include "ieee754.h"
+
+/*
+ * Very naff exception handler (you can plug in your own and
+ * override this).
+ */
+
+static const char *const rtnames[] = {
+	"sp", "dp", "xp", "si", "di"
+};
+
+void ieee754_xcpt(struct ieee754xctx *xcp)
+{
+	printk("floating point exception in \"%s\", type=%s\n",
+		xcp->op, rtnames[xcp->rt]);
+}
+
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/kernel_linkage.c linux/arch/mips/math-emu/kernel_linkage.c
--- v2.4.3/linux/arch/mips/math-emu/kernel_linkage.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/kernel_linkage.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,95 @@
+/**************************************************************************
+ *
+ *  arch/mips/math_emu/kernel_linkage.c
+ *
+ *  Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ *************************************************************************/
+/*
+ * Routines corresponding to Linux kernel FP context
+ * manipulation primitives for the Algorithmics MIPS
+ * FPU Emulator
+ */
+
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/signal.h>
+#include <asm/uaccess.h>
+
+#include <asm/fpu_emulator.h>
+
+extern struct mips_fpu_emulator_private fpuemuprivate;
+
+#define SIGNALLING_NAN 0x7ff800007ff80000LL
+
+void fpu_emulator_init_fpu(void)
+{
+	static int first = 1;
+	int i;
+ 
+	if (first) {
+		first = 0;
+		printk("Algorithmics/MIPS FPU Emulator v1.4\n");
+	}
+
+	current->thread.fpu.soft.sr = 0;
+	for (i = 0; i < 32; i++) {
+		current->thread.fpu.soft.regs[i] = SIGNALLING_NAN;
+	}
+}
+
+
+/*
+ * Emulator context save/restore to/from a signal context
+ * presumed to be on the user stack, and therefore accessed
+ * with appropriate macros from uaccess.h
+ */
+
+int fpu_emulator_save_context(struct sigcontext *sc)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < 32; i++) {
+		err |=
+		    __put_user(current->thread.fpu.soft.regs[i],
+			       &sc->sc_fpregs[i]);
+	}
+	err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+	err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
+
+	return err;
+}
+
+int fpu_emulator_restore_context(struct sigcontext *sc)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < 32; i++) {
+		err |=
+		    __get_user(current->thread.fpu.soft.regs[i],
+			       &sc->sc_fpregs[i]);
+	}
+	err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+	err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
+
+	return err;
+}
+
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_add.c linux/arch/mips/math-emu/sp_add.c
--- v2.4.3/linux/arch/mips/math-emu/sp_add.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_add.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,180 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
+{
+	COMPXSP;
+	COMPYSP;
+
+	EXPLODEXSP;
+	EXPLODEYSP;
+
+	CLEARCX;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(y, "add", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754sp_nanxcpt(x, "add", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754sp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Inifity handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		if (xs == ys)
+			return x;
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+		return x;
+
+		/* Zero handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+		if (xs == ys)
+			return x;
+		else
+			return ieee754sp_zero(ieee754_csr.rm ==
+					      IEEE754_RD);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		return x;
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		SPDNORMX;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		SPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		SPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	assert(xm & SP_HIDDEN_BIT);
+	assert(ym & SP_HIDDEN_BIT);
+
+	/* provide guard,round and stick bit space */
+	xm <<= 3;
+	ym <<= 3;
+
+	if (xe > ye) {
+		/* have to shift y fraction right to align
+		 */
+		int s = xe - ye;
+		SPXSRSYn(s);
+	} else if (ye > xe) {
+		/* have to shift x fraction right to align
+		 */
+		int s = ye - xe;
+		SPXSRSXn(s);
+	}
+	assert(xe == ye);
+	assert(xe <= SP_EMAX);
+
+	if (xs == ys) {
+		/* generate 28 bit result of adding two 27 bit numbers
+		 * leaving result in xm,xs,xe
+		 */
+		xm = xm + ym;
+		xe = xe;
+		xs = xs;
+
+		if (xm >> (SP_MBITS + 1 + 3)) {	/* carry out */
+			SPXSRSX1();
+		}
+	} else {
+		if (xm >= ym) {
+			xm = xm - ym;
+			xe = xe;
+			xs = xs;
+		} else {
+			xm = ym - xm;
+			xe = xe;
+			xs = ys;
+		}
+		if (xm == 0)
+			return ieee754sp_zero(ieee754_csr.rm ==
+					      IEEE754_RD);
+
+		/* normalize in extended single precision */
+		while ((xm >> (SP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+
+	}
+	SPNORMRET2(xs, xe, xm, "add", x, y);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_cmp.c linux/arch/mips/math-emu/sp_cmp.c
--- v2.4.3/linux/arch/mips/math-emu/sp_cmp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_cmp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,58 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp)
+{
+	CLEARCX;
+
+	if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) {
+		if (cmp & IEEE754_CUN)
+			return 1;
+		if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
+			if (SETCX(IEEE754_INVALID_OPERATION))
+				return ieee754si_xcpt(0, "fcmpf", x);
+		}
+		return 0;
+	} else {
+		int vx = x.bits;
+		int vy = y.bits;
+
+		if (vx < 0)
+			vx = -vx ^ SP_SIGN_BIT;
+		if (vy < 0)
+			vy = -vy ^ SP_SIGN_BIT;
+
+		if (vx < vy)
+			return (cmp & IEEE754_CLT) != 0;
+		else if (vx == vy)
+			return (cmp & IEEE754_CEQ) != 0;
+		else
+			return (cmp & IEEE754_CGT) != 0;
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_div.c linux/arch/mips/math-emu/sp_div.c
--- v2.4.3/linux/arch/mips/math-emu/sp_div.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_div.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,160 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
+{
+	COMPXSP;
+	COMPYSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+	EXPLODEYSP;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(y, "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754sp_nanxcpt(x, "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754sp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Infinity handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+		return ieee754sp_zero(xs ^ ys);
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+		return ieee754sp_inf(xs ^ ys);
+
+		/* Zero handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		SETCX(IEEE754_ZERO_DIVIDE);
+		return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+		return ieee754sp_zero(xs == ys ? 0 : 1);
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		SPDNORMX;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		SPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		SPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	assert(xm & SP_HIDDEN_BIT);
+	assert(ym & SP_HIDDEN_BIT);
+
+	/* provide rounding space */
+	xm <<= 3;
+	ym <<= 3;
+
+	{
+		/* now the dirty work */
+
+		unsigned rm = 0;
+		int re = xe - ye;
+		unsigned bm;
+
+		for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) {
+			if (xm >= ym) {
+				xm -= ym;
+				rm |= bm;
+				if (xm == 0)
+					break;
+			}
+			xm <<= 1;
+		}
+		rm <<= 1;
+		if (xm)
+			rm |= 1;	/* have remainder, set sticky */
+
+		assert(rm);
+
+		/* normalise rm to rounding precision ?
+		 */
+		while ((rm >> (SP_MBITS + 3)) == 0) {
+			rm <<= 1;
+			re--;
+		}
+
+		SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_fdp.c linux/arch/mips/math-emu/sp_fdp.c
--- v2.4.3/linux/arch/mips/math-emu/sp_fdp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_fdp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,69 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_fdp(ieee754dp x)
+{
+	COMPXDP;
+
+	CLEARCX;
+
+	EXPLODEXDP;
+
+	switch (xc) {
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_SNAN:
+		return ieee754sp_nanxcpt(buildsp(xs,
+						 SP_EMAX + 1 + SP_EBIAS,
+						 (unsigned long)
+						 (xm >>
+						  (DP_MBITS - SP_MBITS))),
+					 "fdp", x);
+	case IEEE754_CLASS_INF:
+		return ieee754sp_inf(xs);
+	case IEEE754_CLASS_ZERO:
+		return ieee754sp_zero(xs);
+	case IEEE754_CLASS_DNORM:
+		/* cant possibly be sp representable */
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x);
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+
+	{
+		unsigned long rm;
+
+		/* convert from DP_MBITS to SP_MBITS+3 with sticky right shift 
+		 */
+		rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) |
+		    ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0);
+
+		SPNORMRET1(xs, xe, rm, "fdp", x);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_fint.c linux/arch/mips/math-emu/sp_fint.c
--- v2.4.3/linux/arch/mips/math-emu/sp_fint.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_fint.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,78 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_fint(int x)
+{
+	COMPXSP;
+
+	CLEARCX;
+
+	if (x == 0)
+		return ieee754sp_zero(0);
+	if (x == 1 || x == -1)
+		return ieee754sp_one(x < 0);
+	if (x == 10 || x == -10)
+		return ieee754sp_ten(x < 0);
+
+	xs = (x < 0);
+	if (xs) {
+		if (x == (1 << 31))
+			xm = ((unsigned) 1 << 31);	/* max neg can't be safely negated */
+		else
+			xm = -x;
+	} else {
+		xm = x;
+	}
+	xe = SP_MBITS + 3;
+
+	if (xm >> (SP_MBITS + 1 + 3)) {
+		/* shunt out overflow bits 
+		 */
+		while (xm >> (SP_MBITS + 1 + 3)) {
+			SPXSRSX1();
+		}
+	} else {
+		/* normalize in grs extended single precision 
+		 */
+		while ((xm >> (SP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+	}
+	SPNORMRET1(xs, xe, xm, "fint", x);
+}
+
+
+ieee754sp ieee754sp_funs(unsigned int u)
+{
+	if ((int) u < 0)
+		return ieee754sp_add(ieee754sp_1e31(),
+				     ieee754sp_fint(u & ~(1 << 31)));
+	return ieee754sp_fint(u);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_flong.c linux/arch/mips/math-emu/sp_flong.c
--- v2.4.3/linux/arch/mips/math-emu/sp_flong.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_flong.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,77 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_flong(long long x)
+{
+	COMPXDP;		/* <--- need 64-bit mantissa temp */
+
+	CLEARCX;
+
+	if (x == 0)
+		return ieee754sp_zero(0);
+	if (x == 1 || x == -1)
+		return ieee754sp_one(x < 0);
+	if (x == 10 || x == -10)
+		return ieee754sp_ten(x < 0);
+
+	xs = (x < 0);
+	if (xs) {
+		if (x == (1ULL << 63))
+			xm = (1ULL << 63);	/* max neg can't be safely negated */
+		else
+			xm = -x;
+	} else {
+		xm = x;
+	}
+	xe = SP_MBITS + 3;
+
+	if (xm >> (SP_MBITS + 1 + 3)) {
+		/* shunt out overflow bits 
+		 */
+		while (xm >> (SP_MBITS + 1 + 3)) {
+			SPXSRSX1();
+		}
+	} else {
+		/* normalize in grs extended single precision */
+		while ((xm >> (SP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+	}
+	SPNORMRET1(xs, xe, xm, "sp_flong", x);
+}
+
+
+ieee754sp ieee754sp_fulong(unsigned long long u)
+{
+	if ((long long) u < 0)
+		return ieee754sp_add(ieee754sp_1e63(),
+				     ieee754sp_flong(u & ~(1ULL << 63)));
+	return ieee754sp_flong(u);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_frexp.c linux/arch/mips/math-emu/sp_frexp.c
--- v2.4.3/linux/arch/mips/math-emu/sp_frexp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_frexp.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,53 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+/* close to ieeep754sp_logb 
+*/
+ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr)
+{
+	COMPXSP;
+	CLEARCX;
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_INF:
+	case IEEE754_CLASS_ZERO:
+		*eptr = 0;
+		return x;
+	case IEEE754_CLASS_DNORM:
+		SPDNORMX;
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	*eptr = xe + 1;
+	return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_logb.c linux/arch/mips/math-emu/sp_logb.c
--- v2.4.3/linux/arch/mips/math-emu/sp_logb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_logb.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,54 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_logb(ieee754sp x)
+{
+	COMPXSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+		return ieee754sp_nanxcpt(x, "logb", x);
+	case IEEE754_CLASS_QNAN:
+		return x;
+	case IEEE754_CLASS_INF:
+		return ieee754sp_inf(0);
+	case IEEE754_CLASS_ZERO:
+		return ieee754sp_inf(1);
+	case IEEE754_CLASS_DNORM:
+		SPDNORMX;
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	return ieee754sp_fint(xe);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_modf.c linux/arch/mips/math-emu/sp_modf.c
--- v2.4.3/linux/arch/mips/math-emu/sp_modf.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_modf.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,80 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+/* modf function is always exact for a finite number
+*/
+ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip)
+{
+	COMPXSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_INF:
+	case IEEE754_CLASS_ZERO:
+		*ip = x;
+		return x;
+	case IEEE754_CLASS_DNORM:
+		/* far to small */
+		*ip = ieee754sp_zero(xs);
+		return x;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	if (xe < 0) {
+		*ip = ieee754sp_zero(xs);
+		return x;
+	}
+	if (xe >= SP_MBITS) {
+		*ip = x;
+		return ieee754sp_zero(xs);
+	}
+	/* generate ipart mantissa by clearing bottom bits 
+	 */
+	*ip = buildsp(xs, xe + SP_EBIAS,
+		      ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) &
+		      ~SP_HIDDEN_BIT);
+
+	/* generate fpart mantissa by clearing top bits
+	 * and normalizing (must be able to normalize)
+	 */
+	xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe));
+	if (xm == 0)
+		return ieee754sp_zero(xs);
+
+	while ((xm >> SP_MBITS) == 0) {
+		xm <<= 1;
+		xe--;
+	}
+	return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_mul.c linux/arch/mips/math-emu/sp_mul.c
--- v2.4.3/linux/arch/mips/math-emu/sp_mul.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_mul.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,174 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
+{
+	COMPXSP;
+	COMPYSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+	EXPLODEYSP;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(y, "mul", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754sp_nanxcpt(x, "mul", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754sp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Infinity handeling */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		return ieee754sp_inf(xs ^ ys);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		return ieee754sp_zero(xs ^ ys);
+
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		SPDNORMX;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		SPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		SPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	/* rm = xm * ym, re = xe+ye basicly */
+	assert(xm & SP_HIDDEN_BIT);
+	assert(ym & SP_HIDDEN_BIT);
+
+	{
+		int re = xe + ye;
+		int rs = xs ^ ys;
+		unsigned rm;
+
+		/* shunt to top of word */
+		xm <<= 32 - (SP_MBITS + 1);
+		ym <<= 32 - (SP_MBITS + 1);
+
+		/* multiply 32bits xm,ym to give high 32bits rm with stickness
+		 */
+		{
+			unsigned short lxm = xm & 0xffff;
+			unsigned short hxm = xm >> 16;
+			unsigned short lym = ym & 0xffff;
+			unsigned short hym = ym >> 16;
+			unsigned lrm;
+			unsigned hrm;
+
+			lrm = lxm * lym;	/* 16 * 16 => 32 */
+			hrm = hxm * hym;	/* 16 * 16 => 32 */
+
+			{
+				unsigned t = lxm * hym;	/* 16 * 16 => 32 */
+				{
+					unsigned at = lrm + (t << 16);
+					hrm += at < lrm;
+					lrm = at;
+				}
+				hrm = hrm + (t >> 16);
+			}
+
+			{
+				unsigned t = hxm * lym;	/* 16 * 16 => 32 */
+				{
+					unsigned at = lrm + (t << 16);
+					hrm += at < lrm;
+					lrm = at;
+				}
+				hrm = hrm + (t >> 16);
+			}
+			rm = hrm | (lrm != 0);
+		}
+
+		/*
+		 * sticky shift down to normal rounding precision
+		 */
+		if ((int) rm < 0) {
+			rm = (rm >> (32 - (SP_MBITS + 1 + 3))) |
+			    ((rm << (SP_MBITS + 1 + 3)) != 0);
+			re++;
+		} else {
+			rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) |
+			    ((rm << (SP_MBITS + 1 + 3 + 1)) != 0);
+		}
+		assert(rm & (SP_HIDDEN_BIT << 3));
+
+		SPNORMRET2(rs, re, rm, "mul", x, y);
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_scalb.c linux/arch/mips/math-emu/sp_scalb.c
--- v2.4.3/linux/arch/mips/math-emu/sp_scalb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_scalb.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,58 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_scalb(ieee754sp x, int n)
+{
+	COMPXSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+		return ieee754sp_nanxcpt(x, "scalb", x, n);
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_INF:
+	case IEEE754_CLASS_ZERO:
+		return x;
+	case IEEE754_CLASS_DNORM:
+		SPDNORMX;
+		break;
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
+}
+
+
+ieee754sp ieee754sp_ldexp(ieee754sp x, int n)
+{
+	return ieee754sp_scalb(x, n);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_simple.c linux/arch/mips/math-emu/sp_simple.c
--- v2.4.3/linux/arch/mips/math-emu/sp_simple.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_simple.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,66 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+int ieee754sp_finite(ieee754sp x)
+{
+	return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
+}
+
+ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y)
+{
+	CLEARCX;
+	SPSIGN(x) = SPSIGN(y);
+	return x;
+}
+
+
+ieee754sp ieee754sp_neg(ieee754sp x)
+{
+	CLEARCX;
+
+	if (ieee754sp_isnan(x))	/* but not infinity */
+		return ieee754sp_nanxcpt(x, "neg", x);
+
+	/* quick fix up */
+	SPSIGN(x) ^= 1;
+	return x;
+}
+
+
+ieee754sp ieee754sp_abs(ieee754sp x)
+{
+	CLEARCX;
+
+	if (ieee754sp_isnan(x))	/* but not infinity */
+		return ieee754sp_nanxcpt(x, "abs", x);
+
+	/* quick fix up */
+	SPSIGN(x) = 0;
+	return x;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_sqrt.c linux/arch/mips/math-emu/sp_sqrt.c
--- v2.4.3/linux/arch/mips/math-emu/sp_sqrt.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_sqrt.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,115 @@
+/* IEEE754 floating point arithmetic
+ * single precision square root
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+static const struct ieee754sp_konst knan = {
+	0, SP_EBIAS + SP_EMAX + 1, 0
+};
+
+#define nan	((ieee754sp)knan)
+
+ieee754sp ieee754sp_sqrt(ieee754sp x)
+{
+	int sign = (int) 0x80000000;
+	int ix, s, q, m, t, i;
+	unsigned int r;
+	COMPXDP;
+
+	/* take care of Inf and NaN */
+
+	EXPLODEXDP;
+
+	/* x == INF or NAN? */
+	switch (xc) {
+	case IEEE754_CLASS_QNAN:
+	case IEEE754_CLASS_SNAN:
+		/* sqrt(Nan) = Nan */
+		return ieee754sp_nanxcpt(x, "sqrt");
+	case IEEE754_CLASS_ZERO:
+		/* sqrt(0) = 0 */
+		return x;
+	case IEEE754_CLASS_INF:
+		if (xs)
+			/* sqrt(-Inf) = Nan */
+			return ieee754sp_nanxcpt(nan, "sqrt");
+		/* sqrt(+Inf) = Inf */
+		return x;
+	case IEEE754_CLASS_DNORM:
+	case IEEE754_CLASS_NORM:
+		if (xs)
+			/* sqrt(-x) = Nan */
+			return ieee754sp_nanxcpt(nan, "sqrt");
+		break;
+	}
+
+	ix = x.bits;
+
+	/* normalize x */
+	m = (ix >> 23);
+	if (m == 0) {		/* subnormal x */
+		for (i = 0; (ix & 0x00800000) == 0; i++)
+			ix <<= 1;
+		m -= i - 1;
+	}
+	m -= 127;		/* unbias exponent */
+	ix = (ix & 0x007fffff) | 0x00800000;
+	if (m & 1)		/* odd m, double x to make it even */
+		ix += ix;
+	m >>= 1;		/* m = [m/2] */
+
+	/* generate sqrt(x) bit by bit */
+	ix += ix;
+	q = s = 0;		/* q = sqrt(x) */
+	r = 0x01000000;		/* r = moving bit from right to left */
+
+	while (r != 0) {
+		t = s + r;
+		if (t <= ix) {
+			s = t + r;
+			ix -= t;
+			q += r;
+		}
+		ix += ix;
+		r >>= 1;
+	}
+
+	if (ix != 0) {
+		switch (ieee754_csr.rm) {
+		case IEEE754_RP:
+			q += 2;
+			break;
+		case IEEE754_RN:
+			q += (q & 1);
+			break;
+		}
+	}
+	ix = (q >> 1) + 0x3f000000;
+	ix += (m << 23);
+	x.bits = ix;
+	return x;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_sub.c linux/arch/mips/math-emu/sp_sub.c
--- v2.4.3/linux/arch/mips/math-emu/sp_sub.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_sub.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,187 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
+{
+	COMPXSP;
+	COMPYSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+	EXPLODEYSP;
+
+	switch (CLPAIR(xc, yc)) {
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x,
+					 y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+		return ieee754sp_nanxcpt(y, "sub", x, y);
+
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+		return ieee754sp_nanxcpt(x, "sub", x, y);
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+		return ieee754sp_bestnan(x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+	case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+		return x;
+
+
+		/* Inifity handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+		if (xs != ys)
+			return x;
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y);
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+		return ieee754sp_inf(ys ^ 1);
+
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+		return x;
+
+		/* Zero handeling 
+		 */
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+		if (xs != ys)
+			return x;
+		else
+			return ieee754sp_zero(ieee754_csr.rm ==
+					      IEEE754_RD);
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+		return x;
+
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+	case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+		/* quick fix up */
+		DPSIGN(y) ^= 1;
+		return y;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+		SPDNORMX;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+		SPDNORMY;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+		SPDNORMX;
+		break;
+
+	case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+		break;
+	}
+	/* flip sign of y and handle as add */
+	ys ^= 1;
+
+	assert(xm & SP_HIDDEN_BIT);
+	assert(ym & SP_HIDDEN_BIT);
+
+
+	/* provide guard,round and stick bit space */
+	xm <<= 3;
+	ym <<= 3;
+
+	if (xe > ye) {
+		/* have to shift y fraction right to align
+		 */
+		int s = xe - ye;
+		SPXSRSYn(s);
+	} else if (ye > xe) {
+		/* have to shift x fraction right to align
+		 */
+		int s = ye - xe;
+		SPXSRSXn(s);
+	}
+	assert(xe == ye);
+	assert(xe <= SP_EMAX);
+
+	if (xs == ys) {
+		/* generate 28 bit result of adding two 27 bit numbers
+		 */
+		xm = xm + ym;
+		xe = xe;
+		xs = xs;
+
+		if (xm >> (SP_MBITS + 1 + 3)) {	/* carry out */
+			SPXSRSX1();	/* shift preserving sticky */
+		}
+	} else {
+		if (xm >= ym) {
+			xm = xm - ym;
+			xe = xe;
+			xs = xs;
+		} else {
+			xm = ym - xm;
+			xe = xe;
+			xs = ys;
+		}
+		if (xm == 0)
+			if (ieee754_csr.rm == IEEE754_RD)
+				return ieee754sp_zero(1);	/* round negative inf. => sign = -1 */
+			else
+				return ieee754sp_zero(0);	/* other round modes   => sign = 1 */
+
+		/* normalize to rounding precision 
+		 */
+		while ((xm >> (SP_MBITS + 3)) == 0) {
+			xm <<= 1;
+			xe--;
+		}
+	}
+	SPNORMRET2(xs, xe, xm, "sub", x, y);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_tint.c linux/arch/mips/math-emu/sp_tint.c
--- v2.4.3/linux/arch/mips/math-emu/sp_tint.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_tint.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,88 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include <linux/kernel.h>
+#include "ieee754sp.h"
+
+int ieee754sp_tint(ieee754sp x)
+{
+	COMPXSP;
+
+	CLEARCX;
+
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754si_xcpt(ieee754si_indef(), "fixsp", x);
+	case IEEE754_CLASS_INF:
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754si_xcpt(ieee754si_indef(), "fixsp", x);
+	case IEEE754_CLASS_ZERO:
+		return 0;
+	case IEEE754_CLASS_DNORM:	/* much to small */
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754si_xcpt(0, "fixsp", x);
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	if (xe >= 31) {
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754si_xcpt(ieee754si_indef(), "fix", x);
+	}
+	if (xe < 0) {
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754si_xcpt(0, "fix", x);
+	}
+	/* oh gawd */
+	if (xe > SP_MBITS) {
+		xm <<= xe - SP_MBITS;
+	} else if (xe < SP_MBITS) {
+		/* XXX no rounding 
+		 */
+		xm >>= SP_MBITS - xe;
+	}
+	if (xs)
+		return -xm;
+	else
+		return xm;
+}
+
+
+unsigned int ieee754sp_tuns(ieee754sp x)
+{
+	ieee754sp hb = ieee754sp_1e31();
+
+	/* what if x < 0 ?? */
+	if (ieee754sp_lt(x, hb))
+		return (unsigned) ieee754sp_tint(x);
+
+	return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) |
+	    ((unsigned) 1 << 31);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/math-emu/sp_tlong.c linux/arch/mips/math-emu/sp_tlong.c
--- v2.4.3/linux/arch/mips/math-emu/sp_tlong.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/math-emu/sp_tlong.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,87 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.  All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+long long ieee754sp_tlong(ieee754sp x)
+{
+	COMPXDP;		/* <-- need 64-bit mantissa tmp */
+
+	CLEARCX;
+
+	EXPLODEXSP;
+
+	switch (xc) {
+	case IEEE754_CLASS_SNAN:
+	case IEEE754_CLASS_QNAN:
+		SETCX(IEEE754_INVALID_OPERATION);
+		return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+	case IEEE754_CLASS_INF:
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+	case IEEE754_CLASS_ZERO:
+		return 0;
+	case IEEE754_CLASS_DNORM:	/* much to small */
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754di_xcpt(0, "sp_tlong", x);
+	case IEEE754_CLASS_NORM:
+		break;
+	}
+	if (xe >= 63) {
+		SETCX(IEEE754_OVERFLOW);
+		return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+	}
+	if (xe < 0) {
+		SETCX(IEEE754_UNDERFLOW);
+		return ieee754di_xcpt(0, "sp_tlong", x);
+	}
+	/* oh gawd */
+	if (xe > SP_MBITS) {
+		xm <<= xe - SP_MBITS;
+	} else if (xe < SP_MBITS) {
+		/* XXX no rounding 
+		 */
+		xm >>= SP_MBITS - xe;
+	}
+	if (xs)
+		return -xm;
+	else
+		return xm;
+}
+
+
+unsigned long long ieee754sp_tulong(ieee754sp x)
+{
+	ieee754sp hb = ieee754sp_1e63();
+
+	/* what if x < 0 ?? */
+	if (ieee754sp_lt(x, hb))
+		return (unsigned long long) ieee754sp_tlong(x);
+
+	return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) |
+	    (1ULL << 63);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/Makefile linux/arch/mips/mips-boards/atlas/Makefile
--- v2.4.3/linux/arch/mips/mips-boards/atlas/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/atlas/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,42 @@
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+# 
+# This program is distributed in the hope 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.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# #######################################################################
+#
+# Makefile for the MIPS Atlas specific kernel interface routines
+# under Linux.
+#
+# 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 in the main makefile...
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+all: atlas.o
+
+O_TARGET := atlas.o
+
+obj-y	:= atlas_int.o atlas_rtc.o atlas_setup.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_int.c linux/arch/mips/mips-boards/atlas/atlas_int.c
--- v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_int.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/atlas/atlas_int.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,248 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS 
+ * Atlas board.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/irq.h>
+#include <asm/mips-boards/atlas.h>
+#include <asm/mips-boards/atlasint.h>
+#include <asm/gdb-stub.h>
+
+
+struct atlas_ictrl_regs *atlas_hw0_icregs
+	= (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE;
+
+extern asmlinkage void mipsIRQ(void);
+extern void do_IRQ(int irq, struct pt_regs *regs);
+
+unsigned long spurious_count = 0;
+irq_desc_t irq_desc[NR_IRQS];
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+void disable_atlas_irq(unsigned int irq_nr)
+{
+	atlas_hw0_icregs->intrsten = (1 << irq_nr);
+}
+
+void enable_atlas_irq(unsigned int irq_nr)
+{
+	atlas_hw0_icregs->intseten = (1 << irq_nr);
+}
+
+static unsigned int startup_atlas_irq(unsigned int irq)
+{
+	enable_atlas_irq(irq);
+	return 0; /* never anything pending */
+}
+
+#define shutdown_atlas_irq	disable_atlas_irq
+
+#define mask_and_ack_atlas_irq disable_atlas_irq
+
+static void end_atlas_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_atlas_irq(irq);
+}
+
+static struct hw_interrupt_type atlas_irq_type = {
+	"Atlas",
+	startup_atlas_irq,
+	shutdown_atlas_irq,
+	enable_atlas_irq,
+	disable_atlas_irq,
+	mask_and_ack_atlas_irq,
+	end_atlas_irq,
+	NULL
+};
+
+int get_irq_list(char *buf)
+{
+	int i, len = 0;
+	int num = 0;
+	struct irqaction *action;
+
+	for (i = 0; i < ATLASINT_END; i++, num++) {
+		action = irq_desc[i].action;
+		if (!action) 
+			continue;
+		len += sprintf(buf+len, "%2d: %8d %c %s",
+			num, kstat.irqs[0][num],
+			(action->flags & SA_INTERRUPT) ? '+' : ' ',
+			action->name);
+		for (action=action->next; action; action = action->next) {
+			len += sprintf(buf+len, ",%s %s",
+				(action->flags & SA_INTERRUPT) ? " +" : "",
+				action->name);
+		}
+		len += sprintf(buf+len, " [hw0]\n");
+	}
+	return len;
+}
+
+int request_irq(unsigned int irq, 
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{  
+        struct irqaction *action;
+
+	DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+	if (irq >= ATLASINT_END)
+		return -EINVAL;
+	if (!handler)
+		return -EINVAL;
+
+	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if(!action)
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
+	action->dev_id = dev_id;
+	action->next = 0;
+	irq_desc[irq].action = action;
+	enable_atlas_irq(irq);
+
+	return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+	struct irqaction *action;
+
+	if (irq >= ATLASINT_END) {
+		printk("Trying to free IRQ%d\n",irq);
+		return;
+	}
+
+	action = irq_desc[irq].action;
+	irq_desc[irq].action = NULL;
+	disable_atlas_irq(irq);
+	kfree(action);
+}
+
+static inline int ls1bit32(unsigned int x)
+{
+	int b = 31, s;
+
+	s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+	s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
+	s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
+	s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
+	s =  1; if (x <<  1 == 0) s = 0; b -= s;
+
+	return b;
+}
+
+void atlas_hw0_irqdispatch(struct pt_regs *regs)
+{
+	struct irqaction *action;
+	unsigned long int_status;
+	int irq, cpu = smp_processor_id();
+
+	int_status = atlas_hw0_icregs->intstatus; 
+
+	/* if int_status == 0, then the interrupt has already been cleared */
+	if (int_status == 0)
+		return;
+
+	irq = ls1bit32(int_status);
+	action = irq_desc[irq].action;
+
+	DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq);
+
+	/* if action == NULL, then we don't have a handler for the irq */
+	if ( action == NULL ) {
+		printk("No handler for hw0 irq: %i\n", irq);
+		spurious_count++;
+		return;
+	}
+
+	irq_enter(cpu, irq);
+	kstat.irqs[0][irq]++;
+	action->handler(irq, action->dev_id, regs);
+	irq_exit(cpu, irq);
+
+	return;		
+}
+
+unsigned long probe_irq_on (void)
+{
+	return 0;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+	return 0;
+}
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void breakpoint(void);
+extern int remote_debug;
+#endif
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	/* 
+	 * Mask out all interrupt by writing "1" to all bit position in 
+	 * the interrupt reset reg. 
+	 */
+	atlas_hw0_icregs->intrsten = 0xffffffff;    
+
+	/* Now safe to set the exception vector. */
+	set_except_vector(0, mipsIRQ);
+
+	for (i = 0; i <= ATLASINT_END; i++) {
+		irq_desc[i].status	= IRQ_DISABLED;
+		irq_desc[i].action	= 0;
+		irq_desc[i].depth	= 1;
+		irq_desc[i].handler	= &atlas_irq_type;
+	}
+
+#ifdef CONFIG_REMOTE_DEBUG
+	if (remote_debug) {
+		set_debug_traps();
+		breakpoint();
+	}
+#endif
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_rtc.c linux/arch/mips/mips-boards/atlas/atlas_rtc.c
--- v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_rtc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/atlas/atlas_rtc.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,58 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * RTC routines for Atlas style attached Dallas chip.
+ *
+ */
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mips-boards/atlas.h>
+
+
+static unsigned char atlas_rtc_read_data(unsigned long addr)
+{
+	volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG;
+	volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG;
+
+	*rtc_adr_reg = addr;
+
+	return *rtc_dat_reg;
+}
+
+static void atlas_rtc_write_data(unsigned char data, unsigned long addr)
+{
+	volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG;
+	volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG;
+
+	*rtc_adr_reg = addr;
+	*rtc_dat_reg = data;
+}
+
+static int atlas_rtc_bcd_mode(void)
+{
+	return 0;
+}
+
+struct rtc_ops atlas_rtc_ops = {
+	&atlas_rtc_read_data,
+	&atlas_rtc_write_data,
+	&atlas_rtc_bcd_mode
+};
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_setup.c linux/arch/mips/mips-boards/atlas/atlas_setup.c
--- v2.4.3/linux/arch/mips/mips-boards/atlas/atlas_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/atlas/atlas_setup.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,115 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Atlas specific setup.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/gt64120.h>
+#include <asm/mips-boards/atlasint.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void saa9730_kgdb_hook(void);
+extern void breakpoint(void);
+int remote_debug = 0;
+#endif
+
+extern struct rtc_ops atlas_rtc_ops;
+
+extern void mips_reboot_setup(void);
+
+void __init atlas_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+	int rs_putDebugChar(char);
+	char rs_getDebugChar(void);
+	int saa9730_putDebugChar(char);
+	char saa9730_getDebugChar(void);
+	extern int (*putDebugChar)(char);
+	extern char (*getDebugChar)(void);
+#endif
+	char *argptr;
+
+	ioport_resource.end = 0x7fffffff;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	argptr = prom_getcmdline();
+	if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) {
+		int i = 0;
+		char *s = prom_getenv("modetty0");
+		while(s[i] >= '0' && s[i] <= '9')
+			i++;
+		strcpy(serial_console, "ttyS0,");
+		strncpy(serial_console + 6, s, i);
+		prom_printf("Config serial console: %s\n", serial_console);
+		console_setup(serial_console, NULL);
+	}
+#endif	  
+
+#ifdef CONFIG_REMOTE_DEBUG
+	argptr = prom_getcmdline();
+	if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
+		int line;
+		argptr += strlen("kgdb=ttyS");
+		if (*argptr != '0' && *argptr != '1')
+			printk("KGDB: Uknown serial line /dev/ttyS%c, "
+			       "falling back to /dev/ttyS1\n", *argptr);
+		line = *argptr == '0' ? 0 : 1;
+		printk("KGDB: Using serial line /dev/ttyS%d for session\n",
+		       line ? 1 : 0);
+
+		if(line == 0) {
+			rs_kgdb_hook(line);
+			putDebugChar = rs_putDebugChar;
+			getDebugChar = rs_getDebugChar;
+		} else {
+			saa9730_kgdb_hook();
+			putDebugChar = saa9730_putDebugChar;
+			getDebugChar = saa9730_getDebugChar;
+		}
+
+		prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
+			    "please connect your debugger\n", line ? 1 : 0);
+
+		remote_debug = 1;
+		/* Breakpoints and stuff are in atlas_irq_setup() */
+	}
+#endif
+	argptr = prom_getcmdline();
+
+	if ((argptr = strstr(argptr, "nofpu")) != NULL)
+		mips_cpu.options &= ~MIPS_CPU_FPU;
+
+	rtc_ops = &atlas_rtc_ops;
+
+	mips_reboot_setup();
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/Makefile linux/arch/mips/mips-boards/generic/Makefile
--- v2.4.3/linux/arch/mips/mips-boards/generic/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,41 @@
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+# 
+# This program is distributed in the hope 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.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# #######################################################################
+#
+# Makefile for the MIPS boards generic routines under Linux.
+#
+# 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 in the main makefile...
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET := mipsboards.o
+
+obj-y				:= mipsIRQ.o pci.o reset.o display.o init.o \
+				   memory.o printf.o cmdline.o time.o
+obj-$(CONFIG_REMOTE_DEBUG)	+= gdb_hook.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/cmdline.c linux/arch/mips/mips-boards/generic/cmdline.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/cmdline.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/cmdline.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,53 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Kernel command line creation using the prom monitor (YAMON) argc/argv.
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+extern int prom_argc;
+extern char **prom_argv;
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+
+char * __init prom_getcmdline(void)
+{
+	return &(arcs_cmdline[0]);
+}
+
+
+void  __init prom_init_cmdline(void)
+{
+	char *cp;
+	int actr;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	cp = &(arcs_cmdline[0]);
+	while(actr < prom_argc) {
+	        strcpy(cp, prom_argv[actr]);
+		cp += strlen(prom_argv[actr]);
+		*cp++ = ' ';
+		actr++;
+	}
+	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+		--cp;
+	*cp = '\0';
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/display.c linux/arch/mips/mips-boards/generic/display.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/display.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/display.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,47 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ * 
+ * Display routines for display messages in MIPS boards ascii display.
+ *
+ */
+
+#include <asm/mips-boards/generic.h>
+
+
+void mips_display_message(const char *str)
+{
+        volatile unsigned int *display = (void *)ASCII_DISPLAY_POS_BASE;
+	int i;
+
+	for (i = 0; i <= 14; i=i+2) {
+	         if (*str)
+		         display[i] = *str++;
+		 else
+		         display[i] = ' ';
+	}
+}
+
+void mips_display_word(unsigned int num)
+{
+        volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE;
+	
+	*display = num;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/gdb_hook.c linux/arch/mips/mips-boards/generic/gdb_hook.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/gdb_hook.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/gdb_hook.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,205 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * This is the interface to the remote debugger stub.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+
+#include <asm/serial.h>
+#include <asm/io.h>
+
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
+	SERIAL_PORT_DFNS	/* Defined in serial.h */
+};
+
+static struct async_struct kdb_port_info = {0};
+
+int (*putDebugChar)(char);
+char (*getDebugChar)(void);
+
+static __inline__ unsigned int serial_in(struct async_struct *info, int offset)
+{
+	return inb(info->port + offset);
+}
+
+static __inline__ void serial_out(struct async_struct *info, int offset,
+				int value)
+{
+	outb(value, info->port+offset);
+}
+
+void rs_kgdb_hook(int tty_no) {
+	int t;
+	struct serial_state *ser = &rs_table[tty_no];
+
+	kdb_port_info.state = ser;
+	kdb_port_info.magic = SERIAL_MAGIC;
+	kdb_port_info.port = ser->port;
+	kdb_port_info.flags = ser->flags;
+
+	/*
+	 * Clear all interrupts
+	 */
+	serial_in(&kdb_port_info, UART_LSR);
+	serial_in(&kdb_port_info, UART_RX);
+	serial_in(&kdb_port_info, UART_IIR);
+	serial_in(&kdb_port_info, UART_MSR);
+
+	/*
+	 * Now, initialize the UART 
+	 */
+	serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	if (kdb_port_info.flags & ASYNC_FOURPORT) {
+		kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
+		t = UART_MCR_DTR | UART_MCR_OUT1;
+	} else {
+		kdb_port_info.MCR 
+			= UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+		t = UART_MCR_DTR | UART_MCR_RTS;
+	}
+
+	kdb_port_info.MCR = t;		/* no interrupts, please */
+	serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
+	
+	/*
+	 * and set the speed of the serial port
+	 * (currently hardwired to 9600 8N1
+	 */
+
+	/* baud rate is fixed to 9600 (is this sufficient?)*/
+	t = kdb_port_info.state->baud_base / 9600;	
+	/* set DLAB */
+	serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
+	serial_out(&kdb_port_info, UART_DLM, t >> 8);  /* MS of divisor */
+	/* reset DLAB */
+	serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);
+}
+
+int rs_putDebugChar(char c)
+{
+
+	if (!kdb_port_info.state) { 	/* need to init device first */
+		return 0;
+	}
+
+	while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0)
+		;
+
+	serial_out(&kdb_port_info, UART_TX, c);
+
+	return 1;
+}
+
+char rs_getDebugChar(void)
+{
+	if (!kdb_port_info.state) { 	/* need to init device first */
+		return 0;
+	}
+
+	while (!(serial_in(&kdb_port_info, UART_LSR) & 1))
+		;
+
+	return(serial_in(&kdb_port_info, UART_RX));
+}
+
+
+#ifdef CONFIG_MIPS_ATLAS
+
+#include <asm/mips-boards/atlas.h>
+#include <asm/mips-boards/saa9730_uart.h>
+
+#define INB(a)     inb((unsigned long)a)
+#define OUTB(x,a)  outb(x,(unsigned long)a)
+
+/*
+ * This is the interface to the remote debugger stub
+ * if the Philips part is used for the debug port,
+ * called from the platform setup code.
+ *
+ * PCI init will not have been done yet, we make a
+ * universal assumption about the way the bootloader (YAMON)
+ * have located and set up the chip.
+ */
+static t_uart_saa9730_regmap *kgdb_uart = (void *)(ATLAS_SAA9730_REG + SAA9730_UART_REGS_ADDR);
+
+static int saa9730_kgdb_active = 0;
+
+void saa9730_kgdb_hook(void) 
+{
+        volatile unsigned char t;
+
+        /*
+         * Clear all interrupts
+         */
+	t = INB(&kgdb_uart->Lsr);
+	t += INB(&kgdb_uart->Msr);
+	t += INB(&kgdb_uart->Thr_Rbr);
+	t += INB(&kgdb_uart->Iir_Fcr);
+
+        /*
+         * Now, initialize the UART
+         */
+	/* 8 data bits, one stop bit, no parity */
+	OUTB(SAA9730_LCR_DATA8, &kgdb_uart->Lcr);
+
+        /* baud rate is fixed to 9600 (is this sufficient?)*/
+	OUTB(0, &kgdb_uart->BaudDivMsb); /* HACK - Assumes standard crystal */
+	OUTB(23, &kgdb_uart->BaudDivLsb); /* HACK - known for MIPS Atlas */
+
+	/* Set RTS/DTR active */
+	OUTB(SAA9730_MCR_DTR | SAA9730_MCR_RTS, &kgdb_uart->Mcr);
+	saa9730_kgdb_active = 1;
+}
+
+int saa9730_putDebugChar(char c)
+{
+
+        if (!saa9730_kgdb_active) {     /* need to init device first */
+                return 0;
+        }
+
+        while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_THRE))
+                ;
+	OUTB(c, &kgdb_uart->Thr_Rbr);
+
+        return 1;
+}
+
+char saa9730_getDebugChar(void)
+{
+	char c;
+
+        if (!saa9730_kgdb_active) {     /* need to init device first */
+                return 0;
+        }
+        while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_DR))
+                ;
+
+	c = INB(&kgdb_uart->Thr_Rbr);
+        return(c);
+}
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/init.c linux/arch/mips/mips-boards/generic/init.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/init.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/init.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,139 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * PROM library initialisation code.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/gt64120.h>
+#include <asm/mips-boards/malta.h>
+
+/* Environment variable */
+typedef struct
+{
+	char *name;
+	char *val;
+} t_env_var;
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+int init_debug = 0;
+
+char *prom_getenv(char *envname)
+{
+        /*
+	 * Return a pointer to the given environment variable.
+	 */
+
+	t_env_var *env = (t_env_var *)prom_envp;
+	int i;
+
+	i = strlen(envname);
+
+	while(env->name) {
+		if(strncmp(envname, env->name, i) == 0) {
+			return(env->val);
+		}
+		env++;
+	}
+	return(NULL);
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+	if(c >= '0' && c <= '9')
+		return c - '0';
+	if(c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+	int i;
+
+	for(i = 0; i < 6; i++) {
+		unsigned char num;
+
+		if((*str == '.') || (*str == ':'))
+			str++;
+		num = str2hexnum(*str++) << 4;
+		num |= (str2hexnum(*str++));
+		ea[i] = num;
+	}
+}
+ 
+int get_ethernet_addr(char *ethernet_addr)
+{
+        char *ethaddr_str;
+
+        ethaddr_str = prom_getenv("ethaddr");
+	if (!ethaddr_str) {
+	        printk("ethaddr not set in boot prom\n");
+		return -1;
+	}
+	str2eaddr(ethernet_addr, ethaddr_str);
+
+	if (init_debug > 1) {
+	        int i;
+		printk("get_ethernet_addr: ");
+	        for (i=0; i<5; i++)
+		        printk("%02x:", (unsigned char)*(ethernet_addr+i));
+		printk("%02x\n", *(ethernet_addr+i));
+	}
+
+	return 0;
+}
+
+int __init prom_init(int argc, char **argv, char **envp)
+{
+	prom_argc = argc;
+	prom_argv = argv;
+	prom_envp = envp;
+
+	mips_display_message("LINUX");
+
+	/*
+	 * Setup the North bridge to do Master byte-lane swapping when 
+	 * running in bigendian.
+	 */
+#if defined(__MIPSEL__)
+	GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT |
+		 GT_PCI0_CMD_SBYTESWAP_BIT);
+#else
+	GT_WRITE(GT_PCI0_CMD_OFS, 0);
+#endif
+
+#if defined(CONFIG_MIPS_MALTA)
+	mips_io_port_base = MALTA_PORT_BASE;
+#else
+	mips_io_port_base = KSEG1;
+#endif
+	setup_prom_printf(0);
+	prom_printf("\nLINUX started...\n");
+	prom_init_cmdline();
+	prom_meminit();
+
+	return 0;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/memory.c linux/arch/mips/mips-boards/generic/memory.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/memory.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/memory.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,169 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * PROM library functions for acquiring/using memory descriptors given to 
+ * us from the YAMON.
+ * 
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+
+#include <asm/mips-boards/prom.h>
+
+/*#define DEBUG*/
+
+enum yamon_memtypes {
+	yamon_dontuse,
+	yamon_prom,
+	yamon_free,
+};
+struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
+
+#ifdef DEBUG
+static char *mtypes[3] = {
+	"Dont use memory",
+	"YAMON PROM memory",
+	"Free memmory",
+};
+#endif
+
+
+struct prom_pmemblock * __init prom_getmdesc(void)
+{
+	char *memsize_str;
+	unsigned int memsize;
+
+	memsize_str = prom_getenv("memsize");
+	if (!memsize_str) {
+		prom_printf("memsize not set in boot prom, set to default (32Mb)\n");
+		memsize = 0x02000000;
+	} else {
+#ifdef DEBUG
+		prom_printf("prom_memsize = %s\n", memsize_str);
+#endif
+		memsize = simple_strtol(memsize_str, NULL, 0);
+	}
+
+	memset(mdesc, 0, sizeof(mdesc));
+
+	mdesc[0].type = yamon_dontuse;
+	mdesc[0].base = 0x00000000;
+	mdesc[0].size = 0x00001000;
+
+	mdesc[1].type = yamon_prom;
+	mdesc[1].base = 0x00001000;
+	mdesc[1].size = 0x000ef000;
+
+#if (CONFIG_MIPS_MALTA)
+	/* 
+	 * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
+	 * south bridge and PCI access always forwarded to the ISA Bus and 
+	 * BIOSCS# is always generated.
+	 * This mean that this area can't be used as DMA memory for PCI 
+	 * devices.
+	 */
+	mdesc[2].type = yamon_dontuse;
+	mdesc[2].base = 0x000f0000;
+	mdesc[2].size = 0x00010000;
+#else
+	mdesc[2].type = yamon_prom;
+	mdesc[2].base = 0x000f0000;
+	mdesc[2].size = 0x00010000;
+#endif
+
+	mdesc[3].type = yamon_free;
+	mdesc[3].base = 0x00100000;
+	mdesc[3].size = memsize - mdesc[3].base;
+
+	return &mdesc[0];
+}
+
+static int __init prom_memtype_classify (unsigned int type)
+{
+	switch (type) {
+	case yamon_free:
+		return BOOT_MEM_RAM;
+	case yamon_prom:
+		return BOOT_MEM_ROM_DATA;
+	default:
+		return BOOT_MEM_RESERVED;
+	}
+}
+
+void __init prom_meminit(void)
+{
+	struct prom_pmemblock *p;
+
+#ifdef DEBUG
+	int i = 0;
+
+	prom_printf("YAMON MEMORY DESCRIPTOR dump:\n");
+	p = prom_getmdesc();
+	while (p->size) {
+		prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n",
+			    i, p, p->base, p->size, mtypes[p->type]);
+		p++;
+		i++;
+	}
+#endif
+	p = prom_getmdesc();
+	while (p->size) {
+		unsigned long base, size;
+		long type;
+
+		type = prom_memtype_classify (p->type);
+		base = p->base;
+		size = p->size;
+
+		add_memory_region(base, size, type);
+
+		p++;
+	}
+}
+
+void prom_free_prom_memory (void)
+{
+	int i;
+	struct prom_pmemblock *p;
+	unsigned long freed = 0;
+	unsigned long addr;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
+			continue;
+
+		addr = boot_mem_map.map[i].addr;
+		while (addr < boot_mem_map.map[i].addr
+			      + boot_mem_map.map[i].size) {
+		        ClearPageReserved(virt_to_page(phys_to_virt(addr)));
+			set_page_count(virt_to_page(phys_to_virt(addr)), 1);
+			free_page(phys_to_virt(addr));
+			addr += PAGE_SIZE;
+			freed += PAGE_SIZE;
+		}
+	}
+	printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/mipsIRQ.S linux/arch/mips/mips-boards/generic/mipsIRQ.S
--- v2.4.3/linux/arch/mips/mips-boards/generic/mipsIRQ.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/mipsIRQ.S	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,122 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Interrupt exception dispatch code.
+ *
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ *    common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ *    would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ *    between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the MIPS board look basically (barring software
+ * IRQs which we don't use at all and all external interrupt sources are
+ * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        Combined hardware interrupt (hw0)
+ *             3        Hardware (ignored)
+ *             4        Hardware (ignored)
+ *             5        Hardware (ignored)
+ *             6        Hardware (ignored)
+ *             7        R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ----     R4k Timer
+ * Lowest  ----     Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+	.text
+	.set	noreorder
+	.set	noat
+	.align	5
+	NESTED(mipsIRQ, PT_SIZE, sp)
+	SAVE_ALL
+	CLI
+	.set	at
+
+	mfc0	s0, CP0_CAUSE		# get irq mask
+
+	/* First we check for r4k counter/timer IRQ. */
+	andi	a0, s0, CAUSEF_IP7
+	beq	a0, zero, 1f
+	 andi	a0, s0, CAUSEF_IP2	# delay slot, check hw0 interrupt
+
+	/* Wheee, a timer interrupt. */
+	move	a0, sp
+	jal	mips_timer_interrupt
+	 nop
+
+	j	ret_from_irq
+	 nop
+
+1:
+	beq	a0, zero, 1f
+	 nop
+
+	/* Wheee, combined hardware level zero interrupt. */
+#if defined(CONFIG_MIPS_ATLAS)
+	jal	atlas_hw0_irqdispatch
+#elif defined(CONFIG_MIPS_MALTA)
+	jal	malta_hw0_irqdispatch
+#else
+#error "MIPS board not supported\n"	
+#endif
+	 move	a0, sp			# delay slot
+
+	j	ret_from_irq
+	 nop				# delay slot
+
+1:
+	/*
+	 * Here by mistake?  This is possible, what can happen is that by the
+	 * time we take the exception the IRQ pin goes low, so just leave if
+	 * this is the case.
+	 */
+	move	a1,s0
+	PRINT("Got interrupt: c0_cause = %08x\n")
+	mfc0	a1, CP0_EPC
+	PRINT("c0_epc = %08x\n")
+
+	j	ret_from_irq
+	 nop
+	END(mipsIRQ)
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/pci.c linux/arch/mips/mips-boards/generic/pci.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/pci.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,328 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * MIPS boards specific PCI support.
+ *
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/gt64120.h>
+#ifdef CONFIG_MIPS_MALTA
+#include <asm/mips-boards/malta.h>
+#endif
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+static int
+mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev,
+                           unsigned char where, u32 *data)
+{
+	unsigned char bus = dev->bus->number;
+	unsigned char dev_fn = dev->devfn;
+        u32 intr;
+
+	if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0)))
+	        return -1; /* Because of a bug in the galileo (for slot 31). */
+
+	/* Clear cause register bits */
+	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | 
+	                             GT_INTRCAUSE_TARABORT0_BIT));
+
+	/* Setup address */
+	GT_WRITE(GT_PCI0_CFGADDR_OFS, 
+		 (bus         << GT_PCI0_CFGADDR_BUSNUM_SHF)   |
+		 (dev_fn      << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+		 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF)   |
+		 GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+	if (access_type == PCI_ACCESS_WRITE) {
+	        if (bus == 0 && dev_fn == 0) {
+		        /* 
+			 * Galileo is acting differently than other devices. 
+			 */
+		        GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+		} else {
+		        GT_PCI_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+		}
+	} else {
+	        if (bus == 0 && dev_fn == 0) {
+		        /* 
+			 * Galileo is acting differently than other devices. 
+			 */
+		        GT_READ(GT_PCI0_CFGDATA_OFS, *data);
+		} else {
+		        GT_PCI_READ(GT_PCI0_CFGDATA_OFS, *data);
+		}
+	}
+
+	/* Check for master or target abort */
+	GT_READ(GT_INTRCAUSE_OFS, intr);
+
+	if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT))
+	{
+	        /* Error occured */
+
+	        /* Clear bits */
+	        GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | 
+					      GT_INTRCAUSE_TARABORT0_BIT) );
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly.  Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int
+mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val)
+{
+	u32 data = 0;
+
+	if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+		return -1;
+
+	*val = (data >> ((where & 3) << 3)) & 0xff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val)
+{
+	u32 data = 0;
+
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+	       return -1;
+
+	*val = (data >> ((where & 3) << 3)) & 0xffff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val)
+{
+	u32 data = 0;
+
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	
+	if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+		return -1;
+
+	*val = data;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val)
+{
+	u32 data = 0;
+       
+	if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+		return -1;
+
+	data = (data & ~(0xff << ((where & 3) << 3))) |
+	       (val << ((where & 3) << 3));
+
+	if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+		return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val)
+{
+        u32 data = 0;
+
+	if (where & 1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+       
+        if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+	       return -1;
+
+	data = (data & ~(0xffff << ((where & 3) << 3))) | 
+	       (val << ((where & 3) << 3));
+
+	if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+	       return -1;
+
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+	if (where & 3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+	       return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mips_pci_ops = {
+	mips_pcibios_read_config_byte,
+        mips_pcibios_read_config_word,
+	mips_pcibios_read_config_dword,
+	mips_pcibios_write_config_byte,
+	mips_pcibios_write_config_word,
+	mips_pcibios_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+#ifdef CONFIG_MIPS_MALTA
+	struct pci_dev *pdev;
+	unsigned char reg_val;
+#endif
+
+	printk("PCI: Probing PCI hardware on host bus 0.\n");
+	pci_scan_bus(0, &mips_pci_ops, NULL);
+
+	/* 
+	 * Due to a bug in the Galileo system controller, we need to setup 
+	 * the PCI BAR for the Galileo internal registers.
+	 * This should be done in the bios/bootprom and will be fixed in
+	 * a later revision of YAMON (the MIPS boards boot prom).
+	 */
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
+		 (0 << GT_PCI0_CFGADDR_BUSNUM_SHF)   |  /* Local bus */
+		 (0 << GT_PCI0_CFGADDR_DEVNUM_SHF)   |  /* GT64120 device */
+		 (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |  /* Function 0 */
+		 ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) |  /* BAR 4 */
+		 GT_PCI0_CFGADDR_CONFIGEN_BIT );
+
+	/* Perform the write */
+	GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE)); 
+
+#ifdef CONFIG_MIPS_MALTA
+	pci_for_each_dev(pdev) {
+		if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
+		    && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB)
+		    && (PCI_SLOT(pdev->devfn) == 0x0a)) {
+			/*
+			 * IDE Decode enable.
+			 */
+			pci_read_config_byte(pdev, 0x41, &reg_val);
+        		pci_write_config_byte(pdev, 0x41, reg_val | 0x80);
+			pci_read_config_byte(pdev, 0x43, &reg_val);
+        		pci_write_config_byte(pdev, 0x43, reg_val | 0x80);
+		}
+
+		if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
+		    && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0)
+		    && (PCI_SLOT(pdev->devfn) == 0x0a)) {
+			/*
+			 * Set top of main memory accessible by ISA or DMA
+			 * devices to 16 Mb.
+			 */
+			pci_read_config_byte(pdev, 0x69, &reg_val);
+			pci_write_config_byte(pdev, 0x69, reg_val | 0xf0);
+		}
+	}
+
+	/* 
+	 * Activate Floppy Controller in the SMSC FDC37M817 Super I/O 
+	 * Controller.
+	 * This should be done in the bios/bootprom and will be fixed in
+         * a later revision of YAMON (the MIPS boards boot prom).
+	 */
+	/* Entering config state. */
+	SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); 
+       
+	/* Activate floppy controller. */
+	SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
+	SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
+	SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG);
+	SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG);
+
+	/* Exit config state. */
+	SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG);
+#endif
+}
+
+int __init
+pcibios_enable_device(struct pci_dev *dev)
+{
+	/* Not needed, since we enable all devices at startup.  */
+	return 0;
+}
+
+void __init
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+	/* Nothing to do for now.  */
+
+	return str;
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ 0 }
+};
+
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                        struct resource *res, int resource)
+{
+	unsigned long where, size;
+	u32 reg;
+
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	size = res->end - res->start;
+	pci_read_config_dword(dev, where, &reg);
+	reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+	pci_write_config_dword(dev, where, reg);
+}
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_read_bridge_bases(b);
+}
+
+#endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/printf.c linux/arch/mips/mips-boards/generic/printf.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/printf.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/printf.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,140 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Putting things on the screen/serial line using YAMONs facilities.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/serial.h>
+
+
+#ifdef CONFIG_MIPS_ATLAS 
+/* 
+ * Atlas registers are memory mapped on 64-bit aligned boundaries and 
+ * only word access are allowed.
+ * When reading the UART 8 bit registers only the LSB are valid.
+ */
+unsigned int atlas_serial_in(struct async_struct *info, int offset)
+{
+	return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff);
+}
+
+void atlas_serial_out(struct async_struct *info, int offset, int value)
+{
+	*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value;
+}
+
+#define serial_in  atlas_serial_in
+#define serial_out atlas_serial_out
+
+#else
+
+static unsigned int serial_in(struct async_struct *info, int offset)
+{
+	return inb(info->port + offset);
+}
+
+static void serial_out(struct async_struct *info, int offset,
+				int value)
+{
+	outb(value, info->port + offset);
+}
+#endif
+
+static struct serial_state rs_table[] = {
+	SERIAL_PORT_DFNS	/* Defined in serial.h */
+};
+
+/*
+ * Hooks to fake "prom" console I/O before devices 
+ * are fully initialized. 
+ */
+static struct async_struct prom_port_info = {0};
+
+void __init setup_prom_printf(int tty_no) {
+	struct serial_state *ser = &rs_table[tty_no];
+
+	prom_port_info.state = ser;
+	prom_port_info.magic = SERIAL_MAGIC;
+	prom_port_info.port = ser->port;
+	prom_port_info.flags = ser->flags;
+
+	/* No setup of UART - assume YAMON left in sane state */
+}
+
+int putPromChar(char c)
+{
+        if (!prom_port_info.state) { 	/* need to init device first */
+		return 0;
+	}
+
+	while ((serial_in(&prom_port_info, UART_LSR) & UART_LSR_THRE) == 0)
+		;
+
+	serial_out(&prom_port_info, UART_TX, c);
+
+	return 1;
+}
+
+char getPromChar(void)
+{
+	if (!prom_port_info.state) { 	/* need to init device first */
+		return 0;
+	}
+
+	while (!(serial_in(&prom_port_info, UART_LSR) & 1))
+		;
+
+	return(serial_in(&prom_port_info, UART_RX));
+}
+
+static char buf[1024];
+
+void __init prom_printf(char *fmt, ...)
+{
+	va_list args;
+	int l;
+	char *p, *buf_end;
+	long flags;
+
+	int putPromChar(char);
+
+	/* Low level, brute force, not SMP safe... */
+	save_and_cli(flags);
+	va_start(args, fmt);
+	l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
+	va_end(args);
+
+	buf_end = buf + l;
+
+	for (p = buf; p < buf_end; p++) {
+		/* Crude cr/nl handling is better than none */
+		if(*p == '\n')putPromChar('\r');
+		putPromChar(*p);
+	}
+	restore_flags(flags);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/reset.c linux/arch/mips/mips-boards/generic/reset.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/reset.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/reset.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,72 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Reset the MIPS boards.
+ *
+ */
+#include <linux/config.h>
+
+#include <asm/reboot.h>
+#include <asm/mips-boards/generic.h>
+#if defined(CONFIG_MIPS_ATLAS)
+#include <asm/mips-boards/atlas.h>
+#endif
+
+static void mips_machine_restart(char *command);
+static void mips_machine_halt(void);
+#if defined(CONFIG_MIPS_ATLAS)
+static void atlas_machine_power_off(void);
+#endif
+
+static void mips_machine_restart(char *command)
+{
+        volatile unsigned int *softres_reg = (void *)SOFTRES_REG;
+
+	*softres_reg = GORESET;
+}
+
+static void mips_machine_halt(void)
+{
+        volatile unsigned int *softres_reg = (void *)SOFTRES_REG;
+
+	*softres_reg = GORESET;
+}
+
+#if defined(CONFIG_MIPS_ATLAS)
+static void atlas_machine_power_off(void)
+{
+        volatile unsigned int *psustby_reg = (void *)ATLAS_PSUSTBY_REG;
+
+	*psustby_reg = ATLAS_GOSTBY;
+}
+#endif
+
+void mips_reboot_setup(void)
+{
+	_machine_restart = mips_machine_restart;
+	_machine_halt = mips_machine_halt;
+#if defined(CONFIG_MIPS_ATLAS)
+	_machine_power_off = atlas_machine_power_off;
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+	_machine_power_off = mips_machine_halt;
+#endif
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/generic/time.c linux/arch/mips/mips-boards/generic/time.c
--- v2.4.3/linux/arch/mips/mips-boards/generic/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/generic/time.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,410 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Setting up the clock on the MIPS boards.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/div64.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+
+extern volatile unsigned long wall_jiffies;
+static long last_rtc_update = 0;
+unsigned long missed_heart_beats = 0;
+
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur;    /* What counter should be at next timer irq */
+extern rwlock_t xtime_lock;
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+
+#if defined(CONFIG_MIPS_ATLAS)
+static char display_string[] = "        LINUX ON ATLAS       ";
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+static char display_string[] = "        LINUX ON MALTA       ";
+#endif
+static unsigned int display_count = 0;
+#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) 
+
+static unsigned int timer_tick_count=0;
+
+
+static inline void ack_r4ktimer(unsigned long newval)
+{
+	write_32bit_cp0_register(CP0_COMPARE, newval);
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ *      sets the minutes. Usually you won't notice until after reboot!
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned char save_control, save_freq_select;
+
+	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+	cmos_minutes = CMOS_READ(RTC_MINUTES);
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;		/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		CMOS_WRITE(real_seconds,RTC_SECONDS);
+		CMOS_WRITE(real_minutes,RTC_MINUTES);
+	} else {
+		printk(KERN_WARNING
+		       "set_rtc_mmss: can't update from %d to %d\n",
+		       cmos_minutes, real_minutes);
+ 		retval = -1;
+	}
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	return retval;
+}
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around.  This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+void mips_timer_interrupt(struct pt_regs *regs)
+{
+	int irq = 7;
+
+	if (r4k_offset == 0)
+		goto null;
+
+	do {
+		kstat.irqs[0][irq]++;
+		do_timer(regs);
+
+		/* Historical comment/code:
+ 		 * RTC time of day s updated approx. every 11 
+ 		 * minutes.  Because of how the numbers work out 
+ 		 * we need to make absolutely sure we do this update
+ 		 * within 500ms before the * next second starts, 
+ 		 * thus the following code.
+ 		 */
+		read_lock(&xtime_lock);
+		if ((time_status & STA_UNSYNC) == 0 
+		    && xtime.tv_sec > last_rtc_update + 660 
+		    && xtime.tv_usec >= 500000 - (tick >> 1) 
+		    && xtime.tv_usec <= 500000 + (tick >> 1))
+			if (set_rtc_mmss(xtime.tv_sec) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else
+				/* do it again in 60 s */
+	    			last_rtc_update = xtime.tv_sec - 600; 
+		read_unlock(&xtime_lock);
+
+		if ((timer_tick_count++ % HZ) == 0) {
+		    mips_display_message(&display_string[display_count++]);
+		    if (display_count == MAX_DISPLAY_COUNT)
+		        display_count = 0;
+		}
+
+		r4k_cur += r4k_offset;
+		ack_r4ktimer(r4k_cur);
+
+	} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
+	         - r4k_cur) < 0x7fffffff);
+
+	return;
+
+null:
+	ack_r4ktimer(0);
+}
+
+/* 
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick. 
+ * Use the RTC to calculate offset.
+ */
+static unsigned long __init cal_r4koff(void)
+{
+	unsigned long count;
+	unsigned int flags;
+
+	__save_and_cli(flags);
+
+	/* Start counter exactly on falling edge of update flag */
+	while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+	/* Start r4k counter. */
+	write_32bit_cp0_register(CP0_COUNT, 0);
+
+	/* Read counter exactly on falling edge of update flag */
+	while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+	count = read_32bit_cp0_register(CP0_COUNT);
+
+	/* restore interrupts */
+	__restore_flags(flags);
+
+	return (count / HZ);
+}
+
+static unsigned long __init get_mips_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned char save_control;
+
+	save_control = CMOS_READ(RTC_CONTROL);
+
+	/* Freeze it. */
+	CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
+
+	/* Read regs. */
+	sec = CMOS_READ(RTC_SECONDS);
+	min = CMOS_READ(RTC_MINUTES);
+	hour = CMOS_READ(RTC_HOURS);
+
+	if (!(save_control & RTC_24H))
+	{
+		if ((hour & 0xf) == 0xc)
+		        hour &= 0x80;
+	        if (hour & 0x80)
+		        hour = (hour & 0xf) + 12;     
+	}
+	day = CMOS_READ(RTC_DAY_OF_MONTH);
+	mon = CMOS_READ(RTC_MONTH);
+	year = CMOS_READ(RTC_YEAR);
+
+	/* Unfreeze clock. */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+
+	if ((year += 1900) < 1970)
+	        year += 100;
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+void __init time_init(void)
+{
+        unsigned int est_freq, flags;
+
+        /* Set Data mode - binary. */ 
+        CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
+
+	printk("calculating r4koff... ");
+	r4k_offset = cal_r4koff();
+	printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+	est_freq = 2*r4k_offset*HZ;	
+	est_freq += 5000;    /* round */
+	est_freq -= est_freq%10000;
+	printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 
+	       (est_freq%1000000)*100/1000000);
+	r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+
+	write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
+	change_cp0_status(ST0_IM, ALLINTS);
+
+	/* Read time from the RTC chipset. */
+	write_lock_irqsave (&xtime_lock, flags);
+	xtime.tv_sec = get_mips_time();
+	xtime.tv_usec = 0;
+	write_unlock_irqrestore(&xtime_lock, flags);
+}
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff)
+
+/* Cycle counter value at the previous timer interrupt.. */
+
+static unsigned int timerhi = 0, timerlo = 0;
+
+/*
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+
+	/* Last jiffy when do_fast_gettimeoffset() was called. */
+	static unsigned long last_jiffies=0;
+	unsigned long quotient;
+
+	/*
+	 * Cached "1/(clocks per usec)*2^32" value.
+	 * It has to be recalculated once each jiffy.
+	 */
+	static unsigned long cached_quotient=0;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (tmp && last_jiffies != tmp) {
+		last_jiffies = tmp;
+#ifdef CONFIG_CPU_MIPS32
+		if (last_jiffies != 0) {
+			unsigned long r0;
+			do_div64_32(r0, timerhi, timerlo, tmp);
+			do_div64_32(quotient, USECS_PER_JIFFY,
+				    USECS_PER_JIFFY_FRAC, r0);
+			cached_quotient = quotient;
+		}
+#else
+		__asm__(".set\tnoreorder\n\t"
+			".set\tnoat\n\t"
+			".set\tmips3\n\t"
+			"lwu\t%0,%2\n\t"
+			"dsll32\t$1,%1,0\n\t"
+			"or\t$1,$1,%0\n\t"
+			"ddivu\t$0,$1,%3\n\t"
+			"mflo\t$1\n\t"
+			"dsll32\t%0,%4,0\n\t"
+			"nop\n\t"
+			"ddivu\t$0,%0,$1\n\t"
+			"mflo\t%0\n\t"
+			".set\tmips0\n\t"
+			".set\tat\n\t"
+			".set\treorder"
+			:"=&r" (quotient)
+			:"r" (timerhi),
+			 "m" (timerlo),
+			 "r" (tmp),
+			 "r" (USECS_PER_JIFFY)
+			:"$1");
+		cached_quotient = quotient;
+#endif
+	}
+
+	/* Get last timer tick in absolute kernel time */
+	count = read_32bit_cp0_register(CP0_COUNT);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+
+	__asm__("multu\t%1,%2\n\t"
+		"mfhi\t%0"
+		:"=r" (res)
+		:"r" (count),
+		 "r" (quotient));
+
+	/*
+ 	 * Due to possible jiffies inconsistencies, we need to check 
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY-1;
+
+	return res;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned int flags;
+
+	read_lock_irqsave (&xtime_lock, flags);
+	*tv = xtime;
+	tv->tv_usec += do_fast_gettimeoffset();
+
+	/*
+	 * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
+	 * is nonzero if the timer bottom half hasnt executed yet.
+	 */
+	if (jiffies - wall_jiffies)
+		tv->tv_usec += USECS_PER_JIFFY;
+
+	read_unlock_irqrestore (&xtime_lock, flags);
+
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	write_lock_irq (&xtime_lock);
+
+	/* This is revolting. We need to set the xtime.tv_usec correctly.
+	 * However, the value in this location is is value at the last tick.
+	 * Discover what correction gettimeofday would have done, and then
+	 * undo it!
+	 */
+	tv->tv_usec -= do_fast_gettimeoffset();
+
+	if (tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+
+	xtime = *tv;
+	time_adjust = 0;		/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+
+	write_unlock_irq (&xtime_lock);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/Makefile linux/arch/mips/mips-boards/malta/Makefile
--- v2.4.3/linux/arch/mips/mips-boards/malta/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/malta/Makefile	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,40 @@
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+# 
+# This program is distributed in the hope 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.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# #######################################################################
+#
+# Makefile for the MIPS Malta specific kernel interface routines
+# under Linux.
+#
+# 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 in the main makefile...
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET := malta.o
+
+obj-y := malta_int.o malta_rtc.o malta_setup.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/malta_int.c linux/arch/mips/mips-boards/malta/malta_int.c
--- v2.4.3/linux/arch/mips/mips-boards/malta/malta_int.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/malta/malta_int.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,378 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS 
+ * Malta board.
+ * The interrupt controller is located in the South Bridge a PIIX4 device 
+ * with two internal 82C95 interrupt controllers.
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/random.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mips-boards/malta.h>
+#include <asm/mips-boards/maltaint.h>
+#include <asm/mips-boards/piix4.h>
+#include <asm/gt64120.h>
+#include <asm/mips-boards/generic.h>
+
+extern asmlinkage void mipsIRQ(void);
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+static struct irqaction *hw0_irq_action[MALTAINT_END] = {
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL
+};
+
+static struct irqaction r4ktimer_action = {
+	NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
+};
+
+static struct irqaction *irq_action[8] = {
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, &r4ktimer_action
+};
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+/*
+ * This contains the interrupt mask for both 82C59 interrupt controllers.
+ */
+static unsigned int cached_int_mask = 0xffff;
+
+
+void disable_irq(unsigned int irq_nr)
+{
+        unsigned long flags;
+
+	if(irq_nr >= MALTAINT_END) {
+		printk("whee, invalid irq_nr %d\n", irq_nr);
+		panic("IRQ, you lose...");
+	}
+
+	save_and_cli(flags);
+	cached_int_mask |= (1 << irq_nr);
+	if (irq_nr & 8) {
+	        outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+	} else {
+		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+	}
+	restore_flags(flags);
+}
+
+
+void enable_irq(unsigned int irq_nr)
+{
+        unsigned long flags;
+
+	if(irq_nr >= MALTAINT_END) {
+		printk("whee, invalid irq_nr %d\n", irq_nr);
+		panic("IRQ, you lose...");
+	}
+
+	save_and_cli(flags);
+	cached_int_mask &= ~(1 << irq_nr);
+	if (irq_nr & 8) {
+		outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+
+		/* Enable irq 2 (cascade interrupt). */
+	        cached_int_mask &= ~(1 << 2); 
+		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+	} else {
+		outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+	}	
+	restore_flags(flags);
+}
+
+
+int get_irq_list(char *buf)
+{
+	int i, len = 0;
+	int num = 0;
+	struct irqaction *action;
+
+	for (i = 0; i < 8; i++, num++) {
+		action = irq_action[i];
+		if (!action) 
+			continue;
+		len += sprintf(buf+len, "%2d: %8d %c %s",
+			num, kstat.irqs[0][num],
+			(action->flags & SA_INTERRUPT) ? '+' : ' ',
+			action->name);
+		for (action=action->next; action; action = action->next) {
+			len += sprintf(buf+len, ",%s %s",
+				(action->flags & SA_INTERRUPT) ? " +" : "",
+				action->name);
+		}
+		len += sprintf(buf+len, " [on-chip]\n");
+	}
+	for (i = 0; i < MALTAINT_END; i++, num++) {
+		action = hw0_irq_action[i];
+		if (!action) 
+			continue;
+		len += sprintf(buf+len, "%2d: %8d %c %s",
+			num, kstat.irqs[0][num],
+			(action->flags & SA_INTERRUPT) ? '+' : ' ',
+			action->name);
+		for (action=action->next; action; action = action->next) {
+			len += sprintf(buf+len, ",%s %s",
+				(action->flags & SA_INTERRUPT) ? " +" : "",
+				action->name);
+		}
+		len += sprintf(buf+len, " [hw0]\n");
+	}
+	return len;
+}
+
+
+static int setup_irq(unsigned int irq, struct irqaction * new)
+{
+	int shared = 0;
+	struct irqaction *old, **p;
+
+	p = &hw0_irq_action[irq];
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ))
+			return -EBUSY;
+
+		/* Can't share interrupts unless both are same type */
+		if ((old->flags ^ new->flags) & SA_INTERRUPT)
+			return -EBUSY;
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	if (new->flags & SA_SAMPLE_RANDOM)
+		rand_initialize_irq(irq);
+
+	*p = new;
+	if (!shared)
+		enable_irq(irq);
+
+	return 0;
+}
+
+int request_irq(unsigned int irq, 
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{  
+        struct irqaction *action;
+	int retval;
+
+	DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+        if (irq >= MALTAINT_END)
+	        return -EINVAL;
+	if (!handler)
+	        return -EINVAL;
+
+	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if(!action)
+	        return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
+	action->dev_id = dev_id;
+	action->next = 0;
+
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+
+	return retval;	
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+	struct irqaction *action, **p;
+
+	if (irq >= MALTAINT_END) {
+		printk("Trying to free IRQ%d\n",irq);
+		return;
+	}
+	
+	for (p = &hw0_irq_action[irq]; (action = *p) != NULL; 
+	     p = &action->next) 
+	{
+		if (action->dev_id != dev_id)
+			continue;
+
+		/* Found it - now free it */
+		*p = action->next;
+		kfree(action);
+		if (!hw0_irq_action[irq])
+			disable_irq(irq);
+		return;
+	}
+	printk("Trying to free IRQ%d\n",irq);
+}
+
+void __init init_IRQ(void)
+{
+	irq_setup();
+}
+
+static inline int get_int(int *irq)
+{
+	/*  
+	 * Determine highest priority pending interrupt by performing
+         * a PCI Interrupt Acknowledge cycle.
+	 */
+	GT_READ(GT_PCI0_IACK_OFS, *irq);
+	*irq &= 0xFF;
+
+	/*  
+	 * IRQ7 is used to detect spurious interrupts.
+	 * The interrupt acknowledge cycle returns IRQ7, if no 
+	 * interrupts is requested.
+	 * We can differentiate between this situation and a
+	 * "Normal" IRQ7 by reading the ISR.
+	 */
+	if (*irq == 7) 
+	{
+		outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3);
+		if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7)))
+		        return -1;    /* Spurious interrupt. */
+	}
+
+	return 0;
+}
+
+static inline void ack_int(int irq)
+{
+	if (irq & 8) {
+	        /* Specific EOI to cascade */
+		outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2, 
+		     PIIX4_ICTLR1_OCW2);
+
+	        /* Non specific EOI to cascade */
+		outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2);
+	} else {
+	        /* Non specific EOI to cascade */
+		outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2);
+	}
+}
+
+void malta_hw0_irqdispatch(struct pt_regs *regs)
+{
+        struct irqaction *action;
+	int irq=0, cpu = smp_processor_id();
+
+	DEBUG_INT("malta_hw0_irqdispatch\n");
+	
+	if (get_int(&irq))
+	        return;  /* interrupt has already been cleared */
+
+	disable_irq(irq);
+	ack_int(irq);
+
+	DEBUG_INT("malta_hw0_irqdispatch: irq=%d\n", irq);
+	action = hw0_irq_action[irq];
+
+	/* 
+	 * if action == NULL, then we don't have a handler 
+	 * for the irq 
+	 */
+	if ( action == NULL )
+		return;
+
+	irq_enter(cpu, irq);
+	kstat.irqs[0][irq + 8]++;
+	do {
+	        action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+
+	enable_irq(irq);
+	irq_exit(cpu, irq);
+}
+
+
+unsigned long probe_irq_on (void)
+{
+	unsigned int i, irqs = 0;
+	unsigned long delay;
+
+	/* first, enable any unassigned irqs */
+	for (i = MALTAINT_END-1; i > 0; i--) {
+		if (!hw0_irq_action[i]) {
+			enable_irq(i);
+			irqs |= (1 << i);
+		}
+	}
+
+	/* wait for spurious interrupts to mask themselves out again */
+	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
+		/* about 100ms delay */;
+
+	/* now filter out any obviously spurious interrupts */
+	return irqs & ~cached_int_mask;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+	unsigned int i;
+
+	irqs &= cached_int_mask;
+	if (!irqs)
+		return 0;
+	i = ffz(~irqs);
+	if (irqs != (irqs & (1 << i)))
+		i = -i;
+
+	return i;
+}
+
+
+void __init maltaint_init(void)
+{
+        /* 
+	 * Mask out all interrupt by writing "1" to all bit position in 
+	 * the IMR register. 
+	 */
+	outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+	outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+
+	/* Now safe to set the exception vector. */
+	set_except_vector(0, mipsIRQ);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/malta_rtc.c linux/arch/mips/mips-boards/malta/malta_rtc.c
--- v2.4.3/linux/arch/mips/mips-boards/malta/malta_rtc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/malta/malta_rtc.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,51 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * RTC routines for Malta style attached PIIX4 device, which contains a
+ * Motorola MC146818A-compatible Real Time Clock.
+ *
+ */
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mips-boards/malta.h>
+
+static unsigned char malta_rtc_read_data(unsigned long addr)
+{
+	outb(addr, MALTA_RTC_ADR_REG);
+	return inb(MALTA_RTC_DAT_REG);
+}
+
+static void malta_rtc_write_data(unsigned char data, unsigned long addr)
+{
+	outb(addr, MALTA_RTC_ADR_REG);
+	outb(data, MALTA_RTC_DAT_REG);
+}
+
+static int malta_rtc_bcd_mode(void)
+{
+	return 0;
+}
+
+struct rtc_ops malta_rtc_ops = {
+	&malta_rtc_read_data,
+	&malta_rtc_write_data,
+	&malta_rtc_bcd_mode
+};
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mips-boards/malta/malta_setup.c linux/arch/mips/mips-boards/malta/malta_setup.c
--- v2.4.3/linux/arch/mips/mips-boards/malta/malta_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mips-boards/malta/malta_setup.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,159 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Malta specific setup, including init of the feature struct.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#ifdef CONFIG_BLK_DEV_IDE
+#include <linux/ide.h>
+#endif
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/malta.h>
+#include <asm/mips-boards/maltaint.h>
+#ifdef CONFIG_BLK_DEV_FD
+#include <asm/floppy.h>
+#endif
+#include <asm/dma.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_debug_traps(void);
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+static int remote_debug = 0;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+extern struct fd_ops std_fd_ops;
+#endif
+extern struct rtc_ops malta_rtc_ops;
+
+extern void mips_reboot_setup(void);
+
+struct resource standard_io_resources[] = {
+	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+	{ "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+	{ "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+	{ "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+	{ "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+	{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+};
+
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+static void __init malta_irq_setup(void)
+{
+  	maltaint_init();
+
+#ifdef CONFIG_REMOTE_DEBUG
+	if (remote_debug) {
+		set_debug_traps();
+		breakpoint(); 
+	}
+#endif
+}
+
+
+void __init malta_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+	int rs_putDebugChar(char);
+	char rs_getDebugChar(void);
+	extern int (*putDebugChar)(char);
+	extern char (*getDebugChar)(void);
+#endif
+	char *argptr;
+	int i;
+
+	irq_setup = malta_irq_setup;
+
+	/* Request I/O space for devices used on the Malta board. */
+	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+		request_resource(&ioport_resource, standard_io_resources+i);
+
+	/* 
+	 * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge.
+	 */
+	enable_dma(4);
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	argptr = prom_getcmdline();
+	if ((argptr = strstr(argptr, "console=")) == NULL) {
+		argptr = prom_getcmdline();
+		strcat(argptr, " console=ttyS0,38400");
+	}
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+	argptr = prom_getcmdline();
+	if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
+		int line;
+		argptr += strlen("kgdb=ttyS");
+		if (*argptr != '0' && *argptr != '1')
+			printk("KGDB: Uknown serial line /dev/ttyS%c, "
+			       "falling back to /dev/ttyS1\n", *argptr);
+		line = *argptr == '0' ? 0 : 1;
+		printk("KGDB: Using serial line /dev/ttyS%d for session\n",
+		       line ? 1 : 0);
+
+		rs_kgdb_hook(line);
+		putDebugChar = rs_putDebugChar;
+		getDebugChar = rs_getDebugChar;
+
+		prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
+			    "please connect your debugger\n", line ? 1 : 0);
+
+		remote_debug = 1;
+		/* Breakpoints and stuff are in malta_irq_setup() */
+	}
+#endif
+
+	argptr = prom_getcmdline();
+	if ((argptr = strstr(argptr, "nofpu")) != NULL)
+		mips_cpu.options &= ~MIPS_CPU_FPU;
+		
+	rtc_ops = &malta_rtc_ops;
+#ifdef CONFIG_BLK_DEV_IDE
+        ide_ops = &std_ide_ops;
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+        fd_ops = &std_fd_ops;
+#endif
+	mips_reboot_setup();
+}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile
--- v2.4.3/linux/arch/mips/mm/Makefile	Thu Feb 24 22:52:30 2000
+++ linux/arch/mips/mm/Makefile	Fri Apr 13 20:26:07 2001
@@ -8,34 +8,20 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := extable.o init.o fault.o loadmmu.o
 
-ifdef CONFIG_CPU_R3000
-O_OBJS   += r2300.o
-endif
+export-objs			+= umap.o
+obj-y				+= extable.o init.o fault.o loadmmu.o
 
-ifdef CONFIG_CPU_R4300
-O_OBJS   += r4xx0.o
-endif
-
-ifdef CONFIG_CPU_R4X00
-O_OBJS   += r4xx0.o
-endif
-
-ifdef CONFIG_CPU_R5000
-O_OBJS   += r4xx0.o
-endif
-
-ifdef CONFIG_CPU_NEVADA
-O_OBJS   += r4xx0.o
-endif
-
-ifdef CONFIG_SGI_IP22
-O_OBJS   += umap.o
-endif
-
-ifdef CONFIG_BAGET_MIPS
-O_OBJS   += umap.o
-endif
+obj-$(CONFIG_CPU_R3000)		+= r2300.o
+obj-$(CONFIG_CPU_R3912)		+= r2300.o
+obj-$(CONFIG_CPU_R4300)		+= r4xx0.o
+obj-$(CONFIG_CPU_R4X00)		+= r4xx0.o
+obj-$(CONFIG_CPU_R5000)		+= r4xx0.o
+obj-$(CONFIG_CPU_NEVADA)	+= r4xx0.o
+obj-$(CONFIG_CPU_R5432)		+= r5432.o
+obj-$(CONFIG_CPU_RM7000)	+= rm7k.o
+obj-$(CONFIG_CPU_MIPS32)	+= mips32.o
+obj-$(CONFIG_SGI_IP22)		+= umap.o
+obj-$(CONFIG_BAGET_MIPS)	+= umap.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/Makefile linux/arch/mips/orion/Makefile
--- v2.4.3/linux/arch/mips/orion/Makefile	Tue Jul 11 11:14:48 2000
+++ linux/arch/mips/orion/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-#
-# Produce a bootimage for the IPSX
-#  Copyright (C) 2000 Cort Dougan <cort@fsmlabs.com>
-#
-
-.S.s:
-	$(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
-	$(CC) $(CFLAGS) -c $< -o $*.o
-
-OBJS = promcon.o char.o serial.8530.o orion.hw.init.o setup.o irq.o int-handler.o
-
-all: orionkern.a
-
-orionkern.a: $(OBJS) initrd.o #no_initrd.o
-	$(AR) rcs orionkern.a $(OBJS) initrd.o #no_initrd.o
-	sync
-
-initrd.c: piggyback ramdisk.image.gz
-	./piggyback initrd < ramdisk.image.gz > initrd.c
-
-piggyback: piggyback.c
-	$(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
-
-orionboot: orion.ctl
-
-patchapp: patchapp.c
-	$(HOSTCC) -o $@ $^
-
-orion.ctl: patchapp ../../../vmlinux
-	$(OBJCOPY) -Obinary ../../../vmlinux orion.nosym
-	./patchapp orion.nosym orion
-	cp -f orion.bin orion.ctl
-
-# Don't build dependencies, this may die if $(CC) isn't gcc
-dep:
-
-clean:
-	rm -f patchapp orion.bin orion.nosym orion.ctl initrd.c
-
-dummy:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/int-handler.S linux/arch/mips/orion/int-handler.S
--- v2.4.3/linux/arch/mips/orion/int-handler.S	Tue Jul 11 11:14:48 2000
+++ linux/arch/mips/orion/int-handler.S	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-	.text
-	.set    mips1
-	.set    reorder
-	.set    macro
-	.set    noat
-	.align	5
-
-NESTED(orionIRQ, PT_SIZE, sp)
-	SAVE_ALL
-	CLI				# Important: mark KERNEL mode !
-	/*
-	 * Get pending interrupts
-	 */
-	mfc0	t0,CP0_CAUSE		# get pending interrupts
-	mfc0	t1,CP0_STATUS		# get enabled interrupts
-	and	t0,t1			# isolate allowed ones
-	andi	t0,0xff00		# isolate pending bits
-	sll	t0,16			# shift the pending bits down
-	beqz	t0,3f			# no pending intrs, then spurious
-	nop				# delay slot
-	
-	/*
-	 * Find irq with highest priority
-	 * FIXME: This is slow - use binary search
-	 */
-	la	a0,7
-1:	bltz	t0,2f			# found pending irq
-	subu	a0,1
-	sll	t0,1
-	b	1b
-	nop				# delay slot
-
-call_do_IRQ:
-2:	move	a1,sp
-	jal	do_IRQ
-	nop				# delay slot
-
-	mfc0	t0,CP0_STATUS		# disable interrupts
-	ori	t0,1
-	xori	t0,1
-	mtc0	t0,CP0_STATUS
-	
-	la      a1, ret_from_irq
-	jr	a1
-	
-3:	j	spurious_interrupt
-END(orionIRQ)
-
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/irq.c linux/arch/mips/orion/irq.c
--- v2.4.3/linux/arch/mips/orion/irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips/orion/irq.c	Wed Dec 31 16:00:00 1969
@@ -1,281 +0,0 @@
-/*
- * Code to handle irqs on Orion boards
- *  -- Cort <cort@fsmlabs.com>
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/orion.h>
-
-void (*board_time_init)(struct irqaction *irq);
-extern asmlinkage void orionIRQ(void);
-unsigned long spurious_count = 0;
-irq_desc_t irq_desc[NR_IRQS];
-
-static void galileo_ack(unsigned int irq_nr)
-{
-	*((unsigned long *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0xC18) ) = (((( 0 )&0xff)<<24)+	((( 0 )&0xff00)<<8)+	((( 0 )&0xff0000)>>8)+	((( 0 )&0xff000000)>>24))  ;
-}
-
-struct hw_interrupt_type galileo_pic = {
-        " Galileo  ",
-        NULL,
-        NULL,
-        NULL, /* unmask_irq */
-        NULL, /* mask_irq */
-        galileo_ack, /* mask_and_ack */
-        0
-};
-
-/* Function for careful CP0 interrupt mask access */
-static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
-{
-	unsigned long status = read_32bit_cp0_register(CP0_STATUS);
-	status &= ~((clr_mask & 0xFF) << 8);
-	status |=   (set_mask & 0xFF) << 8;
-	write_32bit_cp0_register(CP0_STATUS, status);
-}
-
-static inline void mask_irq(unsigned int irq_nr)
-{
-        modify_cp0_intmask(irq_nr, 0);
-}
-
-static inline void unmask_irq(unsigned int irq_nr)
-{
-	modify_cp0_intmask(0, irq_nr);
-}
-
-void disable_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	mask_irq(irq_nr);
-	restore_flags(flags);
-}
-
-void enable_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	unmask_irq(irq_nr);
-	restore_flags(flags);
-}
-
-/*static struct irqaction *irq_action[NR_IRQS] = {
-	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, 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, NULL, NULL, NULL, NULL, NULL, NULL
-};
-*/
-void __init orion_time_init(struct irqaction *irq)
-{
-	__u32 timer_count;
-	
-	irq_desc[2].handler = &galileo_pic;
-	irq_desc[2].action = irq;
-	
-	/* This code was provided by the CoSine guys and despite its
-	 * appearance init's the timer.
-	 * -- Cort
-	 */
-	*((__u32 *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0x864) ) = (((( 0 )&0xff)<<24)+	((( 0 )&0xff00)<<8)+	((( 0 )&0xff0000)>>8)+	((( 0 )&0xff000000)>>24)) ;
-	
-	*((__u32 *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0x850) ) = (((( 0 )&0xff)<<24)+	((( 0 )&0xff00)<<8)+	((( 0 )&0xff0000)>>8)+	((( 0 )&0xff000000)>>24)) ;
-
-        timer_count = 300000000/100;
-	
-	*((__u32 *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0x850) ) = ((((  timer_count  )&0xff)<<24)+	(((  timer_count  )&0xff00)<<8)+	(((  timer_count  )&0xff0000)>>8)+	(((  timer_count  )&0xff000000)>>24))  ;
-
-	*((__u32 *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0xC1C) ) = ((((  0x100   )&0xff)<<24)+	(((  0x100   )&0xff00)<<8)+	(((  0x100   )&0xff0000)>>8)+	(((  0x100   )&0xff000000)>>24))  ;
-     
-	*((__u32 *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0x864) ) = ((((  0x03  )&0xff)<<24)+	(((  0x03  )&0xff00)<<8)+	(((  0x03  )&0xff0000)>>8)+	(((  0x03  )&0xff000000)>>24))  ;
-     
-	*((__u32 *) (((unsigned)( 0x14000000  )|0xA0000000)   + 0xC18) ) = (((( 0 )&0xff)<<24)+	((( 0 )&0xff00)<<8)+	((( 0 )&0xff0000)>>8)+	((( 0 )&0xff000000)>>24))  ;
-}
-
-int get_irq_list(char *buf)
-{
-	int i, len = 0, j;
-	struct irqaction * action;
-
-	len += sprintf(buf+len, "           ");
-	for (j=0; j<smp_num_cpus; j++)
-		len += sprintf(buf+len, "CPU%d       ",j);
-	*(char *)(buf+len++) = '\n';
-
-	for (i = 0 ; i < NR_IRQS ; i++) {
-		action = irq_desc[i].action;
-		if ( !action || !action->handler )
-			continue;
-		len += sprintf(buf+len, "%3d: ", i);		
-		len += sprintf(buf+len, "%10u ", kstat_irqs(i));
-		if ( irq_desc[i].handler )		
-			len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
-		else
-			len += sprintf(buf+len, "  None      ");
-		len += sprintf(buf+len, "    %s",action->name);
-		for (action=action->next; action; action = action->next) {
-			len += sprintf(buf+len, ", %s", action->name);
-		}
-		len += sprintf(buf+len, "\n");
-	}
-	len += sprintf(buf+len, "BAD: %10lu\n", spurious_count);
-	return len;
-}
-
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
-{
-	struct irqaction *action;
-	int do_random, cpu;
-	int status;
-
-	cpu = smp_processor_id();
-	irq_enter(cpu);
-	kstat.irqs[cpu][irq]++;
-	status = 0;
-
-	if (irq_desc[irq].handler->ack)
-		irq_desc[irq].handler->ack(irq);
-	
-	action = irq_desc[irq].action;
-	if (action && action->handler)
-	{
-		if (!(action->flags & SA_INTERRUPT))
-			__sti();
-		do { 
-			status |= action->flags;
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while ( action );
-		__cli();
-		if (irq_desc[irq].handler)
-		{
-			if (irq_desc[irq].handler->end)
-				irq_desc[irq].handler->end(irq);
-			else if (irq_desc[irq].handler->enable)
-				irq_desc[irq].handler->enable(irq);
-		}
-	}
-
-	irq_exit(cpu);
-
-	if (softirq_active(cpu)&softirq_mask(cpu))
-		do_softirq();
-
-	/* unmasking and bottom half handling is done magically for us. */
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
-{
-	struct irqaction *old, **p, *action;
-	unsigned long flags;
-
-	if (irq >= NR_IRQS)
-		return -EINVAL;
-	if (!handler)
-	{
-		/* Free */
-		for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
-		{
-			/* Found it - now free it */
-			save_flags(flags);
-			cli();
-			*p = action->next;
-			restore_flags(flags);
-			kfree(action);
-			return 0;
-		}
-		return -ENOENT;
-	}
-	
-	action = (struct irqaction *)
-		kmalloc(sizeof(struct irqaction), GFP_KERNEL);
-	if (!action)
-		return -ENOMEM;
-	
-	save_flags(flags);
-	cli();
-	
-	action->handler = handler;
-	action->flags = irqflags;					
-	action->mask = 0;
-	action->name = devname;
-	action->dev_id = dev_id;
-	action->next = NULL;
-	enable_irq(irq);
-	
-	p = &irq_desc[irq].action;
-	
-	if ((old = *p) != NULL) {
-		/* Can't share interrupts unless both agree to */
-		if (!(old->flags & action->flags & SA_SHIRQ))
-			return -EBUSY;
-		/* add new interrupt at end of irq queue */
-		do {
-			p = &old->next;
-			old = *p;
-		} while (old);
-	}
-	*p = action;
-
-	restore_flags(flags);	
-	return 0;
-}
-		
-void free_irq(unsigned int irq, void *dev_id)
-{
-	request_irq(irq, NULL, 0, NULL, dev_id);
-}
-
-
-unsigned long probe_irq_on (void)
-{
-	return 0;
-}
-
-int probe_irq_off (unsigned long irqs)
-{
-	return 0;
-}
-
-int (*irq_cannonicalize)(int irq);
-
-int orion_irq_cannonicalize(int i)
-{
-	return i;
-}
-
-void __init init_IRQ(void)
-{
-	
-	irq_cannonicalize = orion_irq_cannonicalize;
-	set_except_vector(0, orionIRQ);
-}
-
-EXPORT_SYMBOL(irq_cannonicalize);
-
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/ld.script.orion linux/arch/mips/orion/ld.script.orion
--- v2.4.3/linux/arch/mips/orion/ld.script.orion	Tue Jul 11 11:14:48 2000
+++ linux/arch/mips/orion/ld.script.orion	Wed Dec 31 16:00:00 1969
@@ -1,113 +0,0 @@
-OUTPUT_FORMAT("elf32-bigmips")
-OUTPUT_ARCH(mips)
-ENTRY(kernel_entry)
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = 0x80100000;
-  /* app_header is needed for the Orion bootloader -- Cort */
-  .app_header	:	{ *(.app_header) }
-  .init          : { *(.init)		} =0
-  .text      :
-  {
-    _ftext = . ;
-    *(.text)
-    *(.rodata)
-    *(.rodata1)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  } =0
-  _etext = .;
-  PROVIDE (etext = .);
-
-  . = ALIGN(8192);
-  .data.init_task : { *(.data.init_task) }
-
-  /* Startup code */
-  . = ALIGN(4096);
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
-  __initcall_end = .;
-  . = ALIGN(4096);	/* Align double page for init_task_union */
-  __init_end = .;
-
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
-  . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  .fini      : { *(.fini)    } =0
-  .reginfo : { *(.reginfo) }
-  /* Adjust the address for the data segment.  We want to adjust up to
-     the same address within the page on the next page up.  It would
-     be more correct to do this:
-       . = .;
-     The current expression does not correctly handle the case of a
-     text segment ending precisely at the end of a page; it causes the
-     data segment to skip a page.  The above expression does not have
-     this problem, but it will currently (2/95) cause BFD to allocate
-     a single segment, combining both text and data, for this case.
-     This will prevent the text segment from being shared among
-     multiple executions of the program; I think that is more
-     important than losing a page of the virtual address space (note
-     that no actual memory is lost; the page which is skipped can not
-     be referenced).  */
-  . = .;
-  .data    :
-  {
-    _fdata = . ;
-    *(.data)
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  _gp = . + 0x8000;
-  .lit8 : { *(.lit8) }
-  .lit4 : { *(.lit4) }
-  .ctors         : { *(.ctors)   }
-  .dtors         : { *(.dtors)   }
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  _edata  =  .;
-  PROVIDE (edata = .);
-
-  __bss_start = .;
-  _fbss = .;
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  _end = . ;
-  PROVIDE (end = .);
-  }
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* DWARF debug sections.
-     Symbols in the .debug DWARF section are relative to the beginning of the
-     section so we begin .debug at 0.  It's not clear yet what needs to happen
-     for the others.   */
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
-  /* These must appear regardless of  .  */
-  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
-  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/misc.c linux/arch/mips/orion/misc.c
--- v2.4.3/linux/arch/mips/orion/misc.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips/orion/misc.c	Wed Dec 31 16:00:00 1969
@@ -1,100 +0,0 @@
-/*
- * Catch-all for Orion-specify code that doesn't fit easily elsewhere.
- *   -- Cort
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#ifdef CONFIG_BLK_DEV_RAM
-#include <linux/blk.h>
-#endif
-#include <linux/ide.h>
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
-
-#include <asm/asm.h>
-#include <asm/bootinfo.h>
-#include <asm/cachectl.h>
-#include <asm/io.h>
-#include <asm/stackframe.h>
-#include <asm/system.h>
-#include <asm/cpu.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/mc146818rtc.h>
-
-char arcs_cmdline[CL_SIZE] = {0, };
-extern int _end;
-
-static unsigned char orion_rtc_read_data(unsigned long addr)
-{
-	return 0;
-}
-
-static void orion_rtc_write_data(unsigned char data, unsigned long addr)
-{
-}
-
-static int orion_rtc_bcd_mode(void)
-{
-	return 0;
-}
-
-struct rtc_ops orion_rtc_ops = {
-	&orion_rtc_read_data,
-	&orion_rtc_write_data,
-	&orion_rtc_bcd_mode
-};
-
-extern void InitCIB(void);
-extern void InitQpic(void);
-extern void InitCupid(void);
-
-void __init orion_setup(void)
-{
-	InitCIB();
-	InitQpic();
-	InitCupid();
-}
-
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
-
-
-int orion_sysinit(void)
-{
-	unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size;
-	
-	mips_machgroup = MACH_GROUP_ORION;
-	/* 64 MB non-upgradable */
-	mem_size = 32 << 20;
-	
-	free_start = PHYSADDR(PFN_ALIGN(&_end));
-	free_end = mem_size;
-	start_pfn = PFN_UP((unsigned long)&_end);
-	
-	/* Register all the contiguous memory with the bootmem allocator
-	   and free it.  Be careful about the bootmem freemap.  */
-	bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT);
-	
-	/* Free the entire available memory after the _end symbol.  */
-	free_start += bootmap_size;
-	free_bootmem(free_start, free_end-free_start);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/no_initrd.c linux/arch/mips/orion/no_initrd.c
--- v2.4.3/linux/arch/mips/orion/no_initrd.c	Tue Jul 11 11:14:48 2000
+++ linux/arch/mips/orion/no_initrd.c	Wed Dec 31 16:00:00 1969
@@ -1,2 +0,0 @@
-unsigned long *orion_initrd_start = 0;
-unsigned long orion_initrd_size = 0;
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/piggyback.c linux/arch/mips/orion/piggyback.c
--- v2.4.3/linux/arch/mips/orion/piggyback.c	Tue Jul 11 11:14:48 2000
+++ linux/arch/mips/orion/piggyback.c	Wed Dec 31 16:00:00 1969
@@ -1,59 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-
-extern long ce_exec_config[];
-
-int main(int argc, char *argv[])
-{
-	int i, cnt, pos, len;
-	unsigned int cksum, val;
-	unsigned char *lp;
-	unsigned char buf[8192];
-	if (argc != 2)
-	{
-		fprintf(stderr, "usage: %s name <in-file >out-file\n",
-			argv[0]);
-		exit(1);
-	}
-	fprintf(stdout, "/*\n");
-	fprintf(stdout, "* Miscellaneous data structures:\n");
-	fprintf(stdout, "* WARNING - this file is automatically generated!\n");
-	fprintf(stdout, "*/\n");
-	fprintf(stdout, "\n");
-	fprintf(stdout, "unsigned long orion_%s_start[] = {\n", argv[1]);
-	pos = 0;
-	cksum = 0;
-	while ((len = read(0, buf, sizeof(buf))) > 0)
-	{
-		cnt = 0;
-		lp = (unsigned char *)buf;
-		len = (len + 3) & ~3;  /* Round up to longwords */
-		for (i = 0;  i < len;  i += 4)
-		{
-			if (cnt == 0)
-			{
-				fprintf(stdout, "\t");
-			}
-			fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
-			val = *(unsigned long *)lp;
-			cksum ^= val;
-			lp += 4;
-			if (++cnt == 4)
-			{
-				cnt = 0;
-				fprintf(stdout, ", /* %x */\n", pos+i-12);
-				fflush(stdout);
-			} else
-			{
-				fprintf(stdout, ",");
-			}
-		}
-		pos += len;
-	}
-	fprintf(stdout, "0 };\n");
-	fprintf(stdout, "unsigned long orion_%s_size = 0x%x;\n", argv[1], pos);
-	fflush(stdout);
-	fclose(stdout);
-	fprintf(stderr, "cksum = %x\n", cksum);
-	exit(0);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/promcon.c linux/arch/mips/orion/promcon.c
--- v2.4.3/linux/arch/mips/orion/promcon.c	Thu Oct 12 14:20:48 2000
+++ linux/arch/mips/orion/promcon.c	Wed Dec 31 16:00:00 1969
@@ -1,168 +0,0 @@
-/*
- * Wrap-around code for a console using the
- * SGI PROM io-routines.
- *
- * Copyright (c) 1999 Ulf Carlsson
- *
- * Derived from DECstation promcon.c
- * Copyright (c) 1998 Harald Koerfgen 
- */
-
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/fs.h>
-/*
-#include <asm/sgialib.h>
-*/
-extern void prom_printf(char *fmt, ...);
-unsigned long splx(unsigned long mask){return 0;}
-#if 0
-unsigned long ramsize=0x100000;
-unsigned long RamSize(){return ramsize;}
-extern void prom_printf(char *fmt, ...);
-unsigned long splx(unsigned long mask){return 0;}
-long PssSetIntHandler(unsigned long intnum, void *handler){}
-long PssEnableInt(unsigned long intnum){}
-long PssDisableInt(unsigned long intnum){}
-unsigned long t_ident(char name[4], unsigned long node, unsigned long *tid){}
-#endif
-
-extern void  SerialPollConout(unsigned char c);
-static void prom_console_write(struct console *co, const char *s,
-			       unsigned count)
-{
-    unsigned i;
-
-    /*
-     *    Now, do each character
-     */
-    for (i = 0; i < count; i++) {
-	if (*s == 10)
-	  SerialPollConout(13);
-	SerialPollConout(*s++);
-    }
-}
-extern int prom_getchar(void);
-static int prom_console_wait_key(struct console *co)
-{
-    return prom_getchar();
-}
-
-extern void SerialPollInit(void);
-extern void  SerialSetup(unsigned long  baud, unsigned long  console, unsigned long  host, unsigned long  intr_desc);
-static int __init prom_console_setup(struct console *co, char *options)
-{
-  SerialSetup(19200,1,1,3);
-  SerialPollInit();
-  SerialPollOn();
-  return 0;
-}
-
-static kdev_t prom_console_device(struct console *c)
-{
-    return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static struct console sercons =
-{
-    name:	"ttyS",
-    write:	prom_console_write,
-    device:	prom_console_device,
-    wait_key:	prom_console_wait_key,
-    setup:	prom_console_setup,
-    flags:	CON_PRINTBUFFER,
-    index:	-1,
-};
-
-/*
- *    Register console.
- */
-
-void serial_console_init(void)
-{
-	register_console(&sercons);
-}
-
-extern void prom_putchar(int mychar);
-
-static char ppbuf[1000];
-
-
-void prom_printf(char *fmt, ...)
-{
-	va_list args;
-	char ch, *bptr;
-	int i;
-
-	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
-	va_end(args);
-	return;
-}
-
-
-
-void prom_putchar(int mychar){}
-int prom_getchar(void){return 0;}
-struct app_header_s {
-  unsigned long    MAGIC_JMP;
-  unsigned long    MAGIC_NOP;
-  unsigned long    header_tag;    
-  unsigned long    header_flags;
-  unsigned long    header_length;
-  unsigned long    header_cksum;
-     
-  void             *load_addr;
-  void             *end_addr;
-  void             *start_addr;
-  char             *app_name_p;
-  char             *version_p;
-  char             *date_p;
-  char             *time_p;
-  unsigned long    type;
-  unsigned long    crc;
-  unsigned long    reserved;
-};
-typedef struct app_header_s app_header_t;
-char linked_app_name[]="linux";
-char *linked_app_name_p=&linked_app_name[0];
-
-char linked_app_ver[]="2.4 -test1";
-char *linked_app_ver_p=&linked_app_ver[0];
-
-char linked_app_date[]="today";
-char *linked_app_date_p=&linked_app_date[0];
-
-char linked_app_time[]="now";
-char *linked_app_time_p=&linked_app_time[0];
-extern void *__bss_start;
-extern void *kernel_entry;
-
-app_header_t app_header __attribute__ ((section (".app_header"))) = {
-  (0x10000000 | (((sizeof(app_header_t)>>2)-1) & 0xffff)) ,
-  0 ,
-  (((( 0x4321  ) & 0xFFFF) << 16) | ((  0x0100  ) & 0xFFFF))  ,
-  0x80000000 ,
-  sizeof(app_header_t),
-  0,
-  &app_header,
-  &__bss_start,
-  &kernel_entry,
-  linked_app_name,
-  linked_app_ver,
-  linked_app_date,
-  linked_app_time,
-  0
-};
diff -u --recursive --new-file v2.4.3/linux/arch/mips/orion/setup.c linux/arch/mips/orion/setup.c
--- v2.4.3/linux/arch/mips/orion/setup.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips/orion/setup.c	Wed Dec 31 16:00:00 1969
@@ -1,125 +0,0 @@
-/*
- * Catch-all for Orion-specific code that doesn't fit easily elsewhere.
- *   -- Cort
- */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#ifdef CONFIG_BLK_DEV_RAM
-#include <linux/blk.h>
-#endif
-#include <linux/ide.h>
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
-
-#include <asm/asm.h>
-#include <asm/bootinfo.h>
-#include <asm/cachectl.h>
-#include <asm/io.h>
-#include <asm/stackframe.h>
-#include <asm/system.h>
-#include <asm/cpu.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/mc146818rtc.h>
-#include <asm/orion.h>
-
-char arcs_cmdline[CL_SIZE] = { "console=ttyS0,19200" };
-extern int _end;
-
-static unsigned char orion_rtc_read_data(unsigned long addr)
-{
-	return 0;
-}
-
-static void orion_rtc_write_data(unsigned char data, unsigned long addr)
-{
-}
-
-static int orion_rtc_bcd_mode(void)
-{
-	return 0;
-}
-
-struct rtc_ops orion_rtc_ops = {
-	&orion_rtc_read_data,
-	&orion_rtc_write_data,
-	&orion_rtc_bcd_mode
-};
-
-extern void InitCIB(void);
-extern void InitQpic(void);
-extern void InitCupid(void);
-
-void __init orion_setup(void)
-{
-	extern void (*board_time_init)(struct irqaction *irq);
-	void orion_time_init(struct irqaction *);
-	
-	rtc_ops = &orion_rtc_ops;
-	board_time_init = orion_time_init;
-	mips_io_port_base = GT64120_BASE;
-
-	InitCIB();
-	InitQpic();
-	InitCupid();
-}
-
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
-unsigned long mem_size;
-int __init prom_init(int a, char **b, char **c, int *d)
-{
-	unsigned long free_start, free_end, start_pfn, bootmap_size;
-	extern unsigned long orion_initrd_start[], orion_initrd_size;
-
-	mips_machgroup = MACH_GROUP_ORION;
-	/* 64 MB non-upgradable */
-	mem_size = 64 << 20;
-	
-	free_start = PHYSADDR(PFN_ALIGN(&_end));
-	free_end = mem_size;
-	start_pfn = PFN_UP((unsigned long)&_end);
-	
-	/* Register all the contiguous memory with the bootmem allocator
-	   and free it.  Be careful about the bootmem freemap.  */
-	bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT);
-	
-	/* Free the entire available memory after the _end symbol.  */
-	free_start += bootmap_size;
-	free_bootmem(free_start, free_end-free_start);
-
-	initrd_start = (ulong)orion_initrd_start;
-	initrd_end = (ulong)orion_initrd_start + (ulong)orion_initrd_size;
-	initrd_below_start_ok = 1;
-
-	return 0;
-}
-
-void prom_free_prom_memory (void)
-{
-}
-
-int page_is_ram(unsigned long pagenr)
-{
-	if ( pagenr < (mem_size >> PAGE_SHIFT) )
-		return 1;
-	return 0;
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips/sgi/kernel/Makefile linux/arch/mips/sgi/kernel/Makefile
--- v2.4.3/linux/arch/mips/sgi/kernel/Makefile	Sun Jul  9 22:18:15 2000
+++ linux/arch/mips/sgi/kernel/Makefile	Fri Apr 13 20:26:07 2001
@@ -13,21 +13,13 @@
 .S.o:
 	$(CC) $(CFLAGS) -c $< -o $*.o
 
-OBJS  = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \
-        system.o indyIRQ.o reset.o setup.o time.o
-ifdef CONFIG_SGI_PROM_CONSOLE
-OBJS += promcon.o
-endif
+O_TARGET := ip22-kern.o
 
-all: sgikern.a
+all: ip22-kern.o indyIRQ.o
 
-sgikern.a: $(OBJS)
-	$(AR) rcs sgikern.a $(OBJS)
-	sync
+obj-y	+= indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \
+	   indyIRQ.o reset.o setup.o time.o
 
 indyIRQ.o: indyIRQ.S
-
-dep:
-	$(CPP) $(CPPFLAGS) -M *.c > .depend
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips/sni/Makefile linux/arch/mips/sni/Makefile
--- v2.4.3/linux/arch/mips/sni/Makefile	Sat May 13 08:29:14 2000
+++ linux/arch/mips/sni/Makefile	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $
 #
 # Makefile for the SNI specific part of the kernel
 #
@@ -12,12 +11,12 @@
 .S.o:
 	$(CC) $(CFLAGS) -c $< -o $*.o
 
-all: sni.o
+all:	sni.o int-handler.o
+
 O_TARGET := sni.o
-O_OBJS	 := dma.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o
 
-int-handler.o: int-handler.S
+obj-y	 := int-handler.o io.o irq.o pci.o pcimt_scache.o reset.o setup.o
 
-clean:
+int-handler.o: int-handler.S
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/config.in linux/arch/mips64/config.in
--- v2.4.3/linux/arch/mips64/config.in	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/config.in	Tue Apr 17 17:19:25 2001
@@ -25,6 +25,9 @@
 fi
 endmenu
 
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
 #
 # Select some configuration options automatically based on user selections
 #
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/defconfig linux/arch/mips64/defconfig
--- v2.4.3/linux/arch/mips64/defconfig	Sun Mar  4 14:30:18 2001
+++ linux/arch/mips64/defconfig	Fri Apr 13 20:26:07 2001
@@ -120,6 +120,11 @@
 # CONFIG_BRIDGE is not set
 
 #
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
 # Telephony Support
 #
 # CONFIG_PHONE is not set
@@ -422,6 +427,7 @@
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22
--- v2.4.3/linux/arch/mips64/defconfig-ip22	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/defconfig-ip22	Fri Apr 13 20:26:07 2001
@@ -110,6 +110,11 @@
 # CONFIG_BRIDGE is not set
 
 #
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
 # Telephony Support
 #
 # CONFIG_PHONE is not set
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/defconfig-ip27 linux/arch/mips64/defconfig-ip27
--- v2.4.3/linux/arch/mips64/defconfig-ip27	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/defconfig-ip27	Fri Apr 13 20:26:07 2001
@@ -120,6 +120,11 @@
 # CONFIG_BRIDGE is not set
 
 #
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
 # Telephony Support
 #
 # CONFIG_PHONE is not set
@@ -165,6 +170,7 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -421,6 +427,7 @@
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/kernel/semaphore.c linux/arch/mips64/kernel/semaphore.c
--- v2.4.3/linux/arch/mips64/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/mips64/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -127,112 +127,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-/*
- * RW Semaphores
- */
-void
-__down_read(struct rw_semaphore *sem, int count)
-{
-	DOWN_VAR;
-
- retry_down:
-	if (count < 0) {
-		/* Wait for the lock to become unbiased.  Readers
-		   are non-exclusive.  */
-		
-		/* This takes care of granting the lock.  */
-		up_read(sem);
-
-		add_wait_queue(&sem->wait, &wait);
-		while (atomic_read(&sem->count) < 0) {
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&sem->count) >= 0)
-				break;
-			schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_dec_return(&sem->count);
-		if (count <= 0)
-			goto retry_down;
-	} else {
-		add_wait_queue(&sem->wait, &wait);
-
-		while (1) {
-			if (test_and_clear_bit(0, &sem->granted))
-				break;
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if ((sem->granted & 1) == 0)
-				schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-	}
-}
-
-void
-__down_write(struct rw_semaphore *sem, int count)
-{
-	DOWN_VAR;
-
- retry_down:
-	if (count + RW_LOCK_BIAS < 0) {
-		up_write(sem);
-
-		add_wait_queue_exclusive(&sem->wait, &wait);
-	
-		while (atomic_read(&sem->count) < 0) {
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
-				break;
-			schedule();
-		}
-
-		remove_wait_queue(&sem->wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		mb();
-		count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-		if (count != 0)
-			goto retry_down;
-	} else {
-		/* Put ourselves at the end of the list.  */
-		add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
-		while (1) {
-			if (test_and_clear_bit(1, &sem->granted))
-				break;
-			set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-			if ((sem->granted & 2) == 0)
-				schedule();
-		}
-
-		remove_wait_queue(&sem->write_bias_wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		/* If the lock is currently unbiased, awaken the sleepers.
-		   FIXME: This wakes up the readers early in a bit of a
-		   stampede -> bad!  */
-		if (atomic_read(&sem->count) >= 0)
-			wake_up(&sem->wait);
-	}
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
-	if (readers) {
-		if (test_and_set_bit(0, &sem->granted))
-			BUG();
-		wake_up(&sem->wait);
-	} else {
-		if (test_and_set_bit(1, &sem->granted))
-			BUG();
-		wake_up(&sem->write_bias_wait);
-	}
-}
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/mm/Makefile linux/arch/mips64/mm/Makefile
--- v2.4.3/linux/arch/mips64/mm/Makefile	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/mm/Makefile	Fri Apr 13 20:26:07 2001
@@ -4,7 +4,8 @@
 
 O_TARGET := mm.o
 
-obj-y	 := extable.o init.o fault.o loadmmu.o
+export-objs			+= umap.o
+obj-y				:= extable.o init.o fault.o loadmmu.o
 
 obj-$(CONFIG_CPU_R4300)		+= r4xx0.o
 obj-$(CONFIG_CPU_R4X00)		+= r4xx0.o
diff -u --recursive --new-file v2.4.3/linux/arch/mips64/tools/Makefile linux/arch/mips64/tools/Makefile
--- v2.4.3/linux/arch/mips64/tools/Makefile	Sun Jul  9 22:18:16 2000
+++ linux/arch/mips64/tools/Makefile	Fri Apr 13 20:26:07 2001
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.1 1999/08/18 21:46:53 ralf Exp $
 #
 # Makefile for MIPS kernel build tools.
 #
diff -u --recursive --new-file v2.4.3/linux/arch/parisc/config.in linux/arch/parisc/config.in
--- v2.4.3/linux/arch/parisc/config.in	Tue Dec  5 12:29:39 2000
+++ linux/arch/parisc/config.in	Tue Apr 17 17:19:25 2001
@@ -7,6 +7,8 @@
 
 define_bool CONFIG_PARISC y
 define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
diff -u --recursive --new-file v2.4.3/linux/arch/parisc/kernel/semaphore.c linux/arch/parisc/kernel/semaphore.c
--- v2.4.3/linux/arch/parisc/kernel/semaphore.c	Tue Dec  5 12:29:39 2000
+++ linux/arch/parisc/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -129,111 +129,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	__up_read(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-                if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to aquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	current->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-}
-
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-}
-
-void rwsem_wake_writer(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.4.3/linux/arch/ppc/config.in	Sat Mar  3 10:52:13 2001
+++ linux/arch/ppc/config.in	Tue Apr 17 17:19:25 2001
@@ -3,6 +3,8 @@
 # see Documentation/kbuild/config-language.txt.
 #
 define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
diff -u --recursive --new-file v2.4.3/linux/arch/ppc/kernel/semaphore.c linux/arch/ppc/kernel/semaphore.c
--- v2.4.3/linux/arch/ppc/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/ppc/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -137,44 +137,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-
-/*
- * rw semaphores    Ani Joshi <ajoshi@unixbox.com>
- * based on alpha port by Andrea Arcangeli <andrea@suse.de>
- */
-
-void down_read_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	do {
-		__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		spin_unlock_irq(&sem->lock);
-		schedule();
-		spin_lock_irq(&sem->lock);
-	} while(sem->wr);
-
-	remove_wait_queue(&sem->wait, &wait);
-}
-
-void down_write_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	do {
-		__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		spin_unlock_irq(&sem->lock);
-		schedule();
-		spin_lock_irq(&sem->lock);
-	} while(sem->rd || sem->wr);
-
-	remove_wait_queue(&sem->wait, &wait);
-}
-
diff -u --recursive --new-file v2.4.3/linux/arch/s390/Makefile linux/arch/s390/Makefile
--- v2.4.3/linux/arch/s390/Makefile	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/Makefile	Wed Apr 11 19:02:27 2001
@@ -26,10 +26,14 @@
 HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
 SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
-           drivers/s390
+           drivers/s390 arch/s390/math-emu
 CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \
            drivers/s390/io.o
 LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
+
+ifeq ($(CONFIG_MATHEMU),y)
+  CORE_FILES := $(CORE_FILES) arch/s390/math-emu/math-emu.o
+endif
 
 all: image listing
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile
--- v2.4.3/linux/arch/s390/boot/Makefile	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/boot/Makefile	Wed Apr 11 19:02:27 2001
@@ -25,7 +25,7 @@
 image: $(CONFIGURE) $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot ipldump.boot
 	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
-	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
+	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
 
 listing: ../../../vmlinux
 	$(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing
diff -u --recursive --new-file v2.4.3/linux/arch/s390/config.in linux/arch/s390/config.in
--- v2.4.3/linux/arch/s390/config.in	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/config.in	Tue Apr 17 17:19:25 2001
@@ -7,6 +7,8 @@
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_name "Linux Kernel Configuration"
 define_bool CONFIG_ARCH_S390 y
@@ -28,7 +30,7 @@
 mainmenu_option next_comment
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
-bool 'IEEE FPU emulation' CONFIG_IEEEFPU_EMULATION
+bool 'IEEE FPU emulation' CONFIG_MATHEMU
 endmenu
 
 mainmenu_option next_comment
@@ -44,7 +46,7 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
-define CONFIG_KCORE ELF
+define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
@@ -65,6 +67,6 @@
 if [ "$CONFIG_CTC" = "y" ]; then
   bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 fi
-# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/defconfig linux/arch/s390/defconfig
--- v2.4.3/linux/arch/s390/defconfig	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/defconfig	Wed Apr 11 19:02:27 2001
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
@@ -13,12 +13,6 @@
 CONFIG_EXPERIMENTAL=y
 
 #
-# Processor type and features
-#
-CONFIG_SMP=y
-CONFIG_IEEEFPU_EMULATION=y
-
-#
 # Loadable module support
 #
 CONFIG_MODULES=y
@@ -26,6 +20,12 @@
 CONFIG_KMOD=y
 
 #
+# Processor type and features
+#
+CONFIG_SMP=y
+CONFIG_MATHEMU=y
+
+#
 # General setup
 #
 CONFIG_FAST_IRQ=y
@@ -36,6 +36,7 @@
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PROCESS_DEBUG is not set
@@ -49,9 +50,14 @@
 CONFIG_BLK_DEV_RAM_SIZE=24576
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XPRAM=m
+
+#
+# S/390 block device drivers
+#
 CONFIG_DASD=y
 CONFIG_DASD_ECKD=y
 CONFIG_DASD_FBA=y
+# CONFIG_DASD_DIAG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -63,20 +69,31 @@
 CONFIG_MD_RAID1=m
 CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_LVM=m
-CONFIG_LVM_PROC_FS=y
 
 #
 # Character device drivers
 #
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# S/390 character device drivers
+#
 CONFIG_3215=y
 CONFIG_3215_CONSOLE=y
 CONFIG_HWC=y
 CONFIG_HWC_CONSOLE=y
 CONFIG_S390_TAPE=m
+
+#
+# S/390 tape interface support
+#
 CONFIG_S390_TAPE_CHAR=y
 CONFIG_S390_TAPE_BLOCK=y
+
+#
+# S/390 tape hardware support
+#
 CONFIG_S390_TAPE_3490=y
 CONFIG_S390_TAPE_3480=y
 
@@ -88,6 +105,10 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_TR=y
 # CONFIG_FDDI is not set
+
+#
+# S/390 network device drivers
+#
 # CONFIG_CHANDEV is not set
 CONFIG_CTC=m
 CONFIG_IUCV=m
@@ -109,11 +130,16 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
@@ -138,6 +164,8 @@
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -192,8 +220,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -211,8 +237,10 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_MAGIC_SYSRQ is not set
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/Makefile linux/arch/s390/kernel/Makefile
--- v2.4.3/linux/arch/s390/kernel/Makefile	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/Makefile	Wed Apr 11 19:02:27 2001
@@ -14,14 +14,13 @@
 
 O_TARGET := kernel.o
 
-export-objs	:= s390_ksyms.o
+export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
 obj-y	:= 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 \
             semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
 
 obj-$(CONFIG_MODULES)		+= s390_ksyms.o
 obj-$(CONFIG_SMP)		+= smp.o
-obj-$(CONFIG_IEEEFPU_EMULATION)	+= mathemu.o floatlib.o
 
 #
 # Kernel debugging
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c
--- v2.4.3/linux/arch/s390/kernel/cpcmd.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/cpcmd.c	Wed Apr 11 19:02:27 2001
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <asm/ebcdic.h>
+#include <asm/cpcmd.h>
 
 void cpcmd(char *cmd, char *response, int rlen)
 {
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/cpcmd.h linux/arch/s390/kernel/cpcmd.h
--- v2.4.3/linux/arch/s390/kernel/cpcmd.h	Fri May 12 11:41:44 2000
+++ linux/arch/s390/kernel/cpcmd.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- *  arch/s390/kernel/cpcmd.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-
-#ifndef __CPCMD__
-#define __CPCMD__
-
-extern void cpcmd(char *cmd, char *response, int rlen);
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c
--- v2.4.3/linux/arch/s390/kernel/debug.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/debug.c	Wed Apr 11 19:02:27 2001
@@ -15,45 +15,53 @@
 #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/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_S390X)
-#define DEBUG_PROC_HEADER_SIZE 46
-#else
-#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,
@@ -83,6 +91,9 @@
 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_raw_view = {
@@ -90,6 +101,7 @@
 	NULL,
 	&debug_raw_header_fn,
 	&debug_raw_format_fn,
+	NULL,
 	NULL
 };
 
@@ -98,6 +110,7 @@
 	NULL,
 	&debug_dflt_header_fn,
 	&debug_hex_ascii_format_fn,
+	NULL,
 	NULL
 };
 
@@ -106,9 +119,22 @@
 	&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_area_first = NULL;
@@ -137,64 +163,108 @@
 
 static struct proc_dir_entry *debug_proc_root_entry;
 
-
 /* functions */
 
 /*
- * debug_info_create
- * - create new debug-info
+ * debug_info_alloc
+ * - alloc new debug-info
  */
 
-static debug_info_t*  debug_info_create(char *name, int page_order, 
+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 */
+	/* alloc everything */
 
-        rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
-        if(!rc) 
+	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);
-                }
-        }
+	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 */
 
-        /* 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 */
 
-        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);
         rc->proc_root_entry =
             debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
                                         S_IFDIR | S_IRUGO | S_IXUGO |
@@ -216,16 +286,29 @@
         rc->next = NULL;
 
 	debug_info_get(rc);
+out:
 	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_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;
 }
 
 /*
@@ -261,49 +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);
-		kfree(db_info->active_entry);
 		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;
-		kfree(db_info);
+		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;
 }
 
 /*
@@ -322,68 +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,
-						         DEBUG_DATA(act_entry));
-			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
@@ -392,17 +494,14 @@
 
 static int debug_open(struct inode *inode, struct file *file)
 {
-	int i = 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_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 */
@@ -422,87 +521,41 @@
 	/* 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");
+
+	/* make snapshot of current debug areas to get it consistent */
+
+	debug_info_snapshot = debug_info_copy(debug_info);
+
+	if(!debug_info_snapshot){
+		printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\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_info->views[i]->prolog_proc)
-		size +=
-		    debug_info->views[i]->prolog_proc(debug_info,
-							 debug_info->
-							 views[i], NULL);
-
-	if (debug_info->views[i]->header_proc)
-		f_entry_size =
-		    debug_info->views[i]->header_proc(debug_info,
-							 debug_info->
-							 views[i], 0, NULL,
-							 NULL);
-	if (debug_info->views[i]->format_proc)
-		f_entry_size +=
-		    debug_info->views[i]->format_proc(debug_info,
-							 debug_info->
-							 views[i], NULL,
-							 NULL);
-
-	size += f_entry_size 
-		* (PAGE_SIZE / debug_info->entry_size
-		<< debug_info->page_order)
-		* debug_info->nr_areas + 1;	/* terminating \0 */
-#ifdef DEBUG
-	printk("debug_open: size: %i\n", size);
-#endif
 
-	/* 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 ((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;
 	}
-
-	p_info->size = size;
-	p_info->debug_info = debug_info;
+	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_lock_irq(&debug_info->lock);
-
-	p_info->len =
-	    debug_format_output(debug_info, p_info->data, size,
-				debug_info->views[i]);
-#ifdef DEBUG
-	{
-		int ilen = p_info->len;
-		printk("debug_open: len: %i\n", ilen);
-	}
-#endif
-
-	spin_unlock_irq(&debug_info->lock);
 	debug_info_get(debug_info);
 
       out:
 	up(&debug_lock);
-#ifdef MODULE
 	if (rc != 0)
 		MOD_DEC_USE_COUNT;
-#endif
 	return rc;
 }
 
@@ -518,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 */
 }
 
@@ -607,9 +653,7 @@
 {
 	debug_info_t *rc = NULL;
 
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 	if (!initialized)
 		debug_init();
 	down(&debug_lock);
@@ -626,9 +670,7 @@
       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;
@@ -648,9 +690,7 @@
 	debug_info_put(id);
 	up(&debug_lock);
 
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif
       out:
 	return;
 }
@@ -662,7 +702,7 @@
 
 void debug_set_level(debug_info_t* id, int new_level)
 {
-	long flags;
+	unsigned long flags;
 	if(!id)
 		return;	
 	spin_lock_irqsave(&id->lock,flags);
@@ -687,7 +727,7 @@
  * - 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))
@@ -699,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;
@@ -709,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]);
@@ -720,160 +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;
+	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(DEBUG_DATA(active), 0, id->buf_size);
-	memcpy(DEBUG_DATA(active), &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(DEBUG_DATA(active), 0, id->buf_size);
-	strncpy(DEBUG_DATA(active), txt, 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(DEBUG_DATA(active), 0, id->buf_size);
-	memcpy(DEBUG_DATA(active), 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(DEBUG_DATA(active), 0, id->buf_size);
-	memcpy(DEBUG_DATA(active), &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(DEBUG_DATA(active), 0, id->buf_size);
-	strncpy(DEBUG_DATA(active), txt, 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;
+	}
 }
 
 /*
@@ -908,7 +914,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 	mode_t mode = S_IFREG;
 
 	if (!id)
@@ -951,7 +957,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 
 	if (!id)
 		goto out;
@@ -987,13 +993,8 @@
 {
 	int rc = 0;
 
-	if (out_buf == NULL) {
-		rc = 2;
-		goto out;
-	}
 	if(id->level == -1) rc = sprintf(out_buf,"-\n");
 	else rc = sprintf(out_buf, "%i\n", id->level);
-      out:
 	return rc;
 }
 
@@ -1010,8 +1011,10 @@
 
 	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');
 		debug_set_level(id, new_level);
@@ -1036,10 +1039,7 @@
         int rc;
 
 	rc = sizeof(debug_entry_t);
-        if (out_buf == NULL)
-                goto out;
 	memcpy(out_buf,entry,sizeof(debug_entry_t));
-      out:
         return rc;
 }
 
@@ -1053,10 +1053,7 @@
 	int rc;
 
 	rc = id->buf_size;
-	if (out_buf == NULL || in_buf == NULL)
-		goto out;
 	memcpy(out_buf, in_buf, id->buf_size);
-      out:
 	return rc;
 }
 
@@ -1069,10 +1066,6 @@
 {
 	int i, rc = 0;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size * 4 + 3;
-		goto out;
-	}
 	for (i = 0; i < id->buf_size; i++) {
                 rc += sprintf(out_buf + rc, "%02x ",
                               ((unsigned char *) in_buf)[i]);
@@ -1086,7 +1079,6 @@
 			rc += sprintf(out_buf + rc, "%c", c);
 	}
 	rc += sprintf(out_buf + rc, "\n");
-      out:
 	return rc;
 }
 
@@ -1102,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);
@@ -1119,18 +1108,60 @@
 		except_str = "-";
 	caller = (unsigned long) entry->caller;
 #if defined(CONFIG_ARCH_S390X)
-	rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx  ",
-		      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 %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;
 }
 
@@ -1165,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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/ebcdic.c linux/arch/s390/kernel/ebcdic.c
--- v2.4.3/linux/arch/s390/kernel/ebcdic.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/ebcdic.c	Wed Apr 11 19:02:27 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 --recursive --new-file v2.4.3/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- v2.4.3/linux/arch/s390/kernel/entry.S	Fri Mar  2 11:12:06 2001
+++ linux/arch/s390/kernel/entry.S	Wed Apr 11 19:02:27 2001
@@ -9,56 +9,52 @@
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  */
 
+#define ASSEMBLY
+
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
-#define ASSEMBLY
 #include <asm/smp.h>
-#include <asm/s390-regs-common.h>
-
+#include <asm/ptrace.h>
 
 /*
- * stack layout for the system_call stack entry
- * Martin please don't modify these back to hard coded values 
- * You know how bad I'm at mental arithmetic DJB & it gives 
- * me grief when I modify the pt_regs
+ * Stack layout for the system_call stack entry.
+ * The first few entries are identical to the user_regs_struct.
  */
 SP_PTREGS    =  STACK_FRAME_OVERHEAD 
-SP_PSW       =  SP_PTREGS
-SP_R0        =  (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE)
-SP_R1        =  (SP_R0+GPR_SIZE)
-SP_R2        =  (SP_R1+GPR_SIZE)
-SP_R3        =  (SP_R2+GPR_SIZE)
-SP_R4        =  (SP_R3+GPR_SIZE)
-SP_R5        =  (SP_R4+GPR_SIZE)
-SP_R6        =  (SP_R5+GPR_SIZE)
-SP_R7        =  (SP_R6+GPR_SIZE)
-SP_R8        =  (SP_R7+GPR_SIZE)
-SP_R9        =  (SP_R8+GPR_SIZE)
-SP_RA        =  (SP_R9+GPR_SIZE)
-SP_RB        =  (SP_RA+GPR_SIZE)
-SP_RC        =  (SP_RB+GPR_SIZE)
-SP_RD        =  (SP_RC+GPR_SIZE)
-SP_RE        =  (SP_RD+GPR_SIZE)
-SP_RF        =  (SP_RE+GPR_SIZE)
-SP_AREGS     =  (SP_RF+GPR_SIZE)
-SP_ORIG_R2   =  (SP_AREGS+(NUM_ACRS*ACR_SIZE))
+SP_PSW       =  STACK_FRAME_OVERHEAD + PT_PSWMASK
+SP_R0        =  STACK_FRAME_OVERHEAD + PT_GPR0
+SP_R1        =  STACK_FRAME_OVERHEAD + PT_GPR1
+SP_R2        =  STACK_FRAME_OVERHEAD + PT_GPR2
+SP_R3        =  STACK_FRAME_OVERHEAD + PT_GPR3
+SP_R4        =  STACK_FRAME_OVERHEAD + PT_GPR4
+SP_R5        =  STACK_FRAME_OVERHEAD + PT_GPR5
+SP_R6        =  STACK_FRAME_OVERHEAD + PT_GPR6
+SP_R7        =  STACK_FRAME_OVERHEAD + PT_GPR7
+SP_R8        =  STACK_FRAME_OVERHEAD + PT_GPR8
+SP_R9        =  STACK_FRAME_OVERHEAD + PT_GPR9
+SP_R10       =  STACK_FRAME_OVERHEAD + PT_GPR10
+SP_R11       =  STACK_FRAME_OVERHEAD + PT_GPR11
+SP_R12       =  STACK_FRAME_OVERHEAD + PT_GPR12
+SP_R13       =  STACK_FRAME_OVERHEAD + PT_GPR13
+SP_R14       =  STACK_FRAME_OVERHEAD + PT_GPR14
+SP_R15       =  STACK_FRAME_OVERHEAD + PT_GPR15
+SP_AREGS     =  STACK_FRAME_OVERHEAD + PT_ACR0
+SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
+/* Now the additional entries */
 SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
 #if CONFIG_REMOTE_DEBUG
 SP_CRREGS    =  (SP_TRAP+4)
 /* fpu registers are saved & restored by the gdb stub itself */
 SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
 SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not 
- defined in ptrace.h but space is needed for this too */
 SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
 #else
 SP_PGM_OLD_ILC= (SP_TRAP+4)
 #endif
-SP_SVC_STEP   = (SP_PGM_OLD_ILC+4) 
-SP_SIZE      =  (SP_SVC_STEP+4)
+SP_SIZE      =  (SP_PGM_OLD_ILC+4)
 /*
  * these defines are offsets into the thread_struct
  */
@@ -73,6 +69,8 @@
 _TSS_TRAP    = (_TSS_PROT+4)
 _TSS_MM      = (_TSS_TRAP+4)
 _TSS_PER     = (_TSS_MM+8)
+_TSS_IEEE    = (_TSS_PER+36)
+_TSS_FLAGS   = (_TSS_IEEE+4)
 
 /*
  * these are offsets into the task-struct.
@@ -84,11 +82,6 @@
 tsk_ptrace   = 28
 processor    = 60
 
-/* PSW related defines */
-disable      = 0xFC
-enable       = 0x03
-daton        = 0x04
-
 /*
  * Base Address of this Module --- saved in __LC_ENTRY_BASE
  */
@@ -97,26 +90,6 @@
 
 #define BASED(name) name-entry_base(%r13)
 
-#if 0
-/* some code left lying around in case we need a
- *	printk for debugging purposes
- */
-  sysc_printk:        .long  printk
-  sysc_msg:	      .string "<2>r15 %X\n"
-	.align 4
-		
-#	basr    %r13,0
-	l       %r0,SP_PSW+4(%r15)
-	sll     %r0,1
-	chi     %r0,0
-	jnz     sysc_dn
-	l       %r9,sysc_printk-sysc_lit(%r13)
-	la      %r2,sysc_msg-sysc_lit(%r13)
-	lr      %r3,%r15
-	basr    %r14,%r9
-sysc_dn:
-#endif
-
 /*
  * Register usage in interrupt handlers:
  *    R9  - pointer to current task structure
@@ -125,38 +98,41 @@
  *    R15 - kernel stack pointer
  */
 
-#define SAVE_ALL(psworg) \
-	stm     %r13,%r15,__LC_SAVE_AREA ; \
-        stam    %a2,%a4,__LC_SAVE_AREA+12 ; \
-        basr    %r13,0                ; /* temp base pointer */ \
-        l       %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \
-        tm      psworg+1,0x01         ; /* test problem state bit */ \
-	bz	BASED(.+12)           ; /* skip stack setup save */ \
-	l	%r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \
-        lam     %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \
-                                        /* and access reg. 4 to home space */ \
-0:	s       %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \
-        n       %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \
-        stm     %r0,%r12,SP_R0(%r15)  ; /* store gprs 0-12 to kernel stack */ \
-        st      %r2,SP_ORIG_R2(%r15)  ; /* store original content of gpr 2 */ \
-        mvc     SP_RD(12,%r15),__LC_SAVE_AREA  ; /* move R13-R15 to stack */ \
-        stam    %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \
-        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \
-        mvc     SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \
-        la      %r0,psworg            ; /* store trap indication */ \
-        st      %r0,SP_TRAP(%r15)     ; \
-        xc      0(4,%r15),0(%r15)     ; /* clear back chain */
-
-#define RESTORE_ALL \
-        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,0xfd  ; /* clear wait state bit */ \
-        lpsw    __LC_RETURN_PSW           /* back to caller */
+        .macro  SAVE_ALL psworg           # system entry macro
+        stm     %r13,%r15,__LC_SAVE_AREA
+        stam    %a2,%a4,__LC_SAVE_AREA+12
+        basr    %r13,0                    #  temp base pointer
+        l       %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 
+        tm      \psworg+1,0x01            # test problem state bit
+        bz      BASED(.+12)               # skip stack setup save
+        l       %r15,__LC_KERNEL_STACK    # problem state -> load ksp
+        lam     %a2,%a4,BASED(.Lc_ac)     # set ac.reg. 2 to primary space
+                                          # and access reg. 4 to home space
+0:      s       %r15,BASED(.Lc_spsize)    # make room for registers & psw
+        n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
+        stm     %r0,%r12,SP_R0(%r15)      # store gprs 0-12 to kernel stack
+        st      %r2,SP_ORIG_R2(%r15)      # store original content of gpr 2
+        mvc     SP_R13(12,%r15),__LC_SAVE_AREA  # move R13-R15 to stack
+        stam    %a0,%a15,SP_AREGS(%r15)   # store access registers to kst.
+        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
+        mvc     SP_PSW(8,%r15),\psworg    # move user PSW to stack
+        la      %r0,\psworg               # store trap indication
+        st      %r0,SP_TRAP(%r15)
+        xc      0(4,%r15),0(%r15)         # clear back chain
+        .endm
+
+        .macro  RESTORE_ALL               # system exit macro
+        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,0xfd    # clear wait state bit
+        lpsw    __LC_RETURN_PSW           # back to caller
+        .endm
 
-#define GET_CURRENT /* load pointer to task_struct to R9 */ \
-        lr      %r9,%r15              ; \
+        .macro  GET_CURRENT
+        lr      %r9,%r15                  # load pointer to task_struct to %r9
         n       %r9,BASED(.Lc0xffffe000)
+        .endm
 
 
 /*
@@ -173,7 +149,7 @@
         l       %r4,_TSS_PTREGS(%r3)
         tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
         bz      resume_noper-resume_base(%r1) # if not we're fine
-        stctl   %r9,%r11,24(%r15)             # We are using per stuff
+        stctl   %c9,%c11,24(%r15)             # We are using per stuff
         clc     _TSS_PER(12,%r3),24(%r15)
         be      resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
         lctl    %c9,%c11,_TSS_PER(%r3)        # Nope we didn't
@@ -202,13 +178,13 @@
 
 	.globl  system_call
 system_call:
-        SAVE_ALL(0x20)
-	xc      SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+        SAVE_ALL __LC_SVC_OLD_PSW
+	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
 pgm_system_call:	
+        GET_CURRENT               # load pointer to task_struct to R9
         slr     %r8,%r8           # gpr 8 is call save (-> tracesys)
         ic      %r8,0x8B          # get svc number from lowcore
         stosm   24(%r15),0x03     # reenable interrupts
-        GET_CURRENT               # load pointer to task_struct to R9
         sll     %r8,2
         l       %r8,sys_call_table-entry_base(8,%r13) # get address of system call
         tm      tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
@@ -219,7 +195,6 @@
                                   # changing anything here !!
 
 sysc_return:
-        GET_CURRENT               # load pointer to task_struct to R9
         tm      SP_PSW+1(%r15),0x01 # returning to user ?
         bno     BASED(sysc_leave) # no-> skip bottom half, resched & signal
 #
@@ -237,9 +212,9 @@
         icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
         bnz     BASED(sysc_signal_return)
 sysc_leave:
-	icm     %r0,15,SP_SVC_STEP(%r15)   # get sigpending from task_struct
-        bnz     BASED(pgm_svcret)
-	stnsm   24(%r15),disable  # disable I/O and ext. interrupts
+	tm      SP_PGM_OLD_ILC(%r15),0xff
+        bz      BASED(pgm_svcret)
+	stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
         RESTORE_ALL
 
 #
@@ -371,7 +346,7 @@
         br      %r1                   # branch to sys_rt_sigsuspend
 
 sys_sigaltstack_glue:
-        la      %r2,SP_PTREGS(%r15)   # load pt_regs as parameter
+        la      %r4,SP_PTREGS(%r15)   # load pt_regs as parameter
         l       %r1,BASED(.Lsigaltstack)
         br      %r1                   # branch to sys_sigreturn
 
@@ -647,20 +622,19 @@
         n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
         stm     %r0,%r12,SP_R0(%r15)     # store gprs 0-12 to kernel stack
         st      %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
+        mvc     SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
         stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
 	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
         mvc     SP_PSW(8,%r15),0x20      # move user PSW to stack
         la      %r0,0x20                 # store trap indication
         st      %r0,SP_TRAP(%r15)
         xc      0(4,%r15),0(%r15)        # clear back chain
-        mvi     SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
         mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
         b       BASED(pgm_system_call)   # now do the svc
 pgm_svcret:
         mvi     SP_TRAP+3(%r15),0x28     # set trap indication back to pgm_chk
         lh      %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
-        xc      SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+	mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
 	b       BASED(pgm_no_sv)
 pgm_sv:
         tm      0x29,0x01                # test problem state bit
@@ -672,25 +646,25 @@
         n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
         stm     %r0,%r12,SP_R0(%r15)     # store gprs 0-12 to kernel stack
         st      %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
+        mvc     SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
         stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
 	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
         mvc     SP_PSW(8,%r15),0x28      # move user PSW to stack
         la      %r0,0x28                 # store trap indication
         st      %r0,SP_TRAP(%r15)
         xc      0(4,%r15),0(%r15)        # clear back chain
-        xc      SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
-        lh      %r7,__LC_PGM_ILC  # load instruction length
+	mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
+        lh      %r7,__LC_PGM_ILC         # load instruction length
+	GET_CURRENT
 pgm_no_sv:
         lh      %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
-        stosm   24(%r15),0x03     # reenable interrupts
         lr      %r3,%r8
         la      %r0,0x7f
         nr      %r3,%r0           # clear per-event-bit
         be      BASED(pgm_dn)     # none of Martins exceptions occurred bypass
-        l       %r9,BASED(.Ljump_table)
+        l       %r1,BASED(.Ljump_table)
         sll     %r3,2
-        l       %r9,0(%r3,%r9)    # load address of handler routine
+        l       %r1,0(%r3,%r1)    # load address of handler routine
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         srl     %r3,2
         cl      %r3,BASED(.Lc4)   # protection-exception ?
@@ -698,14 +672,17 @@
         l       %r5,SP_PSW+4(15)  # load psw addr
         sr      %r5,%r7           # substract ilc from psw
         st      %r5,SP_PSW+4(15)  # store corrected psw addr
-pgm_go: basr    %r14,%r9          # branch to interrupt-handler
+pgm_per:cl      %r3,BASED(.Lc20)  # pseudo page fault ?
+        be      BASED(pgm_go)     # if yes then don't reenable interrupts
+        stosm   24(%r15),0x03     # reenable interrupts
+pgm_go: basr    %r14,%r1          # branch to interrupt-handler
 pgm_dn: la      %r0,0x80
         nr      %r8,%r0           # check for per exception
         be      BASED(pgm_return)
         la      %r2,SP_PTREGS(15) # address of register-save area
-        l       %r9,BASED(.Lhandle_per) # load adr. of per handler
+        l       %r1,BASED(.Lhandle_per) # load adr. of per handler
         la      %r14,BASED(sysc_return) # load adr. of system return
-        br      %r9               # branch to handle_per_exception
+        br      %r1               # branch to handle_per_exception
 
 #
 # the backend code is the same as for sys-call
@@ -719,19 +696,19 @@
 
         .globl io_int_handler
 io_int_handler:
-        SAVE_ALL(0x38)
+        SAVE_ALL __LC_IO_OLD_PSW
+        GET_CURRENT               # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         sr      %r3,%r3
         icm     %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
-        l       %r4,__LC_IO_INT_PARM       # load interruption parm
-	l       %r5,__LC_IO_INT_WORD       # load interruption word
-        l       %r9,BASED(.Ldo_IRQ)        # load address of do_IRQ
-        basr    %r14,%r9          # branch to standard irq handler
+        l       %r4,__LC_IO_INT_PARM       # load interuption parm
+	l       %r5,__LC_IO_INT_WORD       # load interuption word
+        l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
+        basr    %r14,%r1          # branch to standard irq handler
 
 io_return:
-        GET_CURRENT               # load pointer to task_struct to R9
         tm      SP_PSW+1(%r15),0x01 # returning to user ?
-        bz      BASED(io_leave)   # no-> skip resched & signal
+        bno     BASED(io_leave)   # no-> skip resched & signal
         stosm   24(%r15),0x03     # reenable interrupts
 #
 # check, if bottom-half has to be done
@@ -748,7 +725,7 @@
         icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
         bnz     BASED(io_signal_return)
 io_leave:
-        stnsm   24(%r15),disable  # disable I/O and ext. interrupts
+        stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
         RESTORE_ALL
 
 #
@@ -784,26 +761,27 @@
 
         .globl  ext_int_handler
 ext_int_handler:
-        SAVE_ALL(0x18)
+        SAVE_ALL __LC_EXT_OLD_PSW
+        GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
         lh      %r3,__LC_EXT_INT_CODE  # error code
         lr      %r1,%r3                # calculate index = code & 0xff
         n       %r1,BASED(.Lc0xff)
         sll     %r1,2
-        l       %r9,BASED(.Lext_hash)
-        l       %r9,0(%r1,%r9)         # get first list entry for hash value
-        ltr     %r9,%r9                # == NULL ?
+        l       %r4,BASED(.Lext_hash)
+        l       %r4,0(%r1,%r4)         # get first list entry for hash value
+        ltr     %r4,%r4                # == NULL ?
         bz      BASED(io_return)       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,8(%r9)             # compare external interrupt code
+        ch      %r3,8(%r4)             # compare external interrupt code
         be      BASED(ext_int_found)
-        icm     %r9,15,0(%r9)          # next list entry
+        icm     %r4,15,0(%r4)          # next list entry
         bnz     BASED(ext_int_loop)
         b       BASED(io_return)
 ext_int_found:
-        l       %r9,4(%r9)             # get handler address
+        l       %r4,4(%r4)             # get handler address
         la      %r14,BASED(io_return)
-        br      %r9                    # branch to ext call handler
+        br      %r4                    # branch to ext call handler
 
 /*
  * Machine check handler routines
@@ -811,7 +789,7 @@
 
         .globl mcck_int_handler
 mcck_int_handler:
-        SAVE_ALL(0x30)
+        SAVE_ALL __LC_MCK_OLD_PSW
 	l       %r1,BASED(.Ls390_mcck)
 	basr    %r14,%r1	  # call machine check handler
 mcck_return:
@@ -826,7 +804,7 @@
         l       %r15,__LC_KERNEL_STACK # load ksp
         lctl    %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
         lam     %a0,%a15,__LC_AREGS_SAVE_AREA
-        stosm   0(%r15),daton          # now we can turn dat on
+        stosm   0(%r15),0x04           # now we can turn dat on
         lm      %r6,%r15,24(%r15)      # load registers from clone
         basr    %r14,0
         l       %r14,restart_addr-.(%r14)
@@ -859,6 +837,7 @@
 .Lc_ac:        .long  0,0,1
 .Lc_ENOSYS:    .long  -ENOSYS
 .Lc4:          .long  4
+.Lc20:         .long  20
 .Lc0x1202:     .long  0x1202
 .Lc0x1004:     .long  0x1004
 .Lc0x2401:     .long  0x2401
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/floatlib.c linux/arch/s390/kernel/floatlib.c
--- v2.4.3/linux/arch/s390/kernel/floatlib.c	Fri May 12 11:41:44 2000
+++ linux/arch/s390/kernel/floatlib.c	Wed Dec 31 16:00:00 1969
@@ -1,1021 +0,0 @@
-/*
-** libgcc support for software floating point.
-** Copyright (C) 1991 by Pipeline Associates, Inc.  All rights reserved.
-** Permission is granted to do *anything* you want with this file,
-** commercial or otherwise, provided this message remains intact.  So there!
-** I would appreciate receiving any updates/patches/changes that anyone
-** makes, and am willing to be the repository for said changes (am I
-** making a big mistake?).
-
-Warning! Only single-precision is actually implemented.  This file
-won't really be much use until double-precision is supported.
-
-However, once that is done, this file might eventually become a
-replacement for libgcc1.c.  It might also make possible
-cross-compilation for an IEEE target machine from a non-IEEE
-host such as a VAX.
-
-If you'd like to work on completing this, please talk to rms@gnu.ai.mit.edu.
-
---> Double precision floating support added by James Carlson on 20 April 1998.
-
-**
-** Pat Wood
-** Pipeline Associates, Inc.
-** pipeline!phw@motown.com or
-** sun!pipeline!phw or
-** uunet!motown!pipeline!phw
-**
-** 05/01/91 -- V1.0 -- first release to gcc mailing lists
-** 05/04/91 -- V1.1 -- added float and double prototypes and return values
-**                  -- fixed problems with adding and subtracting zero
-**                  -- fixed rounding in truncdfsf2
-**                  -- fixed SWAP define and tested on 386
-*/
-
-/*
-** The following are routines that replace the libgcc soft floating point
-** routines that are called automatically when -msoft-float is selected.
-** The support single and double precision IEEE format, with provisions
-** for byte-swapped machines (tested on 386).  Some of the double-precision
-** routines work at full precision, but most of the hard ones simply punt
-** and call the single precision routines, producing a loss of accuracy.
-** long long support is not assumed or included.
-** Overall accuracy is close to IEEE (actually 68882) for single-precision
-** arithmetic.  I think there may still be a 1 in 1000 chance of a bit
-** being rounded the wrong way during a multiply.  I'm not fussy enough to
-** bother with it, but if anyone is, knock yourself out.
-**
-** Efficiency has only been addressed where it was obvious that something
-** would make a big difference.  Anyone who wants to do this right for
-** best speed should go in and rewrite in assembler.
-**
-** I have tested this only on a 68030 workstation and 386/ix integrated
-** in with -msoft-float.
-*/
-
-#define float long
-#define double long long
-
-/* the following deal with IEEE single-precision numbers */
-#define EXCESS          126
-#define SIGNBIT         0x80000000
-#define HIDDEN          (1 << 23)
-#define SIGN(fp)        ((fp) & SIGNBIT)
-#define EXP(fp)         (((fp) >> 23) & 0xFF)
-#define MANT(fp)        (((fp) & 0x7FFFFF) | HIDDEN)
-#define PACK(s,e,m)     ((s) | ((e) << 23) | (m))
-
-/* the following deal with IEEE double-precision numbers */
-#define EXCESSD         1022
-#define HIDDEND         (1 << 20)
-#define EXPD(fp)        (((fp.l.upper) >> 20) & 0x7FF)
-#define SIGND(fp)       ((fp.l.upper) & SIGNBIT)
-#define MANTD(fp)       (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) |(fp.l.lower >> 22))
-#define HIDDEND_LL      ((long long)1 << 52)
-#define MANTD_LL(fp)    ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
-#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m))
-
-/* define SWAP for 386/960 reverse-byte-order brain-damaged CPUs */
-union double_long {
-    double d;
-#ifdef SWAP
-    struct {
-      unsigned long lower;
-      long upper;
-    } l;
-#else
-    struct {
-      long upper;
-      unsigned long lower;
-    } l;
-#endif
-    long long ll;
-};
-
-union float_long
-  {
-    float f;
-    long l;
-  };
-
-long long
-__negdi2 (long long u)
-{
-
-  union lll {
-    long long ll;
-    long s[2];
-  };
-
-  union lll w,uu;
-
-  uu.ll = u;
-
-  w.s[1] = -uu.s[1];
-  w.s[0] = -uu.s[0] - ((int) w.s[1] != 0);
-
-  return w.ll;
-}
-
-
-
-/* add two floats */
-float
-__addsf3 (float a1, float a2)
-{
-  register long mant1, mant2;
-  register union float_long fl1, fl2;
-  register int exp1, exp2;
-  int sign = 0;
-
-  fl1.f = a1;
-  fl2.f = a2;
-
-  /* check for zero args */
-  if (!fl1.l) {
-      fl1.f = fl2.f;
-      goto test_done;
-  }
-  if (!fl2.l)
-      goto test_done;
-
-  exp1 = EXP (fl1.l);
-  exp2 = EXP (fl2.l);
-
-  if (exp1 > exp2 + 25)
-      goto test_done;
-  if (exp2 > exp1 + 25) {
-      fl1.f = fl2.f;
-      goto test_done;
-  }
-
-  /* do everything in excess precision so's we can round later */
-  mant1 = MANT (fl1.l) << 6;
-  mant2 = MANT (fl2.l) << 6;
-
-  if (SIGN (fl1.l))
-    mant1 = -mant1;
-  if (SIGN (fl2.l))
-    mant2 = -mant2;
-
-  if (exp1 > exp2)
-    {
-      mant2 >>= exp1 - exp2;
-    }
-  else
-    {
-      mant1 >>= exp2 - exp1;
-      exp1 = exp2;
-    }
-  mant1 += mant2;
-
-  if (mant1 < 0)
-    {
-      mant1 = -mant1;
-      sign = SIGNBIT;
-    }
-  else if (!mant1) {
-      fl1.f = 0;
-      goto test_done;
-  }
-
-  /* normalize up */
-  while (!(mant1 & 0xE0000000))
-    {
-      mant1 <<= 1;
-      exp1--;
-    }
-
-  /* normalize down? */
-  if (mant1 & (1 << 30))
-    {
-      mant1 >>= 1;
-      exp1++;
-    }
-
-  /* round to even */
-  mant1 += (mant1 & 0x40) ? 0x20 : 0x1F;
-
-  /* normalize down? */
-  if (mant1 & (1 << 30))
-    {
-      mant1 >>= 1;
-      exp1++;
-    }
-
-  /* lose extra precision */
-  mant1 >>= 6;
-
-  /* turn off hidden bit */
-  mant1 &= ~HIDDEN;
-
-  /* pack up and go home */
-  fl1.l = PACK (sign, exp1, mant1);
-test_done:
-  return (fl1.f);
-}
-
-/* subtract two floats */
-float
-__subsf3 (float a1, float a2)
-{
-  register union float_long fl1, fl2;
-
-  fl1.f = a1;
-  fl2.f = a2;
-
-  /* check for second arg zero */
-  if (!fl2.l)
-    return (fl1.f);
-  /* twiddle sign bit */
-  fl2.l ^= SIGNBIT;
-  /* check for first arg zero */
-  if (!fl1.l)
-    return (fl2.f);
-  /* add values */ 
-  return __addsf3 (a1, fl2.f);
-}
-
-/* compare two floats */
-long
-__cmpsf2 (float a1, float a2)
-{
-  register union float_long fl1, fl2;
-
-  fl1.f = a1;
-  fl2.f = a2;
-
-  if (SIGN (fl1.l) && SIGN (fl2.l))
-    {
-      fl1.l ^= SIGNBIT;
-      fl2.l ^= SIGNBIT;
-      if (fl1.l < fl2.l)
-	return (-1);
-      if (fl1.l > fl2.l)
-	return (1);
-      return 0;
-    } else {
-      if (fl1.l < fl2.l)
-	return (-1);
-      if (fl1.l > fl2.l)
-	return (1);
-      return (0);
-    }
-}
-
-/* multiply two floats */
-float
-__mulsf3 (float a1, float a2)
-{
-  register union float_long fl1, fl2;
-  register unsigned long result;
-  register int exp;
-  int sign;
-
-  fl1.f = a1;
-  fl2.f = a2;
-
-  if (!fl1.l || !fl2.l) {
-      fl1.f = 0;
-      goto test_done;
-  }
-
-  /* compute sign and exponent */
-  sign = SIGN (fl1.l) ^ SIGN (fl2.l);
-  exp = EXP (fl1.l) - EXCESS;
-  exp += EXP (fl2.l);
-
-  fl1.l = MANT (fl1.l);
-  fl2.l = MANT (fl2.l);
-
-  /* the multiply is done as one 16x16 multiply and two 16x8 multiples */
-  result = (fl1.l >> 8) * (fl2.l >> 8);
-  result += ((fl1.l & 0xFF) * (fl2.l >> 8)) >> 8;
-  result += ((fl2.l & 0xFF) * (fl1.l >> 8)) >> 8;
-
-  result >>= 2;
-  if (result & 0x20000000)
-    {
-      /* round */
-      result += 0x20;
-      result >>= 6;
-    }
-  else
-    {
-      /* round */
-      result += 0x10;
-      result >>= 5;
-      exp--;
-    }
-  if (result & (HIDDEN<<1)) {
-    result >>= 1;
-    exp++;
-  }
-
-  result &= ~HIDDEN;
-
-  /* pack up and go home */
-  fl1.l = PACK (sign, exp, result);
-test_done:
-  return (fl1.f);
-}
-
-/* divide two floats */
-float
-__divsf3 (float a1, float a2)
-{
-  register union float_long fl1, fl2;
-  register int result;
-  register int mask;
-  register int exp, sign;
-
-  fl1.f = a1;
-  fl2.f = a2;
-
-  /* subtract exponents */
-  exp = EXP (fl1.l) - EXP (fl2.l) + EXCESS;
-
-  /* compute sign */
-  sign = SIGN (fl1.l) ^ SIGN (fl2.l);
-
-  /* divide by zero??? */
-  if (!fl2.l)
-    /* return NaN or -NaN */
-    return (sign ? 0xFFFFFFFF : 0x7FFFFFFF);
-
-  /* numerator zero??? */
-  if (!fl1.l)
-    return (0);
-
-  /* now get mantissas */
-  fl1.l = MANT (fl1.l);
-  fl2.l = MANT (fl2.l);
-
-  /* this assures we have 25 bits of precision in the end */
-  if (fl1.l < fl2.l)
-    {
-      fl1.l <<= 1;
-      exp--;
-    }
-
-  /* now we perform repeated subtraction of fl2.l from fl1.l */
-  mask = 0x1000000;
-  result = 0;
-  while (mask)
-    {
-      if (fl1.l >= fl2.l)
-        {
-          result |= mask;
-          fl1.l -= fl2.l;
-        }
-      fl1.l <<= 1;
-      mask >>= 1;
-    }
-
-  /* round */
-  result += 1;
-
-  /* normalize down */
-  exp++;
-  result >>= 1;
-
-  result &= ~HIDDEN;
-
-  /* pack up and go home */
-  fl1.l = PACK (sign, exp, result);
-  return (fl1.f);
-}
-
-/* convert double to float */
-float
-__truncdfsf2 (double a1)
-{
-  register int exp;
-  register long mant;
-  register union float_long fl;
-  register union double_long dl1;
-
-  dl1.d = a1;
-
-  if (!dl1.l.upper && !dl1.l.lower)
-    return (float)(0);
-
-  exp = EXPD (dl1) - EXCESSD + EXCESS;
-
-  /* shift double mantissa 6 bits so we can round */
-  mant = MANTD (dl1) >> 6;
-
-  /* now round and shift down */
-  mant += 1;
-  mant >>= 1;
-   
-  /* did the round overflow? */
-  if (mant & 0xFF000000)
-    {
-      mant >>= 1;
-      exp++;
-    }
-
-  mant &= ~HIDDEN;
-
-  /* pack up and go home */
-  fl.l = PACK (SIGND (dl1), exp, mant);
-  return (fl.f);
-}
-
-/* convert int to double */
-double
-__floatsidf (register long a1)
-{
-  register int sign = 0, exp = 31 + EXCESSD;
-  union double_long dl;
-
-  if (a1 == 0x80000000)
-    {
-      /*
-       * -a1 would be 0 !
-       */
-      dl.l.upper = 0xc1e00000;
-      dl.l.lower = 0x0;
-      return (dl.d);
-    }
-
-  if (!a1)
-    {
-      dl.l.upper = dl.l.lower = 0;
-      return (dl.d);
-    }
-
-  if (a1 < 0)
-    {
-      sign = SIGNBIT;
-      a1 = -a1;
-    }
-
-  while (a1 < 0x1000000)
-    {
-      a1 <<= 4;
-      exp -= 4;
-    }
-
-  while (a1 < 0x40000000)
-    {
-      a1 <<= 1;
-      exp--;
-    }
-
-  /* pack up and go home */
-  dl.l.upper = sign;
-  dl.l.upper |= exp << 20;
-  dl.l.upper |= (a1 >> 10) & ~HIDDEND;
-  dl.l.lower = a1 << 22;
-
-  return (dl.d);
-}
-
-double
-__floatdidf (register long long a1)
-{
-    register int exp = 63 + EXCESSD;
-    union double_long dl;
-
-    dl.l.upper = dl.l.lower = 0;
-    if (a1 == 0)
-        return (dl.d);
-
-    if (a1 < 0) {
-        dl.l.upper = SIGNBIT;
-        a1 = -a1;
-    }
-
-    while (a1 < (long long)1<<54) {
-        a1 <<= 8;
-        exp -= 8;
-    }
-    while (a1 < (long long)1<<62) {
-        a1 <<= 1;
-        exp -= 1;
-    }
-  /* pack up and go home */
-    dl.ll |= (a1 >> 10) & ~HIDDEND_LL;
-    dl.l.upper |= exp << 20;
-
-    return (dl.d);
-}
-
-float
-__floatsisf (register long a1)
-{
-    return __truncdfsf2(__floatsidf(a1));
-}
-
-float
-__floatdisf (register long long a1)
-{
-    return (float)__floatdidf(a1);
-}
-/* negate a float */
-float
-__negsf2 (float a1)
-{
-  register union float_long fl1;
-
-  fl1.f = a1;
-  if (!fl1.l)
-    return (0);
-
-  fl1.l ^= SIGNBIT;
-  return (fl1.f);
-}
-
-/* negate a double */
-double
-__negdf2 (double a1)
-{
-  register union double_long dl1;
-
-  dl1.d = a1;
-
-  if (!dl1.l.upper && !dl1.l.lower)
-      return (dl1.d);
-
-  dl1.l.upper ^= SIGNBIT;
-  return (dl1.d);
-}
-
-/* convert float to double */
-double
-__extendsfdf2 (float a1)
-{
-  register union float_long fl1;
-  register union double_long dl;
-  register int exp;
-
-  fl1.f = a1;
-
-  if (!fl1.l)
-    {
-      dl.l.upper = dl.l.lower = 0;
-      return (dl.d);
-    }
-
-  dl.l.upper = SIGN (fl1.l);
-  exp = EXP (fl1.l) - EXCESS + EXCESSD;
-  dl.l.upper |= exp << 20;
-  dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3;
-  dl.l.lower = MANT (fl1.l) << 29;
-
-  return (dl.d);
-}
-
-
-/* compare two doubles */
-long
-__cmpdf2 (double a1, double a2)
-{
-  register union double_long dl1, dl2;
-
-  dl1.d = a1;
-  dl2.d = a2;
-
-  if (SIGND (dl1) && SIGND (dl2))
-    {
-      dl1.l.upper ^= SIGNBIT;
-      dl2.l.upper ^= SIGNBIT;
-      if (dl1.l.upper < dl2.l.upper)
-	return (1);
-      if (dl1.l.upper > dl2.l.upper)
-	return (-1);
-      if (dl1.l.lower < dl2.l.lower)
-	return (1);
-      if (dl1.l.lower > dl2.l.lower)
-	return (-1);
-      return (0);
-    } else {
-      if (dl1.l.upper < dl2.l.upper)
-	return (-1);
-      if (dl1.l.upper > dl2.l.upper)
-	return (1);
-      if (dl1.l.lower < dl2.l.lower)
-	return (-1);
-      if (dl1.l.lower > dl2.l.lower)
-	return (1);
-      return (0);
-    }
-}
-
-/* convert double to int */
-long
-__fixdfsi (double a1)
-{
-  register union double_long dl1;
-  register int exp;
-  register long l;
-
-  dl1.d = a1;
-
-  if (!dl1.l.upper && !dl1.l.lower)
-    return (0);
-
-  exp = EXPD (dl1) - EXCESSD - 31;
-  l = MANTD (dl1);
-
-  if (exp > 0)
-      return SIGND(dl1) ? (1<<31) : ((1ul<<31)-1);
-
-  /* shift down until exp = 0 or l = 0 */
-  if (exp <= 0 && exp > -32 && l)
-    l >>= -exp;
-  else
-    return (0);
-
-  return (SIGND (dl1) ? -l : l);
-}
-
-/* convert float to int */
-long
-__fixsfsi (float a1)
-{
-    return __fixdfsi(__extendsfdf2(a1));
-}
-
-/* convert double to int */
-long long
-__fixdfdi (double a1)
-{
-    register union double_long dl1;
-    register int exp;
-    register long long l;
-
-    dl1.d = a1;
-
-    if (!dl1.l.upper && !dl1.l.lower)
-        return (0);
-
-    exp = EXPD (dl1) - EXCESSD - 64;
-    l = MANTD_LL(dl1);
-
-    if (exp > 0) {
-        l = (long long)1<<63;
-        if (!SIGND(dl1))
-            l--;
-        return l;
-    }
-
-    /* shift down until exp = 0 or l = 0 */
-    if (exp <= 0 && exp > -64 && l)
-        l >>= -exp;
-    else
-        return (0);
-
-    return (SIGND (dl1) ? -l : l);
-}
-
-/* convert double to unsigned int */
-unsigned long
-__fixunsdfsi (double a1)
-{
-  register union double_long dl1;
-  register int exp;
-  register unsigned long l;
-
-  dl1.d = a1;
-
-  if (!dl1.l.upper && !dl1.l.lower)
-    return (0);
-
-  exp = EXPD (dl1) - EXCESSD - 32;
-  l = (((((dl1.l.upper) & 0xFFFFF) | HIDDEND) << 11) | (dl1.l.lower >> 21));
-
-  if (exp > 0)
-    return (0xFFFFFFFFul);      /* largest integer */
-
-  /* shift down until exp = 0 or l = 0 */
-  if (exp < 0 && exp > -32 && l)
-    l >>= -exp;
-  else
-    return (0);
-
-  return (l);
-}
-
-/* convert double to unsigned int */
-unsigned long long
-__fixunsdfdi (double a1)
-{
-    register union double_long dl1;
-    register int exp;
-    register unsigned long long l;
-
-    dl1.d = a1;
-
-    if (dl1.ll == 0)
-        return (0);
-
-    exp = EXPD (dl1) - EXCESSD - 64;
-
-    l = dl1.ll;
-
-    if (exp > 0)
-        return (unsigned long long)-1;
-
-    /* shift down until exp = 0 or l = 0 */
-    if (exp < 0 && exp > -64 && l)
-        l >>= -exp;
-    else
-        return (0);
-
-    return (l);
-}
-
-/* addtwo doubles */
-double
-__adddf3 (double a1, double a2)
-{
-    register long long mant1, mant2;
-    register union double_long fl1, fl2;
-    register int exp1, exp2;
-    int sign = 0;
-
-    fl1.d = a1;
-    fl2.d = a2;
-
-    /* check for zero args */
-    if (!fl2.ll)
-        goto test_done;
-    if (!fl1.ll) {
-        fl1.d = fl2.d;
-        goto test_done;
-    }
-
-    exp1 = EXPD(fl1);
-    exp2 = EXPD(fl2);
-
-    if (exp1 > exp2 + 54)
-        goto test_done;
-    if (exp2 > exp1 + 54) {
-        fl1.d = fl2.d;
-        goto test_done;
-    }
-
-    /* do everything in excess precision so's we can round later */
-    mant1 = MANTD_LL(fl1) << 9;
-    mant2 = MANTD_LL(fl2) << 9;
-
-    if (SIGND(fl1))
-        mant1 = -mant1;
-    if (SIGND(fl2))
-        mant2 = -mant2;
-
-    if (exp1 > exp2)
-        mant2 >>= exp1 - exp2;
-    else {
-        mant1 >>= exp2 - exp1;
-        exp1 = exp2;
-    }
-    mant1 += mant2;
-
-    if (mant1 < 0) {
-        mant1 = -mant1;
-        sign = SIGNBIT;
-    } else if (!mant1) {
-        fl1.d = 0;
-        goto test_done;
-    }
-
-    /* normalize up */
-    while (!(mant1 & ((long long)7<<61))) {
-        mant1 <<= 1;
-        exp1--;
-    }
-
-    /* normalize down? */
-    if (mant1 & ((long long)3<<62)) {
-        mant1 >>= 1;
-        exp1++;
-    }
-
-    /* round to even */
-    mant1 += (mant1 & (1<<9)) ? (1<<8) : ((1<<8)-1);
-
-    /* normalize down? */
-    if (mant1 & ((long long)3<<62)) {
-        mant1 >>= 1;
-        exp1++;
-    }
-
-    /* lose extra precision */
-    mant1 >>= 9;
-
-    /* turn off hidden bit */
-    mant1 &= ~HIDDEND_LL;
-
-    /* pack up and go home */
-    fl1.ll = PACKD_LL(sign,exp1,mant1);
-
-test_done:
-    return (fl1.d);
-}
-
-/* subtract two doubles */
-double
-__subdf3 (double a1, double a2)
-{
-    register union double_long fl1, fl2;
-
-    fl1.d = a1;
-    fl2.d = a2;
-
-    /* check for zero args */
-    if (!fl2.ll)
-        return (fl1.d);
-    /* twiddle sign bit and add */
-    fl2.l.upper ^= SIGNBIT;
-    if (!fl1.ll)
-        return (fl2.d);
-    return __adddf3 (a1, fl2.d);
-}
-
-/* multiply two doubles */
-double
-__muldf3 (double a1, double a2)
-{
-    register union double_long fl1, fl2;
-    register unsigned long long result=0ULL;
-    register int exp;
-    int sign;
-
-    fl1.d = a1;
-    fl2.d = a2;
-
-    if (!fl1.ll || !fl2.ll) {
-        fl1.d = 0;
-        goto test_done;
-    }
-
-    /* compute sign and exponent */
-    sign = SIGND(fl1) ^ SIGND(fl2);
-    exp = EXPD(fl1) - EXCESSD;
-    exp += EXPD(fl2);
-
-    fl1.ll = MANTD_LL(fl1);
-    fl2.ll = MANTD_LL(fl2);
-
-  /* the multiply is done as one 31x31 multiply and two 31x21 multiples */
-    result = (fl1.ll >> 21) * (fl2.ll >> 21);
-    result += ((fl1.ll & 0x1FFFFF) * (fl2.ll >> 21)) >> 21;
-    result += ((fl2.ll & 0x1FFFFF) * (fl1.ll >> 21)) >> 21;
-
-    result >>= 2;
-    if (result & ((long long)1<<61)) {
-        /* round */
-        result += 1<<8;
-        result >>= 9;
-    } else {
-        /* round */
-        result += 1<<7;
-        result >>= 8;
-        exp--;
-    }
-    if (result & (HIDDEND_LL<<1)) {
-        result >>= 1;
-        exp++;
-    }
-
-    result &= ~HIDDEND_LL;
-
-    /* pack up and go home */
-    fl1.ll = PACKD_LL(sign,exp,result);
-test_done:
-    return (fl1.d);
-}
-
-/* divide two doubles */
-double
-__divdf3 (double a1, double a2)
-{
-    register union double_long fl1, fl2;
-    register long long mask,result;
-    register int exp, sign;
-
-    fl1.d = a1;
-    fl2.d = a2;
-
-    /* subtract exponents */
-    exp = EXPD(fl1) - EXPD(fl2) + EXCESSD;
-
-    /* compute sign */
-    sign = SIGND(fl1) ^ SIGND(fl2);
-
-    /* numerator zero??? */
-    if (fl1.ll == 0) {
-        /* divide by zero??? */
-        if (fl2.ll == 0)
-            fl1.ll = ((unsigned long long)1<<63)-1;     /* NaN */
-        else
-            fl1.ll = 0;
-        goto test_done;
-    }
-
-    /* return +Inf or -Inf */
-    if (fl2.ll == 0) {
-        fl1.ll = PACKD_LL(SIGND(fl1),2047,0);
-        goto test_done;
-    }
-
-
-    /* now get mantissas */
-    fl1.ll = MANTD_LL(fl1);
-    fl2.ll = MANTD_LL(fl2);
-
-    /* this assures we have 54 bits of precision in the end */
-    if (fl1.ll < fl2.ll) {
-        fl1.ll <<= 1;
-        exp--;
-    }
-
-    /* now we perform repeated subtraction of fl2.ll from fl1.ll */
-    mask = (long long)1<<53;
-    result = 0;
-    while (mask) {
-        if (fl1.ll >= fl2.ll)
-        {
-            result |= mask;
-            fl1.ll -= fl2.ll;
-        }
-        fl1.ll <<= 1;
-        mask >>= 1;
-    }
-
-    /* round */
-    result += 1;
-
-    /* normalize down */
-    exp++;
-    result >>= 1;
-
-    result &= ~HIDDEND_LL;
-
-    /* pack up and go home */
-    fl1.ll = PACKD_LL(sign, exp, result);
-
-test_done:
-    return (fl1.d);
-}
-
-int
-__gtdf2 (double a1, double a2)
-{
-    return __cmpdf2 ((float) a1, (float) a2) > 0;
-}
-
-int
-__gedf2 (double a1, double a2)
-{
-    return (__cmpdf2 ((float) a1, (float) a2) >= 0) - 1;
-}
-
-int
-__ltdf2 (double a1, double a2)
-{
-    return - (__cmpdf2 ((float) a1, (float) a2) < 0);
-}
-
-int
-__ledf2 (double a1, double a2)
-{
-    return __cmpdf2 ((float) a1, (float) a2) > 0;
-}
-
-int
-__eqdf2 (double a1, double a2)
-{
-    return *(long long *) &a1 == *(long long *) &a2;
-}
-
-int
-__nedf2 (double a1, double a2)
-{
-    return *(long long *) &a1 != *(long long *) &a2;
-}
-
-/* absolute value of double */
-double
-__absdf2(double a1)
-{
-  if (__cmpdf2(a1,0.0) < 0)
-      return __negdf2(a1);
-  else
-      return a1;
-}
-
-/* absolute value of float */
-float
-__abssf2(float a1)
-{
-  if (__cmpsf2(a1,0.0) < 0)
-      return __negsf2(a1);
-  else
-      return a1;
-}
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- v2.4.3/linux/arch/s390/kernel/head.S	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/head.S	Wed Apr 11 19:02:27 2001
@@ -261,8 +261,9 @@
 	l     %r1,0xb8                         # load ipl subchannel number
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
-        st    %r1,__LC_IPLDEV                  # store ipl device number
         l     %r12,.Lparm                      # pointer to parameter area
+        st    %r1,__LC_IPLDEV                  # store ipl device number
+        st    %r1,IPL_DEVICE-PARMAREA(%r12)
 
 #
 # load parameter file from ipl device
@@ -406,7 +407,8 @@
 	sr    %r3,%r2
 	la    %r3,1(%r3)
 .done:
-	st    %r3,MEMORY_SIZE-PARMAREA(%r11)	
+        l     %r1,.memsize
+	st    %r3,0(%r1)
 	slr   %r0,%r0
 	st    %r0,INITRD_SIZE-PARMAREA(%r11)
 	st    %r0,INITRD_START-PARMAREA(%r11)
@@ -414,6 +416,7 @@
 .tbl:	.long _ebcasc			# translate table
 .cmd:	.long COMMAND_LINE		# address of command line buffer
 .parm:	.long PARMAREA
+.memsize: .long memory_size
 .fourmeg: .long 0x00400000      	# 4M
 .pgmnw:	.long 0x00080000,.pgmx
 .lowcase:
@@ -464,7 +467,7 @@
 #
 # find out memory size.
 #
-	mvc   104(8),.Lpcmem-.LPG1(%r13) # setup program check handler
+	mvc   __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
         lhi   %r2,1
         sll   %r2,17                     # test in increments of 128KB
 	lr    %r1,%r2
@@ -476,78 +479,56 @@
 	bnm   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
 .Lchkmem:
 	n     %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-	st    %r1,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-.Lsizeok:
-
-#
-# Now we have to move the ramdisk to a location approriate for the
-# memory size. If we have more than 64 MB of memory we move it to 32MB
-# to make room for the page tables set up by paging_init.
-#
-        l     %r1,MEMORY_SIZE-PARMAREA(%r12)
-        cl    %r1,.Lbigmem-.LPG1(%r13)   # memory < 64mb ?
-        bl    .Lnomove-.LPG1(%r13)       # if yes ramdisk @8MB is ok
-        icm   %r4,15,INITRD_START-PARMAREA(%r12)
-        bz    .Lnomove-.LPG1(%r13)
-	l     %r2,.Lrdstart-.LPG1(%r13)  # new address of ramdisk
-	st    %r2,INITRD_START-PARMAREA(%r12)
-        l     %r1,INITRD_SIZE-PARMAREA(%r12)
-	ar    %r2,%r1                    # we start moving at the end
-	ar    %r4,%r1                    #  because new location > old location
-.Lmove:	lr    %r0,%r2                    # new - old is the maximum we can move
-	sr    %r0,%r4                    #  because of overlapping
-	cr    %r0,%r1                    # we shouldn't move more than there is
-	bnh   .Lnoend-.LPG1(%r13)
-	lr    %r0,%r1
-.Lnoend:cl    %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go
-	bnh   .Lchunk-.LPG1(%r13)
-	l     %r0,.Lmaxchunk-.LPG1(%r13)
-.Lchunk:sr    %r2,%r0                    # make source & destination pointer
-	sr    %r4,%r0
-	lr    %r3,%r0                    # set source & destination length
-	lr    %r5,%r0
-	mvcl  %r2,%r4
-	sr    %r2,%r0                    # substract length again, since
-	sr    %r4,%r0                    #  mvcl added it to the pointers
-	sr    %r1,%r0                    # substract chunk size from length
-	bnz   .Lmove-.LPG1(%r13)
-.Lnomove:
+        l     %r2,.Lmemsize-.LPG1(%r13)  # address of variable memory_size
+	st    %r1,0(%r2)                 # store memory size
 
+        l      %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
 #
 # find out if we are running under VM
 #
         stidp  __LC_CPUID               # store cpuid
 	tm     __LC_CPUID,0xff          # running under VM ?
 	bno    .Lnovm-.LPG1(%r13)
-        oi     MACHINE_FLAGS+3-PARMAREA(%r12),1    # set VM flag
+        oi     3(%r12),1                # set VM flag
 .Lnovm:
         lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
         bne    .Lnop390-.LPG1(%r13)
-        oi     MACHINE_FLAGS+3-PARMAREA(%r12),4    # set P/390 flag
+        oi     3(%r12),4                # set P/390 flag
 .Lnop390:
 
 #
 # find out if we have an IEEE fpu
 #
-        mvc    104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler
+        mvc    __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
         ld     %f0,.Lflt0-.LPG1(%r13)   # load (float) 0.0
         ldr    %f2,%f0
         adbr   %f0,%f2                  # test IEEE add instruction
-        oi     MACHINE_FLAGS+3-PARMAREA(%r12),2    # set IEEE fpu flag
+        oi     3(%r12),2                # set IEEE fpu flag
 .Lchkfpu:
 
 #
 # find out if we have the CSP instruction
 #
-       mvc    104(8),.Lpccsp-.LPG1(%r13) # setup program check handler
+       mvc    __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
        la     %r0,0
        lr     %r1,%r0
        la     %r2,.Lflt0-.LPG1(%r13)
        csp    %r0,%r2                   # Test CSP instruction
-       oi     MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag
+       oi     3(%r12),8                 # set CSP flag
 .Lchkcsp:
 
+#
+# find out if we have the MVPG instruction
+#
+       mvc    __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13)
+       sr     %r0,%r0
+       la     %r1,0
+       la     %r2,0
+       mvpg   %r1,%r2                   # Test CSP instruction
+       oi     3(%r12),16                # set MVPG flag
+.Lchkmvpg:
+
         lpsw  .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
         .align 8
@@ -571,24 +552,23 @@
 .Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
+.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
 .Lflt0: .double 0
 .Lparm1:.long  PARMAREA
 .L4malign:.long 0xffc00000
 .Lbigmem:.long 0x04000000
 .Lrdstart:.long 0x02000000
 .Lmaxchunk:.long  0x00ffffff
+.Lmemsize:.long memory_size
+.Lmflags:.long machine_flags
 
 #
 # params at 10400 (setup.h)
 #
 	.org   PARMAREA
-        .long  0x0100                   # ORIG_ROOT_DEV: ramdisk major/minor
-        .word  0                        # MOUNT_ROOT_RDONLY: no
-	.long  0                        # MEMORY_SIZE
-	.long  0                        # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE)
-        .long  RAMDISK_ORIGIN           # INITRD_START
-        .long  0x800000                 # INITRD_SIZE
-	.word  0                        # RAMDISK_FLAGS
+        .long  0,0                      # IPL_DEVICE
+        .long  0,RAMDISK_ORIGIN         # INITRD_START
+        .long  0,0x800000               # INITRD_SIZE
 
         .org   COMMAND_LINE
     	.byte  "root=/dev/ram0 ro"
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c
--- v2.4.3/linux/arch/s390/kernel/irq.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/irq.c	Wed Apr 11 19:02:27 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/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
@@ -20,7 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -286,7 +287,7 @@
  */
 void __global_cli(void)
 {
-	unsigned int flags;
+	unsigned long flags;
 
 	__save_flags(flags);
 	if (flags & (1 << EFLAGS_I_SHIFT)) {
@@ -357,48 +358,6 @@
 
 #endif
 
-/*
- * Note : This fuction should be eliminated as it doesn't comply with the
- *         S/390 irq scheme we have implemented ...
- */
-int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs * regs)
-{
-	struct irqaction * action;
-	int                status;
-
-	status = 0;
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-		return( -ENODEV);
-
-	action = ioinfo[irq]->irq_desc.action;
-
-	if (action)
-	{
-		status |= 1;
-
-		if (!(action->flags & SA_INTERRUPT))
-			__sti();
-
-		do
-		{
-			status |= action->flags;
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-
-		if (status & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		__cli();
-
-	} /* endif */
-
-	return status;
-}
-
-void enable_nop(int irq)
-{
-}
 
 void __init init_IRQ(void)
 {
@@ -427,3 +386,8 @@
         /* For now, nothing... */
 }
 
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_bh_lock);
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/irqextras390.c linux/arch/s390/kernel/irqextras390.c
--- v2.4.3/linux/arch/s390/kernel/irqextras390.c	Fri May 12 11:41:44 2000
+++ linux/arch/s390/kernel/irqextras390.c	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- *  arch/s390/kernel/irqextras390.c
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- *
- *  Some channel code by D.J. Barrow
- */
-
-/*
-	
-*/
-#include<asm/irqextras390.h>
-#include<asm/lowcore.h>
-
-#if 0
-// fixchannelprogram is now obselete
-void fixchannelprogram(orb_bits_t *orbptr)
-{
-	__u32	newAddress=orbptr->ccw_program_address;
-	fixccws(orbptr->ccw_program_address);
-	orbptr->ccw_program_address=newAddress;
-	orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address));
-}
-#endif
-
-void fixccws(ccw1_bits_t *ccwptr)
-{
-	for(;;ccwptr++)
-	{	// Just hope nobody starts doing prefixing
-		if(!ccwptr->cc)
-			break;
-	}
-}
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/mathemu.c linux/arch/s390/kernel/mathemu.c
--- v2.4.3/linux/arch/s390/kernel/mathemu.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/mathemu.c	Wed Dec 31 16:00:00 1969
@@ -1,1045 +0,0 @@
-/*
- *  arch/s390/kernel/mathemu.c
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *
- * 'mathemu.c' handles IEEE instructions on a S390 processor
- * that does not have the IEEE fpu
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-
-#include <asm/uaccess.h>
-#include <asm/mathemu.h>
-
-#ifdef CONFIG_SYSCTL
-int sysctl_ieee_emulation_warnings=1;
-#endif
-
-#define mathemu_put_user(x, ptr) \
-{                                \
-	if(put_user((x),(ptr)))  \
-		return 1;        \
-}
-
-#define mathemu_get_user(x, ptr) \
-{                                \
-	if(get_user((x),(ptr)))  \
-		return 1;        \
-}
-
-
-#define mathemu_copy_from_user(to,from,n)                 \
-{                                                         \
-	if(copy_from_user((to),(from),(n))==-EFAULT)      \
-		return 1;                                 \
-}
-
-
-#define mathemu_copy_to_user(to, from, n)                 \
-{                                                         \
-	if(copy_to_user((to),(from),(n))==-EFAULT)      \
-		return 1;                                 \
-}
-
-
-
-static void display_emulation_not_implemented(char *instr)
-{
-	struct pt_regs *regs;
-	__u16 *location;
-	
-#if CONFIG_SYSCTL
-	if(sysctl_ieee_emulation_warnings)
-#endif
-	{
-		regs=current->thread.regs;
-		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
-		printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
-		       instr,
-		       current->comm, current->pid);
-		printk("%s's PSW:    %08lx %08lx\n",instr,
-		       (unsigned long) regs->psw.mask,
-		       (unsigned long) location);
-	}
-}
-
-static int set_CC_df(__u64 val1,__u64 val2) {
-        int rc;
-        rc = __cmpdf2(val1,val2);
-        current->thread.regs->psw.mask &= 0xFFFFCFFF;
-        switch (rc) {
-                case -1:
-                        current->thread.regs->psw.mask |= 0x00001000;
-                        break;
-                case 1:
-                        current->thread.regs->psw.mask |= 0x00002000;
-                        break;
-        }
-	return 0;
-}
-
-static int set_CC_sf(__u32 val1,__u32 val2) {
-        int rc;
-        rc = __cmpsf2(val1,val2);
-        current->thread.regs->psw.mask &= 0xFFFFCFFF;
-        switch (rc) {
-                case -1:
-                        current->thread.regs->psw.mask |= 0x00001000;
-                        break;
-                case 1:
-                        current->thread.regs->psw.mask |= 0x00002000;
-                        break;
-        }
-	return 0;
-}
-
-
-static int emu_adb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_adbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_aeb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_aebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,
-                                        current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_axbr (int rx, int ry) {
-        display_emulation_not_implemented("axbr");
-	return 0;
-}
-
-static int emu_cdb (int rx, __u64 val) {
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,val);
-	return 0;
-}
-
-static int emu_cdbr (int rx, int ry) {
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d);
-	return 0;
-}
-
-static int emu_cdfbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d =
-                     __floatsidf(current->thread.regs->gprs[ry]);
-	return 0;
-}
-
-static int emu_ceb (int rx, __u32 val) {
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,val);
-	return 0;
-}
-
-static int emu_cebr (int rx, int ry) {
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f);
-	return 0;
-}
-
-static int emu_cefbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f =
-                     __floatsisf(current->thread.regs->gprs[ry]);
-	return 0;
-}
-
-static int emu_cfdbr (int rx, int ry, int mask) {
-        current->thread.regs->gprs[rx] =
-                     __fixdfsi(current->thread.fp_regs.fprs[ry].d);
-	return 0;
-}
-
-static int emu_cfebr (int rx, int ry, int mask) {
-        current->thread.regs->gprs[rx] =
-                     __fixsfsi(current->thread.fp_regs.fprs[ry].f);
-	return 0;
-}
-
-static int emu_cfxbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("cfxbr");
-	return 0;
-}
-
-static int emu_cxbr (int rx, int ry) {
-        display_emulation_not_implemented("cxbr");
-	return 0;
-}
-
-static int emu_cxfbr (int rx, int ry) {
-        display_emulation_not_implemented("cxfbr");
-	return 0;
-}
-
-static int emu_ddb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_ddbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_deb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_debr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,
-                                         current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_didbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("didbr");
-	return 0;
-}
-
-static int emu_diebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("diebr");
-	return 0;
-}
-
-static int emu_dxbr (int rx, int ry) {
-        display_emulation_not_implemented("dxbr");
-	return 0;
-}
-
-static int emu_efpc (int rx, int ry) {
-	current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc;
-	return 0;
-}
-
-static int emu_fidbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("fidbr");
-	return 0;
-}
-
-static int emu_fiebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("fiebr");
-	return 0;
-}
-
-static int emu_fixbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("fixbr");
-	return 0;
-}
-
-static int emu_kdb (int rx, __u64 val) {
-        display_emulation_not_implemented("kdb");
-	return 0;
-}
-
-static int emu_kdbr (int rx, int ry) {
-        display_emulation_not_implemented("kdbr");
-	return 0;
-}
-
-static int emu_keb (int rx, __u32 val) {
-        display_emulation_not_implemented("keb");
-	return 0;
-}
-
-static int emu_kebr (int rx, int ry) {
-        display_emulation_not_implemented("kebr");
-	return 0;
-}
-
-static int emu_kxbr (int rx, int ry) {
-        display_emulation_not_implemented("kxbr");
-	return 0;
-}
-
-static int emu_lcdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d =
-        __negdf2(current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_lcebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f =
-        __negsf2(current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_lcxbr (int rx, int ry) {
-        display_emulation_not_implemented("lcxbr");
-	return 0;
-}
-
-static int emu_ldeb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val);
-	return 0;
-}
-
-static int emu_ldebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d =
-        __extendsfdf2(current->thread.fp_regs.fprs[ry].f);
-	return 0;
-}
-
-static int emu_ldxbr (int rx, int ry) {
-        display_emulation_not_implemented("ldxbr");
-	return 0;
-}
-
-static int emu_ledbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_lexbr (int rx, int ry) {
-        display_emulation_not_implemented("lexbr");
-	return 0;
-}
-
-static int emu_lndbr (int rx, int ry) {
-        display_emulation_not_implemented("lndbr");
-	return 0;
-}
-
-static int emu_lnebr (int rx, int ry) {
-        display_emulation_not_implemented("lnebr");
-	return 0;
-}
-
-static int emu_lnxbr (int rx, int ry) {
-        display_emulation_not_implemented("lnxbr");
-	return 0;
-}
-
-static int emu_lpdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0);
-	return 0;
-}
-
-static int emu_lpebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_lpxbr (int rx, int ry) {
-        display_emulation_not_implemented("lpxbr");
-	return 0;
-}
-
-static int emu_ltdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d;
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_ltebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f;
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_ltxbr (int rx, int ry) {
-        display_emulation_not_implemented("ltxbr");
-	return 0;
-}
-
-static int emu_lxdb (int rx, __u64 val) {
-        display_emulation_not_implemented("lxdb");
-	return 0;
-}
-
-static int emu_lxdbr (int rx, int ry) {
-        display_emulation_not_implemented("lxdbr");
-	return 0;
-}
-
-static int emu_lxeb (int rx, __u32 val) {
-        display_emulation_not_implemented("lxeb");
-	return 0;
-}
-
-static int emu_lxebr (int rx, int ry) {
-        display_emulation_not_implemented("lxebr");
-	return 0;
-}
-
-static int emu_madb (int rx, __u64 val, int mask) {
-        display_emulation_not_implemented("madb");
-	return 0;
-}
-
-static int emu_madbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("madbr");
-	return 0;
-}
-
-static int emu_maeb (int rx, __u32 val, int mask) {
-        display_emulation_not_implemented("maeb");
-	return 0;
-}
-
-static int emu_maebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("maebr");
-	return 0;
-}
-
-static int emu_mdb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_mdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_mdeb (int rx, __u32 val) {
-        display_emulation_not_implemented("mdeb");
-	return 0;
-}
-
-static int emu_mdebr (int rx, int ry) {
-        display_emulation_not_implemented("mdebr");
-	return 0;
-}
-
-static int emu_meeb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
-                                         val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_meebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
-                                         current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_msdb (int rx, __u64 val, int mask) {
-        display_emulation_not_implemented("msdb");
-	return 0;
-}
-
-static int emu_msdbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("msdbr");
-	return 0;
-}
-
-static int emu_mseb (int rx, __u32 val, int mask) {
-        display_emulation_not_implemented("mseb");
-	return 0;
-}
-
-static int emu_msebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("msebr");
-	return 0;
-}
-
-static int emu_mxbr (int rx, int ry) {
-        display_emulation_not_implemented("mxbr");
-	return 0;
-}
-
-static int emu_mxdb (int rx, __u64 val) {
-        display_emulation_not_implemented("mxdb");
-	return 0;
-}
-
-static int emu_mxdbr (int rx, int ry) {
-        display_emulation_not_implemented("mxdbr");
-	return 0;
-}
-
-static int emu_sdb (int rx, __u64 val) {
-        current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
-                                         val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_sdbr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
-                                         current->thread.fp_regs.fprs[ry].d);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
-	return 0;
-}
-
-static int emu_seb (int rx, __u32 val) {
-        current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
-                                         val);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_sebr (int rx, int ry) {
-        current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
-                                         current->thread.fp_regs.fprs[ry].f);
-        set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
-	return 0;
-}
-
-static int emu_sfpc (int rx, int ry) {
-	__u32 val=current->thread.regs->gprs[rx];
-	if(val==0)
-		current->thread.fp_regs.fpc=val;
-	else
-		display_emulation_not_implemented("sfpc");
-	return 0;
-}
-
-static int emu_sqdb (int rx, __u64 val) {
-        display_emulation_not_implemented("sqdb");
-	return 0;
-}
-
-static int emu_sqdbr (int rx, int ry) {
-        display_emulation_not_implemented("sqdbr");
-	return 0;
-}
-
-static int emu_sqeb (int rx, __u32 val) {
-        display_emulation_not_implemented("sqeb");
-	return 0;
-}
-
-static int emu_sqebr (int rx, int ry) {
-        display_emulation_not_implemented("sqebr");
-	return 0;
-}
-
-static int emu_sqxbr (int rx, int ry) {
-        display_emulation_not_implemented("sqxbr");
-	return 0;
-}
-
-static int emu_sxbr (int rx, int ry) {
-        display_emulation_not_implemented("sxbr");
-	return 0;
-}
-
-static int emu_tcdb (int rx, __u64 val) {
-        display_emulation_not_implemented("tcdb");
-	return 0;
-}
-
-static int emu_tceb (int rx, __u32 val) {
-        display_emulation_not_implemented("tceb");
-	return 0;
-}
-
-static int emu_tcxb (int rx, __u64 val) {
-        display_emulation_not_implemented("tcxb");
-	return 0;
-}
-
-
-static inline void emu_load_regd(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     ld    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
-                        : "1" );
-        }
-}
-
-static inline void emu_load_rege(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     le    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
-                        : "1" );
-        }
-}
-
-static inline void emu_store_regd(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     std   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
-                        : "1" );
-        }
-}
-
-
-static inline void emu_store_rege(int reg) {
-        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
-                __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
-                        "     bras  1,0f\n"
-                        "     ste   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
-                        : "1" );
-        }
-}
-
-int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
-	int rc=0;
-        static const __u8 format_table[] = {
-                2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
-                1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
-                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,
-                1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0,
-                0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3,
-                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, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
-                0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 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, 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
-        };
-        static const void *jump_table[]= {
-                emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr,
-                emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr,
-                emu_kebr,  emu_cebr,  emu_aebr,  emu_sebr,
-                emu_mdebr, emu_debr,  emu_maebr, emu_msebr,
-                emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr,
-                emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr,
-                emu_kdbr,  emu_cdbr,  emu_adbr,  emu_sdbr,
-                emu_mdbr,  emu_ddbr,  emu_madbr, emu_msdbr,
-                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,      NULL,      NULL,      NULL,
-                emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr,
-                emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr,
-                emu_kxbr,  emu_cxbr,  emu_axbr,  emu_sxbr,
-                emu_mxbr,  emu_dxbr,  NULL,      NULL,
-                NULL,      NULL,      NULL,      emu_diebr,
-                NULL,      NULL,      NULL,      emu_fiebr,
-                NULL,      NULL,      NULL,      emu_didbr,
-                NULL,      NULL,      NULL,      emu_fidbr,
-                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,      NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_sfpc,  NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_efpc,  NULL,      NULL,      NULL,
-                NULL,      NULL,      NULL,      NULL,
-                emu_cefbr, emu_cdfbr, emu_cxfbr, NULL,
-                emu_cfebr, emu_cfdbr, emu_cfxbr
-        };
-
-        switch (format_table[opcode[1]]) {
-        case 1: /* RRE format, double operation */
-                emu_store_regd((opcode[3]>>4)&15);
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-		emu_load_regd((opcode[3]>>4)&15);
-		emu_load_regd(opcode[3]&15);
-                return rc;
-        case 2: /* RRE format, float operation */
-                emu_store_rege((opcode[3]>>4)&15);
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-		emu_load_rege((opcode[3]>>4)&15);
-		emu_load_rege(opcode[3]&15);
-                return rc;
-        case 3: /* RRF format, double operation */
-                emu_store_regd((opcode[3]>>4)&15);
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-		emu_load_regd((opcode[3]>>4)&15);
-		emu_load_regd(opcode[3]&15);
-		return rc;
-        case 4: /* RRF format, float operation */
-                emu_store_rege((opcode[3]>>4)&15);
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-		emu_load_rege((opcode[3]>>4)&15);
-		emu_load_rege(opcode[3]&15);
-                return rc;
-        case 5: /* RRE format, cefbr instruction */
-                emu_store_rege((opcode[3]>>4)&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-		emu_load_rege((opcode[3]>>4)&15);
-                return rc;
-        case 6: /* RRE format, cdfbr & cxfbr instruction */
-                emu_store_regd((opcode[3]>>4)&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-		emu_load_regd((opcode[3]>>4)&15);
-                return rc;
-	case 7: /* RRF format, cfebr instruction */
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                return rc;
-        case 8: /* RRF format, cfdbr & cfxbr instruction */
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                return rc;
-	case 9: /* RRE format, ldebr & mdebr instruction */
-		/* float store but double load */
-                emu_store_rege((opcode[3]>>4)&15);
-                emu_store_rege(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-		emu_load_regd((opcode[3]>>4)&15);
-                return rc;
-        case 10: /* RRE format, ledbr instruction */
-		/* double store but float load */
-                emu_store_regd((opcode[3]>>4)&15);
-                emu_store_regd(opcode[3]&15);
-                /* call the emulation function */
-                rc=((int (*)(int, int))jump_table[opcode[1]])
-                        (opcode[3]>>4,opcode[3]&15);
-		emu_load_rege((opcode[3]>>4)&15);
-                return rc;
-        default:
-                return 1;
-        }
-}
-
-static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
-{
-  rx &= 0xf;
-  rb &= 0xf;
-  disp &= 0xfff;
-  return (void*) ((rx != 0 ? regs->gprs[rx] : 0)  + /* index */   
-         (rb != 0 ? regs->gprs[rb] : 0)  + /* base */
-         disp);
-}
-    
-int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
-	int rc=0;
-
-        static const __u8 format_table[] = {
-                0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
-                2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
-                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,
-                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,
-                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,
-                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
-        };
-        static const void *jump_table[]= {
-                NULL,     NULL,     NULL,     NULL,
-                emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb,
-                emu_keb,  emu_ceb,  emu_aeb,  emu_seb,
-                emu_mdeb, emu_deb,  emu_maeb, emu_mseb,
-                emu_tceb, emu_tcdb, emu_tcxb, NULL,
-                emu_sqeb, emu_sqdb, NULL,     emu_meeb,
-                emu_kdb,  emu_cdb,  emu_adb,  emu_sdb,
-                emu_mdb,  emu_ddb,  emu_madb, emu_msdb
-        };
-
-        switch (format_table[opcode[5]]) {
-        case 1: /* RXE format, __u64 constant */ {
-                __u64 *dxb, temp;
-                __u32 opc;
-
-                emu_store_regd((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                mathemu_copy_from_user(&temp, dxb, 8);
-                /* call the emulation function */
-                rc=((int (*)(int, __u64))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp);
-		emu_load_regd((opcode[1]>>4)&15);
-                return rc;
-        }
-        case 2: /* RXE format, __u32 constant */ {
-                __u32 *dxb, temp;
-                __u32 opc;
-
-                emu_store_rege((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                mathemu_get_user(temp, dxb);
-                /* call the emulation function */
-                rc=((int (*)(int, __u32))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp);
-		emu_load_rege((opcode[1]>>4)&15);
-                return rc;
-        }
-        case 3: /* RXF format, __u64 constant */ {
-                __u32 *dxb, temp;
-                __u32 opc;
-
-                emu_store_regd((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                 mathemu_copy_from_user(&temp, dxb, 8);
-                /* call the emulation function */
-                rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp,opcode[4]>>4);
-		emu_load_regd((opcode[1]>>4)&15);
-                return rc;
-        }
-        case 4: /* RXF format, __u32 constant */ {
-                __u32 *dxb, temp;
-                __u32 opc;
-
-                emu_store_rege((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                mathemu_get_user(temp, dxb);
-                /* call the emulation function */
-                rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp,opcode[4]>>4);
-                emu_load_rege((opcode[1]>>4)&15);
-                return rc;
-        }
-	case 5: /* RXE format, __u32 constant */
-                /* store_rege and load_regd */ 
-	{
-                __u32 *dxb, temp;
-                __u32 opc;
-                emu_store_rege((opcode[1]>>4)&15);
-                opc = *((__u32 *) opcode);
-                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                mathemu_get_user(temp, dxb);
-                /* call the emulation function */
-                rc=((int (*)(int, __u32))jump_table[opcode[5]])
-                        (opcode[1]>>4,temp);
-                emu_load_regd((opcode[1]>>4)&15);
-                return rc;
-        }
-        default:
-                return 1;
-        }
-}
-
-/*
- * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
- */
-int math_emu_ldr(__u8 *opcode) {
-        __u16 opc = *((__u16 *) opcode);
-
-        if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
-                /* we got an exception therfore ry can't be in {0,2,4,6} */
-                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
-                        "     bras  1,0f\n"
-                        "     ld    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (opc&0x00f0),
-                          "a" (&current->thread.fp_regs.fprs[opc&0x000f].d)
-                        : "1" );
-        } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
-                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
-                        "     bras  1,0f\n"
-                        "     std   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" ((opc&0x000f)<<4),
-                          "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].d)
-                        : "1" );
-        } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
-                current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
-                        current->thread.fp_regs.fprs[opc&0x000f];
-        }
-	return 0;
-}
-
-/*
- * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
- */
-int math_emu_ler(__u8 *opcode) {
-        __u16 opc = *((__u16 *) opcode);
-
-        if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
-                /* we got an exception therfore ry can't be in {0,2,4,6} */
-                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
-                        "     bras  1,0f\n"
-                        "     le    0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" (opc&0x00f0),
-                          "a" (&current->thread.fp_regs.fprs[opc&0x000f].f)
-                        : "1" );
-        } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
-                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
-                        "     bras  1,0f\n"
-                        "     ste   0,0(%1)\n"
-                        "0:   ex    %0,0(1)"
-                        : /* no output */
-                        : "a" ((opc&0x000f)<<4),
-                          "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].f)
-                        : "1" );
-        } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
-                current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
-                        current->thread.fp_regs.fprs[opc&0x000f];
-        }
-	return 0;
-}
-
-/*
- * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
- */
-int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u64 *dxb;
-
-        dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        mathemu_copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
-	return 0;
-}
-
-/*
- * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
- */
-int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u32 *mem, *dxb;
-
-        dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
-        mathemu_get_user(mem[0], dxb);
-	return 0;
-}
-
-/*
- * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
- */
-int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u64 *dxb;
-        dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        mathemu_copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
-	return 0;
-}
-
-/*
- * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
- */
-int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
-        __u32 opc = *((__u32 *) opcode);
-        __u32 *mem, *dxb;
-        dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if mathemu_put_user fails ? */
-        mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
-        mathemu_put_user(mem[0], dxb);
-	return 0;
-}
-
-/*
- * Emulate LFPC D(B)
- */
-int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
-	__u32 *dxb,temp;
-	__u32 opc = *((__u32 *) opcode);
-	dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
-	mathemu_get_user(temp, dxb);
-	if(temp!=0)
-		display_emulation_not_implemented("lfpc");
-        return 0;
-}
-
-/*
- * Emulate STFPC D(B)
- */
-int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
-	__u32 *dxb;
-	__u32 opc = *((__u32 *) opcode);
-	dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
-	mathemu_put_user(current->thread.fp_regs.fpc, dxb);
-        return 0;
-}
-
-/*
- * Emulate SRNM D(B)
- */
-int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
-        /* FIXME: how to do that ?!? */
-	display_emulation_not_implemented("srnm");
-        return 0;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- v2.4.3/linux/arch/s390/kernel/process.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/process.c	Wed Apr 11 19:02:28 2001
@@ -42,7 +42,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
-#include <asm/misc390.h>
 #include <asm/irq.h>
 
 spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
@@ -300,12 +299,10 @@
             unsigned long fprs[4];     /* fpr 4 and 6                      */
             unsigned long empty[4];
 #if CONFIG_REMOTE_DEBUG
-	    gdb_pt_regs childregs;
+	    struct gdb_pt_regs childregs;
 #else
-            pt_regs childregs;
+            struct pt_regs childregs;
 #endif
-            __u32   pgm_old_ilc;       /* single step magic from entry.S */
-            __u32   pgm_svc_step;
           } *frame;
 
         frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
@@ -321,7 +318,7 @@
 
         /* fake return stack for resume(), don't go back to schedule */
         frame->gprs[9]  = (unsigned long) frame;
-	frame->pgm_svc_step = 0; /* Nope we aren't single stepping an svc */
+	frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c
--- v2.4.3/linux/arch/s390/kernel/ptrace.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/ptrace.c	Wed Apr 11 19:02:28 2001
@@ -180,9 +180,9 @@
 			copymax=(PT_FPR15_LO+4);
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
 		}
-		else if(useraddr<sizeof(user_regs_struct))
+		else if(useraddr<sizeof(struct user_regs_struct))
 		{
-			copymax=sizeof(user_regs_struct);
+			copymax=sizeof(struct user_regs_struct);
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
 		}
 		else 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c
--- v2.4.3/linux/arch/s390/kernel/s390_ext.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/s390_ext.c	Wed Apr 11 19:02:28 2001
@@ -7,6 +7,7 @@
  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <asm/lowcore.h>
@@ -74,4 +75,6 @@
         return 0;
 }
 
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- v2.4.3/linux/arch/s390/kernel/s390_ksyms.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/s390_ksyms.c	Wed Apr 11 19:02:28 2001
@@ -5,67 +5,14 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/string.h>
-#include <asm/ccwcache.h>
-#include <asm/debug.h>
-#include <asm/irq.h>
-#include <asm/s390_ext.h>
-#include <asm/s390dyn.h>
-#include <asm/ebcdic.h>
 #include <asm/checksum.h>
 #include <asm/delay.h>
-#if CONFIG_CHANDEV
-#include <asm/chandev.h>
-#endif
+#include <asm/setup.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(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_set_level);
-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_ascii_view);
-EXPORT_SYMBOL(debug_raw_view);
-EXPORT_SYMBOL(debug_dflt_header_fn);
-
-/*
  * memory management
  */
 EXPORT_SYMBOL(_oi_bitmap);
@@ -99,42 +46,17 @@
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
-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(module_list);
+EXPORT_SYMBOL(machine_flags);
 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(lowcore_ptr);
-EXPORT_SYMBOL(global_bh_lock);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(smp_ctl_set_bit);
-EXPORT_SYMBOL(smp_ctl_clear_bit);
-#endif
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
-#if CONFIG_CHANDEV
-EXPORT_SYMBOL(chandev_register_and_probe);
-EXPORT_SYMBOL(chandev_request_irq);
-EXPORT_SYMBOL(chandev_unregister);
-EXPORT_SYMBOL(chandev_initdevice);
-EXPORT_SYMBOL(chandev_initnetdevice);
-#endif
+
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigabit ethernet multicast support */
 EXPORT_SYMBOL(arp_mc_map);
 #endif
-EXPORT_SYMBOL(s390_daemonize);
+
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/s390fpu.c linux/arch/s390/kernel/s390fpu.c
--- v2.4.3/linux/arch/s390/kernel/s390fpu.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/s390fpu.c	Wed Apr 11 19:02:28 2001
@@ -57,10 +57,9 @@
 
 void save_fp_regs(s390_fp_regs *fpregs)
 {
-#if CONFIG_IEEEFPU_EMULATION
+#if CONFIG_MATHEMU
 	s390_fp_regs *currentfprs;
-#endif
-#if CONFIG_IEEEFPU_EMULATION
+
 	if(!save_fp_regs1(fpregs))
 	{
 		currentfprs=&current->thread.fp_regs;
@@ -119,11 +118,9 @@
 
 void restore_fp_regs(s390_fp_regs *fpregs)
 {
-#if CONFIG_IEEEFPU_EMULATION
+#if CONFIG_MATHEMU
 	s390_fp_regs *currentfprs;
-#endif
 
-#if CONFIG_IEEEFPU_EMULATION
 	if(!restore_fp_regs1(fpregs))
 	{
 		currentfprs=&current->thread.fp_regs;
@@ -138,15 +135,4 @@
 	restore_fp_regs1(fpregs);
 #endif
 }
-
-
-
-
-
-
-
-
-
-
-
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/semaphore.c linux/arch/s390/kernel/semaphore.c
--- v2.4.3/linux/arch/s390/kernel/semaphore.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -158,145 +158,3 @@
 	spin_unlock_irqrestore(&semaphore_lock, flags);
 	return 1;
 }
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	up_read(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-}
-
-void rwsem_wake_writers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-}
-
-void __down_read_failed(int count, struct rw_semaphore *sem) 
-{
-	do {
-		if (count == -1) {
-			down_read_failed_biased(sem);
-			break;
-		}
-		down_read_failed(sem);
-		count = atomic_dec_return(&sem->count);
-	} while (count != 0);
-}
-
-void __down_write_failed(int count, struct rw_semaphore *sem)
-{
-	do {
-		if (count < 0 && count > -RW_LOCK_BIAS) {
-			down_write_failed_biased(sem);
-			break;
-		}
-		down_write_failed(sem);
-		count = atomic_add_return(-RW_LOCK_BIAS, &sem->count);
-	} while (count != 0);
-}
-
-void __rwsem_wake(int count, struct rw_semaphore *sem)
-{
-	if (count == 0)
-		rwsem_wake_readers(sem);
-	else
-		rwsem_wake_writers(sem);
-}
-
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c
--- v2.4.3/linux/arch/s390/kernel/setup.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/kernel/setup.c	Wed Apr 11 19:02:28 2001
@@ -38,10 +38,13 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
+#include <asm/cpcmd.h>
 
 /*
  * Machine setup..
  */
+unsigned long memory_size = 0;
+unsigned long machine_flags = 0;
 __u16 boot_cpu_addr;
 int cpus_initialized = 0;
 unsigned long cpu_initialized = 0;
@@ -50,17 +53,8 @@
 /*
  * Setup options
  */
-
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;                  /* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;           /* 1 = prompt for ramdisk, 0 = don't prompt*/
-extern int rd_image_start;             /* starting block # of image        */
-#endif
-
-extern int root_mountflags;
 extern int _text,_etext, _edata, _end;
 
-
 /*
  * This is set up by the setup-routine at boot-time
  * for S390 need to find out, what we have to setup
@@ -208,14 +202,9 @@
 	       "This machine has an IEEE fpu\n" :
 	       "This machine has no IEEE fpu\n");
 
-        ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
-#ifdef CONFIG_BLK_DEV_RAM
-        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-        rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-        rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
+        ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
-	memory_end = MEMORY_SIZE;
+	memory_end = memory_size;
         /*
          * We need some free virtual space to be able to do vmalloc.
          * On a machine with 2GB memory we make sure that we have at
@@ -223,8 +212,6 @@
          */
         if (memory_end > 1920*1024*1024)
                 memory_end = 1920*1024*1024;
-        memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
-	memory_end = MEMORY_SIZE;                /* detected in head.s */
         init_mm.start_code = PAGE_OFFSET;
         init_mm.end_code = (unsigned long) &_etext;
         init_mm.end_data = (unsigned long) &_edata;
@@ -311,7 +298,6 @@
          */
         reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
 
-        paging_init();
 #ifdef CONFIG_BLK_DEV_INITRD
         if (INITRD_START) {
 		if (INITRD_START + INITRD_SIZE <= memory_end) {
@@ -326,6 +312,9 @@
 		}
         }
 #endif
+
+        paging_init();
+
 	res = alloc_bootmem_low(sizeof(struct resource));
 	res->start = 0;
 	res->end = memory_end;
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c
--- v2.4.3/linux/arch/s390/kernel/signal.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/kernel/signal.c	Wed Apr 11 19:02:28 2001
@@ -187,7 +187,7 @@
 	int err;
 	s390_fp_regs fpregs;
   
-	err = __copy_to_user(&sregs->regs,regs,sizeof(s390_regs_common));
+	err = __copy_to_user(&sregs->regs,regs,sizeof(_s390_regs_common));
 	if(!err)
 	{
 		save_fp_regs(&fpregs);
@@ -202,7 +202,7 @@
 	int err;
 	s390_fp_regs fpregs;
 	psw_t saved_psw=regs->psw;
-	err=__copy_from_user(regs,&sregs->regs,sizeof(s390_regs_common));
+	err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common));
 	if(!err)
 	{
 		regs->orig_gpr2 = -1;		/* disable syscall checks */
@@ -218,7 +218,7 @@
 }
 
 static int
-restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
+restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 		 _sigregs *sregs,sigset_t *set)
 {
 	unsigned int err;
@@ -555,6 +555,7 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
                                 if (do_coredump(signr, regs))
                                         exit_code |= 0x80;
                                 /* FALLTHRU */
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- v2.4.3/linux/arch/s390/kernel/smp.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/kernel/smp.c	Wed Apr 11 19:02:28 2001
@@ -20,6 +20,7 @@
  * cpu_number_map in other architectures.
  */
 
+#include <linux/module.h>
 #include <linux/init.h>
 
 #include <linux/mm.h>
@@ -33,8 +34,7 @@
 #include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
-
-#include "cpcmd.h"
+#include <asm/cpcmd.h>
 
 /* prototypes */
 extern int cpu_idle(void * unused);
@@ -390,7 +390,7 @@
 
         /* stop all processors */
 
-        smp_signal_others(sigp_stop, 0, TRUE, NULL);
+        smp_signal_others(sigp_stop, 0, 1, NULL);
 
         /* store status of all processors in their lowcores (real 0) */
 
@@ -586,7 +586,7 @@
        struct pt_regs regs;
        /* don't care about the psw and regs settings since we'll never
           reschedule the forked task. */
-       memset(&regs,0,sizeof(pt_regs));
+       memset(&regs,0,sizeof(struct pt_regs));
        return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
 }
 
@@ -772,3 +772,7 @@
         }
 }
 
+EXPORT_SYMBOL(lowcore_ptr);
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
diff -u --recursive --new-file v2.4.3/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c
--- v2.4.3/linux/arch/s390/kernel/traps.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/kernel/traps.c	Wed Apr 11 19:02:28 2001
@@ -35,6 +35,7 @@
 #if CONFIG_REMOTE_DEBUG
 #include <asm/gdb-stub.h>
 #endif
+#include <asm/cpcmd.h>
 
 /* Called from entry.S only */
 extern void handle_per_exception(struct pt_regs *regs);
@@ -51,6 +52,7 @@
 #endif
 
 extern pgm_check_handler_t do_page_fault;
+extern pgm_check_handler_t do_pseudo_page_fault;
 
 spinlock_t die_lock;
 
@@ -140,7 +142,7 @@
 DO_ERROR(SIGILL,  "privileged operation", privileged_op)
 DO_ERROR(SIGILL,  "execute exception", execute_exception)
 DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGILL,  "fixpoint divide exception", divide_exception)
 DO_ERROR(SIGILL,  "translation exception", translation_exception)
 DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
 DO_ERROR(SIGILL,  "operand exception", operand_exception)
@@ -149,7 +151,7 @@
 {
         __u8 opcode[6];
 	__u16 *location;
-	int do_sig = 0;
+	int signal = 0;
 	int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE);
 
         lock_kernel();
@@ -161,82 +163,93 @@
 	if(*((__u16 *)opcode)==S390_BREAKPOINT_U16)
         {
 		if(do_debugger_trap(regs,SIGTRAP))
-			do_sig=1;
+			signal = SIGILL;
 	}
-#ifdef CONFIG_IEEEFPU_EMULATION
-        else if (problem_state )
+#ifdef CONFIG_MATHEMU
+        else if (problem_state)
 	{
 		if (opcode[0] == 0xb3) {
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig = math_emu_b3(opcode, regs);
+			signal = math_emu_b3(opcode, regs);
                 } else if (opcode[0] == 0xed) {
 			get_user(*((__u32 *) (opcode+2)),
 				 (__u32 *)(location+1));
-			do_sig = math_emu_ed(opcode, regs);
+			signal = math_emu_ed(opcode, regs);
 		} else if (*((__u16 *) opcode) == 0xb299) {
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig = math_emu_srnm(opcode, regs);
+			signal = math_emu_srnm(opcode, regs);
 		} else if (*((__u16 *) opcode) == 0xb29c) {
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig = math_emu_stfpc(opcode, regs);
+			signal = math_emu_stfpc(opcode, regs);
 		} else if (*((__u16 *) opcode) == 0xb29d) {
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig = math_emu_lfpc(opcode, regs);
+			signal = math_emu_lfpc(opcode, regs);
 		} else
-			do_sig = 1;
+			signal = SIGILL;
         }
 #endif 
 	else
-		do_sig = 1;
-	if (do_sig)
-		do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
+		signal = SIGILL;
+        if (signal == SIGFPE) {
+		current->thread.ieee_instruction_pointer = (addr_t) location;
+		do_trap(interruption_code, signal,
+			"floating point exception", regs, NULL);
+        } else if (signal)
+		do_trap(interruption_code, signal,
+			"illegal operation", regs, NULL);
         unlock_kernel();
 }
 
 
 
-#ifdef CONFIG_IEEEFPU_EMULATION
-asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code)
+#ifdef CONFIG_MATHEMU
+asmlinkage void 
+specification_exception(struct pt_regs * regs, long interruption_code)
 {
         __u8 opcode[6];
 	__u16 *location;
-	int do_sig = 0;
+	int signal = 0;
 
         lock_kernel();
-        if (regs->psw.mask & 0x00010000L) {
+        if (regs->psw.mask & PSW_PROBLEM_STATE) {
 		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
 		case 0x28: /* LDR Rx,Ry   */
-			do_sig=math_emu_ldr(opcode);
+			signal = math_emu_ldr(opcode);
 			break;
 		case 0x38: /* LER Rx,Ry   */
-			do_sig=math_emu_ler(opcode);
+			signal = math_emu_ler(opcode);
 			break;
 		case 0x60: /* STD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_std(opcode, regs);
+			signal = math_emu_std(opcode, regs);
 			break;
 		case 0x68: /* LD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_ld(opcode, regs);
+			signal = math_emu_ld(opcode, regs);
 			break;
 		case 0x70: /* STE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_ste(opcode, regs);
+			signal = math_emu_ste(opcode, regs);
 			break;
 		case 0x78: /* LE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_le(opcode, regs);
+			signal = math_emu_le(opcode, regs);
 			break;
 		default:
-			do_sig = 1;
+			signal = SIGILL;
 			break;
                 }
         } else
-		do_sig = 1;
-        if (do_sig)
-                do_trap(interruption_code, SIGILL, "specification exception", regs, NULL);
+		signal = SIGILL;
+        if (signal == SIGFPE) {
+		current->thread.ieee_instruction_pointer = (addr_t) location;
+		do_trap(interruption_code, signal,
+			"floating point exception", regs, NULL);
+        } else if (signal)
+                do_trap(interruption_code, signal,
+			"specification exception", regs, NULL);
         unlock_kernel();
 }
 #else
@@ -247,80 +260,79 @@
 {
         __u8 opcode[6];
 	__u16 *location;
-	int do_sig = 0;
+	int signal = 0;
 
         lock_kernel();
 	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
-	if(MACHINE_HAS_IEEE)
-	{
+	if (MACHINE_HAS_IEEE)
 		__asm__ volatile ("stfpc %0\n\t" 
 				  : "=m" (current->thread.fp_regs.fpc));
-	}
-	/* Same code should work when we implement fpu emulation */
-	/* provided we call data exception from the fpu emulator */
-	if(current->thread.fp_regs.fpc&FPC_DXC_MASK)
-	{
-		current->thread.ieee_instruction_pointer=(addr_t)location;
-		force_sig(SIGFPE, current);
-	}
-#ifdef CONFIG_IEEEFPU_EMULATION
-        else if (regs->psw.mask & 0x00010000L) {
+
+#ifdef CONFIG_MATHEMU
+        else if (regs->psw.mask & PSW_PROBLEM_STATE) {
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
 		case 0x28: /* LDR Rx,Ry   */
-			do_sig=math_emu_ldr(opcode);
+			signal = math_emu_ldr(opcode);
 			break;
 		case 0x38: /* LER Rx,Ry   */
-			do_sig=math_emu_ler(opcode);
+			signal = math_emu_ler(opcode);
 			break;
 		case 0x60: /* STD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_std(opcode, regs);
+			signal = math_emu_std(opcode, regs);
 			break;
 		case 0x68: /* LD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_ld(opcode, regs);
+			signal = math_emu_ld(opcode, regs);
 			break;
 		case 0x70: /* STE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_ste(opcode, regs);
+			signal = math_emu_ste(opcode, regs);
 			break;
 		case 0x78: /* LE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig=math_emu_le(opcode, regs);
+			signal = math_emu_le(opcode, regs);
 			break;
 		case 0xb3:
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			do_sig = math_emu_b3(opcode, regs);
+			signal = math_emu_b3(opcode, regs);
 			break;
                 case 0xed:
 			get_user(*((__u32 *) (opcode+2)),
 				 (__u32 *)(location+1));
-			do_sig = math_emu_ed(opcode, regs);
+			signal = math_emu_ed(opcode, regs);
 			break;
 	        case 0xb2:
 			if (opcode[1] == 0x99) {
 				get_user(*((__u16 *) (opcode+2)), location+1);
-				do_sig = math_emu_srnm(opcode, regs);
+				signal = math_emu_srnm(opcode, regs);
 			} else if (opcode[1] == 0x9c) {
 				get_user(*((__u16 *) (opcode+2)), location+1);
-				do_sig = math_emu_stfpc(opcode, regs);
+				signal = math_emu_stfpc(opcode, regs);
 			} else if (opcode[1] == 0x9d) {
 				get_user(*((__u16 *) (opcode+2)), location+1);
-				do_sig = math_emu_lfpc(opcode, regs);
+				signal = math_emu_lfpc(opcode, regs);
 			} else
-				do_sig = 1;
+				signal = SIGILL;
 			break;
 		default:
-			do_sig = 1;
+			signal = SIGILL;
 			break;
                 }
         }
 #endif 
+	if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
+		signal = SIGFPE;
 	else
-		do_sig = 1;
-        if (do_sig)
-                do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
+		signal = SIGILL;
+        if (signal == SIGFPE) {
+		current->thread.ieee_instruction_pointer = (addr_t) location;
+		do_trap(interruption_code, signal,
+			"floating point exception", regs, NULL);
+	} else if (signal) 
+                do_trap(interruption_code, signal,
+			"data exception", regs, NULL);
         unlock_kernel();
 }
 
@@ -337,17 +349,20 @@
         pgm_check_table[1] = &illegal_op;
         pgm_check_table[2] = &privileged_op;
         pgm_check_table[3] = &execute_exception;
+        pgm_check_table[4] = &do_page_fault;
         pgm_check_table[5] = &addressing_exception;
         pgm_check_table[6] = &specification_exception;
         pgm_check_table[7] = &data_exception;
         pgm_check_table[9] = &divide_exception;
+        pgm_check_table[0x10] = &do_page_fault;
+        pgm_check_table[0x11] = &do_page_fault;
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
+ 	pgm_check_table[0x14] = &do_pseudo_page_fault;
         pgm_check_table[0x15] = &operand_exception;
-        pgm_check_table[4] = &do_page_fault;
-        pgm_check_table[0x10] = &do_page_fault;
-        pgm_check_table[0x11] = &do_page_fault;
         pgm_check_table[0x1C] = &privileged_op;
+	if (MACHINE_IS_VM)
+	        cpcmd("SET PAGEX ON", NULL, 0);
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/lib/Makefile linux/arch/s390/lib/Makefile
--- v2.4.3/linux/arch/s390/lib/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/lib/Makefile	Wed Apr 11 19:02:28 2001
@@ -12,7 +12,8 @@
 
 L_TARGET = lib.a
 
-obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
+obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o
+export-objs += misaligned.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/lib/checksum.c linux/arch/s390/lib/checksum.c
--- v2.4.3/linux/arch/s390/lib/checksum.c	Fri May 12 11:41:45 2000
+++ linux/arch/s390/lib/checksum.c	Wed Apr 11 19:02:28 2001
@@ -23,18 +23,17 @@
 unsigned int
 csum_partial (const unsigned char *buff, int len, unsigned int sum)
 {
+	register_pair rp;
 	  /*
 	   * Experiments with ethernet and slip connections show that buff
 	   * is aligned on either a 2-byte or 4-byte boundary.
 	   */
+	rp.subreg.even = (unsigned long) buff;
+	rp.subreg.odd = (unsigned long) len;
         __asm__ __volatile__ (
-                "    lr   2,%1\n"    /* address in gpr 2 */
-                "    lr   3,%2\n"    /* length in gpr 3 */
-                "0:  cksm %0,2\n"    /* do checksum on longs */
+                "0:  cksm %0,%1\n"    /* do checksum on longs */
                 "    jo   0b\n"
-                : "+&d" (sum)
-                : "d" (buff), "d" (len)
-                : "cc", "2", "3" );
+                : "+&d" (sum), "+&a" (rp) : : "cc" );
         return sum;
 }
 
@@ -43,14 +42,16 @@
  */
 unsigned short csum_fold(unsigned int sum)
 {
-        __asm__ __volatile__ (
-                "    sr   3,3\n"   /* %0 = H*65536 + L */
-                "    lr   2,%0\n"  /* %0 = H L, R2/R3 = H L / 0 0 */
-                "    srdl 2,16\n"  /* %0 = H L, R2/R3 = 0 H / L 0 */
-                "    alr  2,3\n"   /* %0 = H L, R2/R3 = L H / L 0 */
-                "    alr  %0,2\n"  /* %0 = H+L+C L+H */
-                "    srl  %0,16\n" /* %0 = H+L+C */
-                : "+d" (sum) : : "cc", "2", "3");
-        return ((unsigned short) ~sum);
+	register_pair rp;
+
+	__asm__ __volatile__ (
+		"    slr  %N1,%N1\n" /* %0 = H L */
+		"    lr   %1,%0\n"   /* %0 = H L, %1 = H L 0 0 */
+		"    srdl %1,16\n"   /* %0 = H L, %1 = 0 H L 0 */
+		"    alr  %1,%N1\n"  /* %0 = H L, %1 = L H L 0 */
+		"    alr  %0,%1\n"   /* %0 = H+L+C L+H */
+		"    srl  %0,16\n"   /* %0 = H+L+C */
+		: "+&d" (sum), "=d" (rp) : : "cc" );
+	return ((unsigned short) ~sum);
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390/lib/misaligned.c linux/arch/s390/lib/misaligned.c
--- v2.4.3/linux/arch/s390/lib/misaligned.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/lib/misaligned.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,29 @@
+/*
+ *  arch/s390/lib/misaligned.c
+ *    S390 misalignment panic stubs
+ *
+ *  S390 version
+ *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com).
+ *
+ * xchg wants to panic if the pointer is not aligned. To avoid multiplying
+ * the panic message over and over again, the panic is done in the helper
+ * functions __misaligned_u32 and __misaligned_u16.
+ */
+
+#include <linux/module.h> 
+#include <linux/kernel.h>
+
+void __misaligned_u16(void)
+{
+	panic("misaligned (__u16 *) in __xchg\n");
+}
+
+void __misaligned_u32(void)
+{
+	panic("misaligned (__u32 *) in __xchg\n");
+}
+
+EXPORT_SYMBOL(__misaligned_u16);
+EXPORT_SYMBOL(__misaligned_u32);
+
diff -u --recursive --new-file v2.4.3/linux/arch/s390/math-emu/Makefile linux/arch/s390/math-emu/Makefile
--- v2.4.3/linux/arch/s390/math-emu/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/math-emu/Makefile	Wed Apr 11 19:02:27 2001
@@ -0,0 +1,12 @@
+#
+# Makefile for the FPU instruction emulation.
+#
+
+O_TARGET := math-emu.o
+obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
+
+EXTRA_CFLAGS = -I. -I$(TOPDIR)/include/math-emu -w
+
+include $(TOPDIR)/Rules.make
+
+
diff -u --recursive --new-file v2.4.3/linux/arch/s390/math-emu/math.c linux/arch/s390/math-emu/math.c
--- v2.4.3/linux/arch/s390/math-emu/math.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/math-emu/math.c	Thu Apr 12 12:16:35 2001
@@ -0,0 +1,2152 @@
+/*
+ *  arch/s390/math-emu/math.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * 'math.c' emulates IEEE instructions on a S390 processor
+ *          that does not have the IEEE fpu (all processors before G5).
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+#include "sfp-util.h"
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+#include <math-emu/quad.h>
+
+/*
+ * I miss a macro to round a floating point number to the
+ * nearest integer in the same floating point format.
+ */
+#define _FP_TO_FPINT_ROUND(fs, wc, X)					\
+  do {									\
+    switch (X##_c)							\
+      {									\
+      case FP_CLS_NORMAL:						\
+        if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs)		\
+          { /* floating point number has no bits after the dot. */	\
+          }								\
+        else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs &&	\
+                 X##_e > _FP_EXPBIAS_##fs)				\
+	  { /* some bits before the dot, some after it. */		\
+            _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs,			\
+                              X##_e - _FP_EXPBIAS_##fs			\
+                              + _FP_FRACBITS_##fs);			\
+	    _FP_ROUND(wc, X);						\
+	    _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs		\
+                              + _FP_FRACBITS_##fs);			\
+          }								\
+        else								\
+          { /* all bits after the dot. */				\
+	    FP_SET_EXCEPTION(FP_EX_INEXACT);				\
+            X##_c = FP_CLS_ZERO;					\
+	  }								\
+        break;								\
+      case FP_CLS_NAN:							\
+      case FP_CLS_INF:							\
+      case FP_CLS_ZERO:							\
+        break;								\
+      }									\
+  } while (0)
+
+#define FP_TO_FPINT_ROUND_S(X)	_FP_TO_FPINT_ROUND(S,1,X)
+#define FP_TO_FPINT_ROUND_D(X)	_FP_TO_FPINT_ROUND(D,2,X)
+#define FP_TO_FPINT_ROUND_Q(X)	_FP_TO_FPINT_ROUND(Q,4,X)
+
+typedef union {
+        long double ld;
+        struct {
+                __u64 high;
+                __u64 low;
+        } w;
+} mathemu_ldcv;
+
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+#define mathemu_put_user(x, p) \
+        do { \
+                if (put_user((x),(p))) \
+                        return SIGSEGV; \
+        } while (0)
+
+#define mathemu_get_user(x, p) \
+        do { \
+                if (get_user((x),(p))) \
+                        return SIGSEGV; \
+        } while (0)
+
+#define mathemu_copy_from_user(d, s, n)\
+        do { \
+                if (copy_from_user((d),(s),(n)) == -EFAULT) \
+                        return SIGSEGV; \
+        } while (0)
+
+#define mathemu_copy_to_user(d, s, n) \
+        do { \
+                if (copy_to_user((d),(s),(n)) == -EFAULT) \
+                        return SIGSEGV; \
+        } while (0)
+
+static void display_emulation_not_implemented(char *instr)
+{
+        struct pt_regs *regs;
+        __u16 *location;
+        
+#if CONFIG_SYSCTL
+        if(sysctl_ieee_emulation_warnings)
+#endif
+        {
+                regs = current->thread.regs;
+                location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+                printk("%s ieee fpu instruction not emulated "
+                       "process name: %s pid: %d \n",
+                       instr, current->comm, current->pid);
+                printk("%s's PSW:    %08lx %08lx\n", instr,
+                       (unsigned long) regs->psw.mask,
+                       (unsigned long) location);
+        }
+}
+
+static inline void emu_set_CC (int cc)
+{
+        current->thread.regs->psw.mask = 
+		(current->thread.regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);
+}
+
+/*
+ * Set the condition code in the user psw.
+ *  0 : Result is zero
+ *  1 : Result is less than zero
+ *  2 : Result is greater than zero
+ *  3 : Result is NaN or INF
+ */
+static inline void emu_set_CC_cs(int class, int sign)
+{
+        switch (class) {
+        case FP_CLS_NORMAL:
+        case FP_CLS_INF:
+                emu_set_CC(sign ? 1 : 2);
+                break;
+        case FP_CLS_ZERO:
+                emu_set_CC(0);
+                break;
+        case FP_CLS_NAN:
+                emu_set_CC(3);
+                break;
+        }
+}
+
+/* Add long double */
+static int emu_axbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QB, &cvt.ld);
+        FP_ADD_Q(QR, QA, QB);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        emu_set_CC_cs(QR_c, QR_s);
+        return _fex;
+}
+
+/* Add double */
+static int emu_adbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_ADD_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Add double */
+static int emu_adb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, val);
+        FP_ADD_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Add float */
+static int emu_aebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_ADD_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Add float */
+static int emu_aeb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, val);
+        FP_ADD_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Compare long double */
+static int emu_cxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB);
+	mathemu_ldcv cvt;
+        int IR;
+
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_RAW_QP(QA, &cvt.ld);
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_RAW_QP(QB, &cvt.ld);
+        FP_CMP_Q(IR, QA, QB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        return 0;
+}
+
+/* Compare double */
+static int emu_cdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DB);
+        int IR;
+
+        FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_CMP_D(IR, DA, DB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        return 0;
+}
+
+/* Compare double */
+static int emu_cdb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DB);
+        int IR;
+
+        FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_RAW_DP(DB, val);
+        FP_CMP_D(IR, DA, DB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        return 0;
+}
+
+/* Compare float */
+static int emu_cebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SB);
+        int IR;
+
+        FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_CMP_S(IR, SA, SB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        return 0;
+}
+
+/* Compare float */
+static int emu_ceb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SB);
+        int IR;
+
+        FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_RAW_SP(SB, val);
+        FP_CMP_S(IR, SA, SB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        return 0;
+}
+
+/* Compare and signal long double */
+static int emu_kxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int IR;
+
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_RAW_QP(QA, &cvt.ld);
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QB, &cvt.ld);
+        FP_CMP_Q(IR, QA, QB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        if (IR == 3)
+                FP_SET_EXCEPTION (FP_EX_INVALID);
+        return _fex;
+}
+
+/* Compare and signal double */
+static int emu_kdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DB);
+        FP_DECL_EX;
+        int IR;
+
+        FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_CMP_D(IR, DA, DB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        if (IR == 3)
+                FP_SET_EXCEPTION (FP_EX_INVALID);
+        return _fex;
+}
+
+/* Compare and signal double */
+static int emu_kdb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DB);
+        FP_DECL_EX;
+        int IR;
+
+        FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_RAW_DP(DB, val);
+        FP_CMP_D(IR, DA, DB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        if (IR == 3)
+                FP_SET_EXCEPTION (FP_EX_INVALID);
+        return _fex;
+}
+
+/* Compare and signal float */
+static int emu_kebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SB);
+        FP_DECL_EX;
+        int IR;
+
+        FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_CMP_S(IR, SA, SB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        if (IR == 3)
+                FP_SET_EXCEPTION (FP_EX_INVALID);
+        return _fex;
+}
+
+/* Compare and signal float */
+static int emu_keb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SB);
+        FP_DECL_EX;
+        int IR;
+
+        FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_RAW_SP(SB, val);
+        FP_CMP_S(IR, SA, SB, 3);
+        /*
+         * IR == -1 if DA < DB, IR == 0 if DA == DB,
+         * IR == 1 if DA > DB and IR == 3 if unorderded
+         */
+        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        if (IR == 3)
+                FP_SET_EXCEPTION (FP_EX_INVALID);
+        return _fex;
+}
+
+/* Convert from fixed long double */
+static int emu_cxfbr (int rx, int ry) {
+        FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        __s32 si;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        si = current->thread.regs->gprs[ry];
+        FP_FROM_INT_Q(QR, si, 32, int);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Convert from fixed double */
+static int emu_cdfbr (int rx, int ry) {
+        FP_DECL_D(DR);
+        FP_DECL_EX;
+        __s32 si;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        si = current->thread.regs->gprs[ry];
+        FP_FROM_INT_D(DR, si, 32, int);
+        FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Convert from fixed float */
+static int emu_cefbr (int rx, int ry) {
+        FP_DECL_S(SR);
+        FP_DECL_EX;
+        __s32 si;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        si = current->thread.regs->gprs[ry];
+        FP_FROM_INT_S(SR, si, 32, int);
+        FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Convert to fixed long double */
+static int emu_cfxbr (int rx, int ry, int mask) {
+        FP_DECL_Q(QA);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        __s32 si;
+        int mode;
+
+	if (mask == 0)
+		mode = current->thread.fp_regs.fpc & 3;
+	else if (mask == 1)
+		mode = FP_RND_NEAREST;
+	else
+		mode = mask - 4;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        FP_TO_INT_ROUND_Q(si, QA, 32, 1);
+        current->thread.regs->gprs[rx] = si;
+        emu_set_CC_cs(QA_c, QA_s);
+        return _fex;
+}
+
+/* Convert to fixed double */
+static int emu_cfdbr (int rx, int ry, int mask) {
+        FP_DECL_D(DA);
+        FP_DECL_EX;
+        __s32 si;
+        int mode;
+
+	if (mask == 0)
+		mode = current->thread.fp_regs.fpc & 3;
+	else if (mask == 1)
+		mode = FP_RND_NEAREST;
+	else
+		mode = mask - 4;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+        FP_TO_INT_ROUND_D(si, DA, 32, 1);
+        current->thread.regs->gprs[rx] = si;
+        emu_set_CC_cs(DA_c, DA_s);
+        return _fex;
+}
+
+/* Convert to fixed float */
+static int emu_cfebr (int rx, int ry, int mask) {
+        FP_DECL_S(SA);
+        FP_DECL_EX;
+        __s32 si;
+        int mode;
+
+	if (mask == 0)
+		mode = current->thread.fp_regs.fpc & 3;
+	else if (mask == 1)
+		mode = FP_RND_NEAREST;
+	else
+		mode = mask - 4;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+        FP_TO_INT_ROUND_S(si, SA, 32, 1);
+        current->thread.regs->gprs[rx] = si;
+        emu_set_CC_cs(SA_c, SA_s);
+        return _fex;
+}
+
+/* Divide long double */
+static int emu_dxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QB, &cvt.ld);
+        FP_DIV_Q(QR, QA, QB);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Divide double */
+static int emu_ddbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_DIV_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Divide double */
+static int emu_ddb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, val);
+        FP_DIV_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Divide float */
+static int emu_debr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_DIV_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Divide float */
+static int emu_deb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, val);
+        FP_DIV_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Divide to integer double */
+static int emu_didbr (int rx, int ry, int mask) {
+        display_emulation_not_implemented("didbr");
+        return 0;
+}
+
+/* Divide to integer float */
+static int emu_diebr (int rx, int ry, int mask) {
+        display_emulation_not_implemented("diebr");
+        return 0;
+}
+
+/* Extract fpc */
+static int emu_efpc (int rx, int ry) {
+        current->thread.regs->gprs[rx] = current->thread.fp_regs.fpc;
+        return 0;
+}
+
+/* Load and test long double */
+static int emu_ltxbr (int rx, int ry) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+	mathemu_ldcv cvt;
+        FP_DECL_Q(QA);
+        FP_DECL_EX;
+
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
+        fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui;
+        emu_set_CC_cs(QA_c, QA_s);
+        return _fex;
+}
+
+/* Load and test double */
+static int emu_ltdbr (int rx, int ry) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        FP_DECL_D(DA);
+        FP_DECL_EX;
+
+        FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
+        fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
+        emu_set_CC_cs(DA_c, DA_s);
+        return _fex;
+}
+
+/* Load and test double */
+static int emu_ltebr (int rx, int ry) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        FP_DECL_S(SA);
+        FP_DECL_EX;
+
+        FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
+        fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
+        emu_set_CC_cs(SA_c, SA_s);
+        return _fex;
+}
+
+/* Load complement long double */
+static int emu_lcxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+	FP_NEG_Q(QR, QA);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        emu_set_CC_cs(QR_c, QR_s);
+        return _fex;
+}
+
+/* Load complement double */
+static int emu_lcdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+	FP_NEG_D(DR, DA);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Load complement float */
+static int emu_lcebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+	FP_NEG_S(SR, SA);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Load floating point integer long double */
+static int emu_fixbr (int rx, int ry, int mask) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        FP_DECL_Q(QA);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        __s32 si;
+        int mode;
+
+	if (mask == 0)
+		mode = fp_regs->fpc & 3;
+	else if (mask == 1)
+		mode = FP_RND_NEAREST;
+	else
+		mode = mask - 4;
+        cvt.w.high = fp_regs->fprs[ry].ui;
+        cvt.w.low = fp_regs->fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+	FP_TO_FPINT_ROUND_Q(QA);
+	FP_PACK_QP(&cvt.ld, QA);
+	fp_regs->fprs[rx].ui = cvt.w.high;
+	fp_regs->fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Load floating point integer double */
+static int emu_fidbr (int rx, int ry, int mask) {
+	/* FIXME: rounding mode !! */
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        FP_DECL_D(DA);
+        FP_DECL_EX;
+        __s32 si;
+        int mode;
+
+	if (mask == 0)
+		mode = fp_regs->fpc & 3;
+	else if (mask == 1)
+		mode = FP_RND_NEAREST;
+	else
+		mode = mask - 4;
+        FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
+	FP_TO_FPINT_ROUND_D(DA);
+	FP_PACK_DP(&fp_regs->fprs[rx].d, DA);
+        return _fex;
+}
+
+/* Load floating point integer float */
+static int emu_fiebr (int rx, int ry, int mask) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        FP_DECL_S(SA);
+        FP_DECL_EX;
+        __s32 si;
+        int mode;
+
+	if (mask == 0)
+		mode = fp_regs->fpc & 3;
+	else if (mask == 1)
+		mode = FP_RND_NEAREST;
+	else
+		mode = mask - 4;
+        FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
+	FP_TO_FPINT_ROUND_S(SA);
+	FP_PACK_SP(&fp_regs->fprs[rx].f, SA);
+        return _fex;
+}
+
+/* Load lengthened double to long double */
+static int emu_lxdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+	FP_CONV (Q, D, 4, 2, QR, DA);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Load lengthened double to long double */
+static int emu_lxdb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, val);
+	FP_CONV (Q, D, 4, 2, QR, DA);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Load lengthened float to long double */
+static int emu_lxebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+	FP_CONV (Q, S, 4, 1, QR, SA);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Load lengthened float to long double */
+static int emu_lxeb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, val);
+	FP_CONV (Q, S, 4, 1, QR, SA);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Load lengthened float to double */
+static int emu_ldebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_D(DR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+	FP_CONV (D, S, 2, 1, DR, SA);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Load lengthened float to double */
+static int emu_ldeb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_D(DR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, val);
+	FP_CONV (D, S, 2, 1, DR, SA);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Load negative long double */
+static int emu_lnxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        if (QA_s == 0) {
+		FP_NEG_Q(QR, QA);
+		FP_PACK_QP(&cvt.ld, QR);
+		current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+		current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+	} else {
+		current->thread.fp_regs.fprs[rx].ui =
+			current->thread.fp_regs.fprs[ry].ui;
+		current->thread.fp_regs.fprs[rx+2].ui =
+			current->thread.fp_regs.fprs[ry+2].ui;
+	}
+	emu_set_CC_cs(QR_c, QR_s);
+        return _fex;
+}
+
+/* Load negative double */
+static int emu_lndbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+        if (DA_s == 0) {
+		FP_NEG_D(DR, DA);
+		FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+	} else
+		current->thread.fp_regs.fprs[rx].ui =
+			current->thread.fp_regs.fprs[ry].ui;
+	emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Load negative float */
+static int emu_lnebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+        if (SA_s == 0) {
+		FP_NEG_S(SR, SA);
+		FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+	} else
+		current->thread.fp_regs.fprs[rx].ui =
+			current->thread.fp_regs.fprs[ry].ui;
+	emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Load positive long double */
+static int emu_lpxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        if (QA_s != 0) {
+		FP_NEG_Q(QR, QA);
+		FP_PACK_QP(&cvt.ld, QR);
+		current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+		current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+	} else{
+		current->thread.fp_regs.fprs[rx].ui =
+			current->thread.fp_regs.fprs[ry].ui;
+		current->thread.fp_regs.fprs[rx+2].ui =
+			current->thread.fp_regs.fprs[ry+2].ui;
+	}
+	emu_set_CC_cs(QR_c, QR_s);
+        return _fex;
+}
+
+/* Load positive double */
+static int emu_lpdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+        if (DA_s != 0) {
+		FP_NEG_D(DR, DA);
+		FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+	} else
+		current->thread.fp_regs.fprs[rx].ui =
+			current->thread.fp_regs.fprs[ry].ui;
+	emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Load positive float */
+static int emu_lpebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+        if (SA_s != 0) {
+		FP_NEG_S(SR, SA);
+		FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+	} else
+		current->thread.fp_regs.fprs[rx].ui =
+			current->thread.fp_regs.fprs[ry].ui;
+	emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Load rounded long double to double */
+static int emu_ldxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_D(DR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+	FP_CONV (D, Q, 2, 4, DR, QA);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].f, DR);
+        return _fex;
+}
+
+/* Load rounded long double to float */
+static int emu_lexbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_S(SR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+	FP_CONV (S, Q, 1, 4, SR, QA);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Load rounded double to float */
+static int emu_ledbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_S(SR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+	FP_CONV (S, D, 1, 2, SR, DA);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Multiply long double */
+static int emu_mxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QB, &cvt.ld);
+        FP_MUL_Q(QR, QA, QB);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Multiply double */
+static int emu_mdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_MUL_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Multiply double */
+static int emu_mdb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, val);
+        FP_MUL_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Multiply double to long double */
+static int emu_mxdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+	FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+	FP_CONV (Q, D, 4, 2, QA, DA);
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+	FP_CONV (Q, D, 4, 2, QB, DA);
+        FP_MUL_Q(QR, QA, QB);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Multiply double to long double */
+static int emu_mxdb (int rx, long double *val) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        FP_UNPACK_QP(QB, val);
+        FP_MUL_Q(QR, QA, QB);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        return _fex;
+}
+
+/* Multiply float */
+static int emu_meebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_MUL_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Multiply float */
+static int emu_meeb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, val);
+        FP_MUL_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        return _fex;
+}
+
+/* Multiply float to double */
+static int emu_mdebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+	FP_CONV (D, S, 2, 1, DA, SA);
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+	FP_CONV (D, S, 2, 1, DB, SA);
+        FP_MUL_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Multiply float to double */
+static int emu_mdeb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+	FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+	FP_CONV (D, S, 2, 1, DA, SA);
+        FP_UNPACK_SP(SA, val);
+	FP_CONV (D, S, 2, 1, DB, SA);
+        FP_MUL_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        return _fex;
+}
+
+/* Multiply and add double */
+static int emu_madbr (int rx, int ry, int rz) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+        FP_MUL_D(DR, DA, DB);
+        FP_ADD_D(DR, DR, DC);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+        return _fex;
+}
+
+/* Multiply and add double */
+static int emu_madb (int rx, double *val, int rz) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, val);
+        FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+        FP_MUL_D(DR, DA, DB);
+        FP_ADD_D(DR, DR, DC);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+        return _fex;
+}
+
+/* Multiply and add float */
+static int emu_maebr (int rx, int ry, int rz) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+        FP_MUL_S(SR, SA, SB);
+        FP_ADD_S(SR, SR, SC);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+        return _fex;
+}
+
+/* Multiply and add float */
+static int emu_maeb (int rx, float *val, int rz) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, val);
+        FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+        FP_MUL_S(SR, SA, SB);
+        FP_ADD_S(SR, SR, SC);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+        return _fex;
+}
+
+/* Multiply and subtract double */
+static int emu_msdbr (int rx, int ry, int rz) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+        FP_MUL_D(DR, DA, DB);
+        FP_SUB_D(DR, DR, DC);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+        return _fex;
+}
+
+/* Multiply and subtract double */
+static int emu_msdb (int rx, double *val, int rz) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, val);
+        FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+        FP_MUL_D(DR, DA, DB);
+        FP_SUB_D(DR, DR, DC);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+        return _fex;
+}
+
+/* Multiply and subtract float */
+static int emu_msebr (int rx, int ry, int rz) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+        FP_MUL_S(SR, SA, SB);
+        FP_SUB_S(SR, SR, SC);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+        return _fex;
+}
+
+/* Multiply and subtract float */
+static int emu_mseb (int rx, float *val, int rz) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, val);
+        FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+        FP_MUL_S(SR, SA, SB);
+        FP_SUB_S(SR, SR, SC);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+        return _fex;
+}
+
+/* Set floating point control word */
+static int emu_sfpc (int rx, int ry) {
+        __u32 temp;
+
+        temp = current->thread.regs->gprs[rx];
+        if ((temp & ~FPC_VALID_MASK) != 0)
+		return SIGILL;
+	current->thread.fp_regs.fpc = temp;
+        return 0;
+}
+
+/* Square root long double */
+static int emu_sqxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+	FP_SQRT_Q(QR, QA);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        emu_set_CC_cs(QR_c, QR_s);
+        return _fex;
+}
+
+/* Square root double */
+static int emu_sqdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+	FP_SQRT_D(DR, DA);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Square root double */
+static int emu_sqdb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, val);
+	FP_SQRT_D(DR, DA);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Square root float */
+static int emu_sqebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+	FP_SQRT_S(SR, SA);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Square root float */
+static int emu_sqeb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, val);
+	FP_SQRT_S(SR, SA);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Subtract long double */
+static int emu_sxbr (int rx, int ry) {
+        FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+        FP_DECL_EX;
+	mathemu_ldcv cvt;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+        FP_UNPACK_QP(QA, &cvt.ld);
+        cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+        cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+        FP_UNPACK_QP(QB, &cvt.ld);
+        FP_SUB_Q(QR, QA, QB);
+        FP_PACK_QP(&cvt.ld, QR);
+        current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+        current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+        emu_set_CC_cs(QR_c, QR_s);
+        return _fex;
+}
+
+/* Subtract double */
+static int emu_sdbr (int rx, int ry) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+        FP_SUB_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Subtract double */
+static int emu_sdb (int rx, double *val) {
+        FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+        FP_UNPACK_DP(DB, val);
+        FP_SUB_D(DR, DA, DB);
+	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+        emu_set_CC_cs(DR_c, DR_s);
+        return _fex;
+}
+
+/* Subtract float */
+static int emu_sebr (int rx, int ry) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+        FP_SUB_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Subtract float */
+static int emu_seb (int rx, float *val) {
+        FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+        FP_DECL_EX;
+        int mode;
+
+	mode = current->thread.fp_regs.fpc & 3;
+        FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+        FP_UNPACK_SP(SB, val);
+        FP_SUB_S(SR, SA, SB);
+	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+        emu_set_CC_cs(SR_c, SR_s);
+        return _fex;
+}
+
+/* Test data class long double */
+static int emu_tcxb (int rx, double *val) {
+        display_emulation_not_implemented("tcxb");
+        return 0;
+}
+
+/* Test data class double */
+static int emu_tcdb (int rx, double *val) {
+        display_emulation_not_implemented("tcdb");
+        return 0;
+}
+
+/* Test data class float */
+static int emu_tceb (int rx, __u32 val) {
+        display_emulation_not_implemented("tceb");
+        return 0;
+}
+
+static inline void emu_load_regd(int reg) {
+        if ((reg&9) != 0)         /* test if reg in {0,2,4,6} */
+                return;
+        asm volatile (            /* load reg from fp_regs.fprs[reg] */
+                "     bras  1,0f\n"
+                "     ld    0,0(%1)\n"
+                "0:   ex    %0,0(1)"
+                : /* no output */
+                : "a" (reg<<4),"a" (&current->thread.fp_regs.fprs[reg].d)
+                : "1" );
+}
+
+static inline void emu_load_rege(int reg) {
+        if ((reg&9) != 0)         /* test if reg in {0,2,4,6} */
+                return;
+        asm volatile (            /* load reg from fp_regs.fprs[reg] */
+                "     bras  1,0f\n"
+                "     le    0,0(%1)\n"
+                "0:   ex    %0,0(1)"
+                : /* no output */
+                : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+                : "1" );
+}
+
+static inline void emu_store_regd(int reg) {
+        if ((reg&9) != 0)         /* test if reg in {0,2,4,6} */
+                return;
+        asm volatile (            /* store reg to fp_regs.fprs[reg] */
+                "     bras  1,0f\n"
+                "     std   0,0(%1)\n"
+                "0:   ex    %0,0(1)"
+                : /* no output */
+                : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
+                : "1" );
+}
+
+
+static inline void emu_store_rege(int reg) {
+        if ((reg&9) != 0)         /* test if reg in {0,2,4,6} */
+                return;
+        asm volatile (            /* store reg to fp_regs.fprs[reg] */
+                "     bras  1,0f\n"
+                "     ste   0,0(%1)\n"
+                "0:   ex    %0,0(1)"
+                : /* no output */
+                : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+                : "1" );
+}
+
+int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+        int _fex = 0;
+        static const __u8 format_table[256] = {
+                [0x00] = 0x03,[0x01] = 0x03,[0x02] = 0x03,[0x03] = 0x03,
+		[0x04] = 0x0f,[0x05] = 0x0d,[0x06] = 0x0e,[0x07] = 0x0d,
+		[0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03,
+                [0x0c] = 0x0f,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06,
+		[0x10] = 0x02,[0x11] = 0x02,[0x12] = 0x02,[0x13] = 0x02,
+		[0x14] = 0x03,[0x15] = 0x02,[0x16] = 0x01,[0x17] = 0x03,
+                [0x18] = 0x02,[0x19] = 0x02,[0x1a] = 0x02,[0x1b] = 0x02,
+		[0x1c] = 0x02,[0x1d] = 0x02,[0x1e] = 0x05,[0x1f] = 0x05,
+		[0x40] = 0x01,[0x41] = 0x01,[0x42] = 0x01,[0x43] = 0x01,
+                [0x44] = 0x12,[0x45] = 0x0d,[0x46] = 0x11,[0x47] = 0x04,
+		[0x48] = 0x01,[0x49] = 0x01,[0x4a] = 0x01,[0x4b] = 0x01,
+		[0x4c] = 0x01,[0x4d] = 0x01,[0x53] = 0x06,[0x57] = 0x06,
+                [0x5b] = 0x05,[0x5f] = 0x05,[0x84] = 0x13,[0x8c] = 0x13,
+		[0x94] = 0x09,[0x95] = 0x08,[0x96] = 0x07,[0x98] = 0x0c,
+		[0x99] = 0x0b,[0x9a] = 0x0a
+        };
+        static const void *jump_table[256]= {
+                [0x00] = emu_lpebr,[0x01] = emu_lnebr,[0x02] = emu_ltebr,
+                [0x03] = emu_lcebr,[0x04] = emu_ldebr,[0x05] = emu_lxdbr,
+                [0x06] = emu_lxebr,[0x07] = emu_mxdbr,[0x08] = emu_kebr,
+                [0x09] = emu_cebr, [0x0a] = emu_aebr, [0x0b] = emu_sebr,
+                [0x0c] = emu_mdebr,[0x0d] = emu_debr, [0x0e] = emu_maebr,
+                [0x0f] = emu_msebr,[0x10] = emu_lpdbr,[0x11] = emu_lndbr, 
+                [0x12] = emu_ltdbr,[0x13] = emu_lcdbr,[0x14] = emu_sqebr,
+                [0x15] = emu_sqdbr,[0x16] = emu_sqxbr,[0x17] = emu_meebr,
+                [0x18] = emu_kdbr, [0x19] = emu_cdbr, [0x1a] = emu_adbr,
+                [0x1b] = emu_sdbr, [0x1c] = emu_mdbr, [0x1d] = emu_ddbr,  
+                [0x1e] = emu_madbr,[0x1f] = emu_msdbr,[0x40] = emu_lpxbr,
+                [0x41] = emu_lnxbr,[0x42] = emu_ltxbr,[0x43] = emu_lcxbr,
+                [0x44] = emu_ledbr,[0x45] = emu_ldxbr,[0x46] = emu_lexbr,
+                [0x47] = emu_fixbr,[0x48] = emu_kxbr, [0x49] = emu_cxbr,  
+                [0x4a] = emu_axbr, [0x4b] = emu_sxbr, [0x4c] = emu_mxbr,
+                [0x4d] = emu_dxbr, [0x53] = emu_diebr,[0x57] = emu_fiebr,
+                [0x5b] = emu_didbr,[0x5f] = emu_fidbr,[0x84] = emu_sfpc,
+                [0x8c] = emu_efpc, [0x94] = emu_cefbr,[0x95] = emu_cdfbr, 
+                [0x96] = emu_cxfbr,[0x98] = emu_cfebr,[0x99] = emu_cfdbr,
+                [0x9a] = emu_cfxbr
+        };
+
+        switch (format_table[opcode[1]]) {
+        case 1: /* RRE format, long double operation */
+                if (opcode[3] & 0x22)
+			return SIGILL;
+                emu_store_regd((opcode[3] >> 4) & 15);
+                emu_store_regd(((opcode[3] >> 4) & 15) + 2);
+                emu_store_regd(opcode[3] & 15);
+                emu_store_regd((opcode[3] & 15) + 2);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+                emu_load_regd(opcode[3] & 15);
+                emu_load_regd((opcode[3] & 15) + 2);
+		break;
+        case 2: /* RRE format, double operation */
+                emu_store_regd((opcode[3] >> 4) & 15);
+                emu_store_regd(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(opcode[3] & 15);
+		break;
+        case 3: /* RRE format, float operation */
+                emu_store_rege((opcode[3] >> 4) & 15);
+                emu_store_rege(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_rege((opcode[3] >> 4) & 15);
+                emu_load_rege(opcode[3] & 15);
+		break;
+        case 4: /* RRF format, long double operation */
+                if (opcode[3] & 0x22)
+			return SIGILL;
+                emu_store_regd((opcode[3] >> 4) & 15);
+                emu_store_regd(((opcode[3] >> 4) & 15) + 2);
+                emu_store_regd(opcode[3] & 15);
+                emu_store_regd((opcode[3] & 15) + 2);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+                emu_load_regd(opcode[3] & 15);
+                emu_load_regd((opcode[3] & 15) + 2);
+		break;
+        case 5: /* RRF format, double operation */
+                emu_store_regd((opcode[2] >> 4) & 15);
+                emu_store_regd((opcode[3] >> 4) & 15);
+                emu_store_regd(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                emu_load_regd((opcode[2] >> 4) & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(opcode[3] & 15);
+		break;
+        case 6: /* RRF format, float operation */
+                emu_store_rege((opcode[2] >> 4) & 15);
+                emu_store_rege((opcode[3] >> 4) & 15);
+                emu_store_rege(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                emu_load_rege((opcode[2] >> 4) & 15);
+                emu_load_rege((opcode[3] >> 4) & 15);
+                emu_load_rege(opcode[3] & 15);
+		break;
+        case 7: /* RRE format, cxfbr instruction */
+                /* call the emulation function */
+                if (opcode[3] & 0x20)
+			return SIGILL;
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+		break;
+        case 8: /* RRE format, cdfbr instruction */
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+		break;
+        case 9: /* RRE format, cefbr instruction */
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_rege((opcode[3] >> 4) & 15);
+		break;
+        case 10: /* RRF format, cfxbr instruction */
+                if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
+			/* mask of { 2,3,8-15 } is invalid */
+			return SIGILL;
+                if (opcode[3] & 2)
+			return SIGILL;
+                emu_store_regd(opcode[3] & 15);
+                emu_store_regd((opcode[3] & 15) + 2);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+		break;
+        case 11: /* RRF format, cfdbr instruction */
+                if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
+			/* mask of { 2,3,8-15 } is invalid */
+			return SIGILL;
+                emu_store_regd(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+		break;
+        case 12: /* RRF format, cfebr instruction */
+                if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
+			/* mask of { 2,3,8-15 } is invalid */
+			return SIGILL;
+                emu_store_rege(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+		break;
+        case 13: /* RRE format, ldxbr & mdxbr instruction */
+                /* double store but long double load */
+                if (opcode[3] & 0x20)
+			return SIGILL;
+                emu_store_regd((opcode[3] >> 4) & 15);
+                emu_store_regd(opcode[3]  & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+		break;
+        case 14: /* RRE format, ldxbr & mdxbr instruction */
+                /* float store but long double load */
+                if (opcode[3] & 0x20)
+			return SIGILL;
+                emu_store_rege((opcode[3] >> 4) & 15);
+                emu_store_rege(opcode[3]  & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+		break;
+        case 15: /* RRE format, ldebr & mdebr instruction */
+                /* float store but double load */
+                emu_store_rege((opcode[3] >> 4) & 15);
+                emu_store_rege(opcode[3]  & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+		break;
+        case 16: /* RRE format, ldxbr instruction */
+                /* long double store but double load */
+                if (opcode[3] & 2)
+			return SIGILL;
+                emu_store_regd(opcode[3] & 15);
+                emu_store_regd((opcode[3] & 15) + 2);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_regd((opcode[3] >> 4) & 15);
+                break;
+        case 17: /* RRE format, ldxbr instruction */
+                /* long double store but float load */
+                if (opcode[3] & 2)
+			return SIGILL;
+                emu_store_regd(opcode[3] & 15);
+                emu_store_regd((opcode[3] & 15) + 2);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_rege((opcode[3] >> 4) & 15);
+                break;
+        case 18: /* RRE format, ledbr instruction */
+                /* double store but float load */
+                emu_store_regd(opcode[3] & 15);
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                emu_load_rege((opcode[3] >> 4) & 15);
+                break;
+        case 19: /* RRE format, efpc & sfpc instruction */
+                /* call the emulation function */
+                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
+                        (opcode[3] >> 4, opcode[3] & 15);
+                break;
+        default: /* invalid operation */
+                return SIGILL;
+        }
+	if (_fex != 0) {
+		current->thread.fp_regs.fpc |= _fex;
+		if (current->thread.fp_regs.fpc & (_fex << 8))
+			return SIGFPE;
+	}
+	return 0;
+}
+
+static void* calc_addr(struct pt_regs *regs, int rx, int rb, int disp)
+{
+        addr_t addr;
+
+        rx &= 15;
+        rb &= 15;
+        addr = disp & 0xfff;
+        addr += (rx != 0) ? regs->gprs[rx] : 0;  /* + index */
+        addr += (rb != 0) ? regs->gprs[rb] : 0;  /* + base  */
+        return (void*) addr;
+}
+    
+int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+        int _fex = 0;
+
+        static const __u8 format_table[256] = {
+                [0x04] = 0x08,[0x05] = 0x07,[0x06] = 0x09,[0x07] = 0x07,
+		[0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03,
+		[0x0c] = 0x08,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06,
+                [0x10] = 0x03,[0x11] = 0x02,[0x12] = 0x01,[0x14] = 0x03,
+		[0x15] = 0x02,[0x17] = 0x03,[0x18] = 0x02,[0x19] = 0x02,
+		[0x1a] = 0x02,[0x1b] = 0x02,[0x1c] = 0x02,[0x1d] = 0x02,
+                [0x1e] = 0x05,[0x1f] = 0x05,
+        };
+        static const void *jump_table[]= {
+                [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb,
+                [0x07] = emu_mxdb,[0x08] = emu_keb, [0x09] = emu_ceb,
+                [0x0a] = emu_aeb, [0x0b] = emu_seb, [0x0c] = emu_mdeb,
+                [0x0d] = emu_deb, [0x0e] = emu_maeb,[0x0f] = emu_mseb,
+                [0x10] = emu_tceb,[0x11] = emu_tcdb,[0x12] = emu_tcxb,
+                [0x14] = emu_sqeb,[0x15] = emu_sqdb,[0x17] = emu_meeb,
+                [0x18] = emu_kdb, [0x19] = emu_cdb, [0x1a] = emu_adb,
+                [0x1b] = emu_sdb, [0x1c] = emu_mdb, [0x1d] = emu_ddb,
+                [0x1e] = emu_madb,[0x1f] = emu_msdb
+        };
+
+        switch (format_table[opcode[5]]) {
+        case 1: /* RXE format, long double constant */ {
+                __u64 *dxb, temp[2];
+                __u32 opc;
+
+                if ((opcode[1] >> 4) & 2)
+			return SIGILL;
+                emu_store_regd((opcode[1] >> 4) & 15);
+                emu_store_regd(((opcode[1] >> 4) & 15) + 2);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_copy_from_user(&temp, dxb, 16);
+                /* call the emulation function */
+                _fex = ((int (*)(int, long double *)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (long double *) &temp);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+                break;
+        }
+        case 2: /* RXE format, double constant */ {
+                __u64 *dxb, temp;
+                __u32 opc;
+
+                emu_store_regd((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_copy_from_user(&temp, dxb, 8);
+                /* call the emulation function */
+                _fex = ((int (*)(int, double *)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (double *) &temp);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                break;
+        }
+        case 3: /* RXE format, float constant */ {
+                __u32 *dxb, temp;
+                __u32 opc;
+
+                emu_store_rege((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_get_user(temp, dxb);
+                /* call the emulation function */
+                _fex = ((int (*)(int, float *)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (float *) &temp);
+                emu_load_rege((opcode[1] >> 4) & 15);
+                break;
+        }
+        case 4: /* RXF format, long double constant */ {
+                __u64 *dxb, temp[2];
+                __u32 opc;
+
+                if (((opcode[1] >> 4) & 0x20) || ((opcode[4] >> 4) & 0x20))
+			return SIGILL;
+                emu_store_regd((opcode[1] >> 4) & 15);
+                emu_store_regd(((opcode[1] >> 4) & 15) + 2);
+                emu_store_regd((opcode[4] >> 4) & 15);
+                emu_store_regd(((opcode[4] >> 4) & 15) + 2);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_copy_from_user(&temp, dxb, 16);
+                /* call the emulation function */
+                _fex = ((int (*)(int,long double *,int)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+                break;
+        }
+        case 5: /* RXF format, double constant */ {
+                __u64 *dxb, temp;
+                __u32 opc;
+
+                emu_store_regd((opcode[1] >> 4) & 15);
+                emu_store_regd((opcode[4] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_copy_from_user(&temp, dxb, 8);
+                /* call the emulation function */
+                _fex = ((int (*)(int, double *, int)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                break;
+        }
+        case 6: /* RXF format, float constant */ {
+                __u32 *dxb, temp;
+                __u32 opc;
+
+                emu_store_rege((opcode[1] >> 4) & 15);
+                emu_store_rege((opcode[4] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_get_user(temp, dxb);
+                /* call the emulation function */
+                _fex = ((int (*)(int, float *, int)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (float *) &temp, opcode[4] >> 4);
+                emu_load_rege((opcode[4] >> 4) & 15);
+                break;
+        }
+        case 7: /* RXE format, double constant */
+                /* store double and load long double */ 
+        {
+                __u64 *dxb, temp;
+                __u32 opc;
+                if ((opcode[1] >> 4) & 0x20)
+			return SIGILL;
+                emu_store_regd((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_copy_from_user(&temp, dxb, 8);
+                /* call the emulation function */
+                _fex = ((int (*)(int, double *)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (double *) &temp);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+                break;
+        }
+        case 8: /* RXE format, float constant */
+                /* store float and load double */ 
+        {
+                __u32 *dxb, temp;
+                __u32 opc;
+                emu_store_rege((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_get_user(temp, dxb);
+                /* call the emulation function */
+                _fex = ((int (*)(int, float *)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (float *) &temp);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                break;
+        }
+        case 9: /* RXE format, float constant */
+                /* store float and load long double */ 
+        {
+                __u32 *dxb, temp;
+                __u32 opc;
+                if ((opcode[1] >> 4) & 0x20)
+			return SIGILL;
+                emu_store_rege((opcode[1] >> 4) & 15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+                mathemu_get_user(temp, dxb);
+                /* call the emulation function */
+                _fex = ((int (*)(int, float *)) jump_table[opcode[5]])
+                        (opcode[1] >> 4, (float *) &temp);
+                emu_load_regd((opcode[1] >> 4) & 15);
+                emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+                break;
+        }
+        default: /* invalid operation */
+                return SIGILL;
+        }
+	if (_fex != 0) {
+		current->thread.fp_regs.fpc |= _fex;
+		if (current->thread.fp_regs.fpc & (_fex << 8))
+			return SIGFPE;
+	}
+	return 0;
+}
+
+/*
+ * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+int math_emu_ldr(__u8 *opcode) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        __u16 opc = *((__u16 *) opcode);
+
+        if ((opc & 0x90) == 0) {           /* test if rx in {0,2,4,6} */
+                /* we got an exception therfore ry can't be in {0,2,4,6} */
+                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
+                        "     bras  1,0f\n"
+                        "     ld    0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (opc & 0xf0),
+                          "a" (&fp_regs->fprs[opc & 0xf].d)
+                        : "1" );
+        } else if ((opc & 0x9) == 0) {     /* test if ry in {0,2,4,6} */
+                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
+                        "     bras  1,0f\n"
+                        "     std   0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" ((opc & 0xf) << 4),
+                          "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
+                        : "1" );
+        } else  /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+                fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
+	return 0;
+}
+
+/*
+ * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+int math_emu_ler(__u8 *opcode) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        __u16 opc = *((__u16 *) opcode);
+
+        if ((opc & 0x90) == 0) {           /* test if rx in {0,2,4,6} */
+                /* we got an exception therfore ry can't be in {0,2,4,6} */
+                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
+                        "     bras  1,0f\n"
+                        "     le    0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (opc & 0xf0),
+                          "a" (&fp_regs->fprs[opc & 0xf].f)
+                        : "1" );
+        } else if ((opc & 0x9) == 0) {     /* test if ry in {0,2,4,6} */
+                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
+                        "     bras  1,0f\n"
+                        "     ste   0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" ((opc & 0xf) << 4),
+                          "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
+                        : "1" );
+        } else  /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+                fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
+	return 0;
+}
+
+/*
+ * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        __u32 opc = *((__u32 *) opcode);
+        __u64 *dxb;
+
+        dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+        mathemu_copy_from_user(&fp_regs->fprs[(opc >> 20) & 0xf].d, dxb, 8);
+	return 0;
+}
+
+/*
+ * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        __u32 opc = *((__u32 *) opcode);
+        __u32 *mem, *dxb;
+
+        dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+        mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
+        mathemu_get_user(mem[0], dxb);
+	return 0;
+}
+
+/*
+ * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        __u32 opc = *((__u32 *) opcode);
+        __u64 *dxb;
+
+        dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+        mathemu_copy_to_user(dxb, &fp_regs->fprs[(opc >> 20) & 0xf].d, 8);
+	return 0;
+}
+
+/*
+ * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+        s390_fp_regs *fp_regs = &current->thread.fp_regs;
+        __u32 opc = *((__u32 *) opcode);
+        __u32 *mem, *dxb;
+
+        dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+        mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
+        mathemu_put_user(mem[0], dxb);
+	return 0;
+}
+
+/*
+ * Emulate LFPC D(B)
+ */
+int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u32 *dxb, temp;
+
+        dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
+        mathemu_get_user(temp, dxb);
+        if ((temp & ~FPC_VALID_MASK) != 0)
+		return SIGILL;
+	current->thread.fp_regs.fpc = temp;
+        return 0;
+}
+
+/*
+ * Emulate STFPC D(B)
+ */
+int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u32 *dxb;
+
+        dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
+        mathemu_put_user(current->thread.fp_regs.fpc, dxb);
+        return 0;
+}
+
+/*
+ * Emulate SRNM D(B)
+ */
+int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u32 temp;
+
+        temp = calc_addr(regs, 0, opc>>12, opc);
+	current->thread.fp_regs.fpc &= ~3;
+        current->thread.fp_regs.fpc |= (temp & 3);
+        return 0;
+}
+
+/* broken compiler ... */
+long long
+__negdi2 (long long u)
+{
+
+  union lll {
+    long long ll;
+    long s[2];
+  };
+
+  union lll w,uu;
+
+  uu.ll = u;
+
+  w.s[1] = -uu.s[1];
+  w.s[0] = -uu.s[0] - ((int) w.s[1] != 0);
+
+  return w.ll;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/s390/math-emu/qrnnd.S linux/arch/s390/math-emu/qrnnd.S
--- v2.4.3/linux/arch/s390/math-emu/qrnnd.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/math-emu/qrnnd.S	Wed Apr 11 19:02:27 2001
@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+        .text
+        .globl __udiv_qrnnd
+__udiv_qrnnd:
+        st    %r2,24(%r15)        # store pointer to reminder for later
+        lr    %r0,%r3             # reload n
+	lr    %r1,%r4
+	ltr   %r2,%r5             # reload and test divisor
+        jp    5f
+        # divisor >= 0x80000000
+	srdl  %r0,2               # n/4
+        srl   %r2,1               # d/2
+        slr   %r1,%r2             # special case if last bit of d is set
+        brc   3,0f                #  (n/4) div (n/2) can overflow by 1
+        ahi   %r0,-1              #  trick: subtract n/2, then divide
+0:      dr    %r0,%r2             # signed division
+        ahi   %r1,1               #  trick part 2: add 1 to the quotient
+        # now (n >> 2) = (d >> 1) * %r1 + %r0
+	lhi   %r3,1
+        nr    %r3,%r1             # test last bit of q
+        jz    1f
+        alr   %r0,%r2             # add (d>>1) to r
+1:      srl   %r1,1               # q >>= 1
+        # now (n >> 2) = (d&-2) * %r1 + %r0
+        lhi   %r3,1
+        nr    %r3,%r5             # test last bit of d
+        jz    2f
+        slr   %r0,%r1             # r -= q
+	brc   3,2f                # borrow ?
+	alr   %r0,%r5             # r += d
+	ahi   %r1,-1
+2:      # now (n >> 2) = d * %r1 + %r0
+        alr   %r1,%r1             # q <<= 1
+        alr   %r0,%r0             # r <<= 1
+        brc   12,3f               # overflow on r ?
+        slr   %r0,%r5             # r -= d
+        ahi   %r1,1               # q += 1
+3:      lhi   %r3,2
+        nr    %r3,%r4             # test next to last bit of n
+        jz    4f
+        ahi   %r0,1               # r += 1
+4:      clr   %r0,%r5             # r >= d ?
+        jl    6f
+        slr   %r0,%r5             # r -= d
+        ahi   %r1,1               # q += 1
+        # now (n >> 1) = d * %r1 + %r0
+        j     6f
+5:      # divisor < 0x80000000
+	srdl  %r0,1
+        dr    %r0,%r2             # signed division
+        # now (n >> 1) = d * %r1 + %r0
+6:      alr   %r1,%r1             # q <<= 1
+        alr   %r0,%r0             # r <<= 1
+        brc   12,7f               # overflow on r ?
+        slr   %r0,%r5             # r -= d
+        ahi   %r1,1               # q += 1
+7:      lhi   %r3,1
+        nr    %r3,%r4             # isolate last bit of n
+        alr   %r0,%r3             # r += (n & 1)
+        clr   %r0,%r5             # r >= d ?
+        jl    8f
+        slr   %r0,%r5             # r -= d
+        ahi   %r1,1               # q += 1
+8:      # now n = d * %r1 + %r0
+	l     %r2,24(%r15)
+        st    %r0,0(%r2)
+        lr    %r2,%r1
+        br    %r14
+	.end	__udiv_qrnnd
diff -u --recursive --new-file v2.4.3/linux/arch/s390/math-emu/sfp-util.h linux/arch/s390/math-emu/sfp-util.h
--- v2.4.3/linux/arch/s390/math-emu/sfp-util.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/math-emu/sfp-util.h	Wed Apr 11 19:02:27 2001
@@ -0,0 +1,63 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({		\
+        unsigned int __sh = (ah);			\
+        unsigned int __sl = (al);			\
+        __asm__ ("   alr  %1,%3\n"			\
+                 "   brc  12,0f\n"			\
+                 "   ahi  %0,1\n"			\
+                 "0: alr  %0,%2"			\
+                 : "+&d" (__sh), "+d" (__sl)		\
+                 : "d" (bh), "d" (bl) : "cc" );		\
+        (sh) = __sh;					\
+        (sl) = __sl;					\
+})
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({		\
+       unsigned int __sh = (ah);			\
+       unsigned int __sl = (al);			\
+       __asm__ ("   slr  %1,%3\n"			\
+                "   brc  3,0f\n"			\
+                "   ahi  %0,-1\n"			\
+                "0: slr  %0,%2"				\
+                : "+&d" (__sh), "+d" (__sl)		\
+                : "d" (bh), "d" (bl) : "cc" );		\
+       (sh) = __sh;					\
+       (sl) = __sl;					\
+})
+
+/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
+#define umul_ppmm(wh, wl, u, v) ({			\
+        unsigned int __wh = u;				\
+        unsigned int __wl = v;				\
+        __asm__ ("   ltr  1,%0\n"			\
+                 "   mr   0,%1\n"			\
+                 "   jnm  0f\n"				\
+                 "   alr  0,%1\n"			\
+                 "0: ltr  %1,%1\n"			\
+                 "   jnm  1f\n"				\
+                 "   alr  0,%0\n"			\
+                 "1: lr   %0,0\n"			\
+                 "   lr   %1,1\n"			\
+                 : "+d" (__wh), "+d" (__wl)		\
+                 : : "0", "1", "cc" );			\
+        wh = __wh;					\
+        wl = __wl;					\
+})
+
+#define udiv_qrnnd(q, r, n1, n0, d)			\
+  do { unsigned long __r;				\
+    (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));		\
+    (r) = __r;						\
+  } while (0)
+extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
+				   unsigned long , unsigned long);
+
+#define UDIV_NEEDS_NORMALIZATION 0
+
+#define abort() return 0
+
+#define __BYTE_ORDER __BIG_ENDIAN
diff -u --recursive --new-file v2.4.3/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c
--- v2.4.3/linux/arch/s390/mm/fault.c	Mon Mar 19 12:35:11 2001
+++ linux/arch/s390/mm/fault.c	Wed Apr 11 19:02:27 2001
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/compatmac.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -263,3 +264,123 @@
 }
 
 
+typedef struct _pseudo_wait_t {
+       struct _pseudo_wait_t *next;
+       wait_queue_head_t queue;
+       unsigned long address;
+       int resolved;
+} pseudo_wait_t;
+
+static pseudo_wait_t *pseudo_lock_queue = NULL;
+static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
+
+/*
+ * This routine handles pseudo page faults.
+ */
+asmlinkage void
+do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+        DECLARE_WAITQUEUE(wait, current);
+        pseudo_wait_t wait_struct;
+        pseudo_wait_t *ptr, *last, *next;
+        unsigned long psw_mask;
+        unsigned long address;
+        int kernel_address;
+
+        /*
+         *  get psw mask of Program old psw to find out,
+         *  if user or kernel mode
+         */
+        psw_mask = S390_lowcore.program_old_psw.mask;
+
+        /*
+         * get the failing address
+         * more specific the segment and page table portion of
+         * the address
+         */
+        address = S390_lowcore.trans_exc_code & 0xfffff000;
+
+        if (address & 0x80000000) {
+                /* high bit set -> a page has been swapped in by VM */
+                address &= 0x7fffffff;
+                spin_lock(&pseudo_wait_spinlock);
+                last = NULL;
+                ptr = pseudo_lock_queue;
+                while (ptr != NULL) {
+                        next = ptr->next;
+                        if (address == ptr->address) {
+				 /*
+                                 * This is one of the processes waiting
+                                 * for the page. Unchain from the queue.
+                                 * There can be more than one process
+                                 * waiting for the same page. VM presents
+                                 * an initial and a completion interrupt for
+                                 * every process that tries to access a 
+                                 * page swapped out by VM. 
+                                 */
+                                if (last == NULL)
+                                        pseudo_lock_queue = next;
+                                else
+                                        last->next = next;
+                                /* now wake up the process */
+                                ptr->resolved = 1;
+                                wake_up(&ptr->queue);
+                        } else
+                                last = ptr;
+                        ptr = next;
+                }
+                spin_unlock(&pseudo_wait_spinlock);
+        } else {
+                /* Pseudo page faults in kernel mode is a bad idea */
+                if (!(psw_mask & PSW_PROBLEM_STATE)) {
+                        /*
+			 * VM presents pseudo page faults if the interrupted
+			 * state was not disabled for interrupts. So we can
+			 * get pseudo page fault interrupts while running
+			 * in kernel mode. We simply access the page here
+			 * while we are running disabled. VM will then swap
+			 * in the page synchronously.
+                         */
+			kernel_address = 0;
+                         switch (S390_lowcore.trans_exc_code & 3) {
+                         case 0: /* Primary Segment Table Descriptor */
+                                 kernel_address = 1;
+                                 break;
+                         case 1: /* STD determined via access register */
+                                 if (S390_lowcore.exc_access_id == 0 ||
+                                     regs->acrs[S390_lowcore.exc_access_id]==0)
+                                         kernel_address = 1;
+                                 break;
+                         case 2: /* Secondary Segment Table Descriptor */
+                         case 3: /* Home Segment Table Descriptor */
+                                 break;
+                         }
+                         if (kernel_address)
+                                 /* dereference a virtual kernel address */
+                                 __asm__ __volatile__ (
+                                         "  ic 0,0(%0)"
+                                         : : "a" (address) : "0");
+                         else
+                                 /* dereference a virtual user address */
+                                 __asm__ __volatile__ (
+                                         "  la   2,0(%0)\n"
+                                         "  sacf 512\n"
+                                         "  ic   2,0(2)\n"
+                                         "  sacf 0"
+                                         : : "a" (address) : "2" );
+
+                        return;
+                }
+		/* initialize and add element to pseudo_lock_queue */
+                init_waitqueue_head (&wait_struct.queue);
+                wait_struct.address = address;
+                wait_struct.resolved = 0;
+                spin_lock(&pseudo_wait_spinlock);
+                wait_struct.next = pseudo_lock_queue;
+                pseudo_lock_queue = &wait_struct;
+                spin_unlock(&pseudo_wait_spinlock);
+                /* go to sleep */
+                wait_event(wait_struct.queue, wait_struct.resolved);
+        }
+}
+    
diff -u --recursive --new-file v2.4.3/linux/arch/s390/mm/init.c linux/arch/s390/mm/init.c
--- v2.4.3/linux/arch/s390/mm/init.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/mm/init.c	Wed Apr 11 19:02:27 2001
@@ -35,27 +35,13 @@
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
 #include <asm/lowcore.h>
+#include <asm/tlb.h>
 
-static unsigned long totalram_pages;
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving an inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
+static unsigned long totalram_pages;
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
-char  empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
-pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE)));
 
 static int test_access(unsigned long loc)
 {
@@ -84,53 +70,6 @@
 	return rc;
 }
 
-static pte_t * get_bad_pte_table(void)
-{
-	pte_t v;
-	int i;
-
-	v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
-
-	for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
-		empty_bad_pte_table[i] = v;
-
-	return empty_bad_pte_table;
-}
-
-static inline void invalidate_page(pte_t *pte)
-{
-        int i;
-        for (i=0;i<PTRS_PER_PTE;i++)
-                pte_clear(pte++);
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-        unsigned long pte;
-
-        pte = (unsigned long) __get_free_page(GFP_KERNEL);
-        if (pmd_none(*pmd)) {
-                if (pte) {
-                        invalidate_page((pte_t*) pte);
-                        pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte);
-                        pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024;
-                        pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048;
-                        pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072;
-                        return (pte_t *) pte + offset;
-                }
-		pte = (unsigned long) get_bad_pte_table();
-                pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte);
-                pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024;
-                pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048;
-                pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072;
-                return NULL;
-        }
-        free_page(pte);
-        if (pmd_bad(*pmd))
-		BUG();
-        return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
@@ -139,9 +78,9 @@
                         if(pgd_quicklist)
                                 free_pgd_slow(get_pgd_fast()), freed += 2;
                         if(pmd_quicklist)
-                                free_pmd_slow(get_pmd_fast()), freed++;
+                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed++;
                         if(pte_quicklist)
-                                free_pte_slow(get_pte_fast()), freed++;
+                                pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++;
                 } while(pgtable_cache_size > low);
         }
         return freed;
diff -u --recursive --new-file v2.4.3/linux/arch/s390/mm/ioremap.c linux/arch/s390/mm/ioremap.c
--- v2.4.3/linux/arch/s390/mm/ioremap.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/mm/ioremap.c	Wed Apr 11 19:02:27 2001
@@ -54,7 +54,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
@@ -67,6 +67,7 @@
 static int remap_area_pages(unsigned long address, unsigned long phys_addr,
 				 unsigned long size, unsigned long flags)
 {
+	int error;
 	pgd_t * dir;
 	unsigned long end = address + size;
 
@@ -75,17 +76,21 @@
 	flush_cache_all();
 	if (address >= end)
 		BUG();
+	spin_lock(&init_mm.page_table_lock);
 	do {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
 		if (!pmd)
-			return -ENOMEM;
+			break;
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
-			return -ENOMEM;
-		set_pgdir(address, *dir);
+			break;
+		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c
--- v2.4.3/linux/arch/s390/tools/dasdfmt/dasdfmt.c	Fri Mar  2 11:12:06 2001
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.c	Wed Apr 11 19:02:27 2001
@@ -7,6 +7,7 @@
  *    Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
  *
  *  Device-in-use-checks by Fritz Elfert, <felfert@to.com>
+ *  Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
  *
  * Still to do:
  *   detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them 
@@ -157,14 +158,15 @@
 exit_usage(int exitcode)
 {
 #ifdef RANGE_FORMATTING
-	printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
 		"<diskspec>\n\n",prog_name);
 #else /* RANGE_FORMATTING */
-	printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
 		"<diskspec>\n\n",prog_name);
 #endif /* RANGE_FORMATTING */
 	printf("       -t means testmode\n");
 	printf("       -v means verbose mode\n");
+	printf("       -C means format compatible disk layout\n");
 	printf("       -V means print version\n");
 	printf("       -L means don't write disk label\n");
 	printf("       <label> is a label which is converted to EBCDIC and " \
@@ -200,7 +202,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) &&
@@ -218,7 +220,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);
 }
 
@@ -488,14 +491,14 @@
 	}
 	check_mounted(major_no, minor_no);
 
+	get_xno_from_xno(&devno,&major_no,&minor_no,
+			GIVEN_MAJOR|GIVEN_MINOR);
 	if ((!writenolabel) && (!labelspec)) {
 		sprintf(label,"LNX1 x%04x",devno);
 	}
 	
 	if ( ((withoutprompt)&&(verbosity>=1)) ||
 		(!withoutprompt) ) {
-		get_xno_from_xno(&devno,&major_no,&minor_no,
-			GIVEN_MAJOR|GIVEN_MINOR);
 		printf("\nI am going to format the device %s in the " \
 			"following way:\n",dev_name);
 		printf("   Device number of device : 0x%x\n",devno);
@@ -505,6 +508,9 @@
 			"no":"yes");
 		if (!writenolabel)
 			printf("   Disk label              : %s\n",label);
+		if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
+			printf("   Compatible Disk Layout  : %s\n",(format_params.intensity&0x08)?
+			       "yes":"no");
 #ifdef RANGE_FORMATTING
 		printf("   Start track             : %d\n" \
 			,format_params.start_unit);
@@ -558,7 +564,7 @@
 			}
 	
 
-			rc=ioctl(fd,BLKGETSIZE,&new_blksize);
+			rc=ioctl(fd,BLKSSZGET,&new_blksize);
 			if (rc) {
 				ERRMSG("%s: the ioctl call to get blocksize " \
 					"returned with the following error " \
@@ -664,9 +670,9 @@
 	opterr=0;
 
 #ifdef RANGE_FORMATTING
-	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
 #endif /* RANGE_FORMATTING */
-	while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
+	while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
 		switch (oc) {
 		case 'y':
 			withoutprompt=1;
@@ -686,6 +692,9 @@
 
 		case 'h':
 			exit_usage(0);
+		case 'C':
+                	format_params.intensity&=0x08;
+			break;
 
 		case 'V':
 			printf("%s version 0.99\n",prog_name);
diff -u --recursive --new-file v2.4.3/linux/arch/s390/tools/silo/silo.c linux/arch/s390/tools/silo/silo.c
--- v2.4.3/linux/arch/s390/tools/silo/silo.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/tools/silo/silo.c	Wed Apr 11 19:02:27 2001
@@ -9,6 +9,9 @@
  *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
  *               Fritz Elfert <felfert@to.com> contributed support for
  *                	/etc/silo.conf based on Intel's lilo
+ *    Changes  :
+ *               01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *                 adapted to deal with devices and bootsects of various sizes
  */
 
 #include <stddef.h>
@@ -376,7 +379,7 @@
     if ( errno == ENOENT ) {
       ITRY (creat ( o-> bootmap, O_RDWR ));
     } else {
-      PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap,
+      PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
 		  strerror(errno));
     }
   }
@@ -482,6 +485,7 @@
   int bs, boots;
   char *tmpdev;
   char buffer[4096]={0,};
+  int blocksize, sectsize;
   ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
   ITRY (fstat (d_fd, &d_st));
   ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
@@ -508,6 +512,7 @@
   NTRY ( tmpdev = tmpnam(NULL) );
   ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
   ITRY (bd_fd = open (tmpdev, O_RDONLY));
+  ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
   ITRY (ioctl(s_fd,FIBMAP,&boots));
   ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
   PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
@@ -515,13 +520,21 @@
   close(s_fd);
   ITRY (unlink(tmpdev));
   /* Now patch the bootsector */
+  ITRY (stat (o->bootsect, &b_st));
+  if ((sectsize = b_st.st_size) > blocksize )
+    {
+      ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
+      rc = -1;
+      errno = EINVAL;
+    }
   ITRY (b_fd = open (o->bootsect, O_RDONLY));
-  NTRY (read (b_fd, buffer, 4096));
+  ITRY (read (b_fd, buffer, sectsize));
   memset (buffer + 0xe0, 0, 8);
   *(int *) (buffer + 0xe0) = boots;
   if ( o -> testlevel <= 0 ) {
-    NTRY (write (d_fd, buffer, 4096));
-    NTRY (write (d_fd, buffer, 4096));
+    ITRY (write (d_fd, buffer, sectsize));
+    ITRY (lseek (d_fd, blocksize, SEEK_SET));
+    ITRY (write (d_fd, buffer, sectsize));
   }
   close (b_fd);
   close (d_fd);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/boot/Makefile linux/arch/s390x/boot/Makefile
--- v2.4.3/linux/arch/s390x/boot/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/boot/Makefile	Wed Apr 11 19:02:29 2001
@@ -25,7 +25,7 @@
 image: $(CONFIGURE) $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot ipldump.boot
 	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
-	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
+	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
 
 listing: ../../../vmlinux
 	$(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/config.in linux/arch/s390x/config.in
--- v2.4.3/linux/arch/s390x/config.in	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/config.in	Tue Apr 17 17:19:25 2001
@@ -6,6 +6,8 @@
 define_bool CONFIG_ISA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_name "Linux Kernel Configuration"
 define_bool CONFIG_ARCH_S390 y
@@ -47,12 +49,13 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
-define CONFIG_KCORE ELF
+define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
 endmenu
 
+
 source drivers/s390/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
@@ -68,6 +71,6 @@
 if [ "$CONFIG_CTC" = "y" ]; then
   bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 fi
-# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/defconfig linux/arch/s390x/defconfig
--- v2.4.3/linux/arch/s390x/defconfig	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/defconfig	Wed Apr 11 19:02:29 2001
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
@@ -37,6 +37,7 @@
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PROCESS_DEBUG is not set
@@ -50,9 +51,14 @@
 CONFIG_BLK_DEV_RAM_SIZE=24576
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XPRAM=m
+
+#
+# S/390 block device drivers
+#
 CONFIG_DASD=y
 CONFIG_DASD_ECKD=y
 CONFIG_DASD_FBA=y
+# CONFIG_DASD_DIAG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -64,20 +70,31 @@
 CONFIG_MD_RAID1=m
 CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_LVM=m
-CONFIG_LVM_PROC_FS=y
 
 #
 # Character device drivers
 #
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# S/390 character device drivers
+#
 CONFIG_3215=y
 CONFIG_3215_CONSOLE=y
 CONFIG_HWC=y
 CONFIG_HWC_CONSOLE=y
 CONFIG_S390_TAPE=m
+
+#
+# S/390 tape interface support
+#
 CONFIG_S390_TAPE_CHAR=y
 CONFIG_S390_TAPE_BLOCK=y
+
+#
+# S/390 tape hardware support
+#
 CONFIG_S390_TAPE_3490=y
 CONFIG_S390_TAPE_3480=y
 
@@ -89,6 +106,10 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_TR=y
 # CONFIG_FDDI is not set
+
+#
+# S/390 network device drivers
+#
 # CONFIG_CHANDEV is not set
 CONFIG_CTC=m
 CONFIG_IUCV=m
@@ -110,11 +131,16 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
@@ -139,6 +165,8 @@
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -193,8 +221,6 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 
@@ -212,8 +238,10 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_MAGIC_SYSRQ is not set
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/Makefile linux/arch/s390x/kernel/Makefile
--- v2.4.3/linux/arch/s390x/kernel/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/Makefile	Wed Apr 11 19:02:29 2001
@@ -14,7 +14,7 @@
 
 O_TARGET := kernel.o
 
-export-objs	:= s390_ksyms.o
+export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
 obj-y	:= 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 \
             semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/binfmt_elf32.c linux/arch/s390x/kernel/binfmt_elf32.c
--- v2.4.3/linux/arch/s390x/kernel/binfmt_elf32.c	Mon Mar 19 12:35:11 2001
+++ linux/arch/s390x/kernel/binfmt_elf32.c	Wed Apr 11 19:02:29 2001
@@ -23,7 +23,8 @@
  * This is used to ensure we don't load something for the wrong architecture.
  */
 #define elf_check_arch(x) \
-	((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+	(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
+         && (x)->e_ident[EI_CLASS] == ELF_CLASS)
 
 /* ELF register definitions */
 #define NUM_GPRS      16
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/cpcmd.c linux/arch/s390x/kernel/cpcmd.c
--- v2.4.3/linux/arch/s390x/kernel/cpcmd.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/cpcmd.c	Wed Apr 11 19:02:29 2001
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <asm/ebcdic.h>
+#include <asm/cpcmd.h>
 
 void cpcmd(char *cmd, char *response, int rlen)
 {
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/cpcmd.h linux/arch/s390x/kernel/cpcmd.h
--- v2.4.3/linux/arch/s390x/kernel/cpcmd.h	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/cpcmd.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- *  arch/s390/kernel/cpcmd.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-
-#ifndef __CPCMD__
-#define __CPCMD__
-
-extern void cpcmd(char *cmd, char *response, int rlen);
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/cpprintk.c linux/arch/s390x/kernel/cpprintk.c
--- v2.4.3/linux/arch/s390x/kernel/cpprintk.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/cpprintk.c	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-#include "cpcmd.h"
-#include <linux/mm.h>
-#include <linux/tty_driver.h>
-#include <linux/smp_lock.h>
-#include <linux/console.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-
-static char buf[1024];
-
-asmlinkage int s390printk(const char *fmt, ...)
-{
-	va_list args;
-	int i;
-	unsigned long flags;
-	spin_lock_irqsave(&console_lock, flags);
-	va_start(args, fmt);
-	i = vsprintf(&buf[0],"MSG * ",args);
-	i = vsprintf(&buf[i], fmt, args); 
-	va_end(args);
-	cpcmd(buf,0,0);
-	spin_unlock_irqrestore(&console_lock, flags);
-	return i;
-}
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/debug.c linux/arch/s390x/kernel/debug.c
--- v2.4.3/linux/arch/s390x/kernel/debug.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/debug.c	Wed Apr 11 19:02:29 2001
@@ -15,45 +15,53 @@
 #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/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_S390X)
-#define DEBUG_PROC_HEADER_SIZE 46
-#else
-#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,
@@ -83,6 +91,9 @@
 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_raw_view = {
@@ -90,6 +101,7 @@
 	NULL,
 	&debug_raw_header_fn,
 	&debug_raw_format_fn,
+	NULL,
 	NULL
 };
 
@@ -98,6 +110,7 @@
 	NULL,
 	&debug_dflt_header_fn,
 	&debug_hex_ascii_format_fn,
+	NULL,
 	NULL
 };
 
@@ -106,9 +119,22 @@
 	&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_area_first = NULL;
@@ -137,64 +163,108 @@
 
 static struct proc_dir_entry *debug_proc_root_entry;
 
-
 /* functions */
 
 /*
- * debug_info_create
- * - create new debug-info
+ * debug_info_alloc
+ * - alloc new debug-info
  */
 
-static debug_info_t*  debug_info_create(char *name, int page_order, 
+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 */
+	/* alloc everything */
 
-        rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
-        if(!rc) 
+	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);
-                }
-        }
+	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 */
 
-        /* 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 */
 
-        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);
         rc->proc_root_entry =
             debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
                                         S_IFDIR | S_IRUGO | S_IXUGO |
@@ -216,16 +286,29 @@
         rc->next = NULL;
 
 	debug_info_get(rc);
+out:
 	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_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;
 }
 
 /*
@@ -261,49 +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);
-		kfree(db_info->active_entry);
 		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;
-		kfree(db_info);
+		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;
 }
 
 /*
@@ -322,68 +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,
-						         DEBUG_DATA(act_entry));
-			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
@@ -392,17 +494,14 @@
 
 static int debug_open(struct inode *inode, struct file *file)
 {
-	int i = 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_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 */
@@ -422,87 +521,41 @@
 	/* 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");
+
+	/* make snapshot of current debug areas to get it consistent */
+
+	debug_info_snapshot = debug_info_copy(debug_info);
+
+	if(!debug_info_snapshot){
+		printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\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_info->views[i]->prolog_proc)
-		size +=
-		    debug_info->views[i]->prolog_proc(debug_info,
-							 debug_info->
-							 views[i], NULL);
-
-	if (debug_info->views[i]->header_proc)
-		f_entry_size =
-		    debug_info->views[i]->header_proc(debug_info,
-							 debug_info->
-							 views[i], 0, NULL,
-							 NULL);
-	if (debug_info->views[i]->format_proc)
-		f_entry_size +=
-		    debug_info->views[i]->format_proc(debug_info,
-							 debug_info->
-							 views[i], NULL,
-							 NULL);
-
-	size += f_entry_size 
-		* (PAGE_SIZE / debug_info->entry_size
-		<< debug_info->page_order)
-		* debug_info->nr_areas + 1;	/* terminating \0 */
-#ifdef DEBUG
-	printk("debug_open: size: %i\n", size);
-#endif
 
-	/* 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 ((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;
 	}
-
-	p_info->size = size;
-	p_info->debug_info = debug_info;
+	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_lock_irq(&debug_info->lock);
-
-	p_info->len =
-	    debug_format_output(debug_info, p_info->data, size,
-				debug_info->views[i]);
-#ifdef DEBUG
-	{
-		int ilen = p_info->len;
-		printk("debug_open: len: %i\n", ilen);
-	}
-#endif
-
-	spin_unlock_irq(&debug_info->lock);
 	debug_info_get(debug_info);
 
       out:
 	up(&debug_lock);
-#ifdef MODULE
 	if (rc != 0)
 		MOD_DEC_USE_COUNT;
-#endif
 	return rc;
 }
 
@@ -518,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 */
 }
 
@@ -607,9 +653,7 @@
 {
 	debug_info_t *rc = NULL;
 
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 	if (!initialized)
 		debug_init();
 	down(&debug_lock);
@@ -626,9 +670,7 @@
       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;
@@ -648,9 +690,7 @@
 	debug_info_put(id);
 	up(&debug_lock);
 
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif
       out:
 	return;
 }
@@ -662,7 +702,7 @@
 
 void debug_set_level(debug_info_t* id, int new_level)
 {
-	long flags;
+	unsigned long flags;
 	if(!id)
 		return;	
 	spin_lock_irqsave(&id->lock,flags);
@@ -687,7 +727,7 @@
  * - 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))
@@ -699,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;
@@ -709,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]);
@@ -720,160 +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;
+	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(DEBUG_DATA(active), 0, id->buf_size);
-	memcpy(DEBUG_DATA(active), &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(DEBUG_DATA(active), 0, id->buf_size);
-	strncpy(DEBUG_DATA(active), txt, 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(DEBUG_DATA(active), 0, id->buf_size);
-	memcpy(DEBUG_DATA(active), 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(DEBUG_DATA(active), 0, id->buf_size);
-	memcpy(DEBUG_DATA(active), &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(DEBUG_DATA(active), 0, id->buf_size);
-	strncpy(DEBUG_DATA(active), txt, 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;
+	}
 }
 
 /*
@@ -908,7 +914,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 	mode_t mode = S_IFREG;
 
 	if (!id)
@@ -951,7 +957,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 
 	if (!id)
 		goto out;
@@ -987,13 +993,8 @@
 {
 	int rc = 0;
 
-	if (out_buf == NULL) {
-		rc = 2;
-		goto out;
-	}
 	if(id->level == -1) rc = sprintf(out_buf,"-\n");
 	else rc = sprintf(out_buf, "%i\n", id->level);
-      out:
 	return rc;
 }
 
@@ -1010,8 +1011,10 @@
 
 	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');
 		debug_set_level(id, new_level);
@@ -1036,10 +1039,7 @@
         int rc;
 
 	rc = sizeof(debug_entry_t);
-        if (out_buf == NULL)
-                goto out;
 	memcpy(out_buf,entry,sizeof(debug_entry_t));
-      out:
         return rc;
 }
 
@@ -1053,10 +1053,7 @@
 	int rc;
 
 	rc = id->buf_size;
-	if (out_buf == NULL || in_buf == NULL)
-		goto out;
 	memcpy(out_buf, in_buf, id->buf_size);
-      out:
 	return rc;
 }
 
@@ -1069,10 +1066,6 @@
 {
 	int i, rc = 0;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size * 4 + 3;
-		goto out;
-	}
 	for (i = 0; i < id->buf_size; i++) {
                 rc += sprintf(out_buf + rc, "%02x ",
                               ((unsigned char *) in_buf)[i]);
@@ -1086,7 +1079,6 @@
 			rc += sprintf(out_buf + rc, "%c", c);
 	}
 	rc += sprintf(out_buf + rc, "\n");
-      out:
 	return rc;
 }
 
@@ -1102,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);
@@ -1119,18 +1108,60 @@
 		except_str = "-";
 	caller = (unsigned long) entry->caller;
 #if defined(CONFIG_ARCH_S390X)
-	rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx  ",
-		      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 %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;
 }
 
@@ -1165,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 --recursive --new-file v2.4.3/linux/arch/s390x/kernel/ebcdic.c linux/arch/s390x/kernel/ebcdic.c
--- v2.4.3/linux/arch/s390x/kernel/ebcdic.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/ebcdic.c	Wed Apr 11 19:02:29 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 --recursive --new-file v2.4.3/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S
--- v2.4.3/linux/arch/s390x/kernel/entry.S	Fri Mar  2 11:12:06 2001
+++ linux/arch/s390x/kernel/entry.S	Wed Apr 11 19:02:29 2001
@@ -9,56 +9,53 @@
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  */
 
+#define ASSEMBLY
+
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
-#define ASSEMBLY
 #include <asm/smp.h>
-#include <asm/s390-regs-common.h>
+#include <asm/ptrace.h>
 
 
 /*
- * stack layout for the system_call stack entry
- * Martin please don't modify these back to hard coded values 
- * You know how bad I'm at mental arithmetic DJB & it gives 
- * me grief when I modify the pt_regs
+ * Stack layout for the system_call stack entry.
+ * The first few entries are identical to the user_regs_struct.
  */
 SP_PTREGS    =  STACK_FRAME_OVERHEAD 
-SP_PSW       =  SP_PTREGS
-SP_R0        =  (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE)
-SP_R1        =  (SP_R0+GPR_SIZE)
-SP_R2        =  (SP_R1+GPR_SIZE)
-SP_R3        =  (SP_R2+GPR_SIZE)
-SP_R4        =  (SP_R3+GPR_SIZE)
-SP_R5        =  (SP_R4+GPR_SIZE)
-SP_R6        =  (SP_R5+GPR_SIZE)
-SP_R7        =  (SP_R6+GPR_SIZE)
-SP_R8        =  (SP_R7+GPR_SIZE)
-SP_R9        =  (SP_R8+GPR_SIZE)
-SP_RA        =  (SP_R9+GPR_SIZE)
-SP_RB        =  (SP_RA+GPR_SIZE)
-SP_RC        =  (SP_RB+GPR_SIZE)
-SP_RD        =  (SP_RC+GPR_SIZE)
-SP_RE        =  (SP_RD+GPR_SIZE)
-SP_RF        =  (SP_RE+GPR_SIZE)
-SP_AREGS     =  (SP_RF+GPR_SIZE)
-SP_ORIG_R2   =  (SP_AREGS+(NUM_ACRS*ACR_SIZE))
+SP_PSW       =  STACK_FRAME_OVERHEAD + PT_PSWMASK
+SP_R0        =  STACK_FRAME_OVERHEAD + PT_GPR0
+SP_R1        =  STACK_FRAME_OVERHEAD + PT_GPR1
+SP_R2        =  STACK_FRAME_OVERHEAD + PT_GPR2
+SP_R3        =  STACK_FRAME_OVERHEAD + PT_GPR3
+SP_R4        =  STACK_FRAME_OVERHEAD + PT_GPR4
+SP_R5        =  STACK_FRAME_OVERHEAD + PT_GPR5
+SP_R6        =  STACK_FRAME_OVERHEAD + PT_GPR6
+SP_R7        =  STACK_FRAME_OVERHEAD + PT_GPR7
+SP_R8        =  STACK_FRAME_OVERHEAD + PT_GPR8
+SP_R9        =  STACK_FRAME_OVERHEAD + PT_GPR9
+SP_R10       =  STACK_FRAME_OVERHEAD + PT_GPR10
+SP_R11       =  STACK_FRAME_OVERHEAD + PT_GPR11
+SP_R12       =  STACK_FRAME_OVERHEAD + PT_GPR12
+SP_R13       =  STACK_FRAME_OVERHEAD + PT_GPR13
+SP_R14       =  STACK_FRAME_OVERHEAD + PT_GPR14
+SP_R15       =  STACK_FRAME_OVERHEAD + PT_GPR15
+SP_AREGS     =  STACK_FRAME_OVERHEAD + PT_ACR0
+SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
+/* Now the additional entries */
 SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
 #if CONFIG_REMOTE_DEBUG
 SP_CRREGS    =  (SP_TRAP+4)
 /* fpu registers are saved & restored by the gdb stub itself */
 SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
 SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not 
- defined in ptrace.h but space is needed for this too */
 SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
 #else
 SP_PGM_OLD_ILC= (SP_TRAP+4)
 #endif
-SP_SVC_STEP   = (SP_PGM_OLD_ILC+4) 
-SP_SIZE      =  (SP_SVC_STEP+4)
+SP_SIZE      =  (SP_PGM_OLD_ILC+4)
 /*
  * these defines are offsets into the thread_struct
  */
@@ -72,6 +69,8 @@
 _TSS_ERROR   = (_TSS_PROT+8)
 _TSS_TRAP    = (_TSS_ERROR+4)
 _TSS_PER     = (_TSS_TRAP+4)
+_TSS_IEEE    = (_TSS_PER+72)
+_TSS_FLAGS   = (_TSS_IEEE+8)
 
 /*
  * these are offsets into the task-struct.
@@ -83,31 +82,6 @@
 tsk_ptrace   = 40
 processor    = 100
 
-/* PSW related defines */
-disable      = 0xFC
-enable       = 0x03
-daton        = 0x04
-
-
-#if 0
-/* some code left lying around in case we need a
- *	printk for debugging purposes
- */
-  sysc_printk:        .long  printk
-  sysc_msg:	      .string "<2>r15 %X\n"
-	.align 4
-		
-#	basr    %r13,0
-	lg      %r0,SP_PSW+8(%r15)
-	sllg    %r0,%r0,1
-	chi     %r0,0
-	jnz     sysc_dn
-        la      %r2,sysc_msg-sysc_lit(%r13)
-        lgr     %r3,%r15
-        brasl   %r14,sysc_printk
-sysc_dn:
-#endif
-
 /*
  * Register usage in interrupt handlers:
  *    R9  - pointer to current task structure
@@ -116,38 +90,41 @@
  *    R15 - kernel stack pointer
  */
 
-#define SAVE_ALL(psworg) \
-	stmg    %r14,%r15,__LC_SAVE_AREA   ; \
-        stam    %a2,%a4,__LC_SAVE_AREA+16 ; \
-        tm      psworg+1,0x01         ; /* test problem state bit */ \
-	jz	0f		      ; /* skip stack setup save */ \
-	lg      %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \
-        slr     %r14,%r14             ; \
-        sar     %a2,%r14              ; /* set ac.reg. 2 to primary space */ \
-        lhi     %r14,1                ; \
-        sar     %a4,%r14              ; /* set access reg. 4 to home space */ \
-0:	aghi    %r15,-SP_SIZE         ; /* make room for registers & psw */ \
-        nill    %r15,0xfff8           ; /* align stack pointer to 8 */ \
-        stmg    %r0,%r14,SP_R0(%r15)  ; /* store gprs 0-14 to kernel stack */ \
-        stg     %r2,SP_ORIG_R2(%r15)  ; /* store original content of gpr 2 */ \
-        mvc     SP_RE(16,%r15),__LC_SAVE_AREA   ; /* move R15 to stack */ \
-        stam    %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\
-        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 ; /* store ac. regs */ \
-        mvc     SP_PSW(16,%r15),psworg; /* move user PSW to stack */ \
-        lhi     %r0,psworg            ; /* store trap indication */ \
-        st      %r0,SP_TRAP(%r15)     ; \
-        xc      0(8,%r15),0(%r15)     ; /* clear back chain */
-
-#define RESTORE_ALL \
-        mvc     __LC_RETURN_PSW(16),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
-        lam     %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
-        lmg     %r0,%r15,SP_R0(%r15)    ; /* load gprs 0-15 of user */ \
-        ni      __LC_RETURN_PSW+1,0xfd  ; /* clear wait state bit */ \
-        lpswe   __LC_RETURN_PSW           /* back to caller */
+        .macro  SAVE_ALL psworg          # system entry macro
+        stmg    %r14,%r15,__LC_SAVE_AREA
+        stam    %a2,%a4,__LC_SAVE_AREA+16
+        tm      \psworg+1,0x01           # test problem state bit
+        jz      0f                       # skip stack setup save
+        lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
+        slr     %r14,%r14
+        sar     %a2,%r14                 # set ac.reg. 2 to primary space
+        lhi     %r14,1
+        sar     %a4,%r14                 # set access reg. 4 to home space
+0:      aghi    %r15,-SP_SIZE            # make room for registers & psw
+        nill    %r15,0xfff8              # align stack pointer to 8
+        stmg    %r0,%r14,SP_R0(%r15)     # store gprs 0-14 to kernel stack
+        stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
+        mvc     SP_R14(16,%r15),__LC_SAVE_AREA # move R15 to stack
+        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
+        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
+        mvc     SP_PSW(16,%r15),\psworg  # move user PSW to stack
+        lhi     %r0,\psworg              # store trap indication
+        st      %r0,SP_TRAP(%r15)
+        xc      0(8,%r15),0(%r15)        # clear back chain
+        .endm
+
+        .macro  RESTORE_ALL              # system exit macro
+        mvc     __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore
+        lam     %a0,%a15,SP_AREGS(%r15)  # load the access registers
+        lmg     %r0,%r15,SP_R0(%r15)     # load gprs 0-15 of user
+        ni      __LC_RETURN_PSW+1,0xfd   # clear wait state bit
+        lpswe   __LC_RETURN_PSW          # back to caller
+        .endm
 
-#define GET_CURRENT /* load pointer to task_struct to R9 */ \
-        lghi    %r9,-16384            ; \
+        .macro  GET_CURRENT
+        lghi    %r9,-16384               # load pointer to task_struct to %r9
         ngr     %r9,15
+        .endm
 
 
 /*
@@ -162,7 +139,7 @@
         lg      %r4,_TSS_PTREGS(%r3)
         tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
         jz      resume_noper            # if not we're fine
-        stctg   %r9,%r11,48(%r15)       # We are using per stuff
+        stctg   %c9,%c11,48(%r15)       # We are using per stuff
         clc     _TSS_PER(24,%r3),48(%r15)
         je      resume_noper            # we got away without bashing TLB's
         lctlg   %c9,%c11,_TSS_PER(%r3)  # Nope we didn't
@@ -191,10 +168,11 @@
 
 	.globl  system_call
 system_call:
-        SAVE_ALL(__LC_SVC_OLD_PSW)
-	xc      SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+        SAVE_ALL __LC_SVC_OLD_PSW
+	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
 pgm_system_call:
-	larl    %r1,sys_call_table
+        GET_CURRENT               # load pointer to task_struct to R9
+	larl    %r7,sys_call_table
 	llgc    %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore
 	stosm   48(%r15),0x03     # reenable interrupts
         sll     %r8,3
@@ -202,8 +180,7 @@
         jo      sysc_noemu
 	la      %r8,4(%r8)        # use 31 bit emulation system calls
 sysc_noemu:
-        GET_CURRENT               # load pointer to task_struct to R9
-        lgf     %r8,0(%r8,%r1)    # load address of system call routine
+        lgf     %r8,0(%r8,%r7)    # load address of system call routine
         tm      tsk_ptrace+7(%r9),0x02 # PT_TRACESYS
         jnz     sysc_tracesys
         basr    %r14,%r8          # call sys_xxxx
@@ -212,7 +189,6 @@
                                   # changing anything here !!
 
 sysc_return:
-        GET_CURRENT               # load pointer to task_struct to R9
         tm      SP_PSW+1(%r15),0x01 # returning to user ?
         jno     sysc_leave        # no-> skip bottom half, resched & signal
 #
@@ -228,12 +204,12 @@
 	lg      %r0,need_resched(%r9) # get need_resched from task_struct
 	ltgr    %r0,%r0
         jnz     sysc_reschedule
-        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+        icm     %r0,15,sigpending(%r9)     # get sigpending from task_struct
         jnz     sysc_signal_return
 sysc_leave:
-	icm     %r0,15,SP_SVC_STEP(%r15)   # get sigpending from task_struct
-        jnz     pgm_svcret
-	stnsm   48(%r15),disable  # disable I/O and ext. interrupts
+        tm      SP_PGM_OLD_ILC(%r15),0xff
+        jz      pgm_svcret
+	stnsm   48(%r15),0xfc         # disable I/O and ext. interrupts
         RESTORE_ALL
 
 #
@@ -667,7 +643,7 @@
         je      pgm_svcper
 # no interesting special case, ignore PER event
         lm      %r13,%r15,__LC_SAVE_AREA
-	lpsw    __LC_PGM_OLD_PSW
+	lpswe   __LC_PGM_OLD_PSW
 # it was a single stepped SVC that is causing all the trouble
 pgm_svcper:
         tm      __LC_SVC_OLD_PSW+1,0x01  # test problem state bit
@@ -681,7 +657,7 @@
         nill    %r15,0xfff8              # align stack pointer to 8
         stmg    %r0,%r14,SP_R0(%r15)     # store gprs 0-14 to kernel stack 
         stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_RE(16,%r15),__LC_SAVE_AREA         # move R14-R15 to stack
+        mvc     SP_R14(16,%r15),__LC_SAVE_AREA         # move R14-R15 to stack
         stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
         mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
         mvc     SP_PSW(16,%r15),__LC_PGM_OLD_PSW      # move user PSW to stack
@@ -689,14 +665,13 @@
         st      %r0,SP_TRAP(%r15)
         xc      0(8,%r15),0(%r15)        # clear back chain
 
-        mvi     SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
         mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
         j       pgm_system_call          # now do the svc
 pgm_svcret:
 	lhi     %r0,__LC_PGM_OLD_PSW     # set trap indication back to pgm_chk
 	st      %r0,SP_TRAP(%r15)
         llgh    %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
-        xc      SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+        mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
 	j       pgm_no_sv
 pgm_sv:
         tm      __LC_PGM_OLD_PSW+1,0x01  # test problem state bit
@@ -710,15 +685,16 @@
         nill    %r15,0xfff8              # align stack pointer to 8
         stmg    %r0,%r14,SP_R0(%r15)     # store gprs 0-14 to kernel stack
         stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_RE(16,%r15),__LC_SAVE_AREA         # move R14-R15 to stack
+        mvc     SP_R14(16,%r15),__LC_SAVE_AREA         # move R14-R15 to stack
         stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
         mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
         mvc     SP_PSW(16,%r15),__LC_PGM_OLD_PSW      # move user PSW to stack
         lhi     %r0,__LC_PGM_OLD_PSW     # store trap indication
         st      %r0,SP_TRAP(%r15)
         xc      0(8,%r15),0(%r15)        # clear back chain
-	xc      SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
-        llgh    %r7,__LC_PGM_ILC  # load instruction length
+        mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
+        llgh    %r7,__LC_PGM_ILC         # load instruction length
+	GET_CURRENT
 pgm_no_sv:
         llgh    %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
         stosm   48(%r15),0x03     # reenable interrupts
@@ -726,8 +702,8 @@
         nr      %r3,%r8           # clear per-event-bit & move to r3
         je      pgm_dn            # none of Martins exceptions occurred bypass
         sll     %r3,3
-        larl    %r9,pgm_check_table
-        lg      %r9,0(%r3,%r9)    # load address of handler routine
+        larl    %r1,pgm_check_table
+        lg      %r1,0(%r3,%r1)    # load address of handler routine
         srl     %r3,3
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         chi     %r3,0x4           # protection-exception ?
@@ -735,7 +711,7 @@
         lg      %r5,SP_PSW+8(15)  # load psw addr
         slgr    %r5,%r7           # substract ilc from psw
         stg     %r5,SP_PSW+8(15)  # store corrected psw addr
-pgm_go: basr    %r14,%r9          # branch to interrupt-handler
+pgm_go: basr    %r14,%r1          # branch to interrupt-handler
 pgm_dn: nill    %r8,0x80          # check for per exception
         je      sysc_return
         la      %r2,SP_PTREGS(15) # address of register-save area
@@ -747,17 +723,17 @@
  */
         .globl io_int_handler
 io_int_handler:
-        SAVE_ALL(__LC_IO_OLD_PSW)
+        SAVE_ALL __LC_IO_OLD_PSW
+        GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
 	llgh    %r3,__LC_SUBCHANNEL_NR # load subchannel number
-        llgf    %r4,__LC_IO_INT_PARM   # load interruption parm
-        llgf    %r5,__LC_IO_INT_WORD   # load interruption word
+        llgf    %r4,__LC_IO_INT_PARM   # load interuption parm
+        llgf    %r5,__LC_IO_INT_WORD   # load interuption word
 	brasl   %r14,do_IRQ            # call standard irq handler
 
 io_return:
-        GET_CURRENT                    # load pointer to task_struct to R9
         tm      SP_PSW+1(%r15),0x01    # returning to user ?
-        jz      io_leave               # no-> skip resched & signal
+        jno     io_leave               # no-> skip resched & signal
         stosm   48(%r15),0x03          # reenable interrupts
 #
 # check, if bottom-half has to be done
@@ -775,7 +751,7 @@
         icm     %r0,15,sigpending(%r9) # get sigpending from task_struct
         jnz     io_signal_return
 io_leave:
-        stnsm   48(%r15),disable       # disable I/O and ext. interrupts
+        stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
         RESTORE_ALL
 
 #
@@ -807,34 +783,35 @@
  */
         .globl  ext_int_handler
 ext_int_handler:
-        SAVE_ALL(__LC_EXT_OLD_PSW)
+        SAVE_ALL __LC_EXT_OLD_PSW
+        GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
         llgh    %r3,__LC_EXT_INT_CODE  # error code
         lgr     %r1,%r3                # calculate index = code & 0xff
 	nill    %r1,0xff
         sll     %r1,3
-        larl    %r9,ext_int_hash
-        lg      %r9,0(%r1,%r9)         # get first list entry for hash value
-        ltgr    %r9,%r9                # == NULL ?
+        larl    %r4,ext_int_hash
+        lg      %r4,0(%r1,%r4)         # get first list entry for hash value
+        ltgr    %r4,%r4                # == NULL ?
         jz      io_return              # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,16(%r9)            # compare external interrupt code
+        ch      %r3,16(%r4)            # compare external interrupt code
         je      ext_int_found
-        lg      %r9,0(%r9)             # next list entry
-	ltgr    %r9,%r9
+        lg      %r4,0(%r4)             # next list entry
+	ltgr    %r4,%r4
         jnz     ext_int_loop
         j       io_return
 ext_int_found:
-        lg      %r9,8(%r9)             # get handler address
+        lg      %r4,8(%r4)             # get handler address
         larl    %r14,io_return
-        br      %r9                    # branch to ext call handler
+        br      %r4                    # branch to ext call handler
 
 /*
  * Machine check handler routines
  */
         .globl mcck_int_handler
 mcck_int_handler:
-        SAVE_ALL(__LC_MCK_OLD_PSW)
+        SAVE_ALL __LC_MCK_OLD_PSW
 	brasl   %r14,s390_do_machine_check
 mcck_return:
         RESTORE_ALL
@@ -848,7 +825,7 @@
         lg      %r15,__LC_KERNEL_STACK # load ksp
         lctlg   %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
         lam     %a0,%a15,__LC_AREGS_SAVE_AREA
-        stosm   0(%r15),daton          # now we can turn dat on
+        stosm   0(%r15),0x04           # now we can turn dat on
         lmg     %r6,%r15,48(%r15)      # load registers from clone
 	jg      start_secondary
 #else
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/exec32.c linux/arch/s390x/kernel/exec32.c
--- v2.4.3/linux/arch/s390x/kernel/exec32.c	Thu Mar 22 09:25:21 2001
+++ linux/arch/s390x/kernel/exec32.c	Wed Apr 11 19:02:29 2001
@@ -82,3 +82,4 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(setup_arg_pages32);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S
--- v2.4.3/linux/arch/s390x/kernel/head.S	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/head.S	Wed Apr 11 19:02:29 2001
@@ -261,8 +261,9 @@
 	l     %r1,0xb8                         # load ipl subchannel number
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
-        st    %r1,__LC_IPLDEV                  # store ipl device number
         l     %r12,.Lparm                      # pointer to parameter area
+        st    %r1,__LC_IPLDEV                  # store ipl device number
+        st    %r1,IPL_DEVICE+4-PARMAREA(%r12)
 
 #
 # load parameter file from ipl device
@@ -405,16 +406,18 @@
 	sr    %r3,%r2
 	la    %r3,1(%r3)
 .done:
-	st    %r3,MEMORY_SIZE-PARMAREA(%r11)	
+	l     %r1,.memsize
+	st    %r3,4(%r1)
 	slr   %r0,%r0
-	st    %r0,INITRD_SIZE-PARMAREA(%r11)
-	st    %r0,INITRD_START-PARMAREA(%r11)
+	st    %r0,INITRD_SIZE+4-PARMAREA(%r11)
+	st    %r0,INITRD_START+4-PARMAREA(%r11)
 	j     startup                   # continue with startup
 .tbl:	.long _ebcasc			# translate table
 .cmd:	.long COMMAND_LINE		# address of command line buffer
 .parm:	.long PARMAREA
 .fourmeg: .long 0x00400000      	# 4M
 .pgmnw:	.long 0x00080000,.pgmx
+.memsize: .long memory_size
 .lowcase:
 	.byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 
 	.byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
@@ -480,21 +483,35 @@
 	bno   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
 .Lchkmem:
 	ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-	stg   %r1,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
+	lg    %r2,.Lmemsize-.LPG1(%r13)  # address of variable memory_size
+	stg   %r1,0(%r2)                 # store memory size
+
+	lg    %r12,.Lmflags-.LPG1(%r13)  # get address of machine_flags
 #
 # find out if we are running under VM
 #
         stidp  __LC_CPUID               # store cpuid
 	tm     __LC_CPUID,0xff          # running under VM ?
 	bno    .Lnovm-.LPG1(%r13)
-        oi     MACHINE_FLAGS+7-PARMAREA(%r12),1    # set VM flag
+        oi     7(%r12),1                # set VM flag
 .Lnovm:
         lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
         bne    .Lnop390-.LPG1(%r13)
-        oi     MACHINE_FLAGS+7-PARMAREA(%r12),4    # set P/390 flag
+        oi     7(%r12),4                # set P/390 flag
 .Lnop390:
 
+#
+# find out if we have the MVPG instruction
+#
+       mvc    __LC_PGM_NEW_PSW(16),.Lpcmvpg-.LPG1(%r13)
+       sgr    %r0,%r0
+       lghi   %r1,0
+       lghi   %r2,0
+       mvpg   %r1,%r2                   # Test CSP instruction
+       oi     7(%r12),16                # set MVPG flag
+.Lchkmvpg:
+
         lpswe .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
         .align 16
@@ -516,24 +533,23 @@
         .quad  0xc0000000               # cr14: machine check handling off
         .quad  0                        # cr15: linkage stack operations
 .Lpcmem:.quad  0x0000000180000000,.Lchkmem
+.Lpcmvpg:.quad 0x0000000180000000,.Lchkmvpg
 .Lflt0: .double 0
 .Lparm1:.quad  PARMAREA
 .Lhighoff:.long 0x7fffffff
 .L4malign:.quad 0xffffffffffc00000
 .Lbigmem:.quad 0x04000000
 .Lmaxchunk:.quad  0x00ffffff
+.Lmemsize:.quad memory_size
+.Lmflags:.quad machine_flags
 
 #
 # params at 10400 (setup.h)
 #
 	.org   PARMAREA
-        .quad  0x0100                   # ORIG_ROOT_DEV: ramdisk major/minor
-        .word  0                        # MOUNT_ROOT_RDONLY: no
-	.quad  0                        # MEMORY_SIZE
-	.quad  0                        # MACHINE_FLAGS (bit 0:VM)
+	.quad  0                        # IPL_DEVICE
         .quad  RAMDISK_ORIGIN           # INITRD_START
         .quad  RAMDISK_SIZE             # INITRD_SIZE
-	.word  0                        # RAMDISK_FLAGS
 
         .org   COMMAND_LINE
     	.byte  "root=/dev/ram0 ro"
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/irq.c linux/arch/s390x/kernel/irq.c
--- v2.4.3/linux/arch/s390x/kernel/irq.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/irq.c	Wed Apr 11 19:02:29 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/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
@@ -351,48 +352,6 @@
 
 #endif
 
-/*
- * Note : This fuction should be eliminated as it doesn't comply with the
- *         S/390 irq scheme we have implemented ...
- */
-int handle_IRQ_event(unsigned int irq, int cpu, struct pt_regs * regs)
-{
-	struct irqaction * action;
-	int                status;
-
-	status = 0;
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-		return( -ENODEV);
-
-	action = ioinfo[irq]->irq_desc.action;
-
-	if (action)
-	{
-		status |= 1;
-
-		if (!(action->flags & SA_INTERRUPT))
-			__sti();
-
-		do
-		{
-			status |= action->flags;
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-
-		if (status & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		__cli();
-
-	} /* endif */
-
-	return status;
-}
-
-void enable_nop(int irq)
-{
-}
 
 void __init init_IRQ(void)
 {
@@ -421,3 +380,8 @@
         /* For now, nothing... */
 }
 
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_bh_lock);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/irqextras390.c linux/arch/s390x/kernel/irqextras390.c
--- v2.4.3/linux/arch/s390x/kernel/irqextras390.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/irqextras390.c	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- *  arch/s390/kernel/irqextras390.c
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- *
- *  Some channel code by D.J. Barrow
- */
-
-/*
-	
-*/
-#include<asm/irqextras390.h>
-#include<asm/lowcore.h>
-
-#if 0
-// fixchannelprogram is now obselete
-void fixchannelprogram(orb_bits_t *orbptr)
-{
-	__u32	newAddress=orbptr->ccw_program_address;
-	fixccws(orbptr->ccw_program_address);
-	orbptr->ccw_program_address=newAddress;
-	orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address));
-}
-#endif
-
-void fixccws(ccw1_bits_t *ccwptr)
-{
-	for(;;ccwptr++)
-	{	// Just hope nobody starts doing prefixing
-		if(!ccwptr->cc)
-			break;
-	}
-}
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- v2.4.3/linux/arch/s390x/kernel/process.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/process.c	Wed Apr 11 19:02:29 2001
@@ -28,7 +28,7 @@
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
@@ -42,7 +42,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
-#include <asm/misc390.h>
 #include <asm/irq.h>
 
 spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
@@ -300,12 +299,10 @@
             unsigned long fprs[2];     /* fpr 4 and 6                      */
             unsigned long empty[2];
 #if CONFIG_REMOTE_DEBUG
-	    gdb_pt_regs childregs;
+	    struct gdb_pt_regs childregs;
 #else
-            pt_regs childregs;
+            struct pt_regs childregs;
 #endif
-            __u32   pgm_old_ilc;       /* single step magic from entry.S */
-            __u32   pgm_svc_step;
           } *frame;
 
         frame = (struct stack_frame *) (4*PAGE_SIZE + (unsigned long) p) -1;
@@ -321,7 +318,7 @@
 
         /* fake return stack for resume(), don't go back to schedule */
         frame->gprs[9]  = (unsigned long) frame;
-	frame->pgm_svc_step = 0; /* Nope we aren't single stepping an svc */
+	frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/ptrace.c linux/arch/s390x/kernel/ptrace.c
--- v2.4.3/linux/arch/s390x/kernel/ptrace.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/ptrace.c	Wed Apr 11 19:02:29 2001
@@ -153,7 +153,7 @@
 			useraddr = 2 * useraddr + sizeof(addr_t) / 2;
 		else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0))
 			useraddr = useraddr + PT_ACR0 / 2;
-		else if(useraddr < PT_ACR0 / 2 + (sizeof(user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
+		else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
 			useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; 
         }
 #endif  
@@ -174,15 +174,15 @@
 			{
 				copymax=PT_PSWMASK;
 			}
-			else if(useraddr<(PT_PSWMASK+PSW_MASK_SIZE))
+			else if(useraddr<(PT_PSWMASK+8))
 			{
-				copymax=(PT_PSWMASK+PSW_MASK_SIZE);
+				copymax=(PT_PSWMASK+8);
 				if(writingtouser)
 					mask=PSW_MASK_DEBUGCHANGE;
 			}
-			else if(useraddr<(PT_PSWADDR+PSW_ADDR_SIZE))
+			else if(useraddr<(PT_PSWADDR+8))
 			{
-				copymax=PT_PSWADDR+PSW_ADDR_SIZE;
+				copymax=PT_PSWADDR+8;
 				mask=PSW_ADDR_DEBUGCHANGE;
 			}
 			else
@@ -194,9 +194,9 @@
 			copymax=(PT_FPR15+sizeof(freg_t));
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
 		}
-		else if(useraddr<sizeof(user_regs_struct))
+		else if(useraddr<sizeof(struct user_regs_struct))
 		{
-			copymax=sizeof(user_regs_struct);
+			copymax=sizeof(struct user_regs_struct);
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
 		}
 		else 
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/s390_ext.c linux/arch/s390x/kernel/s390_ext.c
--- v2.4.3/linux/arch/s390x/kernel/s390_ext.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/s390_ext.c	Wed Apr 11 19:02:29 2001
@@ -7,6 +7,7 @@
  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <asm/lowcore.h>
@@ -74,4 +75,6 @@
         return 0;
 }
 
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/s390_ksyms.c linux/arch/s390x/kernel/s390_ksyms.c
--- v2.4.3/linux/arch/s390x/kernel/s390_ksyms.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/s390_ksyms.c	Wed Apr 11 19:02:29 2001
@@ -4,71 +4,18 @@
  *  S390 version
  */
 #include <linux/config.h>
-#include <linux/module.h>
-#include <linux/string.h>
 #include <linux/highuid.h>
-#include <asm/ccwcache.h>
-#include <asm/debug.h>
-#include <asm/irq.h>
-#include <asm/s390_ext.h>
-#include <asm/s390dyn.h>
-#include <asm/ebcdic.h>
+#include <linux/module.h>
+#include <linux/mm.h>
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
-#include <asm/idals.h>
-#if CONFIG_CHANDEV
-#include <asm/chandev.h>
-#endif
+#include <asm/setup.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(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_set_level);
-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_ascii_view);
-EXPORT_SYMBOL(debug_raw_view);
-EXPORT_SYMBOL(debug_dflt_header_fn);
-
-/*
  * memory management
  */
 EXPORT_SYMBOL(_oi_bitmap);
@@ -94,6 +41,7 @@
 EXPORT_SYMBOL_NOVERS(strlen);
 EXPORT_SYMBOL_NOVERS(strchr);
 EXPORT_SYMBOL_NOVERS(strcmp);
+EXPORT_SYMBOL_NOVERS(strcat);
 EXPORT_SYMBOL_NOVERS(strncat);
 EXPORT_SYMBOL_NOVERS(strncmp);
 EXPORT_SYMBOL_NOVERS(strncpy);
@@ -102,56 +50,22 @@
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
-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);
-
 /*
  * binfmt_elf loader 
  */
-EXPORT_SYMBOL(get_pte_slow);
-EXPORT_SYMBOL(get_pmd_slow);
 extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
 EXPORT_SYMBOL(dump_fpu);
-#ifdef CONFIG_S390_SUPPORT
-extern int setup_arg_pages32(struct linux_binprm *bprm);
-EXPORT_SYMBOL(setup_arg_pages32);
-#endif
 EXPORT_SYMBOL(overflowuid);
 EXPORT_SYMBOL(overflowgid);
 
 /*
  * misc.
  */
-EXPORT_SYMBOL(module_list);
+EXPORT_SYMBOL(machine_flags);
 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(lowcore_ptr);
-EXPORT_SYMBOL(global_bh_lock);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(smp_ctl_set_bit);
-EXPORT_SYMBOL(smp_ctl_clear_bit);
-#endif
 EXPORT_SYMBOL(kernel_thread);
-#if CONFIG_CHANDEV
-EXPORT_SYMBOL(chandev_register_and_probe);
-EXPORT_SYMBOL(chandev_request_irq);
-EXPORT_SYMBOL(chandev_unregister);
-EXPORT_SYMBOL(chandev_initdevice);
-EXPORT_SYMBOL(chandev_initnetdevice);
-#endif
+
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigibit ethernet multicast support */
 EXPORT_SYMBOL(arp_mc_map);
 #endif
-EXPORT_SYMBOL(s390_daemonize);
-EXPORT_SYMBOL (set_normalized_cda);
-
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/semaphore.c linux/arch/s390x/kernel/semaphore.c
--- v2.4.3/linux/arch/s390x/kernel/semaphore.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -158,145 +158,3 @@
 	spin_unlock_irqrestore(&semaphore_lock, flags);
 	return 1;
 }
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	up_read(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-}
-
-void rwsem_wake_writers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-}
-
-void __down_read_failed(int count, struct rw_semaphore *sem) 
-{
-	do {
-		if (count == -1) {
-			down_read_failed_biased(sem);
-			break;
-		}
-		down_read_failed(sem);
-		count = atomic_dec_return(&sem->count);
-	} while (count != 0);
-}
-
-void __down_write_failed(int count, struct rw_semaphore *sem)
-{
-	do {
-		if (count < 0 && count > -RW_LOCK_BIAS) {
-			down_write_failed_biased(sem);
-			break;
-		}
-		down_write_failed(sem);
-		count = atomic_add_return(-RW_LOCK_BIAS, &sem->count);
-	} while (count != 0);
-}
-
-void __rwsem_wake(int count, struct rw_semaphore *sem)
-{
-	if (count == 0)
-		rwsem_wake_readers(sem);
-	else
-		rwsem_wake_writers(sem);
-}
-
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/setup.c linux/arch/s390x/kernel/setup.c
--- v2.4.3/linux/arch/s390x/kernel/setup.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/setup.c	Wed Apr 11 19:02:29 2001
@@ -21,7 +21,7 @@
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
@@ -38,10 +38,13 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
+#include <asm/cpcmd.h>
 
 /*
  * Machine setup..
  */
+unsigned long memory_size = 0;
+unsigned long machine_flags = 0;
 __u16 boot_cpu_addr;
 int cpus_initialized = 0;
 unsigned long cpu_initialized = 0;
@@ -50,17 +53,8 @@
 /*
  * Setup options
  */
-
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;                  /* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;           /* 1 = prompt for ramdisk, 0 = don't prompt*/
-extern int rd_image_start;             /* starting block # of image        */
-#endif
-
-extern int root_mountflags;
 extern int _text,_etext, _edata, _end;
 
-
 /*
  * This is set up by the setup-routine at boot-time
  * for S390 need to find out, what we have to setup
@@ -205,18 +199,9 @@
 	       "We are running under VM\n" :
 	       "We are running native\n");
 
-        ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
-#ifdef CONFIG_BLK_DEV_RAM
-        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-        rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-        rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-	/* nasty stuff with PARMAREAs. we use head.S or parameterline
-	  if (!MOUNT_ROOT_RDONLY)
-	  root_mountflags &= ~MS_RDONLY;
-	*/
+        ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
-	memory_end = MEMORY_SIZE;                /* detected in head.s */
+	memory_end = memory_size;                /* detected in head.s */
         init_mm.start_code = PAGE_OFFSET;
         init_mm.end_code = (unsigned long) &_etext;
         init_mm.end_data = (unsigned long) &_edata;
@@ -303,9 +288,6 @@
          * bootmem allocator with an invalid RAM area.
          */
         reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
-
-
-
 
 #ifdef CONFIG_BLK_DEV_INITRD
         if (INITRD_START) {
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/signal.c linux/arch/s390x/kernel/signal.c
--- v2.4.3/linux/arch/s390x/kernel/signal.c	Fri Feb 16 16:02:35 2001
+++ linux/arch/s390x/kernel/signal.c	Wed Apr 11 19:02:29 2001
@@ -188,7 +188,7 @@
 	int err;
 	s390_fp_regs fpregs;
   
-	err = __copy_to_user(&sregs->regs,regs,sizeof(s390_regs_common));
+	err = __copy_to_user(&sregs->regs,regs,sizeof(_s390_regs_common));
 	if(!err)
 	{
 		save_fp_regs(&fpregs);
@@ -203,7 +203,7 @@
 	int err;
 	s390_fp_regs fpregs;
 	psw_t saved_psw=regs->psw;
-	err=__copy_from_user(regs,&sregs->regs,sizeof(s390_regs_common));
+	err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common));
 	if(!err)
 	{
 		regs->orig_gpr2 = -1;		/* disable syscall checks */
@@ -219,7 +219,7 @@
 }
 
 static int
-restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
+restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 		 _sigregs *sregs,sigset_t *set)
 {
 	unsigned int err;
@@ -562,6 +562,7 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
                                 if (do_coredump(signr, regs))
                                         exit_code |= 0x80;
                                 /* FALLTHRU */
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/signal32.c linux/arch/s390x/kernel/signal32.c
--- v2.4.3/linux/arch/s390x/kernel/signal32.c	Fri Feb 16 16:02:35 2001
+++ linux/arch/s390x/kernel/signal32.c	Wed Apr 11 19:02:29 2001
@@ -343,7 +343,7 @@
 }
 
 static int
-restore_sigcontext32(struct sigcontext32 *sc, pt_regs *regs,
+restore_sigcontext32(struct sigcontext32 *sc, struct pt_regs *regs,
 		 _sigregs32 *sregs,sigset_t *set)
 {
 	unsigned int err;
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c
--- v2.4.3/linux/arch/s390x/kernel/smp.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/smp.c	Wed Apr 11 19:02:29 2001
@@ -20,6 +20,7 @@
  * cpu_number_map in other architectures.
  */
 
+#include <linux/module.h>
 #include <linux/init.h>
 
 #include <linux/mm.h>
@@ -33,8 +34,7 @@
 #include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
-
-#include "cpcmd.h"
+#include <asm/cpcmd.h>
 
 /* prototypes */
 extern int cpu_idle(void * unused);
@@ -392,7 +392,7 @@
 
         /* stop all processors */
 
-        smp_signal_others(sigp_stop, 0, TRUE, NULL);
+        smp_signal_others(sigp_stop, 0, 1, NULL);
 
         /* store status of all processors in their lowcores (real 0) */
 
@@ -574,7 +574,7 @@
        struct pt_regs regs;
        /* don't care about the psw and regs settings since we'll never
           reschedule the forked task. */
-       memset(&regs,0,sizeof(pt_regs));
+       memset(&regs,0,sizeof(struct pt_regs));
        return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
 }
 
@@ -758,3 +758,8 @@
         }
 }
 
+EXPORT_SYMBOL(lowcore_ptr);
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
+EXPORT_SYMBOL(smp_num_cpus);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/sys_s390.c linux/arch/s390x/kernel/sys_s390.c
--- v2.4.3/linux/arch/s390x/kernel/sys_s390.c	Mon Mar 19 12:35:11 2001
+++ linux/arch/s390x/kernel/sys_s390.c	Wed Apr 11 19:02:29 2001
@@ -123,7 +123,7 @@
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc (uint call, int first, int second, 
+asmlinkage int sys_ipc (uint call, int first, long second, 
                         unsigned long third, void *ptr)
 {
         struct ipc_kludge tmp;
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/lib/Makefile linux/arch/s390x/lib/Makefile
--- v2.4.3/linux/arch/s390x/lib/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/lib/Makefile	Wed Apr 11 19:02:29 2001
@@ -12,7 +12,8 @@
 
 L_TARGET = lib.a
 
-obj-y	 = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
+obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o
+export-objs += misaligned.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/lib/delay.c linux/arch/s390x/lib/delay.c
--- v2.4.3/linux/arch/s390x/lib/delay.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/lib/delay.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- *  arch/s390/kernel/delay.c
+ *  arch/s390x/kernel/delay.c
  *    Precise Delay Loops for S390
  *
  *  S390 version
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/lib/misaligned.c linux/arch/s390x/lib/misaligned.c
--- v2.4.3/linux/arch/s390x/lib/misaligned.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390x/lib/misaligned.c	Wed Apr 11 19:02:30 2001
@@ -0,0 +1,34 @@
+/*
+ *  arch/s390/lib/misaligned.c
+ *    S390 misalignment panic stubs
+ *
+ *  S390 version
+ *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com).
+ *
+ * xchg wants to panic if the pointer is not aligned. To avoid multiplying
+ * the panic message over and over again, the panic is done in the helper
+ * functions __misaligned_u64, __misaligned_u32 and __misaligned_u16.
+ */
+ 
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+void __misaligned_u16(void)
+{
+	panic("misaligned (__u16 *) in __xchg\n");
+}
+
+void __misaligned_u32(void)
+{
+	panic("misaligned (__u32 *) in __xchg\n");
+}
+
+void __misaligned_u64(void)
+{
+	panic("misaligned (__u64 *) in __xchg\n");
+}
+
+EXPORT_SYMBOL(__misaligned_u16);
+EXPORT_SYMBOL(__misaligned_u32);
+EXPORT_SYMBOL(__misaligned_u64);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c
--- v2.4.3/linux/arch/s390x/mm/fault.c	Mon Mar 19 12:35:11 2001
+++ linux/arch/s390x/mm/fault.c	Wed Apr 11 19:02:30 2001
@@ -33,6 +33,34 @@
 
 extern void die(const char *,struct pt_regs *,long);
 
+extern spinlock_t timerlist_lock;
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out
+ */
+void bust_spinlocks(int yes)
+{
+        spin_lock_init(&timerlist_lock);
+        if (yes) {
+                oops_in_progress = 1;
+#ifdef CONFIG_SMP
+                atomic_set(&global_irq_lock,0);
+#endif
+        } else {
+                int loglevel_save = console_loglevel;
+                oops_in_progress = 0;
+                /*
+                 * OK, the message is on the console.  Now we call printk()
+                 * without oops_in_progress set so that printk will give klogd
+                 * a poke.  Hold onto your hats...
+                 */
+                console_loglevel = 15;          /* NMI oopser may have shut the console up */
+                printk(" ");
+                console_loglevel = loglevel_save;
+        }
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/mm/init.c linux/arch/s390x/mm/init.c
--- v2.4.3/linux/arch/s390x/mm/init.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/mm/init.c	Wed Apr 11 19:02:30 2001
@@ -35,31 +35,13 @@
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
 #include <asm/lowcore.h>
+ 
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
-/*
- * empty_bad_page is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving an inode
- * unused etc..
- *
- * empty_bad_pte_table is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * empty_bad_pmd_table is the accompanying segment table: it is initialized
- * to point to empty_bad_pte_table page tables.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
-char  empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
-pmd_t empty_bad_pmd_table[PTRS_PER_PMD] __attribute__((__aligned__(PAGE_SIZE)));
-pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE)));
 
 static int test_access(unsigned long loc)
 {
@@ -88,79 +70,6 @@
 	return rc;
 }
 
-static pmd_t *get_bad_pmd_table(void)
-{
-       pmd_t v;
-       int i;
-
-       pmd_set(&v, empty_bad_pte_table);
-
-       for (i = 0; i < PTRS_PER_PMD; i++)
-               empty_bad_pmd_table[i] = v;
-
-       return empty_bad_pmd_table;
-}
-
-static pte_t *get_bad_pte_table(void)
-{
-	pte_t v;
-	int i;
-
-	v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
-
-	for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
-		empty_bad_pte_table[i] = v;
-
-	return empty_bad_pte_table;
-}
-
-pmd_t *
-get_pmd_slow(pgd_t *pgd, unsigned long offset)
-{
-        pmd_t *pmd;
-        int i;
-
-        pmd = (pmd_t *) __get_free_pages(GFP_KERNEL,2);
-        if (pgd_none(*pgd)) {
-                if (pmd) {
-                        for (i = 0; i < PTRS_PER_PMD; i++)
-                                pmd_clear(pmd+i);
-                        pgd_set(pgd, pmd);
-                        return pmd + offset;
-                }
-                pmd = (pmd_t *) get_bad_pmd_table();
-                pgd_set(pgd, pmd);
-                return NULL;
-        }
-        free_pages((unsigned long)pmd,2);
-        if (pgd_bad(*pgd))
-		BUG();
-        return (pmd_t *) pgd_page(*pgd) + offset;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-        pte_t *pte;
-        int i;
-
-        pte = (pte_t*) __get_free_page(GFP_KERNEL);
-        if (pmd_none(*pmd)) {
-                if (pte) {
-                        for (i=0;i<PTRS_PER_PTE;i++)
-                                pte_clear(pte+i);
-                        pmd_set(pmd,pte);
-                        return pte + offset;
-                }
-		pte = (pte_t*) get_bad_pte_table();
-                pmd_set(pmd,pte);
-                return NULL;
-        }
-        free_page(__pa(pte));
-        if (pmd_bad(*pmd))
-		BUG();
-        return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
@@ -169,9 +78,9 @@
                         if(pgd_quicklist)
                                 free_pgd_slow(get_pgd_fast()), freed += 4;
                         if(pmd_quicklist)
-                                free_pmd_slow(get_pmd_fast()), freed += 4;
+                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed += 4;
                         if(pte_quicklist)
-                                free_pte_slow(get_pte_fast()), freed++;
+                                pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++;
                 } while(pgtable_cache_size > low);
         }
         return freed;
@@ -259,34 +168,34 @@
         for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
 
                 if (address >= end_mem) {
-                  pgd_clear(pg_dir);
-                  continue;
+                        pgd_clear(pg_dir);
+                        continue;
                 }          
         
 	        pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4);
-                pgd_set(pg_dir,pm_dir);
+                pgd_populate(&init_mm, pg_dir, pm_dir);
 
                 for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
-                  if (address >= end_mem) {
-                    pmd_clear(pm_dir);
-                    continue; 
-                  }          
-
+                        if (address >= end_mem) {
+                                pmd_clear(pm_dir);
+                                continue; 
+                        }          
+                        
                         pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-                        pmd_set(pm_dir,pt_dir);
+                        pmd_populate(&init_mm, pm_dir, pt_dir);
 	
                         for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
-                          pte = mk_pte_phys(address, PAGE_KERNEL);
-                          if (address >= end_mem) {
-                            pte_clear(&pte); 
-                            continue;
-                          }
-                          set_pte(pt_dir, pte);
-                          address += PAGE_SIZE;
+                                pte = mk_pte_phys(address, PAGE_KERNEL);
+                                if (address >= end_mem) {
+                                        pte_clear(&pte); 
+                                        continue;
+                                }
+                                set_pte(pt_dir, pte);
+                                address += PAGE_SIZE;
                         }
                 }
         }
-
+        
         /* enable virtual mapping in kernel mode */
         __asm__ __volatile__("lctlg 1,1,%0\n\t"
                              "lctlg 7,7,%0\n\t"
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/mm/ioremap.c linux/arch/s390x/mm/ioremap.c
--- v2.4.3/linux/arch/s390x/mm/ioremap.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/mm/ioremap.c	Wed Apr 11 19:02:30 2001
@@ -54,7 +54,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
@@ -67,6 +67,7 @@
 static int remap_area_pages(unsigned long address, unsigned long phys_addr,
 				 unsigned long size, unsigned long flags)
 {
+	int error;
 	pgd_t * dir;
 	unsigned long end = address + size;
 
@@ -75,17 +76,21 @@
 	flush_cache_all();
 	if (address >= end)
 		BUG();
+	spin_lock(&init_mm.page_table_lock);
 	do {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
 		if (!pmd)
-			return -ENOMEM;
+			break;
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
-			return -ENOMEM;
-		set_pgdir(address, *dir);
+			break;
+		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/tools/dasdfmt/dasdfmt.c linux/arch/s390x/tools/dasdfmt/dasdfmt.c
--- v2.4.3/linux/arch/s390x/tools/dasdfmt/dasdfmt.c	Fri Mar  2 11:12:06 2001
+++ linux/arch/s390x/tools/dasdfmt/dasdfmt.c	Wed Apr 11 19:02:29 2001
@@ -7,6 +7,7 @@
  *    Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
  *
  *  Device-in-use-checks by Fritz Elfert, <felfert@to.com>
+ *  Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
  *
  * Still to do:
  *   detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them 
@@ -157,14 +158,15 @@
 exit_usage(int exitcode)
 {
 #ifdef RANGE_FORMATTING
-	printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
 		"<diskspec>\n\n",prog_name);
 #else /* RANGE_FORMATTING */
-	printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
 		"<diskspec>\n\n",prog_name);
 #endif /* RANGE_FORMATTING */
 	printf("       -t means testmode\n");
 	printf("       -v means verbose mode\n");
+	printf("       -C means format compatible disk layout\n");
 	printf("       -V means print version\n");
 	printf("       -L means don't write disk label\n");
 	printf("       <label> is a label which is converted to EBCDIC and " \
@@ -200,7 +202,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) &&
@@ -218,7 +220,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);
 }
 
@@ -488,14 +491,14 @@
 	}
 	check_mounted(major_no, minor_no);
 
+	get_xno_from_xno(&devno,&major_no,&minor_no,
+			GIVEN_MAJOR|GIVEN_MINOR);
 	if ((!writenolabel) && (!labelspec)) {
 		sprintf(label,"LNX1 x%04x",devno);
 	}
 	
 	if ( ((withoutprompt)&&(verbosity>=1)) ||
 		(!withoutprompt) ) {
-		get_xno_from_xno(&devno,&major_no,&minor_no,
-			GIVEN_MAJOR|GIVEN_MINOR);
 		printf("\nI am going to format the device %s in the " \
 			"following way:\n",dev_name);
 		printf("   Device number of device : 0x%x\n",devno);
@@ -505,6 +508,9 @@
 			"no":"yes");
 		if (!writenolabel)
 			printf("   Disk label              : %s\n",label);
+		if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
+			printf("   Compatible Disk Layout  : %s\n",(format_params.intensity&0x08)?
+			       "yes":"no");
 #ifdef RANGE_FORMATTING
 		printf("   Start track             : %d\n" \
 			,format_params.start_unit);
@@ -558,7 +564,7 @@
 			}
 	
 
-			rc=ioctl(fd,BLKGETSIZE,&new_blksize);
+			rc=ioctl(fd,BLKSSZGET,&new_blksize);
 			if (rc) {
 				ERRMSG("%s: the ioctl call to get blocksize " \
 					"returned with the following error " \
@@ -664,9 +670,9 @@
 	opterr=0;
 
 #ifdef RANGE_FORMATTING
-	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
 #endif /* RANGE_FORMATTING */
-	while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
+	while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
 		switch (oc) {
 		case 'y':
 			withoutprompt=1;
@@ -686,6 +692,9 @@
 
 		case 'h':
 			exit_usage(0);
+		case 'C':
+                	format_params.intensity&=0x08;
+			break;
 
 		case 'V':
 			printf("%s version 0.99\n",prog_name);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/tools/silo/silo.c linux/arch/s390x/tools/silo/silo.c
--- v2.4.3/linux/arch/s390x/tools/silo/silo.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/tools/silo/silo.c	Wed Apr 11 19:02:29 2001
@@ -9,6 +9,9 @@
  *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
  *               Fritz Elfert <felfert@to.com> contributed support for
  *                	/etc/silo.conf based on Intel's lilo
+ *    Changes  :
+ *               01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *                 adapted to deal with devices and bootsects of various sizes
  */
 
 #include <stddef.h>
@@ -376,7 +379,7 @@
     if ( errno == ENOENT ) {
       ITRY (creat ( o-> bootmap, O_RDWR ));
     } else {
-      PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap,
+      PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
 		  strerror(errno));
     }
   }
@@ -482,6 +485,7 @@
   int bs, boots;
   char *tmpdev;
   char buffer[4096]={0,};
+  int blocksize, sectsize;
   ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
   ITRY (fstat (d_fd, &d_st));
   ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
@@ -508,6 +512,7 @@
   NTRY ( tmpdev = tmpnam(NULL) );
   ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
   ITRY (bd_fd = open (tmpdev, O_RDONLY));
+  ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
   ITRY (ioctl(s_fd,FIBMAP,&boots));
   ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
   PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
@@ -515,13 +520,21 @@
   close(s_fd);
   ITRY (unlink(tmpdev));
   /* Now patch the bootsector */
+  ITRY (stat (o->bootsect, &b_st));
+  if ((sectsize = b_st.st_size) > blocksize )
+    {
+      ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
+      rc = -1;
+      errno = EINVAL;
+    }
   ITRY (b_fd = open (o->bootsect, O_RDONLY));
-  NTRY (read (b_fd, buffer, 4096));
+  ITRY (read (b_fd, buffer, sectsize));
   memset (buffer + 0xe0, 0, 8);
   *(int *) (buffer + 0xe0) = boots;
   if ( o -> testlevel <= 0 ) {
-    NTRY (write (d_fd, buffer, 4096));
-    NTRY (write (d_fd, buffer, 4096));
+    ITRY (write (d_fd, buffer, sectsize));
+    ITRY (lseek (d_fd, blocksize, SEEK_SET));
+    ITRY (write (d_fd, buffer, sectsize));
   }
   close (b_fd);
   close (d_fd);
diff -u --recursive --new-file v2.4.3/linux/arch/s390x/vmlinux.lds linux/arch/s390x/vmlinux.lds
--- v2.4.3/linux/arch/s390x/vmlinux.lds	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/vmlinux.lds	Wed Apr 11 19:02:29 2001
@@ -26,6 +26,10 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
+  __start___kallsyms = .;       /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   _etext = .;			/* End of text section */
 
   .data : {			/* Data */
diff -u --recursive --new-file v2.4.3/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.4.3/linux/arch/sh/config.in	Thu Jan  4 13:19:13 2001
+++ linux/arch/sh/config.in	Tue Apr 17 17:19:25 2001
@@ -7,6 +7,8 @@
 define_bool CONFIG_SUPERH y
 
 define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile
--- v2.4.3/linux/arch/sh/kernel/Makefile	Thu Jan  4 13:19:13 2001
+++ linux/arch/sh/kernel/Makefile	Wed Apr 11 21:24:52 2001
@@ -20,16 +20,23 @@
 
 obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
 obj-$(CONFIG_CPU_SH4)		+= fpu.o
-obj-$(CONFIG_PCI)		+= pci-sh.o 
 obj-$(CONFIG_SH_RTC)            += rtc.o
 obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
 
+ifeq ($(CONFIG_PCI),y)
+obj-y				+= pci-sh.o 
+obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o
+endif
+
 obj-$(CONFIG_SH_HP600)		+= mach_hp600.o
 machine-specific-objs		+= mach_hp600.o
 
 obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o
 machine-specific-objs		+= mach_se.o setup_se.o io_se.o led_se.o
 
+obj-$(CONFIG_SH_CAT68701) 	+= mach_cat68701.o io_cat68701.o
+machine-specific-objs		+= mach_cat68701.o io_cat68701.o
+
 obj-$(CONFIG_SH_CQREEK)		+= setup_cqreek.o
 machine-specific-objs		+= setup_cqreek.o
 
@@ -39,9 +46,13 @@
 obj-$(CONFIG_HD64461)		+= setup_hd64461.o io_hd64461.o
 machine-specific-objs		+= setup_hd64461.o io_hd64461.o
 
+obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) +=irq_intc2.o
+
 # Doesn't compile well, so don't include in machine-specific-objs
-obj-$(CONFIG_HD64465)		+= setup_hd64465.o io_hd64465.o
-obj-$(CONFIG_SH_FOOBAR)		+= mach_foobar.o
+obj-$(CONFIG_HD64465)		+= setup_hd64465.o io_hd64465.o hd64465_gpio.o
+obj-$(CONFIG_SH_DMIDA)		+= mach_dmida.o
+obj-$(CONFIG_SH_EC3104)         += setup_ec3104.o io_ec3104.o mach_ec3104.o
+obj-$(CONFIG_SH_DREAMCAST)	+= mach_dc.o setup_dc.o io_dc.o
 
 ifeq ($(CONFIG_SH_GENERIC),y)
 obj-y		+= $(machine-specific-objs)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/cf-enabler.c linux/arch/sh/kernel/cf-enabler.c
--- v2.4.3/linux/arch/sh/kernel/cf-enabler.c	Thu Aug 10 13:03:25 2000
+++ linux/arch/sh/kernel/cf-enabler.c	Wed Apr 11 21:24:52 2001
@@ -8,13 +8,41 @@
  *  Enable the CF configuration.
  */
 
+#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include <asm/hitachi_se.h>
+#define CF_CIS_BASE	0xb8000000
+/*
+ * You can connect Compact Flash directly to the bus of SuperH.
+ * This is the enabler for that.
+ *
+ * SIM: How generic is this really? It looks pretty board, or at
+ * least SH sub-type, specific to me.
+ * I know it doesn't work on the Overdrive!
+ */
+
+/*
+ * 0xB8000000 : Attribute
+ * 0xB8001000 : Common Memory
+ * 0xBA000000 : I/O
+ */
 
+static int __init cf_init_default(void)
+{
+#ifdef CONFIG_IDE
+	/* Enable the card, and set the level interrupt */
+	ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
+#endif
+	make_imask_irq(14);
+	disable_irq(14);
+	return 0;
+}
+
+#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_SOLUTION_ENGINE)
+#include <asm/hitachi_se.h>
 
 /*
  * SolutionEngine
@@ -70,37 +98,14 @@
 	ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200);
 	return 0;
 }
-
-#define CF_CIS_BASE	0xb8000000
-/*
- * You can connect Compact Flash directly to the bus of SuperH.
- * This is the enabler for that.
- *
- * SIM: How generic is this really? It looks pretty board, or at
- * least SH sub-type, specific to me.
- * I know it doesn't work on the Overdrive!
- */
-
-/*
- * 0xB8000000 : Attribute
- * 0xB8001000 : Common Memory
- * 0xBA000000 : I/O
- */
-
-static int __init cf_init_default(void)
-{
-	/* Enable the card, and set the level interrupt */
-	ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
-	make_imask_irq(14);
-	disable_irq(14);
-	return 0;
-}
+#endif
 
 int __init cf_init(void)
 {
-	if (MACH_SE) {
+#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_SOLUTION_ENGINE)
+	if (MACH_SE)
 		return cf_init_se();
-	}
+#endif
 	return cf_init_default();
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- v2.4.3/linux/arch/sh/kernel/entry.S	Sun Jan 28 18:56:00 2001
+++ linux/arch/sh/kernel/entry.S	Wed Apr 11 21:24:52 2001
@@ -182,7 +182,7 @@
 	jsr	@r0
 	 mov	r15, r4
 	!
-	tst	#0xff, r0
+	tst	r0, r0
 	bf/s	0f
 	 lds	r10, pr
 	rts
@@ -550,10 +550,10 @@
 ret_with_reschedule:
 	stc	k_current, r1
 	mov.l	@(need_resched,r1), r0
-	tst	#0xff, r0
+	tst	r0, r0
 	bf	reschedule
 	mov.l	@(sigpending,r1), r0
-	tst	#0xff, r0
+	tst	r0, r0
 	bt	restore_all
 signal_return:
 	mov	r15, r4
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/hd64465_gpio.c linux/arch/sh/kernel/hd64465_gpio.c
--- v2.4.3/linux/arch/sh/kernel/hd64465_gpio.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/hd64465_gpio.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,185 @@
+/*
+ * $Id: hd64465_gpio.c,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc
+ *
+ * GPIO pin support for HD64465 companion chip.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/hd64465_gpio.h>
+
+#define _PORTOF(portpin)    (((portpin)>>3)&0x7)
+#define _PINOF(portpin)     ((portpin)&0x7)
+
+/* Register addresses parametrised on port */
+#define GPIO_CR(port)	    (HD64465_REG_GPACR+((port)<<1))
+#define GPIO_DR(port)	    (HD64465_REG_GPADR+((port)<<1))
+#define GPIO_ICR(port)	    (HD64465_REG_GPAICR+((port)<<1))
+#define GPIO_ISR(port)	    (HD64465_REG_GPAISR+((port)<<1))
+
+#define GPIO_NPORTS 5
+
+#define MODNAME "hd64465_gpio"
+
+EXPORT_SYMBOL(hd64465_gpio_configure);
+EXPORT_SYMBOL(hd64465_gpio_get_pin);
+EXPORT_SYMBOL(hd64465_gpio_get_port);
+EXPORT_SYMBOL(hd64465_gpio_register_irq);
+EXPORT_SYMBOL(hd64465_gpio_set_pin);
+EXPORT_SYMBOL(hd64465_gpio_set_port);
+EXPORT_SYMBOL(hd64465_gpio_unregister_irq);
+
+/* TODO: each port should be protected with a spinlock */
+
+
+void hd64465_gpio_configure(int portpin, int direction)
+{
+    	unsigned short cr;
+	unsigned int shift = (_PINOF(portpin)<<1);
+
+	cr = inw(GPIO_CR(_PORTOF(portpin)));
+	cr &= ~(3<<shift);
+	cr |= direction<<shift;
+	outw(cr, GPIO_CR(_PORTOF(portpin)));
+}
+
+void hd64465_gpio_set_pin(int portpin, unsigned int value)
+{
+    	unsigned short d;
+	unsigned short mask = 1<<(_PINOF(portpin));
+	
+	d = inw(GPIO_DR(_PORTOF(portpin)));
+	if (value)
+	    d |= mask;
+	else
+	    d &= ~mask;
+	outw(d, GPIO_DR(_PORTOF(portpin)));
+}
+
+unsigned int hd64465_gpio_get_pin(int portpin)
+{
+	return inw(GPIO_DR(_PORTOF(portpin))) & (1<<(_PINOF(portpin)));
+}
+
+/* TODO: for cleaner atomicity semantics, add a mask to this routine */
+
+void hd64465_gpio_set_port(int port, unsigned int value)
+{
+	outw(value, GPIO_DR(port));
+}
+
+unsigned int hd64465_gpio_get_port(int port)
+{
+	return inw(GPIO_DR(port));
+}
+
+
+static struct {
+    void (*func)(int portpin, void *dev);
+    void *dev;
+} handlers[GPIO_NPORTS * 8];
+
+static void hd64465_gpio_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+    	unsigned short port, pin, isr, mask, portpin;
+	
+	for (port=0 ; port<GPIO_NPORTS ; port++) {
+	    isr = inw(GPIO_ISR(port));
+	    
+	    for (pin=0 ; pin<8 ; pin++) {
+	    	mask = 1<<pin;
+	    	if (isr & mask) {
+		    portpin = (port<<3)|pin;
+		    if (handlers[portpin].func != 0)
+		    	handlers[portpin].func(portpin, handlers[portpin].dev);
+    	    	    else
+		    	printk(KERN_NOTICE "unexpected GPIO interrupt, pin %c%d\n",
+			    port+'A', (int)pin);
+		}
+	    }
+	    
+	    /* Write 1s back to ISR to clear it?  That's what the manual says.. */
+	    outw(isr, GPIO_ISR(port));
+	}
+}
+
+void hd64465_gpio_register_irq(int portpin, int mode,
+	void (*handler)(int portpin, void *dev), void *dev)
+{
+    	unsigned long flags;
+	unsigned short icr, mask;
+
+	if (handler == 0)
+	    return;
+	    
+	save_and_cli(flags);
+	
+	handlers[portpin].func = handler;
+	handlers[portpin].dev = dev;
+
+    	/*
+	 * Configure Interrupt Control Register
+	 */
+	icr = inw(GPIO_ICR(_PORTOF(portpin)));
+	mask = (1<<_PINOF(portpin));
+	
+	/* unmask interrupt */
+	icr &= ~mask;
+	
+	/* set TS bit */
+	mask <<= 8;
+	icr &= ~mask;
+	if (mode == HD64465_GPIO_RISING)
+	    icr |= mask;
+	    
+	outw(icr, GPIO_ICR(_PORTOF(portpin)));
+
+	restore_flags(flags);
+}
+
+void hd64465_gpio_unregister_irq(int portpin)
+{
+    	unsigned long flags;
+	unsigned short icr;
+	
+	save_and_cli(flags);
+
+    	/*
+	 * Configure Interrupt Control Register
+	 */
+	icr = inw(GPIO_ICR(_PORTOF(portpin)));
+	icr |= (1<<_PINOF(portpin));	/* mask interrupt */
+	outw(icr, GPIO_ICR(_PORTOF(portpin)));
+
+	handlers[portpin].func = 0;
+	handlers[portpin].dev = 0;
+	
+	restore_flags(flags);
+}
+
+static int __init hd64465_gpio_init(void)
+{
+    	/* TODO: check return values */
+    	request_region(HD64465_REG_GPACR, 0x1000, MODNAME);
+	request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt,
+	    SA_INTERRUPT, MODNAME, 0);
+
+    	printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO);
+	return 0;
+}
+
+static void __exit hd64465_gpio_exit(void)
+{
+    	release_region(HD64465_REG_GPACR, 0x1000);
+	free_irq(HD64465_IRQ_GPIO, 0);
+}
+
+module_init(hd64465_gpio_init);
+module_exit(hd64465_gpio_exit);
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io.c linux/arch/sh/kernel/io.c
--- v2.4.3/linux/arch/sh/kernel/io.c	Mon Oct  2 11:57:34 2000
+++ linux/arch/sh/kernel/io.c	Wed Apr 11 21:24:52 2001
@@ -8,123 +8,149 @@
  */
 
 #include <asm/io.h>
+#include <linux/module.h>
 
-unsigned int _inb(unsigned long port)
+unsigned char _inb(unsigned long port)
 {
 	return __inb(port);
 }
+EXPORT_SYMBOL(_inb);
 
-unsigned int _inw(unsigned long port)
+unsigned short _inw(unsigned long port)
 {
 	return __inw(port);
 }
+EXPORT_SYMBOL(_inw);
 
 unsigned int _inl(unsigned long port)
 {
 	return __inl(port);
 }
+EXPORT_SYMBOL(_inl);
 
 void _outb(unsigned char b, unsigned long port)
 {
 	__outb(b, port);
 }
+EXPORT_SYMBOL(_outb);
 
 void _outw(unsigned short b, unsigned long port)
 {
 	__outw(b, port);
 }
+EXPORT_SYMBOL(_outw);
+
 
 void _outl(unsigned int b, unsigned long port)
 {
 	__outl(b, port);
 }
+EXPORT_SYMBOL(_outl);
+
 
-unsigned int _inb_p(unsigned long port)
+unsigned char _inb_p(unsigned long port)
 {
 	return __inb_p(port);
 }
+EXPORT_SYMBOL(_inb_p);
 
-unsigned int _inw_p(unsigned long port)
+unsigned short _inw_p(unsigned long port)
 {
 	return __inw_p(port);
 }
+EXPORT_SYMBOL(_inw_p);
+
 
 void _outb_p(unsigned char b, unsigned long port)
 {
 	__outb_p(b, port);
 }
+EXPORT_SYMBOL(_outb_p);
 
 void _outw_p(unsigned short b, unsigned long port)
 {
 	__outw_p(b, port);
 }
+EXPORT_SYMBOL(_outw_p);
 
 void _insb(unsigned long port, void *buffer, unsigned long count)
 {
 	return __insb(port, buffer, count);
 }
+EXPORT_SYMBOL(_insb);
 
 void _insw(unsigned long port, void *buffer, unsigned long count)
 {
 	__insw(port, buffer, count);
 }
+EXPORT_SYMBOL(_insw);
 
 void _insl(unsigned long port, void *buffer, unsigned long count)
 {
 	__insl(port, buffer, count);
 }
+EXPORT_SYMBOL(_insl);
 
 void _outsb(unsigned long port, const void *buffer, unsigned long count)
 {
 	__outsb(port, buffer, count);
 }
+EXPORT_SYMBOL(_outsb);
 
 void _outsw(unsigned long port, const void *buffer, unsigned long count)
 {
 	__outsw(port, buffer, count);
 }
+EXPORT_SYMBOL(_outsw);
 
 void _outsl(unsigned long port, const void *buffer, unsigned long count)
 {
 	__outsl(port, buffer, count);
 
 }
+EXPORT_SYMBOL(_outsl);
 
-unsigned long ___raw_readb(unsigned long addr)
+unsigned char ___raw_readb(unsigned long addr)
 {
 	return __readb(addr);
 }
+EXPORT_SYMBOL(___raw_readb);
 
-unsigned long ___raw_readw(unsigned long addr)
+unsigned short ___raw_readw(unsigned long addr)
 {
 	return __readw(addr);
 }
+EXPORT_SYMBOL(___raw_readw);
 
-unsigned long ___raw_readl(unsigned long addr)
+unsigned int ___raw_readl(unsigned long addr)
 {
 	return __readl(addr);
 }
+EXPORT_SYMBOL(___raw_readl);
 
-unsigned long _readb(unsigned long addr)
+unsigned char _readb(unsigned long addr)
 {
 	unsigned long r = __readb(addr);
 	mb();
 	return r;
 }
+EXPORT_SYMBOL(_readb);
 
-unsigned long _readw(unsigned long addr)
+unsigned short _readw(unsigned long addr)
 {
 	unsigned long r = __readw(addr);
 	mb();
 	return r;
 }
+EXPORT_SYMBOL(_readw);
 
-unsigned long _readl(unsigned long addr)
+unsigned int _readl(unsigned long addr)
 {
 	unsigned long r = __readl(addr);
 	mb();
 	return r;
 }
+EXPORT_SYMBOL(_readl);
 
 void ___raw_writeb(unsigned char b, unsigned long addr)
 {
@@ -135,29 +161,34 @@
 {
 	__writew(b, addr);
 }
+EXPORT_SYMBOL(___raw_writew);
 
 void ___raw_writel(unsigned int b, unsigned long addr)
 {
 	__writel(b, addr);
 }
+EXPORT_SYMBOL(___raw_writel);
 
 void _writeb(unsigned char b, unsigned long addr)
 {
 	__writeb(b, addr);
 	mb();
 }
+EXPORT_SYMBOL(_writeb);
 
 void _writew(unsigned short b, unsigned long addr)
 {
 	__writew(b, addr);
 	mb();
 }
+EXPORT_SYMBOL(_writew);
 
 void _writel(unsigned int b, unsigned long addr)
 {
 	__writel(b, addr);
 	mb();
 }
+EXPORT_SYMBOL(_writel);
 
 /*
  * Copy data from IO memory space to "real" memory space.
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_cat68701.c linux/arch/sh/kernel/io_cat68701.c
--- v2.4.3/linux/arch/sh/kernel/io_cat68701.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/io_cat68701.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,248 @@
+/* 
+ * linux/arch/sh/kernel/io_cat68701.c
+ *
+ * Copyright (C) 2000  Niibe Yutaka
+ *               2001  Yutaro Ebihara
+ *
+ * I/O routine and setup routines for A-ONE Corp CAT-68701 SH7708 Board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <linux/module.h>
+
+#define SH3_PCMCIA_BUG_WORKAROUND 1
+#define DUMMY_READ_AREA6	  0xba000000
+
+#define PORT2ADDR(x) (cat68701_isa_port2addr(x))
+
+static inline void delay(void)
+{
+	ctrl_inw(0xa0000000);
+}
+
+unsigned char cat68701_inb(unsigned long port)
+{
+	return *(volatile unsigned char*)PORT2ADDR(port);
+}
+
+unsigned short cat68701_inw(unsigned long port)
+{
+	return *(volatile unsigned short*)PORT2ADDR(port);
+}
+
+unsigned int cat68701_inl(unsigned long port)
+{
+	return *(volatile unsigned long*)PORT2ADDR(port);
+}
+
+unsigned char cat68701_inb_p(unsigned long port)
+{
+	unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
+
+	delay();
+	return v;
+}
+
+unsigned short cat68701_inw_p(unsigned long port)
+{
+	unsigned long v = *(volatile unsigned short*)PORT2ADDR(port);
+
+	delay();
+	return v;
+}
+
+unsigned int cat68701_inl_p(unsigned long port)
+{
+	unsigned long v = *(volatile unsigned long*)PORT2ADDR(port);
+
+	delay();
+	return v;
+}
+
+void cat68701_insb(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned char *buf=buffer;
+	while(count--) *buf++=inb(port);
+}
+
+void cat68701_insw(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned short *buf=buffer;
+	while(count--) *buf++=inw(port);
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+void cat68701_insl(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned long *buf=buffer;
+	while(count--) *buf++=inl(port);
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+void cat68701_outb(unsigned char b, unsigned long port)
+{
+	*(volatile unsigned char*)PORT2ADDR(port) = b;
+}
+
+void cat68701_outw(unsigned short b, unsigned long port)
+{
+	*(volatile unsigned short*)PORT2ADDR(port) = b;
+}
+
+void cat68701_outl(unsigned int b, unsigned long port)
+{
+        *(volatile unsigned long*)PORT2ADDR(port) = b;
+}
+
+void cat68701_outb_p(unsigned char b, unsigned long port)
+{
+	*(volatile unsigned char*)PORT2ADDR(port) = b;
+	delay();
+}
+
+void cat68701_outw_p(unsigned short b, unsigned long port)
+{
+	*(volatile unsigned short*)PORT2ADDR(port) = b;
+	delay();
+}
+
+void cat68701_outl_p(unsigned int b, unsigned long port)
+{
+	*(volatile unsigned long*)PORT2ADDR(port) = b;
+	delay();
+}
+
+void cat68701_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned char *buf=buffer;
+	while(count--) outb(*buf++, port);
+}
+
+void cat68701_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned short *buf=buffer;
+	while(count--) outw(*buf++, port);
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+void cat68701_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned long *buf=buffer;
+	while(count--) outl(*buf++, port);
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+unsigned char cat68701_readb(unsigned long addr)
+{
+	return *(volatile unsigned char*)addr;
+}
+
+unsigned short cat68701_readw(unsigned long addr)
+{
+	return *(volatile unsigned short*)addr;
+}
+
+unsigned int cat68701_readl(unsigned long addr)
+{
+	return *(volatile unsigned long*)addr;
+}
+
+void cat68701_writeb(unsigned char b, unsigned long addr)
+{
+	*(volatile unsigned char*)addr = b;
+}
+
+void cat68701_writew(unsigned short b, unsigned long addr)
+{
+	*(volatile unsigned short*)addr = b;
+}
+
+void cat68701_writel(unsigned int b, unsigned long addr)
+{
+        *(volatile unsigned long*)addr = b;
+}
+
+void * cat68701_ioremap(unsigned long offset, unsigned long size)
+{
+	return (void *) P2SEGADDR(offset);
+}
+EXPORT_SYMBOL(cat68701_ioremap);
+
+void cat68701_iounmap(void *addr)
+{
+}
+EXPORT_SYMBOL(cat68701_iounmap);
+
+unsigned long cat68701_isa_port2addr(unsigned long offset)
+{
+  /* CompactFlash (IDE) */
+  if(((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6))
+    return 0xba000000 + offset;
+
+  /* INPUT PORT */
+  if((offset >= 0x3fc) && (offset <= 0x3fd))
+    return 0xb4007000 + offset;
+
+  /* OUTPUT PORT */
+  if((offset >= 0x3fe) && (offset <= 0x3ff))
+    return 0xb4007400 + offset;
+
+  return offset + 0xb4000000; /* other I/O (EREA 5)*/
+}
+
+
+int cat68701_irq_demux(int irq)
+{
+  if(irq==13) return 14;
+  if(irq==7)  return 10;
+  return irq;
+}
+
+
+
+/*-------------------------------------------------------*/
+
+void setup_cat68701(){
+  /* dummy read erea5 (CS8900A) */
+}
+
+void init_cat68701_IRQ(){
+  make_imask_irq(10);
+  make_imask_irq(14);
+}
+
+#ifdef CONFIG_HEARTBEAT
+#include <linux/sched.h>
+void heartbeat_cat68701()
+{
+        static unsigned int cnt = 0, period = 0 , bit = 0;
+        cnt += 1;
+        if (cnt < period) {
+                return;
+        }
+        cnt = 0;
+
+        /* Go through the points (roughly!):
+         * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+         */
+        period = 110 - ( (300<<FSHIFT)/
+                         ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+	if(bit){ bit=0; }else{ bit=1; }
+	outw(bit<<15,0x3fe);
+}
+#endif /* CONFIG_HEARTBEAT */
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_dc.c linux/arch/sh/kernel/io_dc.c
--- v2.4.3/linux/arch/sh/kernel/io_dc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/io_dc.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,13 @@
+/*
+ *	$Id: io_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *	I/O routines for SEGA Dreamcast
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+unsigned long dreamcast_isa_port2addr(unsigned long offset)
+{
+	return offset + 0xa0000000;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_ec3104.c linux/arch/sh/kernel/io_ec3104.c
--- v2.4.3/linux/arch/sh/kernel/io_ec3104.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/io_ec3104.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/sh/kernel/io_ec3104.c
+ *  EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip.  While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/ec3104.h>
+
+/*
+ * EC3104 has a real ISA bus which we redirect low port accesses to (the
+ * actual device on mine is a ESS 1868, and I don't want to hack the driver
+ * more than strictly necessary).  I am not going to duplicate the
+ * hard coding of PC addresses (for the 16550s aso) here though;  it's just
+ * too ugly.
+ */
+
+#define low_port(port) ((port) < 0x10000)
+
+static inline unsigned long port2addr(unsigned long port)
+{
+	switch(port >> 16) {
+	case 0:
+		return EC3104_ISA_BASE + port * 2;
+
+		/* XXX hack. it's unclear what to do about the serial ports */
+	case 1:
+		return EC3104_BASE + (port&0xffff) * 4;
+
+	default:
+		/* XXX PCMCIA */
+		return 0;
+	}
+}
+
+unsigned char ec3104_inb(unsigned long port)
+{
+	u8 ret;
+
+	ret = *(volatile u8 *)port2addr(port);
+
+	return ret;
+}
+
+unsigned short ec3104_inw(unsigned long port)
+{
+	BUG();
+}
+
+unsigned long ec3104_inl(unsigned long port)
+{
+	BUG();
+}
+
+void ec3104_outb(unsigned char data, unsigned long port)
+{
+	*(volatile u8 *)port2addr(port) = data;
+}
+
+void ec3104_outw(unsigned short data, unsigned long port)
+{
+	BUG();
+}
+
+void ec3104_outl(unsigned long data, unsigned long port)
+{
+	BUG();
+}
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_generic.c linux/arch/sh/kernel/io_generic.c
--- v2.4.3/linux/arch/sh/kernel/io_generic.c	Thu Aug 10 13:03:25 2000
+++ linux/arch/sh/kernel/io_generic.c	Wed Apr 11 21:24:52 2001
@@ -15,6 +15,7 @@
 
 #include <asm/io.h>
 #include <asm/machvec.h>
+#include <linux/module.h>
 
 #if defined(__sh3__)
 /* I'm not sure SH7709 has this kind of bug */
@@ -31,22 +32,22 @@
 	ctrl_inw(0xa0000000);
 }
 
-unsigned long generic_inb(unsigned int port)
+unsigned char generic_inb(unsigned long port)
 {
 	return *(volatile unsigned char*)PORT2ADDR(port);
 }
 
-unsigned long generic_inw(unsigned int port)
+unsigned short generic_inw(unsigned long port)
 {
 	return *(volatile unsigned short*)PORT2ADDR(port);
 }
 
-unsigned long generic_inl(unsigned int port)
+unsigned int generic_inl(unsigned long port)
 {
 	return *(volatile unsigned long*)PORT2ADDR(port);
 }
 
-unsigned long generic_inb_p(unsigned int port)
+unsigned char generic_inb_p(unsigned long port)
 {
 	unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
 
@@ -54,7 +55,7 @@
 	return v;
 }
 
-unsigned long generic_inw_p(unsigned int port)
+unsigned short generic_inw_p(unsigned long port)
 {
 	unsigned long v = *(volatile unsigned short*)PORT2ADDR(port);
 
@@ -62,7 +63,7 @@
 	return v;
 }
 
-unsigned long generic_inl_p(unsigned int port)
+unsigned int generic_inl_p(unsigned long port)
 {
 	unsigned long v = *(volatile unsigned long*)PORT2ADDR(port);
 
@@ -70,13 +71,13 @@
 	return v;
 }
 
-void generic_insb(unsigned int port, void *buffer, unsigned long count)
+void generic_insb(unsigned long port, void *buffer, unsigned long count)
 {
 	unsigned char *buf=buffer;
 	while(count--) *buf++=inb(port);
 }
 
-void generic_insw(unsigned int port, void *buffer, unsigned long count)
+void generic_insw(unsigned long port, void *buffer, unsigned long count)
 {
 	unsigned short *buf=buffer;
 	while(count--) *buf++=inw(port);
@@ -85,7 +86,7 @@
 #endif
 }
 
-void generic_insl(unsigned int port, void *buffer, unsigned long count)
+void generic_insl(unsigned long port, void *buffer, unsigned long count)
 {
 	unsigned long *buf=buffer;
 	while(count--) *buf++=inl(port);
@@ -94,46 +95,46 @@
 #endif
 }
 
-void generic_outb(unsigned long b, unsigned int port)
+void generic_outb(unsigned char b, unsigned long port)
 {
 	*(volatile unsigned char*)PORT2ADDR(port) = b;
 }
 
-void generic_outw(unsigned long b, unsigned int port)
+void generic_outw(unsigned short b, unsigned long port)
 {
 	*(volatile unsigned short*)PORT2ADDR(port) = b;
 }
 
-void generic_outl(unsigned long b, unsigned int port)
+void generic_outl(unsigned int b, unsigned long port)
 {
         *(volatile unsigned long*)PORT2ADDR(port) = b;
 }
 
-void generic_outb_p(unsigned long b, unsigned int port)
+void generic_outb_p(unsigned char b, unsigned long port)
 {
 	*(volatile unsigned char*)PORT2ADDR(port) = b;
 	delay();
 }
 
-void generic_outw_p(unsigned long b, unsigned int port)
+void generic_outw_p(unsigned short b, unsigned long port)
 {
 	*(volatile unsigned short*)PORT2ADDR(port) = b;
 	delay();
 }
 
-void generic_outl_p(unsigned long b, unsigned int port)
+void generic_outl_p(unsigned int b, unsigned long port)
 {
 	*(volatile unsigned long*)PORT2ADDR(port) = b;
 	delay();
 }
 
-void generic_outsb(unsigned int port, const void *buffer, unsigned long count)
+void generic_outsb(unsigned long port, const void *buffer, unsigned long count)
 {
 	const unsigned char *buf=buffer;
 	while(count--) outb(*buf++, port);
 }
 
-void generic_outsw(unsigned int port, const void *buffer, unsigned long count)
+void generic_outsw(unsigned long port, const void *buffer, unsigned long count)
 {
 	const unsigned short *buf=buffer;
 	while(count--) outw(*buf++, port);
@@ -142,7 +143,7 @@
 #endif
 }
 
-void generic_outsl(unsigned int port, const void *buffer, unsigned long count)
+void generic_outsl(unsigned long port, const void *buffer, unsigned long count)
 {
 	const unsigned long *buf=buffer;
 	while(count--) outl(*buf++, port);
@@ -151,17 +152,17 @@
 #endif
 }
 
-unsigned long generic_readb(unsigned long addr)
+unsigned char generic_readb(unsigned long addr)
 {
 	return *(volatile unsigned char*)addr;
 }
 
-unsigned long generic_readw(unsigned long addr)
+unsigned short generic_readw(unsigned long addr)
 {
 	return *(volatile unsigned short*)addr;
 }
 
-unsigned long generic_readl(unsigned long addr)
+unsigned int generic_readl(unsigned long addr)
 {
 	return *(volatile unsigned long*)addr;
 }
@@ -185,15 +186,12 @@
 {
 	return (void *) P2SEGADDR(offset);
 }
-
-void * generic_ioremap_nocache (unsigned long offset, unsigned long size)
-{
-	return (void *) P2SEGADDR(offset);
-}
+EXPORT_SYMBOL(generic_ioremap);
 
 void generic_iounmap(void *addr)
 {
 }
+EXPORT_SYMBOL(generic_iounmap);
 
 unsigned long generic_isa_port2addr(unsigned long offset)
 {
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_hd64461.c linux/arch/sh/kernel/io_hd64461.c
--- v2.4.3/linux/arch/sh/kernel/io_hd64461.c	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/kernel/io_hd64461.c	Wed Apr 11 21:24:52 2001
@@ -27,6 +27,12 @@
 	   detail of CF's memory mapped addressing. */
 	if (0x1f0<=port && port<=0x1f7)	return 0xb5000000 + port;
 	if (port == 0x3f6) return 0xb50001fe;
+	if (port == 0x3f7) return 0xb50001ff;
+
+	/* ide1 */
+	if (0x170<=port && port<=0x177)	return 0xba000000 + port;
+	if (port == 0x376) return 0xba000376;
+	if (port == 0x377) return 0xba000377;
 #endif
 
 	/* ??? */
@@ -50,80 +56,80 @@
 	ctrl_inw(0xa0000000);
 }
 
-unsigned long hd64461_inb(unsigned int port)
+unsigned char hd64461_inb(unsigned long port)
 {
 	return *(volatile unsigned char*)PORT2ADDR(port);
 }
 
-unsigned long hd64461_inb_p(unsigned int port)
+unsigned char hd64461_inb_p(unsigned long port)
 {
 	unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
 	delay();
 	return v;
 }
 
-unsigned long hd64461_inw(unsigned int port)
+unsigned short hd64461_inw(unsigned long port)
 {
 	return *(volatile unsigned short*)PORT2ADDR(port);
 }
 
-unsigned long hd64461_inl(unsigned int port)
+unsigned int hd64461_inl(unsigned long port)
 {
 	return *(volatile unsigned long*)PORT2ADDR(port);
 }
 
-void hd64461_insb(unsigned int port, void *buffer, unsigned long count)
+void hd64461_insb(unsigned long port, void *buffer, unsigned long count)
 {
 	unsigned char *buf=buffer;
 	while(count--) *buf++=inb(port);
 }
 
-void hd64461_insw(unsigned int port, void *buffer, unsigned long count)
+void hd64461_insw(unsigned long port, void *buffer, unsigned long count)
 {
 	unsigned short *buf=buffer;
 	while(count--) *buf++=inw(port);
 }
 
-void hd64461_insl(unsigned int port, void *buffer, unsigned long count)
+void hd64461_insl(unsigned long port, void *buffer, unsigned long count)
 {
 	unsigned long *buf=buffer;
 	while(count--) *buf++=inl(port);
 }
 
-void hd64461_outb(unsigned long b, unsigned int port)
+void hd64461_outb(unsigned char b, unsigned long port)
 {
 	*(volatile unsigned char*)PORT2ADDR(port) = b;
 }
 
-void hd64461_outb_p(unsigned long b, unsigned int port)
+void hd64461_outb_p(unsigned char b, unsigned long port)
 {
 	*(volatile unsigned char*)PORT2ADDR(port) = b;
 	delay();
 }
 
-void hd64461_outw(unsigned long b, unsigned int port)
+void hd64461_outw(unsigned short b, unsigned long port)
 {
 	*(volatile unsigned short*)PORT2ADDR(port) = b;
 }
 
-void hd64461_outl(unsigned long b, unsigned int port)
+void hd64461_outl(unsigned int b, unsigned long port)
 {
         *(volatile unsigned long*)PORT2ADDR(port) = b;
 }
 
-void hd64461_outsb(unsigned int port, const void *buffer, unsigned long count)
+void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count)
 {
 	const unsigned char *buf=buffer;
 	while(count--) outb(*buf++, port);
 }
 
-void hd64461_outsw(unsigned int port, const void *buffer, unsigned long count)
+void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count)
 {
 	const unsigned short *buf=buffer;
 	while(count--) outw(*buf++, port);
 }
 
-void hd64461_outsl(unsigned int port, const void *buffer, unsigned long count)
+void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count)
 {
 	const unsigned long *buf=buffer;
 	while(count--) outl(*buf++, port);
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_hd64465.c linux/arch/sh/kernel/io_hd64465.c
--- v2.4.3/linux/arch/sh/kernel/io_hd64465.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/io_hd64465.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,249 @@
+/*
+ * $Id: io_hd64465.c,v 1.6 2001/02/15 09:13:51 dave_mckay Exp $
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc
+ *
+ * Derived from io_hd64461.c, which bore the message:
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ *
+ * Typical I/O routines for HD64465 system.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/hd64465.h>
+
+
+#define HD64465_DEBUG 0
+
+#if HD64465_DEBUG
+#define DPRINTK(args...)	printk(args)
+#define DIPRINTK(n, args...)	if (hd64465_io_debug>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif
+
+
+
+/* This is a hack suitable only for debugging IO port problems */
+int hd64465_io_debug;
+EXPORT_SYMBOL(hd64465_io_debug);
+
+/* Low iomap maps port 0-1K to addresses in 8byte chunks */
+#define HD64465_IOMAP_LO_THRESH 0x400
+#define HD64465_IOMAP_LO_SHIFT	3
+#define HD64465_IOMAP_LO_MASK	((1<<HD64465_IOMAP_LO_SHIFT)-1)
+#define HD64465_IOMAP_LO_NMAP	(HD64465_IOMAP_LO_THRESH>>HD64465_IOMAP_LO_SHIFT)
+static unsigned long	hd64465_iomap_lo[HD64465_IOMAP_LO_NMAP];
+static unsigned char	hd64465_iomap_lo_shift[HD64465_IOMAP_LO_NMAP];
+
+/* High iomap maps port 1K-64K to addresses in 1K chunks */
+#define HD64465_IOMAP_HI_THRESH 0x10000
+#define HD64465_IOMAP_HI_SHIFT	10
+#define HD64465_IOMAP_HI_MASK	((1<<HD64465_IOMAP_HI_SHIFT)-1)
+#define HD64465_IOMAP_HI_NMAP	(HD64465_IOMAP_HI_THRESH>>HD64465_IOMAP_HI_SHIFT)
+static unsigned long	hd64465_iomap_hi[HD64465_IOMAP_HI_NMAP];
+static unsigned char	hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP];
+
+#ifndef MAX
+#define MAX(a,b)    ((a)>(b)?(a):(b))
+#endif
+
+void hd64465_port_map(unsigned short baseport, unsigned int nports,
+		      unsigned long addr, unsigned char shift)
+{
+    	unsigned int port, endport = baseport + nports;
+
+    	DPRINTK("hd64465_port_map(base=0x%04hx, n=0x%04hx, addr=0x%08lx,endport=0x%04x)\n",
+	    baseport, nports, addr,endport);
+	    
+	for (port = baseport ;
+	     port < endport && port < HD64465_IOMAP_LO_THRESH ;
+	     port += (1<<HD64465_IOMAP_LO_SHIFT)) {
+	    DPRINTK("    maplo[0x%x] = 0x%08lx\n", port, addr);
+    	    hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = addr;
+    	    hd64465_iomap_lo_shift[port>>HD64465_IOMAP_LO_SHIFT] = shift;
+	    addr += (1<<(HD64465_IOMAP_LO_SHIFT));
+	}
+
+	for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ;
+	     port < endport && port < HD64465_IOMAP_HI_THRESH ;
+	     port += (1<<HD64465_IOMAP_HI_SHIFT)) {
+	    DPRINTK("    maphi[0x%x] = 0x%08lx\n", port, addr);
+    	    hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = addr;
+    	    hd64465_iomap_hi_shift[port>>HD64465_IOMAP_HI_SHIFT] = shift;
+	    addr += (1<<(HD64465_IOMAP_HI_SHIFT));
+	}
+}
+EXPORT_SYMBOL(hd64465_port_map);
+
+void hd64465_port_unmap(unsigned short baseport, unsigned int nports)
+{
+    	unsigned int port, endport = baseport + nports;
+	
+    	DPRINTK("hd64465_port_unmap(base=0x%04hx, n=0x%04hx)\n",
+	    baseport, nports);
+
+	for (port = baseport ;
+	     port < endport && port < HD64465_IOMAP_LO_THRESH ;
+	     port += (1<<HD64465_IOMAP_LO_SHIFT)) {
+    	    hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = 0;
+	}
+
+	for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ;
+	     port < endport && port < HD64465_IOMAP_HI_THRESH ;
+	     port += (1<<HD64465_IOMAP_HI_SHIFT)) {
+    	    hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = 0;
+	}
+}
+EXPORT_SYMBOL(hd64465_port_unmap);
+
+static /*__inline__*/ unsigned long PORT2ADDR(unsigned long port)
+{
+    	unsigned long addr = 0;
+	unsigned char shift;
+
+	/* handle remapping of low IO ports */
+	if (port < HD64465_IOMAP_LO_THRESH) {
+	    addr = hd64465_iomap_lo[port >> HD64465_IOMAP_LO_SHIFT];
+	    shift = hd64465_iomap_lo_shift[port >> HD64465_IOMAP_LO_SHIFT];
+	    if (addr != 0)
+	    	addr += (port & HD64465_IOMAP_LO_MASK) << shift;
+	    else
+		printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port);
+	} else if (port < HD64465_IOMAP_HI_THRESH) {
+	    addr = hd64465_iomap_hi[port >> HD64465_IOMAP_HI_SHIFT];
+	    shift = hd64465_iomap_hi_shift[port >> HD64465_IOMAP_HI_SHIFT];
+	    if (addr != 0)
+		addr += (port & HD64465_IOMAP_HI_MASK) << shift;
+	    else
+		printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port);
+	}
+	    	
+	/* HD64465 internal devices (0xb0000000) */
+	else if (port < 0x20000)
+	    addr = CONFIG_HD64465_IOBASE + port - 0x10000;
+
+	/* Whole physical address space (0xa0000000) */
+	else
+	    addr = P2SEGADDR(port);
+
+    	DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr);
+
+	return addr;
+}
+
+static inline void delay(void)
+{
+	ctrl_inw(0xa0000000);
+}
+
+unsigned char hd64465_inb(unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+	unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+
+	DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b);
+	return b;
+}
+
+unsigned char hd64465_inb_p(unsigned long port)
+{
+    	unsigned long v;
+	unsigned long addr = PORT2ADDR(port);
+
+	v = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+	delay();
+	DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v);
+	return v;
+}
+
+unsigned short hd64465_inw(unsigned long port)
+{
+    	unsigned long addr = PORT2ADDR(port);
+	unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr);
+	DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b);
+	return b;
+}
+
+unsigned int hd64465_inl(unsigned long port)
+{
+    	unsigned long addr = PORT2ADDR(port);
+	unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr);
+	DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b);
+	return b;
+}
+
+void hd64465_insb(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned char *buf=buffer;
+	while(count--) *buf++=inb(port);
+}
+
+void hd64465_insw(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned short *buf=buffer;
+	while(count--) *buf++=inw(port);
+}
+
+void hd64465_insl(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned long *buf=buffer;
+	while(count--) *buf++=inl(port);
+}
+
+void hd64465_outb(unsigned char b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+
+	DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr);
+	if (addr != 0)
+	    *(volatile unsigned char*)addr = b;
+}
+
+void hd64465_outb_p(unsigned char b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+
+	DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr);
+    	if (addr != 0)
+	    *(volatile unsigned char*)addr = b;
+	delay();
+}
+
+void hd64465_outw(unsigned short b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+	DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr);
+	if (addr != 0)
+	    *(volatile unsigned short*)addr = b;
+}
+
+void hd64465_outl(unsigned int b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+	DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr);
+	if (addr != 0)
+            *(volatile unsigned long*)addr = b;
+}
+
+void hd64465_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned char *buf=buffer;
+	while(count--) outb(*buf++, port);
+}
+
+void hd64465_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned short *buf=buffer;
+	while(count--) outw(*buf++, port);
+}
+
+void hd64465_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned long *buf=buffer;
+	while(count--) outl(*buf++, port);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_se.c linux/arch/sh/kernel/io_se.c
--- v2.4.3/linux/arch/sh/kernel/io_se.c	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/kernel/io_se.c	Wed Apr 11 21:24:52 2001
@@ -43,7 +43,7 @@
 }
 
 static inline int
-shifted_port(unsigned int port)
+shifted_port(unsigned long port)
 {
 	/* For IDE registers, value is not shifted */
 	if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
@@ -53,10 +53,10 @@
 }
 
 #define maybebadio(name,port) \
-  printk("bad PC-like io %s for port 0x%x at 0x%08x\n", \
+  printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
 	 #name, (port), (__u32) __builtin_return_address(0))
 
-unsigned long se_inb(unsigned int port)
+unsigned char se_inb(unsigned long port)
 {
 	if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
 		return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); 
@@ -66,7 +66,7 @@
 		return (*port2adr(port))&0xff; 
 }
 
-unsigned long se_inb_p(unsigned int port)
+unsigned char se_inb_p(unsigned long port)
 {
 	unsigned long v;
 
@@ -80,7 +80,7 @@
 	return v;
 }
 
-unsigned long se_inw(unsigned int port)
+unsigned short se_inw(unsigned long port)
 {
 	if (port >= 0x2000 ||
 	    (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
@@ -90,13 +90,13 @@
 	return 0;
 }
 
-unsigned long se_inl(unsigned int port)
+unsigned int se_inl(unsigned long port)
 {
 	maybebadio(inl, port);
 	return 0;
 }
 
-void se_outb(unsigned long value, unsigned int port)
+void se_outb(unsigned char value, unsigned long port)
 {
 	if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
 		*(__u8 *)(sh_pcic_io_wbase + port) = value; 
@@ -106,7 +106,7 @@
 		*(port2adr(port)) = value;
 }
 
-void se_outb_p(unsigned long value, unsigned int port)
+void se_outb_p(unsigned char value, unsigned long port)
 {
 	if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
 		*(__u8 *)(sh_pcic_io_wbase + port) = value; 
@@ -117,7 +117,7 @@
 	delay();
 }
 
-void se_outw(unsigned long value, unsigned int port)
+void se_outw(unsigned short value, unsigned long port)
 {
 	if (port >= 0x2000 ||
 	    (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
@@ -126,12 +126,12 @@
 		maybebadio(outw, port);
 }
 
-void se_outl(unsigned long value, unsigned int port)
+void se_outl(unsigned int value, unsigned long port)
 {
 	maybebadio(outl, port);
 }
 
-void se_insb(unsigned int port, void *addr, unsigned long count)
+void se_insb(unsigned long port, void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
 
@@ -148,19 +148,19 @@
 	}
 }
 
-void se_insw(unsigned int port, void *addr, unsigned long count)
+void se_insw(unsigned long port, void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
 	while (count--)
 		*((__u16 *) addr)++ = *p;
 }
 
-void se_insl(unsigned int port, void *addr, unsigned long count)
+void se_insl(unsigned long port, void *addr, unsigned long count)
 {
 	maybebadio(insl, port);
 }
 
-void se_outsb(unsigned int port, const void *addr, unsigned long count)
+void se_outsb(unsigned long port, const void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
 
@@ -177,29 +177,29 @@
 	}
 }
 
-void se_outsw(unsigned int port, const void *addr, unsigned long count)
+void se_outsw(unsigned long port, const void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
 	while (count--)
 		*p = *((__u16 *) addr)++;
 }
 
-void se_outsl(unsigned int port, const void *addr, unsigned long count)
+void se_outsl(unsigned long port, const void *addr, unsigned long count)
 {
 	maybebadio(outsw, port);
 }
 
-unsigned long se_readb(unsigned long addr)
+unsigned char se_readb(unsigned long addr)
 {
 	return *(volatile unsigned char*)addr;
 }
 
-unsigned long se_readw(unsigned long addr)
+unsigned short se_readw(unsigned long addr)
 {
 	return *(volatile unsigned short*)addr;
 }
 
-unsigned long se_readl(unsigned long addr)
+unsigned int se_readl(unsigned long addr)
 {
 	return *(volatile unsigned long*)addr;
 }
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_unknown.c linux/arch/sh/kernel/io_unknown.c
--- v2.4.3/linux/arch/sh/kernel/io_unknown.c	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/kernel/io_unknown.c	Wed Apr 11 21:24:52 2001
@@ -43,5 +43,4 @@
 UNKNOWN_ALIAS(writel)
 UNKNOWN_ALIAS(isa_port2addr)
 UNKNOWN_ALIAS(ioremap)
-UNKNOWN_ALIAS(ioremap_nocache)
 UNKNOWN_ALIAS(iounmap)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/irq_intc2.c linux/arch/sh/kernel/irq_intc2.c
--- v2.4.3/linux/arch/sh/kernel/irq_intc2.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/irq_intc2.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,127 @@
+/*
+ * linux/arch/sh/kernel/irq_intc2.c
+ *
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Interrupt handling for INTC2-based IRQ.
+ *
+ * These are the "new Hitachi style" interrupts, as present on the 
+ * Hitachi 7751 and the STM ST40 STB1.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+
+struct intc2_data {
+	unsigned int addr;	/* Address of Interrupt Priority Register */
+	int mask; /*Mask to apply */
+};
+
+
+static struct intc2_data intc2_data[NR_INTC2_IRQS];
+
+static void enable_intc2_irq(unsigned int irq);
+static void disable_intc2_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_intc2_irq disable_intc2_irq
+
+static void mask_and_ack_intc2(unsigned int);
+static void end_intc2_irq(unsigned int irq);
+
+static unsigned int startup_intc2_irq(unsigned int irq)
+{ 
+	enable_intc2_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type intc2_irq_type = {
+	"INTC2-based-IRQ",
+	startup_intc2_irq,
+	shutdown_intc2_irq,
+	enable_intc2_irq,
+	disable_intc2_irq,
+	mask_and_ack_intc2,
+	end_intc2_irq
+};
+
+static void disable_intc2_irq(unsigned int irq)
+{
+	unsigned addr;
+	int offset=irq-INTC2_FIRST_IRQ;
+	unsigned val,flags;
+
+	// Sanity check
+	if(offset<0 || offset>=NR_INTC2_IRQS) return;
+
+	addr=intc2_data[offset].addr+INTC2_INTMSK_OFFSET;
+
+	save_and_cli(flags);
+	val=ctrl_inl(addr);
+	val|=intc2_data[offset].mask;
+	ctrl_outl(val,addr);
+
+	restore_flags(flags);
+}
+
+static void enable_intc2_irq(unsigned int irq)
+{
+	int offset=irq-INTC2_FIRST_IRQ;
+
+	// Sanity check
+	if(offset<0 || offset>=NR_INTC2_IRQS) return;
+
+	ctrl_outl(intc2_data[offset].mask,
+		  intc2_data[offset].addr+INTC2_INTMSKCLR_OFFSET);
+
+}
+
+static void mask_and_ack_intc2(unsigned int irq)
+{
+	disable_intc2_irq(irq);
+}
+
+static void end_intc2_irq(unsigned int irq)
+{
+	enable_intc2_irq(irq);
+}
+
+void make_intc2_irq(unsigned int irq, unsigned int addr, 
+		    unsigned int group,int pos, int priority)
+{
+	int offset=irq-INTC2_FIRST_IRQ;
+	unsigned flags,val;
+
+	if(offset<0 || offset>=NR_INTC2_IRQS) {
+		return;
+	}
+
+	disable_irq_nosync(irq);
+	/* Fill the the data we need */
+	intc2_data[offset].addr=addr;
+	intc2_data[offset].mask=1<<pos;
+		
+	/* Set the priority level */
+	save_and_cli(flags);
+	val=ctrl_inl(addr+INTC2_INTPRI_OFFSET);
+	val|=(priority)<< (group<<4);
+	ctrl_outl(val,addr+INTC2_INTPRI_OFFSET);
+	restore_flags(flags);
+
+	irq_desc[irq].handler=&intc2_irq_type;
+
+	disable_intc2_irq(irq);
+}
+
+
+
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/irq_ipr.c linux/arch/sh/kernel/irq_ipr.c
--- v2.4.3/linux/arch/sh/kernel/irq_ipr.c	Mon Oct  2 11:57:34 2000
+++ linux/arch/sh/kernel/irq_ipr.c	Wed Apr 11 21:24:52 2001
@@ -116,14 +116,96 @@
 	disable_ipr_irq(irq);
 }
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+static unsigned char pint_map[256];
+static unsigned long portcr_mask = 0;
+
+static void enable_pint_irq(unsigned int irq);
+static void disable_pint_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_pint_irq disable_pint_irq
+
+static void mask_and_ack_pint(unsigned int);
+static void end_pint_irq(unsigned int irq);
+
+static unsigned int startup_pint_irq(unsigned int irq)
+{ 
+	enable_pint_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type pint_irq_type = {
+	"PINT-IRQ",
+	startup_pint_irq,
+	shutdown_pint_irq,
+	enable_pint_irq,
+	disable_pint_irq,
+	mask_and_ack_pint,
+	end_pint_irq
+};
+
+static void disable_pint_irq(unsigned int irq)
+{
+	unsigned long val, flags;
+
+	save_and_cli(flags);
+	val = ctrl_inw(INTC_INTER);
+	val &= ~(1 << (irq - PINT_IRQ_BASE));
+	ctrl_outw(val, INTC_INTER);	/* disable PINTn */
+	portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
+	restore_flags(flags);
+}
+
+static void enable_pint_irq(unsigned int irq)
+{
+	unsigned long val, flags;
+
+	save_and_cli(flags);
+	val = ctrl_inw(INTC_INTER);
+	val |= 1 << (irq - PINT_IRQ_BASE);
+	ctrl_outw(val, INTC_INTER);	/* enable PINTn */
+	portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
+	restore_flags(flags);
+}
+
+static void mask_and_ack_pint(unsigned int irq)
+{
+	disable_pint_irq(irq);
+}
+
+static void end_pint_irq(unsigned int irq)
+{
+	enable_pint_irq(irq);
+}
+
+void make_pint_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	irq_desc[irq].handler = &pint_irq_type;
+	disable_pint_irq(irq);
+}
+#endif
+
 void __init init_IRQ(void)
 {
+	int i;
+
 	make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
 	make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
 
+#ifdef SCI_ERI_IRQ
 	make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
 	make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
 	make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
+#endif
+
+#ifdef SCIF1_ERI_IRQ
+	make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+	make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+	make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+	make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+#endif
 
 #ifdef SCIF_ERI_IRQ
 	make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
@@ -171,12 +253,30 @@
 	 * You should set corresponding bits of PFC to "00"
 	 * to enable these interrupts.
 	 */
-	make_ipr_irq(IRQ0_IRQ, IRQ0_IRP_ADDR, IRQ0_IRP_POS, IRQ0_PRIORITY);
-	make_ipr_irq(IRQ1_IRQ, IRQ1_IRP_ADDR, IRQ1_IRP_POS, IRQ1_PRIORITY);
-	make_ipr_irq(IRQ2_IRQ, IRQ2_IRP_ADDR, IRQ2_IRP_POS, IRQ2_PRIORITY);
-	make_ipr_irq(IRQ3_IRQ, IRQ3_IRP_ADDR, IRQ3_IRP_POS, IRQ3_PRIORITY);
-	make_ipr_irq(IRQ4_IRQ, IRQ4_IRP_ADDR, IRQ4_IRP_POS, IRQ4_PRIORITY);
-	make_ipr_irq(IRQ5_IRQ, IRQ5_IRP_ADDR, IRQ5_IRP_POS, IRQ5_PRIORITY);
+	make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY);
+	make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY);
+	make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY);
+	make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY);
+	make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY);
+	make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY);
+	make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY);
+	make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY);
+	enable_ipr_irq(PINT0_IRQ);
+	enable_ipr_irq(PINT8_IRQ);
+
+	for(i = 0; i < 16; i++)
+		make_pint_irq(PINT_IRQ_BASE + i);
+	for(i = 0; i < 256; i++)
+	{
+		if(i & 1) pint_map[i] = 0;
+		else if(i & 2) pint_map[i] = 1;
+		else if(i & 4) pint_map[i] = 2;
+		else if(i & 8) pint_map[i] = 3;
+		else if(i & 0x10) pint_map[i] = 4;
+		else if(i & 0x20) pint_map[i] = 5;
+		else if(i & 0x40) pint_map[i] = 6;
+		else if(i & 0x80) pint_map[i] = 7;
+	}
 #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
 
 	/* Perform the machine specific initialisation */
@@ -184,3 +284,43 @@
 		sh_mv.mv_init_irq();
 	}
 }
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+int ipr_irq_demux(int irq)
+{
+	unsigned long creg, dreg, d, sav;
+
+	if(irq == PINT0_IRQ)
+	{
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+		creg = PORT_PACR;
+		dreg = PORT_PADR;
+#else
+		creg = PORT_PCCR;
+		dreg = PORT_PCDR;
+#endif
+		sav = ctrl_inw(creg);
+		ctrl_outw(sav | portcr_mask, creg);
+		d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & ctrl_inw(INTC_INTER) & 0xff;
+		ctrl_outw(sav, creg);
+		if(d == 0) return irq;
+		return PINT_IRQ_BASE + pint_map[d];
+	}
+	else if(irq == PINT8_IRQ)
+	{
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+		creg = PORT_PBCR;
+		dreg = PORT_PBDR;
+#else
+		creg = PORT_PFCR;
+		dreg = PORT_PFDR;
+#endif
+		sav = ctrl_inw(creg);
+		ctrl_outw(sav | (portcr_mask >> 16), creg);
+		d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & (ctrl_inw(INTC_INTER) >> 8) & 0xff;
+		ctrl_outw(sav, creg);
+		if(d == 0) return irq;
+		return PINT_IRQ_BASE + 8 + pint_map[d];
+	}
+	return irq;
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_cat68701.c linux/arch/sh/kernel/mach_cat68701.c
--- v2.4.3/linux/arch/sh/kernel/mach_cat68701.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/mach_cat68701.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/sh/kernel/mach_cat68701.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *               2001 Yutaro Ebihara (ebihara@si-linux.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Machine vector for the A-ONE corp. CAT-68701 SH7708 board
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io_cat68701.h>
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_cat68701 __initmv = {
+	mv_name:		"CAT-68701",
+	mv_nr_irqs:		32,
+	mv_inb:			cat68701_inb,
+	mv_inw:			cat68701_inw,
+	mv_inl:			cat68701_inl,
+	mv_outb:		cat68701_outb,
+	mv_outw:		cat68701_outw,
+	mv_outl:		cat68701_outl,
+
+	mv_inb_p:		cat68701_inb_p,
+	mv_inw_p:		cat68701_inw,
+	mv_inl_p:		cat68701_inl,
+	mv_outb_p:		cat68701_outb_p,
+	mv_outw_p:		cat68701_outw,
+	mv_outl_p:		cat68701_outl,
+
+	mv_insb:		cat68701_insb,
+	mv_insw:		cat68701_insw,
+	mv_insl:		cat68701_insl,
+	mv_outsb:		cat68701_outsb,
+	mv_outsw:		cat68701_outsw,
+	mv_outsl:		cat68701_outsl,
+
+	mv_readb:		cat68701_readb,
+	mv_readw:		cat68701_readw,
+	mv_readl:		cat68701_readl,
+	mv_writeb:		cat68701_writeb,
+	mv_writew:		cat68701_writew,
+	mv_writel:		cat68701_writel,
+
+	mv_ioremap:		cat68701_ioremap,
+	mv_iounmap:		cat68701_iounmap,
+
+	mv_isa_port2addr:	cat68701_isa_port2addr,
+	mv_irq_demux:           cat68701_irq_demux,
+
+	mv_init_arch:		setup_cat68701,
+	mv_init_irq:		init_cat68701_IRQ,
+#ifdef CONFIG_HEARTBEAT
+	mv_heartbeat:		heartbeat_cat68701,
+#endif
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
+};
+ALIAS_MV(cat68701)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_dc.c linux/arch/sh/kernel/mach_dc.c
--- v2.4.3/linux/arch/sh/kernel/mach_dc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/mach_dc.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,66 @@
+/*
+ *	$Id: mach_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *	SEGA Dreamcast machine vector
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io_generic.h>
+#include <asm/io_dc.h>
+#include <asm/irq.h>
+
+void __init setup_dreamcast(void);
+void __init dreamcast_pcibios_init(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_dreamcast __initmv = {
+	mv_name:		"dreamcast",
+
+	mv_nr_irqs:		48,
+
+	mv_inb:			generic_inb,
+	mv_inw:			generic_inw,
+	mv_inl:			generic_inl,
+	mv_outb:		generic_outb,
+	mv_outw:		generic_outw,
+	mv_outl:		generic_outl,
+
+	mv_inb_p:		generic_inb_p,
+	mv_inw_p:		generic_inw,
+	mv_inl_p:		generic_inl,
+	mv_outb_p:		generic_outb_p,
+	mv_outw_p:		generic_outw,
+	mv_outl_p:		generic_outl,
+
+	mv_insb:		generic_insb,
+	mv_insw:		generic_insw,
+	mv_insl:		generic_insl,
+	mv_outsb:		generic_outsb,
+	mv_outsw:		generic_outsw,
+	mv_outsl:		generic_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_ioremap:		generic_ioremap,
+	mv_iounmap:		generic_iounmap,
+
+	mv_init_arch:		setup_dreamcast,
+#ifdef CONFIG_PCI
+	mv_init_pci:		dreamcast_pcibios_init,
+#endif
+	mv_isa_port2addr:	dreamcast_isa_port2addr,
+
+	mv_hw_dreamcast:		1,
+};
+ALIAS_MV(dreamcast)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_dmida.c linux/arch/sh/kernel/mach_dmida.c
--- v2.4.3/linux/arch/sh/kernel/mach_dmida.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/mach_dmida.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,73 @@
+/*
+ * linux/arch/sh/kernel/mach_dmida.c
+ *
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc
+ *
+ * Derived from mach_hp600.c, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Machine vector for the DataMyte Industrial Digital Assistant(tm).
+ * See http://www.dmida.com
+ *
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io.h>
+#include <asm/hd64465.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_dmida __initmv = {
+	mv_name:		"DMIDA",
+
+	mv_nr_irqs:		HD64465_IRQ_BASE+HD64465_IRQ_NUM,
+
+	mv_inb:			hd64465_inb,
+	mv_inw:			hd64465_inw,
+	mv_inl:			hd64465_inl,
+	mv_outb:		hd64465_outb,
+	mv_outw:		hd64465_outw,
+	mv_outl:		hd64465_outl,
+
+	mv_inb_p:		hd64465_inb_p,
+	mv_inw_p:		hd64465_inw,
+	mv_inl_p:		hd64465_inl,
+	mv_outb_p:		hd64465_outb_p,
+	mv_outw_p:		hd64465_outw,
+	mv_outl_p:		hd64465_outl,
+
+	mv_insb:		hd64465_insb,
+	mv_insw:		hd64465_insw,
+	mv_insl:		hd64465_insl,
+	mv_outsb:		hd64465_outsb,
+	mv_outsw:		hd64465_outsw,
+	mv_outsl:		hd64465_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_irq_demux:		hd64465_irq_demux,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
+	mv_hw_hd64465:		1,
+};
+ALIAS_MV(dmida)
+
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_ec3104.c linux/arch/sh/kernel/mach_ec3104.c
--- v2.4.3/linux/arch/sh/kernel/mach_ec3104.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/mach_ec3104.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,69 @@
+/*
+ * linux/arch/sh/kernel/mach_ec3104.c
+ *  EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip.  While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_ec3104 __initmv = {
+	mv_name:		"EC3104",
+
+	mv_nr_irqs:		96,
+
+	mv_inb:			ec3104_inb,
+	mv_inw:			ec3104_inw,
+	mv_inl:			ec3104_inl,
+	mv_outb:		ec3104_outb,
+	mv_outw:		ec3104_outw,
+	mv_outl:		ec3104_outl,
+
+	mv_inb_p:		generic_inb_p,
+	mv_inw_p:		generic_inw,
+	mv_inl_p:		generic_inl,
+	mv_outb_p:		generic_outb_p,
+	mv_outw_p:		generic_outw,
+	mv_outl_p:		generic_outl,
+
+	mv_insb:		generic_insb,
+	mv_insw:		generic_insw,
+	mv_insl:		generic_insl,
+	mv_outsb:		generic_outsb,
+	mv_outsw:		generic_outsw,
+	mv_outsl:		generic_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_irq_demux:		ec3104_irq_demux,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+};
+
+ALIAS_MV(ec3104)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_hp600.c linux/arch/sh/kernel/mach_hp600.c
--- v2.4.3/linux/arch/sh/kernel/mach_hp600.c	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/kernel/mach_hp600.c	Wed Apr 11 21:24:52 2001
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 
 #include <asm/machvec.h>
+#include <asm/rtc.h>
 #include <asm/machvec_init.h>
 
 #include <asm/io_hd64461.h>
@@ -22,8 +23,8 @@
  * The Machine Vector
  */
 
-struct sh_machine_vector mv_hp600 __initmv = {
-	mv_name:		"HP600",
+struct sh_machine_vector mv_hp620 __initmv = {
+	mv_name:		"hp620",
 
 	mv_nr_irqs:		80, /* HD64461_IRQBASE+16, see hd64461.h */
 
@@ -57,7 +58,101 @@
 
 	mv_irq_demux:		hd64461_irq_demux,
 
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
+	mv_hw_hp600:		1,
+	mv_hw_hp620:		1,
+	mv_hw_hd64461:		1,
+};
+ALIAS_MV(hp620)
+
+
+struct sh_machine_vector mv_hp680 __initmv = {
+	mv_name:		"hp680",
+
+	mv_nr_irqs:		80, /* HD64461_IRQBASE+16, see hd64461.h */
+
+	mv_inb:			hd64461_inb,
+	mv_inw:			hd64461_inw,
+	mv_inl:			hd64461_inl,
+	mv_outb:		hd64461_outb,
+	mv_outw:		hd64461_outw,
+	mv_outl:		hd64461_outl,
+
+	mv_inb_p:		hd64461_inb_p,
+	mv_inw_p:		hd64461_inw,
+	mv_inl_p:		hd64461_inl,
+	mv_outb_p:		hd64461_outb_p,
+	mv_outw_p:		hd64461_outw,
+	mv_outl_p:		hd64461_outl,
+
+	mv_insb:		hd64461_insb,
+	mv_insw:		hd64461_insw,
+	mv_insl:		hd64461_insl,
+	mv_outsb:		hd64461_outsb,
+	mv_outsw:		hd64461_outsw,
+	mv_outsl:		hd64461_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_irq_demux:		hd64461_irq_demux,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
+	mv_hw_hp600:		1,
+	mv_hw_hp680:		1,
+	mv_hw_hd64461:		1,
+};
+ALIAS_MV(hp680)
+
+
+struct sh_machine_vector mv_hp690 __initmv = {
+	mv_name:		"hp690",
+
+	mv_nr_irqs:		80, /* HD64461_IRQBASE+16, see hd64461.h */
+
+	mv_inb:			hd64461_inb,
+	mv_inw:			hd64461_inw,
+	mv_inl:			hd64461_inl,
+	mv_outb:		hd64461_outb,
+	mv_outw:		hd64461_outw,
+	mv_outl:		hd64461_outl,
+
+	mv_inb_p:		hd64461_inb_p,
+	mv_inw_p:		hd64461_inw,
+	mv_inl_p:		hd64461_inl,
+	mv_outb_p:		hd64461_outb_p,
+	mv_outw_p:		hd64461_outw,
+	mv_outl_p:		hd64461_outl,
+
+	mv_insb:		hd64461_insb,
+	mv_insw:		hd64461_insw,
+	mv_insl:		hd64461_insl,
+	mv_outsb:		hd64461_outsb,
+	mv_outsw:		hd64461_outsw,
+	mv_outsl:		hd64461_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_irq_demux:		hd64461_irq_demux,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
 	mv_hw_hp600:		1,
+	mv_hw_hp690:		1,
 	mv_hw_hd64461:		1,
 };
-ALIAS_MV(hp600)
+ALIAS_MV(hp690)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_se.c linux/arch/sh/kernel/mach_se.c
--- v2.4.3/linux/arch/sh/kernel/mach_se.c	Thu Aug 10 13:03:25 2000
+++ linux/arch/sh/kernel/mach_se.c	Wed Apr 11 21:24:52 2001
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 
 #include <asm/machvec.h>
+#include <asm/rtc.h>
 #include <asm/machvec_init.h>
 
 #include <asm/io_se.h>
@@ -65,7 +66,6 @@
 	mv_writel:		se_writel,
 
 	mv_ioremap:		generic_ioremap,
-	mv_ioremap_nocache:	generic_ioremap_nocache,
 	mv_iounmap:		generic_iounmap,
 
 	mv_isa_port2addr:	se_isa_port2addr,
@@ -75,6 +75,9 @@
 #ifdef CONFIG_HEARTBEAT
 	mv_heartbeat:		heartbeat_se,
 #endif
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
 
 	mv_hw_se:		1,
 };
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_unknown.c linux/arch/sh/kernel/mach_unknown.c
--- v2.4.3/linux/arch/sh/kernel/mach_unknown.c	Thu Aug 10 13:03:25 2000
+++ linux/arch/sh/kernel/mach_unknown.c	Wed Apr 11 21:24:52 2001
@@ -17,6 +17,7 @@
 
 #include <asm/io_unknown.h>
 
+#include <asm/rtc.h>
 /*
  * The Machine Vector
  */
@@ -61,9 +62,11 @@
 	mv_writel:		unknown_writel,
 
 	mv_ioremap:		unknown_ioremap,
-	mv_ioremap_nocache:	unknown_ioremap_nocache,
 	mv_iounmap:		unknown_iounmap,
 
 	mv_isa_port2addr:	unknown_isa_port2addr,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
 };
 ALIAS_MV(unknown)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/pci_st40.c linux/arch/sh/kernel/pci_st40.c
--- v2.4.3/linux/arch/sh/kernel/pci_st40.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci_st40.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,494 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Support functions for the ST40 PCI hardware.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <asm/pci.h>
+#include <linux/irq.h>
+
+#include "pci_st40.h"
+
+/* This is in P2 of course */
+#define ST40PCI_BASE_ADDRESS     (0xb0000000)
+#define ST40PCI_MEM_ADDRESS      (ST40PCI_BASE_ADDRESS+0x0)
+#define ST40PCI_IO_ADDRESS       (ST40PCI_BASE_ADDRESS+0x06000000)
+#define ST40PCI_REG_ADDRESS      (ST40PCI_BASE_ADDRESS+0x07000000)
+
+#define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x))
+
+#define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg))
+#define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg))
+#define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg))
+
+#define ST40PCI_READ(reg) readl(ST40PCI_REG(reg))
+#define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg))
+#define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg))
+
+#define ST40PCI_SERR_IRQ        64
+#define ST40PCI_SERR_INT_GROUP  0
+#define ST40PCI_SERR_INT_POS    0
+#define ST40PCI_SERR_INT_PRI    15
+
+#define ST40PCI_ERR_IRQ        65
+#define ST40PCI_ERR_INT_GROUP   1
+#define ST40PCI_ERR_INT_POS     1
+#define ST40PCI_ERR_INT_PRI     14
+
+
+/* Macros to extract PLL params */
+#define PLL_MDIV(reg)  ( ((unsigned)reg) & 0xff )
+#define PLL_NDIV(reg) ( (((unsigned)reg)>>8) & 0xff )
+#define PLL_PDIV(reg) ( (((unsigned)reg)>>16) & 0x3 )
+#define PLL_SETUP(reg) ( (((unsigned)reg)>>19) & 0x1ff )
+
+/* Build up the appropriate settings */
+#define PLL_SET(mdiv,ndiv,pdiv,setup) \
+( ((mdiv)&0xff) | (((ndiv)&0xff)<<8) | (((pdiv)&3)<<16)| (((setup)&0x1ff)<<19))
+
+#define PLLPCICR (0xbb040000+0x10)
+
+#define PLLPCICR_POWERON (1<<28)
+#define PLLPCICR_OUT_EN (1<<29)
+#define PLLPCICR_LOCKSELECT (1<<30)
+#define PLLPCICR_LOCK (1<<31)
+
+
+#define PLL_25MHZ 0x793c8512
+#define PLL_33MHZ PLL_SET(18,88,3,295)
+
+
+static __init void SetPCIPLL(void)
+{
+	/* Stop the PLL */
+	writel(0, PLLPCICR);
+
+	/* Always run at 33Mhz. The PCI clock is totally async 
+	 * to the rest of the system
+	 */
+	writel(PLL_33MHZ | PLLPCICR_POWERON, PLLPCICR);
+
+	printk("ST40PCI: Waiting for PCI PLL to lock\n");
+	while ((readl(PLLPCICR) & PLLPCICR_LOCK) == 0);
+	writel(readl(PLLPCICR) | PLLPCICR_OUT_EN, PLLPCICR);
+}
+
+
+static void st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs)
+{
+
+	unsigned pci_int, pci_air, pci_cir, pci_aint;
+
+	pci_int = ST40PCI_READ(INT);
+	pci_cir = ST40PCI_READ(CIR);
+	pci_air = ST40PCI_READ(AIR);
+
+	if (pci_int) {
+		printk("PCI INTERRUPT!\n");
+		printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
+		printk("PCI AIR -> 0x%x\n", pci_air);
+		printk("PCI CIR -> 0x%x\n", pci_cir);
+		ST40PCI_WRITE(INT, ~0);
+	}
+
+	pci_aint = ST40PCI_READ(AINT);
+	if (pci_aint) {
+		printk("PCI ARB INTERRUPT!\n");
+		printk("PCI AINT -> 0x%x\n", pci_aint);
+		printk("PCI AIR -> 0x%x\n", pci_air);
+		printk("PCI CIR -> 0x%x\n", pci_cir);
+		ST40PCI_WRITE(AINT, ~0);
+	}
+
+}
+
+
+/* Rounds a number UP to the nearest power of two. Used for
+ * sizing the PCI window.
+ */
+static u32 __init r2p2(u32 num)
+{
+	int i = 31;
+	u32 tmp = num;
+
+	if (num == 0)
+		return 0;
+
+	do {
+		if (tmp & (1 << 31))
+			break;
+		i--;
+		tmp <<= 1;
+	} while (i >= 0);
+
+	tmp = 1 << i;
+	/* If the original number isn't a power of 2, round it up */
+	if (tmp != num)
+		tmp <<= 1;
+
+	return tmp;
+}
+
+
+int __init st40pci_init(unsigned memStart, unsigned memSize)
+{
+	u32 lsr0;
+
+	SetPCIPLL();
+
+	/* Initialises the ST40 pci subsystem, performing a reset, then programming
+	 * up the address space decoders appropriately
+	 */
+
+	/* Should reset core here as well methink */
+
+	ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_SOFT_RESET);
+
+	/* Loop while core resets */
+	while (ST40PCI_READ(CR) & CR_SOFT_RESET);
+
+	/* Now, lets reset all the cards on the bus with extreme prejudice */
+	ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL);
+	udelay(250);
+
+	/* Set bus active, take it out of reset */
+	ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_CFINT | CR_PFCS | CR_PFE);
+
+	/* The PCI spec says that no access must be made to the bus until 1 second
+	 * after reset. This seem ludicrously long, but some delay is needed here
+	 */
+	mdelay(1000);
+
+	/* Switch off interrupts */
+	ST40PCI_WRITE(INTM, 0);
+	ST40PCI_WRITE(AINT, 0);
+
+	/* Allow it to be a master */
+
+	ST40PCI_WRITE_SHORT(CSR_CMD,
+			    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+			    PCI_COMMAND_IO);
+
+	/* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000
+	 * on the PCI bus. This allows a nice 1-1 bus to phys mapping.
+	 */
+
+
+	ST40PCI_WRITE(MBR, 0x10000000);
+	/* Always set the max size 128M (actually, it is only 96MB wide) */
+	ST40PCI_WRITE(MBMR, 0x07ff0000);
+
+	/* I/O addresses are mapped at 0xb6000000 -> 0xb7000000. These are changed to 0, to 
+	 * allow cards that have legacy io such as vga to function correctly. This gives a 
+	 * maximum of 64K of io/space as only the bottom 16 bits of the address are copied 
+	 * over to the bus  when the transaction is made. 64K of io space is more than enough
+	 */
+	ST40PCI_WRITE(IOBR, 0x0);
+	/* Set up the 64K window */
+	ST40PCI_WRITE(IOBMR, 0x0);
+
+	/* Now we set up the mbars so the PCI bus can see the memory of the machine */
+
+	if (memSize < (64 * 1024)) {
+		printk("Ridiculous memory size of 0x%x?\n",memSize);
+		return 0;
+	}
+
+	lsr0 =
+	    (memSize >
+	     (512 * 1024 * 1024)) ? 0x1fff0001 : ((r2p2(memSize) -
+						   0x10000) | 0x1);
+
+	ST40PCI_WRITE(LSR0, lsr0);
+
+	ST40PCI_WRITE(CSR_MBAR0, memStart);
+	ST40PCI_WRITE(LAR0, memStart);
+
+	/* Maximise timeout values */
+	ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff);
+	ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff);
+	ST40PCI_WRITE_BYTE(CSR_MIT, 0xff);
+
+
+	/* Install the pci interrupt handlers */
+	make_intc2_irq(ST40PCI_SERR_IRQ, INTC2_BASE0,
+		       ST40PCI_SERR_INT_GROUP, ST40PCI_SERR_INT_POS,
+		       ST40PCI_SERR_INT_PRI);
+
+	make_intc2_irq(ST40PCI_ERR_IRQ, INTC2_BASE0, ST40PCI_ERR_INT_GROUP,
+		       ST40PCI_ERR_INT_POS, ST40PCI_ERR_INT_PRI);
+
+
+	return 1;
+}
+
+
+#define SET_CONFIG_BITS(bus,devfn,where)\
+  (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0))
+
+#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where)
+
+
+static int CheckForMasterAbort(void)
+{
+	if (ST40PCI_READ(INT) & INT_MADIM) {
+		/* Should we clear config space version as well ??? */
+		ST40PCI_WRITE(INT, INT_MADIM);
+		ST40PCI_WRITE_SHORT(CSR_STATUS, 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Write to config register */
+static int st40pci_read_config_byte(struct pci_dev *dev, int where,
+				    u8 * val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
+
+	*val = ST40PCI_READ_BYTE(PDR + (where & 3));
+
+	if (CheckForMasterAbort())
+		*val = 0xff;
+
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int st40pci_read_config_word(struct pci_dev *dev, int where,
+				    u16 * val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
+
+	*val = ST40PCI_READ_SHORT(PDR + (where & 2));
+
+	if (CheckForMasterAbort())
+		*val = 0xffff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int st40pci_read_config_dword(struct pci_dev *dev, int where,
+				     u32 * val)
+{
+
+	ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
+
+	*val = ST40PCI_READ(PDR);
+
+	if (CheckForMasterAbort())
+		*val = 0xffffffff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int st40pci_write_config_byte(struct pci_dev *dev, int where,
+				     u8 val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
+
+	ST40PCI_WRITE_BYTE(PDR + (where & 3), val);
+
+	CheckForMasterAbort();
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int st40pci_write_config_word(struct pci_dev *dev, int where,
+				     u16 val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
+
+	ST40PCI_WRITE_SHORT(PDR + (where & 2), val);
+
+	CheckForMasterAbort();
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int st40pci_write_config_dword(struct pci_dev *dev, int where,
+				      u32 val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
+
+	ST40PCI_WRITE(PDR, val);
+
+	CheckForMasterAbort();
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_config_ops = {
+	st40pci_read_config_byte,
+	st40pci_read_config_word,
+	st40pci_read_config_dword,
+	st40pci_write_config_byte,
+	st40pci_write_config_word,
+	st40pci_write_config_dword
+};
+
+
+/* Everything hangs off this */
+static struct pci_bus *pci_root_bus;
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+	return PCI_SLOT(dev->devfn);
+}
+
+
+/* This needs to be shunted out of here into the board specific bit */
+#define HARP_PCI_IRQ    1
+#define HARP_BRIDGE_IRQ 2
+#define OVERDRIVE_SLOT0_IRQ 0
+
+static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	switch (slot) {
+#ifdef CONFIG_SH_STB1_HARP
+	case 2:		/*This is the PCI slot on the */
+		return HARP_PCI_IRQ;
+	case 1:		/* this is the bridge */
+		return HARP_BRIDGE_IRQ;
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+	case 1:
+	case 2:
+	case 3:
+		return slot - 1;
+#else
+#error Unknown board
+#endif
+	default:
+		return -1;
+	}
+}
+
+
+void __init
+pcibios_fixup_pbus_ranges(struct pci_bus *bus,
+			  struct pbus_set_ranges_data *ranges)
+{
+	ranges->io_start -= bus->resource[0]->start;
+	ranges->io_end -= bus->resource[0]->start;
+	ranges->mem_start -= bus->resource[1]->start;
+	ranges->mem_end -= bus->resource[1]->start;
+}
+
+void __init st40_pcibios_init(void)
+{
+	extern unsigned long memory_start, memory_end;
+
+	/* The pci subsytem needs to know where memory is and how much 
+	 * of it there is. I've simply made these globals. A better mechanism
+	 * is probably needed.
+	 */
+	st40pci_init(PHYSADDR(memory_start),
+		     PHYSADDR(memory_end) - PHYSADDR(memory_start));
+
+	if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq, 
+                        SA_INTERRUPT, "st40pci", NULL)) {
+		printk(KERN_ERR "st40pci: Cannot hook interrupt\n");
+		return;
+	}
+
+	/* Enable the PCI interrupts on the device */
+	ST40PCI_WRITE(INTM, ~0);
+	ST40PCI_WRITE(AINT, ~0);
+
+	/* Map the io address apprioately */
+#ifdef CONFIG_HD64465
+	hd64465_port_map(PCIBIOS_MIN_IO, (64 * 1024) - PCIBIOS_MIN_IO + 1,
+			 ST40_IO_ADDR + PCIBIOS_MIN_IO, 0);
+#endif
+
+	/* ok, do the scan man */
+	pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+	pci_assign_unassigned_resources();
+	pci_fixup_irqs(no_swizzle, map_harp_irq);
+
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		r = dev->resource + idx;
+		if (!r->start && r->end) {
+			printk(KERN_ERR
+			       "PCI: Device %s not available because"
+			       " of resource collisions\n",
+			       dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size)
+{
+}
+
+void __init pcibios_update_resource(struct pci_dev *dev,
+				    struct resource *root,
+				    struct resource *res, int resource)
+{
+
+	unsigned long where, size;
+	u32 reg;
+
+	printk("PCI: Assigning %3s %08lx to %s\n",
+	       res->flags & IORESOURCE_IO ? "IO" : "MEM",
+	       res->start, dev->name);
+
+	where = PCI_BASE_ADDRESS_0 + resource * 4;
+	size = res->end - res->start;
+
+	pci_read_config_dword(dev, where, &reg);
+	reg = (reg & size) | (((u32) (res->start - root->start)) & ~size);
+	pci_write_config_dword(dev, where, reg);
+
+}
+
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/pci_st40.h linux/arch/sh/kernel/pci_st40.h
--- v2.4.3/linux/arch/sh/kernel/pci_st40.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci_st40.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,66 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Defintions for the ST40 PCI hardware.
+ */
+
+#ifndef __PCI_ST40_H__
+#define __PCI_ST40_H__
+
+#define ST40PCI_VCR_STATUS    0x00
+
+#define ST40PCI_VCR_VERSION   0x08
+
+#define ST40PCI_CR            0x10
+
+#define CR_SOFT_RESET (1<<12)
+#define CR_PFCS       (1<<11)
+#define CR_PFE        (1<<9)
+#define CR_BMAM       (1<<6)
+#define CR_HOST       (1<<5)
+#define CR_CLKEN      (1<<4)
+#define CR_SOCS       (1<<3)
+#define CR_IOCS       (1<<2)
+#define CR_RSTCTL     (1<<1)
+#define CR_CFINT      (1<<0)
+#define CR_LOCK_MASK  0x5a000000
+
+
+#define ST40PCI_LSR0          0X14
+#define ST40PCI_LAR0          0x1c
+
+#define ST40PCI_INT           0x24
+#define INT_MADIM             (1<<2)
+
+
+#define ST40PCI_INTM          0x28
+#define ST40PCI_AIR           0x2c
+#define ST40PCI_CIR           0x30
+#define ST40PCI_AINT          0x40
+#define ST40PCI_AINTM         0x44
+#define ST40PCI_BMIR          0x48
+#define ST40PCI_PAR           0x4c
+#define ST40PCI_MBR           0x50
+#define ST40PCI_IOBR          0x54
+#define ST40PCI_PINT          0x58
+#define ST40PCI_PINTM         0x5c
+#define ST40PCI_MBMR          0x70
+#define ST40PCI_IOBMR         0x74
+#define ST40PCI_PDR           0x78
+
+/* These are configs space registers */
+#define ST40PCI_CSR_VID               0x10000
+#define ST40PCI_CSR_DID               0x10002
+#define ST40PCI_CSR_CMD               0x10004
+#define ST40PCI_CSR_STATUS            0x10006
+#define ST40PCI_CSR_MBAR0             0x10010
+#define ST40PCI_CSR_TRDY              0x10040
+#define ST40PCI_CSR_RETRY             0x10041
+#define ST40PCI_CSR_MIT               0x1000d
+
+#define ST40_IO_ADDR 0xb6000000       
+
+#endif /* __PCI_ST40_H__ */
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.4.3/linux/arch/sh/kernel/process.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/sh/kernel/process.c	Wed Apr 11 21:24:52 2001
@@ -139,10 +139,6 @@
 /*
  * This is the mechanism for creating a new kernel thread.
  *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
  */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
@@ -154,7 +150,7 @@
 	register unsigned long __sc9 __asm__ ("r9") = (long) fn;
 
 	__asm__("trapa	#0x12\n\t" 	/* Linux/SH system call */
-		"tst	#0xff, r0\n\t"	/* child or parent? */
+		"tst	r0, r0\n\t"	/* child or parent? */
 		"bf	1f\n\t"		/* parent - jump */
 		"jsr	@r9\n\t"	/* call fn */
 		" mov	r8, r4\n\t"	/* push argument */
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c
--- v2.4.3/linux/arch/sh/kernel/ptrace.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/sh/kernel/ptrace.c	Wed Apr 11 21:24:52 2001
@@ -175,14 +175,16 @@
 	if (request == PTRACE_ATTACH) {
 		if (child == tsk)
 			goto out_tsk;
-		if ((!child->dumpable ||
-		    (tsk->uid != child->euid) ||
+		if(((tsk->uid != child->euid) ||
 		    (tsk->uid != child->suid) ||
 		    (tsk->uid != child->uid) ||
 	 	    (tsk->gid != child->egid) ||
 	 	    (tsk->gid != child->sgid) ||
 	 	    (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) ||
 	 	    (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+			goto out_tsk;
+		rmb();
+		if (!child->dumpable && !capable(CAP_SYS_PTRACE))
 			goto out_tsk;
 		/* the same process cannot be attached many times */
 		if (child->ptrace & PT_PTRACED)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/rtc.c linux/arch/sh/kernel/rtc.c
--- v2.4.3/linux/arch/sh/kernel/rtc.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/sh/kernel/rtc.c	Wed Apr 11 21:24:52 2001
@@ -7,6 +7,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/time.h>
 
 #include <asm/io.h>
@@ -44,6 +45,8 @@
 #define RMONAR  	0xfffffeda
 #define RCR1    	0xfffffedc
 #define RCR2    	0xfffffede
+
+#define RTC_BIT_INVERTED	0	/* No bug on SH7708, SH7709A */
 #elif defined(__SH4__)
 /* SH-4 RTC */
 #define R64CNT  	0xffc80000
@@ -62,6 +65,8 @@
 #define RMONAR  	0xffc80034
 #define RCR1    	0xffc80038
 #define RCR2    	0xffc8003c
+
+#define RTC_BIT_INVERTED	0x40	/* bug on SH7750, SH7750S */
 #endif
 
 #ifndef BCD_TO_BIN
@@ -79,7 +84,7 @@
  again:
 	do {
 		ctrl_outb(0, RCR1);  /* Clear CF-bit */
-		sec128 = ctrl_inb(RSECCNT);
+		sec128 = ctrl_inb(R64CNT);
 		sec = ctrl_inb(RSECCNT);
 		min = ctrl_inb(RMINCNT);
 		hr  = ctrl_inb(RHRCNT);
@@ -96,6 +101,14 @@
 #endif
 	} while ((ctrl_inb(RCR1) & RCR1_CF) != 0);
 
+#if RTC_BIT_INVERTED != 0
+	/* Work around to avoid reading correct value. */
+	if (sec128 == RTC_BIT_INVERTED) {
+		schedule_timeout(1);
+		goto again;
+	}
+#endif
+
 	BCD_TO_BIN(yr100);
 	BCD_TO_BIN(yr);
 	BCD_TO_BIN(mon);
@@ -125,7 +138,7 @@
 	}
 
 	tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
-	tv->tv_usec = (sec128 * 1000000) / 128;
+	tv->tv_usec = ((sec128 ^ RTC_BIT_INVERTED) * 1000000) / 128;
 }
 
 static int set_rtc_time(unsigned long nowtime)
@@ -170,5 +183,9 @@
 
 int sh_rtc_settimeofday(const struct timeval *tv)
 {
+#if RTC_BIT_INVERTED != 0
+	/* This is not accurate, but better than nothing. */
+	schedule_timeout(HZ/2);
+#endif
 	return set_rtc_time(tv->tv_sec);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/semaphore.c linux/arch/sh/kernel/semaphore.c
--- v2.4.3/linux/arch/sh/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/sh/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
@@ -135,162 +135,3 @@
 {
 	return waking_non_zero_trylock(sem);
 }
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->read_bias_granted, 1))
-		BUG();
-	wake_up(&sem->wait);
-	return sem;
-}
-
-struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
-{
-	if (xchg(&sem->write_bias_granted, 1))
-		BUG();
-	wake_up(&sem->write_bias_wait);
-	return sem;
-}
-
-struct rw_semaphore * __rwsem_wake(struct rw_semaphore *sem)
-{
-	if (atomic_read(&sem->count) == 0)
-		return rwsem_wake_writer(sem);
-	else
-		return rwsem_wake_readers(sem);
-}
-
-struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->read_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
-
-	for (;;) {
-		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!sem->write_bias_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (atomic_read(&sem->count) >= 0)
-		wake_up(&sem->wait);
-
-	return sem;
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	__up_read(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (atomic_read(&sem->count) < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (atomic_read(&sem->count) >= 0)
-			break;	/* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	return sem;
-}
-
-struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry)
-{
-	if (carry) {
-		int saved, new;
-
-		do {
-			down_read_failed(sem);
-			saved = atomic_read(&sem->count);
-			if ((new = atomic_dec_return(&sem->count)) >= 0)
-				return sem;
-		} while (!(new < 0 && saved >=0));
-	}
-
-	return down_read_failed_biased(sem);
-}
-
-struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry)
-{
-	if (carry) {
-		int saved, new;
-
-		do {
-			down_write_failed(sem);
-			saved = atomic_read(&sem->count);
-			if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count) ) == 0)
-				return sem;
-		} while (!(new < 0 && saved >=0));
-	}
-
-	return down_write_failed_biased(sem);
-}
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- v2.4.3/linux/arch/sh/kernel/setup.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/sh/kernel/setup.c	Wed Apr 11 21:24:52 2001
@@ -50,6 +50,7 @@
 
 struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 0, 0, };
 struct screen_info screen_info;
+unsigned char aux_device_present = 0xaa;
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
@@ -61,6 +62,19 @@
 struct sh_machine_vector sh_mv;
 #endif
 
+/* We need this to satisfy some external references. */
+struct screen_info screen_info = {
+        0, 25,                  /* orig-x, orig-y */
+        0,                      /* unused */
+        0,                      /* orig-video-page */
+        0,                      /* orig-video-mode */
+        80,                     /* orig-video-cols */
+        0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+        25,                     /* orig-video-lines */
+        0,                      /* orig-video-isVGA */
+        16                      /* orig-video-points */
+};
+
 extern void fpu_init(void);
 extern int root_mountflags;
 extern int _text, _etext, _edata, _end;
@@ -115,7 +129,7 @@
 	{ "Kernel data", 0, 0 }
 };
 
-static unsigned long memory_start, memory_end;
+unsigned long memory_start, memory_end;
 
 #ifdef CONFIG_SH_EARLY_PRINTK
 /*
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_cqreek.c linux/arch/sh/kernel/setup_cqreek.c
--- v2.4.3/linux/arch/sh/kernel/setup_cqreek.c	Mon Oct  2 11:57:34 2000
+++ linux/arch/sh/kernel/setup_cqreek.c	Wed Apr 11 21:24:52 2001
@@ -1,4 +1,4 @@
-/* $Id: setup_cqreek.c,v 1.5 2000/09/18 05:51:24 gniibe Exp $
+/* $Id: setup_cqreek.c,v 1.6 2001/02/14 09:36:42 gniibe Exp $
  *
  * arch/sh/kernel/setup_cqreek.c
  *
@@ -18,6 +18,7 @@
 #include <asm/irq.h>
 #include <asm/machvec.h>
 #include <asm/machvec_init.h>
+#include <asm/rtc.h>
 
 #define BRIDGE_FEATURE		0x0002
 
@@ -247,5 +248,11 @@
 	mv_init_irq:		init_cqreek_IRQ,
 
 	mv_isa_port2addr:	cqreek_port2addr,
+
+	mv_ioremap:		generic_ioremap,
+	mv_iounmap:		generic_iounmap,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
 };
 ALIAS_MV(cqreek)
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_dc.c linux/arch/sh/kernel/setup_dc.c
--- v2.4.3/linux/arch/sh/kernel/setup_dc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/setup_dc.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,360 @@
+/*
+ *	$Id: setup_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *	SEGA Dreamcast support
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define	GAPSPCI_REGS		0x01001400
+#define GAPSPCI_DMA_BASE	0x01840000
+#define GAPSPCI_DMA_SIZE	32768
+#define GAPSPCI_BBA_CONFIG	0x01001600
+
+#define	GAPSPCI_IRQ		11
+#define	GAPSPCI_INTC		0x005f6924
+
+static int gapspci_dma_used;
+
+static struct pci_bus *pci_root_bus;
+
+static void disable_gapspci_irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned long intc;
+
+	save_and_cli(flags);
+	intc = inl(GAPSPCI_INTC);
+	intc &= ~(1<<3);
+	outl(intc, GAPSPCI_INTC);
+	restore_flags(flags);
+}
+
+
+static void enable_gapspci_irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned long intc;
+
+	save_and_cli(flags);
+	intc = inl(GAPSPCI_INTC);
+	intc |= (1<<3);
+	outl(intc, GAPSPCI_INTC);
+	restore_flags(flags);
+}
+
+
+static void mask_and_ack_gapspci_irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned long intc;
+
+	save_and_cli(flags);
+	intc = inl(GAPSPCI_INTC);
+	intc &= ~(1<<3);
+	outl(intc, GAPSPCI_INTC);
+	restore_flags(flags);
+}
+
+
+static void end_gapspci_irq(unsigned int irq)
+{
+	enable_gapspci_irq(irq);
+}
+
+
+static unsigned int startup_gapspci_irq(unsigned int irq)
+{ 
+	enable_gapspci_irq(irq);
+	return 0;
+}
+
+
+static void shutdown_gapspci_irq(unsigned int irq)
+{
+	disable_gapspci_irq(irq);
+}
+
+
+static struct hw_interrupt_type gapspci_irq_type = {
+	"GAPSPCI-IRQ",
+	startup_gapspci_irq,
+	shutdown_gapspci_irq,
+	enable_gapspci_irq,
+	disable_gapspci_irq,
+	mask_and_ack_gapspci_irq,
+	end_gapspci_irq
+};
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+	return PCI_SLOT(dev->devfn);
+}
+
+static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return GAPSPCI_IRQ;
+}
+
+int __init setup_dreamcast(void)
+{
+	gapspci_init();
+
+	printk(KERN_INFO "SEGA Dreamcast support.\n");
+#if 0
+	printk(KERN_INFO "BCR1: 0x%08x\n", ctrl_inl(0xff800000));
+	printk(KERN_INFO "BCR2: 0x%08x\n", ctrl_inw(0xff800004));
+	printk(KERN_INFO "WCR1: 0x%08x\n", ctrl_inl(0xff800008));
+	printk(KERN_INFO "WCR2: 0x%08x\n", ctrl_inl(0xff80000c));
+	printk(KERN_INFO "WCR3: 0x%08x\n", ctrl_inl(0xff800010));
+	printk(KERN_INFO "MCR: 0x%08x\n", ctrl_inl(0xff800014));
+	printk(KERN_INFO "PCR: 0x%08x\n", ctrl_inw(0xff800018));
+/*
+ *	BCR1: 0xa3020008
+ *	BCR2: 0x0001
+ *	WCR1: 0x01110111
+ *	WCR2: 0x618066d8
+ *	WCR3: 0x07777777
+ *	MCR: 0xc00a0e24
+ *	PCR: 0x0000
+ */
+#endif
+	return 0;
+}
+
+
+/*
+ *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ */
+
+#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
+
+static int gapspci_read_config_byte(struct pci_dev *dev, int where,
+                                    u8 * val)
+{
+	if (BBA_SELECTED(dev))
+		*val = inb(GAPSPCI_BBA_CONFIG+where);
+	else
+                *val = 0xff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_word(struct pci_dev *dev, int where,
+                                    u16 * val)
+{
+        if (BBA_SELECTED(dev))
+		*val = inw(GAPSPCI_BBA_CONFIG+where);
+	else
+                *val = 0xffff;
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_dword(struct pci_dev *dev, int where,
+                                     u32 * val)
+{
+        if (BBA_SELECTED(dev))
+		*val = inl(GAPSPCI_BBA_CONFIG+where);
+	else
+                *val = 0xffffffff;
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_byte(struct pci_dev *dev, int where,
+                                     u8 val)
+{
+        if (BBA_SELECTED(dev))
+		outb(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int gapspci_write_config_word(struct pci_dev *dev, int where,
+                                     u16 val)
+{
+        if (BBA_SELECTED(dev))
+		outw(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_dword(struct pci_dev *dev, int where,
+                                      u32 val)
+{
+        if (BBA_SELECTED(dev))
+		outl(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_config_ops = {
+        gapspci_read_config_byte,
+        gapspci_read_config_word,
+        gapspci_read_config_dword,
+        gapspci_write_config_byte,
+        gapspci_write_config_word,
+        gapspci_write_config_dword
+};
+
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size)
+{
+}
+
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+}
+
+
+void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			     struct resource *res, int resource)
+{
+}
+
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		r = dev->resource + idx;
+		if (!r->start && r->end) {
+			printk(KERN_ERR
+			       "PCI: Device %s not available because"
+			       " of resource collisions\n",
+			       dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+
+}
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t * dma_handle)
+{
+	unsigned long buf;
+
+	if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
+		return NULL;
+
+	buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
+
+	gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
+	
+	printk("pci_alloc_consistent: %d bytes at 0x%08x\n", size, buf);
+
+	*dma_handle = (dma_addr_t)buf;
+
+	return (void *)P2SEGADDR(buf);
+}
+
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+}
+
+
+void __init
+pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+}                                                                                
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct list_head *ln;
+	struct pci_dev *dev;
+
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		dev = pci_dev_b(ln);
+		if (!BBA_SELECTED(dev)) continue;
+
+		printk("PCI: MMIO fixup to %s\n", dev->name);
+		dev->resource[1].start=0x01001700;
+		dev->resource[1].end=0x010017ff;
+	}
+}
+
+
+void __init dreamcast_pcibios_init(void)
+{
+	pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+	/* pci_assign_unassigned_resources(); */
+	pci_fixup_irqs(no_swizzle, map_od_irq);
+}
+
+
+static __init int gapspci_init(void)
+{
+	int i;
+	char idbuf[16];
+
+	for(i=0; i<16; i++)
+		idbuf[i]=inb(GAPSPCI_REGS+i);
+
+	if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
+		return -1;
+
+	outl(0x5a14a501, GAPSPCI_REGS+0x18);
+
+	for(i=0; i<1000000; i++);
+
+	if(inl(GAPSPCI_REGS+0x18)!=1)
+		return -1;
+
+	outl(0x01000000, GAPSPCI_REGS+0x20);
+	outl(0x01000000, GAPSPCI_REGS+0x24);
+
+	outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
+	outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
+
+	outl(1, GAPSPCI_REGS+0x14);
+	outl(1, GAPSPCI_REGS+0x34);
+
+	gapspci_dma_used=0;
+
+	/*  */
+	irq_desc[GAPSPCI_IRQ].handler = &gapspci_irq_type;
+
+	/* Setting Broadband Adapter */
+	outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
+	outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
+	outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
+	outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
+	outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
+	outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
+	outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
+
+	return 0;
+}
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_ec3104.c linux/arch/sh/kernel/setup_ec3104.c
--- v2.4.3/linux/arch/sh/kernel/setup_ec3104.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/setup_ec3104.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,242 @@
+/*
+ * linux/arch/sh/kernel/setup_ec3104.c
+ *  EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip.  While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ec3104.h>
+
+/* This is for debugging mostly;  here's the table that I intend to keep
+ * in here:
+ *
+ *   index	function	base addr	power		interrupt bit   
+ *	 0	power		b0ec0000	---		00000001 (unused)
+ *	 1	irqs		b0ec1000	---		00000002 (unused)
+ *	 2	??		b0ec2000	b0ec0008	00000004
+ *	 3	PS2 (1)		b0ec3000	b0ec000c	00000008
+ *	 4	PS2 (2)		b0ec4000	b0ec0010	00000010
+ *	 5	??		b0ec5000	b0ec0014	00000020
+ *	 6	I2C		b0ec6000	b0ec0018	00000040
+ *	 7	serial (1)	b0ec7000	b0ec001c	00000080
+ *	 8	serial (2)	b0ec8000	b0ec0020	00000100
+ *	 9	serial (3)	b0ec9000	b0ec0024	00000200
+ *	10	serial (4)	b0eca000	b0ec0028	00000400
+ *	12	GPIO (1)	b0ecc000	b0ec0030
+ *	13      GPIO (2)	b0ecc000	b0ec0030
+ *	16	pcmcia (1)	b0ed0000	b0ec0040	00010000
+ *	17	pcmcia (2)	b0ed1000	b0ec0044	00020000
+ */
+
+/* I used the register names from another interrupt controller I worked with,
+ * since it seems to be identical to the ec3104 except that all bits are
+ * inverted:
+ *
+ * IRR: Interrupt Request Register (pending and enabled interrupts)
+ * IMR: Interrupt Mask Register (which interrupts are enabled)
+ * IPR: Interrupt Pending Register (pending interrupts, even disabled ones)
+ *
+ * 0 bits mean pending or enabled, 1 bits mean not pending or disabled.  all
+ * IRQs seem to be level-triggered.
+ */
+
+#define EC3104_IRR (EC3104_BASE + 0x1000)
+#define EC3104_IMR (EC3104_BASE + 0x1004)
+#define EC3104_IPR (EC3104_BASE + 0x1008)
+
+#define ctrl_readl(addr) (*(volatile u32 *)(addr))
+#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data))
+#define ctrl_readb(addr) (*(volatile u8 *)(addr))
+
+static char *ec3104_name(unsigned index)
+{
+	switch(index) {
+	case 0:
+		return "power management";
+	case 1:
+		return "interrupts";
+	case 3:
+		return "PS2 (1)";
+	case 4:
+		return "PS2 (2)";
+	case 5:
+		return "I2C (1)";
+	case 6:
+		return "I2C (2)";
+	case 7:
+		return "serial (1)";
+	case 8:
+		return "serial (2)";
+	case 9:
+		return "serial (3)";
+	case 10:
+		return "serial (4)";
+	case 16:
+		return "pcmcia (1)";
+	case 17:
+		return "pcmcia (2)";
+	default: {
+		static char buf[32];
+		
+		sprintf(buf, "unknown (%d)", index);
+
+		return buf;
+		}
+	}
+}
+
+int get_pending_interrupts(char *buf)
+{
+	u32 ipr;
+	u32 bit;
+	char *p = buf;
+
+        p += sprintf(p, "pending: (");
+	
+	ipr = ctrl_inl(EC3104_IPR);
+
+	for (bit = 1; bit < 32; bit++)
+		if (!(ipr & (1<<bit)))
+			p += sprintf(p, "%s ", ec3104_name(bit));
+	
+	p += sprintf(p, ")\n");
+
+	return p - buf;
+}
+	
+static inline u32 ec3104_irq2mask(unsigned int irq)
+{
+	return (1 << (irq - EC3104_IRQBASE));
+}
+
+static inline void mask_ec3104_irq(unsigned int irq)
+{
+	u32 mask;
+
+	mask = ctrl_readl(EC3104_IMR);
+
+	mask |= ec3104_irq2mask(irq);
+	
+	ctrl_writel(mask, EC3104_IMR);
+}
+	
+static inline void unmask_ec3104_irq(unsigned int irq)
+{
+	u32 mask;
+
+	mask = ctrl_readl(EC3104_IMR);
+
+	mask &= ~ec3104_irq2mask(irq);
+	
+	ctrl_writel(mask, EC3104_IMR);
+}
+	
+static void disable_ec3104_irq(unsigned int irq)
+{
+	mask_ec3104_irq(irq);
+}
+
+static void enable_ec3104_irq(unsigned int irq)
+{
+	unmask_ec3104_irq(irq);
+}
+
+static void mask_and_ack_ec3104_irq(unsigned int irq)
+{
+	mask_ec3104_irq(irq);
+}
+
+static void end_ec3104_irq(unsigned int irq)
+{
+	unmask_ec3104_irq(irq);
+}
+
+static unsigned int startup_ec3104_irq(unsigned int irq)
+{
+	unmask_ec3104_irq(irq);
+
+	return 0;
+}
+
+static void shutdown_ec3104_irq(unsigned int irq)
+{
+	mask_ec3104_irq(irq);
+
+}
+
+static struct hw_interrupt_type ec3104_int = {
+	typename:	"EC3104",
+	enable:		enable_ec3104_irq,
+	disable:	disable_ec3104_irq,
+	ack:		mask_and_ack_ec3104_irq,
+	end:		end_ec3104_irq,
+	startup:	startup_ec3104_irq,
+	shutdown:	shutdown_ec3104_irq,
+};
+
+/* Yuck.  the _demux API is ugly */
+int ec3104_irq_demux(int irq)
+{
+	if (irq == EC3104_IRQ) {
+		unsigned int mask;
+
+		mask = ctrl_readl(EC3104_IRR);
+
+		if (mask == 0xffffffff)
+			return EC3104_IRQ;
+		else
+			return EC3104_IRQBASE + ffz(mask);
+	}
+
+	return irq;
+}
+
+int __init setup_ec3104(void)
+{
+	char str[8];
+	int i;
+	
+	if (!MACH_EC3104)
+		printk("!MACH_EC3104\n");
+
+	if (0)
+		return 0;
+
+	for (i=0; i<8; i++)
+		str[i] = ctrl_readb(EC3104_BASE + i);
+
+	for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
+		irq_desc[i].handler = &ec3104_int;
+
+	printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
+	       str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
+
+
+	/* mask all interrupts.  this should have been done by the boot
+	 * loader for us but we want to be sure ... */
+	ctrl_writel(0xffffffff, EC3104_IMR);
+	
+	return 0;
+}
+
+module_init(setup_ec3104);
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_hd64461.c linux/arch/sh/kernel/setup_hd64461.c
--- v2.4.3/linux/arch/sh/kernel/setup_hd64461.c	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/kernel/setup_hd64461.c	Wed Apr 11 21:24:52 2001
@@ -88,7 +88,7 @@
 static void hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	printk(KERN_INFO
-	       "HD64461: spurious interrupt, nirr: 0x%lx nimr: 0x%lx\n",
+	       "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
 	       inw(HD64461_NIRR), inw(HD64461_NIMR));
 }
 
@@ -104,7 +104,7 @@
 		if (irq == 16) irq = CONFIG_HD64461_IRQ;
 		else irq += HD64461_IRQBASE;
 	}
-	return irq;
+	return __irq_demux(irq);
 }
 
 static struct irqaction irq0  = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL};
@@ -120,10 +120,9 @@
 	printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
 	       CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ,
 	       HD64461_IRQBASE, HD64461_IRQBASE+15);
-#ifdef CONFIG_CPU_SUBTYPE_SH7709
-	/* IRQ line for HD64461 should be set level trigger mode("10"). */
-	/* And this should be done earlier than the kernel starts. */
-	ctrl_outw(0x0200, INTC_ICR1); /* when connected to IRQ4. */
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7709) /* Should be at processor specific part.. */
+	outw(0x2240, INTC_ICR1);
 #endif
 	outw(0xffff, HD64461_NIMR);
 
@@ -135,7 +134,7 @@
 
 #ifdef CONFIG_HD64461_ENABLER
 	printk(KERN_INFO "HD64461: enabling PCMCIA devices\n");
-	outb(0x04, HD64461_PCC1CSCIER);
+	outb(0x4c, HD64461_PCC1CSCIER);
 	outb(0x00, HD64461_PCC1CSCR);
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_hd64465.c linux/arch/sh/kernel/setup_hd64465.c
--- v2.4.3/linux/arch/sh/kernel/setup_hd64465.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/setup_hd64465.c	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,207 @@
+/*
+ * $Id: setup_hd64465.c,v 1.3 2001/02/07 17:52:53 stuart_menefy Exp $
+ *
+ * Setup and IRQ handling code for the HD64465 companion chip.
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc
+ *
+ * Derived from setup_hd64461.c which bore the message:
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/hd64465.h>
+
+#undef HD64465_DEBUG
+
+#ifdef HD64465_DEBUG
+#define DPRINTK(args...)	printk(args)
+#else
+#define DPRINTK(args...)
+#endif
+
+static void disable_hd64465_irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned short nimr;
+	unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
+
+    	DPRINTK("disable_hd64465_irq(%d): mask=%x\n", irq, mask);
+	save_and_cli(flags);
+	nimr = inw(HD64465_REG_NIMR);
+	nimr |= mask;
+	outw(nimr, HD64465_REG_NIMR);
+	restore_flags(flags);
+}
+
+
+static void enable_hd64465_irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned short nimr;
+	unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
+
+    	DPRINTK("enable_hd64465_irq(%d): mask=%x\n", irq, mask);
+	save_and_cli(flags);
+	nimr = inw(HD64465_REG_NIMR);
+	nimr &= ~mask;
+	outw(nimr, HD64465_REG_NIMR);
+	restore_flags(flags);
+}
+
+
+static void mask_and_ack_hd64465(unsigned int irq)
+{
+	disable_hd64465_irq(irq);
+}
+
+
+static void end_hd64465_irq(unsigned int irq)
+{
+	enable_hd64465_irq(irq);
+}
+
+
+static unsigned int startup_hd64465_irq(unsigned int irq)
+{ 
+	enable_hd64465_irq(irq);
+	return 0;
+}
+
+
+static void shutdown_hd64465_irq(unsigned int irq)
+{
+	disable_hd64465_irq(irq);
+}
+
+
+static struct hw_interrupt_type hd64465_irq_type = {
+	typename:	"HD64465-IRQ",
+	startup:	startup_hd64465_irq,
+	shutdown:	shutdown_hd64465_irq,
+	enable:		enable_hd64465_irq,
+	disable:	disable_hd64465_irq,
+	ack:		mask_and_ack_hd64465,
+	end:		end_hd64465_irq
+};
+
+
+static void hd64465_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	printk(KERN_INFO
+	       "HD64465: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
+	       inw(HD64465_REG_NIRR), inw(HD64465_REG_NIMR));
+}
+
+
+/*====================================================*/
+
+/*
+ * Support for a secondary IRQ demux step.  This is necessary
+ * because the HD64465 presents a very thin interface to the
+ * PCMCIA bus; a lot of features (such as remapping interrupts)
+ * normally done in hardware by other PCMCIA host bridges is
+ * instead done in software.
+ */
+static struct
+{
+    int (*func)(int, void *);
+    void *dev;
+} hd64465_demux[HD64465_IRQ_NUM];
+
+void hd64465_register_irq_demux(int irq,
+		int (*demux)(int irq, void *dev), void *dev)
+{
+    	hd64465_demux[irq - HD64465_IRQ_BASE].func = demux;
+    	hd64465_demux[irq - HD64465_IRQ_BASE].dev = dev;
+}
+EXPORT_SYMBOL(hd64465_register_irq_demux);
+
+void hd64465_unregister_irq_demux(int irq)
+{
+    	hd64465_demux[irq - HD64465_IRQ_BASE].func = 0;
+}
+EXPORT_SYMBOL(hd64465_unregister_irq_demux);
+
+
+
+int hd64465_irq_demux(int irq)
+{
+	if (irq == CONFIG_HD64465_IRQ) {
+		unsigned short i, bit;
+		unsigned short nirr = inw(HD64465_REG_NIRR);
+		unsigned short nimr = inw(HD64465_REG_NIMR);
+
+    	    	DPRINTK("hd64465_irq_demux, nirr=%04x, nimr=%04x\n", nirr, nimr);
+		nirr &= ~nimr;
+		for (bit = 1, i = 0 ; i < HD64465_IRQ_NUM ; bit <<= 1, i++)
+		    if (nirr & bit)
+		    	break;
+
+    	    	if (i < HD64465_IRQ_NUM) {
+		    irq = HD64465_IRQ_BASE + i;
+    	    	    if (hd64465_demux[i].func != 0)
+		    	irq = hd64465_demux[i].func(irq, hd64465_demux[i].dev);
+		}
+	}
+	return irq;
+}
+
+static struct irqaction irq0  = { hd64465_interrupt, SA_INTERRUPT, 0, "HD64465", NULL, NULL};
+
+
+static int __init setup_hd64465(void)
+{
+	int i;
+	unsigned short rev;
+	unsigned short smscr;
+
+	if (!MACH_HD64465)
+		return 0;
+
+	printk(KERN_INFO "HD64465 configured at 0x%x on irq %d(mapped into %d to %d)\n",
+	       CONFIG_HD64465_IOBASE,
+	       CONFIG_HD64465_IRQ,
+	       HD64465_IRQ_BASE,
+	       HD64465_IRQ_BASE+HD64465_IRQ_NUM-1);
+
+	if (inw(HD64465_REG_SDID) != HD64465_SDID) {
+		printk(KERN_ERR "HD64465 device ID not found, check base address\n");
+	}
+
+	rev = inw(HD64465_REG_SRR);
+	printk(KERN_INFO "HD64465 hardware revision %d.%d\n", (rev >> 8) & 0xff, rev & 0xff);
+	       
+	outw(0xffff, HD64465_REG_NIMR); 	/* mask all interrupts */
+
+	for (i = 0; i < HD64465_IRQ_NUM ; i++) {
+		irq_desc[HD64465_IRQ_BASE + i].handler = &hd64465_irq_type;
+	}
+
+	setup_irq(CONFIG_HD64465_IRQ, &irq0);
+
+#ifdef CONFIG_SERIAL
+	/* wake up the UART from STANDBY at this point */
+	smscr = inw(HD64465_REG_SMSCR);
+	outw(smscr & (~HD64465_SMSCR_UARTST), HD64465_REG_SMSCR);
+
+	/* remap IO ports for first ISA serial port to HD64465 UART */
+	hd64465_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
+#endif
+
+	return 0;
+}
+
+module_init(setup_hd64465);
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/sh_ksyms.c linux/arch/sh/kernel/sh_ksyms.c
--- v2.4.3/linux/arch/sh/kernel/sh_ksyms.c	Fri Mar  2 11:15:47 2001
+++ linux/arch/sh/kernel/sh_ksyms.c	Wed Apr 11 21:24:52 2001
@@ -17,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/hardirq.h>
 #include <asm/delay.h>
+#include <asm/pgalloc.h>
 #include <linux/irq.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
@@ -45,6 +46,7 @@
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
 
 /* mem exports */
 EXPORT_SYMBOL(memchr);
diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
--- v2.4.3/linux/arch/sh/kernel/time.c	Thu Jan  4 13:19:13 2001
+++ linux/arch/sh/kernel/time.c	Wed Apr 11 21:24:52 2001
@@ -57,6 +57,13 @@
 #define TMU0_TCR	0xffd80010	/* Word access */
 
 #define FRQCR		0xffc00000
+
+/* Core Processor Version Register */
+#define CCN_PVR		0xff000030
+#define CCN_PVR_CHIP_SHIFT 24
+#define CCN_PVR_CHIP_MASK  0xff
+#define CCN_PVR_CHIP_ST40STB1 0x4
+
 #endif
 
 extern rwlock_t xtime_lock;
@@ -289,13 +296,62 @@
 	static int ifc_table[] = { 1, 2, 3, 4, 6, 8, 1, 1 };
 #define bfc_table ifc_table	/* Same */
 	static int pfc_table[] = { 2, 3, 4, 6, 8, 2, 2, 2 };
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	struct frqcr_data {
+		unsigned short frqcr;
+		struct {
+			unsigned char multiplier;
+			unsigned char divisor;
+		} factor[3];
+	};
+
+	static struct frqcr_data st40_frqcr_table[] = {		
+		{ 0x000, {{1,1}, {1,1}, {1,2}}},
+		{ 0x002, {{1,1}, {1,1}, {1,4}}},
+		{ 0x004, {{1,1}, {1,1}, {1,8}}},
+		{ 0x008, {{1,1}, {1,2}, {1,2}}},
+		{ 0x00A, {{1,1}, {1,2}, {1,4}}},
+		{ 0x00C, {{1,1}, {1,2}, {1,8}}},
+		{ 0x011, {{1,1}, {2,3}, {1,6}}},
+		{ 0x013, {{1,1}, {2,3}, {1,3}}},
+		{ 0x01A, {{1,1}, {1,2}, {1,4}}},
+		{ 0x01C, {{1,1}, {1,2}, {1,8}}},
+		{ 0x023, {{1,1}, {2,3}, {1,3}}},
+		{ 0x02C, {{1,1}, {1,2}, {1,8}}},
+		{ 0x048, {{1,2}, {1,2}, {1,4}}},
+		{ 0x04A, {{1,2}, {1,2}, {1,6}}},
+		{ 0x04C, {{1,2}, {1,2}, {1,8}}},
+		{ 0x05A, {{1,2}, {1,3}, {1,6}}},
+		{ 0x05C, {{1,2}, {1,3}, {1,6}}},
+		{ 0x063, {{1,2}, {1,4}, {1,4}}},
+		{ 0x06C, {{1,2}, {1,4}, {1,8}}},
+		{ 0x091, {{1,3}, {1,3}, {1,6}}},
+		{ 0x093, {{1,3}, {1,3}, {1,6}}},
+		{ 0x0A3, {{1,3}, {1,6}, {1,6}}},
+		{ 0x0DA, {{1,4}, {1,4}, {1,8}}},
+		{ 0x0DC, {{1,4}, {1,4}, {1,8}}},
+		{ 0x0EC, {{1,4}, {1,8}, {1,8}}},
+		{ 0x123, {{1,4}, {1,4}, {1,8}}},
+		{ 0x16C, {{1,4}, {1,8}, {1,8}}},
+	};
+#endif
 #endif
 
+#if defined(CONFIG_SH_DREAMCAST)
+	xtime.tv_sec = 0;
+	xtime.tv_usec = 0;
+#else
 	rtc_gettimeofday(&xtime);
+#endif
 
 	setup_irq(TIMER_IRQ, &irq0);
 
+#if defined(CONFIG_SH_DREAMCAST)
+	timer_freq = 50*1000*1000/4;
+#else
 	timer_freq = get_timer_frequency();
+#endif
 
 	module_clock = timer_freq * 4;
 
@@ -316,15 +372,53 @@
 	}
 #elif defined(__SH4__)
 	{
+		unsigned long pvr;
 		frqcr = ctrl_inw(FRQCR);
-		ifc  = ifc_table[(frqcr>> 6) & 0x0007];
-		bfc  = bfc_table[(frqcr>> 3) & 0x0007];
-		pfc = pfc_table[frqcr & 0x0007];
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+		/* This should probably be moved into the SH3 probing code, and then use the processor
+		 * structure to determine which CPU we are running on.
+		 */
+		pvr = ctrl_inl(CCN_PVR);
+		printk("PVR %08x\n", pvr);
+
+		if (((pvr >>CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) {
+			/* Unfortunatly the STB1 FRQCR values are different from the 7750 ones */
+			struct frqcr_data *d;
+			int a;
+
+			for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) {
+				d = &st40_frqcr_table[a];
+				if (d->frqcr == (frqcr & 0x1ff))
+					break;
+			}
+			if (a == ARRAY_SIZE(st40_frqcr_table)) {
+				d = st40_frqcr_table;
+				printk("ERROR: Unrecognised FRQCR value, using default multipliers\n");
+			}
+
+			printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Periph: %d/%d\n",
+			       d->factor[0].multiplier, d->factor[0].divisor,
+			       d->factor[1].multiplier, d->factor[1].divisor,
+			       d->factor[2].multiplier, d->factor[2].divisor);
+			
+			master_clock = module_clock * d->factor[2].divisor    / d->factor[2].multiplier;
+			bus_clock    = master_clock * d->factor[1].multiplier / d->factor[1].divisor;
+			cpu_clock    = master_clock * d->factor[0].multiplier / d->factor[0].divisor;
+			goto skip_calc;
+		} else
+#endif
+		{
+			ifc  = ifc_table[(frqcr>> 6) & 0x0007];
+			bfc  = bfc_table[(frqcr>> 3) & 0x0007];
+			pfc = pfc_table[frqcr & 0x0007];
+		}
 	}
 #endif
 	master_clock = module_clock * pfc;
 	bus_clock = master_clock / bfc;
 	cpu_clock = master_clock / ifc;
+ skip_calc:
 	printk("CPU clock: %d.%02dMHz\n",
 	       (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
 	printk("Bus clock: %d.%02dMHz\n",
diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
--- v2.4.3/linux/arch/sh/mm/cache.c	Sun Jan 28 18:56:00 2001
+++ linux/arch/sh/mm/cache.c	Wed Apr 11 21:24:52 2001
@@ -148,7 +148,13 @@
 		cpu_data->type = CPU_SH7729;
 	}
 #elif defined(__SH4__)
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	cpu_data->type = CPU_ST40STB1;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
 	cpu_data->type = CPU_SH7750;
+#else
+#error Unknown SH4 CPU type
+#endif
 #endif
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/extable.c linux/arch/sh/mm/extable.c
--- v2.4.3/linux/arch/sh/mm/extable.c	Wed Nov 10 08:31:37 1999
+++ linux/arch/sh/mm/extable.c	Wed Apr 11 21:24:52 2001
@@ -46,7 +46,7 @@
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c
--- v2.4.3/linux/arch/sh/mm/init.c	Tue Nov 28 22:43:39 2000
+++ linux/arch/sh/mm/init.c	Wed Apr 11 21:24:52 2001
@@ -45,104 +45,25 @@
 
 extern unsigned long init_smp_mappings(unsigned long);
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving an inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-
-unsigned long empty_bad_page[1024];
-pte_t empty_bad_pte_table[PTRS_PER_PTE];
 extern unsigned long empty_zero_page[1024];
 
-static pte_t * get_bad_pte_table(void)
-{
-	pte_t v;
-	int i;
-
-	v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
-
-	for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
-		empty_bad_pte_table[i] = v;
-
-	return empty_bad_pte_table;
-}
-
-void __handle_bad_pmd(pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
-}
-
-void __handle_bad_pmd_kernel(pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-	set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page(pte);
-			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
-			return pte + offset;
-		}
-		set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
-		return NULL;
-	}
-	free_page((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	unsigned long pte;
-
-	pte = (unsigned long) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page((void *)pte);
-			set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
-			return (pte_t *)pte + offset;
-		}
-		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
-		return NULL;
-	}
-	free_page(pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
 	if (pgtable_cache_size > high) {
 		do {
-			if (pgd_quicklist)
-				free_pgd_slow(get_pgd_fast()), freed++;
-			if (pmd_quicklist)
-				free_pmd_slow(get_pmd_fast()), freed++;
-			if (pte_quicklist)
-				free_pte_slow(get_pte_fast()), freed++;
+			if (pgd_quicklist) {
+				free_pgd_slow(get_pgd_fast());
+				freed++;
+			}
+			if (pmd_quicklist) {
+				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+				freed++;
+			}
+			if (pte_quicklist) {
+				pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed++;
+			}
 		} while (pgtable_cache_size > low);
 	}
 	return freed;
diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c
--- v2.4.3/linux/arch/sh/mm/ioremap.c	Fri Oct 13 12:06:52 2000
+++ linux/arch/sh/mm/ioremap.c	Wed Apr 11 21:24:52 2001
@@ -25,14 +25,18 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
 	do {
-		if (!pte_none(*pte))
+		if (!pte_none(*pte)) {
 			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
 		set_pte(pte, mk_pte_phys(phys_addr, pgprot));
 		address += PAGE_SIZE;
 		phys_addr += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && address < end);
 }
 
 static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -45,38 +49,48 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	phys_addr -= address;
+	if (address >= end)
+		BUG();
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && address < end);
 	return 0;
 }
 
 static int remap_area_pages(unsigned long address, unsigned long phys_addr,
-	unsigned long size, unsigned long flags)
+			    unsigned long size, unsigned long flags)
 {
+	int error;
 	pgd_t * dir;
 	unsigned long end = address + size;
 
 	phys_addr -= address;
-	dir = pgd_offset_k(address);
+	dir = pgd_offset(&init_mm, address);
 	flush_cache_all();
-	while (address < end) {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
 		if (!pmd)
-			return -ENOMEM;
+			break;
 		if (remap_area_pmd(pmd, address, end - address,
 					phys_addr + address, flags))
-			return -ENOMEM;
+			break;
+		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
-	return 0;
+	return error;
 }
 
 /*
@@ -106,7 +120,7 @@
 	/*
 	 * Don't remap the low PCI/ISA area, it's always mapped..
 	 */
-	if (phys_addr >= 0xA0000 && last_addr <= 0x100000)
+	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
 		return phys_to_virt(phys_addr);
 
 	/*
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.4.3/linux/arch/sparc/config.in	Sun Feb 18 19:49:44 2001
+++ linux/arch/sparc/config.in	Thu Apr 19 08:38:48 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.108 2001/02/18 09:02:59 davem Exp $
+# $Id: config.in,v 1.109 2001/04/18 21:06:05 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
@@ -48,6 +48,8 @@
 define_bool CONFIG_SUN_CONSOLE y
 define_bool CONFIG_SUN_AUXIO y
 define_bool CONFIG_SUN_IO y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
 bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
 if [ "$CONFIG_SUN4" != "y" ]; then
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.4.3/linux/arch/sparc/kernel/irq.c	Sun Feb 18 19:49:44 2001
+++ linux/arch/sparc/kernel/irq.c	Thu Apr 19 08:38:48 2001
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.110 2001/02/13 01:16:43 davem Exp $
+/*  $Id: irq.c,v 1.111 2001/04/14 21:13:46 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -8,7 +8,7 @@
  *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- *  Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com)
+ *  Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org)
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/semaphore.c linux/arch/sparc/kernel/semaphore.c
--- v2.4.3/linux/arch/sparc/kernel/semaphore.c	Mon Jan 22 13:30:20 2001
+++ linux/arch/sparc/kernel/semaphore.c	Thu Apr 19 08:38:48 2001
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.6 2001/01/05 04:40:07 davem Exp $ */
+/* $Id: semaphore.c,v 1.7 2001/04/18 21:06:05 davem Exp $ */
 
 /* sparc32 semaphore implementation, based on i386 version */
 
@@ -150,120 +150,4 @@
 
 	spin_unlock_irqrestore(&semaphore_lock, flags);
 	return 1;
-}
-
-/* rw mutexes
- * Implemented by Jakub Jelinek (jakub@redhat.com) based on
- * i386 implementation by Ben LaHaise (bcrl@redhat.com).
- */
-
-extern inline int ldstub(unsigned char *p)
-{
-	int ret;
-	asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory");
-	return ret;
-}
-
-#define DOWN_VAR				\
-	struct task_struct *tsk = current;	\
-	DECLARE_WAITQUEUE(wait, tsk);
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (!ldstub(&sem->read_not_granted))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->read_not_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
-	for (;;) {
-		if (!ldstub(&sem->write_not_granted))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->write_not_granted)
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (sem->count >= 0)
-		wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	__up_read(sem); /* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (sem->count < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->count >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (sem->count < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->count >= 0)
-			break;  /* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
-	if (readers) {
-		/* Due to lame ldstub we don't do here
-		   a BUG() consistency check */
-		sem->read_not_granted = 0;
-		wake_up(&sem->wait);
-	} else {
-		sem->write_not_granted = 0;
-		wake_up(&sem->write_bias_wait);
-	}
 }
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.4.3/linux/arch/sparc/kernel/setup.c	Sun Feb 18 19:49:54 2001
+++ linux/arch/sparc/kernel/setup.c	Thu Apr 19 08:38:48 2001
@@ -1,8 +1,8 @@
-/*  $Id: setup.c,v 1.123 2001/02/13 01:16:43 davem Exp $
+/*  $Id: setup.c,v 1.124 2001/04/14 21:13:46 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
- *  Copyright (C) 2000  Anton Blanchard (anton@linuxcare.com)
+ *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
  */
 
 #include <linux/errno.h>
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.4.3/linux/arch/sparc/kernel/sys_sparc.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc/kernel/sys_sparc.c	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.68 2001/03/24 09:36:10 davem Exp $
+/* $Id: sys_sparc.c,v 1.70 2001/04/14 01:12:02 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -36,19 +36,28 @@
 
 #define COLOUR_ALIGN(addr)      (((addr)+SHMLBA-1)&~(SHMLBA-1))
 
-unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct * vmm;
 
+	if (flags & MAP_FIXED) {
+		/* We do not accept a shared mapping if it would violate
+		 * cache aliasing constraints.
+		 */
+		if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+			return -EINVAL;
+		return addr;
+	}
+
 	/* See asm-sparc/uaccess.h */
 	if (len > TASK_SIZE - PAGE_SIZE)
-		return 0;
+		return -ENOMEM;
 	if (ARCH_SUN4C_SUN4 && len > 0x20000000)
-		return 0;
+		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+	if (flags & MAP_SHARED)
 		addr = COLOUR_ALIGN(addr);
 	else
 		addr = PAGE_ALIGN(addr);
@@ -60,11 +69,11 @@
 			vmm = find_vma(current->mm, PAGE_OFFSET);
 		}
 		if (TASK_SIZE - PAGE_SIZE - len < addr)
-			return 0;
+			return -ENOMEM;
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
 		addr = vmm->vm_end;
-		if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+		if (flags & MAP_SHARED)
 			addr = COLOUR_ALIGN(addr);
 	}
 }
@@ -233,15 +242,10 @@
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	if (flags & MAP_SHARED)
-		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
-
 	down_write(&current->mm->mmap_sem);
 	retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
 
-	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
-
 out_putf:
 	if (file)
 		fput(file);
@@ -285,9 +289,6 @@
 	    new_len > TASK_SIZE - PAGE_SIZE)
 		goto out;
 	down_write(&current->mm->mmap_sem);
-	vma = find_vma(current->mm, addr);
-	if (vma && (vma->vm_flags & VM_SHARED))
-		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
 	if (flags & MREMAP_FIXED) {
 		if (ARCH_SUN4C_SUN4 &&
 		    new_addr < 0xe0000000 &&
@@ -298,17 +299,30 @@
 	} else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 &&
 		    addr + new_len > 0x20000000) ||
 		   addr + new_len > TASK_SIZE - PAGE_SIZE) {
+		unsigned long map_flags = 0;
+		struct file *file = NULL;
+
 		ret = -ENOMEM;
 		if (!(flags & MREMAP_MAYMOVE))
 			goto out_sem;
-		new_addr = get_unmapped_area (addr, new_len);
-		if (!new_addr)
+
+		vma = find_vma(current->mm, addr);
+		if (vma) {
+			if (vma->vm_flags & VM_SHARED)
+				map_flags |= MAP_SHARED;
+			file = vma->vm_file;
+		}
+
+		new_addr = get_unmapped_area(file, addr, new_len,
+				     vma ? vma->vm_pgoff : 0,
+				     map_flags);
+		ret = new_addr;
+		if (new_addr & ~PAGE_MASK)
 			goto out_sem;
 		flags |= MREMAP_FIXED;
 	}
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
-	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
 	up_write(&current->mm->mmap_sem);
 out:
 	return ret;       
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/lib/memset.S linux/arch/sparc/lib/memset.S
--- v2.4.3/linux/arch/sparc/lib/memset.S	Mon Jun 19 17:59:38 2000
+++ linux/arch/sparc/lib/memset.S	Thu Apr 12 12:10:25 2001
@@ -188,7 +188,7 @@
 	b 30f
 	 add	%o0, %o1, %o0
 30:
-/* %o4 is faulting address, %o5 is %pc where fault occured */
+/* %o4 is faulting address, %o5 is %pc where fault occurred */
 	save	%sp, -104, %sp
 	mov	%i5, %o0
 	mov	%i7, %o1
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c
--- v2.4.3/linux/arch/sparc/mm/generic.c	Wed Aug  9 13:49:55 2000
+++ linux/arch/sparc/mm/generic.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.10 2000/08/09 00:00:15 davem Exp $
+/* $Id: generic.c,v 1.12 2001/04/09 21:40:46 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -21,11 +21,7 @@
 		struct page *ptpage = pte_page(page);
 		if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
 			return;
-		/* 
-		 * free_page() used to be able to clear swap cache
-		 * entries.  We may now have to do it manually.  
-		 */
-		free_page_and_swap_cache(ptpage);
+		page_cache_release(ptpage);
 		return;
 	}
 	swap_free(pte_to_swp_entry(page));
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.4.3/linux/arch/sparc/mm/init.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc/mm/init.c	Thu Apr 19 08:38:48 2001
@@ -1,10 +1,10 @@
-/*  $Id: init.c,v 1.97 2001/02/26 02:57:34 anton Exp $
+/*  $Id: init.c,v 1.98 2001/04/14 21:13:45 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be)
  *  Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *  Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au)
+ *  Copyright (C) 2000 Anton Blanchard (anton@samba.org)
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.4.3/linux/arch/sparc/mm/srmmu.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc/mm/srmmu.c	Thu Apr 19 08:38:48 2001
@@ -1,11 +1,11 @@
-/* $Id: srmmu.c,v 1.228 2001/03/16 06:56:20 davem Exp $
+/* $Id: srmmu.c,v 1.229 2001/04/14 21:13:45 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
  * Copyright (C) 1995 Pete Zaitcev
  * Copyright (C) 1996 Eddie C. Dost    (ecd@skynet.be)
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1999,2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 1999,2000 Anton Blanchard (anton@samba.org)
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.4.3/linux/arch/sparc/mm/sun4c.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc/mm/sun4c.c	Thu Apr 19 08:38:48 2001
@@ -1,10 +1,10 @@
-/* $Id: sun4c.c,v 1.205 2001/03/16 06:57:41 davem Exp $
+/* $Id: sun4c.c,v 1.206 2001/04/14 21:13:45 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au)
- * Copyright (C) 1997-2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org)
  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.4.3/linux/arch/sparc64/config.in	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/config.in	Thu Apr 19 08:38:48 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.136 2001/03/24 06:04:24 davem Exp $
+# $Id: config.in,v 1.141 2001/04/19 01:52:04 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -21,6 +21,8 @@
 mainmenu_option next_comment
 comment 'General setup'
 
+tristate 'UltraSPARC-III bootbus i2c controller driver' CONFIG_BBC_I2C
+
 define_bool CONFIG_VT y
 define_bool CONFIG_VT_CONSOLE y
 
@@ -31,6 +33,8 @@
 
 # Global things across all Sun machines.
 define_bool CONFIG_HAVE_DEC_LOCK y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_ISA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.4.3/linux/arch/sparc64/defconfig	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/defconfig	Thu Apr 19 08:38:48 2001
@@ -17,11 +17,14 @@
 #
 # General setup
 #
+CONFIG_BBC_I2C=m
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SMP is not set
+CONFIG_SMP=y
 CONFIG_SPARC64=y
 CONFIG_HAVE_DEC_LOCK=y
+# CONFIG_RWSEM_GENERIC_SPINLOCK=n
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
@@ -39,7 +42,7 @@
 CONFIG_SUN_IO=y
 CONFIG_PCI=y
 CONFIG_RTC=y
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_NAMES is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
@@ -90,6 +93,7 @@
 # CONFIG_FB_PM2_FIFO_DISCONNECT is not set
 CONFIG_FB_PM2_PCI=y
 # CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_E1355 is not set
 # CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 # CONFIG_FB_ATY128 is not set
@@ -445,6 +449,7 @@
 CONFIG_EFS_FS=m
 # CONFIG_JFFS_FS is not set
 CONFIG_CRAMFS=m
+# CONFIG_TMPFS is not set
 CONFIG_RAMFS=m
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
@@ -519,11 +524,13 @@
 # CONFIG_NLS_CODEPAGE_865 is not set
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -531,11 +538,12 @@
 # CONFIG_NLS_ISO8859_5 is not set
 # CONFIG_NLS_ISO8859_6 is not set
 # CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
 #
@@ -606,7 +614,6 @@
 # USB Serial Converter support
 #
 CONFIG_USB_SERIAL=m
-# CONFIG_USB_SERIAL_DEBUG is not set
 CONFIG_USB_SERIAL_GENERIC=y
 CONFIG_USB_SERIAL_BELKIN=m
 CONFIG_USB_SERIAL_WHITEHEAT=m
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.4.3/linux/arch/sparc64/kernel/Makefile	Tue Mar  6 22:44:16 2001
+++ linux/arch/sparc64/kernel/Makefile	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.64 2001/02/28 05:59:45 davem Exp $
+# $Id: Makefile,v 1.66 2001/04/03 12:29:38 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -24,7 +24,7 @@
 		   traps.o devices.o auxio.o \
 		   irq.o ptrace.o time.o sys_sparc.o signal.o \
 		   unaligned.o central.o pci.o starfire.o semaphore.o \
-		   power.o sbus.o iommu_common.o sparc64_ksyms.o
+		   power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o
 
 obj-$(CONFIG_PCI)	 += ebus.o pci_common.o pci_iommu.o \
 			    pci_psycho.o pci_sabre.o pci_schizo.o
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/chmc.c linux/arch/sparc64/kernel/chmc.c
--- v2.4.3/linux/arch/sparc64/kernel/chmc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/chmc.c	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,451 @@
+/* $Id: chmc.c,v 1.3 2001/04/03 12:49:47 davem Exp $
+ * memctrlr.c: Driver for UltraSPARC-III memory controller.
+ *
+ * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <asm/spitfire.h>
+#include <asm/chmctrl.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+
+#define CHMCTRL_NDGRPS	2
+#define CHMCTRL_NDIMMS	4
+
+#define DIMMS_PER_MC	(CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+
+/* OBP memory-layout property format. */
+struct obp_map {
+	unsigned char	dimm_map[144];
+	unsigned char	pin_map[576];
+};
+
+#define DIMM_LABEL_SZ	8
+
+struct obp_mem_layout {
+	/* One max 8-byte string label per DIMM.  Usually
+	 * this matches the label on the motherboard where
+	 * that DIMM resides.
+	 */
+	char		dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ];
+
+	/* If symmetric use map[0], else it is
+	 * asymmetric and map[1] should be used.
+	 */
+	char		symmetric;
+
+	struct obp_map	map[2];
+};
+
+#define CHMCTRL_NBANKS	4
+
+struct bank_info {
+	struct mctrl_info	*mp;
+	int			bank_id;
+
+	u64			raw_reg;
+	int			valid;
+	int			uk;
+	int			um;
+	int			lk;
+	int			lm;
+	int			interleave;
+	unsigned long		base;
+	unsigned long		size;
+};
+
+struct mctrl_info {
+	struct list_head	list;
+	int			portid;
+	int			index;
+
+	struct obp_mem_layout	layout_prop;
+	int			layout_size;
+
+	void			*regs;
+
+	u64			timing_control1;
+	u64			timing_control2;
+	u64			timing_control3;
+	u64			timing_control4;
+	u64			memaddr_control;
+
+	struct bank_info	logical_banks[CHMCTRL_NBANKS];
+};
+
+static LIST_HEAD(mctrl_list);
+
+/* Does BANK decode PHYS_ADDR? */
+static int bank_match(struct bank_info *bp, unsigned long phys_addr)
+{
+	unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
+	unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
+
+	/* Bank must be enabled to match. */
+	if (bp->valid == 0)
+		return 0;
+
+	/* Would BANK match upper bits? */
+	upper_bits ^= bp->um;		/* What bits are different? */
+	upper_bits  = ~upper_bits;	/* Invert. */
+	upper_bits |= bp->uk;		/* What bits don't matter for matching? */
+	upper_bits  = ~upper_bits;	/* Invert. */
+
+	if (upper_bits)
+		return 0;
+
+	/* Would BANK match lower bits? */
+	lower_bits ^= bp->lm;		/* What bits are different? */
+	lower_bits  = ~lower_bits;	/* Invert. */
+	lower_bits |= bp->lk;		/* What bits don't matter for matching? */
+	lower_bits  = ~lower_bits;	/* Invert. */
+
+	if (lower_bits)
+		return 0;
+
+	/* I always knew you'd be the one. */
+	return 1;
+}
+
+/* Given PHYS_ADDR, search memory controller banks for a match. */
+static struct bank_info *find_bank(unsigned long phys_addr)
+{
+	struct list_head *mctrl_head = &mctrl_list;
+	struct list_head *mctrl_entry = mctrl_head->next;
+
+	for (;;) {
+		struct mctrl_info *mp =
+			list_entry(mctrl_entry, struct mctrl_info, list);
+		int bank_no;
+
+		if (mctrl_entry == mctrl_head)
+			break;
+		mctrl_entry = mctrl_entry->next;
+
+		for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
+			struct bank_info *bp;
+
+			bp = &mp->logical_banks[bank_no];
+			if (bank_match(bp, phys_addr))
+				return bp;
+		}
+	}
+
+	return NULL;
+}
+
+/* This is the main purpose of this driver. */
+#define SYNDROME_MIN	-1
+#define SYNDROME_MAX	144
+int chmc_getunumber(int syndrome_code,
+		    unsigned long phys_addr,
+		    char *buf, int buflen)
+{
+	struct bank_info *bp;
+	struct obp_mem_layout *prop;
+	int bank_in_controller, first_dimm;
+
+	bp = find_bank(phys_addr);
+	if (bp == NULL ||
+	    syndrome_code < SYNDROME_MIN ||
+	    syndrome_code > SYNDROME_MAX) {
+		buf[0] = '?';
+		buf[1] = '?';
+		buf[2] = '?';
+		buf[3] = '\0';
+		return 0;
+	}
+
+	prop = &bp->mp->layout_prop;
+	bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
+	first_dimm  = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
+	first_dimm *= CHMCTRL_NDIMMS;
+
+	if (syndrome_code != SYNDROME_MIN) {
+		struct obp_map *map;
+		int qword, where_in_line, where, map_index, map_offset;
+		unsigned int map_val;
+
+		/* Yaay, single bit error so we can figure out
+		 * the exact dimm.
+		 */
+		if (prop->symmetric)
+			map = &prop->map[0];
+		else
+			map = &prop->map[1];
+
+		/* Covert syndrome code into the way the bits are
+		 * positioned on the bus.
+		 */
+		if (syndrome_code < 144 - 16)
+			syndrome_code += 16;
+		else if (syndrome_code < 144)
+			syndrome_code -= (144 - 7);
+		else if (syndrome_code < (144 + 3))
+			syndrome_code -= (144 + 3 - 4);
+		else
+			syndrome_code -= 144 + 3;
+
+		/* All this magic has to do with how a cache line
+		 * comes over the wire on Safari.  A 64-bit line
+		 * comes over in 4 quadword cycles, each of which
+		 * transmit ECC/MTAG info as well as the actual
+		 * data.  144 bits per quadword, 576 total.
+		 */
+#define LINE_SIZE	64
+#define LINE_ADDR_MSK	(LINE_SIZE - 1)
+#define QW_PER_LINE	4
+#define QW_BYTES	(LINE_SIZE / QW_PER_LINE)
+#define QW_BITS		144
+#define LAST_BIT	(576 - 1)
+
+		qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES;
+		where_in_line = ((3 - qword) * QW_BITS) + syndrome_code;
+		where = (LAST_BIT - where_in_line);
+		map_index = where >> 2;
+		map_offset = where & 0x3;
+		map_val = map->dimm_map[map_index];
+		map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1));
+
+		sprintf(buf, "%s, pin %3d",
+			prop->dimm_labels[first_dimm + map_val],
+			map->pin_map[where_in_line]);
+	} else {
+		int dimm;
+
+		/* Multi-bit error, we just dump out all the
+		 * dimm labels assosciated with this bank.
+		 */
+		for (dimm = 0; dimm < CHMCTRL_NDIMMS; dimm++) {
+			sprintf(buf, "%s ",
+				prop->dimm_labels[first_dimm + dimm]);
+			buf += strlen(buf);
+		}
+	}
+	return 0;
+}
+
+/* Accessing the registers is slightly complicated.  If you want
+ * to get at the memory controller which is on the same processor
+ * the code is executing, you must use special ASI load/store else
+ * you go through the global mapping.
+ */
+static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+{
+	unsigned long ret;
+
+	if (mp->portid == smp_processor_id()) {
+		__asm__ __volatile__("ldxa	[%1] %2, %0"
+				     : "=r" (ret)
+				     : "r" (offset), "i" (ASI_MCU_CTRL_REG));
+	} else {
+		__asm__ __volatile__("ldxa	[%1] %2, %0"
+				     : "=r" (ret)
+				     : "r" (mp->regs + offset),
+				       "i" (ASI_PHYS_BYPASS_EC_E));
+	}
+	return ret;
+}
+
+#if 0 /* currently unused */
+static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
+{
+	if (mp->portid == smp_processor_id()) {
+		__asm__ __volatile__("stxa	%0, [%1] %2"
+				     : : "r" (val),
+				         "r" (offset), "i" (ASI_MCU_CTRL_REG));
+	} else {
+		__asm__ __volatile__("ldxa	%0, [%1] %2"
+				     : : "r" (val),
+				         "r" (mp->regs + offset),
+				         "i" (ASI_PHYS_BYPASS_EC_E));
+	}
+}
+#endif
+
+static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
+{
+	struct bank_info *p = &mp->logical_banks[which_bank];
+
+	p->mp = mp;
+	p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank;
+	p->raw_reg = val;
+	p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
+	p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
+	p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
+	p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
+	p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
+
+	p->base  =  (p->um);
+	p->base &= ~(p->uk);
+	p->base <<= PA_UPPER_BITS_SHIFT;
+
+	switch(p->lk) {
+	case 0xf:
+	default:
+		p->interleave = 1;
+		break;
+
+	case 0xe:
+		p->interleave = 2;
+		break;
+
+	case 0xc:
+		p->interleave = 4;
+		break;
+
+	case 0x8:
+		p->interleave = 8;
+		break;
+
+	case 0x0:
+		p->interleave = 16;
+		break;
+	};
+
+	/* UK[10] is reserved, and UK[11] is not set for the SDRAM
+	 * bank size definition.
+	 */
+	p->size = (((unsigned long)p->uk &
+		    ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+	p->size /= p->interleave;
+}
+
+static void fetch_decode_regs(struct mctrl_info *mp)
+{
+	if (mp->layout_size == 0)
+		return;
+
+	interpret_one_decode_reg(mp, 0,
+				 read_mcreg(mp, CHMCTRL_DECODE1));
+	interpret_one_decode_reg(mp, 1,
+				 read_mcreg(mp, CHMCTRL_DECODE2));
+	interpret_one_decode_reg(mp, 2,
+				 read_mcreg(mp, CHMCTRL_DECODE3));
+	interpret_one_decode_reg(mp, 3,
+				 read_mcreg(mp, CHMCTRL_DECODE4));
+}
+
+static int init_one_mctrl(int node, int index)
+{
+	struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+	int portid = prom_getintdefault(node, "portid", -1);
+	struct linux_prom64_registers p_reg_prop;
+	int t;
+
+	if (!mp)
+		return -1;
+	memset(mp, 0, sizeof(*mp));
+	if (portid == -1)
+		goto fail;
+
+	mp->portid = portid;
+	mp->layout_size = prom_getproplen(node, "memory-layout");
+	if (mp->layout_size < 0)
+		mp->layout_size = 0;
+	if (mp->layout_size > sizeof(mp->layout_prop))
+		goto fail;
+
+	if (mp->layout_size > 0)
+		prom_getproperty(node, "memory-layout",
+				 (char *) &mp->layout_prop,
+				 mp->layout_size);
+
+	t = prom_getproperty(node, "reg",
+			     (char *) &p_reg_prop,
+			     sizeof(p_reg_prop));
+	if (t < 0 || p_reg_prop.reg_size != 0x48)
+		goto fail;
+
+	mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size);
+	if (mp->regs == NULL)
+		goto fail;
+
+	if (mp->layout_size != 0UL) {
+		mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1);
+		mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2);
+		mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3);
+		mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4);
+		mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL);
+	}
+
+	fetch_decode_regs(mp);
+
+	mp->index = index;
+
+	list_add(&mp->list, &mctrl_list);
+
+	/* Report the device. */
+	printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n",
+	       mp->index,
+	       mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
+
+	return 0;
+
+fail:
+	if (mp) {
+		if (mp->regs != NULL)
+			iounmap(mp->regs);
+		kfree(mp);
+	}
+	return -1;
+}
+
+static int __init probe_for_string(char *name, int index)
+{
+	int node = prom_getchild(prom_root_node);
+
+	while ((node = prom_searchsiblings(node, name)) != 0) {
+		int ret = init_one_mctrl(node, index);
+
+		if (!ret)
+			index++;
+
+		node = prom_getsibling(node);
+		if (!node)
+			break;
+	}
+
+	return index;
+}
+
+static int __init chmc_init(void)
+{
+	int index;
+
+	/* This driver is only for cheetah platforms. */
+	if (tlb_type != cheetah)
+		return -ENODEV;
+
+	index = probe_for_string("memory-controller", 0);
+	index = probe_for_string("mc-us3", index);
+
+	return 0;
+}
+
+static void __exit chmc_cleanup(void)
+{
+	struct list_head *head = &mctrl_list;
+	struct list_head *tmp = head->next;
+
+	for (;;) {
+		struct mctrl_info *p =
+			list_entry(tmp, struct mctrl_info, list);
+		if (tmp == head)
+			break;
+		tmp = tmp->next;
+
+		list_del(&p->list);
+		iounmap(p->regs);
+		kfree(p);
+	}
+}
+
+module_init(chmc_init);
+module_exit(chmc_cleanup);
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S
--- v2.4.3/linux/arch/sparc64/kernel/dtlb_prot.S	Sun Nov 12 20:37:16 2000
+++ linux/arch/sparc64/kernel/dtlb_prot.S	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.21 2000/11/10 08:28:45 davem Exp $
+/* $Id: dtlb_prot.S,v 1.22 2001/04/11 23:40:32 davem Exp $
  * dtlb_prot.S: DTLB protection trap strategy.
  *              This is included directly into the trap table.
  *
@@ -43,7 +43,7 @@
 	nop
 	nop
 
-/* PROT ** ICACHE line 3: Unused...	*/
+/* PROT ** ICACHE line 4: Unused...	*/
 	nop
 	nop
 	nop
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.4.3/linux/arch/sparc64/kernel/entry.S	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/entry.S	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.127 2001/03/23 07:56:30 davem Exp $
+/* $Id: entry.S,v 1.128 2001/03/28 10:56:34 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,7 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/visasm.h>
+#include <asm/estate.h>
 
 /* #define SYSCALL_TRACING */
 
@@ -788,6 +789,284 @@
 	call	cee_log
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o2
 	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Capture I/D/E-cache state into per-cpu error scoreboard.
+	 *
+	 * %g1:		(TL>=0) ? 1 : 0
+	 * %g2:		scratch
+	 * %g3:		scratch
+	 * %g4:		AFSR
+	 * %g5:		AFAR
+	 * %g6:		current thread ptr
+	 * %g7:		scratch
+	 */
+#define CHEETAH_LOG_ERROR						\
+	/* Put "TL1" software bit into AFSR. */				\
+	and		%g1, 0x1, %g1;					\
+	sllx		%g1, 63, %g2;					\
+	or		%g4, %g2, %g4;					\
+	/* Get log entry pointer for this cpu at this trap level. */	\
+	ldxa		[%g0] ASI_SAFARI_CONFIG, %g2;			\
+	srlx		%g2, 17, %g2;					\
+	and		%g2, 0x3ff, %g2;				\
+	sllx		%g2, 9, %g2;					\
+	sethi		%hi(cheetah_error_log), %g3;			\
+	ldx		[%g3 + %lo(cheetah_error_log)], %g3;		\
+	brz,pn		%g3, 80f;					\
+	 nop;								\
+	add		%g3, %g2, %g3;					\
+	sllx		%g1, 8, %g1;					\
+	add		%g3, %g1, %g1;					\
+	/* %g1 holds pointer to the top of the logging scoreboard */	\
+	ldx		[%g1 + 0x0], %g7;				\
+	cmp		%g7, -1;					\
+	bne,pn		%xcc, 80f;					\
+	 nop;								\
+	stx		%g4, [%g1 + 0x0];				\
+	stx		%g5, [%g1 + 0x8];				\
+	add		%g1, 0x10, %g1;					\
+	/* %g1 now points to D-cache logging area */			\
+	set		0x3ff8, %g2;	/* DC_addr mask		*/	\
+	and		%g5, %g2, %g2;	/* DC_addr bits of AFAR	*/	\
+	srlx		%g5, 12, %g3;					\
+	or		%g3, 1, %g3;	/* PHYS tag + valid	*/	\
+10:	ldxa		[%g2] ASI_DCACHE_TAG, %g7;			\
+	cmp		%g3, %g7;	/* TAG match?		*/	\
+	bne,pt		%xcc, 13f;					\
+	 nop;								\
+	/* Yep, what we want, capture state. */				\
+	stx		%g2, [%g1 + 0x20];				\
+	stx		%g7, [%g1 + 0x28];				\
+	/* A membar Sync is required before and after utag access. */	\
+	membar		#Sync;						\
+	ldxa		[%g2] ASI_DCACHE_UTAG, %g7;			\
+	membar		#Sync;						\
+	stx		%g7, [%g1 + 0x30];				\
+	ldxa		[%g2] ASI_DCACHE_SNOOP_TAG, %g7;		\
+	stx		%g7, [%g1 + 0x38];				\
+	clr		%g3;						\
+12:	ldxa		[%g2 + %g3] ASI_DCACHE_DATA, %g7;		\
+	stx		%g7, [%g1];					\
+	add		%g3, (1 << 5), %g3;				\
+	cmp		%g3, (4 << 5);					\
+	bl,pt		%xcc, 12b;					\
+	 add		%g1, 0x8, %g1;					\
+	ba,pt		%xcc, 20f;					\
+	 add		%g1, 0x20, %g1;					\
+13:	sethi		%hi(1 << 14), %g7;				\
+	add		%g2, %g7, %g2;					\
+	srlx		%g2, 14, %g7;					\
+	cmp		%g7, 4;						\
+	bl,pt		%xcc, 10b;					\
+	 nop;								\
+	add		%g1, 0x40, %g1;					\
+20:	/* %g1 now points to I-cache logging area */			\
+	set		0x1fe0, %g2;	/* IC_addr mask		*/	\
+	and		%g5, %g2, %g2;	/* IC_addr bits of AFAR	*/	\
+	sllx		%g2, 1, %g2;	/* IC_addr[13:6]==VA[12:5] */	\
+	srlx		%g5, (13 - 8), %g3; /* Make PTAG */		\
+	andn		%g3, 0xff, %g3;	/* Mask off undefined bits */	\
+21:	ldxa		[%g2] ASI_IC_TAG, %g7;				\
+	andn		%g7, 0xff, %g7;					\
+	cmp		%g3, %g7;					\
+	bne,pt		%xcc, 23f;					\
+	 nop;								\
+	/* Yep, what we want, capture state. */				\
+	stx		%g2, [%g1 + 0x40];				\
+	stx		%g7, [%g1 + 0x48];				\
+	add		%g2, (1 << 3), %g2;				\
+	ldxa		[%g2] ASI_IC_TAG, %g7;				\
+	add		%g2, (1 << 3), %g2;				\
+	stx		%g7, [%g1 + 0x50];				\
+	ldxa		[%g2] ASI_IC_TAG, %g7;				\
+	add		%g2, (1 << 3), %g2;				\
+	stx		%g7, [%g1 + 0x60];				\
+	ldxa		[%g2] ASI_IC_TAG, %g7;				\
+	stx		%g7, [%g1 + 0x68];				\
+	sub		%g2, (3 << 3), %g2;				\
+	ldxa		[%g2] ASI_IC_STAG, %g7;				\
+	stx		%g7, [%g1 + 0x58];				\
+	clr		%g3;						\
+	srlx		%g2, 2, %g2;					\
+22:	ldxa		[%g2 + %g3] ASI_IC_INSTR, %g7;			\
+	stx		%g7, [%g1];					\
+	add		%g3, (1 << 3), %g3;				\
+	cmp		%g3, (8 << 3);					\
+	bl,pt		%xcc, 22b;					\
+	 add		%g1, 0x8, %g1;					\
+	ba,pt		%xcc, 30f;					\
+	 add		%g1, 0x30, %g1;					\
+23:	sethi		%hi(1 << 14), %g7;				\
+	add		%g2, %g7, %g2;					\
+	srlx		%g2, 14, %g7;					\
+	cmp		%g7, 4;						\
+	bl,pt		%xcc, 21b;					\
+	 nop;								\
+	add		%g1, 0x70, %g1;					\
+30:	/* %g1 now points to E-cache logging area */			\
+	andn		%g5, (32 - 1), %g2;	/* E-cache subblock */	\
+	stx		%g2, [%g1 + 0x20];				\
+	ldxa		[%g2] ASI_EC_TAG_DATA, %g7;			\
+	stx		%g7, [%g1 + 0x28];				\
+	ldxa		[%g2] ASI_EC_R, %g0;				\
+	clr		%g3;						\
+31:	ldxa		[%g3] ASI_EC_DATA, %g7;				\
+	stx		%g7, [%g1 + %g3];				\
+	add		%g3, 0x8, %g3;					\
+	cmp		%g3, 0x20;					\
+	bl,pt		%xcc, 31b;					\
+	 nop;								\
+80:	/* DONE */
+
+	/* These get patched into the trap table at boot time
+	 * once we know we have a cheetah processor.
+	 */
+	.globl		cheetah_fecc_trap_vector, cheetah_fecc_trap_vector_tl1
+cheetah_fecc_trap_vector:
+	membar		#Sync
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	andn		%g1, DCU_DC | DCU_IC, %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	sethi		%hi(cheetah_fast_ecc), %g2
+	jmpl		%g2 + %lo(cheetah_fast_ecc), %g0
+	 mov		0, %g1
+cheetah_fecc_trap_vector_tl1:
+	membar		#Sync
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	andn		%g1, DCU_DC | DCU_IC, %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	sethi		%hi(cheetah_fast_ecc), %g2
+	jmpl		%g2 + %lo(cheetah_fast_ecc), %g0
+	 mov		1, %g1
+	.globl	cheetah_cee_trap_vector, cheetah_cee_trap_vector_tl1
+cheetah_cee_trap_vector:
+	membar		#Sync
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	andn		%g1, DCU_IC, %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	sethi		%hi(cheetah_cee), %g2
+	jmpl		%g2 + %lo(cheetah_cee), %g0
+	 mov		0, %g1
+cheetah_cee_trap_vector_tl1:
+	membar		#Sync
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	andn		%g1, DCU_IC, %g1
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
+	sethi		%hi(cheetah_cee), %g2
+	jmpl		%g2 + %lo(cheetah_cee), %g0
+	 mov		1, %g1
+	.globl	cheetah_deferred_trap_vector, cheetah_deferred_trap_vector_tl1
+cheetah_deferred_trap_vector:
+	membar		#Sync
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1;
+	andn		%g1, DCU_DC | DCU_IC, %g1;
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG;
+	membar		#Sync;
+	sethi		%hi(cheetah_deferred_trap), %g2
+	jmpl		%g2 + %lo(cheetah_deferred_trap), %g0
+	 mov		0, %g1
+cheetah_deferred_trap_vector_tl1:
+	membar		#Sync;
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1;
+	andn		%g1, DCU_DC | DCU_IC, %g1;
+	stxa		%g1, [%g0] ASI_DCU_CONTROL_REG;
+	membar		#Sync;
+	sethi		%hi(cheetah_deferred_trap), %g2
+	jmpl		%g2 + %lo(cheetah_deferred_trap), %g0
+	 mov		1, %g1
+
+	/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
+	 * in the trap table.  That code has done a memory barrier
+	 * and has disabled both the I-cache and D-cache in the DCU
+	 * control register.  The I-cache is disabled so that we may
+	 * capture the corrupted cache line, and the D-cache is disabled
+	 * because corrupt data may have been placed there and we don't
+	 * want to reference it.
+	 *
+	 * %g1 is one if this trap occured at %tl >= 1.
+	 *
+	 * Next, we turn off error reporting so that we don't recurse.
+	 */
+	.globl		cheetah_fast_ecc
+cheetah_fast_ecc:
+	ldxa		[%g0] ASI_ESTATE_ERROR_EN, %g2
+	andn		%g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
+	stxa		%g2, [%g0] ASI_ESTATE_ERROR_EN
+	membar		#Sync
+
+	/* Fetch and clear AFSR/AFAR */
+	ldxa		[%g0] ASI_AFSR, %g4
+	ldxa		[%g0] ASI_AFAR, %g5
+	stxa		%g4, [%g0] ASI_AFSR
+	membar		#Sync
+
+	CHEETAH_LOG_ERROR
+
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	ba,pt		%xcc, etrap_irq
+	 rd		%pc, %g7
+	mov		%l4, %o1
+	mov		%l5, %o2
+	call		cheetah_fecc_handler
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,a,pt		%xcc, rtrap_clr_l6
+
+	/* Our caller has disabled I-cache and performed membar Sync. */
+	.globl		cheetah_cee
+cheetah_cee:
+	ldxa		[%g0] ASI_ESTATE_ERROR_EN, %g2
+	andn		%g2, ESTATE_ERROR_CEEN, %g2
+	stxa		%g2, [%g0] ASI_ESTATE_ERROR_EN
+	membar		#Sync
+
+	/* Fetch and clear AFSR/AFAR */
+	ldxa		[%g0] ASI_AFSR, %g4
+	ldxa		[%g0] ASI_AFAR, %g5
+	stxa		%g4, [%g0] ASI_AFSR
+	membar		#Sync
+
+	CHEETAH_LOG_ERROR
+
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	ba,pt		%xcc, etrap_irq
+	 rd		%pc, %g7
+	mov		%l4, %o1
+	mov		%l5, %o2
+	call		cheetah_cee_handler
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,a,pt		%xcc, rtrap_clr_l6
+
+	/* Our caller has disabled I-cache+D-cache and performed membar Sync. */
+	.globl		cheetah_deferred_trap
+cheetah_deferred_trap:
+	ldxa		[%g0] ASI_ESTATE_ERROR_EN, %g2
+	andn		%g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
+	stxa		%g2, [%g0] ASI_ESTATE_ERROR_EN
+	membar		#Sync
+
+	/* Fetch and clear AFSR/AFAR */
+	ldxa		[%g0] ASI_AFSR, %g4
+	ldxa		[%g0] ASI_AFAR, %g5
+	stxa		%g4, [%g0] ASI_AFSR
+	membar		#Sync
+
+	CHEETAH_LOG_ERROR
+
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	ba,pt		%xcc, etrap_irq
+	 rd		%pc, %g7
+	mov		%l4, %o1
+	mov		%l5, %o2
+	call		cheetah_deferred_handler
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,a,pt		%xcc, rtrap_clr_l6
 
 	.globl		__do_privact
 __do_privact:
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.4.3/linux/arch/sparc64/kernel/head.S	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/head.S	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.75 2001/03/22 09:54:26 davem Exp $
+/* $Id: head.S,v 1.77 2001/04/05 12:44:34 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -90,13 +90,25 @@
 	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr	%g1, %asr18
 
-	sethi	%uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	or	%g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sethi	%uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	or	%g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
 	sllx	%g5, 32, %g5
 	or	%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
-	ldxa	[%g0] ASI_DCU_CONTROL_REG, %g3
-	or	%g5, %g3, %g5
 	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
+	membar	#Sync
+
+	mov	TSB_EXTENSION_P, %g3
+	stxa	%g0, [%g3] ASI_DMMU
+	stxa	%g0, [%g3] ASI_IMMU
+	membar	#Sync
+
+	mov	TSB_EXTENSION_S, %g3
+	stxa	%g0, [%g3] ASI_DMMU
+	membar	#Sync
+
+	mov	TSB_EXTENSION_N, %g3
+	stxa	%g0, [%g3] ASI_DMMU
+	stxa	%g0, [%g3] ASI_IMMU
 	membar	#Sync
 
 	wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/init_task.c linux/arch/sparc64/kernel/init_task.c
--- v2.4.3/linux/arch/sparc64/kernel/init_task.c	Mon Jul 26 22:41:09 1999
+++ linux/arch/sparc64/kernel/init_task.c	Thu Apr 19 08:38:48 2001
@@ -15,6 +15,5 @@
  * We really don't need this special alignment like the Intel does, but
  * I do it anyways for completeness.
  */
-union task_union init_task_union
-	__attribute__((__section__(".text"))) =
-		{ INIT_TASK(init_task_union.task) };
+__asm__ (".text");
+union task_union init_task_union = { INIT_TASK(init_task_union.task) };
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.4.3/linux/arch/sparc64/kernel/ioctl32.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.110 2001/03/22 12:51:25 davem Exp $
+/* $Id: ioctl32.c,v 1.111 2001/03/27 07:28:43 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -527,6 +527,55 @@
 	return err;
 }
 
+static inline int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data, ethcmd;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+
+	if (get_user(ethcmd, (u32 *)A(data))) {
+		err = -EFAULT;
+		goto out;
+	}
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GSET:
+	case ETHTOOL_SSET:
+	default:		len = sizeof(struct ethtool_cmd); break;
+	}
+
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		u32 data;
+
+		__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
 static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq ifr;
@@ -548,23 +597,11 @@
 	case SIOCGPPPSTATS:
 	case SIOCGPPPCSTATS:
 	case SIOCGPPPVER:
-	case SIOCETHTOOL:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
 		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
 		if (!ifr.ifr_data)
 			return -EAGAIN;
-		if(cmd == SIOCETHTOOL) {
-			u32 data;
-
-			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
-			if(copy_from_user(ifr.ifr_data,
-					  (char *)A(data),
-					  sizeof(struct ethtool_cmd))) {
-				free_page((unsigned long)ifr.ifr_data);
-				return -EFAULT;
-			}
-		}
 		break;
 	default:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
@@ -594,14 +631,11 @@
 		case SIOCGPPPSTATS:
 		case SIOCGPPPCSTATS:
 		case SIOCGPPPVER:
-		case SIOCETHTOOL:
 		{
 			u32 data;
 			int len;
 
 			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
-			if(cmd == SIOCETHTOOL)
-				len = sizeof(struct ethtool_cmd);
 			if(cmd == SIOCGPPPVER)
 				len = strlen((char *)ifr.ifr_data) + 1;
 			else if(cmd == SIOCGPPPCSTATS)
@@ -627,6 +661,14 @@
 				err = -EFAULT;
 			break;
 		}
+	} else {
+		switch (cmd) {
+		case SIOCGPPPSTATS:
+		case SIOCGPPPCSTATS:
+		case SIOCGPPPVER:
+			free_page((unsigned long)ifr.ifr_data);
+			break;
+		}
 	}
 	return err;
 }
@@ -3705,7 +3747,7 @@
 HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
-HANDLE_IOCTL(SIOCETHTOOL, dev_ifsioc)
+HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
 HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
 HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.4.3/linux/arch/sparc64/kernel/pci.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/pci.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.23 2001/03/14 04:17:14 davem Exp $
+/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -73,6 +73,7 @@
 
 spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED;
 volatile int pci_poke_in_progress;
+volatile int pci_poke_cpu = -1;
 volatile int pci_poke_faulted;
 
 /* Probe for all PCI controllers in the system. */
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h
--- v2.4.3/linux/arch/sparc64/kernel/pci_impl.h	Mon Mar 27 10:35:56 2000
+++ linux/arch/sparc64/kernel/pci_impl.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_impl.h,v 1.6 2000/03/25 05:18:11 davem Exp $
+/* $Id: pci_impl.h,v 1.7 2001/03/28 10:56:34 davem Exp $
  * pci_impl.h: Helper definitions for PCI controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -41,6 +41,7 @@
 /* Configuration space access. */
 extern spinlock_t pci_poke_lock;
 extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_cpu;
 extern volatile int pci_poke_faulted;
 
 static __inline__ void pci_config_read8(u8 *addr, u8 *ret)
@@ -49,6 +50,7 @@
 	u8 byte;
 
 	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
 	pci_poke_in_progress = 1;
 	pci_poke_faulted = 0;
 	__asm__ __volatile__("membar #Sync\n\t"
@@ -58,6 +60,7 @@
 			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
 			     : "memory");
 	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
 	if (!pci_poke_faulted)
 		*ret = byte;
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
@@ -69,6 +72,7 @@
 	u16 word;
 
 	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
 	pci_poke_in_progress = 1;
 	pci_poke_faulted = 0;
 	__asm__ __volatile__("membar #Sync\n\t"
@@ -78,6 +82,7 @@
 			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
 			     : "memory");
 	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
 	if (!pci_poke_faulted)
 		*ret = word;
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
@@ -89,6 +94,7 @@
 	u32 dword;
 
 	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
 	pci_poke_in_progress = 1;
 	pci_poke_faulted = 0;
 	__asm__ __volatile__("membar #Sync\n\t"
@@ -98,6 +104,7 @@
 			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
 			     : "memory");
 	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
 	if (!pci_poke_faulted)
 		*ret = dword;
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
@@ -108,6 +115,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
 	pci_poke_in_progress = 1;
 	pci_poke_faulted = 0;
 	__asm__ __volatile__("membar #Sync\n\t"
@@ -117,6 +125,7 @@
 			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
 			     : "memory");
 	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
 }
 
@@ -125,6 +134,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
 	pci_poke_in_progress = 1;
 	pci_poke_faulted = 0;
 	__asm__ __volatile__("membar #Sync\n\t"
@@ -134,6 +144,7 @@
 			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
 			     : "memory");
 	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
 }
 
@@ -142,6 +153,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
 	pci_poke_in_progress = 1;
 	pci_poke_faulted = 0;
 	__asm__ __volatile__("membar #Sync\n\t"
@@ -151,6 +163,7 @@
 			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
 			     : "memory");
 	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
 	spin_unlock_irqrestore(&pci_poke_lock, flags);
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.4.3/linux/arch/sparc64/kernel/pci_psycho.c	Tue Mar  6 22:44:16 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.21 2001/02/28 03:28:55 davem Exp $
+/* $Id: pci_psycho.c,v 1.22 2001/04/17 01:19:23 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -757,6 +757,8 @@
 	error_bits = afsr &
 		(PSYCHO_UEAFSR_PPIO | PSYCHO_UEAFSR_PDRD | PSYCHO_UEAFSR_PDWR |
 		 PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
+	if (!error_bits)
+		return;
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -830,6 +832,8 @@
 	error_bits = afsr &
 		(PSYCHO_CEAFSR_PPIO | PSYCHO_CEAFSR_PDRD | PSYCHO_CEAFSR_PDWR |
 		 PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
+	if (!error_bits)
+		return;
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -922,6 +926,8 @@
 		 PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
 		 PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
 		 PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
+	if (!error_bits)
+		return;
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.4.3/linux/arch/sparc64/kernel/pci_sabre.c	Tue Mar  6 22:44:16 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.25 2001/02/28 03:28:55 davem Exp $
+/* $Id: pci_sabre.c,v 1.26 2001/04/17 01:19:23 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -774,6 +774,8 @@
 		(SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
 		 SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
 		 SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
+	if (!error_bits)
+		return;
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -829,6 +831,8 @@
 	error_bits = afsr &
 		(SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
 		 SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
+	if (!error_bits)
+		return;
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -885,6 +889,8 @@
 		 SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |
 		 SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
 		 SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
+	if (!error_bits)
+		return;
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- v2.4.3/linux/arch/sparc64/kernel/pci_schizo.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.13 2001/03/21 00:29:58 davem Exp $
+/* $Id: pci_schizo.c,v 1.14 2001/04/17 01:19:23 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -716,6 +716,8 @@
 	error_bits = afsr &
 		(SCHIZO_UEAFSR_PPIO | SCHIZO_UEAFSR_PDRD | SCHIZO_UEAFSR_PDWR |
 		 SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
+	if (!error_bits)
+		return;
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -802,6 +804,8 @@
 	error_bits = afsr &
 		(SCHIZO_CEAFSR_PPIO | SCHIZO_CEAFSR_PDRD | SCHIZO_CEAFSR_PDWR |
 		 SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
+	if (!error_bits)
+		return;
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -901,6 +905,8 @@
 		 SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
 		 SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
 		 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
+	if (!error_bits)
+		return;
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.4.3/linux/arch/sparc64/kernel/process.c	Mon Mar 26 11:01:17 2001
+++ linux/arch/sparc64/kernel/process.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.116 2001/03/24 09:36:01 davem Exp $
+/*  $Id: process.c,v 1.117 2001/03/30 07:10:41 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c
--- v2.4.3/linux/arch/sparc64/kernel/semaphore.c	Sat Nov 11 19:02:40 2000
+++ linux/arch/sparc64/kernel/semaphore.c	Tue Apr 17 17:19:30 2001
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.5 2000/11/10 04:02:03 davem Exp $
+/* $Id: semaphore.c,v 1.6 2001/04/14 01:12:02 davem Exp $
  *  Generic semaphore code. Buyer beware. Do your own
  * specific changes in <asm/semaphore-helper.h>
  */
@@ -125,173 +125,4 @@
 int __down_trylock(struct semaphore * sem)
 {
 	return waking_non_zero_trylock(sem);
-}
-
-/* rw mutexes
- * Implemented by Jakub Jelinek (jakub@redhat.com) based on
- * i386 implementation by Ben LaHaise (bcrl@redhat.com).
- */
-
-asm("
-	.text
-	.align	32
-	.globl	__down_read_failed
-__down_read_failed:
-	save		%sp, -160, %sp
-	membar		#StoreStore
-	brz,pt		%g5, 3f
-	 mov		%g7, %l0
-1:	call		down_read_failed
-	 mov		%l0, %o0
-2:	lduw		[%l0], %l1
-	sub		%l1, 1, %l2
-	cas		[%l0], %l1, %l2
-
-	cmp		%l1, %l2
-	bne,pn		%icc, 2b
-	 membar		#StoreStore
-	subcc		%l1, 1, %g0
-	bpos,pt		%icc, 4f
-	 nop
-	bcc,pn		%icc, 1b
-	 nop
-
-3:	call		down_read_failed_biased
-	 mov		%l0, %o0
-4:	ret
-	 restore
-	.previous
-");
-
-asm("
-	.text
-	.align	32
-	.globl	__down_write_failed
-__down_write_failed:
-	save		%sp, -160, %sp
-	membar		#StoreStore
-	tst		%g5
-	bge,pt		%icc, 3f
-	 mov		%g7, %l0
-1:	call		down_write_failed
-	 mov		%l0, %o0
-2:	lduw		[%l0], %l1
-	sethi		%hi (" RW_LOCK_BIAS_STR "), %l3
-	sub		%l1, %l3, %l2
-	cas		[%l0], %l1, %l2
-
-	cmp		%l1, %l2
-	bne,pn		%icc, 2b
-	 membar		#StoreStore
-	subcc		%l1, %l3, %g0
-	be,pt		%icc, 4f
-	 nop
-	bcc,pn		%icc, 1b
-	 nop
-
-3:	call		down_write_failed_biased
-	 mov		%l0, %o0
-4:	ret
-	 restore
-	.previous
-");
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
-
-	for (;;) {
-		if (test_and_clear_le_bit(0, &sem->granted))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!test_le_bit(0, &sem->granted))
-			schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
-	for (;;) {
-		if (test_and_clear_le_bit(1, &sem->granted))
-			break;
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!test_le_bit(1, &sem->granted))
-			schedule();
-	}
-
-	remove_wait_queue(&sem->write_bias_wait, &wait);
-	tsk->state = TASK_RUNNING;
-
-	/* if the lock is currently unbiased, awaken the sleepers
-	 * FIXME: this wakes up the readers early in a bit of a
-	 * stampede -> bad!
-	 */
-	if (sem->count >= 0)
-		wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased.  Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	__up_read(sem); /* this takes care of granting the lock */
-
-	add_wait_queue(&sem->wait, &wait);
-
-	while (sem->count < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->count >= 0)
-			break;
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
-	DOWN_VAR
-
-	__up_write(sem);	/* this takes care of granting the lock */
-
-	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	while (sem->count < 0) {
-		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (sem->count >= 0)
-			break;  /* we must attempt to acquire or bias the lock */
-		schedule();
-	}
-
-	remove_wait_queue(&sem->wait, &wait);
-	tsk->state = TASK_RUNNING;
-}
-
-void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
-	if (readers) {
-		if (test_and_set_le_bit(0, &sem->granted))
-			BUG();
-		wake_up(&sem->wait);
-	} else {
-		if (test_and_set_le_bit(1, &sem->granted))
-			BUG();
-		wake_up(&sem->write_bias_wait);
-	}
 }
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.4.3/linux/arch/sparc64/kernel/smp.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/smp.c	Thu Apr 12 12:10:25 2001
@@ -415,9 +415,7 @@
 
 	/* Setup the dispatch data registers. */
 	__asm__ __volatile__("stxa	%0, [%3] %6\n\t"
-			     "membar	#Sync\n\t"
 			     "stxa	%1, [%4] %6\n\t"
-			     "membar	#Sync\n\t"
 			     "stxa	%2, [%5] %6\n\t"
 			     "membar	#Sync\n\t"
 			     : /* no outputs */
@@ -994,6 +992,8 @@
 
 cycles_t cacheflush_time;
 
+extern unsigned long cheetah_tune_scheduling(void);
+
 static void __init smp_tune_scheduling (void)
 {
 	unsigned long orig_flush_base, flush_base, flags, *p;
@@ -1011,6 +1011,11 @@
 	 * of moving a process from one cpu to another).
 	 */
 	printk("SMP: Calibrating ecache flush... ");
+	if (tlb_type == cheetah) {
+		cacheflush_time = cheetah_tune_scheduling();
+		goto report;
+	}
+
 	ecache_size = prom_getintdefault(linux_cpus[0].prom_node,
 					 "ecache-size", (512 * 1024));
 	if (ecache_size > (4 * 1024 * 1024))
@@ -1063,7 +1068,7 @@
 		cacheflush_time = ((ecache_size << 2) +
 				   (ecache_size << 1));
 	}
-
+report:
 	printk("Using heuristic of %d cycles.\n",
 	       (int) cacheflush_time);
 }
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.4.3/linux/arch/sparc64/kernel/sparc64_ksyms.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.102 2001/03/24 09:36:01 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.105 2001/04/14 01:12:02 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -149,6 +149,8 @@
 EXPORT_SYMBOL(_do_write_unlock);
 #endif
 
+EXPORT_SYMBOL(smp_call_function);
+
 #endif
 
 /* semaphores */
@@ -157,21 +159,16 @@
 EXPORT_SYMBOL(__down_trylock);
 EXPORT_SYMBOL(__up);
 
-/* rw semaphores */
-EXPORT_SYMBOL_NOVERS(__down_read_failed);
-EXPORT_SYMBOL_NOVERS(__down_write_failed);
-EXPORT_SYMBOL_NOVERS(__rwsem_wake);
-
 /* Atomic counter implementation. */
 EXPORT_SYMBOL(__atomic_add);
 EXPORT_SYMBOL(__atomic_sub);
 
 /* Atomic bit operations. */
-EXPORT_SYMBOL(__test_and_set_bit);
-EXPORT_SYMBOL(__test_and_clear_bit);
-EXPORT_SYMBOL(__test_and_change_bit);
-EXPORT_SYMBOL(__test_and_set_le_bit);
-EXPORT_SYMBOL(__test_and_clear_le_bit);
+EXPORT_SYMBOL(___test_and_set_bit);
+EXPORT_SYMBOL(___test_and_clear_bit);
+EXPORT_SYMBOL(___test_and_change_bit);
+EXPORT_SYMBOL(___test_and_set_le_bit);
+EXPORT_SYMBOL(___test_and_clear_le_bit);
 
 EXPORT_SYMBOL(ivector_table);
 EXPORT_SYMBOL(enable_irq);
@@ -180,7 +177,7 @@
 EXPORT_SYMBOL(__flushw_user);
 
 EXPORT_SYMBOL(tlb_type);
-
+EXPORT_SYMBOL(get_fb_unmapped_area);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(__flush_dcache_page);
 
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/starfire.c linux/arch/sparc64/kernel/starfire.c
--- v2.4.3/linux/arch/sparc64/kernel/starfire.c	Sun Feb 18 19:49:54 2001
+++ linux/arch/sparc64/kernel/starfire.c	Thu Apr 19 08:38:49 2001
@@ -1,8 +1,8 @@
-/* $Id: starfire.c,v 1.9 2001/02/13 01:16:44 davem Exp $
+/* $Id: starfire.c,v 1.10 2001/04/14 21:13:45 davem Exp $
  * starfire.c: Starfire/E10000 support.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
  */
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.4.3/linux/arch/sparc64/kernel/sys_sparc.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/sys_sparc.c	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.50 2001/03/24 09:36:10 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 2001/04/14 01:12:02 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -42,19 +42,28 @@
 
 #define COLOUR_ALIGN(addr)	(((addr)+SHMLBA-1)&~(SHMLBA-1))
 
-unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct * vmm;
 	unsigned long task_size = TASK_SIZE;
 
+	if (flags & MAP_FIXED) {
+		/* We do not accept a shared mapping if it would violate
+		 * cache aliasing constraints.
+		 */
+		if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+			return -EINVAL;
+		return addr;
+	}
+
 	if (current->thread.flags & SPARC_FLAG_32BIT)
 		task_size = 0xf0000000UL;
 	if (len > task_size || len > -PAGE_OFFSET)
-		return 0;
+		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+	if (flags & MAP_SHARED)
 		addr = COLOUR_ALIGN(addr);
 	else
 		addr = PAGE_ALIGN(addr);
@@ -68,15 +77,58 @@
 			vmm = find_vma(current->mm, PAGE_OFFSET);
 		}
 		if (task_size < addr)
-			return 0;
+			return -ENOMEM;
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
 		addr = vmm->vm_end;
-		if (current->thread.flags & SPARC_FLAG_MMAPSHARED)
+		if (flags & MAP_SHARED)
 			addr = COLOUR_ALIGN(addr);
 	}
 }
 
+/* Try to align mapping such that we align it as much as possible. */
+unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	unsigned long align_goal, addr = -ENOMEM;
+
+	if (flags & MAP_FIXED) {
+		/* Ok, don't mess with it. */
+		return get_unmapped_area(NULL, addr, len, pgoff, flags);
+	}
+	flags &= ~MAP_SHARED;
+
+	align_goal = PAGE_SIZE;
+	if (len >= (4UL * 1024 * 1024))
+		align_goal = (4UL * 1024 * 1024);
+	else if (len >= (512UL * 1024))
+		align_goal = (512UL * 1024);
+	else if (len >= (64UL * 1024))
+		align_goal = (64UL * 1024);
+
+	do {
+		addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags);
+		if (!(addr & ~PAGE_MASK)) {
+			addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL);
+			break;
+		}
+
+		if (align_goal == (4UL * 1024 * 1024))
+			align_goal = (512UL * 1024);
+		else if (align_goal == (512UL * 1024))
+			align_goal = (64UL * 1024);
+		else
+			align_goal = PAGE_SIZE;
+	} while ((addr & ~PAGE_MASK) && align_goal > PAGE_SIZE);
+
+	/* Mapping is smaller than 64K or larger areas could not
+	 * be obtained.
+	 */
+	if (addr & ~PAGE_MASK)
+		addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags);
+
+	return addr;
+}
+
 extern asmlinkage unsigned long sys_brk(unsigned long brk);
 
 asmlinkage unsigned long sparc_brk(unsigned long brk)
@@ -240,15 +292,10 @@
 			goto out_putf;
 	}
 
-	if (flags & MAP_SHARED)
-		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
-
 	down_write(&current->mm->mmap_sem);
 	retval = do_mmap(file, addr, len, prot, flags, off);
 	up_write(&current->mm->mmap_sem);
 
-	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
-
 out_putf:
 	if (file)
 		fput(file);
@@ -286,25 +333,36 @@
 	if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET)
 		goto out;
 	down_write(&current->mm->mmap_sem);
-	vma = find_vma(current->mm, addr);
-	if (vma && (vma->vm_flags & VM_SHARED))
-		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
 	if (flags & MREMAP_FIXED) {
 		if (new_addr < PAGE_OFFSET &&
 		    new_addr + new_len > -PAGE_OFFSET)
 			goto out_sem;
 	} else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) {
+		unsigned long map_flags = 0;
+		struct file *file = NULL;
+
 		ret = -ENOMEM;
 		if (!(flags & MREMAP_MAYMOVE))
 			goto out_sem;
-		new_addr = get_unmapped_area(addr, new_len);
-		if (!new_addr)
+
+		vma = find_vma(current->mm, addr);
+		if (vma) {
+			if (vma->vm_flags & VM_SHARED)
+				map_flags |= MAP_SHARED;
+			file = vma->vm_file;
+		}
+
+		/* MREMAP_FIXED checked above. */
+		new_addr = get_unmapped_area(file, addr, new_len,
+				    vma ? vma->vm_pgoff : 0,
+				    map_flags);
+		ret = new_addr;
+		if (new_addr & ~PAGE_MASK)
 			goto out_sem;
 		flags |= MREMAP_FIXED;
 	}
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
-	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
 	up_write(&current->mm->mmap_sem);
 out:
 	return ret;       
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.4.3/linux/arch/sparc64/kernel/sys_sparc32.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.174 2001/03/24 09:36:10 davem Exp $
+/* $Id: sys_sparc32.c,v 1.176 2001/04/14 01:12:02 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -4134,24 +4134,35 @@
 	if (addr > 0xf0000000UL - old_len)
 		goto out;
 	down_write(&current->mm->mmap_sem);
-	vma = find_vma(current->mm, addr);
-	if (vma && (vma->vm_flags & VM_SHARED))
-		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
 	if (flags & MREMAP_FIXED) {
 		if (new_addr > 0xf0000000UL - new_len)
 			goto out_sem;
 	} else if (addr > 0xf0000000UL - new_len) {
+		unsigned long map_flags = 0;
+		struct file *file = NULL;
+
 		ret = -ENOMEM;
 		if (!(flags & MREMAP_MAYMOVE))
 			goto out_sem;
-		new_addr = get_unmapped_area(addr, new_len);
-		if (!new_addr)
+
+		vma = find_vma(current->mm, addr);
+		if (vma) {
+			if (vma->vm_flags & VM_SHARED)
+				map_flags |= MAP_SHARED;
+			file = vma->vm_file;
+		}
+
+		/* MREMAP_FIXED checked above. */
+		new_addr = get_unmapped_area(file, addr, new_len,
+				    vma ? vma->vm_pgoff : 0,
+				    map_flags);
+		ret = new_addr;
+		if (new_addr & ~PAGE_MASK)
 			goto out_sem;
 		flags |= MREMAP_FIXED;
 	}
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
-	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
 	up_write(&current->mm->mmap_sem);
 out:
 	return ret;       
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.4.3/linux/arch/sparc64/kernel/trampoline.S	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/trampoline.S	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.19 2001/03/22 09:54:26 davem Exp $
+/* $Id: trampoline.S,v 1.21 2001/04/05 12:44:34 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -44,14 +44,26 @@
 	mov		DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
 	wr		%g1, %asr18
 
-	sethi		%uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
-	or		%g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sethi		%uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	or		%g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
 	sllx		%g5, 32, %g5
 	or		%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
-	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
-	or		%g5, %g3, %g5
 	stxa		%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar		#Sync
+
+	mov	TSB_EXTENSION_P, %g3
+	stxa	%g0, [%g3] ASI_DMMU
+	stxa	%g0, [%g3] ASI_IMMU
+	membar	#Sync
+
+	mov	TSB_EXTENSION_S, %g3
+	stxa	%g0, [%g3] ASI_DMMU
+	membar	#Sync
+
+	mov	TSB_EXTENSION_N, %g3
+	stxa	%g0, [%g3] ASI_DMMU
+	stxa	%g0, [%g3] ASI_IMMU
+	membar	#Sync
 
 	/* Disable STICK_INT interrupts. */
 	sethi		%hi(0x80000000), %g5
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.4.3/linux/arch/sparc64/kernel/traps.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/traps.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.73 2001/03/22 07:26:03 davem Exp $
+/* $Id: traps.c,v 1.76 2001/04/03 13:46:31 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/signal.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/mm.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
@@ -27,231 +28,13 @@
 #include <asm/fpumacro.h>
 #include <asm/lsu.h>
 #include <asm/dcu.h>
+#include <asm/estate.h>
+#include <asm/chafsr.h>
 #include <asm/psrcompat.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
 
-/* #define SYSCALL_TRACING */
-/* #define VERBOSE_SYSCALL_TRACING */
-/* #define DEBUG_FPU */
-
-#ifdef SYSCALL_TRACING
-#ifdef VERBOSE_SYSCALL_TRACING
-struct sdesc {
-	int	scall_num;
-	char	*name;
-	int	num_args;
-	char	arg_is_string[6];
-} sdesc_entries[] = {
-	{ 0, "setup", 0, },
-	{ 1, "exit", 1, { 0, } },
-	{ 2, "fork", 0, },
-	{ 3, "read", 3, { 0, 0, 0, } },
-	{ 4, "write", 3, { 0, 0, 0, } },
-	{ 5, "open", 3, { 1, 0, 0, } },
-	{ 6, "close", 1, { 0, } },
-	{ 7, "wait4", 4, { 0, 0, 0, 0, } },
-	{ 8, "creat", 2, { 1, 0, } },
-	{ 9, "link", 2, { 1, 1, } },
-	{ 10, "unlink", 1, { 1, } },
-	{ 11, "execv", 2, { 1, 0, } },
-	{ 12, "chdir", 1, { 1, } },
-	{ 15, "chmod", 2, { 1, 0, } },
-	{ 16, "chown", 3, { 1, 0, 0, } },
-	{ 17, "brk", 1, { 0, } },
-	{ 19, "lseek", 3, { 0, 0, 0, } },
-	{ 27, "alarm", 1, { 0, } },
-	{ 29, "pause", 0, },
-	{ 33, "access", 2, { 1, 0, } },
-	{ 36, "sync", 0, },
-	{ 37, "kill", 2, { 0, 0, } },
-	{ 38, "stat", 2, { 1, 0, } },
-	{ 40, "lstat", 2, { 1, 0, } },
-	{ 41, "dup", 1, { 0, } },
-	{ 42, "pipd", 0, },
-	{ 54, "ioctl", 3, { 0, 0, 0, } },
-	{ 57, "symlink", 2, { 1, 1, } },
-	{ 58, "readlink", 3, { 1, 0, 0, } },
-	{ 59, "execve", 3, { 1, 0, 0, } },
-	{ 60, "umask", 1, { 0, } },
-	{ 62, "fstat", 2, { 0, 0, } },
-	{ 64, "getpagesize", 0, },
-	{ 71, "mmap", 6, { 0, 0, 0, 0, 0, 0, } },
-	{ 73, "munmap", 2, { 0, 0, } },
-	{ 74, "mprotect", 3, { 0, 0, 0, } },
-	{ 83, "setitimer", 3, { 0, 0, 0, } },
-	{ 90, "dup2", 2, { 0, 0, } },
-	{ 92, "fcntl", 3, { 0, 0, 0, } },
-	{ 93, "select", 5, { 0, 0, 0, 0, 0, } },
-	{ 97, "socket", 3, { 0, 0, 0, } },
-	{ 98, "connect", 3, { 0, 0, 0, } },
-	{ 99, "accept", 3, { 0, 0, 0, } },
-	{ 101, "send", 4, { 0, 0, 0, 0, } },
-	{ 102, "recv", 4, { 0, 0, 0, 0, } },
-	{ 104, "bind", 3, { 0, 0, 0, } },
-	{ 105, "setsockopt", 5, { 0, 0, 0, 0, 0, } },
-	{ 106, "listen", 2, { 0, 0, } },
-	{ 120, "readv", 3, { 0, 0, 0, } },
-	{ 121, "writev", 3, { 0, 0, 0, } },
-	{ 123, "fchown", 3, { 0, 0, 0, } },
-	{ 124, "fchmod", 2, { 0, 0, } },
-	{ 128, "rename", 2, { 1, 1, } },
-	{ 129, "truncate", 2, { 1, 0, } },
-	{ 130, "ftruncate", 2, { 0, 0, } },
-	{ 131, "flock", 2, { 0, 0, } },
-	{ 136, "mkdir", 2, { 1, 0, } },
-	{ 137, "rmdir", 1, { 1, } },
-	{ 146, "killpg", 1, { 0, } },
-	{ 157, "statfs", 2, { 1, 0, } },
-	{ 158, "fstatfs", 2, { 0, 0, } },
-	{ 159, "umount", 1, { 1, } },
-	{ 167, "mount", 5, { 1, 1, 1, 0, 0, } },
-	{ 174, "getdents", 3, { 0, 0, 0, } },
-	{ 176, "fchdir", 2, { 0, 0, } },
-	{ 198, "sigaction", 3, { 0, 0, 0, } },
-	{ 201, "sigsuspend", 1, { 0, } },
-	{ 206, "socketcall", 2, { 0, 0, } },
-	{ 216, "sigreturn", 0, },
-	{ 230, "newselect", 5, { 0, 0, 0, 0, 0, } },
-	{ 236, "llseek", 5, { 0, 0, 0, 0, 0, } },
-	{ 251, "sysctl", 1, { 0, } },
-};
-#define NUM_SDESC_ENTRIES (sizeof(sdesc_entries) / sizeof(sdesc_entries[0]))
-#endif
-
-#ifdef VERBOSE_SYSCALL_TRACING
-static char scall_strbuf[512];
-#endif
-
-void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
-{
-#ifdef VERBOSE_SYSCALL_TRACING
-	struct sdesc *sdp;
-	int i;
-#endif
-
-#if 0
-	if (!current->pid) return;
-#endif	
-	printk("SYS[%s:%d]: PC(%016lx) <%3d> ",
-	       current->comm, current->pid, regs->tpc, (int)g1);
-#ifdef VERBOSE_SYSCALL_TRACING
-	sdp = NULL;
-	for(i = 0; i < NUM_SDESC_ENTRIES; i++)
-		if(sdesc_entries[i].scall_num == g1) {
-			sdp = &sdesc_entries[i];
-			break;
-		}
-	if(sdp) {
-		printk("%s(", sdp->name);
-		for(i = 0; i < sdp->num_args; i++) {
-			if(i)
-				printk(",");
-			if(!sdp->arg_is_string[i]) {
-				if (current->thread.flags & SPARC_FLAG_32BIT)
-					printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]);
-				else
-					printk("%016lx", regs->u_regs[UREG_I0 + i]);
-			} else {
-				if (current->thread.flags & SPARC_FLAG_32BIT)
-					strncpy_from_user(scall_strbuf,
-							  (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff),
-							  512);
-				else
-					strncpy_from_user(scall_strbuf,
-							  (char *)regs->u_regs[UREG_I0 + i],
-							  512);
-				printk("%s", scall_strbuf);
-			}
-		}
-		printk(") ");
-	}
-#endif
-}
-
-unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
-{
-#if 0
-	if (current->pid)
-#endif
-		printk("ret[%016lx]\n", retval);
-	return retval;
-}
-#endif /* SYSCALL_TRACING */
-
-#if 1
-void rtrap_check(struct pt_regs *regs)
-{
-	register unsigned long pgd_phys asm("o1");
-	register unsigned long pgd_cache asm("o2");
-	register unsigned long g1_or_g3 asm("o3");
-	register unsigned long g2 asm("o4");
-	unsigned long ctx;
-
-#if 0
-	do {
-		unsigned long test;
-		__asm__ __volatile__("rdpr	%%pstate, %0"
-				     : "=r" (test));
-		if((test & PSTATE_MG) != 0 ||
-		   (test & PSTATE_IE) == 0) {
-			printk("rtrap_check: Bogus pstate[%016lx]\n", test);
-			return;
-		}
-	} while(0);
-#endif
-
-	__asm__ __volatile__("
-	rdpr	%%pstate, %%o5
-	wrpr	%%o5, %4, %%pstate
-	or	%%g1, %%g3, %2
-	mov	%%g2, %3
-	mov	%%g7, %0
-	mov	%5, %1
-	ldxa	[%1] %6, %1
-	wrpr	%%o5, 0x0, %%pstate"
-	: "=r" (pgd_phys), "=r" (pgd_cache),
-	  "=r" (g1_or_g3), "=r" (g2)
-	: "i" (PSTATE_IE | PSTATE_MG), "i" (TSB_REG),
-	  "i" (ASI_DMMU)
-	: "o5");
-
-	ctx = spitfire_get_secondary_context();
-
-	if((pgd_phys != __pa(current->mm->pgd)) ||
-	   ((pgd_cache != 0) &&
-	    (pgd_cache != pgd_val(current->mm->pgd[0])<<11UL)) ||
-	   (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) ||
-#define KERN_HIGHBITS		((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
-#define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-	   (g2 != (KERN_HIGHBITS | KERN_LOWBITS)) ||
-#undef KERN_HIGHBITS
-#undef KERN_LOWBITS
-	   ((ctx != (current->mm->context & 0x3ff)) ||
-	    (ctx == 0) ||
-	    (CTX_HWBITS(current->mm->context) != ctx))) {
-		printk("SHIT[%s:%d]: "
-		       "(PP[%016lx] CACH[%016lx] CTX[%lx] g1g3[%016lx] g2[%016lx]) ",
-		       current->comm, current->pid,
-		       pgd_phys, pgd_cache, ctx, g1_or_g3, g2);
-		printk("SHIT[%s:%d]: "
-		       "[PP[%016lx] CACH[%016lx] CTX[%lx]] PC[%016lx:%016lx]\n",
-		       current->comm, current->pid,
-		       __pa(current->mm->pgd),
-		       pgd_val(current->mm->pgd[0]),
-		       current->mm->context & 0x3ff,
-		       regs->tpc, regs->tnpc);
-		show_regs(regs);
-#if 1
-		__sti();
-		while(1)
-			barrier();
-#endif
-	}
-}
-#endif
-
 void bad_trap (struct pt_regs *regs, long lvl)
 {
 	siginfo_t info;
@@ -290,10 +73,8 @@
 	siginfo_t info;
 
 	if (regs->tstate & TSTATE_PRIV) {
-#if 1
-		printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n",
+		printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
 		       sfsr, sfar);
-#endif
 		die_if_kernel("Iax", regs);
 	}
 	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
@@ -331,16 +112,11 @@
 			return;
 		}
 		/* Shit... */
-#if 1
-		printk("data_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n",
+		printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
 		       sfsr, sfar);
-#endif
 		die_if_kernel("Dax", regs);
 	}
-#if 0
-	else
-		rtrap_check(regs);
-#endif
+
 	info.si_signo = SIGSEGV;
 	info.si_errno = 0;
 	info.si_code = SEGV_MAPERR;
@@ -352,6 +128,7 @@
 #ifdef CONFIG_PCI
 /* This is really pathetic... */
 extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_cpu;
 extern volatile int pci_poke_faulted;
 #endif
 
@@ -405,7 +182,7 @@
 void do_dae(struct pt_regs *regs)
 {
 #ifdef CONFIG_PCI
-	if (pci_poke_in_progress) {
+	if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
 		clean_and_reenable_l1_caches();
 
 		pci_poke_faulted = 1;
@@ -539,6 +316,986 @@
 	}
 }
 
+/* Cheetah error trap handling. */
+static unsigned long ecache_flush_physbase;
+static unsigned long ecache_flush_linesize;
+static unsigned long ecache_flush_size;
+
+/* WARNING: The error trap handlers in assembly know the precise
+ *	    layout of the following structure.
+ *
+ * C-level handlers below use this information to log the error
+ * and then determine how to recover (if possible).
+ */
+struct cheetah_err_info {
+/*0x00*/u64 afsr;
+/*0x08*/u64 afar;
+
+	/* D-cache state */
+/*0x10*/u64 dcache_data[4];	/* The actual data	*/
+/*0x30*/u64 dcache_index;	/* D-cache index	*/
+/*0x38*/u64 dcache_tag;		/* D-cache tag/valid	*/
+/*0x40*/u64 dcache_utag;	/* D-cache microtag	*/
+/*0x48*/u64 dcache_stag;	/* D-cache snooptag	*/
+
+	/* I-cache state */
+/*0x50*/u64 icache_data[8];	/* The actual insns + predecode	*/
+/*0x90*/u64 icache_index;	/* I-cache index	*/
+/*0x98*/u64 icache_tag;		/* I-cache phys tag	*/
+/*0xa0*/u64 icache_utag;	/* I-cache microtag	*/
+/*0xa8*/u64 icache_stag;	/* I-cache snooptag	*/
+/*0xb0*/u64 icache_upper;	/* I-cache upper-tag	*/
+/*0xb8*/u64 icache_lower;	/* I-cache lower-tag	*/
+
+	/* E-cache state */
+/*0xc0*/u64 ecache_data[4];	/* 32 bytes from staging registers */
+/*0xe0*/u64 ecache_index;	/* E-cache index	*/
+/*0xe8*/u64 ecache_tag;		/* E-cache tag/state	*/
+
+/*0xf0*/u64 __pad[32 - 30];
+};
+#define CHAFSR_INVALID		((u64)-1L)
+
+/* This is allocated at boot time based upon the largest hardware
+ * cpu ID in the system.  We allocate two entries per cpu, one for
+ * TL==0 logging and one for TL >= 1 logging.
+ */
+struct cheetah_err_info *cheetah_error_log;
+
+static __inline__ struct cheetah_err_info *cheetah_get_error_log(unsigned long afsr)
+{
+	struct cheetah_err_info *p;
+	int cpu = smp_processor_id();
+
+	if (!cheetah_error_log)
+		return NULL;
+
+	p = cheetah_error_log + (cpu * 2);
+	if ((afsr & CHAFSR_TL1) != 0UL)
+		p++;
+
+	return p;
+}
+
+extern unsigned int tl0_fecc[], tl1_fecc[];
+extern unsigned int tl0_cee[], tl1_cee[];
+extern unsigned int tl0_iae[], tl1_iae[];
+extern unsigned int tl0_dae[], tl1_dae[];
+extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
+extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
+extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
+
+void cheetah_ecache_flush_init(void)
+{
+	unsigned long largest_size, smallest_linesize, order;
+	char type[16];
+	int node, highest_cpu, i;
+
+	/* Scan all cpu device tree nodes, note two values:
+	 * 1) largest E-cache size
+	 * 2) smallest E-cache line size
+	 */
+	largest_size = 0UL;
+	smallest_linesize = ~0UL;
+	node = prom_getchild(prom_root_node);
+	while ((node = prom_getsibling(node)) != 0) {
+		prom_getstring(node, "device_type", type, sizeof(type));
+		if (!strcmp(type, "cpu")) {
+			unsigned long val;
+
+			val = prom_getintdefault(node, "ecache-size",
+						 (2 * 1024 * 1024));
+			if (val > largest_size)
+				largest_size = val;
+			val = prom_getintdefault(node, "ecache-line-size", 64);
+			if (val < smallest_linesize)
+				smallest_linesize = val;
+		}
+	}
+	if (largest_size == 0UL || smallest_linesize == ~0UL) {
+		prom_printf("cheetah_ecache_flush_init: Cannot probe cpu E-cache "
+			    "parameters.\n");
+		prom_halt();
+	}
+
+	ecache_flush_size = (2 * largest_size);
+	ecache_flush_linesize = smallest_linesize;
+
+	/* Discover a physically contiguous chunk of physical
+	 * memory in 'sp_banks' of size ecache_flush_size calculated
+	 * above.  Store the physical base of this area at
+	 * ecache_flush_physbase.
+	 */
+	for (node = 0; ; node++) {
+		if (sp_banks[node].num_bytes == 0)
+			break;
+		if (sp_banks[node].num_bytes >= ecache_flush_size) {
+			ecache_flush_physbase = sp_banks[node].base_addr;
+			break;
+		}
+	}
+
+	/* Note: Zero would be a valid value of ecache_flush_physbase so
+	 * don't use that as the success test. :-)
+	 */
+	if (sp_banks[node].num_bytes == 0) {
+		prom_printf("cheetah_ecache_flush_init: Cannot find %d byte "
+			    "contiguous physical memory.\n", ecache_flush_size);
+		prom_halt();
+	}
+
+	/* Now allocate error trap reporting scoreboard. */
+	highest_cpu = 0;
+#ifdef CONFIG_SMP
+	for (i = 0; i < NR_CPUS; i++) {
+		if ((1UL << i) & cpu_present_map)
+			highest_cpu = i;
+	}
+#endif
+	highest_cpu++;
+	node = highest_cpu * (2 * sizeof(struct cheetah_err_info));
+	for (order = 0; order < MAX_ORDER; order++) {
+		if ((PAGE_SIZE << order) >= node)
+			break;
+	}
+	cheetah_error_log = (struct cheetah_err_info *)
+		__get_free_pages(GFP_KERNEL, order);
+	if (!cheetah_error_log) {
+		prom_printf("cheetah_ecache_flush_init: Failed to allocate "
+			    "error logging scoreboard (%d bytes).\n", node);
+		prom_halt();
+	}
+	memset(cheetah_error_log, 0, PAGE_SIZE << order);
+
+	/* Mark all AFSRs as invalid so that the trap handler will
+	 * log new new information there.
+	 */
+	for (i = 0; i < 2 * highest_cpu; i++)
+		cheetah_error_log[i].afsr = CHAFSR_INVALID;
+
+	/* Now patch trap tables. */
+	memcpy(tl0_fecc, cheetah_fecc_trap_vector, (8 * 4));
+	memcpy(tl1_fecc, cheetah_fecc_trap_vector_tl1, (8 * 4));
+	memcpy(tl0_cee, cheetah_cee_trap_vector, (8 * 4));
+	memcpy(tl1_cee, cheetah_cee_trap_vector_tl1, (8 * 4));
+	memcpy(tl0_iae, cheetah_deferred_trap_vector, (8 * 4));
+	memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
+	memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
+	memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
+	flushi(PAGE_OFFSET);
+}
+
+static void cheetah_flush_ecache(void)
+{
+	unsigned long flush_base = ecache_flush_physbase;
+	unsigned long flush_linesize = ecache_flush_linesize;
+	unsigned long flush_size = ecache_flush_size;
+
+	__asm__ __volatile__("1: subcc	%0, %4, %0\n\t"
+			     "   bne,pt	%%xcc, 1b\n\t"
+			     "    ldxa	[%2 + %0] %3, %%g0\n\t"
+			     : "=&r" (flush_size)
+			     : "0" (flush_size), "r" (flush_base),
+			       "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
+}
+
+static void cheetah_flush_ecache_line(unsigned long physaddr)
+{
+	unsigned long alias;
+
+	physaddr &= ~(8UL - 1UL);
+	physaddr = (ecache_flush_physbase +
+		    (physaddr & ((ecache_flush_size>>1UL) - 1UL)));
+	alias = physaddr + (ecache_flush_size >> 1UL);
+	__asm__ __volatile__("ldxa [%0] %2, %%g0\n\t"
+			     "ldxa [%1] %2, %%g0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (physaddr), "r" (alias),
+			       "i" (ASI_PHYS_USE_EC));
+}
+
+#ifdef CONFIG_SMP
+unsigned long cheetah_tune_scheduling(void)
+{
+	unsigned long tick1, tick2, raw;
+
+	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick1));
+	cheetah_flush_ecache();
+	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick2));
+
+	raw = (tick2 - tick1);
+
+	return (raw - (raw >> 2));
+}
+#endif
+
+/* Unfortunately, the diagnostic access to the I-cache tags we need to
+ * use to clear the thing interferes with I-cache coherency transactions.
+ *
+ * So we must only flush the I-cache when it is disabled.
+ */
+static void cheetah_flush_icache(void)
+{
+	unsigned long dcu_save, i;
+
+	/* Save current DCU, disable I-cache. */
+	__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
+			     "or %0, %2, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %1\n\t"
+			     "membar #Sync"
+			     : "=r" (dcu_save)
+			     : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
+			     : "g1");
+
+	/* Clear the valid bits in all the tags. */
+	for (i = 0; i < (1 << 16); i += (1 << 5)) {
+		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
+	}
+
+	/* Restore DCU register */
+	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (dcu_save), "i" (ASI_DCU_CONTROL_REG));
+}
+
+static void cheetah_flush_dcache(void)
+{
+	unsigned long i;
+
+	for (i = 0; i < (1 << 16); i += (1 << 5)) {
+		__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (i), "i" (ASI_DCACHE_TAG));
+	}
+}
+
+/* Conversion tables used to frob Cheetah AFSR syndrome values into
+ * something palatable to the memory controller driver get_unumber
+ * routine.
+ */
+#define MT0	137
+#define MT1	138
+#define MT2	139
+#define NONE	254
+#define MTC0	140
+#define MTC1	141
+#define MTC2	142
+#define MTC3	143
+#define C0	128
+#define C1	129
+#define C2	130
+#define C3	131
+#define C4	132
+#define C5	133
+#define C6	134
+#define C7	135
+#define C8	136
+#define M2	144
+#define M3	145
+#define M4	146
+#define M	147
+static unsigned char cheetah_ecc_syntab[] = {
+/*00*/NONE, C0, C1, M2, C2, M2, M3, 47, C3, M2, M2, 53, M2, 41, 29, M,
+/*01*/C4, M, M, 50, M2, 38, 25, M2, M2, 33, 24, M2, 11, M, M2, 16,
+/*02*/C5, M, M, 46, M2, 37, 19, M2, M, 31, 32, M, 7, M2, M2, 10,
+/*03*/M2, 40, 13, M2, 59, M, M2, 66, M, M2, M2, 0, M2, 67, 71, M,
+/*04*/C6, M, M, 43, M, 36, 18, M, M2, 49, 15, M, 63, M2, M2, 6,
+/*05*/M2, 44, 28, M2, M, M2, M2, 52, 68, M2, M2, 62, M2, M3, M3, M4,
+/*06*/M2, 26, 106, M2, 64, M, M2, 2, 120, M, M2, M3, M, M3, M3, M4,
+/*07*/116, M2, M2, M3, M2, M3, M, M4, M2, 58, 54, M2, M, M4, M4, M3,
+/*08*/C7, M2, M, 42, M, 35, 17, M2, M, 45, 14, M2, 21, M2, M2, 5,
+/*09*/M, 27, M, M, 99, M, M, 3, 114, M2, M2, 20, M2, M3, M3, M,
+/*0a*/M2, 23, 113, M2, 112, M2, M, 51, 95, M, M2, M3, M2, M3, M3, M2,
+/*0b*/103, M, M2, M3, M2, M3, M3, M4, M2, 48, M, M, 73, M2, M, M3,
+/*0c*/M2, 22, 110, M2, 109, M2, M, 9, 108, M2, M, M3, M2, M3, M3, M,
+/*0d*/102, M2, M, M, M2, M3, M3, M, M2, M3, M3, M2, M, M4, M, M3,
+/*0e*/98, M, M2, M3, M2, M, M3, M4, M2, M3, M3, M4, M3, M, M, M,
+/*0f*/M2, M3, M3, M, M3, M, M, M, 56, M4, M, M3, M4, M, M, M,
+/*10*/C8, M, M2, 39, M, 34, 105, M2, M, 30, 104, M, 101, M, M, 4,
+/*11*/M, M, 100, M, 83, M, M2, 12, 87, M, M, 57, M2, M, M3, M,
+/*12*/M2, 97, 82, M2, 78, M2, M2, 1, 96, M, M, M, M, M, M3, M2,
+/*13*/94, M, M2, M3, M2, M, M3, M, M2, M, 79, M, 69, M, M4, M,
+/*14*/M2, 93, 92, M, 91, M, M2, 8, 90, M2, M2, M, M, M, M, M4,
+/*15*/89, M, M, M3, M2, M3, M3, M, M, M, M3, M2, M3, M2, M, M3,
+/*16*/86, M, M2, M3, M2, M, M3, M, M2, M, M3, M, M3, M, M, M3,
+/*17*/M, M, M3, M2, M3, M2, M4, M, 60, M, M2, M3, M4, M, M, M2,
+/*18*/M2, 88, 85, M2, 84, M, M2, 55, 81, M2, M2, M3, M2, M3, M3, M4,
+/*19*/77, M, M, M, M2, M3, M, M, M2, M3, M3, M4, M3, M2, M, M,
+/*1a*/74, M, M2, M3, M, M, M3, M, M, M, M3, M, M3, M, M4, M3,
+/*1b*/M2, 70, 107, M4, 65, M2, M2, M, 127, M, M, M, M2, M3, M3, M,
+/*1c*/80, M2, M2, 72, M, 119, 118, M, M2, 126, 76, M, 125, M, M4, M3,
+/*1d*/M2, 115, 124, M, 75, M, M, M3, 61, M, M4, M, M4, M, M, M,
+/*1e*/M, 123, 122, M4, 121, M4, M, M3, 117, M2, M2, M3, M4, M3, M, M,
+/*1f*/111, M, M, M, M4, M3, M3, M, M, M, M3, M, M3, M2, M, M
+};
+static unsigned char cheetah_mtag_syntab[] = {
+       NONE, MTC0,
+       MTC1, NONE,
+       MTC2, NONE,
+       NONE, MT0,
+       MTC3, NONE,
+       NONE, MT1,
+       NONE, MT2,
+       NONE, NONE
+};
+
+/* This table is ordered in priority of errors and matches the
+ * AFAR overwrite policy as well.
+ */
+static struct {
+	unsigned long mask;
+	char *name;
+} cheetah_error_table[] = {
+	{	CHAFSR_PERR,	"System interface protocol error"			},
+	{	CHAFSR_IERR,	"Internal processor error"				},
+	{	CHAFSR_ISAP,	"System request parity error on incoming addresss"	},
+	{	CHAFSR_UCU,	"Uncorrectable E-cache ECC error for ifetch/data"	},
+	{	CHAFSR_UCC,	"SW Correctable E-cache ECC error for ifetch/data"	},
+	{	CHAFSR_UE,	"Uncorrectable system bus data ECC error for read"	},
+	{	CHAFSR_EDU,	"Uncorrectable E-cache ECC error for stmerge/blkld"	},
+	{	CHAFSR_EMU,	"Uncorrectable system bus MTAG error"			},
+	{	CHAFSR_WDU,	"Uncorrectable E-cache ECC error for writeback"		},
+	{	CHAFSR_CPU,	"Uncorrectable ECC error for copyout"			},
+	{	CHAFSR_CE,	"HW corrected system bus data ECC error for read"	},
+	{	CHAFSR_EDC,	"HW corrected E-cache ECC error for stmerge/blkld"	},
+	{	CHAFSR_EMC,	"HW corrected system bus MTAG ECC error"		},
+	{	CHAFSR_WDC,	"HW corrected E-cache ECC error for writeback"		},
+	{	CHAFSR_CPC,	"HW corrected ECC error for copyout"			},
+	{	CHAFSR_TO,	"Unmapped error from system bus"			},
+	{	CHAFSR_BERR,	"Bus error response from system bus"			},
+	/* These two do not update the AFAR. */
+	{	CHAFSR_IVC,	"HW corrected system bus data ECC error for ivec read"	},
+	{	CHAFSR_IVU,	"Uncorrectable system bus data ECC error for ivec read"	},
+	{	0,		NULL							}
+};
+
+/* Return the highest priority error conditon mentioned. */
+static __inline__ unsigned long cheetah_get_hipri(unsigned long afsr)
+{
+	unsigned long tmp = 0;
+	int i;
+
+	for (i = 0; cheetah_error_table[i].mask; i++) {
+		if ((tmp = (afsr & cheetah_error_table[i].mask)) != 0UL)
+			return tmp;
+	}
+	return tmp;
+}
+
+static char *cheetah_get_string(unsigned long bit)
+{
+	int i;
+
+	for (i = 0; cheetah_error_table[i].mask; i++) {
+		if ((bit & cheetah_error_table[i].mask) != 0UL)
+			return cheetah_error_table[i].name;
+	}
+	return "???";
+}
+
+extern int chmc_getunumber(int, unsigned long, char *, int);
+
+static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
+			       unsigned long afsr, unsigned long afar, int recoverable)
+{
+	unsigned long hipri;
+	char unum[256];
+
+	printk("%s" "ERROR(%d): Cheetah error trap taken afsr[%016lx] afar[%016lx] TL1(%d)\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       afsr, afar,
+	       (afsr & CHAFSR_TL1) ? 1 : 0);
+	printk("%s" "ERROR(%d): TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       regs->tpc, regs->tnpc, regs->tstate);
+	printk("%s" "ERROR(%d): M_SYND(%lx),  E_SYND(%lx)%s%s\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT,
+	       (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT,
+	       (afsr & CHAFSR_ME) ? ", Multiple Errors" : "",
+	       (afsr & CHAFSR_PRIV) ? ", Privileged" : "");
+	hipri = cheetah_get_hipri(afsr);
+	printk("%s" "ERROR(%d): Highest priority error (%016lx) \"%s\"\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       hipri, cheetah_get_string(hipri));
+
+	/* Try to get unumber if relevant. */
+#define ESYND_ERRORS	(CHAFSR_IVC | CHAFSR_IVU | \
+			 CHAFSR_CPC | CHAFSR_CPU | \
+			 CHAFSR_UE  | CHAFSR_CE  | \
+			 CHAFSR_EDC | CHAFSR_EDU  | \
+			 CHAFSR_UCC | CHAFSR_UCU  | \
+			 CHAFSR_WDU | CHAFSR_WDC)
+#define MSYND_ERRORS	(CHAFSR_EMC | CHAFSR_EMU)
+	if (afsr & ESYND_ERRORS) {
+		int syndrome;
+		int ret;
+
+		syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
+		syndrome = cheetah_ecc_syntab[syndrome];
+		ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+		if (ret != -1)
+			printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
+			       (recoverable ? KERN_WARNING : KERN_CRIT),
+			       smp_processor_id(), unum);
+	} else if (afsr & MSYND_ERRORS) {
+		int syndrome;
+		int ret;
+
+		syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
+		syndrome = cheetah_mtag_syntab[syndrome];
+		ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+		if (ret != -1)
+			printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
+			       (recoverable ? KERN_WARNING : KERN_CRIT),
+			       smp_processor_id(), unum);
+	}
+
+	/* Now dump the cache snapshots. */
+	printk("%s" "ERROR(%d): D-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       (int) info->dcache_index,
+	       info->dcache_tag,
+	       info->dcache_utag,
+	       info->dcache_stag);
+	printk("%s" "ERROR(%d): D-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       info->dcache_data[0],
+	       info->dcache_data[1],
+	       info->dcache_data[2],
+	       info->dcache_data[3]);
+	printk("%s" "ERROR(%d): I-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx] "
+	       "u[%016lx] l[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       (int) info->icache_index,
+	       info->icache_tag,
+	       info->icache_utag,
+	       info->icache_stag,
+	       info->icache_upper,
+	       info->icache_lower);
+	printk("%s" "ERROR(%d): I-cache INSN0[%016lx] INSN1[%016lx] INSN2[%016lx] INSN3[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       info->icache_data[0],
+	       info->icache_data[1],
+	       info->icache_data[2],
+	       info->icache_data[3]);
+	printk("%s" "ERROR(%d): I-cache INSN4[%016lx] INSN5[%016lx] INSN6[%016lx] INSN7[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       info->icache_data[4],
+	       info->icache_data[5],
+	       info->icache_data[6],
+	       info->icache_data[7]);
+	printk("%s" "ERROR(%d): E-cache idx[%x] tag[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       (int) info->ecache_index, info->ecache_tag);
+	printk("%s" "ERROR(%d): E-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n",
+	       (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
+	       info->ecache_data[0],
+	       info->ecache_data[1],
+	       info->ecache_data[2],
+	       info->ecache_data[3]);
+
+	afsr = (afsr & ~hipri) & CHAFSR_ERRORS;
+	while (afsr != 0UL) {
+		unsigned long bit = cheetah_get_hipri(afsr);
+
+		printk("%s" "ERROR: Multiple-error (%016lx) \"%s\"\n",
+		       (recoverable ? KERN_WARNING : KERN_CRIT),
+		       bit, cheetah_get_string(bit));
+
+		afsr &= ~bit;
+	}
+
+	if (!recoverable)
+		printk(KERN_CRIT "ERROR: This condition is not recoverable.\n");
+}
+
+static int cheetah_recheck_errors(struct cheetah_err_info *logp)
+{
+	unsigned long afsr, afar;
+	int ret = 0;
+
+	__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
+			     : "=r" (afsr)
+			     : "i" (ASI_AFSR));
+	if ((afsr & CHAFSR_ERRORS) != 0) {
+		if (logp != NULL) {
+			__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
+					     : "=r" (afar)
+					     : "i" (ASI_AFAR));
+			logp->afsr = afsr;
+			logp->afar = afar;
+		}
+		ret = 1;
+	}
+	__asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
+			     "membar #Sync\n\t"
+			     : : "r" (afsr), "i" (ASI_AFSR));
+
+	return ret;
+}
+
+void cheetah_fecc_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
+{
+	struct cheetah_err_info local_snapshot, *p;
+	int recoverable;
+
+	/* Flush E-cache */
+	cheetah_flush_ecache();
+
+	p = cheetah_get_error_log(afsr);
+	if (!p) {
+		prom_printf("ERROR: Early Fast-ECC error afsr[%016lx] afar[%016lx]\n",
+			    afsr, afar);
+		prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
+			    smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
+		prom_halt();
+	}
+
+	/* Grab snapshot of logged error. */
+	memcpy(&local_snapshot, p, sizeof(local_snapshot));
+
+	/* If the current trap snapshot does not match what the
+	 * trap handler passed along into our args, big trouble.
+	 * In such a case, mark the local copy as invalid.
+	 *
+	 * Else, it matches and we mark the afsr in the non-local
+	 * copy as invalid so we may log new error traps there.
+	 */
+	if (p->afsr != afsr || p->afar != afar)
+		local_snapshot.afsr = CHAFSR_INVALID;
+	else
+		p->afsr = CHAFSR_INVALID;
+
+	cheetah_flush_icache();
+	cheetah_flush_dcache();
+
+	/* Re-enable I-cache/D-cache */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_DCU_CONTROL_REG),
+			       "i" (DCU_DC | DCU_IC)
+			     : "g1");
+
+	/* Re-enable error reporting */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_ESTATE_ERROR_EN),
+			       "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
+			     : "g1");
+
+	/* Decide if we can continue after handling this trap and
+	 * logging the error.
+	 */
+	recoverable = 1;
+	if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
+		recoverable = 0;
+
+	/* Re-check AFSR/AFAR.  What we are looking for here is whether a new
+	 * error was logged while we had error reporting traps disabled.
+	 */
+	if (cheetah_recheck_errors(&local_snapshot)) {
+		unsigned long new_afsr = local_snapshot.afsr;
+
+		/* If we got a new asynchronous error, die... */
+		if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
+				CHAFSR_WDU | CHAFSR_CPU |
+				CHAFSR_IVU | CHAFSR_UE |
+				CHAFSR_BERR | CHAFSR_TO))
+			recoverable = 0;
+	}
+
+	/* Log errors. */
+	cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
+
+	if (!recoverable)
+		panic("Irrecoverable Fast-ECC error trap.\n");
+
+	/* Flush E-cache to kick the error trap handlers out. */
+	cheetah_flush_ecache();
+}
+
+/* Try to fix a correctable error by pushing the line out from
+ * the E-cache.  Recheck error reporting registers to see if the
+ * problem is intermittent.
+ */
+static int cheetah_fix_ce(unsigned long physaddr)
+{
+	unsigned long orig_estate;
+	unsigned long alias1, alias2;
+	int ret;
+
+	/* Make sure correctable error traps are disabled. */
+	__asm__ __volatile__("ldxa	[%%g0] %2, %0\n\t"
+			     "andn	%0, %1, %%g1\n\t"
+			     "stxa	%%g1, [%%g0] %2\n\t"
+			     "membar	#Sync"
+			     : "=&r" (orig_estate)
+			     : "i" (ESTATE_ERROR_CEEN),
+			       "i" (ASI_ESTATE_ERROR_EN)
+			     : "g1");
+
+	/* We calculate alias addresses that will force the
+	 * cache line in question out of the E-cache.  Then
+	 * we bring it back in with an atomic instruction so
+	 * that we get it in some modified/exclusive state,
+	 * then we displace it again to try and get proper ECC
+	 * pushed back into the system.
+	 */
+	physaddr &= ~(8UL - 1UL);
+	alias1 = (ecache_flush_physbase +
+		  (physaddr & ((ecache_flush_size >> 1) - 1)));
+	alias2 = alias1 + (ecache_flush_size >> 1);
+	__asm__ __volatile__("ldxa	[%0] %3, %%g0\n\t"
+			     "ldxa	[%1] %3, %%g0\n\t"
+			     "casxa	[%2] %3, %%g0, %%g0\n\t"
+			     "ldxa	[%0] %3, %%g0\n\t"
+			     "ldxa	[%1] %3, %%g0\n\t"
+			     "membar	#Sync"
+			     : /* no outputs */
+			     : "r" (alias1), "r" (alias2),
+			       "r" (physaddr), "i" (ASI_PHYS_USE_EC));
+
+	/* Did that trigger another error? */
+	if (cheetah_recheck_errors(NULL)) {
+		/* Try one more time. */
+		__asm__ __volatile__("ldxa [%0] %1, %%g0\n\t"
+				     "membar #Sync"
+				     : : "r" (physaddr), "i" (ASI_PHYS_USE_EC));
+		if (cheetah_recheck_errors(NULL))
+			ret = 2;
+		else
+			ret = 1;
+	} else {
+		/* No new error, intermittent problem. */
+		ret = 0;
+	}
+
+	/* Restore error enables. */
+	__asm__ __volatile__("stxa	%0, [%%g0] %1\n\t"
+			     "membar	#Sync"
+			     : : "r" (orig_estate), "i" (ASI_ESTATE_ERROR_EN));
+
+	return ret;
+}
+
+/* Return non-zero if PADDR is a valid physical memory address. */
+static int cheetah_check_main_memory(unsigned long paddr)
+{
+	int i;
+
+	for (i = 0; ; i++) {
+		if (sp_banks[i].num_bytes == 0)
+			break;
+		if (paddr >= sp_banks[i].base_addr &&
+		    paddr < (sp_banks[i].base_addr + sp_banks[i].num_bytes))
+			return 1;
+	}
+	return 0;
+}
+
+void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
+{
+	struct cheetah_err_info local_snapshot, *p;
+	int recoverable, is_memory;
+
+	p = cheetah_get_error_log(afsr);
+	if (!p) {
+		prom_printf("ERROR: Early CEE error afsr[%016lx] afar[%016lx]\n",
+			    afsr, afar);
+		prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
+			    smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
+		prom_halt();
+	}
+
+	/* Grab snapshot of logged error. */
+	memcpy(&local_snapshot, p, sizeof(local_snapshot));
+
+	/* If the current trap snapshot does not match what the
+	 * trap handler passed along into our args, big trouble.
+	 * In such a case, mark the local copy as invalid.
+	 *
+	 * Else, it matches and we mark the afsr in the non-local
+	 * copy as invalid so we may log new error traps there.
+	 */
+	if (p->afsr != afsr || p->afar != afar)
+		local_snapshot.afsr = CHAFSR_INVALID;
+	else
+		p->afsr = CHAFSR_INVALID;
+
+	is_memory = cheetah_check_main_memory(afar);
+
+	if (is_memory && (afsr & CHAFSR_CE) != 0UL) {
+		/* XXX Might want to log the results of this operation
+		 * XXX somewhere... -DaveM
+		 */
+		cheetah_fix_ce(afar);
+	}
+
+	{
+		int flush_all, flush_line;
+
+		flush_all = flush_line = 0;
+		if ((afsr & CHAFSR_EDC) != 0UL) {
+			if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDC)
+				flush_line = 1;
+			else
+				flush_all = 1;
+		} else if ((afsr & CHAFSR_CPC) != 0UL) {
+			if ((afsr & CHAFSR_ERRORS) == CHAFSR_CPC)
+				flush_line = 1;
+			else
+				flush_all = 1;
+		}
+
+		/* Trap handler only disabled I-cache, flush it. */
+		cheetah_flush_icache();
+
+		/* Re-enable I-cache */
+		__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+				     "or %%g1, %1, %%g1\n\t"
+				     "stxa %%g1, [%%g0] %0\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "i" (ASI_DCU_CONTROL_REG),
+				     "i" (DCU_IC)
+				     : "g1");
+
+		if (flush_all)
+			cheetah_flush_ecache();
+		else if (flush_line)
+			cheetah_flush_ecache_line(afar);
+	}
+
+	/* Re-enable error reporting */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_ESTATE_ERROR_EN),
+			       "i" (ESTATE_ERROR_CEEN)
+			     : "g1");
+
+	/* Decide if we can continue after handling this trap and
+	 * logging the error.
+	 */
+	recoverable = 1;
+	if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
+		recoverable = 0;
+
+	/* Re-check AFSR/AFAR */
+	(void) cheetah_recheck_errors(&local_snapshot);
+
+	/* Log errors. */
+	cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
+
+	if (!recoverable)
+		panic("Irrecoverable Correctable-ECC error trap.\n");
+}
+
+void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
+{
+	struct cheetah_err_info local_snapshot, *p;
+	int recoverable, is_memory;
+
+#ifdef CONFIG_PCI
+	/* Check for the special PCI poke sequence. */
+	if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
+		cheetah_flush_icache();
+		cheetah_flush_dcache();
+
+		/* Re-enable I-cache/D-cache */
+		__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+				     "or %%g1, %1, %%g1\n\t"
+				     "stxa %%g1, [%%g0] %0\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "i" (ASI_DCU_CONTROL_REG),
+				       "i" (DCU_DC | DCU_IC)
+				     : "g1");
+
+		/* Re-enable error reporting */
+		__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+				     "or %%g1, %1, %%g1\n\t"
+				     "stxa %%g1, [%%g0] %0\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "i" (ASI_ESTATE_ERROR_EN),
+				       "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
+				     : "g1");
+
+		(void) cheetah_recheck_errors(NULL);
+
+		pci_poke_faulted = 1;
+		regs->tpc += 4;
+		regs->tnpc = regs->tpc + 4;
+		return;
+	}
+#endif
+
+	p = cheetah_get_error_log(afsr);
+	if (!p) {
+		prom_printf("ERROR: Early deferred error afsr[%016lx] afar[%016lx]\n",
+			    afsr, afar);
+		prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
+			    smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
+		prom_halt();
+	}
+
+	/* Grab snapshot of logged error. */
+	memcpy(&local_snapshot, p, sizeof(local_snapshot));
+
+	/* If the current trap snapshot does not match what the
+	 * trap handler passed along into our args, big trouble.
+	 * In such a case, mark the local copy as invalid.
+	 *
+	 * Else, it matches and we mark the afsr in the non-local
+	 * copy as invalid so we may log new error traps there.
+	 */
+	if (p->afsr != afsr || p->afar != afar)
+		local_snapshot.afsr = CHAFSR_INVALID;
+	else
+		p->afsr = CHAFSR_INVALID;
+
+	is_memory = cheetah_check_main_memory(afar);
+
+	{
+		int flush_all, flush_line;
+
+		flush_all = flush_line = 0;
+		if ((afsr & CHAFSR_EDU) != 0UL) {
+			if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDU)
+				flush_line = 1;
+			else
+				flush_all = 1;
+		} else if ((afsr & CHAFSR_BERR) != 0UL) {
+			if ((afsr & CHAFSR_ERRORS) == CHAFSR_BERR)
+				flush_line = 1;
+			else
+				flush_all = 1;
+		}
+
+		cheetah_flush_icache();
+		cheetah_flush_dcache();
+
+		/* Re-enable I/D caches */
+		__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+				     "or %%g1, %1, %%g1\n\t"
+				     "stxa %%g1, [%%g0] %0\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "i" (ASI_DCU_CONTROL_REG),
+				     "i" (DCU_IC | DCU_DC)
+				     : "g1");
+
+		if (flush_all)
+			cheetah_flush_ecache();
+		else if (flush_line)
+			cheetah_flush_ecache_line(afar);
+	}
+
+	/* Re-enable error reporting */
+	__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
+			     "or %%g1, %1, %%g1\n\t"
+			     "stxa %%g1, [%%g0] %0\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "i" (ASI_ESTATE_ERROR_EN),
+			     "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
+			     : "g1");
+
+	/* Decide if we can continue after handling this trap and
+	 * logging the error.
+	 */
+	recoverable = 1;
+	if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
+		recoverable = 0;
+
+	/* Re-check AFSR/AFAR.  What we are looking for here is whether a new
+	 * error was logged while we had error reporting traps disabled.
+	 */
+	if (cheetah_recheck_errors(&local_snapshot)) {
+		unsigned long new_afsr = local_snapshot.afsr;
+
+		/* If we got a new asynchronous error, die... */
+		if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
+				CHAFSR_WDU | CHAFSR_CPU |
+				CHAFSR_IVU | CHAFSR_UE |
+				CHAFSR_BERR | CHAFSR_TO))
+			recoverable = 0;
+	}
+
+	/* Log errors. */
+	cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
+
+	/* "Recoverable" here means we try to yank the page from ever
+	 * being newly used again.  This depends upon a few things:
+	 * 1) Must be main memory, and AFAR must be valid.
+	 * 2) If we trapped from use, OK.
+	 * 3) Else, if we trapped from kernel we must find exception
+	 *    table entry (ie. we have to have been accessing user
+	 *    space).
+	 *
+	 * If AFAR is not in main memory, or we trapped from kernel
+	 * and cannot find an exception table entry, it is unacceptable
+	 * to try and continue.
+	 */
+	if (recoverable && is_memory) {
+		if ((regs->tstate & TSTATE_PRIV) == 0UL) {
+			/* OK, usermode access. */
+			recoverable = 1;
+		} else {
+			unsigned long g2 = regs->u_regs[UREG_G2];
+			unsigned long fixup = search_exception_table(regs->tpc, &g2);
+
+			if (fixup != 0UL) {
+				/* OK, kernel access to userspace. */
+				recoverable = 1;
+
+			} else {
+				/* BAD, privileged state is corrupted. */
+				recoverable = 0;
+			}
+
+			if (recoverable) {
+				struct page *page = virt_to_page(__va(afar));
+
+				if (VALID_PAGE(page))
+					get_page(page);
+				else
+					recoverable = 0;
+
+				/* Only perform fixup if we still have a
+				 * recoverable condition.
+				 */
+				if (fixup != 0UL && recoverable) {
+					regs->tpc = fixup;
+					regs->tnpc = regs->tpc + 4;
+					regs->u_regs[UREG_G2] = g2;
+				}
+			}
+		}
+	} else {
+		recoverable = 0;
+	}
+
+	if (!recoverable)
+		panic("Irrecoverable deferred error trap.\n");
+}
+
 void do_fpe_common(struct pt_regs *regs)
 {
 	if(regs->tstate & TSTATE_PRIV) {
@@ -575,9 +1332,6 @@
 
 void do_fpieee(struct pt_regs *regs)
 {
-#ifdef DEBUG_FPU
-	printk("fpieee %016lx\n", current->thread.xfsr[0]);
-#endif
 	do_fpe_common(regs);
 }
 
@@ -594,10 +1348,8 @@
 		ret = do_mathemu(regs, f);
 		break;
 	}
-	if (ret) return;
-#ifdef DEBUG_FPU
-	printk("fpother %016lx\n", current->thread.xfsr[0]);
-#endif
+	if (ret)
+		return;
 	do_fpe_common(regs);
 }
 
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.4.3/linux/arch/sparc64/kernel/ttable.S	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/ttable.S	Thu Apr 12 12:10:25 2001
@@ -1,12 +1,16 @@
-/* $Id: ttable.S,v 1.32 2001/03/23 07:56:30 davem Exp $
- * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
+/* $Id: ttable.S,v 1.33 2001/03/28 10:56:34 davem Exp $
+ * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/config.h>
 
-	.globl	sparc64_ttable_tl0, sparc64_ttable_tl1,
+	.globl	sparc64_ttable_tl0, sparc64_ttable_tl1
+	.globl	tl0_fecc, tl1_fecc
+	.globl	tl0_cee, tl1_cee
+	.globl	tl0_iae, tl1_iae
+	.globl	tl0_dae, tl1_dae
 
 sparc64_ttable_tl0:
 tl0_resv000:	BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
@@ -64,7 +68,8 @@
 #include	"dtlb_base.S"
 tl0_daprot:
 #include	"dtlb_prot.S"
-tl0_resv070:	BTRAP(0x70) BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
+tl0_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
+tl0_resv071:	BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
 tl0_resv076:	BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
 tl0_resv07c:	BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
 tl0_s0n:	SPILL_0_NORMAL
@@ -203,13 +208,30 @@
 tl1_ivec:	TRAP_IVEC
 tl1_paw:	TRAPTL1(do_paw_tl1)
 tl1_vaw:	TRAPTL1(do_vaw_tl1)
-tl1_cee:	TRAPTL1_CEE
+
+		/* The grotty trick to save %g1 into current->thread.kernel_cntd0
+		 * is because when we take this trap we could be interrupting trap
+		 * code already using the trap alternate global registers.  It is
+		 * better to corrupt a performance counter than corrupt trap register
+		 * state.  We cross our fingers and pray that this store/load does
+		 * not cause yet another CEE trap.
+		 */
+tl1_cee:	membar	#Sync
+		stx	%g1, [%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0]
+		ldxa	[%g0] ASI_AFSR, %g1
+		membar	#Sync
+		stxa	%g1, [%g0] ASI_AFSR
+		membar	#Sync
+		ldx	[%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0], %g1
+		retry
+
 tl1_iamiss:	BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67)
 tl1_damiss:
 #include	"dtlb_backend.S"
 tl1_daprot:
 #include	"dtlb_prot.S"
-tl1_resv070:	BTRAPTL1(0x70) BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
+tl1_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
+tl1_resc071:	BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
 tl1_resv074:	BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77)
 tl1_resv078:	BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b)
 tl1_resv07c:	BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f)
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c
--- v2.4.3/linux/arch/sparc64/kernel/unaligned.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/unaligned.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.21 2001/03/21 11:46:20 davem Exp $
+/* $Id: unaligned.c,v 1.23 2001/04/09 04:29:03 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <asm/asi.h>
 #include <asm/ptrace.h>
+#include <asm/pstate.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -376,6 +377,9 @@
 	regs->tpc = fixup;
 	regs->tnpc = regs->tpc + 4;
 	regs->u_regs [UREG_G2] = g2;
+
+	regs->tstate &= ~TSTATE_ASI;
+	regs->tstate |= (ASI_AIUS << 24UL);
 }
 
 asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr)
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/lib/bitops.S linux/arch/sparc64/lib/bitops.S
--- v2.4.3/linux/arch/sparc64/lib/bitops.S	Thu Mar 30 16:54:53 2000
+++ linux/arch/sparc64/lib/bitops.S	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.S,v 1.1 2000/03/27 10:38:41 davem Exp $
+/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $
  * bitops.S: Sparc64 atomic bit operations.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -11,8 +11,8 @@
 	.globl	__bitops_begin
 __bitops_begin:
 
-	.globl	__test_and_set_bit
-__test_and_set_bit:	/* %o0=nr, %o1=addr */
+	.globl	___test_and_set_bit
+___test_and_set_bit:	/* %o0=nr, %o1=addr */
 	srlx	%o0, 6, %g1
 	mov	1, %g5
 	sllx	%g1, 3, %g3
@@ -30,8 +30,8 @@
 2:	retl
 	 nop
 
-	.globl	__test_and_clear_bit
-__test_and_clear_bit:	/* %o0=nr, %o1=addr */
+	.globl	___test_and_clear_bit
+___test_and_clear_bit:	/* %o0=nr, %o1=addr */
 	srlx	%o0, 6, %g1
 	mov	1, %g5
 	sllx	%g1, 3, %g3
@@ -49,8 +49,8 @@
 2:	retl
 	 nop
 
-	.globl	__test_and_change_bit
-__test_and_change_bit:	/* %o0=nr, %o1=addr */
+	.globl	___test_and_change_bit
+___test_and_change_bit:	/* %o0=nr, %o1=addr */
 	srlx	%o0, 6, %g1
 	mov	1, %g5
 	sllx	%g1, 3, %g3
@@ -68,8 +68,8 @@
 	 nop
 	nop
 
-	.globl	__test_and_set_le_bit
-__test_and_set_le_bit:	/* %o0=nr, %o1=addr */
+	.globl	___test_and_set_le_bit
+___test_and_set_le_bit:	/* %o0=nr, %o1=addr */
 	srlx	%o0, 5, %g1
 	mov	1, %g5
 	sllx	%g1, 2, %g3
@@ -87,8 +87,8 @@
 2:	retl
 	 nop
 
-	.globl	__test_and_clear_le_bit
-__test_and_clear_le_bit:	/* %o0=nr, %o1=addr */
+	.globl	___test_and_clear_le_bit
+___test_and_clear_le_bit:	/* %o0=nr, %o1=addr */
 	srlx	%o0, 5, %g1
 	mov	1, %g5
 	sllx	%g1, 2, %g3
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.4.3/linux/arch/sparc64/lib/blockops.S	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/lib/blockops.S	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.30 2001/03/22 13:10:10 davem Exp $
+/* $Id: blockops.S,v 1.31 2001/04/05 11:08:12 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -399,7 +399,6 @@
 	jmpl		%o7 + 0x8, %g0
 	 wrpr		%g3, 0x0, %pstate
 
-	/* We will write cheetah optimized versions later. */
 	.globl		cheetah_patch_pgcopyops
 cheetah_patch_pgcopyops:
 	sethi		%hi(FIX_INSN_1), %g1
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c
--- v2.4.3/linux/arch/sparc64/mm/generic.c	Mon Mar 26 15:42:57 2001
+++ linux/arch/sparc64/mm/generic.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.16 2001/03/25 04:40:05 davem Exp $
+/* $Id: generic.c,v 1.17 2001/04/09 04:08:06 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -8,6 +8,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/pagemap.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
@@ -21,11 +22,7 @@
 		struct page *ptpage = pte_page(page);
 		if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
 			return;
-		/* 
-		 * free_page() used to be able to clear swap cache
-		 * entries.  We may now have to do it manually.  
-		 */
-		free_page_and_swap_cache(ptpage);
+		page_cache_release(ptpage);
 		return;
 	}
 	swap_free(pte_to_swp_entry(page));
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.4.3/linux/arch/sparc64/mm/init.c	Mon Mar 26 15:30:06 2001
+++ linux/arch/sparc64/mm/init.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.172 2001/03/24 09:36:01 davem Exp $
+/*  $Id: init.c,v 1.174 2001/03/30 07:10:42 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -1126,6 +1126,7 @@
 /* paging_init() sets up the page tables */
 
 extern void sun_serial_setup(void);
+extern void cheetah_ecache_flush_init(void);
 
 static unsigned long last_valid_pfn;
 
@@ -1466,6 +1467,9 @@
 	       datapages << (PAGE_SHIFT-10), 
 	       initpages << (PAGE_SHIFT-10), 
 	       PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
+
+	if (tlb_type == cheetah)
+		cheetah_ecache_flush_init();
 }
 
 void free_initmem (void)
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c
--- v2.4.3/linux/arch/sparc64/mm/modutil.c	Sun Feb 18 19:49:54 2001
+++ linux/arch/sparc64/mm/modutil.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/*  $Id: modutil.c,v 1.7 2001/02/13 01:16:44 davem Exp $
+/*  $Id: modutil.c,v 1.8 2001/04/04 00:49:39 davem Exp $
  *  arch/sparc64/mm/modutil.c
  *
  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -59,7 +59,7 @@
 	*p = area;
 
 	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
-		vfree(addr);
+		module_unmap(addr);
 		return NULL;
 	}
 	return addr;
diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- v2.4.3/linux/arch/sparc64/solaris/timod.c	Fri Aug  4 18:16:11 2000
+++ linux/arch/sparc64/solaris/timod.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.10 2000/07/28 12:15:02 davem Exp $
+/* $Id: timod.c,v 1.11 2001/04/14 21:12:01 davem Exp $
  * timod.c: timod emulation.
  *
  * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
@@ -611,7 +611,7 @@
 		return 0;
 	}
 	default:
-		printk("timod_putmsg: unsuported command %u.\n", ret);
+		printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
 		break;
 	}
 	return -EINVAL;
diff -u --recursive --new-file v2.4.3/linux/drivers/acpi/namespace/nsxfobj.c linux/drivers/acpi/namespace/nsxfobj.c
--- v2.4.3/linux/drivers/acpi/namespace/nsxfobj.c	Fri Feb  9 11:45:58 2001
+++ linux/drivers/acpi/namespace/nsxfobj.c	Sun Apr  8 10:02:56 2001
@@ -592,7 +592,7 @@
 
 	status = acpi_cm_execute_STA (node, &flags);
 	if (ACPI_FAILURE (status)) {
-		return (status);
+		return AE_OK;
 	}
 
 	if (!(flags & 0x01)) {
diff -u --recursive --new-file v2.4.3/linux/drivers/atm/firestream.c linux/drivers/atm/firestream.c
--- v2.4.3/linux/drivers/atm/firestream.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/atm/firestream.c	Wed Apr 11 19:02:30 2001
@@ -294,6 +294,8 @@
 #endif
 
 
+static int fs_keystream = 0;
+
 #ifdef DEBUG
 /* I didn't forget to set this to zero before shipping. Hit me with a stick 
    if you get this with the debug default not set to zero again. -- REW */
@@ -308,6 +310,7 @@
 #endif
 MODULE_PARM(loopback, "i");
 MODULE_PARM(num, "i");
+MODULE_PARM(fs_keystream, "i");
 /* XXX Add rx_buf_sizes, and rx_pool_sizes As per request Amar. -- REW */
 #endif
 
@@ -377,7 +380,7 @@
 
 
 
-/* It seems the ATM forum recomends this horribly complicated 16bit
+/* It seems the ATM forum recommends this horribly complicated 16bit
  * floating point format. Turns out the Ambassador uses the exact same
  * encoding. I just copied it over. If Mitch agrees, I'll move it over
  * to the atm_misc file or something like that. (and remove it from 
@@ -716,6 +719,8 @@
 
 
 		switch (STATUS_CODE (qe)) {
+		case 0x01: /* This is for AAL0 where we put the chip in streaming mode */
+			/* Fall through */
 		case 0x02:
 			/* Process a real txdone entry. */
 			tmp = qe->p0;
@@ -796,6 +801,8 @@
 
 		/* Single buffer packet */
 		switch (STATUS_CODE (qe)) {
+		case 0x1:
+			/* Fall through for streaming mode */
 		case 0x2:/* Packet received OK.... */
 			if (atm_vcc) {
 				skb = pe->skb;
@@ -877,7 +884,9 @@
 	if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
 		set_bit(ATM_VF_ADDR, &atm_vcc->flags);
 
-	if (atm_vcc->qos.aal != ATM_AAL5) return -EINVAL; /* XXX AAL0 */
+	if ((atm_vcc->qos.aal != ATM_AAL5) &&
+	    (atm_vcc->qos.aal != ATM_AAL2))
+	  return -EINVAL; /* XXX AAL0 */
 
 	fs_dprintk (FS_DEBUG_OPEN, "fs: (itf %d): open %d.%d\n", 
 		    atm_vcc->dev->number, atm_vcc->vpi, atm_vcc->vci);	
@@ -946,12 +955,27 @@
 		   need to wait for completion anyway, to see if it completed
 		   succesfully. */
 
-		tc->flags = 0
+		switch (atm_vcc->qos.aal) {
+		case ATM_AAL2:
+		case ATM_AAL0:
+		  tc->flags = 0
+		    | TC_FLAGS_TRANSPARENT_PAYLOAD
+		    | TC_FLAGS_PACKET
+		    | (1 << 28)
+		    | TC_FLAGS_TYPE_UBR /* XXX Change to VBR -- PVDL */
+		    | TC_FLAGS_CAL0;
+		  break;
+		case ATM_AAL5:
+		  tc->flags = 0
 			| TC_FLAGS_AAL5
 			| TC_FLAGS_PACKET  /* ??? */
 			| TC_FLAGS_TYPE_CBR
 			| TC_FLAGS_CAL0;
-
+		  break;
+		default:
+			printk ("Unknown aal: %d\n", atm_vcc->qos.aal);
+			tc->flags = 0;
+		}
 		/* Docs are vague about this atm_hdr field. By the way, the FS
 		 * chip makes odd errors if lower bits are set.... -- REW */
 		tc->atm_hdr =  (vpi << 20) | (vci << 4); 
@@ -1025,7 +1049,6 @@
 
 		for (bfp = 0;bfp < FS_NR_FREE_POOLS; bfp++)
 			if (atm_vcc->qos.rxtp.max_sdu <= dev->rx_fp[bfp].bufsize) break;
-    
 		if (bfp >= FS_NR_FREE_POOLS) {
 			fs_dprintk (FS_DEBUG_OPEN, "No free pool fits sdu: %d.\n", 
 				    atm_vcc->qos.rxtp.max_sdu);
@@ -1037,12 +1060,23 @@
 			return -EINVAL;
 		}
 
-		submit_command (dev, &dev->hp_txq, 
-				QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo,
-				RC_FLAGS_AAL5 | 
-				RC_FLAGS_BFPS_BFP * bfp |
-				RC_FLAGS_RXBM_PSB, 0, 0);
-    
+		switch (atm_vcc->qos.aal) {
+		case ATM_AAL0:
+		case ATM_AAL2:
+			submit_command (dev, &dev->hp_txq,
+					QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo,
+					RC_FLAGS_TRANSP |
+					RC_FLAGS_BFPS_BFP * bfp |
+					RC_FLAGS_RXBM_PSB, 0, 0);
+			break;
+		case ATM_AAL5:
+			submit_command (dev, &dev->hp_txq,
+					QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo,
+					RC_FLAGS_AAL5 |
+					RC_FLAGS_BFPS_BFP * bfp |
+					RC_FLAGS_RXBM_PSB, 0, 0);
+			break;
+		};
 		if (IS_FS50 (dev)) {
 			submit_command (dev, &dev->hp_txq, 
 					QE_CMD_REG_WR | QE_CMD_IMM_INQ,
@@ -1697,7 +1731,7 @@
 
 	/* AN3: 10 */
 	write_fs (dev, SARMODE1, 0 
-		  | (0 * SARMODE1_DEFHEC) /* XXX PHY */
+		  | (fs_keystream * SARMODE1_DEFHEC) /* XXX PHY */
 		  | ((loopback == 1) * SARMODE1_TSTLP) /* XXX Loopback mode enable... */
 		  | (1 * SARMODE1_DCRM)
 		  | (1 * SARMODE1_DCOAM)
diff -u --recursive --new-file v2.4.3/linux/drivers/atm/firestream.h linux/drivers/atm/firestream.h
--- v2.4.3/linux/drivers/atm/firestream.h	Fri Dec 29 14:35:47 2000
+++ linux/drivers/atm/firestream.h	Wed Apr 11 19:02:30 2001
@@ -369,6 +369,9 @@
 };
 
 #define TC_FLAGS_AAL5      (0x0 << 29)
+#define TC_FLAGS_TRANSPARENT_PAYLOAD (0x1 << 29)
+#define TC_FLAGS_TRANSPARENT_CELL    (0x2 << 29)
+#define TC_FLAGS_STREAMING (0x1 << 28)
 #define TC_FLAGS_PACKET    (0x0) 
 #define TC_FLAGS_TYPE_ABR  (0x0 << 22)
 #define TC_FLAGS_TYPE_CBR  (0x1 << 22)
@@ -498,8 +501,8 @@
  
 /* Within limits this is user-configurable. */
 /* Note: Currently the sum (10 -> 1k channels) is hardcoded in the driver. */
-#define FS155_VPI_BITS 5
-#define FS155_VCI_BITS 5
+#define FS155_VPI_BITS 4
+#define FS155_VCI_BITS 6
 
 #define FS155_CHANNEL_BITS  (FS155_VPI_BITS + FS155_VCI_BITS)
 #define FS155_NR_CHANNELS   (1 << FS155_CHANNEL_BITS)
diff -u --recursive --new-file v2.4.3/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c
--- v2.4.3/linux/drivers/atm/zatm.c	Tue Jul 18 14:55:01 2000
+++ linux/drivers/atm/zatm.c	Wed Apr 11 19:02:30 2001
@@ -1826,9 +1826,13 @@
 			devs++;
 			zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct
 			    zatm_dev),GFP_KERNEL);
-			if (!zatm_dev) break;
+			if (!zatm_dev) {
+				printk(KERN_EMERG "zatm.c: memory shortage\n");
+				goto out;
+			}
 		}
 	}
+out:
 	return devs;
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- v2.4.3/linux/drivers/block/cciss.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/cciss.c	Fri Apr 13 20:26:07 2001
@@ -583,13 +583,15 @@
 		if (iocommand.Request.Type.Direction == XFER_WRITE)
 		{
 			/* Copy the data into the buffer we created */ 
-			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
+			if (copy_from_user(buff, iocommand.buf,
+						iocommand.buf_size)) {
+				kfree(buff);
 				return -EFAULT;
+			}
 		}
 		if ((c = cmd_alloc(NULL)) == NULL)
 		{
-			if(buff!=NULL)
-				kfree(buff);
+			kfree(buff);
 			return -ENOMEM;
 		}
 			// Fill in the command type 
@@ -636,8 +638,7 @@
 		if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
 		{
 			cmd_free(NULL, c);
-			if (buff != NULL) 
-				kfree(buff);
+			kfree(buff);
 			return( -EFAULT);	
 		} 	
 
@@ -648,11 +649,11 @@
 			{
 			             cmd_free(NULL, c);
 			             kfree(buff);
+				     return -EFAULT;	
 			}
                 }
 		cmd_free(NULL, c);
-                if (buff != NULL)
-                	kfree(buff);
+                kfree(buff);
                 return(0);
 	} 
 
@@ -761,7 +762,7 @@
         hba[ctlr]->gendisk.nr_real = 0;
 
         /*
-         * Tell the array controller not to give us any interupts while
+         * Tell the array controller not to give us any interrupts while
          * we check the new geometry.  Then turn interrupts back on when
          * we're done.
          */
@@ -1087,7 +1088,7 @@
 	if (timeout)
 		status = 0; 
 	if(cmd->err_info->CommandStatus != 0) 
-	{ /* an error has occured */ 
+	{ /* an error has occurred */ 
 		switch(cmd->err_info->CommandStatus)
 		{
 			case CMD_TARGET_STATUS:
@@ -1846,12 +1847,9 @@
 			|| (hba[i]->errinfo_pool == NULL))
                 {
                         nr_ctlr = i;
-			if(hba[i]->cmd_pool_bits)
-                                kfree(hba[i]->cmd_pool_bits);
-                        if(hba[i]->cmd_pool)
-                                kfree(hba[i]->cmd_pool);
-			if(hba[i]->errinfo_pool)
-				kfree(hba[i]->errinfo_pool);
+			kfree(hba[i]->cmd_pool_bits);
+			kfree(hba[i]->cmd_pool);
+			kfree(hba[i]->errinfo_pool);
                         free_irq(hba[i]->intr, hba[i]);
                         unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
                         num_cntlrs_reg--;
diff -u --recursive --new-file v2.4.3/linux/drivers/block/cciss.h linux/drivers/block/cciss.h
--- v2.4.3/linux/drivers/block/cciss.h	Sat Feb  3 12:13:19 2001
+++ linux/drivers/block/cciss.h	Fri Apr 13 20:26:07 2001
@@ -122,7 +122,7 @@
 }
 
 /*  
- *  This card is the oposite of the other cards.  
+ *  This card is the opposite of the other cards.  
  *   0 turns interrupts on... 
  *   0x08 turns them off... 
  */
@@ -138,7 +138,7 @@
 	}
 }
 /*
- *  This card is the oposite of the other cards.
+ *  This card is the opposite of the other cards.
  *   0 turns interrupts on...
  *   0x04 turns them off...
  */
diff -u --recursive --new-file v2.4.3/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h
--- v2.4.3/linux/drivers/block/cciss_cmd.h	Fri Sep 22 17:11:37 2000
+++ linux/drivers/block/cciss_cmd.h	Fri Apr 13 20:26:07 2001
@@ -222,7 +222,7 @@
   ErrDescriptor_struct     ErrDesc;
   SGDescriptor_struct      SG[MAXSGENTRIES];
 	/* information associated with the command */ 
-  __u32			   busaddr; /* physical addres of this record */
+  __u32			   busaddr; /* physical address of this record */
   ErrorInfo_struct * 	   err_info; /* pointer to the allocated mem */ 
   int			   cmd_type; 
   struct _CommandList_struct *prev;
diff -u --recursive --new-file v2.4.3/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.4.3/linux/drivers/block/ll_rw_blk.c	Fri Mar 23 11:45:28 2001
+++ linux/drivers/block/ll_rw_blk.c	Thu Apr 12 12:15:52 2001
@@ -231,8 +231,7 @@
  *    If a driver processes several requests at once, it must remove them (or
  *    at least all but one of them) from the request queue.
  *
- *    When a queue is plugged (see blk_queue_pluggable()) the head will be
- *    assumed to be inactive.
+ *    When a queue is plugged the head will be assumed to be inactive.
  **/
  
 void blk_queue_headactive(request_queue_t * q, int active)
@@ -241,35 +240,6 @@
 }
 
 /**
- * blk_queue_pluggable - define a plugging function for a request queue
- * @q:   the request queue to which the function will apply
- * @plug: the function to be called to plug a queue
- *
- * Description:
- *   A request queue will be "plugged" if a request is added to it
- *   while it is empty.  This allows a number of requests to be added
- *   before any are processed, thus providing an opportunity for these
- *   requests to be merged or re-ordered.
- *   The default plugging function (generic_plug_device()) sets the
- *   "plugged" flag for the queue and adds a task to the $tq_disk task
- *   queue to unplug the queue and call the request function at a
- *   later time.
- *
- *   A device driver may provide an alternate plugging function by
- *   passing it to blk_queue_pluggable().  This function should set
- *   the "plugged" flag if it want calls to the request_function to be
- *   blocked, and should place a task on $tq_disk which will unplug
- *   the queue.  Alternately it can simply do nothing and there-by
- *   disable plugging of the device.
- **/
-
-void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug)
-{
-	q->plug_device_fn = plug;
-}
-
-
-/**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
  * @mfn: the alternate make_request function
@@ -590,7 +560,7 @@
 	list_add(&req->queue, insert_here);
 }
 
-void inline blk_refill_freelist(request_queue_t *q, int rw)
+inline void blk_refill_freelist(request_queue_t *q, int rw)
 {
 	if (q->pending_free[rw]) {
 		list_splice(&q->pending_freelist[rw], &q->request_freelist[rw]);
@@ -602,7 +572,7 @@
 /*
  * Must be called with io_request_lock held and interrupts disabled
  */
-void inline blkdev_release_request(struct request *req)
+inline void blkdev_release_request(struct request *req)
 {
 	request_queue_t *q = req->q;
 	int rw = req->cmd;
@@ -1320,15 +1290,19 @@
 #ifdef CONFIG_DDV
 	ddv_init();
 #endif
-#ifdef CONFIG_BLK_DEV_NBD
-	nbd_init();
-#endif
 #ifdef CONFIG_MDISK
 	mdisk_init();
 #endif
 #ifdef CONFIG_DASD
 	dasd_init();
 #endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_BLOCK)
+	tapeblock_init();
+#endif
+#ifdef CONFIG_BLK_DEV_XPRAM
+        xpram_init();
+#endif
+
 #ifdef CONFIG_SUN_JSFLASH
 	jsfd_init();
 #endif
@@ -1343,7 +1317,6 @@
 EXPORT_SYMBOL(__blk_get_queue);
 EXPORT_SYMBOL(blk_cleanup_queue);
 EXPORT_SYMBOL(blk_queue_headactive);
-EXPORT_SYMBOL(blk_queue_pluggable);
 EXPORT_SYMBOL(blk_queue_make_request);
 EXPORT_SYMBOL(generic_make_request);
 EXPORT_SYMBOL(blkdev_release_request);
diff -u --recursive --new-file v2.4.3/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.4.3/linux/drivers/block/loop.c	Tue Mar  6 19:35:36 2001
+++ linux/drivers/block/loop.c	Wed Apr 11 19:05:14 2001
@@ -316,7 +316,6 @@
 static void loop_put_buffer(struct buffer_head *bh)
 {
 	if (bh) {
-		kunmap(bh->b_page);
 		__free_page(bh->b_page);
 		kmem_cache_free(bh_cachep, bh);
 	}
@@ -408,9 +407,16 @@
 	 * blocks... if highmem bounce buffering can get away with it,
 	 * so can we :-)
 	 */
-	bh->b_page = alloc_page(GFP_BUFFER);
-	bh->b_data = kmap(bh->b_page);
+	do {
+		bh->b_page = alloc_page(GFP_BUFFER);
+		if (bh->b_page)
+			break;
+
+		run_task_queue(&tq_disk);
+		schedule_timeout(HZ);
+	} while (1);
 
+	bh->b_data = page_address(bh->b_page);
 	bh->b_end_io = loop_end_io_transfer;
 	bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9);
 	init_waitqueue_head(&bh->b_wait);
@@ -455,6 +461,10 @@
 	 * file backed, queue for loop_thread to handle
 	 */
 	if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
+		/*
+		 * rbh locked at this point, noone else should clear
+		 * the dirty flag
+		 */
 		if (rw == WRITE)
 			set_bit(BH_Dirty, &rbh->b_state);
 		loop_add_bh(lo, rbh);
@@ -469,7 +479,8 @@
 	IV = loop_get_iv(lo, bh->b_rsector);
 	if (rw == WRITE) {
 		set_bit(BH_Dirty, &bh->b_state);
-		if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data, bh->b_size, IV))
+		if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data,
+				   bh->b_size, IV))
 			goto err;
 	}
 
diff -u --recursive --new-file v2.4.3/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.4.3/linux/drivers/block/nbd.c	Tue Mar  6 19:19:21 2001
+++ linux/drivers/block/nbd.c	Wed Apr 11 19:02:30 2001
@@ -26,12 +26,11 @@
  *          structure with userland
  */
 
-#undef	NBD_PLUGGABLE
 #define PARANOIA
 #include <linux/major.h>
 
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
@@ -68,8 +67,6 @@
 static int requests_out;
 #endif
 
-static void nbd_plug_device(request_queue_t *q, kdev_t dev) { }
-
 static int nbd_open(struct inode *inode, struct file *file)
 {
 	int dev;
@@ -88,7 +85,7 @@
 /*
  *  Send or receive packet.
  */
-static int nbd_xmit(int send, struct socket *sock, char *buf, int size)
+static int nbd_xmit(int send, struct socket *sock, char *buf, int size, int msg_flags)
 {
 	mm_segment_t oldfs;
 	int result;
@@ -118,7 +115,7 @@
 		msg.msg_control = NULL;
 		msg.msg_controllen = 0;
 		msg.msg_namelen = 0;
-		msg.msg_flags = 0;
+		msg.msg_flags = msg_flags | MSG_NOSIGNAL;
 
 		if (send)
 			result = sock_sendmsg(sock, &msg, size);
@@ -151,23 +148,28 @@
 {
 	int result;
 	struct nbd_request request;
+	unsigned long size = req->nr_sectors << 9;
 
 	DEBUG("NBD: sending control, ");
 	request.magic = htonl(NBD_REQUEST_MAGIC);
 	request.type = htonl(req->cmd);
 	request.from = cpu_to_be64( (u64) req->sector << 9);
-	request.len = htonl(req->current_nr_sectors << 9);
+	request.len = htonl(size);
 	memcpy(request.handle, &req, sizeof(req));
 
-	result = nbd_xmit(1, sock, (char *) &request, sizeof(request));
+	result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0);
 	if (result <= 0)
 		FAIL("Sendmsg failed for control.");
 
 	if (req->cmd == WRITE) {
+		struct buffer_head *bh = req->bh;
 		DEBUG("data, ");
-		result = nbd_xmit(1, sock, req->buffer, req->current_nr_sectors << 9);
-		if (result <= 0)
-			FAIL("Send data failed.");
+		do {
+			result = nbd_xmit(1, sock, bh->b_data, bh->b_size, bh->b_reqnext == NULL ? 0 : MSG_MORE);
+			if (result <= 0)
+				FAIL("Send data failed.");
+			bh = bh->b_reqnext;
+		} while(bh);
 	}
 	return;
 
@@ -185,7 +187,7 @@
 
 	DEBUG("reading control, ");
 	reply.magic = 0;
-	result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply));
+	result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply), MSG_WAITALL);
 	if (result <= 0)
 		HARDFAIL("Recv control failed.");
 	memcpy(&xreq, reply.handle, sizeof(xreq));
@@ -200,10 +202,14 @@
 	if (ntohl(reply.error))
 		FAIL("Other side returned error.");
 	if (req->cmd == READ) {
+		struct buffer_head *bh = req->bh;
 		DEBUG("data, ");
-		result = nbd_xmit(0, lo->sock, req->buffer, req->current_nr_sectors << 9);
-		if (result <= 0)
-			HARDFAIL("Recv data failed.");
+		do {
+			result = nbd_xmit(0, lo->sock, bh->b_data, bh->b_size, MSG_WAITALL);
+			if (result <= 0)
+				HARDFAIL("Recv data failed.");
+			bh = bh->b_reqnext;
+		} while(bh);
 	}
 	DEBUG("done.\n");
 	return req;
@@ -217,7 +223,6 @@
 void nbd_do_it(struct nbd_device *lo)
 {
 	struct request *req;
-	int dequeued;
 
 	down (&lo->queue_lock);
 	while (1) {
@@ -245,11 +250,9 @@
 		list_del(&req->queue);
 		up (&lo->queue_lock);
 		
-		dequeued = nbd_end_request(req);
+		nbd_end_request(req);
 
 		down (&lo->queue_lock);
-		if (!dequeued)
-			list_add(&req->queue, &lo->queue_head);
 	}
  out:
 	up (&lo->queue_lock);
@@ -258,7 +261,6 @@
 void nbd_clear_que(struct nbd_device *lo)
 {
 	struct request *req;
-	int dequeued;
 
 #ifdef PARANOIA
 	if (lo->magic != LO_MAGIC) {
@@ -283,11 +285,9 @@
 		list_del(&req->queue);
 		up(&lo->queue_lock);
 
-		dequeued = nbd_end_request(req);
+		nbd_end_request(req);
 
 		down(&lo->queue_lock);
-		if (!dequeued)
-			list_add(&req->queue, &lo->queue_head);
 	}
 }
 
@@ -477,11 +477,7 @@
  *  (Just smiley confuses emacs :-)
  */
 
-#ifdef MODULE
-#define nbd_init init_module
-#endif
-
-int nbd_init(void)
+static int __init nbd_init(void)
 {
 	int i;
 
@@ -501,9 +497,6 @@
 	blksize_size[MAJOR_NR] = nbd_blksizes;
 	blk_size[MAJOR_NR] = nbd_sizes;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request);
-#ifndef NBD_PLUGGABLE
-	blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), nbd_plug_device);
-#endif
 	blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
 	for (i = 0; i < MAX_NBD; i++) {
 		nbd_dev[i].refcnt = 0;
@@ -528,8 +521,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit nbd_cleanup(void)
 {
 	devfs_unregister (devfs_handle);
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
@@ -539,4 +531,9 @@
 	else
 		printk("nbd: module cleaned up.\n");
 }
-#endif
+
+module_init(nbd_init);
+module_exit(nbd_cleanup);
+
+MODULE_DESCRIPTION("Network Block Device");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- v2.4.3/linux/drivers/block/paride/Config.in	Mon Jan 24 11:21:47 2000
+++ linux/drivers/block/paride/Config.in	Fri Apr  6 10:42:55 2001
@@ -20,7 +20,8 @@
 dep_tristate '  Parallel port generic ATAPI devices' CONFIG_PARIDE_PG $CONFIG_PARIDE
 comment 'Parallel IDE protocol modules'
 dep_tristate '    ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE
-dep_tristate '    MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
+dep_tristate '    MicroSolutions backpack (Series 5) protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
+dep_tristate '    MicroSolutions backpack (Series 6) protocol' CONFIG_PARIDE_BPCK6 $CONFIG_PARIDE
 dep_tristate '    DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE
 dep_tristate '    DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE
 dep_tristate '    FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE
diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/Makefile linux/drivers/block/paride/Makefile
--- v2.4.3/linux/drivers/block/paride/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/drivers/block/paride/Makefile	Fri Apr  6 10:42:55 2001
@@ -27,5 +27,6 @@
 obj-$(CONFIG_PARIDE_ON20)	+= on20.o
 obj-$(CONFIG_PARIDE_ON26)	+= on26.o
 obj-$(CONFIG_PARIDE_KTTI)	+= ktti.o
+obj-$(CONFIG_PARIDE_BPCK6)	+= bpck6.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/bpck6.c linux/drivers/block/paride/bpck6.c
--- v2.4.3/linux/drivers/block/paride/bpck6.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/bpck6.c	Thu Apr 12 12:16:35 2001
@@ -0,0 +1,317 @@
+/*
+	backpack.c (c) 2001 Micro Solutions Inc.
+		Released under the terms of the GNU General Public license
+
+	backpack.c is a low-level protocol driver for the Micro Solutions
+		"BACKPACK" parallel port IDE adapter
+		(Works on Series 6 drives)
+
+	Written by: Ken Hahn     (linux-dev@micro-solutions.com)
+	            Clive Turvey (linux-dev@micro-solutions.com)
+
+*/
+
+/*
+   This is Ken's linux wrapper for the PPC library
+   Version 1.0.0 is the backpack driver for which source is not available
+   Version 2.0.0 is the first to have source released 
+   Version 2.0.1 is the "Cox-ified" source code 
+   Version 2.0.2 - fixed version string usage, and made ppc functions static 
+*/
+
+
+/* PARAMETERS */
+int verbose=0; /* set this to 1 to see debugging messages and whatnot */
+
+#define BACKPACK_VERSION "2.0.2"
+
+#define EXPORT_SYMTAB 
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PARPORT_MODULE)||defined(CONFIG_PARPORT)
+#include <linux/parport.h>
+#endif
+
+#include "ppc6lnx.c"
+#include "paride.h"
+
+ 
+
+#define PPCSTRUCT(pi) ((PPC *)(pi->private))
+
+/****************************************************************/
+/*
+ ATAPI CDROM DRIVE REGISTERS
+*/
+#define ATAPI_DATA       0      /* data port                  */
+#define ATAPI_ERROR      1      /* error register (read)      */
+#define ATAPI_FEATURES   1      /* feature register (write)   */
+#define ATAPI_INT_REASON 2      /* interrupt reason register  */
+#define ATAPI_COUNT_LOW  4      /* byte count register (low)  */
+#define ATAPI_COUNT_HIGH 5      /* byte count register (high) */
+#define ATAPI_DRIVE_SEL  6      /* drive select register      */
+#define ATAPI_STATUS     7      /* status port (read)         */
+#define ATAPI_COMMAND    7      /* command port (write)       */
+#define ATAPI_ALT_STATUS 0x0e /* alternate status reg (read) */
+#define ATAPI_DEVICE_CONTROL 0x0e /* device control (write)   */
+/****************************************************************/
+
+static int bpck6_read_regr(PIA *pi, int cont, int reg)
+{
+	unsigned int out;
+
+	/* check for bad settings */
+	if (reg<0 || reg>7 || cont<0 || cont>2)
+	{
+		return(-1);
+	}
+	out=ppc6_rd_port(PPCSTRUCT(pi),cont?reg|8:reg);
+	return(out);
+}
+
+static void bpck6_write_regr(PIA *pi, int cont, int reg, int val)
+{
+	/* check for bad settings */
+	if (reg>=0 && reg<=7 && cont>=0 && cont<=1)
+	{
+		ppc6_wr_port(PPCSTRUCT(pi),cont?reg|8:reg,(u8)val);
+	}
+}
+
+static void bpck6_write_block( PIA *pi, char * buf, int len )
+{
+	ppc6_wr_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); 
+}
+
+static void bpck6_read_block( PIA *pi, char * buf, int len )
+{
+	ppc6_rd_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1);
+}
+
+static void bpck6_connect ( PIA *pi  )
+{
+	if(verbose)
+	{
+		printk(KERN_DEBUG "connect\n");
+	}
+
+	if(pi->mode >=2)
+  	{
+		PPCSTRUCT(pi)->mode=4+pi->mode-2;	
+	}
+	else if(pi->mode==1)
+	{
+		PPCSTRUCT(pi)->mode=3;	
+	}
+	else
+	{
+		PPCSTRUCT(pi)->mode=1;		
+	}
+
+	ppc6_open(PPCSTRUCT(pi));  
+	ppc6_wr_extout(PPCSTRUCT(pi),0x3);
+}
+
+static void bpck6_disconnect ( PIA *pi )
+{
+	if(verbose)
+	{
+		printk("disconnect\n");
+	}
+	ppc6_wr_extout(PPCSTRUCT(pi),0x0);
+	ppc6_close(PPCSTRUCT(pi));
+}
+
+static int bpck6_test_port ( PIA *pi )   /* check for 8-bit port */
+{
+	if(verbose)
+	{
+		printk(KERN_DEBUG "PARPORT indicates modes=%x for lp=0x%lx\n",
+               		((struct pardevice*)(pi->pardev))->port->modes,
+			((struct pardevice *)(pi->pardev))->port->base); 
+	}
+
+	/*copy over duplicate stuff.. initialize state info*/
+	PPCSTRUCT(pi)->ppc_id=pi->unit;
+	PPCSTRUCT(pi)->lpt_addr=pi->port;
+
+#ifdef CONFIG_PARPORT_PC_MODULE
+#define CONFIG_PARPORT_PC
+#endif
+
+#ifdef CONFIG_PARPORT_PC
+	/* look at the parport device to see if what modes we can use */
+	if(((struct pardevice *)(pi->pardev))->port->modes & 
+		(PARPORT_MODE_EPP)
+          )
+	{
+		return 5; /* Can do EPP*/
+	}
+	else if(((struct pardevice *)(pi->pardev))->port->modes & 
+			(PARPORT_MODE_TRISTATE)
+               )
+	{
+		return 2;
+	}
+	else /*Just flat SPP*/
+	{
+		return 1;
+	}
+#else
+	/* there is no way of knowing what kind of port we have
+	   default to the highest mode possible */
+	return 5;
+#endif
+}
+
+static int bpck6_probe_unit ( PIA *pi )
+{
+	int out;
+
+	if(verbose)
+	{
+		printk(KERN_DEBUG "PROBE UNIT %x on port:%x\n",pi->unit,pi->port);
+	}
+
+	/*SET PPC UNIT NUMBER*/
+	PPCSTRUCT(pi)->ppc_id=pi->unit;
+
+	/*LOWER DOWN TO UNIDIRECTIONAL*/
+	PPCSTRUCT(pi)->mode=1;		
+
+	out=ppc6_open(PPCSTRUCT(pi));
+
+	if(verbose)
+	{
+		printk(KERN_DEBUG "ppc_open returned %2x\n",out);
+	}
+
+  	if(out)
+ 	{
+		ppc6_close(PPCSTRUCT(pi));
+		return(1);	
+		if(verbose)
+		{
+			printk(KERN_DEBUG "leaving probe\n");
+		}
+	}
+  	else
+  	{
+		if(verbose)
+		{
+			printk(KERN_DEBUG "Failed open\n");
+		}
+    		return(0);
+  	}
+}
+
+static void bpck6_log_adapter( PIA *pi, char * scratch, int verbose )
+{
+	char *mode_string[5]=
+		{"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
+
+	printk("%s: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n",pi->device);
+	printk("%s: Copyright 2001 by Micro Solutions, Inc., DeKalb IL.\n",pi->device);
+	printk("%s: BACKPACK %s, Micro Solutions BACKPACK Drive at 0x%x\n",
+		pi->device,BACKPACK_VERSION,pi->port);
+	printk("%s: Unit: %d Mode:%d (%s) Delay %d\n",pi->device,
+		pi->unit,pi->mode,mode_string[pi->mode],pi->delay);
+}
+
+static void bpck6_init_proto(PIA *pi)
+{
+	int i;
+
+	/* allocate a state structure for this item */
+	pi->private=(int)kmalloc(sizeof(PPC),GFP_KERNEL);
+
+	if(pi->private==(int)NULL)
+	{
+		printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n",pi->device); 
+		return;
+	}
+	else
+	{	
+		MOD_INC_USE_COUNT; 
+	}
+
+	for(i=0;i<sizeof(PPC);i++)
+	{
+		((unsigned char *)(pi->private))[i]=0;
+	}
+}
+
+static void bpck6_release_proto(PIA *pi)
+{
+	MOD_DEC_USE_COUNT;
+	/* free after use count decremented so that we aren't using it
+		when it is decremented */
+	kfree((void *)(pi->private)); 
+}
+
+struct pi_protocol bpck6 = { "bpck6", /* name for proto*/
+				0, /* index into proto table */
+				5, /* max mode =5 */
+				2, /* 2-5 use epp (need 8 ports) */
+				0, /* no delay (not used anyway) */
+				255, /* we can have units  up to 255 */
+				bpck6_write_regr,
+				bpck6_read_regr,
+				bpck6_write_block,
+				bpck6_read_block,
+				bpck6_connect,
+				bpck6_disconnect,
+				bpck6_test_port,
+ 				bpck6_probe_unit,
+				0,
+				bpck6_log_adapter,
+				bpck6_init_proto,
+				bpck6_release_proto
+                        };
+
+
+EXPORT_SYMBOL(bpck6_write_regr);
+EXPORT_SYMBOL(bpck6_read_regr);
+EXPORT_SYMBOL(bpck6_write_block);
+EXPORT_SYMBOL(bpck6_read_block);
+EXPORT_SYMBOL(bpck6_connect);
+EXPORT_SYMBOL(bpck6_disconnect);
+EXPORT_SYMBOL(bpck6_test_port);
+EXPORT_SYMBOL(bpck6_probe_unit);
+EXPORT_SYMBOL(bpck6_log_adapter);
+EXPORT_SYMBOL(bpck6_init_proto);
+EXPORT_SYMBOL(bpck6_release_proto);
+
+/*---------------------------MODULE STUFF-----------------------*/
+
+#ifdef MODULE
+/*module information*/
+
+static int init_module(void)
+{
+	printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n");
+	printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n");
+
+	if(verbose)
+	{
+		printk(KERN_DEBUG "bpck6: verbose debug enabled.\n");
+	}
+
+	return pi_register(&bpck6) - 1;  
+}
+
+void    cleanup_module(void)
+{
+	pi_unregister(&bpck6);
+}
+
+MODULE_AUTHOR("Micro Solutions Inc.");
+MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
+MODULE_PARM(verbose,"i");
+
+#endif
+
diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c
--- v2.4.3/linux/drivers/block/paride/paride.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/paride.c	Fri Apr  6 10:42:55 2001
@@ -15,9 +15,10 @@
 	1.04    GRG 1998.11.28  added support for FRIQ 
 	1.05    TMW 2000.06.06  use parport_find_number instead of
 				parport_enumerate
+	1.06    TMW 2001.03.26  more sane parport-or-not resource management
 */
 
-#define PI_VERSION      "1.05"
+#define PI_VERSION      "1.06"
 
 #include <linux/module.h>
 #include <linux/config.h>
@@ -160,8 +161,10 @@
 void pi_release( PIA *pi)
 
 {	pi_unregister_parport(pi);
-	if ((!pi->pardev)&&(pi->reserved)) 
+#ifndef CONFIG_PARPORT
+	if (pi->reserved)
 		release_region(pi->port,pi->reserved);
+#endif /* !CONFIG_PARPORT */
 	pi->proto->release_proto(pi);
 }
 
@@ -234,7 +237,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static void pi_register_parport( PIA *pi, int verbose)
+static int pi_register_parport( PIA *pi, int verbose)
 
 {
 #ifdef CONFIG_PARPORT
@@ -242,15 +245,16 @@
 	struct parport *port;
 
 	port = parport_find_base (pi->port);
-	if (!port) return;
+	if (!port)
+	  return 0;
 
 	pi->pardev = parport_register_device(port,
 					     pi->device,NULL,
 					     pi_wake_up,NULL,
 					     0,(void *)pi);
 	parport_put_port (port);
-	if (!pi->pardev) return;
-
+	if (!pi->pardev)
+	  return 0;
 
 	init_waitqueue_head(&pi->parq);
 
@@ -258,8 +262,9 @@
 			    port->name);
 	
 	pi->parname = (char *)port->name;
-
 #endif
+
+	return 1;
 }
 
 static int pi_probe_mode( PIA *pi, int max, char * scratch, int verbose)
@@ -271,7 +276,9 @@
 		range = 3;
 		if (pi->mode >= pi->proto->epp_first) range = 8;
 		if ((range == 8) && (pi->port % 8)) return 0;
-		if ((!pi->pardev) && check_region(pi->port,range)) return 0;
+#ifndef CONFIG_PARPORT
+		if (check_region(pi->port,range)) return 0;
+#endif /* !CONFIG_PARPORT */
 		pi->reserved = range;
 		return (!pi_test_proto(pi,scratch,verbose));
 	}
@@ -280,7 +287,9 @@
 		range = 3;
 		if (pi->mode >= pi->proto->epp_first) range = 8;
 		if ((range == 8) && (pi->port % 8)) break;
-		if ((!pi->pardev) && check_region(pi->port,range)) break;
+#ifndef CONFIG_PARPORT
+		if (check_region(pi->port,range)) break;
+#endif /* !CONFIG_PARPORT */
 		pi->reserved = range;
 		if (!pi_test_proto(pi,scratch,verbose)) best = pi->mode;
 	}
@@ -299,9 +308,12 @@
 		e = pi->proto->max_units; 
 	}
 
-	pi_register_parport(pi,verbose);
+	if (!pi_register_parport(pi,verbose))
+	  return 0;
 
-	if ((!pi->pardev) && check_region(pi->port,3)) return 0;
+#ifndef CONFIG_PARPORT
+	if (check_region(pi->port,3)) return 0;
+#endif /* !CONFIG_PARPORT */
 
 	if (pi->proto->test_port) {
 		pi_claim(pi);
@@ -391,8 +403,9 @@
 		return 0;
 	}
 
-	if (!pi->pardev)
-	   request_region(pi->port,pi->reserved,pi->device);
+#ifndef CONFIG_PARPORT
+	request_region(pi->port,pi->reserved,pi->device);
+#endif /* !CONFIG_PARPORT */
 
 	if (pi->parname)
 	   printk("%s: Sharing %s at 0x%x\n",pi->device,
@@ -407,11 +420,16 @@
 
 int	init_module(void)
 
-{	int k;
+{
+	int k;
+	const char *indicate_pp = "";
+#ifdef CONFIG_PARPORT
+	indicate_pp = " (parport)";
+#endif
 
 	for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0;
 
-	printk("paride: version %s installed\n",PI_VERSION);
+	printk("paride: version %s installed%s\n",PI_VERSION,indicate_pp);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/ppc6lnx.c linux/drivers/block/paride/ppc6lnx.c
--- v2.4.3/linux/drivers/block/paride/ppc6lnx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/ppc6lnx.c	Fri Apr  6 10:42:55 2001
@@ -0,0 +1,950 @@
+/*
+	ppc6lnx.c (c) 2001 Micro Solutions Inc.
+		Released under the terms of the GNU General Public license
+
+	ppc6lnx.c  is a par of the protocol driver for the Micro Solutions
+		"BACKPACK" parallel port IDE adapter
+		(Works on Series 6 drives)
+
+*/
+
+//***************************************************************************
+
+// PPC 6 Code in C sanitized for LINUX
+// Original x86 ASM by Ron, Converted to C by Clive
+
+//***************************************************************************
+
+
+#define port_stb					1
+#define port_afd					2
+#define cmd_stb						port_afd
+#define port_init					4
+#define data_stb					port_init
+#define port_sel					8
+#define port_int					16
+#define port_dir					0x20
+
+#define ECR_EPP	0x80
+#define ECR_BI	0x20
+
+//***************************************************************************
+
+//  60772 Commands
+
+#define ACCESS_REG				0x00
+#define ACCESS_PORT				0x40
+
+#define ACCESS_READ				0x00
+#define ACCESS_WRITE			0x20
+
+//  60772 Command Prefix
+
+#define CMD_PREFIX_SET		0xe0		// Special command that modifies the next command's operation
+#define CMD_PREFIX_RESET	0xc0		// Resets current cmd modifier reg bits
+ #define PREFIX_IO16			0x01		// perform 16-bit wide I/O
+ #define PREFIX_FASTWR		0x04		// enable PPC mode fast-write
+ #define PREFIX_BLK				0x08		// enable block transfer mode
+
+// 60772 Registers
+
+#define REG_STATUS				0x00		// status register
+ #define STATUS_IRQA			0x01		// Peripheral IRQA line
+ #define STATUS_EEPROM_DO	0x40		// Serial EEPROM data bit
+#define REG_VERSION				0x01		// PPC version register (read)
+#define REG_HWCFG					0x02		// Hardware Config register
+#define REG_RAMSIZE				0x03		// Size of RAM Buffer
+ #define RAMSIZE_128K			0x02
+#define REG_EEPROM				0x06		// EEPROM control register
+ #define EEPROM_SK				0x01		// eeprom SK bit
+ #define EEPROM_DI				0x02		// eeprom DI bit
+ #define EEPROM_CS				0x04		// eeprom CS bit
+ #define EEPROM_EN				0x08		// eeprom output enable
+#define REG_BLKSIZE				0x08		// Block transfer len (24 bit)
+
+//***************************************************************************
+
+typedef struct ppc_storage {
+	u16	lpt_addr;				// LPT base address
+	u8	ppc_id;
+	u8	mode;						// operating mode
+					// 0 = PPC Uni SW
+					// 1 = PPC Uni FW
+					// 2 = PPC Bi SW
+					// 3 = PPC Bi FW
+					// 4 = EPP Byte
+					// 5 = EPP Word
+					// 6 = EPP Dword
+	u8	ppc_flags;
+	u8	org_data;				// original LPT data port contents
+	u8	org_ctrl;				// original LPT control port contents
+	u8	cur_ctrl;				// current control port contents
+} PPC;
+
+//***************************************************************************
+
+// ppc_flags
+
+#define fifo_wait					0x10
+
+//***************************************************************************
+
+// DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES
+
+#define PPCMODE_UNI_SW		0
+#define PPCMODE_UNI_FW		1
+#define PPCMODE_BI_SW			2
+#define PPCMODE_BI_FW			3
+#define PPCMODE_EPP_BYTE	4
+#define PPCMODE_EPP_WORD	5
+#define PPCMODE_EPP_DWORD	6
+
+//***************************************************************************
+
+static int ppc6_select(PPC *ppc);
+static void ppc6_deselect(PPC *ppc);
+static void ppc6_send_cmd(PPC *ppc, u8 cmd);
+static void ppc6_wr_data_byte(PPC *ppc, u8 data);
+static u8 ppc6_rd_data_byte(PPC *ppc);
+static u8 ppc6_rd_port(PPC *ppc, u8 port);
+static void ppc6_wr_port(PPC *ppc, u8 port, u8 data);
+static u8 ppc6_rd_reg(PPC *ppc, u8 reg);
+static void ppc6_wr_reg(PPC *ppc, u8 reg, u8 data);
+static u8 ppc6_version(PPC *ppc);
+static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count);
+static void ppc6_wait_for_fifo(PPC *ppc);
+static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count);
+static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length);
+static u16 ppc6_rd_port16(PPC *ppc, u8 port);
+static void ppc6_wr_port16(PPC *ppc, u8 port, u16 data);
+static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length);
+static u8 ppc6_rd_eeprom_reg(PPC *ppc);
+static void ppc6_wr_eeprom_reg(PPC *ppc, u8 data);
+static void ppc6_eeprom_start(PPC *ppc);
+static void ppc6_eeprom_end(PPC *ppc);
+static void ppc6_set_cs(PPC *ppc);
+static void ppc6_reset_cs(PPC *ppc);
+static u8 ppc6_rd_eeprom_bit(PPC *ppc);
+static void ppc6_eeprom_ready_wait(PPC *ppc);
+static void ppc6_wr_eeprom_bit(PPC *ppc, u8 bit);
+static u16 ppc6_eeprom_read(PPC *ppc, u8 addr);
+static u8 ppc6_irq_test(PPC *ppc);
+static u8 ppc6_rd_extout(PPC *ppc);
+static void ppc6_wr_extout(PPC *ppc, u8 regdata);
+static int ppc6_open(PPC *ppc);
+static void ppc6_close(PPC *ppc);
+
+//***************************************************************************
+
+static int ppc6_select(PPC *ppc)
+{
+	u8 i, j, k;
+
+	i = inb(ppc->lpt_addr + 1);
+
+	if (i & 1)
+		outb(i, ppc->lpt_addr + 1);
+
+	ppc->org_data = inb(ppc->lpt_addr);
+
+	ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl
+
+	ppc->cur_ctrl = ppc->org_ctrl;
+
+	ppc->cur_ctrl |= port_sel;
+
+	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+	if (ppc->org_data == 'b')
+		outb('x', ppc->lpt_addr);
+
+	outb('b', ppc->lpt_addr);
+	outb('p', ppc->lpt_addr);
+	outb(ppc->ppc_id, ppc->lpt_addr);
+	outb(~ppc->ppc_id,ppc->lpt_addr);
+
+	ppc->cur_ctrl &= ~port_sel;
+
+	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+	ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init;
+
+	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+	i = ppc->mode & 0x0C;
+
+	if (i == 0)
+		i = (ppc->mode & 2) | 1;
+
+	outb(i, ppc->lpt_addr);
+
+	ppc->cur_ctrl |= port_sel;
+
+	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+	// DELAY
+
+	ppc->cur_ctrl |= port_afd;
+
+	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+	j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
+
+	k = inb(ppc->lpt_addr + 1) & 0xB8;
+
+	if (j == k)
+	{
+		ppc->cur_ctrl &= ~port_afd;
+
+		outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+		k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8;
+
+		if (j == k)
+		{
+			if (i & 4)	// EPP
+				ppc->cur_ctrl &= ~(port_sel | port_init);
+			else				// PPC/ECP
+				ppc->cur_ctrl &= ~port_sel;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			return(1);
+		}
+	}
+
+	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
+
+	outb(ppc->org_data, ppc->lpt_addr);
+
+	return(0); // FAIL
+}
+
+//***************************************************************************
+
+static void ppc6_deselect(PPC *ppc)
+{
+	if (ppc->mode & 4)	// EPP
+		ppc->cur_ctrl |= port_init;
+	else								// PPC/ECP
+		ppc->cur_ctrl |= port_sel;
+
+	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+	outb(ppc->org_data, ppc->lpt_addr);
+
+	outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2);
+
+	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
+}
+
+//***************************************************************************
+
+static void ppc6_send_cmd(PPC *ppc, u8 cmd)
+{
+	switch(ppc->mode)
+	{
+		case PPCMODE_UNI_SW :
+		case PPCMODE_UNI_FW :
+		case PPCMODE_BI_SW :
+		case PPCMODE_BI_FW :
+		{
+			outb(cmd, ppc->lpt_addr);
+
+			ppc->cur_ctrl ^= cmd_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+
+		case PPCMODE_EPP_BYTE :
+		case PPCMODE_EPP_WORD :
+		case PPCMODE_EPP_DWORD :
+		{
+			outb(cmd, ppc->lpt_addr + 3);
+
+			break;
+		}
+	}
+}
+
+//***************************************************************************
+
+static void ppc6_wr_data_byte(PPC *ppc, u8 data)
+{
+	switch(ppc->mode)
+	{
+		case PPCMODE_UNI_SW :
+		case PPCMODE_UNI_FW :
+		case PPCMODE_BI_SW :
+		case PPCMODE_BI_FW :
+		{
+			outb(data, ppc->lpt_addr);
+
+			ppc->cur_ctrl ^= data_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+
+		case PPCMODE_EPP_BYTE :
+		case PPCMODE_EPP_WORD :
+		case PPCMODE_EPP_DWORD :
+		{
+			outb(data, ppc->lpt_addr + 4);
+
+			break;
+		}
+	}
+}
+
+//***************************************************************************
+
+static u8 ppc6_rd_data_byte(PPC *ppc)
+{
+	u8 data;
+
+	switch(ppc->mode)
+	{
+		case PPCMODE_UNI_SW :
+		case PPCMODE_UNI_FW :
+		{
+			ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			// DELAY
+
+			data = inb(ppc->lpt_addr + 1);
+
+			data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
+
+			ppc->cur_ctrl |= port_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			// DELAY
+
+			data |= inb(ppc->lpt_addr + 1) & 0xB8;
+
+			break;
+		}
+
+		case PPCMODE_BI_SW :
+		case PPCMODE_BI_FW :
+		{
+			ppc->cur_ctrl |= port_dir;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			data = inb(ppc->lpt_addr);
+
+			ppc->cur_ctrl &= ~port_stb;
+
+			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
+
+			ppc->cur_ctrl &= ~port_dir;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+
+		case PPCMODE_EPP_BYTE :
+		case PPCMODE_EPP_WORD :
+		case PPCMODE_EPP_DWORD :
+		{
+			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
+
+			data = inb(ppc->lpt_addr + 4);
+
+			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
+
+			break;
+		}
+	}
+
+	return(data);
+}
+
+//***************************************************************************
+
+static u8 ppc6_rd_port(PPC *ppc, u8 port)
+{
+	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ));
+
+	return(ppc6_rd_data_byte(ppc));
+}
+
+//***************************************************************************
+
+static void ppc6_wr_port(PPC *ppc, u8 port, u8 data)
+{
+	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE));
+
+	ppc6_wr_data_byte(ppc, data);
+}
+
+//***************************************************************************
+
+static u8 ppc6_rd_reg(PPC *ppc, u8 reg)
+{
+	ppc6_send_cmd(ppc,(u8)(reg | ACCESS_REG | ACCESS_READ));
+
+	return(ppc6_rd_data_byte(ppc));
+}
+
+//***************************************************************************
+
+static void ppc6_wr_reg(PPC *ppc, u8 reg, u8 data)
+{
+	ppc6_send_cmd(ppc,(u8)(reg | ACCESS_REG | ACCESS_WRITE));
+
+	ppc6_wr_data_byte(ppc, data);
+}
+
+//***************************************************************************
+
+static u8 ppc6_version(PPC *ppc)
+{
+	ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_READ));
+
+	return(ppc6_rd_data_byte(ppc) & 0x3F);
+}
+
+//***************************************************************************
+
+static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count)
+{
+	switch(ppc->mode)
+	{
+		case PPCMODE_UNI_SW :
+		case PPCMODE_UNI_FW :
+		{
+			while(count)
+			{
+				u8 d;
+
+				ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
+
+				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+				// DELAY
+
+				d = inb(ppc->lpt_addr + 1);
+
+				d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
+
+				ppc->cur_ctrl |= port_stb;
+
+				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+				// DELAY
+
+				d |= inb(ppc->lpt_addr + 1) & 0xB8;
+
+				*data++ = d;
+				count--;
+			}
+
+			break;
+		}
+
+		case PPCMODE_BI_SW :
+		case PPCMODE_BI_FW :
+		{
+			ppc->cur_ctrl |= port_dir;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			ppc->cur_ctrl |= port_stb;
+
+			while(count)
+			{
+				ppc->cur_ctrl ^= data_stb;
+
+				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+				*data++ = inb(ppc->lpt_addr);
+				count--;
+			}
+
+			ppc->cur_ctrl &= ~port_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			ppc->cur_ctrl &= ~port_dir;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+
+		case PPCMODE_EPP_BYTE :
+		{
+			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
+
+			// DELAY
+
+			while(count)
+			{
+				*data++ = inb(ppc->lpt_addr + 4);
+				count--;
+			}
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+
+		case PPCMODE_EPP_WORD :
+		{
+			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
+
+			// DELAY
+
+			while(count > 1)
+			{
+				*((u16 *)data) = inw(ppc->lpt_addr + 4);
+				data  += 2;
+				count -= 2;
+			}
+
+			while(count)
+			{
+				*data++ = inb(ppc->lpt_addr + 4);
+				count--;
+			}
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+
+		case PPCMODE_EPP_DWORD :
+		{
+			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
+
+			// DELAY
+
+			while(count > 3)
+			{
+				*((u32 *)data) = inl(ppc->lpt_addr + 4);
+				data  += 4;
+				count -= 4;
+			}
+
+			while(count)
+			{
+				*data++ = inb(ppc->lpt_addr + 4);
+				count--;
+			}
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			break;
+		}
+	}
+
+}
+
+//***************************************************************************
+
+static void ppc6_wait_for_fifo(PPC *ppc)
+{
+	int i;
+
+	if (ppc->ppc_flags & fifo_wait)
+	{
+		for(i=0; i<20; i++)
+			inb(ppc->lpt_addr + 1);
+	}
+}
+
+//***************************************************************************
+
+static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count)
+{
+	switch(ppc->mode)
+	{
+		case PPCMODE_UNI_SW :
+		case PPCMODE_BI_SW :
+		{
+			while(count--)
+			{
+				outb(*data++, ppc->lpt_addr);
+
+				ppc->cur_ctrl ^= data_stb;
+
+				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+			}
+
+			break;
+		}
+
+		case PPCMODE_UNI_FW :
+		case PPCMODE_BI_FW :
+		{
+			u8 this, last;
+
+			ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR));
+
+			ppc->cur_ctrl |= port_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			last = *data;
+
+			outb(last, ppc->lpt_addr);
+
+			while(count)
+			{
+				this = *data++;
+				count--;
+
+				if (this == last)
+				{
+					ppc->cur_ctrl ^= data_stb;
+
+					outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+				}
+				else
+				{
+					outb(this, ppc->lpt_addr);
+
+					last = this;
+				}
+			}
+
+			ppc->cur_ctrl &= ~port_stb;
+
+			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
+
+			ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR));
+
+			break;
+		}
+
+		case PPCMODE_EPP_BYTE :
+		{
+			while(count)
+			{
+				outb(*data++,ppc->lpt_addr + 4);
+				count--;
+			}
+
+			ppc6_wait_for_fifo(ppc);
+
+			break;
+		}
+
+		case PPCMODE_EPP_WORD :
+		{
+			while(count > 1)
+			{
+				outw(*((u16 *)data),ppc->lpt_addr + 4);
+				data  += 2;
+				count -= 2;
+			}
+
+			while(count)
+			{
+				outb(*data++,ppc->lpt_addr + 4);
+				count--;
+			}
+
+			ppc6_wait_for_fifo(ppc);
+
+			break;
+		}
+
+		case PPCMODE_EPP_DWORD :
+		{
+			while(count > 3)
+			{
+				outl(*((u32 *)data),ppc->lpt_addr + 4);
+				data  += 4;
+				count -= 4;
+			}
+
+			while(count)
+			{
+				outb(*data++,ppc->lpt_addr + 4);
+				count--;
+			}
+
+			ppc6_wait_for_fifo(ppc);
+
+			break;
+		}
+	}
+}
+
+//***************************************************************************
+
+static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length)
+{
+	length = length << 1;
+
+	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
+	ppc6_wr_data_byte(ppc,(u8)length);
+	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
+	ppc6_wr_data_byte(ppc,0);
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
+
+	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
+
+	ppc6_rd_data_blk(ppc, data, length);
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
+}
+
+//***************************************************************************
+
+static u16 ppc6_rd_port16(PPC *ppc, u8 port)
+{
+	u16 data;
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16));
+
+	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
+
+	data = ppc6_rd_data_byte(ppc);
+
+	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
+
+	data += (u16)ppc6_rd_data_byte(ppc) << 8;
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16));
+
+	return(data);
+}
+
+//***************************************************************************
+
+static void ppc6_wr_port16(PPC *ppc, u8 port, u16 data)
+{
+	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16));
+
+	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
+
+	ppc6_wr_data_byte(ppc, (u8)data);
+
+	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
+
+	ppc6_wr_data_byte(ppc, (u8)(data >> 8));
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16));
+}
+
+//***************************************************************************
+
+static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length)
+{
+	length = length << 1;
+
+	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
+	ppc6_wr_data_byte(ppc,(u8)length);
+	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
+	ppc6_wr_data_byte(ppc,0);
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
+
+	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
+
+	ppc6_wr_data_blk(ppc, data, length);
+
+	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
+}
+
+//***************************************************************************
+
+static u8 ppc6_rd_eeprom_reg(PPC *ppc)
+{
+	ppc6_send_cmd(ppc, (REG_EEPROM | ACCESS_REG | ACCESS_READ));
+
+	return(ppc6_rd_data_byte(ppc));
+}
+
+//***************************************************************************
+
+static void ppc6_wr_eeprom_reg(PPC *ppc, u8 data)
+{
+	ppc6_send_cmd(ppc, (REG_EEPROM | ACCESS_REG | ACCESS_WRITE));
+
+	ppc6_wr_data_byte(ppc, data);
+}
+
+//***************************************************************************
+
+static void ppc6_eeprom_start(PPC *ppc)
+{
+	ppc6_wr_eeprom_reg(ppc, EEPROM_EN);
+}
+
+//***************************************************************************
+
+static void ppc6_eeprom_end(PPC *ppc)
+{
+	ppc6_wr_eeprom_reg(ppc, 0);
+}
+
+//***************************************************************************
+
+static void ppc6_set_cs(PPC *ppc)
+{
+	ppc6_wr_eeprom_reg(ppc, (u8)(ppc6_rd_eeprom_reg(ppc) | EEPROM_CS));
+}
+
+//***************************************************************************
+
+static void ppc6_reset_cs(PPC *ppc)
+{
+	ppc6_wr_eeprom_reg(ppc, (u8)(ppc6_rd_eeprom_reg(ppc) & ~EEPROM_CS));
+}
+
+//***************************************************************************
+
+static u8 ppc6_rd_eeprom_bit(PPC *ppc)
+{
+	ppc6_send_cmd(ppc, (REG_STATUS | ACCESS_REG | ACCESS_READ));
+
+	if (ppc6_rd_data_byte(ppc) & STATUS_EEPROM_DO)
+		return(1);
+	else
+		return(0);
+}
+
+//***************************************************************************
+
+static void ppc6_eeprom_ready_wait(PPC *ppc)
+{
+	ppc6_set_cs(ppc);
+
+	while(ppc6_rd_eeprom_bit(ppc));
+
+	ppc6_reset_cs(ppc);
+}
+
+//***************************************************************************
+
+static void ppc6_wr_eeprom_bit(PPC *ppc, u8 bit)
+{
+	u8 eereg;
+
+	eereg = ppc6_rd_eeprom_reg(ppc);
+
+	eereg &= ~(EEPROM_SK | EEPROM_DI);
+
+	if (bit & 1)
+		eereg |= EEPROM_DI;
+
+	ppc6_wr_eeprom_reg(ppc, eereg);
+
+	eereg |= EEPROM_SK;
+
+	ppc6_wr_eeprom_reg(ppc, eereg);
+
+	eereg &= ~EEPROM_SK;
+
+	ppc6_wr_eeprom_reg(ppc, eereg);
+}
+
+//***************************************************************************
+
+static u16 ppc6_eeprom_read(PPC *ppc, u8 addr)
+{
+	int i;
+	u16 data;
+
+	ppc6_set_cs(ppc);
+
+	ppc6_wr_eeprom_bit(ppc, 1); // Start bit
+
+	ppc6_wr_eeprom_bit(ppc, 1); // opcode 10 (read)
+	ppc6_wr_eeprom_bit(ppc, 0);
+
+	for(i=0; i<6; i++)
+		ppc6_wr_eeprom_bit(ppc, (u8)((addr >> (5 - i)) & 1));
+
+	data = 0;
+
+	for(i=0; i<16; i++)
+	{
+		ppc6_wr_eeprom_bit(ppc,0);
+
+		data = (data << 1) | ppc6_rd_eeprom_bit(ppc);
+	}
+
+	ppc6_reset_cs(ppc);
+
+	return(data);
+}
+
+//***************************************************************************
+
+static u8 ppc6_irq_test(PPC *ppc)
+{
+	ppc6_send_cmd(ppc,(REG_STATUS | ACCESS_REG | ACCESS_READ));
+
+	return(ppc6_rd_data_byte(ppc) & STATUS_IRQA);
+}
+
+//***************************************************************************
+
+static u8 ppc6_rd_extout(PPC *ppc)
+{
+	ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_READ));
+
+	return((ppc6_rd_data_byte(ppc) & 0xC0) >> 6);
+}
+
+//***************************************************************************
+
+static void ppc6_wr_extout(PPC *ppc, u8 regdata)
+{
+	ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE));
+
+	ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6));
+}
+
+//***************************************************************************
+
+static int ppc6_open(PPC *ppc)
+{
+	int ret;
+
+	ret = ppc6_select(ppc);
+
+	if (ret == 0)
+		return(ret);
+
+	ppc->ppc_flags &= ~fifo_wait;
+
+	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE));
+	ppc6_wr_data_byte(ppc, RAMSIZE_128K);
+
+	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION));
+
+	if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C)
+		ppc->ppc_flags |= fifo_wait;
+
+	return(ret);
+}
+
+//***************************************************************************
+
+static void ppc6_close(PPC *ppc)
+{
+	ppc6_deselect(ppc);
+}
+
+//***************************************************************************
+
diff -u --recursive --new-file v2.4.3/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.4.3/linux/drivers/block/ps2esdi.c	Thu Oct 26 23:35:47 2000
+++ linux/drivers/block/ps2esdi.c	Wed Apr 18 11:49:13 2001
@@ -52,6 +52,7 @@
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/dma.h>
+#include <asm/mca_dma.h>
 #include <asm/uaccess.h>
 
 #define PS2ESDI_IRQ 14
@@ -89,8 +90,6 @@
 static void ps2esdi_initial_reset_int_handler(u_int);
 static void ps2esdi_geometry_int_handler(u_int);
 
-static void ps2esdi_continue_request(void);
-
 static int ps2esdi_open(struct inode *inode, struct file *file);
 
 static int ps2esdi_release(struct inode *inode, struct file *file);
@@ -469,29 +468,26 @@
 	       DEVICE_NAME,
 	       CURRENT_DEV, MINOR(CURRENT->rq_dev),
 	       CURRENT->cmd, CURRENT->sector,
-	       CURRENT->nr_sectors, CURRENT->buffer);
+	       CURRENT->current_nr_sectors, CURRENT->buffer);
 #endif
 
 	/* standard macro that ensures that requests are really on the
 	   list + sanity checks.                     */
 	INIT_REQUEST;
 
-	if (virt_to_bus(CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) {
+	if (virt_to_bus(CURRENT->buffer + CURRENT->current_nr_sectors * 512) > 16 * MB) {
 		printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
 		end_request(FAIL);
-		if (!QUEUE_EMPTY)
-			do_ps2esdi_request(q);
-		return;
 	}			/* check for above 16Mb dmas */
-	if ((CURRENT_DEV < ps2esdi_drives) &&
-	    (CURRENT->sector + CURRENT->nr_sectors <=
+	else if ((CURRENT_DEV < ps2esdi_drives) &&
+	    (CURRENT->sector + CURRENT->current_nr_sectors <=
 	     ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects)) {
 #if 0
 		printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld\n",
 		       DEVICE_NAME,
-		       CURRENT_DEV, MINOR(CURRENT->dev),
+		       CURRENT_DEV, MINOR(CURRENT->rq_dev),
 		       CURRENT->cmd, CURRENT->sector,
-		       CURRENT->nr_sectors);
+		       CURRENT->current_nr_sectors);
 #endif
 
 
@@ -500,21 +496,17 @@
 #if 0
 		printk("%s: blocknumber : %d\n", DEVICE_NAME, block);
 #endif
-		count = CURRENT->nr_sectors;
+		count = CURRENT->current_nr_sectors;
 		switch (CURRENT->cmd) {
 		case READ:
 			ps2esdi_readwrite(READ, CURRENT_DEV, block, count);
-			return;
 			break;
 		case WRITE:
 			ps2esdi_readwrite(WRITE, CURRENT_DEV, block, count);
-			return;
 			break;
 		default:
 			printk("%s: Unknown command\n", DEVICE_NAME);
 			end_request(FAIL);
-			if (!QUEUE_EMPTY)
-				do_ps2esdi_request(q);
 			break;
 		}		/* handle different commands */
 	}
@@ -523,8 +515,6 @@
 		printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,
 		       CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);
 		end_request(FAIL);
-		if (!QUEUE_EMPTY)
-			do_ps2esdi_request(q);
 	}
 
 }				/* main strategy routine */
@@ -570,8 +560,6 @@
 	u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];
 
 	/* do some relevant arithmatic */
-	CURRENT->current_nr_sectors =
-	    (count < (2 * MAX_16BIT / SECT_SIZE)) ? count : (2 * MAX_16BIT / SECT_SIZE);
 	track = block / ps2esdi_info[drive].sect;
 	head = track % ps2esdi_info[drive].head;
 	cylinder = track / ps2esdi_info[drive].head;
@@ -590,13 +578,8 @@
 	/* send the command block to the controller */
 	if (ps2esdi_out_cmd_blk(cmd_blk)) {
 		printk("%s: Controller failed\n", DEVICE_NAME);
-		if ((++CURRENT->errors) < MAX_RETRIES)
-			return do_ps2esdi_request(NULL);
-		else {
+		if ((++CURRENT->errors) >= MAX_RETRIES)
 			end_request(FAIL);
-			if (!QUEUE_EMPTY)
-				do_ps2esdi_request(NULL);
-		}
 	}
 	/* check for failure to put out the command block */ 
 	else {
@@ -675,33 +658,23 @@
 /* prepare for dma - do all the necessary setup */
 static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode)
 {
-	u_int tc;
-	
-	buffer=(char *)virt_to_bus(buffer);
-
+	unsigned long flags;
 #if 0
-	printk("ps2esdi: b_wait: %p\n", CURRENT->bh->b_wait);
+	printk("ps2esdi: b_wait: %p\n", &CURRENT->bh->b_wait);
 #endif
-	cli();
+	flags = claim_dma_lock();
 
-	outb(dma_arb_level | DMA_MASK_CHAN, PORT_DMA_FN);
+	mca_disable_dma(dma_arb_level);
 
-	outb(dma_arb_level | DMA_WRITE_ADDR, PORT_DMA_FN);
-	outb((u_int) buffer & (u_int) 0xff, PORT_DMA_EX);
-	outb(((u_int) buffer >> 8) & (u_int) 0xff, PORT_DMA_EX);
-	outb(((u_int) buffer >> 16) & (u_int) 0xff, PORT_DMA_EX);
+	mca_set_dma_addr(dma_arb_level, virt_to_bus(buffer));
 
-	outb(dma_arb_level | DMA_WRITE_TC, PORT_DMA_FN);
-	tc = (length * SECT_SIZE / 2) - 1;
-	outb(tc & 0xff, PORT_DMA_EX);
-	outb((tc >> 8) & 0xff, PORT_DMA_EX);
+	mca_set_dma_count(dma_arb_level, length * 512 / 2);
 
-	outb(dma_arb_level | DMA_WRITE_MODE, PORT_DMA_FN);
-	outb(dma_xmode, PORT_DMA_EX);
+	mca_set_dma_mode(dma_arb_level, dma_xmode);
 
-	outb(dma_arb_level | DMA_UNMASK_CHAN, PORT_DMA_FN);
+	mca_enable_dma(dma_arb_level);
 
-	sti();
+	release_dma_lock(flags);
 
 }				/* prepare for dma */
 
@@ -871,20 +844,26 @@
 
 static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
 {
+	unsigned long flags;
 	u_int status;
+	u_int ending;
 	int i;
 
 	switch (int_ret_code & 0x0f) {
 	case INT_TRANSFER_REQ:
 		ps2esdi_prep_dma(CURRENT->buffer, CURRENT->current_nr_sectors,
-		    (CURRENT->cmd == READ) ? DMA_READ_16 : DMA_WRITE_16);
+		    (CURRENT->cmd == READ)
+		    ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER
+		    : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ);
 		outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL);
+		ending = -1;
 		break;
 
 	case INT_ATTN_ERROR:
 		printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
 		       int_ret_code);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
+		ending = FAIL;
 		break;
 
 	case INT_CMD_COMPLETE:
@@ -893,13 +872,10 @@
 			printk("%s: timeout reading status word\n", DEVICE_NAME);
 			outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 			outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
-			if ((++CURRENT->errors) < MAX_RETRIES)
-				do_ps2esdi_request(NULL);
-			else {
-				end_request(FAIL);
-				if (!QUEUE_EMPTY)
-					do_ps2esdi_request(NULL);
-			}
+			if ((++CURRENT->errors) >= MAX_RETRIES)
+				ending = FAIL;
+			else
+				ending = -1;
 			break;
 		}
 		status = inw(ESDI_STT_INT);
@@ -910,15 +886,16 @@
 			outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 			outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 #if 0
-			printk("ps2esdi: cmd_complete b_wait: %p\n", CURRENT->bh->b_wait);
+			printk("ps2esdi: cmd_complete b_wait: %p\n", &CURRENT->bh->b_wait);
 #endif
-			ps2esdi_continue_request();
+			ending = SUCCES;
 			break;
 		default:
 			printk("%s: interrupt for unknown command %02X\n",
 			       DEVICE_NAME, status & 0x1f);
 			outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 			outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
+			ending = -1;
 			break;
 		}
 		break;
@@ -929,7 +906,7 @@
 		dump_cmd_complete_status(int_ret_code);
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
-		ps2esdi_continue_request();
+		ending = SUCCES;
 		break;
 	case INT_CMD_WARNING:
 	case INT_CMD_ABORT:
@@ -939,22 +916,17 @@
 		dump_cmd_complete_status(int_ret_code);
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
-		if ((++CURRENT->errors) < MAX_RETRIES)
-			do_ps2esdi_request(NULL);
-		else {
-			end_request(FAIL);
-			if (!QUEUE_EMPTY)
-				do_ps2esdi_request(NULL);
-		}
+		if ((++CURRENT->errors) >= MAX_RETRIES)
+			ending = FAIL;
+		else
+			ending = -1;
 		break;
 
 	case INT_CMD_BLK_ERR:
 		dump_cmd_complete_status(int_ret_code);
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
-		end_request(FAIL);
-		if (!QUEUE_EMPTY)
-			do_ps2esdi_request(NULL);
+		ending = FAIL;
 		break;
 
 	case INT_CMD_FORMAT:
@@ -962,12 +934,14 @@
 		       ,DEVICE_NAME);
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
+		ending = -1;
 		break;
 
 	case INT_RESET:
 		/* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ;
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
+		ending = -1;
 		break;
 
 	default:
@@ -975,24 +949,16 @@
 		       DEVICE_NAME, int_ret_code & 0xf);
 		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 		outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
+		ending = -1;
 		break;
 	}
-
-}				/* handle interrupts */
-
-
-static void ps2esdi_continue_request(void)
-{
-	if (CURRENT->nr_sectors -= CURRENT->current_nr_sectors) {
-		CURRENT->buffer += CURRENT->current_nr_sectors * SECT_SIZE;
-		CURRENT->sector += CURRENT->current_nr_sectors;
-		do_ps2esdi_request(NULL);
-	} else {
-		end_request(SUCCES);
-		if (!QUEUE_EMPTY)
-			do_ps2esdi_request(NULL);
+	if(ending != -1) {
+		spin_lock_irqsave(io_request_lock, flags);
+		end_request(ending);
+		do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR));
+		spin_unlock_irqrestore(io_request_lock, flags);
 	}
-}
+}				/* handle interrupts */
 
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.4.3/linux/drivers/cdrom/sbpcd.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/cdrom/sbpcd.c	Fri Apr  6 10:42:55 2001
@@ -350,7 +350,7 @@
 
 #ifndef SBPCD_ISSUE
 #define SBPCD_ISSUE 1
-#endif SBPCD_ISSUE
+#endif /* SBPCD_ISSUE */
 
 #include <linux/module.h>
 
@@ -420,7 +420,7 @@
 #else
 #define SBPCD_CLI
 #define SBPCD_STI
-#endif SBPCD_DIS_IRQ
+#endif /* SBPCD_DIS_IRQ */
 /*==========================================================================*/
 /*
  * auto-probing address list
@@ -478,9 +478,9 @@
 	0x370, 0, /* Lasermate, CI-101P */
 	0x290, 1, /* Soundblaster 16 */
 	0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
-#endif MODULE
+#endif /* MODULE */
 #endif
-#endif DISTRIBUTION
+#endif /* DISTRIBUTION */
 };
 #else
 static int sbpcd[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */
@@ -570,7 +570,7 @@
 			  (1<<DBG_TOC) |
 			  (1<<DBG_MUL) |
 			  (1<<DBG_UPC));
-#endif DISTRIBUTION
+#endif /* DISTRIBUTION */
 
 static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
 static int sbpro_type = SBPRO;
@@ -622,7 +622,7 @@
 
 #if FUTURE
 static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq);
-#endif FUTURE
+#endif /* FUTURE */
 
 static int teac=SBP_TEAC_SPEED;
 static int buffers=SBP_BUFFER_FRAMES;
@@ -647,7 +647,7 @@
 #if OLD_BUSY
 static volatile u_char busy_data;
 static volatile u_char busy_audio; /* true semaphores would be safer */
-#endif OLD_BUSY
+#endif /* OLD_BUSY */ 
 static DECLARE_MUTEX(ioctl_read_sem);
 static u_long timeout;
 static volatile u_char timed_out_delay;
@@ -664,7 +664,7 @@
 static u_int maxtim_data= 9000;
 #else
 static u_int maxtim_data= 3000;
-#endif LONG_TIMING
+#endif /* LONG_TIMING */ 
 #if DISTRIBUTION
 static int n_retries=6;
 #else
@@ -729,7 +729,7 @@
 	u_char vol_ctrl2;
 	char vol_chan3;
 	u_char vol_ctrl3;
-#endif 000
+#endif /*000 */
 	u_char volume_control; /* TEAC on/off bits */
 	
 	u_char SubQ_ctl_adr;
@@ -758,7 +758,7 @@
 	u_int TocEnt_address;
 #if SAFE_MIXED
 	char has_data;
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 	u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
 	
 	struct {
@@ -808,7 +808,7 @@
 #define MSG_LEVEL KERN_NOTICE
 #else
 #define MSG_LEVEL KERN_INFO
-#endif DISTRIBUTION
+#endif /* DISTRIBUTION */
 
 	char buf[256];
 	va_list args;
@@ -824,7 +824,7 @@
 	printk(buf);
 #if KLOGD_PAUSE
 	sbp_sleep(KLOGD_PAUSE); /* else messages get lost */
-#endif KLOGD_PAUSE
+#endif /* KLOGD_PAUSE */ 
 	return;
 }
 /*==========================================================================*/
@@ -1148,7 +1148,7 @@
 	}
 	j=i-response_count;
 	if (j>0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j);
-#endif 000
+#endif /* 000 */
 	for (j=0;j<i;j++)
 		sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
 	msgbuf[j*3]=0;
@@ -1400,7 +1400,7 @@
 		if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */
 #if 01
 		OUT(CDo_sel_i_d,1);
-#endif 01
+#endif /* 01 */
 		if (teac==2)
                   {
                     if ((i=CDi_stat_loop_T()) == -1) break;
@@ -1409,7 +1409,7 @@
                   {
 #if 0
                     OUT(CDo_sel_i_d,1);
-#endif 0
+#endif /* 0 */ 
                     i=inb(CDi_status);
                   }
 		if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */
@@ -1433,7 +1433,7 @@
                                                         l=1;
                                                         msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n");
                                                 }
-#endif TEST_FALSE_FF
+#endif /* TEST_FALSE_FF */ 
                                         }
                                         else infobuf[l++]=inb(CDi_data);
                                         i=inb(CDi_status);
@@ -2028,7 +2028,7 @@
 		msg(DBG_TEA, "================CMDT_RESET given=================.\n");
 		sbp_sleep(3*HZ);
 	}
-#endif 1
+#endif /* 1 */ 
 	flush_status();
 	i=GetStatus();
 	if (i<0) return i;
@@ -2349,7 +2349,7 @@
 		i=ResponseStatus();
 #if 0
                 sbp_sleep(HZ);
-#endif 0
+#endif /* 0 */ 
 		i=ResponseStatus();
 	}
 	if (i<0)
@@ -2694,7 +2694,7 @@
 	D_S[d].vol_ctrl2=0xFF;
 	D_S[d].vol_chan3=3;
 	D_S[d].vol_ctrl3=0xFF;
-#endif 000
+#endif /*  000 */
 	D_S[d].diskstate_flags |= volume_bit;
 	return (0);
 }
@@ -2994,20 +2994,20 @@
 	int i;
 #if TEST_UPC
 	int block, checksum;
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 	
 	if (fam2_drive) return (0); /* not implemented yet */
 	if (famT_drive)	return (0); /* not implemented yet */
 	if (famV_drive)	return (0); /* not implemented yet */
 #if 1
 	if (fam0_drive) return (0); /* but it should work */
-#endif 1
+#endif
 	
 	D_S[d].diskstate_flags &= ~upc_bit;
 #if TEST_UPC
 	for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++)
 	{
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 		clr_cmdbuf();
 		if (fam1_drive)
 		{
@@ -3016,7 +3016,7 @@
 			drvcmd[1]=(block>>16)&0xFF;
 			drvcmd[2]=(block>>8)&0xFF;
 			drvcmd[3]=block&0xFF;
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 			response_count=8;
 			flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
 		}
@@ -3027,7 +3027,7 @@
 			drvcmd[2]=(block>>16)&0xFF;
 			drvcmd[3]=(block>>8)&0xFF;
 			drvcmd[4]=block&0xFF;
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 			response_count=0;
 			flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
 		}
@@ -3058,12 +3058,12 @@
 		}
 #if TEST_UPC
 		checksum=0;
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 		for (i=0;i<(fam1_drive?8:16);i++)
 		{
 #if TEST_UPC
 			checksum |= infobuf[i];
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 			sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
 		}
 		msgbuf[i*3]=0;
@@ -3071,7 +3071,7 @@
 #if TEST_UPC
 		if ((checksum&0x7F)!=0) break;
 	}
-#endif TEST_UPC
+#endif /* TEST_UPC */ 
 	D_S[d].UPC_ctl_adr=0;
 	if (fam1_drive) i=0;
 	else i=2;
@@ -3256,7 +3256,7 @@
 	i=cmd_out(); /* which buffer to use? */
 	return (i);
 }
-#endif FUTURE
+#endif /* FUTURE */ 
 /*==========================================================================*/
 static void __init check_datarate(void)
 {
@@ -3283,7 +3283,7 @@
 		datarate++;
 #if 1
 		if (datarate>0x6FFFFFFF) break;
-#endif 00000
+#endif 
 	}
 	while (!timed_out_delay);
 	del_timer(&delay_timer);
@@ -3299,7 +3299,7 @@
 	maxtim_data=datarate/100;
 #else
 	maxtim_data=datarate/300;
-#endif LONG_TIMING
+#endif /* LONG_TIMING */ 
 #if 0
 	msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data);
 #endif
@@ -3453,7 +3453,7 @@
 		OUT(CDo_reset,0);
 		sbp_sleep(6*HZ);
 		OUT(CDo_enable,D_S[d].drv_sel);
-#endif 0
+#endif
 		drvcmd[0]=CMD2_READ_VER;
 		response_count=12;
 		flags_cmd_out=f_putcmd;
@@ -3743,7 +3743,7 @@
 	OUT(port+3,save_port3);
 	return (0); /* in any case - no real "function" at time */
 }
-#endif PATH_CHECK
+#endif /* PATH_CHECK */ 
 /*==========================================================================*/
 /*==========================================================================*/
 /*
@@ -3850,7 +3850,7 @@
 	if (func2==tell_UPC) return (-1);
 #else
 	return (0);
-#endif 000
+#endif
 }
 /*==========================================================================*/
 static int check_allowed2(u_char func1, u_char func2)
@@ -3868,7 +3868,7 @@
 	}
 #else
 	return (0);
-#endif 000
+#endif
 }
 /*==========================================================================*/
 static int check_allowed3(u_char func1, u_char func2)
@@ -3902,7 +3902,7 @@
 	if (func1==audio_resume) return (-1);
 #else
 	return (0);
-#endif 000
+#endif
 }
 /*==========================================================================*/
 static int seek_pos_audio_end(void)
@@ -3914,7 +3914,7 @@
 	i=cc_Seek(i,0);
 	return (i);
 }
-#endif FUTURE
+#endif /* FUTURE */ 
 /*==========================================================================*/
 static int ReadToC(void)
 {
@@ -4152,7 +4152,7 @@
     }
 	return (0);
 }
-#endif FUTURE
+#endif /* FUTURE */ 
 /*==========================================================================*/
 /*==========================================================================*/
 /*
@@ -4250,7 +4250,7 @@
 		msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */
 		cc_ModeSelect(CD_FRAMESIZE);
 		cc_ModeSense();
 		D_S[d].mode=READ_M1;
@@ -4260,7 +4260,7 @@
 		msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */
 		cc_ModeSelect(CD_FRAMESIZE_RAW1);
 		cc_ModeSense();
 		D_S[d].mode=READ_M2;
@@ -4303,7 +4303,7 @@
 		if (famT_drive) RETURN_UP(-EINVAL);
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 		if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL);
 		i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
 		if (i) RETURN_UP(i);
@@ -4328,7 +4328,7 @@
 #if OLD_BUSY
 		while (busy_data) sbp_sleep(HZ/10); /* wait a bit */
 		busy_audio=1;
-#endif OLD_BUSY
+#endif /* OLD_BUSY */ 
 		error_flag=0;
 		for (data_tries=5; data_tries>0; data_tries--)
 		{
@@ -4460,7 +4460,7 @@
 				i=cc_DriveReset();                /* ugly fix to prevent a hang */
 #else
 				i=cc_ReadError();
-#endif 0000
+#endif
 				continue;
 			}
 			if (fam0L_drive)
@@ -4515,7 +4515,7 @@
 		D_S[d].mode=READ_M1;
 #if OLD_BUSY
 		busy_audio=0;
-#endif OLD_BUSY
+#endif /* OLD_BUSY */ 
 		if (data_tries == 0)
 		{
 			msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__);
@@ -4601,7 +4601,7 @@
 		msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 		if (D_S[d].audio_state==audio_playing)
 		{
 			i=cc_Pause_Resume(1);
@@ -4636,7 +4636,7 @@
 		msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 		if (D_S[d].audio_state==audio_playing)
 		{
 			msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
@@ -4699,7 +4699,7 @@
 		msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 		i=cc_Pause_Resume(1);
 		D_S[d].audio_state=0;
 #if 0
@@ -4942,7 +4942,7 @@
 #if OLD_BUSY
 	while (busy_audio) sbp_sleep(HZ); /* wait a bit */
 	busy_data=1;
-#endif OLD_BUSY
+#endif /* OLD_BUSY */
 	
 	if (D_S[i].audio_state==audio_playing) goto err_done;
 	if (d!=i) switch_drive(i);
@@ -4973,7 +4973,7 @@
 	i=prepare(0,0); /* at moment not really a hassle check, but ... */
 	if (i!=0)
 		msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i);
-#endif FUTURE
+#endif /* FUTURE */ 
 	
 	if (!st_spinning) cc_SpinUp();
 	
@@ -4999,7 +4999,7 @@
 		{
 #if SAFE_MIXED
 			D_S[d].has_data=2; /* is really a data disk */
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 #ifdef DEBUG_GTL
 			printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n",
 				xnr, req, req->sector, req->nr_sectors, jiffies);
@@ -5014,7 +5014,7 @@
  err_done:
 #if OLD_BUSY
 	busy_data=0;
-#endif OLD_BUSY
+#endif /* OLD_BUSY */
 #ifdef DEBUG_GTL
 	printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n",
 		xnr, req, req->sector, req->nr_sectors, jiffies);
@@ -5373,17 +5373,17 @@
 	
 #if 0
 	if (!success)
-#endif 0
+#endif
 		do
 		{
 			if (fam0LV_drive) cc_ReadStatus();
 #if 1
 			if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i);
-#endif 1
+#endif
 			i=ResponseStatus();  /* builds status_bits, returns orig. status (old) or faked p_success (new) */
 #if 1
 			if (famT_drive)	msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i);
-#endif 1
+#endif
 			if (i<0)
 			{
 				msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", D_S[d].status_bits);
@@ -5443,11 +5443,11 @@
 			msg(DBG_INF,"CD contains no data tracks.\n");
 #if SAFE_MIXED
 			D_S[d].has_data=0;
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */
 		}
 #if SAFE_MIXED
 		else if (D_S[d].has_data<1) D_S[d].has_data=1;
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 	}
 	if (!st_spinning) cc_SpinUp();
 	RETURN_UP(0);
@@ -5485,7 +5485,7 @@
 			D_S[d].open_count=0; 
 #if SAFE_MIXED
 			D_S[d].has_data=0;
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 		}
 	}
 	up(&ioctl_read_sem);
@@ -5697,7 +5697,7 @@
 int __init __SBPCD_INIT(void)
 #else
 int __init SBPCD_INIT(void)
-#endif MODULE
+#endif /* MODULE */ 
 {
 	char nbuff[16];
 	int i=0, j=0;
@@ -5724,10 +5724,10 @@
 		msg(DBG_INF,"with your REAL address.\n");
 		msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n");
 	}
-#endif DISTRIBUTION
+#endif /* DISTRIBUTION */
 	sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
 	sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */
-#endif MODULE
+#endif /* MODULE */
 	
 	for (port_index=0;port_index<NUM_PROBE;port_index+=2)
 	{
@@ -5745,7 +5745,7 @@
 		sbpcd_setup((char *)type);
 #if DISTRIBUTION
 		msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type);
-#endif DISTRIBUTION
+#endif /* DISTRIBUTION */
 		if (sbpcd[port_index+1]==2)
 		{
 			i=config_spea();
@@ -5753,7 +5753,7 @@
 		}
 #ifdef PATH_CHECK
 		if (check_card(addr[1])) continue;
-#endif PATH_CHECK
+#endif /* PATH_CHECK */ 
 		i=check_drives();
 		msg(DBG_INI,"check_drives done.\n");
 		if (i>=0) break; /* drive found */
@@ -5766,7 +5766,7 @@
 		return -EIO;
 #else
 		goto init_done;
-#endif MODULE
+#endif /* MODULE */
 	}
 	
 	if (port_index>0)
@@ -5783,7 +5783,7 @@
 		switch_drive(j);
 #if 1
 		if (!famL_drive) cc_DriveReset();
-#endif 0
+#endif
 		if (!st_spinning) cc_SpinUp();
 		D_S[j].sbp_first_frame = -1;  /* First frame in buffer */
 		D_S[j].sbp_last_frame = -1;   /* Last frame in buffer  */
@@ -5794,7 +5794,7 @@
 		D_S[j].f_eject=0;
 #if EJECT
 		if (!fam0_drive) D_S[j].f_eject=1;
-#endif EJECT
+#endif /* EJECT */ 
 		cc_ReadStatus();
 		i=ResponseStatus();  /* returns orig. status or p_busy_new */
 		if (famT_drive) i=ResponseStatus();  /* returns orig. status or p_busy_new */
@@ -5840,7 +5840,7 @@
 #if SOUND_BASE
 	OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */
 	OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */
-#endif SOUND_BASE
+#endif /* SOUND_BASE */ 
 	
 	if (devfs_register_blkdev(MAJOR_NR, major_name, &cdrom_fops) != 0)
 	{
@@ -5849,7 +5849,7 @@
 		return -EIO;
 #else
 		goto init_done;
-#endif MODULE
+#endif /* MODULE */
 	}
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 #ifdef DONT_MERGE_REQUESTS
@@ -5871,7 +5871,7 @@
 		switch_drive(j);
 #if SAFE_MIXED
 		D_S[j].has_data=0;
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 		/*
 		 * allocate memory for the frame buffers
 		 */
@@ -5894,7 +5894,7 @@
 		}
 #ifdef MODULE
 		msg(DBG_INF,"data buffer size: %d frames.\n",buffers);
-#endif MODULE
+#endif /* MODULE */
 		if (D_S[j].sbp_audsiz>0)
 		{
 			D_S[j].aud_buf=(u_char *) vmalloc(D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW);
@@ -5934,15 +5934,15 @@
 #if !(SBPCD_ISSUE-1)
 #ifdef CONFIG_SBPCD2
 	sbpcd2_init();
-#endif CONFIG_SBPCD2
+#endif /* CONFIG_SBPCD2 */
 #ifdef CONFIG_SBPCD3
 	sbpcd3_init();
-#endif CONFIG_SBPCD3
+#endif /* CONFIG_SBPCD3 */ 
 #ifdef CONFIG_SBPCD4
 	sbpcd4_init();
-#endif CONFIG_SBPCD4
-#endif !(SBPCD_ISSUE-1)
-#endif MODULE
+#endif /* CONFIG_SBPCD4 */ 
+#endif /* !(SBPCD_ISSUE-1) */ 
+#endif /* MODULE */
 	return 0;
 }
 /*==========================================================================*/
@@ -5981,7 +5981,7 @@
 module_exit(sbpcd_exit);
 
 
-#endif MODULE
+#endif /* MODULE */ 
 /*==========================================================================*/
 /*
  * Check if the media has changed in the CD-ROM drive.
@@ -6004,7 +6004,7 @@
 		D_S[d].diskstate_flags &= ~cd_size_bit;
 #if SAFE_MIXED
 		D_S[d].has_data=0;
-#endif SAFE_MIXED
+#endif /* SAFE_MIXED */ 
 
                 return (1);
         }
diff -u --recursive --new-file v2.4.3/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.4.3/linux/drivers/char/Makefile	Tue Mar  6 19:44:34 2001
+++ linux/drivers/char/Makefile	Fri Apr 13 20:31:32 2001
@@ -68,6 +68,23 @@
   KEYBD    = scan_keyb.o hp600_keyb.o
   CONSOLE  = console.o
   endif
+  ifeq ($(CONFIG_SH_DMIDA),y)
+  # DMIDA does not connect the HD64465 PS/2 keyboard port
+  # but we allow for USB keyboards to be plugged in.
+  KEYMAP   = defkeymap.o
+  KEYBD    = # hd64465_keyb.o pc_keyb.o
+  CONSOLE  = console.o
+  endif
+  ifeq ($(CONFIG_SH_EC3104),y)
+  KEYMAP   = defkeymap.o
+  KEYBD    = ec3104_keyb.o
+  CONSOLE  = console.o
+  endif
+  ifeq ($(CONFIG_SH_DREAMCAST),y)
+  KEYMAP   = defkeymap.o
+  KEYBD    =
+  CONSOLE  = console.o
+  endif
 endif
 
 ifeq ($(CONFIG_DECSTATION),y)
diff -u --recursive --new-file v2.4.3/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.4.3/linux/drivers/char/agp/agpgart_fe.c	Tue Mar  6 19:28:32 2001
+++ linux/drivers/char/agp/agpgart_fe.c	Wed Apr 11 19:02:30 2001
@@ -879,7 +879,7 @@
 			return -ENOMEM;
 		}
 		if (copy_from_user(segment, (void *) reserve.seg_list,
-				   GFP_KERNEL)) {
+				   sizeof(agp_segment) * reserve.seg_count)) {
 			kfree(segment);
 			return -EFAULT;
 		}
diff -u --recursive --new-file v2.4.3/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.4.3/linux/drivers/char/cyclades.c	Wed Nov 15 00:41:03 2000
+++ linux/drivers/char/cyclades.c	Fri Apr  6 10:42:55 2001
@@ -209,7 +209,7 @@
  * board type.
  *  
  * Revision 1.36.4.30  1997/05/16 15:30:00  daniel
- * Changes to suport new cycladesZ boards.
+ * Changes to support new cycladesZ boards.
  *
  * Revision 1.36.4.29  1997/05/12 11:30:00  daniel
  * Merge of Bentson's and Daniel's version 1.36.4.28.
@@ -241,7 +241,7 @@
  * varying too fast.
  *
  * Revision 1.36.4.27  1997/03/26 10:30:00  daniel
- * Changed for suport linux versions 2.1.X.
+ * Changed for support linux versions 2.1.X.
  * Backward compatible with linux versions 2.0.X.
  * Corrected illegal use of filler field in
  * CH_CTRL struct.
@@ -676,14 +676,6 @@
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
-
-#ifdef CONFIG_COBALT_27
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#define	CACHED_TO_UNCACHED(x)	(((unsigned long)(x) & \
-				  (unsigned long)0x1fffffff) + KSEG1)
-#endif
 
 #define cy_put_user	put_user
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c
--- v2.4.3/linux/drivers/char/drm/ffb_drv.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/char/drm/ffb_drv.c	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.9 2001/03/23 07:58:39 davem Exp $
+/* $Id: ffb_drv.c,v 1.12 2001/04/14 01:12:03 davem Exp $
  * ffb_drv.c: Creator/Creator3D direct rendering driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -6,8 +6,10 @@
 
 #include "drmP.h"
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
+#include <asm/shmparam.h>
 #include <asm/oplib.h>
 #include <asm/upa.h>
 
@@ -34,6 +36,7 @@
 static int  ffb_unlock(struct inode *inode, struct file *filp,
 		       unsigned int cmd, unsigned long arg);
 static int ffb_mmap(struct file *filp, struct vm_area_struct *vma);
+static unsigned long ffb_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
 /* From ffb_context.c */
 extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long);
@@ -46,15 +49,16 @@
 extern int ffb_context_switch(drm_device_t *, int, int);
 
 static struct file_operations ffb_fops = {
-	owner:		THIS_MODULE,
-	open:		ffb_open,
-	flush:		drm_flush,
-	release:	ffb_release,
-	ioctl:		ffb_ioctl,
-	mmap:		ffb_mmap,
-	read:		drm_read,
-	fasync:		drm_fasync,
-	poll:		drm_poll,
+	owner:			THIS_MODULE,
+	open:			ffb_open,
+	flush:			drm_flush,
+	release:		ffb_release,
+	ioctl:			ffb_ioctl,
+	mmap:			ffb_mmap,
+	read:			drm_read,
+	fasync:			drm_fasync,
+	poll:			drm_poll,
+	get_unmapped_area:	ffb_get_unmapped_area,
 };
 
 /* This is just a template, we make a new copy for each FFB
@@ -770,45 +774,6 @@
 	return 0;
 }
 
-static void align_fb_mapping(struct vm_area_struct *vma)
-{
-	unsigned long j, alignment;
-
-	j = vma->vm_end - vma->vm_start;
-	for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3)
-		if (j >= alignment)
-			break;
-	if (alignment > PAGE_SIZE) {
-		j = alignment;
-		alignment = j - (vma->vm_start & (j - 1));
-		if (alignment != j) {
-			struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start);
-
-			if (!vmm || vmm->vm_start >= vma->vm_end + alignment) {
-				vma->vm_start += alignment;
-				vma->vm_end += alignment;
-			}
-		}
-	}
-}
-
-/* The problem here is, due to virtual cache aliasing,
- * we must make sure the shared memory area lands in the
- * same dcache line for both the kernel and all drm clients.
- */
-static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt)
-{
-	kvirt &= PAGE_SIZE;
-	if ((vma->vm_start & PAGE_SIZE) != kvirt) {
-		struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
-
-		if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) {
-			vma->vm_start += PAGE_SIZE;
-			vma->vm_end += PAGE_SIZE;
-		}
-	}
-}
-
 extern struct vm_operations_struct drm_vm_ops;
 extern struct vm_operations_struct drm_vm_shm_ops;
 extern struct vm_operations_struct drm_vm_shm_lock_ops;
@@ -868,7 +833,6 @@
 
 	switch (map->type) {
 	case _DRM_FRAME_BUFFER:
-		align_fb_mapping(vma);
 		/* FALLTHROUGH */
 
 	case _DRM_REGISTERS:
@@ -887,7 +851,6 @@
 		vma->vm_ops = &drm_vm_ops;
 		break;
 	case _DRM_SHM:
-		align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock);
 		if (map->flags & _DRM_CONTAINS_LOCK)
 			vma->vm_ops = &drm_vm_shm_lock_ops;
 		else {
@@ -909,6 +872,69 @@
 	vma->vm_file = filp; /* Needed for drm_vm_open() */
 	drm_vm_open(vma);
 	return 0;
+}
+
+static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev;
+	drm_map_t	*map;
+	int		i;
+
+	if (!priv || (dev = priv->dev) == NULL)
+		return NULL;
+
+	for (i = 0; i < dev->map_count; i++) {
+		unsigned long uoff;
+
+		map = dev->maplist[i];
+
+		/* Ok, a little hack to make 32-bit apps work. */
+		uoff = (map->offset & 0xffffffff);
+		if (uoff == off)
+			return map;
+	}
+	return NULL;
+}
+
+static unsigned long ffb_get_unmapped_area(struct file *filp, unsigned long hint, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT);
+	unsigned long addr = -ENOMEM;
+
+	if (!map)
+		return get_unmapped_area(NULL, hint, len, pgoff, flags);
+
+	if (map->type == _DRM_FRAME_BUFFER ||
+	    map->type == _DRM_REGISTERS) {
+#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
+		addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags);
+#else
+		addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
+#endif
+	} else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) {
+		unsigned long slack = SHMLBA - PAGE_SIZE;
+
+		addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags);
+		if (!(addr & ~PAGE_MASK)) {
+			unsigned long kvirt = (unsigned long) map->handle;
+
+			if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+				unsigned long koff, aoff;
+
+				koff = kvirt & (SHMLBA - 1);
+				aoff = addr & (SHMLBA - 1);
+				if (koff < aoff)
+					koff += SHMLBA;
+
+				addr += (koff - aoff);
+			}
+		}
+	} else {
+		addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
+	}
+
+	return addr;
 }
 
 module_init(ffb_init);
diff -u --recursive --new-file v2.4.3/linux/drivers/char/ec3104_keyb.c linux/drivers/char/ec3104_keyb.c
--- v2.4.3/linux/drivers/char/ec3104_keyb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ec3104_keyb.c	Fri Apr 13 20:31:32 2001
@@ -0,0 +1,461 @@
+/*
+ * linux/drivers/char/ec3104_keyb.c
+ * 
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ * based on linux/drivers/char/pc_keyb.c, which had the following comments:
+ *
+ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ * See keyboard.c for the whole history.
+ *
+ * Major cleanup by Martin Mares, May 1997
+ *
+ * Combined the keyboard and PS/2 mouse handling into one file,
+ * because they share the same hardware.
+ * Johan Myreen <jem@iki.fi> 1998-10-08.
+ *
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip.  While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+#include <linux/config.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/kbd_kern.h>
+#include <linux/smp_lock.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/ec3104.h>
+
+#include <asm/io.h>
+
+/* Some configuration switches are present in the include file... */
+
+#include <linux/pc_keyb.h>
+
+#define MSR_CTS 0x10
+#define MCR_RTS 0x02
+#define LSR_DR 0x01
+#define LSR_BOTH_EMPTY 0x60
+
+static struct e5_struct {
+	u8 packet[8];
+	int pos;
+	int length;
+
+	u8 cached_mcr;
+	u8 last_msr;
+} ec3104_keyb;
+	
+/* Simple translation table for the SysRq keys */
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char ec3104_kbd_sysrq_xlate[128] =
+	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
+	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
+	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
+	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
+	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
+	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+	"\r\000/";					/* 0x60 - 0x6f */
+#endif
+
+static void kbd_write_command_w(int data);
+static void kbd_write_output_w(int data);
+#ifdef CONFIG_PSMOUSE
+static void aux_write_ack(int val);
+static void __aux_write_ack(int val);
+#endif
+
+static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned char handle_kbd_event(void);
+
+/* used only by send_data - set by keyboard_interrupt */
+static volatile unsigned char reply_expected;
+static volatile unsigned char acknowledge;
+static volatile unsigned char resend;
+
+
+int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return 0;
+}
+
+int ec3104_kbd_getkeycode(unsigned int scancode)
+{
+	return 0;
+}
+
+
+/* yes, it probably would be faster to use an array.  I don't care. */
+
+static inline unsigned char ec3104_scan2key(unsigned char scancode)
+{
+	switch (scancode) {
+	case  1: /* '`' */
+		return 41;
+		
+	case  2 ... 27:
+		return scancode;
+		
+	case 28: /* '\\' */
+		return 43;
+
+	case 29 ... 39:
+		return scancode + 1;
+
+	case 40: /* '\r' */
+		return 28;
+
+	case 41 ... 50:
+		return scancode + 3;
+
+	case 51: /* ' ' */
+		return 57;
+		
+	case 52: /* escape */
+		return 1;
+
+	case 54: /* insert/delete (labelled delete) */
+		/* this should arguably be 110, but I'd like to have ctrl-alt-del
+		 * working with a standard keymap */
+		return 111;
+
+	case 55: /* left */
+		return 105;
+	case 56: /* home */
+		return 102;
+	case 57: /* end */
+		return 107;
+	case 58: /* up */
+		return 103;
+	case 59: /* down */
+		return 108;
+	case 60: /* pgup */
+		return 104;
+	case 61: /* pgdown */
+		return 109;
+	case 62: /* right */
+		return 106;
+
+	case 79 ... 88: /* f1 - f10 */
+		return scancode - 20;
+
+	case 89 ... 90: /* f11 - f12 */
+		return scancode - 2;
+
+	case 91: /* left shift */
+		return 42;
+
+	case 92: /* right shift */
+		return 54;
+
+	case 93: /* left alt */
+		return 56;
+	case 94: /* right alt */
+		return 100;
+	case 95: /* left ctrl */
+		return 29;
+	case 96: /* right ctrl */
+		return 97;
+
+	case 97: /* caps lock */
+		return 58;
+	case 102: /* left windows */
+		return 125;
+	case 103: /* right windows */
+		return 126;
+
+	case 106: /* Fn */
+		/* this is wrong. */
+		return 84;
+
+	default:
+		return 0;
+	}
+}
+		
+int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode)
+{
+	scancode &= 0x7f;
+
+	*keycode = ec3104_scan2key(scancode);
+
+ 	return 1;
+}
+
+char ec3104_kbd_unexpected_up(unsigned char keycode)
+{
+	return 0200;
+}
+
+static inline void handle_keyboard_event(unsigned char scancode)
+{
+#ifdef CONFIG_VT
+	handle_scancode(scancode, !(scancode & 0x80));
+#endif				
+	tasklet_schedule(&keyboard_tasklet);
+}	
+
+void ec3104_kbd_leds(unsigned char leds)
+{
+}
+
+static u8 e5_checksum(u8 *packet, int count)
+{
+	int i;
+	u8 sum = 0;
+
+	for (i=0; i<count; i++)
+		sum ^= packet[i];
+		
+	if (sum & 0x80)
+		sum ^= 0xc0;
+
+	return sum;
+}
+
+static void e5_wait_for_cts(struct e5_struct *k)
+{
+	u8 msr;
+		
+	do {
+		msr = ctrl_inb(EC3104_SER4_MSR);
+	} while (!(msr & MSR_CTS));
+}
+
+
+static void e5_send_byte(u8 byte, struct e5_struct *k)
+{
+	u8 status;
+		
+	do {
+		status = ctrl_inb(EC3104_SER4_LSR);
+	} while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
+	
+	printk("<%02x>", byte);
+
+	ctrl_outb(byte, EC3104_SER4_DATA);
+
+	do {
+		status = ctrl_inb(EC3104_SER4_LSR);
+	} while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
+	
+}
+
+static int e5_send_packet(u8 *packet, int count, struct e5_struct *k)
+{
+	int i;
+
+	disable_irq(EC3104_IRQ_SER4);
+	
+	if (k->cached_mcr & MCR_RTS) {
+		printk("e5_send_packet: too slow\n");
+		enable_irq(EC3104_IRQ_SER4);
+		return -EAGAIN;
+	}
+
+	k->cached_mcr |= MCR_RTS;
+	ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+
+	e5_wait_for_cts(k);
+
+	printk("p: ");
+
+	for(i=0; i<count; i++)
+		e5_send_byte(packet[i], k);
+
+	e5_send_byte(e5_checksum(packet, count), k);
+
+	printk("\n");
+
+	udelay(1500);
+
+	k->cached_mcr &= ~MCR_RTS;
+	ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	
+	
+
+	enable_irq(EC3104_IRQ_SER4);
+
+	
+
+	return 0;
+}
+
+/*
+ * E5 packets we know about:
+ * E5->host 0x80 0x05 <checksum> - resend packet
+ * host->E5 0x83 0x43 <contrast> - set LCD contrast
+ * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight
+ * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2 
+ * E5->host 0x88 <scancode> <checksum> - key press
+ */
+
+static void e5_receive(struct e5_struct *k)
+{
+	k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA);
+
+	if (k->pos == 1) {
+		switch(k->packet[0]) {
+		case 0x80:
+			k->length = 3;
+			break;
+			
+		case 0x87: /* PS2 ext */
+			k->length = 6;
+			break;
+
+		case 0x88: /* keyboard */
+			k->length = 3;
+			break;
+
+		default:
+			k->length = 1;
+			printk(KERN_WARNING "unknown E5 packet %02x\n",
+			       k->packet[0]);
+		}
+	}
+
+	if (k->pos == k->length) {
+		int i;
+
+		if (e5_checksum(k->packet, k->length) != 0)
+			printk(KERN_WARNING "E5: wrong checksum\n");
+
+#if 0
+		printk("E5 packet [");
+		for(i=0; i<k->length; i++) {
+			printk("%02x ", k->packet[i]);
+		}
+
+		printk("(%02x)]\n", e5_checksum(k->packet, k->length-1));
+#endif
+
+		switch(k->packet[0]) {
+		case 0x80:
+		case 0x88:
+			handle_keyboard_event(k->packet[1]);
+			break;
+		}
+
+		k->pos = k->length = 0;
+	}
+}
+
+static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+	struct e5_struct *k = &ec3104_keyb;
+	u8 msr, lsr;
+
+	kbd_pt_regs = regs;
+
+	msr = ctrl_inb(EC3104_SER4_MSR);
+	
+	if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
+		if (k->cached_mcr & MCR_RTS)
+			printk("confused: RTS already high\n");
+		/* CTS went high.  Send RTS. */
+		k->cached_mcr |= MCR_RTS;
+		
+		ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+	} else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
+		/* CTS went low. */
+		if (!(k->cached_mcr & MCR_RTS))
+			printk("confused: RTS already low\n");
+
+		k->cached_mcr &= ~MCR_RTS;
+
+		ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+	}
+
+	k->last_msr = msr;
+
+	lsr = ctrl_inb(EC3104_SER4_LSR);
+
+	if (lsr & LSR_DR)
+		e5_receive(k);
+}
+
+static void ec3104_keyb_clear_state(void)
+{
+	struct e5_struct *k = &ec3104_keyb;
+	u8 msr, lsr;
+	
+	/* we want CTS to be low */
+	k->last_msr = 0;
+
+	for (;;) {
+		schedule_timeout(HZ/10);
+
+		msr = ctrl_inb(EC3104_SER4_MSR);
+	
+		lsr = ctrl_inb(EC3104_SER4_LSR);
+		
+		if (lsr & LSR_DR) {
+			e5_receive(k);
+			continue;
+		}
+
+		if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
+			if (k->cached_mcr & MCR_RTS)
+				printk("confused: RTS already high\n");
+			/* CTS went high.  Send RTS. */
+			k->cached_mcr |= MCR_RTS;
+		
+			ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+		} else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
+			/* CTS went low. */
+			if (!(k->cached_mcr & MCR_RTS))
+				printk("confused: RTS already low\n");
+			
+			k->cached_mcr &= ~MCR_RTS;
+			
+			ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+		} else
+			break;
+
+		k->last_msr = msr;
+
+		continue;
+	}
+}
+
+void __init ec3104_kbd_init_hw(void)
+{
+	ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR);
+	ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR);
+
+	ec3104_keyb_clear_state();
+
+	/* Ok, finally allocate the IRQ, and off we go.. */
+	request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL);
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.4.3/linux/drivers/char/epca.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/char/epca.c	Fri Apr 13 20:26:07 2001
@@ -769,7 +769,7 @@
 		globalwinon(ch);
 
 		/* -----------------------------------------------------------------	
-			Anding against size will wrap the pointer back to its begining 
+			Anding against size will wrap the pointer back to its beginning 
 			position if it is necessary.  This will only work if size is
 			a power of 2 which should always be the case.  Size is determined 
 			by the cards on board FEP/OS.
@@ -789,7 +789,7 @@
 			tail = bc->tout;
 
 		/* ------------------------------------------------------------------	
-			Anding against size will wrap the pointer back to its begining 
+			Anding against size will wrap the pointer back to its beginning 
 			position if it is necessary.  This will only work if size is
 			a power of 2 which should always be the case.  Size is determined 
 			by the cards on board FEP/OS.
@@ -818,7 +818,7 @@
 		                tail                               head
 
 			The above diagram shows that buffer locations 2,3,4,5 and 6 have
-			data to be transmited, while head points at the next empty
+			data to be transmitted, while head points at the next empty
 			location.  To calculate how much space is available first we have
 			to determine if the head pointer (tin) has wrapped.  To do this
 			compare the head pointer to the tail pointer,  If head is equal
@@ -827,9 +827,9 @@
 			that value from the buffers size.  A one is subtracted from the
 			new value to indicate how much space is available between the 
 			head pointer and end of buffer; as well as the space between the
-			begining of the buffer and the tail.  If the head is not greater
+			beginning of the buffer and the tail.  If the head is not greater
 			or equal to the tail this indicates that the head has wrapped
-			around to the begining of the buffer.  To calculate the space 
+			around to the beginning of the buffer.  To calculate the space 
 			available in this case simply subtract head from tail.  This new 
 			value minus one represents the space available betwwen the head 
 			and tail pointers.  In this example head (7) is greater than tail (2)
@@ -849,7 +849,7 @@
 		                head                               tail
 
 			The above diagram shows that buffer locations 7,8,9,0 and 1 have
-			data to be transmited, while head points at the next empty
+			data to be transmitted, while head points at the next empty
 			location.  To find the space available we compare head to tail.  If
 			head is not equal to, or greater than tail this indicates that head
 			has wrapped around. In this case head (2) is not equal to, or
@@ -1339,7 +1339,7 @@
 		}
 
 		/* ---------------------------------------------------------------
-			Allow someone else to be scheduled.  We will occasionaly go
+			Allow someone else to be scheduled.  We will occasionally go
 			through this loop until one of the above conditions change.
 			The below schedule call will allow other processes to enter and
 			prevent this loop from hogging the cpu.
@@ -1685,7 +1685,7 @@
 		       the boards array is correct.  This could be wrong if
 		       the card in question is PCI (And therefore has no ports 
 		       entry in the boards structure.)  The rest of the 
-		       information will be valid for PCI because the begining
+		       information will be valid for PCI because the beginning
 		       of pc_init scans for PCI and determines i/o and base
 		       memory addresses.  I am not sure if it is possible to 
 		       read the number of ports supported by the card prior to
@@ -1937,7 +1937,7 @@
  
 	/*  -------------------------------------------------------------
 		This call is made by the user via. the ioctl call DIGI_INIT.
-		It is resposible for setting up all the card specific stuff.
+		It is responsible for setting up all the card specific stuff.
 	---------------------------------------------------------------- */
 	bd = &boards[crd];
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.4.3/linux/drivers/char/esp.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/esp.c	Fri Apr  6 10:42:55 2001
@@ -1907,7 +1907,7 @@
 			    return get_lsr_info(info, (unsigned int *) arg);
 
 		case TIOCSERSWILD:
-			if (!suser())
+			if (!capable(CAP_SYS_ADMIN))
 				return -EPERM;
 			return 0;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/ftape/zftape/zftape-vtbl.c linux/drivers/char/ftape/zftape/zftape-vtbl.c
--- v2.4.3/linux/drivers/char/ftape/zftape/zftape-vtbl.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/ftape/zftape/zftape-vtbl.c	Fri Apr  6 10:42:55 2001
@@ -431,7 +431,7 @@
 /* this functions translates the failed_sector_log, misused as
  * EOF-marker list, into a virtual volume table. The table mustn't be
  * written to tape, because this would occupy the first data segment,
- * which should be the volume table, but is actualy the first segment
+ * which should be the volume table, but is actually the first segment
  * that is filled with data (when using standard ftape).  We assume,
  * that we get a non-empty failed_sector_log.
  */
diff -u --recursive --new-file v2.4.3/linux/drivers/char/hp600_keyb.c linux/drivers/char/hp600_keyb.c
--- v2.4.3/linux/drivers/char/hp600_keyb.c	Fri Sep 22 14:21:17 2000
+++ linux/drivers/char/hp600_keyb.c	Wed Apr 11 21:24:52 2001
@@ -1,13 +1,17 @@
 /*
- *	$Id: hp600_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
+ *	$Id$ 
  *	Copyright (C) 2000 YAEGASHI Takeshi
- *	HP600 keyboard scan routine and translate table
+ *	HP600 keyboard scan routine and translation table
+ *	Copyright (C) 2000 Niibe Yutaka
+ *	HP620 keyboard translation table
  */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/delay.h>
+
+#include <asm/machvec.h>
+#include <asm/delay.h>
 #include <asm/io.h>
 #include "scan_keyb.h"
 
@@ -17,55 +21,119 @@
 #define PFDR 0xa400012a
 #define PGDR 0xa400012c
 #define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static const unsigned char hp620_japanese_table[] = {
+	/* PTD1 */
+	0x0a, 0x0b, 0x0c, 0x00, 0x00, 0x0e, 0x00, 0x00,
+	0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+	/* PTD5 */
+	0x18, 0x19, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	/* PTD7 */
+	0x26, 0x1a, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+	/* PTE0 */
+	0x27, 0x1b, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x2a, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* PTE1 */
+	0x35, 0x28, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x70, 0x3a, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x34,
+	/* PTE3 */
+	0x48, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x2d, 0x2e, 0x7b, 0x30, 0x31, 0x32, 0x33,
+	/* PTE6 */
+	0x4b, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x2c, 0x38, 0x00, 0x39, 0x79, 0x7d, 0x73,
+	/* PTE7 */
+	0x41, 0x42, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
+	/* **** */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
 
-static const unsigned char hp690_japanese_table[]={
-	0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x70, 0x3a,
-	0x3f, 0x3e, 0x40, 0x41, 0x42, 0x3d, 0x3c, 0x3b,
-
-	0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35,
-	0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d,
-
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x50,
-	0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
 
+static const unsigned char hp680_japanese_table[] = {
+	/* PTD1 */
+	0x3a, 0x70, 0x29, 0x00, 0x01, 0x00, 0x00, 0x00,
+	0x3b, 0x3c, 0x3d, 0x42, 0x41, 0x40, 0x3e, 0x3f,
+	/* PTD5 */
+	0x35, 0x28, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00,
+	0x2d, 0x2e, 0x2f, 0x34, 0x33, 0x32, 0x30, 0x31,
+	/* PTD7 */
+	0x50, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x38, 0x7b,
+	/* PTE0 */
+	0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00,
+	0x1d, 0x00, 0x39, 0x53, 0x73, 0xf9, 0x00, 0x00,
+	/* PTE1 */
+	0x27, 0x1b, 0x2b, 0x00, 0x1e, 0x00, 0x00, 0x00,
+	0x1f, 0x20, 0x21, 0x26, 0x25, 0x24, 0x22, 0x23,
+	/* PTE3 */
+	0x48, 0x7d, 0x36, 0x00, 0x0f, 0x00, 0x00, 0x00,
+	0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* PTE6 */
+	0x19, 0x1a, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x00,
+	0x11, 0x12, 0x13, 0x18, 0x17, 0x16, 0x14, 0x15,
+	/* PTE7 */
+	0x0b, 0x0c, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00,
+	0x03, 0x04, 0x05, 0x0a, 0x09, 0x08, 0x06, 0x07,
+	/* **** */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xf9, 0x73, 0x53, 0x39, 0x00, 0x1d,
-
-	0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x1b, 0x27,
-	0x23, 0x22, 0x24, 0x25, 0x26, 0x21, 0x20, 0x1f,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
 
-	0x00, 0x00, 0x00, 0x0f, 0x00, 0x36, 0x7d, 0x48,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00,
 
-	0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x1a, 0x19,
-	0x15, 0x14, 0x16, 0x17, 0x18, 0x13, 0x12, 0x11,
+static int hp620_japanese_scan_kbd(unsigned char *s)
+{
+	int i;
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,	/* PTD1 */
+		0xdf, 0xff,	/* PTD5 */
+		0x7f, 0xff,	/* PTD7 */
+		0xff, 0xfe,	/* PTE0 */
+		0xff, 0xfd,	/* PTE1 */
+		0xff, 0xf7,	/* PTE3 */
+		0xff, 0xbf,	/* PTE6 */
+		0xff, 0x7f,	/* PTE7 */
+	}, *t=matrix_switch;
 
-	0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x0c, 0x0b,
-	0x07, 0x06, 0x08, 0x09, 0x0a, 0x05, 0x04, 0x03,
+	for(i=0; i<8; i++) {
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+		*s++=ctrl_inb(PCDR);
+		*s++=ctrl_inb(PFDR);
+	}
 
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
 
+	*s++=ctrl_inb(PGDR);
+	*s++=ctrl_inb(PHDR);
 
-static const unsigned char hp690_switch[]= {
-	0xfd, 0xff,
-	0xdf, 0xff,
-	0x7f, 0xff,
-	0xff, 0xfe,
-	0xff, 0xfd,
-	0xff, 0xf7,
-	0xff, 0xbf,
-	0xff, 0x7f,
-};
+	return 0;
+}
 
 
-static void hp690_japanese_scan_kbd(unsigned char *s)
+static int hp680_japanese_scan_kbd(unsigned char *s)
 {
 	int i;
-	unsigned const char *t=hp690_switch;
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,	/* PTD1 */
+		0xdf, 0xff,	/* PTD5 */
+		0x7f, 0xff,	/* PTD7 */
+		0xff, 0xfe,	/* PTE0 */
+		0xff, 0xfd,	/* PTE1 */
+		0xff, 0xf7,	/* PTE3 */
+		0xff, 0xbf,	/* PTE6 */
+		0xff, 0x7f,	/* PTE7 */
+	}, *t=matrix_switch;
 
-	for(i=0; i<9; i++) {
+	for(i=0; i<8; i++) {
 		ctrl_outb(*t++, PDDR);
 		ctrl_outb(*t++, PEDR);
 		*s++=ctrl_inb(PCDR);
@@ -77,18 +145,25 @@
 
 	*s++=ctrl_inb(PGDR);
 	*s++=ctrl_inb(PHDR);
+
+	return 0;
 }
 
 
 void __init hp600_kbd_init_hw(void)
 {
 	scan_kbd_init();
-	register_scan_keyboard(hp690_japanese_scan_kbd,
-			       hp690_japanese_table, 18);
+
+	if (MACH_HP620)
+		register_scan_keyboard(hp620_japanese_scan_kbd,
+				       hp620_japanese_table, 18);
+	else if (MACH_HP680 || MACH_HP690) 
+		register_scan_keyboard(hp680_japanese_scan_kbd,
+				       hp680_japanese_table, 18);
+
 	printk(KERN_INFO "HP600 matrix scan keyboard registered\n");
 }
 
-
 /****************************************************************
 HP Jornada 690(Japanese version) keyboard scan matrix
 
@@ -102,7 +177,6 @@
 PTE6	REC			Q	on/off	BS	@	P	
 PTE7	REC			1	on/off	^	-	0	
 
-
 	PTF7	PTF6	PTF5	PTF4	PTF3	PTF2	PTF1	PTF0
 PTD1	F5	F4	F6	F7	F8	F3	F2	F1	
 PTD5	N	B	M	,	.	V	C	X	
@@ -129,3 +203,136 @@
 L: 0x0c3c 0x26	F	F	IP	F	F	IP	IP	F
 
 ****************************************************************/
+
+/****************************************************************
+HP Jornada 620(Japanese version) keyboard scan matrix
+
+	PTC7	PTC6	PTC5	PTC4	PTC3	PTC2	PTC1	PTC0
+PTD1	EREC		BS	Ctrl	on/off	-	0	9
+PTD5	EREC		BS	Ctrl	on/off	^	P	O
+PTD7	EREC		BS	Ctrl	on/off	]	@	L
+PTE0	EREC		BS	Ctrl	on/off	Han/Zen [	;
+PTE1	EREC		BS	Ctrl	on/off	Enter	:	/
+PTE3	EREC		BS	Ctrl	on/off		Right	Up
+PTE6	EREC		BS	Ctrl	on/off		Down	Left
+PTE7	EREC		BS	Ctrl	on/off		F8	F7
+
+	PTF7	PTF6	PTF5	PTF4	PTF3	PTF2	PTF1	PTF0
+PTD1	8	7	6	5	4	3	2	1
+PTD5	I	U	Y	T	R	E	W	Q
+PTD7	K	J	H	G	F	D	S	A
+PTE0						ESC	Tab	Shift
+PTE1	.			V			Caps	Hira
+PTE3	,	M	N	B	Muhen	C	X
+PTE6	_	\	Henkan	Space		Alt	Z
+PTE7	F6	F5	F4	F3	F2	F1		REC
+
+	PTH0
+*	on/off
+
+		7	6	5	4	3	2	1	0
+C: 0xffff 0xff	IP	IP	IP	IP	IP	IP	IP	IP
+D: 0x4404 0xaf	O	F	O	F	F	F	O	F
+E: 0x5045 0xff	O	O	F	F	O	F	O	O
+F: 0xffff 0xff	IP	IP	IP	IP	IP	IP	IP	IP
+G: 0xd5ff 0x00	IP	O	O	O	IP	IP	IP	IP
+H: 0x63ff 0xd1	O	I	F	IP	IP	IP	IP	IP
+J: 0x0004 0x02	F	F	F	F	F	F	O	F
+K: 0x0401 0xff	F	F	O	F	F	F	F	O
+L: 0x0c00 0x20	F	F	IP	F	F	F	F	F
+
+ADCSR: 0x08
+ADCR: 0x3f
+
+ ****************************************************************/
+
+/****************************************************************
+Japanese 109 keyboard scan code layout
+
+                                              E02A-     E1- 
+01    3B 3C 3D 3E  3F 40 41 42  43 44 57 58   E037  46  1045
+                                                                   
+29 02 03 04 05 06 07 08 09 0A 0B 0C 0D 7D 0E  E052 E047 E049   45 E035 37  4A
+0F  10 11 12 13 14 15 16 17 18 19 1A 1B   1C  E053 E04F E051   47  48  49  4E
+3A   1E 1F 20 21 22 23 24 25 26 27 28 2B                       4B  4C  4D
+2A    2C 2D 2E 2F 30 31 32 33 34 35 73    36       E048        4F  50  51  E0-
+1D  DB  38  7B   39   79 70  E038 DC DD E01D  E04B E050 E04D     52    53  1C
+
+****************************************************************/
+
+#if 0
+int __init hp620_keyboard_test(void)
+{
+	int i;
+	unsigned char s[18];
+	unsigned long a, b, c, d;
+
+	printk("PCCR: %04lx, PCDR: %02lx\n",
+	       ctrl_inw(0xa4000104), ctrl_inb(0xa4000124));
+	printk("PDCR: %04lx, PDDR: %02lx\n",
+	       ctrl_inw(0xa4000106), ctrl_inb(0xa4000126));
+	printk("PECR: %04lx, PEDR: %02lx\n",
+	       ctrl_inw(0xa4000108), ctrl_inb(0xa4000128));
+	printk("PFCR: %04lx, PFDR: %02lx\n",
+	       ctrl_inw(0xa400010a), ctrl_inb(0xa400012a));
+	printk("PGCR: %04lx, PGDR: %02lx\n",
+	       ctrl_inw(0xa400010c), ctrl_inb(0xa400012c));
+	printk("PHCR: %04lx, PHDR: %02lx\n",
+	       ctrl_inw(0xa400010e), ctrl_inb(0xa400012e));
+	printk("PJCR: %04lx, PJDR: %02lx\n",
+	       ctrl_inw(0xa4000110), ctrl_inb(0xa4000130));
+	printk("PKCR: %04lx, PKDR: %02lx\n",
+	       ctrl_inw(0xa4000112), ctrl_inb(0xa4000132));
+	printk("PLCR: %04lx, PLDR: %02lx\n",
+	       ctrl_inw(0xa4000114), ctrl_inb(0xa4000134));
+
+	printk("ADCSR: %02lx, ADCR: %02lx\n",
+	       ctrl_inb(0xa4000090), ctrl_inb(0xa4000092));
+
+	ctrl_inb(0xa4000004);
+	ctrl_inb(0xa4000006);
+	ctrl_inb(0xa4000008);
+	ctrl_outb(0, 0xa4000004);
+	ctrl_outb(0, 0xa4000006);
+	ctrl_outb(0, 0xa4000008);
+	ctrl_outb(0, 0xa4000090);
+	ctrl_outb(0x3b, 0xa4000090);
+
+	while(1) {
+		hp620_japanese_scan_kbd(s);
+		for(i=0; i<18; i+=2)
+			printk("%02x%02x ", s[i], s[i+1]);
+
+#if 0
+		ctrl_outb(~2, PJDR);
+		printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR));
+		ctrl_outb(0xff, PJDR);
+		ctrl_outb(~1, PKDR);
+		printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR));
+		ctrl_outb(~32, PKDR);
+		printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR));
+		ctrl_outb(0xff, PKDR);
+#endif
+
+		printk("%02lx%02lx%02lx%02lx ", a, b, c, d);
+		if(ctrl_inb(0xa4000090)&0x80) {
+			a=ctrl_inb(0xa4000080);
+			b=ctrl_inb(0xa4000084);
+			c=ctrl_inb(0xa4000088);
+			d=ctrl_inb(0xa400008c);
+			ctrl_outb(0x3b, 0xa4000090);
+		}
+		printk("%02lx%02lx%02lx ",
+		       ctrl_inb(0xa4000004),
+		       ctrl_inb(0xa4000006),
+		       ctrl_inb(0xa4000008));
+
+		printk("\n");
+	}
+
+	return 0;
+}
+module_init(keyboard_probe);
+#endif
+
+
diff -u --recursive --new-file v2.4.3/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c
--- v2.4.3/linux/drivers/char/i810_rng.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/char/i810_rng.c	Thu Apr 12 12:15:25 2001
@@ -35,7 +35,7 @@
 /*
  * core module and version information
  */
-#define RNG_VERSION "0.9.5"
+#define RNG_VERSION "0.9.6"
 #define RNG_MODULE_NAME "i810_rng"
 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
 #define PFX RNG_MODULE_NAME ": "
@@ -81,26 +81,13 @@
 #define RNG_ADDR			0xFFBC015F
 #define RNG_ADDR_LEN			3
 
-#define RNG_MAX_ENTROPY			8 /* max entropy h/w is capable of */
-
 #define RNG_MISCDEV_MINOR		183 /* official */
 
-
-/*
- * number of bytes required for a FIPS test.
- * do not alter unless you really, I mean
- * REALLY know what you are doing.
- */
-#define RNG_FIPS_TEST_THRESHOLD	2500
-
-
 /*
  * various RNG status variables.  they are globals
  * as we only support a single RNG device
  */
-static int rng_hw_enabled;		/* is the RNG h/w enabled? */
 static void *rng_mem;			/* token to our ioremap'd RNG register area */
-static struct pci_dev *rng_pdev;	/* Firmware Hub PCI device found during PCI probe */
 static struct semaphore rng_open_sem;	/* Semaphore for serializing rng_open/release */
 
 
@@ -113,18 +100,17 @@
 	return readb (rng_mem + RNG_HW_STATUS);
 }
 
-
-static inline void rng_hwstatus_set (u8 hw_status)
+static inline u8 rng_hwstatus_set (u8 hw_status)
 {
 	assert (rng_mem != NULL);
 	writeb (hw_status, rng_mem + RNG_HW_STATUS);
+	return rng_hwstatus ();
 }
 
 
 static inline int rng_data_present (void)
 {
 	assert (rng_mem != NULL);
-	assert (rng_hw_enabled > 0);
 
 	return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
 }
@@ -133,65 +119,67 @@
 static inline int rng_data_read (void)
 {
 	assert (rng_mem != NULL);
-	assert (rng_hw_enabled > 0);
 
 	return readb (rng_mem + RNG_DATA);
 }
 
-
 /*
- * rng_enable - enable or disable the RNG hardware
+ * rng_enable - enable the RNG hardware
  */
-static int rng_enable (int enable)
+
+static int rng_enable (void)
 {
-	int rc = 0, action = 0;
+	int rc = 0;
 	u8 hw_status, new_status;
 
 	DPRINTK ("ENTER\n");
 
 	hw_status = rng_hwstatus ();
 
-	if (enable) {
-		rng_hw_enabled++;
-		MOD_INC_USE_COUNT;
-	} else {
-		if (rng_hw_enabled) {
-			rng_hw_enabled--;
-			MOD_DEC_USE_COUNT;
+	if ((hw_status & RNG_ENABLED) == 0) {
+		new_status = rng_hwstatus_set (hw_status | RNG_ENABLED);
+
+		if (new_status & RNG_ENABLED)
+			printk (KERN_INFO PFX "RNG h/w enabled\n");
+		else {
+			printk (KERN_ERR PFX "Unable to enable the RNG\n");
+			rc = -EIO;
 		}
 	}
 
-	if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) {
-		rng_hwstatus_set (hw_status | RNG_ENABLED);
-		action = 1;
-	}
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
 
-	else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) {
-		rng_hwstatus_set (hw_status & ~RNG_ENABLED);
-		action = 2;
-	}
+/*
+ * rng_disable - disable the RNG hardware
+ */
 
-	new_status = rng_hwstatus ();
+static void rng_disable(void)
+{
+	u8 hw_status, new_status;
 
-	if (action == 1) {
-		if (new_status & RNG_ENABLED)
-			printk (KERN_INFO PFX "RNG h/w enabled\n");
-		else
-			printk (KERN_ERR PFX "Unable to enable the RNG\n");
-	} else if (action == 2) {
+	DPRINTK ("ENTER\n");
+
+	hw_status = rng_hwstatus ();
+
+	if (hw_status & RNG_ENABLED) {
+		new_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED);
+	
 		if ((new_status & RNG_ENABLED) == 0)
 			printk (KERN_INFO PFX "RNG h/w disabled\n");
-		else
+		else {
 			printk (KERN_ERR PFX "Unable to disable the RNG\n");
+		}
 	}
 
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
+	DPRINTK ("EXIT\n");
 }
 
-
 static int rng_dev_open (struct inode *inode, struct file *filp)
 {
+	int rc;
+
 	if ((filp->f_mode & FMODE_READ) == 0)
 		return -EINVAL;
 	if (filp->f_mode & FMODE_WRITE)
@@ -206,9 +194,10 @@
 			return -ERESTARTSYS;
 	}
 
-	if (rng_enable (1)) {
+	rc = rng_enable ();
+	if (rc) {
 		up (&rng_open_sem);
-		return -EIO;
+		return rc;
 	}
 
 	return 0;
@@ -217,7 +206,7 @@
 
 static int rng_dev_release (struct inode *inode, struct file *filp)
 {
-	rng_enable(0);
+	rng_disable ();
 	up (&rng_open_sem);
 	return 0;
 }
@@ -315,8 +304,9 @@
 	}
 
 	/* turn RNG h/w off, if it's on */
-	rc = rng_enable (0);
-	if (rc) {
+	if (hw_status & RNG_ENABLED)
+		hw_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED);
+	if (hw_status & RNG_ENABLED) {
 		printk (KERN_ERR PFX "cannot disable RNG, aborting\n");
 		goto err_out_free_map;
 	}
@@ -381,8 +371,6 @@
 
 	printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
 
-	rng_pdev = pdev;
-
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
 }
@@ -395,13 +383,9 @@
 {
 	DPRINTK ("ENTER\n");
 
-	assert (rng_hw_enabled == 0);
-
 	misc_deregister (&rng_miscdev);
 
 	iounmap (rng_mem);
-
-	rng_pdev = NULL;
 
 	DPRINTK ("EXIT\n");
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/char/ip2.c linux/drivers/char/ip2.c
--- v2.4.3/linux/drivers/char/ip2.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/char/ip2.c	Thu Apr 12 12:16:35 2001
@@ -6,7 +6,6 @@
 //  __initdata should work as advertized
 //
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.4.3/linux/drivers/char/isicom.c	Wed Dec  6 12:06:18 2000
+++ linux/drivers/char/isicom.c	Fri Apr  6 10:42:55 2001
@@ -16,6 +16,10 @@
  *
  *	10/6/99 sameer			Merged the ISA and PCI drivers to
  *					a new unified driver.
+ *	09/06/01 acme@conectiva.com.br	use capable, not suser, do
+ *					restore_flags on failure in
+ *					isicom_send_break, verify put_user
+ *					result
  *	***********************************************************
  *
  *	To use this driver you also need the support package. You 
@@ -1354,13 +1358,13 @@
 	while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));	
 	if (!wait) {
 		printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n");
-		return;
+		goto out;
 	}	
 	outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
 	outw((length & 0xff) << 8 | 0x00, base);
 	outw((length & 0xff00), base);
 	InterruptTheCard(base);
-	restore_flags(flags);
+out:	restore_flags(flags);
 }
 
 static int isicom_get_modem_info(struct isi_port * port, unsigned int * value)
@@ -1375,8 +1379,7 @@
 		((status & ISI_DSR) ? TIOCM_DSR : 0) |
 		((status & ISI_CTS) ? TIOCM_CTS : 0) |
 		((status & ISI_RI ) ? TIOCM_RI  : 0);
-	put_user(info, (unsigned int *) value);
-	return 0;	
+	return put_user(info, (unsigned int *) value);
 }
 
 static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd,
@@ -1438,7 +1441,7 @@
 	reconfig_port = ((port->flags & ASYNC_SPD_MASK) != 
 			 (newinfo.flags & ASYNC_SPD_MASK));
 	
-	if (!suser()) {
+	if (!capable(CAP_SYS_ADMIN)) {
 		if ((newinfo.close_delay != port->close_delay) ||
 		    (newinfo.closing_wait != port->closing_wait) ||
 		    ((newinfo.flags & ~ASYNC_USR_MASK) != 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in
--- v2.4.3/linux/drivers/char/joystick/Config.in	Tue Aug 22 11:55:47 2000
+++ linux/drivers/char/joystick/Config.in	Wed Apr 11 19:02:30 2001
@@ -11,6 +11,7 @@
       dep_tristate '  ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT
       dep_tristate '  PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT
       dep_tristate '  Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT
+      dep_tristate '  Crystal SoundFusion gameports' CONFIG_INPUT_CS461X $CONFIG_INPUT
 
    comment 'Gameport joysticks'
       dep_tristate '  Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT
@@ -31,6 +32,7 @@
       dep_tristate '  LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT
       dep_tristate '  SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT
       dep_tristate '  SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT
+      dep_tristate '  Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT
       dep_tristate '  I-Force/Serial controllers' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT
       dep_tristate '  I-Force/USB controllers' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/Makefile linux/drivers/char/joystick/Makefile
--- v2.4.3/linux/drivers/char/joystick/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/drivers/char/joystick/Makefile	Wed Apr 11 19:02:30 2001
@@ -35,11 +35,13 @@
 obj-$(CONFIG_INPUT_NS558)	+= ns558.o gameport.o
 obj-$(CONFIG_INPUT_LIGHTNING)	+= lightning.o gameport.o
 obj-$(CONFIG_INPUT_PCIGAME)	+= pcigame.o gameport.o
+obj-$(CONFIG_INPUT_CS461X)	+= cs461x.o gameport.o
 
 obj-$(CONFIG_INPUT_WARRIOR)	+= warrior.o serio.o
 obj-$(CONFIG_INPUT_MAGELLAN)	+= magellan.o serio.o
 obj-$(CONFIG_INPUT_SPACEORB)	+= spaceorb.o serio.o
 obj-$(CONFIG_INPUT_SPACEBALL)	+= spaceball.o serio.o
+obj-$(CONFIG_INPUT_STINGER)	+= stinger.o serio.o
 obj-$(CONFIG_INPUT_IFORCE_232)	+= iforce.o serio.o
 obj-$(CONFIG_INPUT_IFORCE_USB)	+= iforce.o
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/adi.c linux/drivers/char/joystick/adi.c
--- v2.4.3/linux/drivers/char/joystick/adi.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/adi.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: adi.c,v 1.12 2000/06/03 20:18:52 vojtech Exp $
+ * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $
  *
  *  Copyright (c) 1998-2000 Vojtech Pavlik
  *
@@ -370,7 +370,8 @@
 		adi->cname[i] = adi_get_bits(adi, 8);
 	adi->cname[i] = 0;
 
-	if (adi->length != (t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4)) {
+	t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
+	if (adi->length != t && adi->length != t + (t & 1)) {
 		printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
 		adi->length = 0;
 		return;
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/cobra.c linux/drivers/char/joystick/cobra.c
--- v2.4.3/linux/drivers/char/joystick/cobra.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/cobra.c	Wed Apr 11 19:02:30 2001
@@ -131,7 +131,7 @@
 			input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
 
 			for (j = 0; cobra_btn[j]; j++)
-				input_report_key(dev, cobra_btn[j], data[i] & (0x20 << i));
+				input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
 
 		}
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/cs461x.c linux/drivers/char/joystick/cs461x.c
--- v2.4.3/linux/drivers/char/joystick/cs461x.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/joystick/cs461x.c	Wed Apr 11 19:02:30 2001
@@ -0,0 +1,331 @@
+/*
+	The all defines and part of code (such as cs461x_*) are 
+	contributed from ALSA 0.5.8 sources. 
+	See http://www.alsa-project.org/ for sources
+	
+	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
+*/
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
+
+/*
+	These options are experimental
+
+#define COOKED_MODE
+#define CS461X_FULL_MAP
+
+*/
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS            0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4610
+#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4612
+#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4615
+#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
+#endif
+
+/* Registers */
+
+#define BA0_JSPT                                0x00000480
+#define BA0_JSCTL                               0x00000484
+#define BA0_JSC1                                0x00000488
+#define BA0_JSC2                                0x0000048C
+#define BA0_JSIO                                0x000004A0
+
+/* Bits for JSPT */
+
+#define JSPT_CAX                                0x00000001
+#define JSPT_CAY                                0x00000002
+#define JSPT_CBX                                0x00000004
+#define JSPT_CBY                                0x00000008
+#define JSPT_BA1                                0x00000010
+#define JSPT_BA2                                0x00000020
+#define JSPT_BB1                                0x00000040
+#define JSPT_BB2                                0x00000080
+
+/* Bits for JSCTL */
+
+#define JSCTL_SP_MASK                           0x00000003
+#define JSCTL_SP_SLOW                           0x00000000
+#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
+#define JSCTL_SP_MEDIUM_FAST                    0x00000002
+#define JSCTL_SP_FAST                           0x00000003
+#define JSCTL_ARE                               0x00000004
+
+/* Data register pairs masks */
+
+#define JSC1_Y1V_MASK                           0x0000FFFF
+#define JSC1_X1V_MASK                           0xFFFF0000
+#define JSC1_Y1V_SHIFT                          0
+#define JSC1_X1V_SHIFT                          16
+#define JSC2_Y2V_MASK                           0x0000FFFF
+#define JSC2_X2V_MASK                           0xFFFF0000
+#define JSC2_Y2V_SHIFT                          0
+#define JSC2_X2V_SHIFT                          16
+
+/* JS GPIO */
+
+#define JSIO_DAX                                0x00000001
+#define JSIO_DAY                                0x00000002
+#define JSIO_DBX                                0x00000004
+#define JSIO_DBY                                0x00000008
+#define JSIO_AXOE                               0x00000010
+#define JSIO_AYOE                               0x00000020
+#define JSIO_BXOE                               0x00000040
+#define JSIO_BYOE                               0x00000080
+
+/* 
+   The card initialization code is obfuscated; the module cs461x 
+   need to be loaded after ALSA modules initialized and something
+   played on the CS 4610 chip (see sources for details of CS4610
+   initialization code from ALSA)
+*/
+
+/* Card specific definitions */
+
+#define CS461X_BA0_SIZE         0x2000
+#define CS461X_BA1_DATA0_SIZE   0x3000
+#define CS461X_BA1_DATA1_SIZE   0x3800
+#define CS461X_BA1_PRG_SIZE     0x7000
+#define CS461X_BA1_REG_SIZE     0x0100
+
+#define BA1_SP_DMEM0                            0x00000000
+#define BA1_SP_DMEM1                            0x00010000
+#define BA1_SP_PMEM                             0x00020000
+#define BA1_SP_REG                              0x00030000
+
+#define BA1_DWORD_SIZE          (13 * 1024 + 512)
+#define BA1_MEMORY_COUNT        3
+
+/* 
+   Only one CS461x card is still suppoted; the code requires
+   redesign to avoid this limitatuion.
+*/
+
+static unsigned long ba0_addr;
+static unsigned int *ba0;
+
+#ifdef CS461X_FULL_MAP
+static unsigned long ba1_addr;
+static union ba1_t {
+        struct {
+                unsigned int *data0;
+                unsigned int *data1;
+                unsigned int *pmem;
+                unsigned int *reg;
+        } name;
+        unsigned int *idx[4];
+} ba1;
+
+static void cs461x_poke(unsigned long reg, unsigned int val)
+{
+        ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
+}
+
+static unsigned int cs461x_peek(unsigned long reg)
+{
+        return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
+}
+
+#endif
+
+static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
+{
+        ba0[reg >> 2] = val;
+}
+
+static unsigned int cs461x_peekBA0(unsigned long reg)
+{
+        return ba0[reg >> 2];
+}
+
+static int cs461x_free(struct pci_dev *pdev)
+{
+	struct gameport *port = (struct gameport *)pdev->driver_data;
+	if(port){
+	    gameport_unregister_port(port);
+	    kfree(port);
+	}    
+	if (ba0) iounmap(ba0);
+#ifdef CS461X_FULL_MAP
+	if (ba1.name.data0) iounmap(ba1.name.data0);
+	if (ba1.name.data1) iounmap(ba1.name.data1);
+	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
+	if (ba1.name.reg)   iounmap(ba1.name.reg);
+#endif
+	return 0;
+}
+
+static void cs461x_gameport_trigger(struct gameport *gameport)
+{
+	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
+}
+
+static unsigned char cs461x_gameport_read(struct gameport *gameport)
+{
+	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
+}
+
+static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	unsigned js1, js2, jst;
+	
+	js1 = cs461x_peekBA0(BA0_JSC1);
+	js2 = cs461x_peekBA0(BA0_JSC2);
+	jst = cs461x_peekBA0(BA0_JSPT);
+	
+	*buttons = (~jst >> 4) & 0x0F; 
+	
+	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
+	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
+	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
+	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
+
+	for(jst=0;jst<4;++jst)
+		if(axes[jst]==0xFFFF) axes[jst] = -1;
+	return 0;
+}
+
+static int cs461x_gameport_open(struct gameport *gameport, int mode)
+{
+	switch (mode) {
+#ifdef COOKED_MODE
+	case GAMEPORT_MODE_COOKED:
+		return 0;
+#endif
+	case GAMEPORT_MODE_RAW:
+		return 0;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+static struct pci_device_id cs461x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
+	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
+	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
+
+static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct gameport* port;
+	
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
+			pdev->bus->number, pdev->devfn, rc);
+		return rc;
+	}
+
+	ba0_addr = pci_resource_start(pdev, 0);
+#ifdef CS461X_FULL_MAP
+	ba1_addr = pci_resource_start(pdev, 1);
+#endif
+	if (ba0_addr == 0 || ba0_addr == ~0 
+#ifdef CS461X_FULL_MAP
+            || ba1_addr == 0 || ba1_addr == ~0
+#endif
+	    ) {
+                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
+#ifdef CS461X_FULL_MAP
+                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
+#endif
+		cs461x_free(pdev);
+                return -ENOMEM;
+        }
+
+	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
+#ifdef CS461X_FULL_MAP
+	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
+	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
+	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
+	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
+
+	if (ba0 == NULL || ba1.name.data0 == NULL ||
+            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
+            ba1.name.reg == NULL) {
+		cs461x_free(pdev);
+                return -ENOMEM;
+        }
+#else
+	if (ba0 == NULL){
+		cs461x_free(pdev);
+		return -ENOMEM;
+	}
+#endif
+	printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
+	    ba0_addr, CS461X_BA0_SIZE);
+        
+	if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
+		printk(KERN_ERR "Memory allocation failed.\n");
+		cs461x_free(pdev);
+		return -ENOMEM;
+	}
+	memset(port, 0, sizeof(struct gameport));
+
+	port->io = -1;
+	port->size = -1;
+	pdev->driver_data = port;
+	
+	port->open = cs461x_gameport_open;
+	port->read = cs461x_gameport_read;
+	port->trigger = cs461x_gameport_trigger;
+#ifdef COOKED_MODE
+	port->cooked_read = cs461x_gameport_cooked_read;
+#endif
+
+	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
+	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
+
+	gameport_register_port(port);
+
+	printk(KERN_INFO "gameport%d: CS461x PCI", port->number);
+	if (port->size > 1) printk(" size %d", port->size);
+	printk(" speed %d kHz\n", port->speed);
+
+	return 0;
+}
+
+static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
+{
+	cs461x_free(pdev);
+}
+	
+static struct pci_driver cs461x_pci_driver = {
+        name:           "PCI Gameport",
+        id_table:       cs461x_pci_tbl,
+        probe:          cs461x_pci_probe,
+        remove:         cs461x_pci_remove,
+};
+
+int __init js_cs461x_init(void)
+{
+        return pci_module_init(&cs461x_pci_driver);
+}
+
+void __exit js_cs461x_exit(void)
+{
+        pci_unregister_driver(&cs461x_pci_driver);
+}
+
+module_init(js_cs461x_init);
+module_exit(js_cs461x_exit);
+
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/gamecon.c linux/drivers/char/joystick/gamecon.c
--- v2.4.3/linux/drivers/char/joystick/gamecon.c	Mon Aug 14 13:55:01 2000
+++ linux/drivers/char/joystick/gamecon.c	Wed Apr 11 19:02:30 2001
@@ -1,11 +1,11 @@
 /*
- * $Id: gamecon.c,v 1.5 2000/06/25 09:56:58 vojtech Exp $
+ * $Id: gamecon.c,v 1.11 2000/11/01 12:38:53 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
  *  Based on the work of:
  *  	Andree Borrmann		John Dahlstrom
- *  	David Kuder
+ *  	David Kuder		Nathan Hand
  *
  *  Sponsored by SuSE
  */
@@ -75,8 +75,7 @@
 static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
 
 static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
-				"Multisystem 2-button joystick", "N64 controller", "PSX pad",
-				"PSX NegCon", "PSX Analog contoller" };
+				"Multisystem 2-button joystick", "N64 controller", "PSX controller" };
 /*
  * N64 support.
  */
@@ -205,22 +204,30 @@
 
 /*
  * PSX support
- */
-
-#define GC_PSX_DELAY	10
-#define GC_PSX_LENGTH	8	/* talk to the controller in bytes */
+ *
+ * See documentation at:
+ *	http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
+ *	http://www.gamesx.com/controldata/psxcont/psxcont.htm
+ *	ftp://milano.usal.es/pablo/
+ *	
+ */
+
+#define GC_PSX_DELAY	60		/* 60 usec */
+#define GC_PSX_LENGTH	8		/* talk to the controller in bytes */
+
+#define GC_PSX_MOUSE	1		/* Mouse */
+#define GC_PSX_NEGCON	2		/* NegCon */
+#define GC_PSX_NORMAL	4		/* Digital / Analog or Rumble in Digital mode  */
+#define GC_PSX_ANALOG	5		/* Analog in Analog mode / Rumble in Green mode */
+#define GC_PSX_RUMBLE	7		/* Rumble in Red mode */
+
+#define GC_PSX_CLOCK	0x04		/* Pin 4 */
+#define GC_PSX_COMMAND	0x01		/* Pin 1 */
+#define GC_PSX_POWER	0xf8		/* Pins 5-9 */
+#define GC_PSX_SELECT	0x02		/* Pin 3 */
 
-#define GC_PSX_MOUSE	0x12	/* PSX Mouse */
-#define GC_PSX_NEGCON	0x23	/* NegCon pad */
-#define GC_PSX_NORMAL	0x41	/* Standard Digital controller */
-#define GC_PSX_ANALOGR	0x73	/* Analog controller in Red mode */
-#define GC_PSX_ANALOGG	0x53	/* Analog controller in Green mode */
-
-#define GC_PSX_CLOCK	0x04	/* Pin 3 */
-#define GC_PSX_COMMAND	0x01	/* Pin 1 */
-#define GC_PSX_POWER	0xf8	/* Pins 5-9 */
-#define GC_PSX_SELECT	0x02	/* Pin 2 */
-#define GC_PSX_NOPOWER  0x04
+#define GC_PSX_ID(x)	((x) >> 4)	/* High nibble is device type */
+#define GC_PSX_LEN(x)	((x) & 0xf)	/* Low nibble is length in words */
 
 static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
 static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
@@ -233,19 +240,17 @@
 
 static int gc_psx_command(struct gc *gc, int b)
 {
-	int i, cmd, ret = 0;
+	int i, cmd, data = 0;
 
-	cmd = (b & 1) ? GC_PSX_COMMAND : 0;
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++, b >>= 1) {
+		cmd = (b & 1) ? GC_PSX_COMMAND : 0;
 		parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
 		udelay(GC_PSX_DELAY);
-		ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
-		cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+		data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
 		parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
 		udelay(GC_PSX_DELAY);
-		b >>= 1;
 	}
-	return ret;
+	return data;
 }
 
 /*
@@ -253,29 +258,31 @@
  * device identifier code.
  */
 
-static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data)
+static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
 {
-	int i, ret;
+	int i, id;
 	unsigned long flags;
 
+	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);	/* Select pad */
+	udelay(GC_PSX_DELAY * 2);
+	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);			/* Deselect, begin command */
+	udelay(GC_PSX_DELAY * 2);
+
 	__save_flags(flags);
 	__cli();
 
-	parport_write_data(gc->pd->port, GC_PSX_POWER);
-
-	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);	/* Select pad */
-	udelay(GC_PSX_DELAY * 2);
 	gc_psx_command(gc, 0x01);							/* Access pad */
-	ret = gc_psx_command(gc, 0x42);							/* Get device id */
-	if (gc_psx_command(gc, 0) == 'Z')						/* okay? */
-		for (i = 0; i < length; i++)
+	id = gc_psx_command(gc, 0x42);							/* Get device id */
+	if (gc_psx_command(gc, 0) == 0x5a) {						/* Okay? */
+		for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
 			data[i] = gc_psx_command(gc, 0);
-	else ret = -1;
+	} else id = 0;
 
-	parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER);
 	__restore_flags(flags);
 
-	return ret;
+	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
+
+	return GC_PSX_ID(id);
 }
 
 /*
@@ -316,8 +323,8 @@
 				input_report_abs(dev + i, ABS_X,  axes[0]);
 				input_report_abs(dev + i, ABS_Y, -axes[1]);
 
-				input_report_abs(dev + i, ABS_HAT0X, !!(s & data[7]) - !!(s & data[6]));
-				input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - !!(s & data[4]));
+				input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
+				input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
 
 				for (j = 0; j < 10; j++)
 					input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
@@ -338,8 +345,8 @@
 			s = gc_status_bit[i];
 
 			if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
-				input_report_abs(dev + i, ABS_X, !!(s & data[7]) - !!(s & data[6]));
-				input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - !!(s & data[4]));
+				input_report_abs(dev + i, ABS_X, ! - !(s & data[6]) - !(s & data[7]));
+				input_report_abs(dev + i, ABS_Y, ! - !(s & data[4]) - !(s & data[5]));
 			}
 
 			if (s & gc->pads[GC_NES])
@@ -365,8 +372,8 @@
 			s = gc_status_bit[i];
 
 			if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
-				input_report_abs(dev + i, ABS_X, !!(s & data[3]) - !!(s & data[2]));
-				input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - !!(s & data[0]));
+				input_report_abs(dev + i, ABS_X,  !(s & data[2]) - !(s & data[3]));
+				input_report_abs(dev + i, ABS_Y,  !(s & data[0]) - !(s & data[1]));
 				input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
 			}
 
@@ -385,37 +392,37 @@
 	       		if (gc->pads[GC_PSX] & gc_status_bit[i])
 				break;
 
- 		switch (gc_psx_read_packet(gc, 6, data)) {
+ 		switch (gc_psx_read_packet(gc, data)) {
+
+			case GC_PSX_RUMBLE:
+
+				input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
+				input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+
+			case GC_PSX_NEGCON:
+			case GC_PSX_ANALOG:
 
-			case GC_PSX_ANALOGG:
-	
 				for (j = 0; j < 4; j++)
 					input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
 
-				input_report_abs(dev + i, ABS_HAT0X, !!(data[0]&0x20) - !!(data[0]&0x80));
-				input_report_abs(dev + i, ABS_HAT0Y, !!(data[0]&0x40) - !!(data[0]&0x10));
+				input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80));
+				input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10));
 
 				for (j = 0; j < 8; j++)
-					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i));
+					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
 
 				input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
 				input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
 
 				break;
 
-			case GC_PSX_ANALOGR:
-
-				input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
-				input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
-
 			case GC_PSX_NORMAL:
-			case GC_PSX_NEGCON:
 
-				input_report_abs(dev + i, ABS_X, 128 + !!(data[0] & 0x20) * 127 - !!(data[0] & 0x80) * 128);
-				input_report_abs(dev + i, ABS_Y, 128 + !!(data[0] & 0x40) * 127 - !!(data[0] & 0x10) * 128);
+				input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128);
+				input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128);
 
 				for (j = 0; j < 8; j++)
-					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i));
+					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
 
 				input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
 				input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
@@ -448,14 +455,12 @@
 	}
 }
 
-
-
 static struct gc __init *gc_probe(int *config)
 {
 	struct gc *gc;
 	struct parport *pp;
-	int i, j, psx, pbtn;
-	unsigned char data[2];
+	int i, j, psx;
+	unsigned char data[32];
 
 	if (config[0] < 0)
 		return NULL;
@@ -545,44 +550,42 @@
 
 			case GC_PSX:
 				
-				psx = gc_psx_read_packet(gc, 2, data);
+				psx = gc_psx_read_packet(gc, data);
 
 				switch(psx) {
 					case GC_PSX_NEGCON:
-						config[i + 1] += 1;
 					case GC_PSX_NORMAL:
-						pbtn = 10;
-						break;
+					case GC_PSX_ANALOG:
+					case GC_PSX_RUMBLE:
 
-					case GC_PSX_ANALOGG:
-					case GC_PSX_ANALOGR:
-						config[i + 1] += 2;
-						pbtn = 12;
 						for (j = 0; j < 6; j++) {
 							psx = gc_psx_abs[j];
 							set_bit(psx, gc->dev[i].absbit);
-							gc->dev[i].absmin[psx] = 4;
-							gc->dev[i].absmax[psx] = 252;
-							gc->dev[i].absflat[psx] = 2;
+							if (j < 4) {
+								gc->dev[i].absmin[psx] = 4;
+								gc->dev[i].absmax[psx] = 252;
+								gc->dev[i].absflat[psx] = 2;
+							} else {
+								gc->dev[i].absmin[psx] = -1;
+								gc->dev[i].absmax[psx] = 1;
+							}
 						}
+
+						for (j = 0; j < 12; j++)
+							set_bit(gc_psx_btn[j], gc->dev[i].keybit);
+
 						break;
 
-					case -1:
+					case 0:
 						gc->pads[GC_PSX] &= ~gc_status_bit[i];
-						pbtn = 0;
 						printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
 						break;
 
 					default:
 						gc->pads[GC_PSX] &= ~gc_status_bit[i];
-						pbtn = 0;
 						printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
 							" please report to <vojtech@suse.cz>.\n", psx);
 				}
-
-				for (j = 0; j < pbtn; j++)
-					set_bit(gc_psx_btn[j], gc->dev[i].keybit);
-
 				break;
 		}
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/iforce.c linux/drivers/char/joystick/iforce.c
--- v2.4.3/linux/drivers/char/joystick/iforce.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/iforce.c	Wed Apr 11 19:02:30 2001
@@ -33,6 +33,7 @@
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <linux/usb.h>
 #include <linux/serio.h>
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/ns558.c linux/drivers/char/joystick/ns558.c
--- v2.4.3/linux/drivers/char/joystick/ns558.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/ns558.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ns558.c,v 1.16 2000/08/17 20:03:56 vojtech Exp $
+ * $Id: ns558.c,v 1.27 2001/03/28 09:25:05 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *  Copyright (c) 1999 Brian Gerst
@@ -47,7 +47,7 @@
 #define NS558_PNP	2
 #define NS558_PCI	3
 
-static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
+static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
 				    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
 
 struct ns558 {
@@ -230,26 +230,30 @@
 /*
  * PnP IDs:
  *
+ * @P@0001 - ALS 100 (no comp. ID)
  * CTL00c1 - SB AWE32 PnP
  * CTL00c3 - SB AWE64 PnP
  * CTL00f0 - SB16 PnP / Vibra 16x
- * CTL7001 - SB Vibra16C PnP
- * CSC0b35 - Crystal ** doesn't have compatibility ID **
+ * CTL7001 - SB Vibra16C PnP (no comp. ID)
+ * CTL7002 - SB AWE32 (no comp. ID)
+ * CSC0b35 - Crystal (no comp. ID)
  * TER1141 - Terratec AD1818
  * YMM0800 - Yamaha OPL3-SA3
  *
  * PNPb02f - Generic gameport
  */
 
-static struct pnp_devid {
-	unsigned int vendor, device;
-} pnp_devids[] = {
-	{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) },
-	{ ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) },
-	{ ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) },
+static struct isapnp_device_id pnp_devids[] = {
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
 	{ 0, },
 };
 
+MODULE_DEVICE_TABLE(isapnp, pnp_devids);
+
 static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
 {
 	int ioport, iolen;
@@ -306,7 +310,7 @@
 	int i = 0;
 #ifdef NSS558_ISAPNP
 	struct pci_dev *dev = NULL;
-	struct pnp_devid *devid;
+	struct isapnp_device_id *devid;
 #endif
 
 /*
@@ -329,7 +333,7 @@
 
 #ifdef NSS558_ISAPNP
 	for (devid = pnp_devids; devid->vendor; devid++) {
-		while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) {
+		while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
 			ns558 = ns558_pnp_probe(dev, ns558);
 		}
 	}
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/sidewinder.c linux/drivers/char/joystick/sidewinder.c
--- v2.4.3/linux/drivers/char/joystick/sidewinder.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/sidewinder.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: sidewinder.c,v 1.16 2000/07/14 09:02:41 vojtech Exp $
+ * $Id: sidewinder.c,v 1.18 2001/02/28 07:09:30 vojtech Exp $
  *
  *  Copyright (c) 1998-2000 Vojtech Pavlik
  *
@@ -334,7 +334,7 @@
 				input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
 
 				for (j = 0; j < 10; j++)
-					input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
+					input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
 			}
 
 			return 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/spaceball.c linux/drivers/char/joystick/spaceball.c
--- v2.4.3/linux/drivers/char/joystick/spaceball.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/spaceball.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: spaceball.c,v 1.7 2000/06/24 11:55:40 vojtech Exp $
+ * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
@@ -108,10 +108,8 @@
 
 /*
  * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
- * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can
- * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think)
- * on whether the axis value is increasing, decreasing, or same as before.
- * (I don't see why this is useful).
+ * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
+ * can occur in the axis values.
  */
 
 static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
@@ -126,7 +124,7 @@
 			return;
 		case '^':
 			if (!spaceball->escape) {
-				spaceball->escape ^= 1;
+				spaceball->escape = 1;
 				return;
 			}
 			spaceball->escape = 0;
@@ -135,7 +133,7 @@
 		case 'S':
 			if (spaceball->escape) {
 				spaceball->escape = 0;
-				data = 0xd;
+				data &= 0x1f;
 			}
 		default:
 			if (spaceball->escape) {
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/stinger.c linux/drivers/char/joystick/stinger.c
--- v2.4.3/linux/drivers/char/joystick/stinger.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/joystick/stinger.c	Wed Apr 11 19:02:30 2001
@@ -0,0 +1,200 @@
+/*
+ * $Id: stinger.c,v 1.1 2000/07/17 10:42:14 vojtech Exp $
+ *
+ *  Copyright (c) 2000 Vojtech Pavlik
+ *  Copyright (c) 2000 Mark Fletcher
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Gravis Stinger gamepad driver for Linux
+ */
+
+/*
+ * This program is free warftware; 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define STINGER_MAX_LENGTH 8
+
+static char *stinger_name = "Gravis Stinger";
+
+/*
+ * Per-Stinger data.
+ */
+
+struct stinger {
+	struct input_dev dev;
+	int idx;
+	unsigned char data[STINGER_MAX_LENGTH];
+};
+
+/*
+ * stinger_process_packet() decodes packets the driver receives from the
+ * Stinger. It updates the data accordingly.
+ */
+
+static void stinger_process_packet(struct stinger *stinger)
+{
+	struct input_dev *dev = &stinger->dev;
+	unsigned char *data = stinger->data;
+
+	if (!stinger->idx) return;
+
+	input_report_key(dev, BTN_A,	  ((data[0] & 0x20) >> 5));
+	input_report_key(dev, BTN_B,	  ((data[0] & 0x10) >> 4));
+	input_report_key(dev, BTN_C,	  ((data[0] & 0x08) >> 3));
+	input_report_key(dev, BTN_X,	  ((data[0] & 0x04) >> 2));
+	input_report_key(dev, BTN_Y,	  ((data[3] & 0x20) >> 5));
+	input_report_key(dev, BTN_Z,	  ((data[3] & 0x10) >> 4));
+	input_report_key(dev, BTN_TL,     ((data[3] & 0x08) >> 3));
+	input_report_key(dev, BTN_TR,     ((data[3] & 0x04) >> 2));
+	input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
+	input_report_key(dev, BTN_START,   (data[3] & 0x01));
+
+	input_report_abs(dev, ABS_X, ((data[1] & 0x3F) - ((data[0] & 0x01) << 6)));
+	input_report_abs(dev, ABS_Y, ((data[2] & 0x3F) - ((data[0] & 0x02) << 5)));
+
+	return;
+}
+
+/*
+ * stinger_interrupt() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct stinger* stinger = serio->private;
+
+	/* All Stinger packets are 4 bytes */
+
+	if (stinger->idx < STINGER_MAX_LENGTH)
+		stinger->data[stinger->idx++] = data;
+
+	if (stinger->idx == 4) {
+		stinger_process_packet(stinger);
+		stinger->idx = 0;
+	}
+
+	return;
+}
+
+/*
+ * stinger_disconnect() is the opposite of stinger_connect()
+ */
+
+static void stinger_disconnect(struct serio *serio)
+{
+	struct stinger* stinger = serio->private;
+	input_unregister_device(&stinger->dev);
+	serio_close(serio);
+	kfree(stinger);
+}
+
+/*
+ * stinger_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Stinger, and if found, registers
+ * it as an input device.
+ */
+
+static void stinger_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct stinger *stinger;
+	int i;
+
+	if (serio->type != (SERIO_RS232 | SERIO_STINGER))
+		return;
+
+	if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
+		return;
+
+	memset(stinger, 0, sizeof(struct stinger));
+
+	stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
+					   BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
+					   BIT(BTN_START) | BIT(BTN_SELECT);
+	stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+	stinger->dev.name = stinger_name;
+	stinger->dev.idbus = BUS_RS232;
+	stinger->dev.idvendor = SERIO_STINGER;
+	stinger->dev.idproduct = 0x0001;
+	stinger->dev.idversion = 0x0100;
+
+	for (i = 0; i < 2; i++) {
+		stinger->dev.absmax[ABS_X+i] =  64;	
+		stinger->dev.absmin[ABS_X+i] = -64;	
+		stinger->dev.absflat[ABS_X+i] = 4;
+	}
+
+	stinger->dev.private = stinger;
+	
+	serio->private = stinger;
+
+	if (serio_open(serio, dev)) {
+		kfree(stinger);
+		return;
+	}
+
+	input_register_device(&stinger->dev);
+
+	printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev stinger_dev = {
+	interrupt:	stinger_interrupt,
+	connect:	stinger_connect,
+	disconnect:	stinger_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init stinger_init(void)
+{
+	serio_register_device(&stinger_dev);
+	return 0;
+}
+
+void __exit stinger_exit(void)
+{
+	serio_unregister_device(&stinger_dev);
+}
+
+module_init(stinger_init);
+module_exit(stinger_exit);
diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/tmdc.c linux/drivers/char/joystick/tmdc.c
--- v2.4.3/linux/drivers/char/joystick/tmdc.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/tmdc.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $
+ * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $
  *
  *  Copyright (c) 1998-2000 Vojtech Pavlik
  *
@@ -49,6 +49,8 @@
 
 #define TMDC_MODE_M3DI		1
 #define TMDC_MODE_3DRP		3
+#define TMDC_MODE_AT		4
+#define TMDC_MODE_FM		8
 #define TMDC_MODE_FGP		163
 
 #define TMDC_BYTE_ID		10
@@ -57,21 +59,35 @@
 
 #define TMDC_ABS		7	
 #define TMDC_ABS_HAT		4
-#define TMDC_BTN_PAD		10
-#define TMDC_BTN_JOY		16
+#define TMDC_BTN		16
 
 static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
 static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
 
-static unsigned char tmdc_abs[TMDC_ABS] =
+static signed char tmdc_abs[TMDC_ABS] =
 	{ ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
-static unsigned char tmdc_abs_hat[TMDC_ABS_HAT] =
+static signed char tmdc_abs_hat[TMDC_ABS_HAT] =
 	{ ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
-static unsigned short tmdc_btn_pad[TMDC_BTN_PAD] =
+static signed char tmdc_abs_at[TMDC_ABS] =
+	{ ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
+static signed char tmdc_abs_fm[TMDC_ABS] =
+	{ ABS_RX, ABS_RY, ABS_X, ABS_Y };
+
+static short tmdc_btn_pad[TMDC_BTN] =
 	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
-static unsigned short tmdc_btn_joy[TMDC_BTN_JOY] =
+static short tmdc_btn_joy[TMDC_BTN] =
 	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
  	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+static short tmdc_btn_fm[TMDC_BTN] =
+        { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
+static short tmdc_btn_at[TMDC_BTN] =
+        { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
+          BTN_BASE3, BTN_BASE2, BTN_BASE };
+
+static struct {
+        int x;
+        int y;
+} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
 
 struct tmdc {
 	struct gameport *gameport;
@@ -79,6 +95,11 @@
 	struct input_dev dev[2];
 	char name[2][64];
 	int mode[2];
+	signed char *abs[2];
+	short *btn[2];
+	unsigned char absc[2];
+	unsigned char btnc[2][4];
+	unsigned char btno[2][4];
 	int used;
 	int reads;
 	int bads;	
@@ -145,7 +166,7 @@
 	struct tmdc *tmdc = (void *) private;
 	struct input_dev *dev;
 	unsigned char r, bad = 0;
-	int i, j;
+	int i, j, k, l;
 
 	tmdc->reads++;
 
@@ -162,44 +183,34 @@
 
 			dev = tmdc->dev + j;
 
-			for (i = 0; i < data[j][TMDC_BYTE_DEF] >> 4; i++)
-				input_report_abs(dev, tmdc_abs[i], data[j][tmdc_byte_a[i]]);
+			for (i = 0; i < tmdc->absc[j]; i++) {
+				if (tmdc->abs[j][i] < 0) continue;
+				input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]);
+			}
 
 			switch (tmdc->mode[j]) {
 
 				case TMDC_MODE_M3DI:
 
 					i = tmdc_byte_d[0];
-
 					input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1));
 					input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i]       & 1));
-
-					for (i = 0; i < 4; i++)
-						input_report_key(dev, tmdc_btn_joy[i],
-							(data[j][tmdc_byte_d[0]] >> (i + 4)) & 1);
-					for (i = 0; i < 2; i++)
-						input_report_key(dev, tmdc_btn_joy[i + 4],
-							(data[j][tmdc_byte_d[1]] >> (i + 6)) & 1);
-
 					break;
 
-				case TMDC_MODE_3DRP:
-				case TMDC_MODE_FGP:
-
-					for (i = 0; i < 10; i++)
-						input_report_key(dev, tmdc_btn_pad[i],
-							(data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1);
+				case TMDC_MODE_AT:
 
+					i = tmdc_byte_a[3];
+					input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x);
+					input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y);
 					break;
 
-				default:
-
-					for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 0xf) << 3) && i < TMDC_BTN_JOY; i++)
-						input_report_key(dev, tmdc_btn_joy[i],
-							(data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1);
-
-					break;
+			}
 
+			for (k = l = 0; k < 4; k++) {
+				for (i = 0; i < tmdc->btnc[j][k]; i++)
+					input_report_key(dev, tmdc->btn[j][i + l],
+						((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
+				l += tmdc->btnc[j][k];
 			}
 	}
 
@@ -229,20 +240,25 @@
 
 static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
 {
-	struct tmdc *tmdc;
-	struct js_tm_models {
+	struct models {
 		unsigned char id;
 		char *name;
 		char abs;
 		char hats;
-		char joybtn;
-		char padbtn;
-	} models[] = {	{   1, "ThrustMaster Millenium 3D Inceptor",	  6, 0, 6,  0 },
-			{   3, "ThrustMaster Rage 3D Gamepad",		  2, 0, 0, 10 },
-			{ 163, "Thrustmaster Fusion GamePad",		  2, 0, 0, 10 },
-			{   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0,  0 }};
+		char btnc[4];
+		char btno[4];
+		signed char *axes;
+		short *buttons;
+	} models[] = {	{   1, "ThrustMaster Millenium 3D Inceptor",	  6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
+			{   3, "ThrustMaster Rage 3D Gamepad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
+			{   4, "ThrustMaster Attack Throttle",		  5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
+			{   8, "ThrustMaster FragMaster",		  4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
+			{ 163, "Thrustmaster Fusion GamePad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
+			{   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }};
+
 	unsigned char data[2][TMDC_MAX_LENGTH];
-	int i, j, m;
+	struct tmdc *tmdc;
+	int i, j, k, l, m;
 
 	if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
 		return;
@@ -268,12 +284,23 @@
 
 			for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++);
 
+			tmdc->abs[j] = models[m].axes;
+			tmdc->btn[j] = models[m].buttons;
+
 			if (!models[m].id) {
 				models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
-				models[m].joybtn = (data[j][TMDC_BYTE_DEF] & 0xf) << 3;
+				for (k = 0; k < 4; k++)
+					models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
 			}
 
-			sprintf(tmdc->name[j], models[m].name, models[m].abs, models[m].joybtn, tmdc->mode[j]);
+			tmdc->absc[j] = models[m].abs;
+			for (k = 0; k < 4; k++) {
+				tmdc->btnc[j][k] = models[m].btnc[k];
+				tmdc->btno[j][k] = models[m].btno[k];
+			}
+
+			sprintf(tmdc->name[j], models[m].name, models[m].abs,
+				(data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
 
 			tmdc->dev[j].private = tmdc;
 			tmdc->dev[j].open = tmdc_open;
@@ -288,11 +315,12 @@
 			tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
-				set_bit(tmdc_abs[i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc_abs[i]] = 8;
-				tmdc->dev[j].absmax[tmdc_abs[i]] = 248;
-				tmdc->dev[j].absfuzz[tmdc_abs[i]] = 2;
-				tmdc->dev[j].absflat[tmdc_abs[i]] = 4;
+				if (tmdc->abs[i] < 0) continue;
+				set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
+				tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
+				tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
+				tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
+				tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
 			}
 
 			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
@@ -301,11 +329,11 @@
 				tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
 			}
 
-			for (i = 0; i < models[m].joybtn && i < TMDC_BTN_JOY; i++)
-				set_bit(tmdc_btn_joy[i], tmdc->dev[j].keybit);
-
-			for (i = 0; i < models[m].padbtn && i < TMDC_BTN_PAD; i++)
-				set_bit(tmdc_btn_pad[i], tmdc->dev[j].keybit);
+			for (k = l = 0; k < 4; k++) {
+				for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
+					set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit);
+				l += models[m].btnc[k];
+			}
 
 			input_register_device(tmdc->dev + j);
 			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
diff -u --recursive --new-file v2.4.3/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c
--- v2.4.3/linux/drivers/char/machzwd.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/char/machzwd.c	Thu Apr 12 12:16:35 2001
@@ -26,6 +26,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.4.3/linux/drivers/char/mem.c	Mon Mar 19 12:35:08 2001
+++ linux/drivers/char/mem.c	Thu Apr 19 22:57:06 2001
@@ -41,6 +41,9 @@
 #ifdef CONFIG_MDA_CONSOLE
 extern void mda_console_init(void);
 #endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
+extern void tapechar_init(void);
+#endif
 #if defined(CONFIG_ADB)
 extern void adbdev_init(void);
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.4.3/linux/drivers/char/misc.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/char/misc.c	Fri Apr 13 20:26:07 2001
@@ -73,10 +73,8 @@
 extern int rtc_DP8570A_init(void);
 extern int rtc_MK48T08_init(void);
 extern int ds1286_init(void);
-extern int dsp56k_init(void);
 extern int radio_init(void);
 extern int pmu_device_init(void);
-extern int qpmouse_init(void);
 extern int tosh_init(void);
 
 static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -173,10 +171,20 @@
 int misc_register(struct miscdevice * misc)
 {
 	static devfs_handle_t devfs_handle;
-
+	struct miscdevice *c;
+	
 	if (misc->next || misc->prev)
 		return -EBUSY;
 	down(&misc_sem);
+	c = misc_list.next;
+
+	while ((c != &misc_list) && (c->minor != misc->minor))
+		c = c->next;
+	if (c != &misc_list) {
+		up(&misc_sem);
+		return -EBUSY;
+	}
+
 	if (misc->minor == MISC_DYNAMIC_MINOR) {
 		int i = DYNAMIC_MINORS;
 		while (--i >= 0)
@@ -245,9 +253,6 @@
 int __init misc_init(void)
 {
 	create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
-#if defined CONFIG_82C710_MOUSE
-	qpmouse_init();
-#endif
 #ifdef CONFIG_MVME16x
 	rtc_MK48T08_init();
 #endif
@@ -256,9 +261,6 @@
 #endif
 #ifdef CONFIG_SGI_DS1286
 	ds1286_init();
-#endif
-#ifdef CONFIG_ATARI_DSP56K
-	dsp56k_init();
 #endif
 #ifdef CONFIG_MISC_RADIO
 	radio_init();
diff -u --recursive --new-file v2.4.3/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- v2.4.3/linux/drivers/char/n_r3964.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/n_r3964.c	Fri Apr 13 20:26:07 2001
@@ -7,7 +7,7 @@
  * http://www.pap-philips.de
  * -----------------------------------------------------------
  * This software may be used and distributed according to the terms of
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  *
  * Author:
  * L. Haag
@@ -65,7 +65,7 @@
 
 //#define DEBUG_QUEUE
 
-/* Log successfull handshake and protocol operations  */
+/* Log successful handshake and protocol operations  */
 //#define DEBUG_PROTO_S
 
 /* Log handshake and protocol errors: */
@@ -983,13 +983,14 @@
    {
 queue_the_message:
 
-      save_flags(flags);
-      cli();
-
       pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
       TRACE_M("add_msg - kmalloc %x",(int)pMsg);
-      if(pMsg==NULL)
+      if(pMsg==NULL) {
          return;
+      }
+
+      save_flags(flags);
+      cli();
 
       pMsg->msg_id = msg_id;
       pMsg->arg    = arg;
diff -u --recursive --new-file v2.4.3/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.4.3/linux/drivers/char/n_tty.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/n_tty.c	Fri Apr  6 10:42:55 2001
@@ -15,7 +15,7 @@
  * This file also contains code originally written by Linus Torvalds,
  * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
  * 
- * This file may be redistributed under the terms of the GNU Public
+ * This file may be redistributed under the terms of the GNU General Public
  * License.
  *
  * Reduced memory usage for older ARM systems  - Russell King.
@@ -100,7 +100,7 @@
 	unsigned long flags;
 	/*
 	 *	The problem of stomping on the buffers ends here.
-	 *	Why didn't anyone see this one comming? --AJK
+	 *	Why didn't anyone see this one coming? --AJK
 	*/
 	spin_lock_irqsave(&tty->read_lock, flags);
 	put_tty_queue_nolock(c, tty);
diff -u --recursive --new-file v2.4.3/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.4.3/linux/drivers/char/pc_keyb.c	Fri Mar  2 18:38:37 2001
+++ linux/drivers/char/pc_keyb.c	Fri Apr  6 10:42:55 2001
@@ -1016,6 +1016,8 @@
 
 	misc_register(&psaux_mouse);
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	if (queue == NULL)
+		panic("psaux_init(): out of memory");
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
 	init_waitqueue_head(&queue->proc_list);
diff -u --recursive --new-file v2.4.3/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.4.3/linux/drivers/char/pcwd.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/pcwd.c	Fri Apr  6 10:42:55 2001
@@ -462,8 +462,8 @@
 			outb_p(0xA5, current_readport + 3);
 			spin_unlock(&io_lock);
 		}
-		unlock_kernel();
 #endif
+		unlock_kernel();
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c
--- v2.4.3/linux/drivers/char/qpmouse.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/qpmouse.c	Fri Apr 13 20:26:07 2001
@@ -24,9 +24,8 @@
  */
 
 #include <linux/module.h>
- 
-#include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
@@ -146,11 +145,11 @@
 	fasync_qp(-1, file, 0);
 	if (!--qp_count) {
 		if (!poll_qp_status())
-			printk("Warning: Mouse device busy in release_qp()\n");
+			printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
 		status = inb_p(qp_status);
 		outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
 		if (!poll_qp_status())
-			printk("Warning: Mouse device busy in release_qp()\n");
+			printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
 		free_irq(QP_IRQ, NULL);
 	}
 	unlock_kernel();
@@ -188,7 +187,7 @@
 	outb_p(status, qp_status);              /* Enable interrupts */
 
 	while (!poll_qp_status()) {
-		printk("Error: Mouse device busy in open_qp()\n");
+		printk(KERN_ERR "Error: Mouse device busy in open_qp()\n");
 		qp_count--;
 		status &= ~(QP_ENABLE|QP_INTS_ON);
 		outb_p(status, qp_status);
@@ -303,7 +302,9 @@
  * Initialize driver.
  */
 static struct miscdevice qp_mouse = {
-	PSMOUSE_MINOR, "QPmouse", &qp_fops
+	minor:		PSMOUSE_MINOR,
+	name:		"QPmouse",
+	fops:		&qp_fops,
 };
 
 /*
@@ -337,37 +338,36 @@
 	return 1;
 }
 
-int __init qpmouse_init(void)
+static const char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n";
+static const char msg_nomem[]  __initdata = KERN_ERR "qpmouse: no queue memory.\n";
+
+static int __init qpmouse_init_driver(void)
 {
 	if (!probe_qp())
 		return -EIO;
 
-	printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
+	printk(msg_banner);
+
 /*	printk("82C710 address = %x (should be 0x310)\n", qp_data); */
 	queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
-	if(queue==NULL)
-	{
-		printk(KERN_ERR "qpmouse: no queue memory.\n");
+	if (queue == NULL) {
+		printk(msg_nomem);
 		return -ENOMEM;
-	}	
+	}
 	qp_present = 1;
 	misc_register(&qp_mouse);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
 	init_waitqueue_head(&queue->proc_list);
-
 	return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-	return qpmouse_init();
-}
-
-void cleanup_module(void)
+static void __exit qpmouse_exit_driver(void)
 {
 	misc_deregister(&qp_mouse);
 	kfree(queue);
 }
-#endif
+
+module_init(qpmouse_init_driver);
+module_exit(qpmouse_exit_driver);
+
diff -u --recursive --new-file v2.4.3/linux/drivers/char/qtronix.c linux/drivers/char/qtronix.c
--- v2.4.3/linux/drivers/char/qtronix.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/qtronix.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,597 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Qtronix 990P infrared keyboard driver.
+ *
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.com
+ *
+ *
+ *  The bottom portion of this driver was take from 
+ *  pc_keyb.c  Please see that file for copyrights.
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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>
+
+/* 
+ * NOTE:  
+ *
+ *	This driver has only been tested with the Consumer IR
+ *	port of the ITE 8172 system controller.
+ *
+ *	You do not need this driver if you are using the ps/2 or
+ *	USB adapter that the keyboard ships with.  You only need 
+ *	this driver if your board has a IR port and the keyboard
+ *	data is being sent directly to the IR.  In that case,
+ *	you also need some low-level IR support. See it8172_cir.c.
+ *	
+ */
+
+#ifdef CONFIG_QTRONIX_KEYBOARD
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_int.h>
+#include <asm/it8172/it8172_cir.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/kbd_kern.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <linux/pc_keyb.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define leading1 0
+#define leading2 0xF
+
+#define KBD_CIR_PORT 0
+#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
+
+static int data_index;
+struct cir_port *cir;
+static unsigned char kbdbytes[5];
+static unsigned char cir_data[32]; /* we only need 16 chars */
+
+static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+static int handle_data(unsigned char *p_data);
+static inline void handle_mouse_event(unsigned char scancode);
+static inline void handle_keyboard_event(unsigned char scancode, int down);
+static int __init psaux_init(void);
+
+static struct aux_queue *queue;	/* Mouse data buffer. */
+static int aux_count = 0;
+
+/*
+ * Keys accessed through the 'Fn' key
+ * The Fn key does not produce a key-up sequence. So, the first
+ * time the user presses it, it will be key-down event. The key
+ * stays down until the user presses it again.
+ */
+#define NUM_FN_KEYS 56
+static unsigned char fn_keys[NUM_FN_KEYS] = {
+	0,0,0,0,0,0,0,0,        /* 0 7   */
+	8,9,10,93,0,0,0,0,      /* 8 15  */
+	0,0,0,0,0,0,0,5,        /* 16 23 */
+	6,7,91,0,0,0,0,0,       /* 24 31 */
+	0,0,0,0,0,2,3,4,        /* 32 39 */
+	92,0,0,0,0,0,0,0,       /* 40 47 */
+	0,0,0,0,11,0,94,95        /* 48 55 */
+
+};
+
+void init_qtronix_990P_kbd(void)
+{
+	int retval;
+
+	cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);
+	if (!cir) {
+		printk("Unable to initialize Qtronix keyboard\n");
+		return;
+	}
+
+	/* 
+	 * revisit
+	 * this should be programmable, somehow by the, by the user.
+	 */
+	cir->port = KBD_CIR_PORT;
+	cir->baud_rate = 0x1d;
+	cir->rdwos = 0;
+	cir->rxdcr = 0x3;
+	cir->hcfs = 0;
+	cir->fifo_tl = 0;
+	cir->cfq = 0x1d;
+	cir_port_init(cir);
+
+	retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler, 
+			(unsigned long )(SA_INTERRUPT|SA_SHIRQ), 
+			(const char *)"Qtronix IR Keyboard", (void *)cir);
+
+	if (retval) {
+		printk("unable to allocate cir %d irq %d\n", 
+				cir->port, IT8172_CIR0_IRQ);
+	}
+#ifdef CONFIG_PSMOUSE
+	psaux_init();
+#endif
+}
+
+static inline unsigned char BitReverse(unsigned short key)
+{
+	unsigned char rkey = 0;
+	rkey |= (key & 0x1) << 7;
+	rkey |= (key & 0x2) << 5;
+	rkey |= (key & 0x4) << 3;
+	rkey |= (key & 0x8) << 1;
+	rkey |= (key & 0x10) >> 1;
+	rkey |= (key & 0x20) >> 3;
+	rkey |= (key & 0x40) >> 5;
+	rkey |= (key & 0x80) >> 7;
+	return rkey;
+
+}
+
+
+static inline u_int8_t UpperByte(u_int8_t data)
+{
+	return (data >> 4);
+}
+
+
+static inline u_int8_t LowerByte(u_int8_t data)
+{
+	return (data & 0xF);
+}
+
+
+int CheckSumOk(u_int8_t byte1, u_int8_t byte2, 
+		u_int8_t byte3, u_int8_t byte4, u_int8_t byte5)
+{
+	u_int8_t CheckSum;
+
+	CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;
+	if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )
+		return 0;
+	else
+		return 1;
+}
+
+
+static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct cir_port *cir;
+	int j;
+	unsigned char int_status;
+
+	cir = (struct cir_port *)dev_id;
+	int_status = get_int_status(cir);;
+	if (int_status & 0x4) {
+		clear_fifo(cir);
+		return;
+	}
+
+	while (cir_get_rx_count(cir)) {
+
+		cir_data[data_index] = cir_read_data(cir);
+
+		if (data_index == 0) {/* expecting first byte */
+			if (cir_data[data_index] != leading1) {
+				//printk("!leading byte %x\n", cir_data[data_index]);
+				set_rx_active(cir);
+				clear_fifo(cir);
+				continue;
+			}
+		}
+		if (data_index == 1) {
+			if ((cir_data[data_index] & 0xf) != leading2) {
+				set_rx_active(cir);
+				data_index = 0; /* start over */
+				clear_fifo(cir);
+				continue;
+			}
+		}
+
+		if ( (cir_data[data_index] == 0xff)) { /* last byte */
+			//printk("data_index %d\n", data_index);
+			set_rx_active(cir);
+#if 0
+			for (j=0; j<=data_index; j++) {
+				printk("rx_data %d:  %x\n", j, cir_data[j]);
+			}
+#endif
+			data_index = 0;
+			handle_data(cir_data);
+			return;
+		}
+		else if (data_index>16) {
+			set_rx_active(cir);
+#if 0
+			printk("warning: data_index %d\n", data_index);
+			for (j=0; j<=data_index; j++) {
+				printk("rx_data %d:  %x\n", j, cir_data[j]);
+			}
+#endif
+			data_index = 0;
+			clear_fifo(cir);
+			return;
+		}
+		data_index++;
+	}
+}
+
+
+#define NUM_KBD_BYTES 5
+static int handle_data(unsigned char *p_data)
+{
+	u_int32_t bit_bucket;
+	u_int32_t i, j;
+	u_int32_t got_bits, next_byte;
+	int down = 0;
+
+	/* Reorganize the bit stream */
+	for (i=0; i<16; i++)
+		p_data[i] = BitReverse(~p_data[i]);
+
+	/* 
+	 * We've already previously checked that p_data[0]
+	 * is equal to leading1 and that (p_data[1] & 0xf)
+	 * is equal to leading2. These twelve bits are the
+	 * leader code.  We can now throw them away (the 12
+	 * bits) and continue parsing the stream.
+	 */
+	bit_bucket = p_data[1] << 12;
+	got_bits = 4;
+	next_byte = 2;
+
+	/* 
+	 * Process four bits at a time
+	 */
+	for (i=0; i<NUM_KBD_BYTES; i++) {
+
+		kbdbytes[i]=0;
+
+		for (j=0; j<8; j++) /* 8 bits per byte */
+		{
+			if (got_bits < 4) {
+				bit_bucket |= (p_data[next_byte++] << (8 - got_bits));
+				got_bits += 8;
+			}
+
+			if ((bit_bucket & 0xF000) == 0x8000) { 
+				/* Convert 1000b to 1 */
+				kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);
+				got_bits -= 4;
+				bit_bucket = bit_bucket << 4;
+			}
+			else if ((bit_bucket & 0xC000) == 0x8000) {
+				/* Convert 10b to 0 */
+				kbdbytes[i] =  kbdbytes[i] >> 1;
+				got_bits -= 2;
+				bit_bucket = bit_bucket << 2;
+			}
+			else {
+				/* bad serial stream */
+				return 1;
+			}
+
+			if (next_byte > 16) {
+				//printk("error: too many bytes\n");
+				return 1;
+			}
+		}
+	}
+
+
+	if (!CheckSumOk(kbdbytes[0], kbdbytes[1], 
+				kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
+		//printk("checksum failed\n");
+		return 1;
+	}
+
+	if (kbdbytes[1] & 0x08) {
+		//printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);
+		handle_mouse_event(kbdbytes[1]);
+		handle_mouse_event(kbdbytes[2]);
+		handle_mouse_event(kbdbytes[3]);
+	}
+	else {
+		if (kbdbytes[2] == 0) down = 1;
+#if 0
+		if (down)
+			printk("down %d\n", kbdbytes[3]);
+		else
+			printk("up %d\n", kbdbytes[3]);
+#endif
+		handle_keyboard_event(kbdbytes[3], down);
+	}
+	return 0;
+}
+
+
+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned char handle_kbd_event(void);
+
+
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	printk("pckbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
+	return 0;
+}
+
+int pckbd_getkeycode(unsigned int scancode)
+{
+	return scancode;
+}
+
+
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode)
+{
+	static int prev_scancode = 0;
+
+	if (scancode == 0x00 || scancode == 0xff) {
+		prev_scancode = 0;
+		return 0;
+	}
+
+	/* todo */
+	if (!prev_scancode && scancode == 160) { /* Fn key down */
+		//printk("Fn key down\n");
+		prev_scancode = 160;
+		return 0;
+	}
+	else if (prev_scancode && scancode == 160) { /* Fn key up */
+		//printk("Fn key up\n");
+		prev_scancode = 0;
+		return 0;
+	}
+
+	/* todo */
+	if (prev_scancode == 160) {
+		if (scancode <= NUM_FN_KEYS) {
+			*keycode = fn_keys[scancode];
+			//printk("fn keycode %d\n", *keycode);
+		}
+		else
+			return 0;
+	} 
+	else if (scancode <= 127) {
+		*keycode = scancode;
+	}
+	else
+		return 0;
+
+
+ 	return 1;
+}
+
+char pckbd_unexpected_up(unsigned char keycode)
+{
+	//printk("pckbd_unexpected_up\n");
+	return 0;
+}
+
+static unsigned char kbd_exists = 1;
+
+static inline void handle_keyboard_event(unsigned char scancode, int down)
+{
+	kbd_exists = 1;
+	handle_scancode(scancode, down);
+	tasklet_schedule(&keyboard_tasklet);
+}	
+
+
+void pckbd_leds(unsigned char leds)
+{
+}
+
+/* dummy */
+void pckbd_init_hw(void)
+{
+}
+
+
+
+static inline void handle_mouse_event(unsigned char scancode)
+{
+	if(scancode == AUX_RECONNECT){
+		queue->head = queue->tail = 0;  /* Flush input queue */
+	//	__aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
+		return;
+	}
+
+	add_mouse_randomness(scancode);
+	if (aux_count) {
+		int head = queue->head;
+
+		queue->buf[head] = scancode;
+		head = (head + 1) & (AUX_BUF_SIZE-1);
+		if (head != queue->tail) {
+			queue->head = head;
+			kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+			wake_up_interruptible(&queue->proc_list);
+		}
+	}
+}
+
+static unsigned char get_from_queue(void)
+{
+	unsigned char result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_controller_lock, flags);
+	result = queue->buf[queue->tail];
+	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+	spin_unlock_irqrestore(&kbd_controller_lock, flags);
+	return result;
+}
+
+
+static inline int queue_empty(void)
+{
+	return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+	int retval;
+
+	//printk("fasync_aux\n");
+	retval = fasync_helper(fd, filp, on, &queue->fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+	lock_kernel();
+	fasync_aux(-1, file, 0);
+	aux_count--;
+	unlock_kernel();
+	return 0;
+}
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+	if (aux_count++) {
+		return 0;
+	}
+	queue->head = queue->tail = 0;		/* Flush input queue */
+	return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+			size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t i = count;
+	unsigned char c;
+
+	if (queue_empty()) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		add_wait_queue(&queue->proc_list, &wait);
+repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (queue_empty() && !signal_pending(current)) {
+			schedule();
+			goto repeat;
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&queue->proc_list, &wait);
+	}
+	while (i > 0 && !queue_empty()) {
+		c = get_from_queue();
+		put_user(c, buffer++);
+		i--;
+	}
+	if (count-i) {
+		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+		return count-i;
+	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+	return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+			 size_t count, loff_t *ppos)
+{
+	/*
+	 * The ITE boards this was tested on did not have the
+	 * transmit wires connected.
+	 */
+	return count;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+	poll_wait(file, &queue->proc_list, wait);
+	if (!queue_empty())
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+struct file_operations psaux_fops = {
+	read:		read_aux,
+	write:		write_aux,
+	poll:		aux_poll,
+	open:		open_aux,
+	release:	release_aux,
+	fasync:		fasync_aux,
+};
+
+/*
+ * Initialize driver.
+ */
+static struct miscdevice psaux_mouse = {
+	PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+static int __init psaux_init(void)
+{
+	misc_register(&psaux_mouse);
+	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	memset(queue, 0, sizeof(*queue));
+	queue->head = queue->tail = 0;
+	init_waitqueue_head(&queue->proc_list);
+
+	return 0;
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/char/qtronixmap.map linux/drivers/char/qtronixmap.map
--- v2.4.3/linux/drivers/char/qtronixmap.map	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/qtronixmap.map	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,287 @@
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+#	keymaps 0-2,4-6,8,12
+# in case you want the entries
+#	altgr   control keycode  83 = Boot            
+#	altgr   control keycode 111 = Boot            
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode   1 = grave        asciitilde
+	alt     keycode   1 = Meta_Escape     
+keycode   2 = one              exclam          
+	alt     keycode   2 = Meta_one        
+keycode   3 = two              at               at              
+	control	keycode   3 = nul             
+	shift	control	keycode   3 = nul             
+	alt	keycode   3 = Meta_two        
+keycode   4 = three            numbersign      
+	control keycode   4 = Escape          
+	alt     keycode   4 = Meta_three      
+keycode   5 = four             dollar           dollar          
+	control keycode   5 = Control_backslash
+	alt     keycode   5 = Meta_four       
+keycode   6 = five             percent         
+	control keycode   6 = Control_bracketright
+	alt     keycode   6 = Meta_five       
+keycode   7 = six              asciicircum     
+	control keycode   7 = Control_asciicircum
+	alt     keycode   7 = Meta_six        
+keycode   8 = seven            ampersand        braceleft       
+	control keycode   8 = Control_underscore
+	alt     keycode   8 = Meta_seven      
+keycode   9 = eight            asterisk         bracketleft     
+	control keycode   9 = Delete          
+	alt     keycode   9 = Meta_eight      
+keycode  10 = nine             parenleft        bracketright    
+	alt     keycode  10 = Meta_nine       
+keycode  11 = zero             parenright       braceright      
+	alt     keycode  11 = Meta_zero       
+keycode  12 = minus            underscore       backslash       
+	control	keycode  12 = Control_underscore
+	shift	control	keycode  12 = Control_underscore
+	alt	keycode  12 = Meta_minus      
+keycode  13 = equal            plus            
+	alt     keycode  13 = Meta_equal      
+keycode  15 = Delete           Delete          
+	control keycode  15 = BackSpace
+	alt     keycode  15 = Meta_Delete     
+keycode  16 = Tab              Tab             
+	alt     keycode  16 = Meta_Tab        
+keycode  17 = q               
+keycode  18 = w               
+keycode  19 = e
+keycode  20 = r               
+keycode  21 = t               
+keycode  22 = y               
+keycode  23 = u	 
+keycode  24 = i               
+keycode  25 = o               
+keycode  26 = p               
+keycode  27 = bracketleft      braceleft       
+	control keycode  27 = Escape          
+	alt     keycode  27 = Meta_bracketleft
+keycode  28 = bracketright     braceright
+	control keycode  28 = Control_bracketright
+	alt     keycode  28 = Meta_bracketright
+keycode  29 = backslash        bar             
+	control keycode  29 = Control_backslash
+	alt     keycode  29 = Meta_backslash  
+keycode  30 = Caps_Lock
+keycode  31 = a               
+keycode  32 = s
+keycode  33 = d
+keycode  34 = f               
+keycode  35 = g               
+keycode  36 = h               
+keycode  37 = j               
+keycode  38 = k               
+keycode  39 = l               
+keycode  40 = semicolon        colon           
+	alt     keycode  39 = Meta_semicolon  
+keycode  41 = apostrophe       quotedbl        
+	control keycode  40 = Control_g       
+	alt     keycode  40 = Meta_apostrophe 
+keycode  42 = grave            asciitilde      
+	control keycode  41 = nul             
+	alt     keycode  41 = Meta_grave      
+keycode  43 = Return          
+	alt     keycode  43 = Meta_Control_m  
+keycode  44 = Shift               
+keycode  46 = z
+keycode  47 = x               
+keycode  48 = c
+keycode  49 = v               
+keycode  50 = b               
+keycode  51 = n
+keycode  52 = m
+keycode  53 = comma            less            
+	alt     keycode  51 = Meta_comma      
+keycode  54 = period           greater         
+	control keycode  52 = Compose         
+	alt     keycode  52 = Meta_period     
+keycode  55 = slash            question        
+	control keycode  53 = Delete          
+	alt     keycode  53 = Meta_slash      
+keycode  57 = Shift
+keycode  58 = Control
+keycode  60 = Alt
+keycode  61 = space            space           
+	control keycode  61 = nul             
+	alt     keycode  61 = Meta_space      
+keycode  62 = Alt
+
+keycode 75 = Insert          
+keycode 76 = Delete          
+
+keycode 83 = Up              
+keycode 84 = Down              
+
+keycode 85 = Prior           
+	shift   keycode 85 = Scroll_Backward 
+keycode 86 = Next            
+	shift   keycode 86 = Scroll_Forward  
+keycode 89 = Right           
+	alt     keycode 89 = Incr_Console
+keycode 79 = Left            
+	alt     keycode 79 = Decr_Console
+
+keycode  90 = Num_Lock
+	shift   keycode  90 = Bare_Num_Lock
+
+keycode 91 = minus
+keycode 92 = plus
+keycode 93 = KP_Multiply
+keycode 94 = period
+keycode 95 = KP_Divide
+
+keycode 107 = Select          
+keycode 108 = Down            
+
+keycode 110 = Escape           Escape          
+	alt     keycode   1 = Meta_Escape     
+
+keycode  112 = F1              F11              Console_13      
+	control keycode  112 = F1              
+	alt     keycode  112 = Console_1       
+	control alt     keycode  112 = Console_1       
+keycode  113 = F2              F12              Console_14      
+	control keycode  113 = F2              
+	alt     keycode  113 = Console_2       
+	control alt     keycode  113 = Console_2       
+keycode  114 = F3              F13              Console_15      
+	control keycode  114 = F3              
+	alt     keycode  114 = Console_3       
+	control alt     keycode  114 = Console_3       
+keycode  115 = F4              F14              Console_16      
+	control keycode  115 = F4              
+	alt     keycode  115 = Console_4       
+	control alt     keycode  115 = Console_4       
+keycode  116 = F5              F15              Console_17      
+	control keycode  116 = F5              
+	alt     keycode  116 = Console_5       
+	control alt     keycode  116 = Console_5       
+keycode  117 = F6              F16              Console_18      
+	control keycode  117 = F6              
+	alt     keycode  117 = Console_6       
+	control alt     keycode  117 = Console_6       
+keycode  118 = F7              F17              Console_19      
+	control keycode  118 = F7              
+	alt     keycode  118 = Console_7       
+	control alt     keycode  118 = Console_7       
+keycode  119 = F8              F18              Console_20      
+	control keycode  119 = F8              
+	alt     keycode  119 = Console_8       
+	control alt     keycode  119 = Console_8       
+keycode  120 = F9              F19              Console_21      
+	control keycode  120 = F9              
+	alt     keycode  120 = Console_9       
+	control alt     keycode  120 = Console_9       
+keycode  121 = F10             F20              Console_22      
+	control keycode  121 = F10             
+	alt     keycode  121 = Console_10      
+	control alt     keycode  121 = Console_10      
+	
+keycode 126 = Pause           
+
+
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'Ŕ'
+compose '`' 'a' to 'ŕ'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ă'
+compose '~' 'a' to 'ă'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Ĺ'
+compose 'o' 'a' to 'ĺ'
+compose '0' 'A' to 'Ĺ'
+compose '0' 'a' to 'ĺ'
+compose 'A' 'A' to 'Ĺ'
+compose 'a' 'a' to 'ĺ'
+compose 'A' 'E' to 'Ć'
+compose 'a' 'e' to 'ć'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'Č'
+compose '`' 'e' to 'č'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ę'
+compose '^' 'e' to 'ę'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ě'
+compose '`' 'i' to 'ě'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ď'
+compose '"' 'i' to 'ď'
+compose '-' 'D' to 'Đ'
+compose '-' 'd' to 'đ'
+compose '~' 'N' to 'Ń'
+compose '~' 'n' to 'ń'
+compose '`' 'O' to 'Ň'
+compose '`' 'o' to 'ň'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Ő'
+compose '~' 'o' to 'ő'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ř'
+compose '/' 'o' to 'ř'
+compose '`' 'U' to 'Ů'
+compose '`' 'u' to 'ů'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Ű'
+compose '^' 'u' to 'ű'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Ţ'
+compose 't' 'h' to 'ţ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to '˙'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to '˙'
diff -u --recursive --new-file v2.4.3/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c
--- v2.4.3/linux/drivers/char/rio/rio_linux.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/rio_linux.c	Fri Apr 13 20:26:07 2001
@@ -1031,8 +1031,10 @@
  free2:kfree (p->RIOHosts);
  free1:kfree (p);
  free0:
-  rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", 
-               p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+  if (p) {
+	rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", 
+        	       p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+  }
   return -ENOMEM;
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/rio/rioctrl.c linux/drivers/char/rio/rioctrl.c
--- v2.4.3/linux/drivers/char/rio/rioctrl.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/rioctrl.c	Fri Apr 13 20:26:07 2001
@@ -764,7 +764,7 @@
 							PortP->Config &= ~RIO_WAITDRAIN;
 					 	}
 					 /*
-					 ** Store setings if locking or unlocking port or if the
+					 ** Store settings if locking or unlocking port or if the
 					 ** port is not locked, when setting the store option.
 					 */
 					 if (PortP->Mapped &&
diff -u --recursive --new-file v2.4.3/linux/drivers/char/scan_keyb.c linux/drivers/char/scan_keyb.c
--- v2.4.3/linux/drivers/char/scan_keyb.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/scan_keyb.c	Wed Apr 11 21:24:52 2001
@@ -18,33 +18,40 @@
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/kbd_kern.h>
+#include <linux/timer.h>
+
+#define SCANHZ	(HZ/20)
 
 struct scan_keyboard {
 	struct scan_keyboard *next;
-	void (*scan)(unsigned char *buffer);
+	int (*scan)(unsigned char *buffer);
 	const unsigned char *table;
 	unsigned char *s0, *s1;
 	int length;
 };
-		     
+
+static int scan_jiffies=0;
 static struct scan_keyboard *keyboards=NULL;
-static struct tq_struct task_scan_kbd;	
+struct timer_list scan_timer;
 
 static void check_kbd(const unsigned char *table,
 		      unsigned char *new, unsigned char *old, int length)
 {
 	int need_tasklet_schedule=0;
-	unsigned char xor, bit;
+	unsigned int xor, bit;
 	
 	while(length-->0) {
 		if((xor=*new^*old)==0) {
 			table+=8;
 		}
 		else {
-			for(bit=0x80; bit!=0; bit>>=1) {
+			for(bit=0x01; bit<0x100; bit<<=1) {
 				if(xor&bit) {
 					handle_scancode(*table, !(*new&bit));
 					need_tasklet_schedule=1;
+#if 0
+					printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed");
+#endif
 				}
 				table++;
 			}
@@ -57,26 +64,39 @@
 }
 
 
-static void scan_kbd(void *dummy)
+static void scan_kbd(unsigned long dummy)
 {
 	struct scan_keyboard *kbd;
 
+	scan_jiffies++;
+
 	for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
-		if(jiffies&1) {
-			kbd->scan(kbd->s0);
-			check_kbd(kbd->table, kbd->s0, kbd->s1, kbd->length);
+		if(scan_jiffies&1) {
+			if(!kbd->scan(kbd->s0))
+				check_kbd(kbd->table,
+					  kbd->s0, kbd->s1, kbd->length);
+			else
+				memcpy(kbd->s0, kbd->s1, kbd->length);
 		}
 		else {
-			kbd->scan(kbd->s1);
-			check_kbd(kbd->table, kbd->s1, kbd->s0, kbd->length);
+			if(!kbd->scan(kbd->s1))
+				check_kbd(kbd->table,
+					  kbd->s1, kbd->s0, kbd->length);
+			else
+				memcpy(kbd->s1, kbd->s0, kbd->length);
 		}
 		
 	}
-	queue_task(&task_scan_kbd, &tq_timer);
+
+	init_timer(&scan_timer);
+	scan_timer.expires = jiffies + SCANHZ;
+	scan_timer.data = 0;
+	scan_timer.function = scan_kbd;
+	add_timer(&scan_timer);
 }
 
 
-int register_scan_keyboard(void (*scan)(unsigned char *buffer),
+int register_scan_keyboard(int (*scan)(unsigned char *buffer),
 			   const unsigned char *table,
 			   int length)
 {
@@ -98,8 +118,8 @@
 	if (kbd->s1 == NULL)
 		goto error_free_s0;
 
-	kbd->scan(kbd->s0);
-	kbd->scan(kbd->s1);
+	memset(kbd->s0, -1, kbd->length);
+	memset(kbd->s1, -1, kbd->length);
 	
 	kbd->next=keyboards;
 	keyboards=kbd;
@@ -119,11 +139,11 @@
 			      
 void __init scan_kbd_init(void)
 {
+	init_timer(&scan_timer);
+	scan_timer.expires = jiffies + SCANHZ;
+	scan_timer.data = 0;
+	scan_timer.function = scan_kbd;
+	add_timer(&scan_timer);
 
-	INIT_LIST_HEAD(task_scan_kbd.list);
-	task_scan_kbd.sync=0;
-	task_scan_kbd.routine=scan_kbd;
-	task_scan_kbd.data=NULL;
-	queue_task(&task_scan_kbd, &tq_timer);
 	printk(KERN_INFO "Generic scan keyboard driver initialized\n");
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/char/scan_keyb.h linux/drivers/char/scan_keyb.h
--- v2.4.3/linux/drivers/char/scan_keyb.h	Fri Jul 21 14:21:06 2000
+++ linux/drivers/char/scan_keyb.h	Wed Apr 11 21:24:52 2001
@@ -6,7 +6,7 @@
  *	Generic scan keyboard driver
  */
 
-int register_scan_keyboard(void (*scan)(unsigned char *buffer),
+int register_scan_keyboard(int (*scan)(unsigned char *buffer),
 			   const unsigned char *table,
 			   int length);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.4.3/linux/drivers/char/serial.c	Tue Mar  6 20:13:51 2001
+++ linux/drivers/char/serial.c	Fri Apr 13 20:26:07 2001
@@ -59,8 +59,8 @@
  *
  */
 
-static char *serial_version = "5.05";
-static char *serial_revdate = "2000-12-13";
+static char *serial_version = "5.05a";
+static char *serial_revdate = "2001-03-20";
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -3924,11 +3924,6 @@
 	       return;
        }
 
-       if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) {
-	       printk("serial: PCI device enable failed\n");
-	       return;
-       }
-
 	/*
 	 * Run the initialization function, if any
 	 */
@@ -4610,7 +4605,8 @@
 	 * (Should we try to make guesses for multiport serial devices
 	 * later?) 
 	 */
-	if ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL ||
+	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+	    ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
 	    (dev->class & 0xff) > 6)
 		return 1;
 
@@ -4639,6 +4635,7 @@
 				     const struct pci_device_id *ent)
 {
 	struct pci_board *board, tmp;
+	int rc;
 
 	for (board = pci_boards; board->vendor; board++) {
 		if (board->vendor != (unsigned short) PCI_ANY_ID &&
@@ -4656,6 +4653,9 @@
 		break;
 	}
 
+	rc = pci_enable_device(dev);
+	if (rc) return rc;
+
 	if (board->vendor == 0 && serial_pci_guess_board(dev, board))
 		return -ENODEV;
 	else if (serial_pci_guess_board(dev, &tmp) == 0) {
@@ -4708,6 +4708,8 @@
 static struct pci_device_id serial_pci_tbl[] __devinitdata = {
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 	 PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, },
        { 0, }
 };
 
@@ -5724,6 +5726,10 @@
 		case 9600:
 		default:
 			cflag |= B9600;
+			/*
+			 * Set this to a sane value to prevent a divide error
+			 */
+			baud  = 9600;
 			break;
 	}
 	switch(bits) {
diff -u --recursive --new-file v2.4.3/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- v2.4.3/linux/drivers/char/sh-sci.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/sh-sci.c	Wed Apr 11 21:24:52 2001
@@ -74,6 +74,8 @@
 static void sci_hungup(void *ptr);
 static void sci_close(void *ptr);
 static int sci_chars_in_buffer(void *ptr);
+static int sci_request_irq(struct sci_port *port);
+static void sci_free_irq(struct sci_port *port);
 static int sci_init_drivers(void);
 
 static struct tty_driver sci_driver, sci_callout_driver;
@@ -83,8 +85,8 @@
 static struct termios *sci_termios[SCI_NPORTS];
 static struct termios *sci_termios_locked[SCI_NPORTS];
 
-int sci_refcount;
-int sci_debug = 0;
+static int sci_refcount;
+static int sci_debug = 0;
 
 #ifdef MODULE
 MODULE_PARM(sci_debug, "i");
@@ -102,7 +104,7 @@
 	do
 		status = sci_in(port, SCxSR);
 	while (!(status & SCxSR_TDxE(port)));
-  
+	
 	sci_out(port, SCxTDR, c);
 	sci_in(port, SCxSR);            /* Dummy read */
 	sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
@@ -626,10 +628,10 @@
 		dprintk("sci: BREAK detected\n");
 	}
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7750)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 	/* XXX: Handle SCIF overrun error */
-	if (port->type == PORT_SCIF && (ctrl_inw(SCLSR2) & SCIF_ORER) != 0) {
-		ctrl_outw(0, SCLSR2);
+	if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+		sci_out(port, SCLSR, 0);
 		if(tty->flip.count<TTY_FLIPBUF_SIZE) {
 			copied++;
 			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
@@ -796,6 +798,7 @@
 	port->gs.flags &= ~ GS_ACTIVE;
 	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL)
 		sci_setsignals(port, 0, 0);
+	sci_free_irq(port);
 }
 
 /* ********************************************************************** *
@@ -828,8 +831,7 @@
 	 */
 	retval = gs_init_port(&port->gs);
 	if (retval) {
-		port->gs.count--;
-		return retval;
+		goto failed_1;
 	}
 
 	port->gs.flags |= GS_ACTIVE;
@@ -837,14 +839,17 @@
 
 	if (port->gs.count == 1) {
 		MOD_INC_USE_COUNT;
+
+		retval = sci_request_irq(port);
+		if (retval) {
+			goto failed_2;
+		}
 	}
 
 	retval = gs_block_til_ready(port, filp);
 
 	if (retval) {
-		MOD_DEC_USE_COUNT;
-		port->gs.count--;
-		return retval;
+		goto failed_3;
 	}
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
@@ -870,6 +875,14 @@
 	port->gs.pgrp = current->pgrp;
 
 	return 0;
+
+failed_3:
+	sci_free_irq(port);
+failed_2:
+	MOD_DEC_USE_COUNT;
+failed_1:
+	port->gs.count--;
+	return retval;
 }
 
 static void sci_hungup(void *ptr)
@@ -1094,29 +1107,46 @@
 	return 0;
 }
 
-int __init sci_init(void)
+static int sci_request_irq(struct sci_port *port)
 {
-	struct sci_port *port;
-	int i, j;
+	int i;
 	void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = {
 		sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
 		sci_br_interrupt,
 	};
 
+	for (i=0; i<4; i++) {
+		if (!port->irqs[i]) continue;
+		if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
+				"sci", port)) {
+			printk(KERN_ERR "sci: Cannot allocate irq.\n");
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+static void sci_free_irq(struct sci_port *port)
+{
+	int i;
+
+	for (i=0; i<4; i++) {
+		if (!port->irqs[i]) continue;
+		free_irq(port->irqs[i], port);
+	}
+}
+
+int __init sci_init(void)
+{
+	struct sci_port *port;
+	int j;
+
 	printk("SuperH SCI(F) driver initialized\n");
 
 	for (j=0; j<SCI_NPORTS; j++) {
 		port = &sci_ports[j];
 		printk("ttySC%d at 0x%08x is a %s\n", j, port->base,
 		       (port->type == PORT_SCI) ? "SCI" : "SCIF");
-		for (i=0; i<4; i++) {
-			if (!port->irqs[i]) continue;
-			if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
-					"sci", port)) {
-				printk(KERN_ERR "sci: Cannot allocate irq.\n");
-				return -ENODEV;
-			}
-		}
 	}
 
 	sci_init_drivers();
@@ -1135,11 +1165,6 @@
 
 void cleanup_module(void)
 {
-	int i;
-
-	for (i=SCI_ERI_IRQ; i<SCI_TEI_IRQ; i++) /* XXX: irq_end?? */
-		free_irq(i, port);
-
 	tty_unregister_driver(&sci_driver);
 	tty_unregister_driver(&sci_callout_driver);
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h
--- v2.4.3/linux/drivers/char/sh-sci.h	Mon Oct  2 11:57:34 2000
+++ linux/drivers/char/sh-sci.h	Wed Apr 11 21:24:52 2001
@@ -25,6 +25,7 @@
 #define SH3_SCIF_IRQS { 56,  57,  59,  58 }
 #define SH3_IRDA_IRQS { 52,  53,  55,  54 }
 #define SH4_SCIF_IRQS { 40,  41,  43,  42 }
+#define STB1_SCIF1_IRQS {23, 24,  26,  25 }
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7708)
 # define SCI_NPORTS 1
@@ -53,12 +54,22 @@
 }
 # define SCSPTR1 0xffe0001c /* 8  bit SCI */
 # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCLSR2  0xFFE80024 /* 16 bit SCIF */
 # define SCIF_ORER 0x0001   /* overrun error bit */
 # define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
 	0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
 	0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
 # define SCI_AND_SCIF
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+# define SCI_NPORTS 2
+# define SCI_INIT { \
+  { {}, PORT_SCIF, 0xffe00000, STB1_SCIF1_IRQS, sci_init_pins_scif }, \
+  { {}, PORT_SCIF, 0xffe80000, SH4_SCIF_IRQS,   sci_init_pins_scif }  \
+}
+# define SCSPTR1 0xffe00020 /* 16 bit SCIF */
+# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
 #else
 # error CPU subtype not defined
 #endif
@@ -260,6 +271,7 @@
 SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8)
 SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
 SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
 
 #define sci_in(port, reg) sci_##reg##_in(port)
 #define sci_out(port, reg, value) sci_##reg##_out(port, value)
@@ -285,11 +297,24 @@
 #elif defined(CONFIG_CPU_SUBTYPE_SH7750)
 static inline int sci_rxd_in(struct sci_port *port)
 {
+#ifndef SCIF_ONLY
 	if (port->base == 0xffe00000)
 		return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+#endif
+#ifndef SCI_ONLY
 	if (port->base == 0xffe80000)
 		return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+#endif
 	return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+static inline int sci_rxd_in(struct sci_port *port)
+{
+	if (port->base == 0xffe00000)
+		return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */
+	else
+		return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+
 }
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/drivers/char/sx.c linux/drivers/char/sx.c
--- v2.4.3/linux/drivers/char/sx.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/char/sx.c	Fri Apr  6 10:42:55 2001
@@ -1767,6 +1767,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)
 {
@@ -1835,7 +1849,6 @@
 			sx_reconfigure_port(port);
 		}
 		break;
-
 	default:
 		rc = -ENOIOCTLCMD;
 		break;
@@ -2215,6 +2228,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 --recursive --new-file v2.4.3/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.4.3/linux/drivers/char/synclink.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/char/synclink.c	Wed Apr 18 14:40:06 2001
@@ -7344,8 +7344,6 @@
 	d->tx_timeout = mgsl_sppp_tx_timeout;
 	d->watchdog_timeo = 10*HZ;
 
-	dev_init_buffers(d);
-
 	if (register_netdev(d) == -1) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
diff -u --recursive --new-file v2.4.3/linux/drivers/char/toshiba.c linux/drivers/char/toshiba.c
--- v2.4.3/linux/drivers/char/toshiba.c	Wed Sep 27 13:53:56 2000
+++ linux/drivers/char/toshiba.c	Fri Apr  6 10:42:55 2001
@@ -1,19 +1,24 @@
 /* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops
  *
- * Copyright (c) 1996-2000  Jonathan A. Buzzard (jonathan@buzzard.org.uk)
+ * Copyright (c) 1996-2001  Jonathan A. Buzzard (jonathan@buzzard.org.uk)
  *
  * Valuable assistance and patches from:
  *     Tom May <tom@you-bastards.com>
  *     Rob Napier <rnapier@employees.org>
  *
  * Fn status port numbers for machine ID's courtesy of
+ *     0xfc02: Scott Eisert <scott.e@sky-eye.com>
+ *     0xfc04: Steve VanDevender <stevev@efn.org>
  *     0xfc08: Garth Berry <garth@itsbruce.net>
+ *     0xfc0a: Egbert Eich <eich@xfree86.org>
+ *     0xfc10: Andrew Lofthouse <Andrew.Lofthouse@robins.af.mil>
  *     0xfc11: Spencer Olson <solson@novell.com>
  *     0xfc13: Claudius Frankewitz <kryp@gmx.de>
  *     0xfc15: Tom May <tom@you-bastards.com>
  *     0xfc17: Dave Konrad <konrad@xenia.it>
  *     0xfc1a: George Betzos <betzos@engr.colostate.edu>
  *     0xfc1d: Arthur Liu <armie@slap.mine.nu>
+ *     0xfcd1: Mr. Dave Konrad <konrad@xenia.it>
  *
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
  *
@@ -46,7 +51,7 @@
  *
  */
 
-#define TOSH_VERSION "1.7 22/6/2000"
+#define TOSH_VERSION "1.9 22/3/2001"
 #define TOSH_DEBUG 0
 
 #include <linux/module.h>
@@ -117,27 +122,6 @@
 
 
 /*
- * At some point we need to emulate setting the HDD auto off times for
- * the new laptops. We can do this by calling the ide_ioctl on /dev/hda.
- * The values we need for the various times are
- *
- *    Disabled   0x00
- *    1 minute   0x0c
- *    3 minutes  0x24
- *    5 minutes  0x3c
- *   10 minutes  0x78
- *   15 minutes  0xb4
- *   20 minutes  0xf0
- *   30 minutes  0xf1
- *
- */
-/*static int tosh_emulate_hdd(SMMRegisters *regs)
-{
-	return 0;
-}*/
-
-
-/*
  * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function
  */
 static int tosh_emulate_fan(SMMRegisters *regs)
@@ -348,11 +332,12 @@
 static void tosh_set_fn_port(void)
 {
 	switch (tosh_id) {
+		case 0xfc02: case 0xfc04: case 0xfc09: case 0xfc0a: case 0xfc10:
 		case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a:
 			tosh_fn = 0x62;
 			break;
-		case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1:
-		case 0xfce0: case 0xfce2:
+		case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: case 0xfce0:
+		case 0xfce2:
 			tosh_fn = 0x68;
 			break;
 		default:
@@ -472,7 +457,6 @@
 	   0xa0-0xbf we can't. We just have to live dangerously and use the
 	   ports anyway, oh boy! */
 
-
 	/* do we need to emulate the fan? */
 
 	if ((tosh_id==0xfccb) || (tosh_id==0xfccc))
@@ -501,7 +485,9 @@
 	misc_register(&tosh_device);
 
 	/* register the proc entry */
+
 	create_proc_info_entry("toshiba", 0, NULL, tosh_get_info);
+
 	return 0;
 }
 
@@ -514,9 +500,11 @@
 void cleanup_module(void)
 {
 	/* remove the proc entry */
+
 	remove_proc_entry("toshiba", NULL);
 
 	/* unregister the device file */
+
 	misc_deregister(&tosh_device);
 }
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.4.3/linux/drivers/ide/ide-pci.c	Tue Jan  2 16:58:45 2001
+++ linux/drivers/ide/ide-pci.c	Thu Apr 19 22:57:06 2001
@@ -571,6 +571,26 @@
 	 * Can we trust the reported IRQ?
 	 */
 	pciirq = dev->irq;
+	
+	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
+	{
+		/* By rights we want to ignore these, but the Promise Fastrak
+		   people have some strange ideas about proprietary so we have
+		   to act otherwise on those. The supertrak however we need
+		   to skip */
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
+		{
+			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
+			if(dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
+				dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
+			{
+				printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
+				return;
+			}
+		}
+		/* Its attached to something else, just a random bridge. 
+		   Suspect a fastrak and fall through */
+	}
 	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
 		printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
 		/*
diff -u --recursive --new-file v2.4.3/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.4.3/linux/drivers/ide/ide.c	Tue Mar  6 19:44:34 2001
+++ linux/drivers/ide/ide.c	Wed Apr 11 19:06:12 2001
@@ -789,7 +789,11 @@
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
 {
 	unsigned long flags;
-	struct request *rq = HWGROUP(drive)->rq;
+	struct request *rq;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	if (rq->cmd == IDE_DRIVE_CMD) {
 		byte *args = (byte *) rq->buffer;
@@ -815,10 +819,8 @@
 	spin_lock_irqsave(&io_request_lock, flags);
 	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
-	blkdev_release_request(rq);
+	end_that_request_last(rq);
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	if (rq->sem != NULL)
-		up(rq->sem);	/* inform originator that rq has been serviced */
 }
 
 /*
@@ -1695,7 +1697,7 @@
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned int major = HWIF(drive)->major;
-	struct list_head * queue_head;
+	struct list_head *queue_head = &drive->queue.queue_head;
 	DECLARE_MUTEX_LOCKED(sem);
 
 #ifdef CONFIG_BLK_DEV_PDC4030
@@ -1708,7 +1710,6 @@
 	if (action == ide_wait)
 		rq->sem = &sem;
 	spin_lock_irqsave(&io_request_lock, flags);
-	queue_head = &drive->queue.queue_head;
 	if (list_empty(queue_head) || action == ide_preempt) {
 		if (action == ide_preempt)
 			hwgroup->rq = NULL;
diff -u --recursive --new-file v2.4.3/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- v2.4.3/linux/drivers/ide/pdc202xx.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/ide/pdc202xx.c	Thu Apr 19 22:57:06 2001
@@ -224,6 +224,7 @@
 	"QUANTUM FIREBALLlct08 08",
 	"QUANTUM FIREBALLP KA6.4",
 	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX20.5",
 	"QUANTUM FIREBALLP LM20.5",
 	NULL
 };
diff -u --recursive --new-file v2.4.3/linux/drivers/input/joydev.c linux/drivers/input/joydev.c
--- v2.4.3/linux/drivers/input/joydev.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/input/joydev.c	Wed Apr 11 19:02:30 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: joydev.c,v 1.13 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: joydev.c,v 1.19 2001/01/10 19:49:40 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik 
  *  Copyright (c) 1999 Colin Van Dyke 
@@ -232,9 +232,10 @@
 	if (count == sizeof(struct JS_DATA_TYPE)) {
 
 		struct JS_DATA_TYPE data;
+		int i;
 
-		data.buttons =  ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) |
-				((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0);
+		for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
+			data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
 		data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
 		data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
 
@@ -323,7 +324,7 @@
 	struct joydev_list *list = file->private_data;
 	struct joydev *joydev = list->joydev;
 	struct input_dev *dev = joydev->handle.dev;
-
+	int i;
 
 	switch (cmd) {
 
@@ -360,6 +361,28 @@
 		case JSIOCGCORR:
 			return copy_to_user((struct js_corr *) arg, joydev->corr,
 						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+		case JSIOCSAXMAP:
+			if (copy_from_user((__u8 *) arg, joydev->abspam, sizeof(__u8) * ABS_MAX))
+				return -EFAULT;
+			for (i = 0; i < ABS_MAX; i++) {
+				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
+				joydev->absmap[joydev->abspam[i]] = i;
+			}
+			return 0;
+		case JSIOCGAXMAP:
+			return copy_to_user((__u8 *) arg, joydev->abspam,
+						sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
+		case JSIOCSBTNMAP:
+			if (copy_from_user((__u16 *) arg, joydev->absmap, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+				return -EFAULT;
+			for (i = 0; i < KEY_MAX - BTN_MISC; i++); {
+				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
+				joydev->keymap[joydev->abspam[i - BTN_MISC]] = i;
+			}
+			return 0;
+		case JSIOCGBTNMAP:
+			return copy_to_user((__u16 *) arg, joydev->keypam,
+						sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
 		default:
 			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
 				int len;
@@ -454,7 +477,7 @@
 
 	joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
 
-	printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number);
+//	printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number);
 
 	return &joydev->handle;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/input/keybdev.c linux/drivers/input/keybdev.c
--- v2.4.3/linux/drivers/input/keybdev.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/input/keybdev.c	Wed Apr 25 14:35:25 2001
@@ -37,7 +37,9 @@
 #include <linux/module.h>
 #include <linux/kbd_kern.h>
 
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) || defined(CONFIG_SPARC64)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
+    defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) || \
+    defined(CONFIG_PPC) || defined(__mc68000__)
 
 static int x86_sysrq_alt = 0;
 #ifdef CONFIG_SPARC64
@@ -62,8 +64,46 @@
 	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
 	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
 
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+extern int mac_hid_mouse_emulate_buttons(int, int, int);
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
+#ifdef CONFIG_MAC_ADBKEYCODES
+extern int mac_hid_keyboard_sends_linux_keycodes(void);
+#else
+#define mac_hid_keyboard_sends_linux_keycodes()	0
+#endif /* CONFIG_MAC_ADBKEYCODES */
+#if defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_ADB_KEYBOARD)
+static unsigned char mac_keycodes[256] = {
+	  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
+	 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
+	  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
+	 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
+	 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
+	 84, 85, 82, 65, 42,  0, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
+	 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117,
+	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0, 95, 55, 55,  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, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102 };
+#endif	/* CONFIG_MAC_ADBKEYCODES || CONFIG_ADB_KEYBOARD */
+ 
 static int emulate_raw(unsigned int keycode, int down)
 {
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+	if (mac_hid_mouse_emulate_buttons(1, keycode, down))
+		return 0;
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
+#if defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_ADB_KEYBOARD)
+	if (!mac_hid_keyboard_sends_linux_keycodes()) {
+		if (keycode > 255 || !mac_keycodes[keycode])
+			return -1;
+       
+		handle_scancode((mac_keycodes[keycode] & 0x7f), down);
+		return 0;
+	}
+#endif	/* CONFIG_MAC_ADBKEYCODES || CONFIG_ADB_KEYBOARD */
+
 	if (keycode > 255 || !x86_keycodes[keycode])
 		return -1; 
 
@@ -76,6 +116,7 @@
 
 	if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
 		handle_scancode(0x54, down);
+
 		return 0;
 	}
 
@@ -106,29 +147,7 @@
 	return 0;
 }
 
-#elif defined(CONFIG_ADB_KEYBOARD)
-
-static unsigned char mac_keycodes[128] =
-	{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
-	 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
-	  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
-	 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
-	 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
-	 84, 85, 82, 65, 42,  0, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
-	 76,125, 75,105,124,  0,115, 62,116, 59, 60,119, 61,121,114,117,
-	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0,  0, 55, 55 };
-
-static int emulate_raw(unsigned int keycode, int down)
-{
-	if (keycode > 127 || !mac_keycodes[keycode])
-		return -1;
-
-	handle_scancode(mac_keycodes[keycode] & 0x7f, down);
-
-	return 0;
-}
-
-#endif
+#endif /* CONFIG_X86 || CONFIG_IA64 || __alpha__ || __mips__ || CONFIG_PPC */
 
 static struct input_handler keybdev_handler;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- v2.4.3/linux/drivers/isdn/Config.in	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/Config.in	Thu Apr 19 22:30:16 2001
@@ -76,8 +76,8 @@
 	 bool '  Am7930' CONFIG_HISAX_AMD7930
       fi
    fi
-
-   dep_tristate '  Sedlbauer PCMCIA cs module' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
+   dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
+   dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
 fi
 endmenu
 
@@ -130,10 +130,10 @@
    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 B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+   dep_tristate '  AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI
+   dep_tristate '  AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $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
+   dep_tristate '  AVM C4/C2 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
 fi
 
 # HYSDN
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h
--- v2.4.3/linux/drivers/isdn/avmb1/avmcard.h	Sat Nov 11 18:58:02 2000
+++ linux/drivers/isdn/avmb1/avmcard.h	Thu Apr 19 22:30:16 2001
@@ -1,9 +1,12 @@
 /*
- * $Id: avmcard.h,v 1.8 2000/10/10 17:44:19 kai Exp $
+ * $Id: avmcard.h,v 1.8.6.1 2001/04/20 02:41:59 keil Exp $
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: avmcard.h,v $
+ * Revision 1.8.6.1  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.8  2000/10/10 17:44:19  kai
  * changes from/for 2.2.18
  *
@@ -83,7 +86,8 @@
 	avm_m2,
 	avm_t1isa,
 	avm_t1pci,
-	avm_c4
+	avm_c4,
+	avm_c2
 };
 
 typedef struct avmcard_dmainfo {
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c
--- v2.4.3/linux/drivers/isdn/avmb1/b1.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/b1.c	Thu Apr 19 22:30:16 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: b1.c,v 1.20.6.3 2001/03/21 08:52:20 kai Exp $
+ * $Id: b1.c,v 1.20.6.4 2001/04/20 02:41:59 keil 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.4  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.20.6.3  2001/03/21 08:52:20  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -126,7 +129,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.20.6.3 $";
+static char *revision = "$Revision: 1.20.6.4 $";
 
 /* ------------------------------------------------------------- */
 
@@ -686,6 +689,7 @@
 	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
 	case avm_t1pci: s = "T1 PCI"; break;
 	case avm_c4: s = "C4"; break;
+	case avm_c2: s = "C2"; break;
 	default: s = "???"; break;
 	}
 	len += sprintf(page+len, "%-16s %s\n", "type", s);
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- v2.4.3/linux/drivers/isdn/avmb1/b1dma.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/b1dma.c	Thu Apr 19 22:30:16 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: b1dma.c,v 1.11.6.3 2001/03/21 08:52:21 kai Exp $
+ * $Id: b1dma.c,v 1.11.6.4 2001/04/20 02:41:59 keil 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.4  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.11.6.3  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -71,7 +74,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.11.6.3 $";
+static char *revision = "$Revision: 1.11.6.4 $";
 
 /* ------------------------------------------------------------- */
 
@@ -907,6 +910,7 @@
 	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
 	case avm_t1pci: s = "T1 PCI"; break;
 	case avm_c4: s = "C4"; break;
+	case avm_c2: s = "C2"; break;
 	default: s = "???"; break;
 	}
 	len += sprintf(page+len, "%-16s %s\n", "type", s);
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- v2.4.3/linux/drivers/isdn/avmb1/b1pci.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/b1pci.c	Thu Apr 19 22:30:16 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: b1pci.c,v 1.29.6.2 2001/03/21 08:52:21 kai Exp $
+ * $Id: b1pci.c,v 1.29.6.3 2001/04/20 02:41:59 keil 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.3  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.29.6.2  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -122,7 +125,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.29.6.2 $";
+static char *revision = "$Revision: 1.29.6.3 $";
 
 /* ------------------------------------------------------------- */
 
@@ -327,7 +330,7 @@
 
 	div4->detach_ctr(ctrl);
 	free_irq(card->irq, card);
-	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
 	kfree(card->ctrlinfo);
@@ -358,7 +361,6 @@
 
 static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
-	unsigned long base, page_offset;
 	avmcard *card;
 	avmctrl_info *cinfo;
 	int retval;
@@ -409,12 +411,8 @@
 		return -EBUSY;
 	}
 
-	base = card->membase & PAGE_MASK;
-	page_offset = card->membase - base;
-	card->mbase = ioremap_nocache(base, page_offset + 64);
-	if (card->mbase) {
-		card->mbase += page_offset;
-	} else {
+	card->mbase = ioremap_nocache(card->membase, 64);
+	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
 	        kfree(card->ctrlinfo);
@@ -429,7 +427,7 @@
 	if ((retval = b1pciv4_detect(card)) != 0) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
@@ -445,7 +443,7 @@
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
@@ -457,7 +455,7 @@
 	cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
@@ -508,21 +506,21 @@
 	struct capicardparams param;
 	int retval;
 
+	if (pci_enable_device(dev) < 0) {
+		printk(KERN_ERR "%s: failed to enable AVM-B1\n",
+		       driver->name);
+		return -ENODEV;
+	}
+	param.irq = dev->irq;
+
 	if (pci_resource_start(dev, 2)) { /* B1 PCI V4 */
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
 		driver = &b1pciv4_driver;
+
+		pci_set_master(dev);
 #endif
 		param.membase = pci_resource_start(dev, 0);
 		param.port = pci_resource_start(dev, 2);
-		param.irq = dev->irq;
-
-		retval = pci_enable_device (dev);
-		if (retval != 0) {
-		        printk(KERN_ERR
-			"%s: failed to enable AVM-B1 V4 at i/o %#x, irq %d, mem %#x err=%d\n",
-			driver->name, param.port, param.irq, param.membase, retval);
-			return -EIO;
-		}
 
 		printk(KERN_INFO
 		"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
@@ -540,15 +538,7 @@
 	} else {
 		param.membase = 0;
 		param.port = pci_resource_start(dev, 1);
-		param.irq = dev->irq;
 
-		retval = pci_enable_device (dev);
-		if (retval != 0) {
-		        printk(KERN_ERR
-			"%s: failed to enable AVM-B1 at i/o %#x, irq %d, err=%d\n",
-			driver->name, param.port, param.irq, retval);
-			return -EIO;
-		}
 		printk(KERN_INFO
 		"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
 		driver->name, param.port, param.irq);
@@ -570,7 +560,6 @@
 #endif
 	struct pci_dev *dev = NULL;
 	char *p;
-	int retval;
 
 	MOD_INC_USE_COUNT;
 
@@ -592,50 +581,29 @@
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
         di = attach_capi_driver(driver);
-
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
 		MOD_DEC_USE_COUNT;
-		return -EIO;
+		return -ENODEV;
 	}
 
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
 	printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision);
 
         div4 = attach_capi_driver(driverv4);
-
 	if (!div4) {
     		detach_capi_driver(driver);
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driverv4->name);
 		MOD_DEC_USE_COUNT;
-		return -EIO;
+		return -ENODEV;
 	}
 #endif
 
-#ifdef CONFIG_PCI
-	if (!pci_present()) {
-		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
-    		detach_capi_driver(driver);
-#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) {
-    			detach_capi_driver(driver);
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-    			detach_capi_driver(driverv4);
-#endif
-			MOD_DEC_USE_COUNT;
-			return retval;
-		}
-		ncards++;
+		if (add_card(dev) == 0)
+			ncards++;
 	}
 	if (ncards) {
 		printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n",
@@ -649,12 +617,7 @@
 	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
+	return -ENODEV;
 }
 
 static void __exit b1pci_exit(void)
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.4.3/linux/drivers/isdn/avmb1/c4.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/c4.c	Thu Apr 19 22:30:16 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: c4.c,v 1.20.6.5 2001/03/21 08:52:21 kai Exp $
+ * $Id: c4.c,v 1.20.6.6 2001/04/20 02:41:59 keil 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.6  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.20.6.5  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -118,17 +121,22 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.5 $";
+static char *revision = "$Revision: 1.20.6.6 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
 
 /* ------------------------------------------------------------- */
+#ifndef PCI_DEVICE_ID_AVM_C2
+#define PCI_DEVICE_ID_AVM_C2	0x1100
+#endif
+/* ------------------------------------------------------------- */
 
 static int suppress_pollack;
 
 static struct pci_device_id c4_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4 },
+	{ PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2 },
 	{ }			/* Terminating entry */
 };
 
@@ -614,7 +622,7 @@
 		MsgLen = _get_slice(&p, card->msgbuf);
 		DataB3Len = _get_slice(&p, card->databuf);
 		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
-		if (cidx > 3) cidx = 0;
+		if (cidx >= card->nlogcontr) cidx = 0;
 		ctrl = card->ctrlinfo[cidx].capi_ctrl;
 
 		if (MsgLen < 30) { /* not CAPI 64Bit */
@@ -637,7 +645,7 @@
 		ApplId = (unsigned) _get_word(&p);
 		MsgLen = _get_slice(&p, card->msgbuf);
 		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
-		if (cidx > 3) cidx = 0;
+		if (cidx >= card->nlogcontr) cidx = 0;
 		ctrl = card->ctrlinfo[cidx].capi_ctrl;
 
 		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
@@ -655,7 +663,7 @@
 		NCCI = _get_word(&p);
 		WindowSize = _get_word(&p);
 		cidx = (NCCI&0x7f) - card->cardnr;
-		if (cidx > 3) cidx = 0;
+		if (cidx >= card->nlogcontr) cidx = 0;
 		ctrl = card->ctrlinfo[cidx].capi_ctrl;
 
 		ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
@@ -669,13 +677,15 @@
 
 		if (NCCI != 0xffffffff) {
 			cidx = (NCCI&0x7f) - card->cardnr;
-			if (cidx > 3) cidx = 0;
+			if (cidx >= card->nlogcontr) cidx = 0;
 			ctrl = card->ctrlinfo[cidx].capi_ctrl;
-			ctrl->free_ncci(ctrl, ApplId, NCCI);
+			if (ctrl)
+				ctrl->free_ncci(ctrl, ApplId, NCCI);
 		} else {
 			for (cidx=0; cidx < 4; cidx++) {
 				ctrl = card->ctrlinfo[cidx].capi_ctrl;
-				ctrl->appl_released(ctrl, ApplId);
+				if (ctrl)
+					ctrl->appl_released(ctrl, ApplId);
 			}
 		}
 		break;
@@ -688,20 +698,28 @@
 			queue_pollack(card);
 		for (cidx=0; cidx < 4; cidx++) {
 			ctrl = card->ctrlinfo[cidx].capi_ctrl;
-			ctrl->resume_output(ctrl);
+			if (ctrl)
+				ctrl->resume_output(ctrl);
 		}
 		break;
 
 	case RECEIVE_STOP:
 		for (cidx=0; cidx < 4; cidx++) {
 			ctrl = card->ctrlinfo[cidx].capi_ctrl;
-			ctrl->suspend_output(ctrl);
+			if (ctrl)
+				ctrl->suspend_output(ctrl);
 		}
 		break;
 
 	case RECEIVE_INIT:
 
-	        cidx = card->nlogcontr++;
+	        cidx = card->nlogcontr;
+		if (cidx >= 4 || !card->ctrlinfo[cidx].capi_ctrl) {
+			printk(KERN_ERR "%s: card with %d controllers ??\n",
+					card->name, cidx+1);
+			break;
+		}
+	        card->nlogcontr++;
 	        cinfo = &card->ctrlinfo[cidx];
 		ctrl = cinfo->capi_ctrl;
 		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
@@ -755,6 +773,8 @@
 	if (status & DBELL_RESET_HOST) {
 		int i;
 		c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+		if (card->nlogcontr == 0)
+			return;
 		printk(KERN_ERR "%s: unexpected reset\n", card->name);
                 for (i=0; i < 4; i++) {
 			avmctrl_info *cinfo = &card->ctrlinfo[i];
@@ -762,6 +782,7 @@
 			if (cinfo->capi_ctrl)
 				cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
 		}
+		card->nlogcontr = 0;
 		return;
 	}
 
@@ -993,6 +1014,7 @@
 		if (cinfo->capi_ctrl)
 			cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
 	}
+	card->nlogcontr = 0;
 }
 
 static void c4_remove_ctr(struct capi_ctr *ctrl)
@@ -1012,7 +1034,7 @@
 	}
 
 	free_irq(card->irq, card);
-	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
 	kfree(card->ctrlinfo);
@@ -1145,6 +1167,7 @@
 	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
 	case avm_t1pci: s = "T1 PCI"; break;
 	case avm_c4: s = "C4"; break;
+	case avm_c2: s = "C2"; break;
 	default: s = "???"; break;
 	}
 	len += sprintf(page+len, "%-16s %s\n", "type", s);
@@ -1192,9 +1215,10 @@
 
 /* ------------------------------------------------------------- */
 
-static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int c4_add_card(struct capi_driver *driver,
+		       struct capicardparams *p,
+		       int nr)
 {
-	unsigned long base, page_offset;
 	avmctrl_info *cinfo;
 	avmcard *card;
 	int retval;
@@ -1232,11 +1256,11 @@
 		cinfo = &card->ctrlinfo[i];
 		cinfo->card = card;
 	}
-	sprintf(card->name, "c4-%x", p->port);
+	sprintf(card->name, "%s-%x", driver->name, p->port);
 	card->port = p->port;
 	card->irq = p->irq;
 	card->membase = p->membase;
-	card->cardtype = avm_c4;
+	card->cardtype = nr == 4 ? avm_c4 : avm_c2;
 
 	if (check_region(card->port, AVMB1_PORTLEN)) {
 		printk(KERN_WARNING
@@ -1249,12 +1273,8 @@
 		return -EBUSY;
 	}
 
-	base = card->membase & PAGE_MASK;
-	page_offset = card->membase - base;
-	card->mbase = ioremap_nocache(base, page_offset + 128);
-	if (card->mbase) {
-		card->mbase += page_offset;
-	} else {
+	card->mbase = ioremap_nocache(card->membase, 128);
+	if (card->mbase == 0) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
 	        kfree(card->ctrlinfo);
@@ -1267,7 +1287,7 @@
 	if ((retval = c4_detect(card)) != 0) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
@@ -1282,7 +1302,7 @@
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
@@ -1291,7 +1311,7 @@
 		return -EBUSY;
 	}
 
-	for (i=0; i < 4; i++) {
+	for (i=0; i < nr ; i++) {
 		cinfo = &card->ctrlinfo[i];
 		cinfo->card = card;
 		cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
@@ -1302,7 +1322,7 @@
 				cinfo = &card->ctrlinfo[i];
 				di->detach_ctr(cinfo->capi_ctrl);
 			}
-                	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                	iounmap(card->mbase);
 			free_irq(card->irq, card);
 			release_region(card->port, AVMB1_PORTLEN);
 	        	kfree(card->dma);
@@ -1318,14 +1338,31 @@
 	skb_queue_head_init(&card->dma->send_queue);
 
 	printk(KERN_INFO
-		"%s: AVM C4 at i/o %#x, irq %d, mem %#lx\n",
-		driver->name, card->port, card->irq, card->membase);
+		"%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
+		driver->name, nr, card->port, card->irq, card->membase);
 
 	return 0;
 }
 
 /* ------------------------------------------------------------- */
 
+static struct capi_driver c2_driver = {
+    name: "c2",
+    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 */
+
+    add_card: 0, /* no add_card function */
+};
+
 static struct capi_driver c4_driver = {
     name: "c4",
     revision: "0.0",
@@ -1345,15 +1382,9 @@
 
 static int ncards = 0;
 
-static int __init c4_init(void)
+static int c4_attach_driver (struct capi_driver * driver)
 {
-	struct capi_driver *driver = &c4_driver;
-	struct pci_dev *dev = NULL;
 	char *p;
-	int retval;
-
-	MOD_INC_USE_COUNT;
-
 	if ((p = strchr(revision, ':')) != 0 && p[1]) {
 		strncpy(driver->revision, p + 2, sizeof(driver->revision));
 		driver->revision[sizeof(driver->revision)-1] = 0;
@@ -1364,74 +1395,101 @@
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
         di = attach_capi_driver(driver);
-
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
 		MOD_DEC_USE_COUNT;
-		return -EIO;
+		return -ENODEV;
 	}
+	return 0;
+}
 
-#ifdef CONFIG_PCI
-	if (!pci_present()) {
-		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
-    		detach_capi_driver(driver);
-		MOD_DEC_USE_COUNT;
-		return -EIO;
-	}
+static int __init search_cards(struct capi_driver * driver,
+				int pci_id, int nr)
+{
+	struct pci_dev *	dev	= NULL;
+	int			retval	= 0;
 
 	while ((dev = pci_find_subsys(
 			PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
-			PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) {
+			PCI_VENDOR_ID_AVM, pci_id, dev))) {
 		struct capicardparams param;
 
+		if (pci_enable_device(dev) < 0) {
+		        printk(KERN_ERR "%s: failed to enable AVM-C%d\n",
+			       driver->name, nr);
+			continue;
+		}
+		pci_set_master(dev);
+
 		param.port = pci_resource_start(dev, 1);
 		param.irq = dev->irq;
 		param.membase = pci_resource_start(dev, 0);
-
-		retval = pci_enable_device (dev);
-		if (retval != 0) {
-		        printk(KERN_ERR
-			"%s: failed to enable AVM-C4 at i/o %#x, irq %d, mem %#x err=%d\n",
-			driver->name, param.port, param.irq, param.membase, retval);
-    			detach_capi_driver(driver);
-			MOD_DEC_USE_COUNT;
-			return -EIO;
-		}
-
+  
 		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);
-		retval = c4_add_card(driver, &param);
+			"%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
+			driver->name, nr, param.port, param.irq, param.membase);
+		retval = c4_add_card(driver, &param, nr);
 		if (retval != 0) {
 		        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);
-    			detach_capi_driver(driver);
-			MOD_DEC_USE_COUNT;
-			return retval;
+			"%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
+			driver->name, nr, param.port, param.irq, param.membase);
+			continue;
 		}
 		ncards++;
 	}
+	return retval;
+}
+
+static int __init c4_init(void)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+
+	retval = c4_attach_driver (&c4_driver);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	retval = c4_attach_driver (&c2_driver);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	retval = search_cards(&c4_driver, PCI_DEVICE_ID_AVM_C4, 4);
+	if (retval && ncards == 0) {
+    		detach_capi_driver(&c2_driver);
+    		detach_capi_driver(&c4_driver);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	retval = search_cards(&c2_driver, PCI_DEVICE_ID_AVM_C2, 2);
+	if (retval && ncards == 0) {
+    		detach_capi_driver(&c2_driver);
+    		detach_capi_driver(&c4_driver);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
 	if (ncards) {
-		printk(KERN_INFO "%s: %d C4 card(s) detected\n",
-				driver->name, ncards);
+		printk(KERN_INFO "%s: %d C4/C2 card(s) detected\n",
+				c4_driver.name, ncards);
 		MOD_DEC_USE_COUNT;
 		return 0;
 	}
-	printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
-	detach_capi_driver(driver);
+	printk(KERN_ERR "%s: NO C4/C2 card detected\n", c4_driver.name);
+	detach_capi_driver(&c4_driver);
+	detach_capi_driver(&c2_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
+	return -ENODEV;
 }
 
 static void __exit c4_exit(void)
 {
+    detach_capi_driver(&c2_driver);
     detach_capi_driver(&c4_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- v2.4.3/linux/drivers/isdn/avmb1/capi.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/capi.c	Wed Apr 18 11:49:13 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: capi.c,v 1.44.6.8 2001/03/21 08:52:21 kai Exp $
+ * $Id: capi.c,v 1.44.6.9 2001/04/08 17:51:42 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.9  2001/04/08 17:51:42  kai
+ * merge various fixes from HEAD (found by the CHECKER project)
+ *
  * Revision 1.44.6.8  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -268,7 +271,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.44.6.8 $";
+static char *revision = "$Revision: 1.44.6.9 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
@@ -533,9 +536,6 @@
 	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)
@@ -553,6 +553,9 @@
 #endif
 	}
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+	for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
+		;
+	*pp = np;
         return np;
 }
 
@@ -1001,6 +1004,8 @@
 		return -ENODEV;
 
 	skb = alloc_skb(count, GFP_USER);
+	if (!skb)
+		return -ENOMEM;
 
 	if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
 		kfree_skb(skb);
@@ -1332,6 +1337,7 @@
 #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;
@@ -1417,6 +1423,8 @@
 		return -EINVAL;
 
 	skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER);
+	if (!skb)
+		return -ENOMEM;
 
 	skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
 	if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
@@ -2116,6 +2124,7 @@
 static int __init capi_init(void)
 {
 	char *p;
+	char *compileinfo;
 
 	MOD_INC_USE_COUNT;
 
@@ -2196,8 +2205,17 @@
 
 	(void)proc_init();
 
-	printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n",
-				rev, capi_major);
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
+        compileinfo = " (middleware+capifs)";
+#else
+        compileinfo = " (no capifs)";
+#endif
+#else
+        compileinfo = " (no middleware)";
+#endif
+	printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n",
+				rev, capi_major, compileinfo);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- v2.4.3/linux/drivers/isdn/avmb1/capidrv.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/capidrv.c	Wed Apr 18 11:49:13 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: capidrv.c,v 1.39.6.4 2001/03/21 08:52:21 kai Exp $
+ * $Id: capidrv.c,v 1.39.6.5 2001/04/08 17:51:42 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.5  2001/04/08 17:51:42  kai
+ * merge various fixes from HEAD (found by the CHECKER project)
+ *
  * Revision 1.39.6.4  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -231,7 +234,7 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.39.6.4 $";
+static char *revision = "$Revision: 1.39.6.5 $";
 static int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -2069,8 +2072,8 @@
 	__u16 datahandle;
 
 	if (!card) {
-		printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n",
-		       card->contrnr, id);
+		printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
+		       id);
 		return 0;
 	}
 	if (debugmode > 1)
@@ -2139,8 +2142,8 @@
 	__u8 *p;
 
 	if (!card) {
-		printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n",
-		       card->contrnr, id);
+		printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
+		       id);
 		return -ENODEV;
 	}
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.4.3/linux/drivers/isdn/avmb1/t1pci.c	Sun Mar 25 18:20:44 2001
+++ linux/drivers/isdn/avmb1/t1pci.c	Wed Apr 18 11:49:13 2001
@@ -124,7 +124,7 @@
 
 	di->detach_ctr(ctrl);
 	free_irq(card->irq, card);
-	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
 	kfree(card->ctrlinfo);
@@ -138,7 +138,6 @@
 
 static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
-	unsigned long base, page_offset;
 	avmcard *card;
 	avmctrl_info *cinfo;
 	int retval;
@@ -189,12 +188,8 @@
 		return -EBUSY;
 	}
 
-	base = card->membase & PAGE_MASK;
-	page_offset = card->membase - base;
-	card->mbase = ioremap_nocache(base, page_offset + 64);
-	if (card->mbase) {
-		card->mbase += page_offset;
-	} else {
+	card->mbase = ioremap_nocache(card->membase, 64);
+	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
 	        kfree(card->ctrlinfo);
@@ -213,7 +208,7 @@
 		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));
+                iounmap(card->mbase);
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
@@ -228,7 +223,7 @@
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
@@ -240,7 +235,7 @@
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+                iounmap(card->mbase);
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
 	        kfree(card->ctrlinfo);
@@ -318,7 +313,6 @@
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
         di = attach_capi_driver(driver);
-
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
@@ -326,31 +320,20 @@
 		return -EIO;
 	}
 
-#ifdef CONFIG_PCI
-	if (!pci_present()) {
-		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
-    		detach_capi_driver(driver);
-		MOD_DEC_USE_COUNT;
-		return -EIO;
-	}
-
 	while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
 		struct capicardparams param;
 
+		if (pci_enable_device(dev) < 0) {
+		        printk(KERN_ERR	"%s: failed to enable AVM-T1-PCI\n",
+			       driver->name);
+			continue;
+		}
+		pci_set_master(dev);
+
 		param.port = pci_resource_start(dev, 1);
  		param.irq = dev->irq;
 		param.membase = pci_resource_start(dev, 0);
 
-		retval = pci_enable_device (dev);
-		if (retval != 0) {
-		        printk(KERN_ERR
-			"%s: failed to enable AVM-T1-PCI at i/o %#x, irq %d, mem %#x err=%d\n",
-			driver->name, param.port, param.irq, param.membase, retval);
-    			detach_capi_driver(&t1pci_driver);
-			MOD_DEC_USE_COUNT;
-			return -EIO;
-		}
-
 		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);
@@ -359,9 +342,7 @@
 		        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);
-    			detach_capi_driver(&t1pci_driver);
-			MOD_DEC_USE_COUNT;
-			return retval;
+			continue;
 		}
 		ncards++;
 	}
@@ -374,12 +355,7 @@
 	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
+	return -ENODEV;
 }
 
 static void __exit t1pci_exit(void)
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c
--- v2.4.3/linux/drivers/isdn/eicon/eicon_idi.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/eicon_idi.c	Wed Apr 18 11:49:13 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $
+/* $Id: eicon_idi.c,v 1.41.6.2 2001/04/07 21:41:44 armin Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  *        IDI interface 
@@ -36,7 +36,7 @@
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.41.6.1 $";
+char *eicon_idi_revision = "$Revision: 1.41.6.2 $";
 
 eicon_manifbuf *manbuf;
 
@@ -2221,7 +2221,10 @@
         static char *connmsg[] =
         {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34",
          "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90",
-         "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"};
+         "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17", "V.32", "K56Flex",
+         "X2", "V.18", "V.18LH", "V.18HL", "V.21LH", "V.21HL",
+         "Bell 103LH", "Bell 103HL", "V.23", "V.23", "EDT 110",
+         "Baudot45", "Baudot47", "Baudot50", "DTMF" };
 	static u_char dtmf_code[] = {
 	'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
 	};
@@ -2243,7 +2246,11 @@
 				cmd.driver = ccard->myid;
 				cmd.command = ISDN_STAT_BCONN;
 				cmd.arg = chan->No;
-				sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
+                                if (p->norm > 34) {
+                                  sprintf(cmd.parm.num, "%d/(%d)", p->speed, p->norm);
+                                } else {
+                                  sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
+                                }
 				ccard->interface.statcallb(&cmd);
 			}
 			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- v2.4.3/linux/drivers/isdn/hisax/Makefile	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/hisax/Makefile	Wed Apr 11 19:02:36 2001
@@ -54,8 +54,9 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_ISDN_DRV_HISAX)		+= hisax.o
+obj-$(CONFIG_ISDN_DRV_HISAX)	+= hisax.o
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)	+= sedlbauer_cs.o
+obj-$(CONFIG_HISAX_ELSA_CS)	+= elsa_cs.o
 
 MD5FILES 	:= isac.c isdnl1.c isdnl2.c isdnl3.c \
 		   tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c
--- v2.4.3/linux/drivers/isdn/hisax/bkm_a8.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/hisax/bkm_a8.c	Wed Apr 18 11:49:13 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.14.6.4 2001/02/16 16:43:25 kai Exp $
+/* $Id: bkm_a8.c,v 1.14.6.5 2001/04/15 14:51:09 keil 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
@@ -27,7 +27,7 @@
 
 extern const char *CardType[];
 
-const char sct_quadro_revision[] = "$Revision: 1.14.6.4 $";
+const char sct_quadro_revision[] = "$Revision: 1.14.6.5 $";
 
 static const char *sct_quadro_subtypes[] =
 {
@@ -205,9 +205,9 @@
 void
 release_io_sct_quadro(struct IsdnCardState *cs)
 {
-	release_region(cs->hw.ax.base & 0xffffffc0, 256);
+	release_region(cs->hw.ax.base & 0xffffffc0, 128);
 	if (cs->subtyp == SCT_1)
-		release_region(cs->hw.ax.plx_adr, 256);
+		release_region(cs->hw.ax.plx_adr, 64);
 }
 
 static void
@@ -403,9 +403,9 @@
 	switch(cs->subtyp) {
 		case 1:
 			cs->hw.ax.base = pci_ioaddr5 + 0x00;
-			if (sct_alloc_io(pci_ioaddr1, 256))
+			if (sct_alloc_io(pci_ioaddr1, 128))
 				return(0);
-			if (sct_alloc_io(pci_ioaddr5, 256))
+			if (sct_alloc_io(pci_ioaddr5, 64))
 				return(0);
 			/* disable all IPAC */
 			writereg(pci_ioaddr5, pci_ioaddr5 + 4,
@@ -419,17 +419,17 @@
 			break;
 		case 2:
 			cs->hw.ax.base = pci_ioaddr4 + 0x08;
-			if (sct_alloc_io(pci_ioaddr4, 256))
+			if (sct_alloc_io(pci_ioaddr4, 64))
 				return(0);
 			break;
 		case 3:
 			cs->hw.ax.base = pci_ioaddr3 + 0x10;
-			if (sct_alloc_io(pci_ioaddr3, 256))
+			if (sct_alloc_io(pci_ioaddr3, 64))
 				return(0);
 			break;
 		case 4:
 			cs->hw.ax.base = pci_ioaddr2 + 0x20;
-			if (sct_alloc_io(pci_ioaddr2, 256))
+			if (sct_alloc_io(pci_ioaddr2, 64))
 				return(0);
 			break;
 	}	
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.4.3/linux/drivers/isdn/hisax/config.c	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/hisax/config.c	Wed Apr 18 11:49:13 2001
@@ -1,4 +1,4 @@
-/* $Id: config.c,v 2.57.6.11 2001/03/13 16:17:08 kai Exp $
+/* $Id: config.c,v 2.57.6.13 2001/04/08 19:41:28 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -914,13 +914,12 @@
 
 	save_flags(flags);
 	cli();
-	if (!(cs = (struct IsdnCardState *)
-		kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
+	cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+	if (!cs) {
 		printk(KERN_WARNING
 		       "HiSax: No memory for IsdnCardState(card %d)\n",
 		       cardnr + 1);
-		restore_flags(flags);
-		return (0);
+		goto out;
 	}
 	memset(cs, 0, sizeof(struct IsdnCardState));
 	card->cs = cs;
@@ -939,241 +938,235 @@
 #endif
 	cs->protocol = card->protocol;
 
-	if ((card->typ > 0) && (card->typ <= ISDN_CTYPE_COUNT)) {
-		if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
-			printk(KERN_WARNING
-				"HiSax: No memory for dlog(card %d)\n",
-				cardnr + 1);
-			restore_flags(flags);
-			return (0);
-		}
-		if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
-			printk(KERN_WARNING
-				"HiSax: No memory for status_buf(card %d)\n",
-				cardnr + 1);
-			kfree(cs->dlog);
-			restore_flags(flags);
-			return (0);
-		}
-		cs->stlist = NULL;
-		cs->status_read = cs->status_buf;
-		cs->status_write = cs->status_buf;
-		cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
-		cs->typ = card->typ;
-		strcpy(cs->iif.id, id);
-		cs->iif.channels = 2;
-		cs->iif.maxbufsize = MAX_DATA_SIZE;
-		cs->iif.hl_hdrlen = MAX_HEADER_LEN;
-		cs->iif.features =
-			ISDN_FEATURE_L2_X75I |
-			ISDN_FEATURE_L2_HDLC |
-			ISDN_FEATURE_L2_HDLC_56K |
-			ISDN_FEATURE_L2_TRANS |
-			ISDN_FEATURE_L3_TRANS |
+	if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
+		printk(KERN_WARNING
+		       "HiSax: Card Type %d out of range\n",
+		       card->typ);
+		goto outf_cs;
+	}
+	if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for dlog(card %d)\n",
+		       cardnr + 1);
+		goto outf_cs;
+	}
+	if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for status_buf(card %d)\n",
+		       cardnr + 1);
+		goto outf_dlog;
+	}
+	cs->stlist = NULL;
+	cs->status_read = cs->status_buf;
+	cs->status_write = cs->status_buf;
+	cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+	cs->typ = card->typ;
+	strcpy(cs->iif.id, id);
+	cs->iif.channels = 2;
+	cs->iif.maxbufsize = MAX_DATA_SIZE;
+	cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+	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
-			ISDN_FEATURE_P_1TR6 |
+		ISDN_FEATURE_P_1TR6 |
 #endif
 #ifdef	CONFIG_HISAX_EURO
-			ISDN_FEATURE_P_EURO |
+		ISDN_FEATURE_P_EURO |
 #endif
 #ifdef	CONFIG_HISAX_NI1
-			ISDN_FEATURE_P_NI1 |
+		ISDN_FEATURE_P_NI1 |
 #endif
-			0;
-
-		cs->iif.command = HiSax_command;
-		cs->iif.writecmd = NULL;
-		cs->iif.writebuf_skb = HiSax_writebuf_skb;
-		cs->iif.readstat = HiSax_readstatus;
-		register_isdn(&cs->iif);
-		cs->myid = cs->iif.channels;
-		printk(KERN_INFO
-			"HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
-			(card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
-			(card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
-			(card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
-			(card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
-			"NONE", cs->iif.id, cs->myid);
-		switch (card->typ) {
+		0;
+	
+	cs->iif.command = HiSax_command;
+	cs->iif.writecmd = NULL;
+	cs->iif.writebuf_skb = HiSax_writebuf_skb;
+	cs->iif.readstat = HiSax_readstatus;
+	register_isdn(&cs->iif);
+	cs->myid = cs->iif.channels;
+	printk(KERN_INFO
+	       "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+	       (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+	       (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+	       (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+	       (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+	       "NONE", cs->iif.id, cs->myid);
+	switch (card->typ) {
 #if CARD_TELES0
-			case ISDN_CTYPE_16_0:
-			case ISDN_CTYPE_8_0:
-				ret = setup_teles0(card);
-				break;
+	case ISDN_CTYPE_16_0:
+	case ISDN_CTYPE_8_0:
+		ret = setup_teles0(card);
+		break;
 #endif
 #if CARD_TELES3
-			case ISDN_CTYPE_16_3:
-			case ISDN_CTYPE_PNP:
-			case ISDN_CTYPE_TELESPCMCIA:
-			case ISDN_CTYPE_COMPAQ_ISA:
-				ret = setup_teles3(card);
-				break;
+	case ISDN_CTYPE_16_3:
+	case ISDN_CTYPE_PNP:
+	case ISDN_CTYPE_TELESPCMCIA:
+	case ISDN_CTYPE_COMPAQ_ISA:
+		ret = setup_teles3(card);
+		break;
 #endif
 #if CARD_S0BOX
-			case ISDN_CTYPE_S0BOX:
-				ret = setup_s0box(card);
-				break;
+	case ISDN_CTYPE_S0BOX:
+		ret = setup_s0box(card);
+		break;
 #endif
 #if CARD_TELESPCI
-			case ISDN_CTYPE_TELESPCI:
-				ret = setup_telespci(card);
-				break;
+	case ISDN_CTYPE_TELESPCI:
+		ret = setup_telespci(card);
+		break;
 #endif
 #if CARD_AVM_A1
-			case ISDN_CTYPE_A1:
-				ret = setup_avm_a1(card);
-				break;
+	case ISDN_CTYPE_A1:
+		ret = setup_avm_a1(card);
+		break;
 #endif
 #if CARD_AVM_A1_PCMCIA
-			case ISDN_CTYPE_A1_PCMCIA:
-				ret = setup_avm_a1_pcmcia(card);
-				break;
+	case ISDN_CTYPE_A1_PCMCIA:
+		ret = setup_avm_a1_pcmcia(card);
+		break;
 #endif
 #if CARD_FRITZPCI
-			case ISDN_CTYPE_FRITZPCI:
-				ret = setup_avm_pcipnp(card);
-				break;
+	case ISDN_CTYPE_FRITZPCI:
+		ret = setup_avm_pcipnp(card);
+		break;
 #endif
 #if CARD_ELSA
-			case ISDN_CTYPE_ELSA:
-			case ISDN_CTYPE_ELSA_PNP:
-			case ISDN_CTYPE_ELSA_PCMCIA:
-			case ISDN_CTYPE_ELSA_PCI:
-				ret = setup_elsa(card);
-				break;
+	case ISDN_CTYPE_ELSA:
+	case ISDN_CTYPE_ELSA_PNP:
+	case ISDN_CTYPE_ELSA_PCMCIA:
+	case ISDN_CTYPE_ELSA_PCI:
+		ret = setup_elsa(card);
+		break;
 #endif
 #if CARD_IX1MICROR2
-			case ISDN_CTYPE_IX1MICROR2:
-				ret = setup_ix1micro(card);
-				break;
+	case ISDN_CTYPE_IX1MICROR2:
+		ret = setup_ix1micro(card);
+		break;
 #endif
 #if CARD_DIEHLDIVA
-			case ISDN_CTYPE_DIEHLDIVA:
-				ret = setup_diva(card);
-				break;
+	case ISDN_CTYPE_DIEHLDIVA:
+		ret = setup_diva(card);
+		break;
 #endif
 #if CARD_ASUSCOM
-			case ISDN_CTYPE_ASUSCOM:
-				ret = setup_asuscom(card);
-				break;
+	case ISDN_CTYPE_ASUSCOM:
+		ret = setup_asuscom(card);
+		break;
 #endif
 #if CARD_TELEINT
-			case ISDN_CTYPE_TELEINT:
-				ret = setup_TeleInt(card);
-				break;
+	case ISDN_CTYPE_TELEINT:
+		ret = setup_TeleInt(card);
+		break;
 #endif
 #if CARD_SEDLBAUER
-			case ISDN_CTYPE_SEDLBAUER:
-			case ISDN_CTYPE_SEDLBAUER_PCMCIA:
-			case ISDN_CTYPE_SEDLBAUER_FAX:
-				ret = setup_sedlbauer(card);
-				break;
+	case ISDN_CTYPE_SEDLBAUER:
+	case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+	case ISDN_CTYPE_SEDLBAUER_FAX:
+		ret = setup_sedlbauer(card);
+		break;
 #endif
 #if CARD_SPORTSTER
-			case ISDN_CTYPE_SPORTSTER:
-				ret = setup_sportster(card);
-				break;
+	case ISDN_CTYPE_SPORTSTER:
+		ret = setup_sportster(card);
+		break;
 #endif
 #if CARD_MIC
-			case ISDN_CTYPE_MIC:
-				ret = setup_mic(card);
-				break;
+	case ISDN_CTYPE_MIC:
+		ret = setup_mic(card);
+		break;
 #endif
 #if CARD_NETJET_S
-			case ISDN_CTYPE_NETJET_S:
-				ret = setup_netjet_s(card);
-				break;
+	case ISDN_CTYPE_NETJET_S:
+		ret = setup_netjet_s(card);
+		break;
 #endif
 #if CARD_HFCS
-			case ISDN_CTYPE_TELES3C:
-			case ISDN_CTYPE_ACERP10:
-				ret = setup_hfcs(card);
-				break;
+	case ISDN_CTYPE_TELES3C:
+	case ISDN_CTYPE_ACERP10:
+		ret = setup_hfcs(card);
+		break;
 #endif
 #if CARD_HFC_PCI
-		        case ISDN_CTYPE_HFC_PCI: 
-				ret = setup_hfcpci(card);
-				break;
+	case ISDN_CTYPE_HFC_PCI: 
+		ret = setup_hfcpci(card);
+		break;
 #endif
 #if CARD_HFC_SX
-		        case ISDN_CTYPE_HFC_SX: 
-				ret = setup_hfcsx(card);
-				break;
+	case ISDN_CTYPE_HFC_SX: 
+		ret = setup_hfcsx(card);
+		break;
 #endif
 #if CARD_NICCY
-			case ISDN_CTYPE_NICCY:
-				ret = setup_niccy(card);
-				break;
+	case ISDN_CTYPE_NICCY:
+		ret = setup_niccy(card);
+		break;
 #endif
 #if CARD_AMD7930
-			case ISDN_CTYPE_AMD7930:
-				ret = setup_amd7930(card);
-				break;
+	case ISDN_CTYPE_AMD7930:
+		ret = setup_amd7930(card);
+		break;
 #endif
 #if CARD_ISURF
-			case ISDN_CTYPE_ISURF:
-				ret = setup_isurf(card);
-				break;
+	case ISDN_CTYPE_ISURF:
+		ret = setup_isurf(card);
+		break;
 #endif
 #if CARD_HSTSAPHIR
-			case ISDN_CTYPE_HSTSAPHIR:
-				ret = setup_saphir(card);
-				break;
+	case ISDN_CTYPE_HSTSAPHIR:
+		ret = setup_saphir(card);
+		break;
 #endif
 #if CARD_TESTEMU
-			case ISDN_CTYPE_TESTEMU:
-				ret = setup_testemu(card);
-				break;
+	case ISDN_CTYPE_TESTEMU:
+		ret = setup_testemu(card);
+		break;
 #endif
 #if	CARD_BKM_A4T       
-           	case ISDN_CTYPE_BKM_A4T:
-	        	ret = setup_bkm_a4t(card);
-			break;
+	case ISDN_CTYPE_BKM_A4T:
+		ret = setup_bkm_a4t(card);
+		break;
 #endif
 #if	CARD_SCT_QUADRO
-	        case ISDN_CTYPE_SCT_QUADRO:
-    			ret = setup_sct_quadro(card);
-			break;
+	case ISDN_CTYPE_SCT_QUADRO:
+		ret = setup_sct_quadro(card);
+		break;
 #endif
 #if CARD_GAZEL
- 		case ISDN_CTYPE_GAZEL:
- 			ret = setup_gazel(card);
- 			break;
+	case ISDN_CTYPE_GAZEL:
+		ret = setup_gazel(card);
+		break;
 #endif
 #if CARD_W6692
-		case ISDN_CTYPE_W6692:
-			ret = setup_w6692(card);
-			break;
+	case ISDN_CTYPE_W6692:
+		ret = setup_w6692(card);
+		break;
 #endif
 #if CARD_NETJET_U
-			case ISDN_CTYPE_NETJET_U:
-				ret = setup_netjet_u(card);
-				break;
+	case ISDN_CTYPE_NETJET_U:
+		ret = setup_netjet_u(card);
+		break;
 #endif
-		default:
-			printk(KERN_WARNING
-				"HiSax: Support for %s Card not selected\n",
-				CardType[card->typ]);
-			ll_unload(cs);
-			restore_flags(flags);
-			return (0);
-		}
-	} else {
+	default:
 		printk(KERN_WARNING
-		       "HiSax: Card Type %d out of range\n",
-		       card->typ);
-		restore_flags(flags);
-		return (0);
+		       "HiSax: Support for %s Card not selected\n",
+		       CardType[card->typ]);
+		ll_unload(cs);
+		goto outf_cs;
 	}
 	if (!ret) {
 		ll_unload(cs);
-		restore_flags(flags);
-		return (0);
+		goto outf_cs;
 	}
 	if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
 		printk(KERN_WARNING
 		       "HiSax: No memory for isac rcvbuf\n");
-		return (1);
+		ll_unload(cs);
+		goto outf_cs;
 	}
 	cs->rcvidx = 0;
 	cs->tx_skb = NULL;
@@ -1190,21 +1183,31 @@
 	ret = init_card(cs);
 	if (ret) {
 		closecard(cardnr);
-		restore_flags(flags);
-		return (0);
+		ret = 0;
+		goto outf_cs;
 	}
 	init_tei(cs, cs->protocol);
 	ret = CallcNewChan(cs);
 	if (ret) {
 		closecard(cardnr);
-		restore_flags(flags);
-		return 0;
+		ret = 0;
+		goto outf_cs;
 	}
 	/* ISAR needs firmware download first */
 	if (!test_bit(HW_ISAR, &cs->HW_Flags))
 		ll_run(cs, 0);
+
+	ret = 1;
+	goto out;
+
+ outf_dlog:
+	kfree(cs->dlog);
+ outf_cs:
+	kfree(cs);
+	card->cs = NULL;
+ out:
 	restore_flags(flags);
-	return (1);
+	return ret;
 }
 
 void __devinit
@@ -1253,9 +1256,6 @@
 		} else {
 			printk(KERN_WARNING "HiSax: Card %s not installed !\n",
 			       CardType[cards[i].typ]);
-			if (cards[i].cs)
-				kfree((void *) cards[i].cs);
-			cards[i].cs = NULL;
 			HiSax_shiftcards(i);
 			nrcards--;
 		}
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/elsa_cs.c linux/drivers/isdn/hisax/elsa_cs.c
--- v2.4.3/linux/drivers/isdn/hisax/elsa_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/elsa_cs.c	Wed Apr 18 11:49:13 2001
@@ -0,0 +1,558 @@
+/*======================================================================
+
+    An elsa_cs PCMCIA client driver
+
+    This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
+    Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
+static char *version =
+"elsa_cs.c $Revision: 1.1.2.1 $ $Date: 2001/04/15 08:01:34 $ (K.Lichtenwalder)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from, the old way */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, 3 */
+static u_long irq_mask = 0xdeb8;
+
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+static int protocol = 2;        /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+extern int elsa_init_pcmcia(int, int, int*, int);
+
+/*====================================================================*/
+
+/*
+   The event() function is this driver's Card Services event handler.
+   It will be called by Card Services when an appropriate card status
+   event is received.  The config() and release() entry points are
+   used to configure or release a socket, in response to card insertion
+   and ejection events.  They are invoked from the elsa_cs event
+   handler.
+*/
+
+static void elsa_cs_config(dev_link_t *link);
+static void elsa_cs_release(u_long arg);
+static int elsa_cs_event(event_t event, int priority,
+                          event_callback_args_t *args);
+
+/*
+   The attach() and detach() entry points are used to create and destroy
+   "instances" of the driver, where each instance represents everything
+   needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *elsa_cs_attach(void);
+static void elsa_cs_detach(dev_link_t *);
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "elsa_cs";
+
+/*
+   A linked list of "instances" of the elsa_cs device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   To simplify the data structure handling, we actually include the
+   dev_link_t structure in the device's private data structure.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally shouldn't be allocated dynamically.
+   In this case, we also provide a flag to indicate if a device is
+   "stopped" due to a power management event, or card ejection.  The
+   device IO routines can use a flag like this to throttle IO to a
+   card that is not ready to accept it.
+
+   The bus_operations pointer is used on platforms for which we need
+   to use special socket-specific versions of normal IO primitives
+   (inb, outb, readb, writeb, etc) for card IO.
+*/
+
+typedef struct local_info_t {
+    dev_link_t          link;
+    dev_node_t          node;
+    int                 busy;
+  struct bus_operations *bus;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret};
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    elsa_cs_attach() creates an "instance" of the driver, allocatingx
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+
+======================================================================*/
+
+static dev_link_t *elsa_cs_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    local_info_t *local;
+    int ret, i;
+    void elsa_interrupt(int, void *, struct pt_regs *);
+
+    DEBUG(0, "elsa_cs_attach()\n");
+
+    /* Allocate space for private device-specific data */
+    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    if (!local) return NULL;
+    memset(local, 0, sizeof(local_info_t));
+    link = &local->link; link->priv = local;
+
+    /* Initialize the dev_link_t structure */
+    link->release.function = &elsa_cs_release;
+    link->release.data = (u_long)link;
+
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID|IRQ_SHARE_ID;
+    if (irq_list[0] == -1)
+        link->irq.IRQInfo2 = irq_mask;
+    else
+        for (i = 0; i < 4; i++)
+            link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = NULL;
+
+    /*
+      General socket configuration defaults can go here.  In this
+      client, we assume very little, and rely on the CIS for almost
+      everything.  In most clients, many details (i.e., number, sizes,
+      and attributes of IO windows) are fixed by the nature of the
+      device, and can be hard-wired here.
+    */
+    link->io.NumPorts1 = 8;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 3;
+
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &elsa_cs_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+        cs_error(link->handle, RegisterClient, ret);
+        elsa_cs_detach(link);
+        return NULL;
+    }
+
+    return link;
+} /* elsa_cs_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void elsa_cs_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    local_info_t *info = link->priv;
+    int ret;
+
+    DEBUG(0, "elsa_cs_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+        if (*linkp == link) break;
+    if (*linkp == NULL)
+        return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+        elsa_cs_release((u_long)link);
+
+    /*
+       If the device is currently configured and active, we won't
+       actually delete it yet.  Instead, it is marked so that when
+       the release() function is called, that will trigger a proper
+       detach().
+    */
+    if (link->state & DEV_CONFIG) {
+      DEBUG(0, "elsa_cs: detach postponed, '%s' "
+               "still locked\n", link->dev->dev_name);
+        link->state |= DEV_STALE_LINK;
+        return;
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle) {
+        ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+
+    /* Unlink device structure and free it */
+    *linkp = link->next;
+    kfree(info);
+
+} /* elsa_cs_detach */
+
+/*======================================================================
+
+    elsa_cs_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    device available to the system.
+
+======================================================================*/
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+                     cisparse_t *parse)
+{
+    int i;
+    i = CardServices(fn, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    i = CardServices(GetTupleData, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+static void elsa_cs_config(dev_link_t *link)
+{
+    client_handle_t handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    local_info_t *dev;
+    int i, j, last_fn;
+    u_short buf[128];
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+
+    DEBUG(0, "elsa_config(0x%p)\n", link);
+    handle = link->handle;
+    dev = link->priv;
+
+    /*
+       This reads the card's CONFIG tuple to find its configuration
+       registers.
+    */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = 255;
+    tuple.TupleOffset = 0;
+    tuple.Attributes = 0;
+    i = first_tuple(handle, &tuple, &parse);
+    if (i != CS_SUCCESS) {
+        last_fn = ParseTuple;
+	goto cs_failed;
+    }
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    i = first_tuple(handle, &tuple, &parse);
+    while (i == CS_SUCCESS) {
+        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
+            printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
+            link->conf.ConfigIndex = cf->index;
+            link->io.BasePort1 = cf->io.win[0].base;
+            i = CardServices(RequestIO, link->handle, &link->io);
+            if (i == CS_SUCCESS) break;
+        } else {
+          printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
+          link->conf.ConfigIndex = cf->index;
+          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
+            link->io.BasePort1 = j;
+            i = CardServices(RequestIO, link->handle, &link->io);
+            if (i == CS_SUCCESS) break;
+          }
+          break;
+        }
+        i = next_tuple(handle, &tuple, &parse);
+    }
+
+    if (i != CS_SUCCESS) {
+	last_fn = RequestIO;
+	goto cs_failed;
+    }
+
+    i = CardServices(RequestIRQ, link->handle, &link->irq);
+    if (i != CS_SUCCESS) {
+        link->irq.AssignedIRQ = 0;
+	last_fn = RequestIRQ;
+        goto cs_failed;
+    }
+
+    i = CardServices(RequestConfiguration, link->handle, &link->conf);
+    if (i != CS_SUCCESS) {
+      last_fn = RequestConfiguration;
+      goto cs_failed;
+    }
+
+    /* At this point, the dev_node_t structure(s) should be
+       initialized and arranged in a linked list at link->dev. *//*  */
+    sprintf(dev->node.dev_name, "elsa");
+    dev->node.major = dev->node.minor = 0x0;
+
+    link->dev = &dev->node;
+
+    /* Finally, report what we've done */
+    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+           dev->node.dev_name, link->conf.ConfigIndex,
+           link->conf.Vcc/10, link->conf.Vcc%10);
+    if (link->conf.Vpp1)
+        printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+        printk(", irq %d", link->irq.AssignedIRQ);
+    if (link->io.NumPorts1)
+        printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+               link->io.BasePort1+link->io.NumPorts1-1);
+    if (link->io.NumPorts2)
+        printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+               link->io.BasePort2+link->io.NumPorts2-1);
+    printk("\n");
+
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    elsa_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ,
+                     &(((local_info_t*)link->priv)->busy),
+                     protocol);
+    return;
+cs_failed:
+    cs_error(link->handle, last_fn, i);
+    elsa_cs_release((u_long)link);
+} /* elsa_cs_config */
+
+/*======================================================================
+
+    After a card is removed, elsa_cs_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void elsa_cs_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "elsa_cs_release(0x%p)\n", link);
+
+    /*
+       If the device is currently in use, we won't release until it
+       is actually closed, because until then, we can't be sure that
+       no one will try to access the device or its data structures.
+    */
+    if (link->open) {
+        DEBUG(1, "elsa_cs: release postponed, '%s' "
+                   "still open\n", link->dev->dev_name);
+        link->state |= DEV_STALE_CONFIG;
+        return;
+    }
+
+    /* Unlink the device chain */
+    link->dev = NULL;
+
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win)
+        CardServices(ReleaseWindow, link->win);
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    link->state &= ~DEV_CONFIG;
+
+    if (link->state & DEV_STALE_LINK)
+        elsa_cs_detach(link);
+
+} /* elsa_cs_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+    When a CARD_REMOVAL event is received, we immediately set a flag
+    to block future accesses to this device.  All the functions that
+    actually access the device should check this flag to make sure
+    the card is still present.
+
+======================================================================*/
+
+static int elsa_cs_event(event_t event, int priority,
+                          event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    local_info_t *dev = link->priv;
+
+    DEBUG(1, "elsa_cs_event(%d)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+        link->state &= ~DEV_PRESENT;
+        if (link->state & DEV_CONFIG) {
+            ((local_info_t*)link->priv)->busy = 1;
+            mod_timer(&link->release, jiffies + HZ/20);
+        }
+        break;
+    case CS_EVENT_CARD_INSERTION:
+        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+        dev->bus = args->bus;
+        elsa_cs_config(link);
+        break;
+    case CS_EVENT_PM_SUSPEND:
+        link->state |= DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+        /* Mark the device as stopped, to block IO until later */
+        dev->busy = 1;
+        if (link->state & DEV_CONFIG)
+            CardServices(ReleaseConfiguration, link->handle);
+        break;
+    case CS_EVENT_PM_RESUME:
+        link->state &= ~DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+        if (link->state & DEV_CONFIG)
+            CardServices(RequestConfiguration, link->handle, &link->conf);
+        dev->busy = 0;
+        break;
+    }
+    return 0;
+} /* elsa_cs_event */
+
+/*====================================================================*/
+
+static int __init init_elsa_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+        printk(KERN_NOTICE "elsa_cs: Card Services release "
+               "does not match!\n");
+        return -1;
+    }
+    register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach);
+    return 0;
+}
+
+static void __exit exit_elsa_cs(void)
+{
+    DEBUG(0, "elsa_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+        elsa_cs_detach(dev_list);
+}
+
+module_init(init_elsa_cs);
+module_exit(exit_elsa_cs);
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- v2.4.3/linux/drivers/isdn/hisax/hfc_pci.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/hisax/hfc_pci.c	Wed Apr 18 11:49:13 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.34.6.4 2001/02/13 10:33:58 kai Exp $
+/* $Id: hfc_pci.c,v 1.34.6.5 2001/04/08 19:32:26 kai Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
@@ -35,7 +35,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.34.6.4 $";
+static const char *hfcpci_revision = "$Revision: 1.34.6.5 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
@@ -235,6 +235,59 @@
 		return (NULL);
 }
 
+/***************************************/
+/* clear the desired B-channel rx fifo */
+/***************************************/
+static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo)
+{       u_char fifo_state;
+        bzfifo_type *bzr;
+
+	if (fifo) {
+	        bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX;
+	} else {
+	        bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
+		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX;
+	}
+	if (fifo_state)
+	        cs->hw.hfcpci.fifo_en ^= fifo_state;
+	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+	cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0;
+	bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
+	bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
+	bzr->f1 = MAX_B_FRAMES;
+	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
+	if (fifo_state)
+	        cs->hw.hfcpci.fifo_en |= fifo_state;
+	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+}   
+
+/***************************************/
+/* clear the desired B-channel tx fifo */
+/***************************************/
+static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo)
+{       u_char fifo_state;
+        bzfifo_type *bzt;
+
+	if (fifo) {
+	        bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
+		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX;
+	} else {
+	        bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
+		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX;
+	}
+	if (fifo_state)
+	        cs->hw.hfcpci.fifo_en ^= fifo_state;
+	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+	bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
+	bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
+	bzt->f1 = MAX_B_FRAMES;
+	bzt->f2 = bzt->f1;	/* init F pointers to remain constant */
+	if (fifo_state)
+	        cs->hw.hfcpci.fifo_en |= fifo_state;
+	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+}   
+
 /*********************************************/
 /* read a complete B-frame out of the buffer */
 /*********************************************/
@@ -428,7 +481,7 @@
 {
 	long flags;
 	struct IsdnCardState *cs = bcs->cs;
-	int rcnt;
+	int rcnt, real_fifo;
 	int receive, count = 5;
 	struct sk_buff *skb;
 	bzfifo_type *bz;
@@ -440,9 +493,11 @@
 	if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
 		bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
 		bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
+		real_fifo = 1;
 	} else {
 		bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
 		bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1;
+		real_fifo = 0;
 	}
       Begin:
 	count--;
@@ -475,6 +530,11 @@
 		rcnt = bz->f1 - bz->f2;
 		if (rcnt < 0)
 			rcnt += MAX_B_FRAMES + 1;
+		if (cs->hw.hfcpci.last_bfifo_cnt[real_fifo] > rcnt + 1) {
+		        rcnt = 0;
+			hfcpci_clear_fifo_rx(cs, real_fifo);
+		}
+		cs->hw.hfcpci.last_bfifo_cnt[real_fifo] = rcnt;
 		if (rcnt > 1)
 			receive = 1;
 		else
@@ -1253,7 +1313,6 @@
 mode_hfcpci(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	bzfifo_type *bzr, *bzt;
 	int flags, fifo2;
 
 	if (cs->debug & L1_DEB_HSCX)
@@ -1300,6 +1359,8 @@
 			}
 			break;
 		case (L1_MODE_TRANS):
+		        hfcpci_clear_fifo_rx(cs, fifo2);
+		        hfcpci_clear_fifo_tx(cs, fifo2);
 			if (bc) {
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
@@ -1312,26 +1373,16 @@
 				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
 				cs->hw.hfcpci.ctmt |= 2;
 				cs->hw.hfcpci.conn &= ~0x18;
-				bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
-				bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
 			} else {
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
 				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
 				cs->hw.hfcpci.ctmt |= 1;
 				cs->hw.hfcpci.conn &= ~0x03;
-				bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
-				bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
 			}
-			bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-			bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
-			bzr->f1 = MAX_B_FRAMES;
-			bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
-			bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-			bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
-			bzt->f1 = MAX_B_FRAMES;
-			bzt->f2 = bzt->f1;	/* init F pointers to remain constant */
 			break;
 		case (L1_MODE_HDLC):
+		        hfcpci_clear_fifo_rx(cs, fifo2);
+		        hfcpci_clear_fifo_tx(cs, fifo2);
 			if (bc) {
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
@@ -1340,11 +1391,13 @@
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
 			}
 			if (fifo2) {
+			        cs->hw.hfcpci.last_bfifo_cnt[1] = 0;  
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
 				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
 				cs->hw.hfcpci.ctmt &= ~2;
 				cs->hw.hfcpci.conn &= ~0x18;
 			} else {
+			        cs->hw.hfcpci.last_bfifo_cnt[0] = 0;  
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
 				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
 				cs->hw.hfcpci.ctmt &= ~1;
@@ -1633,7 +1686,8 @@
 
 #endif				/* CONFIG_PCI */
 
-int __init setup_hfcpci(struct IsdnCard *card)
+int __init
+setup_hfcpci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -1645,7 +1699,7 @@
 #endif
 	strcpy(tmp, hfcpci_revision);
 	printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-#ifdef CONFIG_PCI
+#if CONFIG_PCI
 	cs->hw.hfcpci.int_s1 = 0;
 	cs->dc.hfcpci.ph_state = 0;
 	cs->hw.hfcpci.fifo = 255;
@@ -1659,6 +1713,7 @@
 			if (tmp_hfcpci) {
 				if (pci_enable_device(tmp_hfcpci))
 					continue;
+				pci_set_master(tmp_hfcpci);
 				if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
 					continue;
 				else
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/hfc_pci.h linux/drivers/isdn/hisax/hfc_pci.h
--- v2.4.3/linux/drivers/isdn/hisax/hfc_pci.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/hfc_pci.h	Wed Apr 18 11:49:14 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.h,v 1.8 2000/06/26 08:59:13 keil Exp $
+/* $Id: hfc_pci.h,v 1.8.6.1 2001/04/08 19:32:26 kai Exp $
  *
  *  specific defines for CCD's HFC 2BDS0 PCI chips
  *
@@ -178,6 +178,9 @@
 #define HFCPCI_FIFOEN_B1     0x03
 #define HFCPCI_FIFOEN_B2     0x0C
 #define HFCPCI_FIFOEN_DTX    0x10
+#define HFCPCI_FIFOEN_B1TX   0x01
+#define HFCPCI_FIFOEN_B1RX   0x02
+#define HFCPCI_FIFOEN_B2TX   0x04
 #define HFCPCI_FIFOEN_B2RX   0x08
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.4.3/linux/drivers/isdn/hisax/hisax.h	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/hisax/hisax.h	Wed Apr 18 11:49:14 2001
@@ -1,4 +1,4 @@
-/* $Id: hisax.h,v 2.52.6.3 2001/02/16 16:43:27 kai Exp $
+/* $Id: hisax.h,v 2.52.6.4 2001/04/08 19:32:26 kai Exp $
  *
  *   Basic declarations, defines and prototypes
  *
@@ -687,6 +687,7 @@
         unsigned char *pci_io; /* start of PCI IO memory */
         void *share_start; /* shared memory for Fifos start */
         void *fifos; /* FIFO memory */ 
+        int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
 	struct timer_list timer;
 };
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- v2.4.3/linux/drivers/isdn/hisax/isar.c	Fri Mar  2 11:12:09 2001
+++ linux/drivers/isdn/hisax/isar.c	Wed Apr 18 11:49:14 2001
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $
+/* $Id: isar.c,v 1.17.6.2 2001/04/08 17:51:42 kai Exp $
  *
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
@@ -383,12 +383,12 @@
 	} else {
 		printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n",
 			ireg->cmsb, ireg->clsb, ireg->par[0]);
-		ret = 1;goto reterror;
+		ret = 1;goto reterrflg;
 	}
 	ireg->iis = 0;
 	if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
 		printk(KERN_ERR"isar RQST SVN failed\n");
-		ret = 1;goto reterror;
+		ret = 1;goto reterrflg;
 	}
 	cnt = 30000; /* max 300 ms */
 	while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc
--- v2.4.3/linux/drivers/isdn/hisax/md5sums.asc	Wed Jan 10 14:12:53 2001
+++ linux/drivers/isdn/hisax/md5sums.asc	Thu Apr 19 22:30:09 2001
@@ -7,27 +7,27 @@
 # cards in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
-ca7bd9bac39203f3074f3f093948cc3c  isac.c
-a2ad619fd404b3149099a2984de9d23c  isdnl1.c
-d2a78e407f3d94876deac160c6f9aae6  isdnl2.c
-e7932ca7ae39c497c17f13a2e1434fcd  isdnl3.c
-afb5f2f4ac296d6de45c856993b161e1  tei.c
-00023e2a482cb86a26ea870577ade5d6  callc.c
-a1834e9b2ec068440cff2e899eff4710  cert.c
-1551f78b3cd01097ecd586b5c96d0765  l3dss1.c
-89aecf3a80489c723dc885fcaa4aba1b  l3_1tr6.c
-1685c1ddfecf3e1b88ae5f3d7202ce69  elsa.c
-6d7056d1558bf6cc57dd89b7b260dc27  diva.c
-4398918680d45c4618bb48108ea0c282  sedlbauer.c
+9663cc9f4374c361197d394f6d27c459  isac.c
+9666c672c0fa0e65d5cc5b322f10a18c  isdnl1.c
+9250f15b932dfc36855aa120b896ed0b  isdnl2.c
+0cc2ef892bdb4a2be473e00eb1398950  isdnl3.c
+cac9c32fff889c57ff50d59823053019  tei.c
+665044a72334336533ac79da1a831b17  callc.c
+e592db58630c1f1029cc064110108156  cert.c
+fadeb3b85bb23bc1ac48470c0848d6fa  l3dss1.c
+cf7dec9fac6283716904d26b99188476  l3_1tr6.c
+65d9e5471bc129624f858ebcf0743525  elsa.c
+b4cf8a4dceed9ea6dcba65a85b4eecc7  diva.c
+99e67bea8f6945fa0d4e0aded5bf0fa0  sedlbauer.c
 # end of md5sums
 
 -----BEGIN PGP SIGNATURE-----
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBOlxeLTpxHvX/mS9tAQH6RwP8DhyvqAnXFV6WIGi16iQ3vKikkPoqnDQs
-GEn5uCW0dPYKlwthD2Grj/JbMYZhOmCFuDxF7ufJnjTSDe/D8XNe2wngxzAiwcIe
-WjCrT8X95cuP3HZHscbFTEinVV0GAnoI0ZEgs5eBDhVHDqILLYMaTFBQaRH3jgXc
-i5VH88jPfUM=
-=qc+J
+iQCVAwUBOt+j/jpxHvX/mS9tAQGXwAP/U4voKzXAcTfo9CqJhHN92GRxunj6mlvn
+H+1pxSe0GdtC7BlrPhrokB5dNSwewk89Z5t7kTD76kx2FFuTcXBJxbgH7LZVF3ga
+JX92bOWQekHMH7Hk12Qc7zpeTmPzY02pvVc37Eo614BCvJMCk02cpQyo8a5wWRKH
+8vpQkQKiSyY=
+=FFLG
 -----END PGP SIGNATURE-----
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c
--- v2.4.3/linux/drivers/isdn/hysdn/boardergo.c	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/hysdn/boardergo.c	Wed Apr 18 11:49:14 2001
@@ -386,7 +386,9 @@
 			dpr->ToPcInt = 1;	/* interrupt to E1 for all cards */
 
 			restore_flags(flags);
-			if ((i = hysdn_net_create(card))) {
+			if ((hynet_enable & (1 << card->myid)) 
+			    && (i = hysdn_net_create(card))) 
+			{
 				ergo_stopcard(card);
 				card->state = CARD_STATE_BOOTERR;
 				return (i);
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c
--- v2.4.3/linux/drivers/isdn/hysdn/hycapi.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/isdn/hysdn/hycapi.c	Wed Apr 18 11:49:14 2001
@@ -41,7 +41,10 @@
 #include "hysdn_defs.h"
 #include <linux/kernelcapi.h>
 
-static char hycapi_revision[]="$Revision: 1.8.6.1 $";
+static char hycapi_revision[]="$Revision: 1.11 $";
+
+unsigned int hycapi_enable = 0xffffffff; 
+MODULE_PARM(hycapi_enable, "i");
 
 typedef struct _hycapi_appl {
 	unsigned int ctrl_mask;
@@ -542,15 +545,11 @@
 	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) {
@@ -644,8 +643,6 @@
 	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);
@@ -671,8 +668,6 @@
 {
 	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)
@@ -792,6 +787,9 @@
 #ifdef HYCAPI_PRINTFNAMES
 	printk(KERN_NOTICE "hycapi_capi_create\n");        
 #endif
+	if((hycapi_enable & (1 << card->myid)) == 0) {
+		return 1;
+	}
 	if (!card->hyctrlinfo) {
 		cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
 		if (!cinfo) {
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hysdn/hysdn_defs.h linux/drivers/isdn/hysdn/hysdn_defs.h
--- v2.4.3/linux/drivers/isdn/hysdn/hysdn_defs.h	Tue Nov 28 21:44:41 2000
+++ linux/drivers/isdn/hysdn/hysdn_defs.h	Wed Apr 18 11:49:14 2001
@@ -273,6 +273,7 @@
 extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word);	/* send one cfg line */
 
 /* hysdn_net.c */
+extern unsigned int hynet_enable; 
 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 */
@@ -282,6 +283,7 @@
 extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word);	/* rxed packet from network */
 
 #ifdef CONFIG_HYSDN_CAPI
+extern unsigned int hycapi_enable; 
 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 */
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c
--- v2.4.3/linux/drivers/isdn/hysdn/hysdn_net.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/isdn/hysdn/hysdn_net.c	Wed Apr 18 11:49:14 2001
@@ -37,8 +37,11 @@
 
 #include "hysdn_defs.h"
 
+unsigned int hynet_enable = 0xffffffff; 
+MODULE_PARM(hynet_enable, "i");
+
 /* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.8.6.1 $";
+char *hysdn_net_revision = "$Revision: 1.10 $";
 
 #define MAX_SKB_BUFFERS 20	/* number of buffers for keeping TX-data */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c
--- v2.4.3/linux/drivers/isdn/hysdn/hysdn_procconf.c	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/hysdn/hysdn_procconf.c	Wed Apr 18 11:49:14 2001
@@ -41,7 +41,7 @@
 #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 */
+#define CONF_LINE_LEN   255	/* 255 chars max */
 
 struct conf_writedata {
 	hysdn_card *card;	/* card the device is connected to */
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c
--- v2.4.3/linux/drivers/isdn/hysdn/hysdn_sched.c	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/hysdn/hysdn_sched.c	Wed Apr 18 11:49:14 2001
@@ -47,7 +47,10 @@
 
 	switch (chan) {
 		case CHAN_NDIS_DATA:
-			hysdn_rx_netpkt(card, buf, len);	/* give packet to network handler */
+			if (hynet_enable & (1 << card->myid)) {
+                          /* give packet to network handler */
+				hysdn_rx_netpkt(card, buf, len);
+			}
 			break;
 
 		case CHAN_ERRLOG:
@@ -58,7 +61,9 @@
 #ifdef CONFIG_HYSDN_CAPI
          	case CHAN_CAPI:
 /* give packet to CAPI handler */
-			hycapi_rx_capipkt(card, buf, len);
+			if (hycapi_enable & (1 << card->myid)) {
+				hycapi_rx_capipkt(card, buf, len);
+			}
 			break;
 #endif /* CONFIG_HYSDN_CAPI */
 		default:
@@ -115,7 +120,9 @@
 		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 ((hynet_enable & (1 << card->myid)) && 
+	    (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;
@@ -126,7 +133,9 @@
 			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( ((hycapi_enable & (1 << card->myid))) && 
+	    ((skb = hycapi_tx_capiget(card)) != NULL) )
+	{
 		if (skb->len <= maxlen) {
 			memcpy(buf, skb->data, skb->len);
 			*len = skb->len;
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- v2.4.3/linux/drivers/isdn/icn/icn.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/isdn/icn/icn.c	Thu Apr 19 22:30:23 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.65.6.3 2001/02/16 16:43:31 kai Exp $
+/* $Id: icn.c,v 1.65.6.4 2001/04/20 02:42:01 keil Exp $
 
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -34,7 +34,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.65.6.3 $";
+*revision = "$Revision: 1.65.6.4 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -838,23 +838,23 @@
 			card->other->rvalid = 1;
 	}
 	if (!dev.mvalid) {
-		if (check_shmem((ulong) dev.shmem, 0x4000)) {
+		if (check_mem_region(dev.memaddr, 0x4000)) {
 			printk(KERN_WARNING
-			       "icn: memory at 0x%08lx in use.\n",
-			       (ulong) dev.shmem);
+			       "icn: memory at 0x%08lx in use.\n", dev.memaddr);
 			restore_flags(flags);
 			return -EBUSY;
 		}
-		request_shmem((ulong) dev.shmem, 0x4000, "icn");
+		request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)");
+		dev.shmem = ioremap(dev.memaddr, 0x4000);
 		dev.mvalid = 1;
 	}
 	restore_flags(flags);
 	OUTB_P(0, ICN_RUN);     /* Reset Controller */
 	OUTB_P(0, ICN_MAPRAM);  /* Disable RAM      */
 	icn_shiftout(ICN_CFG, 0x0f, 3, 4);	/* Windowsize= 16k  */
-	icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10);	/* Set RAM-Addr.    */
+	icn_shiftout(ICN_CFG, dev.memaddr, 23, 10);	/* Set RAM-Addr.    */
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
+	printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
 #endif
 	SLEEP(1);
 #ifdef BOOT_DEBUG
@@ -1177,29 +1177,31 @@
 			memcpy(&a, c->parm.num, sizeof(ulong));
 			switch (c->arg) {
 				case ICN_IOCTL_SETMMIO:
-					if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
-						if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
+					if (dev.memaddr != (a & 0x0ffc000)) {
+						if (check_mem_region(a & 0x0ffc000, 0x4000)) {
 							printk(KERN_WARNING
 							       "icn: memory at 0x%08lx in use.\n",
-							       (ulong) (a & 0x0ffc000));
+							       a & 0x0ffc000);
 							return -EINVAL;
 						}
 						icn_stopallcards();
 						save_flags(flags);
 						cli();
-						if (dev.mvalid)
-							release_shmem((ulong) dev.shmem, 0x4000);
+						if (dev.mvalid) {
+							iounmap(dev.shmem);
+							release_mem_region(dev.memaddr, 0x4000);
+						}
 						dev.mvalid = 0;
-						dev.shmem = (icn_shmem *) (a & 0x0ffc000);
+						dev.memaddr = a & 0x0ffc000;
 						restore_flags(flags);
 						printk(KERN_INFO
 						       "icn: (%s) mmio set to 0x%08lx\n",
 						       CID,
-						       (unsigned long) dev.shmem);
+						       dev.memaddr);
 					}
 					break;
 				case ICN_IOCTL_GETMMIO:
-					return (long) dev.shmem;
+					return (long) dev.memaddr;
 				case ICN_IOCTL_SETPORT:
 					if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
 					    || a == 0x340 || a == 0x350 || a == 0x360 ||
@@ -1652,7 +1654,7 @@
 	if (ints[0])
 		portbase = ints[1];
 	if (ints[0] > 1)
-		membase = ints[2];
+		membase = (unsigned long)ints[2];
 	if (str && *str) {
 		strcpy(sid, str);
 		icn_id = sid;
@@ -1673,7 +1675,7 @@
 	char rev[10];
 
 	memset(&dev, 0, sizeof(icn_dev));
-	dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000);
+	dev.memaddr = (membase & 0x0ffc000);
 	dev.channel = -1;
 	dev.mcard = NULL;
 	dev.firstload = 1;
@@ -1685,7 +1687,7 @@
 	} else
 		strcpy(rev, " ??? ");
 	printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
-	       (ulong) dev.shmem);
+	       dev.memaddr);
 	return (icn_addcard(portbase, icn_id, icn_id2));
 }
 
@@ -1719,8 +1721,10 @@
 		card = card->next;
 		kfree(last);
 	}
-	if (dev.mvalid)
-		release_shmem((ulong) dev.shmem, 0x4000);
+	if (dev.mvalid) {
+		iounmap(dev.shmem);
+		release_mem_region(dev.memaddr, 0x4000);
+	}
 	printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- v2.4.3/linux/drivers/isdn/icn/icn.h	Fri Mar  2 11:12:10 2001
+++ linux/drivers/isdn/icn/icn.h	Thu Apr 19 22:30:23 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.30.6.2 2001/02/16 16:43:31 kai Exp $
+/* $Id: icn.h,v 1.30.6.3 2001/04/20 02:42:01 keil Exp $
 
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -187,6 +187,7 @@
  * Main driver data
  */
 typedef struct icn_dev {
+	unsigned long memaddr;	/* Address of memory mapped buffers */
 	icn_shmem *shmem;       /* Pointer to memory-mapped-buffers */
 	int mvalid;             /* IO-shmem has been requested      */
 	int channel;            /* Currently mapped channel         */
@@ -210,7 +211,7 @@
  * integers.
  */
 static int portbase = ICN_BASEADDR;
-static int membase = ICN_MEMADDR;
+static unsigned long membase = ICN_MEMADDR;
 static char *icn_id = "\0";
 static char *icn_id2 = "\0";
 
@@ -218,7 +219,7 @@
 MODULE_AUTHOR("Fritz Elfert");
 MODULE_PARM(portbase, "i");
 MODULE_PARM_DESC(portbase, "Port address of first card");
-MODULE_PARM(membase, "i");
+MODULE_PARM(membase, "l");
 MODULE_PARM_DESC(membase, "Shared memory address of all cards");
 MODULE_PARM(icn_id, "s");
 MODULE_PARM_DESC(icn_id, "ID-String of first card");
@@ -286,14 +287,6 @@
 
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
-
-/* Hopefully, a separate resource-registration-scheme for shared-memory
- * will be introduced into the kernel. Until then, we use the normal
- * routines, designed for port-registration.
- */
-#define check_shmem   check_region
-#define release_shmem release_region
-#define request_shmem request_region
 
 #endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
 #endif                          /* icn_h */
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.4.3/linux/drivers/isdn/isdn_common.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/isdn/isdn_common.c	Wed Apr 18 11:49:14 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.114.6.8 2001/02/16 16:43:22 kai Exp $
+/* $Id: isdn_common.c,v 1.114.6.10 2001/04/08 19:14:00 kai Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -51,7 +51,7 @@
 
 isdn_dev *dev;
 
-static char *isdn_revision = "$Revision: 1.114.6.8 $";
+static char *isdn_revision = "$Revision: 1.114.6.10 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -260,7 +260,6 @@
 static int isdn_timer_cnt1 = 0;
 static int isdn_timer_cnt2 = 0;
 static int isdn_timer_cnt3 = 0;
-static int isdn_timer_cnt4 = 0;
 
 static void
 isdn_timer_funct(ulong dummy)
@@ -284,16 +283,11 @@
 			isdn_timer_cnt2 = 0;
 			if (tf & ISDN_TIMER_NETHANGUP)
 				isdn_net_autohup();
-			if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) {
+			if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
 				isdn_timer_cnt3 = 0;
 				if (tf & ISDN_TIMER_MODEMRING)
 					isdn_tty_modem_ring();
 			}
-			if (++isdn_timer_cnt4 > ISDN_TIMER_KEEPINT) {
-				isdn_timer_cnt4 = 0;
-				if (tf & ISDN_TIMER_KEEPALIVE)
-					isdn_net_slarp_out();
-			}
 			if (tf & ISDN_TIMER_CARRIER)
 				isdn_tty_carrier_timeout();
 		}
@@ -312,7 +306,7 @@
 void
 isdn_timer_ctrl(int tf, int onoff)
 {
-	int flags;
+	int flags, old_tflags;
 
 	save_flags(flags);
 	cli();
@@ -321,11 +315,12 @@
 		isdn_timer_cnt1 = 0;
 		isdn_timer_cnt2 = 0;
 	}
+	old_tflags = dev->tflags;
 	if (onoff)
 		dev->tflags |= tf;
 	else
 		dev->tflags &= ~tf;
-	if (dev->tflags)
+	if (dev->tflags && !old_tflags)
 		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
 	restore_flags(flags);
 }
@@ -1026,7 +1021,7 @@
 		retval = -ENODEV;
 		goto out;
 	}
-	if (minor < ISDN_MINOR_CTRL) {
+	if (minor <= ISDN_MINOR_BMAX) {
 		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0) {
@@ -1119,7 +1114,7 @@
 		return -ENODEV;
 
 	lock_kernel();
-	if (minor < ISDN_MINOR_CTRL) {
+	if (minor <= ISDN_MINOR_BMAX) {
 		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0) {
@@ -1272,7 +1267,7 @@
 	}
 	if (!dev->drivers)
 		return -ENODEV;
-	if (minor < ISDN_MINOR_CTRL) {
+	if (minor <= ISDN_MINOR_BMAX) {
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0)
 			return -ENODEV;
@@ -1687,7 +1682,7 @@
 	}
 	if (!dev->channels)
 		goto out;
-	if (minor < ISDN_MINOR_CTRL) {
+	if (minor <= ISDN_MINOR_BMAX) {
 		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0)
@@ -1747,7 +1742,7 @@
 		goto out;
 	}
 	isdn_unlock_drivers();
-	if (minor < ISDN_MINOR_CTRL)
+	if (minor <= ISDN_MINOR_BMAX)
 		goto out;
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		if (dev->profd == current)
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.4.3/linux/drivers/isdn/isdn_net.c	Thu Feb  8 10:40:25 2001
+++ linux/drivers/isdn/isdn_net.c	Wed Apr 18 11:49:14 2001
@@ -22,6 +22,11 @@
  *
  */
 
+/* Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
+ *           for info on the protocol, see 
+ *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
+ */
+
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
@@ -182,7 +187,10 @@
 int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
 
-char *isdn_net_revision = "$Revision: 1.140.6.3 $";
+static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
+static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
+
+char *isdn_net_revision = "$Revision: 1.144 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -454,6 +462,8 @@
 					pops -> disconn_ind(cprot);
 #endif /* CONFIG_ISDN_X25 */
 				if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
+					if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
+						isdn_net_ciscohdlck_disconnected(lp);
 #ifdef CONFIG_ISDN_PPP
 					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 						isdn_ppp_free(lp);
@@ -498,7 +508,7 @@
 						lp->dialstate = 0;
 						isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
 						if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
-							isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1);
+							isdn_net_ciscohdlck_connected(lp);
 						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;
@@ -660,7 +670,7 @@
 					isdn_net_hangup(&p->dev);
 					break;
 				}
-				if (!strcmp(lp->dial->num, "LEASED")) {
+				if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
 					restore_flags(flags);
 					lp->dialstate = 4;
 					printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
@@ -1415,92 +1425,347 @@
 	return htons(ETH_P_802_2);
 }
 
-static void
-isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
+
+/* 
+ * CISCO HDLC keepalive specific stuff
+ */
+static struct sk_buff*
+isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
 {
 	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);
-	cisco_hdr *ch;
-	cisco_slarp *s;
+	struct sk_buff *skb;
 
+	skb = alloc_skb(hl + len, GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_WARNING
-		       "%s: Could not allocate SLARP reply\n", lp->name);
-		return;
+		printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
+		return 0;
 	}
 	skb_reserve(skb, hl);
-	ch = (cisco_hdr *)skb_put(skb, sizeof(cisco_hdr));
-	ch->addr = CISCO_ADDR_UNICAST;
-	ch->ctrl = 0;
-	ch->type = htons(CISCO_TYPE_SLARP);
-	s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp));
-	if (is_reply) {
-		s->code = htonl(CISCO_SLARP_REPLY);
-		memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32));
-		memset(&s->slarp.reply.netmask, 0, sizeof(__u32));
-	} else {
-		lp->cisco_myseq++;
-		s->code = htonl(CISCO_SLARP_KEEPALIVE);
-		s->slarp.keepalive.my_seq = htonl(lp->cisco_myseq);
-		s->slarp.keepalive.your_seq = htonl(lp->cisco_yourseq);
-	}
-	s->rel = 0xffff;
-	s->t1 = t >> 16;
-	s->t0 = t & 0xffff;
-	isdn_net_write_super(lp, skb);
+	return skb;
 }
 
-static void
-isdn_net_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+/* cisco hdlck device private ioctls */
+int
+isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	cisco_slarp *s = (cisco_slarp *)skb->data;
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	unsigned long len = 0;
+	unsigned long expires = 0;
+	int tmp = 0;
+	int period = lp->cisco_keepalive_period;
+	char debserint = lp->cisco_debserint;
+	int rc = 0;
+
+	if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
+		return -EINVAL;
+
+	switch (cmd) {
+		/* get/set keepalive period */
+		case SIOCGKEEPPERIOD:
+			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
+				(int *)&lp->cisco_keepalive_period, len))
+				rc = -EFAULT;
+			break;
+		case SIOCSKEEPPERIOD:
+			tmp = lp->cisco_keepalive_period;
+			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+			if (copy_from_user((int *)&period,
+				(char *)ifr->ifr_ifru.ifru_data, len))
+				rc = -EFAULT;
+			if ((period > 0) && (period <= 32767))
+				lp->cisco_keepalive_period = period;
+			else
+				rc = -EINVAL;
+			if (!rc && (tmp != lp->cisco_keepalive_period)) {
+				expires = (unsigned long)(jiffies +
+					lp->cisco_keepalive_period * HZ);
+				mod_timer(&lp->cisco_timer, expires);
+				printk(KERN_INFO "%s: Keepalive period set "
+					"to %d seconds.\n",
+					lp->name, lp->cisco_keepalive_period);
+			}
+			break;
 
-	switch (ntohl(s->code)) {
-		case CISCO_SLARP_REQUEST:
-			isdn_net_slarp_send(lp, 1);
+		/* get/set debugging */
+		case SIOCGDEBSERINT:
+			len = (unsigned long)sizeof(lp->cisco_debserint);
+			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
+				(char *)&lp->cisco_debserint, len))
+				rc = -EFAULT;
 			break;
-		case CISCO_SLARP_REPLY:
-			/* Ignore replies */
+		case SIOCSDEBSERINT:
+			len = (unsigned long)sizeof(lp->cisco_debserint);
+			if (copy_from_user((char *)&debserint,
+				(char *)ifr->ifr_ifru.ifru_data, len))
+				rc = -EFAULT;
+			if ((debserint >= 0) && (debserint <= 64))
+				lp->cisco_debserint = debserint;
+			else
+				rc = -EINVAL;
 			break;
-		case CISCO_SLARP_KEEPALIVE:
-			lp->cisco_yourseq = s->slarp.keepalive.my_seq;
-			if (ntohl(s->slarp.keepalive.my_seq == lp->cisco_myseq)) {
-				if (lp->cisco_loop++ == 2) {
-					printk(KERN_WARNING "%s: Keepalive Loop\n",
-					       lp->name);
-					lp->cisco_myseq ^= jiffies;
-				}
-			} else
-				lp->cisco_loop = 0;
+
+		default:
+			rc = -EINVAL;
 			break;
 	}
-	kfree_skb(skb);
+	return (rc);
 }
 
-/*
- * Called every 10 sec. via timer-interrupt if
- * any network-interface has Cisco-Keepalive-Encapsulation
- * and is online.
- * Send Keepalive-Packet and re-schedule.
- */
-void
-isdn_net_slarp_out(void)
+/* called via cisco_timer.function */
+static void
+isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
 {
-	isdn_net_dev *p = dev->netdev;
-	int anymore = 0;
+	isdn_net_local *lp = (isdn_net_local *) data;
+	struct sk_buff *skb;
+	unsigned char *p;
+	unsigned long last_cisco_myseq = lp->cisco_myseq;
+	int myseq_diff = 0;
 
-	while (p) {
-		isdn_net_local *l = p->local;
-		if ((l->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) &&
-		    (l->flags & ISDN_NET_CONNECTED) &&
-		    (!l->dialstate)                           ) {
-			anymore = 1;
-			isdn_net_slarp_send(l, 0);
+	if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		return;
+	}
+	lp->cisco_myseq++;
+
+	myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
+	if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
+		/* line up -> down */
+		lp->cisco_line_state = 0;
+		printk (KERN_WARNING
+				"UPDOWN: Line protocol on Interface %s,"
+				" changed state to down\n", lp->name);
+		/* should stop routing higher-level data accross */
+	} else if ((!lp->cisco_line_state) &&
+		(myseq_diff >= 0) && (myseq_diff <= 2)) {
+		/* line down -> up */
+		lp->cisco_line_state = 1;
+		printk (KERN_WARNING
+				"UPDOWN: Line protocol on Interface %s,"
+				" changed state to up\n", lp->name);
+		/* restart routing higher-level data accross */
+	}
+
+	if (lp->cisco_debserint)
+		printk (KERN_DEBUG "%s: HDLC "
+			"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
+			lp->name, last_cisco_myseq, lp->cisco_mineseen,
+			((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
+			lp->cisco_yourseq,
+			((lp->cisco_line_state) ? "line up" : "line down"));
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp keepalive */
+	p += put_u32(p, CISCO_SLARP_KEEPALIVE);
+	p += put_u32(p, lp->cisco_myseq);
+	p += put_u32(p, lp->cisco_yourseq);
+	p += put_u16(p, 0xffff); // reliablity, always 0xffff
+
+	isdn_net_write_super(lp, skb);
+
+	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
+	
+	add_timer(&lp->cisco_timer);
+}
+
+static void
+isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
+{
+	struct sk_buff *skb;
+	unsigned char *p;
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp request */
+	p += put_u32(p, CISCO_SLARP_REQUEST);
+	p += put_u32(p, 0); // address
+	p += put_u32(p, 0); // netmask
+	p += put_u16(p, 0); // unused
+
+	isdn_net_write_super(lp, skb);
+}
+
+static void 
+isdn_net_ciscohdlck_connected(isdn_net_local *lp)
+{
+	lp->cisco_myseq = 0;
+	lp->cisco_mineseen = 0;
+	lp->cisco_yourseq = 0;
+	lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
+	lp->cisco_last_slarp_in = 0;
+	lp->cisco_line_state = 0;
+	lp->cisco_debserint = 0;
+
+	/* send slarp request because interface/seq.no.s reset */
+	isdn_net_ciscohdlck_slarp_send_request(lp);
+
+	init_timer(&lp->cisco_timer);
+	lp->cisco_timer.data = (unsigned long) lp;
+	lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
+	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
+	add_timer(&lp->cisco_timer);
+}
+
+static void 
+isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
+{
+	del_timer(&lp->cisco_timer);
+}
+
+static void
+isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
+{
+	struct sk_buff *skb;
+	unsigned char *p;
+	struct in_device *in_dev = NULL;
+	u32 addr = 0;		/* local ipv4 address */
+	u32 mask = 0;		/* local netmask */
+
+	if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+		/* take primary(first) address of interface */
+		struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa != NULL) {
+			addr = ifa->ifa_local;
+			mask = ifa->ifa_mask;
 		}
-		p = (isdn_net_dev *) p->next;
 	}
-	isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, anymore);
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp reply, send own ip/netmask; if values are nonsense remote
+	 * should think we are unable to provide it with an address via SLARP */
+	p += put_u32(p, CISCO_SLARP_REPLY);
+	p += put_u32(p, addr);	// address
+	p += put_u32(p, mask);	// netmask
+	p += put_u16(p, 0);	// unused
+
+	isdn_net_write_super(lp, skb);
+}
+
+static void
+isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+{
+	unsigned char *p;
+	int period;
+	__u32 code;
+	__u32 my_seq, addr;
+	__u32 your_seq, mask;
+	__u16 unused;
+
+	if (skb->len < 14)
+		return;
+
+	p = skb->data;
+	p += get_u32(p, &code);
+	
+	switch (code) {
+	case CISCO_SLARP_REQUEST:
+		lp->cisco_yourseq = 0;
+		isdn_net_ciscohdlck_slarp_send_reply(lp);
+		break;
+	case CISCO_SLARP_REPLY:
+		/* Ignore replies - at least for now */
+		if (lp->cisco_debserint) {
+			p += get_u32(p, &addr);
+			p += get_u32(p, &mask);
+			p += get_u16(p, &unused);
+			printk(KERN_DEBUG "%s: got slarp reply (%ul/%ul) - "
+				"ignored\n", lp->name, addr, mask);
+		}
+		break;
+	case CISCO_SLARP_KEEPALIVE:
+		period = (int)((jiffies - lp->cisco_last_slarp_in
+				+ HZ/2 - 1) / HZ);
+		if (lp->cisco_debserint &&
+				(period != lp->cisco_keepalive_period) &&
+				lp->cisco_last_slarp_in) {
+			printk(KERN_DEBUG "%s: Keepalive period mismatch - "
+				"is %d but should be %d.\n",
+				lp->name, period, lp->cisco_keepalive_period);
+		}
+		lp->cisco_last_slarp_in = jiffies;
+		p += get_u32(p, &my_seq);
+		p += get_u32(p, &your_seq);
+		p += get_u16(p, &unused);
+		lp->cisco_yourseq = my_seq;
+		lp->cisco_mineseen = your_seq;
+		break;
+	}
+}
+
+static void
+isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
+{
+	unsigned char *p;
+	__u8 addr;
+	__u8 ctrl;
+	__u16 type;
+	
+	if (skb->len < 4)
+		goto out_free;
+
+	p = skb->data;
+	p += get_u8 (p, &addr);
+	p += get_u8 (p, &ctrl);
+	p += get_u16(p, &type);
+	skb_pull(skb, 4);
+	
+	if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
+		printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
+		       lp->name, addr);
+		goto out_free;
+	}
+	if (ctrl != CISCO_CTRL) {
+		printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
+		       lp->name, ctrl);
+		goto out_free;
+	}
+
+	switch (type) {
+	case CISCO_TYPE_INET:
+		skb->protocol = htons(ETH_P_IP);
+		netif_rx(skb);
+		break;
+	case CISCO_TYPE_SLARP:
+		isdn_net_ciscohdlck_slarp_in(lp, skb);
+		goto out_free;
+	default:
+		printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
+		       lp->name, type);
+		goto out_free;
+	}
+	return;
+
+ out_free:
+	kfree_skb(skb);
 }
 
 /*
@@ -1517,8 +1782,6 @@
 #ifdef CONFIG_ISDN_X25
 	struct concap_proto *cprot = lp -> netdev -> cprot;
 #endif
-	cisco_hdr *ch;
-
 	lp->transcount += skb->len;
 
 	lp->stats.rx_packets++;
@@ -1558,36 +1821,8 @@
 			skb->protocol = htons(ETH_P_IP);
 			break;
 		case ISDN_NET_ENCAP_CISCOHDLCK:
-			ch = (cisco_hdr *)skb->data;
-			if ((ch->addr != CISCO_ADDR_UNICAST) &&
-			    (ch->addr != CISCO_ADDR_BROADCAST)  ) {
-				printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
-				       lp->name, ch->addr);
-				kfree_skb(skb);
-				return;
-			}
-			if (ch->ctrl != 0) {
-				printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
-				       lp->name, ch->ctrl);
-				kfree_skb(skb);
-				return;
-			}
-			switch (ntohs(ch->type)) {
-				case CISCO_TYPE_INET:
-					skb_pull(skb, 4);
-					skb->protocol = htons(ETH_P_IP);
-					break;
-				case CISCO_TYPE_SLARP:
-					skb_pull(skb, 4);
-					isdn_net_slarp_in(olp, skb);
-					return;
-				default:
-					printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
-					       lp->name, ch->type);
-					kfree_skb(skb);
-					return;
-			}
-			break;
+			isdn_net_ciscohdlck_receive(lp, skb);
+			return;
 		case ISDN_NET_ENCAP_CISCOHDLC:
 			/* CISCO-HDLC IP with type field and  fake I-frame-header */
 			skb_pull(skb, 2);
@@ -1705,6 +1940,7 @@
 		void *daddr, void *saddr, unsigned plen)
 {
 	isdn_net_local *lp = dev->priv;
+	unsigned char *p;
 	ushort len = 0;
 
 	switch (lp->p_encap) {
@@ -1733,10 +1969,11 @@
 			len = 2;
 			break;
 		case ISDN_NET_ENCAP_CISCOHDLC:
-			skb_push(skb, 4);
-			skb->data[0] = 0x0f;
-			skb->data[1] = 0x00;
-			*((ushort *) & skb->data[2]) = htons(type);
+		case ISDN_NET_ENCAP_CISCOHDLCK:
+			p = skb_push(skb, 4);
+			p += put_u8 (p, CISCO_ADDR_UNICAST);
+			p += put_u8 (p, CISCO_CTRL);
+			p += put_u16(p, type);
 			len = 4;
 			break;
 #ifdef CONFIG_ISDN_X25
@@ -1842,9 +2079,7 @@
 	ndev->stop = &isdn_net_close;
 	ndev->get_stats = &isdn_net_get_stats;
 	ndev->rebuild_header = &isdn_net_rebuild_header;
-#ifdef CONFIG_ISDN_PPP
-	ndev->do_ioctl = isdn_ppp_dev_ioctl;
-#endif
+	ndev->do_ioctl = NULL;
 	return 0;
 }
 
@@ -2508,6 +2743,7 @@
 #else
 			p->dev.type = ARPHRD_PPP;	/* change ARP type */
 			p->dev.addr_len = 0;
+			p->dev.do_ioctl = isdn_ppp_dev_ioctl;
 #endif
 			break;
 		case ISDN_NET_ENCAP_X25IFACE:
@@ -2519,6 +2755,9 @@
 			p->dev.type = ARPHRD_X25;	/* change ARP type */
 			p->dev.addr_len = 0;
 #endif
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLCK:
+			p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
 			break;
 		default:
 			if( cfg->p_encap >= 0 &&
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h
--- v2.4.3/linux/drivers/isdn/isdn_net.h	Tue Aug  8 15:03:57 2000
+++ linux/drivers/isdn/isdn_net.h	Wed Apr 18 11:49:14 2001
@@ -33,31 +33,9 @@
  * Definitions for Cisco-HDLC header.
  */
 
-typedef struct cisco_hdr {
-	__u8  addr; /* unicast/broadcast */
-	__u8  ctrl; /* Always 0          */
-	__u16 type; /* IP-typefield      */
-} cisco_hdr;
-
-typedef struct cisco_slarp {
-	__u32 code;                     /* SLREQ/SLREPLY/KEEPALIVE */
-	union {
-		struct {
-			__u32 ifaddr;   /* My interface address     */
-			__u32 netmask;  /* My interface netmask     */
-		} reply;
-		struct {
-			__u32 my_seq;   /* Packet sequence number   */
-			__u32 your_seq;
-		} keepalive;
-	} slarp;
-	__u16 rel;                      /* Always 0xffff            */
-	__u16 t1;                       /* Uptime in usec >> 16     */
-	__u16 t0;                       /* Uptime in usec & 0xffff  */
-} cisco_slarp;
-
 #define CISCO_ADDR_UNICAST    0x0f
 #define CISCO_ADDR_BROADCAST  0x8f
+#define CISCO_CTRL            0x00
 #define CISCO_TYPE_INET       0x0800
 #define CISCO_TYPE_SLARP      0x8035
 #define CISCO_SLARP_REPLY     0
@@ -83,7 +61,6 @@
 extern int isdn_net_force_dial(char *);
 extern isdn_net_dev *isdn_net_findif(char *);
 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);
@@ -166,6 +143,52 @@
 		master_lp->netdev->queue = lp->next;
 	lp->next = lp->last = lp;	/* (re)set own pointers */
 	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+}
+
+static inline int
+put_u8(unsigned char *p, __u8 x)
+{
+	p[0] = x;
+	return 1;
+}
+
+static inline int
+put_u16(unsigned char *p, __u16 x)
+{
+	p[0] = x >> 8;
+	p[1] = x;
+	return 2;
+}
+
+static inline int
+put_u32(unsigned char *p, __u32 x)
+{
+	p[0] = x >> 24;
+	p[1] = x >> 16;
+	p[2] = x >> 8;
+	p[3] = x;
+	return 4;
+}
+
+static inline int
+get_u8(unsigned char *p, __u8 *x)
+{
+	*x = p[0];
+	return 1;
+}
+
+static inline int
+get_u16(unsigned char *p, __u16 *x)
+{
+	*x = (p[0] << 8) + p[1];
+	return 2;
+}
+
+static inline int
+get_u32(unsigned char *p, __u32 *x)
+{
+	*x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
+	return 4;
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.4.3/linux/drivers/isdn/isdn_ppp.c	Thu Feb  8 10:40:25 2001
+++ linux/drivers/isdn/isdn_ppp.c	Wed Apr 18 11:49:14 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.85.6.2 2001/01/23 17:45:02 kai Exp $
+/* $Id: isdn_ppp.c,v 1.85.6.4 2001/04/08 18:53:07 kai Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -83,7 +83,7 @@
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
 #endif	/* CONFIG_ISDN_MPP */
   
-char *isdn_ppp_revision = "$Revision: 1.85.6.2 $";
+char *isdn_ppp_revision = "$Revision: 1.85.6.4 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
@@ -165,6 +165,7 @@
 	int unit = 0;
 	long flags;
 	struct ippp_struct *is;
+	int retval;
 
 	save_flags(flags);
 	cli();
@@ -197,12 +198,14 @@
 	if (i >= ISDN_MAX_CHANNELS) {
 		restore_flags(flags);
 		printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
-		return -1;
+		retval = -1;
+		goto out;
 	}
 	unit = isdn_ppp_if_get_unit(lp->name);	/* get unit number from interface name .. ugly! */
 	if (unit < 0) {
 		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
-		return -1;
+		retval = -1;
+		goto out;
 	}
 	
 	lp->ppp_slot = i;
@@ -211,13 +214,16 @@
 	is->unit = unit;
 	is->state = IPPP_OPEN | IPPP_ASSIGNED;	/* assigned to a netdevice but not connected */
 #ifdef CONFIG_ISDN_MPP
-	if (isdn_ppp_mp_init(lp, NULL) < 0)
-		return -ENOMEM;
+	retval = isdn_ppp_mp_init(lp, NULL);
+	if (retval < 0)
+		goto out;
 #endif /* CONFIG_ISDN_MPP */
 
-	restore_flags(flags);
+	retval = lp->ppp_slot;
 
-	return lp->ppp_slot;
+ out:
+	restore_flags(flags);
+	return retval;
 }
 
 /*
@@ -2431,6 +2437,13 @@
 
 	switch(skb->data[0]) {
 	case CCP_CONFREQ:
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Disable compression here!\n");
+		if(proto == PPP_CCP)
+			mis->compflags &= ~SC_COMP_ON;		
+		else
+			is->compflags &= ~SC_LINK_COMP_ON;		
+		break;
 	case CCP_TERMREQ:
 	case CCP_TERMACK:
 		if(is->debug & 0x10)
@@ -2546,6 +2559,17 @@
 
 /* TODO: Clean this up with new Reset semantics */
 
+/* I believe the CCP handling as-is is done wrong. Compressed frames
+ * should only be sent/received after CCP reaches UP state, which means
+ * both sides have sent CONF_ACK. Currently, we handle both directions
+ * independently, which means we may accept compressed frames too early
+ * (supposedly not a problem), but may also mean we send compressed frames
+ * too early, which may turn out to be a problem.
+ * This part of state machine should actually be handled by (i)pppd, but
+ * that's too big of a change now. --kai
+ */
+
+
 static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
 {
 	struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot];
@@ -2580,6 +2604,13 @@
 	
         switch(data[2]) {
 	case CCP_CONFREQ:
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Disable decompression here!\n");
+		if(proto == PPP_CCP)
+			is->compflags &= ~SC_DECOMP_ON;
+		else
+			is->compflags &= ~SC_LINK_DECOMP_ON;
+		break;
 	case CCP_TERMREQ:
 	case CCP_TERMACK:
 		if(is->debug & 0x10)
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c
--- v2.4.3/linux/drivers/isdn/pcbit/drv.c	Fri Mar  2 11:12:09 2001
+++ linux/drivers/isdn/pcbit/drv.c	Wed Apr 11 19:02:36 2001
@@ -412,7 +412,6 @@
 	return len;
 }
 
-
 int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel)
 {
 	struct pcbit_dev * dev;
@@ -436,32 +435,36 @@
 		if (len > BANK4 + 1)
 		{
 			printk("pcbit_writecmd: invalid length %d\n", len);
-			return -EFAULT;
+			return -EINVAL;
 		}
 
 		if (user)
 		{
-			u_char cbuf[1024];
+			u_char *cbuf = kmalloc(len, GFP_KERNEL);
+			if (!cbuf)
+				return -ENOMEM;
 
-			copy_from_user(cbuf, buf, len);
-			for (i=0; i<len; i++)
-				writeb(cbuf[i], dev->sh_mem + i);
+			if (copy_from_user(cbuf, buf, len)) {
+				kfree(cbuf);
+				return -EFAULT;
+			}
+			memcpy_toio(dev->sh_mem, cbuf, len);
+			kfree(cbuf);
 		}
 		else
 			memcpy_toio(dev->sh_mem, buf, len);
 		return len;
-		break;
 	case L2_FWMODE:
 		/* this is the hard part */
 		/* dumb board */
-		if (len < 0)
-			return -EINVAL;
-
 		if (user) {		
 			/* get it into kernel space */
 			if ((ptr = kmalloc(len, GFP_KERNEL))==NULL)
 				return -ENOMEM;
-			copy_from_user(ptr, buf, len);
+			if (copy_from_user(ptr, buf, len)) {
+				kfree(ptr);
+				return -EFAULT;
+			}
 			loadbuf = ptr;
 		}
 		else
@@ -493,12 +496,9 @@
 			kfree(ptr);
 
 		return errstat ? errstat : len;
-
-		break;
 	default:
 		return -EBUSY;
 	}
-	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c
--- v2.4.3/linux/drivers/isdn/sc/interrupt.c	Mon Mar 26 15:38:19 2001
+++ linux/drivers/isdn/sc/interrupt.c	Wed Apr 18 11:49:14 2001
@@ -1,5 +1,5 @@
 /*
- *  $Id: interrupt.c,v 1.4.8.1 2001/03/13 16:17:09 kai Exp $
+ *  $Id: interrupt.c,v 1.4.8.2 2001/04/08 17:51:43 kai Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,6 @@
 
 extern int indicate_status(int, int, ulong, char *);
 extern void check_phystat(unsigned long);
-extern void dump_messages(int);
 extern int receivemessage(int, RspMessage *);
 extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
         unsigned int, unsigned int, unsigned int, unsigned int *);
diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c
--- v2.4.3/linux/drivers/isdn/sc/message.c	Sun Nov  7 16:34:00 1999
+++ linux/drivers/isdn/sc/message.c	Wed Apr 18 11:49:14 2001
@@ -1,5 +1,5 @@
 /*
- *  $Id: message.c,v 1.5 1999/09/04 06:20:07 keil Exp $
+ *  $Id: message.c,v 1.5.8.1 2001/04/08 17:51:43 kai Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  message.c - functions for sending and receiving control messages
@@ -38,55 +38,12 @@
 extern unsigned int cinst;
 
 /*
- * Obligitory function prototypes
+ * Obligatory function prototypes
  */
 extern int indicate_status(int,ulong,char*);
 extern int scm_command(isdn_ctrl *);
 extern void *memcpy_fromshmem(int, void *, const void *, size_t);
 
-/*
- * Dump message queue in shared memory to screen
- */
-void dump_messages(int card) 
-{
-	DualPortMemory dpm;
-	unsigned long flags;
-
-	int i =0;
-	
-	if (!IS_VALID_CARD(card)) {
-		pr_debug("Invalid param: %d is not a valid card id\n", card);
-	}
-
-	save_flags(flags);
-	cli();
-	outb(adapter[card]->ioport[adapter[card]->shmem_pgport], 
-		(adapter[card]->shmem_magic >> 14) | 0x80);
-	memcpy_fromshmem(card, &dpm, 0, sizeof(dpm));
-	restore_flags(flags);
-
-	pr_debug("%s: Dumping Request Queue\n", adapter[card]->devicename);
-	for (i = 0; i < dpm.req_head; i++) {
-		pr_debug("%s: Message #%d: (%d,%d,%d), link: %d\n",
-				adapter[card]->devicename, i,
-				dpm.req_queue[i].type,
-				dpm.req_queue[i].class,
-				dpm.req_queue[i].code,
-				dpm.req_queue[i].phy_link_no);
-	}
-
-	pr_debug("%s: Dumping Response Queue\n", adapter[card]->devicename);
-	for (i = 0; i < dpm.rsp_head; i++) {
-		pr_debug("%s: Message #%d: (%d,%d,%d), link: %d, status: %d\n",
-				adapter[card]->devicename, i,
-				dpm.rsp_queue[i].type,
-				dpm.rsp_queue[i].class,
-				dpm.rsp_queue[i].code,
-				dpm.rsp_queue[i].phy_link_no,
-				dpm.rsp_queue[i].rsp_status);
-	}
-
-}	
 
 /*
  * receive a message from the board
diff -u --recursive --new-file v2.4.3/linux/drivers/md/lvm.c linux/drivers/md/lvm.c
--- v2.4.3/linux/drivers/md/lvm.c	Sun Jan 28 16:11:20 2001
+++ linux/drivers/md/lvm.c	Sat Apr 21 10:37:16 2001
@@ -148,6 +148,9 @@
  *                 procfs is always supported now. (JT)
  *    12/01/2001 - avoided flushing logical volume in case of shrinking
  *                 because of unecessary overhead in case of heavy updates
+ *    05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it
+ *		   destroys stacking devices. call b_end_io on failed maps.
+ *		   (Jens Axboe)
  *
  */
 
@@ -163,13 +166,6 @@
 
 #include <linux/config.h>
 #include <linux/version.h>
-
-#ifdef MODVERSIONS
-#undef MODULE
-#define MODULE
-#include <linux/modversions.h>
-#endif
-
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -1480,14 +1476,14 @@
  */
 static int lvm_map(struct buffer_head *bh, int rw)
 {
-	int minor = MINOR(bh->b_dev);
+	int minor = MINOR(bh->b_rdev);
 	int ret = 0;
 	ulong index;
 	ulong pe_start;
 	ulong size = bh->b_size >> 9;
-	ulong rsector_tmp = bh->b_blocknr * size;
+	ulong rsector_tmp = bh->b_rsector;
 	ulong rsector_sav;
-	kdev_t rdev_tmp = bh->b_dev;
+	kdev_t rdev_tmp = bh->b_rdev;
 	kdev_t rdev_sav;
 	vg_t *vg_this = vg[VG_BLK(minor)];
 	lv_t *lv = vg_this->lv[LV_BLK(minor)];
@@ -1676,8 +1672,13 @@
  */
 static int lvm_make_request_fn(request_queue_t *q,
 			       int rw,
-			       struct buffer_head *bh) {
-	return (lvm_map(bh, rw) < 0) ? 0 : 1;
+			       struct buffer_head *bh)
+{
+	if (lvm_map(bh, rw) >= 0)
+		return 1;
+
+	buffer_IO_error(bh);
+	return 0;
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/md/md.c linux/drivers/md/md.c
--- v2.4.3/linux/drivers/md/md.c	Mon Mar 12 18:13:28 2001
+++ linux/drivers/md/md.c	Fri Apr  6 10:42:55 2001
@@ -1063,10 +1063,10 @@
 	}
 	printk(".\n");
 	if (err) {
-		printk("errors occured during superblock update, repeating\n");
+		printk("errors occurred during superblock update, repeating\n");
 		if (--count)
 			goto repeat;
-		printk("excessive errors occured during superblock update, exiting\n");
+		printk("excessive errors occurred during superblock update, exiting\n");
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in
--- v2.4.3/linux/drivers/media/radio/Config.in	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/Config.in	Fri Apr 13 20:26:07 2001
@@ -23,7 +23,7 @@
 fi
 dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
-dep_tristate '  Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
+dep_tristate '  miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
 dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
 if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
    hex '    SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile
--- v2.4.3/linux/drivers/media/radio/Makefile	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/Makefile	Fri Apr 13 20:26:07 2001
@@ -23,7 +23,9 @@
 
 export-objs     :=	
 
-list-multi	:=	
+list-multi	:= miropcm20.o
+
+miropcm20-objs	:= radio-miropcm20.o rds-miropcm20.o
 
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
@@ -34,9 +36,12 @@
 obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
-obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
+obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 
 include $(TOPDIR)/Rules.make
+
+miropcm20.o: $(miropcm20-objs)
+	$(LD) -r -o $@ $(miropcm20-objs)
diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c
--- v2.4.3/linux/drivers/media/radio/radio-miropcm20.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/radio/radio-miropcm20.c	Fri Apr 13 20:26:07 2001
@@ -2,62 +2,53 @@
  * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
  * Thanks to Norberto Pellici for the ACI device interface specification
  * The API part is based on the radiotrack driver by M. Kirkwood
- * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c)
+ * This driver relies on the aci mixer (drivers/sound/aci.c)
  * Look there for further info...
  */
 
-#include <linux/module.h>		/* Modules 			*/
-#include <linux/init.h>			/* Initdata			*/
-#include <asm/uaccess.h>		/* copy to/from user		*/
-#include <linux/videodev.h>		/* kernel radio structs		*/
-#include "../../sound/miroaci.h"	/* ACI Control by acimixer      */
+/* Revision history:
+ *
+ *   1998        Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ *   2000-09-05  Robert Siemer <Robert.Siemer@gmx.de>
+ *        removed unfinished volume control (maybe adding it later again)
+ *        use OSS-mixer; added stereo control
+ */
+
+/* What ever you think about the ACI, version 0x07 is not very well!
+ * I cant get frequency, 'tuner status', 'tuner flags' or mute/mono
+ * conditions...                Robert 
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/uaccess.h>
+
+char * aci_radio_name;
+
+#include "../../sound/aci.h"
 
 static int users = 0;
 
 struct pcm20_device
 {
-	int port;
-	int curvol;
-	unsigned long curfreq;
+	unsigned long freq;
 	int muted;
+	int stereo;
 };
 
 
-/* local things */
-
-
-static void pcm20_mute(struct pcm20_device *dev)
+static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
 {
-
-	dev->muted = 1;
-	aci_write_cmd(0xa3,0x01);			
-
+	dev->muted = mute;
+	return aci_write_cmd(0xa3, mute);
 }
 
-static int pcm20_setvol(struct pcm20_device *dev, int vol)
+static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
 {
-
-	if(vol == dev->curvol) {	/* requested volume = current */
-		if (dev->muted) {	/* user is unmuting the card  */
-			dev->muted = 0;
-			aci_write_cmd(0xa3,0x00); 	/* enable card */
-		}	
-	
-		return 0;
-	}
-
-	if(vol == 0) {			/* volume = 0 means mute the card */
-		aci_write_cmd(0x3d, 0x20);
-		aci_write_cmd(0x35, 0x20);
-		return 0;
-	}
-
-	dev->muted = 0;
-	aci_write_cmd(0x3d, 32-vol); 	/* Right Channel */
-	aci_write_cmd(0x35, 32-vol);	/* Left Channel */
-	dev->curvol = vol;
-
-	return 0;
+	dev->stereo = stereo;
+	return aci_write_cmd(0xa4, !stereo);
 }
 
 static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
@@ -65,28 +56,79 @@
 	unsigned char freql;
 	unsigned char freqh;
 
-	freq = (freq * 10) / 16;
-	freql = freq & 0xff;
-	freqh = freq >> 8;	
+	dev->freq=freq;
 
+	freq /= 160;
+	if (!(aci_version==0x07 || aci_version>=0xb0))
+		freq /= 10;  /* I don't know exactly which version
+			      * needs this hack */
+	freql = freq & 0xff;
+	freqh = freq >> 8;
 
-	aci_write_cmd_d(0xa7, freql, freqh);	/*  Tune to frequency	*/
+	aci_rds_cmd(RDS_RESET, 0, 0);
+	pcm20_stereo(dev, 1);
 
-	return 0;
+	return aci_rw_cmd(0xa7, freql, freqh);	/*  Tune to frequency	*/
 }
 
-int pcm20_getsigstr(struct pcm20_device *dev)
+static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
 {
+	/* okay, check for signal, stereo and rds here... */
+	int i;
 	unsigned char buf;
-	aci_indexed_cmd(0xf0, 0x32, &buf);
-	if ((buf & 0x80) == 0x80)	
+
+	if ((i=aci_rw_cmd(0xa9, -1, -1))<0)
+		return i;
+#if DEBUG
+	printk("check_sig: 0x%x\n", i);
+#endif
+	if (i & 0x80) {
+		/* no signal from tuner */
+		*flags=0;
+		*signal=0;
+		return 0;
+	} else
+		*signal=0xffff;
+
+	if ((i=aci_rw_cmd(0xa8, -1, -1))<0)
+		return i;
+	if (i & 0x40) {
+		*flags=0;
+	} else {
+		/* stereo */
+		*flags=VIDEO_TUNER_STEREO_ON;
+		/* I cant see stereo, when forced to mono */
+		dev->stereo=1;
+	}
+
+	if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
+		return i;
+	if (buf & 1)
+		/* RDS available */
+		*flags|=VIDEO_TUNER_RDS_ON;
+	else
 		return 0;
-	return 1;		/* signal present		*/
+
+	if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
+		return i;
+#if DEBUG
+	printk("rds-signal: %d\n", buf);
+#endif
+	if (buf > 15) {
+		printk("rds-miropcm20: RX strengths unexpected high...\n");
+		buf=15;
+	}
+	/* refine signal */
+	if ((*signal=SCALE(15, 0xffff, buf))==0)
+		*signal = 1;
+
+	return 0;
 }
 
 static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
 	struct pcm20_device *pcm20=dev->priv;
+	int i;
 	
 	switch(cmd)
 	{
@@ -113,11 +155,11 @@
 				return -EFAULT;
 			if(v.tuner)	/* Only 1 tuner */ 
 				return -EINVAL;
-			v.rangelow=(int)(87.5*16);
-			v.rangehigh=(int)(108.0*16);
-			v.flags=0;
+			v.rangelow=87*16000;
+			v.rangehigh=108*16000;
+			pcm20_getflags(pcm20, &v.flags, &v.signal);
+			v.flags|=VIDEO_TUNER_LOW;
 			v.mode=VIDEO_MODE_AUTO;
-			v.signal=0xFFFF*pcm20_getsigstr(pcm20);
 			strcpy(v.name, "FM");
 			if(copy_to_user(arg,&v, sizeof(v)))
 				return -EFAULT;
@@ -134,20 +176,28 @@
 			return 0;
 		}
 		case VIDIOCGFREQ:
-			if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq)))
+			if(copy_to_user(arg, &pcm20->freq, sizeof(pcm20->freq)))
 				return -EFAULT;
 			return 0;
 		case VIDIOCSFREQ:
-			if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq)))
+			if(copy_from_user(&pcm20->freq, arg, sizeof(pcm20->freq)))
 				return -EFAULT;
-			pcm20_setfreq(pcm20, pcm20->curfreq);
-			return 0;
+			i=pcm20_setfreq(pcm20, pcm20->freq);
+#if DEBUG
+			printk("First view (setfreq): 0x%x\n", i);
+#endif
+			return i;
 		case VIDIOCGAUDIO:
 		{	
 			struct video_audio v;
 			memset(&v,0, sizeof(v));
-			v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			v.volume=pcm20->curvol * 2048;
+			v.flags=VIDEO_AUDIO_MUTABLE;
+			if (pcm20->muted)
+				v.flags|=VIDEO_AUDIO_MUTE;
+			v.mode=VIDEO_SOUND_STEREO;
+			if (pcm20->stereo)
+				v.mode|=VIDEO_SOUND_MONO;
+			/* v.step=2048; */
 			strcpy(v.name, "Radio");
 			if(copy_to_user(arg,&v, sizeof(v)))
 				return -EFAULT;
@@ -157,14 +207,15 @@
 		{
 			struct video_audio v;
 			if(copy_from_user(&v, arg, sizeof(v))) 
-				return -EFAULT;	
+				return -EFAULT;
 			if(v.audio) 
 				return -EINVAL;
 
-			if(v.flags&VIDEO_AUDIO_MUTE) 
-				pcm20_mute(pcm20);
-			else
-				pcm20_setvol(pcm20,v.volume/2048);	
+			pcm20_mute(pcm20, !!(v.flags&VIDEO_AUDIO_MUTE));
+			if(v.flags&VIDEO_SOUND_MONO)
+				pcm20_stereo(pcm20, 0);
+			if(v.flags&VIDEO_SOUND_STEREO)
+				pcm20_stereo(pcm20, 1);
 
 			return 0;
 		}
@@ -186,7 +237,12 @@
 	users--;
 }
 
-static struct pcm20_device pcm20_unit;
+static struct pcm20_device pcm20_unit=
+{
+	freq:   87*16000,
+	muted:  1,
+	stereo: 0
+};
 
 static struct video_device pcm20_radio=
 {
@@ -197,24 +253,23 @@
 	open:		pcm20_open,
 	close:		pcm20_close,
 	ioctl:		pcm20_ioctl,
+	priv:		&pcm20_unit
 };
 
 static int __init pcm20_init(void)
 {
-
-	pcm20_radio.priv=&pcm20_unit;
-	
 	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1)
 		return -EINVAL;
 		
+	if(attach_aci_rds()<0) {
+		video_unregister_device(&pcm20_radio);
+		return -EINVAL;
+	}
+#if DEBUG
+	printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0));
+#endif
 	printk(KERN_INFO "Miro PCM20 radio card driver.\n");
 
- 	/* mute card - prevents noisy bootups */
-
-	/* this ensures that the volume is all the way down  */
-
-	pcm20_unit.curvol = 0;
-
 	return 0;
 }
 
@@ -225,9 +280,9 @@
 
 static void __exit pcm20_cleanup(void)
 {
+	unload_aci_rds();
 	video_unregister_device(&pcm20_radio);
 }
 
 module_init(pcm20_init);
 module_exit(pcm20_cleanup);
-
diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/rds-miropcm20.c linux/drivers/media/radio/rds-miropcm20.c
--- v2.4.3/linux/drivers/media/radio/rds-miropcm20.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/rds-miropcm20.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,249 @@
+/*
+ *  Many thanks to Fred Seidel <seidel@metabox.de>, the
+ *  designer of the RDS decoder hardware. With his help
+ *  I was able to code this driver.
+ *  Thanks also to Norberto Pellicci, Dominic Mounteney
+ *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
+ *  for good hints on finding Fred. It was somewhat hard
+ *  to locate him here in Germany... [:
+ *
+ * Revision history:
+ *
+ *   2000-08-09  Robert Siemer <Robert.Siemer@gmx.de>
+ *        RDS support for MiroSound PCM20 radio
+ */
+
+#define _NO_VERSION_
+
+/* #include <linux/kernel.h> */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include "../../sound/aci.h"
+
+#define WATCHMASK       0352 /* 11101010 */
+
+#define DEBUG 0
+
+static struct semaphore aci_rds_sem;
+
+
+#define RDS_BUSYMASK        0x10   /* Bit 4 */
+#define RDS_CLOCKMASK       0x08   /* Bit 3 */
+#define RDS_DATAMASK        0x04   /* Bit 2 */
+
+
+static void print_matrix(char array[], unsigned int length)
+{
+        int i, j;
+
+        for (i=0; i<length; i++) {
+                printk("aci-rds: ");
+                for (j=7; j>=0; j--) {
+                        printk("%d", (array[i] >> j) & 0x1);
+                }
+                if (i%8 == 0)
+                        printk(" byte-border\n");
+                else
+                        printk("\n");
+        }
+}
+
+static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
+{
+	int i;
+
+	if (size != 8)
+		return -1;
+	for (i = 7; i >= 0; i--)
+		sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
+	sendbuffer[0] |= RDS_CLOCKMASK;
+
+	return 0;
+}
+
+static int trans2byte(unsigned char buffer[], int size)
+{
+	int i;
+	unsigned char byte=0;
+
+	if (size != 8)
+		return -1;
+	for (i = 7; i >= 0; i--)
+		byte |= ((buffer[7-i] & RDS_DATAMASK) ? 1 : 0) << i;
+
+	return byte;
+}
+
+static int trans2data(unsigned char readbuffer[], int readsize, unsigned char data[], int datasize)
+{
+	int i,j;
+
+	if (readsize != datasize*8)
+		return -1;
+	for (i = 0; i < datasize; i++)
+		if ((j=trans2byte(&readbuffer[i*8], 8)) < 0)
+			return -1;
+		else
+			data[i]=j;
+	return 0;
+}
+
+static int rds_waitread(void)
+{
+	unsigned char byte;
+	int i=2000;
+
+	do {
+		byte=inb(RDS_REGISTER);
+		if ((byte & WATCHMASK) != WATCHMASK)
+			printk("aci-rds: Hidden information discoverd!\n");
+		i--;
+	}
+	while ((byte & RDS_BUSYMASK) && i);
+
+	if (i) {
+#if DEBUG
+		printk("rds_waitread()");
+		print_matrix(&byte, 1);
+#endif
+		return (byte);
+	} else {
+		printk("aci-rds: rds_waitread() timeout...\n");
+		return -1;
+	}
+}
+
+/* dont use any ..._nowait() function if you are not sure what you do... */
+
+static inline void rds_rawwrite_nowait(unsigned char byte)
+{
+#if DEBUG
+	printk("rds_rawwrite()");
+	print_matrix(&byte, 1);
+#endif
+	outb(byte, RDS_REGISTER);
+}
+
+static int rds_rawwrite(unsigned char byte)
+{
+	if (rds_waitread() >= 0) {
+		rds_rawwrite_nowait(byte);
+		return 0;
+	} else
+		return -1;
+}
+
+static int rds_write(unsigned char cmd)
+{
+	unsigned char sendbuffer[8];
+	int i;
+	
+	if (byte2trans(cmd, sendbuffer, 8) != 0){
+		return -1;
+	} else {
+		for (i=0; i<8; i++) {
+			rds_rawwrite(sendbuffer[i]);
+		}
+	}
+	return 0;
+}
+
+static int rds_readcycle_nowait(void)
+{
+	rds_rawwrite_nowait(0);
+	return rds_waitread();
+}
+
+static int rds_readcycle(void)
+{
+	if (rds_rawwrite(0) < 0)
+		return -1;
+	return rds_waitread();
+}
+
+static int rds_read(unsigned char databuffer[], int datasize)
+{
+
+#define READSIZE (8*datasize)
+
+	int i,j;
+	unsigned char* readbuffer;
+
+	if (!datasize)  /* nothing to read */
+		return 0;
+
+	/* to be able to use rds_readcycle_nowait()
+	   I have to readwait() here */
+	if (rds_waitread() < 0)
+		return -1;
+	
+	if ((readbuffer=kmalloc(READSIZE, GFP_KERNEL)) == 0) {
+		printk("aci-rds: Out of memory...\n");
+		return -ENOMEM;
+	} else {
+		if (signal_pending(current)) {
+			kfree(readbuffer);
+			return -EINTR;
+		}
+	}
+	
+	for (i=0; i< READSIZE; i++)
+		if((j=rds_readcycle_nowait()) < 0) {
+			kfree(readbuffer);
+			return -1;
+		} else
+			readbuffer[i]=j;
+	if (trans2data(readbuffer, READSIZE, databuffer, datasize) < 0) {
+		kfree(readbuffer);
+		return -1;
+	}
+	kfree(readbuffer);
+	return 0;
+}
+
+static int rds_ack(void)
+{
+	int i=rds_readcycle();
+
+	if (i < 0)
+		return -1;
+	if (i & RDS_DATAMASK) {
+		return 0;  /* ACK  */
+	} else {
+		return 1;  /* NACK */
+	}
+}
+
+int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
+{
+	int ret;
+
+	if (down_interruptible(&aci_rds_sem))
+		return -EINTR;
+
+	if (rds_write(cmd))
+		ret = -2;
+
+	/* RDS_RESET doesn't need further processing */
+	if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
+		ret = -1;
+	else
+		ret = 0;
+
+	up(&aci_rds_sem);
+	
+	return ret;
+}
+
+int __init attach_aci_rds(void)
+{
+	init_MUTEX(&aci_rds_sem);
+	return 0;
+}
+
+void __exit unload_aci_rds(void)
+{
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- v2.4.3/linux/drivers/media/video/bttv-cards.c	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/bttv-cards.c	Wed Apr 11 19:02:36 2001
@@ -1404,7 +1404,7 @@
 	bits_out = (PT2254_DBS_IN_2>>(vol%5));
 	/* tens */
 	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-	bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL;
+	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
 	data = btread(BT848_GPIO_DATA);
 	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
 		  WINVIEW_PT2254_STROBE);
diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- v2.4.3/linux/drivers/media/video/bttv.h	Tue Mar  6 19:44:34 2001
+++ linux/drivers/media/video/bttv.h	Wed Apr 11 19:02:36 2001
@@ -91,8 +91,8 @@
 #define I2C_DPL3518	   0x84
 
 /* more card-specific defines */
-#define PT2254_L_CHANEL 0x10
-#define PT2254_R_CHANEL 0x08
+#define PT2254_L_CHANNEL 0x10
+#define PT2254_R_CHANNEL 0x08
 #define PT2254_DBS_IN_2 0x400
 #define PT2254_DBS_IN_10 0x20000
 #define WINVIEW_PT2254_CLK  0x40
diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- v2.4.3/linux/drivers/media/video/cpia.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/cpia.c	Fri Apr  6 10:42:55 2001
@@ -2832,7 +2832,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 --recursive --new-file v2.4.3/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c
--- v2.4.3/linux/drivers/media/video/stradis.c	Fri Mar  2 11:12:10 2001
+++ linux/drivers/media/video/stradis.c	Thu Apr 19 09:34:05 2001
@@ -54,8 +54,8 @@
 #include "cs8420.h"
 
 #define DEBUG(x) 		/* debug driver */
-#undef  IDEBUG(x) 		/* debug irq handler */
-#undef  MDEBUG(x) 		/* debug memory management */
+#undef  IDEBUG	 		/* debug irq handler */
+#undef  MDEBUG	 		/* debug memory management */
 
 #define SAA7146_MAX 6
 
@@ -2196,9 +2196,9 @@
 
 		/* disable PCI bus-mastering */
 		pci_read_config_byte(saa->dev, PCI_COMMAND, &command);
-		/* Should this be &=~ ?? */
 		command &= ~PCI_COMMAND_MASTER;
 		pci_write_config_byte(saa->dev, PCI_COMMAND, command);
+
 		/* unmap and free memory */
 		saa->audhead = saa->audtail = saa->osdhead = 0;
 		saa->vidhead = saa->vidtail = saa->osdtail = 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/mtd/pmc551.c linux/drivers/mtd/pmc551.c
--- v2.4.3/linux/drivers/mtd/pmc551.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/mtd/pmc551.c	Fri Apr  6 10:42:55 2001
@@ -13,17 +13,17 @@
  *
  * Description:
  *	 This driver is intended to support the PMC551 PCI Ram device from
- *	 Ramix Inc.  The PMC551 is a PMC Mezzanine module for cPCI embeded
+ *	 Ramix Inc.  The PMC551 is a PMC Mezzanine module for cPCI embedded
  *	 systems.  The device contains a single SROM that initally programs the
  *	 V370PDC chipset onboard the device, and various banks of DRAM/SDRAM
  *	 onboard.  This driver implements this PCI Ram device as an MTD (Memory
  *	 Technologies Device) so that it can be used to hold a filesystem, or
- *	 for added swap space in embeded systems.  Since the memory on this
+ *	 for added swap space in embedded systems.  Since the memory on this
  *	 board isn't as fast as main memory we do not try to hook it into main
  *	 memeory as that would simply reduce performance on the system.  Using
  *	 it as a block device allows us to use it as high speed swap or for a
- *	 high speed disk device of some sort.  Which becomes very usefull on
- *	 diskless systems in the embeded market I might add.
+ *	 high speed disk device of some sort.  Which becomes very useful on
+ *	 diskless systems in the embedded market I might add.
  *	 
  * Notes:
  *	 Due to what I assume is more buggy SROM, the 64M PMC551 I have
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.4.3/linux/drivers/net/3c501.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/3c501.c	Thu Apr 19 09:34:52 2001
@@ -85,7 +85,7 @@
  *
  */
 
-static const char *version =
+static const char version[] =
     "3c501.c: 2000/02/08 Alan Cox (alan@redhat.com).\n";
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v2.4.3/linux/drivers/net/3c503.c	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/3c503.c	Thu Apr 19 09:34:52 2001
@@ -30,7 +30,7 @@
 
 */
 
-static const char *version =
+static const char version[] =
     "3c503.c:v1.10 9/23/93  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.4.3/linux/drivers/net/3c505.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/3c505.c	Thu Apr 19 09:34:52 2001
@@ -119,13 +119,13 @@
  *
  *********************************************************/
 
-static const char *filename = __FILE__;
+static const char filename[] = __FILE__;
 
-static const char *timeout_msg = "*** timeout at %s:%s (line %d) ***\n";
+static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n";
 #define TIMEOUT_MSG(lineno) \
 	printk(timeout_msg, filename,__FUNCTION__,(lineno))
 
-static const char *invalid_pcb_msg =
+static const char invalid_pcb_msg[] =
 "*** invalid pcb length %d at %s:%s (line %d) ***\n";
 #define INVALID_PCB_MSG(len) \
 	printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__)
@@ -149,7 +149,7 @@
 #ifdef ELP_DEBUG
 static const int elp_debug = ELP_DEBUG;
 #else
-static const int elp_debug = 0;
+static const int elp_debug;
 #endif
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.4.3/linux/drivers/net/3c507.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/3c507.c	Thu Apr 19 09:34:52 2001
@@ -23,7 +23,7 @@
 	The statistics need to be updated correctly.
 */
 
-static const char *version =
+static const char version[] =
 	"3c507.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 
@@ -323,7 +323,7 @@
 
 static int __init el16_probe1(struct net_device *dev, int ioaddr)
 {
-	static unsigned char init_ID_done = 0, version_printed = 0;
+	static unsigned char init_ID_done, version_printed;
 	int i, irq, irqval, retval;
 	struct net_local *lp;
 
@@ -858,7 +858,7 @@
 #ifdef MODULE
 static struct net_device dev_3c507;
 static int io = 0x300;
-static int irq = 0;
+static int irq;
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.4.3/linux/drivers/net/3c509.c	Sun Mar 25 18:14:25 2001
+++ linux/drivers/net/3c509.c	Thu Apr 12 12:15:25 2001
@@ -144,7 +144,7 @@
 	char mca_slot;
 };
 static int id_port __initdata = 0x110;	/* Start with 0x110 to avoid new sound cards.*/
-static struct net_device *el3_root_dev = NULL;
+static struct net_device *el3_root_dev;
 
 static ushort id_read_eeprom(int index);
 static ushort read_eeprom(int ioaddr, int index);
@@ -209,10 +209,10 @@
 	short lrs_state = 0xff, i;
 	int ioaddr, irq, if_port;
 	u16 phys_addr[3];
-	static int current_tag = 0;
+	static int current_tag;
 	int mca_slot = -1;
 #ifdef CONFIG_ISAPNP
-	static int pnp_cards = 0;
+	static int pnp_cards;
 #endif /* CONFIG_ISAPNP */
 
 	if (dev) SET_MODULE_OWNER(dev);
@@ -942,7 +942,7 @@
 	int ioaddr = dev->base_addr;
 
 	if (el3_debug > 1) {
-		static int old = 0;
+		static int old;
 		if (old != dev->mc_count) {
 			old = dev->mc_count;
 			printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.4.3/linux/drivers/net/3c515.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/3c515.c	Thu Apr 12 12:15:25 2001
@@ -407,7 +407,7 @@
 #ifdef MODULE
 static int debug = -1;
 /* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_corkscrew_dev = NULL;
+static struct net_device *root_corkscrew_dev;
 
 int init_module(void)
 {
@@ -445,7 +445,7 @@
 	static int ioaddr;
 #ifdef CONFIG_ISAPNP
 	short i;
-	static int pnp_cards = 0;
+	static int pnp_cards;
 #endif
 
 #ifdef CONFIG_ISAPNP
@@ -1166,7 +1166,7 @@
 		printk("%s: interrupt, status %4.4x, timer %d.\n",
 			dev->name, status, latency);
 	if ((status & 0xE000) != 0xE000) {
-		static int donedidthis = 0;
+		static int donedidthis;
 		/* Some interrupt controllers store a bogus interrupt from boot-time.
 		   Ignore a single early interrupt, but don't hang the machine for
 		   other interrupt problems. */
@@ -1234,7 +1234,7 @@
 				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
 			}
 			if (status & StatsFull) {	/* Empty statistics. */
-				static int DoneDidThat = 0;
+				static int DoneDidThat;
 				if (corkscrew_debug > 4)
 					printk("%s: Updating stats.\n",
 					       dev->name);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.4.3/linux/drivers/net/3c523.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/3c523.c	Thu Apr 12 12:15:25 2001
@@ -404,7 +404,7 @@
 
 int __init elmc_probe(struct net_device *dev)
 {
-	static int slot = 0;
+	static int slot;
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 	u_char status = 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c527.c linux/drivers/net/3c527.c
--- v2.4.3/linux/drivers/net/3c527.c	Sun Mar  4 14:05:04 2001
+++ linux/drivers/net/3c527.c	Thu Apr 12 12:15:25 2001
@@ -270,7 +270,7 @@
 
 static int __init mc32_probe1(struct net_device *dev, int slot)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	int i, err;
 	u8 POS;
 	u32 base;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.4.3/linux/drivers/net/3c59x.c	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/3c59x.c	Thu Apr 12 12:16:35 2001
@@ -192,6 +192,7 @@
 #error You must compile this driver with "-O".
 #endif
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.4.3/linux/drivers/net/8139too.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/8139too.c	Thu Apr 19 09:32:48 2001
@@ -149,7 +149,7 @@
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.15c"
+#define RTL8139_VERSION "0.9.16"
 #define MODNAME "8139too"
 #define RTL8139_DRIVER_NAME   MODNAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX MODNAME ": "
@@ -204,6 +204,7 @@
 #define RX_BUF_PAD 16
 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
 #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+#define RX_EARLY_THRESH 2
 
 /* Number of Tx descriptor registers. */
 #define NUM_TX_DESC	4
@@ -220,8 +221,8 @@
 #define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
 
 /* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
-#define RX_FIFO_THRESH	6	/* Rx buffer level before first PCI xfer.  */
-#define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define RX_FIFO_THRESH	7	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	7	/* Maximum PCI burst, '6' is 1024 */
 #define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
 
 
@@ -491,7 +492,7 @@
 } chip_t;
 
 enum chip_flags {
-	HasPwrDn = (1 << 0),
+	HasHltClk = (1 << 0),
 	HasLWake = (1 << 1),
 };
 
@@ -506,19 +507,19 @@
 	{ "RTL-8139",
 	  0x40,
 	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
-	  HasPwrDn,
+	  HasHltClk,
 	},
 
 	{ "RTL-8139 rev K",
 	  0x60,
 	  0xf0fe0040,
-	  HasPwrDn,
+	  HasHltClk,
 	},
 
 	{ "RTL-8139A",
 	  0x70,
 	  0xf0fe0040,
-	  0,
+	  HasHltClk, /* XXX undocumented? */
 	},
 
 	{ "RTL-8139B",
@@ -572,6 +573,7 @@
 	pid_t thr_pid;
 	wait_queue_head_t thr_wait;
 	struct semaphore thr_exited;
+	u32 rx_config;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -633,6 +635,7 @@
 #define RTL_W32_F(reg, val32)	do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
 
 
+#define MMIO_FLUSH_AUDIT_COMPLETE 1
 #if MMIO_FLUSH_AUDIT_COMPLETE
 
 /* write MMIO register */
@@ -662,7 +665,7 @@
 	TxErr | TxOK | RxErr | RxOK;
 
 static const unsigned int rtl8139_rx_config =
-	  RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap |
+	  (RX_EARLY_THRESH << RxCfgEarlyRxShift) | RxCfgRcv32K | RxNoWrap |
 	  (RX_FIFO_THRESH << RxCfgFIFOShift) |
 	  (RX_DMA_BURST << RxCfgDMAShift);
 
@@ -700,6 +703,23 @@
 }
 
 
+static void rtl8139_chip_reset (void *ioaddr)
+{
+	int i;
+
+	/* Soft reset the chip. */
+	RTL_W8 (ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--) {
+		barrier();
+		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+			break;
+		udelay (10);
+	}
+}
+
+
 static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 					 struct net_device **dev_out)
 {
@@ -707,7 +727,8 @@
 	struct net_device *dev;
 	struct rtl8139_private *tp;
 	u8 tmp8;
-	int rc, i;
+	int rc;
+	unsigned int i, have_pci_pm = 1;
 	u32 pio_start, pio_end, pio_flags, pio_len;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
 	u32 tmp;
@@ -748,30 +769,37 @@
 	 * we talk to the chip directly */
 	DPRINTK("PIO region size == 0x%02X\n", pio_len);
 	DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
-	if (pio_len == RTL8139B_IO_SIZE)
-		tp->chipset = CH_8139B;
 
+	/* ugly hueristic, but it's a chicken-and-egg problem */
+	if (pio_len < RTL8139B_IO_SIZE)
+		have_pci_pm = 0;
+	
+#ifdef USE_IO_OPS
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
 		printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name);
 		rc = -ENODEV;
 		goto err_out;
 	}
-
+	/* check for weird/broken PCI region reporting */
+	if (pio_len < RTL_MIN_IO_SIZE) {
+		printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pdev->slot_name);
+		rc = -ENODEV;
+		goto err_out;
+	}
+#else
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(mmio_flags & IORESOURCE_MEM)) {
 		printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name);
 		rc = -ENODEV;
 		goto err_out;
 	}
-
-	/* check for weird/broken PCI region reporting */
-	if ((pio_len < RTL_MIN_IO_SIZE) ||
-	    (mmio_len < RTL_MIN_IO_SIZE)) {
-		printk (KERN_ERR PFX "%s: Invalid PCI region size(s), aborting\n", pdev->slot_name);
+	if (mmio_len < RTL_MIN_IO_SIZE) {
+		printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pdev->slot_name);
 		rc = -ENODEV;
 		goto err_out;
 	}
+#endif
 
 	rc = pci_request_regions (pdev, "8139too");
 	if (rc)
@@ -795,61 +823,43 @@
 	tp->mmio_addr = ioaddr;
 #endif /* USE_IO_OPS */
 
-	/* Bring the chip out of low-power mode. */
-	if (rtl_chip_info[tp->chipset].flags & HasPwrDn) {
-		tmp8 = RTL_R8 (Config1);
-		if (tmp8 & (SLEEP|PWRDN)) {
-			RTL_W8_F (Cfg9346, Cfg9346_Unlock);
-			RTL_W8 (Config1, tmp8 & ~(SLEEP|PWRDN));
-			RTL_W8_F (Cfg9346, Cfg9346_Lock);
-		}
-	} else {
+	/* Bring old chips out of low-power mode. */
+	if (have_pci_pm) {
 		u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
 		if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
 		    (tmp8 & LWAKE))
 			new_tmp8 &= ~LWAKE;
 		new_tmp8 |= Cfg1_PM_Enable;
 		if (new_tmp8 != tmp8) {
-			RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
 			RTL_W8 (Config1, tmp8);
-			RTL_W8_F (Cfg9346, Cfg9346_Lock);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
 		}
 		if (rtl_chip_info[tp->chipset].flags & HasLWake) {
 			tmp8 = RTL_R8 (Config4);
 			if (tmp8 & LWPTN)
 				RTL_W8 (Config4, tmp8 & ~LWPTN);
 		}
+	} else {
+		RTL_W8 (HltClk, 'R');
+		tmp8 = RTL_R8 (Config1);
+		tmp8 &= ~(SLEEP | PWRDN);
+		RTL_W8 (Config1, tmp8);
 	}
 
-	/* Soft reset the chip. */
-	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
-
-	/* Check that the chip has finished the reset. */
-	for (i = 1000; i > 0; i--) {
-		barrier();
-		udelay (10);
-		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
-			break;
-	}
+	rtl8139_chip_reset (ioaddr);
 
-	/* make sure chip thinks PIO and MMIO are enabled */
-	tmp8 = RTL_R8 (Config1);
-	if ((tmp8 & Cfg1_PIO) == 0) {
-		printk (KERN_ERR PFX "%s: PIO not enabled, Cfg1=%02X, aborting\n",
-			pdev->slot_name, tmp8);
-		rc = -EIO;
-		goto err_out;
-	}
-	if ((tmp8 & Cfg1_MMIO) == 0) {
-		printk (KERN_ERR PFX "%s: MMIO not enabled, Cfg1=%02X, aborting\n",
-			pdev->slot_name, tmp8);
+	/* check for missing/broken hardware */
+	if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
+		printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
+			pdev->slot_name);
 		rc = -EIO;
 		goto err_out;
 	}
 
 	/* identify chip attached to board */
 	tmp = RTL_R8 (ChipVersion);
-	for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--)
+	for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
 		if (tmp == rtl_chip_info[i].version) {
 			tp->chipset = i;
 			goto match;
@@ -886,7 +896,6 @@
 	int i, addr_len, option;
 	void *ioaddr;
 	static int board_idx = -1;
-	static int printed_version;
 
 	DPRINTK ("ENTER\n");
 
@@ -895,10 +904,16 @@
 
 	board_idx++;
 
-	if (!printed_version) {
-		printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n");
-		printed_version = 1;
+	/* when we're built into the kernel, the driver version message
+	 * is only printed if at least one 8139 board has been found
+	 */
+#ifndef MODULE
+	{
+		static int printed_version;
+		if (!printed_version++)
+			printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
 	}
+#endif
 
 	i = rtl8139_init_board (pdev, &dev);
 	if (i < 0) {
@@ -987,14 +1002,6 @@
 #endif
 		tp->phys[0] = 32;
 
-	/* Put the chip into low-power mode. */
-	if (rtl_chip_info[tp->chipset].flags & HasPwrDn) {
-		RTL_W8_F (Cfg9346, Cfg9346_Unlock);
-		RTL_W8_F (Config1, RTL_R8 (Config1) | PWRDN);
-		RTL_W8_F (HltClk, 'H');	/* 'R' would leave the clock running. */
-		RTL_W8_F (Cfg9346, Cfg9346_Lock);
-	}
-
 	/* The lower four bits are the media type. */
 	option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
 	if (option > 0) {
@@ -1020,6 +1027,10 @@
 				   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 	}
 
+	/* Put the chip into low-power mode. */
+	if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+		RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+
 	DPRINTK ("EXIT - returning 0\n");
 	return 0;
 
@@ -1215,11 +1226,11 @@
 	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
 		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);
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
+			RTL_W16 (BasicModeCtrl, value);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
 		} else if (location < 8 && mii_2_8139_map[location])
-			RTL_W16_F (mii_2_8139_map[location], value);
+			RTL_W16 (mii_2_8139_map[location], value);
 		return;
 	}
 
@@ -1314,33 +1325,30 @@
 
 	DPRINTK ("ENTER\n");
 
-	/* Soft reset the chip. */
-	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
-	udelay (100);
+	/* Bring old chips out of low-power mode. */
+	if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+		RTL_W8 (HltClk, 'R');
 
-	/* Check that the chip has finished the reset. */
-	for (i = 1000; i > 0; i--)
-		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
-			break;
+	rtl8139_chip_reset (ioaddr);
 
 	/* unlock Config[01234] and BMCR register writes */
-	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+	RTL_W8 (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)));
+	RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
 
 	/* Must enable Tx/Rx before setting transfer thresholds! */
-	RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) |
-			   CmdRxEnb | CmdTxEnb);
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
 
-	i = rtl8139_rx_config |
-	    (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
-	RTL_W32_F (RxConfig, i);
+	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+	RTL_W32 (RxConfig, rtl8139_rx_config);
 
 	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
 
 	tp->cur_rx = 0;
+	
+	DPRINTK("check_duplex");
 
 	/* This is check_duplex() */
 	if (tp->phys[0] >= 0  ||  (tp->drv_flags & HAS_MII_XCVR)) {
@@ -1357,8 +1365,6 @@
 			   tp->full_duplex ? "full" : "half", mii_reg5);
 	}
 
-	RTL_W8 (Config1, RTL_R8 (Config1) | Cfg1_Driver_Load);
-
 	if (tp->chipset >= CH_8139B) {
 		tmp = RTL_R8 (Config4) & ~(1<<2);
 		/* chip will clear Rx FIFO overflow automatically */
@@ -1370,9 +1376,10 @@
 		RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5));
 	}
 
+	DPRINTK("init buffer addresses\n");
+
 	/* Lock Config[01234] and BMCR register writes */
-	RTL_W8_F (Cfg9346, Cfg9346_Lock);
-	udelay (10);
+	RTL_W8 (Cfg9346, Cfg9346_Lock);
 
 	/* init Rx ring buffer DMA address */
 	RTL_W32_F (RxBuf, tp->rx_ring_dma);
@@ -1381,7 +1388,7 @@
 	for (i = 0; i < NUM_TX_DESC; i++)
 		RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
 
-	RTL_W32_F (RxMissed, 0);
+	RTL_W32 (RxMissed, 0);
 
 	rtl8139_set_rx_mode (dev);
 
@@ -1389,11 +1396,12 @@
 	RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
 
 	/* make sure RxTx has started */
-	RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) |
-			   CmdRxEnb | CmdTxEnb);
+	tmp = RTL_R8 (ChipCmd);
+	if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
+		RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
-	RTL_W16_F (IntrMask, rtl8139_intr_mask);
+	RTL_W16 (IntrMask, rtl8139_intr_mask);
 
 	netif_start_queue (dev);
 
@@ -1627,6 +1635,7 @@
 	void *ioaddr = tp->mmio_addr;
 	int i;
 	u8 tmp8;
+	unsigned long flags;
 
 	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
 		 "media %2.2x.\n", dev->name,
@@ -1637,7 +1646,7 @@
 	/* disable Tx ASAP, if not already */
 	tmp8 = RTL_R8 (ChipCmd);
 	if (tmp8 & CmdTxEnb)
-		RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb);
+		RTL_W8 (ChipCmd, CmdRxEnb);
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	RTL_W16 (IntrMask, 0x0000);
@@ -1652,9 +1661,9 @@
 				" (queue head)" : "");
 
 	/* Stop a shared interrupt from scavenging while we are. */
-	spin_lock_irq (&tp->lock);
+	spin_lock_irqsave (&tp->lock, flags);
 	rtl8139_tx_clear (tp);
-	spin_unlock_irq (&tp->lock);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
 	/* ...and finally, reset everything */
 	rtl8139_hw_start (dev);
@@ -1668,7 +1677,8 @@
 {
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
-	int entry;
+	unsigned int entry;
+	unsigned long flags;
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = tp->cur_tx % NUM_TX_DESC;
@@ -1695,13 +1705,13 @@
 
 	dev->trans_start = jiffies;
 
-	spin_lock_irq (&tp->lock);
+	spin_lock_irqsave (&tp->lock, flags);
 
 	tp->cur_tx++;
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
 
-	spin_unlock_irq (&tp->lock);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
 	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
 		 dev->name, skb->data, skb->len, entry);
@@ -1774,6 +1784,7 @@
 
 		dirty_tx++;
 		tx_left--;
+		barrier();
 	}
 
 #ifndef RTL8139_NDEBUG
@@ -1818,8 +1829,7 @@
 	tp->cur_rx = 0;
 
 	/* disable receive */
-	tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear;
-	RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb);
+	RTL_W8 (ChipCmd, CmdTxEnb);
 
 	/* A.C.: Reset the multicast list. */
 	rtl8139_set_rx_mode (dev);
@@ -1827,11 +1837,11 @@
 	/* XXX potentially temporary hack to
 	 * restart hung receiver */
 	while (--tmp_work > 0) {
+		barrier();
 		tmp8 = RTL_R8 (ChipCmd);
 		if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
 			break;
-		RTL_W8_F (ChipCmd,
-			  (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);
+		RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
 	}
 
 	/* G.S.: Re-enable receiver */
@@ -1843,13 +1853,12 @@
 }
 
 
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
-   field alignments and semantics. */
 static void rtl8139_rx_interrupt (struct net_device *dev,
-				  struct rtl8139_private *tp, void *ioaddr)
+				  struct rtl8139_private *tp, void *ioaddr,
+				  u16 status)
 {
 	unsigned char *rx_ring;
-	u16 cur_rx;
+	u16 cur_rx, ackstat;
 
 	assert (dev != NULL);
 	assert (tp != NULL);
@@ -1863,6 +1872,11 @@
 		 RTL_R16 (RxBufAddr),
 		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
 
+	if (status & RxFIFOOver)
+		status = RxOverflow | RxOK;
+	else
+		status = RxOK;
+
 	while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
 		int ring_offset = cur_rx % RX_BUF_LEN;
 		u32 rx_status;
@@ -1870,6 +1884,8 @@
 		unsigned int pkt_size;
 		struct sk_buff *skb;
 
+		mb();
+
 		/* 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;
@@ -1889,16 +1905,7 @@
 		}
 #endif
 
-		/* E. Gill */
-		/* Note from BSD driver:
-		 * Here's a totally undocumented fact for you. When the
-		 * RealTek chip is in the process of copying a packet into
-		 * RAM for you, the length will be 0xfff0. If you spot a
-		 * packet header with this value, you need to stop. The
-		 * datasheet makes absolutely no mention of this and
-		 * RealTek should be shot for this.
-		 */
-		if (rx_size == 0xfff0)
+		if (rx_size == 0xfff0) /* Early Rx in progress */
 			break;
 
 		/* If Rx err or invalid rx_size/rx_status received
@@ -1907,6 +1914,7 @@
 		 * Rx processing.
 		 */
 		if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+		    (rx_size < 8) ||
 		    (!(rx_status & RxStatusOK))) {
 			rtl8139_rx_err (rx_status, dev, tp, ioaddr);
 			return;
@@ -1942,7 +1950,11 @@
 		}
 
 		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
-		RTL_W16_F (RxBufPtr, cur_rx - 16);
+		RTL_W16 (RxBufPtr, cur_rx - 16);
+
+		ackstat = RTL_R16 (IntrStatus) & status;
+		if (ackstat)
+			RTL_W16 (IntrStatus, ackstat);
 	}
 
 	DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
@@ -1951,6 +1963,12 @@
 		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
 
 	tp->cur_rx = cur_rx;
+
+	if (RTL_R8 (ChipCmd) & RxBufEmpty) {
+		ackstat = RTL_R16 (IntrStatus) & status;
+		if (ackstat)
+			RTL_W16_F (IntrStatus, ackstat);
+	}
 }
 
 
@@ -1996,11 +2014,6 @@
 		tp->stats.rx_length_errors++;
 	if (status & (RxUnderrun | RxFIFOOver))
 		tp->stats.rx_fifo_errors++;
-	if (status & RxOverflow) {
-		tp->stats.rx_over_errors++;
-		tp->cur_rx = RTL_R16 (RxBufAddr) % RX_BUF_LEN;
-		RTL_W16_F (RxBufPtr, tp->cur_rx - 16);
-	}
 	if (status & PCIErr) {
 		u16 pci_cmd_status;
 		pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
@@ -2020,7 +2033,8 @@
 	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 */
+	int ackstat, status;
+	int link_changed = 0; /* avoid bogus "uninit" warning */
 
 	do {
 		status = RTL_R16 (IntrStatus);
@@ -2053,17 +2067,21 @@
 		   CPU speed, lower CPU speed --> more errors).
 		   After clearing the RxOverflow bit the transfer of the
 		   packet was repeated and all data are error free transferred */
-		RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
+		ackstat = status & ~(RxFIFOOver | RxOverflow | RxOK);
+		RTL_W16 (IntrStatus, ackstat);
 
-		DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
-				dev->name, status,
-				RTL_R16 (IntrStatus));
+		DPRINTK ("%s: interrupt  status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n",
+			 dev->name, ackstat, status, RTL_R16 (IntrStatus));
 
 		if ((status &
 		     (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
 		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
 			break;
 
+		if (netif_running (dev) &&
+		    status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
+			rtl8139_rx_interrupt (dev, tp, ioaddr, status);
+
 		/* Check uncommon events with one test. */
 		if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
 		  	      RxFIFOOver | TxErr | RxErr))
@@ -2071,10 +2089,6 @@
 						 status, link_changed);
 
 		if (netif_running (dev) &&
-		    status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
-			rtl8139_rx_interrupt (dev, tp, ioaddr);
-
-		if (netif_running (dev) &&
 		    status & (TxOK | TxErr)) {
 			spin_lock (&tp->lock);
 			rtl8139_tx_interrupt (dev, tp, ioaddr);
@@ -2104,6 +2118,7 @@
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int ret = 0;
+	unsigned long flags;
 
 	DPRINTK ("ENTER\n");
 
@@ -2121,19 +2136,19 @@
 	DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
 			dev->name, RTL_R16 (IntrStatus));
 
-	spin_lock_irq (&tp->lock);
+	spin_lock_irqsave (&tp->lock, flags);
 
 	/* Stop the chip's Tx and Rx DMA processes. */
-	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
+	RTL_W8 (ChipCmd, 0);
 
 	/* Disable interrupts by clearing the interrupt mask. */
-	RTL_W16 (IntrMask, 0x0000);
+	RTL_W16 (IntrMask, 0);
 
 	/* Update the error counts. */
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 	RTL_W32 (RxMissed, 0);
 
-	spin_unlock_irq (&tp->lock);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
 	synchronize_irq ();
 	free_irq (dev->irq, dev);
@@ -2150,10 +2165,8 @@
 	/* Green! Put the chip in low-power mode. */
 	RTL_W8 (Cfg9346, Cfg9346_Unlock);
 
-	if (rtl_chip_info[tp->chipset].flags & HasPwrDn) {
-		RTL_W8 (Config1, 0x03);
+	if (rtl_chip_info[tp->chipset].flags & HasHltClk)
 		RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
-	}
 
 	DPRINTK ("EXIT\n");
 	return 0;
@@ -2212,14 +2225,15 @@
 {
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
 
 	DPRINTK ("ENTER\n");
 
 	if (netif_running(dev)) {
-		spin_lock_irq (&tp->lock);
+		spin_lock_irqsave (&tp->lock, flags);
 		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 		RTL_W32 (RxMissed, 0);
-		spin_unlock_irq (&tp->lock);
+		spin_unlock_irqrestore (&tp->lock, flags);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -2279,22 +2293,26 @@
 		mc_filter[1] = mc_filter[0] = 0xffffffff;
 	} else {
 		struct dev_mc_list *mclist;
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
 		mc_filter[1] = mc_filter[0] = 0;
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-		     i++, mclist = mclist->next)
+		     i++, mclist = mclist->next) {
 			set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26,
 				 mc_filter);
+			rx_mode |= AcceptMulticast;
+		}
 	}
 
 	spin_lock_irqsave (&tp->lock, flags);
 
 	/* We can safely update without stopping the chip. */
-	tmp = rtl8139_rx_config | rx_mode |
-		(RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
-	RTL_W32_F (RxConfig, tmp);
+	tmp = rtl8139_rx_config | rx_mode;
+	if (tp->rx_config != tmp) {
+		RTL_W32 (RxConfig, tmp);
+		tp->rx_config = tmp;
+	}
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
-	RTL_W32_F (MAR0 + 4, mc_filter[1]);
+	RTL_W32 (MAR0 + 4, mc_filter[1]);
 
 	spin_unlock_irqrestore (&tp->lock, flags);
 
@@ -2317,8 +2335,8 @@
 	spin_lock_irqsave (&tp->lock, flags);
 
 	/* Disable interrupts, stop Tx and Rx. */
-	RTL_W16 (IntrMask, 0x0000);
-	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
+	RTL_W16 (IntrMask, 0);
+	RTL_W8 (ChipCmd, 0);
 
 	/* Update the error counts. */
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
@@ -2351,6 +2369,13 @@
 
 static int __init rtl8139_init_module (void)
 {
+	/* when we're a module, we always print a version message,
+	 * even if no 8139 board is found.
+	 */
+#ifdef MODULE
+	printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+#endif
+
 	return pci_module_init (&rtl8139_pci_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.4.3/linux/drivers/net/82596.c	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/82596.c	Thu Apr 12 12:15:25 2001
@@ -1095,7 +1095,7 @@
 	int i;
 	struct i596_private *lp;
 	char eth_addr[8];
-	static int probed = 0;
+	static int probed;
 
 	if (probed)
 		return -ENODEV;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.4.3/linux/drivers/net/8390.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/net/8390.c	Thu Apr 19 09:34:52 2001
@@ -45,7 +45,7 @@
 
   */
 
-static const char *version =
+static const char version[] =
     "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/8390.h linux/drivers/net/8390.h
--- v2.4.3/linux/drivers/net/8390.h	Mon Mar 26 15:49:39 2001
+++ linux/drivers/net/8390.h	Wed Apr 25 16:22:04 2001
@@ -116,7 +116,8 @@
  
 #if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
     defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
-    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
+    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \
+    defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #else
 #define EI_SHIFT(x)	(x)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.4.3/linux/drivers/net/Config.in	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/Config.in	Sun Apr 22 15:43:21 2001
@@ -49,6 +49,9 @@
    if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
       tristate '  MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
    fi
+   if [ "$CONFIG_MIPS_GT96100" = "y" ]; then
+      bool '  MIPS GT96100 Ethernet support' CONFIG_MIPS_GT96100ETH
+   fi
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
@@ -164,6 +167,9 @@
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
 	 bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
       fi
+      if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ORION" = "y" ]; then
+	 bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
+      fi
    fi
    bool '  Pocket and portable adapters' CONFIG_NET_POCKET
    if [ "$CONFIG_NET_POCKET" = "y" ]; then
@@ -221,6 +227,7 @@
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
    dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
+   dep_bool '  PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER
    dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
    dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
    dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
diff -u --recursive --new-file v2.4.3/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.4.3/linux/drivers/net/Makefile	Mon Mar 26 15:39:56 2001
+++ linux/drivers/net/Makefile	Thu Apr 19 22:46:05 2001
@@ -18,6 +18,8 @@
 export-objs     :=	8390.o arlan.o aironet4500_core.o aironet4500_card.o \
 			ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \
 			net_init.o
+list-multi	:=	rcpci.o
+rcpci-objs	:=	rcpci45.o rclanmtl.o
 
 ifeq ($(CONFIG_TULIP),y)
   obj-y += tulip/tulip.o
@@ -169,6 +171,7 @@
 obj-$(CONFIG_WAVELAN) += wavelan.o
 obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
 obj-$(CONFIG_ZNET) += znet.o
+obj-$(CONFIG_LAN_SAA9730) += saa9730.o
 obj-$(CONFIG_DEPCA) += depca.o
 obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_ATP) += atp.o
@@ -187,6 +190,7 @@
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
+obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
 obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_BAGETLANCE) += bagetlance.o
 obj-$(CONFIG_DECLANCE) += declance.o
@@ -201,19 +205,28 @@
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_TUN) += tun.o
+
+ifeq ($(CONFIG_ARCH_ACORN),y)
+mod-subdirs	+= ../acorn/net
+subdir-y	+= ../acorn/net
+obj-y		+= ../acorn/net/acorn-net.o
+endif
+
 #
 # HIPPI adapters
 #
 
 ifneq ($(ARCH),s390)
+ifneq ($(ARCH),s390x)
 obj-y += auto_irq.o
 endif
+endif
 
 include $(TOPDIR)/Rules.make
 
 clean:
 	rm -f core *.o *.a *.s
 
-rcpci.o: rcpci45.o rclanmtl.o
-	$(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
+rcpci.o: $(rcpci-objs)
+	$(LD) -r -o $@ $(rcpci-objs)
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.4.3/linux/drivers/net/Space.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/Space.c	Wed Apr 18 11:39:21 2001
@@ -544,7 +544,6 @@
 #ifdef CONFIG_TR
 /* Token-ring device probe */
 extern int ibmtr_probe(struct net_device *);
-extern int olympic_probe(struct net_device *);
 extern int smctr_probe(struct net_device *);
 
 static int
@@ -553,9 +552,6 @@
     if (1
 #ifdef CONFIG_IBMTR
 	&& ibmtr_probe(dev)
-#endif
-#ifdef CONFIG_IBMOL
-	&& olympic_probe(dev)
 #endif
 #ifdef CONFIG_SMCTR
 	&& smctr_probe(dev)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.4.3/linux/drivers/net/a2065.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/a2065.c	Thu Apr 12 12:15:25 2001
@@ -137,7 +137,7 @@
 };
 
 #ifdef MODULE
-static struct lance_private *root_a2065_dev = NULL;
+static struct lance_private *root_a2065_dev;
 #endif
 
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v2.4.3/linux/drivers/net/ac3200.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ac3200.c	Thu Apr 19 09:34:52 2001
@@ -19,7 +19,7 @@
 
   */
 
-static const char *version =
+static const char version[] =
 	"ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.4.3/linux/drivers/net/acenic.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/acenic.c	Fri Apr 13 20:26:07 2001
@@ -2,7 +2,7 @@
  * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card
  *           and other Tigon based cards.
  *
- * Copyright 1998-2000 by Jes Sorensen, <jes@linuxcare.com>.
+ * Copyright 1998-2001 by Jes Sorensen, <jes@linuxcare.com>.
  *
  * Thanks to Alteon and 3Com for providing hardware and documentation
  * enabling me to write this driver.
@@ -62,6 +62,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 #include <linux/sockios.h>
 
 #ifdef SIOCETHTOOL
@@ -282,6 +283,10 @@
 
 #include "acenic_firmware.h"
 
+#ifndef tigon2FwReleaseLocal
+#define tigon2FwReleaseLocal 0
+#endif
+
 /*
  * This driver currently supports Tigon I and Tigon II based cards
  * including the Alteon AceNIC, the 3Com 3C985[B] and NetGear
@@ -464,7 +469,7 @@
  * Jumbo frames are enabled, the user wants optimal tuning for that case.
  */
 #define DEF_TX_COAL		400 /* 996 */
-#define DEF_TX_MAX_DESC		40
+#define DEF_TX_MAX_DESC		60  /* was 40 */
 #define DEF_RX_COAL		120 /* 1000 */
 #define DEF_RX_MAX_DESC		25
 #define DEF_TX_RATIO		21 /* 24 */
@@ -475,10 +480,26 @@
 #define DEF_JUMBO_RX_MAX_DESC	6
 #define DEF_JUMBO_TX_RATIO	21
 
-#define TX_COAL_INTS_ONLY	0	/* seems not worth it */
+#if tigon2FwReleaseLocal < 20001118
+/*
+ * Standard firmware and early modifications duplicate
+ * IRQ load without this flag (coal timer is never reset).
+ * Note that with this flag tx_coal should be less than
+ * time to xmit full tx ring.
+ * 400usec is not so bad for tx ring size of 128.
+ */
+#define TX_COAL_INTS_ONLY	1	/* worth it */
+#else
+/*
+ * With modified firmware, this is not necessary, but still useful.
+ */
+#define TX_COAL_INTS_ONLY	1
+#endif
+
 #define DEF_TRACE		0
 #define DEF_STAT		(2 * TICKS_PER_SEC)
 
+
 static int link[ACE_MAX_MOD_PARMS];
 static int trace[ACE_MAX_MOD_PARMS];
 static int tx_coal_tick[ACE_MAX_MOD_PARMS];
@@ -489,7 +510,7 @@
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static char version[] __initdata = 
-  "acenic.c: v0.50 02/02/2001  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.80 03/08/2001  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -560,6 +581,12 @@
 		dev->irq = pdev->irq;
 		dev->open = &ace_open;
 		dev->hard_start_xmit = &ace_start_xmit;
+		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+		if (1) {
+			static void ace_watchdog(struct net_device *dev);
+			dev->tx_timeout = &ace_watchdog;
+			dev->watchdog_timeo = 5*HZ;
+		}
 		dev->stop = &ace_close;
 		dev->get_stats = &ace_get_stats;
 		dev->set_multicast_list = &ace_set_multicast_list;
@@ -762,15 +789,17 @@
 			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
 
 			if (skb) {
+#ifndef DUMMY_PCI_UNMAP
 				dma_addr_t mapping;
 
 				mapping = ap->skb->rx_std_skbuff[i].mapping;
-
-				ap->rx_std_ring[i].size = 0;
-				ap->skb->rx_std_skbuff[i].skb = NULL;
 				pci_unmap_single(ap->pdev, mapping,
 						 ACE_STD_BUFSIZE - (2 + 16),
 						 PCI_DMA_FROMDEVICE);
+#endif
+
+				ap->rx_std_ring[i].size = 0;
+				ap->skb->rx_std_skbuff[i].skb = NULL;
 				dev_kfree_skb(skb);
 			}
 		}
@@ -779,14 +808,16 @@
 				struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
 
 				if (skb) {
+#ifndef DUMMY_PCI_UNMAP
 					dma_addr_t mapping;
 
 					mapping = ap->skb->rx_mini_skbuff[i].mapping;
-					ap->rx_mini_ring[i].size = 0;
-					ap->skb->rx_mini_skbuff[i].skb = NULL;
 					pci_unmap_single(ap->pdev, mapping,
 							 ACE_MINI_BUFSIZE - (2 + 16),
 							 PCI_DMA_FROMDEVICE);
+#endif
+					ap->rx_mini_ring[i].size = 0;
+					ap->skb->rx_mini_skbuff[i].skb = NULL;
 					dev_kfree_skb(skb);
 				}
 			}
@@ -794,15 +825,17 @@
 		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
 			struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
 			if (skb) {
+#ifndef DUMMY_PCI_UNMAP
 				dma_addr_t mapping;
 
 				mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
-
-				ap->rx_jumbo_ring[i].size = 0;
-				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
 				pci_unmap_single(ap->pdev, mapping,
 						 ACE_JUMBO_BUFSIZE - (2 + 16),
 						 PCI_DMA_FROMDEVICE);
+#endif
+
+				ap->rx_jumbo_ring[i].size = 0;
+				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
 				dev_kfree_skb(skb);
 			}
 		}
@@ -1177,10 +1210,21 @@
 				printk(KERN_INFO "  Disabling PCI memory "
 				       "write and invalidate\n");
 			}
+#ifdef __alpha__
+			/* This maximizes throughput on my alpha. */
+			tmp |= DMA_WRITE_MAX_128;
+#endif
 		} else if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
 			printk(KERN_INFO "  PCI memory write & invalidate "
 			       "enabled by BIOS, enabling counter measures\n");
 
+#ifdef __alpha__
+			/* All the docs sy MUST NOT. Well, I did.
+			 * Nothing terrible happens, if we load wrong size.
+			 * Bit w&i still works better!
+			 */
+			tmp |= DMA_WRITE_MAX_128;
+#else
 			switch(SMP_CACHE_BYTES) {
 			case 16:
 				tmp |= DMA_WRITE_MAX_16;
@@ -1199,6 +1243,7 @@
 				pci_write_config_word(ap->pdev, PCI_COMMAND,
 						      ap->pci_command);
 			}
+#endif
 		}
 	}
 
@@ -1218,6 +1263,9 @@
 	tmp |= DMA_READ_MAX_64;
 	tmp |= DMA_WRITE_MAX_64;
 #endif
+#ifdef __alpha__
+	tmp |= DMA_READ_MAX_128;
+#endif
 	writel(tmp, &regs->PciState);
 
 #if 0
@@ -1313,7 +1361,7 @@
 
 	set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
 	info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
-	info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
+	info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
 
 	memset(ap->rx_std_ring, 0,
 	       RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1328,7 +1376,7 @@
 		    (ap->rx_ring_base_dma +
 		     (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
 	info->rx_jumbo_ctrl.max_len = 0;
-	info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
+	info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
 
 	memset(ap->rx_jumbo_ring, 0,
 	       RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1349,7 +1397,7 @@
 			      (RX_STD_RING_ENTRIES +
 			       RX_JUMBO_RING_ENTRIES))));
 		info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
-		info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
+		info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
 
 		for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
 			ap->rx_mini_ring[i].flags =
@@ -1384,13 +1432,10 @@
 	set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
 
 	info->tx_ctrl.max_len = TX_RING_ENTRIES;
-
-	tmp = 0;
+	tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING;
 #if TX_COAL_INTS_ONLY
 	tmp |= RCB_FLG_COAL_INT_ONLY;
 #endif
-	tmp |= RCB_FLG_TX_HOST_RING;
-
 	info->tx_ctrl.flags = tmp;
 
 	set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma);
@@ -1398,8 +1443,13 @@
 	/*
 	 * Potential item for tuning parameter
 	 */
+#if 0 /* NO */
+	writel(DMA_THRESH_16W, &regs->DmaReadCfg);
+	writel(DMA_THRESH_16W, &regs->DmaWriteCfg);
+#else
 	writel(DMA_THRESH_8W, &regs->DmaReadCfg);
 	writel(DMA_THRESH_8W, &regs->DmaWriteCfg);
+#endif
 
 	writel(0, &regs->MaskInt);
 	writel(1, &regs->IfIdx);
@@ -1430,7 +1480,7 @@
 		if (trace[board_idx])
 			writel(trace[board_idx], &regs->TuneTrace);
 
-		if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64))
+		if ((tx_ratio[board_idx] > 0) && (tx_ratio[board_idx] < 64))
 			writel(tx_ratio[board_idx], &regs->TxBufRat);
 	}
 
@@ -1501,7 +1551,6 @@
 	 * tx ints before we are up and running, which may cause a null
 	 * pointer access in the int handler.
 	 */
-	ap->tx_full = 0;
 	ap->cur_rx = 0;
 	ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0;
 
@@ -1510,6 +1559,11 @@
 	writel(0, &regs->RxRetCsm);
 
 	/*
+	 * Zero the stats before starting the interface
+	 */
+	memset(&ap->stats, 0, sizeof(ap->stats));
+
+	/*
 	 * Start the NIC CPU
 	 */
 	writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
@@ -1611,12 +1665,9 @@
 }
 
 
-/*
- * Monitor the card to detect hangs.
- */
-static void ace_timer(unsigned long data)
+static void ace_watchdog(struct net_device *data)
 {
-	struct net_device *dev = (struct net_device *)data;
+	struct net_device *dev = data;
 	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 
@@ -1628,13 +1679,13 @@
 	if (*ap->tx_csm != ap->tx_ret_csm) {
 		printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n",
 		       dev->name, (unsigned int)readl(&regs->HostCtrl));
+		/* This can happen due to ieee flow control. */
+	} else {
+		printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n", dev->name);
+		netif_wake_queue(dev);
 	}
-
-	ap->timer.expires = jiffies + (5/2*HZ);
-	add_timer(&ap->timer);
 }
 
-
 static void ace_tasklet(unsigned long dev)
 {
 	struct ace_private *ap = ((struct net_device *)dev)->priv;
@@ -1719,7 +1770,9 @@
 					 ACE_STD_BUFSIZE - (2 + 16),
 					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
+#ifndef DUMMY_PCI_UNMAP
 		ap->skb->rx_std_skbuff[idx].mapping = mapping;
+#endif
 
 		rd = &ap->rx_std_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1781,7 +1834,9 @@
 					 ACE_MINI_BUFSIZE - (2 + 16),
 					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
+#ifndef DUMMY_PCI_UNMAP
 		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
+#endif
 
 		rd = &ap->rx_mini_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1840,7 +1895,9 @@
 					 ACE_JUMBO_BUFSIZE - (2 + 16),
 					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
+#ifndef DUMMY_PCI_UNMAP
 		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
+#endif
 
 		rd = &ap->rx_jumbo_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1870,8 +1927,9 @@
 	clear_bit(0, &ap->jumbo_refill_busy);
 	return;
  error_out:
-	printk(KERN_INFO "Out of memory when allocating "
-	       "jumbo receive buffers\n");
+	if (net_ratelimit())
+		printk(KERN_INFO "Out of memory when allocating "
+		       "jumbo receive buffers\n");
 	goto out;
 }
 
@@ -1902,9 +1960,16 @@
 			u16 code = ap->evt_ring[evtcsm].code;
 			switch (code) {
 			case E_C_LINK_UP:
-				printk(KERN_WARNING "%s: Optical link UP\n",
-				       dev->name);
+			{
+				u32 state = readl(&ap->regs->GigLnkState);
+				printk(KERN_WARNING "%s: Optical link UP "
+				       "(%s Duplex, Flow Control: %s%s)\n",
+				       dev->name,
+				       state & LNK_FULL_DUPLEX ? "Full":"Half",
+				       state & LNK_TX_FLOW_CTL_Y ? "TX " : "",
+				       state & LNK_RX_FLOW_CTL_Y ? "RX" : "");
 				break;
+			}
 			case E_C_LINK_DOWN:
 				printk(KERN_WARNING "%s: Optical link DOWN\n",
 				       dev->name);
@@ -1965,8 +2030,6 @@
 			ap->rx_jumbo_skbprd = 0;
 			printk(KERN_INFO "%s: Jumbo ring flushed\n",
 			       dev->name);
-			if (!ap->tx_full)
-				netif_wake_queue(dev);
 			clear_bit(0, &ap->jumbo_refill_busy);
 			break;
 		}
@@ -1994,12 +2057,13 @@
 		struct sk_buff *skb;
 		struct rx_desc *rxdesc, *retdesc;
 		u32 skbidx;
-		int desc_type, mapsize;
+		int bd_flags, desc_type, mapsize;
 		u16 csum;
 
 		retdesc = &ap->rx_return_ring[idx];
 		skbidx = retdesc->idx;
-		desc_type = retdesc->flags & (BD_FLG_JUMBO | BD_FLG_MINI);
+		bd_flags = retdesc->flags;
+		desc_type = bd_flags & (BD_FLG_JUMBO | BD_FLG_MINI);
 
 		switch(desc_type) {
 			/*
@@ -2036,8 +2100,10 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
+#ifndef DUMMY_PCI_UNMAP
 		pci_unmap_single(ap->pdev, rip->mapping, mapsize,
 				 PCI_DMA_FROMDEVICE);
+#endif
 		skb_put(skb, retdesc->size);
 #if 0
 		/* unncessary */
@@ -2053,15 +2119,15 @@
 		skb->protocol = eth_type_trans(skb, dev);
 
 		/*
-		 * If the checksum is correct and this is not a
-		 * fragment, tell the stack that the data is correct.
+		 * Instead of forcing the poor tigon mips cpu to calculate
+		 * pseudo hdr checksum, we do this ourselves.
 		 */
-		if(!(csum ^ 0xffff) &&
-		   (!(((struct iphdr *)skb->data)->frag_off &
-		      __constant_htons(IP_MF|IP_OFFSET))))
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-		else
+		if (bd_flags & BD_FLG_TCP_UDP_SUM) {
+			skb->csum = htons(csum);
+			skb->ip_summed = CHECKSUM_HW;
+		} else {
 			skb->ip_summed = CHECKSUM_NONE;
+		}
 
 		netif_rx(skb);		/* send it up */
 
@@ -2094,6 +2160,75 @@
 }
 
 
+static inline void ace_tx_int(struct net_device *dev,
+			      u32 txcsm, u32 idx)
+{
+	struct ace_private *ap = dev->priv;
+
+	do {
+		struct sk_buff *skb;
+#ifndef DUMMY_PCI_UNMAP
+		dma_addr_t mapping;
+#endif
+		struct tx_ring_info *info;
+
+		info = ap->skb->tx_skbuff + idx;
+		skb = info->skb;
+#ifndef DUMMY_PCI_UNMAP
+		mapping = info->mapping;
+
+		if (mapping) {
+			pci_unmap_single(ap->pdev, mapping, info->maplen,
+					 PCI_DMA_TODEVICE);
+			info->mapping = 0;
+		}
+#endif
+		if (skb) {
+			ap->stats.tx_packets++;
+			ap->stats.tx_bytes += skb->len;
+			dev_kfree_skb_irq(skb);
+			info->skb = NULL;
+		}
+
+		idx = (idx + 1) % TX_RING_ENTRIES;
+	} while (idx != txcsm);
+
+	if (netif_queue_stopped(dev))
+		netif_wake_queue(dev);
+
+	wmb();
+	ap->tx_ret_csm = txcsm;
+
+	/* So... tx_ret_csm is advanced _after_ check for device wakeup.
+	 *
+	 * We could try to make it before. In this case we would get
+	 * the following race condition: hard_start_xmit on other cpu
+	 * enters after we advanced tx_ret_csm and fills space,
+	 * which we have just freed, so that we make illegal device wakeup.
+	 * There is no good way to workaround this (at entry
+	 * to ace_start_xmit detects this condition and prevents
+	 * ring corruption, but it is not a good workaround.)
+	 *
+	 * When tx_ret_csm is advanced after, we wake up device _only_
+	 * if we really have some space in ring (though the core doing
+	 * hard_start_xmit can see full ring for some period and has to
+	 * synchronize.) Superb.
+	 * BUT! We get another subtle race condition. hard_start_xmit
+	 * may think that ring is full between wakeup and advancing
+	 * tx_ret_csm and will stop device instantly! It is not so bad.
+	 * We are guaranteed that there is something in ring, so that
+	 * the next irq will resume transmission. To speedup this we could
+	 * mark descriptor, which closes ring with BD_FLG_COAL_NOW
+	 * (see ace_start_xmit).
+	 *
+	 * Well, this dilemma exists in all lock-free devices.
+	 * We, following scheme used in drivers by Donald Becker,
+	 * select the least dangerous.
+	 *							--ANK
+	 */
+}
+
+
 static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	struct ace_private *ap;
@@ -2115,9 +2250,14 @@
 		return;
 
 	/*
-	 * Tell the card not to generate interrupts while we are in here.
+	 * ACK intr now. Otherwise we will lose updates to rx_ret_prd,
+	 * which happened _after_ rxretprd = *ap->rx_ret_prd; but before
+	 * writel(0, &regs->Mb0Lo).
+	 *
+	 * "IRQ avoidance" recommended in docs applies to IRQs served
+	 * threads and it is wrong even for that case.
 	 */
-	writel(1, &regs->Mb0Lo);
+	writel(0, &regs->Mb0Lo);
 
 	/*
 	 * There is no conflict between transmit handling in
@@ -2136,75 +2276,15 @@
 	idx = ap->tx_ret_csm;
 
 	if (txcsm != idx) {
-		do {
-			struct sk_buff *skb;
-
-			skb = ap->skb->tx_skbuff[idx].skb;
-			/*
-			 * Race condition between the code cleaning
-			 * the tx queue in the interrupt handler and the
-			 * interface close,
-			 *
-			 * This is a kludge that really should be fixed 
-			 * by preventing the driver from generating a tx
-			 * interrupt when the packet has already been
-			 * removed from the tx queue.
-			 *
-			 * Nailed by Don Dugger and Chip Salzenberg of
-			 * VA Linux.
-			 */
-			if (skb) {
-				dma_addr_t mapping;
-
-				mapping = ap->skb->tx_skbuff[idx].mapping;
-
-				ap->stats.tx_packets++;
-				ap->stats.tx_bytes += skb->len;
-				pci_unmap_single(ap->pdev, mapping, skb->len,
-						 PCI_DMA_TODEVICE);
-				dev_kfree_skb_irq(skb);
-
-				ap->skb->tx_skbuff[idx].skb = NULL;
-			}
-
-			/*
-			 * Question here is whether one should not skip
-			 * these writes - I have never seen any errors
-			 * caused by the NIC actually trying to access
-			 * these incorrectly.
-			 */
-#ifdef ACE_64BIT_PTR
-			ap->tx_ring[idx].addr.addrhi = 0;
-#endif
-			ap->tx_ring[idx].addr.addrlo = 0;
-			ap->tx_ring[idx].flagsize = 0;
-
-			idx = (idx + 1) % TX_RING_ENTRIES;
-		} while (idx != txcsm);
-
 		/*
-		 * Once we actually get to this point the tx ring has
-		 * already been trimmed thus it cannot be full!
-		 * Ie. skip the comparison of the tx producer vs. the
-		 * consumer.
+		 * If each skb takes only one descriptor this check degenerates
+		 * to identity, because new space has just been opened.
+		 * But if skbs are fragmented we must check that this index
+		 * update releases enough of space, otherwise we just
+		 * wait for device to make more work.
 		 */
-		if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) {
-			/*
-			 * This does not need to be atomic (and expensive),
-			 * I've seen cases where it would fail otherwise ;-(
-			 */
-			netif_wake_queue(dev);
-			ace_mark_net_bh();
-
-			/*
-			 * TX ring is no longer full, aka the
-			 * transmitter is working fine - kill timer.
-			 */
-			del_timer(&ap->timer);
-		}
-
-		ap->tx_ret_csm = txcsm;
-		wmb();
+		if (!tx_ring_full(txcsm, ap->tx_prd))
+			ace_tx_int(dev, txcsm, idx);
 	}
 
 	evtcsm = readl(&regs->EvtCsm);
@@ -2272,11 +2352,6 @@
 			tasklet_schedule(&ap->ace_tasklet);
 		}
 	}
-
-	/*
-	 * Allow the card to generate interrupts again
-	 */
-	writel(0, &regs->Mb0Lo);
 }
 
 
@@ -2296,11 +2371,6 @@
 
 	writel(dev->mtu + ETH_HLEN + 4, &regs->IfMtu);
 
-	/*
-	 * Zero the stats when restarting the interface...
-	 */
-	memset(&ap->stats, 0, sizeof(ap->stats));
-
 	cmd.evt = C_CLEAR_STATS;
 	cmd.code = 0;
 	cmd.idx = 0;
@@ -2338,13 +2408,6 @@
 	ACE_MOD_INC_USE_COUNT;
 
 	/*
-	 * Setup the timer
-	 */
-	init_timer(&ap->timer);
-	ap->timer.data = (unsigned long)dev;
-	ap->timer.function = ace_timer;
-
-	/*
 	 * Setup the bottom half rx ring refill handler
 	 */
 	tasklet_init(&ap->ace_tasklet, ace_tasklet, (unsigned long)dev);
@@ -2361,13 +2424,17 @@
 	short i;
 
 	ace_if_down(dev);
+
+	/*
+	 * Without (or before) releasing irq and stopping hardware, this
+	 * is an absolute non-sense, by the way. It will be reset instantly
+	 * by the first irq.
+	 */
 	netif_stop_queue(dev);
 
 	ap = dev->priv;
 	regs = ap->regs;
 
-	del_timer(&ap->timer);
-
 	if (ap->promisc) {
 		cmd.evt = C_SET_PROMISC_MODE;
 		cmd.code = C_C_PROMISC_DISABLE;
@@ -2392,16 +2459,26 @@
 
 	for (i = 0; i < TX_RING_ENTRIES; i++) {
 		struct sk_buff *skb;
+#ifndef DUMMY_PCI_UNMAP
 		dma_addr_t mapping;
+#endif
+		struct tx_ring_info *info;
 
-		skb = ap->skb->tx_skbuff[i].skb;
-		mapping = ap->skb->tx_skbuff[i].mapping;
-		if (skb) {
-			memset(&ap->tx_ring[i].addr, 0, sizeof(struct tx_desc));
-			pci_unmap_single(ap->pdev, mapping, skb->len,
+		info = ap->skb->tx_skbuff + i;
+		skb = info->skb;
+#ifndef DUMMY_PCI_UNMAP
+		mapping = info->mapping;
+
+		if (mapping) {
+			memset(ap->tx_ring+i, 0, sizeof(struct tx_desc));
+			pci_unmap_single(ap->pdev, mapping, info->maplen,
 					 PCI_DMA_TODEVICE);
+			info->mapping = 0;
+		}
+#endif
+		if (skb) {
 			dev_kfree_skb(skb);
-			ap->skb->tx_skbuff[i].skb = NULL;
+			info->skb = NULL;
 		}
 	}
 
@@ -2419,85 +2496,216 @@
 }
 
 
+/*
+ * Following below should be (in more clean form!) in arch/ARCH/kernel/pci_*.
+ * For now, let it stay here.
+ */
+#if defined(CONFIG_HIGHMEM) && MAX_SKB_FRAGS
+#ifndef DUMMY_PCI_UNMAP
+#error Sorry, cannot DMA from high memory on this architecture.
+#endif
+
+#if defined(CONFIG_X86)
+#define DMAADDR_OFFSET	0
+typedef unsigned long long dmaaddr_high_t;
+#elif defined(CONFIG_PPC)
+#define DMAADDR_OFFSET PCI_DRAM_OFFSET
+typedef unsigned long dmaaddr_high_t;
+#endif
+
+
+static inline dmaaddr_high_t
+pci_map_single_high(struct pci_dev *hwdev, struct page *page,
+		    int offset, size_t size, int dir)
+{
+	dmaaddr_high_t phys;
+
+	phys = (page-mem_map) *	(dmaaddr_high_t) PAGE_SIZE + offset;
+
+	return (phys + DMAADDR_OFFSET);
+}
+
+#else
+
+typedef unsigned long dmaaddr_high_t;
+
+static inline dmaaddr_high_t
+pci_map_single_high(struct pci_dev *hwdev, struct page *page,
+		    int offset, size_t size, int dir)
+{
+	return pci_map_single(hwdev, page_address(page) + offset, size, dir);
+}
+
+#endif
+
+
+static inline dmaaddr_high_t
+ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
+	       struct sk_buff *tail, u32 idx)
+{
+	unsigned long addr;
+	struct tx_ring_info *info;
+
+	addr = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+	info = ap->skb->tx_skbuff + idx;
+	info->skb = tail;
+#ifndef DUMMY_PCI_UNMAP
+	info->mapping = addr;
+	info->maplen = skb->len;
+#endif
+	return addr;
+}
+
+
+static inline void
+ace_load_tx_bd(struct tx_desc *desc, dmaaddr_high_t addr, u32 flagsize)
+{
+#if !USE_TX_COAL_NOW
+	flagsize &= ~BD_FLG_COAL_NOW;
+#endif
+
+#ifdef ACE_64BIT_PTR
+	desc->addr.addrhi = addr >> 32;
+#endif
+	desc->addr.addrlo = addr;
+	desc->flagsize = flagsize;
+}
+
+
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
-	unsigned long addr;
+	struct tx_desc *desc;
 	u32 idx, flagsize;
 
-	/*
+ 	/*
 	 * This only happens with pre-softnet, ie. 2.2.x kernels.
-	 */
+ 	 */
 	if (early_stop_netif_stop_queue(dev))
-		return 1;
+ 		return 1;
+
 
+restart:
 	idx = ap->tx_prd;
 
-	if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) {
-		ap->tx_full = 1;
-#if DEBUG
-		printk("%s: trying to transmit while the tx ring is full "
-		       "- this should not happen!\n", dev->name);
+	if (tx_ring_full(ap->tx_ret_csm, idx))
+		goto overflow;
+
+#if MAX_SKB_FRAGS
+	if (!skb_shinfo(skb)->nr_frags)
 #endif
-		return 1;
-	}
+	{
+		unsigned long addr;
 
-	ap->skb->tx_skbuff[idx].skb = skb;
-	ap->skb->tx_skbuff[idx].mapping =
-		pci_map_single(ap->pdev, skb->data, skb->len,
-			       PCI_DMA_TODEVICE);
-	addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
-	flagsize = (skb->len << 16) | (BD_FLG_END) ;
-	set_aceaddr(&ap->tx_ring[idx].addr, addr);
-	ap->tx_ring[idx].flagsize = flagsize;
-	wmb();
-	idx = (idx + 1) % TX_RING_ENTRIES;
+		addr = ace_map_tx_skb(ap, skb, skb, idx);
+		flagsize = (skb->len << 16) | (BD_FLG_END);
+		if (skb->ip_summed == CHECKSUM_HW)
+			flagsize |= BD_FLG_TCP_UDP_SUM;
+		desc = ap->tx_ring + idx;
+		idx = (idx + 1) % TX_RING_ENTRIES;
+
+		/* Look at ace_tx_int for explanations. */
+		if (tx_ring_full(ap->tx_ret_csm, idx))
+			flagsize |= BD_FLG_COAL_NOW;
+
+		ace_load_tx_bd(desc, addr, flagsize);
+	}
+#if MAX_SKB_FRAGS
+	else {
+		unsigned long addr;
+		int i, len = 0;
+
+		addr = ace_map_tx_skb(ap, skb, NULL, idx);
+		flagsize = ((skb->len - skb->data_len) << 16);
+		if (skb->ip_summed == CHECKSUM_HW)
+			flagsize |= BD_FLG_TCP_UDP_SUM;
+
+		ace_load_tx_bd(ap->tx_ring + idx, addr, flagsize);
+
+		idx = (idx + 1) % TX_RING_ENTRIES;
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			struct tx_ring_info *info;
+			dmaaddr_high_t phys;
+
+			len += frag->size;
+			info = ap->skb->tx_skbuff + idx;
+			desc = ap->tx_ring + idx;
+
+			phys = pci_map_single_high(ap->pdev, frag->page,
+						   frag->page_offset,
+						   frag->size,
+						   PCI_DMA_TODEVICE);
+
+			flagsize = (frag->size << 16);
+			if (skb->ip_summed == CHECKSUM_HW)
+				flagsize |= BD_FLG_TCP_UDP_SUM;
+			idx = (idx + 1) % TX_RING_ENTRIES;
 
-	ap->tx_prd = idx;
-	ace_set_txprd(regs, ap, idx);
+			if (i == skb_shinfo(skb)->nr_frags-1) {
+				flagsize |= BD_FLG_END;
+				if (tx_ring_full(ap->tx_ret_csm, idx))
+					flagsize |= BD_FLG_COAL_NOW;
+
+				/*
+				 * Only the last fragment frees
+				 * the skb!
+				 */
+				info->skb = skb;
+			} else {
+				info->skb = NULL;
+			}
+#ifndef DUMMY_PCI_UNMAP
+			info->mapping = phys;
+			info->maplen = frag->size;
+#endif
+			ace_load_tx_bd(desc, phys, flagsize);
+		}
+	}
+#endif
 
-	/*
-	 * tx_csm is set by the NIC whereas we set tx_ret_csm which
-	 * is always trying to catch tx_csm
-	 */
-	if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm) {
-		ap->tx_full = 1;
-		/*
-		 * Queue is full, add timer to detect whether the
-		 * transmitter is stuck. Use mod_timer as we can get
-		 * into the situation where we risk adding several
-		 * timers.
-		 */
-		mod_timer(&ap->timer, jiffies + (3 * HZ));
+ 	wmb();
+ 	ap->tx_prd = idx;
+ 	ace_set_txprd(regs, ap, idx);
+
+	if (flagsize & BD_FLG_COAL_NOW) {
+		netif_stop_queue(dev);
 
 		/*
-		 * The following check will fix a race between the interrupt
-		 * handler increasing the tx_ret_csm and testing for tx_full
-		 * and this tx routine's testing the tx_ret_csm and setting
-		 * the tx_full; note that this fix makes assumptions on the
-		 * ordering of writes (sequential consistency will fly; TSO
-		 * processor order would work too) but that's what lock-less
-		 * programming is all about
+		 * A TX-descriptor producer (an IRQ) might have gotten
+		 * inbetween, making the ring free again. Since xmit is
+		 * serialized, this is the only situation we have to
+		 * re-test.
 		 */
-		if (((idx + 2) % TX_RING_ENTRIES != ap->tx_ret_csm)
-			&& xchg(&ap->tx_full, 0)) {
-			del_timer(&ap->timer);
-			/*
-			 * We may not need this one in the post softnet era
-			 * in this case this can be changed to a
-			 * early_stop_netif_wake_queue(dev);
-			 */
+		if (!tx_ring_full(ap->tx_ret_csm, idx))
 			netif_wake_queue(dev);
-		} else {
-			late_stop_netif_stop_queue(dev);
-		}
-	} else {
-		early_stop_netif_wake_queue(dev);
 	}
 
 	dev->trans_start = jiffies;
 	return 0;
+
+overflow:
+	/*
+	 * This race condition is unavoidable with lock-free drivers.
+	 * We wake up the queue _before_ tx_prd is advanced, so that we can
+	 * enter hard_start_xmit too early, while tx ring still looks closed.
+	 * This happens ~1-4 times per 100000 packets, so that we can allow
+	 * to loop syncing to other CPU. Probably, we need an additional
+	 * wmb() in ace_tx_intr as well.
+	 *
+	 * Note that this race is relieved by reserving one more entry
+	 * in tx ring than it is necessary (see original non-SG driver).
+	 * However, with SG we need to reserve 2*MAX_SKB_FRAGS+1, which
+	 * is already overkill.
+	 *
+	 * Alternative is to return with 1 not throttling queue. In this
+	 * case loop becomes longer, no more useful effects.
+	 */
+	barrier();
+	goto restart;
 }
 
 
@@ -2522,7 +2730,6 @@
 			ace_set_rxtx_parms(dev, 1);
 		}
 	} else {
-		netif_stop_queue(dev);
 		while (test_and_set_bit(0, &ap->jumbo_refill_busy));
 		synchronize_irq();
 		ace_set_rxtx_parms(dev, 0);
@@ -2542,27 +2749,12 @@
 
 static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-#ifdef SIOCETHTOOL
 	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
+#ifdef SIOCETHTOOL
 	struct ethtool_cmd ecmd;
 	u32 link, speed;
 
-#ifdef SPIN_DEBUG
-	if (cmd == (SIOCDEVPRIVATE+0x0e)) {
-		printk(KERN_NOTICE "%s: dumping debug info\n", dev->name);
-		printk(KERN_NOTICE "%s: tbusy %li, tx_ret_csm %i, "
-		       "tx_prd %i\n", dev->name, dev->tbusy,
-		       ap->tx_ret_csm, ap->tx_prd);
-		printk(KERN_NOTICE "%s: cur_rx %i, std_refill %li, "
-		       "mini_rx %i, mini_refill %li\n", dev->name,
-		       atomic_read(&ap->cur_rx_bufs), ap->std_refill_busy,
-		       atomic_read(&ap->cur_mini_bufs), ap->mini_refill_busy);
-		printk(KERN_NOTICE "%s: CpuCtrl %08x\n",
-		       dev->name, readl(&regs->CpuCtrl));
-		return 0;
-	}
-#endif
 	if (cmd != SIOCETHTOOL)
 		return -EOPNOTSUPP;
 	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
@@ -2699,7 +2891,8 @@
 
 	regs = ((struct ace_private *)dev->priv)->regs;
 	writel(da[0] << 8 | da[1], &regs->MacAddrHi);
-	writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5] , &regs->MacAddrLo);
+	writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5],
+	       &regs->MacAddrLo);
 
 	cmd.evt = C_SET_MAC_ADDR;
 	cmd.code = 0;
@@ -2774,11 +2967,12 @@
 	ap->stats.multicast = readl(&mac_stats->kept_mc);
 	ap->stats.collisions = readl(&mac_stats->coll);
 
-	return(&ap->stats);
+	return &ap->stats;
 }
 
 
-static void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)
+static void __init ace_copy(struct ace_regs *regs, void *src,
+			    u32 dest, int size)
 {
 	unsigned long tdest;
 	u32 *wsrc;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.4.3/linux/drivers/net/acenic.h	Sat Dec 30 11:23:13 2000
+++ linux/drivers/net/acenic.h	Thu Apr 12 12:11:39 2001
@@ -1,6 +1,19 @@
 #ifndef _ACENIC_H_
 #define _ACENIC_H_
 
+
+/*
+ * Generate TX index update each time, when TX ring is closed.
+ * Normally, this is not useful, because results in more dma (and irqs
+ * without TX_COAL_INTS_ONLY).
+ */
+#define USE_TX_COAL_NOW	 0
+
+#ifndef MAX_SKB_FRAGS
+#define MAX_SKB_FRAGS 0
+#endif
+
+
 /*
  * Addressing:
  *
@@ -258,7 +271,12 @@
  * DMA config
  */
 
+#define DMA_THRESH_1W		0x10
+#define DMA_THRESH_2W		0x20
+#define DMA_THRESH_4W		0x40
 #define DMA_THRESH_8W		0x80
+#define DMA_THRESH_16W		0x100
+#define DMA_THRESH_32W		0x0	/* not described in doc, but exists. */
 
 
 /*
@@ -399,6 +417,7 @@
 #define BD_FLG_IP_SUM		0x02
 #define BD_FLG_END		0x04
 #define BD_FLG_JUMBO		0x10
+#define BD_FLG_COAL_NOW		0x800
 #define BD_FLG_MINI		0x1000
 
 
@@ -407,6 +426,7 @@
  */
 #define RCB_FLG_TCP_UDP_SUM	0x01
 #define RCB_FLG_IP_SUM		0x02
+#define RCB_FLG_NO_PSEUDO_HDR	0x08
 #define RCB_FLG_VLAN_ASSIST	0x10
 #define RCB_FLG_COAL_INT_ONLY	0x20
 #define RCB_FLG_TX_HOST_RING	0x40
@@ -561,12 +581,29 @@
 	aceaddr	stats2_ptr;
 };
 
+#if defined(CONFIG_X86) || defined(CONFIG_PPC)
+/* Intel has null pci_unmap_single, no reasons to remember mapping. */
+#define DUMMY_PCI_UNMAP
+#endif
 
 struct ring_info {
 	struct sk_buff		*skb;
+#ifndef DUMMY_PCI_UNMAP
 	dma_addr_t		mapping;
+#endif
 };
 
+/* Funny... As soon as we add maplen on alpha, it starts to work
+ * much slower. Hmm... is it because struct does not fit to one cacheline?
+ * So, split tx_ring_info.
+ */
+struct tx_ring_info {
+	struct sk_buff		*skb;
+#ifndef DUMMY_PCI_UNMAP
+	dma_addr_t		mapping;
+	int			maplen;
+#endif
+};
 
 /*
  * struct ace_skb holding the rings of skb's. This is an awful lot of
@@ -575,7 +612,7 @@
  */
 struct ace_skb
 {
-	struct ring_info	tx_skbuff[TX_RING_ENTRIES];
+	struct tx_ring_info	tx_skbuff[TX_RING_ENTRIES];
 	struct ring_info	rx_std_skbuff[RX_STD_RING_ENTRIES];
 	struct ring_info	rx_mini_skbuff[RX_MINI_RING_ENTRIES];
 	struct ring_info	rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES];
@@ -605,11 +642,10 @@
 	/*
 	 * TX elements
 	 */
-	struct tx_desc		*tx_ring
-				__attribute__ ((aligned (SMP_CACHE_BYTES)));
-	struct timer_list	timer;		/* used by TX handling only */
+	struct tx_desc		*tx_ring;
 	u32			tx_prd;
-	volatile u32		tx_full, tx_ret_csm;
+	volatile u32		tx_ret_csm;
+	struct timer_list	timer;
 
 	/*
 	 * RX elements
@@ -657,6 +693,22 @@
 };
 
 
+#define TX_RESERVED	MAX_SKB_FRAGS
+
+static inline int tx_space (u32 csm, u32 prd)
+{
+	return (csm - prd - 1) & (TX_RING_ENTRIES - 1);
+}
+
+#define tx_free(ap) 		tx_space((ap)->tx_ret_csm, (ap)->tx_prd)
+
+#if MAX_SKB_FRAGS
+#define tx_ring_full(csm, prd)	(tx_space(csm, prd) <= TX_RESERVED)
+#else
+#define tx_ring_full		0
+#endif
+
+
 static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
 {
 	unsigned long baddr = (unsigned long) addr;
@@ -717,14 +769,10 @@
 static int ace_open(struct net_device *dev);
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int ace_close(struct net_device *dev);
-static void ace_timer(unsigned long data);
 static void ace_tasklet(unsigned long dev);
 static void ace_dump_trace(struct ace_private *ap);
 static void ace_set_multicast_list(struct net_device *dev);
 static int ace_change_mtu(struct net_device *dev, int new_mtu);
-#ifdef SKB_RECYCLE
-extern int ace_recycle(struct sk_buff *skb);
-#endif
 static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static int ace_set_mac_addr(struct net_device *dev, void *p);
 static void ace_set_rxtx_parms(struct net_device *dev, int jumbo);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/aironet4500_card.c linux/drivers/net/aironet4500_card.c
--- v2.4.3/linux/drivers/net/aironet4500_card.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/aironet4500_card.c	Thu Apr 19 09:34:52 2001
@@ -128,17 +128,12 @@
 //		request_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
 //		request_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
 
-//		pci_write_config_word(pdev, PCI_COMMAND, 0);
-		udelay(10000);
+		mdelay(10);
 
 		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-		new_command = pci_command |0x100 | PCI_COMMAND_MEMORY|PCI_COMMAND_IO;
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled this"
-				   " device!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_command, new_command);
+		new_command = pci_command | PCI_COMMAND_SERR;
+		if (pci_command != new_command)
 			pci_write_config_word(pdev, PCI_COMMAND, new_command);
-		}
 
 
 /*		if (device == PCI_DEVICE_AIRONET_4800)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c
--- v2.4.3/linux/drivers/net/am79c961a.c	Tue Feb 13 13:15:04 2001
+++ linux/drivers/net/am79c961a.c	Thu Apr 12 12:15:25 2001
@@ -637,7 +637,7 @@
 
 static void __init am79c961_banner(void)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 
 	if (net_debug && version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/apne.c linux/drivers/net/apne.c
--- v2.4.3/linux/drivers/net/apne.c	Mon Nov 27 17:11:26 2000
+++ linux/drivers/net/apne.c	Thu Apr 19 09:34:52 2001
@@ -116,10 +116,10 @@
 #define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
 
 
-static const char *version =
+static const char version[] =
     "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
 
-static int apne_owned = 0;	/* signal if card already owned */
+static int apne_owned;	/* signal if card already owned */
 
 int __init apne_probe(struct net_device *dev)
 {
@@ -173,7 +173,7 @@
 #ifndef MANUAL_HWADDR0
     int neX000, ctron;
 #endif
-    static unsigned version_printed = 0;
+    static unsigned version_printed;
     static u32 pcmcia_offsets[16]={
                 0,   1+GAYLE_ODD,   2,   3+GAYLE_ODD,
                 4,   5+GAYLE_ODD,   6,   7+GAYLE_ODD,
diff -u --recursive --new-file v2.4.3/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c
--- v2.4.3/linux/drivers/net/appletalk/cops.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/appletalk/cops.c	Wed Apr 18 14:40:05 2001
@@ -98,7 +98,7 @@
 static int io = 0x240;		/* Default IO for Dayna */
 static int irq = 5;		/* Default IRQ */
 #else
-static int io = 0;		/* Default IO for Dayna */
+static int io;			/* Default IO for Dayna */
 #endif
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c
--- v2.4.3/linux/drivers/net/appletalk/ipddp.c	Sun Dec  3 17:45:22 2000
+++ linux/drivers/net/appletalk/ipddp.c	Fri Apr 13 20:26:07 2001
@@ -20,12 +20,9 @@
  *      Director, National Security Agency.
  *
  *      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 = 
-	"ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -39,7 +36,9 @@
 
 #include "ipddp.h"		/* Our stuff */
 
-static struct ipddp_route *ipddp_route_list = NULL;
+static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+
+static struct ipddp_route *ipddp_route_list;
 
 #ifdef CONFIG_IPDDP_ENCAP
 static int ipddp_mode = IPDDP_ENCAP;
@@ -47,12 +46,6 @@
 static int ipddp_mode = IPDDP_DECAP;
 #endif
 
-/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef IPDDP_DEBUG
-#define IPDDP_DEBUG 1
-#endif
-static unsigned int ipddp_debug = IPDDP_DEBUG;
-
 /* Index to functions, as function prototypes. */
 static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
 static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
@@ -64,12 +57,12 @@
 
 static int __init ipddp_init(struct net_device *dev)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 
 	SET_MODULE_OWNER(dev);
 
-	if (ipddp_debug && version_printed++ == 0)
-                printk("%s", version);
+	if (version_printed++ == 0)
+                printk(version);
 
 	/* Let the user now what mode we are in */
 	if(ipddp_mode == IPDDP_ENCAP)
@@ -193,25 +186,23 @@
 static int ipddp_create(struct ipddp_route *new_rt)
 {
         struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
-	struct ipddp_route *test;
 
-        if(rt == NULL)
+        if (rt == NULL)
                 return -ENOMEM;
 
         rt->ip = new_rt->ip;
         rt->at = new_rt->at;
         rt->next = NULL;
-        rt->dev = atrtr_get_dev(&rt->at);
-        if(rt->dev == NULL)
-        {
-        	kfree(rt);
-                return (-ENETUNREACH);
+        if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
+		kfree(rt);
+                return -ENETUNREACH;
         }
 
-	test = ipddp_find_route(rt);
-	if(test != NULL)
-		return (-EEXIST);
-	
+	if (ipddp_find_route(rt)) {
+		kfree(rt);
+		return -EEXIST;
+	}
+
         rt->next = ipddp_route_list;
         ipddp_route_list = rt;
 
@@ -307,11 +298,16 @@
 
 static void __exit ipddp_cleanup_module(void)
 {
+        struct ipddp_route *p;
+
 	unregister_netdev(&dev_ipddp);
         kfree(dev_ipddp.priv);
 
-	memset(&dev_ipddp, 0, sizeof(dev_ipddp));
-	dev_ipddp.init = ipddp_init;
+        while (ipddp_route_list) {
+                p = ipddp_route_list->next;
+                kfree(ipddp_route_list);
+                ipddp_route_list = p;
+        }
 }
 
 module_init(ipddp_init_module);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c
--- v2.4.3/linux/drivers/net/appletalk/ltpc.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/appletalk/ltpc.c	Wed Apr 18 14:40:05 2001
@@ -197,14 +197,14 @@
 */
 
 /* insmod-tweakable variables */
-static int debug=0;
+static int debug;
 #define DEBUG_VERBOSE 1
 #define DEBUG_UPPER 2
 #define DEBUG_LOWER 4
 
-static int io=0;
-static int irq=0;
-static int dma=0;
+static int io;
+static int irq;
+static int dma;
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -281,7 +281,7 @@
 
 /* the transmit queue itself */
 
-static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
+static struct xmitQel *xmQhd, *xmQtl;
 
 static void enQ(struct xmitQel *qel)
 {
@@ -489,7 +489,7 @@
 static unsigned char rescbuf[2] = {LT_GETRESULT,0};
 static unsigned char resdbuf[2];
 
-static int QInIdle=0;
+static int QInIdle;
 
 /* idle expects to be called with the IRQ line high -- either because of
  * an interrupt, or because the line is tri-stated
@@ -910,7 +910,7 @@
 	return 0;
 }
 
-static int ltpc_poll_counter = 0;
+static int ltpc_poll_counter;
 
 static void ltpc_poll(unsigned long l)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c
--- v2.4.3/linux/drivers/net/arcnet/arcnet.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/net/arcnet/arcnet.c	Wed Apr 18 14:40:06 2001
@@ -107,7 +107,7 @@
 
 void __init arcnet_init(void)
 {
-	static int arcnet_inited = 0;
+	static int arcnet_inited;
 	int count;
 
 	if (arcnet_inited++)
@@ -361,8 +361,6 @@
 	dev->get_stats = arcnet_get_stats;
 	dev->hard_header = arcnet_header;
 	dev->rebuild_header = arcnet_rebuild_header;
-
-	dev_init_buffers(dev);
 }
 
 
@@ -528,7 +526,7 @@
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 	int status = 0;		/* default is failure */
 	unsigned short type;
-	uint8_t daddr;
+	uint8_t daddr=0;
 
 	if (skb->nh.raw - skb->mac.raw != 2) {
 		BUGMSG(D_NORMAL,
diff -u --recursive --new-file v2.4.3/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c
--- v2.4.3/linux/drivers/net/arcnet/com20020-pci.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/arcnet/com20020-pci.c	Wed Apr 18 14:40:05 2001
@@ -44,12 +44,12 @@
 
 /* Module parameters */
 
-static int node = 0;
+static int node;
 static char *device;		/* use eg. device="arc1" to change name */
 static int timeout = 3;
-static int backplane = 0;
-static int clockp = 0;
-static int clockm = 0;
+static int backplane;
+static int clockp;
+static int clockm;
 
 MODULE_PARM(node, "i");
 MODULE_PARM(device, "s");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c
--- v2.4.3/linux/drivers/net/arcnet/com90io.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/arcnet/com90io.c	Wed Apr 18 14:40:05 2001
@@ -373,8 +373,8 @@
 
 /* Module parameters */
 
-static int io = 0x0;		/* use the insmod io= irq= shmem= options */
-static int irq = 0;
+static int io;			/* use the insmod io= irq= shmem= options */
+static int irq;
 static char *device;		/* use eg. device=arc1 to change name */
 
 MODULE_PARM(io, "i");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/arcnet/com90xx.c linux/drivers/net/arcnet/com90xx.c
--- v2.4.3/linux/drivers/net/arcnet/com90xx.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/arcnet/com90xx.c	Wed Apr 18 14:40:05 2001
@@ -610,9 +610,9 @@
 
 /* Module parameters */
 
-static int io = 0x0;		/* use the insmod io= irq= shmem= options */
-static int irq = 0;
-static int shmem = 0;
+static int io;			/* use the insmod io= irq= shmem= options */
+static int irq;
+static int shmem;
 static char *device;		/* use eg. device=arc1 to change name */
 
 MODULE_PARM(io, "i");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v2.4.3/linux/drivers/net/ariadne.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ariadne.c	Thu Apr 12 12:15:25 2001
@@ -121,7 +121,7 @@
 };
 
 #ifdef MODULE
-static struct ariadne_private *root_ariadne_dev = NULL;
+static struct ariadne_private *root_ariadne_dev;
 #endif
 
 static int ariadne_open(struct net_device *dev);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c
--- v2.4.3/linux/drivers/net/ariadne2.c	Thu Jan  4 13:00:55 2001
+++ linux/drivers/net/ariadne2.c	Thu Apr 12 12:15:25 2001
@@ -62,7 +62,7 @@
 #define WORDSWAP(a)	((((a)>>8)&0xff) | ((a)<<8))
 
 #ifdef MODULE
-static struct net_device *root_ariadne2_dev = NULL;
+static struct net_device *root_ariadne2_dev;
 #endif
 
 static const struct card_info {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c
--- v2.4.3/linux/drivers/net/arlan-proc.c	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/arlan-proc.c	Thu Apr 12 12:15:25 2001
@@ -1031,7 +1031,7 @@
 
 
 
-static struct ctl_table_header *arlan_device_sysctl_header = NULL;
+static struct ctl_table_header *arlan_device_sysctl_header;
 
 int init_arlan_proc(void)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.4.3/linux/drivers/net/atari_bionet.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/atari_bionet.c	Thu Apr 19 09:34:52 2001
@@ -79,7 +79,7 @@
 
 #define MAX_POLL_TIME	10
 
-static char *version =
+static char version[] =
 	"bionet.c:v1.0 06-feb-96 (c) Hartmut Laue.\n";
 
 #include <linux/module.h>
@@ -327,8 +327,8 @@
 int __init 
 bionet_probe(struct net_device *dev){
 	unsigned char station_addr[6];
-	static unsigned version_printed = 0;
-	static int no_more_found = 0; /* avoid "Probing for..." printed 4 times */
+	static unsigned version_printed;
+	static int no_more_found;	/* avoid "Probing for..." printed 4 times */
 	int i;
 
 	if (!MACH_IS_ATARI || no_more_found)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c
--- v2.4.3/linux/drivers/net/atari_pamsnet.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/atari_pamsnet.c	Thu Apr 12 12:15:25 2001
@@ -569,9 +569,9 @@
 	HADDR *hwaddr;
 
 	unsigned char station_addr[6];
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	/* avoid "Probing for..." printed 4 times - the driver is supporting only one adapter now! */
-	static int no_more_found = 0;
+	static int no_more_found;
 
 	if (no_more_found)
 		return -ENODEV;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v2.4.3/linux/drivers/net/atarilance.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/atarilance.c	Fri Apr 20 11:54:22 2001
@@ -42,7 +42,7 @@
 
 */
 
-static char *version = "atarilance.c: v1.3 04/04/96 "
+static char version[] = "atarilance.c: v1.3 04/04/96 "
 					   "Roman.Hodek@informatik.uni-erlangen.de\n";
 
 #include <linux/module.h>
@@ -375,8 +375,8 @@
 
 int __init atarilance_probe( struct net_device *dev )
 {	
-    int i;
-	static int found = 0;
+	int i;
+	static int found;
 
 	SET_MODULE_OWNER(dev);
 
@@ -458,7 +458,7 @@
 	struct lance_private	*lp;
 	struct lance_ioreg		*IO;
 	int 					i;
-	static int 				did_version = 0;
+	static int 				did_version;
 	unsigned short			save1, save2;
 
 	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
diff -u --recursive --new-file v2.4.3/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.4.3/linux/drivers/net/atp.c	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/atp.c	Thu Apr 12 12:15:25 2001
@@ -209,7 +209,7 @@
 
 
 /* A list of all installed ATP devices, for removing the driver module. */
-static struct net_device *root_atp_dev = NULL;
+static struct net_device *root_atp_dev;
 
 /* Check for a network adapter of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
@@ -584,7 +584,7 @@
 	struct net_device *dev = (struct net_device *)dev_instance;
 	struct net_local *lp;
 	long ioaddr;
-	static int num_tx_since_rx = 0;
+	static int num_tx_since_rx;
 	int boguscount = max_interrupt_work;
 
 	if (dev == NULL) {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c
--- v2.4.3/linux/drivers/net/bagetlance.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/bagetlance.c	Thu Apr 12 12:15:25 2001
@@ -471,7 +471,7 @@
 int __init bagetlance_probe( struct net_device *dev )
 
 {	int i;
-	static int found = 0;
+	static int found;
 
 	SET_MODULE_OWNER(dev);
 
@@ -519,7 +519,7 @@
 	struct lance_private	*lp;
 	struct lance_ioreg		*IO;
 	int 					i;
-	static int 				did_version = 0;
+	static int 				did_version;
 	unsigned short			save1, save2;
 
 	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
diff -u --recursive --new-file v2.4.3/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.4.3/linux/drivers/net/cs89x0.c	Tue Mar  6 19:28:34 2001
+++ linux/drivers/net/cs89x0.c	Thu Apr 12 12:16:35 2001
@@ -130,7 +130,6 @@
 #include <asm/dma.h>
 #endif
 #include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/spinlock.h>
 
 #include <linux/netdevice.h>
@@ -361,7 +360,7 @@
 cs89x0_probe1(struct net_device *dev, int ioaddr)
 {
 	struct net_local *lp;
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	int i;
 	unsigned rev_type = 0;
 	int eeprom_buff[CHKSUM_LEN];
@@ -1590,14 +1589,14 @@
  * avoid breaking someone's startup scripts 
  */
 
-static int io=0;
-static int irq=0;
-static int debug=0;
+static int io;
+static int irq;
+static int debug;
 static char media[8];
 static int duplex=-1;
 
-static int use_dma = 0;			/* These generate unused var warnings if ALLOW_DMA = 0 */
-static int dma=0;
+static int use_dma;			/* These generate unused var warnings if ALLOW_DMA = 0 */
+static int dma;
 static int dmasize=16;			/* or 64 */
 
 MODULE_PARM(io, "i");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c
--- v2.4.3/linux/drivers/net/daynaport.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/daynaport.c	Thu Apr 12 12:15:25 2001
@@ -250,12 +250,12 @@
 
 int __init mac8390_probe(struct net_device *dev)
 {
-	static int slots = 0;
+	static int slots;
 	volatile unsigned short *i;
 	volatile unsigned char *p;
 	int plen;
 	int id;
-	static struct nubus_dev* ndev = NULL;
+	static struct nubus_dev* ndev;
 
 	/* Find the first card that hasn't already been seen */
 	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
diff -u --recursive --new-file v2.4.3/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.4.3/linux/drivers/net/de4x5.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/de4x5.c	Fri Apr 13 20:26:07 2001
@@ -429,11 +429,17 @@
                            <mporter@eng.mcd.mot.com>
                           Remove double checking for DEBUG_RX in de4x5_dbg_rx()
 			   from report by <geert@linux-m68k.org>
- 
+      0.546  22-Feb-01    Fixes Alpha XP1000 oops.  The srom_search function
+                           was causing a page fault when initializing the
+                           variable 'pb', on a non de4x5 PCI device, in this
+                           case a PCI bridge (DEC chip 21152). The value of
+                           'pb' is now only initialized if a de4x5 chip is
+                           present. 
+                           <france@handhelds.org>  
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -585,7 +591,7 @@
 #ifdef DE4X5_PARM
 static char *args = DE4X5_PARM;
 #else
-static char *args = NULL;
+static char *args;
 #endif
 
 struct parameters {
@@ -666,7 +672,7 @@
 #define DESC_ALIGN
 
 #ifndef DEC_ONLY                        /* See README.de4x5 for using this */
-static int dec_only = 0;
+static int dec_only;
 #else
 static int dec_only = 1;
 #endif
@@ -1039,24 +1045,24 @@
 MODULE_PARM(dec_only, "i");
 MODULE_PARM(args, "s");
 # else
-static int loading_module = 0;
+static int loading_module;
 #endif /* MODULE */
 
 static char name[DE4X5_NAME_LENGTH + 1];
 #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
-static int lastEISA = 0;
+static int lastEISA;
 #  ifdef DE4X5_FORCE_EISA                 /* Force an EISA bus probe or not */
 static int forceEISA = 1;
 #  else
-static int forceEISA = 0;
+static int forceEISA;
 #  endif
 #endif
-static int num_de4x5s = 0;
-static int cfrv = 0, useSROM = 0;
+static int num_de4x5s;
+static int cfrv, useSROM;
 static int lastPCI = -1;
-static struct net_device *lastModule = NULL;
-static struct pci_dev *pdev = NULL;
+static struct net_device *lastModule;
+static struct pci_dev *pdev;
 
 /*
 ** List the SROM infoleaf functions and chipsets
@@ -2304,12 +2310,12 @@
 	/* Skip the pci_bus list entry */
 	if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue;
 
-	pb = this_dev->bus->number;
 	vendor = this_dev->vendor;
 	device = this_dev->device << 8;
 	if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
 
 	/* Get the chip configuration revision register */
+	pb = this_dev->bus->number;
 	pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv);
 
 	/* Set the device number information */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.4.3/linux/drivers/net/de600.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/de600.c	Thu Apr 19 09:34:52 2001
@@ -1,4 +1,4 @@
-static const char *version =
+static const char version[] =
 	"de600.c: $Revision: 1.40 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
 /*
  *	de600.c
@@ -265,14 +265,14 @@
 /*
  * D-Link driver variables:
  */
-static volatile int		rx_page		= 0;
+static volatile int		rx_page;
 
 #define TX_PAGES 2
 static volatile int		tx_fifo[TX_PAGES];
-static volatile int		tx_fifo_in = 0;
-static volatile int		tx_fifo_out = 0;
+static volatile int		tx_fifo_in;
+static volatile int		tx_fifo_out;
 static volatile int		free_tx_pages = TX_PAGES;
-static int			was_down = 0;
+static int			was_down;
 
 /*
  * Convenience macros/functions for D-Link adapter
@@ -597,7 +597,6 @@
 	}
 
 	skb = dev_alloc_skb(size+2);
-	restore_flags(flags);
 	if (skb == NULL) {
 		printk("%s: Couldn't allocate a sk_buff of size %d.\n",
 			dev->name, size);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.4.3/linux/drivers/net/de620.c	Tue Mar  6 19:28:34 2001
+++ linux/drivers/net/de620.c	Thu Apr 19 09:34:52 2001
@@ -38,7 +38,7 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *****************************************************************************/
-static const char *version =
+static const char version[] =
 	"de620.c: $Revision: 1.40 $,  Bjorn Ekwall <bj0rn@blox.se>\n";
 
 /***********************************************************************
@@ -183,8 +183,8 @@
  * Make a clone skip the Ethernet-address range check:
  *	insmod de620.o clone=1
  */
-static int bnc = 0;
-static int utp = 0;
+static int bnc;
+static int utp;
 static int io  = DE620_IO;
 static int irq = DE620_IRQ;
 static int clone = DE620_CLONE;
@@ -690,7 +690,6 @@
 		else { /* Yep! Go get it! */
 			skb_reserve(skb,2);	/* Align */
 			skb->dev = dev;
-			skb->used = 0;
 			/* skb->data points to the start of sk_buff data area */
 			buffer = skb_put(skb,size);
 			/* copy the packet into the buffer */
@@ -722,7 +721,7 @@
 static int adapter_init(struct net_device *dev)
 {
 	int i;
-	static int was_down = 0;
+	static int was_down;
 
 	if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
 		EIPRegister = NCTL0;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/declance.c linux/drivers/net/declance.c
--- v2.4.3/linux/drivers/net/declance.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/declance.c	Thu Apr 12 12:15:25 2001
@@ -1217,7 +1217,7 @@
 /* Find all the lance cards on the system and initialize them */
 static int __init dec_lance_probe(void)
 {
-	static int called = 0;
+	static int called;
 
 #ifdef MODULE
 	root_lance_dev = NULL;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.4.3/linux/drivers/net/defxx.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/defxx.c	Fri Apr 20 11:54:23 2001
@@ -414,14 +414,17 @@
 {
 	struct net_device *dev;
 	DFX_board_t	  *bp;			/* board pointer */
-	static int version_disp;
 	int err;
 
-	if (!version_disp)					/* display version info if adapter is found */
+#ifndef MODULE
+	static int version_disp;
+
+	if (!version_disp)	/* display version info if adapter is found */
 	{
-		version_disp = 1;				/* set display flag to TRUE so that */
-		printk(version);				/* we only display this string ONCE */
+		version_disp = 1;	/* set display flag to TRUE so that */
+		printk(version);	/* we only display this string ONCE */
 	}
+#endif
 
 	/*
 	 * init_fddidev() allocates a device structure with private data, clears the device structure and private data,
@@ -3384,6 +3387,11 @@
 static int __init dfx_init(void)
 {
 	int rc_pci, rc_eisa;
+
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 
 	rc_pci = pci_module_init(&dfx_driver);
 	if (rc_pci >= 0) dfx_have_pci = 1;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.4.3/linux/drivers/net/depca.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/depca.c	Fri Apr 13 20:26:07 2001
@@ -1818,9 +1818,7 @@
   ManCode[5]='\0';
 
   for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
-    const char * volatile lhs = ManCode;
-    const char * volatile rhs = signatures[i];		/* egcs-1.1.2 bug */
-    if (strstr(lhs, rhs) != NULL) {
+    if (strstr(ManCode, signatures[i]) != NULL) {
       strcpy(name,ManCode);
       status = 1;
     }
diff -u --recursive --new-file v2.4.3/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.4.3/linux/drivers/net/dgrs.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/dgrs.c	Thu Apr 12 12:15:25 2001
@@ -174,7 +174,7 @@
 static uchar	dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
 static uchar	dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
 static __u32	dgrs_ipxnet = -1;
-static int	dgrs_nicmode = 0;
+static int	dgrs_nicmode;
 
 /*
  *	Chain of device structures
diff -u --recursive --new-file v2.4.3/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- v2.4.3/linux/drivers/net/dmfe.c	Tue Mar 20 12:05:01 2001
+++ linux/drivers/net/dmfe.c	Wed Apr 25 16:14:08 2001
@@ -57,6 +57,14 @@
    Resource usage cleanups.
    Report driver version to user.
 
+   Tobias Ringstr÷m <zajbot@goteborg.utfors.se> :
+   Added additional proper locking
+   Rewrote the transmit code to actually use the ring buffer,
+   and to generate a lot fewer interrupts.
+
+   Frank Davis <fdavis112@juno.com>
+   Added SMP-safe locking mechanisms in addition to Andrew Morton's work
+
    TODO
 
    Implement pci_driver::suspend() and pci_driver::resume()
@@ -68,7 +76,7 @@
 
  */
 
-#define DMFE_VERSION "1.30 (June 11, 2000)"
+#define DMFE_VERSION "1.30p3 (April 17, 2001)"
 
 #include <linux/module.h>
 
@@ -88,12 +96,16 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include <asm/processor.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
+static char version[] __initdata =
+KERN_INFO "Davicom DM91xx net driver, version " DMFE_VERSION "\n";
+
 
 
 /* Board/System/Debug information/definition ---------------- */
@@ -108,6 +120,7 @@
 #define TX_MAX_SEND_CNT 0x1	/* Maximum tx packet per time */
 #define TX_DESC_CNT     0x10	/* Allocated Tx descriptors */
 #define RX_DESC_CNT     0x10	/* Allocated Rx descriptors */
+#define TX_IRQ_THR      12
 #define DESC_ALL_CNT    TX_DESC_CNT+RX_DESC_CNT
 #define TX_BUF_ALLOC    0x600
 #define RX_ALLOC_SIZE   0x620
@@ -187,7 +200,7 @@
 	u32 chip_id;		/* Chip vendor/Device ID */
 	u32 chip_revision;	/* Chip revision */
 	struct net_device *next_dev;	/* next device */
-
+	spinlock_t lock; /* Spinlock */
 	struct pci_dev *net_dev;	/* PCI device */
 
 	unsigned long ioaddr;		/* I/O base address */
@@ -207,8 +220,9 @@
 	struct rx_desc *first_rx_desc;
 	struct rx_desc *rx_insert_ptr;
 	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
-	u32 tx_packet_cnt;	/* transmitted packet count */
-	u32 tx_queue_cnt;	/* wait to send packet count */
+	int tx_int_pkt_num;	/* number of packets to transmit until
+				 * a transmit interrupt is requested */
+	u32 tx_live_cnt;	/* number of used/live tx slots */
 	u32 rx_avail_cnt;	/* available rx descriptor count */
 	u32 interval_rx_cnt;	/* rx packet count a callback time */
 
@@ -220,7 +234,7 @@
 	u8 link_failed;		/* Ever link failed */
 	u8 wait_reset;		/* Hardware failed, need to reset */
 	u8 in_reset_state;	/* Now driver in reset routine */
-	u8 rx_error_cnt;	/* recievd abnormal case count */
+	u8 rx_error_cnt;	/* recieved abnormal case count */
 	u8 dm910x_chk_mode;	/* Operating mode check */
 	struct timer_list timer;
 	struct net_device_stats stats;	/* statistic counter */
@@ -240,13 +254,13 @@
 };
 
 /* Global variable declaration ----------------------------- */
-static int dmfe_debug = 0;
+static int dmfe_debug;
 static unsigned char dmfe_media_mode = 8;
-static u32 dmfe_cr6_user_set = 0;
+static u32 dmfe_cr6_user_set;
 
 /* For module input parameter */
-static int debug = 0;
-static u32 cr6set = 0;
+static int debug;
+static u32 cr6set;
 static unsigned char mode = 8;
 static u8 chkmode = 1;
 
@@ -364,6 +378,13 @@
 	u32 dev_rev;
 	u16 pci_command;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	DMFE_DBUG(0, "dmfe_probe()", 0);
 
 	/* Enable Master/IO access, Disable memory access */
@@ -380,14 +401,14 @@
 
 	/* Interrupt check */
 	if (pci_irqline == 0) {
-		printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n",
-		       pci_irqline);
+		printk(KERN_ERR "dmfe(%s): Interrupt wrong : IRQ=%d\n",
+		       pdev->slot_name, pci_irqline);
 		goto err_out;
 	}
 
 	/* iobase check */
-	if (pci_iobase == 0) {
-		printk(KERN_ERR "dmfe: I/O base is zero\n");
+	if (pci_iobase == 0 || pci_resource_len(pdev, 0) == 0) {
+		printk(KERN_ERR "dmfe(%s): I/O base is zero\n", pdev->slot_name);
 		goto err_out;
 	}
 
@@ -404,20 +425,17 @@
 	pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
 
 	/* Init network device */
-	dev = init_etherdev(NULL, sizeof(*db));
+	dev = alloc_etherdev(sizeof(*db));
 	if (dev == NULL)
 		goto err_out;
 	SET_MODULE_OWNER(dev);
 
-	/* IO range check */
-	if (!request_region(pci_iobase, CHK_IO_SIZE(pdev, dev_rev), dev->name)) {
-		printk(KERN_ERR "dmfe: I/O conflict : IO=%lx Range=%x\n",
-		       pci_iobase, CHK_IO_SIZE(pdev, dev_rev));
+	if (pci_request_regions(pdev, "dmfe"))
 		goto err_out_netdev;
-	}
 
 	db = dev->priv;
 	pci_set_drvdata(pdev, dev);
+	spin_lock_init(&db->lock);
 
 	db->chip_id = ent->driver_data;
 	db->ioaddr = pci_iobase;
@@ -442,10 +460,23 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = db->srom[20 + i];
 
+	i = register_netdev(dev);
+	if (i)
+		goto err_out_res;
+
+	printk(KERN_INFO "%s: Davicom DM%04lx at 0x%lx,",
+	       dev->name,
+	       ent->driver_data >> 16,
+	       pci_iobase);
+	for (i = 0; i < 6; i++)
+		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(", IRQ %d\n", pci_irqline);
+
 	return 0;
 
+err_out_res:
+	pci_release_regions(pdev);
 err_out_netdev:
-	unregister_netdev(dev);
 	kfree(dev);
 err_out:
 	return -ENODEV;
@@ -462,7 +493,7 @@
 	db = dev->priv;
 
 	unregister_netdev(dev);
-	release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision));
+	pci_release_regions(pdev);
 	kfree(dev);	/* free board information */
 
 	pci_set_drvdata(pdev, NULL);
@@ -509,8 +540,8 @@
 
 	/* system variable init */
 	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
-	db->tx_packet_cnt = 0;
-	db->tx_queue_cnt = 0;
+	db->tx_int_pkt_num = TX_IRQ_THR;
+	db->tx_live_cnt = 0;
 	db->rx_avail_cnt = 0;
 	db->link_failed = 0;
 	db->wait_reset = 0;
@@ -552,7 +583,7 @@
 {
 	struct dmfe_board_info *db = dev->priv;
 	u32 ioaddr = db->ioaddr;
-
+	
 	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
 
 	/* Reset DM910x board : need 32 PCI clock to complete */
@@ -611,46 +642,41 @@
 {
 	struct dmfe_board_info *db = dev->priv;
 	struct tx_desc *txptr;
+	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_start_xmit", 0);
- 
-	netif_stop_queue(dev);
+	spin_lock_irqsave(&db->lock, flags);
 	
-	/* Too large packet check */
-	if (skb->len > MAX_PACKET_SIZE) {
-		printk(KERN_ERR "%s: oversized frame (%d bytes) for transmit.\n", dev->name, (u16) skb->len);
-		dev_kfree_skb(skb);
-		return 0;
-	}
-	/* No Tx resource check, it never happen nromally */
-	if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
-		return 1;
-	}
-
 	/* transmit this packet */
 	txptr = db->tx_insert_ptr;
 	memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
-	txptr->tdes1 = 0xe1000000 | skb->len;
+	if (--db->tx_int_pkt_num < 0)
+	{
+		txptr->tdes1 = 0xe1000000 | skb->len;
+		db->tx_int_pkt_num = TX_IRQ_THR;
+	}
+	else
+		txptr->tdes1 = 0x61000000 | skb->len;
+
+	/* Transmit Packet Process */
+	txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */
+	outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
+	dev->trans_start = jiffies;     /* saved the time stamp */
 
 	/* Point to next transmit free descriptor */
-	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
+	txptr = (struct tx_desc *)txptr->next_tx_desc;
 
-	/* Transmit Packet Process */
-	if (db->tx_packet_cnt < TX_MAX_SEND_CNT) {
-		txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */
-		db->tx_packet_cnt++;	/* Ready to send count */
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
-	} else {
-		db->tx_queue_cnt++;	/* queue the tx packet */
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
-	}
+	if (txptr->tdes0 & 0x80000000)
+		netif_stop_queue(dev);
 
-	/* Tx resource check */
-	if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
-		netif_wake_queue(dev);
+	db->tx_insert_ptr = txptr;
+	db->tx_live_cnt++;
+
+	spin_unlock_irqrestore(&db->lock, flags);
 
 	/* free this SKB */
 	dev_kfree_skb(skb);
+
 	return 0;
 }
 
@@ -674,7 +700,7 @@
 
 	/* deleted timer */
 	del_timer_sync(&db->timer);
-
+	
 	/* free interrupt */
 	free_irq(dev->irq, dev);
 
@@ -699,6 +725,7 @@
 	struct tx_desc *txptr;
 	struct dmfe_board_info *db;
 	u32 ioaddr;
+	unsigned long flags;
 
 	if (!dev) {
 		DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0);
@@ -710,6 +737,8 @@
 
 	DMFE_DBUG(0, "dmfe_interrupt()", 0);
 
+	spin_lock_irqsave(&db->lock, flags);
+
 	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
 	outl(0, ioaddr + DCR7);
 
@@ -725,14 +754,15 @@
 		netif_stop_queue(dev);
 		db->wait_reset = 1;		/* Need to RESET */
 		outl(0, ioaddr + DCR7);		/* disable all interrupt */
+		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
+
 	/* Free the transmitted descriptor */
 	txptr = db->tx_remove_ptr;
-	while (db->tx_packet_cnt) {
+	while (db->tx_live_cnt > 0 && (txptr->tdes0 & 0x80000000) == 0)
+	{
 		/* printk("tdes0=%x\n", txptr->tdes0); */
-		if (txptr->tdes0 & 0x80000000)
-			break;
 		db->stats.tx_packets++;
 		
 		if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) {
@@ -748,21 +778,12 @@
 				db->stats.tx_errors++;
 		}
 		txptr = (struct tx_desc *) txptr->next_tx_desc;
-		db->tx_packet_cnt--;
+		db->tx_live_cnt--;
 	}
 	/* Update TX remove pointer to next */
 	db->tx_remove_ptr = (struct tx_desc *) txptr;
 
-	/* Send the Tx packet in queue */
-	if ((db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt) {
-		txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */
-		db->tx_packet_cnt++;	/* Ready to send count */
-		outl(0x1, ioaddr + DCR1);	/* Issue Tx polling command */
-		dev->trans_start = jiffies;	/* saved the time stamp */
-		db->tx_queue_cnt--;
- 	}
-	/* Resource available check */
-	if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
+	if ((db->tx_insert_ptr->tdes0 & 0x80000000) == 0)
 		netif_wake_queue(dev);
 
 	/* Received the coming packet */
@@ -786,6 +807,8 @@
 	else
 		db->cr7_data = 0x1a2cd;
 	outl(db->cr7_data, ioaddr + DCR7);
+
+	spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /*
@@ -877,19 +900,23 @@
 static void dmfe_set_filter_mode(struct net_device *dev)
 {
 	struct dmfe_board_info *db = dev->priv;
+	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
+	spin_lock_irqsave(&db->lock, flags);
 
 	if (dev->flags & IFF_PROMISC) {
 		DMFE_DBUG(0, "Enable PROM Mode", 0);
 		db->cr6_data |= CR6_PM | CR6_PBF;
 		update_cr6(db->cr6_data, db->ioaddr);
+		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
 	if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {
 		DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
 		db->cr6_data &= ~(CR6_PM | CR6_PBF);
 		db->cr6_data |= CR6_PAM;
+		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
 	DMFE_DBUG(0, "Set multicast address", dev->mc_count);
@@ -897,11 +924,17 @@
 		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
 	else
 		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */
+	spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /*
    Process the upper socket ioctl command
  */
+
+/* 
+ * The following function just returns 0. Shouldn't it do more? 
+ */
+
 static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
@@ -918,12 +951,16 @@
 	unsigned char tmp_cr12;
 	struct net_device *dev = (struct net_device *) data;
 	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+	unsigned long flags;
 
 	DMFE_DBUG(0, "dmfe_timer()", 0);
+	spin_lock_irqsave(&db->lock, flags);
 
 	/* Do reset now */
-	if (db->in_reset_state)
+	if (db->in_reset_state) {
+		spin_unlock_irqrestore(&db->lock, flags);
 		return;
+	}
 
 	/* Operating Mode Check */
 	if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET)) {
@@ -944,15 +981,18 @@
 
 	db->interval_rx_cnt = 0;
 
-	if (db->wait_reset | (db->tx_packet_cnt &&
-			      ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) | (db->rx_error_cnt > 3)) {
+	if (db->wait_reset ||
+	    (db->tx_live_cnt > 0 &&
+	     ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) ||
+	    (db->rx_error_cnt > 3)) {
 		/*
 		   printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start);
 		 */
-		DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
+		DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx monitor step1", 0);
 		dmfe_dynamic_reset(dev);
 		db->timer.expires = jiffies + DMFE_TIMER_WUT;
 		add_timer(&db->timer);
+		spin_unlock_irqrestore(&db->lock, flags);
 		return;
 	}
 	db->rx_error_cnt = 0;	/* Clear previos counter */
@@ -1008,6 +1048,7 @@
 	/* Timer active again */
 	db->timer.expires = jiffies + DMFE_TIMER_WUT;
 	add_timer(&db->timer);
+	spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /*
@@ -1036,8 +1077,8 @@
 	dmfe_free_rxbuffer(db);
 
 	/* system variable init */
-	db->tx_packet_cnt = 0;
-	db->tx_queue_cnt = 0;
+	db->tx_int_pkt_num = TX_IRQ_THR;
+	db->tx_live_cnt = 0;
 	db->rx_avail_cnt = 0;
 	db->link_failed = 0;
 	db->wait_reset = 0;
@@ -1207,11 +1248,17 @@
 	u32 *suptr;
 	int i;
 
-	DMFE_DBUG(0, "send_filetr_frame()", 0);
+	DMFE_DBUG(0, "send_filter_frame()", 0);
 
 	txptr = db->tx_insert_ptr;
 	suptr = (u32 *) txptr->tx_buf_ptr;
 
+	if (txptr->tdes0 & 0x80000000) {
+		printk(KERN_WARNING "%s: Too busy to send filter frame\n",
+		       dev->name);
+		return;
+	}
+
 	/* Node address */
 	addrptr = (u16 *) dev->dev_addr;
 	*suptr++ = addrptr[0];
@@ -1231,26 +1278,20 @@
 		*suptr++ = addrptr[2];
 	}
 
-	for (; i < 14; i++) {
+	for (i=0; i < 14; i++) 
 		*suptr++ = 0xffff;
 		*suptr++ = 0xffff;
 		*suptr++ = 0xffff;
-	}
+	
 	/* prepare the setup frame */
 	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
+	db->tx_live_cnt++;
 	txptr->tdes1 = 0x890000c0;
-	/* Resource Check and Send the setup packet */
-	if (!db->tx_packet_cnt) {
-		/* Resource Empty */
-		db->tx_packet_cnt++;
-		txptr->tdes0 = 0x80000000;
-		update_cr6(db->cr6_data | 0x2000, dev->base_addr);
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
-		update_cr6(db->cr6_data, dev->base_addr);
-	} else {
-		/* Put into TX queue */
-		db->tx_queue_cnt++;
-	}
+	/* Send the setup packet */
+	txptr->tdes0 = 0x80000000;
+	update_cr6(db->cr6_data | 0x2000, dev->base_addr);
+	outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
+	update_cr6(db->cr6_data, dev->base_addr);
 }
 
 /*
@@ -1593,6 +1634,11 @@
 {
 	int rc;
 	
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
+
 	DMFE_DBUG(0, "init_module() ", debug);
 
 	if (debug)
@@ -1616,8 +1662,6 @@
 	if (rc < 0)
 		return rc;
 
-	printk (KERN_INFO "Davicom DM91xx net driver loaded, version "
-		DMFE_VERSION "\n");
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v2.4.3/linux/drivers/net/e2100.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/e2100.c	Thu Apr 19 09:34:52 2001
@@ -31,7 +31,7 @@
 	If this happens, you must power down the machine for about 30 seconds.
 */
 
-static const char *version =
+static const char version[] =
 	"e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
@@ -140,7 +140,7 @@
 {
 	int i, status, retval;
 	unsigned char *station_addr = dev->dev_addr;
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 
 	if (!request_region(ioaddr, E21_IO_EXTENT, dev->name))
 		return -EBUSY;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.4.3/linux/drivers/net/eepro.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/eepro.c	Thu Apr 19 09:34:52 2001
@@ -96,7 +96,7 @@
 
 */
 
-static const char *version =
+static const char version[] =
 	"eepro.c: v0.12c 01/08/2000 aris@conectiva.com.br\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.4.3/linux/drivers/net/epic100.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/epic100.c	Fri Apr 20 11:54:23 2001
@@ -43,14 +43,6 @@
 
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version[] =
-"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/epic100.html\n";
-static const char version3[] =
-" (unofficial 2.4.x kernel port, version 1.1.6, January 11, 2001)\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -115,6 +107,14 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
+static char version2[] __devinitdata =
+"  http://www.scyld.com/network/epic100.html\n";
+static char version3[] __devinitdata =
+"  (unofficial 2.4.x kernel port, version 1.1.7, April 17, 2001)\n";
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
 MODULE_PARM(debug, "i");
@@ -337,7 +337,6 @@
 				    const struct pci_device_id *ent)
 {
 	static int card_idx = -1;
-	static int printed_version;
 	long ioaddr;
 	int chip_idx = (int) ent->driver_data;
 	int irq;
@@ -347,11 +346,15 @@
 	void *ring_space;
 	dma_addr_t ring_dma;
 
-	card_idx++;
-	
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
 	if (!printed_version++)
 		printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
 			version, version2, version3);
+#endif
+	
+	card_idx++;
 	
 	i = pci_enable_device(pdev);
 	if (i)
@@ -1440,6 +1443,12 @@
 
 static int __init epic_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
+		version, version2, version3);
+#endif
+
 	return pci_module_init (&epic_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.4.3/linux/drivers/net/eql.c	Tue Mar 20 12:05:01 2001
+++ linux/drivers/net/eql.c	Wed Apr 18 14:40:06 2001
@@ -240,8 +240,6 @@
 	 *	eql-generic values. 
 	 */
 
-	dev_init_buffers(dev);
-	
 	/*
 	 *	Now we undo some of the things that eth_setup does
 	 * 	that we don't like 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/es3210.c linux/drivers/net/es3210.c
--- v2.4.3/linux/drivers/net/es3210.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/es3210.c	Thu Apr 19 09:34:52 2001
@@ -45,7 +45,7 @@
 
 */
 
-static const char *version =
+static const char version[] =
 	"es3210.c: Driver revision v0.03, 14/09/96\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.4.3/linux/drivers/net/eth16i.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/net/eth16i.c	Thu Apr 19 09:34:52 2001
@@ -434,7 +434,7 @@
 
 static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
 
-static char *cardname = "ICL EtherTeam 16i/32";
+static char cardname[] = "ICL EtherTeam 16i/32";
 
 int __init eth16i_probe(struct net_device *dev)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- v2.4.3/linux/drivers/net/ethertap.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ethertap.c	Thu Apr 12 12:15:25 2001
@@ -43,7 +43,7 @@
 static void set_multicast_list(struct net_device *dev);
 #endif
 
-static int ethertap_debug = 0;
+static int ethertap_debug;
 
 static struct net_device *tap_map[32];	/* Returns the tap device for a given netlink */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.4.3/linux/drivers/net/ewrk3.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/net/ewrk3.c	Thu Apr 12 12:15:25 2001
@@ -330,12 +330,12 @@
 #else
 static u_char irq[] =
 {5, 0, 10, 3, 11, 9, 15, 12};
-static int autoprobed = 0, loading_module = 0;
+static int autoprobed, loading_module;
 
 #endif				/* MODULE */
 
 static char name[EWRK3_STRLEN + 1];
-static int num_ewrk3s = 0, num_eth = 0;
+static int num_ewrk3s, num_eth;
 
 /*
    ** Miscellaneous defines...
diff -u --recursive --new-file v2.4.3/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- v2.4.3/linux/drivers/net/fc/iph5526.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/fc/iph5526.c	Wed Apr 18 14:40:05 2001
@@ -241,7 +241,7 @@
 	struct fc_info *fi = (struct fc_info *)dev->priv;
 #else
 	struct fc_info *fi;
-	static int count = 0;
+	static int count;
  
 	if(fc[count] != NULL) {
 		if (dev == NULL) {
@@ -4523,9 +4523,9 @@
 
 static struct net_device *dev_fc[MAX_FC_CARDS];
 
-static int io =  0;
-static int irq  = 0;
-static int bad  = 0;	/* 0xbad = bad sig or no reset ack */
+static int io;
+static int irq;
+static int bad;	/* 0xbad = bad sig or no reset ack */
 static int scsi_registered;
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.4.3/linux/drivers/net/fmv18x.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/net/fmv18x.c	Thu Apr 19 09:34:52 2001
@@ -31,7 +31,7 @@
     The Fujitsu FMV-181/182 user's guide
 */
 
-static const char *version =
+static const char version[] =
 	"fmv18x.c:v2.2.0 09/24/98  Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/gt96100eth.c linux/drivers/net/gt96100eth.c
--- v2.4.3/linux/drivers/net/gt96100eth.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/gt96100eth.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,1253 @@
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or support@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Ethernet driver for the MIPS GT96100 Advanced Communication Controller.
+ * 
+ */
+
+#ifndef __mips__
+#error This driver only works with MIPS architectures!
+#endif
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include "gt96100eth.h"
+
+#ifdef GT96100_DEBUG
+static int gt96100_debug = GT96100_DEBUG;
+#else
+static int gt96100_debug = 3;
+#endif
+
+// prototypes
+static void *dmaalloc(size_t size, dma_addr_t * dma_handle);
+static void dmafree(size_t size, void *vaddr);
+static int gt96100_add_hash_entry(struct net_device *dev,
+				  unsigned char *addr);
+static void read_mib_counters(struct gt96100_private *gp);
+static int read_MII(struct net_device *dev, u32 reg);
+static int write_MII(struct net_device *dev, u32 reg, u16 data);
+static void dump_MII(struct net_device *dev);
+static void update_stats(struct gt96100_private *gp);
+static void abort(struct net_device *dev, u32 abort_bits);
+static void hard_stop(struct net_device *dev);
+static void enable_ether_irq(struct net_device *dev);
+static void disable_ether_irq(struct net_device *dev);
+static int __init gt96100_probe1(struct net_device *dev, long ioaddr,
+				 int irq, int port_num);
+static int gt96100_init(struct net_device *dev);
+static int gt96100_open(struct net_device *dev);
+static int gt96100_close(struct net_device *dev);
+static int gt96100_tx(struct sk_buff *skb, struct net_device *dev);
+static int gt96100_rx(struct net_device *dev, u32 status);
+static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void gt96100_tx_timeout(struct net_device *dev);
+static void gt96100_set_rx_mode(struct net_device *dev);
+static struct net_device_stats *gt96100_get_stats(struct net_device *dev);
+
+static char version[] __devinitdata =
+    "gt96100eth.c:0.1 stevel@mvista.com\n";
+
+// FIX! Need real Ethernet addresses
+static unsigned char gt96100_station_addr[2][6] __devinitdata =
+    { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+{0x01, 0x02, 0x03, 0x04, 0x05, 0x07}
+};
+
+#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))
+
+#define RUN_AT(x) (jiffies + (x))
+
+// For reading/writing 32-bit words from/to DMA memory
+#define cpu_to_dma32 cpu_to_be32
+#define dma32_to_cpu be32_to_cpu
+
+/*
+ * Base address and interupt of the GT96100 ethernet controllers
+ */
+static struct {
+	unsigned int port;
+	int irq;
+} gt96100_iflist[NUM_INTERFACES] = {
+	{
+	GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, {
+	GT96100_ETH1_BASE, GT96100_ETHER1_IRQ}
+};
+
+/*
+  DMA memory allocation, derived from pci_alloc_consistent.
+*/
+static void *dmaalloc(size_t size, dma_addr_t * dma_handle)
+{
+	void *ret;
+
+	ret =
+	    (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA,
+				      get_order(size));
+
+	if (ret != NULL) {
+		dma_cache_inv((unsigned long) ret, size);
+		if (dma_handle != NULL)
+			*dma_handle = virt_to_phys(ret);
+
+		/* bump virtual address up to non-cached area */
+		ret = KSEG1ADDR(ret);
+	}
+
+	return ret;
+}
+
+static void dmafree(size_t size, void *vaddr)
+{
+	vaddr = KSEG0ADDR(vaddr);
+	free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+static int read_MII(struct net_device *dev, u32 reg)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	int timedout = 20;
+	u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) |
+	    (reg << smirRegAdBit);
+
+	// wait for last operation to complete
+	while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
+		// snooze for 1 msec and check again
+#if 0
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(10 * HZ / 10000);
+#else
+		mdelay(1);
+#endif
+
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: read_MII busy timeout!!\n",
+			       dev->name);
+			return -1;
+		}
+	}
+
+	GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
+
+	timedout = 20;
+	// wait for read to complete
+	while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) {
+		// snooze for 1 msec and check again
+#if 0
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(10 * HZ / 10000);
+#else
+		mdelay(1);
+#endif
+
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: read_MII timeout!!\n",
+			       dev->name);
+			return -1;
+		}
+	}
+
+	return (int) (smir & smirDataMask);
+}
+
+static int write_MII(struct net_device *dev, u32 reg, u16 data)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	int timedout = 20;
+	u32 smir =
+	    (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data;
+
+	// wait for last operation to complete
+	while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
+		// snooze for 1 msec and check again
+#if 0
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(10 * HZ / 10000);
+#else
+		mdelay(1);
+#endif
+
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: write_MII busy timeout!!\n",
+			       dev->name);
+			return -1;
+		}
+	}
+
+	GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
+	return 0;
+}
+
+
+static void dump_MII(struct net_device *dev)
+{
+	int i, val;
+
+	for (i = 0; i < 7; i++) {
+		if ((val = read_MII(dev, i)) >= 0)
+			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+	}
+	for (i = 16; i < 21; i++) {
+		if ((val = read_MII(dev, i)) >= 0)
+			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+	}
+}
+
+
+static int
+gt96100_add_hash_entry(struct net_device *dev, unsigned char *addr)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	u16 hashResult, stmp;
+	unsigned char ctmp, hash_ea[6];
+	u32 tblEntry, *tblEntryAddr;
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		// nibble swap
+		ctmp = nibswap(addr[i]);
+		// invert every nibble
+		hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) |
+		    ((ctmp & 2) << 1) | ((ctmp & 4) >> 1);
+		hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) |
+		    ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1);
+	}
+
+	if (gp->hash_mode == 0) {
+		hashResult = ((u16) hash_ea[0] & 0xfc) << 7;
+		stmp =
+		    ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f)
+						 << 2);
+		stmp ^=
+		    (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] <<
+							1);
+		stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8);
+		hashResult |= stmp;
+	} else {
+		return -1;	// don't support hash mode 1
+	}
+
+	tblEntryAddr =
+	    (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]);
+
+	for (i = 0; i < HASH_HOP_NUMBER; i++) {
+		if ((*tblEntryAddr & hteValid)
+		    && !(*tblEntryAddr & hteSkip)) {
+			// This entry is already occupied, go to next entry
+			tblEntryAddr += 2;
+		} else {
+			memset(tblEntryAddr, 0, 8);
+			tblEntry = hteValid | hteRD;
+			tblEntry |= (u32) addr[5] << 3;
+			tblEntry |= (u32) addr[4] << 11;
+			tblEntry |= (u32) addr[3] << 19;
+			tblEntry |= ((u32) addr[2] & 0x1f) << 27;
+			*(tblEntryAddr + 1) = cpu_to_dma32(tblEntry);
+			tblEntry = ((u32) addr[2] >> 5) & 0x07;
+			tblEntry |= (u32) addr[1] << 3;
+			tblEntry |= (u32) addr[0] << 11;
+			*tblEntryAddr = cpu_to_dma32(tblEntry);
+			break;
+		}
+	}
+
+	if (i >= HASH_HOP_NUMBER) {
+		printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n",
+		       dev->name);
+		return -1;	// Couldn't find an unused entry
+	}
+
+	return 0;
+}
+
+
+static void read_mib_counters(struct gt96100_private *gp)
+{
+	u32 *mib_regs = (u32 *) & gp->mib;
+	int i;
+
+	for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++)
+		mib_regs[i] =
+		    GT96100ETH_READ(gp,
+				    GT96100_ETH_MIB_COUNT_BASE +
+				    i * sizeof(u32));
+}
+
+
+static void update_stats(struct gt96100_private *gp)
+{
+	mib_counters_t *mib = &gp->mib;
+	struct net_device_stats *stats = &gp->stats;
+
+	read_mib_counters(gp);
+
+	stats->rx_packets = mib->totalFramesReceived;
+	stats->tx_packets = mib->framesSent;
+	stats->rx_bytes = mib->totalByteReceived;
+	stats->tx_bytes = mib->byteSent;
+	stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;
+	//the tx error counters are incremented by the ISR
+	//rx_dropped incremented by gt96100_rx
+	//tx_dropped incremented by gt96100_tx
+	stats->multicast = mib->multicastFramesReceived;
+	// Tx collisions incremented by ISR, so add in MIB Rx collisions
+	stats->collisions += mib->collision + mib->lateCollision;
+	stats->rx_length_errors = mib->oversizeFrames + mib->fragments;
+	// The RxError condition means the Rx DMA encountered a
+	// CPU owned descriptor, which, if things are working as
+	// they should, means the Rx ring has overflowed.
+	stats->rx_over_errors = mib->macRxError;
+	stats->rx_crc_errors = mib->cRCError;
+}
+
+static void abort(struct net_device *dev, u32 abort_bits)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	int timedout = 100;	// wait up to 100 msec for hard stop to complete
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: abort\n", dev->name);
+
+	// Return if neither Rx or Tx abort bits are set
+	if (!(abort_bits & (sdcmrAR | sdcmrAT)))
+		return;
+
+	// make sure only the Rx/Tx abort bits are set
+	abort_bits &= (sdcmrAR | sdcmrAT);
+
+	spin_lock(&gp->lock);
+
+	// abort any Rx/Tx DMA immediately
+	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: abort: SDMA comm = %x\n",
+		       dev->name, GT96100ETH_READ(gp,
+						  GT96100_ETH_SDMA_COMM));
+
+	// wait for abort to complete
+	while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) {
+		// snooze for 20 msec and check again
+#if 0
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(10 * HZ / 10000);
+#else
+		mdelay(1);
+#endif
+
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: abort timeout!!\n",
+			       dev->name);
+			break;
+		}
+	}
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name,
+		       timedout);
+
+	spin_unlock(&gp->lock);
+}
+
+
+static void hard_stop(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: hard stop\n", dev->name);
+
+	disable_ether_irq(dev);
+
+	abort(dev, sdcmrAR | sdcmrAT);
+
+	// disable port
+	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0);
+}
+
+
+static void enable_ether_irq(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	u32 intMask;
+
+	// unmask interrupts
+	GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK,
+			 icrRxBuffer | icrTxBufferLow | icrTxEndLow |
+			 icrRxError | icrTxErrorLow | icrRxOVR |
+			 icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 |
+			 icrMIIPhySTC);
+
+	// now route ethernet interrupts to GT Int0 (eth0 and eth1 will be
+	// sharing it).
+	// FIX! The kernel's irq code should do this
+	intMask = GT96100_READ(GT96100_INT0_HIGH_MASK);
+	intMask |= 1 << gp->port_num;
+	GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask);
+}
+
+static void disable_ether_irq(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	u32 intMask;
+
+	// FIX! The kernel's irq code should do this
+	intMask = GT96100_READ(GT96100_INT0_HIGH_MASK);
+	intMask &= ~(1 << gp->port_num);
+	GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask);
+
+	GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0);
+}
+
+
+/*
+ * Probe for a GT96100 ethernet controller.
+ */
+int __init gt96100_probe(struct net_device *dev)
+{
+	unsigned int base_addr = dev ? dev->base_addr : 0;
+	int i;
+
+#ifndef CONFIG_MIPS_GT96100ETH
+	return -ENODEV;
+#endif
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: gt96100_probe\n", dev->name);
+
+	if (base_addr >= KSEG0)	/* Check a single specified location. */
+		return gt96100_probe1(dev, base_addr, dev->irq, 0);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return -ENXIO;
+
+//	for (i = 0; i<NUM_INTERFACES; i++) {
+	for (i = NUM_INTERFACES - 1; i >= 0; i--) {
+		int base_addr = gt96100_iflist[i].port;
+#if 0
+		if (check_region(base_addr, GT96100_ETH_IO_SIZE)) {
+			printk(KERN_ERR
+			       "%s: gt96100_probe: ioaddr 0x%lx taken?\n",
+			       dev->name, base_addr);
+			continue;
+		}
+#endif
+		if (gt96100_probe1
+		    (dev, base_addr, gt96100_iflist[i].irq, i) == 0)
+			return 0;
+	}
+	return -ENODEV;
+}
+
+
+
+static int __init
+gt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num)
+{
+	static unsigned version_printed = 0;
+	struct gt96100_private *gp = NULL;
+	int i, retval;
+	u32 cpuConfig;
+
+	// FIX! probe for GT96100 by reading a suitable register
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n",
+		       ioaddr, irq);
+
+	request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH");
+
+	cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG);
+	if (cpuConfig & (1 << 12)) {
+		printk(KERN_ERR
+		       "gt96100_probe1: must be in Big Endian mode!\n");
+		retval = -ENODEV;
+		goto free_region;
+	}
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO
+		       "gt96100_probe1: chip in Big Endian mode - cool\n");
+
+	/* Allocate a new 'dev' if needed. */
+	if (dev == NULL)
+		dev = init_etherdev(0, sizeof(struct gt96100_private));
+
+	if (gt96100_debug && version_printed++ == 0)
+		printk(version);
+
+	if (irq < 0) {
+		printk(KERN_ERR
+		       "gt96100_probe1: irq unknown - probing not supported\n");
+		retval = -ENODEV;
+		goto free_region;
+	}
+
+	printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n",
+	       dev->name, ioaddr, irq);
+
+	/* private struct aligned and zeroed by init_etherdev */
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	memcpy(dev->dev_addr, gt96100_station_addr[port_num],
+	       sizeof(dev->dev_addr));
+
+	printk(KERN_INFO "%s: HW Address ", dev->name);
+	for (i = 0; i < sizeof(dev->dev_addr); i++) {
+		printk("%2.2x", dev->dev_addr[i]);
+		printk(i < 5 ? ":" : "\n");
+	}
+
+	/* Initialize our private structure. */
+	if (dev->priv == NULL) {
+
+		gp =
+		    (struct gt96100_private *) kmalloc(sizeof(*gp),
+						       GFP_KERNEL);
+		if (gp == NULL) {
+			retval = -ENOMEM;
+			goto free_region;
+		}
+
+		dev->priv = gp;
+	}
+
+	gp = dev->priv;
+
+	memset(gp, 0, sizeof(*gp));	// clear it
+
+	gp->port_num = port_num;
+	gp->io_size = GT96100_ETH_IO_SIZE;
+	gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
+	gp->phy_addr = port_num + 1;
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: gt96100_probe1, port %d\n",
+		       dev->name, gp->port_num);
+
+	// Allocate Rx and Tx descriptor rings
+	if (gp->rx_ring == NULL) {
+		// All descriptors in ring must be 16-byte aligned
+		gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE
+				       +
+				       sizeof(gt96100_td_t) * TX_RING_SIZE,
+				       &gp->rx_ring_dma);
+		if (gp->rx_ring == NULL) {
+			retval = -ENOMEM;
+			goto free_region;
+		}
+
+		gp->tx_ring =
+		    (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE);
+		gp->tx_ring_dma =
+		    gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE;
+	}
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO
+		       "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n",
+		       dev->name, gp->rx_ring, gp->tx_ring);
+
+	// Allocate Rx Hash Table
+	if (gp->hash_table == NULL) {
+		gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE,
+						   &gp->hash_table_dma);
+		if (gp->hash_table == NULL) {
+			dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE
+				+ sizeof(gt96100_td_t) * TX_RING_SIZE,
+				gp->rx_ring);
+			retval = -ENOMEM;
+			goto free_region;
+		}
+	}
+
+	if (gt96100_debug > 2)
+		printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n",
+		       dev->name, gp->hash_table);
+
+	spin_lock_init(&gp->lock);
+
+	dev->open = gt96100_open;
+	dev->hard_start_xmit = gt96100_tx;
+	dev->stop = gt96100_close;
+	dev->get_stats = gt96100_get_stats;
+	//dev->do_ioctl = gt96100_ioctl;
+	dev->set_multicast_list = gt96100_set_rx_mode;
+	dev->tx_timeout = gt96100_tx_timeout;
+	dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+	return 0;
+
+      free_region:
+	release_region(ioaddr, gp->io_size);
+	unregister_netdev(dev);
+	if (dev->priv != NULL)
+		kfree(dev->priv);
+	kfree(dev);
+	printk(KERN_ERR "%s: gt96100_probe1 failed.  Returns %d\n",
+	       dev->name, retval);
+	return retval;
+}
+
+
+static int gt96100_init(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	unsigned long flags;
+	u32 phyAD, ciu;
+	int i;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: dev=%p\n", dev->name, dev);
+
+	// Stop and disable Port
+	hard_stop(dev);
+
+	spin_lock_irqsave(&gp->lock, flags);
+
+	// First things first, set-up hash table
+	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);	// clear it
+	gp->hash_mode = 0;
+	// Add a single entry to hash table - our ethernet address
+	gt96100_add_hash_entry(dev, dev->dev_addr);
+	// Set-up DMA ptr to hash table
+	GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name,
+		       GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
+
+	// Setup Tx descriptor ring
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		gp->tx_ring[i].cmdstat = 0;	// CPU owns
+		gp->tx_ring[i].byte_cnt = 0;
+		gp->tx_ring[i].buff_ptr = 0;
+		gp->tx_ring[i].next =
+		    cpu_to_dma32(gp->tx_ring_dma +
+				 sizeof(gt96100_td_t) * (i + 1));
+	}
+	/* Wrap the ring. */
+	gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma);
+
+	// setup only the lowest priority TxCDP reg
+	GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0,
+			 gp->tx_ring_dma);
+	GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0);
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n",
+		       dev->name, GT96100ETH_READ(gp,
+						  GT96100_ETH_CURR_TX_DESC_PTR0));
+
+	// Setup Rx descriptor ring 
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		dma_addr_t rx_buff_dma;
+		gp->rx_ring[i].next =
+		    cpu_to_dma32(gp->rx_ring_dma +
+				 sizeof(gt96100_rd_t) * (i + 1));
+		if (gp->rx_buff[i] == NULL)
+			gp->rx_buff[i] =
+			    dmaalloc(PKT_BUF_SZ, &rx_buff_dma);
+		else
+			rx_buff_dma = virt_to_phys(gp->rx_buff[i]);
+		if (gp->rx_buff[i] == NULL)
+			break;
+		gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma);
+		gp->rx_ring[i].buff_cnt_sz =
+		    cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit);
+		// Give ownership to device, enable interrupt
+		gp->rx_ring[i].cmdstat =
+		    cpu_to_dma32((u32) (rxOwn | rxEI));
+	}
+
+	if (i != RX_RING_SIZE) {
+		int j;
+		for (j = 0; j < RX_RING_SIZE; j++) {
+			if (gp->rx_buff[j]) {
+				dmafree(PKT_BUF_SZ, gp->rx_buff[j]);
+				gp->rx_buff[j] = NULL;
+			}
+		}
+		printk(KERN_ERR "%s: Rx ring allocation failed.\n",
+		       dev->name);
+		spin_unlock_irqrestore(&gp->lock, flags);
+		return -ENOMEM;
+	}
+
+	/* Wrap the ring. */
+	gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma);
+
+	// Set our MII PHY device address
+	phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);
+	phyAD &= ~(0x1f << (gp->port_num * 5));
+	phyAD |= gp->phy_addr << (gp->port_num * 5);
+	GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD);
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: PhyAD=%x\n", dev->name,
+		       GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
+
+	// Clear all the RxFDP and RXCDP regs...
+	for (i = 0; i < 4; i++) {
+		GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4,
+				 0);
+		GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4,
+				 0);
+	}
+	// and setup only the lowest priority RxFDP and RxCDP regs
+	GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0,
+			 gp->rx_ring_dma);
+	GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0,
+			 gp->rx_ring_dma);
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n",
+		       dev->name, GT96100ETH_READ(gp,
+						  GT96100_ETH_1ST_RX_DESC_PTR0),
+		       GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
+
+	// init Rx/Tx indeces and pkt counters
+	gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0;
+	gp->tx_count = 0;
+
+	// setup DMA
+
+	// FIX! this should be done by Kernel setup code
+	ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG);
+	ciu |= (0x0c << (gp->port_num * 2));	// set Ether DMA req priority to high
+	// FIX! setting the following bit causes the EV96100 board to hang!!!
+	//ciu |= (1 << (24+gp->port_num));   // pull Ethernet port out of Reset???
+	// FIX! endian mode???
+	ciu &= ~(1 << 31);	// set desc endianess to Big
+	GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu);
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name,
+		       ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
+
+	// We want the Rx/Tx DMA to write/read data to/from memory in
+	// Big Endian mode. Also set DMA Burst Size to 8 64Bit words.
+	// FIX! endian mode???
+	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,
+			 //sdcrBLMR | sdcrBLMT |
+			 (0xf << sdcrRCBit) | sdcrRIFB | (3 << sdcrBSZBit));
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: SDMA Config=%x\n", dev->name,
+		       GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
+
+	// start Rx DMA
+	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name,
+		       GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
+
+	// enable interrupts
+	enable_ether_irq(dev);
+
+	/*
+	 * Disable all Type-of-Service queueing. All Rx packets will be
+	 * treated normally and will be sent to the lowest priority
+	 * queue.
+	 *
+	 * Disable flow-control for now. FIX! support flow control?
+	 */
+	// clear all the MIB ctr regs
+	// Enable reg clear on read. FIX! desc of this bit is inconsistent
+	// in the GT-96100A datasheet.
+	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+			 pcxrFCTL | pcxrFCTLen | pcxrFLP);
+	read_mib_counters(gp);
+	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+			 pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode);
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name,
+		       GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
+
+	// enable this port (set hash size to 1/2K)
+	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_init: Port Config=%x\n", dev->name,
+		       GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
+
+	// we should now be receiving frames
+	if (gt96100_debug > 2)
+		dump_MII(dev);
+
+	spin_unlock_irqrestore(&gp->lock, flags);
+	return 0;
+}
+
+
+static int gt96100_open(struct net_device *dev)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_open: dev=%p\n", dev->name, dev);
+
+	if ((retval = request_irq(dev->irq, &gt96100_interrupt,
+				  SA_SHIRQ, dev->name, dev))) {
+		printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
+		       dev->irq);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	// Initialize and startup the GT-96100 ethernet port
+	if ((retval = gt96100_init(dev))) {
+		printk(KERN_ERR "%s: error in gt96100_init\n", dev->name);
+		free_irq(dev->irq, dev);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	netif_start_queue(dev);
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_open: Initialization done.\n",
+		       dev->name);
+
+	return 0;
+}
+
+static int gt96100_close(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	int i;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_close: dev=%p\n", dev->name, dev);
+
+	// stop the device
+	if (netif_device_present(dev)) {
+		netif_stop_queue(dev);
+		hard_stop(dev);
+	}
+	// free the Rx DMA buffers
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (gp->rx_buff[i]) {
+			dmafree(PKT_BUF_SZ, gp->rx_buff[i]);
+			gp->rx_buff[i] = NULL;
+		}
+	}
+
+	free_irq(dev->irq, dev);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static int gt96100_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	unsigned long flags;
+	int nextIn;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_tx: skb->len=%d, skb->data=%p\n",
+		       dev->name, skb->len, skb->data);
+
+	spin_lock_irqsave(&gp->lock, flags);
+
+	if (gp->tx_count >= TX_RING_SIZE) {
+		printk(KERN_WARNING
+		       "%s: Tx Ring full, refusing to send buffer.\n",
+		       dev->name);
+		gp->stats.tx_dropped++;
+		spin_unlock_irqrestore(&gp->lock, flags);
+		return 1;
+	}
+	// Prepare the Descriptor at tx_next_in
+	nextIn = gp->tx_next_in;
+
+	if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
+		printk(KERN_ERR "%s: gt96100_tx: TxOwn bit wrong!!\n",
+		       dev->name);
+	}
+
+	gp->tx_skbuff[nextIn] = skb;
+	gp->tx_ring[nextIn].byte_cnt =
+	    cpu_to_dma32(skb->len << tdByteCntBit);
+	gp->tx_ring[nextIn].buff_ptr =
+	    cpu_to_dma32(virt_to_phys(skb->data));
+	// Give ownership to device, set first and last desc, enable interrupt
+	// Setting of ownership bit must be *last*!
+	gp->tx_ring[nextIn].cmdstat =
+	    cpu_to_dma32((u32) (txOwn | txEI | txFirst | txLast));
+
+	// increment tx_next_in with wrap
+	gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE;
+	// If count is zero, DMA should be stopped, so restart
+	if (gp->tx_count == 0) {
+		if (GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) &
+		    psrTxLow) printk(KERN_WARNING
+				     "%s: Tx count zero but Tx queue running!\n",
+				     dev->name);
+		GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
+				 sdcmrERD | sdcmrTXDL);
+	}
+	// increment count and stop queue if full
+	if (++gp->tx_count == TX_RING_SIZE)
+		netif_stop_queue(dev);
+
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(&gp->lock, flags);
+
+	return 0;
+}
+
+
+static int gt96100_rx(struct net_device *dev, u32 status)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	struct sk_buff *skb;
+	int pkt_len, nextOut;
+	gt96100_rd_t *rd;
+	u32 cmdstat;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_rx: dev=%p, status = %x\n",
+		       dev->name, dev, status);
+
+	// Continue until we reach the current descriptor pointer
+	for (nextOut = gp->rx_next_out;
+	     nextOut !=
+	     (GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0) -
+	      gp->rx_ring_dma) / sizeof(gt96100_rd_t);
+	     nextOut = (nextOut + 1) % RX_RING_SIZE) {
+
+		rd = &gp->rx_ring[nextOut];
+		cmdstat = dma32_to_cpu(rd->cmdstat);
+
+		if (cmdstat & (u32) rxOwn) {
+			cmdstat &= ~((u32) rxOwn);
+			rd->cmdstat = cpu_to_dma32(cmdstat);
+			printk(KERN_ERR
+			       "%s: gt96100_rx: ownership bit wrong!\n",
+			       dev->name);
+		}
+		// must be first and last (ie only) buffer of packet
+		if (!(cmdstat & (u32) rxFirst)
+		    || !(cmdstat & (u32) rxLast)) {
+			printk(KERN_ERR
+			       "%s: gt96100_rx: desc not first and last!\n",
+			       dev->name);
+			continue;
+		}
+		// drop this received pkt if there were any errors
+		if ((cmdstat & (u32) rxErrorSummary)
+		    || (status & icrRxErrorQ0)) {
+			// update the detailed rx error counters that are not covered
+			// by the MIB counters.
+			if (cmdstat & (u32) rxOverrun)
+				gp->stats.rx_fifo_errors++;
+			continue;
+		}
+
+		pkt_len = dma32_to_cpu(rd->buff_cnt_sz) & rdByteCntMask;
+
+		/* Create new skb. */
+		skb = dev_alloc_skb(pkt_len + 2);
+		if (skb == NULL) {
+			printk(KERN_ERR
+			       "%s: Memory squeeze, dropping packet.\n",
+			       dev->name);
+			gp->stats.rx_dropped++;
+			continue;
+		}
+		skb->dev = dev;
+		skb_reserve(skb, 2);	/* 16 byte IP header align */
+		skb_put(skb, pkt_len);	/* Make room */
+		eth_copy_and_sum(skb, gp->rx_buff[nextOut], pkt_len, 0);
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);	/* pass the packet to upper layers */
+
+		// now we can release ownership of this desc back to device
+		cmdstat |= (u32) rxOwn;
+		rd->cmdstat = cpu_to_dma32(cmdstat);
+
+		dev->last_rx = jiffies;
+	}
+
+	gp->rx_next_out = nextOut;
+	return 0;
+}
+
+
+static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	u32 status;
+
+	if (dev == NULL) {
+		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
+		return;
+	}
+
+	status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE);
+	// ACK interrupts
+#if 0
+	GT96100ETH_CLRBIT(gp, GT96100_ETH_INT_CAUSE,
+			  icrEtherIntSum | icrRxBufferQ1 | icrRxBufferQ2 |
+			  icrRxBufferQ3 | icrRxBufferQ0 | icrTxBufferHigh |
+			  icrTxEndHigh | icrTxBufferLow | icrTxEndLow |
+			  icrTxErrorHigh | icrTxErrorLow | icrTxUdr);
+#else
+	GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
+#endif
+
+	if ((status & icrEtherIntSum) == 0) {
+		// not our interrupt
+		//printk("%s: isr: no ints? icr=%x,cp0_cause=%x\n",
+		//       dev->name, status, read_32bit_cp0_register(CP0_CAUSE));
+		return;
+	}
+
+	if (gt96100_debug > 3)
+		printk("%s: isr: entry, icr=%x\n", dev->name, status);
+
+	if (status & (icrRxBufferQ1 | icrRxBufferQ2 | icrRxBufferQ3)) {
+		printk(KERN_ERR "%s: isr: Rx intr in unused queues!?\n",
+		       dev->name);
+	}
+
+	if (status & icrRxBufferQ0) {
+		gt96100_rx(dev, status);
+	}
+
+	if (status & (icrTxBufferHigh | icrTxEndHigh)) {
+		printk(KERN_ERR "%s: isr: Tx intr in unused queue!?\n",
+		       dev->name);
+	}
+
+	if (status & icrMIIPhySTC) {
+		u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS);
+		printk("%s: port status:\n", dev->name);
+		printk
+		    ("%s:     %s MBit/s, %s-duplex, flow-control %s, link is %s,\n",
+		     dev->name, psr & psrSpeed ? "100" : "10",
+		     psr & psrDuplex ? "full" : "half",
+		     psr & psrFctl ? "disabled" : "enabled",
+		     psr & psrLink ? "up" : "down");
+		printk
+		    ("%s:     TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n",
+		     dev->name, psr & psrTxLow ? "running" : "stopped",
+		     psr & psrTxHigh ? "running" : "stopped",
+		     psr & psrTxInProg ? "on" : "off");
+		gp->last_psr = psr;
+	}
+
+	if (status & (icrTxBufferLow | icrTxEndLow)) {
+		int nextOut;
+		gt96100_td_t *td;
+		u32 cmdstat;
+
+		// Continue until we reach the current descriptor pointer
+		for (nextOut = gp->tx_next_out;
+		     nextOut !=
+		     (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) -
+		      gp->tx_ring_dma) / sizeof(gt96100_td_t);
+		     nextOut = (nextOut + 1) % TX_RING_SIZE) {
+
+			td = &gp->tx_ring[nextOut];
+			cmdstat = dma32_to_cpu(td->cmdstat);
+
+			if (gt96100_debug > 2)
+				printk("%s: isr: Tx desc cmdstat=%x\n",
+				       dev->name, cmdstat);
+
+			if (cmdstat & (u32) txOwn) {
+				cmdstat &= ~((u32) txOwn);
+				td->cmdstat = cpu_to_dma32(cmdstat);
+				printk(KERN_ERR
+				       "%s: isr: Tx ownership bit wrong!\n",
+				       dev->name);
+			}
+			// increment Tx error stats
+			if (cmdstat & (u32) txErrorSummary) {
+				if (gt96100_debug > 2)
+					printk
+					    ("%s: gt96100_interrupt: Tx error, cmdstat = %x\n",
+					     dev->name, cmdstat);
+				gp->stats.tx_errors++;
+				if (cmdstat & (u32) txReTxLimit)
+					gp->stats.collisions++;
+				if (cmdstat & (u32) txUnderrun)
+					gp->stats.tx_fifo_errors++;
+				if (cmdstat & (u32) txLateCollision)
+					gp->stats.tx_window_errors++;
+			}
+			// Wake the queue if the ring was full
+			if (gp->tx_count == TX_RING_SIZE)
+				netif_wake_queue(dev);
+
+			// decrement tx ring buffer count
+			if (gp->tx_count)
+				gp->tx_count--;
+
+			// free the skb
+			if (gp->tx_skbuff[nextOut]) {
+				if (gt96100_debug > 2)
+					printk
+					    ("%s: isr: good Tx, skb=%p\n",
+					     dev->name,
+					     gp->tx_skbuff[nextOut]);
+				dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
+				gp->tx_skbuff[nextOut] = NULL;
+			} else {
+				printk(KERN_ERR "%s: isr: no skb!\n",
+				       dev->name);
+			}
+		}
+
+		if (gp->tx_count == 0 && nextOut != gp->tx_next_in) {
+			// FIX! this should probably be a panic
+			printk(KERN_ERR
+			       "%s: isr: warning! Tx queue inconsistent\n",
+			       dev->name);
+		}
+
+		gp->tx_next_out = nextOut;
+
+		if ((status & icrTxEndLow) && gp->tx_count != 0) {
+			// we must restart the DMA
+			if (gt96100_debug > 2)
+				printk("%s: isr: Restarting Tx DMA\n",
+				       dev->name);
+			GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
+					 sdcmrERD | sdcmrTXDL);
+		}
+	}
+	// Now check TX errors (RX errors were handled in gt96100_rx)
+
+	if (status & icrTxErrorHigh) {
+		printk(KERN_ERR
+		       "%s: isr: Tx resource error in unused queue!?\n",
+		       dev->name);
+	}
+
+	if (status & icrTxErrorLow) {
+		printk(KERN_ERR "%s: isr: Tx resource error\n", dev->name);
+	}
+
+	if (status & icrTxUdr) {
+		printk(KERN_ERR "%s: isr: Tx underrun error\n", dev->name);
+	}
+
+	if (gt96100_debug > 3)
+		printk("%s: isr: exit, icr=%x\n",
+		       dev->name, GT96100ETH_READ(gp,
+						  GT96100_ETH_INT_CAUSE));
+}
+
+
+/*
+ * The Tx ring has been full longer than the watchdog timeout
+ * value, meaning that the interrupt routine has not been freeing
+ * up space in the Tx ring buffer.
+ */
+static void gt96100_tx_timeout(struct net_device *dev)
+{
+//    struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+
+	printk(KERN_ERR "%s: gt96100_tx_timeout: dev=%p\n", dev->name,
+	       dev);
+
+	// FIX! do something, like reset the device
+}
+
+
+static void gt96100_set_rx_mode(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	unsigned long flags;
+	struct dev_mc_list *mcptr;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_set_rx_mode: dev=%p, flags=%x\n",
+		       dev->name, dev, dev->flags);
+
+	// stop the Receiver DMA
+	abort(dev, sdcmrAR);
+
+	spin_lock_irqsave(&gp->lock, flags);
+
+	if (dev->flags & IFF_PROMISC)
+		GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG,
+				 pcrEN | pcrHS | pcrPM);
+
+	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);	// clear hash table
+	// Add our ethernet address
+	gt96100_add_hash_entry(dev, dev->dev_addr);
+
+	if (dev->mc_count) {
+		for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
+			gt96100_add_hash_entry(dev, mcptr->dmi_addr);
+		}
+	}
+	// restart Rx DMA
+	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
+
+	spin_unlock_irqrestore(&gp->lock, flags);
+}
+
+static struct net_device_stats *gt96100_get_stats(struct net_device *dev)
+{
+	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+	unsigned long flags;
+
+	if (gt96100_debug > 2)
+		printk("%s: gt96100_get_stats: dev=%p\n", dev->name, dev);
+
+	if (netif_device_present(dev)) {
+		spin_lock_irqsave(&gp->lock, flags);
+		update_stats(gp);
+		spin_unlock_irqrestore(&gp->lock, flags);
+	}
+
+	return &gp->stats;
+}
+
+module_init(gt96100_probe);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/gt96100eth.h linux/drivers/net/gt96100eth.h
--- v2.4.3/linux/drivers/net/gt96100eth.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/gt96100eth.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or support@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Ethernet driver definitions for the MIPS GT96100 Advanced
+ * Communication Controller.
+ * 
+ */
+#ifndef _GT96100ETH_H
+#define _GT96100ETH_H
+
+#include <linux/config.h>
+#include <asm/galileo-boards/gt96100.h>
+
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+#define PKT_BUF_SZ	1536	/* Size of each temporary Rx buffer. */
+
+#define RX_HASH_TABLE_SIZE 16384
+#define HASH_HOP_NUMBER 12
+
+#define NUM_INTERFACES 2
+
+#define GT96100ETH_TX_TIMEOUT HZ
+
+#define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG)
+#define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE)
+
+#ifdef CONFIG_MIPS_EV96100
+#define GT96100_ETHER0_IRQ 4
+#define GT96100_ETHER1_IRQ 4
+#else
+#define GT96100_ETHER0_IRQ -1
+#define GT96100_ETHER1_IRQ -1
+#endif
+
+#define GT96100ETH_READ(gp, offset) \
+    GT96100_READ((gp->port_offset + offset))
+
+#define GT96100ETH_WRITE(gp, offset, data) \
+    GT96100_WRITE((gp->port_offset + offset), data)
+
+#define GT96100ETH_SETBIT(gp, offset, bits) {\
+    u32 val = GT96100ETH_READ(gp, offset); val |= (u32)(bits); \
+    GT96100ETH_WRITE(gp, offset, val); }
+
+#define GT96100ETH_CLRBIT(gp, offset, bits) {\
+    u32 val = GT96100ETH_READ(gp, offset); val &= (u32)(~(bits)); \
+    GT96100ETH_WRITE(gp, offset, val); }
+
+
+/* Bit definitions of the SMI Reg */
+enum {
+	smirDataMask = 0xffff,
+	smirPhyAdMask = 0x1f << 16,
+	smirPhyAdBit = 16,
+	smirRegAdMask = 0x1f << 21,
+	smirRegAdBit = 21,
+	smirOpCode = 1 << 26,
+	smirReadValid = 1 << 27,
+	smirBusy = 1 << 28
+};
+
+/* Bit definitions of the Port Config Reg */
+enum pcr_bits {
+	pcrPM = 1,
+	pcrRBM = 2,
+	pcrPBF = 4,
+	pcrEN = 1 << 7,
+	pcrLPBKMask = 0x3 << 8,
+	pcrLPBKBit = 8,
+	pcrFC = 1 << 10,
+	pcrHS = 1 << 12,
+	pcrHM = 1 << 13,
+	pcrHDM = 1 << 14,
+	pcrHD = 1 << 15,
+	pcrISLMask = 0x7 << 28,
+	pcrISLBit = 28,
+	pcrACCS = 1 << 31
+};
+
+/* Bit definitions of the Port Config Extend Reg */
+enum pcxr_bits {
+	pcxrIGMP = 1,
+	pcxrSPAN = 2,
+	pcxrPAR = 4,
+	pcxrPRIOtxMask = 0x7 << 3,
+	pcxrPRIOtxBit = 3,
+	pcxrPRIOrxMask = 0x3 << 6,
+	pcxrPRIOrxBit = 6,
+	pcxrPRIOrxOverride = 1 << 8,
+	pcxrDPLXen = 1 << 9,
+	pcxrFCTLen = 1 << 10,
+	pcxrFLP = 1 << 11,
+	pcxrFCTL = 1 << 12,
+	pcxrMFLMask = 0x3 << 14,
+	pcxrMFLBit = 14,
+	pcxrMIBclrMode = 1 << 16,
+	pcxrSpeed = 1 << 18,
+	pcxrSpeeden = 1 << 19,
+	pcxrRMIIen = 1 << 20,
+	pcxrDSCPen = 1 << 21
+};
+
+/* Bit definitions of the Port Command Reg */
+enum pcmr_bits {
+	pcmrFJ = 1 << 15
+};
+
+
+/* Bit definitions of the Port Status Reg */
+enum psr_bits {
+	psrSpeed = 1,
+	psrDuplex = 2,
+	psrFctl = 4,
+	psrLink = 8,
+	psrPause = 1 << 4,
+	psrTxLow = 1 << 5,
+	psrTxHigh = 1 << 6,
+	psrTxInProg = 1 << 7
+};
+
+/* Bit definitions of the SDMA Config Reg */
+enum sdcr_bits {
+	sdcrRCMask = 0xf << 2,
+	sdcrRCBit = 2,
+	sdcrBLMR = 1 << 6,
+	sdcrBLMT = 1 << 7,
+	sdcrPOVR = 1 << 8,
+	sdcrRIFB = 1 << 9,
+	sdcrBSZMask = 0x3 << 12,
+	sdcrBSZBit = 12
+};
+
+/* Bit definitions of the SDMA Command Reg */
+enum sdcmr_bits {
+	sdcmrERD = 1 << 7,
+	sdcmrAR = 1 << 15,
+	sdcmrSTDH = 1 << 16,
+	sdcmrSTDL = 1 << 17,
+	sdcmrTXDH = 1 << 23,
+	sdcmrTXDL = 1 << 24,
+	sdcmrAT = 1 << 31
+};
+
+/* Bit definitions of the Interrupt Cause Reg */
+enum icr_bits {
+	icrRxBuffer = 1,
+	icrTxBufferHigh = 1 << 2,
+	icrTxBufferLow = 1 << 3,
+	icrTxEndHigh = 1 << 6,
+	icrTxEndLow = 1 << 7,
+	icrRxError = 1 << 8,
+	icrTxErrorHigh = 1 << 10,
+	icrTxErrorLow = 1 << 11,
+	icrRxOVR = 1 << 12,
+	icrTxUdr = 1 << 13,
+	icrRxBufferQ0 = 1 << 16,
+	icrRxBufferQ1 = 1 << 17,
+	icrRxBufferQ2 = 1 << 18,
+	icrRxBufferQ3 = 1 << 19,
+	icrRxErrorQ0 = 1 << 20,
+	icrRxErrorQ1 = 1 << 21,
+	icrRxErrorQ2 = 1 << 22,
+	icrRxErrorQ3 = 1 << 23,
+	icrMIIPhySTC = 1 << 28,
+	icrSMIdone = 1 << 29,
+	icrEtherIntSum = 1 << 31
+};
+
+
+/* The Rx and Tx descriptor lists. */
+
+typedef struct {
+	u32 cmdstat;
+	u32 byte_cnt;
+	u32 buff_ptr;
+	u32 next;
+} gt96100_td_t;
+
+#define tdByteCntBit 16
+
+typedef struct {
+	u32 cmdstat;
+	u32 buff_cnt_sz;
+	u32 buff_ptr;
+	u32 next;
+} gt96100_rd_t;
+
+#define rdBuffSzBit 16
+#define rdByteCntMask 0xffff
+
+
+/* Values for the Tx command-status descriptor entry. */
+enum td_cmdstat {
+	txOwn = 1 << 31,
+	txAutoMode = 1 << 30,
+	txEI = 1 << 23,
+	txGenCRC = 1 << 22,
+	txPad = 1 << 18,
+	txFirst = 1 << 17,
+	txLast = 1 << 16,
+	txErrorSummary = 1 << 15,
+	txReTxCntMask = 0x0f << 10,
+	txReTxCntBit = 10,
+	txCollision = 1 << 9,
+	txReTxLimit = 1 << 8,
+	txUnderrun = 1 << 6,
+	txLateCollision = 1 << 5
+};
+
+#define TxReTxCntBit 10
+
+/* Values for the Rx command-status descriptor entry. */
+enum rd_cmdstat {
+	rxOwn = 1 << 31,
+	rxAutoMode = 1 << 30,
+	rxEI = 1 << 23,
+	rxFirst = 1 << 17,
+	rxLast = 1 << 16,
+	rxErrorSummary = 1 << 15,
+	rxIGMP = 1 << 14,
+	rxHashExpired = 1 << 13,
+	rxMissedFrame = 1 << 12,
+	rxFrameType = 1 << 11,
+	rxShortFrame = 1 << 8,
+	rxMaxFrameLen = 1 << 7,
+	rxOverrun = 1 << 6,
+	rxCollision = 1 << 4,
+	rxCRCError = 1
+};
+
+/* Bit fields of a Hash Table Entry */
+enum hash_table_entry {
+	hteValid = 1,
+	hteSkip = 2,
+	hteRD = 4
+};
+
+// The MIB counters
+typedef struct {
+	u32 byteReceived;
+	u32 byteSent;
+	u32 framesReceived;
+	u32 framesSent;
+	u32 totalByteReceived;
+	u32 totalFramesReceived;
+	u32 broadcastFramesReceived;
+	u32 multicastFramesReceived;
+	u32 cRCError;
+	u32 oversizeFrames;
+	u32 fragments;
+	u32 jabber;
+	u32 collision;
+	u32 lateCollision;
+	u32 frames64;
+	u32 frames65_127;
+	u32 frames128_255;
+	u32 frames256_511;
+	u32 frames512_1023;
+	u32 frames1024_MaxSize;
+	u32 macRxError;
+	u32 droppedFrames;
+	u32 outMulticastFrames;
+	u32 outBroadcastFrames;
+	u32 undersizeFrames;
+} mib_counters_t;
+
+
+struct gt96100_private {
+	gt96100_rd_t *rx_ring;
+	gt96100_td_t *tx_ring;
+	// The Rx and Tx rings must be 16-byte aligned
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
+	char *hash_table;
+	// The Hash Table must be 8-byte aligned
+	dma_addr_t hash_table_dma;
+	int hash_mode;
+
+	// The Rx buffers must be 8-byte aligned
+	char *rx_buff[RX_RING_SIZE];
+	// Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
+	// of payload must be 8-byte aligned
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	int rx_next_out;	/* The next free ring entry to receive */
+	int tx_next_in;		/* The next free ring entry to send */
+	int tx_next_out;	/* The last ring entry the ISR processed */
+	int tx_count;		/* current # of pkts waiting to be sent in Tx ring */
+
+	mib_counters_t mib;
+	struct net_device_stats stats;
+
+	int io_size;
+	int port_num;		// 0 or 1
+	u32 port_offset;
+
+	int phy_addr;		// PHY address
+	u32 last_psr;		// last value of the port status register
+
+	int options;		/* User-settable misc. driver options. */
+	int drv_flags;
+	unsigned char phys[2];	/* MII device addresses. */
+	spinlock_t lock;	/* Serialise access to device */
+};
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c
--- v2.4.3/linux/drivers/net/hamachi.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/hamachi.c	Fri Apr 20 11:54:23 2001
@@ -27,16 +27,6 @@
 
 */
 
-static const char *version =
-"hamachi.c:v1.01 5/16/2000  Written by Donald Becker\n"
-"   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
-"   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n"
-"   Support by many others\n"
-"   http://www.scyld.com/network/hamachi.html\n"
-"   or\n"
-"   http://www.parl.clemson.edu/~keithu/drivers/hamachi.html\n";
-
-
 /* A few user-configurable values. */
 
 static int debug = 1;		/* 1 normal messages, 0 quiet .. 7 verbose.  */
@@ -44,7 +34,7 @@
 #define hamachi_debug debug
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 40;
-static int mtu = 0;
+static int mtu;
 /* Default values selected by testing on a dual processor PIII-450 */
 /* These six interrupt control parameters may be set directly when loading the
  * module, or through the rx_params and tx_params variables
@@ -60,13 +50,13 @@
    -Setting to > 1518 causes all frames to be copied
 	-Setting to 0 disables copies
 */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* An override for the hardware detection of bus width.
 	Set to 1 to force 32 bit PCI bus detection.  Set to 4 to force 64 bit.
 	Add 2 to disable parity detection.
 */
-static int force32 = 0;
+static int force32;
 
 
 /* Used to pass the media type, etc.
@@ -175,6 +165,12 @@
 #include <linux/ip.h>
 #include <linux/delay.h>
 
+static char version[] __initdata =
+KERN_INFO "hamachi.c:v1.01 5/16/2000  Written by Donald Becker\n"
+KERN_INFO "   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
+KERN_INFO "   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n";
+
+
 /* IP_MF appears to be only defined in <netinet/ip.h>, however,
    we need it for hardware checksumming support.  FYI... some of
    the definitions in <netinet/ip.h> conflict/duplicate those in
@@ -548,17 +544,20 @@
 static int __init hamachi_init_one (struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
-	static int did_version = 0;			/* Already printed version info. */
 	struct hamachi_private *hmp;
 	int option, i, rx_int_var, tx_int_var, boguscnt;
 	int chip_id = ent->driver_data;
 	int irq;
 	long ioaddr;
-	static int card_idx = 0;
+	static int card_idx;
 	struct net_device *dev;
 
-	if (hamachi_debug > 0  &&  did_version++ == 0)
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
 		printk(version);
+#endif
 
 	if (pci_enable_device(pdev))
 		return -EIO;
@@ -1887,6 +1886,10 @@
 
 static int __init hamachi_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	if (pci_register_driver(&hamachi_driver) > 0)
 		return 0;
 	pci_unregister_driver(&hamachi_driver);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- v2.4.3/linux/drivers/net/hamradio/6pack.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/net/hamradio/6pack.c	Wed Apr 18 14:40:06 2001
@@ -711,10 +711,6 @@
 	/* Do sanity checks on maximum device parameter. */
 	if (sixpack_maxdev < 4)
 		sixpack_maxdev = 4;
-	if (sixpack_maxdev * sizeof(void*) >= KMALLOC_MAXSIZE) {
-	        printk(msg_invparm);
-		return -ENFILE;
-	}
 
 	printk(msg_banner, sixpack_maxdev);
 
@@ -797,8 +793,6 @@
 
 	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);	/* Only activated in AX.25 mode */
 	memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);	/*    ""      ""       ""    "" */
-
-	dev_init_buffers(dev);
 
 	/* New-style flags. */
 	dev->flags		= 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.4.3/linux/drivers/net/hamradio/baycom_epp.c	Mon Dec 11 13:23:31 2000
+++ linux/drivers/net/hamradio/baycom_epp.c	Wed Apr 18 14:40:06 2001
@@ -1379,8 +1379,6 @@
 	dev->get_stats = baycom_get_stats;
 
 	/* Fill in the fields of the device structure */
-	dev_init_buffers(dev);
-
 	bc->skb = NULL;
 	
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c
--- v2.4.3/linux/drivers/net/hamradio/baycom_par.c	Wed Jul  5 12:59:11 2000
+++ linux/drivers/net/hamradio/baycom_par.c	Wed Apr 18 14:40:05 2001
@@ -569,7 +569,7 @@
 
 static int __init baycom_par_setup(char *str)
 {
-        static unsigned nr_dev = 0;
+        static unsigned nr_dev;
 	int ints[2];
 
         if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c
--- v2.4.3/linux/drivers/net/hamradio/baycom_ser_fdx.c	Wed Jul  5 12:59:11 2000
+++ linux/drivers/net/hamradio/baycom_ser_fdx.c	Wed Apr 18 14:40:05 2001
@@ -689,7 +689,7 @@
 
 static int __init baycom_ser_fdx_setup(char *str)
 {
-        static unsigned nr_dev = 0;
+        static unsigned nr_dev;
         int ints[4];
 
         if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c
--- v2.4.3/linux/drivers/net/hamradio/baycom_ser_hdx.c	Wed Jul  5 12:59:11 2000
+++ linux/drivers/net/hamradio/baycom_ser_hdx.c	Wed Apr 18 14:40:05 2001
@@ -729,7 +729,7 @@
 
 static int __init baycom_ser_hdx_setup(char *str)
 {
-        static unsigned nr_dev = 0;
+        static unsigned nr_dev;
 	int ints[3];
 
         if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- v2.4.3/linux/drivers/net/hamradio/bpqether.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/net/hamradio/bpqether.c	Wed Apr 18 14:40:06 2001
@@ -530,8 +530,6 @@
                 return -EIO;
         }
 
-	dev_init_buffers(dev);
-
 	dev->hard_start_xmit = bpq_xmit;
 	dev->open	     = bpq_open;
 	dev->stop	     = bpq_close;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.4.3/linux/drivers/net/hamradio/dmascc.c	Tue Jul 18 16:52:35 2000
+++ linux/drivers/net/hamradio/dmascc.c	Wed Apr 18 14:40:06 2001
@@ -294,7 +294,7 @@
 
 /* Global variables */
 
-static struct scc_info *first = NULL;
+static struct scc_info *first;
 static unsigned long rand;
 
 
@@ -593,7 +593,6 @@
     dev->tx_queue_len = 64;
     memcpy(dev->broadcast, ax25_broadcast, 7);
     memcpy(dev->dev_addr, ax25_test, 7);
-    dev_init_buffers(dev);
     rtnl_lock();
     if (register_netdevice(dev)) {
       printk("dmascc: could not register %s\n", dev->name);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c
--- v2.4.3/linux/drivers/net/hamradio/hdlcdrv.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/hamradio/hdlcdrv.c	Wed Apr 18 14:40:06 2001
@@ -791,7 +791,6 @@
 	dev->get_stats = hdlcdrv_get_stats;
 
 	/* Fill in the fields of the device structure */
-	dev_init_buffers(dev);
 
 	s->skb = NULL;
 	
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- v2.4.3/linux/drivers/net/hamradio/mkiss.c	Mon Jan 22 13:32:10 2001
+++ linux/drivers/net/hamradio/mkiss.c	Wed Apr 18 14:40:06 2001
@@ -935,8 +935,6 @@
 	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
 	memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
 
-	dev_init_buffers(dev);
-
 	/* New-style flags. */
 	dev->flags      = 0;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.4.3/linux/drivers/net/hamradio/scc.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/hamradio/scc.c	Thu Apr 19 09:34:52 2001
@@ -214,7 +214,7 @@
 static int scc_net_set_mac_address(struct net_device *dev, void *addr);
 static struct net_device_stats * scc_net_get_stats(struct net_device *dev);
 
-static unsigned char *SCC_DriverName = "scc";
+static unsigned char SCC_DriverName[] = "scc";
 
 static struct irqflags { unsigned char used : 1; } Ivec[16];
 	
@@ -1574,8 +1574,6 @@
 
 static int scc_net_init(struct net_device *dev)
 {
-	dev_init_buffers(dev);
-	
 	dev->tx_queue_len    = 16;	/* should be enough... */
 
 	dev->open            = scc_net_open;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c
--- v2.4.3/linux/drivers/net/hamradio/soundmodem/sm.c	Wed Jul  5 12:59:11 2000
+++ linux/drivers/net/hamradio/soundmodem/sm.c	Wed Apr 18 14:40:05 2001
@@ -728,7 +728,7 @@
 
 static int __init sm_setup(char *str)
 {
-	static unsigned nr_dev = 0;
+	static unsigned nr_dev;
 	int ints[8];
 
 	if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- v2.4.3/linux/drivers/net/hamradio/yam.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/hamradio/yam.c	Wed Apr 18 14:40:06 2001
@@ -1071,7 +1071,6 @@
 	dev->hard_start_xmit = yam_send_packet;
 	dev->get_stats = yam_get_stats;
 
-	dev_init_buffers(dev);
 	skb_queue_head_init(&yp->send_queue);
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v2.4.3/linux/drivers/net/hp-plus.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/hp-plus.c	Thu Apr 19 09:34:52 2001
@@ -18,7 +18,7 @@
 	programming information.
 */
 
-static const char *version =
+static const char version[] =
 "hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
@@ -141,7 +141,7 @@
 {
 	int i, retval;
 	unsigned char checksum = 0;
-	const char *name = "HP-PC-LAN+";
+	const char name[] = "HP-PC-LAN+";
 	int mem_start;
 	static unsigned version_printed;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v2.4.3/linux/drivers/net/hp.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/hp.c	Thu Apr 19 09:34:52 2001
@@ -18,7 +18,7 @@
 	  The Crynwr packet driver.
 */
 
-static const char *version =
+static const char version[] =
 	"hp.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hplance.c linux/drivers/net/hplance.c
--- v2.4.3/linux/drivers/net/hplance.c	Tue Feb 13 13:15:04 2001
+++ linux/drivers/net/hplance.c	Thu Apr 12 12:15:25 2001
@@ -63,7 +63,7 @@
 static unsigned short hplance_readrdp(struct hplance_private *lp);
 
 #ifdef MODULE
-static struct hplance_private *root_hplance_dev = NULL;
+static struct hplance_private *root_hplance_dev;
 #endif
 
 /* Find all the HP Lance boards and initialise them... */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/hydra.c linux/drivers/net/hydra.c
--- v2.4.3/linux/drivers/net/hydra.c	Tue Feb 13 13:15:04 2001
+++ linux/drivers/net/hydra.c	Thu Apr 12 12:15:25 2001
@@ -60,7 +60,7 @@
 #define WORDSWAP(a)     ((((a)>>8)&0xff) | ((a)<<8))
 
 #ifdef MODULE
-static struct net_device *root_hydra_dev = NULL;
+static struct net_device *root_hydra_dev;
 #endif
 
 static int __init hydra_probe(void);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/isa-skeleton.c linux/drivers/net/isa-skeleton.c
--- v2.4.3/linux/drivers/net/isa-skeleton.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/isa-skeleton.c	Thu Apr 12 12:15:25 2001
@@ -163,7 +163,7 @@
 static int __init netcard_probe1(struct net_device *dev, int ioaddr)
 {
 	struct net_local *np;
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	int i;
 
 	/*
diff -u --recursive --new-file v2.4.3/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c
--- v2.4.3/linux/drivers/net/jazzsonic.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/jazzsonic.c	Thu Apr 12 12:15:25 2001
@@ -118,7 +118,7 @@
 static int __init sonic_probe1(struct net_device *dev,
                                unsigned int base_addr, unsigned int irq)
 {
-    static unsigned version_printed = 0;
+    static unsigned version_printed;
     unsigned int silicon_revision;
     unsigned int val;
     struct sonic_local *lp;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.4.3/linux/drivers/net/lance.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/lance.c	Thu Apr 19 09:34:52 2001
@@ -38,7 +38,7 @@
     Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
 */
 
-static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -389,9 +389,9 @@
 	int i, reset_val, lance_version;
 	const char *chipname;
 	/* Flags for specific chips or boards. */
-	unsigned char hpJ2405A = 0;			/* HP ISA adaptor */
-	int hp_builtin = 0;					/* HP on-board ethernet. */
-	static int did_version = 0;			/* Already printed version info. */
+	unsigned char hpJ2405A = 0;		/* HP ISA adaptor */
+	int hp_builtin = 0;			/* HP on-board ethernet. */
+	static int did_version;			/* Already printed version info. */
 	unsigned long flags;
 
 	/* First we look for special cases.
diff -u --recursive --new-file v2.4.3/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.4.3/linux/drivers/net/loopback.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/loopback.c	Wed Apr 18 14:40:06 2001
@@ -105,7 +105,7 @@
 /* Initialize the rest of the LOOPBACK device. */
 int __init loopback_init(struct net_device *dev)
 {
-	dev->mtu		= PAGE_SIZE - LOOPBACK_OVERHEAD;
+	dev->mtu		= (16 * 1024) + 20 + 20 + 12;
 	dev->hard_start_xmit	= loopback_xmit;
 	dev->hard_header	= eth_header;
 	dev->hard_header_cache	= eth_header_cache;
@@ -116,20 +116,16 @@
 	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001		*/
 	dev->rebuild_header	= eth_rebuild_header;
 	dev->flags		= IFF_LOOPBACK;
+	dev->features		= NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA;
 	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
 	if (dev->priv == NULL)
 			return -ENOMEM;
 	memset(dev->priv, 0, sizeof(struct net_device_stats));
 	dev->get_stats = get_stats;
 
-	if (num_physpages >= ((128*1024*1024)>>PAGE_SHIFT))
-		dev->mtu = 4096*4 - LOOPBACK_OVERHEAD;
-
 	/*
 	 *	Fill in the generic fields of the device structure. 
 	 */
    
-	dev_init_buffers(dev);
-  
 	return(0);
 };
diff -u --recursive --new-file v2.4.3/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.4.3/linux/drivers/net/mace.c	Tue Mar 20 12:05:01 2001
+++ linux/drivers/net/mace.c	Thu Apr 12 12:15:25 2001
@@ -20,7 +20,7 @@
 #include <asm/pgtable.h>
 #include "mace.h"
 
-static struct net_device *mace_devs = NULL;
+static struct net_device *mace_devs;
 
 #define N_RX_RING	8
 #define N_TX_RING	6
diff -u --recursive --new-file v2.4.3/linux/drivers/net/macmace.c linux/drivers/net/macmace.c
--- v2.4.3/linux/drivers/net/macmace.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/macmace.c	Thu Apr 12 12:15:25 2001
@@ -200,7 +200,7 @@
 int mace68k_probe(struct net_device *unused)
 {
 	int j;
-	static int once=0;
+	static int once;
 	struct mace68k_data *mp;
 	unsigned char *addr;
 	struct net_device *dev;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/mvme147.c linux/drivers/net/mvme147.c
--- v2.4.3/linux/drivers/net/mvme147.c	Tue Feb 13 13:15:04 2001
+++ linux/drivers/net/mvme147.c	Thu Apr 12 12:15:25 2001
@@ -66,13 +66,13 @@
 typedef unsigned short (*readrdp_t)(void *);
 
 #ifdef MODULE
-static struct m147lance_private *root_m147lance_dev = NULL;
+static struct m147lance_private *root_m147lance_dev;
 #endif
 
 /* Initialise the one and only on-board 7990 */
 int __init mvme147lance_probe(struct net_device *dev)
 {
-	static int called = 0;
+	static int called;
 	static const char name[] = "MVME147 LANCE";
 	struct m147lance_private *lp;
 	u_long *addr;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.4.3/linux/drivers/net/myri_sbus.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/myri_sbus.c	Thu Apr 19 09:34:52 2001
@@ -3,7 +3,7 @@
  * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
  */
 
-static char *version =
+static char version[] =
         "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
@@ -89,7 +89,7 @@
 #endif
 
 #ifdef MODULE
-static struct myri_eth *root_myri_dev = NULL;
+static struct myri_eth *root_myri_dev;
 #endif
 
 static void myri_reset_off(unsigned long lp, unsigned long cregs)
@@ -886,7 +886,7 @@
 
 static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, int num)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	struct myri_eth *mp;
 	unsigned char prop_buf[32];
 	int i;
@@ -1109,7 +1109,7 @@
 	struct net_device *dev = NULL;
 	struct sbus_bus *bus;
 	struct sbus_dev *sdev = 0;
-	static int called = 0;
+	static int called;
 	int cards = 0, v;
 
 #ifdef MODULE
diff -u --recursive --new-file v2.4.3/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- v2.4.3/linux/drivers/net/natsemi.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/natsemi.c	Fri Apr 20 11:54:23 2001
@@ -37,13 +37,6 @@
 
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"natsemi.c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/natsemi.html\n";
-static const char version3[] =
-"  (unofficial 2.4.x kernel port, version 1.0.4, February 26, 2001 Jeff Garzik, Tjeerd Mulder)\n";
 /* Updated to recommendations in pci-skeleton v2.03. */
 
 /* Automatically extracted configuration info:
@@ -64,14 +57,14 @@
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
-static int mtu = 0;
+static int mtu;
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
    This chip uses a 512 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 100;
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
@@ -125,6 +118,12 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "natsemi.c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
+KERN_INFO "  (unofficial 2.4.x kernel port, version 1.0.5, April 17, 2001 Jeff Garzik, Tjeerd Mulder)\n";
+
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
@@ -368,15 +367,17 @@
 	struct netdev_private *np;
 	int i, option, irq, chip_idx = ent->driver_data;
 	static int find_cnt = -1;
-	static int printed_version;
 	unsigned long ioaddr, iosize;
 	const int pcibar = 1; /* PCI base address register */
 	int prev_eedata;
 	u32 tmp;
 
-	if ((debug <= 1) && !printed_version++)
-		printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-			version1, version2, version3);
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
 
 	i = pci_enable_device(pdev);
 	if (i) return i;
@@ -1250,9 +1251,10 @@
 
 static int __init natsemi_init_mod (void)
 {
-	if (debug > 1)
-		printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-			version1, version2, version3);
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 
 	return pci_module_init (&natsemi_driver);
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.4.3/linux/drivers/net/ne.c	Tue Mar  6 19:28:34 2001
+++ linux/drivers/net/ne.c	Thu Apr 12 12:15:25 2001
@@ -238,7 +238,7 @@
 	int start_page, stop_page;
 	int neX000, ctron, copam, bad_card;
 	int reg0, ret;
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 
 	if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
 		return -EBUSY;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.4.3/linux/drivers/net/ne2k-pci.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/ne2k-pci.c	Fri Apr 20 11:54:23 2001
@@ -25,12 +25,6 @@
 	Limited full-duplex support.
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n";
-static const char version2[] =
-"  http://www.scyld.com/network/ne2k-pci.html\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -60,6 +54,11 @@
 #include <linux/etherdevice.h>
 #include "8390.h"
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n"
+KERN_INFO "  http://www.scyld.com/network/ne2k-pci.html\n";
+
 #if defined(__powerpc__)
 #define inl_le(addr)  le32_to_cpu(inl(addr))
 #define inw_le(addr)  le16_to_cpu(inw(addr))
@@ -199,8 +198,14 @@
 	long ioaddr;
 	int flags = pci_clone_list[chip_idx].flags;
 
-	if (fnd_cnt++ == 0)
-		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
+	fnd_cnt++;
 
 	i = pci_enable_device (pdev);
 	if (i)
@@ -593,6 +598,10 @@
 
 static int __init ne2k_pci_init(void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init (&ne2k_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.4.3/linux/drivers/net/net_init.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/net_init.c	Wed Apr 18 14:40:06 2001
@@ -171,16 +171,16 @@
 	return dev;
 }
 
+#if defined(CONFIG_HIPPI) || defined(CONFIG_TR) || defined(CONFIG_NET_FC)
 static int __register_netdev(struct net_device *dev)
 {
-	dev_init_buffers(dev);
-	
 	if (dev->init && dev->init(dev) != 0) {
 		unregister_netdev(dev);
 		return -EIO;
 	}
 	return 0;
 }
+#endif
 
 /**
  * init_etherdev - Register ethernet device
@@ -416,8 +416,6 @@
 
 	/* New-style flags. */
 	dev->flags		= IFF_BROADCAST|IFF_MULTICAST;
-
-	dev_init_buffers(dev);
 }
 EXPORT_SYMBOL(ether_setup);
 
@@ -444,10 +442,6 @@
 
 	/* New-style flags */
 	dev->flags		= IFF_BROADCAST | IFF_MULTICAST;
-
-	dev_init_buffers(dev);
-	
-	return;
 }
 EXPORT_SYMBOL(fddi_setup);
 
@@ -484,8 +478,6 @@
 	 * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. 
 	 */
 	dev->flags = 0; 
-
-	dev_init_buffers(dev);
 }
 EXPORT_SYMBOL(hippi_setup);
 #endif /* CONFIG_HIPPI */
@@ -523,8 +515,6 @@
 	dev->broadcast[0]	= 0xFF;
 
 	dev->flags		= IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
-
-	dev_init_buffers(dev);
 }
 EXPORT_SYMBOL(ltalk_setup);
 
@@ -674,7 +664,6 @@
 
         /* New-style flags. */
         dev->flags              =        IFF_BROADCAST;
-	dev_init_buffers(dev);
 }
 
 /**
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c
--- v2.4.3/linux/drivers/net/ni5010.c	Tue Mar  6 19:28:34 2001
+++ linux/drivers/net/ni5010.c	Thu Apr 12 12:15:25 2001
@@ -74,7 +74,7 @@
 	"ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n";
 	
 /* bufsize_rcv == 0 means autoprobing */
-static unsigned int bufsize_rcv = 0;
+static unsigned int bufsize_rcv;
 
 #define jumpered_interrupts	/* IRQ line jumpered on board */
 #undef jumpered_dma		/* No DMA used */
@@ -186,7 +186,7 @@
 
 static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	int i;
 	unsigned int data = 0;
 	int boguscount = 40;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.4.3/linux/drivers/net/ni52.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ni52.c	Thu Apr 12 12:15:25 2001
@@ -99,9 +99,9 @@
  * < 30.Sep.93: first versions
  */
 
-static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume = 0; /* experimental .. better should be zero */
-static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
+static int debuglevel;	/* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume; /* experimental .. better should be zero */
+static int rfdadd;	/* rfdadd=1 may be better for 8K MEM cards */
 static int fifo=0x8;	/* don't change */
 
 /* #define REALLY_SLOW_IO */
@@ -1289,8 +1289,8 @@
 /* set: io,irq,memstart,memend or set it when calling insmod */
 static int irq=9;
 static int io=0x300;
-static long memstart=0; /* e.g 0xd0000 */
-static long memend=0;	 /* e.g 0xd4000 */
+static long memstart;	/* e.g 0xd0000 */
+static long memend;	/* e.g 0xd4000 */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.4.3/linux/drivers/net/ni65.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ni65.c	Wed Apr 18 14:40:04 2001
@@ -1174,16 +1174,12 @@
 }
 
 #ifdef MODULE
-static struct net_device dev_ni65 = {
-	"",	/* "ni6510": device name inserted by net_init.c */
-	0, 0, 0, 0,
-	0x360, 9,	 /* I/O address, IRQ */
-	0, 0, 0, NULL, ni65_probe };
+static struct net_device dev_ni65 = { base_addr: 0x360, irq: 9, init: ni65_probe };
 
 /* set: io,irq,dma or set it when calling insmod */
-static int irq=0;
-static int io=0;
-static int dma=0;
+static int irq;
+static int io;
+static int dma;
 
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c
--- v2.4.3/linux/drivers/net/pci-skeleton.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pci-skeleton.c	Fri Apr 20 11:54:23 2001
@@ -36,7 +36,7 @@
 	-----<snip>-----
 
 	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.
 
 
 -----------------------------------------------------------------------------
@@ -83,13 +83,6 @@
 
 IVc. Errata
 
-1) The RTL-8139 has a serious problem with motherboards which do
-posted MMIO writes to PCI space.  This driver works around the
-problem by having an MMIO  register write be immediately followed by
-an MMIO register read.
-
-2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver.
-
 */
 
 #include <linux/module.h>
@@ -102,12 +95,14 @@
 #include <linux/delay.h>
 #include <asm/io.h>
 
-
 #define NETDRV_VERSION		"1.0.0"
 #define MODNAME			"netdrv"
 #define NETDRV_DRIVER_LOAD_MSG	"MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
 #define PFX			MODNAME ": "
 
+static char version[] __devinitdata =
+KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
+KERN_INFO "  Support available from http://foo.com/bar/baz.html\n";
 
 /* define to 1 to enable PIO instead of MMIO */
 #undef USE_IO_OPS
@@ -740,9 +735,15 @@
 	int i, addr_len, option;
 	void *ioaddr = NULL;
 	static int board_idx = -1;
-	static int printed_version = 0;
 	u8 tmp;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	DPRINTK ("ENTER\n");
 
 	assert (pdev != NULL);
@@ -750,11 +751,6 @@
 
 	board_idx++;
 
-	if (!printed_version) {
-		printk (KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n");
-		printed_version = 1;
-	}
-
 	i = netdrv_init_board (pdev, &dev, &ioaddr);
 	if (i < 0) {
 		DPRINTK ("EXIT, returning %d\n", i);
@@ -1973,6 +1969,10 @@
 
 static int __init netdrv_init_module (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init (&netdrv_pci_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/3c574_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/3c574_cs.c	Wed Apr 18 14:40:05 2001
@@ -210,7 +210,7 @@
 /* Set iff a MII transceiver on any interface requires mdio preamble.
    This only set with the original DP83840 on older 3c905 boards, so the extra
    code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required = 0;
+static char mii_preamble_required;
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
@@ -253,7 +253,7 @@
 static dev_link_t *tc574_attach(void);
 static void tc574_detach(dev_link_t *);
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 static void flush_stale_links(void)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/3c589_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/3c589_cs.c	Wed Apr 18 14:40:05 2001
@@ -127,7 +127,7 @@
 /* Parameters that can be set with 'insmod' */
 
 /* Special hook for setting if_port when module is loaded */
-static int if_port = 0;
+static int if_port;
 
 /* Bit map of interrupts to choose from */
 static u_int irq_mask = 0xdeb8;
@@ -163,7 +163,7 @@
 static dev_link_t *tc589_attach(void);
 static void tc589_detach(dev_link_t *);
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 /*======================================================================
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/aironet4500_cs.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/pcmcia/aironet4500_cs.c	Wed Apr 18 14:40:05 2001
@@ -81,7 +81,7 @@
 static int awc_event(event_t event, int priority,
 					   event_callback_args_t *args);
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 static void cs_error(client_handle_t handle, int func, int ret)
 {
@@ -179,12 +179,14 @@
 	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
 	if (!link)
 		return NULL;
+	memset(link, 0, sizeof(struct dev_link_t));
+
 	link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL);
 	if (!link->dev) {
 		kfree(link);
 		return NULL;
 	}
-	memset(link, 0, sizeof(struct dev_link_t));
+
 	memset(link->dev, 0, sizeof(struct dev_node_t));
 
 	link->release.function = &awc_release;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/com20020_cs.c linux/drivers/net/pcmcia/com20020_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/com20020_cs.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/pcmcia/com20020_cs.c	Wed Apr 18 14:40:05 2001
@@ -104,11 +104,11 @@
 
 /* Parameters that can be set with 'insmod' */
 
-static int node = 0;
+static int node;
 static int timeout = 3;
-static int backplane = 0;
-static int clockp = 0;
-static int clockm = 0;
+static int backplane;
+static int clockp;
+static int clockm;
 
 MODULE_PARM(node, "i");
 MODULE_PARM(timeout, "i");
@@ -135,7 +135,7 @@
 static dev_link_t *com20020_attach(void);
 static void com20020_detach(dev_link_t *);
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 /*====================================================================*/
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/fmvj18x_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Wed Apr 18 14:40:05 2001
@@ -76,7 +76,7 @@
 
 /* SRAM configuration */
 /* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
-static int sram_config = 0;
+static int sram_config;
 
 MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
@@ -117,7 +117,7 @@
 static void fjn_tx_timeout(struct net_device *dev);
 
 static dev_info_t dev_info = "fmvj18x_cs";
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 /*
     card type
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/hermes.c linux/drivers/net/pcmcia/hermes.c
--- v2.4.3/linux/drivers/net/pcmcia/hermes.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcmcia/hermes.c	Wed Apr 25 14:45:48 2001
@@ -19,9 +19,9 @@
 
 static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>";
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <asm/io.h>
 #include <linux/ptrace.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/hermes.h linux/drivers/net/pcmcia/hermes.h
--- v2.4.3/linux/drivers/net/pcmcia/hermes.h	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcmcia/hermes.h	Wed Apr 25 14:45:48 2001
@@ -35,18 +35,18 @@
 /*
  * Limits and constants
  */
-#define		HERMES_ALLOC_LEN_MIN		((uint16_t)4)
-#define		HERMES_ALLOC_LEN_MAX		((uint16_t)2400)
+#define		HERMES_ALLOC_LEN_MIN		(4)
+#define		HERMES_ALLOC_LEN_MAX		(2400)
 #define		HERMES_LTV_LEN_MAX		(34)
-#define		HERMES_BAP_DATALEN_MAX		((uint16_t)4096)
-#define		HERMES_BAP_OFFSET_MAX		((uint16_t)4096)
-#define		HERMES_PORTID_MAX		((uint16_t)7)
-#define		HERMES_NUMPORTS_MAX		((uint16_t)(HERMES_PORTID_MAX+1))
-#define		HERMES_PDR_LEN_MAX		((uint16_t)260)	/* in bytes, from EK */
-#define		HERMES_PDA_RECS_MAX		((uint16_t)200)	/* a guess */
-#define		HERMES_PDA_LEN_MAX		((uint16_t)1024)	/* in bytes, from EK */
-#define		HERMES_SCANRESULT_MAX		((uint16_t)35)
-#define		HERMES_CHINFORESULT_MAX		((uint16_t)8)
+#define		HERMES_BAP_DATALEN_MAX		(4096)
+#define		HERMES_BAP_OFFSET_MAX		(4096)
+#define		HERMES_PORTID_MAX		(7)
+#define		HERMES_NUMPORTS_MAX		(HERMES_PORTID_MAX+1)
+#define		HERMES_PDR_LEN_MAX		(260)	/* in bytes, from EK */
+#define		HERMES_PDA_RECS_MAX		(200)	/* a guess */
+#define		HERMES_PDA_LEN_MAX		(1024)	/* in bytes, from EK */
+#define		HERMES_SCANRESULT_MAX		(35)
+#define		HERMES_CHINFORESULT_MAX		(8)
 #define		HERMES_FRAME_LEN_MAX		(2304)
 #define		HERMES_MAX_MULTICAST		(16)
 #define		HERMES_MAGIC			(0x7d1f)
@@ -86,119 +86,125 @@
 /*
  * CMD register bitmasks
  */
-#define		HERMES_CMD_BUSY			((uint16_t)0x8000)
-#define		HERMES_CMD_AINFO		((uint16_t)0x7f00)
-#define		HERMES_CMD_MACPORT		((uint16_t)0x0700)
-#define		HERMES_CMD_RECL			((uint16_t)0x0100)
-#define		HERMES_CMD_WRITE		((uint16_t)0x0100)
-#define		HERMES_CMD_PROGMODE		((uint16_t)0x0300)
-#define		HERMES_CMD_CMDCODE		((uint16_t)0x003f)
+#define		HERMES_CMD_BUSY			(0x8000)
+#define		HERMES_CMD_AINFO		(0x7f00)
+#define		HERMES_CMD_MACPORT		(0x0700)
+#define		HERMES_CMD_RECL			(0x0100)
+#define		HERMES_CMD_WRITE		(0x0100)
+#define		HERMES_CMD_PROGMODE		(0x0300)
+#define		HERMES_CMD_CMDCODE		(0x003f)
 
 /*
  * STATUS register bitmasks
  */
-#define		HERMES_STATUS_RESULT		((uint16_t)0x7f00)
-#define		HERMES_STATUS_CMDCODE		((uint16_t)0x003f)
+#define		HERMES_STATUS_RESULT		(0x7f00)
+#define		HERMES_STATUS_CMDCODE		(0x003f)
 
 /*
  * OFFSET refister bitmasks
  */
-#define		HERMES_OFFSET_BUSY		((uint16_t)0x8000)
-#define		HERMES_OFFSET_ERR		((uint16_t)0x4000)
-#define		HERMES_OFFSET_DATAOFF		((uint16_t)0x0ffe)
+#define		HERMES_OFFSET_BUSY		(0x8000)
+#define		HERMES_OFFSET_ERR		(0x4000)
+#define		HERMES_OFFSET_DATAOFF		(0x0ffe)
 
 /*
  * Event register bitmasks (INTEN, EVSTAT, EVACK)
  */
-#define		HERMES_EV_TICK			((uint16_t)0x8000)
-#define		HERMES_EV_WTERR			((uint16_t)0x4000)
-#define		HERMES_EV_INFDROP		((uint16_t)0x2000)
-#define		HERMES_EV_INFO			((uint16_t)0x0080)
-#define		HERMES_EV_DTIM			((uint16_t)0x0020)
-#define		HERMES_EV_CMD			((uint16_t)0x0010)
-#define		HERMES_EV_ALLOC			((uint16_t)0x0008)
-#define		HERMES_EV_TXEXC			((uint16_t)0x0004)
-#define		HERMES_EV_TX			((uint16_t)0x0002)
-#define		HERMES_EV_RX			((uint16_t)0x0001)
+#define		HERMES_EV_TICK			(0x8000)
+#define		HERMES_EV_WTERR			(0x4000)
+#define		HERMES_EV_INFDROP		(0x2000)
+#define		HERMES_EV_INFO			(0x0080)
+#define		HERMES_EV_DTIM			(0x0020)
+#define		HERMES_EV_CMD			(0x0010)
+#define		HERMES_EV_ALLOC			(0x0008)
+#define		HERMES_EV_TXEXC			(0x0004)
+#define		HERMES_EV_TX			(0x0002)
+#define		HERMES_EV_RX			(0x0001)
 
 /*
  * Command codes
  */
 /*--- Controller Commands --------------------------*/
-#define		HERMES_CMD_INIT			((uint16_t)0x00)
-#define		HERMES_CMD_ENABLE		((uint16_t)0x01)
-#define		HERMES_CMD_DISABLE		((uint16_t)0x02)
-#define		HERMES_CMD_DIAG			((uint16_t)0x03)
+#define		HERMES_CMD_INIT			(0x0000)
+#define		HERMES_CMD_ENABLE		(0x0001)
+#define		HERMES_CMD_DISABLE		(0x0002)
+#define		HERMES_CMD_DIAG			(0x0003)
 
 /*--- Buffer Mgmt Commands --------------------------*/
-#define		HERMES_CMD_ALLOC		((uint16_t)0x0A)
-#define		HERMES_CMD_TX			((uint16_t)0x0B)
-#define		HERMES_CMD_CLRPRST		((uint16_t)0x12)
+#define		HERMES_CMD_ALLOC		(0x000A)
+#define		HERMES_CMD_TX			(0x000B)
+#define		HERMES_CMD_CLRPRST		(0x0012)
 
 /*--- Regulate Commands --------------------------*/
-#define		HERMES_CMD_NOTIFY		((uint16_t)0x10)
-#define		HERMES_CMD_INQ			((uint16_t)0x11)
+#define		HERMES_CMD_NOTIFY		(0x0010)
+#define		HERMES_CMD_INQ			(0x0011)
 
 /*--- Configure Commands --------------------------*/
-#define		HERMES_CMD_ACCESS		((uint16_t)0x21)
-#define		HERMES_CMD_DOWNLD		((uint16_t)0x22)
+#define		HERMES_CMD_ACCESS		(0x0021)
+#define		HERMES_CMD_DOWNLD		(0x0022)
 
 /*--- Debugging Commands -----------------------------*/
-#define 	HERMES_CMD_MONITOR		((uint16_t)(0x38))
-#define		HERMES_MONITOR_ENABLE		((uint16_t)(0x0b))
-#define		HERMES_MONITOR_DISABLE		((uint16_t)(0x0f))
+#define 	HERMES_CMD_MONITOR		(0x0038)
+#define		HERMES_MONITOR_ENABLE		(0x000b)
+#define		HERMES_MONITOR_DISABLE		(0x000f)
 
 /*
  * Configuration RIDs
  */
 
-#define		HERMES_RID_CNF_PORTTYPE		((uint16_t)0xfc00)
-#define		HERMES_RID_CNF_MACADDR		((uint16_t)0xfc01)
-#define		HERMES_RID_CNF_DESIRED_SSID	((uint16_t)0xfc02)
-#define		HERMES_RID_CNF_CHANNEL		((uint16_t)0xfc03)
-#define		HERMES_RID_CNF_OWN_SSID		((uint16_t)0xfc04)
-#define		HERMES_RID_CNF_SYSTEM_SCALE	((uint16_t)0xfc06)
-#define		HERMES_RID_CNF_MAX_DATA_LEN	((uint16_t)0xfc07)
-#define		HERMES_RID_CNF_PM_ENABLE	((uint16_t)0xfc09)
-#define		HERMES_RID_CNF_PM_MCAST_RX	((uint16_t)0xfc0b)
-#define		HERMES_RID_CNF_PM_PERIOD	((uint16_t)0xfc0c)
-#define		HERMES_RID_CNF_PM_HOLDOVER	((uint16_t)0xfc0d)
-#define		HERMES_RID_CNF_NICKNAME		((uint16_t)0xfc0e)
-#define		HERMES_RID_CNF_WEP_ON		((uint16_t)0xfc20)
-#define		HERMES_RID_CNF_MWO_ROBUST	((uint16_t)0xfc25)
-#define		HERMES_RID_CNF_PRISM2_WEP_ON	((uint16_t)0xfc28)
-#define		HERMES_RID_CNF_MULTICAST_LIST	((uint16_t)0xfc80)
-#define		HERMES_RID_CNF_CREATEIBSS	((uint16_t)0xfc81)
-#define		HERMES_RID_CNF_FRAG_THRESH	((uint16_t)0xfc82)
-#define		HERMES_RID_CNF_RTS_THRESH	((uint16_t)0xfc83)
-#define		HERMES_RID_CNF_TX_RATE_CTRL	((uint16_t)0xfc84)
-#define		HERMES_RID_CNF_PROMISCUOUS	((uint16_t)0xfc85)
-#define		HERMES_RID_CNF_KEYS		((uint16_t)0xfcb0)
-#define		HERMES_RID_CNF_TX_KEY		((uint16_t)0xfcb1)
-#define		HERMES_RID_CNF_TICKTIME		((uint16_t)0xfce0)
-
-#define		HERMES_RID_CNF_PRISM2_TX_KEY	((uint16_t)0xfc23)
-#define		HERMES_RID_CNF_PRISM2_KEY0	((uint16_t)0xfc24)
-#define		HERMES_RID_CNF_PRISM2_KEY1	((uint16_t)0xfc25)
-#define		HERMES_RID_CNF_PRISM2_KEY2	((uint16_t)0xfc26)
-#define		HERMES_RID_CNF_PRISM2_KEY3	((uint16_t)0xfc27)
-#define		HERMES_RID_CNF_SYMBOL_AUTH_TYPE		((uint16_t)0xfc2A)
-/* This one is read only */
-#define		HERMES_RID_CNF_SYMBOL_KEY_LENGTH	((uint16_t)0xfc2B)
-#define		HERMES_RID_CNF_SYMBOL_BASIC_RATES	((uint16_t)0xfc8A)
+#define		HERMES_RID_CNF_PORTTYPE		(0xfc00)
+#define		HERMES_RID_CNF_MACADDR		(0xfc01)
+#define		HERMES_RID_CNF_DESIRED_SSID	(0xfc02)
+#define		HERMES_RID_CNF_CHANNEL		(0xfc03)
+#define		HERMES_RID_CNF_OWN_SSID		(0xfc04)
+#define		HERMES_RID_CNF_SYSTEM_SCALE	(0xfc06)
+#define		HERMES_RID_CNF_MAX_DATA_LEN	(0xfc07)
+#define		HERMES_RID_CNF_PM_ENABLE	(0xfc09)
+#define		HERMES_RID_CNF_PM_MCAST_RX	(0xfc0b)
+#define		HERMES_RID_CNF_PM_PERIOD	(0xfc0c)
+#define		HERMES_RID_CNF_PM_HOLDOVER	(0xfc0d)
+#define		HERMES_RID_CNF_NICKNAME		(0xfc0e)
+#define		HERMES_RID_CNF_WEP_ON		(0xfc20)
+#define		HERMES_RID_CNF_MWO_ROBUST	(0xfc25)
+#define		HERMES_RID_CNF_PRISM2_WEP_ON	(0xfc28)
+#define		HERMES_RID_CNF_MULTICAST_LIST	(0xfc80)
+#define		HERMES_RID_CNF_CREATEIBSS	(0xfc81)
+#define		HERMES_RID_CNF_FRAG_THRESH	(0xfc82)
+#define		HERMES_RID_CNF_RTS_THRESH	(0xfc83)
+#define		HERMES_RID_CNF_TX_RATE_CTRL	(0xfc84)
+#define		HERMES_RID_CNF_PROMISCUOUS	(0xfc85)
+#define		HERMES_RID_CNF_KEYS		(0xfcb0)
+#define		HERMES_RID_CNF_TX_KEY		(0xfcb1)
+#define		HERMES_RID_CNF_TICKTIME		(0xfce0)
+
+#define		HERMES_RID_CNF_PRISM2_TX_KEY	(0xfc23)
+#define		HERMES_RID_CNF_PRISM2_KEY0	(0xfc24)
+#define		HERMES_RID_CNF_PRISM2_KEY1	(0xfc25)
+#define		HERMES_RID_CNF_PRISM2_KEY2	(0xfc26)
+#define		HERMES_RID_CNF_PRISM2_KEY3	(0xfc27)
+#define		HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID	(0xfc21)
+#define		HERMES_RID_CNF_SYMBOL_AUTH_TYPE		(0xfc2A)
+#define		HERMES_RID_CNF_SYMBOL_BASIC_RATES	(0xfc8A)
+#define		HERMES_RID_CNF_SYMBOL_PREAMBLE		(0xfc8C)
 
 /*
  * Information RIDs
  */
-#define		HERMES_RID_CHANNEL_LIST		((uint16_t)0xfd10)
-#define		HERMES_RID_STAIDENTITY		((uint16_t)0xfd20)
-#define		HERMES_RID_CURRENT_SSID		((uint16_t)0xfd41)
-#define		HERMES_RID_CURRENT_BSSID	((uint16_t)0xfd42)
-#define		HERMES_RID_COMMSQUALITY		((uint16_t)0xfd43)
-#define 	HERMES_RID_CURRENT_TX_RATE	((uint16_t)0xfd44)
-#define		HERMES_RID_WEP_AVAIL		((uint16_t)0xfd4f)
-#define		HERMES_RID_CURRENT_CHANNEL	((uint16_t)0xfdc1)
-#define		HERMES_RID_DATARATES		((uint16_t)0xfdc6)
+#define		HERMES_RID_CHANNEL_LIST		(0xfd10)
+#define		HERMES_RID_STAIDENTITY		(0xfd20)
+#define		HERMES_RID_CURRENT_SSID		(0xfd41)
+#define		HERMES_RID_CURRENT_BSSID	(0xfd42)
+#define		HERMES_RID_COMMSQUALITY		(0xfd43)
+#define 	HERMES_RID_CURRENT_TX_RATE	(0xfd44)
+#define 	HERMES_RID_SHORT_RETRY_LIMIT	(0xfd48)
+#define 	HERMES_RID_LONG_RETRY_LIMIT	(0xfd49)
+#define 	HERMES_RID_MAX_TX_LIFETIME	(0xfd4A)
+#define		HERMES_RID_WEP_AVAIL		(0xfd4f)
+#define		HERMES_RID_CURRENT_CHANNEL	(0xfdc1)
+#define		HERMES_RID_DATARATES		(0xfdc6)
+#define		HERMES_RID_SYMBOL_PRIMARY_VER	(0xfd03)
+#define		HERMES_RID_SYMBOL_SECONDARY_VER	(0xfd21)
+#define		HERMES_RID_SYMBOL_KEY_LENGTH	(0xfc2B)
 
 /*
  * Frame structures and constants
@@ -213,19 +219,19 @@
 	uint16_t tx_ctl; /* 0xC */
 } __attribute__ ((packed)) hermes_frame_desc_t;
 
-#define		HERMES_RXSTAT_ERR		((uint16_t)0x0003)
-#define		HERMES_RXSTAT_MACPORT		((uint16_t)0x0700)
-#define		HERMES_RXSTAT_MSGTYPE		((uint16_t)0xE000)
+#define		HERMES_RXSTAT_ERR		(0x0003)
+#define		HERMES_RXSTAT_MACPORT		(0x0700)
+#define		HERMES_RXSTAT_MSGTYPE		(0xE000)
 
-#define		HERMES_RXSTAT_BADCRC		((uint16_t)0x0001)
-#define		HERMES_RXSTAT_UNDECRYPTABLE	((uint16_t)0x0002)
+#define		HERMES_RXSTAT_BADCRC		(0x0001)
+#define		HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
 
 /* RFC-1042 encoded frame */
-#define		HERMES_RXSTAT_1042		((uint16_t)0x2000)
+#define		HERMES_RXSTAT_1042		(0x2000)
 /* Bridge-tunnel encoded frame */
-#define		HERMES_RXSTAT_TUNNEL		((uint16_t)0x4000)
+#define		HERMES_RXSTAT_TUNNEL		(0x4000)
 /* Wavelan-II Management Protocol frame */
-#define		HERMES_RXSTAT_WMP		((uint16_t)0x6000)
+#define		HERMES_RXSTAT_WMP		(0x6000)
 
 #ifdef __KERNEL__
 
@@ -328,8 +334,6 @@
 	(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
 #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
 	(hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf)))
-#define HERMES_WRITE_RECORD_LEN(hw, bap, rid, buf, len) \
-	(hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(len),(buf)))
 
 static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/ibmtr_cs.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Wed Apr 18 14:40:05 2001
@@ -93,10 +93,10 @@
 static int irq_list[4] = { -1 };
 
 /* MMIO base address */
-static u_long mmiobase = 0;
+static u_long mmiobase;
 
 /* SRAM base address */
-static u_long srambase = 0;
+static u_long srambase;
 
 /* SRAM size 8,16,32,64 */
 static u_long sramsize = 16;
@@ -124,7 +124,7 @@
 static dev_link_t *ibmtr_attach(void);
 static void ibmtr_detach(dev_link_t *);
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 extern int ibmtr_probe(struct net_device *dev);
 unsigned char pcmcia_reality_check(unsigned char gss);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/netwave_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/netwave_cs.c	Wed Apr 25 14:36:23 2001
@@ -187,7 +187,7 @@
  * This timing should be provided by the HBA. If it becomes a 
  * problem, try setting mem_speed to 400. 
  */
-static int mem_speed = 0;
+static int mem_speed;
 
 /* Bit map of interrupts to choose from */
 /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
@@ -250,7 +250,7 @@
    memory card driver uses an array of dev_link_t pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 /*
    A dev_link_t structure has fields for most things that are needed
@@ -710,8 +710,17 @@
        if(wrq->u.data.pointer != (caddr_t) 0) {
 	   struct iw_range	range;
 		   
-	   /* Set the length (useless : its constant...) */
+	   /* Set the length (very important for backward compatibility) */
 	   wrq->u.data.length = sizeof(struct iw_range);
+
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
+
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 		   
 	   /* Set information in the range struct */
 	   range.throughput = 450 * 1000;	/* don't argue on this ! */
@@ -1554,7 +1563,7 @@
    
 #ifdef PCMCIA_DEBUG
     if (pc_debug > 2) {
-	static int old = 0;
+	static int old;
 	if (old != dev->mc_count) {
 	    old = dev->mc_count;
 	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/nmclan_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/nmclan_cs.c	Wed Apr 18 14:40:05 2001
@@ -379,7 +379,7 @@
 #endif
 
 static dev_info_t dev_info="nmclan_cs";
-static dev_link_t *dev_list=NULL;
+static dev_link_t *dev_list;
 
 static char *if_names[]={
     "Auto", "10baseT", "BNC",
@@ -400,7 +400,7 @@
 ---------------------------------------------------------------------------- */
 
 /* 0=auto, 1=10baseT, 2 = 10base2, default=auto */
-static int if_port=0;
+static int if_port;
 
 /* Bit map of interrupts to choose from */
 static u_int irq_mask = 0xdeb8;
@@ -1605,7 +1605,7 @@
 
 #ifdef PCMCIA_DEBUG
   if (pc_debug > 1) {
-    static int old = 0;
+    static int old;
     if (dev->mc_count != old) {
       old = dev->mc_count;
       DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
@@ -1660,7 +1660,7 @@
 
 #ifdef PCMCIA_DEBUG
   if (pc_debug > 1) {
-    static int old = 0;
+    static int old;
     if (dev->mc_count != old) {
       old = dev->mc_count;
       DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/orinoco_cs.c linux/drivers/net/pcmcia/orinoco_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/orinoco_cs.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcmcia/orinoco_cs.c	Wed Apr 25 14:45:48 2001
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.03	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.04	- (formerly known as dldwd_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -97,6 +97,28 @@
  *	o Finish external renaming to orinoco...
  *	o Testing with various Wavelan firmwares
  *
+ * v0.03 -> v0.04 - 30/3/2001 - Jean II
+ *	o Update to Wireless 11 -> add retry limit/lifetime support
+ *	o Tested with a D-Link DWL 650 card, fill in firmware support
+ *	o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
+ *	o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-(
+ *	  It work on D-Link *only* after a tcpdump. Weird...
+ *	  And still doesn't work on Intel card. Grrrr...
+ *	o Update the mode after a setport3
+ *	o Add preamble setting for Symbol cards (not yet enabled)
+ *	o Don't complain as much about Symbol cards...
+ *
+ * v0.04 -> v0.04b - 22/4/2001 - David Gibson
+ *      o Removed the 'eth' parameter - always use ethXX as the
+ *        interface name instead of dldwdXX.  The other was racy
+ *        anyway.
+ *	o Clean up RID definitions in hermes.h, other cleanups
+ *
+ * v0.04b -> v0.04c - 24/4/2001 - Jean II
+ *	o Tim Hurley <timster@seiki.bliztech.com> reported a D-Link card
+ *	  with vendor 02 and firmware 0.08. Added in the capabilities...
+ *	o Tested Lucent firmware 7.28, everything works...
+ *
  * TODO - Jean II
  *	o inline functions (lot's of candidate, need to reorder code)
  *	o Separate Pcmcia specific code to help Airport/Mini PCI driver
@@ -133,7 +155,7 @@
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
-static char *version = "orinoco_cs.c 0.03 (David Gibson <hermes@gibson.dropbear.id.au>)";
+static char *version = "orinoco_cs.c 0.04 (David Gibson <hermes@gibson.dropbear.id.au>)";
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 #define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0)
@@ -165,12 +187,12 @@
 static uint irq_mask = 0xdeb8;
 /* Newer, simpler way of listing specific interrupts */
 static int irq_list[4] = { -1 };
-/* Control device name allocation. 0 -> dldwdX ; 1 -> ethX */
-static int eth = 1;
+/* Do a Pcmcia soft reset (may help some cards) */
+static int reset_cor = 0;
 
 MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(eth, "i");
+MODULE_PARM(reset_cor, "i");
 
 /*====================================================================*/
 
@@ -239,13 +261,15 @@
 	int has_wep, has_big_wep;
 	int has_mwo;
 	int has_pm;
+	int has_retry;
+	int has_preamble;
 	int broken_reset, broken_allocate;
 	uint16_t channel_mask;
 
 	/* Current configuration */
 	uint32_t iw_mode;
 	int port_type, allow_ibss;
-	uint16_t wep_on, wep_auth, tx_key;
+	uint16_t wep_on, wep_restrict, tx_key;
 	dldwd_keys_t keys;
  	char nick[IW_ESSID_MAX_SIZE+1];
 	char desired_essid[IW_ESSID_MAX_SIZE+1];
@@ -254,6 +278,8 @@
 	uint16_t ap_density, rts_thresh;
 	uint16_t tx_rate_ctrl;
 	uint16_t pm_on, pm_mcast, pm_period, pm_timeout;
+	uint16_t retry_short, retry_long, retry_time;
+	uint16_t preamble;
 
 	int promiscuous, allmulti, mc_count;
 
@@ -645,6 +671,34 @@
 			goto out;
 	}
 
+	/* Set retry settings - will fail on lot's of firmwares */
+	if (priv->has_retry) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT,
+					   priv->retry_short);
+		if (err) {
+			printk(KERN_WARNING "%s: Can't set retry limit!\n", dev->name);
+			goto out;
+		}
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT,
+					   priv->retry_long);
+		if (err)
+			goto out;
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME,
+					   priv->retry_time);
+		if (err)
+			goto out;
+	}
+
+	/* Set preamble - only for Symbol so far... */
+	if (priv->has_preamble) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE,
+					   priv->preamble);
+		if (err) {
+			printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name);
+			goto out;
+		}
+	}
+
 	/* Set promiscuity / multicast*/
 	priv->promiscuous = 0;
 	priv->allmulti = 0;
@@ -672,7 +726,8 @@
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	
+	int	extra_wep_flag = 0;
+
 	switch (priv->firmware_type) {
 	case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */
 		if (priv->wep_on) {
@@ -696,33 +751,53 @@
 			int keylen;
 			int i;
 			
-			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY,
-						   priv->tx_key);
-			if (err)
-				return err;
-			
-			keybuf[LARGE_KEY_SIZE] = '\0';
-
 			/* Write all 4 keys */
 			for(i = 0; i < MAX_KEYS; i++) {
 				keylen = priv->keys[i].len;
-				keybuf[SMALL_KEY_SIZE] = '\0';
+				keybuf[keylen] = '\0';
 				memcpy(keybuf, priv->keys[i].data, keylen);
-				err = HERMES_WRITE_RECORD_LEN(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY0, &keybuf, keylen);
+				err = hermes_write_ltv(hw, USER_BAP,
+						       HERMES_RID_CNF_PRISM2_KEY0 + i,
+						       HERMES_BYTES_TO_RECLEN(keylen + 1),
+						       &keybuf);
 				if (err)
 					return err;
 			}
-			/* Symbol cards : set the authentication :
-			 * 0 -> no encryption, 1 -> open,
-			 * 2 -> shared key, 3 -> shared key 128bit only */
+
+			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY,
+						   priv->tx_key);
+			if (err)
+				return err;
+
+			/* Authentication is where Prism2 and Symbol
+			 * firmware differ... */
 			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
-				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_auth);
+				/* Symbol cards : set the authentication :
+				 * 0 -> no encryption, 1 -> open,
+				 * 2 -> shared key, 3 -> shared key 128bit */
+				if(priv->wep_restrict) {
+					if(priv->keys[priv->tx_key].len >
+					   SMALL_KEY_SIZE)
+						extra_wep_flag = 3;
+					else
+						extra_wep_flag = 2;
+				} else
+					extra_wep_flag = 1;
+				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict);
 				if (err)
 					return err;
+			} else {
+				/* Prism2 card : we need to modify master
+				 * WEP setting */
+				if(priv->wep_restrict)
+					extra_wep_flag = 2;
+				else
+					extra_wep_flag = 0;
 			}
 		}
 		
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, priv->wep_on);
+		/* Master WEP setting : on/off */
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag));
 		if (err)
 			return err;	
 		break;
@@ -1246,6 +1321,7 @@
 	}
 
 	firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor;
+	DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver);
 
 	/* Determine capabilities from the firmware version */
 
@@ -1259,7 +1335,7 @@
 		priv->firmware_type = FIRMWARE_TYPE_LUCENT;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
-		priv->has_port3 = 1;
+		priv->has_port3 = 1;		/* Still works in 7.28 */
 		priv->has_ibss = (firmver >= 0x60006);
 		priv->has_ibss_any = (firmver >= 0x60010);
 		priv->has_wep = (firmver >= 0x40020);
@@ -1267,26 +1343,52 @@
 					  Gold cards from the others? */
 		priv->has_mwo = (firmver >= 0x60000);
 		priv->has_pm = (firmver >= 0x40020);
+		priv->has_retry = 0;
+		priv->has_preamble = 0;
 		/* Tested with Lucent firmware :
-		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 => Jean II
+		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
 		 * Tested CableTron firmware : 4.32 => Anton */
 		break;
 	case 0x2:
 		vendor_str = "Generic Prism II";
-		/* Note : my Intel card report this value, but I can't do
-		 * much with it, so I guess it's broken - Jean II */
+		/* Some D-Link cards report vendor 0x02... */
 
 		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
 		priv->broken_reset = 0;
-		priv->broken_allocate = (firmver <= 0x10001);
+		priv->broken_allocate = 0;
 		priv->has_port3 = 1;
-		priv->has_ibss = 0; /* FIXME: no idea if this is right */
-		priv->has_wep = (firmver >= 0x20000);
-		priv->has_big_wep = 1;
+		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
+		priv->has_wep = (firmver >= 0x00007); /* FIXME */
+		priv->has_big_wep = 0;
 		priv->has_mwo = 0;
-		priv->has_pm = (firmver >= 0x20000);
-		/* Tested with Intel firmware : 1.01 => Jean II */
-		/* Note : firmware 1.01 is *seriously* broken */
+		priv->has_pm = (firmver >= 0x00007); /* FIXME */
+		priv->has_retry = 0;
+		priv->has_preamble = 0;
+
+		/* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */
+
+		/* Special case for Symbol cards */
+		if(firmver == 0x10001) {
+			/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+			vendor_str = "Symbol";
+			/* Intel MAC : 00:02:B3:* */
+			/* 3Com MAC : 00:50:DA:* */
+
+			/* FIXME : probably need to use SYMBOL_***ARY_VER
+			 * to get proper firmware version */
+			priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
+			priv->broken_reset = 0;
+			priv->broken_allocate = 1;
+			priv->has_port3 = 1;
+			priv->has_ibss = 1; /* FIXME */
+			priv->has_wep = 1; /* FIXME */
+			priv->has_big_wep = 1;	/* RID_SYMBOL_KEY_LENGTH */
+			priv->has_mwo = 0;
+			priv->has_pm = 1; /* FIXME */
+			priv->has_retry = 0;
+			priv->has_preamble = 0; /* FIXME */
+			/* Tested with Intel firmware : v15 => Jean II */
+		}
 		break;
 	case 0x3:
 		vendor_str = "Samsung";
@@ -1301,37 +1403,28 @@
 		priv->has_big_wep = 0; /* FIXME */
 		priv->has_mwo = 0;
 		priv->has_pm = (firmver >= 0x20000); /* FIXME */
+		priv->has_retry = 0;
+		priv->has_preamble = 0;
 		break;
 	case 0x6:
+		/* D-Link DWL 650, ... */
 		vendor_str = "LinkSys/D-Link";
-		/* To check */
+		/* D-Link MAC : 00:40:05:* */
 
 		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
 		priv->broken_reset = 0;
 		priv->broken_allocate = 0;
 		priv->has_port3 = 1;
-		priv->has_ibss = 0; /* FIXME: available in later firmwares */
-		priv->has_wep = (firmver >= 0x20000); /* FIXME */
+		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
+		priv->has_wep = (firmver >= 0x00007); /* FIXME */
 		priv->has_big_wep = 0;
 		priv->has_mwo = 0;
-		priv->has_pm = (firmver >= 0x20000); /* FIXME */
+		priv->has_pm = (firmver >= 0x00007); /* FIXME */
+		priv->has_retry = 0;
+		priv->has_preamble = 0;
+		/* Tested with D-Link firmware 0.07 => Jean II */
+		/* Note : with 0.07, IBSS to a Lucent card seem flaky */
 		break;
-#if 0
-	case 0x???:		/* Could someone help here ??? */
-		vendor_str = "Symbol";
-		/* Symbol , 3Com AirConnect, Ericsson WLAN */
-
-		priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;
-		priv->has_ibss = 0; /* FIXME: available in later firmwares */
-		priv->has_wep = (firmver >= 0x20000); /* FIXME */
-		priv->has_big_wep = 1;	/* Probably RID_SYMBOL_KEY_LENGTH */
-		priv->has_mwo = 0;
-		priv->has_pm = (firmver >= 0x20000);
-		break;
-#endif
 	default:
 		vendor_str = "UNKNOWN";
 
@@ -1344,14 +1437,14 @@
 		priv->has_big_wep = 0;
 		priv->has_mwo = 0;
 		priv->has_pm = 0;
+		priv->has_retry = 0;
+		priv->has_preamble = 0;
 	}
 
 	printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n",
 	       dev->name, priv->firmware_info.id, priv->firmware_info.vendor,
 	       vendor_str, priv->firmware_info.major, priv->firmware_info.minor);
 	
-	if ((priv->broken_reset) || (priv->broken_allocate))
-		printk(KERN_INFO "%s: Buggy firmware, please upgrade ASAP.\n", dev->name);
 	if (priv->has_port3)
 		printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name);
 	if (priv->has_ibss)
@@ -1362,7 +1455,7 @@
 		if (priv->has_big_wep)
 			printk("\"128\"-bit key.\n");
 		else
-			printk("40-bit key.");
+			printk("40-bit key.\n");
 	}
 
 	/* Get the MAC address */
@@ -1452,6 +1545,28 @@
 			goto out;
 		}
 	}
+
+	/* Retry setup */
+	if (priv->has_retry) {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &priv->retry_short);
+		if (err)
+			goto out;
+
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &priv->retry_long);
+		if (err)
+			goto out;
+
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &priv->retry_time);
+		if (err)
+			goto out;
+	}
+		
+	/* Preamble setup */
+	if (priv->has_preamble) {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble);
+		if (err)
+			goto out;
+	}
 		
 	/* Set up the default configuration */
 	priv->iw_mode = IW_MODE_INFRA;
@@ -1802,6 +1917,11 @@
 
 	/* Much of this shamelessly taken from wvlan_cs.c. No idea
 	 * what it all means -dgibson */
+#if WIRELESS_EXT > 10
+	range.we_version_compiled = WIRELESS_EXT;
+	range.we_version_source = 11;
+#endif /* WIRELESS_EXT > 10 */
+
 	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
 
 	/* Set available channels/frequencies */
@@ -1881,6 +2001,16 @@
 	range.txpower[0] = 15; /* 15dBm */
 	range.txpower_capa = IW_TXPOW_DBM;
 
+#if WIRELESS_EXT > 10
+	range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range.retry_flags = IW_RETRY_LIMIT;
+	range.r_time_flags = IW_RETRY_LIFETIME;
+	range.min_retry = 0;
+	range.max_retry = 65535;	/* ??? */
+	range.min_r_time = 0;
+	range.max_r_time = 65535 * 1000;	/* ??? */
+#endif /* WIRELESS_EXT > 10 */
+
 	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
 		return -EFAULT;
 
@@ -1895,7 +2025,7 @@
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	int setindex = priv->tx_key;
 	int enable = priv->wep_on;
-	int auth = priv->wep_auth;
+	int restricted = priv->wep_restrict;
 	uint16_t xlen = 0;
 	int err = 0;
 	char keybuf[MAX_KEY_SIZE];
@@ -1957,16 +2087,11 @@
 	
 	if (erq->flags & IW_ENCODE_DISABLED)
 		enable = 0;
-	/* Only for symbol cards (so far) - Jean II */
+	/* Only for Prism2 & Symbol cards (so far) - Jean II */
 	if (erq->flags & IW_ENCODE_OPEN)
-		auth = 1;
+		restricted = 0;
 	if (erq->flags & IW_ENCODE_RESTRICTED)
-		auth = 2;	/* If all key are 128 -> should be 3 ??? */
-	/* Agree with master wep setting */
-	if (enable == 0)
-		auth = 0;
-	else if(auth == 0)
-		auth = 1;	/* Encryption require some authentication */
+		restricted = 1;
 
 	if (erq->pointer) {
 		priv->keys[index].len = cpu_to_le16(xlen);
@@ -1975,7 +2100,7 @@
 	}
 	priv->tx_key = setindex;
 	priv->wep_on = enable;
-	priv->wep_auth = auth;
+	priv->wep_restrict = restricted;
 	
  out:
 	dldwd_unlock(priv);
@@ -2002,19 +2127,11 @@
 	erq->flags |= index + 1;
 	
 	/* Only for symbol cards - Jean II */
-	if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
-		switch(priv->wep_auth)	{
-		case 1:
-			erq->flags |= IW_ENCODE_OPEN;
-			break;
-		case 2:
-		case 3:
+	if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) {
+		if(priv->wep_restrict)
 			erq->flags |= IW_ENCODE_RESTRICTED;
-			break;
-		case 0:
-		default:
-			break;
-		}
+		else
+			erq->flags |= IW_ENCODE_OPEN;
 	}
 
 	xlen = le16_to_cpu(priv->keys[index].len);
@@ -2520,6 +2637,92 @@
 	return err;
 }
 
+#if WIRELESS_EXT > 10
+static int dldwd_ioctl_setretry(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+
+
+	dldwd_lock(priv);
+
+	if ((rrq->disabled) || (!priv->has_retry)){
+		err = -EOPNOTSUPP;
+		goto out;
+	} else {
+		if (rrq->flags & IW_RETRY_LIMIT) {
+			if (rrq->flags & IW_RETRY_MAX)
+				priv->retry_long = rrq->value;
+			else if (rrq->flags & IW_RETRY_MIN)
+				priv->retry_short = rrq->value;
+			else {
+				/* No modifier : set both */
+				priv->retry_long = rrq->value;
+				priv->retry_short = rrq->value;
+			}
+		}
+		if (rrq->flags & IW_RETRY_LIFETIME) {
+			priv->retry_time = rrq->value / 1000;
+		}
+		if ((rrq->flags & IW_RETRY_TYPE) == 0) {
+			err = -EINVAL;
+			goto out;
+		}			
+	}
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t short_limit, long_limit, lifetime;
+
+	dldwd_lock(priv);
+	
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime);
+	if (err)
+		goto out;
+
+	rrq->disabled = 0;		/* Can't be disabled */
+
+	/* Note : by default, display the retry number */
+	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		rrq->flags = IW_RETRY_LIFETIME;
+		rrq->value = lifetime * 1000;	/* ??? */
+	} else {
+		/* By default, display the min number */
+		if ((rrq->flags & IW_RETRY_MAX)) {
+			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+			rrq->value = long_limit;
+		} else {
+			rrq->flags = IW_RETRY_LIMIT;
+			rrq->value = short_limit;
+			if(short_limit != long_limit)
+				rrq->flags |= IW_RETRY_MIN;
+		}
+	}
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+#endif /* WIRELESS_EXT > 10 */
+
 static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
 {
 	dldwd_priv_t *priv = dev->priv;
@@ -2549,6 +2752,10 @@
 		err = -EINVAL;
 	}
 
+	if (! err)
+		/* Actually update the mode we are using */
+		set_port_type(priv);
+
 	dldwd_unlock(priv);
 
 	return err;
@@ -2858,6 +3065,20 @@
 		wrq->u.txpower.flags = IW_TXPOW_DBM;
 		break;
 
+#if WIRELESS_EXT > 10
+	case SIOCSIWRETRY:
+		DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name);
+		err = dldwd_ioctl_setretry(dev, &wrq->u.retry);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWRETRY:
+		DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
+		err = dldwd_ioctl_getretry(dev, &wrq->u.retry);
+		break;
+#endif /* WIRELESS_EXT > 10 */
+
 	case SIOCSIWSPY:
 		DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
 
@@ -2880,7 +3101,13 @@
 				  0, "set_port3" },
 				{ SIOCDEVPRIVATE + 0x3, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_port3" }
+				  "get_port3" },
+				{ SIOCDEVPRIVATE + 0x4,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  0, "set_preamble" },
+				{ SIOCDEVPRIVATE + 0x5, 0,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  "get_preamble" }
 			};
 
 			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
@@ -2924,6 +3151,46 @@
 		err = dldwd_ioctl_getport3(dev, wrq);
 		break;
 
+	case SIOCDEVPRIVATE + 0x4: /* set_preamble */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+
+		/* 802.11b has recently defined some short preamble.
+		 * Basically, the Phy header has been reduced in size.
+		 * This increase performance, especially at high rates
+		 * (the preamble is transmitted at 1Mb/s), unfortunately
+		 * this give compatibility troubles... - Jean II */
+		if(priv->has_preamble) {
+			int val = *( (int *) wrq->u.name );
+
+			dldwd_lock(priv);
+			if(val)
+				priv->preamble = 1;
+			else
+				priv->preamble = 0;
+			dldwd_unlock(priv);
+			changed = 1;
+		} else
+			err = -EOPNOTSUPP;
+		break;
+
+	case SIOCDEVPRIVATE + 0x5: /* get_preamble */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n",
+		      dev->name);
+		if(priv->has_preamble) {
+			int *val = (int *)wrq->u.name;
+
+			dldwd_lock(priv);
+			*val = priv->preamble;
+			dldwd_unlock(priv);
+		} else
+			err = -EOPNOTSUPP;
+		break;
+
 	default:
 		err = -EOPNOTSUPP;
 	}
@@ -3600,6 +3867,44 @@
 	TRACE_EXIT("dldwd");
 }				/* dldwd_detach */
 
+/*
+ * Do a soft reset of the Pcmcia card using the Configuration Option Register
+ * Can't do any harm, and actually may do some good on some cards...
+ */
+static int dldwd_cor_reset(dev_link_t *link)
+{
+	conf_reg_t reg;
+	u_long default_cor; 
+
+	/* Save original COR value */
+	reg.Function = 0;
+	reg.Action = CS_READ;
+	reg.Offset = CISREG_COR;
+	reg.Value = 0;
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+	default_cor = reg.Value;
+
+	DEBUG(2, "dldwd : dldwd_cor_reset() : cor=0x%lX\n", default_cor);
+
+	/* Soft-Reset card */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_COR;
+	reg.Value = (default_cor | COR_SOFT_RESET);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Wait until the card has acknowledged our reset */
+	mdelay(1);
+
+	/* Restore original COR configuration index */
+	reg.Value = (default_cor & COR_CONFIG_MASK);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Wait until the card has finished restarting */
+	mdelay(1);
+
+	return(0);
+}
+
 /*======================================================================
   dldwd_config() is scheduled to run after a CARD_INSERTION event
   is received, to configure the PCMCIA socket, and to make the
@@ -3623,6 +3928,7 @@
 	int last_fn, last_ret;
 	u_char buf[64];
 	config_info_t conf;
+	cistpl_cftable_entry_t dflt = { 0 };
 	cisinfo_t info;
 
 	TRACE_ENTER("dldwd");
@@ -3669,7 +3975,6 @@
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	CS_CHECK(GetFirstTuple, handle, &tuple);
 	while (1) {
-		cistpl_cftable_entry_t dflt = { 0 };
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 		CFG_CHECK(GetTupleData, handle, &tuple);
 		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
@@ -3693,12 +3998,16 @@
 		/*  Note that the CIS values need to be rescaled */
 		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 			if (conf.Vcc !=
-			    cfg->vcc.param[CISTPL_POWER_VNOM] /
-			    10000) goto next_entry;
+			    cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+				DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+				goto next_entry;
+			}
 		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
 			if (conf.Vcc !=
-			    dflt.vcc.param[CISTPL_POWER_VNOM] /
-			    10000) goto next_entry;
+			    dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
+				DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+				goto next_entry;
+			}
 		}
 
 		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
@@ -3789,12 +4098,12 @@
 	ndev->base_addr = link->io.BasePort1;
 	ndev->irq = link->irq.AssignedIRQ;
 
-	/* Instance name : by default, use hermesX, on demand use the
-	 * regular ethX (less risky) - Jean II */
-	if(!eth)
-		sprintf(ndev->name, "hermes%d", priv->instance);
-	else
-		ndev->name[0] = '\0';
+	/* Do a Pcmcia soft reset of the card (optional) */
+	if(reset_cor)
+		dldwd_cor_reset(link);
+
+	/* register_netdev will give us an ethX name */
+	ndev->name[0] = '\0';
 	/* Tell the stack we exist */
 	if (register_netdev(ndev) != 0) {
 		printk(KERN_ERR "orinoco_cs: register_netdev() failed\n");
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/pcnet_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/pcnet_cs.c	Fri Apr 20 11:54:22 2001
@@ -195,6 +195,7 @@
     { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
     { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
       DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
+    { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
     { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
     { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
     { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/ray_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/ray_cs.c	Wed Apr 25 14:36:23 2001
@@ -82,7 +82,7 @@
 #define PCMCIA_DEBUG RAYLINK_DEBUG
 #endif
 #ifdef PCMCIA_DEBUG
-static int ray_debug = 0;
+static int ray_debug;
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 /* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */
@@ -172,19 +172,19 @@
 static int beacon_period = 256;
 
 /* power save mode (0 = off, 1 = save power) */
-static int psm = 0;
+static int psm;
 
 /* String for network's Extended Service Set ID. 32 Characters max */
-static char *essid = NULL;
+static char *essid;
 
 /* Default to encapsulation unless translation requested */
 static int translate = 1;
 
 static int country = USA;
 
-static int sniffer = 0;
+static int sniffer;
 
-static int bc = 0;
+static int bc;
 
 /* 48 bit physical card address if overriding card's real physical
  * address is required.  Since IEEE 802.11 addresses are 48 bits
@@ -1332,8 +1332,14 @@
 	  struct iw_range	range;
 	  memset((char *) &range, 0, sizeof(struct iw_range));
 
-	  /* Set the length (useless : its constant...) */
+	  /* Set the length (very important for backward compatibility) */
 	  wrq->u.data.length = sizeof(struct iw_range);
+
+#if WIRELESS_EXT > 10
+	  /* Set the Wireless Extension versions */
+	  range.we_version_compiled = WIRELESS_EXT;
+	  range.we_version_source = 9;
+#endif /* WIRELESS_EXT > 10 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.1 * 1000 * 1000;	/* Put the right number here */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/smc91c92_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Wed Apr 18 14:40:05 2001
@@ -76,7 +76,7 @@
    1 = 10baseT (and autoselect if #define AUTOSELECT),
    2 = AUI/10base2,
 */
-static int if_port = 0;
+static int if_port;
 
 /* Bit map of interrupts to choose from. */
 static u_int irq_mask = 0xdeb8;
@@ -100,7 +100,7 @@
 
 static dev_info_t dev_info = "smc91c92_cs";
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 struct smc_private {
     dev_link_t			link;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/wavelan_cs.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Wed Apr 25 14:36:23 2001
@@ -2239,8 +2239,15 @@
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (useless : its constant...) */
+	  /* Set the length (very important for backward compatibility) */
 	  wrq->u.data.length = sizeof(struct iw_range);
+
+	  /* Set all the info we don't care or don't know about to zero */
+	  memset(&range, 0, sizeof(range));
+
+	  /* Set the Wireless Extension versions */
+	  range.we_version_compiled = WIRELESS_EXT;
+	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.4.3/linux/drivers/net/pcmcia/wavelan_cs.h	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Wed Apr 18 14:40:05 2001
@@ -737,11 +737,11 @@
 /**************************** VARIABLES ****************************/
 
 static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list = NULL;	/* Linked list of devices */
+static dev_link_t *dev_list;		/* Linked list of devices */
 
 /* WARNING : the following variable MUST be volatile
  * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int	wv_wait_completed = 0;
+static volatile int	wv_wait_completed;
 
 /*
  * Parameters that can be set with 'insmod'
@@ -754,7 +754,7 @@
 static int 	irq_list[4] = { -1 };
 
 /* Shared memory speed, in ns */
-static int	mem_speed = 0;
+static int	mem_speed;
 
 /* New module interface */
 MODULE_PARM(irq_mask, "i");
@@ -763,7 +763,7 @@
 
 #ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
 /* Enable roaming mode ? No ! Please keep this to 0 */
-static int	do_roaming = 0;
+static int	do_roaming;
 MODULE_PARM(do_roaming, "i");
 #endif	/* WAVELAN_ROAMING */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- v2.4.3/linux/drivers/net/pcmcia/xirc2ps_cs.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Wed Apr 18 14:40:05 2001
@@ -328,7 +328,7 @@
  * device numbers are used to derive the corresponding array index.
  */
 
-static dev_link_t *dev_list = NULL;
+static dev_link_t *dev_list;
 
 /****************
  * A dev_link_t structure has fields for most things that are needed
diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.4.3/linux/drivers/net/pcnet32.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcnet32.c	Thu Apr 19 22:57:06 2001
@@ -535,13 +535,12 @@
     pcnet32_dwio_reset(ioaddr);
     pcnet32_wio_reset(ioaddr);
 
-    /* Important to do the check for dwio mode first. */
-    if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
-        a = &pcnet32_dwio;
+    /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */
+    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
+	a = &pcnet32_wio;
     } else {
-        if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && 
-	    pcnet32_wio_check(ioaddr)) {
-	    a = &pcnet32_wio;
+	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+	    a = &pcnet32_dwio;
 	} else
 	    return -ENODEV;
     }
@@ -653,7 +652,13 @@
 	    promaddr[i] = inb(ioaddr + i);
 	}
 	if( memcmp( promaddr, dev->dev_addr, 6) )
-	    printk(" warning: PROM address does not match CSR address");
+	{
+	    printk(" warning PROM address does not match CSR address");
+#if defined(__i386__)
+	    printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name);
+	    memcpy(dev->dev_addr, promaddr, 6);
+#endif
+	}	    	    
     }
     /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
     if( !is_valid_ether_addr(dev->dev_addr) )
diff -u --recursive --new-file v2.4.3/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.4.3/linux/drivers/net/plip.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/plip.c	Thu Apr 19 09:34:52 2001
@@ -54,7 +54,7 @@
  *     To use with DOS box, please do (Turn on ARP switch):
  *	# ifconfig plip[0-2] arp
  */
-static const char *version = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n";
+static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n";
 
 /*
   Sources:
@@ -1293,7 +1293,7 @@
 }
 
 static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 };
-static int timid = 0;
+static int timid;
 
 MODULE_PARM(parport, "1-" __MODULE_STRING(PLIP_MAX) "i");
 MODULE_PARM(timid, "1i");
@@ -1314,7 +1314,7 @@
  * available to use. */
 static void plip_attach (struct parport *port)
 {
-	static int i = 0;
+	static int i;
 
 	if ((parport[0] == -1 && (!timid || !port->devices)) || 
 	    plip_searchfor(parport, port->number)) {
@@ -1377,7 +1377,7 @@
 
 #ifndef MODULE
 
-static int parport_ptr = 0;
+static int parport_ptr;
 
 static int __init plip_setup(char *str)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.4.3/linux/drivers/net/ppp_async.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ppp_async.c	Fri Apr 20 11:54:24 2001
@@ -244,11 +244,6 @@
 		err = 0;
 		break;
 
-	case PPPIOCATTACH:
-	case PPPIOCDETACH:
-		err = ppp_channel_ioctl(&ap->chan, cmd, arg);
-		break;
-
 	default:
 		err = -ENOIOCTLCMD;
 	}
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.4.3/linux/drivers/net/ppp_generic.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/net/ppp_generic.c	Sun Apr 22 09:46:40 2001
@@ -19,7 +19,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000417==
+ * ==FILEVERSION 20000902==
  */
 
 #include <linux/config.h>
@@ -32,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
+#include <linux/filter.h>
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
 #include <linux/ppp-comp.h>
@@ -121,6 +122,10 @@
 	struct sk_buff_head mrq;	/* MP: receive reconstruction queue */
 #endif /* CONFIG_PPP_MULTILINK */
 	struct net_device_stats stats;	/* statistics */
+#ifdef CONFIG_PPP_FILTER
+	struct sock_fprog pass_filter;	/* filter for packets to pass */
+	struct sock_fprog active_filter;/* filter for pkts to reset idle */
+#endif /* CONFIG_PPP_FILTER */
 };
 
 /*
@@ -621,6 +626,43 @@
 		err = 0;
 		break;
 
+#ifdef CONFIG_PPP_FILTER
+	case PPPIOCSPASS:
+	case PPPIOCSACTIVE:
+	{
+		struct sock_fprog uprog, *filtp;
+		struct sock_filter *code = NULL;
+		int len;
+
+		if (copy_from_user(&uprog, (void *) arg, sizeof(uprog)))
+			break;
+		if (uprog.len > 0) {
+			err = -ENOMEM;
+			len = uprog.len * sizeof(struct sock_filter);
+			code = kmalloc(len, GFP_KERNEL);
+			if (code == 0)
+				break;
+			err = -EFAULT;
+			if (copy_from_user(code, uprog.filter, len))
+				break;
+			err = sk_chk_filter(code, uprog.len);
+			if (err) {
+				kfree(code);
+				break;
+			}
+		}
+		filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter;
+		ppp_lock(ppp);
+		if (filtp->filter)
+			kfree(filtp->filter);
+		filtp->filter = code;
+		filtp->len = uprog.len;
+		ppp_unlock(ppp);
+		err = 0;
+		break;
+	}
+#endif /* CONFIG_PPP_FILTER */
+
 #ifdef CONFIG_PPP_MULTILINK
 	case PPPIOCSMRRU:
 		if (get_user(val, (int *) arg))
@@ -848,8 +890,6 @@
 	dev->tx_queue_len = 3;
 	dev->type = ARPHRD_PPP;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-
-	dev_init_buffers(dev);
 	return 0;
 }
 
@@ -892,6 +932,33 @@
 	int len;
 	unsigned char *cp;
 
+	if (proto < 0x8000) {
+#ifdef CONFIG_PPP_FILTER
+		/* check if we should pass this packet */
+		/* the filter instructions are constructed assuming
+		   a four-byte PPP header on each packet */
+		*skb_push(skb, 2) = 1;
+		if (ppp->pass_filter.filter
+		    && sk_run_filter(skb, ppp->pass_filter.filter,
+				     ppp->pass_filter.len) == 0) {
+			if (ppp->debug & 1) {
+				printk(KERN_DEBUG "PPP: outbound frame not passed\n");
+				kfree_skb(skb);
+				return;
+			}
+		}
+		/* if this packet passes the active filter, record the time */
+		if (!(ppp->active_filter.filter
+		      && sk_run_filter(skb, ppp->active_filter.filter,
+				       ppp->active_filter.len) == 0))
+			ppp->last_xmit = jiffies;
+		skb_pull(skb, 2);
+#else
+		/* for data packets, record the time */
+		ppp->last_xmit = jiffies;
+#endif /* CONFIG_PPP_FILTER */
+	}
+
 	++ppp->stats.tx_packets;
 	ppp->stats.tx_bytes += skb->len - 2;
 
@@ -964,10 +1031,6 @@
 		}
 	}
 
-	/* for data packets, record the time */
-	if (proto < 0x8000)
-		ppp->last_xmit = jiffies;
-
 	/*
 	 * If we are waiting for traffic (demand dialling),
 	 * queue it up for pppd to receive.
@@ -1402,7 +1465,29 @@
 
 	} else {
 		/* network protocol frame - give it to the kernel */
+
+#ifdef CONFIG_PPP_FILTER
+		/* check if the packet passes the pass and active filters */
+		/* the filter instructions are constructed assuming
+		   a four-byte PPP header on each packet */
+		*skb_push(skb, 2) = 0;
+		if (ppp->pass_filter.filter
+		    && sk_run_filter(skb, ppp->pass_filter.filter,
+				     ppp->pass_filter.len) == 0) {
+			if (ppp->debug & 1)
+				printk(KERN_DEBUG "PPP: inbound frame not passed\n");
+			kfree_skb(skb);
+			return;
+		}
+		if (!(ppp->active_filter.filter
+		      && sk_run_filter(skb, ppp->active_filter.filter,
+				       ppp->active_filter.len) == 0))
+			ppp->last_recv = jiffies;
+		skb_pull(skb, 2);
+#else
 		ppp->last_recv = jiffies;
+#endif /* CONFIG_PPP_FILTER */
+
 		if ((ppp->dev->flags & IFF_UP) == 0
 		    || ppp->npmode[npi] != NPMODE_PASS) {
 			kfree_skb(skb);
@@ -1808,70 +1893,6 @@
 }
 
 /*
- * This is basically temporary compatibility stuff.
- */
-ssize_t
-ppp_channel_read(struct ppp_channel *chan, struct file *file,
-		 char *buf, size_t count)
-{
-	struct channel *pch = chan->ppp;
-
-	if (pch == 0)
-		return -ENXIO;
-	return ppp_file_read(&pch->file, file, buf, count);
-}
-
-ssize_t
-ppp_channel_write(struct ppp_channel *chan, const char *buf, size_t count)
-{
-	struct channel *pch = chan->ppp;
-
-	if (pch == 0)
-		return -ENXIO;
-	return ppp_file_write(&pch->file, buf, count);
-}
-
-/* No kernel lock - fine */
-unsigned int
-ppp_channel_poll(struct ppp_channel *chan, struct file *file, poll_table *wait)
-{
-	unsigned int mask;
-	struct channel *pch = chan->ppp;
-
-	mask = POLLOUT | POLLWRNORM;
-	if (pch != 0) {
-		poll_wait(file, &pch->file.rwait, wait);
-		if (skb_peek(&pch->file.rq) != 0)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	return mask;
-}
-
-int ppp_channel_ioctl(struct ppp_channel *chan, unsigned int cmd,
-		      unsigned long arg)
-{
-	struct channel *pch = chan->ppp;
-	int err = -ENOTTY;
-	int unit;
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-	if (pch == 0)
-		return -EINVAL;
-	switch (cmd) {
-	case PPPIOCATTACH:
-		if (get_user(unit, (int *) arg))
-			break;
-		err = ppp_connect_channel(pch, unit);
-		break;
-	case PPPIOCDETACH:
-		err = ppp_disconnect_channel(pch);
-		break;
-	}
-	return err;
-}
-
-/*
  * Compression control.
  */
 
@@ -1967,15 +1988,30 @@
 
 	switch (CCP_CODE(dp)) {
 	case CCP_CONFREQ:
+
+		/* A ConfReq starts negotiation of compression 
+		 * in one direction of transmission,
+		 * and hence brings it down...but which way?
+		 *
+		 * Remember:
+		 * A ConfReq indicates what the sender would like to receive
+		 */
+		if(inbound)
+			/* He is proposing what I should send */
+			ppp->xstate &= ~SC_COMP_RUN;
+		else	
+			/* I am proposing to what he should send */
+			ppp->rstate &= ~SC_DECOMP_RUN;
+		
+		break;
+		
 	case CCP_TERMREQ:
 	case CCP_TERMACK:
 		/*
-		 * CCP is going down - disable compression.
+		 * CCP is going down, both directions of transmission 
 		 */
-		if (inbound)
-			ppp->rstate &= ~SC_DECOMP_RUN;
-		else
-			ppp->xstate &= ~SC_COMP_RUN;
+		ppp->rstate &= ~SC_DECOMP_RUN;
+		ppp->xstate &= ~SC_COMP_RUN;
 		break;
 
 	case CCP_CONFACK:
@@ -2194,6 +2230,7 @@
 	ppp->file.index = unit;
 	ppp->mru = PPP_MRU;
 	init_ppp_file(&ppp->file, INTERFACE);
+	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
 	for (i = 0; i < NUM_NP; ++i)
 		ppp->npmode[i] = NPMODE_PASS;
 	INIT_LIST_HEAD(&ppp->channels);
@@ -2265,6 +2302,16 @@
 #ifdef CONFIG_PPP_MULTILINK
 	skb_queue_purge(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
+#ifdef CONFIG_PPP_FILTER
+	if (ppp->pass_filter.filter) {
+		kfree(ppp->pass_filter.filter);
+		ppp->pass_filter.filter = NULL;
+	}
+	if (ppp->active_filter.filter) {
+		kfree(ppp->active_filter.filter);
+		ppp->active_filter.filter = 0;
+	}
+#endif /* CONFIG_PPP_FILTER */
 	dev = ppp->dev;
 	ppp->dev = 0;
 	ppp_unlock(ppp);
@@ -2431,9 +2478,5 @@
 EXPORT_SYMBOL(ppp_output_wakeup);
 EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
-EXPORT_SYMBOL(ppp_channel_read);
-EXPORT_SYMBOL(ppp_channel_write);
-EXPORT_SYMBOL(ppp_channel_poll);
-EXPORT_SYMBOL(ppp_channel_ioctl);
 EXPORT_SYMBOL(all_ppp_units); /* for debugging */
 EXPORT_SYMBOL(all_channels); /* for debugging */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c
--- v2.4.3/linux/drivers/net/ppp_synctty.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ppp_synctty.c	Fri Apr 20 11:54:24 2001
@@ -233,31 +233,25 @@
 }
 
 /*
- * Read a PPP frame, for compatibility until pppd is updated.
+ * Read does nothing - no data is ever available this way.
+ * Pppd reads and writes packets via /dev/ppp instead.
  */
 static ssize_t
 ppp_sync_read(struct tty_struct *tty, struct file *file,
 	       unsigned char *buf, size_t count)
 {
-	struct syncppp *ap = tty->disc_data;
-
-	if (ap == 0)
-		return -ENXIO;
-	return ppp_channel_read(&ap->chan, file, buf, count);
+	return -EAGAIN;
 }
 
 /*
- * Write a ppp frame, for compatibility until pppd is updated.
+ * Write on the tty does nothing, the packets all come in
+ * from the ppp generic stuff.
  */
 static ssize_t
 ppp_sync_write(struct tty_struct *tty, struct file *file,
 		const unsigned char *buf, size_t count)
 {
-	struct syncppp *ap = tty->disc_data;
-
-	if (ap == 0)
-		return -ENXIO;
-	return ppp_channel_write(&ap->chan, buf, count);
+	return -EAGAIN;
 }
 
 static int
@@ -308,30 +302,6 @@
 		err = 0;
 		break;
 
-	/*
-	 * Compatibility calls until pppd is updated.
-	 */
-	case PPPIOCGFLAGS:
-	case PPPIOCSFLAGS:
-	case PPPIOCGASYNCMAP:
-	case PPPIOCSASYNCMAP:
-	case PPPIOCGRASYNCMAP:
-	case PPPIOCSRASYNCMAP:
-	case PPPIOCGXASYNCMAP:
-	case PPPIOCSXASYNCMAP:
-	case PPPIOCGMRU:
-	case PPPIOCSMRU:
-		err = -EPERM;
-		if (!capable(CAP_NET_ADMIN))
-			break;
-		err = ppp_sync_ioctl(&ap->chan, cmd, arg);
-		break;
-
-	case PPPIOCATTACH:
-	case PPPIOCDETACH:
-		err = ppp_channel_ioctl(&ap->chan, cmd, arg);
-		break;
-
 	default:
 		err = -ENOIOCTLCMD;
 	}
@@ -343,16 +313,7 @@
 static unsigned int
 ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 {
-	struct syncppp *ap = tty->disc_data;
-	unsigned int mask;
-
-	mask = POLLOUT | POLLWRNORM;
-	/* compatibility for old pppd */
-	if (ap != 0)
-		mask |= ppp_channel_poll(&ap->chan, file, wait);
-	if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file))
-		mask |= POLLHUP;
-	return mask;
+	return 0;
 }
 
 static int
diff -u --recursive --new-file v2.4.3/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c
--- v2.4.3/linux/drivers/net/ptifddi.c	Tue Jul 11 15:46:08 2000
+++ linux/drivers/net/ptifddi.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: ptifddi.c,v 1.13 2000/07/11 22:35:22 davem Exp $
+/* $Id: ptifddi.c,v 1.14 2001/04/14 01:12:04 davem Exp $
  * ptifddi.c: Network driver for Performance Technologies single-attach
  *            and dual-attach FDDI sbus cards.
  *
@@ -16,7 +16,7 @@
 #include "ptifddi_asm.h"
 
 #ifdef MODULE
-static struct ptifddi *root_pti_dev = NULL;
+static struct ptifddi *root_pti_dev;
 #endif
 
 static inline void pti_reset(struct ptifddi *pp)
@@ -151,7 +151,7 @@
 
 static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, int num)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	struct ptifddi *pp;
 	int i;
 
@@ -208,7 +208,7 @@
 {
 	struct sbus_bus *bus;
 	struct sbus_dev *sdev = 0;
-	static int called = 0;
+	static int called;
 	int cards = 0, v;
 
 	if(called)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.4.3/linux/drivers/net/rcpci45.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/rcpci45.c	Thu Apr 12 12:15:25 2001
@@ -91,7 +91,7 @@
 #define DEFAULT_RECV_INIT_CONTEXT  0xA17  
 
 
-static U32 DriverControlWord =  0;
+static U32 DriverControlWord;
 
 static void rc_timer(unsigned long);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c
--- v2.4.3/linux/drivers/net/rrunner.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/rrunner.c	Wed Apr 18 14:40:04 2001
@@ -104,7 +104,7 @@
 
 static char version[] __initdata = "rrunner.c: v0.22 03/01/2000  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
 
-static struct net_device *root_dev = NULL;
+static struct net_device *root_dev;
 
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/net/saa9730.c linux/drivers/net/saa9730.c
--- v2.4.3/linux/drivers/net/saa9730.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/saa9730.c	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,1082 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * SAA9730 ethernet driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+
+#include <asm/addrspace.h>
+#include <asm/mips-boards/prom.h>
+
+#include "saa9730.h"
+
+#ifdef LAN_SAA9730_DEBUG
+int lan_saa9730_debug = LAN_SAA9730_DEBUG;
+#else
+int lan_saa9730_debug;
+#endif
+
+
+/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
+static unsigned int pci_irq_line = 0;
+
+#define INL(a)     inl((unsigned long)a)
+#define OUTL(x,a)  outl(x,(unsigned long)a)
+
+static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp)
+{
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
+	     &lp->evm_saa9730_regs->InterruptBlock1);
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT,
+	     &lp->evm_saa9730_regs->InterruptStatus1);
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT |
+	     EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1);
+}
+static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp)
+{
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
+	     &lp->evm_saa9730_regs->InterruptBlock1);
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT,
+	     &lp->evm_saa9730_regs->InterruptEnable1);
+}
+
+static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp)
+{
+	OUTL(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1);
+}
+
+static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp)
+{
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
+	     &lp->evm_saa9730_regs->InterruptBlock1);
+}
+
+static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
+{
+	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
+	     &lp->evm_saa9730_regs->InterruptBlock1);
+}
+
+static void show_saa9730_regs(struct lan_saa9730_private *lp)
+{
+	int i, j;
+	printk("TxmBufferA = %x\n", lp->TxmBuffer[0][0]);
+	printk("TxmBufferB = %x\n", lp->TxmBuffer[1][0]);
+	printk("RcvBufferA = %x\n", lp->RcvBuffer[0][0]);
+	printk("RcvBufferB = %x\n", lp->RcvBuffer[1][0]);
+	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+		for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
+			printk("TxmBuffer[%d][%d] = %x\n", i, j,
+			       le32_to_cpu(*(unsigned int *)
+					   lp->TxmBuffer[i][j]));
+		}
+	}
+	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+		for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
+			printk("RcvBuffer[%d][%d] = %x\n", i, j,
+			       le32_to_cpu(*(unsigned int *)
+					   lp->RcvBuffer[i][j]));
+		}
+	}
+	printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n",
+	       INL(&lp->evm_saa9730_regs->InterruptBlock1));
+	printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n",
+	       INL(&lp->evm_saa9730_regs->InterruptStatus1));
+	printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n",
+	       INL(&lp->evm_saa9730_regs->InterruptEnable1));
+	printk("lp->lan_saa9730_regs->Ok2Use = %x\n",
+	       INL(&lp->lan_saa9730_regs->Ok2Use));
+	printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex);
+	printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex);
+	printk("lp->PendingTxmBufferIndex = %x\n",
+	       lp->PendingTxmBufferIndex);
+	printk("lp->PendingTxmPacketIndex = %x\n",
+	       lp->PendingTxmPacketIndex);
+	printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n",
+	       INL(&lp->lan_saa9730_regs->LanDmaCtl));
+	printk("lp->lan_saa9730_regs->DmaStatus = %x\n",
+	       INL(&lp->lan_saa9730_regs->DmaStatus));
+	printk("lp->lan_saa9730_regs->CamCtl = %x\n",
+	       INL(&lp->lan_saa9730_regs->CamCtl));
+	printk("lp->lan_saa9730_regs->TxCtl = %x\n",
+	       INL(&lp->lan_saa9730_regs->TxCtl));
+	printk("lp->lan_saa9730_regs->TxStatus = %x\n",
+	       INL(&lp->lan_saa9730_regs->TxStatus));
+	printk("lp->lan_saa9730_regs->RxCtl = %x\n",
+	       INL(&lp->lan_saa9730_regs->RxCtl));
+	printk("lp->lan_saa9730_regs->RxStatus = %x\n",
+	       INL(&lp->lan_saa9730_regs->RxStatus));
+	for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
+		OUTL(i, &lp->lan_saa9730_regs->CamAddress);
+		printk("lp->lan_saa9730_regs->CamData = %x\n",
+		       INL(&lp->lan_saa9730_regs->CamData));
+	}
+	printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
+	printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
+	printk("lp->stats.tx_aborted_errors = %lx\n",
+	       lp->stats.tx_aborted_errors);
+	printk("lp->stats.tx_window_errors = %lx\n",
+	       lp->stats.tx_window_errors);
+	printk("lp->stats.tx_carrier_errors = %lx\n",
+	       lp->stats.tx_carrier_errors);
+	printk("lp->stats.tx_fifo_errors = %lx\n",
+	       lp->stats.tx_fifo_errors);
+	printk("lp->stats.tx_heartbeat_errors = %lx\n",
+	       lp->stats.tx_heartbeat_errors);
+	printk("lp->stats.collisions = %lx\n", lp->stats.collisions);
+
+	printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets);
+	printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors);
+	printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped);
+	printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors);
+	printk("lp->stats.rx_frame_errors = %lx\n",
+	       lp->stats.rx_frame_errors);
+	printk("lp->stats.rx_fifo_errors = %lx\n",
+	       lp->stats.rx_fifo_errors);
+	printk("lp->stats.rx_length_errors = %lx\n",
+	       lp->stats.rx_length_errors);
+
+	printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
+	       INL(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
+	printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n",
+	       INL(&lp->lan_saa9730_regs->DebugLanTxStateMachine));
+	printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n",
+	       INL(&lp->lan_saa9730_regs->DebugLanRxStateMachine));
+	printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n",
+	       INL(&lp->lan_saa9730_regs->DebugLanTxFifoPointers));
+	printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n",
+	       INL(&lp->lan_saa9730_regs->DebugLanRxFifoPointers));
+	printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n",
+	       INL(&lp->lan_saa9730_regs->DebugLanCtlStateMachine));
+}
+
+static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp)
+{
+	int i, j;
+
+	/* Init RX buffers */
+	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+		for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
+			*(unsigned int *) lp->RcvBuffer[i][j] =
+			    cpu_to_le32(RXSF_READY <<
+					RX_STAT_CTL_OWNER_SHF);
+		}
+	}
+
+	/* Init TX buffers */
+	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+		for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
+			*(unsigned int *) lp->TxmBuffer[i][j] =
+			    cpu_to_le32(TXSF_EMPTY <<
+					TX_STAT_CTL_OWNER_SHF);
+		}
+	}
+}
+
+static int lan_saa9730_allocate_buffers(struct lan_saa9730_private *lp)
+{
+	unsigned int mem_size;
+	void *Pa;
+	unsigned int i, j, RcvBufferSize, TxmBufferSize;
+	unsigned int buffer_start;
+
+	/* 
+	 * Allocate all RX and TX packets in one chunk. 
+	 * The Rx and Tx packets must be PACKET_SIZE aligned.
+	 */
+	mem_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) *
+		    LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) +
+	    LAN_SAA9730_PACKET_SIZE;
+	buffer_start =
+	    (unsigned int) kmalloc(mem_size, GFP_DMA | GFP_KERNEL);
+
+	/* 
+	 * Set DMA buffer to kseg1 (uncached).
+	 * Make sure to flush before using it uncached.
+	 */
+	Pa = (void *) KSEG1ADDR((buffer_start + LAN_SAA9730_PACKET_SIZE) &
+				~(LAN_SAA9730_PACKET_SIZE - 1));
+	dma_cache_wback_inv((unsigned long) Pa, mem_size);
+
+	/* Initialize buffer space */
+	RcvBufferSize = LAN_SAA9730_PACKET_SIZE;
+	TxmBufferSize = LAN_SAA9730_PACKET_SIZE;
+	lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE;
+	lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE;
+
+	/* Init RX buffers */
+	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+		for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
+			*(unsigned int *) Pa =
+			    cpu_to_le32(RXSF_READY <<
+					RX_STAT_CTL_OWNER_SHF);
+			lp->RcvBuffer[i][j] = (unsigned int) Pa;
+			Pa += RcvBufferSize;
+		}
+	}
+
+	/* Init TX buffers */
+	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+		for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
+			*(unsigned int *) Pa =
+			    cpu_to_le32(TXSF_EMPTY <<
+					TX_STAT_CTL_OWNER_SHF);
+			lp->TxmBuffer[i][j] = (unsigned int) Pa;
+			Pa += TxmBufferSize;
+		}
+	}
+
+	/* 
+	 * Set rx buffer A and rx buffer B to point to the first two buffer 
+	 * spaces.
+	 */
+	OUTL(PHYSADDR(lp->RcvBuffer[0][0]),
+	     &lp->lan_saa9730_regs->RxBuffA);
+	OUTL(PHYSADDR(lp->RcvBuffer[1][0]),
+	     &lp->lan_saa9730_regs->RxBuffB);
+
+	/* Initialize Buffer Index */
+	lp->NextRcvPacketIndex = 0;
+	lp->NextRcvToUseIsA = 1;
+
+	/* Set current buffer index & next availble packet index */
+	lp->NextTxmPacketIndex = 0;
+	lp->NextTxmBufferIndex = 0;
+	lp->PendingTxmPacketIndex = 0;
+	lp->PendingTxmBufferIndex = 0;
+
+	/* 
+	 * Set txm_buf_a and txm_buf_b to point to the first two buffer
+	 * space 
+	 */
+	OUTL(PHYSADDR(lp->TxmBuffer[0][0]),
+	     &lp->lan_saa9730_regs->TxBuffA);
+	OUTL(PHYSADDR(lp->TxmBuffer[1][0]),
+	     &lp->lan_saa9730_regs->TxBuffB);
+
+	/* Set packet number */
+	OUTL((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) |
+	     (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) |
+	     (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) |
+	     (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF),
+	     &lp->lan_saa9730_regs->PacketCount);
+
+	return 0;
+}
+
+static int lan_saa9730_cam_load(struct lan_saa9730_private *lp)
+{
+	unsigned int i;
+	unsigned char *NetworkAddress;
+
+	NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0];
+
+	for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
+		/* First set address to where data is written */
+		OUTL(i, &lp->lan_saa9730_regs->CamAddress);
+		OUTL((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16)
+		     | (NetworkAddress[2] << 8) | NetworkAddress[3],
+		     &lp->lan_saa9730_regs->CamData);
+		NetworkAddress += 4;
+	}
+	return 0;
+}
+
+static int lan_saa9730_cam_init(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+	unsigned int i;
+
+	/* Copy MAC-address into all entries. */
+	for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) {
+		memcpy((unsigned char *) lp->PhysicalAddress[i],
+		       (unsigned char *) dev->dev_addr, 6);
+	}
+
+	return 0;
+}
+
+static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
+{
+	int i, l;
+
+	/* Check link status, spin here till station is not busy. */
+	i = 0;
+	while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
+		i++;
+		if (i > 100) {
+			printk("Error: lan_saa9730_mii_init: timeout\n");
+			return -1;
+		}
+		udelay(1000);	/* wait 1 ms. */
+	}
+
+	/* Now set the control and address register. */
+	OUTL(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF,
+	     &lp->lan_saa9730_regs->StationMgmtCtl);
+
+	/* check link status, spin here till station is not busy */
+	i = 0;
+	while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
+		i++;
+		if (i > 100) {
+			printk("Error: lan_saa9730_mii_init: timeout\n");
+			return -1;
+		}
+		udelay(1000);	/* wait 1 ms. */
+	}
+
+	/* Wait for 1 ms. */
+	udelay(1000);
+
+	/* Check the link status. */
+	if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
+	    PHY_STATUS_LINK_UP) {
+		/* Link is up. */
+		return 0;
+	} else {
+		/* Link is down, reset the PHY first. */
+
+		/* set PHY address = 'CONTROL' */
+		OUTL(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL,
+		     &lp->lan_saa9730_regs->StationMgmtCtl);
+
+		/* Wait for 1 ms. */
+		udelay(1000);
+
+		/* set 'CONTROL' = force reset and renegotiate */
+		OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
+		     PHY_CONTROL_RESTART_AUTO_NEG,
+		     &lp->lan_saa9730_regs->StationMgmtData);
+
+		/* Wait for 50 ms. */
+		udelay(50 * 1000);
+
+		/* set 'BUSY' to start operation */
+		OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
+		     PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl);
+
+		/* await completion */
+		i = 0;
+		while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
+		       MD_CA_BUSY) {
+			i++;
+			if (i > 100) {
+				printk
+				    ("Error: lan_saa9730_mii_init: timeout\n");
+				return -1;
+			}
+			udelay(1000);	/* wait 1 ms. */
+		}
+
+		/* Wait for 1 ms. */
+		udelay(1000);
+
+		for (l = 0; l < 2; l++) {
+			/* set PHY address = 'STATUS' */
+			OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF |
+			     PHY_STATUS,
+			     &lp->lan_saa9730_regs->StationMgmtCtl);
+
+			/* await completion */
+			i = 0;
+			while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
+			       MD_CA_BUSY) {
+				i++;
+				if (i > 100) {
+					printk
+					    ("Error: lan_saa9730_mii_init: timeout\n");
+					return -1;
+				}
+				udelay(1000);	/* wait 1 ms. */
+			}
+
+			/* wait for 3 sec. */
+			udelay(3000 * 1000);
+
+			/* check the link status */
+			if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
+			    PHY_STATUS_LINK_UP) {
+				/* link is up */
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int lan_saa9730_control_init(struct lan_saa9730_private *lp)
+{
+	/* Initialize DMA control register. */
+	OUTL((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) |
+	     (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) |
+	     (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF)
+	     | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN |
+	     DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN,
+	     &lp->lan_saa9730_regs->LanDmaCtl);
+
+	/* Initial MAC control register. */
+	OUTL((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP,
+	     &lp->lan_saa9730_regs->MacCtl);
+
+	/* Initialize CAM control register. */
+	OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC,
+	     &lp->lan_saa9730_regs->CamCtl);
+
+	/* 
+	 * Initialize CAM enable register, only turn on first entry, should
+	 * contain own addr. 
+	 */
+	OUTL(0x0001, &lp->lan_saa9730_regs->CamEnable);
+
+	/* Initialize Tx control register */
+	OUTL(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl);
+
+	/* Initialize Rcv control register */
+	OUTL(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl);
+
+	/* Reset DMA engine */
+	OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
+
+	return 0;
+}
+
+static int lan_saa9730_stop(struct lan_saa9730_private *lp)
+{
+	int i;
+
+	/* Stop DMA first */
+	OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) &
+	     ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA),
+	     &lp->lan_saa9730_regs->LanDmaCtl);
+
+	/* Set the SW Reset bits in DMA and MAC control registers */
+	OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
+	OUTL(INL(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET,
+	     &lp->lan_saa9730_regs->MacCtl);
+
+	/* 
+	 * Wait for MAC reset to have finished. The reset bit is auto cleared
+	 * when the reset is done.
+	 */
+	i = 0;
+	while (INL(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) {
+		i++;
+		if (i > 100) {
+			printk
+			    ("Error: lan_sa9730_stop: MAC reset timeout\n");
+			return -1;
+		}
+		udelay(1000);	/* wait 1 ms. */
+	}
+
+	return 0;
+}
+
+static int lan_saa9730_dma_init(struct lan_saa9730_private *lp)
+{
+	/* Stop lan controller. */
+	lan_saa9730_stop(lp);
+
+	OUTL(LAN_SAA9730_DEFAULT_TIME_OUT_CNT,
+	     &lp->lan_saa9730_regs->Timeout);
+
+	return 0;
+}
+
+static int lan_saa9730_start(struct lan_saa9730_private *lp)
+{
+	lan_saa9730_buffer_init(lp);
+
+	/* Initialize Rx Buffer Index */
+	lp->NextRcvPacketIndex = 0;
+	lp->NextRcvToUseIsA = 1;
+
+	/* Set current buffer index & next availble packet index */
+	lp->NextTxmPacketIndex = 0;
+	lp->NextTxmBufferIndex = 0;
+	lp->PendingTxmPacketIndex = 0;
+	lp->PendingTxmBufferIndex = 0;
+
+	OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA |
+	     DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl);
+
+	/* For Tx, turn on MAC then DMA */
+	OUTL(INL(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN,
+	     &lp->lan_saa9730_regs->TxCtl);
+
+	/* For Rx, turn on DMA then MAC */
+	OUTL(INL(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN,
+	     &lp->lan_saa9730_regs->RxCtl);
+
+	/* Set Ok2Use to let hardware owns the buffers */
+	OUTL(OK2USE_RX_A | OK2USE_RX_B | OK2USE_TX_A | OK2USE_TX_B,
+	     &lp->lan_saa9730_regs->Ok2Use);
+
+	return 0;
+}
+
+static int lan_saa9730_restart(struct lan_saa9730_private *lp)
+{
+	lan_saa9730_stop(lp);
+	lan_saa9730_start(lp);
+
+	return 0;
+}
+
+static int lan_saa9730_tx(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+	unsigned int *pPacket;
+	unsigned int tx_status;
+
+	if (lan_saa9730_debug > 5)
+		printk("lan_saa9730_tx interrupt\n");
+
+	/* Clear interrupt. */
+	OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus);
+
+	while (1) {
+		pPacket =
+		    (unsigned int *) lp->TxmBuffer[lp->
+						   PendingTxmBufferIndex]
+		    [lp->PendingTxmPacketIndex];
+
+		/* Get status of first packet transmitted. */
+		tx_status = le32_to_cpu(*pPacket);
+
+		/* Check ownership. */
+		if ((tx_status & TX_STAT_CTL_OWNER_MSK) !=
+		    (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break;
+
+		/* Check for error. */
+		if (tx_status & TX_STAT_CTL_ERROR_MSK) {
+			if (lan_saa9730_debug > 1)
+				printk("lan_saa9730_tx: tx error = %x\n",
+				       tx_status);
+
+			lp->stats.tx_errors++;
+			if (tx_status &
+			    (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
+				    lp->stats.tx_aborted_errors++;
+			if (tx_status &
+			    (TX_STATUS_LATE_COLL <<
+			     TX_STAT_CTL_STATUS_SHF)) lp->stats.
+	     tx_window_errors++;
+			if (tx_status &
+			    (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
+				    lp->stats.tx_carrier_errors++;
+			if (tx_status &
+			    (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
+				    lp->stats.tx_fifo_errors++;
+			if (tx_status &
+			    (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
+				    lp->stats.tx_heartbeat_errors++;
+
+			lp->stats.collisions +=
+			    tx_status & TX_STATUS_TX_COLL_MSK;
+		}
+
+		/* Free buffer. */
+		*pPacket =
+		    cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF);
+
+		/* Update pending index pointer. */
+		lp->PendingTxmPacketIndex++;
+		if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) {
+			lp->PendingTxmPacketIndex = 0;
+			lp->PendingTxmBufferIndex ^= 1;
+		}
+	}
+
+	/* Make sure A and B are available to hardware. */
+	OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
+
+	if (netif_queue_stopped(dev)) {
+		/* The tx buffer is no longer full. */
+		netif_wake_queue(dev);
+	}
+
+	return 0;
+}
+
+static int lan_saa9730_rx(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+	int len = 0;
+	struct sk_buff *skb = 0;
+	unsigned int rx_status;
+	int BufferIndex;
+	int PacketIndex;
+	unsigned int *pPacket;
+	unsigned char *pData;
+
+	if (lan_saa9730_debug > 5)
+		printk("lan_saa9730_rx interrupt\n");
+
+	/* Clear receive interrupts. */
+	OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
+	     DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus);
+
+	/* Address next packet */
+	if (lp->NextRcvToUseIsA)
+		BufferIndex = 0;
+	else
+		BufferIndex = 1;
+	PacketIndex = lp->NextRcvPacketIndex;
+	pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex];
+	rx_status = le32_to_cpu(*pPacket);
+
+	/* Process each packet. */
+	while ((rx_status & RX_STAT_CTL_OWNER_MSK) ==
+	       (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) {
+		/* Check the rx status. */
+		if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) {
+			/* Received packet is good. */
+			len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >>
+			    RX_STAT_CTL_LENGTH_SHF;
+
+			pData = (unsigned char *) pPacket;
+			pData += 4;
+			skb = dev_alloc_skb(len + 2);
+			if (skb == 0) {
+				printk
+				    ("%s: Memory squeeze, deferring packet.\n",
+				     dev->name);
+				lp->stats.rx_dropped++;
+			} else {
+				lp->stats.rx_bytes += len;
+				lp->stats.rx_packets++;
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align */
+				skb_put(skb, len);	/* make room */
+				eth_copy_and_sum(skb,
+						 (unsigned char *) pData,
+						 len, 0);
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+			}
+		} else {
+			/* We got an error packet. */
+			if (lan_saa9730_debug > 2)
+				printk
+				    ("lan_saa9730_rx: We got an error packet = %x\n",
+				     rx_status);
+
+			lp->stats.rx_errors++;
+			if (rx_status &
+			    (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
+				    lp->stats.rx_crc_errors++;
+			if (rx_status &
+			    (RX_STATUS_ALIGN_ERR <<
+			     RX_STAT_CTL_STATUS_SHF)) lp->stats.
+	     rx_frame_errors++;
+			if (rx_status &
+			    (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
+				    lp->stats.rx_fifo_errors++;
+			if (rx_status &
+			    (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
+				    lp->stats.rx_length_errors++;
+		}
+
+		/* Indicate we have processed the buffer. */
+		*pPacket =
+		    cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF);
+
+		/* Go to next packet in sequence. */
+		lp->NextRcvPacketIndex++;
+		if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) {
+			lp->NextRcvPacketIndex = 0;
+			if (BufferIndex) {
+				lp->NextRcvToUseIsA = 1;
+			} else {
+				lp->NextRcvToUseIsA = 0;
+			}
+		}
+		OUTL(OK2USE_RX_A | OK2USE_RX_B,
+		     &lp->lan_saa9730_regs->Ok2Use);
+
+		/* Address next packet */
+		if (lp->NextRcvToUseIsA)
+			BufferIndex = 0;
+		else
+			BufferIndex = 1;
+		PacketIndex = lp->NextRcvPacketIndex;
+		pPacket =
+		    (unsigned int *) lp->
+		    RcvBuffer[BufferIndex][PacketIndex];
+		rx_status = le32_to_cpu(*pPacket);
+	}
+
+	/* Make sure A and B are available to hardware. */
+	OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use);
+
+	return 0;
+}
+
+static void lan_saa9730_interrupt(const int irq, void *dev_id,
+				  struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+
+	if (lan_saa9730_debug > 5)
+		printk("lan_saa9730_interrupt\n");
+
+	/* Disable the EVM LAN interrupt. */
+	evm_saa9730_block_lan_int(lp);
+
+	/* Clear the EVM LAN interrupt. */
+	evm_saa9730_clear_lan_int(lp);
+
+	/* Service pending transmit interrupts. */
+	if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT)
+		lan_saa9730_tx(dev);
+
+	/* Service pending receive interrupts. */
+	if (INL(&lp->lan_saa9730_regs->DmaStatus) &
+	    (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
+	     DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev);
+
+	/* Enable the EVM LAN interrupt. */
+	evm_saa9730_unblock_lan_int(lp);
+
+	return;
+}
+
+static int lan_saa9730_open_fail(struct net_device *dev)
+{
+	return -ENODEV;
+}
+
+static int lan_saa9730_open(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+
+	/* Associate IRQ with lan_saa9730_interrupt */
+	if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth",
+			dev)) {
+		printk("lan_saa9730_open: Can't get irq %d\n", dev->irq);
+		return -EAGAIN;
+	}
+
+	/* Enable the Lan interrupt in the event manager. */
+	evm_saa9730_enable_lan_int(lp);
+
+	/* Start the LAN controller */
+	if (lan_saa9730_start(lp))
+		return -1;
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static int lan_saa9730_write(struct lan_saa9730_private *lp,
+			     struct sk_buff *skb, int skblen)
+{
+	unsigned char *pbData = skb->data;
+	unsigned int len = skblen;
+	unsigned char *pbPacketData;
+	unsigned int tx_status;
+	int BufferIndex;
+	int PacketIndex;
+
+	if (lan_saa9730_debug > 5)
+		printk("lan_saa9730_write: skb=%08x\n",
+		       (unsigned int) skb);
+
+	BufferIndex = lp->NextTxmBufferIndex;
+	PacketIndex = lp->NextTxmPacketIndex;
+
+	tx_status =
+	    le32_to_cpu(*(unsigned int *) lp->
+			TxmBuffer[BufferIndex][PacketIndex]);
+	if ((tx_status & TX_STAT_CTL_OWNER_MSK) !=
+	    (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) {
+		if (lan_saa9730_debug > 4)
+			printk
+			    ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n",
+			     tx_status);
+		return -1;
+	}
+
+	lp->NextTxmPacketIndex++;
+	if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) {
+		lp->NextTxmPacketIndex = 0;
+		lp->NextTxmBufferIndex ^= 1;
+	}
+
+	pbPacketData =
+	    (unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex];
+	pbPacketData += 4;
+
+	/* copy the bits */
+	memcpy(pbPacketData, pbData, len);
+
+	/* Set transmit status for hardware */
+	*(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] =
+	    cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) |
+			(TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF)
+			| (len << TX_STAT_CTL_LENGTH_SHF));
+
+	/* Set hardware tx buffer. */
+	OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
+
+	return 0;
+}
+
+static void lan_saa9730_tx_timeout(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+
+	/* Transmitter timeout, serious problems */
+	lp->stats.tx_errors++;
+	printk("%s: transmit timed out, reset\n", dev->name);
+	/*show_saa9730_regs(lp); */
+	lan_saa9730_restart(lp);
+
+	dev->trans_start = jiffies;
+	netif_start_queue(dev);
+}
+
+static int lan_saa9730_start_xmit(struct sk_buff *skb,
+				  struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+	unsigned long flags;
+	int skblen;
+	int len;
+
+	if (lan_saa9730_debug > 4)
+		printk("Send packet: skb=%08x\n", (unsigned int) skb);
+
+	skblen = skb->len;
+	save_and_cli(flags);
+	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+
+	if (lan_saa9730_write(lp, skb, skblen)) {
+		restore_flags(flags);
+		printk
+		    ("Error when writing packet to controller: skb=%08x\n",
+		     (unsigned int) skb);
+		netif_stop_queue(dev);
+		return -1;
+	}
+
+	lp->stats.tx_bytes += len;
+	lp->stats.tx_packets++;
+
+	dev->trans_start = jiffies;
+	netif_start_queue(dev);
+	dev_kfree_skb(skb);
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+static int lan_saa9730_close(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+
+	if (lan_saa9730_debug > 1)
+		printk("lan_saa9730_close:\n");
+
+	netif_stop_queue(dev);
+
+	/* Disable the Lan interrupt in the event manager. */
+	evm_saa9730_disable_lan_int(lp);
+
+	/* Stop the controller */
+	if (lan_saa9730_stop(lp))
+		return -1;
+
+	free_irq(dev->irq, (void *) dev);
+
+	return 0;
+}
+
+static struct net_device_stats *lan_saa9730_get_stats(struct net_device
+						      *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+
+	return &lp->stats;
+}
+
+static void lan_saa9730_set_multicast(struct net_device *dev)
+{
+	struct lan_saa9730_private *lp =
+	    (struct lan_saa9730_private *) dev->priv;
+
+	/* Stop the controller */
+	lan_saa9730_stop(lp);
+
+	if (dev->flags & IFF_PROMISC) {
+		/* accept all packets */
+		OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC |
+		     CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
+		     &lp->lan_saa9730_regs->CamCtl);
+	} else {
+		if (dev->flags & IFF_ALLMULTI) {
+			/* accept all multicast packets */
+			OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+			     CAM_CONTROL_BROAD_ACC,
+			     &lp->lan_saa9730_regs->CamCtl);
+		} else {
+			/* 
+			 * Will handle the multicast stuff later. -carstenl
+			 */
+		}
+	}
+
+	lan_saa9730_restart(lp);
+}
+
+static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq)
+{
+	struct lan_saa9730_private *lp;
+	unsigned char ethernet_addr[6];
+
+	dev = init_etherdev(dev, 0);
+
+	dev->open = lan_saa9730_open_fail;
+	if (get_ethernet_addr(ethernet_addr))
+		return -1;
+
+	memcpy(dev->dev_addr, ethernet_addr, 6);
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* 
+	 * Make certain the data structures used by the controller are aligned 
+	 * and DMAble. 
+	 */
+	lp = (struct lan_saa9730_private *) (((unsigned long)
+					      kmalloc(sizeof(*lp) + 7,
+						      GFP_DMA | GFP_KERNEL)
+					      + 7) & ~7);
+
+	dev->priv = lp;
+	memset(lp, 0, sizeof(*lp));
+
+	/* Set SAA9730 LAN base address. */
+	lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr +
+							 SAA9730_LAN_REGS_ADDR);
+
+	/* Set SAA9730 EVM base address. */
+	lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr +
+							 SAA9730_EVM_REGS_ADDR);
+
+	/* Allocate LAN RX/TX frame buffer space. */
+	if (lan_saa9730_allocate_buffers(lp))
+		return -1;
+
+	/* Stop LAN controller. */
+	if (lan_saa9730_stop(lp))
+		return -1;
+
+	/* Initialize CAM registers. */
+	if (lan_saa9730_cam_init(dev))
+		return -1;
+
+	/* Initialize MII registers. */
+	if (lan_saa9730_mii_init(lp))
+		return -1;
+
+	/* Initialize control registers. */
+	if (lan_saa9730_control_init(lp))
+		return -1;
+
+	/* Load CAM registers. */
+	if (lan_saa9730_cam_load(lp))
+		return -1;
+
+	/* Initialize DMA context registers. */
+	if (lan_saa9730_dma_init(lp))
+		return -1;
+
+	dev->open = lan_saa9730_open;
+	dev->hard_start_xmit = lan_saa9730_start_xmit;
+	dev->stop = lan_saa9730_close;
+	dev->get_stats = lan_saa9730_get_stats;
+	dev->set_multicast_list = lan_saa9730_set_multicast;
+	dev->tx_timeout = lan_saa9730_tx_timeout;
+	dev->watchdog_timeo = (HZ >> 1);
+	dev->dma = 0;
+
+	return 0;
+}
+
+
+static int __init saa9730_probe(void)
+{
+	struct net_device *dev = NULL;
+
+	if (pci_present()) {
+		struct pci_dev *pdev = NULL;
+		if (lan_saa9730_debug > 1)
+			printk
+			    ("saa9730.c: PCI bios is present, checking for devices...\n");
+
+		while ((pdev = pci_find_device(PCI_VENDOR_ID_PHILIPS,
+					       PCI_DEVICE_ID_PHILIPS_SAA9730,
+					       pdev))) {
+			unsigned int pci_ioaddr;
+
+			pci_irq_line = pdev->irq;
+			/* LAN base address in located at BAR 1. */
+
+			pci_ioaddr = pci_resource_start(pdev, 1);
+			pci_set_master(pdev);
+
+			printk("Found SAA9730 (PCI) at %#x, irq %d.\n",
+			       pci_ioaddr, pci_irq_line);
+			if (!lan_saa9730_init
+			    (dev, pci_ioaddr, pci_irq_line)) return 0;
+			else
+				printk("Lan init failed.\n");
+		}
+	}
+
+	return -ENODEV;
+}
+
+module_init(saa9730_probe);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/saa9730.h linux/drivers/net/saa9730.h
--- v2.4.3/linux/drivers/net/saa9730.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/saa9730.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,370 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * SAA9730 ethernet driver description.
+ *
+ */
+#ifndef _SAA9730_H
+#define _SAA9730_H
+
+
+/* Number of 6-byte entries in the CAM. */
+#define LAN_SAA9730_CAM_ENTRIES              10
+#define	LAN_SAA9730_CAM_DWORDS               ((LAN_SAA9730_CAM_ENTRIES*6)/4)
+
+/* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */
+#define LAN_SAA9730_PACKET_SIZE                       2048
+
+/* 
+ * Number of TX buffers = number of RX buffers = 2, which is fixed according 
+ * to HW requirements. 
+ */
+#define LAN_SAA9730_BUFFERS                           2
+
+/* Number of RX packets per RX buffer. */
+#define LAN_SAA9730_RCV_Q_SIZE                        15
+
+/* Number of TX packets per TX buffer. */
+#define LAN_SAA9730_TXM_Q_SIZE                        15
+
+/*
+ * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD 
+ * packets received. 
+ * If however we receive less than  LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
+ * packets, the hardware can timeout after a certain time and still tell 
+ * us packets have arrived.
+ * The timeout value in unit of 32 PCI clocks (33Mhz).
+ * The value 200 approximates 0.0002 seconds.
+ */
+#define LAN_SAA9730_RCV_Q_INT_THRESHOLD               1
+#define LAN_SAA9730_DEFAULT_TIME_OUT_CNT              10
+
+#define RXSF_NDIS                       0
+#define RXSF_READY                      2
+#define RXSF_HWDONE                     3
+
+#define TXSF_EMPTY                      0
+#define TXSF_READY                      2
+#define TXSF_HWDONE                     3
+
+#define LANEND_LITTLE                   0
+#define LANEND_BIG_2143                 1
+#define LANEND_BIG_4321                 2
+
+#define LANMB_ANY                       0
+#define LANMB_8                         1
+#define LANMB_32                        2
+#define LANMB_64                        3
+
+#define MACCM_AUTOMATIC                 0
+#define MACCM_10MB                      1
+#define MACCM_MII                       2
+
+/* 
+ * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board) 
+ */
+#define PHY_CONTROL                     0x0
+#define PHY_STATUS                      0x1
+#define PHY_STATUS_LINK_UP              0x4
+#define PHY_CONTROL_RESET               0x8000
+#define PHY_CONTROL_AUTO_NEG            0x1000
+#define PHY_CONTROL_RESTART_AUTO_NEG    0x0200
+#define PHY_ADDRESS                     0x0
+
+/* PK_COUNT register. */
+#define PK_COUNT_TX_A_SHF               24
+#define PK_COUNT_TX_A_MSK               (0xff << PK_COUNT_TX_A_SHF)
+#define PK_COUNT_TX_B_SHF               16
+#define PK_COUNT_TX_B_MSK               (0xff << PK_COUNT_TX_B_SHF)
+#define PK_COUNT_RX_A_SHF               8
+#define PK_COUNT_RX_A_MSK               (0xff << PK_COUNT_RX_A_SHF)
+#define PK_COUNT_RX_B_SHF               0
+#define PK_COUNT_RX_B_MSK               (0xff << PK_COUNT_RX_B_SHF)
+
+/* OK2USE register. */
+#define OK2USE_TX_A                     0x8
+#define OK2USE_TX_B                     0x4
+#define OK2USE_RX_A                     0x2
+#define OK2USE_RX_B                     0x1
+
+/* LAN DMA CONTROL register. */
+#define DMA_CTL_BLK_INT                 0x80000000
+#define DMA_CTL_MAX_XFER_SHF            18
+#define DMA_CTL_MAX_XFER_MSK            (0x3 << LAN_DMA_CTL_MAX_XFER_SHF)
+#define DMA_CTL_ENDIAN_SHF              16
+#define DMA_CTL_ENDIAN_MSK              (0x3 << LAN_DMA_CTL_ENDIAN_SHF)
+#define DMA_CTL_RX_INT_COUNT_SHF        8
+#define DMA_CTL_RX_INT_COUNT_MSK        (0xff << LAN_DMA_CTL_RX_INT_COUNT_SHF)
+#define DMA_CTL_EN_TX_DMA               0x00000080
+#define DMA_CTL_EN_RX_DMA               0x00000040
+#define DMA_CTL_RX_INT_BUFFUL_EN        0x00000020
+#define DMA_CTL_RX_INT_TO_EN            0x00000010
+#define DMA_CTL_RX_INT_EN               0x00000008
+#define DMA_CTL_TX_INT_EN               0x00000004
+#define DMA_CTL_MAC_TX_INT_EN           0x00000002
+#define DMA_CTL_MAC_RX_INT_EN           0x00000001
+
+/* DMA STATUS register. */
+#define DMA_STATUS_BAD_ADDR_SHF         16
+#define DMA_STATUS_BAD_ADDR_MSK         (0xf << DMA_STATUS_BAD_ADDR_SHF)
+#define DMA_STATUS_RX_PKTS_RECEIVED_SHF 8
+#define DMA_STATUS_RX_PKTS_RECEIVED_MSK (0xff << DMA_STATUS_RX_PKTS_RECEIVED_SHF)
+#define DMA_STATUS_TX_EN_SYNC           0x00000080
+#define DMA_STATUS_RX_BUF_A_FUL         0x00000040
+#define DMA_STATUS_RX_BUF_B_FUL         0x00000020
+#define DMA_STATUS_RX_TO_INT            0x00000010
+#define DMA_STATUS_RX_INT               0x00000008
+#define DMA_STATUS_TX_INT               0x00000004
+#define DMA_STATUS_MAC_TX_INT           0x00000002
+#define DMA_STATUS_MAC_RX_INT           0x00000001
+
+/* DMA TEST/PANIC SWITHES register. */
+#define DMA_TEST_LOOPBACK               0x01000000
+#define DMA_TEST_SW_RESET               0x00000001
+
+/* MAC CONTROL register. */
+#define MAC_CONTROL_EN_MISS_ROLL        0x00002000
+#define MAC_CONTROL_MISS_ROLL           0x00000400
+#define MAC_CONTROL_LOOP10              0x00000080
+#define MAC_CONTROL_CONN_SHF            5
+#define MAC_CONTROL_CONN_MSK            (0x3 << MAC_CONTROL_CONN_SHF)
+#define MAC_CONTROL_MAC_LOOP            0x00000010
+#define MAC_CONTROL_FULL_DUP            0x00000008
+#define MAC_CONTROL_RESET               0x00000004
+#define MAC_CONTROL_HALT_IMM            0x00000002
+#define MAC_CONTROL_HALT_REQ            0x00000001
+
+/* CAM CONTROL register. */
+#define CAM_CONTROL_COMP_EN             0x00000010
+#define CAM_CONTROL_NEG_CAM             0x00000008
+#define CAM_CONTROL_BROAD_ACC           0x00000004
+#define CAM_CONTROL_GROUP_ACC           0x00000002
+#define CAM_CONTROL_STATION_ACC         0x00000001
+
+/* TRANSMIT CONTROL register. */
+#define TX_CTL_EN_COMP                  0x00004000
+#define TX_CTL_EN_TX_PAR                0x00002000
+#define TX_CTL_EN_LATE_COLL             0x00001000
+#define TX_CTL_EN_EX_COLL               0x00000800
+#define TX_CTL_EN_L_CARR                0x00000400
+#define TX_CTL_EN_EX_DEFER              0x00000200
+#define TX_CTL_EN_UNDER                 0x00000100
+#define TX_CTL_MII10                    0x00000080
+#define TX_CTL_SD_PAUSE                 0x00000040
+#define TX_CTL_NO_EX_DEF0               0x00000020
+#define TX_CTL_F_BACK                   0x00000010
+#define TX_CTL_NO_CRC                   0x00000008
+#define TX_CTL_NO_PAD                   0x00000004
+#define TX_CTL_TX_HALT                  0x00000002
+#define TX_CTL_TX_EN                    0x00000001
+
+/* TRANSMIT STATUS register. */
+#define TX_STATUS_SQ_ERR                0x00010000
+#define TX_STATUS_TX_HALTED             0x00008000
+#define TX_STATUS_COMP                  0x00004000
+#define TX_STATUS_TX_PAR                0x00002000
+#define TX_STATUS_LATE_COLL             0x00001000
+#define TX_STATUS_TX10_STAT             0x00000800
+#define TX_STATUS_L_CARR                0x00000400
+#define TX_STATUS_EX_DEFER              0x00000200
+#define TX_STATUS_UNDER                 0x00000100
+#define TX_STATUS_IN_TX                 0x00000080
+#define TX_STATUS_PAUSED                0x00000040
+#define TX_STATUS_TX_DEFERRED           0x00000020
+#define TX_STATUS_EX_COLL               0x00000010
+#define TX_STATUS_TX_COLL_SHF           0
+#define TX_STATUS_TX_COLL_MSK           (0xf << TX_STATUS_TX_COLL_SHF)
+
+/* RECEIVE CONTROL register. */
+#define RX_CTL_EN_GOOD                  0x00004000
+#define RX_CTL_EN_RX_PAR                0x00002000
+#define RX_CTL_EN_LONG_ERR              0x00000800
+#define RX_CTL_EN_OVER                  0x00000400
+#define RX_CTL_EN_CRC_ERR               0x00000200
+#define RX_CTL_EN_ALIGN                 0x00000100
+#define RX_CTL_IGNORE_CRC               0x00000040
+#define RX_CTL_PASS_CTL                 0x00000020
+#define RX_CTL_STRIP_CRC                0x00000010
+#define RX_CTL_SHORT_EN                 0x00000008
+#define RX_CTL_LONG_EN                  0x00000004
+#define RX_CTL_RX_HALT                  0x00000002
+#define RX_CTL_RX_EN                    0x00000001
+
+/* RECEIVE STATUS register. */
+#define RX_STATUS_RX_HALTED             0x00008000
+#define RX_STATUS_GOOD                  0x00004000
+#define RX_STATUS_RX_PAR                0x00002000
+#define RX_STATUS_LONG_ERR              0x00000800
+#define RX_STATUS_OVERFLOW              0x00000400
+#define RX_STATUS_CRC_ERR               0x00000200
+#define RX_STATUS_ALIGN_ERR             0x00000100
+#define RX_STATUS_RX10_STAT             0x00000080
+#define RX_STATUS_INT_RX                0x00000040
+#define RX_STATUS_CTL_RECD              0x00000020
+
+/* MD_CA register. */
+#define MD_CA_PRE_SUP                   0x00001000
+#define MD_CA_BUSY                      0x00000800
+#define MD_CA_WR                        0x00000400
+#define MD_CA_PHY_SHF                   5
+#define MD_CA_PHY_MSK                   (0x1f << MD_CA_PHY_SHF)
+#define MD_CA_ADDR_SHF                  0
+#define MD_CA_ADDR_MSK                  (0x1f << MD_CA_ADDR_SHF)
+
+/* Tx Status/Control. */
+#define TX_STAT_CTL_OWNER_SHF           30
+#define TX_STAT_CTL_OWNER_MSK           (0x3 << TX_STAT_CTL_OWNER_SHF)
+#define TX_STAT_CTL_FRAME_SHF           27
+#define TX_STAT_CTL_FRAME_MSK           (0x7 << TX_STAT_CTL_FRAME_SHF)
+#define TX_STAT_CTL_STATUS_SHF          11
+#define TX_STAT_CTL_STATUS_MSK          (0x1ffff << TX_STAT_CTL_STATUS_SHF)
+#define TX_STAT_CTL_LENGTH_SHF          0
+#define TX_STAT_CTL_LENGTH_MSK          (0x7ff << TX_STAT_CTL_LENGTH_SHF)
+
+#define TX_STAT_CTL_ERROR_MSK           ((TX_STATUS_SQ_ERR      |     \
+					  TX_STATUS_TX_HALTED   |     \
+					  TX_STATUS_TX_PAR      |     \
+					  TX_STATUS_LATE_COLL   |     \
+					  TX_STATUS_L_CARR      |     \
+					  TX_STATUS_EX_DEFER    |     \
+					  TX_STATUS_UNDER       |     \
+					  TX_STATUS_PAUSED      |     \
+					  TX_STATUS_TX_DEFERRED |     \
+					  TX_STATUS_EX_COLL     |     \
+					  TX_STATUS_TX_COLL_MSK)      \
+                                                    << TX_STAT_CTL_STATUS_SHF)
+#define TX_STAT_CTL_INT_AFTER_TX        0x4
+
+/* Rx Status/Control. */
+#define RX_STAT_CTL_OWNER_SHF           30
+#define RX_STAT_CTL_OWNER_MSK           (0x3 << RX_STAT_CTL_OWNER_SHF)
+#define RX_STAT_CTL_STATUS_SHF          11
+#define RX_STAT_CTL_STATUS_MSK          (0xffff << RX_STAT_CTL_STATUS_SHF)
+#define RX_STAT_CTL_LENGTH_SHF          0
+#define RX_STAT_CTL_LENGTH_MSK          (0x7ff << RX_STAT_CTL_LENGTH_SHF)
+
+
+
+/* The SAA9730 (LAN) controller register map, as seen via the PCI-bus. */
+#define SAA9730_LAN_REGS_ADDR   0x20400
+
+struct lan_saa9730_regmap {
+	volatile unsigned int TxBuffA;			/* 0x20400 */
+	volatile unsigned int TxBuffB;			/* 0x20404 */
+	volatile unsigned int RxBuffA;			/* 0x20408 */
+	volatile unsigned int RxBuffB;			/* 0x2040c */
+	volatile unsigned int PacketCount;		/* 0x20410 */
+	volatile unsigned int Ok2Use;			/* 0x20414 */
+	volatile unsigned int LanDmaCtl;		/* 0x20418 */
+	volatile unsigned int Timeout;			/* 0x2041c */
+	volatile unsigned int DmaStatus;		/* 0x20420 */
+	volatile unsigned int DmaTest;			/* 0x20424 */
+	volatile unsigned char filler20428[0x20430 - 0x20428];
+	volatile unsigned int PauseCount;		/* 0x20430 */
+	volatile unsigned int RemotePauseCount;		/* 0x20434 */
+	volatile unsigned char filler20438[0x20440 - 0x20438];
+	volatile unsigned int MacCtl;			/* 0x20440 */
+	volatile unsigned int CamCtl;			/* 0x20444 */
+	volatile unsigned int TxCtl;			/* 0x20448 */
+	volatile unsigned int TxStatus;			/* 0x2044c */
+	volatile unsigned int RxCtl;			/* 0x20450 */
+	volatile unsigned int RxStatus;			/* 0x20454 */
+	volatile unsigned int StationMgmtData;		/* 0x20458 */
+	volatile unsigned int StationMgmtCtl;		/* 0x2045c */
+	volatile unsigned int CamAddress;		/* 0x20460 */
+	volatile unsigned int CamData;			/* 0x20464 */
+	volatile unsigned int CamEnable;		/* 0x20468 */
+	volatile unsigned char filler2046c[0x20500 - 0x2046c];
+	volatile unsigned int DebugPCIMasterAddr;	/* 0x20500 */
+	volatile unsigned int DebugLanTxStateMachine;	/* 0x20504 */
+	volatile unsigned int DebugLanRxStateMachine;	/* 0x20508 */
+	volatile unsigned int DebugLanTxFifoPointers;	/* 0x2050c */
+	volatile unsigned int DebugLanRxFifoPointers;	/* 0x20510 */
+	volatile unsigned int DebugLanCtlStateMachine;	/* 0x20514 */
+};
+typedef volatile struct lan_saa9730_regmap t_lan_saa9730_regmap;
+
+
+/* EVM interrupt control registers. */
+#define EVM_LAN_INT                     0x00010000
+#define EVM_MASTER_EN                   0x00000001
+
+/* The SAA9730 (EVM) controller register map, as seen via the PCI-bus. */
+#define SAA9730_EVM_REGS_ADDR   0x02000
+
+struct evm_saa9730_regmap {
+	volatile unsigned int InterruptStatus1;		/* 0x2000 */
+	volatile unsigned int InterruptEnable1;		/* 0x2004 */
+	volatile unsigned int InterruptMonitor1;	/* 0x2008 */
+	volatile unsigned int Counter;			/* 0x200c */
+	volatile unsigned int CounterThreshold;		/* 0x2010 */
+	volatile unsigned int CounterControl;		/* 0x2014 */
+	volatile unsigned int GpioControl1;		/* 0x2018 */
+	volatile unsigned int InterruptStatus2;		/* 0x201c */
+	volatile unsigned int InterruptEnable2;		/* 0x2020 */
+	volatile unsigned int InterruptMonitor2;	/* 0x2024 */
+	volatile unsigned int GpioControl2;		/* 0x2028 */
+	volatile unsigned int InterruptBlock1;		/* 0x202c */
+	volatile unsigned int InterruptBlock2;		/* 0x2030 */
+};
+typedef volatile struct evm_saa9730_regmap t_evm_saa9730_regmap;
+
+
+struct lan_saa9730_private {
+	/* Pointer for the SAA9730 LAN controller register set. */
+	t_lan_saa9730_regmap *lan_saa9730_regs;
+
+	/* Pointer to the SAA9730 EVM register. */
+	t_evm_saa9730_regmap *evm_saa9730_regs;
+
+	/* TRUE if the next buffer to write is RxBuffA,  FALSE if RxBuffB. */
+	unsigned char NextRcvToUseIsA;
+	/* Rcv buffer Index. */
+	unsigned char NextRcvPacketIndex;
+
+	/* Index of next packet to use in that buffer. */
+	unsigned char NextTxmPacketIndex;
+	/* Next buffer index. */
+	unsigned char NextTxmBufferIndex;
+
+	/* Index of first pending packet ready to send. */
+	unsigned char PendingTxmPacketIndex;
+	/* Pending buffer index. */
+	unsigned char PendingTxmBufferIndex;
+
+	unsigned char DmaRcvPackets;
+	unsigned char DmaTxmPackets;
+
+	unsigned char RcvAIndex;	/* index into RcvBufferSpace[] for Blk A */
+	unsigned char RcvBIndex;	/* index into RcvBufferSpace[] for Blk B */
+
+	unsigned int
+	    TxmBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_TXM_Q_SIZE];
+	unsigned int
+	    RcvBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_RCV_Q_SIZE];
+	unsigned int TxBufferFree[LAN_SAA9730_BUFFERS];
+
+	unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6];
+
+	struct net_device_stats stats;
+};
+
+#endif /* _SAA9730_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c
--- v2.4.3/linux/drivers/net/sb1000.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/sb1000.c	Wed Apr 18 11:49:14 2001
@@ -191,7 +191,7 @@
 		ioaddr[0]=idev->resource[0].start;
 		ioaddr[1]=idev->resource[1].start;
 		
-		irq = idev->irq;
+		irq = idev->irq_resource[0].start;
 
 		/* check I/O base and IRQ */
 		if (dev->base_addr != 0 && dev->base_addr != ioaddr[0])
diff -u --recursive --new-file v2.4.3/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.4.3/linux/drivers/net/seeq8005.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/seeq8005.c	Thu Apr 19 09:34:52 2001
@@ -14,7 +14,7 @@
 
 */
 
-static const char *version =
+static const char version[] =
 	"seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n";
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c
--- v2.4.3/linux/drivers/net/sgiseeq.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/sgiseeq.c	Thu Apr 12 12:15:25 2001
@@ -206,7 +206,7 @@
 
 void sgiseeq_dump_rings(void)
 {
-	static int once = 0;
+	static int once;
 	struct sgiseeq_rx_desc *r = gpriv->srings.rx_desc;
 	struct sgiseeq_tx_desc *t = gpriv->srings.tx_desc;
 	volatile struct hpc3_ethregs *hregs = gpriv->hregs;
@@ -611,7 +611,7 @@
 int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs,
 		 struct hpc3_ethregs *hregs, int irq)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	int i;
 	struct sgiseeq_private *sp;
 
@@ -704,7 +704,7 @@
 
 int sgiseeq_probe(struct net_device *dev)
 {
-	static int initialized = 0;
+	static int initialized;
 	char *ep;
 
 	if (initialized)	/* Already initialized? */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.4.3/linux/drivers/net/shaper.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/shaper.c	Wed Apr 18 14:40:06 2001
@@ -651,8 +651,6 @@
 	 *	Intialise the packet queues
 	 */
 	 
-	dev_init_buffers(dev);
-	
 	/*
 	 *	Handlers for when we attach to a device.
 	 */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- v2.4.3/linux/drivers/net/sis900.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/sis900.c	Fri Apr 20 11:54:23 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.07.08	Jan. 8 2001
+   Revision:	1.07.11	Apr. 10 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.07.11 Apr.  2 2001 Hui-Fen Hsu  updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
+   Rev 1.07.10 Mar.  1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support 
    Rev 1.07.09 Feb.  9 2001 Dave Jones <davej@suse.de> PCI enable cleanup
    Rev 1.07.08 Jan.  8 2001 Lei-Chun Chang added RTL8201 PHY support
    Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix
@@ -60,10 +62,10 @@
 
 #include "sis900.h"
 
-static const char *version =
-"sis900.c: v1.07.09  2/9/2001\n";
+static char version[] __devinitdata =
+KERN_INFO "sis900.c: v1.07.11  4/10/2001\n";
 
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 40;
 static int multicast_filter_limit = 128;
 
 #define sis900_debug debug
@@ -91,31 +93,33 @@
 };
 MODULE_DEVICE_TABLE (pci, sis900_pci_tbl);
 
-static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
-static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
-static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
-static void rtl8201_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
+static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex);
 
 static struct mii_chip_info {
 	const char * name;
 	u16 phy_id0;
 	u16 phy_id1;
-	void (*read_mode) (struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
+	u8  phy_types;
+#define	HOME 	0x0001
+#define LAN	0x0002
+#define MIX	0x0003
 } mii_chip_table[] = {
-	{"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
-	{"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},
+	{ "SiS 900 Internal MII PHY", 		0x001d, 0x8000, LAN },
+	{ "SiS 7014 Physical Layer Solution", 	0x0016, 0xf830, LAN },
+	{ "AMD 79C901 10BASE-T PHY",  		0x0000, 0x6B70, LAN },
+	{ "AMD 79C901 HomePNA PHY",		0x0000, 0x6B90, HOME},
+	{ "ICS LAN PHY",			0x0015, 0xF440, LAN },
+	{ "NS 83851 PHY",			0x2000, 0x5C20, MIX },
 	{0,},
 };
 
 struct mii_phy {
 	struct mii_phy * next;
-	struct mii_chip_info * chip_info;
 	int phy_addr;
+	u16 phy_id0;
+	u16 phy_id1;
 	u16 status;
+	u8  phy_types;
 };
 
 typedef struct _BufferDesc {
@@ -131,11 +135,13 @@
 	spinlock_t lock;
 
 	struct mii_phy * mii;
+	struct mii_phy * first_mii; /* record the first mii structure */
 	unsigned int cur_phy;
 
-	struct timer_list timer;			/* Link status detection timer. */
+	struct timer_list timer; /* Link status detection timer. */
+	u8     autong_complete; /* 1: auto-negotiate complete  */
 
-	unsigned int cur_rx, dirty_rx;		/* producer/comsumer pointers for Tx/Rx ring */
+	unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */
 	unsigned int cur_tx, dirty_tx;
 
 	/* The saved address of a sent/receive-in-place packet buffer */
@@ -171,11 +177,16 @@
 static int sis900_close(struct net_device *net_dev);
 static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
-static u16 sis900_compute_hashtable_index(u8 *addr);
+static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision);
 static void set_rx_mode(struct net_device *net_dev);
 static void sis900_reset(struct net_device *net_dev);
 static void sis630_set_eq(struct net_device *net_dev, u8 revision);
 static int sis900_set_config(struct net_device *dev, struct ifmap *map);
+static u16 sis900_default_phy(struct net_device * net_dev);
+static void sis900_set_capability( struct net_device *net_dev ,struct mii_phy *phy);
+static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr);
+static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr);
+static void sis900_set_mode (long ioaddr, int speed, int duplex);
 
 /**
  *	sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
@@ -239,6 +250,44 @@
 	return 1;
 }
 
+
+/**
+ *	sis635_get_mac_addr: - Get MAC address for SIS635 model
+ *	@pci_dev: the sis900 pci device
+ *	@net_dev: the net device to get address for 
+ *
+ *	SiS635 model, set MAC Reload Bit to load Mac address from APC
+ *	to rfdr. rfdr is accessed through rfcr. MAC address is read into 
+ *	@net_dev->dev_addr.
+ */
+
+static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+{
+	long ioaddr = net_dev->base_addr;
+	u32 rfcrSave;
+	u32 i;
+
+	rfcrSave = inl(rfcr + ioaddr);
+
+	outl(rfcrSave | RELOAD, ioaddr + cr);
+	outl(0, ioaddr + cr);
+
+	/* disable packet filtering before setting filter */
+	outl(rfcrSave & ~RFEN, rfcr + ioaddr);
+
+	/* load MAC addr to filter data register */
+	for (i = 0 ; i < 3 ; i++) {
+		outl((i << RFADDR_shift), ioaddr + rfcr);
+		*( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr);
+	}
+
+	/* enable packet filitering */
+	outl(rfcrSave | RFEN, rfcr + ioaddr);
+
+	return 1;
+}
+
+
 /**
  *	sis900_probe: - Probe for sis900 device
  *	@pci_dev: the sis900 pci device
@@ -253,64 +302,48 @@
 static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
 	struct sis900_private *sis_priv;
-	long ioaddr;
 	struct net_device *net_dev;
-	int irq;
+	long ioaddr;
 	int i, ret;
 	u8 revision;
 	char *card_name = card_names[pci_id->driver_data];
 
-	/* setup various bits in PCI command register */
-	ret = pci_enable_device (pci_dev);
-	if (ret) return ret;
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
 
+	/* setup various bits in PCI command register */
+	ret = pci_enable_device(pci_dev);
+	if(ret) return ret;
+	
 	i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK);
-	if (i) {
-		printk(KERN_ERR "sis900.c: architecture does not support "
-		       "32bit PCI busmaster DMA\n");
+	if(i){
+		printk(KERN_ERR "sis900.c: architecture does not support"
+			"32bit PCI busmaster DMA\n");
 		return i;
 	}
-
+	
 	pci_set_master(pci_dev);
-
-	irq = pci_dev->irq;
-	ioaddr = pci_resource_start(pci_dev, 0);
-
+	
 	net_dev = alloc_etherdev(sizeof(struct sis900_private));
 	if (!net_dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(net_dev);
 
+	/* We do a request_region() to register /proc/ioports info. */
+	ioaddr = pci_resource_start(pci_dev, 0);	
 	ret = pci_request_regions(pci_dev, "sis900");
 	if (ret)
 		goto err_out;
 
-	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-	if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV)
-		ret = sis630e_get_mac_addr(pci_dev, net_dev);
-	else if (revision == SIS630S_900_REV)
-		ret = sis630e_get_mac_addr(pci_dev, net_dev);
-	else
-		ret = sis900_get_mac_addr(pci_dev, net_dev);
-
-	if (ret == 0) {
-		ret = -ENODEV;
-		goto err_out_region;
-	}
-
 	sis_priv = net_dev->priv;
-
-	/* We do a request_region() to register /proc/ioports info. */
 	net_dev->base_addr = ioaddr;
-	net_dev->irq = irq;
+	net_dev->irq = pci_dev->irq;
 	sis_priv->pci_dev = pci_dev;
 	spin_lock_init(&sis_priv->lock);
-	
-	/* probe for mii transciver */
-	if (sis900_mii_probe(net_dev) == 0) {
-		ret = -ENODEV;
-		goto err_out_region;
-	}
 
 	pci_set_drvdata(pci_dev, net_dev);
 
@@ -324,25 +357,47 @@
 	net_dev->do_ioctl = &mii_ioctl;
 	net_dev->tx_timeout = sis900_tx_timeout;
 	net_dev->watchdog_timeo = TX_TIMEOUT;
-
+	
 	ret = register_netdev(net_dev);
 	if (ret)
 		goto err_out_cleardev;
+		
+	/* Get Mac address according to the chip revision */
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
+	ret = 0;
+
+	if (revision == SIS630E_900_REV)
+		ret = sis630e_get_mac_addr(pci_dev, net_dev);
+	else if ((revision > 0x81) && (revision <= 0x90) )
+		ret = sis635_get_mac_addr(pci_dev, net_dev);
+	else
+		ret = sis900_get_mac_addr(pci_dev, net_dev);
+
+	if (ret == 0) {
+		ret = -ENODEV;
+		goto err_out_region;
+	}
+
+	/* probe for mii transciver */
+	if (sis900_mii_probe(net_dev) == 0) {
+		ret = -ENODEV;
+		goto err_out_region;
+	}
 
 	/* print some information about our NIC */
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
-	       card_name, ioaddr, irq);
+	       card_name, ioaddr, net_dev->irq);
 	for (i = 0; i < 5; i++)
 		printk("%2.2x:", (u8)net_dev->dev_addr[i]);
 	printk("%2.2x.\n", net_dev->dev_addr[i]);
 
 	return 0;
 
-err_out_cleardev:
-	pci_set_drvdata(pci_dev, NULL);
-err_out_region:
+ err_out_cleardev:
+ 	pci_set_drvdata(pci_dev, NULL);
+ err_out_region:
 	pci_release_regions(pci_dev);
-err_out:
+ err_out:
 	kfree(net_dev);
 	return ret;
 }
@@ -350,7 +405,7 @@
 /**
  *	sis900_mii_probe: - Probe MII PHY for sis900
  *	@net_dev: the net device to probe for
- *
+ *	
  *	Search for total of 32 possible mii phy addresses.
  *	Identify and set current phy if found one,
  *	return error if it failed to found.
@@ -359,59 +414,83 @@
 static int __init sis900_mii_probe (struct net_device * net_dev)
 {
 	struct sis900_private * sis_priv = net_dev->priv;
+	u16 poll_bit = MII_STAT_LINK, status = 0;
+	unsigned int timeout = jiffies + 5 * HZ;
 	int phy_addr;
 	u8 revision;
 
 	sis_priv->mii = NULL;
 
 	/* search for total of 32 possible mii phy addresses */
-	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+	for (phy_addr = 0; phy_addr < 32; phy_addr++) {	
+		struct mii_phy * mii_phy = NULL;
 		u16 mii_status;
-		u16 phy_id0, phy_id1;
 		int i;
 
-		mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
+		mii_phy = NULL;
+		for(i = 0; i < 2; i++)
+			mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
+
 		if (mii_status == 0xffff || mii_status == 0x0000)
 			/* the mii is not accessable, try next one */
 			continue;
+		
+		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
+			printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n");
+			return 0;
+		}
+		
+		mii_phy->phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
+		mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);		
+		mii_phy->phy_addr = phy_addr;
+		mii_phy->status = mii_status;
+		mii_phy->next = sis_priv->mii;
+		sis_priv->mii = mii_phy;
+		sis_priv->first_mii = mii_phy;
 
-		phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
-		phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
-
-		/* 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 &&
-			    phy_id1 == mii_chip_table[i].phy_id1) {
-				struct mii_phy * mii_phy;
-
-				printk(KERN_INFO
-				       "%s: %s transceiver found at address %d.\n",
-				       net_dev->name, mii_chip_table[i].name,
-				       phy_addr);
-				if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) {
-					mii_phy->chip_info = mii_chip_table+i;
-					mii_phy->phy_addr = phy_addr;
-					mii_phy->status = mdio_read(net_dev, phy_addr,
-								    MII_STATUS);
-					mii_phy->next = sis_priv->mii;
-					sis_priv->mii = mii_phy;
-				}
-				/* the current mii is on our mii_info_table,
-				   try next address */
+			if ((mii_phy->phy_id0 == mii_chip_table[i].phy_id0 ) &&
+			    ((mii_phy->phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
+				mii_phy->phy_types = mii_chip_table[i].phy_types;
+				if (mii_chip_table[i].phy_types == MIX)
+					mii_phy->phy_types =
+						(mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME;
+				printk(KERN_INFO "%s: %s transceiver found at address %d.\n",
+				       net_dev->name, mii_chip_table[i].name, phy_addr);
 				break;
 			}
+			
+		if( !mii_chip_table[i].phy_id1 )
+			printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
+			       net_dev->name, phy_addr);			
 	}
-
+	
 	if (sis_priv->mii == NULL) {
 		printk(KERN_INFO "%s: No MII transceivers found!\n",
 		       net_dev->name);
 		return 0;
 	}
 
-	/* arbitrary choose that last PHY as current PHY */
-	sis_priv->cur_phy = sis_priv->mii->phy_addr;
-	printk(KERN_INFO "%s: Using %s as default\n", net_dev->name,
-	       sis_priv->mii->chip_info->name);
+	/* select default PHY for mac */
+	sis_priv->mii = NULL;
+	sis900_default_phy( net_dev );
+
+	/* Reset phy if default phy is internal sis900 */
+        if ((sis_priv->mii->phy_id0 == 0x001D) &&
+	    ((sis_priv->mii->phy_id1&0xFFF0) == 0x8000))
+        	status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
+
+	if(status & MII_STAT_LINK){
+		while (poll_bit) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(0);
+			poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit);
+			if (jiffies >= timeout) {
+				printk(KERN_WARNING "%s: reset phy and link down now\n", net_dev->name);
+				return -ETIME;
+			}
+		}
+	}
 
 	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
 	if (revision == SIS630E_900_REV) {
@@ -420,7 +499,7 @@
 		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22);
 		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00);
 		mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0);
-		mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);	
+		//mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);	
 	}
 
 	if (sis_priv->mii->status & MII_STAT_LINK)
@@ -431,6 +510,86 @@
 	return 1;
 }
 
+/**
+ *	sis900_default_phy: - Select default PHY for sis900 mac.
+ *	@net_dev: the net device to probe for
+ *
+ *	Select first detected PHY with link as default.
+ *	If no one is link on, select PHY whose types is HOME as default.
+ *	If HOME doesn't exist, select LAN.
+ */
+
+static u16 sis900_default_phy(struct net_device * net_dev)
+{
+	struct sis900_private * sis_priv = net_dev->priv;
+ 	struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL;
+	u16 status;
+
+        for( phy=sis_priv->first_mii; phy; phy=phy->next ){
+		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+
+		/* Link ON & Not select deafalut PHY */
+		 if ( (status & MII_STAT_LINK) && !(default_phy) )
+		 	default_phy = phy;
+		 else{
+			status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL);
+			mdio_write(net_dev, phy->phy_addr, MII_CONTROL,
+				status | MII_CNTL_AUTO | MII_CNTL_ISOLATE);
+			if( phy->phy_types == HOME )
+				phy_home = phy;
+		 }
+	}
+
+	if( (!default_phy) && phy_home )
+		default_phy = phy_home;
+	else if(!default_phy)
+		default_phy = sis_priv->first_mii;
+
+	if( sis_priv->mii != default_phy ){
+		sis_priv->mii = default_phy;
+		sis_priv->cur_phy = default_phy->phy_addr;
+		printk(KERN_INFO "%s: Using transceiver found at address %d as default\n", net_dev->name,sis_priv->cur_phy);
+	}
+	
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
+	status &= (~MII_CNTL_ISOLATE);
+
+	mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status);	
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
+
+	return status;	
+}
+
+
+/**
+ * 	sis900_set_capability: - set the media capability of network adapter.
+ *	@net_dev : the net device to probe for
+ *	@mii_phy : default PHY
+ *
+ *	Set the media capability of network adapter according to
+ *	mii status register. It's necessary before auto-negotiate.
+ */
+ 
+static void sis900_set_capability( struct net_device *net_dev , struct mii_phy *phy )
+{
+	u16 cap;
+	u16 status;
+	
+	status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+	status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+	
+	cap = MII_NWAY_CSMA_CD |
+		((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) |
+		((phy->status & MII_STAT_CAN_TX)    ? MII_NWAY_TX:0) |
+		((phy->status & MII_STAT_CAN_T_FDX) ? MII_NWAY_T_FDX:0)|
+		((phy->status & MII_STAT_CAN_T)     ? MII_NWAY_T:0);
+
+	mdio_write(net_dev, phy->phy_addr, MII_ANADV, cap);
+}
+
+
 /* Delay between EEPROM clock transitions. */
 #define eeprom_delay()  inl(ee_addr)
 
@@ -605,6 +764,30 @@
 	return;
 }
 
+
+/**
+ *	sis900_reset_phy: - reset sis900 mii phy.
+ *	@net_dev: the net device to write
+ *	@phy_addr: default phy address
+ *
+ *	Some specific phy can't work properly without reset.
+ *	This function will be called during initialization and
+ *	link status change from ON to DOWN.
+ */
+
+static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr)
+{
+	int i = 0;
+	u16 status;
+
+	while (i++ < 2)
+		status = mdio_read(net_dev, phy_addr, MII_STATUS);
+
+	mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET );
+	
+	return status;
+}
+
 /**
  *	sis900_open: - open sis900 device
  *	@net_dev: the net device to open
@@ -626,9 +809,7 @@
 
 	/* Equalizer workaround Rule */
 	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||
-	    revision == SIS630A_900_REV)
-		sis630_set_eq(net_dev,revision);
+	sis630_set_eq(net_dev, revision);
 
 	ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev);
 	if (ret)
@@ -679,7 +860,7 @@
 	rfcrSave = inl(rfcr + ioaddr);
 
 	/* disable packet filtering before setting filter */
-	outl(rfcrSave & ~RFEN, rfcr);
+	outl(rfcrSave & ~RFEN, rfcr + ioaddr);
 
 	/* load MAC addr to filter data register */
 	for (i = 0 ; i < 3 ; i++) {
@@ -820,7 +1001,11 @@
 	int i, maxcount=10;
 	struct pci_dev *dev=NULL;
 
-	if ((dev = pci_find_device(SIS630_DEVICE_ID, SIS630_VENDOR_ID, dev)))
+	if ( !(revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||
+	       revision == SIS630A_900_REV) )
+		return;
+
+	if ((dev = pci_find_device(SIS630_VENDOR_ID, SIS630_DEVICE_ID, dev)))
 		pci_read_config_byte(dev, PCI_CLASS_REVISION, &host_bridge_rev);
 
 	if (netif_carrier_ok(net_dev)) {
@@ -842,13 +1027,6 @@
 			else if (max_value >= 15)
 				eq_value=(max_value == min_value) ? max_value+6 : max_value+5;
 		}
-		/* 630A0 rule to determine the equalizer value */
-		if (revision == SIS630A_900_REV && host_bridge_rev == SIS630A0) {
-			if (max_value < 5)
-				eq_value=max_value+3;
-			else if (max_value >= 5)
-				eq_value=max_value+5;
-		}
 		/* 630B0&B1 rule to determine the equalizer value */
 		if (revision == SIS630A_900_REV && 
 		    (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) {
@@ -865,7 +1043,11 @@
 	}
 	else {
 		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
-		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF);
+		if (revision == SIS630A_900_REV && 
+		    (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) 
+			mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2200) & 0xBFFF);
+		else
+			mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF);
 	}
 	return;
 }
@@ -887,60 +1069,52 @@
 	u16 status;
 	u8 revision;
 
-	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
-	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
-
-	/* current mii phy is failed to link, try another one */
-	while (!(status & MII_STAT_LINK)) {
-		if (mii_phy->next == NULL) {
-			if (netif_carrier_ok(net_dev)) {
-				/* link stat change from ON to OFF */
-				next_tick = HZ;
-				netif_carrier_off(net_dev);
-
-				/* Equalizer workaround Rule */
-				pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-				if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||
-				    revision == SIS630A_900_REV)
-					sis630_set_eq(net_dev, revision);
+	if (!sis_priv->autong_complete){
+		int speed, duplex = 0;
 
-				printk(KERN_INFO "%s: Media Link Off\n",
-				       net_dev->name);
-			}
-			sis_priv->timer.expires = jiffies + next_tick;
-			add_timer(&sis_priv->timer);
-			return;
+		sis900_read_mode(net_dev, &speed, &duplex);
+		if (duplex){
+			sis900_set_mode(net_dev->base_addr, speed, duplex);
+			pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+			sis630_set_eq(net_dev, revision);
 		}
-		mii_phy = mii_phy->next;
-		status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS);
-	}
 
-	if (!netif_carrier_ok(net_dev)) {
-		/* link stat change forn OFF to ON, read and report link mode */
-		netif_carrier_on(net_dev);
-		next_tick = 5*HZ;
+		sis_priv->timer.expires = jiffies + HZ;
+		add_timer(&sis_priv->timer);
+		return;
+	}
 
-		/* Equalizer workaround Rule */
-		pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-		if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||
-		    revision == SIS630A_900_REV)
-			sis630_set_eq(net_dev, revision);
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
 
-		/* change what cur_phy means */
-		if (mii_phy->phy_addr != sis_priv->cur_phy) {
-			printk(KERN_INFO "%s: Changing transceiver to %s\n",
-			       net_dev->name, mii_phy->chip_info->name);
-			/* disable previous PHY */
-			status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
-			mdio_write(net_dev, sis_priv->cur_phy,
-				   MII_CONTROL, status | MII_CNTL_ISOLATE);
-			/* enable next PHY */
-			status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL);
-			mdio_write(net_dev, mii_phy->phy_addr,
-				   MII_CONTROL, status & ~MII_CNTL_ISOLATE);
-			sis_priv->cur_phy = mii_phy->phy_addr;
+	/* Link OFF -> ON */
+	if (!netif_carrier_ok(net_dev)) {
+	LookForLink:
+		/* Search for new PHY */
+		status = sis900_default_phy(net_dev);
+		mii_phy = sis_priv->mii;
+
+		if (status & MII_STAT_LINK){
+			sis900_check_mode(net_dev, mii_phy);
+			netif_carrier_on(net_dev);
 		}
-		sis900_check_mode(net_dev, mii_phy);
+	}
+	/* Link ON -> OFF */
+	else {
+                if (!(status & MII_STAT_LINK)){
+                	netif_carrier_off(net_dev);
+                	printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+
+                	/* Change mode issue */
+                	if ((mii_phy->phy_id0 == 0x001D) && 
+			    ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
+               			sis900_reset_phy(net_dev,  sis_priv->cur_phy);
+  
+                	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+			sis630_set_eq(net_dev, revision);
+  
+                	goto LookForLink;
+                }
 	}
 
 	sis_priv->timer.expires = jiffies + next_tick;
@@ -952,8 +1126,11 @@
  *	@net_dev: the net device to be checked
  *	@mii_phy: the mii phy
  *
- *	call mii_phy->chip_info->read_mode function
- *	to check the speed and duplex mode for sis900
+ *	Older driver gets the media mode from mii status output
+ *	register. Now we set our media capability and auto-negotiate
+ *	to get the upper bound of speed and duplex between two ends.
+ *	If the types of mii phy is HOME, it doesn't need to auto-negotiate
+ *	and autong_complete should be set to 1.
  */
 
 static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy)
@@ -961,12 +1138,44 @@
 	struct sis900_private *sis_priv = net_dev->priv;
 	long ioaddr = net_dev->base_addr;
 	int speed, duplex;
-	u32 tx_flags = 0, rx_flags = 0;
 
-	mii_phy->chip_info->read_mode(net_dev, sis_priv->cur_phy, &speed, &duplex);
+	if( mii_phy->phy_types == LAN  ){
+		outl( ~EXD & inl( ioaddr + cfg ), ioaddr + cfg);
+		sis900_set_capability(net_dev , mii_phy);
+		sis900_auto_negotiate(net_dev, sis_priv->cur_phy);
+	}else{
+		outl(EXD | inl( ioaddr + cfg ), ioaddr + cfg);
+		speed = HW_SPEED_HOME;
+		duplex = FDX_CAPABLE_HALF_SELECTED;
+		sis900_set_mode(ioaddr, speed, duplex);
+		sis_priv->autong_complete = 1;
+	}
+}
 
-	tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
-	rx_flags = RX_DMA_BURST << RxMXDMA_shift;
+/**
+ *	sis900_set_mode: - Set the media mode of mac register.
+ *	@speed : the transmit speed to be determined
+ *	@duplex: the duplex mode to be determined
+ *
+ *	Set the media mode of mac register txcfg/rxcfg according to
+ *	speed and duplex of phy. Bit EDB_MASTER_EN indicates the EDB
+ *	bus is used instead of PCI bus. When this bit is set 1, the
+ *	Max DMA Burst Size for TX/RX DMA should be no larger than 16
+ *	double words.
+ */
+
+static void sis900_set_mode (long ioaddr, int speed, int duplex)
+{
+	u32 tx_flags = 0, rx_flags = 0;
+
+	if( inl(ioaddr + cfg) & EDB_MASTER_EN ){
+		tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
+		rx_flags = DMA_BURST_64 << RxMXDMA_shift;
+	}
+	else{
+		tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
+		rx_flags = DMA_BURST_512 << RxMXDMA_shift;
+	}
 
 	if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) {
 		rx_flags |= (RxDRNT_10 << RxDRNT_shift);
@@ -987,184 +1196,86 @@
 }
 
 /**
- *	sis900_read_mode: - read media mode for sis900 internal phy
+ *	sis900_auto_negotiate:  Set the Auto-Negotiation Enable/Reset bit.
  *	@net_dev: the net device to read mode for
  *	@phy_addr: mii phy address
- *	@speed: the transmit speed to be determined
- *	@duplex: the duplex mode to be determined
  *
- *	read MII_STSOUT register from sis900 internal phy
- *	to determine the speed and duplex mode for sis900
+ *	If the adapter is link-on, set the auto-negotiate enable/reset bit.
+ *	autong_complete should be set to 0 when starting auto-negotiation.
+ *	autong_complete should be set to 1 if we didn't start auto-negotiation.
+ *	sis900_timer will wait for link on again if autong_complete = 0.
  */
 
-static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex)
+static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr)
 {
+	struct sis900_private *sis_priv = net_dev->priv;
 	int i = 0;
 	u32 status;
-
-	/* STSOUT register is Latched on Transition, read operation updates it */
+	
 	while (i++ < 2)
-		status = mdio_read(net_dev, phy_addr, MII_STSOUT);
-
-	if (status & MII_STSOUT_SPD)
-		*speed = HW_SPEED_100_MBPS;
-	else
-		*speed = HW_SPEED_10_MBPS;
-
-	if (status & MII_STSOUT_DPLX)
-		*duplex = FDX_CAPABLE_FULL_SELECTED;
-	else
-		*duplex = FDX_CAPABLE_HALF_SELECTED;
+		status = mdio_read(net_dev, phy_addr, MII_STATUS);
 
-	if (status & MII_STSOUT_LINK_FAIL)
+	if (!(status & MII_STAT_LINK)){
 		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
-	else
-		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");
+		sis_priv->autong_complete = 1;
+		netif_carrier_off(net_dev);
+		return;
+	}
+
+	/* (Re)start AutoNegotiate */
+	mdio_write(net_dev, phy_addr, MII_CONTROL,
+		   MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+	sis_priv->autong_complete = 0;
 }
 
+
 /**
- *	amd79c901_read_mode: - read media mode for amd79c901 phy
+ *	sis900_read_mode: - read media mode for sis900 internal phy
  *	@net_dev: the net device to read mode for
- *	@phy_addr: mii phy address
- *	@speed: the transmit speed to be determined
- *	@duplex: the duplex mode to be determined
+ *	@speed  : the transmit speed to be determined
+ *	@duplex : the duplex mode to be determined
  *
- *	read MII_STATUS register from amd79c901 phy
- *	to determine the speed and duplex mode for sis900
+ *	The capability of remote end will be put in mii register autorec
+ *	after auto-negotiation. Use AND operation to get the upper bound
+ *	of speed and duplex between two ends.
  */
 
-static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex)
+static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex)
 {
-	int i;
-	u16 status;
+	struct sis900_private *sis_priv = net_dev->priv;
+	int phy_addr = sis_priv->cur_phy;
+	u32 status;
+	u16 autoadv, autorec;
+	int i = 0;
 
-	for (i = 0; i < 2; i++)
+	while (i++ < 2)
 		status = mdio_read(net_dev, phy_addr, MII_STATUS);
 
-	if (status & MII_STAT_CAN_AUTO) {
-		/* 10BASE-T PHY */
-		for (i = 0; i < 2; i++)
-			status = mdio_read(net_dev, phy_addr, MII_STATUS_SUMMARY);
-		if (status & MII_STSSUM_SPD)
-			*speed = HW_SPEED_100_MBPS;
-		else
-			*speed = HW_SPEED_10_MBPS;
-		if (status & MII_STSSUM_DPLX)
-			*duplex = FDX_CAPABLE_FULL_SELECTED;
-		else
-			*duplex = FDX_CAPABLE_HALF_SELECTED;
-
-		if (status & MII_STSSUM_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);
-	}
-	else {
-		/* HomePNA */
-		*speed = HW_SPEED_HOME;
-		*duplex = FDX_CAPABLE_HALF_SELECTED;
-		if (status & MII_STAT_LINK)
-			printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n",
-			       net_dev->name);
-		else
-			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
-	}
-}
-
-/**
- *	ics1893_read_mode: - read media mode for ICS1893 PHY
- *	@net_dev: the net device to read mode for
- *	@phy_addr: mii phy address
- *	@speed: the transmit speed to be determined
- *	@duplex: the duplex mode to be determined
- *
- *	ICS1893 PHY use Quick Poll Detailed Status register
- *	to determine the speed and duplex mode for sis900
- */
-
-static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex)
-{
-	int i = 0;
-	u32 status;
+	if (!(status & MII_STAT_LINK))
+		return;
 
-	/* 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);
+	/* AutoNegotiate completed */
+	autoadv = mdio_read(net_dev, phy_addr, MII_ANADV);
+	autorec = mdio_read(net_dev, phy_addr, MII_ANLPAR);
+	status = autoadv & autorec;
 
-	if (status & MII_STSICS_SPD)
+	if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
 		*speed = HW_SPEED_100_MBPS;
 	else
 		*speed = HW_SPEED_10_MBPS;
-
-	if (status & MII_STSICS_DPLX)
+	if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
 		*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);
-}
-
-/**
- *	rtl8201_read_mode: - read media mode for rtl8201 phy
- *	@net_dev: the net device to read mode for
- *	@phy_addr: mii phy address
- *	@speed: the transmit speed to be determined
- *	@duplex: the duplex mode to be determined
- *
- *	read MII_STATUS register from rtl8201 phy
- *	to determine the speed and duplex mode for sis900
- */
-
-static void rtl8201_read_mode(struct net_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);
+	sis_priv->autong_complete = 1;
+	
+	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");
 }
 
 /**
@@ -1628,83 +1739,81 @@
         
 	u16 status;
 
-	/* 
-	   )*/    
 	if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-        /* we switch on the ifmap->port field. I couldn't find anything
-           like a definition or standard for the values of that field.
-           I think the meaning of those values is device specific. But
-           since I would like to change the media type via the ifconfig
-           command I use the definition from linux/netdevice.h 
-           (which seems to be different from the ifport(pcmcia) definition) 
-        */
+		/* we switch on the ifmap->port field. I couldn't find anything
+		   like a definition or standard for the values of that field.
+		   I think the meaning of those values is device specific. But
+		   since I would like to change the media type via the ifconfig
+		   command I use the definition from linux/netdevice.h 
+		   (which seems to be different from the ifport(pcmcia) definition) 
+		*/
 		switch(map->port){
-			case IF_PORT_UNKNOWN: /* use auto here */   
-                		dev->if_port = map->port;
-                		/* we are going to change the media type, so the Link will
-                		be temporary down and we need to reflect that here. When
-                		the Link comes up again, it will be sensed by the sis_timer
-                		procedure, which also does all the rest for us */
-				netif_carrier_off(dev);
+		case IF_PORT_UNKNOWN: /* use auto here */   
+			dev->if_port = map->port;
+			/* we are going to change the media type, so the Link will
+			   be temporary down and we need to reflect that here. When
+			   the Link comes up again, it will be sensed by the sis_timer
+			   procedure, which also does all the rest for us */
+			netif_carrier_off(dev);
                 
-                		/* read current state */
-                		status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+			/* read current state */
+			status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
                 
-                		/* enable auto negotiation and reset the negotioation
-                		(I dont really know what the auto negatiotiation reset
-                		really means, but it sounds for me right to do one here)*/
-                		mdio_write(dev, mii_phy->phy_addr,
-                                           MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+			/* enable auto negotiation and reset the negotioation
+			   (I dont really know what the auto negatiotiation reset
+			   really means, but it sounds for me right to do one here)*/
+			mdio_write(dev, mii_phy->phy_addr,
+				   MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
 
-            			break;
+			break;
             
-            		case IF_PORT_10BASET: /* 10BaseT */         
-                		dev->if_port = map->port;
+		case IF_PORT_10BASET: /* 10BaseT */         
+			dev->if_port = map->port;
                 
-                		/* we are going to change the media type, so the Link will
-                		be temporary down and we need to reflect that here. When
-                		the Link comes up again, it will be sensed by the sis_timer
-                		procedure, which also does all the rest for us */
-				netif_carrier_off(dev);
+			/* we are going to change the media type, so the Link will
+			   be temporary down and we need to reflect that here. When
+			   the Link comes up again, it will be sensed by the sis_timer
+			   procedure, which also does all the rest for us */
+			netif_carrier_off(dev);
         
-                		/* set Speed to 10Mbps */
-                		/* read current state */
-                		status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+			/* set Speed to 10Mbps */
+			/* read current state */
+			status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
                 
-                		/* disable auto negotiation and force 10MBit mode*/
-                		mdio_write(dev, mii_phy->phy_addr,
-                                           MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO));
-            			break;
+			/* disable auto negotiation and force 10MBit mode*/
+			mdio_write(dev, mii_phy->phy_addr,
+				   MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO));
+			break;
             
-            		case IF_PORT_100BASET: /* 100BaseT */
-            		case IF_PORT_100BASETX: /* 100BaseTx */ 
-                		dev->if_port = map->port;
+		case IF_PORT_100BASET: /* 100BaseT */
+		case IF_PORT_100BASETX: /* 100BaseTx */ 
+			dev->if_port = map->port;
                 
-                		/* we are going to change the media type, so the Link will
-                		be temporary down and we need to reflect that here. When
-                		the Link comes up again, it will be sensed by the sis_timer
-                		procedure, which also does all the rest for us */
-				netif_carrier_off(dev);
+			/* we are going to change the media type, so the Link will
+			   be temporary down and we need to reflect that here. When
+			   the Link comes up again, it will be sensed by the sis_timer
+			   procedure, which also does all the rest for us */
+			netif_carrier_off(dev);
                 
-                		/* set Speed to 100Mbps */
-                		/* disable auto negotiation and enable 100MBit Mode */
-                		status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
-                		mdio_write(dev, mii_phy->phy_addr,
-                                           MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED);
+			/* set Speed to 100Mbps */
+			/* disable auto negotiation and enable 100MBit Mode */
+			status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+			mdio_write(dev, mii_phy->phy_addr,
+				   MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED);
                 
-            			break;
+			break;
             
-            		case IF_PORT_10BASE2: /* 10Base2 */
-            		case IF_PORT_AUI: /* AUI */
-            		case IF_PORT_100BASEFX: /* 100BaseFx */
+		case IF_PORT_10BASE2: /* 10Base2 */
+		case IF_PORT_AUI: /* AUI */
+		case IF_PORT_100BASEFX: /* 100BaseFx */
                 	/* These Modes are not supported (are they?)*/
-                		printk(KERN_INFO "Not supported");
-                		return -EOPNOTSUPP;
-            			break;
+			printk(KERN_INFO "Not supported");
+			return -EOPNOTSUPP;
+			break;
             
-            		default:
-                		printk(KERN_INFO "Invalid");
-                		return -EINVAL;
+		default:
+			printk(KERN_INFO "Invalid");
+			return -EINVAL;
 		}
 	}
 	return 0;
@@ -1713,12 +1822,15 @@
 /**
  *	sis900_compute_hashtable_index: - compute hashtable index 
  *	@addr: multicast address
+ *	@revision: revision id of chip
  *
  *	SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast
  *	hash table, which makes this function a little bit different from other drivers
+ *	SiS 900 B0 & 635 M/B uses the most significat 8 bits to index 256 bits
+ *   	multicast hash table. 
  */
 
-static u16 sis900_compute_hashtable_index(u8 *addr)
+static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision)
 {
 
 /* what is the correct value of the POLYNOMIAL ??
@@ -1741,51 +1853,63 @@
 			byte >>= 1;
 		}
 	}
-	/* leave 7 most siginifant bits */ 
-	return ((int)(crc >> 25));
+
+	/* leave 8 or 7 most siginifant bits */
+	if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
+		return ((int)(crc >> 24));
+	else
+		return ((int)(crc >> 25));
 }
 
 /**
  *	set_rx_mode: - Set SiS900 receive mode 
  *	@net_dev: the net device to be set
  *
- *	Set SiS900 receive mode for promiscuous, multicast, or broadcast mode. 
+ *	Set SiS900 receive mode for promiscuous, multicast, or broadcast mode.
  *	And set the appropriate multicast filter.
+ *	Multicast hash table changes from 128 to 256 bits for 635M/B & 900B0.
  */
 
 static void set_rx_mode(struct net_device *net_dev)
 {
 	long ioaddr = net_dev->base_addr;
-	u16 mc_filter[8];			/* 128 bits multicast hash table */
-	int i;
+	struct sis900_private * sis_priv = net_dev->priv;
+	u16 mc_filter[16] = {0};	/* 256/128 bits multicast hash table */
+	int i, table_entries;
 	u32 rx_mode;
+	u8 revision;
+
+	/* 635 Hash Table entires = 256(2^16) */
+	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+	if((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
+		table_entries = 16;
+	else
+		table_entries = 8;
 
 	if (net_dev->flags & IFF_PROMISC) {
 		/* Accept any kinds of packets */
 		rx_mode = RFPromiscuous;
-		for (i = 0; i < 8; i++)
+		for (i = 0; i < table_entries; i++)
 			mc_filter[i] = 0xffff;
 	} else if ((net_dev->mc_count > multicast_filter_limit) ||
 		   (net_dev->flags & IFF_ALLMULTI)) {
 		/* too many multicast addresses or accept all multicast packet */
 		rx_mode = RFAAB | RFAAM;
-		for (i = 0; i < 8; i++)
+		for (i = 0; i < table_entries; i++)
 			mc_filter[i] = 0xffff;
 	} else {
 		/* Accept Broadcast packet, destination address matchs our MAC address,
 		   use Receive Filter to reject unwanted MCAST packet */
 		struct dev_mc_list *mclist;
 		rx_mode = RFAAB;
-		for (i = 0; i < 8; i++)
-			mc_filter[i]=0;
 		for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count;
 		     i++, mclist = mclist->next)
-			set_bit(sis900_compute_hashtable_index(mclist->dmi_addr),
+			set_bit(sis900_compute_hashtable_index(mclist->dmi_addr, revision),
 				mc_filter);
 	}
 
 	/* update Multicast Hash Table in Receive Filter */
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < table_entries; i++) {
                 /* why plus 0x04 ??, That makes the correct value for hash table. */
 		outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
 		outl(mc_filter[i], ioaddr + rfdr);
@@ -1804,7 +1928,7 @@
 		outl(inl(ioaddr + rxcfg) | RxATX, ioaddr + rxcfg);
 		/* restore cr */
 		outl(cr_saved, ioaddr + cr);
-	}		
+	}
 
 	return;
 }
@@ -1815,13 +1939,16 @@
  *
  *	reset sis900 MAC and wait until finished
  *	reset through command register
+ *	change backoff algorithm for 900B0 & 635 M/B
  */
 
 static void sis900_reset(struct net_device *net_dev)
 {
+	struct sis900_private * sis_priv = net_dev->priv;
 	long ioaddr = net_dev->base_addr;
 	int i = 0;
 	u32 status = TxRCMP | RxRCMP;
+	u8  revision;
 
 	outl(0, ioaddr + ier);
 	outl(0, ioaddr + imr);
@@ -1834,7 +1961,11 @@
 		status ^= (inl(isr + ioaddr) & status);
 	}
 
-	outl(PESEL, ioaddr + cfg);
+	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+	if( (revision == SIS635A_900_REV) || (revision == SIS900B_900_REV) )
+		outl(PESEL | RND_CNT, ioaddr + cfg);
+	else
+		outl(PESEL, ioaddr + cfg);
 }
 
 /**
@@ -1847,7 +1978,15 @@
 static void __devexit sis900_remove(struct pci_dev *pci_dev)
 {
 	struct net_device *net_dev = pci_get_drvdata(pci_dev);
-		
+	struct sis900_private * sis_priv = net_dev->priv;
+	struct mii_phy *phy = NULL;
+
+	while (sis_priv->first_mii) {
+		phy = sis_priv->first_mii;
+		sis_priv->first_mii = phy->next;
+		kfree(phy);
+	}
+
 	unregister_netdev(net_dev);
 	kfree(net_dev);
 	pci_release_regions(pci_dev);
@@ -1865,7 +2004,10 @@
 
 static int __init sis900_init_module(void)
 {
-	printk(KERN_INFO "%s", version);
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 
 	return pci_module_init(&sis900_pci_driver);
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sis900.h linux/drivers/net/sis900.h
--- v2.4.3/linux/drivers/net/sis900.h	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/sis900.h	Wed Apr 11 21:17:59 2001
@@ -50,7 +50,10 @@
 enum sis900_configuration_register_bits {
 	DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080,
 	SB    = 0x00000040, POW = 0x00000020, EXD = 0x00000010, 
-	PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001
+	PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001,
+	/* 635 & 900B Specific */
+	RND_CNT = 0x00000400, FAIR_BACKOFF = 0x00000200,
+	EDB_MASTER_EN = 0x00002000
 };
 
 enum sis900_eeprom_access_reigster_bits {
@@ -78,8 +81,10 @@
 #define MAX_DMA_RANGE	7	/* actually 0 means MAXIMUM !! */
 #define TxMXDMA_shift   	20
 #define RxMXDMA_shift    20
-#define TX_DMA_BURST    	0
-#define RX_DMA_BURST    	0
+
+enum sis900_tx_rx_dma{
+	DMA_BURST_512 = 0,	DMA_BURST_64 = 5
+};
 
 /* transmit FIFO threshholds */
 #define TX_FILL_THRESH   16	/* 1/4 FIFO size */
@@ -233,7 +238,8 @@
 
 enum sis900_revision_id {
 	SIS630A_900_REV = 0x80,		SIS630E_900_REV = 0x81,
-	SIS630S_900_REV = 0x82,		SIS630EA1_900_REV = 0x83
+	SIS630S_900_REV = 0x82,		SIS630EA1_900_REV = 0x83,
+	SIS635A_900_REV = 0x90,		SIS900B_900_REV = 0x03
 };
 
 enum sis630_revision_id {
@@ -263,8 +269,8 @@
 /* PCI stuff, should be move to pic.h */
 #define PCI_DEVICE_ID_SI_900	0x900   
 #define PCI_DEVICE_ID_SI_7016	0x7016
-#define SIS630_VENDOR_ID        0x0630
-#define SIS630_DEVICE_ID        0x1039
+#define SIS630_VENDOR_ID        0x1039
+#define SIS630_DEVICE_ID        0x0630
 
 /* ioctl for accessing MII transceiver */
 #define SIOCGMIIPHY (SIOCDEVPRIVATE)		/* Get the PHY in use. */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.4.3/linux/drivers/net/sk98lin/skge.c	Tue Mar  6 19:28:34 2001
+++ linux/drivers/net/sk98lin/skge.c	Wed Apr 18 14:40:05 2001
@@ -1,4 +1,4 @@
-/******************************************************************************
+;/******************************************************************************
  *
  * Name:      	skge.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
@@ -343,7 +343,7 @@
 
 /* global variables *********************************************************/
 static const char *BootString = BOOT_STRING;
-static struct net_device *root_dev = NULL;
+static struct net_device *root_dev;
 static int probed __initdata = 0;
 
 /* local variables **********************************************************/
@@ -602,8 +602,8 @@
 #endif
 
 
-static int debug = 0; /* not used */
-static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */
+static int debug; /* not used */
+static int options[SK_MAX_CARD_PARAM]; /* not used */
 
 
 /*****************************************************************************
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.4.3/linux/drivers/net/sk_g16.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/sk_g16.c	Thu Apr 19 09:34:52 2001
@@ -23,7 +23,7 @@
  *
 -*/
 
-static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
+static const char rcsid[] = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
 
 /*
  * The Schneider & Koch (SK) G16 Network device driver is based
@@ -622,7 +622,7 @@
 
 
 #ifdef MODULE
-static int io = 0; /* 0 == probe */
+static int io;	/* 0 == probe */
 
 static int __init SK_init_module (void)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c
--- v2.4.3/linux/drivers/net/skfp/skfddi.c	Tue Mar  6 19:28:34 2001
+++ linux/drivers/net/skfp/skfddi.c	Wed Apr 18 14:40:05 2001
@@ -2557,7 +2557,7 @@
  *
  ************************/
 #define LP(a) ((struct s_smc*)(a))
-static struct net_device *mdev = NULL;
+static struct net_device *mdev;
 
 /************************
  *
diff -u --recursive --new-file v2.4.3/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.4.3/linux/drivers/net/slip.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/slip.c	Wed Apr 18 14:40:06 2001
@@ -92,7 +92,7 @@
 	struct slip	ctrl;		/* SLIP things			*/
 	struct net_device	dev;		/* the device			*/
 } slip_ctrl_t;
-static slip_ctrl_t	**slip_ctrls = NULL;
+static slip_ctrl_t	**slip_ctrls;
 
 int slip_maxdev = SL_NRUNIT;		/* Can be overridden with insmod! */
 MODULE_PARM(slip_maxdev, "i");
@@ -647,8 +647,6 @@
 	dev->tx_queue_len	= 10;
 
 	SET_MODULE_OWNER(dev);
-
-	dev_init_buffers(dev);
 
 	/* New-style flags. */
 	dev->flags		= IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.4.3/linux/drivers/net/smc-ultra.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/smc-ultra.c	Thu Apr 19 09:34:52 2001
@@ -53,7 +53,7 @@
 	interface and then load the module with an explicit io=0x___ option.
 */
 
-static const char *version =
+static const char version[] =
 	"smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.4.3/linux/drivers/net/smc9194.c	Tue Mar 20 12:05:01 2001
+++ linux/drivers/net/smc9194.c	Thu Apr 19 09:34:52 2001
@@ -53,7 +53,7 @@
  .      12/15/00  Christian Jullien fix "Warning: kfree_skb on hard IRQ"
  ----------------------------------------------------------------------------*/
 
-static const char *version =
+static const char version[] =
 	"smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n";
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.4.3/linux/drivers/net/starfire.c	Fri Aug 11 15:57:58 2000
+++ linux/drivers/net/starfire.c	Fri Apr 20 11:54:23 2001
@@ -36,15 +36,6 @@
 	- Merge Becker version 1.03
 */
 
-/* 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.4.x kernel port, version 1.1.4, August 10, 2000)\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -53,7 +44,7 @@
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
-static int mtu = 0;
+static int mtu;
 /* 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;
@@ -88,25 +79,31 @@
 
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
+/*
+ * 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
+ */
+#ifdef __ia64__
+#define PKT_SHOULD_COPY(pkt_len)	1
+#else
+#define PKT_SHOULD_COPY(pkt_len)	(pkt_len < rx_copybreak)
+#endif
+
 #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 files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/version.h>
 #include <linux/module.h>
-#if LINUX_VERSION_CODE < 0x20300  &&  defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
-
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -117,6 +114,12 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO " Updates and info at http://www.scyld.com/network/starfire.html\n"
+KERN_INFO " (unofficial 2.4.x kernel port, version 1.1.4a, April 17, 2001)\n";
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
@@ -323,6 +326,7 @@
 	dma_addr_t mapping;
 };
 
+#define MII_CNT		4
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
 	struct starfire_rx_desc *rx_ring;
@@ -359,7 +363,7 @@
 	/* MII transceiver section. */
 	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
+	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 };
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
@@ -388,16 +392,21 @@
 	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 = netdrv_tbl[chip_idx].io_size;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	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);
 	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
@@ -405,23 +414,18 @@
 		return -ENODEV;
 	}
 	
-	dev = init_etherdev(NULL, sizeof(*np));
+	dev = alloc_etherdev(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);
+	if (pci_request_regions (pdev, "starfire"))
 		goto err_out_free_netdev;
-	}
-	
-	if (pci_enable_device (pdev))
-		goto err_out_free_res;
-	
+
 	ioaddr = (long) ioremap (ioaddr, io_size);
 	if (!ioaddr) {
 		printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n",
@@ -431,15 +435,9 @@
 
 	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)
@@ -455,7 +453,7 @@
 	dev->irq = irq;
 
 	np = dev->priv;
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
 	np->pci_dev = pdev;
 	drv_flags = netdrv_tbl[chip_idx].drv_flags;
@@ -490,9 +488,19 @@
 	if (mtu)
 		dev->mtu = mtu;
 
+	i = register_netdev(dev);
+	if (i)
+		goto err_out_cleardev;
+
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, netdrv_tbl[chip_idx].name, ioaddr);
+	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 (drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
-		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
@@ -507,8 +515,11 @@
 
 	return 0;
 
+err_out_cleardev:
+	pci_set_drvdata(pdev, NULL);
+	iounmap((void *)ioaddr);
 err_out_free_res:
-	release_mem_region (ioaddr, io_size);
+	pci_release_regions (pdev);
 err_out_free_netdev:
 	unregister_netdev (dev);
 	kfree (dev);
@@ -540,19 +551,15 @@
 
 static int netdev_open(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i, retval;
 
 	/* Do we ever need to reset the chip??? */
 
-	MOD_INC_USE_COUNT;
-
 	retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
-	if (retval) {
-		MOD_DEC_USE_COUNT;
+	if (retval)
 		return retval;
-	}
 
 	/* Disable the Rx and Tx, and reset the chip. */
 	writel(0, ioaddr + GenCtrl);
@@ -583,7 +590,6 @@
 		if (np->rx_ring)
 			pci_free_consistent(np->pci_dev, PAGE_SIZE,
 								np->rx_ring, np->rx_ring_dma);
-		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 
@@ -669,7 +675,7 @@
 
 static void check_duplex(struct net_device *dev, int startup)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int new_tx_mode ;
 
@@ -702,7 +708,7 @@
 static void netdev_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;		/* Check before driver release. */
 
@@ -730,7 +736,7 @@
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
@@ -812,8 +818,8 @@
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
-	unsigned entry;
+	struct netdev_private *np = dev->priv;
+	unsigned int entry;
 
 	/* Caution: the write order is important here, set the field
 	   with the "ownership" bits last. */
@@ -843,6 +849,9 @@
 #endif
 
 	/* 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, dev->base_addr + TxProducerIdx);
@@ -977,7 +986,7 @@
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 	u32 desc_status;
 
@@ -1015,7 +1024,7 @@
 #endif
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
-			if (pkt_len < rx_copybreak
+			if (PKT_SHOULD_COPY(pkt_len)
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
@@ -1037,14 +1046,6 @@
 				temp = skb_put(skb, pkt_len);
 				np->rx_info[entry].skb = NULL;
 				np->rx_info[entry].mapping = 0;
-#ifndef final_version				/* Remove after testing. */
-				if (le32_to_cpu(np->rx_ring[entry].rxaddr & ~3) != ((unsigned long) temp))
-					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-						   "do not match in netdev_rx: %d vs. %p / %p.\n",
-						   dev->name,
-						   le32_to_cpu(np->rx_ring[entry].rxaddr),
-						   skb->head, temp);
-#endif
 			}
 #ifndef final_version				/* Remove after testing. */
 			/* You will want this info for the initial debug. */
@@ -1107,7 +1108,7 @@
 
 static void netdev_error(struct net_device *dev, int intr_status)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 
 	if (intr_status & LinkChange) {
 		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
@@ -1136,7 +1137,7 @@
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 
 	/* This adapter architecture needs no SMP locks. */
 	np->stats.tx_bytes = readl(ioaddr + 0x57010);
@@ -1241,7 +1242,7 @@
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
@@ -1279,7 +1280,7 @@
 static int netdev_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	netif_stop_queue(dev);
@@ -1341,15 +1342,13 @@
 		np->tx_info[i].mapping = 0;
 	}
 
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
 
 static void __devexit starfire_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct netdev_private *np;
 	
 	if (!dev)
@@ -1359,6 +1358,7 @@
 
 	unregister_netdev(dev);
 	iounmap((char *)dev->base_addr);
+	pci_release_regions (pdev);
 
 	if (np->tx_done_q)
 		pci_free_consistent(np->pci_dev, PAGE_SIZE,
@@ -1374,6 +1374,8 @@
 				    np->rx_ring, np->rx_ring_dma);
 
 	kfree(dev);
+
+	pci_set_drvdata(pdev, NULL);
 }
 
 
@@ -1387,6 +1389,10 @@
 
 static int __init starfire_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init (&starfire_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/stnic.c linux/drivers/net/stnic.c
--- v2.4.3/linux/drivers/net/stnic.c	Sat Dec 30 11:23:14 2000
+++ linux/drivers/net/stnic.c	Wed Apr 11 21:24:52 2001
@@ -7,6 +7,7 @@
  * Copyright (C) 1999 kaz Kojima
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -21,6 +22,9 @@
 #include <asm/io.h>
 #include <asm/hitachi_se.h>
 #include <asm/machvec.h>
+#ifdef CONFIG_SH_STANDARD_BIOS 
+#include <asm/sh_bios.h>
+#endif
 
 #include "8390.h"
 
@@ -74,6 +78,7 @@
   vword trash;
   trash = *(vword *) 0xa0000000;
   trash = *(vword *) 0xa0000000;
+  trash = *(vword *) 0xa0000000;
 }
 
 static inline byte
@@ -112,10 +117,13 @@
   /* Allocate dev->priv and fill in 8390 specific dev fields. */
   if (ethdev_init (dev))
     {
-      printk ("Unable to get memory for dev->priv.\n");
+      printk (KERN_EMERG "Unable to get memory for dev->priv.\n");
       return -ENOMEM;
     }
 
+#ifdef CONFIG_SH_STANDARD_BIOS 
+  sh_bios_get_node_addr (stnic_eadr);
+#endif
   for (i = 0; i < ETHER_ADDR_LEN; i++)
     dev->dev_addr[i] = stnic_eadr[i];
 
@@ -129,7 +137,7 @@
      share and the board will usually be enabled. */
   i = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev);
   if (i)  {
-      printk (" unable to get IRQ %d.\n", dev->irq);
+      printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq);
       unregister_netdev(dev);
       kfree(dev->priv);
       kfree(dev);
@@ -157,7 +165,7 @@
 stnic_open (struct net_device *dev)
 {
 #if 0
-  printk ("stnic open\n");
+  printk (KERN_DEBUG "stnic open\n");
 #endif
   ei_open (dev);
   return 0;
@@ -176,7 +184,7 @@
   *(vhalf *) PA_83902_RST = 0;
   udelay (5);
   if (ei_debug > 1)
-    printk("8390 reset done (%ld).\n", jiffies);
+    printk (KERN_WARNING "8390 reset done (%ld).\n", jiffies);
   *(vhalf *) PA_83902_RST = ~0;
   udelay (5);
 }
@@ -206,7 +214,7 @@
 #endif
 
   if (ei_debug > 1)
-    printk ("ring %x status %02x next %02x count %04x.\n",
+    printk (KERN_DEBUG "ring %x status %02x next %02x count %04x.\n",
 	    ring_page, hdr->status, hdr->next, hdr->count);
 
   STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA);
@@ -254,22 +262,14 @@
 stnic_block_output (struct net_device *dev, int length,
 		    const unsigned char *buf, int output_page)
 {
-#if 0
-  STNIC_WRITE (PG0_RBCR0, 1);
-  STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA);
-#else  /* XXX: I don't know why but this works.  -- gniibe  */
-  STNIC_WRITE (PG0_RBCR0, 0x42);
-  STNIC_WRITE (PG0_RBCR1, 0x00);
-  STNIC_WRITE (PG0_RBCR0, 0x42);
-  STNIC_WRITE (PG0_RBCR1, 0x00);
+  STNIC_WRITE (PG0_RBCR0, 1);	/* Write non-zero value */
   STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA);
   STNIC_DELAY ();
-#endif
 
-  STNIC_WRITE (PG0_RSAR0, 0);
-  STNIC_WRITE (PG0_RSAR1, output_page);
   STNIC_WRITE (PG0_RBCR0, length & 0xff);
   STNIC_WRITE (PG0_RBCR1, length >> 8);
+  STNIC_WRITE (PG0_RSAR0, 0);
+  STNIC_WRITE (PG0_RSAR1, output_page);
   STNIC_WRITE (STNIC_CR, CR_RWR | CR_PG0 | CR_STA);
 
   if (length & 1)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.4.3/linux/drivers/net/sun3lance.c	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/sun3lance.c	Wed Apr 18 14:40:04 2001
@@ -243,7 +243,7 @@
 
 int __init sun3lance_probe( struct net_device *dev )
 {	
-	static int found = 0;
+	static int found;
 
 	if(found)
 		return(ENODEV);
@@ -262,7 +262,7 @@
 	
 	struct lance_private	*lp;
 	int 			i;
-	static int 		did_version = 0;
+	static int 		did_version;
 	int found = 0;
 	volatile unsigned short *ioaddr_probe;
 	unsigned short tmp1, tmp2;
@@ -585,7 +585,7 @@
 	struct net_device *dev = dev_id;
 	struct lance_private *lp = dev->priv;
 	int csr0;
-	static int in_interrupt = 0;
+	static int in_interrupt;
 
 	if (dev == NULL) {
 		DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" ));
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.4.3/linux/drivers/net/sunbmac.c	Tue Mar  6 22:44:16 2001
+++ linux/drivers/net/sunbmac.c	Fri Apr 20 11:54:22 2001
@@ -63,7 +63,7 @@
 #define DIRQ(x)
 #endif
 
-static struct bigmac *root_bigmac_dev = NULL;
+static struct bigmac *root_bigmac_dev;
 
 #define DEFAULT_JAMSIZE    4 /* Toe jam */
 
@@ -910,7 +910,10 @@
 		return ret;
 	}
 	init_timer(&bp->bigmac_timer);
-	return bigmac_init(bp, 0);
+	ret = bigmac_init(bp, 0);
+	if (ret)
+		free_irq(dev->irq, bp);
+	return ret;
 }
 
 static int bigmac_close(struct net_device *dev)
@@ -923,7 +926,7 @@
 
 	bigmac_stop(bp);
 	bigmac_clean_rings(bp);
-	free_irq(dev->irq, (void *)bp);
+	free_irq(dev->irq, bp);
 	return 0;
 }
 
@@ -1249,7 +1252,7 @@
 	struct net_device *dev = NULL;
 	struct sbus_bus *sbus;
 	struct sbus_dev *sdev = 0;
-	static int called = 0;
+	static int called;
 	int cards = 0, v;
 
 	root_bigmac_dev = NULL;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sundance.c linux/drivers/net/sundance.c
--- v2.4.3/linux/drivers/net/sundance.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/sundance.c	Fri Apr 20 11:54:22 2001
@@ -18,19 +18,13 @@
 	http://www.scyld.com/network/sundance.html
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"sundance.c:v1.01 4/09/00  Written by Donald Becker\n";
-static const char version2[] =
-"  http://www.scyld.com/network/sundance.html\n";
-
 /* 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. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
-static int mtu = 0;
+static int mtu;
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
    Typical is a 64 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 32;
@@ -39,7 +33,7 @@
    Setting to > 1518 effectively disables this feature.
    This chip can receive into offset buffers, so the Alpha does not
    need a copy-align. */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
@@ -97,6 +91,10 @@
 
 #include <linux/spinlock.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "sundance.c:v1.01 4/09/00  Written by Donald Becker\n"
+KERN_INFO "  http://www.scyld.com/network/sundance.html\n";
 
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
@@ -384,6 +382,13 @@
 	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 	long ioaddr;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	if (pci_enable_device(pdev))
 		return -EIO;
 	pci_set_master(pdev);
@@ -404,7 +409,7 @@
 	ioaddr = pci_resource_start(pdev, 1);
 	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
 	if (!ioaddr)
-		goto err_out_iomem;
+		goto err_out_res;
 #endif
 
 	for (i = 0; i < 3; i++)
@@ -445,6 +450,7 @@
 	dev->do_ioctl = &mii_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	pci_set_drvdata(pdev, dev);
 
 	if (mtu)
 		dev->mtu = mtu;
@@ -493,7 +499,7 @@
 	pci_set_drvdata(pdev, NULL);
 #ifndef USE_IO_OPS
 	iounmap((void *)ioaddr);
-err_out_iomem:
+err_out_res:
 #endif
 	pci_release_regions(pdev);
 err_out_netdev:
@@ -527,7 +533,7 @@
 /* Set iff a MII transceiver on any interface requires mdio preamble.
    This only set with older tranceivers, so the extra
    code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required = 0;
+static char mii_preamble_required;
 
 enum mii_reg_bits {
 	MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
@@ -1239,7 +1245,7 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (dev) {
+	if (dev) {
 		unregister_netdev(dev);
 		pci_release_regions(pdev);
 #ifndef USE_IO_OPS
@@ -1260,6 +1266,10 @@
 
 static int __init sundance_init(void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init(&sundance_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sungem.c linux/drivers/net/sungem.c
--- v2.4.3/linux/drivers/net/sungem.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/net/sungem.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.8 2001/03/22 22:48:51 davem Exp $
+/* $Id: sungem.c,v 1.12 2001/04/17 07:20:20 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -159,13 +159,20 @@
 			       dev->name);
 	}
 
-	if (pcs_miistat & PCS_MIISTAT_LS)
+	if (pcs_miistat & PCS_MIISTAT_LS) {
 		printk(KERN_INFO "%s: PCS link is now up.\n",
 		       dev->name);
-	else
+	} else {
 		printk(KERN_INFO "%s: PCS link is now down.\n",
 		       dev->name);
 
+		/* If this happens and the link timer is not running,
+		 * reset so we re-negotiate.
+		 */
+		if (!timer_pending(&gp->link_timer))
+			return 1;
+	}
+
 	return 0;
 }
 
@@ -405,21 +412,41 @@
 	while (entry != limit) {
 		struct sk_buff *skb;
 		struct gem_txd *txd;
-		u32 dma_addr;
+		u32 dma_addr, dma_len;
+		int frag;
 
-		txd = &gp->init_block->txd[entry];
 		skb = gp->tx_skbs[entry];
-		dma_addr = (u32) le64_to_cpu(txd->buffer);
-		pci_unmap_single(gp->pdev, dma_addr,
-				 skb->len, PCI_DMA_TODEVICE);
-		gp->tx_skbs[entry] = NULL;
+		if (skb_shinfo(skb)->nr_frags) {
+			int last = entry + skb_shinfo(skb)->nr_frags;
+			int walk = entry;
+			int incomplete = 0;
 
+			last &= (TX_RING_SIZE - 1);
+			for (;;) {
+				walk = NEXT_TX(walk);
+				if (walk == limit)
+					incomplete = 1;
+				if (walk == last)
+					break;
+			}
+			if (incomplete)
+				break;
+		}
+		gp->tx_skbs[entry] = NULL;
 		gp->net_stats.tx_bytes += skb->len;
-		gp->net_stats.tx_packets++;
 
-		dev_kfree_skb_irq(skb);
+		for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+			txd = &gp->init_block->txd[entry];
 
-		entry = NEXT_TX(entry);
+			dma_addr = (u32) le64_to_cpu(txd->buffer);
+			dma_len = le64_to_cpu(txd->control_word) & TXDCTRL_BUFSZ;
+
+			pci_unmap_single(gp->pdev, dma_addr, dma_len, PCI_DMA_TODEVICE);
+			entry = NEXT_TX(entry);
+		}
+
+		gp->net_stats.tx_packets++;
+		dev_kfree_skb_irq(skb);
 	}
 	gp->tx_old = entry;
 
@@ -441,7 +468,7 @@
 			struct gem_rxd *rxd =
 				&gp->init_block->rxd[cluster_start];
 			for (;;) {
-				rxd->status_word = cpu_to_le64(RXDCTRL_FRESH);
+				rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
 				rxd++;
 				cluster_start = NEXT_RX(cluster_start);
 				if (cluster_start == curr)
@@ -491,19 +518,19 @@
 		if (len > RX_COPY_THRESHOLD) {
 			struct sk_buff *new_skb;
 
-			new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+			new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
 			if (new_skb == NULL) {
 				drops++;
 				goto drop_it;
 			}
 			pci_unmap_single(gp->pdev, dma_addr,
-					 RX_BUF_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
+					 RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE);
 			gp->rx_skbs[entry] = new_skb;
 			new_skb->dev = gp->dev;
 			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
 			rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev,
 								 new_skb->data,
-								 RX_BUF_ALLOC_SIZE,
+								 RX_BUF_ALLOC_SIZE(gp),
 								 PCI_DMA_FROMDEVICE));
 			skb_reserve(new_skb, RX_OFFSET);
 
@@ -527,6 +554,8 @@
 			skb = copy_skb;
 		}
 
+		skb->csum = ((status & RXDCTRL_TCPCSUM) ^ 0xffff);
+		skb->ip_summed = CHECKSUM_HW;
 		skb->protocol = eth_type_trans(skb, gp->dev);
 		netif_rx(skb);
 
@@ -548,8 +577,8 @@
 
 static void gem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct gem *gp = (struct gem *) dev->priv;
+	struct net_device *dev = dev_id;
+	struct gem *gp = dev->priv;
 	u32 gem_status = readl(gp->regs + GREG_STAT);
 
 	spin_lock(&gp->lock);
@@ -567,33 +596,114 @@
 	spin_unlock(&gp->lock);
 }
 
+static void gem_tx_timeout(struct net_device *dev)
+{
+	struct gem *gp = dev->priv;
+
+	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+	printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n",
+	       dev->name,
+	       readl(gp->regs + TXDMA_CFG),
+	       readl(gp->regs + MAC_TXSTAT),
+	       readl(gp->regs + MAC_TXCFG));
+	printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n",
+	       dev->name,
+	       readl(gp->regs + RXDMA_CFG),
+	       readl(gp->regs + MAC_RXSTAT),
+	       readl(gp->regs + MAC_RXCFG));
+
+	spin_lock_irq(&gp->lock);
+
+	gem_stop(gp, gp->regs);
+	gem_init_rings(gp, 1);
+	gem_init_hw(gp);
+
+	spin_unlock_irq(&gp->lock);
+
+	netif_wake_queue(dev);
+}
+
 static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct gem *gp = (struct gem *) dev->priv;
-	long len;
-	int entry, avail;
-	u32 mapping;
+	struct gem *gp = dev->priv;
+	int entry;
+	u64 ctrl;
 
-	len = skb->len;
-	mapping = pci_map_single(gp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	ctrl = 0;
+	if (skb->ip_summed == CHECKSUM_HW) {
+		u64 csum_start_off, csum_stuff_off;
+
+		csum_start_off = (u64) (skb->h.raw - skb->data);
+		csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data);
+
+		ctrl = (TXDCTRL_CENAB |
+			(csum_start_off << 15) |
+			(csum_stuff_off << 21));
+	}
 
 	spin_lock_irq(&gp->lock);
-	entry = gp->tx_new;
-	gp->tx_skbs[entry] = skb;
 
-	gp->tx_new = NEXT_TX(entry);
-	avail = TX_BUFFS_AVAIL(gp);
-	if (avail <= 0)
+	if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
+		spin_unlock_irq(&gp->lock);
+		return 1;
+	}
 
-	{
+	entry = gp->tx_new;
+	gp->tx_skbs[entry] = skb;
+
+	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct gem_txd *txd = &gp->init_block->txd[entry];
-		u64 ctrl = (len & TXDCTRL_BUFSZ) | TXDCTRL_EOF | TXDCTRL_SOF;
+		u32 mapping, len;
 
-		txd->control_word = cpu_to_le64(ctrl);
+		len = skb->len;
+		mapping = pci_map_single(gp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+		ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len;
 		txd->buffer = cpu_to_le64(mapping);
+		txd->control_word = cpu_to_le64(ctrl);
+		entry = NEXT_TX(entry);
+	} else {
+		struct gem_txd *txd;
+		u32 first_len, first_mapping;
+		int frag, first_entry = entry;
+
+		/* We must give this initial chunk to the device last.
+		 * Otherwise we could race with the device.
+		 */
+		first_len = skb->len - skb->data_len;
+		first_mapping = pci_map_single(gp->pdev, skb->data,
+					       first_len, PCI_DMA_TODEVICE);
+		entry = NEXT_TX(entry);
+
+		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+			u32 len, mapping;
+			u64 this_ctrl;
+
+			len = this_frag->size;
+			mapping = pci_map_single(gp->pdev,
+						 ((void *) page_address(this_frag->page) +
+						  this_frag->page_offset),
+						 len, PCI_DMA_TODEVICE);
+			this_ctrl = ctrl;
+			if (frag == skb_shinfo(skb)->nr_frags - 1)
+				this_ctrl |= TXDCTRL_EOF;
+			
+			txd = &gp->init_block->txd[entry];
+			txd->buffer = cpu_to_le64(mapping);
+			txd->control_word = cpu_to_le64(this_ctrl | len);
+
+			entry = NEXT_TX(entry);
+		}
+		txd = &gp->init_block->txd[first_entry];
+		txd->buffer = cpu_to_le64(first_mapping);
+		txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | first_len);
 	}
 
+	gp->tx_new = entry;
+	if (TX_BUFFS_AVAIL(gp) <= 0)
+		netif_stop_queue(dev);
+
 	writel(gp->tx_new, gp->regs + TXDMA_KICK);
 	spin_unlock_irq(&gp->lock);
 
@@ -602,6 +712,30 @@
 	return 0;
 }
 
+/* Jumbo-grams don't seem to work :-( */
+#if 1
+#define MAX_MTU		1500
+#else
+#define MAX_MTU		9000
+#endif
+
+static int gem_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct gem *gp = dev->priv;
+
+	if (new_mtu < 0 || new_mtu > MAX_MTU)
+		return -EINVAL;
+
+	spin_lock_irq(&gp->lock);
+	gem_stop(gp, gp->regs);
+	dev->mtu = new_mtu;
+	gem_init_rings(gp, 1);
+	gem_init_hw(gp);
+	spin_unlock_irq(&gp->lock);
+
+	return 0;
+}
+
 #define STOP_TRIES 32
 
 static void gem_stop(struct gem *gp, unsigned long regs)
@@ -676,8 +810,29 @@
 	} else if (full_duplex) {
 		val |= MAC_XIFCFG_FLED;
 	}
+
+	if (speed == 1000)
+		val |= (MAC_XIFCFG_GMII);
+
 	writel(val, gp->regs + MAC_XIFCFG);
 
+	/* If gigabit and half-duplex, enable carrier extension
+	 * mode.  Else, disable it.
+	 */
+	if (speed == 1000 && !full_duplex) {
+		val = readl(gp->regs + MAC_TXCFG);
+		writel(val | MAC_TXCFG_TCE, gp->regs + MAC_TXCFG);
+
+		val = readl(gp->regs + MAC_RXCFG);
+		writel(val | MAC_RXCFG_RCE, gp->regs + MAC_RXCFG);
+	} else {
+		val = readl(gp->regs + MAC_TXCFG);
+		writel(val & ~MAC_TXCFG_TCE, gp->regs + MAC_TXCFG);
+
+		val = readl(gp->regs + MAC_RXCFG);
+		writel(val & ~MAC_RXCFG_RCE, gp->regs + MAC_RXCFG);
+	}
+
 	if (gp->phy_type == phy_serialink ||
 	    gp->phy_type == phy_serdes) {
 		u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
@@ -689,10 +844,6 @@
 			val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE);
 		writel(val, gp->regs + MAC_MCCFG);
 
-		/* XXX Set up PCS MII Control and Serialink Control
-		 * XXX registers.
-		 */
-
 		if (!full_duplex)
 			writel(512, gp->regs + MAC_STIME);
 		else
@@ -767,7 +918,16 @@
 			restart_timer = gem_mdio_link_not_up(gp);
 		}
 	} else {
-		/* XXX Code PCS support... XXX */
+		u32 val = readl(gp->regs + PCS_MIISTAT);
+
+		if (!(val & PCS_MIISTAT_LS))
+			val = readl(gp->regs + PCS_MIISTAT);
+
+		if ((val & PCS_MIISTAT_LS) == 0) {
+			restart_timer = 1;
+		} else {
+			gem_set_link_modes(gp);
+		}
 	}
 
 	if (restart_timer) {
@@ -792,7 +952,7 @@
 			skb = gp->rx_skbs[i];
 			dma_addr = (u32) le64_to_cpu(rxd->buffer);
 			pci_unmap_single(gp->pdev, dma_addr,
-					 RX_BUF_ALLOC_SIZE,
+					 RX_BUF_ALLOC_SIZE(gp),
 					 PCI_DMA_FROMDEVICE);
 			dev_kfree_skb_any(skb);
 			gp->rx_skbs[i] = NULL;
@@ -804,14 +964,22 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (gp->tx_skbs[i] != NULL) {
 			struct gem_txd *txd;
+			int frag;
 
 			skb = gp->tx_skbs[i];
-			txd = &gb->txd[i];
-			dma_addr = (u32) le64_to_cpu(txd->buffer);
-			pci_unmap_single(gp->pdev, dma_addr,
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_any(skb);
 			gp->tx_skbs[i] = NULL;
+
+			for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+				txd = &gb->txd[i];
+				dma_addr = (u32) le64_to_cpu(txd->buffer);
+				pci_unmap_single(gp->pdev, dma_addr,
+						 le64_to_cpu(txd->control_word) &
+						 TXDCTRL_BUFSZ, PCI_DMA_TODEVICE);
+
+				if (frag != skb_shinfo(skb)->nr_frags)
+					i++;
+			}
+			dev_kfree_skb_any(skb);
 		}
 	}
 }
@@ -834,7 +1002,7 @@
 		struct sk_buff *skb;
 		struct gem_rxd *rxd = &gb->rxd[i];
 
-		skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+		skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags);
 		if (!skb) {
 			rxd->buffer = 0;
 			rxd->status_word = 0;
@@ -845,10 +1013,10 @@
 		skb->dev = dev;
 		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
 		dma_addr = pci_map_single(gp->pdev, skb->data,
-					  RX_BUF_ALLOC_SIZE,
+					  RX_BUF_ALLOC_SIZE(gp),
 					  PCI_DMA_FROMDEVICE);
 		rxd->buffer = cpu_to_le64(dma_addr);
-		rxd->status_word = cpu_to_le64(RXDCTRL_FRESH);
+		rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
 		skb_reserve(skb, RX_OFFSET);
 	}
 
@@ -863,15 +1031,19 @@
 static void gem_init_phy(struct gem *gp)
 {
 	if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {
+		u32 val;
+
 		/* Init datapath mode register. */
 		if (gp->phy_type == phy_mii_mdio0 ||
 		    gp->phy_type == phy_mii_mdio1) {
-			writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+			val = PCS_DMODE_MGM;
 		} else if (gp->phy_type == phy_serialink) {
-			writel(PCS_DMODE_SM, gp->regs + PCS_DMODE);
+			val = PCS_DMODE_SM | PCS_DMODE_GMOE;
 		} else {
-			writel(PCS_DMODE_ESM, gp->regs + PCS_DMODE);
+			val = PCS_DMODE_ESM;
 		}
+
+		writel(val, gp->regs + PCS_DMODE);
 	}
 
 	if (gp->phy_type == phy_mii_mdio0 ||
@@ -899,7 +1071,59 @@
 		val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
 		phy_write(gp, PHY_CTRL, val);
 	} else {
-		/* XXX Implement me XXX */
+		u32 val;
+		int limit;
+
+		/* Reset PCS unit. */
+		val = readl(gp->regs + PCS_MIICTRL);
+		val |= PCS_MIICTRL_RST;
+		writeb(val, gp->regs + PCS_MIICTRL);
+
+		limit = 32;
+		while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) {
+			udelay(100);
+			if (limit-- <= 0)
+				break;
+		}
+		if (limit <= 0)
+			printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
+			       gp->dev->name);
+
+		/* Make sure PCS is disabled while changing advertisement
+		 * configuration.
+		 */
+		val = readl(gp->regs + PCS_CFG);
+		val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
+		writel(val, gp->regs + PCS_CFG);
+
+		/* Advertise all capabilities. */
+		val = readl(gp->regs + PCS_MIIADV);
+		val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
+			PCS_MIIADV_SP | PCS_MIIADV_AP);
+		writel(val, gp->regs + PCS_MIIADV);
+
+		/* Enable and restart auto-negotiation, disable wrapback/loopback,
+		 * and re-enable PCS.
+		 */
+		val = readl(gp->regs + PCS_MIICTRL);
+		val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE);
+		val &= ~PCS_MIICTRL_WB;
+		writel(val, gp->regs + PCS_MIICTRL);
+
+		val = readl(gp->regs + PCS_CFG);
+		val |= PCS_CFG_ENABLE;
+		writel(val, gp->regs + PCS_CFG);
+
+		/* Make sure serialink loopback is off.  The meaning
+		 * of this bit is logically inverted based upon whether
+		 * you are in Serialink or SERDES mode.
+		 */
+		val = readl(gp->regs + PCS_SCTRL);
+		if (gp->phy_type == phy_serialink)
+			val &= ~PCS_SCTRL_LOOP;
+		else
+			val |= PCS_SCTRL_LOOP;
+		writel(val, gp->regs + PCS_SCTRL);
 	}
 }
 
@@ -907,7 +1131,7 @@
 {
 	u32 val;
 
-	val = (TXDMA_CFG_BASE | (0x4ff << 10) | TXDMA_CFG_PMODE);
+	val = (TXDMA_CFG_BASE | (0x7ff << 10) | TXDMA_CFG_PMODE);
 	writel(val, gp->regs + TXDMA_CFG);
 
 	writel(0, gp->regs + TXDMA_DBHI);
@@ -916,7 +1140,7 @@
 	writel(0, gp->regs + TXDMA_KICK);
 
 	val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
-	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
+	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512);
 	writel(val, gp->regs + RXDMA_CFG);
 
 	writel(0, gp->regs + RXDMA_DBHI);
@@ -931,12 +1155,12 @@
 	writel(val, gp->regs + RXDMA_PTHRESH);
 
 	if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
-		writel(((5 & RXDMA_BLANK_IPKTS) |
-			((8 << 12) & RXDMA_BLANK_ITIME)),
+		writel(((6 & RXDMA_BLANK_IPKTS) |
+			((4 << 12) & RXDMA_BLANK_ITIME)),
 		       gp->regs + RXDMA_BLANK);
 	else
-		writel(((5 & RXDMA_BLANK_IPKTS) |
-			((4 << 12) & RXDMA_BLANK_ITIME)),
+		writel(((6 & RXDMA_BLANK_IPKTS) |
+			((2 << 12) & RXDMA_BLANK_ITIME)),
 		       gp->regs + RXDMA_BLANK);
 }
 
@@ -955,7 +1179,7 @@
 	writel(0x04, gp->regs + MAC_IPG2);
 	writel(0x40, gp->regs + MAC_STIME);
 	writel(0x40, gp->regs + MAC_MINFSZ);
-	writel(0x5ee, gp->regs + MAC_MAXFSZ);
+	writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ);
 	writel(0x07, gp->regs + MAC_PASIZE);
 	writel(0x04, gp->regs + MAC_JAMSIZE);
 	writel(0x10, gp->regs + MAC_ATTLIM);
@@ -1097,7 +1321,7 @@
 
 static int gem_open(struct net_device *dev)
 {
-	struct gem *gp = (struct gem *) dev->priv;
+	struct gem *gp = dev->priv;
 	unsigned long regs = gp->regs;
 
 	del_timer(&gp->link_timer);
@@ -1117,6 +1341,9 @@
 {
 	struct gem *gp = dev->priv;
 
+	del_timer(&gp->link_timer);
+	gem_stop(gp, gp->regs);
+	gem_clean_rings(gp);
 	free_irq(gp->pdev->irq, (void *)dev);
 	return 0;
 }
@@ -1263,13 +1490,17 @@
 	/* Determine initial PHY interface type guess.  MDIO1 is the
 	 * external PHY and thus takes precedence over MDIO0.
 	 */
-	if (mif_cfg & MIF_CFG_MDI1)
+	if (mif_cfg & MIF_CFG_MDI1) {
 		gp->phy_type = phy_mii_mdio1;
-	else if (mif_cfg & MIF_CFG_MDI0)
+		mif_cfg |= MIF_CFG_PSELECT;
+		writel(mif_cfg, gp->regs + MIF_CFG);
+	} else if (mif_cfg & MIF_CFG_MDI0) {
 		gp->phy_type = phy_mii_mdio0;
-	else
+		mif_cfg &= ~MIF_CFG_PSELECT;
+		writel(mif_cfg, gp->regs + MIF_CFG);
+	} else {
 		gp->phy_type = phy_serialink;
-
+	}
 	if (gp->phy_type == phy_mii_mdio1 ||
 	    gp->phy_type == phy_mii_mdio0) {
 		int i;
@@ -1279,6 +1510,13 @@
 			if (phy_read(gp, PHY_CTRL) != 0xffff)
 				break;
 		}
+		if (i == 32) {
+			if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
+				printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
+				return -1;
+			}
+			gp->phy_type = phy_serdes;
+		}
 	}
 
 	/* Fetch the FIFO configurations now too. */
@@ -1309,23 +1547,50 @@
 	if (gp->rx_fifo_sz <= (2 * 1024)) {
 		gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
 	} else {
-		int off = ((gp->rx_fifo_sz * 3) / 4);
-		int on = off - (1 * 1024);
+		int off = (gp->rx_fifo_sz - (5 * 1024));
+		int on = off - 1024;
 
 		gp->rx_pause_off = off;
 		gp->rx_pause_on = on;
 	}
 
 	{
-		u32 bifcfg = readl(gp->regs + GREG_BIFCFG);
+		u32 cfg = readl(gp->regs + GREG_BIFCFG);
 
-		bifcfg |= GREG_BIFCFG_B64DIS;
-		writel(bifcfg, gp->regs + GREG_BIFCFG);
+		cfg |= GREG_BIFCFG_B64DIS;
+		writel(cfg, gp->regs + GREG_BIFCFG);
+
+		cfg  = GREG_CFG_IBURST;
+		cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
+		cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
+		writel(cfg, gp->regs + GREG_CFG);
 	}
 
 	return 0;
 }
 
+static void __devinit gem_get_device_address(struct gem *gp)
+{
+	struct net_device *dev = gp->dev;
+	struct pci_dev *pdev = gp->pdev;
+
+#ifdef __sparc__
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	int node = -1;
+
+	if (pcp != NULL) {
+		node = pcp->prom_node;
+		if (prom_getproplen(node, "local-mac-address") == 6)
+			prom_getproperty(node, "local-mac-address",
+					 dev->dev_addr, 6);
+		else
+			node = -1;
+	}
+	if (node == -1)
+		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+#endif
+}
+
 static int __devinit gem_init_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
@@ -1352,6 +1617,7 @@
 		printk(KERN_ERR PFX "Etherdev init failed, aborting.\n");
 		return -ENOMEM;
 	}
+	SET_MODULE_OWNER(dev);
 
 	if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) {
 		printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, "
@@ -1372,6 +1638,7 @@
 
 	gp->pdev = pdev;
 	dev->base_addr = (long) pdev;
+	gp->dev = dev;
 
 	spin_lock_init(&gp->lock);
 
@@ -1402,9 +1669,7 @@
 	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
 	       dev->name);
 
-#ifdef __sparc__
-	memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#endif
+	gem_get_device_address(gp);
 
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
@@ -1415,15 +1680,20 @@
 	gp->link_timer.function = gem_link_timer;
 	gp->link_timer.data = (unsigned long) gp;
 
-	gp->dev = dev;
 	dev->open = gem_open;
 	dev->stop = gem_close;
 	dev->hard_start_xmit = gem_start_xmit;
 	dev->get_stats = gem_get_stats;
 	dev->set_multicast_list = gem_set_multicast;
 	dev->do_ioctl = gem_ioctl;
+	dev->tx_timeout = gem_tx_timeout;
+	dev->watchdog_timeo = 5 * HZ;
+	dev->change_mtu = gem_change_mtu;
 	dev->irq = pdev->irq;
 	dev->dma = 0;
+
+	/* GEM can do it all... */
+	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
 	return 0;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sungem.h linux/drivers/net/sungem.h
--- v2.4.3/linux/drivers/net/sungem.h	Sun Mar 25 18:14:21 2001
+++ linux/drivers/net/sungem.h	Thu Apr 12 12:11:39 2001
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.5 2001/03/21 23:02:04 davem Exp $
+/* $Id: sungem.h,v 1.7 2001/04/04 14:49:40 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -727,7 +727,10 @@
 #define PCS_DMODE_MGM	0x00000004	/* MII/GMII mode		*/
 #define PCS_DMODE_GMOE	0x00000008	/* GMII Output Enable		*/
 
-/* Serialink Control Register. */
+/* Serialink Control Register.
+ *
+ * NOTE: When in SERDES mode, the loopback bit has inverse logic.
+ */
 #define PCS_SCTRL_LOOP	0x00000001	/* Loopback enable		*/
 #define PCS_SCTRL_ESCD	0x00000002	/* Enable sync char detection	*/
 #define PCS_SCTRL_LOCK	0x00000004	/* Lock to reference clock	*/
@@ -837,8 +840,8 @@
 #define RXDCTRL_ALTMAC	0x2000000000000000	/* Matched ALT MAC	*/
 #define RXDCTRL_BAD	0x4000000000000000	/* Frame has bad CRC	*/
 
-#define RXDCTRL_FRESH	\
-	((((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \
+#define RXDCTRL_FRESH(gp)	\
+	((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \
 	 RXDCTRL_OWN)
 
 #define TX_RING_SIZE 128
@@ -897,7 +900,7 @@
 	  (GP)->tx_old - (GP)->tx_new - 1)
 
 #define RX_OFFSET          2
-#define RX_BUF_ALLOC_SIZE  (1546 + RX_OFFSET + 64)
+#define RX_BUF_ALLOC_SIZE(gp)	((gp)->dev->mtu + 46 + RX_OFFSET + 64)
 
 #define RX_COPY_THRESHOLD  256
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.4.3/linux/drivers/net/sunhme.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/sunhme.c	Thu Apr 19 09:34:52 2001
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.105 2000/12/05 02:00:36 anton Exp $
+/* $Id: sunhme.c,v 1.116 2001/04/17 07:20:52 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -13,7 +13,7 @@
  *     argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50
  */
 
-static char *version =
+static char version[] =
         "sunhme.c:v1.99 12/Sep/99 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
@@ -73,14 +73,14 @@
 /* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
 MODULE_PARM(macaddr, "6i");
 
-static struct happy_meal *root_happy_dev = NULL;
+static struct happy_meal *root_happy_dev;
 
 #ifdef CONFIG_SBUS
-static struct quattro *qfe_sbus_list = NULL;
+static struct quattro *qfe_sbus_list;
 #endif
 
 #ifdef CONFIG_PCI
-static struct quattro *qfe_pci_list = NULL;
+static struct quattro *qfe_pci_list;
 #endif
 
 #undef HMEDEBUG
@@ -102,7 +102,7 @@
 };
 #define TX_LOG_LEN	128
 static struct hme_tx_logent tx_log[TX_LOG_LEN];
-static int txlog_cur_entry = 0;
+static int txlog_cur_entry;
 static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s)
 {
 	struct hme_tx_logent *tlp;
@@ -1277,12 +1277,23 @@
 			struct sk_buff *skb = hp->tx_skbs[i];
 			struct happy_meal_txd *txd;
 			u32 dma_addr;
+			int frag;
 
-			txd = &hp->happy_block->happy_meal_txd[i];
-			dma_addr = hme_read_desc32(hp, &txd->tx_addr);
-			hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
-			dev_kfree_skb_any(skb);
 			hp->tx_skbs[i] = NULL;
+
+			for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+				txd = &hp->happy_block->happy_meal_txd[i];
+				dma_addr = hme_read_desc32(hp, &txd->tx_addr);
+				hme_dma_unmap(hp, dma_addr,
+					      (hme_read_desc32(hp, &txd->tx_flags)
+					       & TXFLAG_SIZE),
+					      DMA_TODEVICE);
+
+				if (frag != skb_shinfo(skb)->nr_frags)
+					i++;
+			}
+
+			dev_kfree_skb_any(skb);
 		}
 	}
 }
@@ -1842,7 +1853,7 @@
 
 	if (status & GREG_STAT_NORXD) {
 		/* This is harmless, it just means the system is
-		 * quite loaded and the incomming packet rate was
+		 * quite loaded and the incoming packet rate was
 		 * faster than the interrupt handler could keep up
 		 * with.
 		 */
@@ -1958,23 +1969,40 @@
 	TXD(("TX<"));
 	while (elem != hp->tx_new) {
 		struct sk_buff *skb;
-		u32 flags, dma_addr;
+		u32 flags, dma_addr, dma_len;
+		int frag;
 
 		TXD(("[%d]", elem));
 		this = &txbase[elem];
 		flags = hme_read_desc32(hp, &this->tx_flags);
 		if (flags & TXFLAG_OWN)
 			break;
-		dma_addr = hme_read_desc32(hp, &this->tx_addr);
 		skb = hp->tx_skbs[elem];
-		hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
+		if (skb_shinfo(skb)->nr_frags) {
+			int last;
+
+			last = elem + skb_shinfo(skb)->nr_frags;
+			last &= (TX_RING_SIZE - 1);
+			flags = hme_read_desc32(hp, &txbase[last].tx_flags);
+			if (flags & TXFLAG_OWN)
+				break;
+		}
 		hp->tx_skbs[elem] = NULL;
 		hp->net_stats.tx_bytes += skb->len;
 
-		dev_kfree_skb_irq(skb);
+		for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+			dma_addr = hme_read_desc32(hp, &this->tx_addr);
+			dma_len = hme_read_desc32(hp, &this->tx_flags);
+
+			dma_len &= TXFLAG_SIZE;
+			hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);
 
+			elem = NEXT_TX(elem);
+			this = &txbase[elem];
+		}
+
+		dev_kfree_skb_irq(skb);
 		hp->net_stats.tx_packets++;
-		elem = NEXT_TX(elem);
 	}
 	hp->tx_old = elem;
 	TXD((">"));
@@ -2079,10 +2107,8 @@
 		}
 
 		/* This card is _fucking_ hot... */
-		if (!(csum ^ 0xffff))
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-		else
-			skb->ip_summed = CHECKSUM_NONE;
+		skb->csum = (csum ^ 0xffff);
+		skb->ip_summed = CHECKSUM_HW;
 
 		RXD(("len=%d csum=%4x]", len, csum));
 		skb->protocol = eth_type_trans(skb, dev);
@@ -2104,7 +2130,7 @@
 static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct happy_meal *hp  = (struct happy_meal *) dev->priv;
+	struct happy_meal *hp  = dev->priv;
 	u32 happy_status       = hme_read32(hp, hp->gregs + GREG_STAT);
 
 	HMD(("happy_meal_interrupt: status=%08x ", happy_status));
@@ -2141,7 +2167,7 @@
 
 	for (i = 0; i < 4; i++) {
 		struct net_device *dev = qp->happy_meals[i];
-		struct happy_meal *hp  = (struct happy_meal *) dev->priv;
+		struct happy_meal *hp  = dev->priv;
 		u32 happy_status       = hme_read32(hp, hp->gregs + GREG_STAT);
 
 		HMD(("quattro_interrupt: status=%08x ", happy_status));
@@ -2179,8 +2205,7 @@
 
 static int happy_meal_open(struct net_device *dev)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
-	int res;
+	struct happy_meal *hp = dev->priv;
 
 	HMD(("happy_meal_open: "));
 
@@ -2204,16 +2229,12 @@
 	}
 
 	HMD(("to happy_meal_init\n"));
-	res = happy_meal_init(hp, 0);
-	if (!res) {
-		MOD_INC_USE_COUNT;
-	}
-	return res;
+	return happy_meal_init(hp, 0);
 }
 
 static int happy_meal_close(struct net_device *dev)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct happy_meal *hp = dev->priv;
 
 	happy_meal_stop(hp, hp->gregs);
 	happy_meal_clean_rings(hp);
@@ -2226,9 +2247,8 @@
 	 * time and never unregister.
 	 */
 	if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)
-		free_irq(dev->irq, (void *)dev);
+		free_irq(dev->irq, dev);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -2241,7 +2261,7 @@
 #ifdef CONFIG_SBUS
 static void happy_meal_tx_timeout(struct net_device *dev)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct happy_meal *hp = dev->priv;
 
 	printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 	tx_dump_log();
@@ -2256,22 +2276,79 @@
 
 static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
-	int len, entry;
-	u32 mapping;
-
-	len = skb->len;
-	mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+	struct happy_meal *hp = dev->priv;
+ 	int entry;
+ 	u32 tx_flags;
+
+	tx_flags = TXFLAG_OWN;
+	if (skb->ip_summed == CHECKSUM_HW) {
+		u32 csum_start_off, csum_stuff_off;
+
+		csum_start_off = (u32) (skb->h.raw - skb->data);
+		csum_stuff_off = (u32) ((skb->h.raw + skb->csum) - skb->data);
+
+		tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE |
+			    ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) |
+			    ((csum_stuff_off << 20) & TXFLAG_CSLOCATION));
+	}
 
 	spin_lock_irq(&hp->happy_lock);
 
+ 	if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&hp->happy_lock);
+		return 1;
+	}
+
 	entry = hp->tx_new;
 	SXD(("SX<l[%d]e[%d]>", len, entry));
 	hp->tx_skbs[entry] = skb;
-	hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
-		      (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)),
-		      mapping);
-	hp->tx_new = NEXT_TX(entry);
+
+	if (skb_shinfo(skb)->nr_frags == 0) {
+		u32 mapping, len;
+
+		len = skb->len;
+		mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+		tx_flags |= (TXFLAG_SOP | TXFLAG_EOP);
+		hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
+			      (tx_flags | (len & TXFLAG_SIZE)),
+			      mapping);
+		entry = NEXT_TX(entry);
+	} else {
+		u32 first_len, first_mapping;
+		int frag, first_entry = entry;
+
+		/* We must give this initial chunk to the device last.
+		 * Otherwise we could race with the device.
+		 */
+		first_len = skb->len - skb->data_len;
+		first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
+		entry = NEXT_TX(entry);
+
+		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+			u32 len, mapping, this_txflags;
+
+			len = this_frag->size;
+			mapping = hme_dma_map(hp,
+					      ((void *) page_address(this_frag->page) +
+					       this_frag->page_offset),
+					      len, DMA_TODEVICE);
+			this_txflags = tx_flags;
+			if (frag == skb_shinfo(skb)->nr_frags - 1)
+				this_txflags |= TXFLAG_EOP;
+			hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
+				      (this_txflags | (len & TXFLAG_SIZE)),
+				      mapping);
+			entry = NEXT_TX(entry);
+		}
+		hme_write_txd(hp, &hp->happy_block->happy_meal_txd[first_entry],
+			      (tx_flags | TXFLAG_SOP | (first_len & TXFLAG_SIZE)),
+			      first_mapping);
+	}
+
+	hp->tx_new = entry;
+
 	if (TX_BUFFS_AVAIL(hp) <= 0)
 		netif_stop_queue(dev);
 
@@ -2288,7 +2365,7 @@
 
 static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct happy_meal *hp = dev->priv;
 
 	happy_meal_get_counters(hp, hp->bigmacregs);
 	return &hp->net_stats;
@@ -2296,7 +2373,7 @@
 
 static void happy_meal_set_multicast(struct net_device *dev)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct happy_meal *hp = dev->priv;
 	unsigned long bregs = hp->bigmacregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
@@ -2355,7 +2432,7 @@
 static int happy_meal_ioctl(struct net_device *dev,
 			    struct ifreq *rq, int cmd)
 {
-	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct happy_meal *hp = dev->priv;
 	struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data;
 	struct ethtool_cmd ecmd;
 
@@ -2429,7 +2506,7 @@
 		return -EOPNOTSUPP;
 }
 
-static int hme_version_printed = 0;
+static int hme_version_printed;
 
 #ifdef CONFIG_SBUS
 void __init quattro_get_ranges(struct quattro *qp)
@@ -2480,27 +2557,23 @@
 	struct sbus_bus *sbus;
 	struct sbus_dev *sdev;
 	struct quattro *qp;
+	int i;
 
 	if (qfe_sbus_list == NULL)
 		goto found;
 
 	for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		for (sdev = qp->quattro_dev;
-		     sdev != NULL;
-		     sdev = sdev->next) {
+		for (i = 0, sdev = qp->quattro_dev;
+		     (sdev != NULL) && (i < 4);
+		     sdev = sdev->next, i++) {
 			if (sdev == goal_sdev)
 				return qp;
 		}
 	}
 	for_each_sbus(sbus) {
 		for_each_sbusdev(sdev, sbus) {
-			if (sdev->child != NULL) {
-				struct sbus_dev *p;
-
-				for (p = sdev->child; p != NULL; p = p->next)
-					if (p == goal_sdev)
-						goto found;
-			}
+			if (sdev == goal_sdev)
+				goto found;
 		}
 	}
 
@@ -2578,12 +2651,11 @@
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_init(struct net_device *dev,
-				       struct sbus_dev *sdev,
-				       int is_qfe)
+static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
 {
 	struct quattro *qp = NULL;
 	struct happy_meal *hp;
+	struct net_device *dev;
 	int i, qfe_slot = -1;
 
 	if (is_qfe) {
@@ -2596,13 +2668,12 @@
 		if (qfe_slot == 4)
 			return -ENODEV;
 	}
-	if (dev == NULL) {
-		dev = init_etherdev(0, sizeof(struct happy_meal));
-	} else {
-		dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL);
-		if (dev->priv == NULL)
-			return -ENOMEM;
-	}
+
+	dev = init_etherdev(NULL, sizeof(struct happy_meal));
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
+
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
@@ -2637,7 +2708,7 @@
 		       dev->dev_addr[i], i == 5 ? ' ' : ':');
 	printk("\n");
 
-	hp = (struct happy_meal *) dev->priv;
+	hp = dev->priv;
 	memset(hp, 0, sizeof(*hp));
 
 	hp->happy_dev = sdev;
@@ -2733,6 +2804,9 @@
 	dev->watchdog_timeo = 5*HZ;
 	dev->do_ioctl = &happy_meal_ioctl;
 
+	/* Happy Meal can do it all... */
+	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+
 	dev->irq = sdev->irqs[0];
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
@@ -2766,7 +2840,7 @@
 #endif
 
 #ifdef CONFIG_PCI
-static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pdev)
+static int __init happy_meal_pci_init(struct pci_dev *pdev)
 {
 	struct quattro *qp = NULL;
 #ifdef __sparc__
@@ -2774,6 +2848,7 @@
 	int node;
 #endif
 	struct happy_meal *hp;
+	struct net_device *dev;
 	unsigned long hpreg_base;
 	int i, qfe_slot = -1;
 	char prom_name[64];
@@ -2803,13 +2878,12 @@
 		if (qfe_slot == 4)
 			return -ENODEV;
 	}
-	if (dev == NULL) {
-		dev = init_etherdev(0, sizeof(struct happy_meal));
-	} else {
-		dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL);
-		if (dev->priv == NULL)
-			return -ENOMEM;
-	}
+
+	dev = init_etherdev(NULL, sizeof(struct happy_meal));
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
+
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
@@ -2856,7 +2930,10 @@
 		printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
 		return -ENODEV;
 	}
-	hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000);
+	if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) {
+		printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n");
+		return -ENODEV;
+	}
 
 	for (i = 0; i < 6; i++) {
 		if (macaddr[i] != 0)
@@ -2941,6 +3018,9 @@
 	dev->irq = pdev->irq;
 	dev->dma = 0;
 
+	/* Happy Meal can do it all... */
+	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
 	/* Hook up PCI register/dma accessors. */
 	hp->read_desc32 = pci_hme_read_desc32;
@@ -2972,25 +3052,29 @@
 #endif
 
 #ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_probe(struct net_device *dev)
+static int __init happy_meal_sbus_probe(void)
 {
 	struct sbus_bus *sbus;
 	struct sbus_dev *sdev;
 	int cards = 0;
+	char model[128];
 
 	for_each_sbus(sbus) {
 		for_each_sbusdev(sdev, sbus) {
 			char *name = sdev->prom_name;
 
-			if (cards)
-				dev = NULL;
 			if (!strcmp(name, "SUNW,hme")) {
 				cards++;
-				happy_meal_sbus_init(dev, sdev, 0);
+				prom_getstring(sdev->prom_node, "model",
+					       model, sizeof(model));
+				if (!strcmp(model, "SUNW,sbus-qfe"))
+					happy_meal_sbus_init(sdev, 1);
+				else
+					happy_meal_sbus_init(sdev, 0);
 			} else if (!strcmp(name, "qfe") ||
 				   !strcmp(name, "SUNW,qfe")) {
 				cards++;
-				happy_meal_sbus_init(dev, sdev, 1);
+				happy_meal_sbus_init(sdev, 1);
 			}
 		}
 	}
@@ -3001,7 +3085,7 @@
 #endif
 
 #ifdef CONFIG_PCI
-static int __init happy_meal_pci_probe(struct net_device *dev)
+static int __init happy_meal_pci_probe(void)
 {
 	struct pci_dev *pdev = NULL;
 	int cards = 0;
@@ -3010,10 +3094,8 @@
 				       PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
 		if (pci_enable_device(pdev))
 			continue;
-		if (cards)
-			dev = NULL;
 		cards++;
-		happy_meal_pci_init(dev, pdev);
+		happy_meal_pci_init(pdev);
 	}
 	return cards;
 }
@@ -3021,7 +3103,6 @@
 
 static int __init happy_meal_probe(void)
 {
-	struct net_device *dev = NULL;
 	static int called = 0;
 	int cards;
 
@@ -3033,12 +3114,10 @@
 
 	cards = 0;
 #ifdef CONFIG_SBUS
-	cards += happy_meal_sbus_probe(dev);
-	if (cards != 0)
-		dev = NULL;
+	cards += happy_meal_sbus_probe();
 #endif
 #ifdef CONFIG_PCI
-	cards += happy_meal_pci_probe(dev);
+	cards += happy_meal_pci_probe();
 #endif
 	if (!cards)
 		return -ENODEV;
@@ -3048,12 +3127,23 @@
 
 static void __exit happy_meal_cleanup_module(void)
 {
+#ifdef CONFIG_SBUS
+	struct quattro *last_seen_qfe = NULL;
+#endif
+
 	while (root_happy_dev) {
 		struct happy_meal *hp = root_happy_dev;
 		struct happy_meal *next = root_happy_dev->next_module;
 
 #ifdef CONFIG_SBUS
 		if (!(hp->happy_flags & HFLAG_PCI)) {
+			if (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;
+				}
+			}
+
 			sbus_iounmap(hp->gregs, GREG_REG_SIZE);
 			sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
 			sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
@@ -3071,6 +3161,7 @@
 					    PAGE_SIZE,
 					    hp->happy_block,
 					    hp->hblock_dvma);
+			iounmap((void *)hp->gregs);
 		}
 #endif
 		unregister_netdev(hp->dev);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.4.3/linux/drivers/net/sunhme.h	Mon Dec 11 13:01:05 2000
+++ linux/drivers/net/sunhme.h	Thu Apr 12 12:11:39 2001
@@ -1,4 +1,4 @@
-/* $Id: sunhme.h,v 1.31 2000/11/12 10:23:30 davem Exp $
+/* $Id: sunhme.h,v 1.32 2000/12/13 18:31:47 davem Exp $
  * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver.
  *           Also known as the "Happy Meal".
  *
@@ -151,7 +151,8 @@
 #define ERX_CFG_SIZE128      0x00000400 /* Receive ring size == 128  */
 #define ERX_CFG_SIZE256      0x00000600 /* Receive ring size == 256  */
 #define ERX_CFG_RESV3        0x0000f800 /* Unused...                 */
-#define ERX_CFG_CSUMSTART    0x007f0000 /* Offset of checksum start  */
+#define ERX_CFG_CSUMSTART    0x007f0000 /* Offset of checksum start,
+					 * in halfwords. */
 
 /* I'd like a Big Mac, small fries, small coke, and SparcLinux please. */
 #define BMAC_XIFCFG	0x0000UL	/* XIF config register                */
@@ -445,14 +446,31 @@
 #define TX_RING_SIZE       32         /* Must be >16 and <255, multiple of 16  */
 #define RX_RING_SIZE       32         /* see ERX_CFG_SIZE* for possible values */
 
+#if (TX_RING_SIZE < 16 || TX_RING_SIZE > 256 || (TX_RING_SIZE % 16) != 0)
+#error TX_RING_SIZE holds illegal value
+#endif
+
 #define TX_RING_MAXSIZE    256
 #define RX_RING_MAXSIZE    256
 
-/* 34 byte offset for checksum computation.  This works because ip_input() will clear out
- * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
- * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr)
- */
-#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|(0x22<<16))
+/* We use a 14 byte offset for checksum computation. */
+#if (RX_RING_SIZE == 32)
+#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|((14/2)<<16))
+#else
+#if (RX_RING_SIZE == 64)
+#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE64|((14/2)<<16))
+#else
+#if (RX_RING_SIZE == 128)
+#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE128|((14/2)<<16))
+#else
+#if (RX_RING_SIZE == 256)
+#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE256|((14/2)<<16))
+#else
+#error RX_RING_SIZE holds illegal value
+#endif
+#endif
+#endif
+#endif
 
 #define NEXT_RX(num)       (((num) + 1) & (RX_RING_SIZE - 1))
 #define NEXT_TX(num)       (((num) + 1) & (TX_RING_SIZE - 1))
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.4.3/linux/drivers/net/sunlance.c	Tue Mar  6 22:44:16 2001
+++ linux/drivers/net/sunlance.c	Thu Apr 19 09:34:52 2001
@@ -66,10 +66,10 @@
 
 #undef DEBUG_DRIVER
 
-static char *version =
+static char version[] =
 	"sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
 
-static char *lancestr = "LANCE";
+static char lancestr[] = "LANCE";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -291,7 +291,7 @@
 
 #define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
 
-static struct lance_private *root_lance_dev = NULL;
+static struct lance_private *root_lance_dev;
 
 /* Load the CSR registers */
 static void load_csrs(struct lance_private *lp)
@@ -1307,7 +1307,7 @@
 				   struct sbus_dma *ledma,
 				   struct sbus_dev *lebuffer)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	struct lance_private *lp = NULL;
 	int    i;
 
@@ -1518,7 +1518,7 @@
 static int __init sparc_lance_probe(void)
 {
 	static struct sbus_dev sdev;
-	static int called = 0;
+	static int called;
 
 	root_lance_dev = NULL;
 
@@ -1545,7 +1545,7 @@
 	struct sbus_dev *sdev = 0;
 	struct net_device *dev = NULL;
 	struct sbus_dma *ledma = 0;
-	static int called = 0;
+	static int called;
 	int cards = 0, v;
 
 	root_lance_dev = NULL;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.4.3/linux/drivers/net/sunqe.c	Tue Mar  6 22:44:16 2001
+++ linux/drivers/net/sunqe.c	Thu Apr 19 09:34:52 2001
@@ -7,7 +7,7 @@
  * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
  */
 
-static char *version =
+static char version[] =
         "sunqe.c:v2.9 9/11/99 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
@@ -46,7 +46,7 @@
 
 #include "sunqe.h"
 
-static struct sunqec *root_qec_dev = NULL;
+static struct sunqec *root_qec_dev;
 
 static void qe_set_multicast(struct net_device *dev);
 
@@ -733,7 +733,7 @@
 /* Four QE's per QEC card. */
 static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	struct net_device *qe_devs[4];
 	struct sunqe *qeps[4];
 	struct sbus_dev *qesdevs[4];
@@ -983,7 +983,7 @@
 	struct net_device *dev = NULL;
 	struct sbus_bus *bus;
 	struct sbus_dev *sdev = 0;
-	static int called = 0;
+	static int called;
 	int cards = 0, v;
 
 	root_qec_dev = NULL;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.4.3/linux/drivers/net/tlan.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/tlan.c	Thu Apr 19 09:34:52 2001
@@ -205,7 +205,7 @@
 static	int		bbuf;
 static	u8		*TLanPadBuffer;
 static	char		TLanSignature[] = "TLAN";
-static const char *tlan_banner = "ThunderLAN driver v1.14a\n";
+static const char tlan_banner[] = "ThunderLAN driver v1.14a\n";
 static int tlan_have_pci;
 static int tlan_have_eisa;
 
@@ -427,7 +427,7 @@
 
 static int __init tlan_probe(void)
 {
-	static int	pad_allocated = 0;
+	static int	pad_allocated;
 	
 	printk(KERN_INFO "%s", tlan_banner);
 	
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c
--- v2.4.3/linux/drivers/net/tokenring/lanstreamer.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/tokenring/lanstreamer.c	Thu Apr 19 09:34:52 2001
@@ -121,7 +121,7 @@
  * Official releases will only have an a.b.c version number format.
  */
 
-static char *version = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
+static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/madgemc.c linux/drivers/net/tokenring/madgemc.c
--- v2.4.3/linux/drivers/net/tokenring/madgemc.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/net/tokenring/madgemc.c	Fri Apr 20 11:54:22 2001
@@ -17,7 +17,7 @@
  *	16-Jan-00	AF	Created
  *
  */
-static const char *version = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
+static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
 
 #include <linux/module.h>
 #include <linux/mca.h>
@@ -61,7 +61,7 @@
 
 	struct madgemc_card *next;
 };
-static struct madgemc_card *madgemc_card_list = NULL;
+static struct madgemc_card *madgemc_card_list;
 
 
 int madgemc_probe(void);
@@ -155,7 +155,7 @@
 
 int __init madgemc_probe(void)
 {	
-	static int versionprinted = 0;
+	static int versionprinted;
 	struct net_device *dev;
 	struct net_local *tp;
 	struct madgemc_card *card;
@@ -525,7 +525,7 @@
  */
 static void madgemc_setregpage(struct net_device *dev, int page)
 {	
-	static int reg1 = 0;
+	static int reg1;
 
 	reg1 = inb(dev->base_addr + MC_CONTROL_REG1);
 	if ((page == 0) && (reg1 & MC_CONTROL_REG1_SRSX)) {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- v2.4.3/linux/drivers/net/tokenring/olympic.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/tokenring/olympic.c	Wed Apr 18 11:39:21 2001
@@ -1,6 +1,6 @@
 /*
  *   olympic.c (c) 1999 Peter De Schrijver All Rights Reserved
- *		   1999 Mike Phillips (mikep@linuxtr.net)
+ *		   1999/2000 Mike Phillips (mikep@linuxtr.net)
  *
  *  Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic
  *  chipset. 
@@ -38,10 +38,21 @@
  *            Fixing the hardware descriptors was another matter,
  *            because they weren't going through read[wl](), there all
  *            the results had to be in memory in le32 values. kdaaker
+ *
  * 12/23/00 - Added minimal Cardbus support (Thanks Donald).
  *
+ * 03/09/01 - Add new pci api, dev_base_lock, general clean up. 
+ *
+ * 03/27/01 - Add new dma pci (Thanks to Kyle Lucke) and alloc_trdev
+ *	      Change proc_fs behaviour, now one entry per adapter.
+ *
+ * 04/09/01 - Couple of bug fixes to the dma unmaps and ejecting the
+ *	      adapter when live does not take the system down with it.
+ * 
  *  To Do:
- *           Complete full Cardbus / hot-swap support.
+ *
+ *	     Complete full Cardbus / hot-swap support.
+ *	     Wake on lan	
  * 
  *  If Problems do Occur
  *  Most problems can be rectified by either closing and opening the interface
@@ -53,14 +64,6 @@
 
 #define OLYMPIC_DEBUG 0
 
-/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel.
- * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the
- * kernel.
- * Intended to be used to create a ring-error reporting network module 
- * i.e. it will give you the source address of beaconers on the ring 
- */
-
-#define OLYMPIC_NETWORK_MONITOR 0
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -100,14 +103,7 @@
  */
 
 static char *version = 
-"Olympic.c v0.5.C 12/23/00 - Peter De Schrijver & Mike Phillips" ; 
-
-static struct pci_device_id olympic_pci_tbl[] __initdata = {
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, PCI_ANY_ID, PCI_ANY_ID, },
-	{ }			/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, olympic_pci_tbl);
-
+"Olympic.c v0.9.C 4/18/01 - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -137,22 +133,34 @@
  */
 
 static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ;
-
 MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i");
 
 /* Packet buffer size */
 
 static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ;
- 
 MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
 
 /* Message Level */
 
 static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; 
-
 MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
 
-static int olympic_scan(struct net_device *dev);
+/* Change network_monitor to receive mac frames through the arb channel.
+ * Will also create a /proc/net/olympic_tr%d entry, where %d is the tr
+ * device, i.e. tr0, tr1 etc. 
+ * Intended to be used to create a ring-error reporting network module 
+ * i.e. it will give you the source address of beaconers on the ring 
+ */
+static int network_monitor[OLYMPIC_MAX_ADAPTERS] = {0,};
+MODULE_PARM(network_monitor, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i");
+
+static struct pci_device_id olympic_pci_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_TR_WAKE,PCI_ANY_ID,PCI_ANY_ID,},
+	{ } 	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci,olympic_pci_tbl) ; 
+
+static int __init olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); 
 static int olympic_init(struct net_device *dev);
 static int olympic_open(struct net_device *dev);
 static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -165,109 +173,89 @@
 static int olympic_change_mtu(struct net_device *dev, int mtu);
 static void olympic_srb_bh(struct net_device *dev) ; 
 static void olympic_asb_bh(struct net_device *dev) ; 
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-static int sprintf_info(char *buffer, struct net_device *dev) ; 
-#endif
-#endif
+static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) ; 
 
-int __init olympic_probe(struct net_device *dev)
+static int __init olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	int cards_found;
+	struct net_device *dev ; 
+	struct olympic_private *olympic_priv;
+	static int card_no = -1 ;
+	int i ; 
 
-	cards_found=olympic_scan(dev);
-	return cards_found ? 0 : -ENODEV;
-}
+	card_no++ ; 
 
-static int __init olympic_scan(struct net_device *dev)
-{
-	struct pci_dev *pci_device = NULL ;
-	struct olympic_private *olympic_priv;
-	int card_no = 0 ;
-	if (pci_present()) {
+	if ((i = pci_enable_device(pdev))) {
+		return i ; 
+	}
 
-		while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
-			__u16 pci_command ; 
+	pci_set_master(pdev);
 
-			if (pci_enable_device(pci_device))
-				continue;
+	if ((i = pci_request_regions(pdev,"olympic"))) { 
+		return i ; 
+	} ; 
+ 
+	dev = alloc_trdev(sizeof(struct olympic_private)) ; 
 
-			/* These lines are needed by the PowerPC, it appears that these flags
-			 * are not being set properly for the PPC, this may well be fixed with
-			 * the new PCI code */ 
-			pci_read_config_word(pci_device, PCI_COMMAND, &pci_command);
-			pci_command |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-			pci_write_config_word(pci_device, PCI_COMMAND,pci_command);
-			pci_set_master(pci_device);
-
-			/* Check to see if io has been allocated, if so, we've already done this card,
-			   so continue on the card discovery loop  */
-
-			if (check_region(pci_resource_start(pci_device, 0), OLYMPIC_IO_SPACE)) {
-				card_no++ ; 
-				continue ; 
-			}
+	if (!dev) {
+		pci_release_regions(pdev) ; 
+		return -ENOMEM ; 
+	}
 
-			olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL);
-			if (!olympic_priv)
-				return 0;
-			memset(olympic_priv, 0, sizeof(struct olympic_private));
-			init_waitqueue_head(&olympic_priv->srb_wait);
-			init_waitqueue_head(&olympic_priv->trb_wait);
-#ifndef MODULE
-			dev = init_trdev(NULL, 0);
-			if (!dev) {
-				kfree(olympic_priv);
-				return 0;
-			}
-#endif
-			dev->priv=(void *)olympic_priv;
+	olympic_priv = dev->priv ;
+	
+	init_waitqueue_head(&olympic_priv->srb_wait);
+	init_waitqueue_head(&olympic_priv->trb_wait);
 #if OLYMPIC_DEBUG  
-			printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv);
+	printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, dev->priv);
 #endif
-			dev->irq=pci_device->irq;
-			dev->base_addr=pci_resource_start(pci_device, 0);
-			dev->init=&olympic_init;	/* AKPM: Not needed */
-			olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; 
-			/* FIXME: check ioremap return val, handle cleanup */
-			olympic_priv->olympic_mmio = 
-				ioremap(pci_resource_start(pci_device,1),256);
-			olympic_priv->olympic_lap = 
-				ioremap(pci_resource_start(pci_device,2),2048);
-			
-			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
-				olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; 
-			else
-				olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 
-
-			olympic_priv->olympic_ring_speed = ringspeed[card_no] ; 
-			olympic_priv->olympic_message_level = message_level[card_no] ; 
-	
-			if(olympic_init(dev)==-1) {
-				kfree(dev->priv);
-#ifndef MODULE
-				unregister_netdev(dev);
-				kfree(dev);
-#endif
-				return 0;
-			}				
+	dev->irq=pdev->irq;
+	dev->base_addr=pci_resource_start(pdev, 0);
+	dev->init=NULL; /* Must be NULL otherwise we get called twice */
+	olympic_priv->olympic_card_name = (char *)pdev->name ; 
+	olympic_priv->olympic_mmio = ioremap(pci_resource_start(pdev,1),256);
+	olympic_priv->olympic_lap = ioremap(pci_resource_start(pdev,2),2048);
+	olympic_priv->pdev = pdev ; 
+				
+	if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
+		olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; 
+	else
+		olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 
 
-			dev->open=&olympic_open;
-			dev->hard_start_xmit=&olympic_xmit;
-			dev->change_mtu=&olympic_change_mtu;
-
-			dev->stop=&olympic_close;
-			dev->do_ioctl=NULL;
-			dev->set_multicast_list=&olympic_set_rx_mode;
-			dev->get_stats=&olympic_get_stats ;
-			dev->set_mac_address=&olympic_set_mac_address ;  
-			return 1; 
-		}
+	dev->mtu = olympic_priv->pkt_buf_sz - TR_HLEN ; 
+	olympic_priv->olympic_ring_speed = ringspeed[card_no] ; 
+	olympic_priv->olympic_message_level = message_level[card_no] ; 
+	olympic_priv->olympic_network_monitor = network_monitor[card_no];
+	
+	if((i = olympic_init(dev))) {
+		iounmap(olympic_priv->olympic_mmio) ; 
+		iounmap(olympic_priv->olympic_lap) ; 
+		kfree(dev) ; 
+		pci_release_regions(pdev) ; 
+		return i ; 
+	}				
+
+	dev->open=&olympic_open;
+	dev->hard_start_xmit=&olympic_xmit;
+	dev->change_mtu=&olympic_change_mtu;
+	dev->stop=&olympic_close;
+	dev->do_ioctl=NULL;
+	dev->set_multicast_list=&olympic_set_rx_mode;
+	dev->get_stats=&olympic_get_stats ;
+	dev->set_mac_address=&olympic_set_mac_address ;  
+
+	pci_set_drvdata(pdev,dev) ; 
+	register_netdev(dev) ; 
+	printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name);
+	if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */ 
+		char proc_name[20] ; 
+		strcpy(proc_name,"net/olympic_") ; 
+		strcat(proc_name,dev->name) ; 
+		create_proc_read_entry(proc_name,0,0,olympic_proc_info,(void *)dev) ; 
+		printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); 
 	}
 	return  0 ;
 }
 
-
 static int __init olympic_init(struct net_device *dev)
 {
     	struct olympic_private *olympic_priv;
@@ -279,17 +267,15 @@
 	olympic_mmio=olympic_priv->olympic_mmio;
 
 	printk("%s \n", version);
-	printk("%s: %s. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, olympic_priv->olympic_card_name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
+	printk("%s. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n", olympic_priv->olympic_card_name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
 
-	request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic");
 	writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
 	t=jiffies;
 	while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
 		schedule();		
 		if(jiffies-t > 40*HZ) {
 			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
-			release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; 
-			return -1;
+			return -ENODEV;
 		}
 	}
 
@@ -313,14 +299,14 @@
 	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
 		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
 		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name);
+			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",olympic_priv->olympic_card_name);
 	} else if (olympic_priv->olympic_ring_speed == 16) {
 		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name);
+			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", olympic_priv->olympic_card_name);
 		writel(GPR_16MBPS, olympic_mmio+GPR);
 	} else if (olympic_priv->olympic_ring_speed == 4) {
 		if (olympic_priv->olympic_message_level) 
-			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; 
+			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", olympic_priv->olympic_card_name) ; 
 		writel(0, olympic_mmio+GPR);
 	} 
 	
@@ -335,10 +321,9 @@
 	t=jiffies;
 	while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) {
 		schedule();		
-		if(jiffies-t > 40*HZ) {
+		if(jiffies-t > 15*HZ) {
 			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
-			release_region(dev->base_addr, OLYMPIC_IO_SPACE); 
-			return -1;
+			return -ENODEV;
 		}
 	}
 	
@@ -361,8 +346,7 @@
 #endif	
 	if(readw(init_srb+6)) {
 		printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6));
-		release_region(dev->base_addr, OLYMPIC_IO_SPACE);
-		return -1;
+		return -ENODEV;
 	}
 
 	if (olympic_priv->olympic_message_level) {
@@ -401,15 +385,10 @@
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
 	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
-	unsigned long flags;
+	unsigned long flags, t;
 	char open_error[255] ; 
 	int i, open_finished = 1 ;
 
-#if OLYMPIC_NETWORK_MONITOR
-	__u8 *oat ; 
-	__u8 *opt ; 
-#endif
-
 	if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
 		return -EAGAIN;
 	}
@@ -451,12 +430,10 @@
 		writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2);
 
 		/* If Network Monitor, instruct card to copy MAC frames through the ARB */
-
-#if OLYMPIC_NETWORK_MONITOR
-		writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8);
-#else
-		writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8);
-#endif		
+		if (olympic_priv->olympic_network_monitor) 
+			writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8);
+		else
+			writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8);
 
 		if (olympic_priv->olympic_laa[0]) {
 			writeb(olympic_priv->olympic_laa[0],init_srb+12);
@@ -473,17 +450,23 @@
 
 		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
 
+		t = jiffies ; 
  		while(olympic_priv->srb_queued) {        
         		interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ);
         		if(signal_pending(current))	{            
-				printk(KERN_WARNING "%s: SRB timed out.\n",
+				printk(KERN_WARNING "%s: Signal received in open.\n",
                 			dev->name);
-            			printk(KERN_WARNING "SISR=%x MISR=%x\n",
+            			printk(KERN_WARNING "SISR=%x LISR=%x\n",
                 			readl(olympic_mmio+SISR),
                 			readl(olympic_mmio+LISR));
             			olympic_priv->srb_queued=0;
             			break;
         		}
+			if ((jiffies-t) > 60*HZ) { 
+				printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; 
+				olympic_priv->srb_queued=0;
+				break ; 
+			} 
     		}
 		restore_flags(flags);
 #if OLYMPIC_DEBUG
@@ -572,7 +555,8 @@
 
 		skb->dev = dev;
 
-		olympic_priv->olympic_rx_ring[i].buffer = cpu_to_le32(virt_to_bus(skb->data));
+		olympic_priv->olympic_rx_ring[i].buffer = cpu_to_le32(pci_map_single(olympic_priv->pdev, 
+							  skb->data,olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)) ; 
 		olympic_priv->olympic_rx_ring[i].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); 
 		olympic_priv->rx_ring_skb[i]=skb;
 	}
@@ -583,12 +567,16 @@
 		return -EIO;
 	}
 
-	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]), olympic_mmio+RXDESCQ);
-	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]), olympic_mmio+RXCDA);
+	olympic_priv->rx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_rx_ring, 
+					 sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
+	writel(olympic_priv->rx_ring_dma_addr, olympic_mmio+RXDESCQ);
+	writel(olympic_priv->rx_ring_dma_addr, olympic_mmio+RXCDA);
 	writew(i, olympic_mmio+RXDESCQCNT);
 		
-	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]), olympic_mmio+RXSTATQ);
-	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]), olympic_mmio+RXCSA);
+	olympic_priv->rx_status_ring_dma_addr = pci_map_single(olympic_priv->pdev, olympic_priv->olympic_rx_status_ring, 
+						sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
+	writel(olympic_priv->rx_status_ring_dma_addr, olympic_mmio+RXSTATQ);
+	writel(olympic_priv->rx_status_ring_dma_addr, olympic_mmio+RXCSA);
 	
  	olympic_priv->rx_ring_last_received = OLYMPIC_RX_RING_SIZE - 1;	/* last processed rx status */
 	olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE - 1;  
@@ -597,20 +585,22 @@
 
 #if OLYMPIC_DEBUG 
 	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
-	printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+	printk("RXCSA: %x, rx_status_ring[0]: %p\n",readl(olympic_mmio+RXCSA),&olympic_priv->olympic_rx_status_ring[0]);
 	printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) );
 	printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) );
 	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
 
-	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+	printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);
+	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr =
+%08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
 #endif
 
 	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
 
 #if OLYMPIC_DEBUG 
 	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
-	printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
-	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+	printk("RXCSA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCSA),&olympic_priv->olympic_rx_status_ring[0]);
+	printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);
 #endif 
 
 	writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM);
@@ -622,12 +612,16 @@
 		olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef;
 
 	olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE;
-	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]), olympic_mmio+TXDESCQ_1);
-	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]), olympic_mmio+TXCDA_1);
+	olympic_priv->tx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_tx_ring,
+					 sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE,PCI_DMA_TODEVICE) ; 
+	writel(olympic_priv->tx_ring_dma_addr, olympic_mmio+TXDESCQ_1);
+	writel(olympic_priv->tx_ring_dma_addr, olympic_mmio+TXCDA_1);
 	writew(OLYMPIC_TX_RING_SIZE, olympic_mmio+TXDESCQCNT_1);
 	
-	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1);
-	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1);
+	olympic_priv->tx_status_ring_dma_addr = pci_map_single(olympic_priv->pdev, olympic_priv->olympic_tx_status_ring,
+						sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
+	writel(olympic_priv->tx_status_ring_dma_addr,olympic_mmio+TXSTATQ_1);
+	writel(olympic_priv->tx_status_ring_dma_addr,olympic_mmio+TXCSA_1);
 	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1);
 		
 	olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
@@ -640,33 +634,32 @@
 	printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK));
 #endif
 
-#if OLYMPIC_NETWORK_MONITOR
-	oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-	opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
-
-	printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
-	printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
-		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
-
-	printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+	if (olympic_priv->olympic_network_monitor) { 
+		__u8 *oat ; 
+		__u8 *opt ; 
+		oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+		opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+
+		printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+		printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
+			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+		printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
 			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
 			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
 			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
 			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
 			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
 			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
-
-
-#endif 	
+	}
 	
 	netif_start_queue(dev);
 	MOD_INC_USE_COUNT ;
@@ -703,7 +696,6 @@
 		olympic_priv->rx_status_last_received++ ;
 		olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
 #if OLYMPIC_DEBUG
-		printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); 
 		printk("rx status: %x rx len: %x \n", le32_to_cpu(rx_status->status_buffercnt), le32_to_cpu(rx_status->fragmentcnt_framelen));
 #endif
 		length = le32_to_cpu(rx_status->fragmentcnt_framelen) & 0xffff;
@@ -760,10 +752,17 @@
 						olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
 						rx_ring_last_received = olympic_priv->rx_ring_last_received ;
 						skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
+						/* unmap buffer */
+						pci_unmap_single(olympic_priv->pdev,
+							le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), 
+							olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
 						skb_put(skb2,length);
 						skb2->protocol = tr_type_trans(skb2,dev);
-						olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = cpu_to_le32(virt_to_bus(skb->data));
-						olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); 
+						olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = 
+							cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data, 
+							olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE));
+						olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = 
+							cpu_to_le32(olympic_priv->pkt_buf_sz); 
 						olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
 						netif_rx(skb2) ; 
 					} else {
@@ -773,13 +772,13 @@
 							rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
 							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
 							cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); 
-							memcpy(skb_put(skb, cpy_length), bus_to_virt(le32_to_cpu(rx_desc->buffer)), cpy_length) ; 
+							memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ;
 						} while (--i) ; 
 		
 						skb->protocol = tr_type_trans(skb,dev);
 						netif_rx(skb) ; 
 					} 
-					dev->last_rx = jiffies ;
+					dev->last_rx = jiffies ; 
 					olympic_priv->olympic_stats.rx_packets++ ; 
 					olympic_priv->olympic_stats.rx_bytes += length ; 
 				} /* if skb == null */
@@ -807,10 +806,15 @@
 	__u32 sisr;
 	__u8 *adapter_check_area ; 
 	
-	sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ 
-	
+	/* 
+	 *  Read sisr but don't reset it yet. 
+	 *  The indication bit may have been set but the interrupt latch
+	 *  bit may not be set, so we'd lose the interrupt later. 
+	 */ 
+	sisr=readl(olympic_mmio+SISR) ; 
 	if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ 
 		return ;
+	sisr=readl(olympic_mmio+SISR_RR) ;  /* Read & Reset sisr */ 
 
 	spin_lock(&olympic_priv->olympic_lock);
 
@@ -826,15 +830,22 @@
 			olympic_priv->srb_queued=0;
 		} /* SISR_SRB_REPLY */
 
+		/* We shouldn't ever miss the Tx interrupt, but the you never know, hence the loop to ensure
+		   we get all tx completions. */
 		if (sisr & SISR_TX1_EOF) {
-			olympic_priv->tx_ring_last_status++;
-			olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1);
-			olympic_priv->free_tx_ring_entries++;
-			olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
-			olympic_priv->olympic_stats.tx_packets++ ; 
-			dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
-			olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
-			olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
+			while(olympic_priv->olympic_tx_status_ring[(olympic_priv->tx_ring_last_status + 1) & (OLYMPIC_TX_RING_SIZE-1)].status) { 
+				olympic_priv->tx_ring_last_status++;
+				olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1);
+				olympic_priv->free_tx_ring_entries++;
+				olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
+				olympic_priv->olympic_stats.tx_packets++ ; 
+				pci_unmap_single(olympic_priv->pdev, 
+					le32_to_cpu(olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer), 
+					olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len,PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
+				olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
+				olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
+			}
 			netif_wake_queue(dev);
 		} /* SISR_TX1_EOF */
 	
@@ -843,12 +854,39 @@
 		} /* SISR_RX_STATUS */
 	
 		if (sisr & SISR_ADAPTER_CHECK) {
+			int i ; 
+			netif_stop_queue(dev);
 			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
 			writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
 			adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; 
 			printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
-			free_irq(dev->irq, dev) ; 
-	
+			/* The adapter is effectively dead, clean up and exit */
+			for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+				dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+				if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
+					pci_unmap_single(olympic_priv->pdev, 
+						le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
+						olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
+				}
+				olympic_priv->rx_status_last_received++;
+				olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+			}
+			/* unmap rings */
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, 
+				sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
+				sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
+
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, 
+				sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, 
+				sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
+
+			free_irq(dev->irq, dev) ;
+			MOD_DEC_USE_COUNT ;
+			dev->stop = NULL ;  
+			spin_unlock(&olympic_priv->olympic_lock) ; 
+			return ; 
 		} /* SISR_ADAPTER_CHECK */
 	
 		if (sisr & SISR_ASB_FREE) {
@@ -878,7 +916,6 @@
 		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr);
 		printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ;
 	} /* One if the interrupts we want */
-
 	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
 	
 	spin_unlock(&olympic_priv->olympic_lock) ; 
@@ -895,17 +932,15 @@
 	netif_stop_queue(dev);
 	
 	if(olympic_priv->free_tx_ring_entries) {
-		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer = cpu_to_le32(virt_to_bus(skb->data));
+		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer = 
+			cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data, skb->len,PCI_DMA_TODEVICE));
 		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length = cpu_to_le32(skb->len | (0x80000000));
 		olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb;
 		olympic_priv->free_tx_ring_entries--;
 
         	olympic_priv->tx_ring_free++;
         	olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1);
-
-
 		writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
-
 		netif_wake_queue(dev);
 		spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
 		return 0;
@@ -921,7 +956,7 @@
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
     	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
-	unsigned long flags;
+	unsigned long t,flags;
 	int i;
 
 	netif_stop_queue(dev);
@@ -939,18 +974,21 @@
 	olympic_priv->srb_queued=1;
 
 	writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
+	
+	t = jiffies ; 
 	while(olympic_priv->srb_queued) {
 	        interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ);
         	if(signal_pending(current))	{            
-			printk(KERN_WARNING "%s: SRB timed out.\n",
-                		dev->name);
-            		printk(KERN_WARNING "SISR=%x MISR=%x\n",
-                	readl(olympic_mmio+SISR),
-                	readl(olympic_mmio+LISR));
+			printk(KERN_WARNING "%s: SRB timed out.\n",dev->name);
+            		printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR));
             		olympic_priv->srb_queued=0;
             		break;
         	}
+		if ((jiffies-t) > 60*HZ) { 
+			printk(KERN_WARNING "%s: SRB timed out. May not be fatal. \n",dev->name) ; 
+			olympic_priv->srb_queued=0;
+			break ; 
+		} 
     	}
 
 	restore_flags(flags) ; 
@@ -959,9 +997,24 @@
 	
 	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
 		dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+		if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
+			pci_unmap_single(olympic_priv->pdev, 
+				le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
+				olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
+		}
 		olympic_priv->rx_status_last_received++;
 		olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
 	}
+	/* unmap rings */
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, 
+		sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
+		sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
+
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, 
+		sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, 
+		sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
 
 	/* reset tx/rx fifo's and busmaster logic */
 
@@ -1239,9 +1292,6 @@
 	__u8 fdx_prot_error ; 
 	__u16 next_ptr;
 	int i ; 
-#if OLYMPIC_NETWORK_MONITOR
-	struct trh_hdr *mac_hdr ; 
-#endif
 
 	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
 	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
@@ -1271,8 +1321,7 @@
 #endif 
 		mac_frame = dev_alloc_skb(frame_len) ; 
 		if (!mac_frame) {
-			printk(KERN_WARNING "%s: Memory squeeze, dropping "
-			       "frame.\n", dev->name);
+			printk(KERN_WARNING "%s: Memory squeeze, dropping frame.\n", dev->name);
 			goto drop_frame;
 		}
 
@@ -1283,19 +1332,19 @@
 			buffer_len = swab16(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
 			memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ;
 			next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
-
 		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
 
-#if OLYMPIC_NETWORK_MONITOR
-		printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
-		mac_hdr = (struct trh_hdr *)mac_frame->data ; 
-		printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
-		printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
-#endif
+		if (olympic_priv->olympic_network_monitor) { 
+			struct trh_hdr *mac_hdr ; 
+			printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+			mac_hdr = (struct trh_hdr *)mac_frame->data ; 
+			printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
+			printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
+		}
 		mac_frame->dev = dev ; 
 		mac_frame->protocol = tr_type_trans(mac_frame,dev);
 		netif_rx(mac_frame) ; 	
-		dev->last_rx = jiffies ;
+		dev->last_rx = jiffies;
 
 drop_frame:
 		/* Now tell the card we have dealt with the received frame */
@@ -1351,17 +1400,29 @@
 			writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
 			netif_stop_queue(dev);
 			olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; 
-			
-			olympic_priv->rx_status_last_received++;
-			olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
 			for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
-				dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+				dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+				if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
+					pci_unmap_single(olympic_priv->pdev, 
+						le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
+						olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
+				}
 				olympic_priv->rx_status_last_received++;
 				olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
 			}
+			/* unmap rings */
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, 
+				sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
+				sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
+
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, 
+				sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, 
+				sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
 
 			free_irq(dev->irq,dev);
-			
+			dev->stop=NULL;
 			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
 			MOD_DEC_USE_COUNT ; 
 		} /* If serious error */
@@ -1489,61 +1550,20 @@
 	return 0 ; 
 }
 
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
 static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
 {
-	struct pci_dev *pci_device = NULL ;
+	struct net_device *dev = (struct net_device *)data ; 
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+	__u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+	int size = 0 ; 
 	int len=0;
 	off_t begin=0;
 	off_t pos=0;
-	int size;
 	
-	struct net_device *dev;
-
-
 	size = sprintf(buffer, 
-		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n");
-	
-	pos+=size;
-	len+=size;
-	
-
-	while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
-	
-		for (dev = dev_base; dev != NULL; dev = dev->next) 
-		{
-			if (dev->base_addr == pci_device->resource[0].start ) { /* Yep, an Olympic device */	
-				size = sprintf_info(buffer+len, dev);
-				len+=size;
-				pos=begin+len;
-				
-				if(pos<offset)
-				{
-					len=0;
-					begin=pos;
-				}
-				if(pos>offset+length)
-					break;
-			} /* if */
-		} /* for */
-	} /* While */
-
-	*start=buffer+(offset-begin);	/* Start of wanted data */
-	len-=(offset-begin);		/* Start slop */
-	if(len>length)
-		len=length;		/* Ending slop */
-	return len;
-}
-
-static int sprintf_info(char *buffer, struct net_device *dev)
-{
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-	__u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-	__u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
-	int size = 0 ; 
-		
-	size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
+		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name);
+	size += sprintf(buffer+size, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
  	   dev->name); 
 
 	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
@@ -1628,70 +1648,56 @@
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3));
 
- 
-	return size;
+	len=size;
+	pos=begin+size;
+	if (pos<offset) {
+		len=0;
+		begin=pos;
+	}
+	*start=buffer+(offset-begin);	/* Start of wanted data */
+	len-=(offset-begin);		/* Start slop */
+	if(len>length)
+		len=length;		/* Ending slop */
+	return len;
 }
-#endif
-#endif 
-
-#ifdef MODULE
 
-static struct net_device* dev_olympic[OLYMPIC_MAX_ADAPTERS];
-
-int init_module(void)
+static void __devexit olympic_remove_one(struct pci_dev *pdev) 
 {
-        int i;
-
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-	create_proc_read_entry("net/olympic_tr",0,0,olympic_proc_info,NULL); 
-#endif
-#endif
-        for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) {
-		dev_olympic[i] = NULL;
-                dev_olympic[i] = init_trdev(dev_olympic[i], 0);
-                if (dev_olympic[i] == NULL) {
-			if (i == 0)
-                        	return -ENOMEM;
-			break;
-		}
-
-		dev_olympic[i]->init      = &olympic_probe;
+	struct net_device *dev = pdev->driver_data ; 
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
 
-	        if (register_trdev(dev_olympic[i]) != 0) {
-			kfree(dev_olympic[i]);
-			dev_olympic[i] = NULL;
-		        if (i == 0) {
-			        printk("Olympic: No IBM PCI Token Ring cards found in system.\n");
-		                return -EIO;
-			} else {
-			       	printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; 
-				return 0;
-			}
-	        }
+	if (olympic_priv->olympic_network_monitor) { 
+		char proc_name[20] ; 
+		strcpy(proc_name,"net/olympic_") ; 
+		strcat(proc_name,dev->name) ;
+		remove_proc_entry(proc_name,NULL); 
 	}
+	unregister_trdev(dev) ; 
+	iounmap(olympic_priv->olympic_mmio) ; 
+	iounmap(olympic_priv->olympic_lap) ; 
+	pci_release_regions(pdev) ; 	
+	kfree(dev) ; 
+}
 
-	return 0;
+static struct pci_driver olympic_driver = { 
+	name:		"olympic",
+	id_table:	olympic_pci_tbl,
+	probe:		olympic_probe,
+	remove:		olympic_remove_one
+};
+
+static int __init olympic_pci_init(void) 
+{
+	return pci_module_init (&olympic_driver) ; 
 }
 
-void cleanup_module(void)
+static void __exit olympic_pci_cleanup(void)
 {
-        int i;
+	return pci_unregister_driver(&olympic_driver) ; 
+}	
+
+
+module_init(olympic_pci_init) ; 
+module_exit(olympic_pci_cleanup) ; 
 
-        for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++)
-	        if (dev_olympic[i]) {
-			 unregister_trdev(dev_olympic[i]);
-			 release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE);
-			 kfree(dev_olympic[i]->priv);
-			 kfree(dev_olympic[i]);
-			 dev_olympic[i] = NULL;
-                }
-
-#if OLYMPIC_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("net/olympic_tr", NULL) ; 
-#endif 
-#endif
-}
-#endif /* MODULE */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h
--- v2.4.3/linux/drivers/net/tokenring/olympic.h	Tue Mar  6 19:28:35 2001
+++ linux/drivers/net/tokenring/olympic.h	Wed Apr 18 11:39:21 2001
@@ -1,6 +1,6 @@
 /*
  *  olympic.h (c) 1999 Peter De Schrijver All Rights Reserved
- *                1999 Mike Phillips (mikep@linuxtr.net)
+ *                1999,2000 Mike Phillips (mikep@linuxtr.net)
  *
  *  Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset.
  *
@@ -251,6 +251,7 @@
 
 	__u8 *olympic_mmio;
 	__u8 *olympic_lap;
+	struct pci_dev *pdev ; 
 	char *olympic_card_name ; 
 
 	spinlock_t olympic_lock ; 
@@ -263,10 +264,12 @@
 	volatile int trb_queued;   /* True if a TRB is posted */
 	wait_queue_head_t trb_wait ; 
 
+	/* These must be on a 4 byte boundary. */
 	struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE];
 	struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE];
 	struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE];	
 	struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE];	
+
 	struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE];	
 	int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries;
 
@@ -274,9 +277,13 @@
 	__u16 olympic_lan_status ;
 	__u8 olympic_ring_speed ;
 	__u16 pkt_buf_sz ; 
-	__u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;  
+	__u8 olympic_receive_options, olympic_copy_all_options,olympic_message_level, olympic_network_monitor;  
 	__u16 olympic_addr_table_addr, olympic_parms_addr ; 
 	__u8 olympic_laa[6] ; 
+	__u32 rx_ring_dma_addr;
+	__u32 rx_status_ring_dma_addr;
+	__u32 tx_ring_dma_addr;
+	__u32 tx_status_ring_dma_addr;
 };
 
 struct olympic_adapter_addr_table {
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- v2.4.3/linux/drivers/net/tokenring/smctr.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/tokenring/smctr.c	Thu Apr 19 09:34:52 2001
@@ -63,7 +63,7 @@
 #include "smctr_firmware.h"      /* SMC adapter firmware */
 
 static char version[] __initdata = KERN_INFO "smctr.c: v1.4 7/12/00 by jschlst@turbolinux.com\n";
-static const char *cardname = "smctr";
+static const char cardname[] = "smctr";
 
 
 #define SMCTR_IO_EXTENT   20
@@ -82,7 +82,7 @@
 static int ringspeed;
 
 /* SMC Name of the Adapter. */
-static char *smctr_name = "SMC TokenCard";
+static char smctr_name[] = "SMC TokenCard";
 char *smctr_model = "Unknown";
 
 /* Use 0 for production, 1 for verification, 2 for debug, and
@@ -5269,7 +5269,7 @@
         return (POSITIVE_ACK);
 }
 
-/* Reset the ring speed to the oposite of what it was. This auto-pilot
+/* Reset the ring speed to the opposite of what it was. This auto-pilot
  * mode requires a complete reset and re-init of the adapter.
  */
 static int smctr_set_ring_speed(struct net_device *dev)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c
--- v2.4.3/linux/drivers/net/tokenring/tms380tr.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/tokenring/tms380tr.c	Thu Apr 19 09:34:52 2001
@@ -68,7 +68,7 @@
  */
 
 #ifdef MODULE
-static const char *version = "tms380tr.c: v1.08 14/01/2001 by Christoph Goos, Adam Fritzler\n";
+static const char version[] = "tms380tr.c: v1.08 14/01/2001 by Christoph Goos, Adam Fritzler\n";
 #endif
 
 #ifdef MODULE
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/tmsisa.c linux/drivers/net/tokenring/tmsisa.c
--- v2.4.3/linux/drivers/net/tokenring/tmsisa.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/tokenring/tmsisa.c	Fri Apr 20 11:54:22 2001
@@ -19,7 +19,7 @@
  *  TODO:
  *	1. Add support for Proteon TR ISA adapters (1392, 1392+)
  */
-static const char *version = "tmsisa.c: v1.00 14/01/2001 by Jochen Friedrich\n";
+static const char version[] = "tmsisa.c: v1.00 14/01/2001 by Jochen Friedrich\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -60,7 +60,7 @@
 	0
 };
 
-static char *isa_cardname = "SK NET TR 4/16 ISA\0";
+static char isa_cardname[] = "SK NET TR 4/16 ISA\0";
 
 int tms_isa_probe(struct net_device *dev);
 static int tms_isa_open(struct net_device *dev);
@@ -93,7 +93,7 @@
 	struct tms_isa_card *next;
 };
 
-static struct tms_isa_card *tms_isa_card_list = NULL;
+static struct tms_isa_card *tms_isa_card_list;
 
 static int __init tms_isa_probe1(int ioaddr)
 {
@@ -129,7 +129,7 @@
 
 int __init tms_isa_probe(struct net_device *dev)
 {
-        static int versionprinted = 0;
+        static int versionprinted;
 	struct net_local *tp;
 	int j;
 	struct tms_isa_card *card;
@@ -271,6 +271,14 @@
 	{
 		/* Enlist in the card list */
 		card = kmalloc(sizeof(struct tms_isa_card), GFP_KERNEL);
+		if (!card) {
+			unregister_trdev(dev);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			free_irq(dev->irq, dev);
+			free_dma(dev->dma);
+			tmsdev_term(dev);
+			return -1;
+		}
 		card->next = tms_isa_card_list;
 		tms_isa_card_list = card;
 		card->dev = dev;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c
--- v2.4.3/linux/drivers/net/tulip/21142.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/tulip/21142.c	Tue Apr  3 10:19:43 2001
@@ -2,14 +2,15 @@
 	drivers/net/tulip/21142.c
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/networking/tulip.txt for more
-	information on this driver.
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
@@ -107,16 +108,17 @@
 	dev->if_port = 0;
 	tp->nway = tp->mediasense = 1;
 	tp->nwayset = tp->lpar = 0;
+	if (tp->chip_id == PNIC2) {
+		tp->csr6 = 0x01000000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0);
+		return;
+	}
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n",
 			   dev->name, csr14);
 	outl(0x0001, ioaddr + CSR13);
 	udelay(100);
 	outl(csr14, ioaddr + CSR14);
-	if (tp->chip_id == PNIC2)
-	  tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
-	else
-	  tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+	tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0);
 	tulip_outl_csr(tp, tp->csr6, CSR6);
 	if (tp->mtable  &&  tp->mtable->csr15dir) {
 		outl(tp->mtable->csr15dir, ioaddr + CSR15);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog
--- v2.4.3/linux/drivers/net/tulip/ChangeLog	Fri Mar  2 11:02:14 2001
+++ linux/drivers/net/tulip/ChangeLog	Fri Apr 20 11:54:22 2001
@@ -1,3 +1,105 @@
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c: Now that dev->name is only available late
+	  in the probe, insert a hack to replace a not-evaluated
+	  "eth%d" string with an evaluated "tulip%d" string.
+	  Also, remove obvious comment and an indentation cleanup.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c: If we are a module, always print out the
+	  version string.  If we are built into the kernel, only print
+	  the version string if at least one tulip is detected.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	Merged from Becker's tulip.c 0.92t:
+
+	* tulip_core.c: Add support for Conexant LANfinity.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c: Only suspend/resume if the interface
+	  is up and running.  Use alloc_etherdev and pci_request_regions.
+	  Spelling fix.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c: Remove code that existed when one or more of
+	  the following defines existed.  These defines were never used
+	  by normal users in practice: TULIP_FULL_DUPLEX,
+	  TULIP_DEFAULT_MEDIA, and TULIP_NO_MEDIA_SWITCH.
+	  
+	* tulip.h, eeprom.c: Move EE_* constants from tulip.h to eeprom.c.
+	* tulip.h, media.c: Move MDIO_* constants from tulip.h to media.c.
+
+	* media.c: Add barrier() to mdio_read/write's PNIC status check
+	  loops.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	Merged from Becker's tulip.c 0.92t:
+
+	* tulip.h: Add MEDIA_MASK constant for bounding medianame[]
+	  array lookups.
+	* eeprom.c, media.c, timer.c, tulip_core.c: Use it.
+
+	* media.c, tulip_core.c: mdio_{read,write} cleanup.  Since this
+	  is called [pretty much] directly from ioctl, we mask
+	  read/write arguments to limit the values passed.
+	  Added mii_lock.  Added comet_miireg2offset and better
+	  Comet-specific mdio_read/write code.	Pay closer attention
+	  to the bits we set in ioctl.	Remove spinlocks from ioctl,
+	  they are in mdio_read/write now.  Use mask to limit
+	  phy number in tulip_init_one's MII scan.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	Merged from Becker's tulip.c 0.92t:
+
+	* 21142.c, tulip_core.c: PNIC2 MAC address and NWay fixes.
+	* tulip.h: Add FullDuplex constant, used in above change.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* timer.c: Do not call netif_carrier_{on,off}, it is not used in
+	  the main tree.  Leave code in, disabled, as markers for future
+	  carrier notification.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	Merged from Becker's tulip.c 0.92t, except for the tulip.h
+	whitespace cleanup:
+
+	* interrupt.c: If Rx stops, make sure to update the
+	  multicast filter before restarting.
+	* tulip.h: Add COMET_MAC_ADDR feature flag, clean up flags.
+	  Add Accept* Rx mode bit constants.
+	  Add mc_filter[] to driver private struct.
+	* tulip_core.c: Add new Comet PCI id 0x1113:0x9511.
+	  Add COMET_MAC_ADDR feature flag to comet entry in board info array.
+	  Prefer to test COMET_MAC_ADDR flag to testing chip_id for COMET,
+	  when dealing with the Comet's MAC address.
+	  Enable Tx underrun recovery for Comet chips.
+	  Use new Accept* constants in set_rx_mode.
+	  Prefer COMET_MAC_ADDR flag test to chip_id test in set_rx_mode.
+	  Store built mc_filter for later use in intr handler by Comets.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core.c: Use tp->cur_tx when building the
+	  setup frame, instead of assuming that the setup
+	  frame is always built in slot zero.  This case is
+	  hit during PM resume.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* *.c: Update file headers (copyright, urls, etc.)
+	* Makefile: re-order to that chip-specific modules on own line
+	* eeprom.c: BSS/zero-init cleanup (Andrey Panin)
+	* tulip_core.c: merge medianame[] update from tulip.c.
+	  Additional arch-specific rx_copybreak, csr0 values. (various)
+
 2001-02-20  Jeff Garzik  <jgarzik@mandrakesoft.com>
 
 	* media.c (tulip_select_media): No need to initialize
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/Makefile linux/drivers/net/tulip/Makefile
--- v2.4.3/linux/drivers/net/tulip/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/tulip/Makefile	Tue Apr  3 10:19:43 2001
@@ -9,7 +9,9 @@
 
 O_TARGET := tulip.o
 
-obj-y   := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o
+obj-y   := eeprom.o interrupt.o media.o \
+	   timer.o tulip_core.o		\
+	   21142.o pnic.o
 obj-m   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c
--- v2.4.3/linux/drivers/net/tulip/eeprom.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/tulip/eeprom.c	Tue Apr  3 10:19:43 2001
@@ -2,14 +2,15 @@
 	drivers/net/tulip/eeprom.c
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/networking/tulip.txt for more
-	information on this driver.
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
@@ -77,9 +78,9 @@
 void __devinit tulip_parse_eeprom(struct net_device *dev)
 {
 	/* The last media info list parsed, for multiport boards.  */
-	static struct mediatable *last_mediatable = NULL;
-	static unsigned char *last_ee_data = NULL;
-	static int controller_index = 0;
+	static struct mediatable *last_mediatable;
+	static unsigned char *last_ee_data;
+	static int controller_index;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	unsigned char *ee_data = tp->eeprom;
 	int i;
@@ -143,9 +144,10 @@
 
 		printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
 			   dev->name, media,
-			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
+			   media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
 		for (i = 0; i < count; i++) {
-			unsigned char media_code = *p++;
+			unsigned char media_block = *p++;
+			int media_code = media_block & MEDIA_MASK;
 			if (media_code & 0x40)
 				p += 6;
 			printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
@@ -182,7 +184,7 @@
 		mtable->csr15dir = mtable->csr15val = 0;
 
 		printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,
-			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
+			   media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
 		for (i = 0; i < count; i++) {
 			struct medialeaf *leaf = &mtable->mleaf[i];
 
@@ -216,7 +218,7 @@
 					new_advertise |= get_u16(&p[7+gpr_len+reset_len]);
 				} else {
 					mtable->has_nonmii = 1;
-					leaf->media = p[2] & 0x0f;
+					leaf->media = p[2] & MEDIA_MASK;
 					/* Davicom's media number for 100BaseTX is strange */
 					if (tp->chip_id == DM910X && leaf->media == 1)
 						leaf->media = 3;
@@ -261,6 +263,23 @@
 	}
 }
 /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x02	/* EEPROM shift clock. */
+#define EE_CS			0x01	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x04	/* Data from the Tulip to EEPROM. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x05
+#define EE_DATA_READ	0x08	/* Data from the EEPROM chip. */
+#define EE_ENB			(0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+   We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay()	inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_READ_CMD		(6)
 
 /* Note: this routine returns extra data bits for size detection. */
 int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len)
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c
--- v2.4.3/linux/drivers/net/tulip/interrupt.c	Fri Mar  2 11:02:14 2001
+++ linux/drivers/net/tulip/interrupt.c	Fri Apr 20 11:54:22 2001
@@ -2,14 +2,15 @@
 	drivers/net/tulip/interrupt.c
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/networking/tulip.txt for more
-	information on this driver.
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
@@ -300,6 +301,12 @@
 				tulip_restart_rxtx(tp, tp->csr6);
 				outl(0, ioaddr + CSR1);
 			}
+			if (csr5 & (RxDied | RxNoBuf)) {
+				if (tp->flags & COMET_MAC_ADDR) {
+					outl(tp->mc_filter[0], ioaddr + 0xAC);
+					outl(tp->mc_filter[1], ioaddr + 0xB0);
+				}
+			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
 				tp->stats.rx_errors++;
 				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
@@ -314,7 +321,19 @@
 					(tp->link_change)(dev, csr5);
 			}
 			if (csr5 & SytemError) {
-				printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
+				int error = (csr5 >> 23) & 7;
+				/* oops, we hit a PCI error.  The code produced corresponds
+				 * to the reason:
+				 *  0 - parity error
+				 *  1 - master abort
+				 *  2 - target abort
+				 * Note that on parity error, we should do a software reset
+				 * of the chip to get it back into a sane state (according
+				 * to the 21142/3 docs that is).
+				 *   -- rmk
+				 */
+				printk(KERN_ERR "%s: (%lu) System Error occured (%d)\n",
+					dev->name, tp->nir, error);
 			}
 			/* Clear all error sources, included undocumented ones! */
 			outl(0x0800f7ba, ioaddr + CSR5);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c
--- v2.4.3/linux/drivers/net/tulip/media.c	Fri Mar  2 11:02:14 2001
+++ linux/drivers/net/tulip/media.c	Tue Apr  3 10:19:43 2001
@@ -2,14 +2,15 @@
 	drivers/net/tulip/media.c
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/networking/tulip.txt for more
-	information on this driver.
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
@@ -22,6 +23,25 @@
    10base2(!) packets trigger a full-duplex-request interrupt. */
 #define FULL_DUPLEX_MAGIC	0x6969
 
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  It is just different enough from the EEPROM protocol
+   to not share code.  The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK		0x10000
+#define MDIO_DATA_WRITE0	0x00000
+#define MDIO_DATA_WRITE1	0x20000
+#define MDIO_ENB		0x00000 /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN		0x40000
+#define MDIO_DATA_READ		0x80000
+
+static const unsigned char comet_miireg2offset[32] = {
+	0xB4, 0xB8, 0xBC, 0xC0,  0xC4, 0xC8, 0xCC, 0,  0,0,0,0,  0,0,0,0,
+	0,0xD0,0,0,  0,0,0,0,  0,0,0,0, 0, 0xD4, 0xD8, 0xDC, };
+
 
 /* MII transceiver control section.
    Read and write the MII registers using software-generated serial
@@ -32,32 +52,34 @@
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
 	int retval = 0;
 	long ioaddr = dev->base_addr;
 	long mdio_addr = ioaddr + CSR9;
+	unsigned long flags;
+
+	if (location & ~0x1f)
+		return 0xffff;
+
+	if (tp->chip_id == COMET  &&  phy_id == 30) {
+		if (comet_miireg2offset[location])
+			return inl(ioaddr + comet_miireg2offset[location]);
+		return 0xffff;
+	}
 
+	spin_lock_irqsave(&tp->mii_lock, flags);
 	if (tp->chip_id == LC82C168) {
 		int i = 1000;
 		outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
 		inl(ioaddr + 0xA0);
 		inl(ioaddr + 0xA0);
-		while (--i > 0)
+		while (--i > 0) {
+			barrier();
 			if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
-				return retval & 0xffff;
-		return 0xffff;
-	}
-
-	if (tp->chip_id == COMET) {
-		if (phy_id == 1) {
-			if (location < 7)
-				return inl(ioaddr + 0xB4 + (location<<2));
-			else if (location == 17)
-				return inl(ioaddr + 0xD0);
-			else if (location >= 29 && location <= 31)
-				return inl(ioaddr + 0xD4 + ((location-29)<<2));
+				break;
 		}
-		return 0xffff;
+		spin_unlock_irqrestore(&tp->mii_lock, flags);
+		return retval & 0xffff;
 	}
 
 	/* Establish sync by sending at least 32 logic ones. */
@@ -84,36 +106,39 @@
 		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
 	}
+
+	spin_unlock_irqrestore(&tp->mii_lock, flags);
 	return (retval>>1) & 0xffff;
 }
 
-void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value)
+void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
-	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff);
 	long ioaddr = dev->base_addr;
 	long mdio_addr = ioaddr + CSR9;
+	unsigned long flags;
+
+	if (location & ~0x1f)
+		return;
+
+	if (tp->chip_id == COMET && phy_id == 30) {
+		if (comet_miireg2offset[location])
+			outl(val, ioaddr + comet_miireg2offset[location]);
+		return;
+	}
 
+	spin_lock_irqsave(&tp->mii_lock, flags);
 	if (tp->chip_id == LC82C168) {
 		int i = 1000;
 		outl(cmd, ioaddr + 0xA0);
-		do
+		do {
+			barrier();
 			if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
 				break;
-		while (--i > 0);
-		return;
-	}
-
-	if (tp->chip_id == COMET) {
-		if (phy_id != 1)
-			return;
-		if (location < 7)
-			outl(value, ioaddr + 0xB4 + (location<<2));
-		else if (location == 17)
-			outl(value, ioaddr + 0xD0);
-		else if (location >= 29 && location <= 31)
-			outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+		} while (--i > 0);
+		spin_unlock_irqrestore(&tp->mii_lock, flags);
 		return;
 	}
 
@@ -139,6 +164,8 @@
 		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
 	}
+
+	spin_unlock_irqrestore(&tp->mii_lock, flags);
 }
 
 
@@ -172,7 +199,7 @@
 			for (i = 0; i < 5; i++)
 				setup[i] = get_u16(&p[i*2 + 1]);
 
-			dev->if_port = p[0] & 15;
+			dev->if_port = p[0] & MEDIA_MASK;
 			if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
 				tp->full_duplex = 1;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c
--- v2.4.3/linux/drivers/net/tulip/pnic.c	Fri Mar  2 11:02:14 2001
+++ linux/drivers/net/tulip/pnic.c	Tue Apr  3 10:19:43 2001
@@ -2,14 +2,15 @@
 	drivers/net/tulip/pnic.c
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/networking/tulip.txt for more
-	information on this driver.
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c
--- v2.4.3/linux/drivers/net/tulip/timer.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/tulip/timer.c	Tue Apr  3 10:19:43 2001
@@ -2,14 +2,15 @@
 	drivers/net/tulip/timer.c
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/networking/tulip.txt for more
-	information on this driver.
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
@@ -133,13 +134,13 @@
 				((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
 				if (tulip_debug > 2)
 					printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
-						   medianame[mleaf->media]);
+					       medianame[mleaf->media & MEDIA_MASK]);
 				if ((p[2] & 0x61) == 0x01)	/* Bogus Znyx board. */
 					goto actually_mii;
-				netif_carrier_on(dev);
+				/* netif_carrier_on(dev); */
 				break;
 			}
-			netif_carrier_off(dev);
+			/* netif_carrier_off(dev); */
 			if (tp->medialock)
 				break;
 	  select_next_media:
@@ -152,9 +153,9 @@
 				goto select_next_media; /* Skip FD entries. */
 			if (tulip_debug > 1)
 				printk(KERN_DEBUG "%s: No link beat on media %s,"
-					   " trying transceiver type %s.\n",
-					   dev->name, medianame[mleaf->media & 15],
-					   medianame[tp->mtable->mleaf[tp->cur_index].media]);
+				       " trying transceiver type %s.\n",
+				       dev->name, medianame[mleaf->media & MEDIA_MASK],
+				       medianame[tp->mtable->mleaf[tp->cur_index].media]);
 			tulip_select_media(dev, 0);
 			/* Restart the transmit process. */
 			tulip_restart_rxtx(tp, tp->csr6);
@@ -164,9 +165,9 @@
 		case 1:  case 3:		/* 21140, 21142 MII */
 		actually_mii:
 			if (tulip_check_duplex(dev) < 0)
-				netif_carrier_off(dev);
+				{ /* netif_carrier_off(dev); */ }
 			else
-				netif_carrier_on(dev);
+				{ /* netif_carrier_on(dev); */ }
 			next_tick = 60*HZ;
 			break;
 		case 2:					/* 21142 serial block has no link beat. */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h
--- v2.4.3/linux/drivers/net/tulip/tulip.h	Tue Mar  6 22:44:16 2001
+++ linux/drivers/net/tulip/tulip.h	Fri Apr 20 11:54:22 2001
@@ -1,12 +1,16 @@
 /*
 	drivers/net/tulip/tulip.h
 
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
+
 */
 
 #ifndef __NET_TULIP_H__
@@ -46,17 +50,18 @@
 
 
 enum tbl_flag {
-	HAS_MII = 1,
-	HAS_MEDIA_TABLE = 2,
-	CSR12_IN_SROM = 4,
-	ALWAYS_CHECK_MII = 8,
-	HAS_ACPI = 0x10,
-	MC_HASH_ONLY = 0x20,	/* Hash-only multicast filter. */
-	HAS_PNICNWAY = 0x80,
-	HAS_NWAY = 0x40,	/* Uses internal NWay xcvr. */
-	HAS_INTR_MITIGATION = 0x100,
-	IS_ASIX = 0x200,
-	HAS_8023X = 0x400,
+	HAS_MII			= 0x0001,
+	HAS_MEDIA_TABLE		= 0x0002,
+	CSR12_IN_SROM		= 0x0004,
+	ALWAYS_CHECK_MII	= 0x0008,
+	HAS_ACPI		= 0x0010,
+	MC_HASH_ONLY		= 0x0020, /* Hash-only multicast filter. */
+	HAS_PNICNWAY		= 0x0080,
+	HAS_NWAY		= 0x0040, /* Uses internal NWay xcvr. */
+	HAS_INTR_MITIGATION	= 0x0100,
+	IS_ASIX			= 0x0200,
+	HAS_8023X		= 0x0400,
+	COMET_MAC_ADDR		= 0x0800,
 };
 
 
@@ -78,6 +83,7 @@
 	COMPEX9881,
 	I21145,
 	DM910X,
+	CONEXANT,
 };
 
 
@@ -139,6 +145,15 @@
 };
 
 
+enum tulip_rx_modes {
+	FullDuplex		= 0x0200,
+	AcceptBroadcast		= 0x0100,
+	AcceptAllMulticast	= 0x0080,
+	AcceptAllPhys		= 0x0040,
+	AcceptRunt		= 0x0008,
+};
+
+
 /* The Tulip Rx and Tx buffer descriptors. */
 struct tulip_rx_desc {
 	s32 status;
@@ -236,6 +251,7 @@
 #define TX_RING_SIZE	16
 #define RX_RING_SIZE	32
 
+#define MEDIA_MASK     31
 
 #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
 
@@ -251,45 +267,11 @@
 #define DESC_RING_WRAP 0x02000000
 
 
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK	0x02	/* EEPROM shift clock. */
-#define EE_CS			0x01	/* EEPROM chip select. */
-#define EE_DATA_WRITE	0x04	/* Data from the Tulip to EEPROM. */
-#define EE_WRITE_0		0x01
-#define EE_WRITE_1		0x05
-#define EE_DATA_READ	0x08	/* Data from the EEPROM chip. */
-#define EE_ENB			(0x4800 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
-   Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
-   We add a bus turn-around to insure that this remains true. */
-#define eeprom_delay()	inl(ee_addr)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_READ_CMD		(6)
-
 #define EEPROM_SIZE 128 	/* 2 << EEPROM_ADDRLEN */
 
 
-/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues or future 66Mhz PCI. */
-#define mdio_delay() inl(mdio_addr)
-
-/* Read and write the MII registers using software-generated serial
-   MDIO protocol.  It is just different enough from the EEPROM protocol
-   to not share code.  The maxium data clock rate is 2.5 Mhz. */
-#define MDIO_SHIFT_CLK	0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */
-#define MDIO_ENB_IN		0x40000
-#define MDIO_DATA_READ	0x80000
-
-
 #define RUN_AT(x) (jiffies + (x))
 
-
 #if defined(__i386__)			/* AKA get_unaligned() */
 #define get_u16(ptr) (*(u16 *)(ptr))
 #else
@@ -346,7 +328,9 @@
 	int flags;
 	struct net_device_stats stats;
 	struct timer_list timer;	/* Media selection timer. */
+	u32 mc_filter[2];
 	spinlock_t lock;
+	spinlock_t mii_lock;
 	unsigned int cur_rx, cur_tx;	/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- v2.4.3/linux/drivers/net/tulip/tulip_core.c	Fri Mar  2 11:02:14 2001
+++ linux/drivers/net/tulip/tulip_core.c	Fri Apr 20 11:54:22 2001
@@ -2,20 +2,15 @@
 
 /*
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000  The Linux Kernel Team
-	Written/copyright 1994-1999 by Donald Becker.
+	Copyright 2000,2001  The Linux Kernel Team
+	Written/copyright 1994-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please read Documentation/networking/tulip.txt for more
-	information.
-
-	For this specific driver variant please use linux-kernel for
-	bug reports.
-
-	Additional information available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	for more information on this driver, or visit the project
+	Web page at http://sourceforge.net/projects/tulip/
 
 */
 
@@ -28,7 +23,7 @@
 #include <asm/unaligned.h>
 
 static char version[] __devinitdata =
-	"Linux Tulip driver version 0.9.14 (February 20, 2001)\n";
+	"Linux Tulip driver version 0.9.14e (April 20, 2001)\n";
 
 
 /* A few user-configurable values. */
@@ -43,16 +38,19 @@
 static int mtu[MAX_UNITS];			/* Jumbo MTU for interfaces. */
 
 /*  The possible media types that can be set in options[] are: */
-const char * const medianame[] = {
+const char * const medianame[32] = {
 	"10baseT", "10base2", "AUI", "100baseTx",
-	"10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
-	"100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
-	"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+	"10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx",
+	"100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII",
+	"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4",
+	"MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19",
+	"","","","", "","","","",  "","","","Transceiver reset",
 };
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
 #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
-	|| defined(__sparc_) || defined(__ia64__)
+	|| defined(__sparc_) || defined(__ia64__) \
+	|| defined(__sh__) || defined(__mips__)
 static int rx_copybreak = 1518;
 #else
 static int rx_copybreak = 100;
@@ -81,7 +79,7 @@
  * any more than that.
  */
 static int csr0 = 0x01A00000 | 0x9000;
-#elif defined(__arm__)
+#elif defined(__arm__) || defined(__sh__)
 static int csr0 = 0x01A00000 | 0x4800;
 #else
 #warning Processor architecture undefined!
@@ -162,7 +160,7 @@
 
   /* COMET */
   { "ADMtek Comet", 256, 0x0001abef,
-	MC_HASH_ONLY, comet_timer },
+	MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
 
   /* COMPEX9881 */
   { "Compex 9881 PMAC", 128, 0x0001ebef,
@@ -177,6 +175,11 @@
   { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
 	tulip_timer },
+
+  /* CONEXANT */
+  { "Conexant LANfinity", 0x100, 0x0001ebef,
+	HAS_MII | HAS_ACPI,
+	tulip_timer },
 };
 
 
@@ -204,14 +207,16 @@
 	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },
 	{ 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
-	{0, }
+	{ 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
+	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
 
 
 /* A full-duplex map for media types. */
-const char tulip_media_cap[] =
-{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
+const char tulip_media_cap[32] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20,  28,31,0,0, };
 u8 t21040_csr13[] = {2,0x0C,8,4,  4,0,0,0, 0,0,0,0, 4,0,0,0};
 
 /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
@@ -286,6 +291,14 @@
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
 
+	if (tp->chip_id == PNIC2) {
+		u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0);
+		/* This address setting does not appear to impact chip operation?? */
+		outl((dev->dev_addr[5]<<8) + dev->dev_addr[4] +
+			(dev->dev_addr[3]<<24) + (dev->dev_addr[2]<<16),
+			ioaddr + 0xB0);
+		outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
+	}
 	if (tp->flags & MC_HASH_ONLY) {
 		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
 		u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
@@ -294,7 +307,7 @@
 			outl(addr_low,  ioaddr + CSR14);
 			outl(1, ioaddr + CSR13);
 			outl(addr_high, ioaddr + CSR14);
-		} else if (tp->chip_id == COMET) {
+		} else if (tp->flags & COMET_MAC_ADDR) {
 			outl(addr_low,  ioaddr + 0xA4);
 			outl(addr_high, ioaddr + 0xA8);
 			outl(0, ioaddr + 0xAC);
@@ -316,13 +329,13 @@
 		mapping = pci_map_single(tp->pdev, tp->setup_frame,
 					 sizeof(tp->setup_frame),
 					 PCI_DMA_TODEVICE);
-		tp->tx_buffers[0].skb = NULL;
-		tp->tx_buffers[0].mapping = mapping;
+		tp->tx_buffers[tp->cur_tx].skb = NULL;
+		tp->tx_buffers[tp->cur_tx].mapping = mapping;
 
 		/* Put the setup frame on the Tx list. */
-		tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
-		tp->tx_ring[0].buffer1 = cpu_to_le32(mapping);
-		tp->tx_ring[0].status = cpu_to_le32(DescOwned);
+		tp->tx_ring[tp->cur_tx].length = cpu_to_le32(0x08000000 | 192);
+		tp->tx_ring[tp->cur_tx].buffer1 = cpu_to_le32(mapping);
+		tp->tx_ring[tp->cur_tx].status = cpu_to_le32(DescOwned);
 
 		tp->cur_tx++;
 	}
@@ -349,7 +362,7 @@
 			}
 	}
 	if ((tp->mtable->defaultmedia & 0x0800) == 0) {
-		int looking_for = tp->mtable->defaultmedia & 15;
+		int looking_for = tp->mtable->defaultmedia & MEDIA_MASK;
 		for (i = 0; i < tp->mtable->leafcount; i++)
 			if (tp->mtable->mleaf[i].media == looking_for) {
 				printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
@@ -418,7 +431,9 @@
 		outl(0x0000, ioaddr + CSR14);
 		outl(0x0008, ioaddr + CSR15);
 	} else if (tp->chip_id == COMET) {
-		dev->if_port = 0;
+		/* Enable automatic Tx underrun recovery. */
+		outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
+		dev->if_port = tp->mii_cnt ? 11 : 0;
 		tp->csr6 = 0x00040000;
 	} else if (tp->chip_id == AX88140) {
 		tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
@@ -789,16 +804,16 @@
 
 
 /* Provide ioctl() calls to examine the MII xcvr state. */
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct tulip_private *tp = dev->priv;
 	long ioaddr = dev->base_addr;
-	u16 *data = (u16 *)&rq->ifr_data;
+	u16 *data = (u16 *) & rq->ifr_data;
 	int phy = tp->phys[0] & 0x1f;
-	long flags;
+	unsigned int regnum = data[1];
 
-	switch(cmd) {
-	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+	switch (cmd) {
+	case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
 		if (tp->mii_cnt)
 			data[0] = phy;
 		else if (tp->flags & HAS_NWAY)
@@ -807,42 +822,64 @@
 			data[0] = 1;
 		else
 			return -ENODEV;
-	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		if (data[0] == 32  &&  (tp->flags & HAS_NWAY)) {
-			int csr12 = inl(ioaddr + CSR12);
-			int csr14 = inl(ioaddr + CSR14);
-			switch (data[1]) {
-			case 0: {
-				data[3] = (csr14<<5) & 0x1000;
-				break; }
+	case SIOCDEVPRIVATE + 1:	/* Read the specified MII register. */
+		if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
+			int csr12 = inl (ioaddr + CSR12);
+			int csr14 = inl (ioaddr + CSR14);
+			switch (regnum) {
+			case 0:
+				data[3] = (csr14 << 5) & 0x1000;
+				break;
 			case 1:
-				data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
-					+ (csr12&0x06 ? 0x04 : 0);
+				data[3] =
+				  0x7848 +
+				  ((csr12 & 0x7000) == 0x5000 ? 0x20 : 0) +
+				  (csr12 & 0x06 ? 0x04 : 0);
 				break;
-			case 4: {
-				data[3] = ((csr14>>9)&0x07C0) +
-					((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
+			case 4:
+				data[3] =
+				  ((csr14 >> 9) & 0x07C0) +
+				  ((inl (ioaddr + CSR6) >> 3) & 0x0040) +
+				  ((csr14 >> 1) & 0x20) + 1;
+				break;
+			case 5:
+				data[3] = csr12 >> 16;
+				break;
+			default:
+				data[3] = 0;
 				break;
-			}
-			case 5: data[3] = csr12 >> 16; break;
-			default: data[3] = 0; break;
 			}
 		} else {
-			spin_lock_irqsave (&tp->lock, flags);
-			data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-			spin_unlock_irqrestore (&tp->lock, flags);
+			data[3] = tulip_mdio_read (dev, data[0] & 0x1f, regnum);
 		}
 		return 0;
-	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
+	case SIOCDEVPRIVATE + 2:	/* Write the specified MII register */
+		if (!capable (CAP_NET_ADMIN))
 			return -EPERM;
-		if (data[0] == 32  &&  (tp->flags & HAS_NWAY)) {
-			if (data[1] == 5)
+		if (regnum & ~0x1f)
+			return -EINVAL;
+		if (data[0] == phy) {
+			u16 value = data[2];
+			switch (regnum) {
+			case 0:	/* Check for autonegotiation on or reset. */
+				tp->full_duplex_lock = (value & 0x9000) ? 0 : 1;
+				if (tp->full_duplex_lock)
+					tp->full_duplex = (value & 0x0100) ? 1 : 0;
+				break;
+			case 4:
 				tp->to_advertise = data[2];
+				break;
+			}
+		}
+		if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
+			u16 value = data[2];
+			if (regnum == 0) {
+				if ((value & 0x1200) == 0x1200)
+					t21142_start_nway (dev);
+			} else if (regnum == 4)
+				tp->to_advertise = value;
 		} else {
-			spin_lock_irqsave (&tp->lock, flags);
-			tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-			spin_unlock_irqrestore(&tp->lock, flags);
+			tulip_mdio_write (dev, data[0] & 0x1f, regnum, data[2]);
 		}
 		return 0;
 	default:
@@ -967,38 +1004,56 @@
 
 	tp->csr6 &= ~0x00D5;
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
-		tp->csr6 |= 0x00C0;
-		csr6 |= 0x00C0;
+		tp->csr6 |= AcceptAllMulticast | AcceptAllPhys;
+		csr6 |= AcceptAllMulticast | AcceptAllPhys;
 		/* Unconditionally log net taps. */
 		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
 	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {
 		/* Too many to filter well -- accept all multicasts. */
-		tp->csr6 |= 0x0080;
-		csr6 |= 0x0080;
+		tp->csr6 |= AcceptAllMulticast;
+		csr6 |= AcceptAllMulticast;
 	} else	if (tp->flags & MC_HASH_ONLY) {
 		/* Some work-alikes have only a 64-entry hash filter table. */
 		/* Should verify correctness on big-endian/__powerpc__ */
 		struct dev_mc_list *mclist;
 		int i;
-		u32 mc_filter[2];		 /* Multicast hash filter */
 		if (dev->mc_count > 64) {		/* Arbitrary non-effective limit. */
-			tp->csr6 |= 0x0080;
-			csr6 |= 0x0080;
+			tp->csr6 |= AcceptAllMulticast;
+			csr6 |= AcceptAllMulticast;
 		} else {
-			mc_filter[1] = mc_filter[0] = 0;
+			u32 mc_filter[2] = {0, 0};		 /* Multicast hash filter */
+			int filterbit;
 			for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-				 i++, mclist = mclist->next)
-				set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
-
-			if (tp->chip_id == AX88140) {
+				 i++, mclist = mclist->next) {
+				if (tp->flags & COMET_MAC_ADDR)
+					filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
+				else
+					filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+				filterbit &= 0x3f;
+				set_bit(filterbit, mc_filter);
+				if (tulip_debug > 2) {
+					printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
+						   "%2.2x:%2.2x:%2.2x  %8.8x bit %d.\n", dev->name,
+						   mclist->dmi_addr[0], mclist->dmi_addr[1],
+						   mclist->dmi_addr[2], mclist->dmi_addr[3],
+						   mclist->dmi_addr[4], mclist->dmi_addr[5],
+						   ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+				}
+			}
+			if (mc_filter[0] == tp->mc_filter[0]  &&
+				mc_filter[1] == tp->mc_filter[1])
+				;				/* No change. */
+			else if (tp->flags & IS_ASIX) {
 				outl(2, ioaddr + CSR13);
 				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. */
+			} else if (tp->flags & COMET_MAC_ADDR) {
 				outl(mc_filter[0], ioaddr + 0xAC);
 				outl(mc_filter[1], ioaddr + 0xB0);
 			}
+			tp->mc_filter[0] = mc_filter[0];
+			tp->mc_filter[1] = mc_filter[1];
 		}
 	} else {
 		unsigned long flags;
@@ -1068,12 +1123,11 @@
 static int __devinit tulip_init_one (struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
-	static int did_version;			/* Already printed version info. */
 	struct tulip_private *tp;
 	/* See note below on the multiport cards. */
 	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
 	static int last_irq;
-	static int multiport_cnt;		/* For four-port boards w/one EEPROM */
+	static int multiport_cnt;	/* For four-port boards w/one EEPROM */
 	u8 chip_rev;
 	int i, irq;
 	unsigned short sum;
@@ -1082,11 +1136,16 @@
 	long ioaddr;
 	static int board_idx = -1;
 	int chip_idx = ent->driver_data;
+	int t2104x_mode = 0;
+	int eeprom_missing = 0;
 
-	board_idx++;
-
+#ifndef MODULE
+	static int did_version;		/* Already printed version info. */
 	if (tulip_debug > 0  &&  did_version++ == 0)
 		printk (KERN_INFO "%s", version);
+#endif
+
+	board_idx++;
 
 	/*
 	 *	Lan media wire a tulip chip to a wan interface. Needs a very
@@ -1146,7 +1205,7 @@
 	irq = pdev->irq;
 
 	/* init_etherdev ensures aligned and zeroed private structures */
-	dev = init_etherdev (NULL, sizeof (*tp));
+	dev = alloc_etherdev (sizeof (*tp));
 	if (!dev) {
 		printk (KERN_ERR PFX "ether device alloc failed, aborting\n");
 		return -ENOMEM;
@@ -1154,36 +1213,23 @@
 
 	if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
 		printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
-			"aborting\n", dev->name, pci_resource_len (pdev, 0),
+			"aborting\n", pdev->slot_name,
+			pci_resource_len (pdev, 0),
 			pci_resource_start (pdev, 0));
 		goto err_out_free_netdev;
 	}
 
 	/* grab all resources from both PIO and MMIO regions, as we
 	 * don't want anyone else messing around with our hardware */
-	if (!request_region (pci_resource_start (pdev, 0),
-			     pci_resource_len (pdev, 0),
-			     dev->name)) {
-		printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) unavailable, "
-			"aborting\n", dev->name, pci_resource_len (pdev, 0),
-			pci_resource_start (pdev, 0));
+	if (pci_request_regions (pdev, "tulip"))
 		goto err_out_free_netdev;
-	}
-	if (!request_mem_region (pci_resource_start (pdev, 1),
-				 pci_resource_len (pdev, 1),
-				 dev->name)) {
-		printk (KERN_ERR PFX "%s: MMIO region (0x%lx@0x%lx) unavailable, "
-			"aborting\n", dev->name, pci_resource_len (pdev, 1),
-			pci_resource_start (pdev, 1));
-		goto err_out_free_pio_res;
-	}
 
 	pci_set_master(pdev);
 
 	pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
 
 	/*
-	 * initialize priviate data structure 'tp'
+	 * initialize private data structure 'tp'
 	 * it is zeroed and aligned in init_etherdev
 	 */
 	tp = dev->priv;
@@ -1193,7 +1239,7 @@
 					   sizeof(struct tulip_tx_desc) * TX_RING_SIZE,
 					   &tp->rx_ring_dma);
 	if (!tp->rx_ring)
-		goto err_out_free_mmio_res;
+		goto err_out_free_res;
 	tp->tx_ring = (struct tulip_tx_desc *)(tp->rx_ring + RX_RING_SIZE);
 	tp->tx_ring_dma = tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * RX_RING_SIZE;
 
@@ -1204,24 +1250,10 @@
 	tp->revision = chip_rev;
 	tp->csr0 = csr0;
 	spin_lock_init(&tp->lock);
+	spin_lock_init(&tp->mii_lock);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-	pci_set_drvdata(pdev, dev);
-
-#ifdef TULIP_FULL_DUPLEX
-	tp->full_duplex = 1;
-	tp->full_duplex_lock = 1;
-#endif
-#ifdef TULIP_DEFAULT_MEDIA
-	tp->default_port = TULIP_DEFAULT_MEDIA;
-#endif
-#ifdef TULIP_NO_MEDIA_SWITCH
-	tp->medialock = 1;
-#endif
-
-	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
-		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
 
 	/* bugfix: the ASIX must have a burst limit or horrible things happen. */
 	if (chip_idx == AX88140) {
@@ -1239,10 +1271,10 @@
 
 	if (chip_idx == DC21041) {
 		if (inl(ioaddr + CSR9) & 0x8000) {
-			printk(" 21040 compatible mode,");
 			chip_idx = DC21040;
+			t2104x_mode = 1;
 		} else {
-			printk(" 21041 mode,");
+			t2104x_mode = 2;
 		}
 	}
 
@@ -1315,7 +1347,7 @@
 	   Many PCI BIOSes also incorrectly report the IRQ line, so we correct
 	   that here as well. */
 	if (sum == 0  || sum == 6*0xff) {
-		printk(" EEPROM not present,");
+		eeprom_missing = 1;
 		for (i = 0; i < 5; i++)
 			dev->dev_addr[i] = last_phys_addr[i];
 		dev->dev_addr[i] = last_phys_addr[i] + 1;
@@ -1326,21 +1358,23 @@
 	}
 
 	for (i = 0; i < 6; i++)
-		printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
-	printk(", IRQ %d.\n", irq);
+		last_phys_addr[i] = dev->dev_addr[i];
 	last_irq = irq;
 
 	/* The lower four bits are the media type. */
 	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
-		tp->default_port = options[board_idx] & 15;
-		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+		if (options[board_idx] & MEDIA_MASK)
+			tp->default_port = options[board_idx] & MEDIA_MASK;
+		if ((options[board_idx] & FullDuplex) || full_duplex[board_idx] > 0)
 			tp->full_duplex = 1;
 		if (mtu[board_idx] > 0)
 			dev->mtu = mtu[board_idx];
 	}
-	if (dev->mem_start)
-		tp->default_port = dev->mem_start;
+	if (dev->mem_start & MEDIA_MASK)
+		tp->default_port = dev->mem_start & MEDIA_MASK;
 	if (tp->default_port) {
+		printk(KERN_INFO "%s: Transceiver selection forced to %s.\n",
+		       pdev->slot_name, medianame[tp->default_port & MEDIA_MASK]);
 		tp->medialock = 1;
 		if (tulip_media_cap[tp->default_port] & MediaAlwaysFD)
 			tp->full_duplex = 1;
@@ -1356,16 +1390,18 @@
 	else
 		tp->to_advertise = 0x01e1;
 
-	/* This is logically part of _init_one(), but too complex to write inline. */
 	if (tp->flags & HAS_MEDIA_TABLE) {
 		memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+
+		sprintf(dev->name, "tulip%d", board_idx);	/* hack */
 		tulip_parse_eeprom(dev);
+		strcpy(dev->name, "eth%d");			/* un-hack */
 	}
 
 	if ((tp->flags & ALWAYS_CHECK_MII) ||
 		(tp->mtable  &&  tp->mtable->has_mii) ||
 		( ! tp->mtable  &&  (tp->flags & HAS_MII))) {
-		int phy, phy_idx;
+		int phyn, phy_idx = 0;
 		if (tp->mtable  &&  tp->mtable->has_mii) {
 			for (i = 0; i < tp->mtable->leafcount; i++)
 				if (tp->mtable->mleaf[i].media == 11) {
@@ -1379,8 +1415,8 @@
 		/* Find the connected MII xcvrs.
 		   Doing this in open() would allow detecting external xcvrs later,
 		   but takes much time. */
-		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
-			 phy++) {
+		for (phyn = 1; phyn <= 32 && phy_idx < sizeof(tp->phys); phyn++) {
+			int phy = phyn & 0x1f;
 			int mii_status = tulip_mdio_read(dev, phy, 1);
 			if ((mii_status & 0x8301) == 0x8001 ||
 				((mii_status & 0x8000) == 0  && (mii_status & 0x7800) != 0)) {
@@ -1391,15 +1427,15 @@
 				tp->advertising[phy_idx++] = reg4;
 				printk(KERN_INFO "%s:  MII transceiver #%d "
 					   "config %4.4x status %4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_reg0, mii_status, mii_advert);
+					   pdev->slot_name, phy, mii_reg0, mii_status, mii_advert);
 				/* Fixup for DLink with miswired PHY. */
 				if (mii_advert != reg4) {
 					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
 						   " previously advertising %4.4x.\n",
-						   dev->name, reg4, phy, mii_advert);
+						   pdev->slot_name, reg4, phy, mii_advert);
 					printk(KERN_DEBUG "%s:  Advertising %4.4x (to advertise"
 						   " is %4.4x).\n",
-						   dev->name, reg4, tp->to_advertise);
+						   pdev->slot_name, reg4, tp->to_advertise);
 					tulip_mdio_write(dev, phy, 4, reg4);
 				}
 				/* Enable autonegotiation: some boards default to off. */
@@ -1411,7 +1447,7 @@
 		tp->mii_cnt = phy_idx;
 		if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
 			printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
-				   dev->name);
+			       pdev->slot_name);
 			tp->phys[0] = 1;
 		}
 	}
@@ -1426,6 +1462,23 @@
 	dev->do_ioctl = private_ioctl;
 	dev->set_multicast_list = set_rx_mode;
 
+	if (register_netdev(dev))
+		goto err_out_mtable;
+
+	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+	       dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+	pci_set_drvdata(pdev, dev);
+
+	if (t2104x_mode == 1)
+		printk(" 21040 compatible mode,");
+	else if (t2104x_mode == 2)
+		printk(" 21041 mode,");
+	if (eeprom_missing)
+		printk(" EEPROM not present,");
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(", IRQ %d.\n", irq);
+
 	if ((tp->flags & HAS_NWAY)  || tp->chip_id == DC21041)
 		tp->link_change = t21142_lnk_change;
 	else if (tp->flags & HAS_PNICNWAY)
@@ -1493,12 +1546,11 @@
 
 	return 0;
 
-err_out_free_mmio_res:
-	release_mem_region (pci_resource_start (pdev, 1),
-			    pci_resource_len (pdev, 1));
-err_out_free_pio_res:
-	release_region (pci_resource_start (pdev, 0),
-			pci_resource_len (pdev, 0));
+err_out_mtable:
+	if (tp->mtable)
+		kfree (tp->mtable);
+err_out_free_res:
+	pci_release_regions (pdev);
 err_out_free_netdev:
 	unregister_netdev (dev);
 	kfree (dev);
@@ -1510,7 +1562,7 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
-	if (dev && netif_device_present (dev)) {
+	if (dev && netif_running (dev) && netif_device_present (dev)) {
 		netif_device_detach (dev);
 		tulip_down (dev);
 		/* pci_power_off(pdev, -1); */
@@ -1522,10 +1574,10 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
+	if (dev && netif_running (dev) && !netif_device_present (dev)) {
 #if 1
-	pci_enable_device (pdev);
+		pci_enable_device (pdev);
 #endif
-	if (dev && !netif_device_present (dev)) {
 		/* pci_power_on(pdev); */
 		tulip_up (dev);
 		netif_device_attach (dev);
@@ -1547,14 +1599,10 @@
 			     sizeof (struct tulip_tx_desc) * TX_RING_SIZE,
 			     tp->rx_ring, tp->rx_ring_dma);
 	unregister_netdev (dev);
-	release_mem_region (pci_resource_start (pdev, 1),
-			    pci_resource_len (pdev, 1));
-	release_region (pci_resource_start (pdev, 0),
-			pci_resource_len (pdev, 0));
 	if (tp->mtable)
 		kfree (tp->mtable);
 	kfree (dev);
-
+	pci_release_regions (pdev);
 	pci_set_drvdata (pdev, NULL);
 
 	/* pci_power_off (pdev, -1); */
@@ -1573,6 +1621,10 @@
 
 static int __init tulip_init (void)
 {
+#ifdef MODULE
+	printk (KERN_INFO "%s", version);
+#endif
+
 	/* copy module parms into globals */
 	tulip_rx_copybreak = rx_copybreak;
 	tulip_max_interrupt_work = max_interrupt_work;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/tun.c linux/drivers/net/tun.c
--- v2.4.3/linux/drivers/net/tun.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/tun.c	Wed Apr 18 14:40:06 2001
@@ -48,7 +48,7 @@
 #include <asm/uaccess.h>
 
 #ifdef TUN_DEBUG
-static int debug=0;
+static int debug;
 #endif
 
 /* Network device part of the driver */
@@ -147,8 +147,6 @@
 		dev->type = ARPHRD_PPP; 
 		dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
 		dev->tx_queue_len = 10;
-
-		dev_init_buffers(dev);
 		break;
 
 	case TUN_TAP_DEV:
diff -u --recursive --new-file v2.4.3/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.4.3/linux/drivers/net/via-rhine.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/via-rhine.c	Fri Apr 20 11:54:23 2001
@@ -69,7 +69,7 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
@@ -131,10 +131,9 @@
 #include <asm/irq.h>
 
 /* These identify the driver base version and may not be removed. */
-static char version1[] __devinitdata =
-"via-rhine.c:v1.08b-LK1.1.7  8/9/2000  Written by Donald Becker\n";
-static char version2[] __devinitdata =
-"  http://www.scyld.com/network/via-rhine.html\n";
+static char version[] __devinitdata =
+KERN_INFO "via-rhine.c:v1.08b-LK1.1.8  4/17/2000  Written by Donald Becker\n"
+KERN_INFO "  http://www.scyld.com/network/via-rhine.html\n";
 
 
 
@@ -477,17 +476,17 @@
 	int i, option;
 	int chip_id = (int) ent->driver_data;
 	static int card_idx = -1;
-	static int did_version = 0;
 	long ioaddr;
 	int io_size;
 	int pci_flags;
 	
-	/* print version once and once only */
-	if (! did_version++) {
-		printk (KERN_INFO "%s", version1);
-		printk (KERN_INFO "%s", version2);
-	}
-	
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	card_idx++;
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 	io_size = via_rhine_chip_info[chip_id].io_size;
@@ -1499,6 +1498,10 @@
 
 static int __init via_rhine_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init (&via_rhine_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in
--- v2.4.3/linux/drivers/net/wan/Config.in	Tue Mar  6 19:44:37 2001
+++ linux/drivers/net/wan/Config.in	Thu Apr 12 12:11:39 2001
@@ -75,15 +75,13 @@
    if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
       bool '  WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS
       if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then
-	 dep_tristate '    Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS
+	 dep_tristate '    Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER
 	 if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
-	    int '      Maximum number of cards' CONFIG_WANPIPE_CARDS 1
 	    bool '      WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC
-	    if [ "$CONFIG_OBSOLETE" = "y" ]; then
-	       bool '      WANPIPE Frame Relay support (OBSOLETE)' CONFIG_WANPIPE_FR
-	       bool '      WANPIPE X.25 support (OBSOLETE)' CONFIG_WANPIPE_X25
-	    fi
+	    bool '      WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+	    bool '      WANPIPE X.25 support' CONFIG_WANPIPE_X25
 	    bool '      WANPIPE PPP support' CONFIG_WANPIPE_PPP
+	    bool '      WANPIPE Multi-Port PPP support' CONFIG_WANPIPE_MULTPPP
 	 fi
 	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	    dep_tristate '    Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile
--- v2.4.3/linux/drivers/net/wan/Makefile	Tue Mar  6 19:44:37 2001
+++ linux/drivers/net/wan/Makefile	Thu Apr 12 12:11:39 2001
@@ -12,11 +12,12 @@
 export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o
 list-multi =	wanpipe.o cyclomx.o
 
-wanpipe-objs = sdlamain.o $(wanpipe-y)
+wanpipe-objs = sdlamain.o sdla_ft1.o $(wanpipe-y)
 wanpipe-$(CONFIG_WANPIPE_X25)	+= sdla_x25.o
 wanpipe-$(CONFIG_WANPIPE_FR)	+= sdla_fr.o
 wanpipe-$(CONFIG_WANPIPE_CHDLC)	+= sdla_chdlc.o
 wanpipe-$(CONFIG_WANPIPE_PPP)	+= sdla_ppp.o
+wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o
 
 cyclomx-objs = cycx_main.o $(cyclomx-y)  
 cyclomx-$(CONFIG_CYCLOMX_X25)	+= cycx_x25.o
@@ -45,7 +46,11 @@
  
 obj-$(CONFIG_DLCI)		+= dlci.o 
 obj-$(CONFIG_SDLA)		+= sdla.o
-obj-$(CONFIG_VENDOR_SANGOMA)	+= sdladrv.o wanpipe.o
+ifeq ($(CONFIG_WANPIPE_MULTPPP),y)
+  obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o	
+else
+  obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o
+endif
 obj-$(CONFIG_CYCLADES_SYNC)	+= cycx_drv.o cyclomx.o
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.4.3/linux/drivers/net/wan/cycx_x25.c	Tue Mar 20 12:05:01 2001
+++ linux/drivers/net/wan/cycx_x25.c	Wed Apr 18 14:40:06 2001
@@ -492,7 +492,6 @@
         dev->tx_queue_len = 10;
 
 	/* Initialize socket buffers */
-	dev_init_buffers(dev);
 	set_chan_state(dev, WAN_DISCONNECTED);
 
 	return 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c
--- v2.4.3/linux/drivers/net/wan/dlci.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/net/wan/dlci.c	Fri Apr 20 11:54:22 2001
@@ -57,8 +57,8 @@
 
 #include <net/sock.h>
 
-static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
+static const char devname[] = "dlci";
+static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
 
 static struct net_device *open_dev[CONFIG_DLCI_COUNT];
 
@@ -575,8 +575,6 @@
 	dev->addr_len		= sizeof(short);
 	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
 
-	dev_init_buffers(dev);
-	
 	return(0);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/dscc4.c linux/drivers/net/wan/dscc4.c
--- v2.4.3/linux/drivers/net/wan/dscc4.c	Tue Mar 20 12:05:00 2001
+++ linux/drivers/net/wan/dscc4.c	Fri Apr 20 11:54:22 2001
@@ -107,7 +107,7 @@
 #include <linux/hdlc.h>
 
 /* Version */
-static const char * version = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
+static const char version[] = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
 static int debug;
 
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/hdlc.c linux/drivers/net/wan/hdlc.c
--- v2.4.3/linux/drivers/net/wan/hdlc.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/hdlc.c	Wed Apr 18 14:40:07 2001
@@ -1292,8 +1292,6 @@
 		pvc->netdev.tx_queue_len = 0;
 		pvc->netdev.flags = IFF_POINTOPOINT;
 
-		dev_init_buffers(&pvc->netdev);
-
 		pvc->master = hdlc;
 		*(u16*)pvc->netdev.dev_addr = htons(dlci);
 		dlci_to_q922(pvc->netdev.broadcast, dlci);
@@ -1393,7 +1391,6 @@
 
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 
-	dev_init_buffers(dev);
 	return 0;
 }
 
@@ -1423,7 +1420,6 @@
 	if (result != 0)
 		return -EIO;
 
-	dev_init_buffers(dev);
 	MOD_INC_USE_COUNT;
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/hostess_sv11.c linux/drivers/net/wan/hostess_sv11.c
--- v2.4.3/linux/drivers/net/wan/hostess_sv11.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/hostess_sv11.c	Wed Apr 18 14:40:07 2001
@@ -347,7 +347,6 @@
 		d->do_ioctl = hostess_ioctl;
 #ifdef LINUX_21			
 		d->neigh_setup = hostess_neigh_setup_dev;
-		dev_init_buffers(d);
 #else
 		d->init = return_0;
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- v2.4.3/linux/drivers/net/wan/lapbether.c	Mon Jan 22 13:32:10 2001
+++ linux/drivers/net/wan/lapbether.c	Wed Apr 18 14:40:07 2001
@@ -400,8 +400,6 @@
                 return -EIO;
         }
 
-	dev_init_buffers(dev);
-
 	dev->hard_start_xmit = lapbeth_xmit;
 	dev->open	     = lapbeth_open;
 	dev->stop	     = lapbeth_close;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c
--- v2.4.3/linux/drivers/net/wan/sdla.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/wan/sdla.c	Wed Apr 18 14:40:07 2001
@@ -1641,8 +1641,6 @@
 	dev->addr_len		= 0;
 	dev->mtu		= SDLA_MAX_MTU;
 
-	dev_init_buffers(dev);
-   
 	flp->activate		= sdla_activate;
 	flp->deactivate		= sdla_deactivate;
 	flp->assoc		= sdla_assoc;
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- v2.4.3/linux/drivers/net/wan/sdla_chdlc.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/sdla_chdlc.c	Fri Apr 20 11:54:22 2001
@@ -4,14 +4,40 @@
 * Authors: 	Nenad Corbic <ncorbic@sangoma.com>
 *		Gideon Hack  
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2001 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* Feb 28, 2000  Jeff Garzik	softnet updates
+* Feb 28, 2001  Nenad Corbic	Updated if_tx_timeout() routine for 
+* 				2.4.X kernels.
+* Jan 25, 2001  Nenad Corbic	Added a TTY Sync serial driver over the
+* 				HDLC streaming protocol
+* 				Added a TTY Async serial driver over the
+* 				Async protocol.
+* Dec 15, 2000  Nenad Corbic    Updated for 2.4.X Kernel support
+* Nov 13, 2000  Nenad Corbic    Added true interface type encoding option.
+* 				Tcpdump doesn't support CHDLC inteface
+* 				types, to fix this "true type" option will set
+* 				the interface type to RAW IP mode.
+* Nov 07, 2000  Nenad Corbic	Added security features for UDP debugging:
+*                               Deny all and specify allowed requests.
+* Jun 20, 2000  Nenad Corbic	Fixed the API IP ERROR bug. Caused by the 
+*                               latest update.
+* May 09, 2000	Nenad Corbic	Option to bring down an interface
+*                               upon disconnect.
+* Mar 23, 2000  Nenad Corbic	Improved task queue, bh handling.
+* Mar 16, 2000	Nenad Corbic	Fixed the SLARP Dynamic IP addressing.
+* Mar 06, 2000  Nenad Corbic	Bug Fix: corrupted mbox recovery.
+* Feb 10, 2000  Gideon Hack     Added ASYNC support.
+* Feb 09, 2000  Nenad Corbic    Fixed two shutdown bugs in update() and
+*                               if_stats() functions.
+* Jan 24, 2000  Nenad Corbic    Fixed a startup wanpipe state racing,  
+*                               condition between if_open and isr. 
+* Jan 10, 2000  Nenad Corbic    Added new socket API support.
+* Dev 15, 1999  Nenad Corbic    Fixed up header files for 2.0.X kernels
 * Nov 20, 1999  Nenad Corbic 	Fixed zero length API bug.
 * Sep 30, 1999  Nenad Corbic    Fixed dynamic IP and route setup.
 * Sep 23, 1999  Nenad Corbic    Added SMP support, fixed tracing 
@@ -22,18 +48,26 @@
 * Aug 07, 1998	David Fong	Initial version.
 *****************************************************************************/
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
-#include <linux/inetdevice.h>
-#include <asm/uaccess.h>
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ #include <asm/uaccess.h>
+ #include <linux/inetdevice.h>
+ #include <linux/netdevice.h>
+#else 				
+ #include <asm/segment.h>
+ #include <net/route.h>          /* Adding new route entries : 2.0.X kernels */
+#endif
+
 #include <linux/in.h>		/* sockaddr_in */
 #include <linux/inet.h>	
 #include <linux/if.h>
@@ -42,32 +76,42 @@
 #include <asm/io.h>
 
 #include <linux/sdla_chdlc.h>		/* CHDLC firmware API definitions */
+#include <linux/sdla_asy.h>           	/* CHDLC (async) API definitions */
 
-/****** Defines & Macros ****************************************************/
+#include <linux/if_wanpipe_common.h>    /* Socket Driver common area */
+#include <linux/if_wanpipe.h>		
+
+/* TTY Includes */
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
 
-#ifdef	_DEBUG_
-#define	STATIC
-#else
-#define	STATIC		static
-#endif
+
+/****** Defines & Macros ****************************************************/
 
 /* reasons for enabling the timer interrupt on the adapter */
-#define TMR_INT_ENABLED_UDP   	0x0001
-#define TMR_INT_ENABLED_UPDATE	0x0002
- 
+#define TMR_INT_ENABLED_UDP   		0x01
+#define TMR_INT_ENABLED_UPDATE		0x02
+#define TMR_INT_ENABLED_CONFIG		0x10
+
+#define MAX_IP_ERRORS	10
+
+#define TTY_CHDLC_MAX_MTU	2000
 #define	CHDLC_DFLT_DATA_LEN	1500		/* default MTU */
 #define CHDLC_HDR_LEN		1
 
-#define IFF_POINTTOPOINT 0x10
-
-#define WANPIPE 0x00
-#define API	0x01
 #define CHDLC_API 0x01
 
 #define PORT(x)   (x == 0 ? "PRIMARY" : "SECONDARY" )
+#define MAX_BH_BUFF	10
+
+//#define PRINT_DEBUG
+#ifdef PRINT_DEBUG
+#define dbg_printk(format, a...) printk(format, ## a)
+#else
+#define dbg_printk(format, a...)
+#endif  
 
-#define TX_TIMEOUT	(5*HZ)
- 
 /******Data Structures*****************************************************/
 
 /* This structure is placed in the private data area of the device structure.
@@ -77,9 +121,7 @@
 
 typedef struct chdlc_private_area
 {
-	/* This member must be first. */
-	struct net_device *slave;		/* WAN slave */
-
+	wanpipe_common_t common;
 	sdla_t		*card;
 	int 		TracingEnabled;		/* For enabling Tracing */
 	unsigned long 	curr_trace_addr;	/* Used for Tracing */
@@ -96,12 +138,38 @@
 	unsigned long 	router_up_time;
         u32             IP_address;		/* IP addressing */
         u32             IP_netmask;
+	u32		ip_local;
+	u32		ip_remote;
+	u32 		ip_local_tmp;
+	u32		ip_remote_tmp;
+	u8		ip_error;
+	u8		config_chdlc;
+	u8 		config_chdlc_timeout;
 	unsigned char  mc;			/* Mulitcast support on/off */
 	unsigned short udp_pkt_lgth;		/* udp packet processing */
 	char udp_pkt_src;
 	char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
 	unsigned short timer_int_enabled;
 	char update_comms_stats;		/* updating comms stats */
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	bh_data_t *bh_head;	  	  /* Circular buffer for chdlc_bh */
+	unsigned long  tq_working;
+	volatile int  bh_write;
+	volatile int  bh_read;
+	atomic_t  bh_buff_used;
+#endif
+	
+	unsigned char interface_down;
+
+	/* Polling task queue. Each interface
+         * has its own task queue, which is used
+         * to defer events from the interrupt */
+	struct tq_struct poll_task;
+	struct timer_list poll_delay_timer;
+
+	u8 gateway;
+	u8 true_if_encoding;
 	//FIXME: add driver stats as per frame relay!
 
 } chdlc_private_area_t;
@@ -125,41 +193,47 @@
 /****** Function Prototypes *************************************************/
 /* WAN link driver entry points. These are called by the WAN router module. */
 static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, struct net_device* dev,
+static int new_if (wan_device_t* wandev, netdevice_t* dev,
 	wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, struct net_device* dev);
 
 /* Network device interface */
-static int if_init   (struct net_device* dev);
-static int if_open   (struct net_device* dev);
-static int if_close  (struct net_device* dev);
-static void if_tx_timeout (struct net_device *dev);
-static int if_header (struct sk_buff* skb, struct net_device* dev,
+static int if_init   (netdevice_t* dev);
+static int if_open   (netdevice_t* dev);
+static int if_close  (netdevice_t* dev);
+static int if_header (struct sk_buff* skb, netdevice_t* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len);
-#ifdef LINUX_2_1
-static int if_rebuild_hdr (struct sk_buff *skb);
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+  static int if_rebuild_hdr (struct sk_buff *skb);
+  static struct net_device_stats* if_stats (netdevice_t* dev);
+
 #else
-static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr,
+  static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
         struct sk_buff* skb);
+  static struct enet_statistics* if_stats (netdevice_t* dev);
 #endif
-static int if_send (struct sk_buff* skb, struct net_device* dev);
-static struct net_device_stats* if_stats (struct net_device* dev);
+  
+static int if_send (struct sk_buff* skb, netdevice_t* dev);
 
 /* CHDLC Firmware interface functions */
 static int chdlc_configure 	(sdla_t* card, void* data);
 static int chdlc_comm_enable 	(sdla_t* card);
-static int chdlc_comm_disable 	(sdla_t* card);
 static int chdlc_read_version 	(sdla_t* card, char* str);
 static int chdlc_set_intr_mode 	(sdla_t* card, unsigned mode);
 static int chdlc_send (sdla_t* card, void* data, unsigned len);
 static int chdlc_read_comm_err_stats (sdla_t* card);
 static int chdlc_read_op_stats (sdla_t* card);
+static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
+
 
+static int chdlc_disable_comm_shutdown (sdla_t *card);
+#ifdef LINUX_2_4
+  static void if_tx_timeout (netdevice_t *dev);
+#endif
 
 /* Miscellaneous CHDLC Functions */
 static int set_chdlc_config (sdla_t* card);
-static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev );
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
+static void init_chdlc_tx_rx_buff( sdla_t* card);
 static int process_chdlc_exception(sdla_t *card);
 static int process_global_exception(sdla_t *card);
 static int update_comms_stats(sdla_t* card,
@@ -168,23 +242,40 @@
 static int unconfigure_ip (sdla_t* card);
 static void process_route(sdla_t *card);
 static void port_set_state (sdla_t *card, int);
+static int config_chdlc (sdla_t *card);
+static void disable_comm (sdla_t *card);
+
+static void trigger_chdlc_poll (netdevice_t *);
+static void chdlc_poll (netdevice_t *);
+static void chdlc_poll_delay (unsigned long dev_ptr);
+
 
+/* Miscellaneous asynchronous interface Functions */
+static int set_asy_config (sdla_t* card);
+static int asy_comm_enable (sdla_t* card);
 
 /* Interrupt handlers */
 static void wpc_isr (sdla_t* card);
 static void rx_intr (sdla_t* card);
 static void timer_intr(sdla_t *);
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+  /* Bottom half handlers */
+  static void chdlc_bh (netdevice_t *);
+  static int chdlc_bh_cleanup (netdevice_t *);
+  static int bh_enqueue (netdevice_t *, struct sk_buff *);
+#endif
+
 /* Miscellaneous functions */
-static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev,
+static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev,
 				struct sk_buff *skb);
 static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static int intr_test( sdla_t* card, struct net_device *dev );
+static int intr_test( sdla_t* card);
 static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, struct net_device* dev,
+                                struct sk_buff *skb, netdevice_t* dev,
                                 chdlc_private_area_t* chdlc_priv_area);
-static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,  
+static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,  
 				chdlc_private_area_t* chdlc_priv_area);
 static unsigned short calc_checksum (char *, int);
 static void s508_lock (sdla_t *card, unsigned long *smp_flags);
@@ -192,6 +283,46 @@
 
 
 static int  Intr_test_counter;
+
+/* TTY Global Definitions */
+
+#if defined(LINUX_2_4) || defined(LINUX_2_1)
+
+#define NR_PORTS 4
+#define WAN_TTY_MAJOR 226
+#define WAN_TTY_MINOR 0
+
+#define WAN_CARD(port) (tty_card_map[port])
+#define MIN_PORT 0
+#define MAX_PORT NR_PORTS-1 
+
+#define CRC_LENGTH 2
+
+static int wanpipe_tty_init(sdla_t *card);
+static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int);
+static void wanpipe_tty_trigger_poll(sdla_t *card);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount=1;
+static int tty_init_cnt=0;
+
+static struct serial_state rs_table[NR_PORTS];
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+static char tty_driver_mode=WANOPT_TTY_SYNC;
+
+static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX",
+	  	             "CRTSCTS XONXOFF-RX","XONXOFF-TX",
+		             "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"};
+static char *p_decode[] = {"NONE","ODD","EVEN"};
+
+static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL};
+
+#endif
+
+
 /****** Public Functions ****************************************************/
 
 /*============================================================================
@@ -211,6 +342,7 @@
 	unsigned char port_num;
 	int err;
 	unsigned long max_permitted_baud = 0;
+	SHARED_MEMORY_INFO_STRUCT *flags;
 
 	union
 		{
@@ -234,7 +366,7 @@
 			if (conf->comm_port != card->next->u.c.comm_port){
 				card->u.c.comm_port = conf->comm_port;
 			}else{
-				printk(KERN_ERR "%s: ERROR - %s port used!\n",
+				printk(KERN_INFO "%s: ERROR - %s port used!\n",
         		        	card->wandev.name, PORT(conf->comm_port));
 				return -EINVAL;
 			}
@@ -242,7 +374,7 @@
 			card->u.c.comm_port = conf->comm_port;
 		}
 	}else{
-		printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n",
+		printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n",
                 			card->wandev.name);
 		return -EINVAL;
 	}
@@ -305,15 +437,11 @@
 	card->exec			= NULL;
 	card->wandev.update		= &update;
  	card->wandev.new_if		= &new_if;
-	card->wandev.del_if		= &del_if;
-	card->wandev.state		= WAN_DUALPORT;
+	card->wandev.del_if		= NULL;
 	card->wandev.udp_port   	= conf->udp_port;
-
+	card->disable_comm		= &disable_comm;
 	card->wandev.new_if_cnt = 0;
 
-	/* This is for the ports link state */
-	card->u.c.state = WAN_DISCONNECTED;
-	
 	/* reset the number of times the 'update()' proc has been called */
 	card->u.c.update_call_count = 0;
 	
@@ -331,18 +459,27 @@
 
 	port_num = card->u.c.comm_port;
 
+	/* in API mode, we can configure for "receive only" buffering */
+	if(card->hw.type == SDLA_S514) {
+		card->u.c.receive_only = conf->receive_only;
+		if(conf->receive_only) {
+			printk(KERN_INFO
+				"%s: Configured for 'receive only' mode\n",
+                                card->devname);
+		}
+	}
+
 	/* Setup Port Bps */
 
 	if(card->wandev.clocking) {
-                      
-		if(port_num == WANOPT_PRI) {
+		if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
 			/* For Primary Port 0 */
                		max_permitted_baud =
 				(card->hw.type == SDLA_S514) ?
 				PRI_MAX_BAUD_RATE_S514 : 
 				PRI_MAX_BAUD_RATE_S508;
-		}
-		else if(port_num == WANOPT_SEC) {
+
+		}else if(port_num == WANOPT_SEC) {
 			/* For Secondary Port 1 */
                         max_permitted_baud =
                                (card->hw.type == SDLA_S514) ?
@@ -357,14 +494,14 @@
  				printk(KERN_INFO "%s: Baud rate set to %lu bps\n", 
 					card->wandev.name, max_permitted_baud);
 			}
-                             
 			card->wandev.bps = conf->bps;
 	}else{
         	card->wandev.bps = 0;
   	}
 
 	/* Setup the Port MTU */
-	if(port_num == WANOPT_PRI) {
+	if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
+
 		/* For Primary Port 0 */
 		card->wandev.mtu =
 			(conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
@@ -387,8 +524,6 @@
 	mb1->command = READ_CHDLC_CONFIGURATION;
 	err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
 	if(err != COMMAND_OK) {
-		clear_bit(1, (void*)&card->wandev.critical);
-
                 if(card->hw.type != SDLA_S514)
                 	enable_irq(card->hw.irq);
 
@@ -406,6 +541,72 @@
 			ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
 	}
 
+	flags = card->u.c.flags;
+	
+	/* This is for the ports link state */
+	card->wandev.state = WAN_DUALPORT;
+	card->u.c.state = WAN_DISCONNECTED;
+
+
+	if (!card->wandev.piggyback){	
+		int err;
+
+		/* Perform interrupt testing */
+		err = intr_test(card);
+
+		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { 
+			printk(KERN_INFO "%s: Interrupt test failed (%i)\n",
+					card->devname, Intr_test_counter);
+			printk(KERN_INFO "%s: Please choose another interrupt\n",
+					card->devname);
+			return -EIO;
+		}
+		
+		printk(KERN_INFO "%s: Interrupt test passed (%i)\n", 
+				card->devname, Intr_test_counter);
+		card->configured = 1;
+	}
+
+	if ((card->tty_opt=conf->tty) == WANOPT_YES){
+#if defined(LINUX_2_4) || defined(LINUX_2_1)	
+		int err;
+		card->tty_minor = conf->tty_minor;
+
+		/* On ASYNC connections internal clocking 
+		 * is mandatory */
+		if ((card->u.c.async_mode = conf->tty_mode)){
+			card->wandev.clocking = 1;
+		}
+		err=wanpipe_tty_init(card);
+		if (err){
+			return err;
+		}
+#else
+		printk(KERN_INFO "%s: Error: TTY driver is not supported on 2.0.X kernels!\n",
+				card->devname);	
+		return -EINVAL;  
+#endif
+	}else{
+	
+
+		if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){
+			printk (KERN_INFO "%s: 
+				Failed to set interrupt triggers!\n",
+				card->devname);
+			return -EIO;	
+        	}
+	
+		/* Mask the Timer interrupt */
+		flags->interrupt_info_struct.interrupt_permission &= 
+			~APP_INT_ON_TIMER;
+	}
+
+	/* If we are using CHDLC in backup mode, this flag will
+	 * indicate not to look for IP addresses in config_chdlc()*/
+	card->u.c.backup = conf->backup;
+	
+	printk(KERN_INFO "\n");
+
 	return 0;
 }
 
@@ -427,8 +628,8 @@
 static int update (wan_device_t* wandev)
 {
 	sdla_t* card = wandev->private;
- 	struct net_device* dev = card->wandev.dev;
-        volatile chdlc_private_area_t* chdlc_priv_area = dev->priv;
+ 	netdevice_t* dev;
+        volatile chdlc_private_area_t* chdlc_priv_area;
         SHARED_MEMORY_INFO_STRUCT *flags;
 	unsigned long timeout;
 
@@ -442,10 +643,14 @@
 	/* more sanity checks */
         if(!card->u.c.flags)
                 return -ENODEV;
-	if(test_bit(1, (void*)&card->wandev.critical))
+
+	if(test_bit(PERI_CRIT, (void*)&card->wandev.critical))
                 return -EAGAIN;
 
-	if(!netif_running(dev))
+	if((dev=card->wandev.dev) == NULL)
+		return -ENODEV;
+
+	if((chdlc_priv_area=dev->priv) == NULL)
 		return -ENODEV;
 
       	flags = card->u.c.flags;
@@ -488,13 +693,17 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf)
+static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
 {
 	sdla_t* card = wandev->private;
 	chdlc_private_area_t* chdlc_priv_area;
 
+
+	printk(KERN_INFO "%s: Configuring Interface: %s\n",
+			card->devname, conf->name);
+ 
 	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
-		printk(KERN_INFO "%s: invalid interface name!\n",
+		printk(KERN_INFO "%s: Invalid interface name!\n",
 			card->devname);
 		return -EINVAL;
 	}
@@ -506,9 +715,11 @@
 		return -ENOMEM;
 
 	memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t));
-	
+
 	chdlc_priv_area->card = card; 
-	
+	chdlc_priv_area->common.sk = NULL;
+	chdlc_priv_area->common.func = NULL;	
+
 	/* initialize data */
 	strcpy(card->u.c.if_name, conf->name);
 
@@ -523,110 +734,216 @@
 	chdlc_priv_area->route_status = NO_ROUTE;
 	chdlc_priv_area->route_removed = 0;
 
-	/* Setup protocol options */
-
-	card->u.c.protocol_options = 0;
-
-	if (conf->ignore_dcd == WANOPT_YES){
-		card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT;
-	}
+	card->u.c.async_mode = conf->async_mode;
+	
+	/* setup for asynchronous mode */
+	if(conf->async_mode) {
+		printk(KERN_INFO "%s: Configuring for asynchronous mode\n",
+			wandev->name);
 
-	if (conf->ignore_cts == WANOPT_YES){
-		card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT;
-	}
+		if(card->u.c.comm_port == WANOPT_PRI) {
+			printk(KERN_INFO
+				"%s:Asynchronous mode on secondary port only\n",
+					wandev->name);
+			kfree(chdlc_priv_area);
+			return -EINVAL;
+		}
 
-	if (conf->ignore_keepalive == WANOPT_YES) {
-		card->u.c.protocol_options |= IGNORE_KPALV_FOR_LINK_STAT;
-		card->u.c.kpalv_tx  = MIN_Tx_KPALV_TIMER; 
-		card->u.c.kpalv_rx  = MIN_Rx_KPALV_TIMER; 
-		card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; 
+	       	if(strcmp(conf->usedby, "WANPIPE") == 0) {
+			printk(KERN_INFO
+                                "%s: Running in WANIPE Async Mode\n",                                        			wandev->name);
+			card->u.c.usedby = WANPIPE;
+		}else{
+			card->u.c.usedby = API;
+		}
 
-	} else {   /* Do not ignore keepalives */
+		if(!card->wandev.clocking) {
+			printk(KERN_INFO
+				"%s: Asynch. clocking must be 'Internal'\n",
+				wandev->name);
+			kfree(chdlc_priv_area);
+			return -EINVAL;
+		}
 
-		card->u.c.kpalv_tx =
-  	   		(conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ?
-	   		min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) :
-	   					DEFAULT_Tx_KPALV_TIMER;
+		if((card->wandev.bps < MIN_ASY_BAUD_RATE) ||
+			(card->wandev.bps > MAX_ASY_BAUD_RATE)) {
+			printk(KERN_INFO "%s: Selected baud rate is invalid.\n",
+				wandev->name);
+			printk(KERN_INFO "Must be between %u and %u bps.\n",
+				MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE);
+			kfree(chdlc_priv_area);
+			return -EINVAL;
+		}
 
-		card->u.c.kpalv_rx =
-	   		(conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ?
-	   		min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) :
-	   					DEFAULT_Rx_KPALV_TIMER;
+		card->u.c.api_options = 0;
+                if (conf->asy_data_trans == WANOPT_YES) {
+                        card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT;
+                }
+		
+		card->u.c.protocol_options = 0;
+		if (conf->rts_hs_for_receive == WANOPT_YES) {
+			card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX;
+	        }
+                if (conf->xon_xoff_hs_for_receive == WANOPT_YES) {
+                        card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX;
+                }
+                if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) {
+                        card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX;
+                }
+                if (conf->dcd_hs_for_transmit == WANOPT_YES) {
+                        card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX;
+                }
+                if (conf->cts_hs_for_transmit == WANOPT_YES) {
+                        card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX;
+                }
 
-		card->u.c.kpalv_err =
-	   		(conf->keepalive_err_margin - MIN_KPALV_ERR_TOL) >= 0 ?
-	   		min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : 
-	   					DEFAULT_KPALV_ERR_TOL;
-	}
+		card->u.c.tx_bits_per_char = conf->tx_bits_per_char;
+                card->u.c.rx_bits_per_char = conf->rx_bits_per_char;
+                card->u.c.stop_bits = conf->stop_bits;
+		card->u.c.parity = conf->parity;
+		card->u.c.break_timer = conf->break_timer;
+		card->u.c.inter_char_timer = conf->inter_char_timer;
+		card->u.c.rx_complete_length = conf->rx_complete_length;
+		card->u.c.xon_char = conf->xon_char;
+
+	} else {	/* setup for synchronous mode */
+
+		card->u.c.protocol_options = 0;
+		if (conf->ignore_dcd == WANOPT_YES){
+			card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT;
+		}
+		if (conf->ignore_cts == WANOPT_YES){
+			card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT;
+		}
 
+		if (conf->ignore_keepalive == WANOPT_YES) {
+			card->u.c.protocol_options |=
+				IGNORE_KPALV_FOR_LINK_STAT;
+			card->u.c.kpalv_tx  = MIN_Tx_KPALV_TIMER; 
+			card->u.c.kpalv_rx  = MIN_Rx_KPALV_TIMER; 
+			card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; 
+
+		} else {   /* Do not ignore keepalives */
+			card->u.c.kpalv_tx =
+				((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER)
+				>= 0) ?
+	   			min(conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) :
+				DEFAULT_Tx_KPALV_TIMER;
+
+			card->u.c.kpalv_rx =
+		   		((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER)
+				>= 0) ?
+	   			min(conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) :
+				DEFAULT_Rx_KPALV_TIMER;
+
+			card->u.c.kpalv_err =
+		   		((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL)
+				>= 0) ?
+	   			min(conf->keepalive_err_margin,
+				MAX_KPALV_ERR_TOL) : 
+	   			DEFAULT_KPALV_ERR_TOL;
+		}
 
-	/* Setup slarp timer to control delay between slarps 
-         */ 
-	card->u.c.slarp_timer = 
-		(conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ?
-		min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) :
-					DEFAULT_SLARP_REQ_TIMER;
+		/* Setup slarp timer to control delay between slarps */
+		card->u.c.slarp_timer = 
+			((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ?
+			min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) :
+			DEFAULT_SLARP_REQ_TIMER;
+
+#ifdef LINUX_2_0
+		if (card->u.c.slarp_timer){
+			printk(KERN_INFO 
+				"%s: Error: Dynamic IP support not available for 2.0.X kernels\n",
+					card->devname);
+			printk(KERN_INFO "%s:        Defaulting to Static IP addressing\n",
+						card->devname);
+		}
+		card->u.c.slarp_timer=0;
+#endif	
 
 
-	/* If HDLC_STRAMING is enabled then IGNORE DCD, CTS and KEEPALIVES
-         * are automatically ignored 
-	 */
-	if (conf->hdlc_streaming == WANOPT_YES) {
-		printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n",
-			wandev->name);
-		card->u.c.protocol_options = HDLC_STREAMING_MODE;
-	}
+		if (conf->hdlc_streaming == WANOPT_YES) {
+			printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n",
+				wandev->name);
+			card->u.c.protocol_options = HDLC_STREAMING_MODE;
+		}
 
+		if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){
+			printk(KERN_INFO 
+				"%s: Enabling, true interface type encoding.\n",
+				card->devname);
+		}
+		
+        	/* Setup wanpipe as a router (WANPIPE) or as an API */
+		if( strcmp(conf->usedby, "WANPIPE") == 0) {
 
-        /* Setup wanpipe as a router (WANPIPE) or as an API */
-	if( strcmp(conf->usedby, "WANPIPE") == 0) {
-		printk(KERN_INFO "%s: Running in WANPIPE mode !\n",wandev->name);
-		card->u.c.usedby = WANPIPE;
-
-	} else if( strcmp(conf->usedby, "API") == 0){
-
-#ifdef CHDLC_API 
-		card->u.c.usedby = API;
-		printk(KERN_INFO "%s: Running in API mode !\n",wandev->name);
+			printk(KERN_INFO "%s: Running in WANPIPE mode!\n",
+				wandev->name);
+			card->u.c.usedby = WANPIPE;
+
+			/* Option to bring down the interface when 
+        		 * the link goes down */
+			if (conf->if_down){
+				set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down);
+				printk(KERN_INFO 
+				 "%s: Dynamic interface configuration enabled\n",
+				   card->devname);
+			} 
+
+		} else if( strcmp(conf->usedby, "API") == 0) {
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+			card->u.c.usedby = API;
+			printk(KERN_INFO "%s: Running in API mode !\n",
+				wandev->name);
 #else
-		printk(KERN_INFO "%s: API Mode is not supported!\n",
-			wandev->name);
-		printk(KERN_INFO "%s: Chdlc API patch can be obtained from Sangoma Tech.\n",
-					wandev->name);
-                kfree(chdlc_priv_area);
-		return -EINVAL;
+			printk(KERN_INFO "%s: API Mode is not supported for kernels lower than 2.2.X!\n",
+				wandev->name);
+			printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel fro the API support\n",
+				wandev->name);
+	                kfree(chdlc_priv_area);
+			return -EINVAL;
 #endif
+		}
 	}
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	/* Tells us that if this interface is a
+         * gateway or not */
+	if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){
+		printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
+			card->devname,card->u.c.if_name);
+	}
+#endif
 
 	/* Get Multicast Information */
 	chdlc_priv_area->mc = conf->mc;
 
 	/* prepare network device data space for registration */
-	strcpy(dev->name, card->u.c.if_name);
+#ifdef LINUX_2_4
+	strcpy(dev->name,card->u.c.if_name);
+#else
+	dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); 
+	sprintf(dev->name, "%s", card->u.c.if_name);
+#endif
+
 	dev->init = &if_init;
 	dev->priv = chdlc_priv_area;
 
-	return 0;
-}
-
-/*============================================================================
- * Delete logical channel.
- */
-static int del_if (wan_device_t* wandev, struct net_device* dev)
-{
-
-/* FIXME: This code generates kernel panic during
-          router stop!. Investigate futher.
-	  (Error is dereferencing a NULL pointer)
-
-	if(dev->priv){
-
-		kfree(dev->priv);
-                dev->priv = NULL;
+	/* Initialize the polling task routine */
+#ifndef LINUX_2_4
+	chdlc_priv_area->poll_task.next = NULL;
+#endif
+	chdlc_priv_area->poll_task.sync=0;
+	chdlc_priv_area->poll_task.routine = (void*)(void*)chdlc_poll;
+	chdlc_priv_area->poll_task.data = dev;
+
+	/* Initialize the polling delay timer */
+	init_timer(&chdlc_priv_area->poll_delay_timer);
+	chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev;
+	chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay;
+	
+	printk(KERN_INFO "\n");
 
-        }
-*/
 	return 0;
 }
 
@@ -640,12 +957,12 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init (struct net_device* dev)
+static int if_init (netdevice_t* dev)
 	{
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
 	wan_device_t* wandev = &card->wandev;
-#ifndef LINUX_2_1
+#ifdef LINUX_2_0
 	int i;
 #endif
 
@@ -656,22 +973,41 @@
 	dev->rebuild_header	= &if_rebuild_hdr;
 	dev->hard_start_xmit	= &if_send;
 	dev->get_stats		= &if_stats;
+#ifdef LINUX_2_4
 	dev->tx_timeout		= &if_tx_timeout;
 	dev->watchdog_timeo	= TX_TIMEOUT;
+#endif
 
+	
 	/* Initialize media-specific parameters */
-	dev->flags		|= IFF_POINTTOPOINT;
+	dev->flags		|= IFF_POINTOPOINT;
+	dev->flags		|= IFF_NOARP;
 
 	/* Enable Mulitcasting if user selected */
 	if (chdlc_priv_area->mc == WANOPT_YES){
 		dev->flags 	|= IFF_MULTICAST;
 	}
-
-#ifndef LINUX_2_1
+	
+#ifdef LINUX_2_0
 	dev->family		= AF_INET;
 #endif	
-	dev->type		= ARPHRD_PPP;	/* ARP hw type -- dummy value */
+
+	if (chdlc_priv_area->true_if_encoding){
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+		dev->type	= ARPHRD_HDLC; /* This breaks the tcpdump */
+#else
+		dev->type	= ARPHRD_PPP;
+#endif
+	}else{
+		dev->type	= ARPHRD_PPP;
+	}
+	
 	dev->mtu		= card->wandev.mtu;
+	/* for API usage, add the API header size to the requested MTU size */
+	if(card->u.c.usedby == API) {
+		dev->mtu += sizeof(api_tx_hdr_t);
+	}
+ 
 	dev->hard_header_len	= CHDLC_HDR_LEN;
 
 	/* Initialize hardware parameters */
@@ -688,13 +1024,10 @@
         dev->tx_queue_len = 100;
    
 	/* Initialize socket buffers */
-#ifdef LINUX_2_1
-	dev_init_buffers(dev);
-#else
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
         for (i = 0; i < DEV_NUMBUFFS; ++i)
                 skb_queue_head_init(&dev->buffs[i]);
 #endif
-
 	return 0;
 }
 
@@ -705,85 +1038,63 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open (struct net_device* dev)
+static int if_open (netdevice_t* dev)
 {
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
-	SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags;
 	struct timeval tv;
 	int err = 0;
 
 	/* Only one open per interface is allowed */
 
-	if(netif_running(dev))
+	if (is_dev_running(dev))
 		return -EBUSY;
-	
-	if(test_and_set_bit(1, (void*)&card->wandev.critical)) {
-		return -EAGAIN;
-	}
-	
-	/* Setup the Board for CHDLC */
-	if (set_chdlc_config(card)) {
-		clear_bit(1, (void*)&card->wandev.critical);
-		return -EIO;
-	}
-
-	if (!card->configured && !card->wandev.piggyback){	
-		/* Perform interrupt testing */
-		err = intr_test(card, dev);
-
-		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { 
-			printk(KERN_ERR "%s: Interrupt test failed (%i)\n",
-					card->devname, Intr_test_counter);
-			printk(KERN_ERR "%s: Please choose another interrupt\n",
-					card->devname);
-			clear_bit(1, (void*)&card->wandev.critical);
-			return -EIO;
-		}
-		
-		printk(KERN_INFO "%s: Interrupt test passed (%i)\n", 
-				card->devname, Intr_test_counter);
-		card->configured = 1;
-	}else{
-		printk(KERN_INFO "%s: Card configured, skip interrupt test\n", 
-				card->devname);
-	}
-
-	/* Initialize Rx/Tx buffer control fields */
-	init_chdlc_tx_rx_buff(card, dev);
-
-	/* Set interrupt mode and mask */
-        if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
-                		APP_INT_ON_GLOBAL_EXCEP_COND |
-                		APP_INT_ON_TX_FRAME |
-                		APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
 
-			clear_bit(1, (void*)&card->wandev.critical);
-                        return -EIO;
-        }
-	
-
-	/* Mask the Transmit and Timer interrupt */
-	flags->interrupt_info_struct.interrupt_permission &= 
-		~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
-
-
-	/* Enable communications */
-	if (chdlc_comm_enable(card)) {
-		clear_bit(1, (void*)&card->wandev.critical);
-		return -EIO;
-	}
-
-	clear_bit(1, (void*)&card->wandev.critical);
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	/* Initialize the task queue */
+	chdlc_priv_area->tq_working=0;
 
-	port_set_state(card, WAN_CONNECTING);
+#ifndef LINUX_2_4
+	chdlc_priv_area->common.wanpipe_task.next = NULL;
+#endif
+	chdlc_priv_area->common.wanpipe_task.sync = 0;
+	chdlc_priv_area->common.wanpipe_task.routine = (void *)(void *)chdlc_bh;
+	chdlc_priv_area->common.wanpipe_task.data = dev;
+
+	/* Allocate and initialize BH circular buffer */
+	/* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */
+	chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC);
+	memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1)));
+	atomic_set(&chdlc_priv_area->bh_buff_used, 0);
+#endif
+ 
 	do_gettimeofday(&tv);
 	chdlc_priv_area->router_start_time = tv.tv_sec;
- 
+
+#ifdef LINUX_2_4
 	netif_start_queue(dev);
-	dev->flags |= IFF_POINTTOPOINT;
+#else
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+#endif
+
 	wanpipe_open(card);
 
+	/* TTY is configured during wanpipe_set_termios
+	 * call, not here */
+	if (card->tty_opt)
+		return err;
+	
+	set_bit(0,&chdlc_priv_area->config_chdlc);
+	chdlc_priv_area->config_chdlc_timeout=jiffies;
+	del_timer(&chdlc_priv_area->poll_delay_timer);
+
+	/* Start the CHDLC configuration after 1sec delay.
+	 * This will give the interface initilization time
+	 * to finish its configuration */
+	chdlc_priv_area->poll_delay_timer.expires=jiffies+HZ;
+	add_timer(&chdlc_priv_area->poll_delay_timer);
 	return err;
 }
 
@@ -792,25 +1103,76 @@
  * o if this is the last close, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close (struct net_device* dev)
+static int if_close (netdevice_t* dev)
 {
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
 
-	if(test_and_set_bit(1, (void*)&card->wandev.critical))
-		return -EAGAIN;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 
-	netif_stop_queue(dev);
+	if (chdlc_priv_area->bh_head){
+		int i;
+		struct sk_buff *skb;
+	
+		for (i=0; i<(MAX_BH_BUFF+1); i++){
+			skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb;
+			if (skb != NULL){
+                		wan_dev_kfree_skb(skb, FREE_READ);
+			}
+		}
+		kfree(chdlc_priv_area->bh_head);
+		chdlc_priv_area->bh_head=NULL;
+	}
+#endif
+
+	stop_net_queue(dev);
+#ifndef LINUX_2_4
+	dev->start=0;
+#endif
 	wanpipe_close(card);
-	port_set_state(card, WAN_DISCONNECTED);
-	chdlc_set_intr_mode(card, 0);
-	chdlc_comm_disable(card);
+	del_timer(&chdlc_priv_area->poll_delay_timer);
+	return 0;
+}
 
-	clear_bit(1, (void*)&card->wandev.critical);
+static void disable_comm (sdla_t *card)
+{
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	
+	if (card->u.c.comm_enabled){
+		chdlc_disable_comm_shutdown (card);
+	}else{
+		flags->interrupt_info_struct.interrupt_permission = 0;	
+	}
 
-	return 0;
+#if defined(LINUX_2_4) || defined(LINUX_2_1)	
+	if (!tty_init_cnt)
+		return;
+
+	if (card->tty_opt){
+		struct serial_state * state;
+		if (!(--tty_init_cnt)){
+			int e1,e2;
+			*serial_driver.refcount=0;
+			
+			if ((e1 = tty_unregister_driver(&serial_driver)))
+				printk("SERIAL: failed to unregister serial driver (%d)\n",
+				       e1);
+			if ((e2 = tty_unregister_driver(&callout_driver)))
+				printk("SERIAL: failed to unregister callout driver (%d)\n", 
+				       e2);
+			printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n",
+					card->devname,WAN_TTY_MAJOR);
+		}
+		card->tty=NULL;
+		tty_card_map[card->tty_minor]=NULL;
+		state = &rs_table[card->tty_minor];
+		memset(state,0,sizeof(state));
+	}
+#endif
+	return;
 }
 
+
 /*============================================================================
  * Build media header.
  *
@@ -820,7 +1182,7 @@
  *
  * Return:	media header length.
  */
-static int if_header (struct sk_buff* skb, struct net_device* dev,
+static int if_header (struct sk_buff* skb, netdevice_t* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len)
 {
 	skb->protocol = htons(type);
@@ -828,49 +1190,50 @@
 	return CHDLC_HDR_LEN;
 }
 
+
+#ifdef LINUX_2_4
+/*============================================================================
+ * Handle transmit timeout event from netif watchdog
+ */
+static void if_tx_timeout (netdevice_t *dev)
+{
+    	chdlc_private_area_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	
+	/* If our device stays busy for at least 5 seconds then we will
+	 * kick start the device by making dev->tbusy = 0.  We expect
+	 * that our device never stays busy more than 5 seconds. So this                 
+	 * is only used as a last resort.
+	 */
+
+	++card->wandev.stats.collisions;
+
+	printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
+	netif_wake_queue (dev);
+}
+#endif
+
+
+
 /*============================================================================
  * Re-build media header.
  *
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 static int if_rebuild_hdr (struct sk_buff *skb)
 {
 	return 1;
 }
 #else
-static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr,
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
                            struct sk_buff* skb)
 {
         return 1;
 }
 #endif
 
-
-/*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
-static void if_tx_timeout (struct net_device *dev)
-{
-	chdlc_private_area_t *chdlc_priv_area = dev->priv;
-	sdla_t *card = chdlc_priv_area->card;
-
-	/* If our device stays busy for at least 5 seconds then we will
-	 * kick start the device by making dev->tbusy = 0.  We expect 
-	 * that our device never stays busy more than 5 seconds. So this
-	 * is only used as a last resort. 
-	 */
-	++card->wandev.stats.collisions;
-
-	printk (KERN_INFO "%s: Transmit timeout !\n",
-		card->devname);
-
-	/* unbusy the interface */
-	netif_wake_queue (dev);
-}
-
-
 /*============================================================================
  * Send a packet on a network interface.
  * o set tbusy flag (marks start of the transmission) to block a timer-based
@@ -888,7 +1251,7 @@
  * 2. Setting tbusy flag will inhibit further transmit requests from the
  *    protocol stack and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff* skb, struct net_device* dev)
+static int if_send (struct sk_buff* skb, netdevice_t* dev)
 {
 	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 	sdla_t *card = chdlc_priv_area->card;
@@ -896,33 +1259,68 @@
 	INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
 	int udp_type = 0;
 	unsigned long smp_flags;
+	int err=0;
 
-	if(skb == NULL) {
+#ifdef LINUX_2_4
+	netif_stop_queue(dev);
+#endif
+	
+	if (skb == NULL){
 		/* If we get here, some higher layer thinks we've missed an
 		 * tx-done interrupt.
 		 */
 		printk(KERN_INFO "%s: interface %s got kicked!\n",
 			card->devname, dev->name);
-		netif_wake_queue(dev);
+
+		wake_net_dev(dev);
 		return 0;
 	}
 
-   	if(ntohs(skb->protocol) != 0x16) {
+#ifndef LINUX_2_4
+	if (dev->tbusy){
+
+		/* If our device stays busy for at least 5 seconds then we will
+		 * kick start the device by making dev->tbusy = 0.  We expect 
+		 * that our device never stays busy more than 5 seconds. So this
+		 * is only used as a last resort. 
+		 */
+                ++card->wandev.stats.collisions;
+		if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) {
+			return 1;
+		}
+
+		printk (KERN_INFO "%s: Transmit timeout !\n",
+			card->devname);
+
+		/* unbusy the interface */
+		clear_bit(0,&dev->tbusy);
+	}
+#endif
+
+   	if (ntohs(skb->protocol) != htons(PVC_PROT)){
 
 		/* check the udp packet type */
+		
 		udp_type = udp_pkt_type(skb, card);
-		if(udp_type == UDP_CPIPE_TYPE) {
+
+		if (udp_type == UDP_CPIPE_TYPE){
                         if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
-                                chdlc_priv_area))
+                                chdlc_priv_area)){
 	                	chdlc_int->interrupt_permission |=
 					APP_INT_ON_TIMER;
+			}
+			start_net_queue(dev);
 			return 0;
 		}
 
 		/* check to see if the source IP address is a broadcast or */
 		/* multicast IP address */
-                if(chk_bcast_mcast_addr(card, dev, skb))
-                        return 0;
+                if(chk_bcast_mcast_addr(card, dev, skb)){
+			++card->wandev.stats.tx_dropped;
+			wan_dev_kfree_skb(skb,FREE_WRITE);
+			start_net_queue(dev);
+			return 0;
+		}
         }
 
 	/* Lock the 508 Card: SMP is supported */
@@ -930,29 +1328,24 @@
 		s508_lock(card,&smp_flags);
 	} 
 
-    	if(test_and_set_bit(0, (void*)&card->wandev.critical)) {
+    	if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
 	
 		printk(KERN_INFO "%s: Critical in if_send: %lx\n",
 					card->wandev.name,card->wandev.critical);
                 ++card->wandev.stats.tx_dropped;
-#ifdef LINUX_2_1
-    		dev_kfree_skb(skb);
-#else
-                dev_kfree_skb(skb, FREE_WRITE);
-#endif	
-		if(card->hw.type != SDLA_S514){
-			s508_unlock(card,&smp_flags);
-		}
-		return 0;
+		start_net_queue(dev);
+		goto if_send_exit_crit;
 	}
 
-	if(card->u.c.state != WAN_CONNECTED)
+	if(card->u.c.state != WAN_CONNECTED){
        		++card->wandev.stats.tx_dropped;
-
-	else if(!skb->protocol)
+		start_net_queue(dev);
+		
+	}else if(!skb->protocol){
         	++card->wandev.stats.tx_errors;
-
-	else {
+		start_net_queue(dev);
+		
+	}else {
 		void* data = skb->data;
 		unsigned len = skb->len;
 		unsigned char attr;
@@ -964,18 +1357,14 @@
 		if (card->u.c.usedby == API){
 			api_tx_hdr_t* api_tx_hdr;
 
-			if (len <= sizeof(api_tx_hdr_t)){
-#ifdef LINUX_2_1
- 		               	dev_kfree_skb(skb);
-#else
-                		dev_kfree_skb(skb, FREE_WRITE);
-#endif
+			/* discard the frame if we are configured for */
+			/* 'receive only' mode or if there is no data */
+			if (card->u.c.receive_only ||
+				(len <= sizeof(api_tx_hdr_t))) {
+				
 				++card->wandev.stats.tx_dropped;
-				clear_bit(0, (void*)&card->wandev.critical);
-				if(card->hw.type != SDLA_S514){
-					s508_unlock(card,&smp_flags);
-				}
-                		return 0;
+				start_net_queue(dev);
+				goto if_send_exit_crit;
 			}
 				
 			api_tx_hdr = (api_tx_hdr_t *)data;
@@ -985,24 +1374,36 @@
 		}
 
 		if(chdlc_send(card, data, len)) {
-			netif_stop_queue(dev);
-			chdlc_priv_area->tick_counter = jiffies;
-			chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
-		}
-		else {
+			stop_net_queue(dev);
+		}else{
 			++card->wandev.stats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
                         card->wandev.stats.tx_bytes += len;
+#endif
+			
+			start_net_queue(dev);
+			
+#ifdef LINUX_2_4
+		 	dev->trans_start = jiffies;
+#endif
 		}	
 	}
 
-	if (!netif_queue_stopped(dev))
-		dev_kfree_skb(skb);
+if_send_exit_crit:
+	
+	if (!(err=is_queue_stopped(dev))) {
+		wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+		chdlc_priv_area->tick_counter = jiffies;
+		chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
+	}
 
-	clear_bit(0, (void*)&card->wandev.critical);
+	clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
 	if(card->hw.type != SDLA_S514){
 		s508_unlock(card,&smp_flags);
 	}
-	return netif_queue_stopped(dev);
+	
+	return err;
 }
 
 
@@ -1011,19 +1412,19 @@
  * multicast source IP address.
  */
 
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
 				struct sk_buff *skb)
 {
 	u32 src_ip_addr;
         u32 broadcast_ip_addr = 0;
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         struct in_device *in_dev;
 #endif
         /* read the IP source address from the outgoing packet */
         src_ip_addr = *(u32 *)(skb->data + 12);
 
 	/* read the IP broadcast address for the device */
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         in_dev = dev->ip_ptr;
         if(in_dev != NULL) {
                 struct in_ifaddr *ifa= in_dev->ifa_list;
@@ -1040,12 +1441,6 @@
         if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
                 printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n",
 				card->devname);
-#ifdef LINUX_2_1
-                dev_kfree_skb(skb);
-#else
-                dev_kfree_skb(skb, FREE_WRITE);
-#endif
-                ++card->wandev.stats.tx_dropped;
                 return 1;
         } 
 
@@ -1054,12 +1449,6 @@
 		(ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
                 printk(KERN_INFO "%s: Multicast Source Address silently discarded\n",
 				card->devname);
-#ifdef LINUX_2_1
-                dev_kfree_skb(skb);
-#else
-                dev_kfree_skb(skb, FREE_WRITE);
-#endif
-                ++card->wandev.stats.tx_dropped;
                 return 1;
         }
 
@@ -1169,23 +1558,29 @@
 
 /*============================================================================
  * Get ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats.
+ * Return a pointer to struct enet_statistics.
  */
-#ifdef LINUX_2_1
-static struct net_device_stats* if_stats (struct net_device* dev)
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats* if_stats (netdevice_t* dev)
 {
 	sdla_t *my_card;
-	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	chdlc_private_area_t* chdlc_priv_area;
+
+	if ((chdlc_priv_area=dev->priv) == NULL)
+		return NULL;
 
 	my_card = chdlc_priv_area->card;
 	return &my_card->wandev.stats; 
 }
 #else
-static struct net_device_stats* if_stats (struct net_device* dev)
+static struct enet_statistics* if_stats (netdevice_t* dev)
 {
         sdla_t *my_card;
         chdlc_private_area_t* chdlc_priv_area = dev->priv;
 
+	if ((chdlc_priv_area=dev->priv) == NULL)
+		return NULL;
+
         my_card = chdlc_priv_area->card;
         return &my_card->wandev.stats;
 }
@@ -1261,44 +1656,63 @@
 }
 
 
-/*============================================================================
- * Enable communications.
- */
+/*===========================================================
+ * chdlc_disable_comm_shutdown
+ *
+ * Shutdown() disables the communications. We must
+ * have a sparate functions, because we must not
+ * call chdlc_error() hander since the private
+ * area has already been replaced */
 
-static int chdlc_comm_enable (sdla_t* card)
+static int chdlc_disable_comm_shutdown (sdla_t *card)
 {
-	int err;
 	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	CHDLC_INT_TRIGGERS_STRUCT* int_data =
+		 (CHDLC_INT_TRIGGERS_STRUCT *)mb->data;
+	int err;
+
+	/* Disable Interrutps */
+	int_data->CHDLC_interrupt_triggers 	= 0;
+	int_data->IRQ				= card->hw.irq;
+	int_data->interrupt_timer               = 1;
+   
+	mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT);
+	mb->command = SET_CHDLC_INTERRUPT_TRIGGERS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
 
+	/* Disable Communications */
+
+	if (card->u.c.async_mode) {
+		mb->command = DISABLE_ASY_COMMUNICATIONS;
+	}else{
+		mb->command = DISABLE_CHDLC_COMMUNICATIONS;
+	}
+	
 	mb->buffer_length = 0;
-	mb->command = ENABLE_CHDLC_COMMUNICATIONS;
 	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-	if (err != COMMAND_OK)
-		chdlc_error(card, err, mb);
-	return err;
+	
+	card->u.c.comm_enabled = 0;
+	
+	return 0;
 }
 
 /*============================================================================
- * Disable communications and Drop the Modem lines (DCD and RTS).
+ * Enable communications.
  */
-static int chdlc_comm_disable (sdla_t* card)
+
+static int chdlc_comm_enable (sdla_t* card)
 {
 	int err;
 	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
 
 	mb->buffer_length = 0;
-	mb->command = DISABLE_CHDLC_COMMUNICATIONS;
-	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-	if (err != COMMAND_OK)
-		chdlc_error(card,err,mb);
-
-	mb->command = SET_MODEM_STATUS;
-	mb->buffer_length = 1;
-	mb->data[0] = 0;
+	mb->command = ENABLE_CHDLC_COMMUNICATIONS;
 	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
 	if (err != COMMAND_OK)
-		chdlc_error(card,err,mb);
-
+		chdlc_error(card, err, mb);
+	else
+		card->u.c.comm_enabled = 1;
+	
 	return err;
 }
 
@@ -1397,10 +1811,10 @@
 	
 	/* Update transmit buffer control fields */
 	card->u.c.txbuf = ++txbuf;
-
+	
 	if ((void*)txbuf > card->u.c.txbuf_last)
 		card->u.c.txbuf = card->u.c.txbuf_base;
-
+	
 	return 0;
 }
 
@@ -1420,7 +1834,7 @@
 	switch (err) {
 
 	case CMD_TIMEOUT:
-		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+		printk(KERN_INFO "%s: command 0x%02X timed out!\n",
 			card->devname, cmd);
 		break;
 
@@ -1440,17 +1854,112 @@
 	return 0;
 }
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+/********** Bottom Half Handlers ********************************************/
+
+/* NOTE: There is no API, BH support for Kernels lower than 2.2.X.
+ *       DO NOT INSERT ANY CODE HERE, NOTICE THE 
+ *       PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE
+ *       DOING */
+
+static void chdlc_bh (netdevice_t * dev)
+{
+	chdlc_private_area_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	struct sk_buff *skb;
+
+	if (atomic_read(&chan->bh_buff_used) == 0){
+		clear_bit(0, &chan->tq_working);
+		return;
+	}
+
+	while (atomic_read(&chan->bh_buff_used)){
+
+		skb  = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
+
+		if (skb != NULL){
+
+			if (chan->common.sk == NULL || chan->common.func == NULL){
+				++card->wandev.stats.rx_dropped;
+				wan_dev_kfree_skb(skb, FREE_READ);
+				chdlc_bh_cleanup(dev);
+				continue;
+			}
+
+			if (chan->common.func(skb,dev,chan->common.sk) != 0){
+				/* Sock full cannot send, queue us for another
+                                 * try */
+				atomic_set(&chan->common.receive_block,1);
+				return;
+			}else{
+				chdlc_bh_cleanup(dev);
+			}
+		}else{
+			chdlc_bh_cleanup(dev);
+		}
+	}	
+	clear_bit(0, &chan->tq_working);
+
+	return;
+}
+
+static int chdlc_bh_cleanup (netdevice_t *dev)
+{
+	chdlc_private_area_t* chan = dev->priv;
+
+	((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
+
+	if (chan->bh_read == MAX_BH_BUFF){
+		chan->bh_read=0;
+	}else{
+		++chan->bh_read;	
+	}
+
+	atomic_dec(&chan->bh_buff_used);
+	return 0;
+}
+
+
+
+static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+{
+	/* Check for full */
+	chdlc_private_area_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+
+	if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){
+		++card->wandev.stats.rx_dropped;
+		wan_dev_kfree_skb(skb, FREE_READ);
+		return 1; 
+	}
+
+	((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
+
+	if (chan->bh_write == MAX_BH_BUFF){
+		chan->bh_write=0;
+	}else{
+		++chan->bh_write;
+	}
+
+	atomic_inc(&chan->bh_buff_used);
+
+	return 0;
+}
+
+/* END OF API BH Support */
+
+#endif
+
 /****** Interrupt Handlers **************************************************/
 
 /*============================================================================
  * Cisco HDLC interrupt service routine.
  */
-STATIC void wpc_isr (sdla_t* card)
+static void wpc_isr (sdla_t* card)
 {
-	struct net_device* dev;
-	chdlc_private_area_t* chdlc_priv_area;
+	netdevice_t* dev;
 	SHARED_MEMORY_INFO_STRUCT* flags = NULL;
-	int i, interrupt_serviced = 0;
+	int i;
 	sdla_t *my_card;
 
 
@@ -1462,95 +1971,97 @@
 	flags = card->u.c.flags;
 	if (!flags->interrupt_info_struct.interrupt_type){
 		/* Check for a second port (piggybacking) */
-		if((my_card = card->next)){
+		if ((my_card = card->next)){
 			flags = my_card->u.c.flags;
 			if (flags->interrupt_info_struct.interrupt_type){
 				card = my_card;
+				card->isr(card);
+				return;
 			}
 		}
 	}
 
+	flags = card->u.c.flags;
+	card->in_isr = 1;
 	dev = card->wandev.dev;
 	
-	card->in_isr = 1;
+	/* If we get an interrupt with no network device, stop the interrupts
+	 * and issue an error */
+	if (!card->tty_opt && !dev && 
+	    flags->interrupt_info_struct.interrupt_type != 
+	    	COMMAND_COMPLETE_APP_INT_PEND){
+
+		goto isr_done;
+	}
 	
 	/* if critical due to peripheral operations
 	 * ie. update() or getstats() then reset the interrupt and
 	 * wait for the board to retrigger.
 	 */
-	if(test_bit(1, (void*)&card->wandev.critical)) {
-               	if(card->u.c.flags != NULL) {
-                       	flags = card->u.c.flags;
-			if(flags->interrupt_info_struct.
-					interrupt_type) {
-					flags->interrupt_info_struct.
-						interrupt_type = 0;
-			}
-		}
-		card->in_isr = 0;
-		return;
+	if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
+		printk(KERN_INFO "ISR CRIT TO PERI\n");
+		goto isr_done;
 	}
 
-
 	/* On a 508 Card, if critical due to if_send 
-         * Major Error !!!
-	 */
+         * Major Error !!! */
 	if(card->hw.type != SDLA_S514) {
-		if(test_and_set_bit(0, (void*)&card->wandev.critical)) {
+		if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
 			printk(KERN_INFO "%s: Critical while in ISR: %lx\n",
 				card->devname, card->wandev.critical);
 			card->in_isr = 0;
+			flags->interrupt_info_struct.interrupt_type = 0;
 			return;
 		}
 	}
 
-	/* FIXME: Take this check out later in the future */
-	if(card->u.c.flags != NULL) {
-	
-		flags = card->u.c.flags;
+	switch(flags->interrupt_info_struct.interrupt_type) {
 
-		switch(flags->interrupt_info_struct.interrupt_type) {
+	case RX_APP_INT_PEND:	/* 0x01: receive interrupt */
+		rx_intr(card);
+		break;
 
-		case RX_APP_INT_PEND:	/* 0x01: receive interrupt */
-			interrupt_serviced = 1;
-			rx_intr(card);
-			break;
+	case TX_APP_INT_PEND:	/* 0x02: transmit interrupt */
+		flags->interrupt_info_struct.interrupt_permission &=
+			 ~APP_INT_ON_TX_FRAME;
 
-		case TX_APP_INT_PEND:	/* 0x02: transmit interrupt */
-			interrupt_serviced = 1;
-			flags->interrupt_info_struct.interrupt_permission &=
-				 ~APP_INT_ON_TX_FRAME;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 
-			chdlc_priv_area = dev->priv;
-			netif_wake_queue(dev);
+		if (card->tty_opt){
+			wanpipe_tty_trigger_poll(card);
 			break;
+		}
 
-		case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
-			interrupt_serviced = 1;
-			++ Intr_test_counter;
-			break;
+		if (dev && is_queue_stopped(dev)){
+			if (card->u.c.usedby == API){
+				start_net_queue(dev);
+				wakeup_sk_bh(dev);
+			}else{
+				wake_net_dev(dev);
+			}
+		}
+#else
+		wake_net_dev(dev);
+#endif
+		break;
 
-		case CHDLC_EXCEP_COND_APP_INT_PEND:	/* 0x20 */
-			interrupt_serviced = 1;
-			process_chdlc_exception(card);
-			break;
+	case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
+		++ Intr_test_counter;
+		break;
 
-		case GLOBAL_EXCEP_COND_APP_INT_PEND:
-			interrupt_serviced = 1;
-			process_global_exception(card);
-			break;
+	case CHDLC_EXCEP_COND_APP_INT_PEND:	/* 0x20 */
+		process_chdlc_exception(card);
+		break;
 
-		case TIMER_APP_INT_PEND:
-			interrupt_serviced = 1;
-			timer_intr(card);
-			break;
+	case GLOBAL_EXCEP_COND_APP_INT_PEND:
+		process_global_exception(card);
+		break;
 
-		default:
-			break;
-		}	
-	}
+	case TIMER_APP_INT_PEND:
+		timer_intr(card);
+		break;
 
-	if(!interrupt_serviced) {
+	default:
 		printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", 
 			card->devname,
 			flags->interrupt_info_struct.interrupt_type);
@@ -1563,14 +2074,14 @@
 			printk(KERN_INFO "%c", 
 				flags->global_info_struct.codeversion[i]); 
 		printk(KERN_INFO "\n");	
+		break;
 	}
 
+isr_done:
+
 	card->in_isr = 0;
 	flags->interrupt_info_struct.interrupt_type = 0;
-        if(card->hw.type != SDLA_S514){
-        	clear_bit(0, (void*)&card->wandev.critical);
-	}
-        
+	return;
 }
 
 /*============================================================================
@@ -1578,15 +2089,16 @@
  */
 static void rx_intr (sdla_t* card)
 {
-	struct net_device 			*dev;
-	chdlc_private_area_t		*chdlc_priv_area;
-	SHARED_MEMORY_INFO_STRUCT 	*flags = card->u.c.flags;
-	CHDLC_DATA_RX_STATUS_EL_STRUCT	*rxbuf = card->u.c.rxmb;
-	struct sk_buff			*skb;
-	unsigned 			len;
-	void				*buf;
-	int 				i,udp_type;
-	
+	netdevice_t *dev;
+	chdlc_private_area_t *chdlc_priv_area;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb;
+	struct sk_buff *skb;
+	unsigned len;
+	unsigned addr = rxbuf->ptr_data_bfr;
+	void *buf;
+	int i,udp_type;
+
 	if (rxbuf->opp_flag != 0x01) {
 		printk(KERN_INFO 
 			"%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", 
@@ -1600,90 +2112,132 @@
                         printk(KERN_INFO "%c",
                                 flags->global_info_struct.codeversion[i]);
                 printk(KERN_INFO "\n");
+
+
+		/* Bug Fix: Mar 6 2000
+                 * If we get a corrupted mailbox, it measn that driver 
+                 * is out of sync with the firmware. There is no recovery.
+                 * If we don't turn off all interrupts for this card
+                 * the machine will crash. 
+                 */
+		printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
+		printk(KERN_INFO "Please contact Sangoma Technologies !\n");
+		chdlc_set_intr_mode(card,0);	
 		return;
 	}
 
+	len  = rxbuf->frame_length;
+
+#if defined(LINUX_2_4) || defined(LINUX_2_1)	
+	if (card->tty_opt){
+
+		if (rxbuf->error_flag){	
+			goto rx_exit;
+		}
+
+		if (len <= CRC_LENGTH){
+			goto rx_exit;
+		}
+		
+		if (!card->u.c.async_mode){
+			len -= CRC_LENGTH;
+		}
+
+		wanpipe_tty_receive(card,addr,len);
+		goto rx_exit;
+	}
+#endif
+
 	dev = card->wandev.dev;
-	chdlc_priv_area = dev->priv;
 
-	if(dev && netif_running(dev)) {
+	if (!dev){
+		goto rx_exit;
+	}
+
+	if (!is_dev_running(dev))
+		goto rx_exit;
 
-		len  = rxbuf->frame_length;
+	chdlc_priv_area = dev->priv;
 
-		/* Allocate socket buffer */
-		skb = dev_alloc_skb(len);
+	
+	/* Allocate socket buffer */
+	skb = dev_alloc_skb(len);
 
-		if (skb != NULL) {
-			/* Copy data to the socket buffer */
-			unsigned addr = rxbuf->ptr_data_bfr;
-		
-			if((addr + len) >
-			card->u.c.rx_top + 1) {
-				unsigned tmp = 
-				card->u.c.rx_top - addr + 1;
-				buf = skb_put(skb, tmp);
-				sdla_peek(&card->hw, addr, buf, tmp);
-				addr = card->u.c.rx_base;
-				len -= tmp;
-			}
+	if (skb == NULL) {
+		printk(KERN_INFO "%s: no socket buffers available!\n",
+					card->devname);
+		++card->wandev.stats.rx_dropped;
+		goto rx_exit;
+	}
+
+	/* Copy data to the socket buffer */
+	if((addr + len) > card->u.c.rx_top + 1) {
+		unsigned tmp = card->u.c.rx_top - addr + 1;
+		buf = skb_put(skb, tmp);
+		sdla_peek(&card->hw, addr, buf, tmp);
+		addr = card->u.c.rx_base;
+		len -= tmp;
+	}
 		
-			buf = skb_put(skb, len);
-			sdla_peek(&card->hw, addr, buf, len);
+	buf = skb_put(skb, len);
+	sdla_peek(&card->hw, addr, buf, len);
 
-			/* Decapsulate packet */
-			skb->protocol = htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 
-			card->wandev.stats.rx_packets ++;
-#ifdef LINUX_2_1
-			card->wandev.stats.rx_bytes += skb->len;
+	card->wandev.stats.rx_packets ++;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	card->wandev.stats.rx_bytes += skb->len;
 #endif
-			udp_type = udp_pkt_type( skb, card );
+	udp_type = udp_pkt_type( skb, card );
 
-			if(udp_type == UDP_CPIPE_TYPE) {
-				if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK,
-					card, skb, dev, chdlc_priv_area)) {
-       				        flags->interrupt_info_struct.
+	if(udp_type == UDP_CPIPE_TYPE) {
+		if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK,
+   				      card, skb, dev, chdlc_priv_area)) {
+     		        flags->interrupt_info_struct.
 						interrupt_permission |= 
 							APP_INT_ON_TIMER; 
-				}
-
-			} else {
- 
-				if(card->u.c.usedby == API) {
-					api_rx_hdr_t* api_rx_hdr;
-              				skb_push(skb, sizeof(api_rx_hdr_t));
-                                        api_rx_hdr =
-						(api_rx_hdr_t*)&skb->data[0x00];
-					api_rx_hdr->error_flag =
-						rxbuf->error_flag;
-          				api_rx_hdr->time_stamp =
-                                                rxbuf->time_stamp;
-                                	skb->protocol = htons(0x16);
-                                	skb->pkt_type = PACKET_HOST;
-				}
-
-/* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic
-                                ++ chdlc_priv_area->if_stats.multicast;
-*/
-                               	/* Pass it up the protocol stack */
-                                skb->dev = dev;
-                                skb->mac.raw  = skb->data;
-                                netif_rx(skb);
-			}
-
-		} else {
-			printk(KERN_INFO
-				"%s: no socket buffers available!\n",
-					card->devname);
-			++card->wandev.stats.rx_dropped;
 		}
-     	}
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	} else if(card->u.c.usedby == API) {
 
-	/* Release buffer element and calculate a pointer to the next one */
-	rxbuf->opp_flag = 0x00;
-	card->u.c.rxmb = ++ rxbuf;
-	if((void*)rxbuf > card->u.c.rxbuf_last)
-		card->u.c.rxmb = card->u.c.rxbuf_base;
+		api_rx_hdr_t* api_rx_hdr;
+       		skb_push(skb, sizeof(api_rx_hdr_t));
+                api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
+		api_rx_hdr->error_flag = rxbuf->error_flag;
+     		api_rx_hdr->time_stamp = rxbuf->time_stamp;
+
+                skb->protocol = htons(PVC_PROT);
+     		skb->mac.raw  = skb->data;
+		skb->dev      = dev;
+               	skb->pkt_type = WAN_PACKET_DATA;
+
+		bh_enqueue(dev, skb);
+
+		if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)){
+			wanpipe_queue_tq(&chdlc_priv_area->common.wanpipe_task);
+		        wanpipe_mark_bh();
+		}
+#endif
+	}else{
+		/* FIXME: we should check to see if the received packet is a 
+                          multicast packet so that we can increment the multicast 
+                          statistic
+                          ++ chdlc_priv_area->if_stats.multicast;
+		*/
+               	/* Pass it up the protocol stack */
+	
+                skb->dev = dev;
+                skb->mac.raw  = skb->data;
+                netif_rx(skb);
+	}
+
+rx_exit:
+	/* Release buffer element and calculate a pointer to the next one */
+	rxbuf->opp_flag = 0x00;
+	card->u.c.rxmb = ++ rxbuf;
+	if((void*)rxbuf > card->u.c.rxbuf_last){
+		card->u.c.rxmb = card->u.c.rxbuf_base;
+	}
 }
 
 /*============================================================================
@@ -1694,13 +2248,25 @@
  */
 void timer_intr(sdla_t *card)
 {
-        struct net_device* dev;
+        netdevice_t* dev;
         chdlc_private_area_t* chdlc_priv_area = NULL;
         SHARED_MEMORY_INFO_STRUCT* flags = NULL;
 
-        dev = card->wandev.dev; 
+        if ((dev = card->wandev.dev)==NULL){
+		flags = card->u.c.flags;
+                flags->interrupt_info_struct.interrupt_permission &=
+                        ~APP_INT_ON_TIMER;
+		return;
+	}
+	
         chdlc_priv_area = dev->priv;
 
+	if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) {
+		if (!config_chdlc(card)){
+			chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
+		}
+	}
+
 	/* process a udp call if pending */
        	if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) {
                	process_udp_mgmt_pkt(card, dev,
@@ -1733,16 +2299,14 @@
 
 static int set_chdlc_config(sdla_t* card)
 {
-
-	struct net_device * dev = card->wandev.dev;
-	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 	CHDLC_CONFIGURATION_STRUCT cfg;
 
 	memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT));
 
-	if(card->wandev.clocking)
+	if(card->wandev.clocking){
 		cfg.baud_rate = card->wandev.bps;
-
+	}
+		
 	cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
 		INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
 
@@ -1750,9 +2314,18 @@
 	cfg.modem_status_timer		= 100;
 
 	cfg.CHDLC_protocol_options	= card->u.c.protocol_options;
-	cfg.percent_data_buffer_for_Tx	= 50;
+
+	if (card->tty_opt){
+		cfg.CHDLC_API_options	= DISCARD_RX_ERROR_FRAMES;
+	}
+	
+	cfg.percent_data_buffer_for_Tx  = (card->u.c.receive_only) ? 0 : 50;
 	cfg.CHDLC_statistics_options	= (CHDLC_TX_DATA_BYTE_COUNT_STAT |
 		CHDLC_RX_DATA_BYTE_COUNT_STAT);
+	
+	if (card->tty_opt){
+		card->wandev.mtu = TTY_CHDLC_MAX_MTU;
+	}
 	cfg.max_CHDLC_data_field_length	= card->wandev.mtu;
 	cfg.transmit_keepalive_timer	= card->u.c.kpalv_tx;
 	cfg.receive_keepalive_timer	= card->u.c.kpalv_rx;
@@ -1762,9 +2335,12 @@
 	if (cfg.SLARP_request_timer) {
 		cfg.IP_address		= 0;
 		cfg.IP_netmask		= 0;
-	}
-	else {
-#ifdef LINUX_2_1
+		
+	}else if (card->wandev.dev){
+		netdevice_t * dev = card->wandev.dev;
+		chdlc_private_area_t *chdlc_priv_area = dev->priv;
+		
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
                 struct in_device *in_dev = dev->ip_ptr;
 
 		if(in_dev != NULL) {
@@ -1773,10 +2349,8 @@
 			if (ifa != NULL ) {
 				cfg.IP_address	= ntohl(ifa->ifa_local);
 				cfg.IP_netmask	= ntohl(ifa->ifa_mask); 
-				chdlc_priv_area->IP_address = 
-					ntohl(ifa->ifa_local);
-				chdlc_priv_area->IP_netmask =
-					ntohl(ifa->ifa_mask); 
+				chdlc_priv_area->IP_address = ntohl(ifa->ifa_local);
+				chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); 
 			}
 		}
 #else
@@ -1803,6 +2377,70 @@
 }
 
 
+/*-----------------------------------------------------------------------------
+   set_asy_config() used to set asynchronous configuration options on the board
+------------------------------------------------------------------------------*/
+
+static int set_asy_config(sdla_t* card)
+{
+
+        ASY_CONFIGURATION_STRUCT cfg;
+ 	CHDLC_MAILBOX_STRUCT *mailbox = card->mbox;
+	int err;
+
+	memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT));
+
+	if(card->wandev.clocking)
+		cfg.baud_rate = card->wandev.bps;
+
+	cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
+		INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
+
+	cfg.modem_config_options	= 0;
+	cfg.asy_API_options 		= card->u.c.api_options;
+	cfg.asy_protocol_options	= card->u.c.protocol_options;
+	cfg.Tx_bits_per_char		= card->u.c.tx_bits_per_char;
+	cfg.Rx_bits_per_char		= card->u.c.rx_bits_per_char;
+	cfg.stop_bits			= card->u.c.stop_bits;
+	cfg.parity			= card->u.c.parity;
+	cfg.break_timer			= card->u.c.break_timer;
+	cfg.asy_Rx_inter_char_timer	= card->u.c.inter_char_timer; 
+	cfg.asy_Rx_complete_length	= card->u.c.rx_complete_length; 
+	cfg.XON_char			= card->u.c.xon_char;
+	cfg.XOFF_char			= card->u.c.xoff_char;
+	cfg.asy_statistics_options	= (CHDLC_TX_DATA_BYTE_COUNT_STAT |
+		CHDLC_RX_DATA_BYTE_COUNT_STAT);
+
+	mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT);
+	memcpy(mailbox->data, &cfg, mailbox->buffer_length);
+	mailbox->command = SET_ASY_CONFIGURATION;
+	err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK) 
+		chdlc_error (card, err, mailbox);
+	return err;
+}
+
+/*============================================================================
+ * Enable asynchronous communications.
+ */
+
+static int asy_comm_enable (sdla_t* card)
+{
+
+	int err;
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+	mb->buffer_length = 0;
+	mb->command = ENABLE_ASY_COMMUNICATIONS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK && card->wandev.dev)
+		chdlc_error(card, err, mb);
+	
+	if (!err)
+		card->u.c.comm_enabled = 1;
+
+	return err;
+}
 
 /*============================================================================
  * Process global exception condition
@@ -1830,7 +2468,8 @@
 					printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname);
 					break;
 				case (CTS_HIGH):
-                                        printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname);                                        break;
+                                        printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); 
+					break;
                                 case ((DCD_HIGH | CTS_HIGH)):
                                         printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname);
                                         break;
@@ -1850,6 +2489,19 @@
 				card->devname); 
 			break;
 
+		case 0x17:
+			if (card->tty_opt){
+				if (card->tty && card->tty_open){ 
+					printk(KERN_INFO 
+						"%s: Modem Hangup Exception: Hanging Up!\n",
+						card->devname);
+					tty_hangup(card->tty);
+				}
+				break;
+			}
+
+			/* If TTY is not used just drop throught */
+			
                 default:
                         printk(KERN_INFO "%s: Global exception %x\n",
 				card->devname, mbox->return_code);
@@ -1877,11 +2529,13 @@
 
 		case EXCEP_LINK_ACTIVE:
 			port_set_state(card, WAN_CONNECTED);
+			trigger_chdlc_poll(card->wandev.dev);
 			break;
 
 		case EXCEP_LINK_INACTIVE_MODEM:
 			port_set_state(card, WAN_DISCONNECTED);
 			unconfigure_ip(card);
+			trigger_chdlc_poll(card->wandev.dev);
 			break;
 
 		case EXCEP_LINK_INACTIVE_KPALV:
@@ -1889,6 +2543,7 @@
 			printk(KERN_INFO "%s: Keepalive timer expired.\n",
 				 		card->devname);
 			unconfigure_ip(card);
+			trigger_chdlc_poll(card->wandev.dev);
 			break;
 
 		case EXCEP_IP_ADDRESS_DISCOVERED:
@@ -1919,10 +2574,16 @@
 
 static int configure_ip (sdla_t* card)
 {
-	struct net_device *dev = card->wandev.dev;
-        chdlc_private_area_t *chdlc_priv_area = dev->priv;
+	netdevice_t *dev = card->wandev.dev;
+        chdlc_private_area_t *chdlc_priv_area;
         char err;
 
+	if (!dev)
+		return 0;
+
+	chdlc_priv_area = dev->priv;
+	
+	
         /* set to discover */
         if(card->u.c.slarp_timer != 0x00) {
 		CHDLC_MAILBOX_STRUCT* mb = card->mbox;
@@ -1940,14 +2601,14 @@
 		cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data;
                 chdlc_priv_area->IP_address = cfg->IP_address;
                 chdlc_priv_area->IP_netmask = cfg->IP_netmask;
-        }
 
-	/* Set flag to add route */
-	chdlc_priv_area->route_status = ADD_ROUTE;
+		/* Set flag to add route */
+		chdlc_priv_area->route_status = ADD_ROUTE;
 
-	/* The idea here is to add the route in the poll routine.
-	   This way, we aren't in interrupt context when adding routes */
-	card->poll = process_route;
+		/* The idea here is to add the route in the poll routine.
+	   	This way, we aren't in interrupt context when adding routes */
+		trigger_chdlc_poll(dev);
+        }
 
 	return 0;
 }
@@ -1960,17 +2621,23 @@
 
 static int unconfigure_ip (sdla_t* card)
 {
-	struct net_device *dev = card->wandev.dev;
-	chdlc_private_area_t *chdlc_priv_area= dev->priv;
+	netdevice_t *dev = card->wandev.dev;
+	chdlc_private_area_t *chdlc_priv_area;
+
+	if (!dev)
+		return 0;
 
+	chdlc_priv_area= dev->priv;
+	
 	if (chdlc_priv_area->route_status == ROUTE_ADDED) {
-	      	chdlc_priv_area->route_status = REMOVE_ROUTE;
-		/* The idea here is to delete the route in 
-		 * the poll routine.
-	   	 * This way, we aren't in interrupt context 
-		 * when adding routes 
+
+		/* Note: If this function is called, the 
+                 * port state has been DISCONNECTED.  This state
+                 * change will trigger a poll_disconnected 
+                 * function, that will check for this condition. 
 		 */
-                card->poll = process_route;
+		chdlc_priv_area->route_status = REMOVE_ROUTE;
+
 	}
 	return 0;
 }
@@ -1982,14 +2649,14 @@
 
 static void process_route (sdla_t *card)
 {
-        struct net_device *dev = card->wandev.dev;
+        netdevice_t *dev = card->wandev.dev;
         unsigned char port_num;
         chdlc_private_area_t *chdlc_priv_area = NULL;
 	u32 local_IP_addr = 0;
 	u32 remote_IP_addr = 0;
 	u32 IP_netmask, IP_addr;
         int err = 0;
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct in_device *in_dev;
 	mm_segment_t fs;
 	struct ifreq if_info;
@@ -2002,16 +2669,25 @@
         chdlc_priv_area = dev->priv;
         port_num = card->u.c.comm_port;
 
+	/* Bug Fix Mar 16 2000
+	 * AND the IP address to the Mask before checking
+         * the last two bits. */
+
 	if((chdlc_priv_area->route_status == ADD_ROUTE) &&
-		((chdlc_priv_area->IP_address & 0x000000FF) > 2)) {
+		((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) {
+
 		printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname);
+
                 if(card->u.c.slarp_timer) {
+
 			printk(KERN_INFO "%s: Bad IP address %s received\n",
 				card->devname,
 				in_ntoa(ntohl(chdlc_priv_area->IP_address)));
                         printk(KERN_INFO "%s: from remote station.\n",
 				card->devname);
+
                 }else{ 
+
                         printk(KERN_INFO "%s: Bad IP address %s issued\n",
 				card->devname,
 				in_ntoa(ntohl(chdlc_priv_area->IP_address)));
@@ -2033,11 +2709,10 @@
 
  	        /* do not remove a bad route that has already been removed */
         	if(chdlc_priv_area->route_removed) {
-                	card->poll = NULL;
 	                return;
         	}
 
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
                 in_dev = dev->ip_ptr;
 
                 if(in_dev != NULL) {
@@ -2058,7 +2733,17 @@
 		*/
 		IP_netmask = ntohl(chdlc_priv_area->IP_netmask);
 	        remote_IP_addr = ntohl(chdlc_priv_area->IP_address);
-        	local_IP_addr = (remote_IP_addr & ntohl(0xFFFFFF00)) +
+	
+
+		/* If Netmask is 255.255.255.255 the local address
+                 * calculation will fail. Default it back to 255.255.255.0 */
+		if (IP_netmask == 0xffffffff)
+			IP_netmask &= 0x00ffffff;
+
+		/* Bug Fix Mar 16 2000
+		 * AND the Remote IP address with IP netmask, instead
+                 * of static netmask of 255.255.255.0 */
+        	local_IP_addr = (remote_IP_addr & IP_netmask) +
                 	(~remote_IP_addr & ntohl(0x0003));
 
 	        if(!card->u.c.slarp_timer) {
@@ -2071,7 +2756,7 @@
         fs = get_fs();                  /* Save file system  */
         set_fs(get_ds());               /* Get user space block */
 
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         /* Setup a structure for adding/removing routes */
         memset(&if_info, 0, sizeof(if_info));
         strcpy(if_info.ifr_name, dev->name);
@@ -2099,7 +2784,7 @@
 	case ADD_ROUTE:
 
 		if(!card->u.c.slarp_timer) {
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 			if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
 			if_data2->sin_addr.s_addr = remote_IP_addr;
 			if_data2->sin_family = AF_INET;
@@ -2108,7 +2793,7 @@
                         err = ip_rt_new(&route);
 #endif
 		} else { 
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 			if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
 			if_data1->sin_addr.s_addr = local_IP_addr;
 			if_data1->sin_family = AF_INET;
@@ -2141,7 +2826,7 @@
 
 	case REMOVE_ROUTE:
 	
-#ifdef LINUX_2_1
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 		/* Change the local ip address of the interface to 0.
 		 * This will also delete the destination route.
 		 */
@@ -2179,9 +2864,6 @@
 
         set_fs(fs);                     /* Restore file system */
 
-        /* Once we've processed the route, stop polling */
-        card->poll = NULL;
-
 }
 
 
@@ -2190,7 +2872,7 @@
  */
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, struct net_device* dev,
+                                struct sk_buff *skb, netdevice_t* dev,
                                 chdlc_private_area_t* chdlc_priv_area )
 {
 	int udp_pkt_stored = 0;
@@ -2204,15 +2886,12 @@
 		udp_pkt_stored = 1;
 	}
 
-#ifdef LINUX_2_1
-	dev_kfree_skb(skb);
-#else
-	if(udp_pkt_src == UDP_PKT_FRM_STACK)
-		dev_kfree_skb(skb, FREE_WRITE);
-	else
-                dev_kfree_skb(skb, FREE_READ);
-#endif
-	
+	if(udp_pkt_src == UDP_PKT_FRM_STACK){
+		wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+                wan_dev_kfree_skb(skb, FREE_READ);
+	}
+		
 	return(udp_pkt_stored);
 }
 
@@ -2221,7 +2900,7 @@
  * Process UDP management packet.
  */
 
-static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
+static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,
 				chdlc_private_area_t* chdlc_priv_area ) 
 {
 	unsigned char *buf;
@@ -2240,22 +2919,30 @@
 
 	chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data;
 
-	switch(chdlc_udp_pkt->cblock.command) {
+	if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){
 
-	   	case FT1_MONITOR_STATUS_CTRL:
-		case CPIPE_ENABLE_TRACING:
-	   	case CPIPE_DISABLE_TRACING:
- 	  	case CPIPE_GET_TRACE_INFO:
-	   	case SET_FT1_MODE:
-			if(chdlc_priv_area->udp_pkt_src == 
-				UDP_PKT_FRM_NETWORK) {
-			     udp_mgmt_req_valid = 0;
-       			}	 
-       			break;
-	   
-		default:
-       			break;
-  	} 
+		/* Only these commands are support for remote debugging.
+		 * All others are not */
+		switch(chdlc_udp_pkt->cblock.command) {
+
+			case READ_GLOBAL_STATISTICS:
+			case READ_MODEM_STATUS:  
+			case READ_CHDLC_LINK_STATUS:
+			case CPIPE_ROUTER_UP_TIME:
+			case READ_COMMS_ERROR_STATS:
+			case READ_CHDLC_OPERATIONAL_STATS:
+
+			/* These two commands are executed for
+			 * each request */
+			case READ_CHDLC_CONFIGURATION:
+			case READ_CHDLC_CODE_VERSION:
+				udp_mgmt_req_valid = 1;
+				break;
+			default:
+				udp_mgmt_req_valid = 0;
+				break;
+		} 
+	}
 	
   	if(!udp_mgmt_req_valid) {
 
@@ -2265,6 +2952,12 @@
     		/* set return code */
 		chdlc_udp_pkt->cblock.return_code = 0xCD;
 
+		if (net_ratelimit()){	
+			printk(KERN_INFO 
+			"%s: Warning, Illegal UDP command attempted from network: %x\n",
+			card->devname,chdlc_udp_pkt->cblock.command);
+		}
+
    	} else {
 	   	unsigned long trace_status_cfg_addr = 0;
 		TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct;
@@ -2488,11 +3181,12 @@
 
 			((unsigned char *)chdlc_udp_pkt->data )[1] =
 				flags->FT1_info_struct.parallel_port_B_input;
-				 
+				
 			chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+			chdlc_udp_pkt->cblock.buffer_length = 2;
 			mb->buffer_length = 2;
 			break;
-		
+
 		case CPIPE_ROUTER_UP_TIME:
 			do_gettimeofday( &tv );
 			chdlc_priv_area->router_up_time = tv.tv_sec - 
@@ -2500,6 +3194,8 @@
 			*(unsigned long *)&chdlc_udp_pkt->data = 
 					chdlc_priv_area->router_up_time;	
 			mb->buffer_length = sizeof(unsigned long);
+			chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long);
+			chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
 			break;
 
    		case FT1_MONITOR_STATUS_CTRL:
@@ -2525,8 +3221,10 @@
 		  			break;
 	   	    	     	} 
 	      		} 	
-	
+			goto dflt_1;
+
 		default:
+dflt_1:
 			/* it's a board command */
 			mb->command = chdlc_udp_pkt->cblock.command;
 			mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length;
@@ -2556,12 +3254,19 @@
 
      	len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length);
 	
-     	if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) {
-			++ card->wandev.stats.tx_packets;
-#ifdef LINUX_2_1
-			card->wandev.stats.tx_bytes += len;
+
+     	if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){
+
+		/* Must check if we interrupted if_send() routine. The
+		 * tx buffers might be used. If so drop the packet */
+	   	if (!test_bit(SEND_CRIT,&card->wandev.critical)) {
+		
+			if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) {
+				++ card->wandev.stats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+				card->wandev.stats.tx_bytes += len;
 #endif
+			}
 		}
 	} else {	
 	
@@ -2595,7 +3300,7 @@
  * Initialize Receive and Transmit Buffers.
  */
 
-static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev )
+static void init_chdlc_tx_rx_buff( sdla_t* card)
 {
 	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
 	CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config;
@@ -2607,7 +3312,9 @@
 	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
 
 	if(err != COMMAND_OK) {
-		chdlc_error(card,err,mb);
+		if (card->wandev.dev){
+			chdlc_error(card,err,mb);
+		}
 		return;
 	}
 
@@ -2678,19 +3385,13 @@
  * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR
  * _TEST_COUNTER times.
  */
-static int intr_test( sdla_t* card, struct net_device *dev )
+static int intr_test( sdla_t* card)
 {
 	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
 	int err,i;
 
 	Intr_test_counter = 0;
-
-	/* The critical flag is unset because during intialization (if_open) 
-	 * we want the interrupts to be enabled so that when the wpc_isr is
-	 * called it does not exit due to critical flag set.
-	 */ 
-
-	clear_bit(1, (void*)&card->wandev.critical);
+	
 	err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE);
 
 	if (err == CMD_OK) { 
@@ -2707,8 +3408,6 @@
 	}
 
 	err = chdlc_set_intr_mode(card, 0);
-	set_bit(1, (void*)&card->wandev.critical);
-
 
 	if (err != CMD_OK)
 		return err;
@@ -2723,13 +3422,33 @@
 {
 	 chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data;
 
+#ifdef _WAN_UDP_DEBUG
+		printk(KERN_INFO "SIG %s = %s\n\
+				  UPP %x = %x\n\
+				  PRT %x = %x\n\
+				  REQ %i = %i\n\
+				  36 th = %x 37th = %x\n",
+				  chdlc_udp_pkt->wp_mgmt.signature,
+				  UDPMGMT_SIGNATURE,
+				  chdlc_udp_pkt->udp_pkt.udp_dst_port,
+				  ntohs(card->wandev.udp_port),
+				  chdlc_udp_pkt->ip_pkt.protocol,
+				  UDPMGMT_UDP_PROTOCOL,
+				  chdlc_udp_pkt->wp_mgmt.request_reply,
+				  UDPMGMT_REQUEST,
+				  skb->data[36], skb->data[37]);
+#endif	
+		
 	if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) &&
 	   (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
 	   (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
 	   (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
+
 		return UDP_CPIPE_TYPE;
+
+	}else{ 
+		return UDP_INVALID_TYPE;
 	}
-	else return UDP_INVALID_TYPE;
 }
 
 /*============================================================================
@@ -2744,7 +3463,7 @@
                 case WAN_CONNECTED:
                         printk (KERN_INFO "%s: Link connected!\n",
                                 card->devname);
-                      break;
+                      	break;
 
                 case WAN_CONNECTING:
                         printk (KERN_INFO "%s: Link connecting...\n",
@@ -2758,31 +3477,1268 @@
                 }
 
                 card->wandev.state = card->u.c.state = state;
+		if (card->wandev.dev){
+			netdevice_t *dev = card->wandev.dev;
+			chdlc_private_area_t *chdlc_priv_area = dev->priv;
+			chdlc_priv_area->common.state = state;
+		}
         }
 }
 
-void s508_lock (sdla_t *card, unsigned long *smp_flags)
+/*===========================================================================
+ * config_chdlc
+ *
+ *	Configure the chdlc protocol and enable communications.		
+ *
+ *   	The if_open() function binds this function to the poll routine.
+ *      Therefore, this function will run every time the chdlc interface
+ *      is brought up. We cannot run this function from the if_open 
+ *      because if_open does not have access to the remote IP address.
+ *      
+ *	If the communications are not enabled, proceed to configure
+ *      the card and enable communications.
+ *
+ *      If the communications are enabled, it means that the interface
+ *      was shutdown by ether the user or driver. In this case, we 
+ *      have to check that the IP addresses have not changed.  If
+ *      the IP addresses have changed, we have to reconfigure the firmware
+ *      and update the changed IP addresses.  Otherwise, just exit.
+ *
+ */
+
+static int config_chdlc (sdla_t *card)
 {
-#ifdef CONFIG_SMP
-                spin_lock_irqsave(&card->lock, *smp_flags);
-                if (card->next){
-                        spin_lock(&card->next->lock);
-                }
-#else
-                disable_irq(card->hw.irq);
-#endif                                                                     
+	netdevice_t *dev = card->wandev.dev;
+	chdlc_private_area_t *chdlc_priv_area = dev->priv;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+
+	if (card->u.c.comm_enabled){
+
+		/* Jun 20. 2000: NC
+		 * IP addresses are not used in the API mode */
+		
+		if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local ||
+		     chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && 
+		     card->u.c.usedby == WANPIPE) {
+			
+			/* The IP addersses have changed, we must
+                         * stop the communications and reconfigure
+                         * the card. Reason: the firmware must know
+                         * the local and remote IP addresses. */
+			disable_comm(card);
+			port_set_state(card, WAN_DISCONNECTED);
+			printk(KERN_INFO 
+				"%s: IP addresses changed!\n",
+					card->devname);
+			printk(KERN_INFO 
+				"%s: Restarting communications ...\n",
+					card->devname);
+		}else{ 
+			/* IP addresses are the same and the link is up, 
+                         * we dont have to do anything here. Therefore, exit */
+			return 0;
+		}
+	}
+
+	chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp;
+	chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp;
+
+
+	/* Setup the Board for asynchronous mode */
+	if (card->u.c.async_mode){
+		
+		if (set_asy_config(card)) {
+			printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n",
+				card->devname);
+			return 0;
+		}
+	}else{
+		/* Setup the Board for CHDLC */
+		if (set_chdlc_config(card)) {
+			printk (KERN_INFO "%s: Failed CHDLC configuration!\n",
+				card->devname);
+			return 0;
+		}
+	}
+
+	/* Set interrupt mode and mask */
+        if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
+                		APP_INT_ON_GLOBAL_EXCEP_COND |
+                		APP_INT_ON_TX_FRAME |
+                		APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
+		printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
+				card->devname);
+		return 0;	
+        }
+	
+
+	/* Mask the Transmit and Timer interrupt */
+	flags->interrupt_info_struct.interrupt_permission &= 
+		~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
+
+	/* In TTY mode, receive interrupt will be enabled during
+	 * wanpipe_tty_open() operation */
+	if (card->tty_opt){
+		flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME;
+	}
+
+	/* Enable communications */
+ 	if (card->u.c.async_mode){
+		if (asy_comm_enable(card) != 0) {
+			printk(KERN_INFO "%s: Failed to enable async commnunication!\n",
+					card->devname);
+			flags->interrupt_info_struct.interrupt_permission = 0;
+			card->u.c.comm_enabled=0;
+			chdlc_set_intr_mode(card,0);
+			return 0;
+		}
+        }else{ 
+		if (chdlc_comm_enable(card) != 0) {
+			printk(KERN_INFO "%s: Failed to enable chdlc communications!\n",
+					card->devname);
+			flags->interrupt_info_struct.interrupt_permission = 0;
+			card->u.c.comm_enabled=0;
+			chdlc_set_intr_mode(card,0);
+			return 0;
+		}
+	}
+
+	/* Initialize Rx/Tx buffer control fields */
+	init_chdlc_tx_rx_buff(card);
+	port_set_state(card, WAN_CONNECTING);
+	return 0; 
 }
 
-void s508_unlock (sdla_t *card, unsigned long *smp_flags)
+
+/*============================================================
+ * chdlc_poll
+ *	
+ * Rationale:
+ * 	We cannot manipulate the routing tables, or
+ *      ip addresses withing the interrupt. Therefore
+ *      we must perform such actons outside an interrupt 
+ *      at a later time. 
+ *
+ * Description:	
+ *	CHDLC polling routine, responsible for 
+ *     	shutting down interfaces upon disconnect
+ *     	and adding/removing routes. 
+ *      
+ * Usage:        
+ * 	This function is executed for each CHDLC  
+ * 	interface through a tq_schedule bottom half.
+ *      
+ *      trigger_chdlc_poll() function is used to kick
+ *      the chldc_poll routine.  
+ */
+
+static void chdlc_poll (netdevice_t *dev)
 {
-#ifdef CONFIG_SMP
-                        if (card->next){
-                                spin_unlock(&card->next->lock);
-                        }
-                        spin_unlock_irqrestore(&card->lock, *smp_flags);
-#else
-                        enable_irq(card->hw.irq);
-#endif           
-}
+	chdlc_private_area_t *chdlc_priv_area;
+	sdla_t *card;
+	u8 check_gateway=0;	
+	SHARED_MEMORY_INFO_STRUCT* flags;
+
+	
+	if (!dev || (chdlc_priv_area=dev->priv) == NULL)
+		return;
+
+	card = chdlc_priv_area->card;
+	flags = card->u.c.flags;
+	
+	/* (Re)Configuraiton is in progress, stop what you are 
+	 * doing and get out */
+	if (test_bit(PERI_CRIT,&card->wandev.critical)){
+		clear_bit(POLL_CRIT,&card->wandev.critical);
+		return;
+	}
+	
+	/* if_open() function has triggered the polling routine
+	 * to determine the configured IP addresses.  Once the
+	 * addresses are found, trigger the chdlc configuration */
+	if (test_bit(0,&chdlc_priv_area->config_chdlc)){
+
+		chdlc_priv_area->ip_local_tmp  = get_ip_address(dev,WAN_LOCAL_IP);
+		chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
+	
+	       /* Jun 20. 2000 Bug Fix
+	 	* Only perform this check in WANPIPE mode, since
+	 	* IP addresses are not used in the API mode. */
+	
+		if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && 
+		    card->u.c.slarp_timer == 0x00 && 
+		    !card->u.c.backup && 
+		    card->u.c.usedby == WANPIPE){
+
+			if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){
+				printk(KERN_INFO "\n%s: --- WARNING ---\n",
+						card->devname);
+				printk(KERN_INFO 
+				"%s: The local IP address is the same as the\n",
+						card->devname);
+				printk(KERN_INFO 
+				"%s: Point-to-Point IP address.\n",
+						card->devname);
+				printk(KERN_INFO "%s: --- WARNING ---\n\n",
+						card->devname);
+			}else{
+				clear_bit(POLL_CRIT,&card->wandev.critical);
+				chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ;
+				add_timer(&chdlc_priv_area->poll_delay_timer);
+				return;
+			}
+		}
+
+		clear_bit(0,&chdlc_priv_area->config_chdlc);
+		clear_bit(POLL_CRIT,&card->wandev.critical);
+		
+		chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
+		flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
+		return;
+	}
+	/* Dynamic interface implementation, as well as dynamic
+	 * routing.  */
+	
+	switch (card->u.c.state){
+
+	case WAN_DISCONNECTED:
+
+		/* If the dynamic interface configuration is on, and interface 
+		 * is up, then bring down the netowrk interface */
+		
+		if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && 
+		    !test_bit(DEV_DOWN,  &chdlc_priv_area->interface_down) &&		
+		    card->wandev.dev->flags & IFF_UP){	
+
+			printk(KERN_INFO "%s: Interface %s down.\n",
+				card->devname,card->wandev.dev->name);
+			change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP));
+			set_bit(DEV_DOWN,&chdlc_priv_area->interface_down);
+			chdlc_priv_area->route_status = NO_ROUTE;
+
+		}else{
+			/* We need to check if the local IP address is
+               	  	 * zero. If it is, we shouldn't try to remove it.
+                 	 */
+
+			if (card->wandev.dev->flags & IFF_UP && 
+		    	    get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && 
+		    	    chdlc_priv_area->route_status != NO_ROUTE &&
+			    card->u.c.slarp_timer){
+
+				process_route(card);
+			}
+		}
+		break;
+
+	case WAN_CONNECTED:
+
+		/* In SMP machine this code can execute before the interface
+		 * comes up.  In this case, we must make sure that we do not
+		 * try to bring up the interface before dev_open() is finished */
+
+
+		/* DEV_DOWN will be set only when we bring down the interface
+		 * for the very first time. This way we know that it was us
+		 * that brought the interface down */
+		
+		if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) &&
+		    test_bit(DEV_DOWN,  &chdlc_priv_area->interface_down) &&
+		    !(card->wandev.dev->flags & IFF_UP)){
+			
+			printk(KERN_INFO "%s: Interface %s up.\n",
+				card->devname,card->wandev.dev->name);
+			change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP));
+			clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down);
+			check_gateway=1;
+		}
+
+		if (chdlc_priv_area->route_status == ADD_ROUTE && 
+		    card->u.c.slarp_timer){ 
+
+			process_route(card);
+			check_gateway=1;
+		}
+
+		if (chdlc_priv_area->gateway && check_gateway)
+			add_gateway(card,dev);
+
+		break;
+	}	
+
+	clear_bit(POLL_CRIT,&card->wandev.critical);
+}
+
+/*============================================================
+ * trigger_chdlc_poll
+ *
+ * Description:
+ * 	Add a chdlc_poll() task into a tq_scheduler bh handler
+ *      for a specific dlci/interface.  This will kick
+ *      the fr_poll() routine at a later time. 
+ *
+ * Usage:
+ * 	Interrupts use this to defer a taks to 
+ *      a polling routine.
+ *
+ */	
+static void trigger_chdlc_poll (netdevice_t *dev)
+{
+	chdlc_private_area_t *chdlc_priv_area;
+	sdla_t *card;
+
+	if (!dev)
+		return;
+	
+	if ((chdlc_priv_area = dev->priv)==NULL)
+		return;
+
+	card = chdlc_priv_area->card;
+	
+	if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){
+		return;
+	}
+	if (test_bit(PERI_CRIT,&card->wandev.critical)){
+		return; 
+	}
+#ifdef LINUX_2_4
+	schedule_task(&chdlc_priv_area->poll_task);
+#else
+	queue_task(&chdlc_priv_area->poll_task, &tq_scheduler);
+#endif
+	return;
+}
+
+
+static void chdlc_poll_delay (unsigned long dev_ptr)
+{
+	netdevice_t *dev = (netdevice_t *)dev_ptr;
+	trigger_chdlc_poll(dev);
+}
+
+
+void s508_lock (sdla_t *card, unsigned long *smp_flags)
+{
+#if defined(__SMP__) || defined(LINUX_2_4)
+	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
+        if (card->next){
+        	spin_lock(&card->next->wandev.lock);
+	}
+#else
+        disable_irq(card->hw.irq);
+#endif                                                                     
+}
+
+void s508_unlock (sdla_t *card, unsigned long *smp_flags)
+{
+#if defined(__SMP__) || defined(LINUX_2_4)
+        if (card->next){
+        	spin_unlock(&card->next->wandev.lock);
+        }
+        spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
+#else
+        enable_irq(card->hw.irq);
+#endif           
+}
+
+//*********** TTY SECTION ****************
+#if defined(LINUX_2_4) || defined(LINUX_2_1)
+
+static void wanpipe_tty_trigger_tx_irq(sdla_t *card)
+{
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
+	chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
+}
+
+static void wanpipe_tty_trigger_poll(sdla_t *card)
+{
+#ifdef LINUX_2_4
+	schedule_task(&card->tty_task_queue);
+#else
+	queue_task(&card->tty_task_queue, &tq_scheduler);
+#endif
+}
+
+static void tty_poll_task (void* data)
+{
+	sdla_t *card = (sdla_t*)data;
+	struct tty_struct *tty;
+
+	if ((tty=card->tty)==NULL)
+		return;
+	
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup){
+		(tty->ldisc.write_wakeup)(tty);
+	}
+	wake_up_interruptible(&tty->write_wait);
+#if defined(SERIAL_HAVE_POLL_WAIT) || \
+         (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
+	wake_up_interruptible(&tty->poll_wait);
+#endif	
+	return;
+}
+
+static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp)
+{
+	sdla_t *card;
+	unsigned long smp_flags;
+	
+	if (!tty || !tty->driver_data){
+		return;
+	}
+	
+	card = (sdla_t*)tty->driver_data;
+	
+	if (!card)
+		return;
+
+	printk(KERN_INFO "%s: Closing TTY Driver!\n",
+			card->devname);
+
+	/* Sanity Check */
+	if (!card->tty_open)
+		return;
+	
+	wanpipe_close(card);
+	if (--card->tty_open == 0){
+
+		lock_adapter_irq(&card->wandev.lock,&smp_flags);	
+		card->tty=NULL;
+		chdlc_disable_comm_shutdown(card);
+		unlock_adapter_irq(&card->wandev.lock,&smp_flags);
+
+		if (card->tty_buf){
+			kfree(card->tty_buf);
+			card->tty_buf=NULL;			
+		}
+
+		if (card->tty_rx){
+			kfree(card->tty_rx);
+			card->tty_rx=NULL;
+		}
+	}
+	return;
+}
+static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp)
+{
+	unsigned long smp_flags;
+	sdla_t *card;
+	
+	if (!tty){
+		return -ENODEV;
+	}
+	
+	if (!tty->driver_data){
+		int port;
+		port = MINOR(tty->device) - tty->driver.minor_start;
+		if ((port < 0) || (port >= NR_PORTS)) 
+			return -ENODEV;
+		
+		tty->driver_data = WAN_CARD(port);
+		if (!tty->driver_data)
+			return -ENODEV;
+	}
+
+	card = (sdla_t*)tty->driver_data;
+
+	if (!card){
+		lock_adapter_irq(&card->wandev.lock,&smp_flags);	
+		card->tty=NULL;
+		unlock_adapter_irq(&card->wandev.lock,&smp_flags);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "%s: Opening TTY Driver!\n",
+			card->devname);
+
+	if (card->tty_open == 0){
+		lock_adapter_irq(&card->wandev.lock,&smp_flags);	
+		card->tty=tty;
+		unlock_adapter_irq(&card->wandev.lock,&smp_flags);
+
+		if (!card->tty_buf){
+			card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL);
+			if (!card->tty_buf){
+				card->tty_buf=NULL;
+				card->tty=NULL;
+				return -ENOMEM;	
+			}
+		}
+
+		if (!card->tty_rx){
+			card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL);
+			if (!card->tty_rx){
+				/* Free the buffer above */
+				kfree(card->tty_buf);
+				card->tty_buf=NULL;
+				card->tty=NULL;
+				return -ENOMEM;	
+			}
+		}
+	}
+
+	++card->tty_open;
+	wanpipe_open(card);
+	return 0;
+}
+
+static int wanpipe_tty_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	unsigned long smp_flags=0;
+	sdla_t *card=NULL;
+
+	if (!tty){
+		dbg_printk(KERN_INFO "NO TTY in Write\n");
+		return -ENODEV;
+	}
+
+	card = (sdla_t *)tty->driver_data;
+			
+	if (!card){
+		dbg_printk(KERN_INFO "No Card in TTY Write\n");
+		return -ENODEV;
+	}	
+
+	if (count > card->wandev.mtu){
+		dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n",
+				count,card->wandev.mtu);
+		return -EINVAL;
+	}
+	
+	if (card->wandev.state != WAN_CONNECTED){
+		dbg_printk(KERN_INFO "Card not connected in TTY Write\n");
+		return -EINVAL;
+	}
+
+	/* Lock the 508 Card: SMP is supported */
+      	if(card->hw.type != SDLA_S514){
+		s508_lock(card,&smp_flags);
+	} 
+	
+	if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){
+		printk(KERN_INFO "%s: Critical in TTY Write\n",
+				card->devname);
+		
+		/* Lock the 508 Card: SMP is supported */
+		if(card->hw.type != SDLA_S514)
+			s508_unlock(card,&smp_flags);
+		
+		return -EINVAL; 
+	}
+	
+	if (from_user) {
+		
+		unsigned char *tmp_buf;
+		
+		if ((tmp_buf=card->tty_buf)==NULL){
+			dbg_printk(KERN_INFO "No TTY BUF in Write\n");
+			
+			clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+			
+			if(card->hw.type != SDLA_S514)
+				s508_unlock(card,&smp_flags);
+			
+			return -ENOMEM;
+		}
+		
+		if (copy_from_user(tmp_buf,buf,count)){
+			dbg_printk(KERN_INFO "%s: Failed to copy from user!\n",
+					card->devname);
+			
+			clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+			
+			if(card->hw.type != SDLA_S514)
+				s508_unlock(card,&smp_flags);
+			
+			return -EINVAL;
+		}
+
+		if (chdlc_send(card,(void*)tmp_buf,count)){
+			dbg_printk(KERN_INFO "%s: Failed to send, retry later: user!\n",
+					card->devname);
+			
+			clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+			
+			wanpipe_tty_trigger_tx_irq(card);
+			
+			if(card->hw.type != SDLA_S514)
+				s508_unlock(card,&smp_flags);
+			return 0;
+		}
+
+	}else{
+	 	if (chdlc_send(card,(void*)buf,count)){
+			dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n",
+					card->devname);
+			clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+	
+			wanpipe_tty_trigger_tx_irq(card);
+			
+			if(card->hw.type != SDLA_S514)
+				s508_unlock(card,&smp_flags);
+			return 0;
+		}
+	}
+	dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count);
+	clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+	
+	if(card->hw.type != SDLA_S514)
+		s508_unlock(card,&smp_flags);
+
+	return count;
+}
+
+static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len)
+{
+	unsigned offset=0;
+	unsigned olen=len;
+	char fp=0;
+	struct tty_struct *tty;
+	int i;
+	
+	if (!card->tty_open){
+		dbg_printk(KERN_INFO "%s: TTY not open during receive\n",
+				card->devname);
+		return;
+	}
+	
+	if ((tty=card->tty) == NULL){
+		dbg_printk(KERN_INFO "%s: No TTY on receive\n",
+				card->devname);
+		return;
+	}
+	
+	if (!tty->driver_data){
+		dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n",
+				card->devname);
+		return;
+	}
+	
+
+	if (card->u.c.async_mode){
+		if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){
+			if (net_ratelimit()){
+				printk(KERN_INFO 
+					"%s: Received packet size too big: %i bytes, Max: %i!\n",
+					card->devname,len,TTY_FLIPBUF_SIZE);
+			}
+			return;
+		}
+
+		
+		if((addr + len) > card->u.c.rx_top + 1) {
+			offset = card->u.c.rx_top - addr + 1;
+			
+			sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset);
+			
+			addr = card->u.c.rx_base;
+			len -= offset;
+			
+			tty->flip.char_buf_ptr+=offset;
+			tty->flip.count+=offset;
+			for (i=0;i<offset;i++){
+				*tty->flip.flag_buf_ptr = 0;
+				tty->flip.flag_buf_ptr++;
+			}
+		}
+		
+		sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len);
+			
+		tty->flip.char_buf_ptr+=len;
+		card->tty->flip.count+=len;
+		for (i=0;i<len;i++){
+			*tty->flip.flag_buf_ptr = 0;
+			tty->flip.flag_buf_ptr++;
+		}
+
+		tty->low_latency=1;
+		tty_flip_buffer_push(tty);
+	}else{
+		if (!card->tty_rx){	
+			if (net_ratelimit()){
+				printk(KERN_INFO 
+				"%s: Receive sync buffer not available!\n",
+				 card->devname);
+			}
+			return;
+		}
+	
+		if (len > TTY_CHDLC_MAX_MTU){
+			if (net_ratelimit()){
+				printk(KERN_INFO 
+				"%s: Received packet size too big: %i bytes, Max: %i!\n",
+					card->devname,len,TTY_FLIPBUF_SIZE);
+			}
+			return;
+		}
+
+		
+		if((addr + len) > card->u.c.rx_top + 1) {
+			offset = card->u.c.rx_top - addr + 1;
+			
+			sdla_peek(&card->hw, addr, card->tty_rx, offset);
+			
+			addr = card->u.c.rx_base;
+			len -= offset;
+		}
+		sdla_peek(&card->hw, addr, card->tty_rx+offset, len);
+		if (tty->ldisc.receive_buf){
+			tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen);
+		}else{
+			if (net_ratelimit()){
+				printk(KERN_INFO 
+					"%s: NO TTY Sync line discipline!\n",
+					card->devname);
+			}
+		}
+	}
+
+	dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen);
+	return;
+}
+
+#if 0
+static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+#endif
+
+static void wanpipe_tty_stop(struct tty_struct *tty)
+{
+	return;
+}
+
+static void wanpipe_tty_start(struct tty_struct *tty)
+{
+	return;
+}
+
+static int config_tty (sdla_t *card)
+{
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+
+	/* Setup the Board for asynchronous mode */
+	if (card->u.c.async_mode){
+		
+		if (set_asy_config(card)) {
+			printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n",
+				card->devname);
+			return -EINVAL;
+		}
+	}else{
+		/* Setup the Board for CHDLC */
+		if (set_chdlc_config(card)) {
+			printk (KERN_INFO "%s: Failed CHDLC configuration!\n",
+				card->devname);
+			return -EINVAL;
+		}
+	}
+
+	/* Set interrupt mode and mask */
+        if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
+                		APP_INT_ON_GLOBAL_EXCEP_COND |
+                		APP_INT_ON_TX_FRAME |
+                		APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
+		printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
+				card->devname);
+		return -EINVAL;	
+        }
+	
+
+	/* Mask the Transmit and Timer interrupt */
+	flags->interrupt_info_struct.interrupt_permission &= 
+		~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
+
+	
+	/* Enable communications */
+ 	if (card->u.c.async_mode){
+		if (asy_comm_enable(card) != 0) {
+			printk(KERN_INFO "%s: Failed to enable async commnunication!\n",
+					card->devname);
+			flags->interrupt_info_struct.interrupt_permission = 0;
+			card->u.c.comm_enabled=0;
+			chdlc_set_intr_mode(card,0);
+			return -EINVAL;
+		}
+        }else{ 
+		if (chdlc_comm_enable(card) != 0) {
+			printk(KERN_INFO "%s: Failed to enable chdlc communications!\n",
+					card->devname);
+			flags->interrupt_info_struct.interrupt_permission = 0;
+			card->u.c.comm_enabled=0;
+			chdlc_set_intr_mode(card,0);
+			return -EINVAL;
+		}
+	}
+
+	/* Initialize Rx/Tx buffer control fields */
+	init_chdlc_tx_rx_buff(card);
+	port_set_state(card, WAN_CONNECTING);
+	return 0; 
+}
+
+
+static int change_speed(sdla_t *card, struct tty_struct *tty,
+			 struct termios *old_termios)
+{
+	int	baud, ret=0;
+	unsigned cflag; 
+	int	dbits,sbits,parity,handshaking;
+
+	cflag = tty->termios->c_cflag;
+
+	/* There is always one stop bit */
+	sbits=WANOPT_ONE;
+	
+	/* Parity is defaulted to NONE */
+	parity = WANOPT_NONE;
+
+	handshaking=0;
+	
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	      case CS5: dbits = 5; break;
+	      case CS6: dbits = 6; break;
+	      case CS7: dbits = 7; break;
+	      case CS8: dbits = 8; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      default:  dbits = 8; break;
+	}
+	
+	/* One more stop bit should be supported, thus increment
+	 * the number of stop bits Max=2 */
+	if (cflag & CSTOPB) {
+		sbits = WANOPT_TWO;
+	}
+	if (cflag & PARENB) {
+		parity = WANOPT_EVEN;
+	}
+	if (cflag & PARODD){
+		parity = WANOPT_ODD;
+	}
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(tty);
+
+	if (!baud)
+		baud = 9600;	/* B0 transition handled in rs_set_termios */
+
+	if (cflag & CRTSCTS) {
+		handshaking|=ASY_RTS_HS_FOR_RX;
+	}
+	
+	if (I_IGNPAR(tty))
+		parity = WANOPT_NONE;
+
+	if (I_IXOFF(tty)){
+		handshaking|=ASY_XON_XOFF_HS_FOR_RX;
+		handshaking|=ASY_XON_XOFF_HS_FOR_TX;
+	}
+
+	if (I_IXON(tty)){
+		handshaking|=ASY_XON_XOFF_HS_FOR_RX;
+		handshaking|=ASY_XON_XOFF_HS_FOR_TX;
+	}
+
+	if (card->u.c.async_mode){
+		if (card->wandev.bps != baud)
+			ret=1;
+		card->wandev.bps = baud;
+	}
+
+	if (card->u.c.async_mode){
+		if (card->u.c.protocol_options != handshaking)
+			ret=1;
+		card->u.c.protocol_options = handshaking;
+
+		if (card->u.c.tx_bits_per_char != dbits)
+			ret=1;
+		card->u.c.tx_bits_per_char = dbits;
+
+		if (card->u.c.rx_bits_per_char != dbits)
+			ret=1;
+		card->u.c.rx_bits_per_char = dbits;
+		
+		if (card->u.c.stop_bits != sbits)
+			ret=1;
+		card->u.c.stop_bits = sbits;
+
+		if (card->u.c.parity != parity)
+			ret=1;
+		card->u.c.parity = parity;	
+
+		card->u.c.break_timer = 50;
+		card->u.c.inter_char_timer = 10;
+		card->u.c.rx_complete_length = 100;
+		card->u.c.xon_char = 0xFE;
+	}else{
+		card->u.c.protocol_options = HDLC_STREAMING_MODE;
+	}
+	
+	return ret;
+}
+
+	
+static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	sdla_t *card;
+	int err=1;
+
+	if (!tty){
+		return;
+	}
+
+	card = (sdla_t *)tty->driver_data;
+			
+	if (!card)
+		return;
+
+	if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){
+		unsigned long smp_flags;
+		
+		if (card->u.c.comm_enabled){
+			lock_adapter_irq(&card->wandev.lock,&smp_flags);
+			chdlc_disable_comm_shutdown(card);
+			unlock_adapter_irq(&card->wandev.lock,&smp_flags);
+		}
+		lock_adapter_irq(&card->wandev.lock,&smp_flags);
+		err = config_tty(card);
+		unlock_adapter_irq(&card->wandev.lock,&smp_flags);
+		if (card->u.c.async_mode){
+			printk(KERN_INFO "%s: TTY Async Configuration:\n"
+				 "   Baud        =%i\n"
+				 "   Handshaking =%s\n"
+				 "   Tx Dbits    =%i\n"
+				 "   Rx Dbits    =%i\n"
+				 "   Parity      =%s\n"
+				 "   Stop Bits   =%i\n",
+				 card->devname,
+				 card->wandev.bps,
+				 opt_decode[card->u.c.protocol_options],
+				 card->u.c.tx_bits_per_char,
+				 card->u.c.rx_bits_per_char,
+				 p_decode[card->u.c.parity] ,
+				 card->u.c.stop_bits);
+		}else{
+			printk(KERN_INFO "%s: TTY Sync Configuration:\n"
+				 "   Baud        =%i\n"
+				 "   Protocol    =HDLC_STREAMING\n",
+				 card->devname,card->wandev.bps);
+		}
+		if (!err){
+			port_set_state(card,WAN_CONNECTED);
+		}else{
+			port_set_state(card,WAN_DISCONNECTED);
+		}
+	}
+	return;
+}
+
+static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	sdla_t *card;
+	unsigned long smp_flags=0;
+
+	if (!tty){
+		return;
+	}
+	
+	card = (sdla_t *)tty->driver_data;
+			
+	if (!card)
+		return;
+
+	if (card->wandev.state != WAN_CONNECTED)
+		return;
+
+	if(card->hw.type != SDLA_S514)
+		s508_lock(card,&smp_flags);
+	
+	if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){
+		
+		wanpipe_tty_trigger_tx_irq(card);
+
+		if(card->hw.type != SDLA_S514)
+			s508_unlock(card,&smp_flags);
+		return;
+	}
+
+	if (chdlc_send(card,(void*)&ch,1)){
+		wanpipe_tty_trigger_tx_irq(card);
+		dbg_printk("%s: Failed to TX char!\n",card->devname);
+	}
+	
+	dbg_printk("%s: Char TX OK\n",card->devname);
+	
+	clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+	
+	if(card->hw.type != SDLA_S514)
+		s508_unlock(card,&smp_flags);
+	
+	return;
+}
+
+static void wanpipe_tty_flush_chars(struct tty_struct *tty)
+{
+	return;
+}
+
+static void wanpipe_tty_flush_buffer(struct tty_struct *tty)
+{
+	if (!tty)
+		return;
+	
+	wake_up_interruptible(&tty->write_wait);
+#if defined(SERIAL_HAVE_POLL_WAIT) || \
+         (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
+	wake_up_interruptible(&tty->poll_wait);
+#endif
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	return;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+	return;
+}
+
+
+static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0;
+}
+
+
+static int wanpipe_tty_write_room(struct tty_struct *tty)
+{
+	sdla_t *card;
+
+	printk(KERN_INFO "TTY Write Room\n");
+	
+	if (!tty){
+		return 0;
+	}
+
+	card = (sdla_t *)tty->driver_data;
+	if (!card)
+		return 0;
+
+	if (card->wandev.state != WAN_CONNECTED)
+		return 0;
+	
+	return SEC_MAX_NO_DATA_BYTES_IN_FRAME;
+}
+
+
+static int set_modem_status(sdla_t *card, unsigned char data)
+{
+	CHDLC_MAILBOX_STRUCT *mb = card->mbox;
+	int err;
+
+	mb->buffer_length=1;
+	mb->command=SET_MODEM_STATUS;
+	mb->data[0]=data;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK) 
+		chdlc_error (card, err, mb);
+	
+	return err;
+}
+
+static void wanpipe_tty_hangup(struct tty_struct *tty)
+{
+	sdla_t *card;
+	unsigned long smp_flags;
+
+	printk(KERN_INFO "TTY Hangup!\n");
+	
+	if (!tty){
+		return;
+	}
+
+	card = (sdla_t *)tty->driver_data;
+	if (!card)
+		return;
+
+	lock_adapter_irq(&card->wandev.lock,&smp_flags);
+	set_modem_status(card,0);
+	unlock_adapter_irq(&card->wandev.lock,&smp_flags);
+	return;
+}
+
+static void wanpipe_tty_break(struct tty_struct *tty, int break_state)
+{
+	return;
+}
+
+static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	return;
+}
+
+static void wanpipe_tty_throttle(struct tty_struct * tty)
+{
+	return;
+}
+
+static void wanpipe_tty_unthrottle(struct tty_struct * tty)
+{
+	return;
+}
+
+int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	return 0;
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+int wanpipe_tty_init(sdla_t *card)
+{
+	struct serial_state * state;
+	
+	/* Initialize the tty_driver structure */
+
+	if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){
+		printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n",
+				card->devname,card->tty_minor);
+		return -EINVAL;
+	}
+
+	if (WAN_CARD(card->tty_minor)){
+		printk(KERN_INFO "%s: TTY Minor %i, already in use\n",
+				card->devname,card->tty_minor);
+		return -EBUSY;
+	}
+
+	if (tty_init_cnt==0){
+		
+		printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n",
+				card->devname,
+				card->u.c.async_mode ? "ASYNC" : "SYNC",
+				WAN_TTY_MAJOR,MIN_PORT,MAX_PORT);
+		
+		tty_driver_mode = card->u.c.async_mode;
+		
+		memset(&serial_driver, 0, sizeof(struct tty_driver));
+		serial_driver.magic = TTY_DRIVER_MAGIC;
+		serial_driver.driver_name = "wanpipe_tty"; 
+		serial_driver.name = "ttyW";
+		serial_driver.major = WAN_TTY_MAJOR;
+		serial_driver.minor_start = WAN_TTY_MINOR;
+		serial_driver.num = NR_PORTS; 
+		serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+		serial_driver.subtype = SERIAL_TYPE_NORMAL;
+		
+		serial_driver.init_termios = tty_std_termios;
+		serial_driver.init_termios.c_cflag =
+			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+		serial_driver.flags = TTY_DRIVER_REAL_RAW;
+		
+		serial_driver.refcount = &serial_refcount;
+		serial_driver.table = serial_table;
+		serial_driver.termios = serial_termios;
+		serial_driver.termios_locked = serial_termios_locked;
+
+		serial_driver.open = wanpipe_tty_open;
+		serial_driver.close = wanpipe_tty_close;
+		serial_driver.write = wanpipe_tty_write;
+		
+		serial_driver.put_char = wanpipe_tty_put_char;
+		serial_driver.flush_chars = wanpipe_tty_flush_chars;
+		serial_driver.write_room = wanpipe_tty_write_room;
+		serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer;
+		serial_driver.flush_buffer = wanpipe_tty_flush_buffer;
+		//serial_driver.ioctl = wanpipe_tty_ioctl;
+		serial_driver.throttle = wanpipe_tty_throttle;
+		serial_driver.unthrottle = wanpipe_tty_unthrottle;
+		serial_driver.send_xchar = wanpipe_tty_send_xchar;
+		serial_driver.set_termios = wanpipe_tty_set_termios;
+		serial_driver.stop = wanpipe_tty_stop;
+		serial_driver.start = wanpipe_tty_start;
+		serial_driver.hangup = wanpipe_tty_hangup;
+		serial_driver.break_ctl = wanpipe_tty_break;
+		serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent;
+		serial_driver.read_proc = wanpipe_tty_read_proc;
+		
+		/*
+		 * The callout device is just like normal device except for
+		 * major number and the subtype code.
+		 */
+		callout_driver = serial_driver;
+		callout_driver.name = "cuw";
+		callout_driver.major = TTYAUX_MAJOR;
+		callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+		callout_driver.read_proc = 0;
+		callout_driver.proc_entry = 0;
+
+		if (tty_register_driver(&serial_driver)){
+			printk(KERN_INFO "%s: Failed to register serial driver!\n",
+					card->devname);
+		}
+
+		if (tty_register_driver(&callout_driver)){
+			printk(KERN_INFO "%s: Failed to register callout driver!\n",
+					card->devname);
+		}
+
+	}
+
+
+	/* The subsequent ports must comply to the initial configuration */
+	if (tty_driver_mode != card->u.c.async_mode){
+		printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n",
+				card->devname);
+		printk(KERN_INFO "%s: The TTY driver is configured for %s!\n",
+				card->devname, tty_driver_mode ? "ASYNC" : "SYNC");
+		return -EINVAL;
+	}
+	
+	tty_init_cnt++;
+	
+	printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n",
+			card->devname,
+			tty_driver_mode ? "ASYNC" : "SYNC",
+			card->tty_minor);
+	
+	tty_card_map[card->tty_minor] = card;
+	state = &rs_table[card->tty_minor];
+	
+	state->magic = SSTATE_MAGIC;
+	state->line = 0;
+	state->type = PORT_UNKNOWN;
+	state->custom_divisor = 0;
+	state->close_delay = 5*HZ/10;
+	state->closing_wait = 30*HZ;
+	state->callout_termios = callout_driver.init_termios;
+	state->normal_termios = serial_driver.init_termios;
+	state->icount.cts = state->icount.dsr = 
+		state->icount.rng = state->icount.dcd = 0;
+	state->icount.rx = state->icount.tx = 0;
+	state->icount.frame = state->icount.parity = 0;
+	state->icount.overrun = state->icount.brk = 0;
+	state->irq = card->wandev.irq; 
+
+	card->tty_task_queue.routine = tty_poll_task;
+	card->tty_task_queue.data = (void*)card;
+	return 0;
+}
+
+#endif
+
 
 /****** End ****************************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.4.3/linux/drivers/net/wan/sdla_fr.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/sdla_fr.c	Fri Apr 20 11:54:22 2001
@@ -4,14 +4,43 @@
 * Author(s):	Nenad Corbic  <ncorbic@sangoma.com>
 *		Gideon Hack
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2001 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* Feb 28, 2000  Jeff Garzik	o softnet updates
+* Nov 23, 2000  Nenad Corbic    o Added support for 2.4.X kernels
+* Nov 15, 2000  David Rokavarg  
+*               Nenad Corbic	o Added frame relay bridging support.
+* 				  Original code from Mark Wells and Kristian Hoffmann has
+* 				  been integrated into the frame relay driver.
+* Nov 13, 2000  Nenad Corbic    o Added true interface type encoding option.
+* 				  Tcpdump doesn't support Frame Relay inteface
+* 				  types, to fix this true type option will set
+* 				  the interface type to RAW IP mode.
+* Nov 07, 2000  Nenad Corbic	o Added security features for UDP debugging:
+*                                 Deny all and specify allowed requests.
+* Nov 06, 2000  Nenad Corbic	o Wanpipe interfaces conform to raw packet interfaces.  
+*                                 Moved the if_header into the if_send() routine.
+*                                 The if_header() was breaking the libpcap 
+*                                 support. i.e. support for tcpdump, ethereal ...
+* Oct 12. 2000  Nenad Corbic    o Added error message in fr_configure
+* Jul 31, 2000  Nenad Corbic	o Fixed the Router UP Time.
+* Apr 28, 2000  Nenad Corbic	o Added the option to shutdown an interface
+*                                 when the channel gets disconnected.
+* Apr 28, 2000  Nenad Corbic 	o Added M.Grants patch: disallow duplicate
+*                                 interface setups. 
+* Apr 25, 2000  Nenad Corbic	o Added M.Grants patch: dynamically add/remove 
+*                                 new dlcis/interfaces.
+* Mar 23, 2000  Nenad Corbic 	o Improved task queue, bh handling.
+* Mar 16, 2000	Nenad Corbic	o Added Inverse ARP support
+* Mar 13, 2000  Nenad Corbic	o Added new socket API support.
+* Mar 06, 2000  Nenad Corbic	o Bug Fix: corrupted mbox recovery.
+* Feb 24, 2000  Nenad Corbic    o Fixed up FT1 UDP debugging problem.
+* Dev 15, 1999  Nenad Corbic    o Fixed up header files for 2.0.X kernels
+*
 * Nov 08, 1999  Nenad Corbic    o Combined all debug UDP calls into one function
 *                               o Removed the ARP support. This has to be done
 *                                 in the next version.
@@ -109,12 +138,12 @@
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
-#include <linux/config.h>
+#include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
@@ -123,14 +152,29 @@
 #include <linux/time.h>	 	/* for do_gettimeofday */	
 #include <linux/in.h>		/* sockaddr_in */
 #include <linux/inet.h>		/* in_ntoa(), etc... */
-#include <asm/uaccess.h>
-#include <linux/inetdevice.h>
+#include <asm/errno.h>
+
 #include <linux/ip.h>
-#include <net/route.h>          /* Dynamic Route Creation */
 #include <linux/if.h>
 
-#include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
- 
+#include <linux/if_wanpipe_common.h>	/* Wanpipe Socket */
+#include <linux/if_wanpipe.h>	
+
+#include <linux/sdla_fr.h>		/* frame relay firmware API definitions */
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ #include <asm/uaccess.h>
+ #include <linux/inetdevice.h>
+ #include <linux/netdevice.h>
+
+#else
+ #include <asm/segment.h>
+#endif
+
+#include <net/route.h>          	/* Dynamic Route Creation */
+#include <linux/etherdevice.h>		/* eth_type_trans() used for bridging */
+#include <linux/random.h>
+
 /****** Defines & Macros ****************************************************/
 
 #define	MAX_CMD_RETRY	10		/* max number of firmware retries */
@@ -151,25 +195,20 @@
 #define CIR_ENABLED	0x00
 #define CIR_DISABLED	0x01
 
-#define WANPIPE 0x00
-#define API     0x01
 #define FRAME_RELAY_API 1
-
-#define TX_TIMEOUT	(5*HZ)
+#define MAX_BH_BUFF	10
 
 /* For handle_IPXWAN() */
 #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
  
 /****** Data Structures *****************************************************/
 
-/* This is an extention of the 'struct net_device' we create for each network
+/* This is an extention of the 'struct device' we create for each network
  * interface to keep the rest of channel-specific data.
  */
 typedef struct fr_channel
 {
-	/* This member must be first. */
-	struct net_device *slave;	/* WAN slave */
-
+	wanpipe_common_t common;
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
 	unsigned dlci_configured  ;	/* check whether configured or not */
 	unsigned cir_status;		/* check whether CIR enabled or not */
@@ -183,7 +222,6 @@
 	unsigned long router_start_time;/* Router start time in seconds */
 	unsigned long tick_counter;	/* counter for transmit time out */
 	char dev_pending_devtint;	/* interface pending dev_tint() */
-	char state;			/* channel state */
 	void *dlci_int_interface;	/* pointer to the DLCI Interface */ 
 	unsigned long IB_addr;		/* physical address of Interface Byte */
 	unsigned long state_tick;	/* time of the last state change */
@@ -192,19 +230,52 @@
 	sdla_t *card;			/* -> owner */
 	unsigned route_flag;		/* Add/Rem dest addr in route tables */
 	unsigned inarp;			/* Inverse Arp Request status */ 
+	unsigned char inarp_ready;	/* Ready to send requests */
 	int inarp_interval;		/* Time between InArp Requests */
 	unsigned long inarp_tick;	/* InArp jiffies tick counter */
+	unsigned char interface_down;	/* Bring interface down on disconnect */
+      #if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct net_device_stats ifstats;	/* interface statistics */
+      #else
+	struct enet_statistics ifstats;
+      #endif	
 	if_send_stat_t drvstats_if_send;
         rx_intr_stat_t drvstats_rx_intr;
         pipe_mgmt_stat_t drvstats_gen;
-
-	unsigned char usedby;  /* Used by WANPIPE or API */
-
 	unsigned long router_up_time;
 
 	unsigned short transmit_length;
-	char transmit_buffer[FR_MAX_NO_DATA_BYTES_IN_FRAME];
+	struct sk_buff *delay_skb;
+
+
+      #if defined(LINUX_2_1) || defined(LINUX_2_4)
+	bh_data_t *bh_head;	  	  /* Circular buffer for chdlc_bh */
+	unsigned long  tq_working;
+	volatile int  bh_write;
+	volatile int  bh_read;
+	atomic_t  bh_buff_used;
+      #endif
+
+	/* Polling task queue. Each interface
+         * has its own task queue, which is used
+         * to defer events from the interrupt */
+	struct tq_struct fr_poll_task;
+	struct timer_list fr_arp_timer;
+
+	u32 ip_local;
+	u32 ip_remote;
+	u8  config_dlci;
+	u32 unconfig_dlci;
+
+	/* Whether this interface should be setup as a gateway.
+	 * Used by dynamic route setup code */
+	u8  gateway;
+
+	/* True interface type */
+	u8 true_if_encoding;
+	u8 fr_header[FR_HEADER_LEN];
+	char fr_header_len;
+
 } fr_channel_t;
 
 /* Route Flag options */
@@ -212,6 +283,7 @@
 #define ADD_ROUTE 	0x01
 #define ROUTE_ADDED	0x02
 #define REMOVE_ROUTE 	0x03
+#define ARP_REQ		0x04
 
 /* inarp options */
 #define INARP_NONE		0x00
@@ -221,6 +293,10 @@
 /* reasons for enabling the timer interrupt on the adapter */
 #define TMR_INT_ENABLED_UDP   	0x01
 #define TMR_INT_ENABLED_UPDATE 	0x02
+#define TMR_INT_ENABLED_ARP	0x04
+#define TMR_INT_ENABLED_UPDATE_STATE 	0x08
+#define TMR_INT_ENABLED_CONFIG	0x10
+#define TMR_INT_ENABLED_UNCONFIG	0x20
 
 
 typedef struct dlci_status
@@ -248,7 +324,6 @@
 /* variable for keeping track of enabling/disabling FT1 monitor status */
 static int rCount = 0;
 
-extern int ip_rt_ioctl(unsigned int, void *);
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
@@ -256,27 +331,43 @@
  * interrupt test routine 
  */
 static int Intr_test_counter;
+
 /****** Function Prototypes *************************************************/
 
 /* WAN link driver entry points. These are called by the WAN router module. */
 static int update(wan_device_t *wandev);
-static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf);
-static int del_if(wan_device_t *wandev, struct net_device *dev);
+static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf);
+static int del_if(wan_device_t *wandev, netdevice_t *dev);
+static void disable_comm (sdla_t *card);
 
 /* WANPIPE-specific entry points */
 static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
 
 /* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
-static int if_rebuild_hdr(struct sk_buff *skb);
-static int if_send(struct sk_buff *skb, struct net_device *dev);
-static void if_tx_timeout (struct net_device *dev);
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
+static int if_init(netdevice_t *dev);
+static int if_open(netdevice_t *dev);
+static int if_close(netdevice_t *dev);
+
+
+#ifdef LINUX_2_4
+static void if_tx_timeout (netdevice_t *dev);
+#endif
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static int if_rebuild_hdr (struct sk_buff *skb);
+#else
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
+        struct sk_buff* skb);
+#endif
+
+static int if_send(struct sk_buff *skb, netdevice_t *dev);
+static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
                                 struct sk_buff *skb);
-static struct net_device_stats *if_stats(struct net_device *dev);
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats *if_stats(netdevice_t *dev);
+#else
+static struct enet_statistics* if_stats (netdevice_t* dev);
+#endif
 
 /* Interrupt handlers */
 static void fr_isr(sdla_t *card);
@@ -292,7 +383,7 @@
 static int fr_init_dlci (sdla_t *card, fr_channel_t *chan);
 static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout);
 static int fr_comm_enable(sdla_t *card);
-static int fr_comm_disable(sdla_t *card);
+static void fr_comm_disable(sdla_t *card);
 static int fr_get_err_stats(sdla_t *card);
 static int fr_get_stats(sdla_t *card);
 static int fr_add_dlci(sdla_t *card, int dlci);
@@ -301,6 +392,13 @@
 static int fr_issue_isf(sdla_t *card, int isf);
 static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len,
 	void *buf);
+static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len,
+	void *buf,unsigned char hdr_len);
+static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset);
+
+static int check_dlci_config (sdla_t *card, fr_channel_t *chan);
+static void initialize_rx_tx_buffers (sdla_t *card);
+
 
 /* Firmware asynchronous event handlers */
 static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox);
@@ -308,9 +406,9 @@
 static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox);
 
 /* Miscellaneous functions */
-static int update_chan_state(struct net_device *dev);
-static void set_chan_state(struct net_device *dev, int state);
-static struct net_device *find_channel(sdla_t *card, unsigned dlci);
+static int update_chan_state(netdevice_t *dev);
+static void set_chan_state(netdevice_t *dev, int state);
+static netdevice_t *find_channel(sdla_t *card, unsigned dlci);
 static int is_tx_ready(sdla_t *card, fr_channel_t *chan);
 static unsigned int dec_to_uint(unsigned char *str, int len);
 static int reply_udp( unsigned char *data, unsigned int mbox_len );
@@ -319,14 +417,38 @@
 static void init_chan_statistics( fr_channel_t* chan );
 static void init_global_statistics( sdla_t* card );
 static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
-static void setup_for_delayed_transmit(struct net_device* dev, void* buf,
-	unsigned len);
+static int setup_for_delayed_transmit(netdevice_t* dev, struct sk_buff *skb);
+
+netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *);
+static int check_tx_status(sdla_t *, netdevice_t *);
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+/* Frame Relay Socket API */
+static void trigger_fr_bh (fr_channel_t *);
+static void fr_bh (netdevice_t *);
+static int fr_bh_cleanup (netdevice_t *);
+static int bh_enqueue (netdevice_t *, struct sk_buff *);
+#endif
+
+static void trigger_fr_poll (netdevice_t *);
+static void fr_poll (netdevice_t *);
+//static void add_gateway (netdevice_t *);
+
+static void trigger_unconfig_fr (netdevice_t *dev);
+static void unconfig_fr (sdla_t *);
+
+static void trigger_config_fr (sdla_t *);
+static void config_fr (sdla_t *);
 
 
 /* Inverse ARP and Dynamic routing functions */
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev);
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t *dev);
 int is_arp(void *buf);
-int send_inarp_request(sdla_t *card, struct net_device *dev);
+int send_inarp_request(sdla_t *card, netdevice_t *dev);
+
+static void trigger_fr_arp (netdevice_t *);
+static void fr_arp (unsigned long data);
+
 
 /* Udp management functions */
 static int process_udp_mgmt_pkt(sdla_t *card);
@@ -346,6 +468,7 @@
 void 	s508_s514_lock(sdla_t *card, unsigned long *smp_flags);
 
 unsigned short calc_checksum (char *, int);
+static int setup_fr_header(struct sk_buff** skb, netdevice_t* dev, char op_mode);
 
 
 /****** Public Functions ****************************************************/
@@ -366,15 +489,20 @@
 {
 
 	int err;
+	fr508_flags_t* flags;
 
 	union
 	{
 		char str[80];
 		fr_conf_t cfg;
 	} u;
+
 	fr_buf_info_t* buf_info;
 	int i;
 
+
+	printk(KERN_INFO "\n");
+
 	/* Verify configuration ID */
 	if (conf->config_id != WANCONFIG_FR) {
 		
@@ -403,6 +531,8 @@
 			return -EINVAL;
 	}
 
+	flags = card->flags;
+
 	/* Read firmware version.  Note that when adapter initializes, it
 	 * clears the mailbox, so it may appear that the first command was
 	 * executed successfully when in fact it was merely erased. To work
@@ -429,7 +559,7 @@
 	memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map));
  	
 	/* Configure adapter firmware */
-	
+
 	u.cfg.mtu	= conf->mtu;
 	u.cfg.kbps	= conf->bps / 1000;
 
@@ -546,9 +676,7 @@
                         (void*)(buf_info->rse_base +
                         (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
                         card->hw.dpmbase);
-	}
-
-	else {	
+	}else{	
 		buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
 
 		card->rxmb = (void*)(buf_info->rse_next -
@@ -582,6 +710,8 @@
 	card->wandev.state	= WAN_DISCONNECTED;
 	card->wandev.ttl	= conf->ttl;
         card->wandev.udp_port 	= conf->udp_port;       
+	card->disable_comm	= &disable_comm;	
+	card->u.f.arp_dev 	= NULL;
 
 	/* Intialize global statistics for a card */
 	init_global_statistics( card );
@@ -593,11 +723,13 @@
 	card->intr_mode = INTR_TEST_MODE;
 	err = intr_test( card );
 
+	printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x  count=%i\n",
+			card->devname,err,Intr_test_counter); 
+	
 	if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
-		printk( 
-			"%s: Interrupt Test Failed, Counter: %i\n", 
+		printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", 
 			card->devname, Intr_test_counter);
-		printk( "Please choose another interrupt\n");
+		printk(KERN_ERR "Please choose another interrupt\n");
 		err = -EIO;
 		return err;
 	}
@@ -606,6 +738,32 @@
 			card->devname, Intr_test_counter);
 
 
+	/* Apr 28 2000. Nenad Corbic
+	 * Enable commnunications here, not in if_open or new_if, since
+         * interfaces come down when the link is disconnected. 
+         */
+	 
+	/* If you enable comms and then set ints, you get a Tx int as you
+	 * perform the SET_INT_TRIGGERS command. So, we only set int
+	 * triggers and then adjust the interrupt mask (to disable Tx ints)
+	 * before enabling comms. 
+	 */	
+        if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY |
+		FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) ,
+		card->wandev.mtu, 0)) {
+		return -EIO;
+	}
+
+	flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER);
+ 
+	if (fr_comm_enable(card)) {
+		return -EIO;
+	}	
+	wanpipe_set_state(card, WAN_CONNECTED);
+	spin_lock_init(&card->u.f.if_send_lock);
+	
+	printk(KERN_INFO "\n");
+
         return 0;
 }
 
@@ -627,9 +785,6 @@
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
 
-	if (test_bit(1, (void*)&wandev->critical))
-		return -EAGAIN;
-
 	card = wandev->private;
 	flags = card->flags;
 
@@ -646,6 +801,7 @@
  			return -EAGAIN;
 		}
         }
+
 	return 0;
 }
 
@@ -661,16 +817,17 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf)
+static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
 {
 	sdla_t* card = wandev->private;
 	fr_channel_t* chan;
 	int dlci = 0;
 	int err = 0;
+
 	
 	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
 		
-		printk(KERN_INFO "%s: invalid interface name!\n",
+		printk(KERN_INFO "%s: Invalid interface name!\n",
 			card->devname);
 		return -EINVAL;
 	}
@@ -684,7 +841,7 @@
 	memset(chan, 0, sizeof(fr_channel_t));
 	strcpy(chan->name, conf->name);
 	chan->card = card;
- 
+
 	/* verify media address */
 	if (is_digit(conf->addr[0])) {
 
@@ -697,36 +854,89 @@
 		} else {
 		
 			printk(KERN_ERR
-				"%s: invalid DLCI %u on interface %s!\n",
+				"%s: Invalid DLCI %u on interface %s!\n",
 				wandev->name, dlci, chan->name);
 			err = -EINVAL;
 		}
 
 	} else {
 		printk(KERN_ERR
-			"%s: invalid media address on interface %s!\n",
+			"%s: Invalid media address on interface %s!\n",
 			wandev->name, chan->name);
 		err = -EINVAL;
 	}
 
-        /* Setup wanpipe as a router (WANPIPE) or as an API */
-        if(strcmp(conf->usedby, "WANPIPE") == 0){
-                printk(KERN_INFO "%s: Running in WANPIPE mode %s\n",
-			wandev->name, chan->name);
-                chan->usedby = WANPIPE;
+	if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){
+		printk(KERN_INFO 
+			"%s: Enabling, true interface type encoding.\n",
+			card->devname);
+	}
+	
 
-        } else if(strcmp(conf->usedby, "API") == 0){
 
-#ifdef FRAME_RELAY_API
-                chan->usedby = API;
-                printk(KERN_INFO "%s: Running in API mode %s\n",
-			wandev->name, chan->name);
+    /* Setup wanpipe as a router (WANPIPE) even if it is
+	 * a bridged DLCI, or as an API 
+	 */
+        if (strcmp(conf->usedby, "WANPIPE")  == 0  || 
+	    strcmp(conf->usedby, "BRIDGE")   == 0  ||
+	    strcmp(conf->usedby, "BRIDGE_N") == 0){
+		
+		if(strcmp(conf->usedby, "WANPIPE") == 0){
+			chan->common.usedby = WANPIPE;
+			
+	                printk(KERN_INFO "%s: Running in WANPIPE mode.\n", 
+					card->devname);
+			
+		}else if(strcmp(conf->usedby, "BRIDGE") == 0){
+			
+			chan->common.usedby = BRIDGE;
+			
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+			printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", 
+					card->devname);
+#else
+			printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n",
+					card->devname);
+			err = -EPROTONOSUPPORT;
+#endif
+		}else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){
+			
+			chan->common.usedby = BRIDGE_NODE;
+		
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+			printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", 
+					card->devname);
 #else
-                printk(KERN_INFO "%s: API Mode is not supported !\n",
+			printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n",
+					card->devname);
+			err = -EPROTONOSUPPORT;
+#endif
+		}
+
+		if (!err){
+			/* Dynamic interface configuration option.
+			 * On disconnect, if the options is selected,
+			 * the interface will be brought down */
+			if (conf->if_down == WANOPT_YES){ 
+				set_bit(DYN_OPT_ON,&chan->interface_down);
+				printk(KERN_INFO 
+				    "%s: Dynamic interface configuration enabled.\n",
+					card->devname);
+			}
+		}
+
+        } else if(strcmp(conf->usedby, "API") == 0){
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+                chan->common.usedby = API;
+                printk(KERN_INFO "%s: Running in API mode.\n",
 			wandev->name);
-                printk(KERN_INFO
-			"%s: API patch can be obtained from Sangoma Tech.\n",
-                        	wandev->name);
+#else
+                printk(KERN_INFO "%s: The API Mode is not supported for"
+				 "kernels lower than 2.2.X !\n",
+					wandev->name);
+		printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel for the API support\n",
+					wandev->name);
                 err = -EINVAL;
 #endif
         }
@@ -737,8 +947,6 @@
 		return err;
 	}
 
-	card->u.f.dlci_to_dev_map[dlci] = dev;
- 
 	/* place cir,be,bc and other channel specific information into the
 	 * chan structure 
          */
@@ -774,20 +982,24 @@
 
 	chan->mc = conf->mc;
 
-	/* FIXME: ARP is not supported by this frame relay verson */
 	if (conf->inarp == WANOPT_YES){
-		printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support ARPs\n",
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+		printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname);
+		chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE;
+		chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10;
+#else
+		printk(KERN_INFO "%s: Warning, Inverse ARP Support not available for 2.0.X kernels!\n",
 				card->devname);
-	
-		//chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE;
-		//chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10;
-		kfree(chan);
-		return -EINVAL;
+		chan->inarp = INARP_NONE;
+		chan->inarp_interval = 10;
+#endif
 	}else{
+		printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname);
 		chan->inarp = INARP_NONE;
 		chan->inarp_interval = 10;
 	}
 
+
 	chan->dlci_configured = DLCI_NOT_CONFIGURED;	
 
 
@@ -814,64 +1026,107 @@
 	chan->transmit_length = 0;
 
 	/* prepare network device data space for registration */
-	strcpy(dev->name, chan->name);
+#ifdef LINUX_2_4
+	strcpy(dev->name,chan->name);
+#else
+	dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL); 
+	if(dev->name == NULL)
+	{
+		kfree(chan);
+		return -ENOMEM;
+	}
+	sprintf(dev->name, "%s", chan->name);
+#endif
+	
 	dev->init = &if_init;
 	dev->priv = chan;
 
-
-	/* Enable Interrupts and Communications */
-	if (!wandev->new_if_cnt){
-		fr508_flags_t* flags = card->flags;
-
-		wandev->new_if_cnt++;
-
-		/* 
-		If you enable comms and then set ints, you get a Tx int as you
-		perform the SET_INT_TRIGGERS command. So, we only set int
-		triggers and then adjust the interrupt mask (to disable Tx ints)
-		before enabling comms. 
-		*/	
-                if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY |
-			FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) ,
-			card->wandev.mtu, 0)) {
-			kfree(chan);
-			return -EIO;
-		}
-
-		flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER);
- 
-		if (fr_comm_enable(card)) {
-			kfree(chan);
-			return -EIO;
-		}	
-		wanpipe_set_state(card, WAN_CONNECTED);
+	/* Initialize FR Polling Task Queue
+         * We need a poll routine for each network
+         * interface. 
+         */
+#ifndef LINUX_2_4
+	chan->fr_poll_task.next = NULL;
+#endif
+	chan->fr_poll_task.sync = 0;
+	chan->fr_poll_task.routine = (void *)(void *)fr_poll;
+	chan->fr_poll_task.data = dev;
+
+	init_timer(&chan->fr_arp_timer);
+	chan->fr_arp_timer.data=(unsigned long)dev;
+	chan->fr_arp_timer.function = fr_arp;
+
+	wandev->new_if_cnt++;
+
+	/* Tells us that if this interface is a
+         * gateway or not */
+	if ((chan->gateway = conf->gateway) == WANOPT_YES){
+		printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
+			card->devname,dev->name);
+	}
+
+	/* M. Grant Patch Apr 28 2000 
+         * Disallow duplicate dlci configurations. */
+	if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) {
+		kfree(chan);
+		return -EBUSY;
 	}
 
+	/* Configure this dlci at a later date, when
+         * the interface comes up. i.e. when if_open() 
+         * executes */
+	set_bit(0,&chan->config_dlci);
+	
+	printk(KERN_INFO "\n");
+
 	return 0;
 }
 
 /*============================================================================
  * Delete logical channel.
  */
-static int del_if (wan_device_t* wandev, struct net_device* dev)
+static int del_if (wan_device_t* wandev, netdevice_t* dev)
 {
-	sdla_t *card = wandev->private;
+	fr_channel_t* chan = dev->priv;
+	unsigned long smp_flags=0;
 
-	/* Execute shutdown very first time we enter del_if */
+	/* This interface is dead, make sure the 
+	 * ARP timer is stopped */
+	del_timer(&chan->fr_arp_timer);
+	
+	/* If we are a NODE, we must unconfigure this DLCI
+	 * Trigger an unconfigure command that will
+	 * be executed in timer interrupt. We must wait
+	 * for the command to complete. */
+	trigger_unconfig_fr(dev);
+
+	lock_adapter_irq(&wandev->lock, &smp_flags);
+	wandev->new_if_cnt--;
+	unlock_adapter_irq(&wandev->lock, &smp_flags);
 
-	if (!wandev->del_if_cnt) {
-		wandev->del_if_cnt++;
-		wanpipe_set_state(card, WAN_DISCONNECTED);
-		fr_set_intr_mode(card, 0, 0, 0);
-		fr_comm_disable(card);
-	}
+	return 0;
+}
 
-	if (dev->priv) {
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
 
-	return 0;
+/*=====================================================================
+ * disable_comm
+ *
+ * Description:
+ *	Disable communications.
+ * 	This code runs in shutdown (sdlamain.c)
+ *      under critical flag. Therefore it is not
+ *      necessary to set a critical flag here 
+ *
+ * Usage:
+ * 	Commnunications are disabled only on a card
+ *      shutdown.
+ */
+
+static void disable_comm (sdla_t *card)
+{
+	printk(KERN_INFO "%s: Disabling Communications!\n",
+			card->devname);
+	fr_comm_disable(card);
 }
 
 /****** WANPIPE-specific entry points ***************************************/
@@ -886,6 +1141,8 @@
 	int err, len;
 	fr_cmd_t cmd;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
 	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
 		return -EFAULT;
 	
@@ -916,6 +1173,43 @@
 		return -EFAULT;
 	return 0;
 
+#else
+        if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(fr_cmd_t)))
+                return -EFAULT;
+
+        memcpy_fromfs((void*)&cmd, u_cmd, sizeof(cmd));
+
+        if (cmd.length) {
+
+                if (!u_data || verify_area(VERIFY_READ, u_data, cmd.length))
+                        return -EFAULT;
+        }
+
+        /* execute command */
+        do
+        {
+                memcpy(&mbox->cmd, &cmd, sizeof(cmd));
+
+                if (cmd.length)
+                        memcpy_fromfs((void*)&mbox->data, u_data, cmd.length);
+
+                if (sdla_exec(mbox))
+                        err = mbox->cmd.result;
+
+                else return -EIO;
+        } while (err && retry-- && fr_event(card, err, mbox));
+
+        /* return result */
+        memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t));
+        len = mbox->cmd.length;
+
+        if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len))
+                memcpy_tofs(u_data, (void*)&mbox->data, len);
+
+        return 0;
+
+#endif
+
 }
 
 /****** Network Device Interface ********************************************/
@@ -927,44 +1221,79 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init (struct net_device* dev)
+static int if_init (netdevice_t* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 	wan_device_t* wandev = &card->wandev;
+#ifdef LINUX_2_0
+	int i;
+#endif
 
 	/* Initialize device driver entry points */
 	dev->open		= &if_open;
 	dev->stop		= &if_close;
-	dev->hard_header	= &if_header;
+	dev->hard_header	= NULL;
 	dev->rebuild_header	= &if_rebuild_hdr;
 	dev->hard_start_xmit	= &if_send;
 	dev->get_stats		= &if_stats;
+#ifdef LINUX_2_4
 	dev->tx_timeout		= &if_tx_timeout;
 	dev->watchdog_timeo	= TX_TIMEOUT;
+#endif
+	
+	if (chan->common.usedby == WANPIPE || chan->common.usedby == API){
+#ifdef LINUX_2_0
+		dev->family = AF_INET;
+#endif
+		/* Initialize media-specific parameters */
+		if (chan->true_if_encoding){
+			dev->type 		= ARPHRD_DLCI;  /* This breaks tcpdump */
+		}else{
+			dev->type		= ARPHRD_PPP; 	/* ARP h/w type */
+		}
+		
+		dev->flags		|= IFF_POINTOPOINT;
+		dev->flags		|= IFF_NOARP;
 
-	/* Initialize media-specific parameters */
-	dev->type		= ARPHRD_DLCI;	/* ARP h/w type */
-	dev->flags		|= IFF_POINTOPOINT;	
-
-	/* Enable Multicast addressing */
-	if (chan->mc == WANOPT_YES){
-		dev->flags 	|= IFF_MULTICAST;
-	}
+		/* Enable Multicast addressing */
+		if (chan->mc == WANOPT_YES){
+			dev->flags 	|= IFF_MULTICAST;
+		}
 
-	dev->mtu		= wandev->mtu - FR_HEADER_LEN;
-	/* For an API, the maximum number of bytes that the stack will pass
-	   to the driver is (dev->mtu + dev->hard_header_len). So, adjust the
-	   mtu so that a frame of maximum size can be transmitted by the API. 
-	*/
-	if(chan->usedby == API) {
-		dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN);
-	}
-	
-	dev->hard_header_len	= FR_HEADER_LEN;/* media header length */
-	dev->addr_len		= 2; 		/* hardware address length */
-	*(unsigned short*)dev->dev_addr = htons(chan->dlci);
+		dev->mtu		= wandev->mtu - FR_HEADER_LEN;
+		/* For an API, the maximum number of bytes that the stack will pass
+		   to the driver is (dev->mtu + dev->hard_header_len). So, adjust the
+		   mtu so that a frame of maximum size can be transmitted by the API. 
+		*/
+		if(chan->common.usedby == API) {
+			dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN);
+		}
+		
+		dev->hard_header_len	= FR_HEADER_LEN;/* media header length */
+		dev->addr_len		= 2; 		/* hardware address length */
+		*(unsigned short*)dev->dev_addr = htons(chan->dlci);
+
+		/* Set transmit buffer queue length */
+        	dev->tx_queue_len = 100;
+
+			/* Initialize socket buffers */
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
+	        for (i = 0; i < DEV_NUMBUFFS; ++i)
+			skb_queue_head_init(&dev->buffs[i]);
+#endif
+	}else{
 
+		/* Setup the interface for Bridging */
+		int hw_addr=0;
+		ether_setup(dev);
+		
+		/* Use a random number to generate the MAC address */
+		memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6);
+		get_random_bytes(&hw_addr, sizeof(hw_addr));
+		*(int *)(dev->dev_addr + 2) += hw_addr;
+	}
+		
 	/* Initialize hardware parameters (just for reference) */
 	dev->irq	= wandev->irq;
 	dev->dma	= wandev->dma;
@@ -972,13 +1301,6 @@
 	dev->mem_start	= wandev->maddr;
 	dev->mem_end	= wandev->maddr + wandev->msize - 1;
 
-        /* Set transmit buffer queue length */
-        dev->tx_queue_len = 100;
-   
-	/* Initialize socket buffers */
-	dev_init_buffers(dev);
-
-	set_chan_state(dev, WAN_DISCONNECTED);
 	return 0;
 }
 
@@ -989,60 +1311,51 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open (struct net_device* dev)
+static int if_open (netdevice_t* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 	int err = 0;
 	struct timeval tv;
 
-	if (netif_running(dev))
-		return -EBUSY;		/* only one open is allowed */
-
-	if (test_and_set_bit(1, (void*)&card->wandev.critical))
-		return -EAGAIN;
+	if (is_dev_running(dev))
+		return -EBUSY;
 	
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	/* Initialize the task queue */
+	chan->tq_working=0;
 
-	/* If signalling is set to NO, then setup 
-         * DLCI addresses right away.  Don't have to wait for
-	 * link to connect. 
-	 */
-	if (card->wandev.signalling == WANOPT_NO){
-		printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n",
-					card->wandev.name);
-		if (fr_init_dlci(card,chan)){
-			return -EAGAIN;
-		}
-	}
-
-	if (card->wandev.station == WANOPT_CPE) {
-
-		/* CPE: issue full status enquiry */
-		fr_issue_isf(card, FR_ISF_FSE);
-
-	} else {	/* FR switch: activate DLCI(s) */
-		
-		/* For Switch emulation we have to ADD and ACTIVATE
-		 * the DLCI(s) that were configured with the SET_DLCI_
-		 * CONFIGURATION command. Add and Activate will fail if
-		 * DLCI specified is not included in the list.
-		 *
-		 * Also If_open is called once for each interface. But
-		 * it does not get in here for all the interface. So
-	 	 * we have to pass the entire list of DLCI(s) to add 
-		 * activate routines.  
-		 */ 
-	
-		fr_add_dlci(card, chan->dlci);
-		fr_activate_dlci(card, chan->dlci);
-	}
+#ifndef LINUX_2_4
+	chan->common.wanpipe_task.next = NULL;
+#endif
+	chan->common.wanpipe_task.sync = 0;
+	chan->common.wanpipe_task.routine = (void *)(void *)fr_bh;
+	chan->common.wanpipe_task.data = dev;
+
+	/* Allocate and initialize BH circular buffer */
+	chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC);
+	memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF));
+	atomic_set(&chan->bh_buff_used, 0);
+#endif
 
+#ifdef LINUX_2_4
 	netif_start_queue(dev);
+#else	
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+#endif
+
 	wanpipe_open(card);
-	update_chan_state(dev);
 	do_gettimeofday( &tv );
 	chan->router_start_time = tv.tv_sec;
-        clear_bit(1, (void*)&card->wandev.critical);
+	
+	if (test_bit(0,&chan->config_dlci)){
+		trigger_config_fr (card);
+	}else if (chan->inarp == INARP_REQUEST){
+		trigger_fr_arp(dev);
+	}
+	
 	return err;
 }
 
@@ -1051,61 +1364,42 @@
  * o if this is the last open, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close (struct net_device* dev)
+static int if_close (netdevice_t* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
-	if (test_and_set_bit(1, (void*)&card->wandev.critical))
-		return -EAGAIN;
+	if (chan->inarp == INARP_CONFIGURED) {
+		chan->inarp = INARP_REQUEST;
+	}
 
-	netif_stop_queue(dev);
+	stop_net_queue(dev);
+#ifndef LINUX_2_4
+	dev->start=0;
+#endif
 	wanpipe_close(card);
-	if (card->wandev.station == WANOPT_NODE) {
-		fr_delete_dlci (card,chan->dlci);
-	}
 
-        clear_bit(1, (void*)&card->wandev.critical);
 	return 0;
 }
 
 /*============================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return:	media header length.
- */
-static int if_header (struct sk_buff* skb, struct net_device* dev,
-	unsigned short type, void* daddr, void* saddr, unsigned len)
-{
-	int hdr_len = 0;
-	
-	skb->protocol = type;
-	hdr_len = wanrouter_encapsulate(skb, dev);
-
-	if (hdr_len < 0) {
-		hdr_len = 0;
-		skb->protocol = 0;
-	}
-	skb_push(skb, 1);
-	skb->data[0] = Q922_UI;
-	++hdr_len;
-	return hdr_len;
-}
-
-/*============================================================================
  * Re-build media header.
  *
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	struct net_device *dev = skb->dev;
+#else
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
+                           struct sk_buff* skb)
+{
+#endif
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+	netdevice_t *dev = skb->dev;
+#endif
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
@@ -1114,13 +1408,14 @@
 	return 1;
 }
 
-
+#ifdef LINUX_2_4
 /*============================================================================
  * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (struct net_device *dev)
+static void if_tx_timeout (netdevice_t *dev)
 {
     	fr_channel_t* chan = dev->priv;
+	sdla_t *card = chan->card;
 
 	/* If our device stays busy for at least 5 seconds then we will
 	 * kick start the device by making dev->tbusy = 0.  We expect
@@ -1131,12 +1426,13 @@
 	chan->drvstats_if_send.if_send_tbusy++;
 	++chan->ifstats.collisions;
 
-	printk (KERN_INFO "%s: Transmit timed out\n", chan->name);
+	printk (KERN_INFO "%s: Transmit timed out on %s\n", 
+			card->devname, dev->name);
 	chan->drvstats_if_send.if_send_tbusy_timeout++;
 	netif_wake_queue (dev);
 
 }
-
+#endif
 
 /*============================================================================
  * Send a packet on a network interface.
@@ -1154,23 +1450,28 @@
  * Notes:
  * 1. This routine is called either by the protocol stack or by the "net
  *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer.
+ * 
+ * 2. Using the start_net_queue() and stop_net_queue() MACROS
+ *    will inhibit further transmit requests from the protocol stack 
+ *    and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff* skb, struct net_device* dev)
+static int if_send (struct sk_buff* skb, netdevice_t* dev)
 {
     	fr_channel_t* chan = dev->priv;
     	sdla_t* card = chan->card;
         int err;
     	unsigned char *sendpacket;
     	fr508_flags_t* adptr_flags = card->flags;
-	int udp_type, send_data;
+	int udp_type, delay_tx_queued=0;
 	unsigned long smp_flags=0;
-	void* data;
-	unsigned len;
+	unsigned char attr = 0;
 
 	chan->drvstats_if_send.if_send_entry++;
 
+#ifdef LINUX_2_4
+	netif_stop_queue(dev);
+#endif
+	
         if (skb == NULL) {             
 		/* if we get here, some higher layer thinks we've missed an
 		 * tx-done interrupt.
@@ -1178,7 +1479,19 @@
 		printk(KERN_INFO "%s: interface %s got kicked!\n", 
 			card->devname, dev->name);
 		chan->drvstats_if_send.if_send_skb_null ++;
-		netif_wake_queue(dev);
+
+		wake_net_dev(dev);
+		return 0;
+	}
+
+	/* If a peripheral task is running just drop packets */
+	if (test_bit(PERI_CRIT, &card->wandev.critical)){
+		
+		printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n",
+				card->devname);
+		
+		wan_dev_kfree_skb(skb,FREE_WRITE);
+		start_net_queue(dev);
 		return 0;
 	}
 
@@ -1187,23 +1500,58 @@
 	   ensure that the transmit interrupt does not reset the 'tbusy' flag
 	   just before we set it, as this will result in a "transmit timeout".
 	*/
-	set_bit(2, (void*)&card->wandev.critical);
+	set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
         if(chan->transmit_length) {
-		netif_stop_queue(dev);
-	        chan->tick_counter = jiffies;
- 		clear_bit(2, (void*)&card->wandev.critical);
+		stop_net_queue(dev);
+		chan->tick_counter = jiffies;
+ 		clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
 		return 1;
 	}
-       	clear_bit(2, (void*)&card->wandev.critical);
-  
-	data = skb->data;
+       	clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
+ 
+#ifndef LINUX_2_4
+    	if (dev->tbusy) {
+
+		/* If our device stays busy for at least 5 seconds then we will
+                 * kick start the device by making dev->tbusy = 0.  We expect
+                 * that our device never stays busy more than 5 seconds. So this                 
+		 * is only used as a last resort.
+                 */
+		
+		chan->drvstats_if_send.if_send_tbusy++;
+		++chan->ifstats.collisions;
+
+		if ((jiffies - chan->tick_counter) < (5 * HZ)) {
+			return 1;
+		}
+
+		printk(KERN_INFO "%s: Transmit timed out on %s\n", 
+				card->devname, chan->name);
+		chan->drvstats_if_send.if_send_tbusy_timeout ++;
+		dev->tbusy = 0;
+    	}
+#endif
+
+	
+	/* Move the if_header() code to here. By inserting frame
+	 * relay header in if_header() we would break the
+	 * tcpdump and other packet sniffers */
+	chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby);
+	if (chan->fr_header_len < 0 ){
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+		
+		wan_dev_kfree_skb(skb,FREE_WRITE);
+		start_net_queue(dev);	
+		return 0;
+	}
+
 	sendpacket = skb->data;
-        len = skb->len;
 
 	udp_type = udp_pkt_type(skb, card);
 
         if(udp_type != UDP_INVALID_TYPE) {
-                if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,
+		if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,
                         chan->dlci)) {
                         adptr_flags->imask |= FR_INTR_TIMER;
                         if (udp_type == UDP_FPIPE_TYPE){
@@ -1211,61 +1559,92 @@
 					if_send_PIPE_request ++;
 			}
                 }
+		start_net_queue(dev);
 		return 0;
 	}
 
-	if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) {
-		//FIXME: increment some error statistic
-                dev_kfree_skb(skb);
-                return 0;
- 	}
- 
 	//FIXME: can we do better than sendpacket[2]?
-  	if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) {
+  	if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) {
+		
                	/* check to see if the source IP address is a broadcast or */
                 /* multicast IP address */
-                if(chk_bcast_mcast_addr(card, dev, skb))
-                        return 0;
+                if(chk_bcast_mcast_addr(card, dev, skb)){
+            		++chan->ifstats.tx_dropped;
+			++card->wandev.stats.tx_dropped;
+                	wan_dev_kfree_skb(skb, FREE_WRITE);
+			start_net_queue(dev);
+			return 0;
+		}
 	}
 
-	/* Lock the 508 card: SMP Supported */
+	
+	/* Lock the S514/S508 card: SMP Supported */
     	s508_s514_lock(card,&smp_flags);
 
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+	if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
+		
 		chan->drvstats_if_send.if_send_critical_non_ISR ++;
 		chan->ifstats.tx_dropped ++;
-		printk(KERN_INFO "%s Critical in IF_SEND %02X\n", 
-				card->devname, card->wandev.critical);
-		dev_kfree_skb(skb);
-		/* Unlock the 508 card */
-               	s508_s514_unlock(card,&smp_flags);
-		return 0;
+		printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", 
+				card->devname);
+		goto if_send_start_and_exit;
 	}
- 	
-	if (card->wandev.state != WAN_CONNECTED) {
-		chan->drvstats_if_send.if_send_wan_disconnected ++;
-		++chan->ifstats.tx_dropped;
-        	++card->wandev.stats.tx_dropped;
 	
-	} else if (chan->state != WAN_CONNECTED) {
-		chan->drvstats_if_send.if_send_dlci_disconnected ++;
-		/* Critical area on 514, since disabl_irq is not used
-                 * thus, interrupt would execute a command at
-		 * the same time as if_send.
-                 */
-     		set_bit(1, (void*)&card->wandev.critical);
-		update_chan_state(dev);
-		clear_bit(1, (void*)&card->wandev.critical);
-        	++chan->ifstats.tx_dropped;
+	/* API packet check: minimum packet size must be greater than 
+	 * 16 byte API header */
+	if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) {
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+	    
+		
+		goto if_send_start_and_exit;
+
+ 	}else{
+		/* During API transmission, get rid of the API header */
+		if (chan->common.usedby == API) {
+			api_tx_hdr_t* api_tx_hdr;
+			api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];
+			attr = api_tx_hdr->attr;
+			skb_pull(skb,sizeof(api_tx_hdr_t));
+		}
+	}
+
+	if (card->wandev.state != WAN_CONNECTED) {
+		chan->drvstats_if_send.if_send_wan_disconnected ++;
+		++chan->ifstats.tx_dropped;
         	++card->wandev.stats.tx_dropped;
+	
+	} else if (chan->common.state != WAN_CONNECTED) {
+		chan->drvstats_if_send.if_send_dlci_disconnected ++;
 
+		/* Update the DLCI state in timer interrupt */
+		card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE;	
+		adptr_flags->imask |= FR_INTR_TIMER;
+
+        	++chan->ifstats.tx_dropped;
+        	++card->wandev.stats.tx_dropped;
+		
 	} else if (!is_tx_ready(card, chan)) {
-		setup_for_delayed_transmit(dev, data, len);
+		/* No tx buffers available, store for delayed transmit */
+		if (!setup_for_delayed_transmit(dev, skb)){
+			set_bit(1,&delay_tx_queued);
+		}
 		chan->drvstats_if_send.if_send_no_bfrs++;
- 	} else {
-		send_data = 1;
+		
+	} else if (!skb->protocol) {
+		/* No protocols drop packet */
+		chan->drvstats_if_send.if_send_protocol_error ++;
+		++card->wandev.stats.tx_errors;
+	
+	} else if (test_bit(ARP_CRIT,&card->wandev.critical)){
+		/* We are trying to send an ARP Packet, block IP data until
+		 * ARP is sent */
+		++chan->ifstats.tx_dropped;
+        	++card->wandev.stats.tx_dropped;
+		
+	} else {
 		//FIXME: IPX is not implemented in this version of Frame Relay ?
-		if((chan->usedby == WANPIPE) &&
+		if((chan->common.usedby == WANPIPE) &&
 		 	sendpacket[1] == 0x00 &&
 		    	sendpacket[2] == 0x80 &&
 		    	sendpacket[6] == 0x81 &&
@@ -1279,32 +1658,28 @@
 				printk(KERN_INFO 
 				"%s: WARNING: Unsupported IPX data in send, packet dropped\n",
 					card->devname);
-				send_data = 0;
-			}
-		}
-
-		if (send_data) {
-			unsigned char attr = 0;
-
-			/* For an API transmission, get rid of the API header */
-                        if (chan->usedby == API) {
-                                api_tx_hdr_t* api_tx_hdr;
-           			api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];
-                      		attr = api_tx_hdr->attr;
-				data += sizeof(api_tx_hdr_t);
-				len -= sizeof(api_tx_hdr_t);
 			}
-
-        		err = fr_send(card, chan->dlci, attr, len, data);
+			
+		}else{
+        		err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len);
 			if (err) {
 				switch(err) {
 				case FRRES_CIR_OVERFLOW:
 				case FRRES_BUFFER_OVERFLOW:
-                			setup_for_delayed_transmit(dev, data,
-						len);
+                			if (!setup_for_delayed_transmit(dev, skb)){
+						set_bit(1,&delay_tx_queued);
+					}
            				chan->drvstats_if_send.
 						if_send_adptr_bfrs_full ++;
-					break;	
+					break;
+					
+				case FRRES_TOO_LONG:
+					if (net_ratelimit()){
+						printk(KERN_INFO 
+						"%s: Error: Frame too long, transmission failed %i\n",
+						 card->devname, (unsigned int)skb->len);
+					}
+					/* Drop down to default */
 				default:
 					chan->drvstats_if_send.
 						if_send_dlci_disconnected ++;
@@ -1317,20 +1692,37 @@
 					if_send_bfr_passed_to_adptr++;
 				++chan->ifstats.tx_packets;
 				++card->wandev.stats.tx_packets;
-                                chan->ifstats.tx_bytes += len;
-                                card->wandev.stats.tx_bytes += len;
+				
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+                                chan->ifstats.tx_bytes += skb->len;
+                                card->wandev.stats.tx_bytes += skb->len;
+#endif
+#ifdef LINUX_2_4
+				dev->trans_start = jiffies;
+#endif
 			}
 		}
 	}
 
-        if (!netif_queue_stopped(dev))
-		dev_kfree_skb(skb);
+if_send_start_and_exit:
+
+	start_net_queue(dev);
+	
+	/* If we queued the packet for transmission, we must not
+	 * deallocate it. The packet is unlinked from the IP stack
+	 * not copied. Therefore, we must keep the original packet */
+	if (!test_bit(1,&delay_tx_queued)) {
+                wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+		adptr_flags->imask |= FR_INTR_TXRDY;
+		card->u.f.tx_interrupts_pending ++;
+	}
 
-        clear_bit(0, (void*)&card->wandev.critical);
+        clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
 
 	s508_s514_unlock(card,&smp_flags);
 
-        return (netif_queue_stopped(dev));
+	return 0;
 }
 
 
@@ -1339,33 +1731,49 @@
  * Setup so that a frame can be transmitted on the occurence of a transmit
  * interrupt.
  */
-static void setup_for_delayed_transmit (struct net_device* dev, void* buf,
-	unsigned len)
+static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb)
 {
         fr_channel_t* chan = dev->priv;
         sdla_t* card = chan->card;
-        fr508_flags_t* adptr_flags = card->flags;
-        fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
+        fr_dlci_interface_t* dlci_interface;
+	int len = skb->len;
+
+	/* Check that the dlci is properly configured,
+         * before using tx interrupt */
+	if (!chan->dlci_int_interface){
+		if (net_ratelimit()){ 
+			printk(KERN_INFO 
+				"%s: ERROR on DLCI %i: Not configured properly !\n",
+					card->devname, chan->dlci);
+			printk(KERN_INFO "%s: Please contact Sangoma Technologies\n",
+					card->devname);
+		}
+		return 1;
+	}
+		
+	dlci_interface = chan->dlci_int_interface;
 
         if(chan->transmit_length) {
                 printk(KERN_INFO "%s: Big mess in setup_for_del...\n",
 				card->devname);
-                return;
+                return 1;
         }
 
 	if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) {
 		//FIXME: increment some statistic */
-		return;
+		return 1;
 	}
 
+	skb_unlink(skb);
+	
         chan->transmit_length = len;
-        memcpy(chan->transmit_buffer, buf, len);
-
+	chan->delay_skb = skb;
+        
         dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
         dlci_interface->packet_length = len;
-        adptr_flags->imask |= FR_INTR_TXRDY;
 
-	card->u.f.tx_interrupts_pending ++;
+	/* Turn on TX interrupt at the end of if_send */
+	return 0;
 }
 
 
@@ -1375,18 +1783,21 @@
  * Return 0 if not broadcast/multicast address, otherwise return 1.
  */
 
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
                                 struct sk_buff *skb)
 {
         u32 src_ip_addr;
         u32 broadcast_ip_addr = 0;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         struct in_device *in_dev;
+#endif
         fr_channel_t* chan = dev->priv;
  
         /* read the IP source address from the outgoing packet */
         src_ip_addr = *(u32 *)(skb->data + 14);
 
         /* read the IP broadcast address for the device */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         in_dev = dev->ip_ptr;
         if(in_dev != NULL) {
                 struct in_ifaddr *ifa= in_dev->ifa_list;
@@ -1395,13 +1806,15 @@
                 else
                         return 0;
         }
+#else
+        broadcast_ip_addr = dev->pa_brdaddr;
+#endif
 
         /* check if the IP Source Address is a Broadcast address */
-        if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {                printk(KERN_INFO
+        if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
+                printk(KERN_INFO
                         "%s: Broadcast Source Address silently discarded\n",
                         card->devname);
-                dev_kfree_skb(skb);
-                ++ chan->ifstats.tx_dropped;
                 return 1;
         }
 
@@ -1411,8 +1824,6 @@
                 printk(KERN_INFO
                         "%s: Multicast Source Address silently discarded\n",
                         card->devname);
-                dev_kfree_skb(skb);
-                ++ chan->ifstats.tx_dropped;
                 return 1;
         }
 
@@ -1433,7 +1844,7 @@
 	fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; 
 
 	/* Set length of packet */
-	len = sizeof(fr_encap_hdr_t)+
+	len = //sizeof(fr_encap_hdr_t)+
 	      sizeof(ip_pkt_t)+ 
 	      sizeof(udp_pkt_t)+
 	      sizeof(wp_mgmt_t)+
@@ -1481,7 +1892,7 @@
 	fr_udp_pkt->udp_pkt.udp_checksum = 0;
 
 	fr_udp_pkt->udp_pkt.udp_checksum = 
-		calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)],
+		calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/],
 			      udp_length+UDP_OFFSET);
 
 	/* fill in IP length */
@@ -1499,7 +1910,7 @@
 	/* fill in IP checksum */
 	fr_udp_pkt->ip_pkt.hdr_checksum = 0;
 	fr_udp_pkt->ip_pkt.hdr_checksum = 
-		calc_checksum(&data[sizeof(fr_encap_hdr_t)],
+		calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0],
 		      	      sizeof(ip_pkt_t));
 
 	return len;
@@ -1588,9 +1999,13 @@
 
 /*============================================================================
  * Get ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats.
+ * Return a pointer to struct enet_statistics.
  */
-static struct net_device_stats* if_stats (struct net_device* dev)
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats *if_stats(netdevice_t *dev)
+#else
+static struct enet_statistics* if_stats (netdevice_t* dev)
+#endif
 {
 	fr_channel_t* chan = dev->priv;
 	
@@ -1603,7 +2018,12 @@
 /****** Interrupt Handlers **************************************************/
 
 /*============================================================================
- * S508 frame relay interrupt service routine.
+ * fr_isr:	S508 frame relay interrupt service routine.
+ *
+ * Description:
+ *	Frame relay main interrupt service route. This
+ *      function check the interrupt type and takes
+ *      the appropriate action.
  */
 static void fr_isr (sdla_t* card)
 {
@@ -1613,26 +2033,25 @@
 	fr_mbox_t* mbox = card->mbox;
 
 	/* This flag prevents nesting of interrupts.  See sdla_isr() routine
-         * in sdlamain.c. 
-	 */
+         * in sdlamain.c.  */
 	card->in_isr = 1;
 	
 	++card->statistics.isr_entry;
 
-	if(test_bit(1, (void*)&card->wandev.critical)) {
-		card->wandev.critical = 0;
-		flags->iflag = 0;
-		card->in_isr = 0;
-		return;
-	}
 
+	/* All peripheral (configuraiton, re-configuration) events
+	 * take presidence over the ISR.  Thus, retrigger */
+	if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
+		++card->statistics.isr_already_critical;
+		goto fr_isr_exit;
+	}
+	
         if(card->hw.type != SDLA_S514) {
-		if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
-                        printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n",
-                                card->devname, card->wandev.critical);
+		if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
+                        printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n",
+                                card->devname);
 			++card->statistics.isr_already_critical;
-			card->in_isr = 0;
-			return;
+			goto fr_isr_exit;
 		}
 	}
 
@@ -1649,12 +2068,12 @@
 			tx_intr(card); 
             		break;
 
-                case FR_INTR_READY:
+                case FR_INTR_READY:  	
 	    		Intr_test_counter++;
 			++card->statistics.isr_intr_test;
 	    		break;	
 
-                case FR_INTR_DLC: /* Event interrupt occurred */
+                case FR_INTR_DLC: /* Event interrupt occured */
 			mbox->cmd.command = FR_READ_STATUS;
 			mbox->cmd.length = 0;
 			err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
@@ -1680,27 +2099,31 @@
 			break;
     	}
 
+fr_isr_exit:
+	
 	card->in_isr = 0;
 	flags->iflag = 0;
-        if(card->hw.type != SDLA_S514)
-                clear_bit(0, (void*)&card->wandev.critical);
+	return;
 }
 
 
 
-/*============================================================================
- * Receive interrupt handler.
- * When a receive interrupt occurs do the following:
- *	1- Find the structure for the dlci that the interrupt occurred on
- *      2- If it doesn't exist then print appropriate msg and goto step 8. 
- * 	3- If it exist then copy data to a skb.
- * 	4- If skb contains Sangoma UDP data then process them
- *	5- If skb contains IPXWAN data then send IPXWAN reply packets
- *	6- If skb contains Inverse Arp data then send Inv Arp replies
- *	7- If skb contains any other data then decapsulate the packet and
- *	   send it to the stack.
- * 	8- Release the receive element and update receive pointers on the board 
+/*===========================================================
+ * rx_intr	Receive interrupt handler.
+ *
+ * Description
+ * 	Upon receiveing an interrupt: 
+ *	1. Check that the firmware is in sync with 
+ *     	   the driver. 
+ *      2. Find an appropriate network interface
+ *         based on the received dlci number.
+ *	3. Check that the netowrk interface exists
+ *         and that it's setup properly.
+ *	4. Copy the data into an skb buffer.
+ *	5. Check the packet type and take
+ *         appropriate acton: UPD, API, ARP or Data.
  */
+
 static void rx_intr (sdla_t* card)
 {
 	fr_rx_buf_ctl_t* frbuf = card->rxmb;
@@ -1708,11 +2131,13 @@
 	fr_channel_t* chan;
 	char *ptr = &flags->iflag;
 	struct sk_buff* skb;
-	struct net_device* dev;
+	netdevice_t* dev;
 	void* buf;
 	unsigned dlci, len, offs, len_incl_hdr;
 	int i, udp_type;	
 
+
+	/* Check that firmware buffers are in sync */
 	if (frbuf->flag != 0x01) {
 
 		printk(KERN_INFO 
@@ -1725,6 +2150,16 @@
 		printk(KERN_INFO "\n");
 	
 		++card->statistics.rx_intr_corrupt_rx_bfr;
+
+		/* Bug Fix: Mar 6 2000
+                 * If we get a corrupted mailbox, it means that driver 
+                 * is out of sync with the firmware. There is no recovery.
+                 * If we don't turn off all interrupts for this card
+                 * the machine will crash. 
+                 */
+		printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
+		printk(KERN_INFO "Please contact Sangoma Technologies !\n");
+		fr_set_intr_mode(card, 0, 0, 0);	
 		return;
 	}
 
@@ -1732,134 +2167,206 @@
 	dlci = frbuf->dlci;
 	offs = frbuf->offset;
 
-	/* Find network interface for this packet */
+	/* Find the network interface for this packet */
 	dev = find_channel(card, dlci);
-        
-	if (dev == NULL) {
+   
 
-		/* unconfigured DLCI, so discard packet */
-   		printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
+	/* Check that the network interface is active and
+         * properly setup */
+	if (dev == NULL) {
+   		if( net_ratelimit()) { 
+			printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
                                                 card->devname, dlci);
+		}
 		++card->statistics.rx_intr_on_orphaned_DLCI; 
+		++card->wandev.stats.rx_dropped;
+		goto rx_done;
+	}
 
-       	} else {
-		chan = dev->priv;
+	if ((chan = dev->priv) == NULL){
+		if( net_ratelimit()) { 
+			printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
+                                                card->devname, dlci);
+		}
+		++card->statistics.rx_intr_on_orphaned_DLCI; 
+		++card->wandev.stats.rx_dropped;
+		goto rx_done;
+	}
 
-   		skb = dev_alloc_skb(len); 
+	skb = dev_alloc_skb(len); 
 
-		if (!netif_running(dev) || (skb == NULL)) { 
-			++chan->ifstats.rx_dropped;
-		
-			if(netif_running(dev)) {
+	if (!is_dev_running(dev) || (skb == NULL)){
 
+		++chan->ifstats.rx_dropped;
+	
+		if(skb == NULL) {
+			if (net_ratelimit()) { 
 				printk(KERN_INFO 
-				"%s: no socket buffers available!\n", 
-				card->devname);
-	    			chan->drvstats_rx_intr.rx_intr_no_socket ++;
-                		
-			} else
-				chan->drvstats_rx_intr.
-					rx_intr_dev_not_started ++;
-		} else {
-			/* Copy data to the socket buffer */
-			if ((offs + len) > card->u.f.rx_top + 1) {
-				unsigned tmp = card->u.f.rx_top - offs + 1;
-
-				buf = skb_put(skb, tmp);
-				sdla_peek(&card->hw, offs, buf, tmp);
-				offs = card->u.f.rx_base;
-               			len -= tmp;
-               		}
-
-			buf = skb_put(skb, len);
-			sdla_peek(&card->hw, offs, buf, len);
-
-			udp_type = udp_pkt_type( skb, card );
-
-                        if(udp_type != UDP_INVALID_TYPE) {
-                                if(store_udp_mgmt_pkt(udp_type,
-                                        UDP_PKT_FRM_NETWORK, card, skb, dlci)) {
-                                        flags->imask |= FR_INTR_TIMER;
-                                        if (udp_type == UDP_FPIPE_TYPE){
-                                                chan->drvstats_rx_intr.
-						    rx_intr_PIPE_request ++;
-					}
-				}			
+					"%s: no socket buffers available!\n", 
+						card->devname);
 			}
+			chan->drvstats_rx_intr.rx_intr_no_socket ++;
+		} 
 
-			else if (chan->usedby == API) {
-				api_rx_hdr_t* api_rx_hdr;
-				chan->drvstats_rx_intr.
-                                	rx_intr_bfr_passed_to_stack ++;
-				chan->ifstats.rx_packets ++;
-                                card->wandev.stats.rx_packets ++;
-				chan->ifstats.rx_bytes += skb->len;
-				card->wandev.stats.rx_bytes += skb->len;
-
-				skb_push(skb, sizeof(api_rx_hdr_t));
-				api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
-				api_rx_hdr->attr = frbuf->attr;
-				api_rx_hdr->time_stamp = frbuf->tmstamp;
-				skb->protocol = htons(0x16);
-				skb->pkt_type = PACKET_HOST;
-                                /* Pass it up the protocol stack */
-                                skb->dev = dev;
-                                skb->mac.raw  = skb->data;
-                                netif_rx(skb);
-
-			} else if (handle_IPXWAN(skb->data,chan->name,
-				chan->enable_IPX, chan->network_number)) {
-				if (chan->enable_IPX) {
-                                        fr_send(card, dlci, 0, skb->len,
-						skb->data);
-				}
-				dev_kfree_skb(skb);
+		if (!is_dev_running(dev)){
+			chan->drvstats_rx_intr.
+				rx_intr_dev_not_started ++;
+			if (skb){
+				wan_dev_kfree_skb(skb, FREE_READ);
+			}
+		}
+		goto rx_done;
+	}
 
-/*FIXME: Fix the ARPS in next release
+	/* Copy data from the board into the socket buffer */
+	if ((offs + len) > card->u.f.rx_top + 1) {
+		unsigned tmp = card->u.f.rx_top - offs + 1;
 
-			} else if (is_arp(skb->data)) {
-				if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) {
-					printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname);
-				}
-				dev_kfree_skb(skb);
-*/
+		buf = skb_put(skb, tmp);
+		sdla_peek(&card->hw, offs, buf, tmp);
+		offs = card->u.f.rx_base;
+		len -= tmp;
+	}
 
-			} else if ( skb->data[0] != 0x03) {
-				printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname);
-				dev_kfree_skb(skb);
+	buf = skb_put(skb, len);
+	sdla_peek(&card->hw, offs, buf, len);
 
-			} else {
 
-				len_incl_hdr = skb->len;
-                    		/* Decapsulate packet and pass it up the
-			   	   protocol stack */
-				skb->dev = dev;
+	/* We got the packet from the bard. 
+         * Check the packet type and take appropriate action */
 
-				/* remove hardware header */
-				buf = skb_pull(skb, 1); 
+	udp_type = udp_pkt_type( skb, card );
 
-				if (!wanrouter_type_trans(skb, dev)) {
-					
-					/* can't decapsulate packet */
-					dev_kfree_skb(skb);
-					chan->drvstats_rx_intr.
-					     rx_intr_bfr_not_passed_to_stack ++;
- 					++ chan->ifstats.rx_errors;
-		                       	++ card->wandev.stats.rx_errors;
-					
-				} else {
-					netif_rx(skb);
-					chan->drvstats_rx_intr.
-						rx_intr_bfr_passed_to_stack ++;
-					++ chan->ifstats.rx_packets;
-					++ card->wandev.stats.rx_packets;
-                                        chan->ifstats.rx_bytes += len_incl_hdr;
-                                        card->wandev.stats.rx_bytes += 
-						len_incl_hdr;
+	if(udp_type != UDP_INVALID_TYPE) {
+
+		/* UDP Debug packet received, store the
+		 * packet and handle it in timer interrupt */
+
+		skb_pull(skb, 1); 
+		if (wanrouter_type_trans(skb, dev)){ 
+			if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){
+
+				flags->imask |= FR_INTR_TIMER;
+
+				if (udp_type == UDP_FPIPE_TYPE){
+					++chan->drvstats_rx_intr.rx_intr_PIPE_request;
 				}
-                	}
-            	}
-       	}
+			}
+		}
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	}else if (chan->common.usedby == API) {
+
+		/* We are in API mode. 
+                 * Add an API header to the RAW packet
+                 * and queue it into a circular buffer.
+                 * Then kick the fr_bh() bottom half handler */
+
+		api_rx_hdr_t* api_rx_hdr;
+		chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++;
+		chan->ifstats.rx_packets ++;
+		card->wandev.stats.rx_packets ++;
+
+		chan->ifstats.rx_bytes += skb->len;
+		card->wandev.stats.rx_bytes += skb->len;
+
+		skb_push(skb, sizeof(api_rx_hdr_t));
+		api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
+		api_rx_hdr->attr = frbuf->attr;
+		api_rx_hdr->time_stamp = frbuf->tmstamp;
+
+		skb->protocol = htons(ETH_P_IP);
+		skb->mac.raw  = skb->data;
+		skb->dev      = dev;
+		skb->pkt_type = WAN_PACKET_DATA;
+
+		bh_enqueue(dev, skb);
+
+		trigger_fr_bh(chan);
+	#endif
+
+	}else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){
+
+		//FIXME: Frame Relay IPX is not supported, Yet !
+		//if (chan->enable_IPX) {
+		//	fr_send(card, dlci, 0, skb->len,skb->data);
+		//}
+		wan_dev_kfree_skb(skb, FREE_READ);
+
+	} else if (is_arp(skb->data)) {
+
+		/* ARP support enabled Mar 16 2000 
+		 * Process incoming ARP reply/request, setup
+		 * dynamic routes. */ 
+
+		if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) {
+			if (net_ratelimit()){  
+				printk (KERN_INFO 
+				   "%s: Error processing ARP Packet.\n", 
+					card->devname);
+			}
+		}
+		wan_dev_kfree_skb(skb, FREE_READ);
+
+	} else if (skb->data[0] != 0x03) {
+
+		if (net_ratelimit()) { 
+			printk(KERN_INFO "%s: Non IETF packet discarded.\n", 
+				card->devname);
+		}
+		wan_dev_kfree_skb(skb, FREE_READ);
+
+	} else {
+
+		len_incl_hdr = skb->len;
+		/* Decapsulate packet and pass it up the
+		   protocol stack */
+		skb->dev = dev;
+		
+		if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){
+		
+			/* Make sure it's an Ethernet frame, otherwise drop it */
+			if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) {
+				skb_pull(skb, 8);
+				skb->protocol=eth_type_trans(skb,dev);
+			}else{
+				++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack;
+				++chan->ifstats.rx_errors;
+				++card->wandev.stats.rx_errors;
+				goto rx_done;
+			}
+		}else{
+		
+			/* remove hardware header */
+			buf = skb_pull(skb, 1); 
+			
+			if (!wanrouter_type_trans(skb, dev)) {
+				
+				/* can't decapsulate packet */
+				wan_dev_kfree_skb(skb, FREE_READ);
+
+				++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack;
+				++chan->ifstats.rx_errors;
+				++card->wandev.stats.rx_errors;
+				goto rx_done;	
+			}
+			skb->mac.raw = skb->data;
+		} 
+		
+
+		/* Send a packed up the IP stack */
+		netif_rx(skb);
+		++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack;
+		++chan->ifstats.rx_packets;
+		++card->wandev.stats.rx_packets;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+		chan->ifstats.rx_bytes += len_incl_hdr;
+		card->wandev.stats.rx_bytes += len_incl_hdr;
+#endif
+	}
+
+rx_done:
 
        	/* Release buffer element and calculate a pointer to the next one */ 
        	frbuf->flag = 0;
@@ -1869,14 +2376,36 @@
 
 }
 
-/*============================================================================
- * Transmit interrupt handler.
+/*==================================================================
+ * tx_intr:	Transmit interrupt handler.
+ *
+ * Rationale:
+ *      If the board is busy transmitting, if_send() will
+ *      buffers a single packet and turn on
+ *      the tx interrupt. Tx interrupt will be called
+ *      by the board, once the firmware can send more
+ *      data. Thus, no polling is required.	 
+ *
+ * Description:
+ *	Tx interrupt is called for each 
+ *      configured dlci channel. Thus: 
+ * 	1. Obtain the netowrk interface based on the
+ *         dlci number.
+ *      2. Check that network interface is up and
+ *         properly setup.
+ * 	3. Check for a buffered packed.
+ *      4. Transmit the packed.
+ *	5. If we are in WANPIPE mode, mark the 
+ *         NET_BH handler. 
+ *      6. If we are in API mode, kick
+ *         the AF_WANPIPE socket for more data. 
+ *	   
  */
 static void tx_intr(sdla_t *card)
 {
         fr508_flags_t* flags = card->flags;
         fr_tx_buf_ctl_t* bctl;
-        struct net_device* dev = card->wandev.dev;
+        netdevice_t* dev;
         fr_channel_t* chan;
 
         if(card->hw.type == SDLA_S514){
@@ -1888,61 +2417,112 @@
 
         /* Find the structure and make it unbusy */
         dev = find_channel(card, flags->dlci);
-        chan = dev->priv;
+	if (dev == NULL){
+		printk(KERN_INFO "NO DEV IN TX Interrupt\n");	
+		goto end_of_tx_intr;
+	}
+
+        if ((chan = dev->priv) == NULL){
+		printk(KERN_INFO "NO CHAN IN TX Interrupt\n");	
+		goto end_of_tx_intr;
+	}
 
-        if(!chan->transmit_length) {
+        if(!chan->transmit_length || !chan->delay_skb) {
                 printk(KERN_INFO "%s: tx int error - transmit length zero\n",
 				card->wandev.name);
-                return;
+                goto end_of_tx_intr;
         }
 
 	/* If the 'if_send()' procedure is currently checking the 'tbusy'
 	   status, then we cannot transmit. Instead, we configure the microcode
 	   so as to re-issue this transmit interrupt at a later stage. 
 	*/
-	if (test_bit(2, (void*)&card->wandev.critical)) {
+	if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
+
 		fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
 		bctl->flag = 0xA0;
 		dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
-		printk(KERN_INFO "%s: TX Interrupt Detected busy if_send\n",card->devname);
+		return;
 
- 	} else {
+ 	}else{
         	bctl->dlci = flags->dlci;
-	        bctl->length = chan->transmit_length;
-        	sdla_poke(&card->hw, bctl->offset, chan->transmit_buffer,
-                	chan->transmit_length);
+	        bctl->length = chan->transmit_length+chan->fr_header_len;
+        	sdla_poke(&card->hw, 
+		          fr_send_hdr(card,bctl->dlci,bctl->offset), 
+			  chan->delay_skb->data,
+ 	              	  chan->delay_skb->len);
 	        bctl->flag = 0xC0;
 
 		++chan->ifstats.tx_packets;
 		++card->wandev.stats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 		chan->ifstats.tx_bytes += chan->transmit_length;
 		card->wandev.stats.tx_bytes += chan->transmit_length;
+#endif
+
+		/* We must free an sk buffer, which we used
+		 * for delayed transmission; Otherwise, the sock
+		 * will run out of memory */
+                wan_dev_kfree_skb(chan->delay_skb, FREE_WRITE);
+
+		chan->delay_skb = NULL;				
         	chan->transmit_length = 0;
 
-	        /* if any other interfaces have transmit interrupts pending, */
-		/* do not disable the global transmit interrupt */
-		if(!(-- card->u.f.tx_interrupts_pending))
-        	        flags->imask &= ~FR_INTR_TXRDY;
+#ifdef LINUX_2_4
+		dev->trans_start = jiffies;
+#endif
 
-		netif_wake_queue (dev);
+#ifdef LINUX_2_0
+		wake_net_dev(dev);
+#else
+		if (is_queue_stopped(dev)){
+			/* If using API, than wakeup socket BH handler */
+			if (chan->common.usedby == API){
+				start_net_queue(dev);
+				wakeup_sk_bh(dev);
+			}else{
+				wake_net_dev(dev);
+			}
+		}
+#endif
 	}
+
+end_of_tx_intr:
+
+ 	/* if any other interfaces have transmit interrupts pending, 
+	 * do not disable the global transmit interrupt */
+	if(!(-- card->u.f.tx_interrupts_pending))
+       	        flags->imask &= ~FR_INTR_TXRDY;
+
+
 }
 
 
 /*============================================================================
- * Timer interrupt handler.
- FIXME: update comments as we modify the code
- * The timer interrupt is used for three purposes:
- *    1) Processing udp calls from 'fpipemon'.
- *    2) Processing update calls from /proc file system
- *    2) Reading board-level statistics for updating the proc file system.
- *    3) Sending inverse ARP request packets.
+ * timer_intr:	Timer interrupt handler.
+ *
+ * Rationale:
+ *	All commans must be executed within the timer
+ *      interrupt since no two commands should execute
+ *      at the same time.
+ *
+ * Description:
+ *	The timer interrupt is used to:
+ *    	1. Processing udp calls from 'fpipemon'.
+ *    	2. Processing update calls from /proc file system
+ *   	3. Reading board-level statistics for 
+ *         updating the proc file system.
+ *    	4. Sending inverse ARP request packets.
+ *	5. Configure a dlci/channel.
+ *	6. Unconfigure a dlci/channel. (Node only)
  */
+
 static void timer_intr(sdla_t *card)
 {
 	fr508_flags_t* flags = card->flags;
 
-        if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) {
+	/* UDP Debuging: fpipemon call */
+        if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) {
 		if(card->u.f.udp_type == UDP_FPIPE_TYPE) {
                     	if(process_udp_mgmt_pkt(card)) {
 		                card->u.f.timer_int_enabled &=
@@ -1951,81 +2531,132 @@
 		}
         }
 
-	if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
+	/* /proc update call : triggered from update() */
+	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
 		fr_get_err_stats(card);
 		fr_get_stats(card);
 		card->u.f.update_comms_stats = 0;
 		card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
 	}
 
+	/* Update the channel state call.  This is call is
+         * triggered by if_send() function */
+	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){
+		netdevice_t *dev;
+		if (card->wandev.state == WAN_CONNECTED){
+			for (dev=card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)){
+				fr_channel_t *chan = dev->priv;	
+				if (chan->common.state != WAN_CONNECTED){
+					update_chan_state(dev);
+				}
+			}
+		}
+		card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE;
+	}
+
+	/* configure a dlci/channel */
+	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){
+		config_fr(card);
+		card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
+	}
 
-//FIXME: Fix the dynamic IP addressing
-/*
-goto L4;
+	/* unconfigure a dlci/channel */
+	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){
+		unconfig_fr(card);
+		card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
+	}
 
-	// Used to send inarp request at given interval 
-	if (card->wandev.state == WAN_CONNECTED) {
-        	int num_remaining = 0;
-
-		dev = card->wandev.dev;
-		while (dev) {
-                	fr_channel_t *chan = dev->priv;
-
-                        if (chan->inarp == INARP_REQUEST &&
-                        	chan->state == WAN_CONNECTED) {
-                                num_remaining++;
-
-                                if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) {
-                                	send_inarp_request(card,dev);
-                                	chan->inarp_tick = jiffies;
-                                }
+	
+	/* Transmit ARP packets */
+	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){
+		int i=0;
+		netdevice_t *dev;
+
+		if (card->u.f.arp_dev == NULL)
+			card->u.f.arp_dev = card->wandev.dev;
+
+		dev = card->u.f.arp_dev;
+
+		for (;;){ 
+
+			fr_channel_t *chan = dev->priv;
+
+			/* If the interface is brought down cancel sending In-ARPs */
+			if (!(dev->flags&IFF_UP)){
+				clear_bit(0,&chan->inarp_ready);	
+			}
+
+			if (test_bit(0,&chan->inarp_ready)){
+
+				if (check_tx_status(card,dev)){
+					set_bit(ARP_CRIT,&card->wandev.critical);
+					break;
+				}
+
+				if (!send_inarp_request(card,dev)){
+					trigger_fr_arp(dev);
+					chan->inarp_tick = jiffies;
+				}
+
+				clear_bit(0,&chan->inarp_ready);
+				dev = move_dev_to_next(card,dev);
+				break;
+			}
+			dev = move_dev_to_next(card,dev);
+
+			if (++i == card->wandev.new_if_cnt){
+				card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP;
+				break;
 			}
-			dev = chan->slave;
-		}
-		if (!num_remaining) {   // no more to process 
-                        flags->imask &= ~FR_INTR_TIMER;
 		}
+		card->u.f.arp_dev = dev;
 	}
-L4:
-	;
-*/
+
         if(!card->u.f.timer_int_enabled)
                 flags->imask &= ~FR_INTR_TIMER;
 }
 
 
 /*============================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o 
+ * spur_intr:	Spurious interrupt handler.
+ * 
+ * Description:
+ *  	We don't know this interrupt.
+ *      Print a warning.
  */
+
 static void spur_intr (sdla_t* card)
 {
-	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+	if (net_ratelimit()){ 
+		printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+	}
 }
 
+
 //FIXME: Fix the IPX in next version
 /*===========================================================================
  *  Return 0 for non-IPXWAN packet
  *         1 for IPXWAN packet or IPX is not enabled!
  *  FIXME: Use a IPX structure here not offsets
  */
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
+static int handle_IPXWAN(unsigned char *sendpacket, 
+			 char *devname, unsigned char enable_IPX, 
+			 unsigned long network_number)
 {
 	int i;
 
-	if( sendpacket[1] == 0x00 &&
-	    sendpacket[2] == 0x80 &&
-	    sendpacket[6] == 0x81 &&
-	    sendpacket[7] == 0x37) { 
+	if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 &&
+	    sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { 
 
 		/* It's an IPX packet */
-		if(!enable_IPX) {
+		if (!enable_IPX){
 			/* Return 1 so we don't pass it up the stack. */
 			//FIXME: Take this out when IPX is fixed
-			printk (KERN_INFO 
+			if (net_ratelimit()){ 
+				printk (KERN_INFO 
 				"%s: WARNING: Unsupported IPX packet received and dropped\n",
 					devname);
+			}
 			return 1;
 		}
 	} else {
@@ -2033,39 +2664,33 @@
 		return 0;
 	}
 
-	if( sendpacket[24] == 0x90 &&
-	    sendpacket[25] == 0x04)
-	{
+	if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){
 		/* It's IPXWAN */
 
-		if( sendpacket[10] == 0x02 &&
-		    sendpacket[42] == 0x00)
-		{
+		if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){
+
 			/* It's a timer request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",
+					devname);
 
 			/* Go through the routing options and answer no to every
 			 * option except Unnumbered RIP/SAP
 			 */
-			for(i = 49; sendpacket[i] == 0x00; i += 5)
-			{
+			for(i = 49; sendpacket[i] == 0x00; i += 5){
 				/* 0x02 is the option for Unnumbered RIP/SAP */
-				if( sendpacket[i + 4] != 0x02)
-				{
+				if( sendpacket[i + 4] != 0x02){
 					sendpacket[i + 1] = 0;
 				}
 			}
 
 			/* Skip over the extended Node ID option */
-			if( sendpacket[i] == 0x04 )
-			{
+			if( sendpacket[i] == 0x04 ){
 				i += 8;
 			}
 
 			/* We also want to turn off all header compression opt.
 			 */
-			for(; sendpacket[i] == 0x80 ;)
-			{
+			for(; sendpacket[i] == 0x80 ;){
 				sendpacket[i + 1] = 0;
 				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
 			}
@@ -2073,12 +2698,15 @@
 			/* Set the packet type to timer response */
 			sendpacket[42] = 0x01;
 
-			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
-		}
-		else if( sendpacket[42] == 0x02 )
-		{
+			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",
+					devname);
+
+		} else if( sendpacket[42] == 0x02 ){
+
 			/* This is an information request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+			printk(KERN_INFO 
+				"%s: Received IPXWAN Information Request packet\n",
+						devname);
 
 			/* Set the packet type to information response */
 			sendpacket[42] = 0x03;
@@ -2103,10 +2731,10 @@
 				sendpacket[i] = 0;
 			}
 
-			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
-		}
-		else
-		{
+			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",
+					devname);
+		} else {
+
 			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
 			return 0;
 		}
@@ -2128,103 +2756,183 @@
 	return 0;
 }
 /*============================================================================
- * Process Route.
- * This routine is called as a polling routine to dynamically add/delete routes
- * negotiated by inverse ARP.  It is in this "task" because we don't want routes
- * to be added while in interrupt context.
-*/
+ * process_route
+ * 
+ * Rationale:
+ *	If the interface goes down, or we receive an ARP request,
+ *      we have to change the network interface ip addresses.
+ * 	This cannot be done within the interrupt.
+ *
+ * Description:
+ *
+ * 	This routine is called as a polling routine to dynamically 
+ *	add/delete routes negotiated by inverse ARP.  It is in this 
+ *    	"task" because we don't want routes to be added while in 
+ *      interrupt context.
+ *
+ * Usage:
+ *	This function is called by fr_poll() polling funtion.
+ */
 
-static void process_route (sdla_t* card)
+static void process_route (netdevice_t *dev)
 {
-	struct net_device* dev;
-	struct in_device *in_dev;
-    	struct rtentry route;
-        int err = 0;
-        mm_segment_t fs;
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 
-	/* Dynamic Route adding/removing */
-	dev = card->wandev.dev;
-	while (dev) {
-		fr_channel_t *chan = dev->priv;
-
-		if (chan->route_flag == ADD_ROUTE   ||
-		    chan->route_flag == REMOVE_ROUTE ) {
-			fs = get_fs();
-		
-			in_dev = dev->ip_ptr;
-
-			if( in_dev != NULL && in_dev->ifa_list != NULL) {
-				memset(&route, 0, sizeof(route));
-				route.rt_dev   = dev->name;
-				route.rt_flags = 0;
-
-				((struct sockaddr_in *) &(route.rt_dst)) ->
-					sin_addr.s_addr=in_dev->ifa_list->ifa_address;
-				((struct sockaddr_in *) &(route.rt_dst)) ->
-					sin_family = AF_INET;
-				((struct sockaddr_in *) &(route.rt_genmask)) ->
-					sin_addr.s_addr = 0xFFFFFFFF;
-				((struct sockaddr_in *) &(route.rt_genmask)) ->
-					sin_family = AF_INET;
-
-				switch(chan->route_flag) {
-
-				case ADD_ROUTE:
-					set_fs(get_ds());     /* get user space block */
-					err = ip_rt_ioctl( SIOCADDRT, &route);	
-					set_fs(fs);	      /* restore old block */
-
-					if (err) {
-						printk(KERN_INFO "%s: Adding of route failed.  Error: %d\n", card->devname,err);
-						printk(KERN_INFO "%s: Address: %s\n",
-						       chan->name,
-						       in_ntoa(in_dev->ifa_list->ifa_address) );
-					} else {
-						chan->route_flag = ROUTE_ADDED;
-					}
-					break;
+	struct ifreq if_info;
+	struct sockaddr_in *if_data;
+	mm_segment_t fs = get_fs();
+	u32 ip_tmp;
+	int err;
 
-				case REMOVE_ROUTE:
-					set_fs(get_ds());     /* get user space block */
-					err = ip_rt_ioctl( SIOCDELRT, &route);
-					set_fs(fs);	      /* restore old block */
-
-					if (err) {
-						printk(KERN_INFO "%s: Deleting of route failed.  Error: %d\n", card->devname,err);
-						printk(KERN_INFO "%s: Address: %s\n",
-						       dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
-					} else {
-						printk(KERN_INFO "%s: Removed route.\n",
-						       chan->name);
-						chan->route_flag = NO_ROUTE;
-					}
-					break;
-				} /* Case Statement */
-			}
-		} /* If ADD/DELETE ROUTE */
 
-		dev = chan->slave;
-	}  /* Device 'While' Loop */
+	switch(chan->route_flag){
 
-	card->poll = NULL;
-}
+	case ADD_ROUTE:
+				
+		/* Set remote addresses */
+		memset(&if_info, 0, sizeof(if_info));
+		strcpy(if_info.ifr_name, dev->name);
 
+		set_fs(get_ds());     /* get user space block */ 
+		
+		if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+		if_data->sin_addr.s_addr = chan->ip_remote;
+		if_data->sin_family = AF_INET;
+		err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
 
+		set_fs(fs);           /* restore old block */
 
-/****** Frame Relay Firmware-Specific Functions *****************************/
+		if (err) {
 
-/*============================================================================
- * Read firmware code version.
- * o fill string str with firmware version info. 
- */
-static int fr_read_version (sdla_t* card, char* str)
-{
-	fr_mbox_t* mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err;
+			printk(KERN_INFO 
+				"%s: Route Add failed.  Error: %d\n", 
+					card->devname,err);
+			printk(KERN_INFO "%s: Address: %s\n",
+				chan->name, in_ntoa(chan->ip_remote));
+
+		}else {
+			printk(KERN_INFO "%s: Route Added Successfully: %s\n",
+				card->devname,in_ntoa(chan->ip_remote));
+			chan->route_flag = ROUTE_ADDED;
+		}
+		break;
 
-	do
+	case REMOVE_ROUTE:
+
+		/* Set remote addresses */
+		memset(&if_info, 0, sizeof(if_info));
+		strcpy(if_info.ifr_name, dev->name);
+
+		ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);	
+
+		set_fs(get_ds());     /* get user space block */ 
+		
+		if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+		if_data->sin_addr.s_addr = 0;
+		if_data->sin_family = AF_INET;
+		err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+
+		set_fs(fs);    
+		
+		if (err) {
+
+			printk(KERN_INFO 
+				"%s: Deleting of route failed.  Error: %d\n", 
+					card->devname,err);
+			printk(KERN_INFO "%s: Address: %s\n",
+				dev->name,in_ntoa(chan->ip_remote) );
+
+		} else {
+
+			printk(KERN_INFO "%s: Route Removed Sucessfuly: %s\n", 
+				card->devname,in_ntoa(ip_tmp));
+			chan->route_flag = NO_ROUTE;
+		}
+		break;
+
+	} /* Case Statement */
+
+#else
+        /* Dynamic Route adding/removing */
+	struct rtentry route;
+        int err = 0;
+        unsigned long fs = get_fs();
+
+	memset(&route, 0, sizeof(route));
+	route.rt_dev   = dev->name;
+	route.rt_flags = 0;
+
+	((struct sockaddr_in *) &(route.rt_dst)) ->
+					sin_addr.s_addr=dev->pa_dstaddr;
+	((struct sockaddr_in *) &(route.rt_dst)) ->
+						sin_family = AF_INET;
+	((struct sockaddr_in *) &(route.rt_genmask)) ->
+				sin_addr.s_addr = 0xFFFFFFFF;
+	((struct sockaddr_in *) &(route.rt_genmask)) ->
+						sin_family = AF_INET;
+	switch(chan->route_flag) {
+
+	case ADD_ROUTE:
+
+		set_fs(get_ds());     /* get user space block */
+		err = ip_rt_new(&route);
+		set_fs(fs);           /* restore old block */
+
+		if (err) {
+			printk(KERN_INFO "%s: Adding of route failed.  Error: %d\n", 
+						card->devname,err);
+			printk(KERN_INFO "%s: Address: %s\n",
+				chan->name, in_ntoa(dev->pa_dstaddr) );
+			}
+		else {
+			chan->route_flag = ROUTE_ADDED;
+		}
+		break;
+
+	case REMOVE_ROUTE:
+
+		set_fs(get_ds());     /* get user space block */
+		err = ip_rt_kill(&route);
+		set_fs(fs);           /* restore old block */
+
+		if (err) {
+
+		     printk(KERN_INFO "%s: Deleting of route failed.  Error: %d\n", 
+				card->devname,err);
+		     printk(KERN_INFO "%s: Address: %s\n",
+				dev->name,in_ntoa(dev->pa_dstaddr) );
+		} else {
+
+		     printk(KERN_INFO "%s: Removed route.\n",
+			((fr_channel_t*)dev->priv)->name);
+		     chan->route_flag = NO_ROUTE;
+
+		}
+		break;
+	}
+
+#endif	
+
+}
+
+
+
+/****** Frame Relay Firmware-Specific Functions *****************************/
+
+/*============================================================================
+ * Read firmware code version.
+ * o fill string str with firmware version info. 
+ */
+static int fr_read_version (sdla_t* card, char* str)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
 	{
 		mbox->cmd.command = FR_READ_CODE_VERSION;
 		mbox->cmd.length = 0;
@@ -2264,6 +2972,12 @@
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	
 	} while (err && retry-- && fr_event(card, err, mbox));
+
+	/*NC Oct 12 2000 */
+	if (err != CMD_OK){
+		printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n",
+				card->devname,err);
+	}
 	
 	return err;
 }
@@ -2338,33 +3052,39 @@
 }
 
 /*============================================================================
- * Disable communications. 
+ * fr_comm_disable 
+ *
+ * Warning: This functin is called by the shutdown() procedure. It is void
+ *          since dev->priv are has already been deallocated and no
+ *          error checking is possible using fr_event() function.
  */
-static int fr_comm_disable (sdla_t* card)
+static void fr_comm_disable (sdla_t* card)
 {
 	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err;
 
-	do
-	{
-		mbox->cmd.command = FR_COMM_DISABLE;
-		mbox->cmd.length = 0;
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && fr_event(card, err, mbox));
-
-	retry = MAX_CMD_RETRY;
-
 	do {
 	mbox->cmd.command = FR_SET_MODEM_STATUS;
 	mbox->cmd.length = 1;
 	mbox->data[0] = 0;
 	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && fr_event(card, err, mbox));
+	} while (err && retry--);
 	
-	return err;
+	retry = MAX_CMD_RETRY;
+	
+	do
+	{
+		mbox->cmd.command = FR_COMM_DISABLE;
+		mbox->cmd.length = 0;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry--);
+
+	return;
 }
 
+
+
 /*============================================================================
  * Get communications error statistics. 
  */
@@ -2518,9 +3238,58 @@
 	return err;
 }
 
+
+static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset)
+{
+	netdevice_t *dev = find_channel(card,dlci);	
+	fr_channel_t *chan;
+
+	if (!dev || !(chan=dev->priv))
+		return offset;
+	
+	if (chan->fr_header_len){
+		sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len);
+	}
+	
+	return offset+chan->fr_header_len;
+}
+
 /*============================================================================
  * Send a frame on a selected DLCI.  
  */
+static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len,
+	void *buf, unsigned char hdr_len)
+{
+	fr_mbox_t* mbox = card->mbox + 0x800;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		mbox->cmd.dlci    = dlci;
+		mbox->cmd.attr    = attr;
+		mbox->cmd.length  = len+hdr_len;
+		mbox->cmd.command = FR_WRITE;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err) {
+		fr_tx_buf_ctl_t* frbuf;
+ 
+               	if(card->hw.type == SDLA_S514)
+			frbuf = (void*)(*(unsigned long*)mbox->data +
+                        	card->hw.dpmbase);
+		else
+			frbuf = (void*)(*(unsigned long*)mbox->data -
+                        	FR_MB_VECTOR + card->hw.dpmbase);
+
+		sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len);
+		frbuf->flag = 0x01;
+	}
+
+	return err;
+}
+
 static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len,
 	void *buf)
 {
@@ -2538,7 +3307,6 @@
 	} while (err && retry-- && fr_event(card, err, mbox));
 
 	if (!err) {
-
 		fr_tx_buf_ctl_t* frbuf;
  
                	if(card->hw.type == SDLA_S514)
@@ -2555,6 +3323,7 @@
 	return err;
 }
 
+
 /****** Firmware Asynchronous Event Handlers ********************************/
 
 /*============================================================================
@@ -2577,46 +3346,41 @@
 
 		case FRRES_CHANNEL_DOWN:
 			{
-			struct net_device *dev;
+			netdevice_t *dev;
 
 			/* Remove all routes from associated DLCI's */
-			dev = card->wandev.dev;
-			while (dev) {
+			for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
 				fr_channel_t *chan = dev->priv;
 				if (chan->route_flag == ROUTE_ADDED) {
 					chan->route_flag = REMOVE_ROUTE;
-					card->poll = &process_route;
 				}
 
 				if (chan->inarp == INARP_CONFIGURED) {
 					chan->inarp = INARP_REQUEST;
 				}
 
-				dev = chan->slave;
+				/* If the link becomes disconnected then,
+                                 * all channels will be disconnected
+                                 * as well.
+                                 */
+				set_chan_state(dev,WAN_DISCONNECTED);
 			}
-
+				
 			wanpipe_set_state(card, WAN_DISCONNECTED);
 			return 1;
 			}
 
 		case FRRES_CHANNEL_UP:
 			{
-			struct net_device *dev;
-			int num_requests = 0;
+			netdevice_t *dev;
 
-			/* Remove all routes from associated DLCI's */
-			dev = card->wandev.dev;
-			while (dev) {
-				fr_channel_t *chan = dev->priv;	
-				if( chan->inarp == INARP_REQUEST ){
-					num_requests++;
-					chan->inarp_tick = jiffies;
-				}
-				dev = chan->slave;
+			/* FIXME: Only startup devices that are on the list */
+			
+			for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
+				
+				set_chan_state(dev,WAN_CONNECTED);
 			}
 
-			/* Allow timer interrupts */
-			if (num_requests) flags->imask |= 0x20;	
 			wanpipe_set_state(card, WAN_CONNECTED);
 			return 1;
 			}
@@ -2644,8 +3408,10 @@
  
 		case FRRES_CIR_OVERFLOW:
 			break;
+			
 		case FRRES_BUFFER_OVERFLOW:
 			break; 
+			
 		default:
 			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
 				, card->devname, mbox->cmd.command, event);
@@ -2684,13 +3450,13 @@
 	dlci_status_t* status = (void*)mbox->data;
 	int cnt = mbox->cmd.length / sizeof(dlci_status_t);
 	fr_channel_t *chan;
-	struct net_device* dev2;
+	netdevice_t* dev2;
 	
 
 	for (; cnt; --cnt, ++status) {
 
 		unsigned short dlci= status->dlci;
-		struct net_device* dev = find_channel(card, dlci);
+		netdevice_t* dev = find_channel(card, dlci);
 		
 		if (dev == NULL){
 			printk(KERN_INFO 
@@ -2707,7 +3473,7 @@
 					"%s: DLCI %u is inactive!\n",
 					card->devname, dlci);
 
-				if (dev && netif_running(dev))
+				if (dev && is_dev_running(dev))
 					set_chan_state(dev, WAN_DISCONNECTED);
 			}
 	
@@ -2717,12 +3483,14 @@
 					"%s: DLCI %u has been deleted!\n",
 					card->devname, dlci);
 
-				if (dev && netif_running(dev)) {
+				if (dev && is_dev_running(dev)){
+
 					fr_channel_t *chan = dev->priv;
 
 					if (chan->route_flag == ROUTE_ADDED) {
 						chan->route_flag = REMOVE_ROUTE;
-						card->poll = &process_route;
+						/* The state change will trigger
+                                                 * the fr polling routine */
 					}
 
 					if (chan->inarp == INARP_CONFIGURED) {
@@ -2740,16 +3508,15 @@
 				   DLCI(s) when they become active.
 			 	*/ 
 				chan->dlci_configured = DLCI_CONFIG_PENDING;
-			
-				if (dev && netif_running(dev))
-					set_chan_state(dev, WAN_CONNECTED);
+	
+				set_chan_state(dev, WAN_CONNECTED);
 		
 			}
 		}
 	}
 	
-	dev2 = card->wandev.dev;
-	while (dev2) {
+	for (dev2 =card->wandev.dev; dev2; dev2 = *((netdevice_t **)dev2->priv)){
+		
 		chan = dev2->priv;
 	
 		if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
@@ -2758,7 +3525,6 @@
 			}
 		}
 
-		dev2 = chan->slave;
 	}
 	return 1;
 }
@@ -2767,8 +3533,7 @@
 static int fr_init_dlci (sdla_t *card, fr_channel_t *chan)
 {
 	fr_dlc_conf_t cfg;
-	fr508_flags_t* flags = card->flags;
-
+	
 	memset(&cfg, 0, sizeof(cfg));
 
 	if ( chan->cir_status == CIR_DISABLED) {
@@ -2786,22 +3551,16 @@
 	}
 	
 	if (fr_dlci_configure( card, &cfg , chan->dlci)){
-	printk(KERN_INFO 
-		"%s: DLCI Configure failed for %d\n",
-			card->devname, chan->dlci);
+		printk(KERN_INFO 
+			"%s: DLCI Configure failed for %d\n",
+				card->devname, chan->dlci);
 		return 1;	
 	}
 	
 	chan->dlci_configured = DLCI_CONFIGURED;
 
-	/* Allow timer interrupts */
-	if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) {
-		chan->inarp_tick = jiffies;
-		flags->imask |= 0x20;	
-	}	
-
 	/* Read the interface byte mapping into the channel 
-	   structure.
+	 * structure.
 	 */
 	read_DLCI_IB_mapping( card, chan );
 
@@ -2812,7 +3571,7 @@
 /*============================================================================
  * Update channel state. 
  */
-static int update_chan_state (struct net_device* dev)
+static int update_chan_state (netdevice_t* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -2828,14 +3587,25 @@
 	} while (err && retry-- && fr_event(card, err, mbox));
 
 	if (!err) {
-
+		
 		unsigned short* list = (void*)mbox->data;
 		int cnt = mbox->cmd.length / sizeof(short);
-
+		
+		err=1;
+		
 		for (; cnt; --cnt, ++list) {
 
 			if (*list == chan->dlci) {
  				set_chan_state(dev, WAN_CONNECTED);
+
+
+				/* May 23 2000. NC
+				 * When a dlci is added or restarted,
+                                 * the dlci_int_interface pointer must
+				 * be reinitialized.  */
+				if (!chan->dlci_int_interface){
+					err=fr_init_dlci (card,chan);
+				}
 				break;
 			}
 		}
@@ -2847,16 +3617,12 @@
 /*============================================================================
  * Set channel state.
  */
-static void set_chan_state (struct net_device* dev, int state)
+static void set_chan_state (netdevice_t* dev, int state)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
-	if (chan->state != state) {
+	if (chan->common.state != state) {
 
 		switch (state) {
 
@@ -2864,6 +3630,12 @@
 				printk(KERN_INFO
 					"%s: Interface %s: DLCI %d connected\n",
 					card->devname, dev->name, chan->dlci);
+
+				/* If the interface was previoulsy down,
+                                 * bring it up, since the channel is active */
+
+				trigger_fr_poll (dev);
+				trigger_fr_arp  (dev);
 				break;
 
 			case WAN_CONNECTING:
@@ -2876,20 +3648,29 @@
 				printk (KERN_INFO 
 				    "%s: Interface %s: DLCI %d disconnected!\n",
 					card->devname, dev->name, chan->dlci);
+			
+				/* If the interface is up, bring it down,
+                                 * since the channel is now disconnected */
+				trigger_fr_poll (dev);
 				break;
 		}
 
-		chan->state = state;
+		chan->common.state = state;
 	}
 
 	chan->state_tick = jiffies;
-	restore_flags(flags);
 }
 
 /*============================================================================
  * Find network device by its channel number.
+ *
+ * We need this critical flag because we change
+ * the dlci_to_dev_map outside the interrupt.
+ *
+ * NOTE: del_if() functions updates this array, it uses
+ *       the spin locks to avoid corruption.
  */
-static struct net_device* find_channel (sdla_t* card, unsigned dlci)
+static netdevice_t* find_channel (sdla_t* card, unsigned dlci)
 {
 	if(dlci > HIGHEST_VALID_DLCI)
 		return NULL;
@@ -2945,9 +3726,15 @@
                                 struct sk_buff *skb, int dlci)
 {
         int udp_pkt_stored = 0;
-
-        if(!card->u.f.udp_pkt_lgth &&(skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
-                card->u.f.udp_pkt_lgth = skb->len;
+	
+	netdevice_t *dev=find_channel(card,dlci);
+	fr_channel_t *chan;
+	
+	if (!dev || !(chan=dev->priv))
+		return 1;
+	
+        if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
+                card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len;
                 card->u.f.udp_type = udp_type;
                 card->u.f.udp_pkt_src = udp_pkt_src;
                 card->u.f.udp_dlci = dlci;
@@ -2960,8 +3747,12 @@
 							dlci);
 	}
 
-        dev_kfree_skb(skb);
-
+        if(udp_pkt_src == UDP_PKT_FRM_STACK){
+                wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+                wan_dev_kfree_skb(skb, FREE_READ);
+	}
+		
         return(udp_pkt_stored);
 }
 
@@ -2982,7 +3773,7 @@
 	int err;
 	struct timeval tv;
 	int udp_mgmt_req_valid = 1;
-        struct net_device* dev;
+        netdevice_t* dev;
         fr_channel_t* chan;
         fr_udp_pkt_t *fr_udp_pkt;
 	unsigned short num_trc_els;
@@ -2995,7 +3786,14 @@
 
 	/* Find network interface for this packet */
 	dev = find_channel(card, dlci);
-        chan = dev->priv;
+	if (!dev){
+		card->u.f.udp_pkt_lgth = 0;
+		return 1;
+	}
+        if ((chan = dev->priv) == NULL){
+		card->u.f.udp_pkt_lgth = 0;
+		return 1;
+	}
 
 	/* If the UDP packet is from the network, we are going to have to 
 	   transmit a response. Before doing so, we must check to see that
@@ -3003,39 +3801,49 @@
 	   that we are not already in a 'delayed transmit' state.
 	*/
 	if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		if (test_bit(0, (void*)&card->wandev.critical) ||
-			test_bit(2, (void*)&card->wandev.critical)) {
-			return 0;
-  		}
-		if((netif_queue_stopped(dev)) || (card->u.f.tx_interrupts_pending)) {
-			return 0;
+		if (check_tx_status(card,dev)){
+			card->u.f.udp_pkt_lgth = 0;
+			return 1;
 		}
         }
 
         fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data;
 
-	switch(fr_udp_pkt->cblock.command) {
+	if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+	
+		switch(fr_udp_pkt->cblock.command) {
 
-		case FPIPE_ENABLE_TRACING:
-		case FPIPE_DISABLE_TRACING:
-		case FPIPE_GET_TRACE_INFO:
-		case FR_SET_FT1_MODE:
-			if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-                    		chan->drvstats_gen.
-					UDP_PIPE_mgmt_direction_err ++;
+			case FR_READ_MODEM_STATUS:
+			case FR_READ_STATUS:
+			case FPIPE_ROUTER_UP_TIME:
+			case FR_READ_ERROR_STATS:
+			case FPIPE_DRIVER_STAT_GEN:
+			case FR_READ_STATISTICS:
+			case FR_READ_ADD_DLC_STATS:
+			case FR_READ_CONFIG:
+			case FR_READ_CODE_VERSION:
+				udp_mgmt_req_valid = 1;
+				break;
+			default:
 				udp_mgmt_req_valid = 0;
 				break;
-			}
-
-		default:
-			break;
-       	}
+		}
+	}
 
 	if(!udp_mgmt_req_valid) {
 		/* set length to 0 */
 		fr_udp_pkt->cblock.length = 0;
 		/* set return code */
 		fr_udp_pkt->cblock.result = 0xCD; 
+		
+		chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++;
+
+		if (net_ratelimit()){	
+			printk(KERN_INFO 
+			"%s: Warning, Illegal UDP command attempted from network: %x\n",
+			card->devname,fr_udp_pkt->cblock.command);
+		}
+		
 	} else {   
            
 		switch(fr_udp_pkt->cblock.command) {
@@ -3074,7 +3882,7 @@
 				/* Calculate the maximum trace data area in */
 				/* the UDP packet */
 				card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT -
-					sizeof(fr_encap_hdr_t) -
+					//sizeof(fr_encap_hdr_t) -
 					sizeof(ip_pkt_t) -
 					sizeof(udp_pkt_t) -
 					sizeof(wp_mgmt_t) -
@@ -3204,7 +4012,7 @@
                 case FPIPE_FT1_READ_STATUS:
 			sdla_peek(&card->hw, 0xF020,
 				&fr_udp_pkt->data[0x00] , 2);
-			fr_udp_pkt->cblock.length = 2;
+			fr_udp_pkt->cblock.length = mbox->cmd.length = 2;
 			fr_udp_pkt->cblock.result = 0;
 			break;
 
@@ -3220,44 +4028,32 @@
 						chan->router_start_time;
     	                *(unsigned long *)&fr_udp_pkt->data =
     				chan->router_up_time;	
-			mbox->cmd.length = 4;
+			mbox->cmd.length = fr_udp_pkt->cblock.length = 4;
+			fr_udp_pkt->cblock.result = 0;
 			break;
 
-
-		case FR_FT1_STATUS_CTRL:
-			if(fr_udp_pkt->data[0] == 1) {
-				if(rCount++ != 0 ){
-					fr_udp_pkt->cblock.result = 0;
-					mbox->cmd.length = 1;
-					break;
-				} 
-			}
-           
-			/* Disable FT1 MONITOR STATUS */
-                        if(fr_udp_pkt->data[0] == 0) {
-				if( --rCount != 0) {
-                                        fr_udp_pkt->cblock.result = 0;
-					mbox->cmd.length = 1;
-					break;
-				} 
-			}  
-
 		case FPIPE_DRIVER_STAT_IFSEND:
 			memcpy(fr_udp_pkt->data,
 				&chan->drvstats_if_send.if_send_entry,
 				sizeof(if_send_stat_t));
-			mbox->cmd.length = sizeof(if_send_stat_t);	
+			mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t);	
+			fr_udp_pkt->cblock.result = 0;
 			break;
 	
 		case FPIPE_DRIVER_STAT_INTR:
+
 			memcpy(fr_udp_pkt->data,
                                 &card->statistics.isr_entry,
                                 sizeof(global_stats_t));
+
                         memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)],
                                 &chan->drvstats_rx_intr.rx_intr_no_socket,
                                 sizeof(rx_intr_stat_t));
-			mbox->cmd.length = sizeof(global_stats_t) +
+
+			mbox->cmd.length = fr_udp_pkt->cblock.length = 
+					sizeof(global_stats_t) +
 					sizeof(rx_intr_stat_t);
+			fr_udp_pkt->cblock.result = 0;
 			break;
 
 		case FPIPE_DRIVER_STAT_GEN:
@@ -3268,13 +4064,34 @@
                         memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
                                &card->statistics, sizeof(global_stats_t));
 
-                        fr_udp_pkt->cblock.result = 0;
-                        fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
+                        mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
                                                      sizeof(rx_intr_stat_t);
-                        mbox->cmd.length = fr_udp_pkt->cblock.length;
+			fr_udp_pkt->cblock.result = 0;
                         break;
-		
+
+
+		case FR_FT1_STATUS_CTRL:
+			if(fr_udp_pkt->data[0] == 1) {
+				if(rCount++ != 0 ){
+					fr_udp_pkt->cblock.result = 0;
+					mbox->cmd.length = 1;
+					break;
+				} 
+			}
+           
+			/* Disable FT1 MONITOR STATUS */
+                        if(fr_udp_pkt->data[0] == 0) {
+				if( --rCount != 0) {
+                                        fr_udp_pkt->cblock.result = 0;
+					mbox->cmd.length = 1;
+					break;
+				} 
+			}  
+			goto udp_mgmt_dflt;
+
+			
 		default:
+udp_mgmt_dflt:
  			do {
 				memcpy(&mbox->cmd,
 					&fr_udp_pkt->cblock.command,
@@ -3312,12 +4129,19 @@
         len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length);
 
         if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		
-                err = fr_send(card, dlci, 0, len, card->u.f.udp_pkt_data);
-		if (err) 
+
+		chan->fr_header_len=2;
+		chan->fr_header[0]=Q922_UI;
+		chan->fr_header[1]=NLPID_IP;
+			
+		err = fr_send_data_header(card, dlci, 0, len, 
+			card->u.f.udp_pkt_data,chan->fr_header_len);
+		if (err){ 
 			chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++;
-		else
+		}else{
 			chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++;
+		}
+		
 	} else {
 		/* Allocate socket buffer */
 		if((new_skb = dev_alloc_skb(len)) != NULL) {
@@ -3326,22 +4150,12 @@
 			buf = skb_put(new_skb, len);
 			memcpy(buf, card->u.f.udp_pkt_data, len);
         
-			/* Decapsulate packet and pass it up the protocol 
-			   stack */
+			chan->drvstats_gen.
+				UDP_PIPE_mgmt_passed_to_stack ++;
 			new_skb->dev = dev;
-			buf = skb_pull(new_skb, 1);  /* remove hardware header*/
-			
-			if(!wanrouter_type_trans(new_skb, dev)) {
-
-				chan->drvstats_gen.
-					UDP_PIPE_mgmt_not_passed_to_stack ++;
-				/* can't decapsulate packet */
-				dev_kfree_skb(new_skb);
-			} else {
-				chan->drvstats_gen.
-					UDP_PIPE_mgmt_passed_to_stack ++;
-				netif_rx(new_skb);
-                	}
+			new_skb->protocol = htons(ETH_P_IP);
+			new_skb->mac.raw = new_skb->data;
+			netif_rx(new_skb);
             	
 		} else {
 			chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++;
@@ -3360,15 +4174,19 @@
  * Send Inverse ARP Request
  */
 
-int send_inarp_request(sdla_t *card, struct net_device *dev)
+int send_inarp_request(sdla_t *card, netdevice_t *dev)
 {
+	int err=0;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
 	arphdr_1490_t *ArpPacket;
 	arphdr_fr_t *arphdr;
 	fr_channel_t *chan = dev->priv;
 	struct in_device *in_dev;
 
 	in_dev = dev->ip_ptr;
-	
+
 	if(in_dev != NULL ) {	
 
 		ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
@@ -3396,16 +4214,66 @@
 		arphdr->ar_tha = 0; 		/* dst HW DLCI - Doesn't matter */
 		arphdr->ar_tip = 0;		/* Remote Address -- what we want */
 
-		printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci);
-                fr_send(card, chan->dlci, 0,
-		   sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
-		   (void *)ArpPacket);
+		err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
+		   			(void *)ArpPacket);
+
+		if (!err){
+			printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", 
+				card->devname, chan->dlci);
+			clear_bit(ARP_CRIT,&card->wandev.critical);
+		}
+
 		kfree(ArpPacket);
+	}else{
+		printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n",
+				card->devname,dev->name);
+		return 1;
 	}
 
-	return 1;
-}
-	
+#else
+        arphdr_1490_t *ArpPacket;
+        arphdr_fr_t *arphdr;
+        fr_channel_t *chan = dev->priv;
+
+        ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
+        /* SNAP Header indicating ARP */
+        ArpPacket->control      = 0x03;
+        ArpPacket->pad          = 0x00;
+        ArpPacket->NLPID        = 0x80;
+        ArpPacket->OUI[0]       = 0;
+        ArpPacket->OUI[1]       = 0;
+        ArpPacket->OUI[2]       = 0;
+        ArpPacket->PID          = 0x0608;
+
+        arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet
+       /* InARP request */
+        arphdr->ar_hrd = 0x0F00;        /* Frame Relay HW type */
+        arphdr->ar_pro = 0x0008;        /* IP Protocol         */
+        arphdr->ar_hln = 2;             /* HW addr length      */
+        arphdr->ar_pln = 4;             /* IP addr length      */
+        arphdr->ar_op = htons(0x08);    /* InARP Request       */
+        arphdr->ar_sha = 0;             /* src HW DLCI - Doesn't matter */
+        arphdr->ar_sip = dev->pa_addr;  /* Local Address       */
+        arphdr->ar_tha = 0;             /* dst HW DLCI - Doesn't matter */
+        arphdr->ar_tip = 0;             /* Remote Address -- what we want */
+
+        printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci);
+        err = fr_send(card, chan->dlci, 0,
+                   sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
+                   (void *)ArpPacket);
+	
+	if (!err){
+         	printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n",
+                        card->devname, chan->dlci);
+                clear_bit(ARP_CRIT,&card->wandev.critical);
+        }
+
+        kfree(ArpPacket);
+#endif
+
+	return 0;
+}
+	
 
 /*==============================================================================
  * Check packet for ARP Type
@@ -3426,123 +4294,289 @@
  * Process ARP Packet Type
  */
 
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev)
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev)
 {
 
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
 	fr_rx_buf_ctl_t* frbuf = card->rxmb;
 	struct in_device *in_dev;
+	fr_channel_t *chan = dev->priv;		
+#else
+  	arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
+        fr_rx_buf_ctl_t* frbuf = card->rxmb;
+#endif
+	
+	/* Before we transmit ARP packet, we must check 
+	 * to see that we are not currently transmitting a 
+	 * frame (in 'if_send()') and that we are not 
+	 * already in a 'delayed transmit' state. */
+	if (check_tx_status(card,dev)){
+		if (net_ratelimit()){ 	
+			printk(KERN_INFO "%s: Disabling comminication to process ARP\n",
+					card->devname);
+		}
+		set_bit(ARP_CRIT,&card->wandev.critical);
+		return 0;
+	}
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 
 	in_dev = dev->ip_ptr;
-	if( in_dev != NULL && in_dev->ifa_list != NULL) {
-		switch (ntohs(arphdr->ar_op)) {
 
-		case 0x08:  // Inverse ARP request  -- Send Reply, add route.
+	/* Check that IP addresses exist for our network address */
+	if (in_dev == NULL || in_dev->ifa_list == NULL) 
+		return -1;
+
+	switch (ntohs(arphdr->ar_op)) {
+
+	case 0x08:  // Inverse ARP request  -- Send Reply, add route.
 			
-			/* Check for valid Address */
-			printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+		/* Check for valid Address */
+		printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %s\n", 
+			card->devname, in_ntoa(arphdr->ar_sip));
 
-			if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
-				printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", card->devname);
-				printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask);
-				printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local);
-				return -1;
-			}
-		
-			if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
-				printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", card->devname);
-				return -1;
-			}
+
+		/* Check that the network address is the same as ours, only
+                 * if the netowrk mask is not 255.255.255.255. Otherwise
+                 * this check would not make sense */
+
+		if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && 
+		    (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != 
+		    (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){
+
+			printk(KERN_INFO 
+				"%s: Invalid PtP address. %s  InARP ignored.\n", 
+					card->devname,in_ntoa(arphdr->ar_sip));
+
+			printk(KERN_INFO "%s: mask %s\n", 
+				card->devname, in_ntoa(in_dev->ifa_list->ifa_mask));
+				printk(KERN_INFO "%s: local %s\n", 
+				card->devname,in_ntoa(in_dev->ifa_list->ifa_local));
+			return -1;
+		}
+
+		if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){
+			printk(KERN_INFO 
+				"%s: Local addr = PtP addr.  InARP ignored.\n", 
+					card->devname);
+			return -1;
+		}
 	
-			arphdr->ar_op = htons(0x09);	/* InARP Reply */
+		arphdr->ar_op = htons(0x09);	/* InARP Reply */
 
-			/* Set addresses */
-			arphdr->ar_tip = arphdr->ar_sip;
-			arphdr->ar_sip = in_dev->ifa_list->ifa_local;
+		/* Set addresses */
+		arphdr->ar_tip = arphdr->ar_sip;
+		arphdr->ar_sip = in_dev->ifa_list->ifa_local;
 
-                        fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
+		chan->ip_local = in_dev->ifa_list->ifa_local;
+		chan->ip_remote = arphdr->ar_sip;
 
-			/* Modify Point-to-Point Address */
-			{
-			struct ifreq if_info;
-			struct sockaddr_in *if_data;
-			mm_segment_t fs = get_fs();
-			int err;
-
-			/* Set remote addresses */
-			memset(&if_info, 0, sizeof(if_info));
-			strcpy(if_info.ifr_name, dev->name);
-
-          		set_fs(get_ds());     /* get user space block */ 
-	
-			if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
-			if_data->sin_addr.s_addr = arphdr->ar_tip;
-			if_data->sin_family = AF_INET;
-			err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+		fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
 
-                	set_fs(fs);           /* restore old block */
+		if (test_bit(ARP_CRIT,&card->wandev.critical)){
+			if (net_ratelimit()){ 	
+				printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n",
+					card->devname);
 			}
-				
-			/* Add Route Flag */
-			/* The route will be added in the polling routine so
-			   that it is not interrupt context. */
+		}
+		clear_bit(ARP_CRIT,&card->wandev.critical);
+		
+		chan->ip_local = in_dev->ifa_list->ifa_local;
+		chan->ip_remote = arphdr->ar_sip;
 
-			((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
-			card->poll	= &process_route;
+		/* Add Route Flag */
+		/* The route will be added in the polling routine so
+		   that it is not interrupt context. */
 
-			break;
+		chan->route_flag = ADD_ROUTE;
+		trigger_fr_poll (dev);
 
-		case 0x09:  // Inverse ARP reply
+		break;
 
-			/* Check for valid Address */
-			printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+	case 0x09:  // Inverse ARP reply
 
-			if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
-				printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", card->devname);
-				return -1;
-			}
+		/* Check for valid Address */
+		printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", 
+				card->devname, in_ntoa(arphdr->ar_sip));
 
-			if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
-				printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", card->devname);
-				return -1;
-			}			
 
-			/* Modify Point-to-Point Address */
-			{
-			struct ifreq if_info;
-			struct sockaddr_in *if_data;
-			mm_segment_t fs = get_fs();
-			int err;
+		/* Compare network addresses, only if network mask
+                 * is not 255.255.255.255  It would not make sense
+                 * to perform this test if the mask was all 1's */
 
-			/* Set remote addresses */
-			memset(&if_info, 0, sizeof(if_info));
-			strcpy(if_info.ifr_name, dev->name);
+		if (in_dev->ifa_list->ifa_mask != 0xffffffff &&
+		    (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != 
+			(in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
 
-          		set_fs(get_ds());     /* get user space block */ 
-	
-			if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
-			if_data->sin_addr.s_addr = arphdr->ar_sip;
-			if_data->sin_family = AF_INET;
-			err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+			printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", 
+					card->devname);
+			return -1;
+		}
 
-                	set_fs(fs);           /* restore old block */
-			}
+		/* Make sure that the received IP address is not
+                 * the same as our own local address */
+		if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
+			printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", 
+				card->devname);
+			return -1;
+		}			
 
-			/* Add Route Flag */
-			/* The route will be added in the polling routine so
-			   that it is not interrupt context. */
+		chan->ip_local  = in_dev->ifa_list->ifa_local;
+		chan->ip_remote = arphdr->ar_sip;
 
-			((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
-			((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED;
-			card->poll	= &process_route;
-			
-			break;
-		default:  // ARP's and RARP's -- Shouldn't happen.
-		}
+		/* Add Route Flag */
+		/* The route will be added in the polling routine so
+		   that it is not interrupt context. */
+
+		chan->route_flag = ADD_ROUTE;
+		chan->inarp = INARP_CONFIGURED;
+		trigger_fr_poll(dev);
+		
+		break;
+	default:  // ARP's and RARP's -- Shouldn't happen.
 	}
 
 	return 0;	
+#else
+
+        switch (ntohs(arphdr->ar_op)) {
+
+                case 0x08:  // Inverse ARP request  -- Send Reply, add route.
+
+                        /* Check for valid Address */
+                        printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", 
+				((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+
+
+			if (dev->pa_mask != 0xFFFFFFFF){
+
+	                        if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
+        	                        printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", 
+							card->devname);
+                        	        return -1;
+                        	}
+			}
+
+                        if (dev->pa_addr == arphdr->ar_sip) {
+                                printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", 
+						card->devname);
+                                return -1;
+                        }
+
+                        arphdr->ar_op = htons(0x09);    /* InARP Reply */
+
+                        /* Set addresses */
+                        arphdr->ar_tip = arphdr->ar_sip;
+                        arphdr->ar_sip = dev->pa_addr;
+
+                        fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
+
+			clear_bit(ARP_CRIT,&card->wandev.critical);
+
+                        /* Modify Point-to-Point Address */
+                        dev->pa_dstaddr = arphdr->ar_tip;
+
+                        /* Add Route Flag */
+                        /* The route will be added in the polling routine so
+                           that it is not interrupt context. */
+                        ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
+			trigger_fr_poll(dev);
+
+                        break;
+                case 0x09:  // Inverse ARP reply
+
+                        /* Check for valid Address */
+                        printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", 
+				((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+
+                        if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
+                                printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", 
+					card->devname);
+                                return -1;
+                        }
+
+                        if (dev->pa_addr == arphdr->ar_sip) {
+                                printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", 
+					card->devname);
+                                return -1;
+                        }
+
+                        /* Modify Point-to-Point Address */
+                        dev->pa_dstaddr = arphdr->ar_sip;
+                        /* Add Route Flag */
+                        /* The route will be added in the polling routine so
+                           that it is not interrupt context. */
+
+                        ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
+                        ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED;
+			trigger_fr_poll(dev);
+
+                        break;
+                default:  // ARP's and RARP's -- Shouldn't happen.
+        }
+
+        return 0;
+
+#endif
+}
+
+
+/*============================================================
+ * trigger_fr_arp
+ *
+ * Description:
+ * 	Add an fr_arp() task into a arp
+ *      timer handler for a specific dlci/interface.  
+ *      This will kick the fr_arp() routine 
+ *      within the specified time interval. 
+ *
+ * Usage:
+ * 	This timer is used to send ARP requests at
+ *      certain time intervals. 
+ * 	Called by an interrupt to request an action
+ *      at a later date.
+ */	
+
+static void trigger_fr_arp (netdevice_t *dev)
+{
+	fr_channel_t* chan = dev->priv;
+
+	del_timer(&chan->fr_arp_timer);
+	chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ);
+	add_timer(&chan->fr_arp_timer);
+	return;
+}
+
+
+
+/*==============================================================================
+ * ARP Request Action
+ *
+ *	This funciton is called by timer interrupt to send an arp request
+ *      to the remote end.
+ */
+
+static void fr_arp (unsigned long data)
+{
+	netdevice_t *dev = (netdevice_t *)data;
+	fr_channel_t *chan = dev->priv;
+	volatile sdla_t *card = chan->card;
+	fr508_flags_t* flags = card->flags;
+
+	/* Send ARP packets for all devs' until
+         * ARP state changes to CONFIGURED */
+
+	if (chan->inarp == INARP_REQUEST &&
+	    chan->common.state == WAN_CONNECTED && 
+	    card->wandev.state == WAN_CONNECTED){
+		set_bit(0,&chan->inarp_ready);
+		card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP;
+		flags->imask |= FR_INTR_TIMER;	
+	}
+ 
+	return;
 }
 	
 
@@ -3555,11 +4589,6 @@
 	fr_mbox_t* mb = card->mbox;
 	int err,i;
 
-	/* The critical flag is unset here because we want to get into the
-	   ISR without the flag already set. The If_open sets the flag.
-	*/
-        clear_bit(1, (void*)&card->wandev.critical);
-
         err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 );
 	
 	if (err == CMD_OK) {
@@ -3582,7 +4611,6 @@
 	if( err != CMD_OK ) 
 		return err;
 
-	set_bit(1, (void*)&card->wandev.critical);
 	return 0;
 }
 
@@ -3593,6 +4621,9 @@
 {
 	fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data;
 
+	/* Quick HACK */
+	
+	
         if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
 		(fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
 		(fr_udp_pkt->udp_pkt.udp_dst_port == 
@@ -3600,10 +4631,10 @@
 		(fr_udp_pkt->wp_mgmt.request_reply == 
 		UDPMGMT_REQUEST)) {
                         if(!strncmp(fr_udp_pkt->wp_mgmt.signature,
-                                UDPMGMT_FPIPE_SIGNATURE, 8))
+                                UDPMGMT_FPIPE_SIGNATURE, 8)){
                                 return UDP_FPIPE_TYPE;
+			}
 	}
-
         return UDP_INVALID_TYPE;
 }
 
@@ -3674,38 +4705,772 @@
 		card->devname, chan->dlci);
 }
 
+
+
 void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
 {
-
 	if (card->hw.type != SDLA_S514){
-#ifdef CONFIG_SMP
-		spin_lock_irqsave(&card->lock, *smp_flags);
+
+#if defined(__SMP__) || defined(LINUX_2_4)
+		spin_lock_irqsave(&card->wandev.lock, *smp_flags);
 #else
-    		disable_irq(card->hw.irq);
+          	disable_irq(card->hw.irq);
 #endif
-	}
-#ifdef CONFIG_SMP
-	else{
-		spin_lock(&card->lock);
-	}	
+	}else{
+#if defined(__SMP__) || defined(LINUX_2_4)
+		spin_lock(&card->u.f.if_send_lock);
 #endif
+	}
+	return;
 }
 
+
 void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
 {
 	if (card->hw.type != SDLA_S514){
-#ifdef CONFIG_SMP
-		spin_unlock_irqrestore(&card->lock, *smp_flags);
+
+#if defined(__SMP__) || defined(LINUX_2_4)
+		spin_unlock_irqrestore (&card->wandev.lock, *smp_flags);
 #else
-    		enable_irq(card->hw.irq);
+          	enable_irq(card->hw.irq);
+#endif
+	}else{
+#if defined(__SMP__) || defined(LINUX_2_4)
+		spin_unlock(&card->u.f.if_send_lock);
 #endif
 	}
-#ifdef CONFIG_SMP
-	else{
-		spin_unlock(&card->lock);
+	return;
+}
+
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
+/*----------------------------------------------------------------------
+                  RECEIVE INTERRUPT: BOTTOM HALF HANDLERS 
+ ----------------------------------------------------------------------*/
+
+
+/*========================================================
+ * bh_enqueue
+ *
+ * Description:
+ *	Insert a received packed into a circular
+ *      rx queue.  This packed will be picked up 
+ *      by fr_bh() and sent up the stack to the
+ *      user.
+ *       	
+ * Usage: 
+ *	This function is called by rx interrupt,
+ *      in API mode.
+ *
+ */
+
+static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+{
+	/* Check for full */
+	fr_channel_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+
+
+	if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){
+		++card->wandev.stats.rx_dropped;
+		wan_dev_kfree_skb(skb, FREE_READ);
+		return 1; 
+	}
+
+	((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
+
+	if (chan->bh_write == (MAX_BH_BUFF-1)){
+		chan->bh_write=0;
+	}else{
+		++chan->bh_write;
+	}
+
+	atomic_inc(&chan->bh_buff_used);
+
+	return 0;
+}
+
+
+/*========================================================
+ * trigger_fr_bh
+ *
+ * Description:
+ * 	Kick the fr_bh() handler
+ *
+ * Usage:
+ *	rx interrupt calls this function during
+ *      the API mode. 
+ */
+
+static void trigger_fr_bh (fr_channel_t *chan)
+{
+	if (!test_and_set_bit(0,&chan->tq_working)){
+		wanpipe_queue_tq(&chan->common.wanpipe_task);
+		wanpipe_mark_bh();
+	}
+}
+
+
+/*========================================================
+ * fr_bh
+ *
+ * Description:
+ *	Frame relay receive BH handler. 
+ *	Dequeue data from the BH circular 
+ *	buffer and pass it up the API sock.
+ *       	
+ * Rationale: 
+ *	This fuction is used to offload the 
+ *	rx_interrupt during API operation mode.  
+ *	The fr_bh() function executes for each 
+ *	dlci/interface.  
+ * 
+ *      Once receive interrupt copies data from the
+ *      card into an skb buffer, the skb buffer
+ *  	is appended to a circular BH buffer.
+ *  	Then the interrupt kicks fr_bh() to finish the
+ *      job at a later time (no within the interrupt).
+ *       
+ * Usage:
+ * 	Interrupts use this to defer a taks to 
+ *      a polling routine.
+ *
+ */	
+
+static void fr_bh (netdevice_t * dev)
+{
+	fr_channel_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	struct sk_buff *skb;
+
+	if (atomic_read(&chan->bh_buff_used) == 0){
+		clear_bit(0, &chan->tq_working);
+		return;
+	}
+
+	while (atomic_read(&chan->bh_buff_used)){
+
+		if (chan->common.sk == NULL || chan->common.func == NULL){
+			clear_bit(0, &chan->tq_working);
+			return;
+		}
+
+		skb  = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
+
+		if (skb != NULL){
+
+			if (chan->common.sk == NULL || chan->common.func == NULL){
+				++card->wandev.stats.rx_dropped;
+				++chan->ifstats.rx_dropped;
+				wan_dev_kfree_skb(skb, FREE_READ);
+				fr_bh_cleanup(dev);
+				continue;
+			}
+
+			if (chan->common.func(skb,dev,chan->common.sk) != 0){
+				/* Sock full cannot send, queue us for
+                                 * another try */
+				atomic_set(&chan->common.receive_block,1);
+				return;
+			}else{
+				fr_bh_cleanup(dev);
+			}
+		}else{
+			fr_bh_cleanup(dev);
+		}
 	}	
+	clear_bit(0, &chan->tq_working);
+
+	return;
+}
+
+static int fr_bh_cleanup (netdevice_t *dev)
+{
+	fr_channel_t* chan = dev->priv;
+
+	((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
+
+	if (chan->bh_read == (MAX_BH_BUFF-1)){
+		chan->bh_read=0;
+	}else{
+		++chan->bh_read;	
+	}
+
+	atomic_dec(&chan->bh_buff_used);
+	return 0;
+}
+#endif
+
+
+/*----------------------------------------------------------------------
+               POLL BH HANDLERS AND KICK ROUTINES 
+ ----------------------------------------------------------------------*/
+
+/*============================================================
+ * trigger_fr_poll
+ *
+ * Description:
+ * 	Add a fr_poll() task into a tq_scheduler bh handler
+ *      for a specific dlci/interface.  This will kick
+ *      the fr_poll() routine at a later time. 
+ *
+ * Usage:
+ * 	Interrupts use this to defer a taks to 
+ *      a polling routine.
+ *
+ */	
+static void trigger_fr_poll (netdevice_t *dev)
+{
+	fr_channel_t* chan = dev->priv;
+#ifdef LINUX_2_4
+	schedule_task(&chan->fr_poll_task);
+#else
+	queue_task(&chan->fr_poll_task, &tq_scheduler);
+#endif
+	return;
+}
+
+
+/*============================================================
+ * fr_poll
+ *	
+ * Rationale:
+ * 	We cannot manipulate the routing tables, or
+ *      ip addresses withing the interrupt. Therefore
+ *      we must perform such actons outside an interrupt 
+ *      at a later time. 
+ *
+ * Description:	
+ *	Frame relay polling routine, responsible for 
+ *     	shutting down interfaces upon disconnect
+ *     	and adding/removing routes. 
+ *      
+ * Usage:        
+ * 	This function is executed for each frame relay
+ * 	dlci/interface through a tq_schedule bottom half.
+ *      
+ *      trigger_fr_poll() function is used to kick
+ *      the fr_poll routine.  
+ */
+
+static void fr_poll (netdevice_t *dev)
+{
+
+	fr_channel_t* chan;
+	sdla_t *card;
+	u8 check_gateway=0;
+
+	if (!dev || (chan = dev->priv) == NULL)
+		return;
+
+	card = chan->card;
+	
+	/* (Re)Configuraiton is in progress, stop what you are 
+	 * doing and get out */
+	if (test_bit(PERI_CRIT,&card->wandev.critical)){
+		return;
+	}
+
+	switch (chan->common.state){
+
+	case WAN_DISCONNECTED:
+
+		if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
+		    !test_bit(DEV_DOWN, &chan->interface_down) &&
+		    dev->flags&IFF_UP){
+
+			printk(KERN_INFO "%s: Interface %s is Down.\n", 
+				card->devname,dev->name);
+			change_dev_flags(dev,dev->flags&~IFF_UP);
+			set_bit(DEV_DOWN, &chan->interface_down);
+			chan->route_flag = NO_ROUTE;
+			
+		}else{
+			if (chan->inarp != INARP_NONE)
+				process_route(dev);	
+		}
+		break;
+
+	case WAN_CONNECTED:
+
+		if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
+		    test_bit(DEV_DOWN, &chan->interface_down) &&
+		    !(dev->flags&IFF_UP)){
+
+			printk(KERN_INFO "%s: Interface %s is Up.\n", 
+					card->devname,dev->name);
+
+			change_dev_flags(dev,dev->flags|IFF_UP);
+			clear_bit(DEV_DOWN, &chan->interface_down);
+			check_gateway=1;
+		}
+
+		if (chan->inarp != INARP_NONE){
+			process_route(dev);
+			check_gateway=1;
+		}
+
+		if (chan->gateway && check_gateway)
+			add_gateway(card,dev);
+
+		break;
+
+	}
+
+	return;	
+}
+
+/*==============================================================
+ * check_tx_status
+ *
+ * Rationale:
+ *	We cannot transmit from an interrupt while
+ *      the if_send is transmitting data.  Therefore,
+ *      we must check whether the tx buffers are
+ *      begin used, before we transmit from an
+ *      interrupt.	
+ * 
+ * Description:	
+ *	Checks whether it's safe to use the transmit 
+ *      buffers. 
+ *
+ * Usage:
+ * 	ARP and UDP handling routines use this function
+ *      because, they need to transmit data during
+ *      an interrupt.
+ */
+
+static int check_tx_status(sdla_t *card, netdevice_t *dev)
+{
+
+	if (card->hw.type == SDLA_S514){
+		if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) ||
+			test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
+			return 1;
+		}
+	}
+
+	if (is_queue_stopped(dev) || (card->u.f.tx_interrupts_pending))
+     		return 1; 
+
+	return 0;
+}
+
+/*===============================================================
+ * move_dev_to_next
+ *  
+ * Description:
+ *	Move the dev pointer to the next location in the
+ *      link list.  Check if we are at the end of the 
+ *      list, if so start from the begining.
+ *
+ * Usage:
+ * 	Timer interrupt uses this function to efficiently
+ *      step through the devices that need to send ARP data.
+ *
+ */
+
+netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
+{
+	if (card->wandev.new_if_cnt != 1){
+		if (*((netdevice_t **)dev->priv) == NULL){
+			return card->wandev.dev;
+		}else{
+			return *((netdevice_t **)dev->priv);
+		}
+	}
+	return dev;
+}
+
+/*==============================================================
+ * trigger_config_fr
+ *
+ * Rationale:
+ *	All commands must be performed inside of a  
+ *      interrupt.   
+ *
+ * Description:
+ *	Kick the config_fr() routine throught the
+ *      timer interrupt.
+ */
+
+
+static void trigger_config_fr (sdla_t *card)
+{
+	fr508_flags_t* flags = card->flags;
+
+	card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
+	flags->imask |= FR_INTR_TIMER;
+}
+
+
+/*==============================================================
+ * config_fr
+ *
+ * Rationale:
+ * 	All commands must be performed inside of a  
+ *      interrupt.  
+ &
+ * Description:	
+ * 	Configure a DLCI. This function is executed
+ *      by a timer_interrupt.  The if_open() function
+ *      triggers it.
+ *
+ * Usage:
+ *	new_if() collects all data necessary to
+ *      configure the DLCI. It sets the chan->dlci_ready 
+ *      bit.  When the if_open() function is executed
+ *      it checks this bit, and if its set it triggers
+ *      the timer interrupt to execute the config_fr()
+ *      function.
+ */
+
+static void config_fr (sdla_t *card)
+{
+	netdevice_t *dev;
+	fr_channel_t *chan;
+
+	for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
+	
+		if ((chan=dev->priv) == NULL)
+			continue;
+		
+		if (!test_bit(0,&chan->config_dlci))
+			continue;
+
+		clear_bit(0,&chan->config_dlci);
+
+		/* If signalling is set to NO, then setup 
+        	 * DLCI addresses right away.  Don't have to wait for
+		 * link to connect. 
+		 */
+		if (card->wandev.signalling == WANOPT_NO){
+			printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n",
+					card->wandev.name);
+			if (fr_init_dlci(card,chan)){
+				printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n",
+					card->devname, chan->dlci);
+				return;
+			}
+		}
+
+		if (card->wandev.station == WANOPT_CPE) {
+	
+			update_chan_state(dev);	
+			
+			/* CPE: issue full status enquiry */
+			fr_issue_isf(card, FR_ISF_FSE);
+
+		} else {	
+			/* FR switch: activate DLCI(s) */
+	
+			/* For Switch emulation we have to ADD and ACTIVATE
+			 * the DLCI(s) that were configured with the SET_DLCI_
+			 * CONFIGURATION command. Add and Activate will fail if
+			 * DLCI specified is not included in the list.
+			 *
+			 * Also If_open is called once for each interface. But
+			 * it does not get in here for all the interface. So
+		 	 * we have to pass the entire list of DLCI(s) to add 
+			 * activate routines.  
+			 */ 
+			
+			if (!check_dlci_config (card, chan)){
+				fr_add_dlci(card, chan->dlci);
+				fr_activate_dlci(card, chan->dlci);
+			}
+		}
+
+		card->u.f.dlci_to_dev_map[chan->dlci] = dev;
+	}
+	return;
+}
+
+
+/*==============================================================
+ * config_fr
+ *
+ * Rationale:
+ *	All commands must be executed during an interrupt.
+ * 
+ * Description:	
+ *	Trigger uncofig_fr() function through 
+ *      the timer interrupt.
+ *
+ */
+
+static void trigger_unconfig_fr (netdevice_t *dev)
+{
+	fr_channel_t *chan = dev->priv;
+	volatile sdla_t *card = chan->card;
+	u32 timeout;
+	fr508_flags_t* flags = card->flags;
+	int reset_critical=0;
+	
+	if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
+		clear_bit(PERI_CRIT,(void*)&card->wandev.critical);
+		reset_critical=1;
+	}
+		
+	/* run unconfig_dlci() function 
+         * throught the timer interrupt */
+	set_bit(0,(void*)&chan->unconfig_dlci);
+	card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG;
+	flags->imask |= FR_INTR_TIMER;
+
+	/* Wait for the command to complete */
+	timeout = jiffies;
+     	for(;;) {
+
+		if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG))
+			break;
+
+             	if ((jiffies - timeout) > (1 * HZ)){
+    			card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
+			printk(KERN_INFO "%s: Failed to delete DLCI %i\n",
+				card->devname,chan->dlci);
+ 			break;
+		}
+	}
+
+	if (reset_critical){
+		set_bit(PERI_CRIT,(void*)&card->wandev.critical);
+	}
+}
+
+/*==============================================================
+ * unconfig_fr
+ *
+ * Rationale:
+ *	All commands must be executed during an interrupt.
+ * 
+ * Description:	
+ *	Remove the dlci from firmware.
+ *	This funciton is used in NODE shutdown.
+ */
+
+static void unconfig_fr (sdla_t *card)
+{
+	netdevice_t *dev;
+	fr_channel_t *chan;
+
+	for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
+	
+		if ((chan=dev->priv) == NULL)
+			continue;
+		
+		if (!test_bit(0,&chan->unconfig_dlci))
+			continue;
+
+		clear_bit(0,&chan->unconfig_dlci);
+
+		if (card->wandev.station == WANOPT_NODE){
+			printk(KERN_INFO "%s: Unconfiguring DLCI %i\n",
+					card->devname,chan->dlci);
+			fr_delete_dlci(card,chan->dlci);
+		}
+		card->u.f.dlci_to_dev_map[chan->dlci] = NULL;
+	}
+}
+
+static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode)
+{
+	struct sk_buff *skb = *skb_orig;
+	fr_channel_t *chan=dev->priv;
+
+	if (op_mode == WANPIPE){
+
+		chan->fr_header[0]=Q922_UI;
+		
+		switch (htons(skb->protocol)){
+			
+		case ETH_P_IP:
+			chan->fr_header[1]=NLPID_IP;
+			break;
+		default:
+			return -EINVAL;
+		}
+			
+		return 2;
+	}
+
+	/* If we are in bridging mode, we must apply
+	 * an Ethernet header */
+	if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
+		/* Encapsulate the packet as a bridged Ethernet frame. */
+#ifdef DEBUG
+		printk(KERN_INFO "%s: encapsulating skb for frame relay\n", 
+			dev->name);
+#endif
+		
+		chan->fr_header[0] = 0x03;
+		chan->fr_header[1] = 0x00;
+		chan->fr_header[2] = 0x80;
+		chan->fr_header[3] = 0x00;
+		chan->fr_header[4] = 0x80;
+		chan->fr_header[5] = 0xC2;
+		chan->fr_header[6] = 0x00;
+		chan->fr_header[7] = 0x07;
+
+		/* Yuck. */
+		skb->protocol = ETH_P_802_3;
+		return 8;
+
+#else
+
+		/* BRIDGING is not supported in 2.0.X */
+		return -EINVAL;
+
 #endif
+	}
+		
+	return 0;
+}
+
+
+static int check_dlci_config (sdla_t *card, fr_channel_t *chan)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int err=0;
+	fr_conf_t *conf=NULL;
+	unsigned short dlci_num = chan->dlci;
+	int dlci_offset=0;
+	netdevice_t *dev=NULL;
+	
+	mbox->cmd.command = FR_READ_CONFIG;
+	mbox->cmd.length = 0;
+	mbox->cmd.dlci = dlci_num; 	
+
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	
+	if (err == CMD_OK){
+		return 0;
+	}
+
+	for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+		set_chan_state(dev,WAN_DISCONNECTED);
+	}
+	
+	printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num);
+	
+	mbox->cmd.command = FR_COMM_DISABLE;
+	mbox->cmd.length = 0;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	if (err != CMD_OK){
+		fr_event(card, err, mbox);
+		return 2;
+	}
+
+	printk(KERN_INFO "Disabled Communications \n");
+	
+	mbox->cmd.command = FR_READ_CONFIG;
+	mbox->cmd.length = 0;
+	mbox->cmd.dlci = 0; 	
+
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	
+	if (err != CMD_OK){
+		fr_event(card, err, mbox);
+		return 2;
+	}
+	
+	conf = (fr_conf_t *)mbox->data;
+
+	dlci_offset=0;
+	for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+		fr_channel_t *chan_tmp = dev->priv;
+		conf->dlci[dlci_offset] = chan_tmp->dlci;		
+		dlci_offset++;
+	}
+	
+	printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n",
+		mbox->cmd.length,
+		mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, 
+		dlci_offset );
+	
+	mbox->cmd.length = 0x20 + dlci_offset*2;
+
+	mbox->cmd.command = FR_SET_CONFIG;
+	mbox->cmd.dlci = 0; 
+
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+	if (err != CMD_OK){
+		fr_event(card, err, mbox);
+		return 2;
+	}
+
+	initialize_rx_tx_buffers (card);
+
+	
+	printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num);
+
+	if (fr_comm_enable (card)){
+		return 2;
+	}
+
+	printk(KERN_INFO "Enabling Communications \n");
+
+	for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+		fr_channel_t *chan_tmp = dev->priv;
+		fr_init_dlci(card,chan_tmp);
+		fr_add_dlci(card, chan_tmp->dlci);
+		fr_activate_dlci(card, chan_tmp->dlci);
+	}
 
+	printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num);
+	
+	return 1;
 }
+
+static void initialize_rx_tx_buffers (sdla_t *card)
+{
+	fr_buf_info_t* buf_info;
+	
+	if (card->hw.type == SDLA_S514) {
+	
+                buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR +
+			FR508_RXBC_OFFS);
+
+                card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase);
+
+                card->u.f.rxmb_base =
+                        (void*)(buf_info->rse_base + card->hw.dpmbase); 
+
+                card->u.f.rxmb_last =
+                        (void*)(buf_info->rse_base +
+                        (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
+                        card->hw.dpmbase);
+	}else{	
+		buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
+
+		card->rxmb = (void*)(buf_info->rse_next -
+			FR_MB_VECTOR + card->hw.dpmbase);
+		
+		card->u.f.rxmb_base =
+			(void*)(buf_info->rse_base -
+			FR_MB_VECTOR + card->hw.dpmbase);
+		
+		card->u.f.rxmb_last =
+			(void*)(buf_info->rse_base +
+			(buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) -
+			FR_MB_VECTOR + card->hw.dpmbase);
+	}
+
+	card->u.f.rx_base = buf_info->buf_base;
+	card->u.f.rx_top  = buf_info->buf_top;
+
+	card->u.f.tx_interrupts_pending = 0;
+
+	return;
+}
+
+	
+
 
 /****** End *****************************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_ft1.c linux/drivers/net/wan/sdla_ft1.c
--- v2.4.3/linux/drivers/net/wan/sdla_ft1.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/sdla_ft1.c	Thu Apr 12 12:11:39 2001
@@ -0,0 +1,386 @@
+/*****************************************************************************
+* sdla_chdlc.c	WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module.
+*
+* Authors: 	Nenad Corbic <ncorbic@sangoma.com>
+*		Gideon Hack  
+*
+* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Sep 30, 1999  Nenad Corbic    Fixed dynamic IP and route setup.
+* Sep 23, 1999  Nenad Corbic    Added SMP support, fixed tracing 
+* Sep 13, 1999  Nenad Corbic	Split up Port 0 and 1 into separate devices.
+* Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
+* Oct 30, 1998	Jaspreet Singh	Added Support for CHDLC API (HDLC STREAMING).
+* Oct 28, 1998	Jaspreet Singh	Added Support for Dual Port CHDLC.
+* Aug 07, 1998	David Fong	Initial version.
+*****************************************************************************/
+
+#include <linux/version.h>
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+
+#if defined(LINUX_2_4)
+  #include <linux/inetdevice.h>
+  #include <asm/uaccess.h>
+
+#elif defined(LINUX_2_1)
+  #include <linux/inetdevice.h>
+  #include <asm/uaccess.h>
+
+#else
+  #include <net/route.h>          /* Adding new route entries */
+  #include <asm/segment.h>
+  #define test_and_set_bit set_bit
+#endif
+
+#include <linux/in.h>		/* sockaddr_in */
+#include <linux/inet.h>	
+#include <linux/if.h>
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <linux/sdlapci.h>
+#include <asm/io.h>
+
+#include <linux/sdla_chdlc.h>		/* CHDLC firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+/* reasons for enabling the timer interrupt on the adapter */
+#define TMR_INT_ENABLED_UDP   	0x0001
+#define TMR_INT_ENABLED_UPDATE	0x0002
+ 
+#define	CHDLC_DFLT_DATA_LEN	1500		/* default MTU */
+#define CHDLC_HDR_LEN		1
+
+#define IFF_POINTTOPOINT 0x10
+
+#define WANPIPE 0x00
+#define API	0x01
+#define CHDLC_API 0x01
+
+#define PORT(x)   (x == 0 ? "PRIMARY" : "SECONDARY" )
+
+ 
+/******Data Structures*****************************************************/
+
+/* This structure is placed in the private data area of the device structure.
+ * The card structure used to occupy the private area but now the following 
+ * structure will incorporate the card structure along with CHDLC specific data
+ */
+
+typedef struct chdlc_private_area
+{
+	netdevice_t 	*slave;
+	sdla_t		*card;
+	int 		TracingEnabled;		/* For enabling Tracing */
+	unsigned long 	curr_trace_addr;	/* Used for Tracing */
+	unsigned long 	start_trace_addr;
+	unsigned long 	end_trace_addr;
+	unsigned long 	base_addr_trace_buffer;
+	unsigned long 	end_addr_trace_buffer;
+	unsigned short 	number_trace_elements;
+	unsigned  	available_buffer_space;
+	unsigned long 	router_start_time;
+	unsigned char 	route_status;
+	unsigned char 	route_removed;
+	unsigned long 	tick_counter;		/* For 5s timeout counter */
+	unsigned long 	router_up_time;
+        u32             IP_address;		/* IP addressing */
+        u32             IP_netmask;
+	unsigned char  mc;			/* Mulitcast support on/off */
+	unsigned short udp_pkt_lgth;		/* udp packet processing */
+	char udp_pkt_src;
+	char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+	unsigned short timer_int_enabled;
+	char update_comms_stats;		/* updating comms stats */
+	//FIXME: add driver stats as per frame relay!
+
+} chdlc_private_area_t;
+
+/* Route Status options */
+#define NO_ROUTE	0x00
+#define ADD_ROUTE	0x01
+#define ROUTE_ADDED	0x02
+#define REMOVE_ROUTE	0x03
+
+
+/****** Function Prototypes *************************************************/
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data);
+static int chdlc_read_version (sdla_t* card, char* str);
+static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
+
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * Cisco HDLC protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wpft1_init (sdla_t* card, wandev_conf_t* conf)
+{
+	unsigned char port_num;
+	int err;
+
+	union
+		{
+		char str[80];
+		} u;
+	volatile CHDLC_MAILBOX_STRUCT* mb;
+	CHDLC_MAILBOX_STRUCT* mb1;
+	unsigned long timeout;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_CHDLC) {
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+				  card->devname, conf->config_id);
+		return -EINVAL;
+	}
+
+	/* Use primary port */
+	card->u.c.comm_port = 0;
+	
+
+	/* Initialize protocol-specific fields */
+	if(card->hw.type != SDLA_S514){
+		card->mbox  = (void *) card->hw.dpmbase;
+	}else{ 
+		card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT;
+	}
+
+	mb = mb1 = card->mbox;
+
+	if (!card->configured){
+
+		/* The board will place an 'I' in the return code to indicate that it is
+	   	ready to accept commands.  We expect this to be completed in less
+           	than 1 second. */
+
+		timeout = jiffies;
+		while (mb->return_code != 'I')	/* Wait 1s for board to initialize */
+			if ((jiffies - timeout) > 1*HZ) break;
+
+		if (mb->return_code != 'I') {
+			printk(KERN_INFO
+				"%s: Initialization not completed by adapter\n",
+				card->devname);
+			printk(KERN_INFO "Please contact Sangoma representative.\n");
+			return -EIO;
+		}
+	}
+
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+
+	if (chdlc_read_version(card, u.str))
+		return -EIO;
+
+	printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n",
+		card->devname, u.str); 
+
+	card->isr			= NULL;
+	card->poll			= NULL;
+	card->exec			= &wpft1_exec;
+	card->wandev.update		= NULL;
+ 	card->wandev.new_if		= NULL;
+	card->wandev.del_if		= NULL;
+	card->wandev.state		= WAN_DUALPORT;
+	card->wandev.udp_port   	= conf->udp_port;
+
+	card->wandev.new_if_cnt = 0;
+
+	/* This is for the ports link state */
+	card->u.c.state = WAN_DISCONNECTED;
+	
+	/* reset the number of times the 'update()' proc has been called */
+	card->u.c.update_call_count = 0;
+	
+	card->wandev.ttl = 0x7F;
+	card->wandev.interface = 0; 
+
+	card->wandev.clocking = 0;
+
+	port_num = card->u.c.comm_port;
+
+	/* Setup Port Bps */
+
+       	card->wandev.bps = 0;
+
+	card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG;
+
+	/* Set up the interrupt status area */
+	/* Read the CHDLC Configuration and obtain: 
+	 *	Ptr to shared memory infor struct
+         * Use this pointer to calculate the value of card->u.c.flags !
+ 	 */
+	mb1->buffer_length = 0;
+	mb1->command = READ_CHDLC_CONFIGURATION;
+	err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
+	if(err != COMMAND_OK) {
+		chdlc_error(card, err, mb1);
+		return -EIO;
+	}
+
+	if(card->hw.type == SDLA_S514){
+               	card->u.c.flags = (void *)(card->hw.dpmbase +
+               		(((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
+			ptr_shared_mem_info_struct));
+        }else{
+                card->u.c.flags = (void *)(card->hw.dpmbase +
+                        (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
+			ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
+	}
+
+	card->wandev.state = WAN_FT1_READY;
+	printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname);
+
+	return 0;
+}
+
+static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data)
+{
+	CHDLC_MAILBOX_STRUCT* mbox = card->mbox;
+	int len;
+
+	
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){
+		return -EFAULT;
+	}
+
+	len = mbox->buffer_length;
+
+	if (len) {
+		if( copy_from_user((void*)&mbox->data, u_data, len)){
+			return -EFAULT;
+		}
+	}
+
+	/* execute command */
+	if (!sdla_exec(mbox)){
+		return -EIO;
+	}
+
+	/* return result */
+	if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){
+		return -EFAULT;
+	}
+
+	len = mbox->buffer_length;
+
+	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){
+		return -EFAULT;
+	}
+
+#else
+
+        if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(ft1_exec_cmd_t))){
+                return -EFAULT;
+	}
+
+        memcpy_fromfs((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t));
+
+	len = mbox->buffer_length;
+
+        if (len) {
+                if (!u_data || verify_area(VERIFY_READ, u_data, len))
+                        return -EFAULT;
+		memcpy_fromfs((void*)&mbox->data, u_data, len);
+        }
+
+        /* execute command */
+        if (!sdla_exec(mbox))
+               	return -EIO;
+
+        /* return result */
+        memcpy_tofs(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t));
+        len = mbox->buffer_length;
+
+        if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)){
+                memcpy_tofs(u_data, (void*)&mbox->data, len);
+	}
+
+#endif
+
+	return 0;
+
+}
+
+/*============================================================================
+ * Read firmware code version.
+ *	Put code version as ASCII string in str. 
+ */
+static int chdlc_read_version (sdla_t* card, char* str)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int len;
+	char err;
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_CODE_VERSION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+	if(err != COMMAND_OK) {
+		chdlc_error(card,err,mb);
+	}
+	else if (str) {  /* is not null */
+		len = mb->buffer_length;
+		memcpy(str, mb->data, len);
+		str[len] = '\0';
+	}
+	return (err);
+}
+
+/*============================================================================
+ * Firmware error handler.
+ *	This routine is called whenever firmware command returns non-zero
+ *	return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb)
+{
+	unsigned cmd = mb->command;
+
+	switch (err) {
+
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, cmd);
+		break;
+
+	case S514_BOTH_PORTS_SAME_CLK_MODE:
+		if(cmd == SET_CHDLC_CONFIGURATION) {
+			printk(KERN_INFO
+			 "%s: Configure both ports for the same clock source\n",
+				card->devname);
+			break;
+		}
+
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+			card->devname, cmd, err);
+	}
+
+	return 0;
+}
+
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- v2.4.3/linux/drivers/net/wan/sdla_ppp.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/sdla_ppp.c	Fri Apr 20 11:54:22 2001
@@ -3,14 +3,30 @@
 *
 * Author: 	Nenad Corbic <ncorbic@sangoma.com>
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2001 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-*
+* Feb 28, 2001  Nenad Corbic	o Updated if_tx_timeout() routine for 
+* 				  2.4.X kernels.
+* Nov 29, 2000  Nenad Corbic	o Added the 2.4.x kernel support:
+* 				  get_ip_address() function has moved
+* 				  into the ppp_poll() routine. It cannot
+* 				  be called from an interrupt.
+* Nov 07, 2000  Nenad Corbic	o Added security features for UDP debugging:
+*                                 Deny all and specify allowed requests.
+* May 02, 2000  Nenad Corbic	o Added the dynamic interface shutdown
+*                                 option. When the link goes down, the
+*                                 network interface IFF_UP flag is reset.
+* Mar 06, 2000  Nenad Corbic	o Bug Fix: corrupted mbox recovery.
+* Feb 25, 2000  Nenad Corbic    o Fixed the FT1 UDP debugger problem.
+* Feb 09, 2000  Nenad Coribc    o Shutdown bug fix. update() was called
+*                                 with NULL dev pointer: no check.
+* Jan 24, 2000  Nenad Corbic    o Disabled use of CMD complete inter.
+* Dev 15, 1999  Nenad Corbic    o Fixed up header files for 2.0.X kernels
 * Oct 25, 1999  Nenad Corbic    o Support for 2.0.X kernels
 *                                 Moved dynamic route processing into 
 *                                 a polling routine.
@@ -74,13 +90,12 @@
 * Jan 06, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
@@ -88,24 +103,29 @@
 #include <linux/in.h>		/* sockaddr_in */
 #include <linux/inet.h>		/* in_aton(), in_ntoa() prototypes */
 
-#include <linux/inetdevice.h>
-#include <asm/uaccess.h>
+
+/* ---- 2.4.X KERNEL SUPPORT -----------------------*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ #include <asm/uaccess.h>
+ #include <linux/inetdevice.h>
+ #include <linux/netdevice.h>
+#else
+ #include <asm/segment.h>
+ #include <net/route.h>          /* Adding new route entries : 2.0.X kernels */
+#endif
 
 #include <linux/if.h>
+#include <linux/wanpipe.h>
 #include <linux/sdla_ppp.h>		/* PPP firmware API definitions */
 #include <linux/sdlasfm.h>		/* S514 Type Definition */
 /****** Defines & Macros ****************************************************/
 
-#ifdef	_DEBUG_
-#define	STATIC
-#else
-#define	STATIC		static
-#endif
-
 #define	PPP_DFLT_MTU	1500		/* default MTU */
 #define	PPP_MAX_MTU	4000		/* maximum MTU */
 #define PPP_HDR_LEN	1
 
+#define MAX_IP_ERRORS 100 
+
 #define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
 #define	HOLD_DOWN_TIME	(5*HZ)		/* link hold down time : Changed from 30 to 5 */
 
@@ -125,9 +145,10 @@
 #define LCP(a)   ( a == 0x09 ? "OPEN" : "CLOSED" )
 #define IP(a)    ( a == 0x09 ? "ENABLED" : "DISABLED" )
 
-#define TMR_INT_ENABLED_UPDATE  	1
-#define TMR_INT_ENABLED_PPP_EVENT	2
-#define TMR_INT_ENABLED_UDP		4
+#define TMR_INT_ENABLED_UPDATE  	0x01
+#define TMR_INT_ENABLED_PPP_EVENT	0x02
+#define TMR_INT_ENABLED_UDP		0x04
+#define TMR_INT_ENABLED_CONFIG		0x20
 
 /* Set Configuraton Command Definitions */
 #define PERCENT_TX_BUFF			60
@@ -143,8 +164,11 @@
 #define NUM_AUTH_REQ_WITHOUT_REPLY      10
 
 #define END_OFFSET 0x1F0
+#if LINUX_VERSION_CODE < 0x020125
+#define test_and_set_bit set_bit
+#define net_ratelimit() 1
+#endif
 
-#define TX_TIMEOUT (5*HZ)
 
 /******Data Structures*****************************************************/
 
@@ -155,9 +179,7 @@
   
 typedef struct ppp_private_area
 {
-	/* This member must be first. */
-	struct net_device *slave;	/* WAN slave */
-
+	netdevice_t *slave;
 	sdla_t* card;	
 	unsigned long router_start_time;	/*router start time in sec */
 	unsigned long tick_counter;		/*used for 5 second counter*/
@@ -173,12 +195,20 @@
 	u32 ip_local;				/* Local IP Address */
 	u32 ip_remote;				/* remote IP Address */
 
+	u32 ip_local_tmp;
+	u32 ip_remote_tmp;
+	
 	unsigned char timer_int_enabled;	/* Who enabled the timer inter*/
 	unsigned char update_comms_stats;	/* Used by update function */
 	unsigned long curr_trace_addr;		/* Trace information */
 	unsigned long start_trace_addr;
 	unsigned long end_trace_addr;
 
+	unsigned char interface_down;		/* Brind down interface when channel 
+                                                   goes down */
+	unsigned long config_wait_timeout;	/* After if_open() if in dynamic if mode,
+						   wait a few seconds before configuring */
+	
 	unsigned short udp_pkt_lgth;
 	char  udp_pkt_src;
       	char  udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
@@ -191,6 +221,16 @@
 
 	unsigned long router_up_time; 
 
+	/* Polling task queue. Each interface
+         * has its own task queue, which is used
+         * to defer events from the interrupt */
+	struct tq_struct poll_task;
+	struct timer_list poll_delay_timer;
+
+	u8 gateway;
+	u8 config_ppp;
+	u8 ip_error;
+	
 }ppp_private_area_t;
 
 /* variable for keeping track of enabling/disabling FT1 monitor status */
@@ -203,22 +243,32 @@
 
 /* WAN link driver entry points. These are called by the WAN router module. */
 static int update(wan_device_t *wandev);
-static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf);
-static int del_if(wan_device_t *wandev, struct net_device *dev);
+static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf);
+static int del_if(wan_device_t *wandev, netdevice_t *dev);
 
 /* WANPIPE-specific entry points */
 static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data);
 
 /* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-static void if_tx_timeout (struct net_device *dev);
-static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, 
+static int if_init(netdevice_t *dev);
+static int if_open(netdevice_t *dev);
+static int if_close(netdevice_t *dev);
+static int if_header(struct sk_buff *skb, netdevice_t *dev, unsigned short type, 
 		     void *daddr, void *saddr, unsigned len);
+
+#ifdef LINUX_2_4
+static void if_tx_timeout (netdevice_t *dev);
+#endif
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 static int if_rebuild_hdr(struct sk_buff *skb);
-static struct net_device_stats *if_stats(struct net_device *dev);
-static int if_send(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *if_stats(netdevice_t *dev);
+#else
+static struct enet_statistics *if_stats(netdevice_t *dev);
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
+        struct sk_buff* skb);
+#endif
+static int if_send(struct sk_buff *skb, netdevice_t *dev);
 
 
 /* PPP firmware interface functions */
@@ -229,27 +279,28 @@
 static int ppp_set_intr_mode(sdla_t *card, unsigned char mode);
 static int ppp_comm_enable(sdla_t *card);
 static int ppp_comm_disable(sdla_t *card);
+static int ppp_comm_disable_shutdown(sdla_t *card);
 static int ppp_get_err_stats(sdla_t *card);
 static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto);
 static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb);
 
-STATIC void wpp_isr(sdla_t *card);
+static void wpp_isr(sdla_t *card);
 static void rx_intr(sdla_t *card);
 static void event_intr(sdla_t *card);
 static void timer_intr(sdla_t *card);
 
 /* Background polling routines */
 static void process_route(sdla_t *card);
-static void poll_disconnected(sdla_t *card);
+static void retrigger_comm(sdla_t *card);
 
 /* Miscellaneous functions */
 static int read_info( sdla_t *card );
 static int read_connection_info (sdla_t *card);
-static int remove_route( sdla_t *card );
-static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card);
+static void remove_route( sdla_t *card );
+static int config508(netdevice_t *dev, sdla_t *card);
 static void show_disc_cause(sdla_t * card, unsigned cause);
 static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, 
+static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, 
 				ppp_private_area_t *ppp_priv_area);
 static void init_ppp_tx_rx_buff( sdla_t *card );
 static int intr_test( sdla_t *card );
@@ -258,12 +309,20 @@
 static void init_global_statistics( sdla_t *card );
 static int tokenize(char *str, char **tokens);
 static char* strstrip(char *str, char *s);
-static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev,
+static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev,
 				struct sk_buff *skb);
+
+static int config_ppp (sdla_t *);
+static void ppp_poll(netdevice_t *);
+static void trigger_ppp_poll(netdevice_t *);
+static void ppp_poll_delay (unsigned long dev_ptr);
+
+
 static int Read_connection_info;
 static int Intr_test_counter;
 static unsigned short available_buffer_space;
 
+
 /* IPX functions */
 static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, 
 			       unsigned char incoming);
@@ -275,12 +334,11 @@
 static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, struct net_device* dev,
+                                struct sk_buff *skb, netdevice_t* dev,
                                 ppp_private_area_t* ppp_priv_area );
 static unsigned short calc_checksum (char *data, int len);
-
-
-
+static void disable_comm (sdla_t *card);
+static int detect_and_fix_tx_bug (sdla_t *card);
 
 /****** Public Functions ****************************************************/
 
@@ -298,6 +356,7 @@
  */
 int wpp_init(sdla_t *card, wandev_conf_t *conf)
 {
+	ppp_flags_t *flags;
 	union
 	{
 		char str[80];
@@ -329,6 +388,7 @@
 			return -EINVAL;
 
 	}
+	flags = card->flags;
 
 	/* Read firmware version.  Note that when adapter initializes, it
 	 * clears the mailbox, so it may appear that the first command was
@@ -353,9 +413,10 @@
 	card->wandev.update	= &update;
 	card->wandev.new_if	= &new_if;
 	card->wandev.del_if	= &del_if;
-	card->wandev.state	= WAN_DISCONNECTED;
         card->wandev.udp_port   = conf->udp_port;
 	card->wandev.ttl	= conf->ttl;
+	card->wandev.state      = WAN_DISCONNECTED;
+	card->disable_comm	= &disable_comm;
 	card->irq_dis_if_send_count = 0;
         card->irq_dis_poll_count = 0;
 	card->u.p.authenticator = conf->u.ppp.authenticator;
@@ -367,6 +428,33 @@
 	/* initialize global statistics */
 	init_global_statistics( card );
 
+
+
+	if (!card->configured){
+		int err;
+
+		Intr_test_counter = 0;
+		err = intr_test(card);
+
+		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
+			printk("%s: Interrupt Test Failed, Counter: %i\n", 
+				card->devname, Intr_test_counter);
+			printk( "%s: Please choose another interrupt\n",card->devname);
+			return -EIO;
+		}
+		
+		printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", 
+			card->devname, Intr_test_counter);
+		card->configured = 1;
+	}
+
+	ppp_set_intr_mode(card, PPP_INTR_TIMER); 
+
+	/* Turn off the transmit and timer interrupt */
+	flags->imask &= ~PPP_INTR_TIMER;
+
+	printk(KERN_INFO "\n");
+
 	return 0;
 }
 
@@ -378,8 +466,8 @@
 static int update(wan_device_t *wandev)
 {
 	sdla_t* card = wandev->private;
- 	struct net_device* dev = card->wandev.dev;
-        volatile ppp_private_area_t *ppp_priv_area = dev->priv;
+ 	netdevice_t* dev;
+        volatile ppp_private_area_t *ppp_priv_area;
 	ppp_flags_t *flags = card->flags;
 	unsigned long timeout;
 
@@ -390,9 +478,17 @@
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
 	
-	//FIXME: Do we need this
-	if (test_bit(0, (void*)&wandev->critical))
-		return -EAGAIN;
+	/* Shutdown bug fix. This function can be
+         * called with NULL dev pointer during
+         * shutdown 
+	 */
+	if ((dev=card->wandev.dev) == NULL){
+		return -ENODEV;
+	}
+
+	if ((ppp_priv_area=dev->priv) == NULL){
+		return -ENODEV;
+	}
 	
 	ppp_priv_area->update_comms_stats = 2;
 	ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
@@ -427,17 +523,21 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf)
+static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf)
 {
 	sdla_t *card = wandev->private;
 	ppp_private_area_t *ppp_priv_area;
-	
+
 	if (wandev->ndev)
 		return -EEXIST;
 	
+
+	printk(KERN_INFO "%s: Configuring Interface: %s\n",
+			card->devname, conf->name);
+
 	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
 
-		printk(KERN_INFO "%s: invalid interface name!\n",
+		printk(KERN_INFO "%s: Invalid interface name!\n",
 			card->devname);
 		return -EINVAL;
 
@@ -464,6 +564,14 @@
 	ppp_priv_area->pap = conf->pap;
 	ppp_priv_area->chap = conf->chap;
 
+	/* Option to bring down the interface when 
+         * the link goes down */
+	if (conf->if_down){
+		set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down);
+		printk("%s: Dynamic interface configuration enabled\n",
+			card->devname);
+	} 
+
 	/* If no user ids are specified */
 	if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){
 		kfree(ppp_priv_area);
@@ -494,16 +602,53 @@
 
 	
 	ppp_priv_area->enable_IPX = conf->enable_IPX;
-	if (conf->network_number)
+	if (conf->network_number){
 		ppp_priv_area->network_number = conf->network_number;
-	else
+	}else{
 		ppp_priv_area->network_number = 0xDEADBEEF;
+	}
 
+	/* Tells us that if this interface is a
+         * gateway or not */
+	if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){
+		printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
+			card->devname,card->u.p.if_name);
+	}
 
 	/* prepare network device data space for registration */
-	strcpy(dev->name, card->u.p.if_name);
+#ifdef LINUX_2_4
+ 	strcpy(dev->name,card->u.p.if_name);
+#else
+	dev->name = (char *)kmalloc(strlen(card->u.p.if_name) + 2, GFP_KERNEL); 
+	if(dev->name == NULL)
+	{
+		kfree(ppp_priv_area);
+		return -ENOMEM;
+	}
+	sprintf(dev->name, "%s", card->u.p.if_name);
+#endif
+	
 	dev->init = &if_init;
 	dev->priv = ppp_priv_area;
+	dev->mtu = min(dev->mtu, card->wandev.mtu);
+
+	/* Initialize the polling task routine */
+#ifndef LINUX_2_4
+	ppp_priv_area->poll_task.next = NULL;
+#endif
+	ppp_priv_area->poll_task.sync=0;
+	ppp_priv_area->poll_task.routine = (void*)(void*)ppp_poll;
+	ppp_priv_area->poll_task.data = dev;
+
+	/* Initialize the polling delay timer */
+	init_timer(&ppp_priv_area->poll_delay_timer);
+	ppp_priv_area->poll_delay_timer.data = (unsigned long)dev;
+	ppp_priv_area->poll_delay_timer.function = ppp_poll_delay;
+	
+	
+	/* Since we start with dummy IP addresses we can say
+	 * that route exists */
+	printk(KERN_INFO "\n");
 
 	return 0;
 }
@@ -511,17 +656,17 @@
 /*============================================================================
  * Delete logical channel.
  */
-static int del_if(wan_device_t *wandev, struct net_device *dev)
+static int del_if(wan_device_t *wandev, netdevice_t *dev)
 {
-	if (dev->priv) {
-
-                kfree(dev->priv);
-                dev->priv = NULL;
-        }
-
 	return 0;
 }
 
+static void disable_comm (sdla_t *card)
+{
+	ppp_comm_disable_shutdown(card);
+	return;
+}
+
 /****** WANPIPE-specific entry points ***************************************/
 
 /*============================================================================
@@ -534,6 +679,7 @@
 	ppp_mbox_t *mbox = card->mbox;
 	int len;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
 		return -EFAULT;
 
@@ -558,6 +704,35 @@
 	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
 		return -EFAULT;
 
+#else
+
+        if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(ppp_cmd_t)))
+                return -EFAULT;
+
+        memcpy_fromfs((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t));
+
+	len = mbox->cmd.length;
+
+        if (len) {
+
+                if (!u_data || verify_area(VERIFY_READ, u_data, len))
+                        return -EFAULT;
+        }
+
+        /* execute command */
+        if (!sdla_exec(mbox))
+               	return -EIO;
+
+        /* return result */
+        memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t));
+        len = mbox->cmd.length;
+
+        if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len))
+                memcpy_tofs(u_data, (void*)&mbox->data, len);
+
+
+#endif
+
 	return 0;
 }
 
@@ -570,12 +745,12 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init(struct net_device *dev)
+static int if_init(netdevice_t *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 	wan_device_t *wandev = &card->wandev;
-#ifndef LINUX_2_1
+#ifdef LINUX_2_0
 	int i;
 #endif
 
@@ -586,19 +761,22 @@
 	dev->rebuild_header	= &if_rebuild_hdr;
 	dev->hard_start_xmit	= &if_send;
 	dev->get_stats		= &if_stats;
+#ifdef LINUX_2_4
 	dev->tx_timeout		= &if_tx_timeout;
 	dev->watchdog_timeo	= TX_TIMEOUT;
+#endif
 
 	/* Initialize media-specific parameters */
 	dev->type		= ARPHRD_PPP;	/* ARP h/w type */
-	dev->flags	       |= IFF_POINTOPOINT;
+	dev->flags		|= IFF_POINTOPOINT;
+	dev->flags		|= IFF_NOARP;
 
 	/* Enable Mulitcasting if specified by user*/
 	if (ppp_priv_area->mc == WANOPT_YES){
-		dev->flags     |= IFF_MULTICAST;
+		dev->flags	|= IFF_MULTICAST;
 	}
 
-#ifndef LINUX_2_1
+#ifdef LINUX_2_0
 	dev->family		= AF_INET;
 #endif	
 	dev->mtu		= wandev->mtu;
@@ -615,7 +793,11 @@
         dev->tx_queue_len = 100;
    
 	/* Initialize socket buffers */
-	dev_init_buffers(dev);
+      #if !defined(LINUX_2_1) && !defined(LINUX_2_4)
+        for (i = 0; i < DEV_NUMBUFFS; ++i)
+                skb_queue_head_init(&dev->buffs[i]);
+      #endif
+
 	return 0;
 }
 
@@ -626,105 +808,44 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open(struct net_device *dev)
+static int if_open (netdevice_t *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
-	ppp_flags_t *flags = card->flags;
 	struct timeval tv;
-	int err = 0;
-
-	if (netif_running(dev))
-		return -EBUSY;		/* only one open is allowed */
-	
-	if (test_and_set_bit(0, (void*)&card->wandev.critical))
-		return -EAGAIN;
-
-	if (!card->configured){
-
-		if (config508(ppp_priv_area, card)){
-
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-
-		Intr_test_counter = 0;
-		err = intr_test( card );
-
-		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
-			printk("%s: Interrupt Test Failed, Counter: %i\n", 
-				card->devname, Intr_test_counter);
-			printk( "%s: Please choose another interrupt\n",card->devname);
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-		
-		printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", 
-			card->devname, Intr_test_counter);
-		card->configured = 1;
-
-	}
-
-	/* Initialize Rx/Tx buffer control fields */
-	init_ppp_tx_rx_buff( card );
-
-	if (ppp_set_intr_mode(card, PPP_INTR_RXRDY|
-			    		PPP_INTR_TXRDY|
-				    	PPP_INTR_MODEM|
-				    	PPP_INTR_CMD  |
-				    	PPP_INTR_DISC |
-				    	PPP_INTR_OPEN |
-				    	PPP_INTR_DROP_DTR |
-					PPP_INTR_TIMER)) {
-	
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
+	//unsigned long smp_flags;
 
-	}
-
-        /* Turn off the transmit and timer interrupt */
-	flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ;
+	if (is_dev_running(dev))
+		return -EBUSY;
 
-	/* If you are not the authenticator and any one of the protocol is 
-	 * enabled then we call the set_out_bound_authentication.
-	 */
-	if ( !card->u.p.authenticator  && (ppp_priv_area->pap || ppp_priv_area->chap)) {
-		if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-	} 
-	
-	/* If you are the authenticator and any one of the protocol is enabled
-	 * then we call the set_in_bound_authentication.
-	 */
-	if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) {
-		if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-	}
+	wanpipe_open(card);
 
-	if (ppp_comm_enable(card)) {
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
-	}
+#ifdef LINUX_2_4
+	netif_start_queue(dev);
+#else
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+#endif
 	
-	wanpipe_set_state(card, WAN_CONNECTING);
-	wanpipe_open(card);
-	dev->mtu = min(dev->mtu, card->wandev.mtu);
-	netif_start_queue(dev);	
 	do_gettimeofday( &tv );
 	ppp_priv_area->router_start_time = tv.tv_sec;
-	card->wandev.critical = 0;
 
-	return err;
+	/* We cannot configure the card here because we don't
+	 * have access to the interface IP addresses.
+         * Once the interface initilization is complete, we will be
+         * able to access the IP addresses.  Therefore,
+         * configure the ppp link in the poll routine */
+	set_bit(0,&ppp_priv_area->config_ppp);
+	ppp_priv_area->config_wait_timeout=jiffies;
+
+	/* Start the PPP configuration after 1sec delay.
+	 * This will give the interface initilization time
+	 * to finish its configuration */
+	del_timer(&ppp_priv_area->poll_delay_timer);
+	ppp_priv_area->poll_delay_timer.expires = jiffies+HZ;
+	add_timer(&ppp_priv_area->poll_delay_timer);
+	return 0;
 }
 
 /*============================================================================
@@ -732,20 +853,18 @@
  * o if this is the last open, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close(struct net_device *dev)
+static int if_close(netdevice_t *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 
-	if (test_and_set_bit(0, (void*)&card->wandev.critical))
-		return -EAGAIN;
-	
-	netif_stop_queue(dev);
+	stop_net_queue(dev);
+#ifndef LINUX_2_4
+	dev->start=0;
+#endif
 	wanpipe_close(card);
-	wanpipe_set_state(card, WAN_DISCONNECTED);
-	ppp_set_intr_mode(card, 0);
-	ppp_comm_disable(card);
-	card->wandev.critical = 0;
+
+	del_timer (&ppp_priv_area->poll_delay_timer);
 	return 0;
 }
 
@@ -758,13 +877,12 @@
  *
  * Return:	media header length.
  */
-static int if_header(struct sk_buff *skb, struct net_device *dev,
+static int if_header(struct sk_buff *skb, netdevice_t *dev,
 	unsigned short type, void *daddr, void *saddr, unsigned len)
 {
 	switch (type)
 	{
 		case ETH_P_IP:
-	
 		case ETH_P_IPX:
 			skb->protocol = htons(type);
 			break;
@@ -782,10 +900,10 @@
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
-
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 static int if_rebuild_hdr (struct sk_buff *skb)
 {
-	struct net_device *dev = skb->dev;
+	netdevice_t *dev = skb->dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 
@@ -794,33 +912,39 @@
 	return 1;
 }
 
+#else
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
+                           struct sk_buff* skb)
+{
+	return 1;
+
+}
+#endif
 
+#ifdef LINUX_2_4
 /*============================================================================
- * Handle transmit timeout from netif watchdog
+ * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (struct net_device *dev)
+static void if_tx_timeout (netdevice_t *dev)
 {
-	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card = ppp_priv_area->card;
-
-
+    	ppp_private_area_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	
 	/* If our device stays busy for at least 5 seconds then we will
-	 * kick start the device by making dev->tbusy = 0.  We expect 
-	 * that our device never stays busy more than 5 seconds. So this
-	 * is only used as a last resort. 
+	 * kick start the device by making dev->tbusy = 0.  We expect
+	 * that our device never stays busy more than 5 seconds. So this                 
+	 * is only used as a last resort.
 	 */
 
-	++ppp_priv_area->if_send_stat.if_send_tbusy;
-	++card->wandev.stats.collisions;
-
-	printk (KERN_INFO "%s: Transmit times out\n", card->devname);
-
-	++ppp_priv_area->if_send_stat.if_send_tbusy_timeout;
+	++ chan->if_send_stat.if_send_tbusy;
 	++card->wandev.stats.collisions;
 
-	/* unbusy the card (because only one interface per card) */
-	netif_wake_queue(dev);
+	printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
+	++chan->if_send_stat.if_send_tbusy_timeout;
+	netif_wake_queue (dev);
 }
+#endif
+
 
 
 /*============================================================================
@@ -840,19 +964,22 @@
  * 2. Setting tbusy flag will inhibit further transmit requests from the
  *    protocol stack and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff *skb, struct net_device *dev)
+static int if_send (struct sk_buff *skb, netdevice_t *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 	unsigned char *sendpacket;
 	unsigned long smp_flags;
 	ppp_flags_t *flags = card->flags;
-	int retry = 0;
 	int udp_type;
-	
+	int err=0;
 	
 	++ppp_priv_area->if_send_stat.if_send_entry;
 
+#ifdef LINUX_2_4
+	netif_stop_queue(dev);
+#endif
+	
 	if (skb == NULL) {
 
 		/* If we get here, some higher layer thinks we've missed an
@@ -862,12 +989,37 @@
 			card->devname, dev->name);
 		
 		++ppp_priv_area->if_send_stat.if_send_skb_null;
-		
-		netif_wake_queue(dev);
+	
+		wake_net_dev(dev);
 		return 0;
-
 	}
 
+#ifndef LINUX_2_4
+	if (dev->tbusy) {
+
+		/* If our device stays busy for at least 5 seconds then we will
+		 * kick start the device by making dev->tbusy = 0.  We expect 
+		 * that our device never stays busy more than 5 seconds. So this
+		 * is only used as a last resort. 
+		 */
+              
+		++ppp_priv_area->if_send_stat.if_send_tbusy;
+        	++card->wandev.stats.collisions;
+
+		if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) {
+			return 1;
+		}
+
+		printk (KERN_INFO "%s: Transmit times out on %s\n",card->devname,dev->name);
+	
+		++ppp_priv_area->if_send_stat.if_send_tbusy_timeout;
+		++card->wandev.stats.collisions;
+
+		/* unbusy the card (because only one interface per card)*/
+		dev->tbusy = 0;
+	}	
+#endif
+	
 	sendpacket = skb->data;
 
 	udp_type = udp_pkt_type( skb, card );
@@ -879,15 +1031,18 @@
 	               	flags->imask |= PPP_INTR_TIMER;
 		}
 		++ppp_priv_area->if_send_stat.if_send_PIPE_request;
+		start_net_queue(dev);
 		return 0;
-
 	}
 
 	/* Check for broadcast and multicast addresses 
 	 * If found, drop (deallocate) a packet and return.
 	 */
 	if(chk_bcast_mcast_addr(card, dev, skb)){
-                        return 0;
+		++card->wandev.stats.tx_dropped;
+		wan_dev_kfree_skb(skb,FREE_WRITE);
+		start_net_queue(dev);
+		return 0;
 	}
 
 
@@ -895,31 +1050,28 @@
 		s508_lock(card,&smp_flags);
 	}
 
-    	if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+    	if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
 
 		printk(KERN_INFO "%s: Critical in if_send: %lx\n",
 				card->wandev.name,card->wandev.critical);
-    		dev_kfree_skb(skb);
-
+		
 		++card->wandev.stats.tx_dropped;
 		++ppp_priv_area->if_send_stat.if_send_critical_non_ISR;
-	
-		if(card->hw.type != SDLA_S514){	
-			s508_unlock(card,&smp_flags);
-		}
-
-		return 0;
+		start_net_queue(dev);
+		goto if_send_exit_crit;
 	}
 
 	if (card->wandev.state != WAN_CONNECTED) {
 
 		++ppp_priv_area->if_send_stat.if_send_wan_disconnected;
         	++card->wandev.stats.tx_dropped;
-
+		start_net_queue(dev);
+		
      	} else if (!skb->protocol) {
 		++ppp_priv_area->if_send_stat.if_send_protocol_error;
         	++card->wandev.stats.tx_errors;
-
+		start_net_queue(dev);
+		
 	} else {
 
 		/*If it's IPX change the network numbers to 0 if they're ours.*/
@@ -929,37 +1081,43 @@
 					ppp_priv_area->network_number, 0);
 			} else {
 				++card->wandev.stats.tx_dropped;
-				goto tx_done;
+				start_net_queue(dev);
+				goto if_send_exit_crit;
 			}
 		}
 
 		if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
-			retry = 1;
-			netif_stop_queue(dev);
+			stop_net_queue(dev);
 			++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full;
 			++ppp_priv_area->if_send_stat.if_send_tx_int_enabled;
-			ppp_priv_area->tick_counter = jiffies;
-			flags->imask |= 0x02;	/* unmask Tx interrupts */
 		} else {
 			++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr;
 			++card->wandev.stats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 			card->wandev.stats.tx_bytes += skb->len;
+#endif
+			start_net_queue(dev);
+#ifdef LINUX_2_4
+			dev->trans_start = jiffies;
+#endif
 		}
     	}
 	
-tx_done:	
-	if (!retry){
-		dev_kfree_skb(skb);
+if_send_exit_crit:
+	
+	if (!(err=is_queue_stopped(dev))){
+      		wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+		ppp_priv_area->tick_counter = jiffies;
+		flags->imask |= PPP_INTR_TXRDY;	/* unmask Tx interrupts */
 	}
-
-	card->wandev.critical = 0;
 	
+	clear_bit(SEND_CRIT,&card->wandev.critical);
 	if(card->hw.type != SDLA_S514){	
 		s508_unlock(card,&smp_flags);
 	}
 
-	
-	return retry;
+	return err;
 }
 
 
@@ -968,7 +1126,7 @@
  */
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, struct net_device* dev,
+                                struct sk_buff *skb, netdevice_t* dev,
                                 ppp_private_area_t* ppp_priv_area )
 {
 	int udp_pkt_stored = 0;
@@ -982,8 +1140,13 @@
 		udp_pkt_stored = 1;
 	}else{
 		if (skb->len > MAX_LGTH_UDP_MGNT_PKT){
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 			printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n",
 				card->devname, skb->len);
+#else
+			printk(KERN_INFO "%s: PIPEMON UDP request too long : %li\n",
+				card->devname, skb->len);
+#endif
 		}else{
 			printk(KERN_INFO "%s: PIPEMON UPD request already pending\n",
 				card->devname);
@@ -991,7 +1154,12 @@
 		ppp_priv_area->udp_pkt_lgth = 0;
 	}
 
-	dev_kfree_skb(skb);
+	if(udp_pkt_src == UDP_PKT_FRM_STACK){
+		wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+                wan_dev_kfree_skb(skb, FREE_READ);
+	}
+
 	return(udp_pkt_stored);
 }
 
@@ -1157,7 +1325,11 @@
  * Get ethernet-style interface statistics.
  * Return a pointer to struct net_device_stats.
  */
-static struct net_device_stats *if_stats(struct net_device *dev)
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats *if_stats(netdevice_t *dev)
+#else
+static struct enet_statistics *if_stats(netdevice_t *dev)
+#endif
 {
 
 	ppp_private_area_t *ppp_priv_area = dev->priv;
@@ -1354,7 +1526,7 @@
 
        /* If timer has been enabled, set the timer delay to 1sec */
        if (mode & 0x80){
-       		ppp_intr_data->timer_len = 5;//100; //250;
+       		ppp_intr_data->timer_len = 250; //5;//100; //250;
                 mb->cmd.length = 4;
         }
 	
@@ -1382,7 +1554,9 @@
 	
 	if (err != CMD_OK) 
 		ppp_error(card, err, mb);
-	
+	else	
+		card->u.p.comm_enabled = 1;	
+
 	return err;
 }
 
@@ -1399,10 +1573,46 @@
 	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
 	if (err != CMD_OK) 
 		ppp_error(card, err, mb);
+	else
+		card->u.p.comm_enabled = 0;
 
 	return err;
 }
 
+static int ppp_comm_disable_shutdown(sdla_t *card)
+{
+	ppp_mbox_t *mb = card->mbox;
+	ppp_intr_info_t *ppp_intr_data;
+	int err;
+
+	if (!mb){
+		return 1;
+	}
+	
+	ppp_intr_data = (ppp_intr_info_t *) &mb->data[0];
+	
+	/* Disable all interrupts */
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	ppp_intr_data->i_enable = 0;
+
+	ppp_intr_data->irq = card->hw.irq;
+	mb->cmd.length = 2;
+
+	mb->cmd.command = PPP_SET_INTR_FLAGS;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+	/* Disable communicatinons */
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_COMM_DISABLE;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+	card->u.p.comm_enabled = 0;
+
+	return 0;
+}
+
+
+
 /*============================================================================
  * Get communications error statistics.
  */
@@ -1495,36 +1705,40 @@
 /*============================================================================
  * PPP interrupt service routine.
  */
-STATIC void wpp_isr(sdla_t *card)
+static void wpp_isr (sdla_t *card)
 {
 	ppp_flags_t *flags = card->flags;
 	char *ptr = &flags->iflag;
-	struct net_device *dev = card->wandev.dev;
-
-
+	netdevice_t *dev = card->wandev.dev;
 	int i;
 
 	card->in_isr = 1;
-	
 	++card->statistics.isr_entry;
 
-	//FIXME: Do we need this
-	card->force_enable_irq = 0;
-
-	if(card->hw.type != SDLA_S514){
-		if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
-        	
+	if (!dev && flags->iflag != PPP_INTR_CMD){
+		card->in_isr = 0;
+		flags->iflag = 0;
+		return;
+	}
+	
+	if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
+		card->in_isr = 0;
+		flags->iflag = 0;
+		return;
+	}
+	
+	
+	if(card->hw.type != SDLA_S514){
+		if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
 			++card->statistics.isr_already_critical;
 			printk (KERN_INFO "%s: Critical while in ISR!\n",
 					card->devname);
 			card->in_isr = 0;
+			flags->iflag = 0;
 			return;
-	
 		}
 	}
 
-	card->buff_int_mode_unbusy = 0;
-
 	switch (flags->iflag) {
 
 		case PPP_INTR_RXRDY:	/* receive interrupt  0x01  (bit 0)*/
@@ -1535,8 +1749,7 @@
 		case PPP_INTR_TXRDY:	/* transmit interrupt  0x02 (bit 1)*/
 			++card->statistics.isr_tx;
 			flags->imask &= ~PPP_INTR_TXRDY;
-			netif_wake_queue (dev);
-			card->buff_int_mode_unbusy = 1;
+			wake_net_dev(dev);
 			break;
 
 		case PPP_INTR_CMD:      /* interface command completed */
@@ -1567,10 +1780,7 @@
 	
 	card->in_isr = 0;
 	flags->iflag = 0;
-	card->wandev.critical = 0;
-
-	if(card->buff_int_mode_unbusy)
-		netif_wake_queue(dev);
+	return;
 }
 
 /*============================================================================
@@ -1579,7 +1789,7 @@
 static void rx_intr(sdla_t *card)
 {
 	ppp_buf_ctl_t *rxbuf = card->rxmb;
-	struct net_device *dev = card->wandev.dev;
+	netdevice_t *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area;
 	struct sk_buff *skb;
 	unsigned len;
@@ -1603,11 +1813,21 @@
 		printk(KERN_INFO "\n");	
 		
 		++card->statistics.rx_intr_corrupt_rx_bfr;
-		return;
 
-	}
 
-	if (dev && netif_running(dev)) {
+		/* Bug Fix: Mar 6 2000
+                 * If we get a corrupted mailbox, it means that driver 
+                 * is out of sync with the firmware. There is no recovery.
+                 * If we don't turn off all interrupts for this card
+                 * the machine will crash. 
+                 */
+		printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
+		printk(KERN_INFO "Please contact Sangoma Technologies !\n");
+		ppp_set_intr_mode(card,0);
+		return;
+	}
+      
+	if (dev && is_dev_running(dev) && dev->priv){
 	
 		len  = rxbuf->length;
 		ppp_priv_area = dev->priv;
@@ -1662,9 +1882,12 @@
 			
 				/* Handle an IPXWAN packet */
 				if( ppp_priv_area->enable_IPX) {
-					ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX));
-                        		dev_kfree_skb(skb);
-
+					
+					/* Make sure we are not already sending */
+					if (!test_bit(SEND_CRIT, &card->wandev.critical)){
+					 	ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX));
+					}
+					wan_dev_kfree_skb(skb,FREE_READ);
 
 				} else {
 					++card->wandev.stats.rx_dropped;
@@ -1675,15 +1898,19 @@
 				skb->mac.raw  = skb->data;
 
 			    	++card->wandev.stats.rx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 				card->wandev.stats.rx_bytes += skb->len;
+#endif
 		    		++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack;	
 				netif_rx(skb);
 			}
 
 		} else {
-		
-			printk(KERN_INFO "%s: no socket buffers available!\n",
-				card->devname);
+	
+			if (net_ratelimit()){
+				printk(KERN_INFO "%s: no socket buffers available!\n",
+					card->devname);
+			}
 			++card->wandev.stats.rx_dropped;
 			++ppp_priv_area->rx_intr_stat.rx_intr_no_socket;
 		}
@@ -1703,16 +1930,18 @@
 void event_intr (sdla_t *card)
 {
 
- 	struct net_device* dev = card->wandev.dev;
+ 	netdevice_t* dev = card->wandev.dev;
         ppp_private_area_t* ppp_priv_area = dev->priv;
 	volatile ppp_flags_t *flags = card->flags;
 
 	switch (flags->iflag){
 
 		case PPP_INTR_MODEM:    /* modem status change (DCD, CTS) 0x04  (bit 2)*/
-			printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n",
-				card->devname, DCD(flags->mstatus), CTS(flags->mstatus));
 
+			if (net_ratelimit()){
+				printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n",
+					card->devname, DCD(flags->mstatus), CTS(flags->mstatus));
+			}
 			break;
 
 		case PPP_INTR_DISC:  	/* Data link disconnected 0x10  (bit 4)*/	
@@ -1723,15 +1952,16 @@
 			if (flags->disc_cause &
 				(PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP |
 				PPP_REMOTE_TERMINATION)) {
+
 				if (card->u.p.ip_mode == WANOPT_PPP_PEER) { 
-					Read_connection_info = 1;
-					remove_route (card);
+					set_bit(0,&Read_connection_info);
 				}
 				wanpipe_set_state(card, WAN_DISCONNECTED);
+
 				show_disc_cause(card, flags->disc_cause);
-				ppp_priv_area->timer_int_enabled |= 
-						TMR_INT_ENABLED_PPP_EVENT;
+				ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT;
 				flags->imask |= PPP_INTR_TIMER;
+				trigger_ppp_poll(dev);
 			}
 			break;
 
@@ -1743,30 +1973,68 @@
 
 			if (flags->lcp_state == 0x09 && 
                            (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){
+
                                 /* Initialize the polling timer and set the state
-                                 * to WAN_CONNNECTED 
-                                 */
-                                card->state_tick = jiffies;
-				wanpipe_set_state(card, WAN_CONNECTED);
-				ppp_priv_area->timer_int_enabled |= 
+                                 * to WAN_CONNNECTED */
+
+
+				/* BUG FIX: When the protocol restarts, during heavy 
+                                 * traffic, board tx buffers and driver tx buffers
+                                 * can go out of sync.  This checks the condition
+                                 * and if the tx buffers are out of sync, the 
+                                 * protocols are restarted. 
+                                 * I don't know why the board tx buffer is out
+                                 * of sync. It could be that a packets is tx
+                                 * while the link is down, but that is not 
+                                 * possible. The other possiblility is that the
+                                 * firmware doesn't reinitialize properly.
+                                 * FIXME: A better fix should be found.
+                                 */ 
+				if (detect_and_fix_tx_bug(card)){
+
+					ppp_comm_disable(card);
+
+					wanpipe_set_state(card, WAN_DISCONNECTED);
+
+					ppp_priv_area->timer_int_enabled |= 
 						TMR_INT_ENABLED_PPP_EVENT;
+					flags->imask |= PPP_INTR_TIMER;
+					break;	
+				}
+
+				card->state_tick = jiffies;
+				wanpipe_set_state(card, WAN_CONNECTED);
+
+				NEX_PRINTK(KERN_INFO "CON: L Tx: %lx  B Tx: %lx || L Rx %lx B Rx %lx\n",
+					(unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next,
+					(unsigned long)card->rxmb, *card->u.p.rxbuf_next);
+
+				/* Tell timer interrupt that PPP event occured */
+				ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT;
 				flags->imask |= PPP_INTR_TIMER;
 
+				/* If we are in PEER mode, we must first obtain the
+				 * IP information and then go into the poll routine */
+				if (card->u.p.ip_mode != WANOPT_PPP_PEER){	
+					trigger_ppp_poll(dev);
+				}
 			}
                    	break;
 
 		case PPP_INTR_DROP_DTR:		/* DTR drop timeout expired  0x40 bit 6 */
 
 			NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); 
+
 			if (card->u.p.ip_mode == WANOPT_PPP_PEER) { 
-				Read_connection_info = 1;
-				remove_route (card);
+				set_bit(0,&Read_connection_info);
 			}
+		
 			wanpipe_set_state(card, WAN_DISCONNECTED);
+
 			show_disc_cause(card, flags->disc_cause);
-			ppp_priv_area->timer_int_enabled |= 
-						TMR_INT_ENABLED_PPP_EVENT;
+			ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT;
 			flags->imask |= PPP_INTR_TIMER;
+			trigger_ppp_poll(dev);
 			break;
 		
 		default:
@@ -1781,10 +2049,18 @@
 void timer_intr (sdla_t *card)
 {
 
-        struct net_device* dev = card->wandev.dev;
+        netdevice_t* dev = card->wandev.dev;
         ppp_private_area_t* ppp_priv_area = dev->priv;
 	ppp_flags_t *flags = card->flags;
 
+
+	if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){
+		if (!config_ppp(card)){
+			ppp_priv_area->timer_int_enabled &= 
+					~TMR_INT_ENABLED_CONFIG;	
+		}
+	}
+
 	/* Update statistics */
 	if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){
 		ppp_get_err_stats(card);
@@ -1801,12 +2077,11 @@
 		ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
 	}
 
-
 	/* PPP Event */
 	if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){
 
 		if (card->wandev.state == WAN_DISCONNECTED){
-			poll_disconnected(card);
+			retrigger_comm(card);
 		}
 
 		/* If the state is CONNECTING, it means that communicatins were
@@ -1823,21 +2098,22 @@
 	 	 * poll for an IP address which will be provided by remote end.
 	 	 */
 		else if ((card->wandev.state == WAN_CONNECTED && 
-		  	card->u.p.ip_mode == WANOPT_PPP_PEER) && 
-		  	Read_connection_info){
+		  	  card->u.p.ip_mode == WANOPT_PPP_PEER) && 
+		  	  test_bit(0,&Read_connection_info)){
 
 			card->state_tick = jiffies;
-			if (!read_connection_info (card)){
-				card->poll = &process_route;
+			if (read_connection_info (card)){
+				printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n",
+					card->devname);
+			}else{
+				clear_bit(0,&Read_connection_info);
+				set_bit(1,&Read_connection_info);
+				trigger_ppp_poll(dev);
 			}
-
 		}else{
-			/* If we are using Static IP,no need to poll for
-			 * an IP address. 
-		 	 */
-			NEX_PRINTK(KERN_INFO "Turning off TIMER \n");
+			//FIXME Put the comment back int
 			ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT;
-		}	
+		}
 
 	}/* End of PPP_EVENT */
 
@@ -1970,32 +2246,62 @@
 static void process_route (sdla_t *card)
 {
 	ppp_flags_t *flags = card->flags;
-	struct net_device *dev = card->wandev.dev;
-	struct in_device *in_dev = dev->ip_ptr;
+	netdevice_t *dev = card->wandev.dev;
+	ppp_private_area_t *ppp_priv_area = dev->priv;
 	
-	if (in_dev != NULL ) {
-		if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
-		    (Read_connection_info && flags->ip_state == 0x09)){ 
-		
-			printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname);
-			if (read_info( card )) {
-   				printk(KERN_INFO 
-					"%s: An error occurred in IP assignment.\n", 
-					card->devname);
-			} else {
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
+	if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
+	    (flags->ip_state == 0x09)){ 
+
+		/* We get ip_local from the firmware in PEER mode.
+	         * Therefore, if ip_local is 0, we failed to obtain
+         	 * the remote IP address. */
+		if (ppp_priv_area->ip_local == 0) 
+			return;
+		
+		printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname);
+		if (read_info( card )) {
+   			printk(KERN_INFO 
+				"%s: An error occurred in IP assignment.\n", 
+				card->devname);
+		} else {
+			struct in_device *in_dev = dev->ip_ptr;
+			if (in_dev != NULL ) {
 				struct in_ifaddr *ifa = in_dev->ifa_list;
 				printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", 
-						card->devname, in_ntoa(ifa->ifa_local));
+					card->devname, in_ntoa(ifa->ifa_local));
 				printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", 
 						card->devname, in_ntoa(ifa->ifa_address));
+			}else{
+				printk(KERN_INFO 
+				"%s: Error: Failed to add a route for PPP interface %s\n",
+					card->devname,dev->name);	
 			}
-			Read_connection_info = 0;
 		}
-	}else{
-		printk(KERN_INFO "%s: Error: Null pointer in Poll Active\n",
+	}
+#else
+
+	if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
+	    (flags->ip_state == 0x09)){ 
+	
+		if (ppp_priv_area->ip_local == 0)
+			return;
+	
+		printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname);
+		if (read_info( card )) {
+			printk(KERN_INFO 
+				"%s: An error occurred in IP assignment.\n", 
 				card->devname);
+		} else {
+			printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", 
+					card->devname, in_ntoa(dev->pa_addr));
+			printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", 
+					card->devname, in_ntoa(dev->pa_dstaddr));
+		}
 	}
-	card->poll = NULL;
+
+#endif
 
 }
 
@@ -2004,19 +2310,17 @@
  *  o if interface is up and the hold-down timeout has expired, then retry
  *    connection.
  */
-static void poll_disconnected(sdla_t *card)
+static void retrigger_comm(sdla_t *card)
 {
-	struct net_device *dev = card->wandev.dev;
+	netdevice_t *dev = card->wandev.dev;
+
+	if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
 
-	if (dev && netif_running(dev) &&
-	    ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
-	
 		wanpipe_set_state(card, WAN_CONNECTING);
-		
+
 		if(ppp_comm_enable(card) == CMD_OK){
 			init_ppp_tx_rx_buff( card );
 		}	         
-		
 	}
 }
 
@@ -2025,12 +2329,14 @@
 /*============================================================================
  * Configure S508 adapter.
  */
-static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card)
+static int config508(netdevice_t *dev, sdla_t *card)
 {
 	ppp508_conf_t cfg;
-	struct net_device *dev = card->wandev.dev;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct in_device *in_dev = dev->ip_ptr;
-	
+#endif
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+
 	/* Prepare PPP configuration structure */
 	memset(&cfg, 0, sizeof(ppp508_conf_t));
 
@@ -2040,6 +2346,7 @@
 	if (card->wandev.interface == WANOPT_RS232)
 		cfg.conf_flags |= INTERFACE_LEVEL_RS232;
 
+
         cfg.conf_flags 	|= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/
 	cfg.txbuf_percent	= PERCENT_TX_BUFF;	/* % of Tx bufs */
 	cfg.mtu_local		= card->wandev.mtu;
@@ -2065,6 +2372,7 @@
 				card->devname);
 		cfg.auth_options = INBOUND_AUTH;
 	}
+
 	if( ppp_priv_area->pap == WANOPT_YES){
 		cfg.auth_options |=PAP_AUTH;
 		printk(KERN_INFO "%s: Pap enabled\n", card->devname);
@@ -2076,6 +2384,7 @@
 
 
 	if (ppp_priv_area->enable_IPX == WANOPT_YES){
+		printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname);
 		cfg.ipx_options		= ENABLE_IPX | ROUTING_PROT_DEFAULT;
 	}else{
 		cfg.ipx_options 	= DISABLE_IPX;
@@ -2085,25 +2394,92 @@
 	
 		case WANOPT_PPP_STATIC:
 
+			printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname);
 			cfg.ip_options		= L_AND_R_IP_NO_ASSIG | 
 							    ENABLE_IP;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 			cfg.ip_local		= in_dev->ifa_list->ifa_local;
 			cfg.ip_remote		= in_dev->ifa_list->ifa_address;
+#else
+			cfg.ip_local		= dev->pa_addr;
+			cfg.ip_remote		= dev->pa_dstaddr;
+#endif
+
+			/* Debugging code used to check that IP addresses
+                         * obtained from the kernel are correct */
+
+			{
+			char laddr[20];
+			char raddr[20];
+			strcpy(laddr,in_ntoa(cfg.ip_local));
+			strcpy(raddr,in_ntoa(cfg.ip_remote));
+
                         NEX_PRINTK(KERN_INFO "Local %s Remote %s Name %s\n",
-					in_ntoa(cfg.ip_local), 
-					in_ntoa(cfg.ip_remote), 
-					dev->name);
+					laddr,raddr, dev->name);
+			
+			}	
+			break;
+
+		case WANOPT_PPP_HOST:
+
+			printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname);
+			cfg.ip_options		= L_IP_LOCAL_ASSIG |
+						  R_IP_LOCAL_ASSIG | 
+						  ENABLE_IP;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+			cfg.ip_local		= in_dev->ifa_list->ifa_local;
+			cfg.ip_remote		= in_dev->ifa_list->ifa_address;
+#else
+			cfg.ip_local		= dev->pa_addr;
+			cfg.ip_remote		= dev->pa_dstaddr;
+#endif
+
+			/* Debugging code used to check that IP addresses
+                         * obtained from the kernel are correct */
+			{
+			char laddr[20];
+			char raddr[20];
+			strcpy(laddr,in_ntoa(cfg.ip_local));
+			strcpy(raddr,in_ntoa(cfg.ip_remote));
+
+                        NEX_PRINTK (KERN_INFO "Local %s Remote %s Name %s\n",
+					laddr,raddr, dev->name);
+			
+			}	
+
+
 			break;
 	
 		case WANOPT_PPP_PEER:
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
+			printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname);
 			cfg.ip_options		= L_IP_REMOTE_ASSIG | 
 						  R_IP_REMOTE_ASSIG | 
 							  ENABLE_IP;
 			cfg.ip_local		= 0x00;
 			cfg.ip_remote		= 0x00;
 			break;
-	
+
+#else
+
+			/* No PEER support for 2.0.X kernels, drop down to default
+   			 * condition */
+
+			printk(KERN_INFO "%s: ERROR, PEER mode is not supported in 2.0.X kernels\n",
+						card->devname);
+			
+#endif
+
+		default:
+			printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n",
+					card->devname);
+			printk(KERN_INFO "%s:        PPP IP Modes: STATIC, PEER or HOST\n",
+					card->devname);	
+			return 1;
 	}
+
 	return ppp_configure(card, &cfg);
 }
 
@@ -2168,7 +2544,7 @@
 /*=============================================================================
  * Process UDP call of type PTPIPEAB.
  */
-static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, 
+static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, 
 				 ppp_private_area_t *ppp_priv_area ) 
 {
 	unsigned char buf2[5];
@@ -2186,33 +2562,31 @@
 	memcpy(&buf2, &card->wandev.udp_port, 2 );
 
 
-	switch(ppp_udp_pkt->cblock.command) {
+	if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
 
-		/* FT1 MONITOR STATUS */
-		case FT1_MONITOR_STATUS_CTRL:
-		
-		/* PPIPE_ENABLE_TRACING */
-		case PPIPE_ENABLE_TRACING:
-		   
-		/* PPIPE_DISABLE_TRACING */
-		case PPIPE_DISABLE_TRACING:
-		   
-		/* PPIPE_GET_TRACE_INFO */
-		case PPIPE_GET_TRACE_INFO:
-		   
-		/* SET FT1 MODE */
-		case SET_FT1_MODE:
-			if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-			
-				++ppp_priv_area->pipe_mgmt_stat.
-						UDP_PIPE_mgmt_direction_err;
+		switch(ppp_udp_pkt->cblock.command) {
+
+			case PPIPE_GET_IBA_DATA:
+			case PPP_READ_CONFIG:
+			case PPP_GET_CONNECTION_INFO:
+			case PPIPE_ROUTER_UP_TIME:
+			case PPP_READ_STATISTICS:
+			case PPP_READ_ERROR_STATS:
+			case PPP_READ_PACKET_STATS:
+			case PPP_READ_LCP_STATS:
+			case PPP_READ_IPCP_STATS:
+			case PPP_READ_IPXCP_STATS:
+			case PPP_READ_PAP_STATS:
+			case PPP_READ_CHAP_STATS:
+			case PPP_READ_CODE_VERSION:
+				udp_mgmt_req_valid = 1;
+				break;
+			   
+			default:
 				udp_mgmt_req_valid = 0;
-			}	 
-			break;
-		   
-		default:
-			break;
-	} 
+				break;
+		} 
+	}
 	
   	if(!udp_mgmt_req_valid) {
 	    
@@ -2221,7 +2595,13 @@
 
     		/* set return code */
     		ppp_udp_pkt->cblock.result = 0xCD; 
-
+		++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err;
+	
+		if (net_ratelimit()){	
+			printk(KERN_INFO 
+			"%s: Warning, Illegal UDP command attempted from network: %x\n",
+			card->devname,ppp_udp_pkt->cblock.command);
+		}
    	} else {
 		/* Initialize the trace element */
 		trace_element_t trace_element;		    
@@ -2422,27 +2802,24 @@
 
 			/* set return code */
 			ppp_udp_pkt->cblock.result = 0x00;
-
-			break;
-
-		/* PPIPE_KILL_BOARD */
-		case PPIPE_KILL_BOARD:
+			ppp_udp_pkt->cblock.result = 0;
 			break;
 
 		/* PPIPE_FT1_READ_STATUS */
 		case PPIPE_FT1_READ_STATUS:
-			sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data, 2);
-			ppp_udp_pkt->cblock.length = 2;
+			sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2);
+			ppp_udp_pkt->cblock.length = mbox->cmd.length = 2;
 			ppp_udp_pkt->cblock.result = 0;
-			mbox->cmd.length = 2;
 			break;
 		
 		case PPIPE_FLUSH_DRIVER_STATS:   
 			init_ppp_priv_struct( ppp_priv_area );
 			init_global_statistics( card );
 			mbox->cmd.length = 0;
+			ppp_udp_pkt->cblock.result = 0;
 			break;
 
+		
 		case PPIPE_ROUTER_UP_TIME:
 
 			do_gettimeofday( &tv );
@@ -2450,34 +2827,11 @@
 					ppp_priv_area->router_start_time;
 			*(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time;
 			mbox->cmd.length = 4;
+			ppp_udp_pkt->cblock.result = 0;
 			break;
 
-		/* FT1 MONITOR STATUS */
-   		case FT1_MONITOR_STATUS_CTRL:
-	
-			/* Enable FT1 MONITOR STATUS */
-	        	if( ppp_udp_pkt->data[0] == 1) {
-			
-				if( rCount++ != 0 ) {
-		        		ppp_udp_pkt->cblock.result = 0;
-	          			mbox->cmd.length = 1;
-		  			break;
-		    		}	
-	      		}
-
-	      		/* Disable FT1 MONITOR STATUS */
-	      		if( ppp_udp_pkt->data[0] == 0) {
-
-	      	   		if( --rCount != 0) {
-		  			ppp_udp_pkt->cblock.result = 0;
-		  			mbox->cmd.length = 1;
-		  			break;
-	   	    		} 
-	      		} 	
-
-		/* PPIPE_DRIVER_STATISTICS */   
+				/* PPIPE_DRIVER_STATISTICS */   
 		case PPIPE_DRIVER_STAT_IFSEND:
-			printk(KERN_INFO "Getting IF_SEND Drivers Statistics\n");
 			memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, 
 				sizeof(if_send_stat_t));
 
@@ -2515,8 +2869,38 @@
 			mbox->cmd.length = ppp_udp_pkt->cblock.length;
 			break;
 
+
+		/* FT1 MONITOR STATUS */
+   		case FT1_MONITOR_STATUS_CTRL:
 	
+			/* Enable FT1 MONITOR STATUS */
+	        	if( ppp_udp_pkt->data[0] == 1) {
+			
+				if( rCount++ != 0 ) {
+		        		ppp_udp_pkt->cblock.result = 0;
+	          			mbox->cmd.length = 1;
+		  			break;
+		    		}	
+	      		}
+
+	      		/* Disable FT1 MONITOR STATUS */
+	      		if( ppp_udp_pkt->data[0] == 0) {
+
+	      	   		if( --rCount != 0) {
+		  			ppp_udp_pkt->cblock.result = 0;
+		  			mbox->cmd.length = 1;
+		  			break;
+	   	    		} 
+	      		} 	
+			goto udp_dflt_cmd;
+			
+		/* WARNING: FIXME: This should be fixed.
+		 * The FT1 Status Ctrl doesn't have a break
+                 * statment.  Thus, no code must be inserted
+                 * HERE: between default and above case statement */
+
 		default:
+udp_dflt_cmd:
 	        
 			/* it's a board command */
 			mbox->cmd.command = ppp_udp_pkt->cblock.command;
@@ -2555,9 +2939,12 @@
      	len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length);
 
      	if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-	
-		++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr;
-		ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol);
+
+		/* Make sure we are not already sending */
+		if (!test_bit(SEND_CRIT,&card->wandev.critical)){
+			++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr;
+			ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol);
+		}
 
 	} else {	
 	
@@ -2587,6 +2974,8 @@
     	}	
 
 	ppp_priv_area->udp_pkt_lgth = 0;
+	
+	return; 
 }
 
 /*=============================================================================
@@ -2648,9 +3037,12 @@
 			(info->rxb_num - 1);
 	}
 
+	card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; 
+	card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr;
+
 	card->u.p.rx_base = info->rxb_base;
         card->u.p.rx_top  = info->rxb_end;
-       
+      
 	card->u.p.txbuf = card->u.p.txbuf_base;
 	card->rxmb = card->u.p.rxbuf_base;
 
@@ -2662,21 +3054,32 @@
  */
 static int read_info( sdla_t *card )
 {
-	struct net_device *dev = card->wandev.dev;
+	netdevice_t *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	int err;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct ifreq if_info;
 	struct sockaddr_in *if_data1, *if_data2;
 	mm_segment_t fs;
+#else
+#ifdef _DYNAMIC_ROUTE_20X_SUPPORT_
+        struct rtentry route;
+#endif
+#endif
+
+
+	
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 
 	/* Set Local and remote addresses */
 	memset(&if_info, 0, sizeof(if_info));
 	strcpy(if_info.ifr_name, dev->name);
 
+
 	fs = get_fs();
 	set_fs(get_ds());     /* get user space block */ 
 
-	
 	/* Change the local and remote ip address of the interface.
 	 * This will also add in the destination route.
 	 */	
@@ -2690,11 +3093,43 @@
 	err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
 
 	set_fs(fs);           /* restore old block */
+	
+#else
+	/* FIXME: Dynamic Routing in 2.0.X kernels is not
+         * supported. Sorry ! I'll come back to it when I get
+         * a chance. */
+	
+	printk(KERN_INFO "%s: ERROR, Dynamic routing is not supported in 2.0.X kernels\n",
+				card->devname);
+	printk(KERN_INFO "%s:        Please use the STATIC IP mode!\n",
+				card->devname);
+
+	err = 0;
+
+#ifdef _DYNAMIC_ROUTE_20X_SUPPORT_
+	dev->pa_dstaddr = ppp_priv_area->ip_remote;
+	dev->pa_addr = ppp_priv_area->ip_local;
+
+	memset(&route, 0, sizeof(route));
+	route.rt_dev = dev->name;
+	route.rt_flags = 0;
+	((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr =
+		dev->pa_dstaddr;
+	((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET;
+	((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr =
+			0xFFFFFFFF;
+	((struct sockaddr_in *)&(route.rt_genmask))->sin_family =
+			AF_INET;
+	
+	err = ip_rt_new(&route);
 
+#endif
+
+#endif
 
 	if (err) {
-		printk (KERN_INFO "%s: Adding of route failed:\n",
-			card->devname);
+		printk (KERN_INFO "%s: Adding of route failed: %i\n",
+			card->devname,err);
 		printk (KERN_INFO "%s:	Local : %s\n",
 			card->devname,in_ntoa(ppp_priv_area->ip_local));
 		printk (KERN_INFO "%s:	Remote: %s\n",
@@ -2708,31 +3143,39 @@
  * Called when ppp interface disconnected.
  */
 
-static int remove_route( sdla_t *card )
+static void remove_route( sdla_t *card )
 {
 
-	struct net_device *dev = card->wandev.dev;
+	netdevice_t *dev = card->wandev.dev;
 	long ip_addr;
 	int err;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         mm_segment_t fs;
 	struct ifreq if_info;
 	struct sockaddr_in *if_data1;
         struct in_device *in_dev = dev->ip_ptr;
         struct in_ifaddr *ifa = in_dev->ifa_list;	
+#else
+	unsigned long fs = 0;
+        struct rtentry route;
+#endif
 
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	ip_addr = ifa->ifa_local;
 
 	/* Set Local and remote addresses */
 	memset(&if_info, 0, sizeof(if_info));
 	strcpy(if_info.ifr_name, dev->name);
+#endif
 
 
 	fs = get_fs();
        	set_fs(get_ds());     /* get user space block */ 
 
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)	
 	/* Change the local ip address of the interface to 0.
 	 * This will also delete the destination route.
 	 */	
@@ -2740,6 +3183,26 @@
 	if_data1->sin_addr.s_addr = 0;
 	if_data1->sin_family = AF_INET;
 	err = devinet_ioctl( SIOCSIFADDR, &if_info );
+#else
+
+	ip_addr = dev->pa_addr;
+	dev->pa_dstaddr = 0;
+
+	memset(&route, 0, sizeof(route));
+	route.rt_dev = dev->name;
+	route.rt_flags = 0;
+	((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr =
+			dev->pa_dstaddr;
+	((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET;
+	((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr =
+			0xFFFFFFFF;
+        ((struct sockaddr_in *)&(route.rt_genmask))->sin_family =
+			AF_INET;
+
+
+	err = ip_rt_kill(&route);
+
+#endif
 
         set_fs(fs);           /* restore old block */
 
@@ -2747,13 +3210,12 @@
 	if (err) {
 		printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n",
 			 card->devname, err);
-		return err;
-	}else
-		printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfully\n",
+		return;
+	}else{
+		printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n",
 			card->devname, in_ntoa(ip_addr));
-
-	
-	return 0;
+	}
+	return;
 }
 
 /*=============================================================================
@@ -2765,13 +3227,6 @@
 	ppp_mbox_t *mb = card->mbox;
 	int err,i;
 
-	/* The critical flag is unset because during intialization (if_open) 
-	 * we want the interrupts to be enabled so that when the wpp_isr is
-	 * called it does not exit due to critical flag set.
-	 */ 
-	 
-	card->wandev.critical = 0;
-
 	err = ppp_set_intr_mode( card, 0x08 );
 	
 	if (err == CMD_OK) { 
@@ -2792,7 +3247,6 @@
 	if (err != CMD_OK) 
 		return err;
 
-	card->wandev.critical = 1;
 	return 0;
 }
 
@@ -2803,7 +3257,6 @@
 {
 	unsigned char *sendpacket;
 	unsigned char buf2[5]; 
-	//FIXME: Use the structure
 	ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; 
 	
 	sendpacket = skb->data;
@@ -2850,16 +3303,19 @@
  * multicast source IP address.
  */
 
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
 				struct sk_buff *skb)
 {
 	u32 src_ip_addr;
         u32 broadcast_ip_addr = 0;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         struct in_device *in_dev;
+#endif
         /* read the IP source address from the outgoing packet */
         src_ip_addr = *(u32 *)(skb->data + 12);
 
 	/* read the IP broadcast address for the device */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         in_dev = dev->ip_ptr;
         if(in_dev != NULL) {
                 struct in_ifaddr *ifa= in_dev->ifa_list;
@@ -2868,13 +3324,14 @@
                 else
                         return 0;
         }
+#else
+        broadcast_ip_addr = dev->pa_brdaddr;
+#endif
  
         /* check if the IP Source Address is a Broadcast address */
         if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
                 printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n",
 				card->devname);
-                dev_kfree_skb(skb);
-                ++card->wandev.stats.tx_dropped;
                 return 1;
         } 
 
@@ -2883,8 +3340,6 @@
 		(ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
                 printk(KERN_INFO "%s: Multicast Source Address silently discarded\n",
 				card->devname);
-                dev_kfree_skb(skb);
-                ++card->wandev.stats.tx_dropped;
                 return 1;
         }
 
@@ -2893,8 +3348,8 @@
 
 void s508_lock (sdla_t *card, unsigned long *smp_flags)
 {
-#ifdef CONFIG_SMP
-	spin_lock_irqsave(&card->lock, *smp_flags);
+#if defined(__SMP__) || defined(LINUX_2_4)
+	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
 #else
 	disable_irq(card->hw.irq);
 #endif                                                                     
@@ -2902,8 +3357,8 @@
 
 void s508_unlock (sdla_t *card, unsigned long *smp_flags)
 {
-#ifdef CONFIG_SMP
-        spin_unlock_irqrestore(&card->lock, *smp_flags);
+#if defined(__SMP__) || defined(LINUX_2_4)
+        spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
 #else
 	enable_irq(card->hw.irq);
 #endif           
@@ -2912,7 +3367,7 @@
 static int read_connection_info (sdla_t *card)
 {
 	ppp_mbox_t *mb = card->mbox;
-	struct net_device *dev = card->wandev.dev;
+	netdevice_t *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	ppp508_connect_info_t *ppp508_connect_info;
 	int err;
@@ -2924,15 +3379,347 @@
 
 	if (err != CMD_OK) { 
 		ppp_error(card, err, mb);
+		ppp_priv_area->ip_remote = 0;
+		ppp_priv_area->ip_local = 0;
 	}
 	else {
 		ppp508_connect_info = (ppp508_connect_info_t *)mb->data;
-
 		ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote;
 		ppp_priv_area->ip_local = ppp508_connect_info->ip_local;
+
+		NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n",
+				ppp_priv_area->ip_remote,
+				ppp_priv_area->ip_local);
 	}
 
 	return err;
 }
+
+/*===============================================================================
+ * config_ppp
+ *
+ *	Configure the ppp protocol and enable communications.		
+ *
+ *   	The if_open function binds this function to the poll routine.
+ *      Therefore, this function will run every time the ppp interface
+ *      is brought up.  
+ *      
+ *	If the communications are not enabled, proceed to configure
+ *      the card and enable communications.
+ *
+ *      If the communications are enabled, it means that the interface
+ *      was shutdown by ether the user or driver. In this case, we 
+ *      have to check that the IP addresses have not changed.  If
+ *      the IP addresses changed, we have to reconfigure the firmware
+ *      and update the changed IP addresses.  Otherwise, just exit.
+ */
+static int config_ppp (sdla_t *card)
+{
+
+	netdevice_t *dev = card->wandev.dev;
+	ppp_flags_t *flags = card->flags;
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+
+	if (card->u.p.comm_enabled){
+
+		if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local ||
+		    ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){
+			
+			/* The IP addersses have changed, we must
+                         * stop the communications and reconfigure
+                         * the card. Reason: the firmware must know
+                         * the local and remote IP addresses. */
+			disable_comm(card);
+			wanpipe_set_state(card, WAN_DISCONNECTED);
+			printk(KERN_INFO 
+				"%s: IP addresses changed!\n",
+					card->devname);
+			printk(KERN_INFO "%s: Restarting communications ...\n",
+					card->devname);
+		}else{ 
+			/* IP addresses are the same and the link is up, 
+                         * we dont have to do anything here. Therefore, exit */
+			return 0;
+		}
+	}
+
+	/* Record the new IP addreses */
+	ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp;
+	ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp;
+
+	if (config508(dev, card)){
+		printk(KERN_INFO "%s: Failed to configure PPP device\n",
+			card->devname);
+		return 0;
+	}
+
+	if (ppp_set_intr_mode(card, PPP_INTR_RXRDY|
+			    		PPP_INTR_TXRDY|
+				    	PPP_INTR_MODEM|
+				    	PPP_INTR_DISC |
+				    	PPP_INTR_OPEN |
+				    	PPP_INTR_DROP_DTR |
+					PPP_INTR_TIMER)) {
+
+		printk(KERN_INFO "%s: Failed to configure board interrupts !\n", 
+			card->devname);
+		return 0;
+	}
+
+        /* Turn off the transmit and timer interrupt */
+	flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ;
+
+
+	/* If you are not the authenticator and any one of the protocol is 
+	 * enabled then we call the set_out_bound_authentication.
+	 */
+	if ( !card->u.p.authenticator  && (ppp_priv_area->pap || ppp_priv_area->chap)) {
+		if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){
+			printk(KERN_INFO "%s: Outbound authentication failed !\n",
+				card->devname);
+			return 0;
+		}
+	} 
+	
+	/* If you are the authenticator and any one of the protocol is enabled
+	 * then we call the set_in_bound_authentication.
+	 */
+	if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){
+		if (ppp_set_inbnd_auth(card, ppp_priv_area)){
+			printk(KERN_INFO "%s: Inbound authentication failed !\n",
+				card->devname);	
+			return 0;
+		}
+	}
+
+	/* If we fail to enable communications here it's OK,
+	 * since the DTR timer will cause a disconnected, which
+	 * will retrigger communication in timer_intr() */
+	if (ppp_comm_enable(card) == CMD_OK) {
+		wanpipe_set_state(card, WAN_CONNECTING);
+		init_ppp_tx_rx_buff(card);
+	}
+
+	return 0; 
+}
+
+/*============================================================
+ * ppp_poll
+ *	
+ * Rationale:
+ * 	We cannot manipulate the routing tables, or
+ *      ip addresses withing the interrupt. Therefore
+ *      we must perform such actons outside an interrupt 
+ *      at a later time. 
+ *
+ * Description:	
+ *	PPP polling routine, responsible for 
+ *     	shutting down interfaces upon disconnect
+ *     	and adding/removing routes. 
+ *      
+ * Usage:        
+ * 	This function is executed for each ppp  
+ * 	interface through a tq_schedule bottom half.
+ *      
+ *      trigger_ppp_poll() function is used to kick
+ *      the ppp_poll routine.  
+ */
+static void ppp_poll (netdevice_t *dev)
+{
+	ppp_private_area_t *ppp_priv_area; 	
+	sdla_t *card;
+	u8 check_gateway=0;
+	ppp_flags_t *flags;
+
+	if (!dev || (ppp_priv_area = dev->priv) == NULL)
+		return;
+
+	card = ppp_priv_area->card;
+	flags = card->flags;
+
+	/* Shutdown is in progress, stop what you are 
+	 * doing and get out */
+	if (test_bit(PERI_CRIT,&card->wandev.critical)){
+		clear_bit(POLL_CRIT,&card->wandev.critical);
+		return;
+	}
+
+	/* if_open() function has triggered the polling routine
+	 * to determine the configured IP addresses.  Once the
+	 * addresses are found, trigger the chdlc configuration */
+	if (test_bit(0,&ppp_priv_area->config_ppp)){
+
+		ppp_priv_area->ip_local_tmp  = get_ip_address(dev,WAN_LOCAL_IP);
+		ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
+
+		if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && 
+	            card->u.p.ip_mode == WANOPT_PPP_HOST){
+			
+			if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){
+				printk(KERN_INFO "\n%s: --- WARNING ---\n",
+						card->devname);
+				printk(KERN_INFO "%s: The local IP address is the same as the\n",
+						card->devname);
+				printk(KERN_INFO "%s: Point-to-Point IP address.\n",
+						card->devname);
+				printk(KERN_INFO "%s: --- WARNING ---\n\n",
+						card->devname);
+			}else{
+				clear_bit(POLL_CRIT,&card->wandev.critical);
+				ppp_priv_area->poll_delay_timer.expires = jiffies+HZ;
+				add_timer(&ppp_priv_area->poll_delay_timer);
+				return;
+			}
+		}
+
+		ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
+		flags->imask |= PPP_INTR_TIMER;	
+		ppp_priv_area->ip_error=0;	
+		
+		clear_bit(0,&ppp_priv_area->config_ppp);
+		clear_bit(POLL_CRIT,&card->wandev.critical);
+		return;
+	}
+
+	/* Dynamic interface implementation, as well as dynamic
+	 * routing.  */
+	
+	switch (card->wandev.state) {
+	
+	case WAN_DISCONNECTED:
+
+		/* If the dynamic interface configuration is on, and interface 
+		 * is up, then bring down the netowrk interface */
+
+		if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) &&
+		    !test_bit(DEV_DOWN,&ppp_priv_area->interface_down)	&&	
+		    card->wandev.dev->flags & IFF_UP){	
+
+			printk(KERN_INFO "%s: Interface %s down.\n",
+				card->devname,card->wandev.dev->name);
+			change_dev_flags(card->wandev.dev,
+					(card->wandev.dev->flags&~IFF_UP));
+			set_bit(DEV_DOWN,&ppp_priv_area->interface_down);
+		}else{
+			/* We need to check if the local IP address is
+               	   	 * zero. If it is, we shouldn't try to remove it.
+                 	 * For some reason the kernel crashes badly if 
+                 	 * we try to remove the route twice */
+
+			if (card->wandev.dev->flags & IFF_UP && 
+		    	    get_ip_address(card->wandev.dev,WAN_LOCAL_IP) &&
+		    	    card->u.p.ip_mode == WANOPT_PPP_PEER){
+
+				remove_route(card);
+			}
+		}
+		break;
+
+	case WAN_CONNECTED:
+		
+		/* In SMP machine this code can execute before the interface
+		 * comes up.  In this case, we must make sure that we do not
+		 * try to bring up the interface before dev_open() is finished */
+
+
+		/* DEV_DOWN will be set only when we bring down the interface
+		 * for the very first time. This way we know that it was us
+		 * that brought the interface down */
+		
+		if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) &&
+	            test_bit(DEV_DOWN,  &ppp_priv_area->interface_down) &&
+ 		    !(card->wandev.dev->flags & IFF_UP)){
+			
+			printk(KERN_INFO "%s: Interface %s up.\n",
+				card->devname,card->wandev.dev->name);
+			
+			change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP));
+			clear_bit(DEV_DOWN,&ppp_priv_area->interface_down);
+			check_gateway=1;
+		}
+
+		if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && 
+		    test_bit(1,&Read_connection_info)) { 
+			
+			process_route(card);
+			clear_bit(1,&Read_connection_info);
+			check_gateway=1;
+		}
+
+		if (ppp_priv_area->gateway && check_gateway)
+			add_gateway(card,dev);
+
+		break;
+	}
+	clear_bit(POLL_CRIT,&card->wandev.critical);
+	return;
+}
+
+/*============================================================
+ * trigger_ppp_poll
+ *
+ * Description:
+ * 	Add a ppp_poll() task into a tq_scheduler bh handler
+ *      for a specific interface.  This will kick
+ *      the ppp_poll() routine at a later time. 
+ *
+ * Usage:
+ * 	Interrupts use this to defer a taks to 
+ *      a polling routine.
+ *
+ */	
+
+static void trigger_ppp_poll (netdevice_t *dev)
+{
+	ppp_private_area_t *ppp_priv_area;
+	if ((ppp_priv_area=dev->priv) != NULL){ 	
+		
+		sdla_t *card = ppp_priv_area->card;
+
+		if (test_bit(PERI_CRIT,&card->wandev.critical)){
+			return;
+		}
+		
+		if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){
+			return;
+		}
+
+#ifdef LINUX_2_4
+		schedule_task(&ppp_priv_area->poll_task);
+#else
+		queue_task(&ppp_priv_area->poll_task, &tq_scheduler);
+#endif
+	}
+	return;
+}
+
+static void ppp_poll_delay (unsigned long dev_ptr)
+{
+	netdevice_t *dev = (netdevice_t *)dev_ptr;
+	trigger_ppp_poll(dev);
+}
+
+/*============================================================
+ * detect_and_fix_tx_bug
+ *
+ * Description:
+ *	On connect, if the board tx buffer ptr is not the same
+ *      as the driver tx buffer ptr, we found a firmware bug.
+ *      Report the bug to the above layer.  To fix the
+ *      error restart communications again.
+ *
+ * Usage:
+ *
+ */	
+
+static int detect_and_fix_tx_bug (sdla_t *card)
+{
+	if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){
+		NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n");
+		return 1;
+	}
+	return 0;
+}
+
 
 /****** End *****************************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- v2.4.3/linux/drivers/net/wan/sdla_x25.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/sdla_x25.c	Fri Apr 20 11:54:22 2001
@@ -1,16 +1,55 @@
 /*****************************************************************************
 * sdla_x25.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  X.25 module.
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
+* Author:	Nenad Corbic	<ncorbic@sangoma.com>
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2001 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* Mar 15, 1998  Alan Cox	 o 2.1.x porting
+* Apr 03, 2001  Nenad Corbic	 o Fixed the rx_skb=NULL bug in x25 in rx_intr().
+* Dec 26, 2000  Nenad Corbic	 o Added a new polling routine, that uses
+*                                  a kernel timer (more efficient).
+* Dec 25, 2000  Nenad Corbic	 o Updated for 2.4.X kernel
+* Jul 26, 2000  Nenad Corbic	 o Increased the local packet buffering
+* 				   for API to 4096+header_size. 
+* Jul 17, 2000  Nenad Corbic	 o Fixed the x25 startup bug. Enable 
+* 				   communications only after all interfaces
+* 				   come up.  HIGH SVC/PVC is used to calculate
+* 				   the number of channels.
+*                                  Enable protocol only after all interfaces
+*                                  are enabled.
+* Jul 10, 2000	Nenad Corbic	 o Fixed the M_BIT bug. 
+* Apr 25, 2000  Nenad Corbic	 o Pass Modem messages to the API.
+*                                  Disable idle timeout in X25 API.
+* Apr 14, 2000  Nenad Corbic	 o Fixed: Large LCN number support.
+*                                  Maximum LCN number is 4095.
+*                                  Maximum number of X25 channels is 255.
+* Apr 06, 2000  Nenad Corbic	 o Added SMP Support.
+* Mar 29, 2000  Nenad Corbic	 o Added support for S514 PCI Card
+* Mar 23, 2000  Nenad Corbic	 o Improved task queue, BH handling.
+* Mar 14, 2000  Nenad Corbic  	 o Updated Protocol Violation handling
+*                                  routines.  Bug Fix.
+* Mar 10, 2000  Nenad Corbic	 o Bug Fix: corrupted mbox recovery.
+* Mar 09, 2000  Nenad Corbic     o Fixed the auto HDLC bug.
+* Mar 08, 2000	Nenad Corbic     o Fixed LAPB HDLC startup problems.
+*                                  Application must bring the link up 
+*                                  before tx/rx, and bring the 
+*                                  link down on close().
+* Mar 06, 2000	Nenad Corbic	 o Added an option for logging call setup 
+*                                  information. 
+* Feb 29, 2000  Nenad Corbic 	 o Added support for LAPB HDLC API
+* Feb 25, 2000  Nenad Corbic     o Fixed the modem failure handling.
+*                                  No Modem OOB message will be passed 
+*                                  to the user.
+* Feb 21, 2000  Nenad Corbic 	 o Added Xpipemon Debug Support
+* Dec 30, 1999 	Nenad Corbic	 o Socket based X25API 
+* Sep 17, 1998	Jaspreet Singh	 o Updates for 2.2.X  kernel
+* Mar 15, 1998	Alan Cox	 o 2.1.x porting
+* Dec 19, 1997	Jaspreet Singh	 o Added multi-channel IPX support
 * Nov 27, 1997	Jaspreet Singh	 o Added protection against enabling of irqs
 *				   when they are disabled.
 * Nov 17, 1997  Farhan Thawar    o Added IPX support
@@ -38,21 +77,41 @@
 * Jan 07, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
+/*======================================================
+ * 	Includes 
+ *=====================================================*/
 
+#include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/ctype.h>
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>	/* Experimental delay */
 
-#define	_GNUC_
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ #include <asm/uaccess.h>
+#else
+ #include <asm/segment.h>
+ #include <net/route.h>
+#endif
+
+#include <linux/if.h>
+#include <linux/if_arp.h>
 #include <linux/sdla_x25.h>	/* X.25 firmware API definitions */
+#include <linux/if_wanpipe_common.h>
+#include <linux/if_wanpipe.h>
+
+
+/*======================================================
+ * 	Defines & Macros 
+ *=====================================================*/
 
-/****** Defines & Macros ****************************************************/
 
 #define	CMD_OK		0		/* normal firmware return code */
 #define	CMD_TIMEOUT	0xFF		/* firmware command timed out */
@@ -64,27 +123,141 @@
 #define	X25_RECON_TMOUT	(10*HZ)		/* link connection timeout */
 #define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
 #define	HOLD_DOWN_TIME	(30*HZ)		/* link hold down time */
+#define MAX_BH_BUFF	10
+#define M_BIT		0x01	
+
+//#define PRINT_DEBUG 1
+#ifdef PRINT_DEBUG
+#define DBG_PRINTK(format, a...) printk(format, ## a)
+#else
+#define DBG_PRINTK(format, a...)
+#endif  
+
+#define TMR_INT_ENABLED_POLL_ACTIVE      0x01
+#define TMR_INT_ENABLED_POLL_CONNECT_ON  0x02
+#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04
+#define TMR_INT_ENABLED_POLL_DISCONNECT  0x08
+#define TMR_INT_ENABLED_CMD_EXEC	 0x10
+#define TMR_INT_ENABLED_UPDATE		 0x20
+#define TMR_INT_ENABLED_UDP_PKT		 0x40
+
+#define MAX_X25_ADDR_SIZE	16
+#define MAX_X25_DATA_SIZE 	129
+#define MAX_X25_FACL_SIZE	110
+
+#define TRY_CMD_AGAIN	2
+#define DELAY_RESULT    1
+#define RETURN_RESULT   0
+
+#define DCD(x) (x & 0x03 ? "HIGH" : "LOW")
+#define CTS(x) (x & 0x05 ? "HIGH" : "LOW")
+
+
+/* Driver will not write log messages about 
+ * modem status if defined.*/
+#define MODEM_NOT_LOG 1
+
+/*==================================================== 
+ * 	For IPXWAN 
+ *===================================================*/
 
-/* For IPXWAN */
 #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
 
-/****** Data Structures *****************************************************/
 
-/* This is an extention of the 'struct net_device' we create for each network
- * interface to keep the rest of X.25 channel-specific data.
+/*====================================================
+ *           MEMORY DEBUGGING FUNCTION
+ *====================================================
+
+#define KMEM_SAFETYZONE 8
+
+static void * dbg_kmalloc(unsigned int size, int prio, int line) {
+	int i = 0;
+	void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio);
+	char * c1 = v;	
+	c1 += sizeof(unsigned int);
+	*((unsigned int *)v) = size;
+
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D';
+		c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F';
+		c1 += 8;
+	}
+	c1 += size;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G';
+		c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L';
+		c1 += 8;
+	}
+	v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8;
+	printk(KERN_INFO "line %d  kmalloc(%d,%d) = %p\n",line,size,prio,v);
+	return v;
+}
+static void dbg_kfree(void * v, int line) {
+	unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8));
+	unsigned int size = *sp;
+	char * c1 = ((char *)v) - KMEM_SAFETYZONE*8;
+	int i = 0;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		if (   c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D'
+		    || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') {
+			printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v);
+			printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
+			                c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
+		}
+		c1 += 8;
+	}
+	c1 += size;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		if (   c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G'
+		    || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L'
+		   ) {
+			printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v);
+			printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
+			                c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
+		}
+		c1 += 8;
+	}
+	printk(KERN_INFO "line %d  kfree(%p)\n",line,v);
+	v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8);
+	kfree(v);
+}
+
+#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
+#define kfree(x) dbg_kfree(x,__LINE__)
+
+==============================================================*/
+
+
+
+/*===============================================
+ * 	Data Structures 
+ *===============================================*/
+
+
+/*========================================================
+ * Name: 	x25_channel
+ *
+ * Purpose:	To hold private informaton for each  
+ *              logical channel.
+ *		
+ * Rationale:  	Per-channel debugging is possible if each 
+ *              channel has its own private area.
+ *	
+ * Assumptions:
+ *
+ * Description:	This is an extention of the 'netdevice_t' 
+ *              we create for each network interface to keep 
+ *              the rest of X.25 channel-specific data. 
+ *
+ * Construct:	Typedef
  */
 typedef struct x25_channel
 {
-	/* This member must be first. */
-	struct net_device *slave;	/* WAN slave */
-
+	wanpipe_common_t common;	/* common area for x25api and socket */
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
 	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
-	unsigned lcn;			/* logical channel number */
 	unsigned tx_pkt_size;
 	unsigned short protocol;	/* ethertype, 0 - multiplexed */
-	char svc;			/* 0 - permanent, 1 - switched */
-	char state;			/* channel state */
 	char drop_sequence;		/* mark sequence for dropping */
 	unsigned long state_tick;	/* time of the last state change */
 	unsigned idle_timeout;		/* sec, before disconnecting */
@@ -94,63 +267,144 @@
 	char devtint;			/* Weather we should dev_tint() */
 	struct sk_buff* rx_skb;		/* receive socket buffer */
 	struct sk_buff* tx_skb;		/* transmit socket buffer */
+
+	bh_data_t *bh_head;	  	  /* Circular buffer for x25api_bh */
+	unsigned long  tq_working;
+	volatile int  bh_write;
+	volatile int  bh_read;
+	atomic_t  bh_buff_used;
+
 	sdla_t* card;			/* -> owner */
+	netdevice_t *dev;		/* -> bound devce */
+
 	int ch_idx;
+	unsigned char enable_IPX;
+	unsigned long network_number;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct net_device_stats ifstats;	/* interface statistics */
+#else
+	struct enet_statistics ifstats;
+#endif	
+	unsigned short transmit_length;
+	unsigned short tx_offset;
+	char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)];
+
+	if_send_stat_t   if_send_stat;
+        rx_intr_stat_t   rx_intr_stat;
+        pipe_mgmt_stat_t pipe_mgmt_stat;    
+
+	unsigned long router_start_time; /* Router start time in seconds */
+	unsigned long router_up_time;
+	
 } x25_channel_t;
 
+/* FIXME Take this out */
+
+#ifdef NEX_OLD_CALL_INFO
 typedef struct x25_call_info
 {
-	char dest[17];			/* ASCIIZ destination address */
-	char src[17];			/* ASCIIZ source address */
-	char nuser;			/* number of user data bytes */
-	unsigned char user[127];	/* user data */
-	char nfacil;			/* number of facilities */
+	char dest[17];			PACKED;/* ASCIIZ destination address */
+	char src[17];			PACKED;/* ASCIIZ source address */
+	char nuser;			PACKED;/* number of user data bytes */
+	unsigned char user[127];	PACKED;/* user data */
+	char nfacil;			PACKED;/* number of facilities */
 	struct
 	{
-		unsigned char code;
-		unsigned char parm;
-	} facil[64];			/* facilities */
+		unsigned char code;     PACKED;
+		unsigned char parm;     PACKED;
+	} facil[64];			        /* facilities */
+} x25_call_info_t;
+#else
+typedef struct x25_call_info
+{
+	char dest[MAX_X25_ADDR_SIZE]		PACKED;/* ASCIIZ destination address */
+	char src[MAX_X25_ADDR_SIZE]		PACKED;/* ASCIIZ source address */
+	unsigned char nuser			PACKED;
+	unsigned char user[MAX_X25_DATA_SIZE]	PACKED;/* user data */
+	unsigned char nfacil			PACKED;
+	unsigned char facil[MAX_X25_FACL_SIZE]	PACKED;
+	unsigned short lcn             		PACKED;
 } x25_call_info_t;
+#endif
+
 
-/****** Function Prototypes *************************************************/
+  
+/*===============================================
+ *	Private Function Prototypes
+ *==============================================*/
 
-/* WAN link driver entry points. These are called by the WAN router module. */
+
+/*================================================= 
+ * WAN link driver entry points. These are 
+ * called by the WAN router module.
+ */
 static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, struct net_device* dev,
+static int new_if (wan_device_t* wandev, netdevice_t* dev,
 	wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, struct net_device* dev);
+static int del_if (wan_device_t* wandev, netdevice_t* dev);
+static void disable_comm (sdla_t* card);
+static void disable_comm_shutdown(sdla_t *card);
 
-/* WANPIPE-specific entry points */
+
+
+/*================================================= 
+ *	WANPIPE-specific entry points 
+ */
 static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
+static void x25api_bh (netdevice_t *);
+static int x25api_bh_cleanup (netdevice_t *);
+static int bh_enqueue (netdevice_t *, struct sk_buff *);
+
 
-/* Network device interface */
-static int if_init   (struct net_device* dev);
-static int if_open   (struct net_device* dev);
-static int if_close  (struct net_device* dev);
-static int if_header (struct sk_buff* skb, struct net_device* dev,
+/*=================================================  
+ * 	Network device interface 
+ */
+static int if_init   (netdevice_t* dev);
+static int if_open   (netdevice_t* dev);
+static int if_close  (netdevice_t* dev);
+static int if_header (struct sk_buff* skb, netdevice_t* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len);
 static int if_rebuild_hdr (struct sk_buff* skb);
-static int if_send (struct sk_buff* skb, struct net_device* dev);
-static struct net_device_stats * if_stats (struct net_device* dev);
+static int if_send (struct sk_buff* skb, netdevice_t* dev);
+static struct net_device_stats *if_stats (netdevice_t* dev);
 
-/* Interrupt handlers */
-static void wpx_isr	(sdla_t* card);
-static void rx_intr	(sdla_t* card);
-static void tx_intr	(sdla_t* card);
-static void status_intr	(sdla_t* card);
-static void event_intr	(sdla_t* card);
-static void spur_intr	(sdla_t* card);
+#ifdef LINUX_2_4
+static void if_tx_timeout (netdevice_t *dev);
+#endif
+
+/*=================================================  
+ * 	Interrupt handlers 
+ */
+static void wpx_isr	(sdla_t *);
+static void rx_intr	(sdla_t *);
+static void tx_intr	(sdla_t *);
+static void status_intr	(sdla_t *);
+static void event_intr	(sdla_t *);
+static void spur_intr	(sdla_t *);
+static void timer_intr  (sdla_t *);
 
-/* Background polling routines */
+static int tx_intr_send(sdla_t *, netdevice_t *);
+static netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *);
+
+/*=================================================  
+ *	Background polling routines 
+ */
 static void wpx_poll (sdla_t* card);
 static void poll_disconnected (sdla_t* card);
 static void poll_connecting (sdla_t* card);
 static void poll_active (sdla_t* card);
+static void trigger_x25_poll(sdla_t *card);
+static void x25_timer_routine(unsigned long data);
+
+
 
-/* X.25 firmware interface functions */
+/*=================================================  
+ *	X.25 firmware interface functions 
+ */
 static int x25_get_version (sdla_t* card, char* str);
 static int x25_configure (sdla_t* card, TX25Config* conf);
+static int hdlc_configure (sdla_t* card, TX25Config* conf);
+static int set_hdlc_level (sdla_t* card);
 static int x25_get_err_stats (sdla_t* card);
 static int x25_get_stats (sdla_t* card);
 static int x25_set_intr_mode (sdla_t* card, int mode);
@@ -166,62 +420,136 @@
 static int x25_fetch_events (sdla_t* card);
 static int x25_error (sdla_t* card, int err, int cmd, int lcn);
 
-/* X.25 asynchronous event handlers */
+/*=================================================  
+ *	X.25 asynchronous event handlers 
+ */
 static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
 static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
 static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
 static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
 static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
 
-/* Miscellaneous functions */
+
+/*=================================================  
+ *	Miscellaneous functions 
+ */
 static int connect (sdla_t* card);
 static int disconnect (sdla_t* card);
-static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
-static int chan_connect (struct net_device* dev);
-static int chan_disc (struct net_device* dev);
-static void set_chan_state (struct net_device* dev, int state);
-static int chan_send (struct net_device* dev, struct sk_buff* skb);
+static netdevice_t* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
+static int chan_connect (netdevice_t* dev);
+static int chan_disc (netdevice_t* dev);
+static void set_chan_state (netdevice_t* dev, int state);
+static int chan_send (netdevice_t* , void* , unsigned, unsigned char);
 static unsigned char bps_to_speed_code (unsigned long bps);
 static unsigned int dec_to_uint (unsigned char* str, int len);
-static unsigned int hex_to_uint (unsigned char* str, int len);
-static void parse_call_info (unsigned char* str, x25_call_info_t* info);
+static unsigned int hex_to_uint (unsigned char*, int);
+static void parse_call_info (unsigned char*, x25_call_info_t*);
+static netdevice_t * find_channel(sdla_t *, unsigned);
+static void bind_lcn_to_dev (sdla_t *, netdevice_t *,unsigned);
+static void setup_for_delayed_transmit (netdevice_t*, void*, unsigned);
+
+
+/*=================================================  
+ *      X25 API Functions 
+ */
+static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **);
+static void timer_intr_exec(sdla_t *, unsigned char);
+static int execute_delayed_cmd (sdla_t*, netdevice_t *, mbox_cmd_t *,char);
+static int api_incoming_call (sdla_t*, TX25Mbox *, int);
+static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int);
+static void send_delayed_cmd_result(sdla_t *, netdevice_t *dev, TX25Mbox*);
+static int clear_confirm_event (sdla_t *, TX25Mbox*);
+static void send_oob_msg (sdla_t *, netdevice_t *, TX25Mbox *);
+static int timer_intr_cmd_exec(sdla_t *card);
+static void api_oob_event (sdla_t *card,TX25Mbox *mbox);
+static int check_bad_command (sdla_t *, netdevice_t *);
+static int channel_disconnect (sdla_t*, netdevice_t *);
+static void hdlc_link_down (sdla_t*);
+
+/*=================================================
+ *     XPIPEMON Functions
+ */
+static int process_udp_mgmt_pkt(sdla_t *);
+static int udp_pkt_type( struct sk_buff *, sdla_t*);
+static int reply_udp( unsigned char *, unsigned int); 
+static void init_x25_channel_struct( x25_channel_t *);
+static void init_global_statistics( sdla_t *);
+static int store_udp_mgmt_pkt(int, char, sdla_t*, netdevice_t *, struct sk_buff *, int);
+static unsigned short calc_checksum (char *, int);
 
-/* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
+
+
+/*================================================= 
+ *	IPX functions 
+ */
+static void switch_net_numbers(unsigned char *, unsigned long, unsigned char);
+static int handle_IPXWAN(unsigned char *, char *, unsigned char , 
+			 unsigned long , unsigned short );
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
-/****** Global Data **********************************************************
- * Note: All data must be explicitly initialized!!!
- */
+static void S508_S514_lock(sdla_t *, unsigned long *);
+static void S508_S514_unlock(sdla_t *, unsigned long *);
 
-/****** Public Functions ****************************************************/
 
-/*============================================================================
- * X.25 Protocol Initialization routine.
+/*=================================================  
+ * 	Global Variables 
+ *=================================================*/
+
+
+
+/*================================================= 
+ *	Public Functions 
+ *=================================================*/
+
+
+
+
+/*===================================================================
+ * wpx_init:	X.25 Protocol Initialization routine.
+ *
+ * Purpose:	To initialize the protocol/firmware.
+ * 
+ * Rationale:	This function is called by setup() function, in
+ *              sdlamain.c, to dynamically setup the x25 protocol.
+ *		This is the first protocol specific function, which
+ *              executes once on startup.
+ *                
+ * Description:	This procedure initializes the x25 firmware and
+ *    		sets up the mailbox, transmit and receive buffer
+ *              pointers. It also initializes all debugging structures
+ *              and sets up the X25 environment.
  *
- * This routine is called by the main WANPIPE module during setup.  At this
- * point adapter is completely initialized and X.25 firmware is running.
- *  o read firmware version (to make sure it's alive)
- *  o configure adapter
- *  o initialize protocol-specific fields of the adapter data space.
+ *		Sets up hardware options defined by user in [wanpipe#] 
+ *		section of wanpipe#.conf configuration file. 
  *
- * Return:	0	o.k.
- *		< 0	failure.
+ * 		At this point adapter is completely initialized 
+ *      	and X.25 firmware is running.
+ *  		o read firmware version (to make sure it's alive)
+ *  		o configure adapter
+ *  		o initialize protocol-specific fields of the 
+ *                adapter data space.
+ *
+ * Called by:	setup() function in sdlamain.c
+ *
+ * Assumptions:	None
+ *
+ * Warnings:	None
+ *
+ * Return: 	0	o.k.
+ *	 	< 0	failure.
  */
+
 int wpx_init (sdla_t* card, wandev_conf_t* conf)
 {
-	union
-	{
+	union{
 		char str[80];
 		TX25Config cfg;
 	} u;
 
 	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_X25)
-	{
+	if (conf->config_id != WANCONFIG_X25){
 		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
 			card->devname, conf->config_id)
 		;
@@ -233,23 +561,43 @@
 	card->rxmb  = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
 	card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
 
+	/* Initialize for S514 Card */
+	if(card->hw.type == SDLA_S514) {
+		card->mbox += X25_MB_VECTOR;
+		card->flags += X25_MB_VECTOR;
+		card->rxmb += X25_MB_VECTOR;
+	}
+
+
 	/* Read firmware version.  Note that when adapter initializes, it
 	 * clears the mailbox, so it may appear that the first command was
 	 * executed successfully when in fact it was merely erased. To work
 	 * around this, we execute the first command twice.
 	 */
 	if (x25_get_version(card, NULL) || x25_get_version(card, u.str))
-		return -EIO
-	;
-	printk(KERN_INFO "%s: running X.25 firmware v%s\n",
-		card->devname, u.str)
-	;
+		return -EIO;
+
+
+	/* X25 firmware can run ether in X25 or LAPB HDLC mode.
+         * Check the user defined option and configure accordingly */
+	if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){
+		if (set_hdlc_level(card) != CMD_OK){
+			return -EIO;	
+		}else{
+			printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n",
+				card->devname, u.str);
+		}
+		card->u.x.LAPB_hdlc = 1;
+	}else{
+		printk(KERN_INFO "%s: running X.25 firmware v%s\n",
+				card->devname, u.str);
+		card->u.x.LAPB_hdlc = 0;
+	}
 
 	/* Configure adapter. Here we set resonable defaults, then parse
 	 * device configuration structure and set configuration options.
 	 * Most configuration options are verified and corrected (if
-	 * necessary) since we can't rely on the adapter to do so and don't
-	 * want it to fail either.
+	 * necessary) since we can't rely on the adapter to do so.
 	 */
 	memset(&u.cfg, 0, sizeof(u.cfg));
 	u.cfg.t1		= 3;
@@ -258,7 +606,7 @@
 	u.cfg.hdlcWindow	= 7;
 	u.cfg.pktWindow		= 2;
 	u.cfg.station		= 1;		/* DTE */
-	u.cfg.options		= 0x00B0;	/* disable D-bit pragmatics */
+	u.cfg.options		= 0x0090;	/* disable D-bit pragmatics */
 	u.cfg.ccittCompat	= 1988;
 	u.cfg.t10t20		= 30;
 	u.cfg.t11t21		= 30;
@@ -271,71 +619,120 @@
 	u.cfg.r13r23		= 5;
 	u.cfg.responseOpt	= 1;		/* RR's after every packet */
 
+	if (card->u.x.LAPB_hdlc){
+		u.cfg.hdlcMTU = 1027;
+	}
+
+	if (conf->u.x25.x25_conf_opt){
+		u.cfg.options = conf->u.x25.x25_conf_opt;
+	}
+
 	if (conf->clocking != WANOPT_EXTERNAL)
-		u.cfg.baudRate = bps_to_speed_code(conf->bps)
-	;
-	if (conf->station != WANOPT_DTE)
-	{
+		u.cfg.baudRate = bps_to_speed_code(conf->bps);
+
+	if (conf->station != WANOPT_DTE){
 		u.cfg.station = 0;		/* DCE mode */
 	}
-        if (conf->interface != WANOPT_RS232 ) {
+
+        if (conf->interface != WANOPT_RS232 ){
 	        u.cfg.hdlcOptions |= 0x80;      /* V35 mode */
 	} 
+
 	/* adjust MTU */
 	if (!conf->mtu || (conf->mtu >= 1024))
-		card->wandev.mtu = 1024
-	;
+		card->wandev.mtu = 1024;
 	else if (conf->mtu >= 512)
-		card->wandev.mtu = 512
-	;
+		card->wandev.mtu = 512;
 	else if (conf->mtu >= 256)
-		card->wandev.mtu = 256
-	;
+		card->wandev.mtu = 256;
 	else if (conf->mtu >= 128)
-		card->wandev.mtu = 128
-	;
-	else card->wandev.mtu = 64;
+		card->wandev.mtu = 128;
+	else 
+		card->wandev.mtu = 64;
+
 	u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
 
-	if (conf->u.x25.hi_pvc)
-	{
-		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095);
+	if (conf->u.x25.hi_pvc){
+		card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, MAX_LCN_NUM);
 		card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc);
 	}
-	if (conf->u.x25.hi_svc)
-	{
-		card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095);
+
+	if (conf->u.x25.hi_svc){
+		card->u.x.hi_svc = min(conf->u.x25.hi_svc, MAX_LCN_NUM);
 		card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc);
 	}
-	u.cfg.loPVC	  = card->u.x.lo_pvc;
-	u.cfg.hiPVC	  = card->u.x.hi_pvc;
+
+	/* Figure out the total number of channels to configure */
+	card->u.x.num_of_ch = 0;
+	if (card->u.x.hi_svc != 0){
+		card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1;
+	}
+	if (card->u.x.hi_pvc != 0){
+		card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1;
+	}
+
+	if (card->u.x.num_of_ch == 0){
+		printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n"
+				 "%s: Please set the Lowest/Highest PVC/SVC values !\n",
+				 card->devname,card->devname);
+		return -ECHRNG;
+	}
+	
+	u.cfg.loPVC = card->u.x.lo_pvc;
+	u.cfg.hiPVC = card->u.x.hi_pvc;
 	u.cfg.loTwoWaySVC = card->u.x.lo_svc;
 	u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
 
 	if (conf->u.x25.hdlc_window)
-		u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7)
-	;
+		u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7);
 	if (conf->u.x25.pkt_window)
-		u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7)
-	;
+		u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7);
+
 	if (conf->u.x25.t1)
-		u.cfg.t1 = min(conf->u.x25.t1, 30)
-	;
-	u.cfg.t2 = min(conf->u.x25.t2, 29);
-	u.cfg.t4 = min(conf->u.x25.t4, 240);
+		u.cfg.t1 = min(conf->u.x25.t1, 30);
+	if (conf->u.x25.t2)
+		u.cfg.t2 = min(conf->u.x25.t2, 29);
+	if (conf->u.x25.t4)
+		u.cfg.t4 = min(conf->u.x25.t4, 240);
 	if (conf->u.x25.n2)
-		u.cfg.n2 = min(conf->u.x25.n2, 30)
-	;
+		u.cfg.n2 = min(conf->u.x25.n2, 30);
+
+	if (conf->u.x25.t10_t20)
+		u.cfg.t10t20 = min(conf->u.x25.t10_t20,255);
+	if (conf->u.x25.t11_t21)
+		u.cfg.t11t21 = min(conf->u.x25.t11_t21,255);
+	if (conf->u.x25.t12_t22)
+		u.cfg.t12t22 = min(conf->u.x25.t12_t22,255);
+	if (conf->u.x25.t13_t23)	
+		u.cfg.t13t23 = min(conf->u.x25.t13_t23,255);
+	if (conf->u.x25.t16_t26)
+		u.cfg.t16t26 = min(conf->u.x25.t16_t26, 255);
+	if (conf->u.x25.t28)
+		u.cfg.t28 = min(conf->u.x25.t28, 255);
+
+	if (conf->u.x25.r10_r20)
+		u.cfg.r10r20 = min(conf->u.x25.r10_r20,250);
+	if (conf->u.x25.r12_r22)
+		u.cfg.r12r22 = min(conf->u.x25.r12_r22,250);
+	if (conf->u.x25.r13_r23)
+		u.cfg.r13r23 = min(conf->u.x25.r13_r23,250);
+
+
 	if (conf->u.x25.ccitt_compat)
-		u.cfg.ccittCompat = conf->u.x25.ccitt_compat
-	;
+		u.cfg.ccittCompat = conf->u.x25.ccitt_compat;
 
 	/* initialize adapter */
-	if ((x25_configure(card, &u.cfg) != CMD_OK) ||
-	    (x25_close_hdlc(card) != CMD_OK) ||		/* close HDLC link */
+	if (card->u.x.LAPB_hdlc){
+		if (hdlc_configure(card, &u.cfg) != CMD_OK)
+			return -EIO;
+	}else{
+		if (x25_configure(card, &u.cfg) != CMD_OK)
+			return -EIO;
+	}
+
+	if ((x25_close_hdlc(card) != CMD_OK) ||		/* close HDLC link */
 	    (x25_set_dtr(card, 0) != CMD_OK))		/* drop DTR */
-		return -EIO
-	;
+		return -EIO;
 
 	/* Initialize protocol-specific fields of adapter data space */
 	card->wandev.bps	= conf->bps;
@@ -343,202 +740,392 @@
 	card->wandev.clocking	= conf->clocking;
 	card->wandev.station	= conf->station;
 	card->isr		= &wpx_isr;
-	card->poll		= &wpx_poll;
+	card->poll		= NULL; //&wpx_poll;
+	card->disable_comm	= &disable_comm;
 	card->exec		= &wpx_exec;
 	card->wandev.update	= &update;
 	card->wandev.new_if	= &new_if;
 	card->wandev.del_if	= &del_if;
+
+	/* WARNING: This function cannot exit with an error
+	 *          after the change of state */
 	card->wandev.state	= WAN_DISCONNECTED;
+	
 	card->wandev.enable_tx_int = 0;
 	card->irq_dis_if_send_count = 0;
         card->irq_dis_poll_count = 0;
-	card->wandev.enable_IPX = conf->enable_IPX;
+	card->u.x.tx_dev = NULL;
+	card->u.x.no_dev = 0;
+
+
+	/* Configure for S514 PCI Card */
+	if (card->hw.type == SDLA_S514) {
+		card->u.x.hdlc_buf_status = 
+			(volatile unsigned char *)
+				(card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS);
+	}else{
+		card->u.x.hdlc_buf_status = 
+			(volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); 
+	}
+
+	card->u.x.poll_device=NULL;
+	card->wandev.udp_port = conf->udp_port;
+
+	/* Enable or disable call setup logging */
+	if (conf->u.x25.logging == WANOPT_YES){
+		printk(KERN_INFO "%s: Enabling Call Logging.\n",
+			card->devname);
+		card->u.x.logging = 1;
+	}else{	
+		card->u.x.logging = 0;
+	}
+
+	/* Enable or disable modem status reporting */
+	if (conf->u.x25.oob_on_modem == WANOPT_YES){
+		printk(KERN_INFO "%s: Enabling OOB on Modem change.\n",
+			card->devname);
+		card->u.x.oob_on_modem = 1;
+	}else{
+		card->u.x.oob_on_modem = 0;
+	}
+	
+	init_global_statistics(card);	
+
+#ifndef LINUX_2_4
+	card->u.x.x25_poll_task.next = NULL;
+#endif
+	card->u.x.x25_poll_task.sync=0;
+	card->u.x.x25_poll_task.routine = (void*)(void*)wpx_poll;
+	card->u.x.x25_poll_task.data = card;
+
+	init_timer(&card->u.x.x25_timer);
+	card->u.x.x25_timer.data = (unsigned long)card;
+	card->u.x.x25_timer.function = x25_timer_routine;
 	
-	if (conf->network_number)
-		card->wandev.network_number = conf->network_number;
-	else
-		card->wandev.network_number = 0xDEADBEEF;
 	return 0;
 }
 
-/******* WAN Device Driver Entry Points *************************************/
+/*=========================================================
+ *	WAN Device Driver Entry Points 
+ *========================================================*/
 
-/*============================================================================
- * Update device status & statistics.
+/*============================================================
+ * Name:	update(),  Update device status & statistics.
+ *
+ * Purpose:	To provide debugging and statitical
+ *              information to the /proc file system.
+ *              /proc/net/wanrouter/wanpipe#
+ *              	
+ * Rationale:	The /proc file system is used to collect
+ *              information about the kernel and drivers.
+ *              Using the /proc file system the user
+ *              can see exactly what the sangoma drivers are
+ *              doing. And in what state they are in. 
+ *                
+ * Description: Collect all driver statistical information
+ *              and pass it to the top laywer. 
+ *		
+ *		Since we have to execute a debugging command, 
+ *              to obtain firmware statitics, we trigger a 
+ *              UPDATE function within the timer interrtup.
+ *              We wait until the timer update is complete.
+ *              Once complete return the appropriate return
+ *              code to indicate that the update was successful.
+ *              
+ * Called by:	device_stat() in wanmain.c
+ *
+ * Assumptions:	
+ *
+ * Warnings:	This function will degrade the performance
+ *              of the router, since it uses the mailbox. 
+ *
+ * Return: 	0 	OK
+ * 		<0	Failed (or busy).
  */
+
 static int update (wan_device_t* wandev)
 {
-	sdla_t* card;
+	volatile sdla_t* card;
+	TX25Status* status;
+	unsigned long timeout;
 
 	/* sanity checks */
 	if ((wandev == NULL) || (wandev->private == NULL))
 		return -EFAULT;
+
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
-	if (test_and_set_bit(0, (void*)&wandev->critical))
+
+	if (test_bit(SEND_CRIT, (void*)&wandev->critical))
 		return -EAGAIN;
+
+	if (!wandev->dev)
+		return -ENODEV;
+	
 	card = wandev->private;
+	status = card->flags;
 
-	x25_get_err_stats(card);
-	x25_get_stats(card);
-	wandev->critical = 0;
+	card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
+	status->imask |= INTR_ON_TIMER;
+	timeout = jiffies;	
+
+	for (;;){
+		if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){	
+			break;
+		}
+		if ((jiffies-timeout) > 1*HZ){
+			card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
+			return -EAGAIN;
+		}
+	}
 	return 0;
 }
 
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
+
+/*===================================================================
+ * Name:	new_if
+ *
+ * Purpose:	To allocate and initialize resources for a 
+ *              new logical channel.  
+ * 
+ * Rationale:	A new channel can be added dynamically via
+ *              ioctl call.
+ *                
+ * Description:	Allocate a private channel structure, x25_channel_t.
+ *		Parse the user interface options from wanpipe#.conf 
+ *		configuration file. 
+ *		Bind the private are into the network device private
+ *              area pointer (dev->priv).
+ *		Prepare the network device structure for registration.
+ *
+ * Called by:	ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() 
+ *              (wanmain.c)
+ *
+ * Assumptions: None
  *
- * Return:	0	o.k.
- *		< 0	failure (channel will not be created)
+ * Warnings:	None
+ *
+ * Return: 	0 	Ok
+ *		<0 	Failed (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf)
+static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
 {
 	sdla_t* card = wandev->private;
 	x25_channel_t* chan;
 	int err = 0;
 
-	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
-	{
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){
 		printk(KERN_INFO "%s: invalid interface name!\n",
-			card->devname)
-		;
+			card->devname);
 		return -EINVAL;
 	}
 
+	if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) {
+		printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n",
+						card->devname);
+		printk(KERN_INFO 
+			"%s: Maximum number of network interfaces must be one !\n",
+						card->devname);
+		return -EEXIST;
+	}
+
 	/* allocate and initialize private data */
-	chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL);
-	if (chan == NULL)
-		return -ENOMEM
-	;
+	chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC);
+	if (chan == NULL){
+		return -ENOMEM;
+	}
+	
 	memset(chan, 0, sizeof(x25_channel_t));
+
+	/* Bug Fix: Seg Err on PVC startup
+	 * It must be here since bind_lcn_to_dev expects 
+	 * it bellow */
+	dev->priv = chan;
+	
 	strcpy(chan->name, conf->name);
 	chan->card = card;
-	chan->protocol = ETH_P_IP;
+	chan->dev = dev;
+	chan->common.sk = NULL;
+	chan->common.func = NULL;
+	chan->common.rw_bind = 0;
 	chan->tx_skb = chan->rx_skb = NULL;
 
 	/* verify media address */
-	if (conf->addr[0] == '@')		/* SVC */
-	{
-		chan->svc = 1;
+	if (conf->addr[0] == '@'){		/* SVC */
+		chan->common.svc = 1;
 		strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
 
 		/* Set channel timeouts (default if not specified) */
-		chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 					90;
-		chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout :					10;
-	}
-	else if (is_digit(conf->addr[0]))	/* PVC */
-	{
+		chan->idle_timeout = (conf->idle_timeout) ? 
+					conf->idle_timeout : 90;
+		chan->hold_timeout = (conf->hold_timeout) ? 
+					conf->hold_timeout : 10;
+
+	}else if (is_digit(conf->addr[0])){	/* PVC */
 		int lcn = dec_to_uint(conf->addr, 0);
 
-		if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc))
-		{
-			chan->lcn = lcn;
-		}
-		else
-		{
+		if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){
+			bind_lcn_to_dev (card, dev, lcn);
+		}else{
 			printk(KERN_ERR
 				"%s: PVC %u is out of range on interface %s!\n",
-				wandev->name, lcn, chan->name)
-			;
+				wandev->name, lcn, chan->name);
 			err = -EINVAL;
 		}
-	}
-	else
-	{
+	}else{
 		printk(KERN_ERR
 			"%s: invalid media address on interface %s!\n",
-			wandev->name, chan->name)
-		;
+			wandev->name, chan->name);
 		err = -EINVAL;
 	}
-	if (err)
-	{
+
+	if(strcmp(conf->usedby, "WANPIPE") == 0){
+                printk(KERN_INFO "%s: Running in WANPIPE mode %s\n",
+			wandev->name, chan->name);
+                chan->common.usedby = WANPIPE;
+		chan->protocol = htons(ETH_P_IP);
+
+        }else if(strcmp(conf->usedby, "API") == 0){
+		chan->common.usedby = API;
+                printk(KERN_INFO "%s: Running in API mode %s\n",
+			wandev->name, chan->name);
+		chan->protocol = htons(X25_PROT);
+	}
+
+
+	if (err){
 		kfree(chan);
+		dev->priv = NULL;
 		return err;
 	}
+	
+	chan->enable_IPX = conf->enable_IPX;
+	
+	if (chan->enable_IPX)
+		chan->protocol = htons(ETH_P_IPX);
+	
+	if (conf->network_number)
+		chan->network_number = conf->network_number;
+	else
+		chan->network_number = 0xDEADBEEF;
 
 	/* prepare network device data space for registration */
-	strcpy(dev->name, chan->name);
+#ifdef LINUX_2_4
+	strcpy(dev->name,chan->name);
+#else
+	dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL); 
+	if(dev->name == NULL)
+	{
+		kfree(chan);
+		dev->priv = NULL;
+		return -ENOMEM;
+	}
+	sprintf(dev->name, "%s", chan->name);
+#endif
 	dev->init = &if_init;
-	dev->priv = chan;
+
+	init_x25_channel_struct(chan);
+
 	return 0;
 }
 
-/*============================================================================
- * Delete logical channel.
+/*===================================================================
+ * Name:	del_if(),  Remove a logical channel.	 
+ *
+ * Purpose:	To dynamically remove a logical channel.
+ * 
+ * Rationale:	Each logical channel should be dynamically
+ *              removable. This functin is called by an 
+ *              IOCTL_IFDEL ioctl call or shutdown(). 
+ *                
+ * Description: Do nothing.
+ *
+ * Called by:	IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c
+ *              shutdown() from sdlamain.c
+ *
+ * Assumptions: 
+ *
+ * Warnings:
+ *
+ * Return: 	0 Ok. Void function.
  */
-static int del_if (wan_device_t* wandev, struct net_device* dev)
+
+//FIXME Del IF Should be taken out now.
+
+static int del_if (wan_device_t* wandev, netdevice_t* dev)
 {
-	if (dev->priv)
-	{
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
 	return 0;
 }
 
-/****** WANPIPE-specific entry points ***************************************/
 
-/*============================================================================
- * Execute adapter interface command.
- */
+/*============================================================
+ * Name:	wpx_exec
+ *
+ * Description:	Execute adapter interface command.
+ * 		This option is currently dissabled.
+ *===========================================================*/
 
 static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
 {
-	TX25Mbox* mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	int err, len;
-	TX25Cmd cmd;
-
-	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
-		return -EFAULT;
-		
-	/* execute command */
+        return 0;
+}
 
-	do
-	{
-		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
-		if (cmd.length)
-		{
-			if(copy_from_user((void*)&mbox->data, u_data, cmd.length))
-				return-EFAULT;
-		}
-		if (sdla_exec(mbox))
-			err = mbox->cmd.result
-		;
-		else return -EIO;
-	}
-	while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn));
+/*============================================================
+ * Name:	disable_comm	
+ *
+ * Description:	Disable communications during shutdown.
+ *              Dont check return code because there is 
+ *              nothing we can do about it.  
+ *
+ * Warning:	Dev and private areas are gone at this point.
+ *===========================================================*/
 
-	/* return result */
-	if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd)))
-		return -EFAULT;
-	len = mbox->cmd.length;
-	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
-		return -EFAULT;
-	return 0;
+static void disable_comm(sdla_t* card)
+{
+	disable_comm_shutdown(card);
+	del_timer(&card->u.x.x25_timer);
+	return;
 }
 
-/****** Network Device Interface ********************************************/
 
-/*============================================================================
- * Initialize Linux network interface.
+/*============================================================
+ *	Network Device Interface 
+ *===========================================================*/
+
+/*===================================================================
+ * Name:	if_init(),   Netowrk Interface Initialization 	 
  *
- * This routine is called only once for each interface, during Linux network
- * interface registration.  Returning anything but zero will fail interface
- * registration.
+ * Purpose:	To initialize a network interface device structure.
+ * 
+ * Rationale:	During network interface startup, the if_init
+ *              is called by the kernel to initialize the
+ *              netowrk device structure.  Thus a driver
+ *              can customze a network device. 
+ *                
+ * Description:	Initialize the netowrk device call back
+ *              routines.  This is where we tell the kernel
+ *              which function to use when it wants to send
+ *              via our interface. 
+ *		Furthermore, we initialize the device flags, 
+ *              MTU and physical address of the board.
+ *
+ * Called by:	Kernel (/usr/src/linux/net/core/dev.c)
+ * 		(dev->init())
+ *
+ * Assumptions: None
+ *	
+ * Warnings:	None
+ *
+ * Return: 	0 	Ok : Void function.
  */
-static int if_init (struct net_device* dev)
+static int if_init (netdevice_t* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 	wan_device_t* wandev = &card->wandev;
+#ifdef LINUX_2_0
+	int i;
+#endif
 
 	/* Initialize device driver entry points */
 	dev->open		= &if_open;
@@ -548,127 +1135,266 @@
 	dev->hard_start_xmit	= &if_send;
 	dev->get_stats		= &if_stats;
 
+#ifdef LINUX_2_4
+	dev->tx_timeout		= &if_tx_timeout;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+#endif
+
 	/* Initialize media-specific parameters */
-	dev->type		= 30;		/* ARP h/w type */
-	dev->mtu		= X25_CHAN_MTU;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	dev->type		= ARPHRD_PPP;		/* ARP h/w type */
+#else
+        dev->family             = AF_INET;      /* address family */
+        dev->type               = ARPHRD_PPP;   /* no x25 type */
+#endif
+	dev->flags		|= IFF_POINTOPOINT;
+	dev->flags		|= IFF_NOARP;
+
+	if (chan->common.usedby == API){
+		dev->mtu	= X25_CHAN_MTU+sizeof(x25api_hdr_t);
+	}else{
+		dev->mtu	= card->wandev.mtu; 	
+	}
+	
 	dev->hard_header_len	= X25_HRDHDR_SZ; /* media header length */
 	dev->addr_len		= 2;		/* hardware address length */
-	if (!chan->svc)
-		*(unsigned short*)dev->dev_addr = htons(chan->lcn);
-
+	
+	if (!chan->common.svc){
+		*(unsigned short*)dev->dev_addr = htons(chan->common.lcn);
+	}
+	
 	/* Initialize hardware parameters (just for reference) */
 	dev->irq	= wandev->irq;
 	dev->dma	= wandev->dma;
 	dev->base_addr	= wandev->ioport;
 	dev->mem_start	= (unsigned long)wandev->maddr;
-	dev->mem_end	= dev->mem_end + wandev->msize - 1;
+	dev->mem_end	= wandev->maddr + wandev->msize - 1;
 
         /* Set transmit buffer queue length */
-        dev->tx_queue_len = 10;
+        dev->tx_queue_len = 100;
 
 	/* Initialize socket buffers */
-	
-	dev_init_buffers(dev);
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
+        for (i = 0; i < DEV_NUMBUFFS; ++i)
+                skb_queue_head_init(&dev->buffs[i]);
+#endif
+	/* FIXME Why are we doing this */
 	set_chan_state(dev, WAN_DISCONNECTED);
 	return 0;
 }
 
-/*============================================================================
- * Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
+
+/*===================================================================
+ * Name:	if_open(),   Open/Bring up the Netowrk Interface 
+ *
+ * Purpose:	To bring up a network interface.
+ * 
+ * Rationale:	
+ *                
+ * Description:	Open network interface.
+ * 		o prevent module from unloading by incrementing use count
+ * 		o if link is disconnected then initiate connection
+ *
+ * Called by:	Kernel (/usr/src/linux/net/core/dev.c)
+ * 		(dev->open())
  *
- * Return 0 if O.k. or errno.
+ * Assumptions: None
+ *	
+ * Warnings:	None
+ *
+ * Return: 	0 	Ok
+ * 		<0 	Failur: Interface will not come up.
  */
-static int if_open (struct net_device* dev)
+
+static int if_open (netdevice_t* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
+	struct timeval tv;
+	unsigned long smp_flags;
+	
+	if (is_dev_running(dev))
+		return -EBUSY;
+
+	chan->tq_working = 0;
+
+	/* Initialize the task queue */
+#ifndef LINUX_2_4
+	chan->common.wanpipe_task.next = NULL;
+#endif
+	chan->common.wanpipe_task.sync = 0;
+	chan->common.wanpipe_task.routine = (void *)(void *)x25api_bh;
+	chan->common.wanpipe_task.data = dev;
+
+	/* Allocate and initialize BH circular buffer */
+	/* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */
+	chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC);
+
+	if (chan->bh_head == NULL){
+		printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n",
+				card->devname);
+
+		return -ENOBUFS;
+	}
+	memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1)));
+	atomic_set(&chan->bh_buff_used, 0);
 
-	if (dev->start)
-		return -EBUSY;		/* only one open is allowed */
+	/* Increment the number of interfaces */
+	++card->u.x.no_dev;
 	
-	if (test_and_set_bit(0, (void*)&card->wandev.critical))
-		return -EAGAIN;
+	wanpipe_open(card);
 
+	/* LAPB protocol only uses one interface, thus
+	 * start the protocol after it comes up. */
+	if (card->u.x.LAPB_hdlc){
+		if (card->open_cnt == 1){
+			TX25Status* status = card->flags;
+			S508_S514_lock(card, &smp_flags);
+			x25_set_intr_mode(card, INTR_ON_TIMER); 
+			status->imask &= ~INTR_ON_TIMER;
+			S508_S514_unlock(card, &smp_flags);
+		}
+	}else{
+		/* X25 can have multiple interfaces thus, start the 
+		 * protocol once all interfaces are up */
+
+		//FIXME: There is a bug here. If interface is
+		//brought down and up, it will try to enable comm.
+		if (card->open_cnt == card->u.x.num_of_ch){
+
+			S508_S514_lock(card, &smp_flags);
+			connect(card);
+			S508_S514_unlock(card, &smp_flags);
+
+			del_timer(&card->u.x.x25_timer);
+			card->u.x.x25_timer.expires=jiffies+HZ;
+			add_timer(&card->u.x.x25_timer);
+		}
+	}
+	/* Device is not up untill the we are in connected state */
+	do_gettimeofday( &tv );
+	chan->router_start_time = tv.tv_sec;
+
+#ifdef LINUX_2_4
+	netif_start_queue(dev);
+#else	
 	dev->interrupt = 0;
 	dev->tbusy = 0;
 	dev->start = 1;
-	wanpipe_open(card);
-
-	/* If this is the first open, initiate physical connection */
-	if (card->open_cnt == 1)
-		connect(card);
-	card->wandev.critical = 0;
+#endif
 	return 0;
 }
 
-/*============================================================================
- * Close network interface.
- * o reset flags.
- * o if there's no more open channels then disconnect physical link.
+/*===================================================================
+ * Name:	if_close(),   Close/Bring down the Netowrk Interface 
+ *
+ * Purpose:	To bring down a network interface.
+ * 
+ * Rationale:	
+ *                
+ * Description:	Close network interface.
+ * 		o decrement use module use count
+ *
+ * Called by:	Kernel (/usr/src/linux/net/core/dev.c)
+ * 		(dev->close())
+ *		ifconfig <name> down: will trigger the kernel
+ *              which will call this function.
+ *
+ * Assumptions: None
+ *	
+ * Warnings:	None
+ *
+ * Return: 	0 	Ok
+ * 		<0 	Failure: Interface will not exit properly.
  */
-static int if_close (struct net_device* dev)
+static int if_close (netdevice_t* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
-
-	if (test_and_set_bit(0, (void*)&card->wandev.critical))
-		return -EAGAIN;
-
-	dev->start = 0;
-	if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING))
+	unsigned long smp_flags;
+	
+	stop_net_queue(dev);
+#ifndef LINUX_2_4
+	dev->start=0;
+#endif
+
+	if ((chan->common.state == WAN_CONNECTED) || 
+	    (chan->common.state == WAN_CONNECTING)){
+		S508_S514_lock(card, &smp_flags);
 		chan_disc(dev);
-		
+		S508_S514_unlock(card, &smp_flags);
+	}
+
 	wanpipe_close(card);
 
-	/* If this is the last close, disconnect physical link */
-	if (!card->open_cnt)
-		disconnect(card);
-		
-	card->wandev.critical = 0;
+	S508_S514_lock(card, &smp_flags);
+	if (chan->bh_head){
+		int i;
+		struct sk_buff *skb;
+	
+		for (i=0; i<(MAX_BH_BUFF+1); i++){
+			skb = ((bh_data_t *)&chan->bh_head[i])->skb;
+			if (skb != NULL){
+                		wan_dev_kfree_skb(skb, FREE_READ);
+			}
+		}
+		kfree(chan->bh_head);
+		chan->bh_head=NULL;
+	}
+	S508_S514_unlock(card, &smp_flags);
+
+	/* If this is the last close, disconnect physical link */
+	if (!card->open_cnt){
+		S508_S514_lock(card, &smp_flags);
+		disconnect(card);
+		x25_set_intr_mode(card, 0);
+		S508_S514_unlock(card, &smp_flags);
+	}
+	
+	/* Decrement the number of interfaces */
+	--card->u.x.no_dev;
 	return 0;
 }
 
-/*============================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
+/*======================================================================
+ * 	Build media header.
+ * 	o encapsulate packet according to encapsulation type.
  *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
+ * 	The trick here is to put packet type (Ethertype) into 'protocol' 
+ *      field of the socket buffer, so that we don't forget it.  
+ *      If encapsulation fails, set skb->protocol to 0 and discard 
+ *      packet later.
  *
- * Return:	media header length.
- */
-static int if_header (struct sk_buff* skb, struct net_device* dev,
+ * 	Return:		media header length.
+ *======================================================================*/
+
+static int if_header (struct sk_buff* skb, netdevice_t* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len)
 {
 	x25_channel_t* chan = dev->priv;
 	int hdr_len = dev->hard_header_len;
-
-	skb->protocol = type;
-	if (!chan->protocol)
-	{
-		hdr_len = wanrouter_encapsulate(skb, dev);
-		if (hdr_len < 0)
-		{
+	
+	skb->protocol = htons(type);
+	if (!chan->protocol){
+		hdr_len = wanrouter_encapsulate(skb, dev, type);
+		if (hdr_len < 0){
 			hdr_len = 0;
-			skb->protocol = 0;
+			skb->protocol = htons(0);
 		}
 	}
 	return hdr_len;
 }
 
-/*============================================================================
- * Re-build media header.
+/*===============================================================
+ * 	Re-build media header.
  *
- * Return:	1	physical address resolved.
- *		0	physical address not resolved
- */
- 
+ * 	Return:		1	physical address resolved.
+ *			0	physical address not resolved
+ *==============================================================*/
+
 static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	struct net_device *dev=skb->dev;
+	netdevice_t *dev = skb->dev; 
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
@@ -677,185 +1403,294 @@
 	return 1;
 }
 
+
+#ifdef LINUX_2_4
 /*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
+ * Handle transmit timeout event from netif watchdog
+ */
+static void if_tx_timeout (netdevice_t *dev)
+{
+    	x25_channel_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+
+	/* If our device stays busy for at least 5 seconds then we will
+	 * kick start the device by making dev->tbusy = 0.  We expect
+	 * that our device never stays busy more than 5 seconds. So this                 
+	 * is only used as a last resort.
+	 */
+
+	++chan->if_send_stat.if_send_tbusy_timeout;
+	printk (KERN_INFO "%s: Transmit timed out on %s\n", 
+			card->devname, dev->name);
+	netif_wake_queue (dev);
+}
+#endif
+
+
+/*=========================================================================
+ * 	Send a packet on a network interface.
+ * 	o set tbusy flag (marks start of the transmission).
+ * 	o check link state. If link is not up, then drop the packet.
+ * 	o check channel status. If it's down then initiate a call.
+ * 	o pass a packet to corresponding WAN device.
+ * 	o free socket buffer
  *
- * Return:	0	complete (socket buffer must be freed)
+ * 	Return:	0	complete (socket buffer must be freed)
  *		non-0	packet may be re-transmitted (tbusy must be set)
  *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer.
- */
+ * 	Notes:
+ * 	1. This routine is called either by the protocol stack or by the "net
+ *    	bottom half" (with interrupts enabled).
+ * 	2. Setting tbusy flag will inhibit further transmit requests from the
+ *    	protocol stack and can be used for flow control with protocol layer.
+ *
+ *========================================================================*/
 
-static int if_send (struct sk_buff* skb, struct net_device* dev)
+static int if_send (struct sk_buff* skb, netdevice_t* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
-	struct net_device *dev2;
 	TX25Status* status = card->flags;
-	unsigned long host_cpu_flags;
+	int udp_type;
+	unsigned long smp_flags=0;
 
-	if (dev->tbusy)
-	{
-		++chan->ifstats.rx_dropped;	
-		if ((jiffies - chan->tick_counter) < (5*HZ))
-		{
-			return dev->tbusy;
+	++chan->if_send_stat.if_send_entry;
+
+#ifdef LINUX_2_4
+	netif_stop_queue(dev);
+#endif
+
+	/* No need to check frame length, since socket code
+         * will perform the check for us */
+
+#ifndef LINUX_2_4
+	if (dev->tbusy){
+		netdevice_t *dev2;
+		
+		++chan->if_send_stat.if_send_tbusy;
+		if ((jiffies - chan->tick_counter) < (5*HZ)){
+			return 1;
 		}
 		printk(KERN_INFO "%s: Transmit time out %s!\n",
-		       card->devname, dev->name);
+			card->devname, dev->name);
+		
+		for( dev2 = card->wandev.dev; dev2; 
+		     dev2 = *((netdevice_t**)dev2->priv)){
 
-		dev2 = card->wandev.dev;
-		while (dev2) {
-			x25_channel_t *chan2 = dev2->priv;
 	        	dev2->tbusy = 0;
-			dev2 = chan2->slave;
 		}
+		++chan->if_send_stat.if_send_tbusy_timeout;
 	}
+#endif
+
 	chan->tick_counter = jiffies;
+	
+	/* Critical region starts here */
+	S508_S514_lock(card, &smp_flags);
+	
+	if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){
+		printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical);
+		goto if_send_crit_exit;
+	}
+	
+	udp_type = udp_pkt_type(skb, card);
 
-	disable_irq(card->hw.irq);
-	++card->irq_dis_if_send_count;
+        if(udp_type != UDP_INVALID_TYPE) {
 
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
-	{
-		printk(KERN_INFO "Hit critical in if_send()!\n");
-		if (card->wandev.critical == CRITICAL_IN_ISR) 
-		{
-			card->wandev.enable_tx_int = 1;
-			dev->tbusy = 1;
-			
-			save_flags(host_cpu_flags);
-                        cli();
-                        if ((!(--card->irq_dis_if_send_count)) &&
-                                        (!card->irq_dis_poll_count))
-                                enable_irq(card->hw.irq);
-                        restore_flags(host_cpu_flags);
-			
-			return dev->tbusy;
-		}
-		dev_kfree_skb(skb);
-		
-		save_flags(host_cpu_flags);
-                cli();
-                if ((!(--card->irq_dis_if_send_count)) &&
-                                         (!card->irq_dis_poll_count))
-                        enable_irq(card->hw.irq);
-                restore_flags(host_cpu_flags);
+                if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb,
+                        chan->common.lcn)) {
 
-		return dev->tbusy;
+                        status->imask |= INTR_ON_TIMER;
+                        if (udp_type == UDP_XPIPE_TYPE){
+                                chan->if_send_stat.if_send_PIPE_request++;
+			}
+               	}
+		start_net_queue(dev);
+		clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+		S508_S514_unlock(card, &smp_flags);
+		return 0;
 	}
 
-	/* Below is only until we have per-channel IPX going.... */
-	if(!(chan->svc))
-		chan->protocol = skb->protocol;
+	if (chan->transmit_length){
+		//FIXME: This check doesn't make sense any more
+		if (chan->common.state != WAN_CONNECTED){
+			chan->transmit_length=0;
+			atomic_set(&chan->common.driver_busy,0);
+		}else{
+			stop_net_queue(dev);
+			++card->u.x.tx_interrupts_pending;
+		        status->imask |= INTR_ON_TX_FRAME;
+			clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+			S508_S514_unlock(card, &smp_flags);
+			return 1;
+		}
+	}
 
-	if (card->wandev.state != WAN_CONNECTED)
+	if (card->wandev.state != WAN_CONNECTED){
 		++chan->ifstats.tx_dropped;
-
-	/* Below is only until we have per-channel IPX going.... */
-	else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol)))
-	{
+		++card->wandev.stats.tx_dropped;
+		++chan->if_send_stat.if_send_wan_disconnected;	
+		
+	}else if ( chan->protocol && (chan->protocol != skb->protocol)){
 		printk(KERN_INFO
 			"%s: unsupported Ethertype 0x%04X on interface %s!\n",
-			card->devname, skb->protocol, dev->name);
+			chan->name, htons(skb->protocol), dev->name);
+		
+		printk(KERN_INFO "PROTO %Xn", htons(chan->protocol));
 		++chan->ifstats.tx_errors;
-	}
-	else switch (chan->state)
-	{
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+		++chan->if_send_stat.if_send_protocol_error;
+		
+	}else switch (chan->common.state){
+
 		case WAN_DISCONNECTED:
 			/* Try to establish connection. If succeded, then start
 			 * transmission, else drop a packet.
 			 */
-			if (chan_connect(dev) != 0)
-			{
+			if (chan->common.usedby == API){
 				++chan->ifstats.tx_dropped;
 				++card->wandev.stats.tx_dropped;
 				break;
+			}else{
+				if (chan_connect(dev) != 0){
+					++chan->ifstats.tx_dropped;
+					++card->wandev.stats.tx_dropped;
+					break;
+				}
 			}
 			/* fall through */
 
 		case WAN_CONNECTED:
-			if( skb->protocol == ETH_P_IPX ) 
-			{
-				if(card->wandev.enable_IPX) 
-				{
+			if( skb->protocol == htons(ETH_P_IPX)) {
+				if(chan->enable_IPX) {
 					switch_net_numbers( skb->data, 
-						card->wandev.network_number, 0);
-				}
-				else 
-				{
+						chan->network_number, 0);
+				} else {
 					++card->wandev.stats.tx_dropped;
 					++chan->ifstats.tx_dropped;
-					goto tx_done;
+					++chan->if_send_stat.if_send_protocol_error;
+					goto if_send_crit_exit;
 				}
 			}
-			dev->trans_start = jiffies;
-			if(chan_send(dev, skb))
-			{
-				dev->tbusy = 1;
-				status->imask |= 0x2;
-			}
+			/* We never drop here, if cannot send than, copy
+	                 * a packet into a transmit buffer 
+                         */
+			chan_send(dev, skb->data, skb->len, 0);
 			break;
 
 		default:
 			++chan->ifstats.tx_dropped;	
 			++card->wandev.stats.tx_dropped;
+			break;
 	}
-tx_done:
-	if (!dev->tbusy)
-		dev_kfree_skb(skb);
-
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-        cli();
-        if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
-                enable_irq(card->hw.irq);
-        restore_flags(host_cpu_flags);
-	return dev->tbusy;
+
+
+if_send_crit_exit:
+	
+       	wan_dev_kfree_skb(skb, FREE_WRITE);
+
+	start_net_queue(dev);
+	clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
+	S508_S514_unlock(card, &smp_flags);
+	return 0;
 }
 
 /*============================================================================
- * Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats
- */
- 
-static struct net_device_stats* if_stats (struct net_device* dev)
+ * Setup so that a frame can be transmitted on the occurence of a transmit
+ * interrupt.
+ *===========================================================================*/
+
+static void setup_for_delayed_transmit (netdevice_t* dev, void* buf,
+	unsigned len)
 {
-	x25_channel_t* chan = dev->priv;
-	if(chan==NULL)
+        x25_channel_t* chan = dev->priv;
+        sdla_t* card = chan->card;
+	TX25Status* status = card->flags;
+
+	++chan->if_send_stat.if_send_adptr_bfrs_full;
+
+        if(chan->transmit_length) {
+                printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n",
+				card->devname);
+                return;
+        }
+
+	if (chan->common.usedby == API){
+		if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) {
+			++chan->ifstats.tx_dropped;	
+			++card->wandev.stats.tx_dropped;
+			printk(KERN_INFO "%s: Length is too big for delayed transmit\n",
+				card->devname);
+			return;
+		}
+	}else{
+		if (len > X25_MAX_DATA) {
+			++chan->ifstats.tx_dropped;	
+			++card->wandev.stats.tx_dropped;
+			printk(KERN_INFO "%s: Length is too big for delayed transmit\n",
+				card->devname);
+			return;
+		}
+	}
+
+        chan->transmit_length = len;
+	atomic_set(&chan->common.driver_busy,1);
+        memcpy(chan->transmit_buffer, buf, len);
+
+	++chan->if_send_stat.if_send_tx_int_enabled;
+
+	/* Enable Transmit Interrupt */
+	++card->u.x.tx_interrupts_pending;
+        status->imask |= INTR_ON_TX_FRAME;
+}
+
+
+/*===============================================================
+ * net_device_stats
+ *
+ * 	Get ethernet-style interface statistics.
+ * 	Return a pointer to struct enet_statistics.
+ *
+ *==============================================================*/
+static struct net_device_stats *if_stats (netdevice_t* dev)
+{
+	x25_channel_t *chan = dev->priv;
+
+	if(chan == NULL)
 		return NULL;
+
 	return &chan->ifstats;
 }
 
-/****** Interrupt Handlers **************************************************/
 
-/*============================================================================
+/*
+ *	Interrupt Handlers 
+ */
+
+/*
  * X.25 Interrupt Service Routine.
  */
- 
+
 static void wpx_isr (sdla_t* card)
 {
 	TX25Status* status = card->flags;
-	struct net_device *dev;
-	unsigned long host_cpu_flags;
 
 	card->in_isr = 1;
-	card->buff_int_mode_unbusy = 0;
+	++card->statistics.isr_entry;
 
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
-	{
+	if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
+		card->in_isr=0;
+		status->iflags = 0;
+		return;
+	}
+	
+	if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){
 
- 		printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags);
+ 		printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", 
+			card->devname, card->wandev.critical, status->iflags);
 		card->in_isr = 0;
+		status->iflags = 0;
 		return;
 	}
 
@@ -863,92 +1698,62 @@
          * If the if_send routine is called with this flag set it will set
          * the enable transmit flag to 1. (for a delayed interrupt)
          */
-	card->wandev.critical = CRITICAL_IN_ISR;
+	switch (status->iflags){
 
-	switch (status->iflags)
-	{
-		case 0x01:		/* receive interrupt */
+		case RX_INTR_PENDING:		/* receive interrupt */
 			rx_intr(card);
 			break;
 
-		case 0x02:		/* transmit interrupt */
+		case TX_INTR_PENDING:		/* transmit interrupt */
 			tx_intr(card);
-			card->buff_int_mode_unbusy = 1;
-			status->imask &= ~0x2;
 			break;
 
-		case 0x04:		/* modem status interrupt */
+		case MODEM_INTR_PENDING:	/* modem status interrupt */
 			status_intr(card);
 			break;
 
-		case 0x10:		/* network event interrupt */
+		case X25_ASY_TRANS_INTR_PENDING:	/* network event interrupt */
 			event_intr(card);
 			break;
 
+		case TIMER_INTR_PENDING:
+			timer_intr(card);
+			break;
+
 		default:		/* unwanted interrupt */
 			spur_intr(card);
 	}
-	card->wandev.critical = CRITICAL_INTR_HANDLED;
-	if( card->wandev.enable_tx_int)
-	{
-		card->wandev.enable_tx_int = 0;
-		status->imask |= 0x2;
-	}
-	save_flags(host_cpu_flags);
-	cli();
+
 	card->in_isr = 0;
 	status->iflags = 0;	/* clear interrupt condition */
-	card->wandev.critical = 0;
-	restore_flags(host_cpu_flags);
-
-	if(card->buff_int_mode_unbusy)
-	{
-		x25_channel_t *chan;
-
-		dev = card->wandev.dev;
-		while (dev) {
-			chan = dev->priv;
-			if(chan->devtint) {
-				mark_bh(NET_BH);
-				return;
-			}	
-
-			dev = chan->slave;
-		}
-	}
 }
 
-/*============================================================================
- * Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map ligical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
- *   decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- *    coming and we have to allocate buffer for the maximum IP packet size
- *    expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- *    socket buffers available) the whole packet sequence must be discarded.
+/*
+ * 	Receive interrupt handler.
+ * 	This routine handles fragmented IP packets using M-bit according to the
+ * 	RFC1356.
+ * 	o map ligical channel number to network interface.
+ * 	o allocate socket buffer or append received packet to the existing one.
+ * 	o if M-bit is reset (i.e. it's the last packet in a sequence) then 
+ *   	decapsulate packet and pass socket buffer to the protocol stack.
+ *
+ * 	Notes:
+ * 	1. When allocating a socket buffer, if M-bit is set then more data is
+ *    	coming and we have to allocate buffer for the maximum IP packet size
+ *    	expected on this channel.
+ * 	2. If something goes wrong and X.25 packet has to be dropped (e.g. no
+ *    	socket buffers available) the whole packet sequence must be discarded.
  */
 
 static void rx_intr (sdla_t* card)
 {
 	TX25Mbox* rxmb = card->rxmb;
-	unsigned lcn = rxmb->cmd.lcn;		/* logical channel number */
-	unsigned len = rxmb->cmd.length;	/* packet length */
-	unsigned qdm = rxmb->cmd.qdm;		/* Q,D and M bits */
-	wan_device_t* wandev = &card->wandev;
-	struct net_device* dev = get_dev_by_lcn(wandev, lcn);
+	unsigned lcn = rxmb->cmd.lcn;
+	netdevice_t* dev = find_channel(card,lcn);
 	x25_channel_t* chan;
-	struct sk_buff* skb;
-	void* bufptr;
+	struct sk_buff* skb=NULL;
 
-	if (dev == NULL)
-	{
+	if (dev == NULL){
 		/* Invalid channel, discard packet */
 		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
 			card->devname, lcn);
@@ -957,171 +1762,565 @@
 
 	chan = dev->priv;
 	chan->i_timeout_sofar = jiffies;
-	if (chan->drop_sequence)
-	{
-		if (!(qdm & 0x01)) chan->drop_sequence = 0;
+
+
+	/* Copy the data from the board, into an
+         * skb buffer 
+	 */
+	if (wanpipe_pull_data_in_skb(card,dev,&skb)){
+		++chan->ifstats.rx_dropped;
+		++card->wandev.stats.rx_dropped;
+		++chan->rx_intr_stat.rx_intr_no_socket;
+		++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
 		return;
 	}
 
-	skb = chan->rx_skb;
-	if (skb == NULL)
-	{
-		/* Allocate new socket buffer */
-		int bufsize = (qdm & 0x01) ? dev->mtu : len;
+	dev->last_rx = jiffies;		/* timestamp */
 
-		skb = dev_alloc_skb(bufsize + dev->hard_header_len);
-		if (skb == NULL)
-		{
-			printk(KERN_INFO "%s: no socket buffers available!\n",
-				card->devname);
-			chan->drop_sequence = 1;	/* set flag */
+
+	/* ------------ API ----------------*/
+
+	if (chan->common.usedby == API){
+
+		if (bh_enqueue(dev, skb)){
 			++chan->ifstats.rx_dropped;
+			++card->wandev.stats.rx_dropped;
+			++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
+			wan_dev_kfree_skb(skb, FREE_READ);
 			return;
-		}
-		skb->dev = dev;
-		skb->protocol = htons(chan->protocol);
-		chan->rx_skb = skb;
-	}
+		}		
 
-	if (skb_tailroom(skb) < len)
-	{
-		/* No room for the packet. Call off the whole thing! */
-		dev_kfree_skb(skb);
-		chan->rx_skb = NULL;
-		if (qdm & 0x01) chan->drop_sequence = 1;
+		++chan->ifstats.rx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+		chan->ifstats.rx_bytes += skb->len;
+#endif
+		
 
-		printk(KERN_INFO "%s: unexpectedly long packet sequence "
-			"on interface %s!\n", card->devname, dev->name);
-		++chan->ifstats.rx_length_errors;
+		chan->rx_skb = NULL;
+		if (!test_and_set_bit(0, &chan->tq_working)){
+			wanpipe_queue_tq(&chan->common.wanpipe_task);
+			wanpipe_mark_bh();
+		}
 		return;
 	}
 
-	/* Append packet to the socket buffer */
-	bufptr = skb_put(skb, len);
-	memcpy(bufptr, rxmb->data, len);
-
-	if (qdm & 0x01)
-		return;		/* more data is coming */
-
-	dev->last_rx = jiffies;		/* timestamp */
-	chan->rx_skb = NULL;		/* dequeue packet */
 
+	/* ------------- WANPIPE -------------------*/
+	
+	/* set rx_skb to NULL so we won't access it later when kernel already owns it */
+	chan->rx_skb=NULL;
+	
 	/* Decapsulate packet, if necessary */
-	if (!skb->protocol && !wanrouter_type_trans(skb, dev))
-	{
+	if (!skb->protocol && !wanrouter_type_trans(skb, dev)){
 		/* can't decapsulate packet */
-		dev_kfree_skb(skb);
+                wan_dev_kfree_skb(skb, FREE_READ);
 		++chan->ifstats.rx_errors;
-	}
-	else
-	{
-		if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol))
-		{
-			if( card->wandev.enable_IPX )
-			{
-				if(chan_send(dev, skb))
-				{
+		++chan->ifstats.rx_dropped;
+		++card->wandev.stats.rx_dropped;
+		++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
+
+	}else{
+		if( handle_IPXWAN(skb->data, chan->name, 
+				  chan->enable_IPX, chan->network_number, 
+				  skb->protocol)){
+
+			if( chan->enable_IPX ){
+				if(chan_send(dev, skb->data, skb->len,0)){
 					chan->tx_skb = skb;
+				}else{
+                                        wan_dev_kfree_skb(skb, FREE_WRITE);
+					++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
 				}
-				else
-				{
-					dev_kfree_skb(skb);
-				}
+			}else{
+				/* increment IPX packet dropped statistic */
+				++chan->ifstats.rx_dropped;
+				++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
 			}
-			else
-			{
-				/* FIXME: increment IPX packet dropped statistic */
-			}
-		}
-		else
-		{
-			netif_rx(skb);
-			++chan->ifstats.rx_packets;
+		}else{
+			skb->mac.raw = skb->data;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 			chan->ifstats.rx_bytes += skb->len;
+#endif
+			++chan->ifstats.rx_packets;
+			++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack;
+			netif_rx(skb);
 		}
 	}
+	
+	return;
 }
 
-/*============================================================================
- * Transmit interrupt handler.
- *	o Release socket buffer
- *	o Clear 'tbusy' flag
- */
 
-static void tx_intr (sdla_t* card)
+static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb)
 {
-	struct net_device *dev;
-	x25_channel_t *chan;
+	void *bufptr;
+	TX25Mbox* rxmb = card->rxmb;
+	unsigned len = rxmb->cmd.length;	/* packet length */
+	unsigned qdm = rxmb->cmd.qdm;		/* Q,D and M bits */
+	x25_channel_t *chan = dev->priv;
+	struct sk_buff *new_skb = *skb;
+
+	if (chan->common.usedby == WANPIPE){
+		if (chan->drop_sequence){
+			if (!(qdm & 0x01)){ 
+				chan->drop_sequence = 0;
+			}
+			return 1;
+		}
+		new_skb = chan->rx_skb;
+	}else{
+		/* Add on the API header to the received
+                 * data 
+		 */
+		len += sizeof(x25api_hdr_t);
+	}
 
-	/* unbusy all devices and then dev_tint(); */
-	dev = card->wandev.dev;
-	while (dev) {
-		chan->devtint = dev->tbusy; 
-		dev->tbusy = 0;
+	if (new_skb == NULL){
+		int bufsize;
 
-		dev = chan->slave;
+		if (chan->common.usedby == WANPIPE){
+			bufsize = (qdm & 0x01) ? dev->mtu : len;
+		}else{
+			bufsize = len;
+		}
+
+		/* Allocate new socket buffer */
+		new_skb = dev_alloc_skb(bufsize + dev->hard_header_len);
+		if (new_skb == NULL){
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+				card->devname);
+			chan->drop_sequence = 1;	/* set flag */
+			++chan->ifstats.rx_dropped;
+			return 1;
+		}
 	}
 
-}
+	if (skb_tailroom(new_skb) < len){
+		/* No room for the packet. Call off the whole thing! */
+                wan_dev_kfree_skb(new_skb, FREE_READ);
+		if (chan->common.usedby == WANPIPE){
+			chan->rx_skb = NULL;
+			if (qdm & 0x01){ 
+				chan->drop_sequence = 1;
+			}
+		}
 
-/*============================================================================
- * Modem status interrupt handler.
- */
-static void status_intr (sdla_t* card)
-{
-}
+		printk(KERN_INFO "%s: unexpectedly long packet sequence "
+			"on interface %s!\n", card->devname, dev->name);
+		++chan->ifstats.rx_length_errors;
+		return 1;
+	}
 
-/*============================================================================
- * Network event interrupt handler.
- */
-static void event_intr (sdla_t* card)
-{
-}
+	bufptr = skb_put(new_skb,len);
 
-/*============================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o 
- * If number of spurious interrupts exceeded some limit, then ???
- */
-static void spur_intr (sdla_t* card)
-{
-	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
-}
 
-/****** Background Polling Routines  ****************************************/
+	if (chan->common.usedby == API){
+		/* Fill in the x25api header 
+		 */
+		x25api_t * api_data = (x25api_t*)bufptr;
+		api_data->hdr.qdm = rxmb->cmd.qdm;
+		api_data->hdr.cause = rxmb->cmd.cause;
+		api_data->hdr.diagn = rxmb->cmd.diagn;
+		api_data->hdr.length = rxmb->cmd.length;
+		memcpy(api_data->data, rxmb->data, rxmb->cmd.length);
+	}else{
+		memcpy(bufptr, rxmb->data, len);
+	}
+
+	new_skb->dev = dev;
+
+	if (chan->common.usedby == API){
+		new_skb->mac.raw = new_skb->data;
+		new_skb->protocol = htons(X25_PROT);
+		new_skb->pkt_type = WAN_PACKET_DATA;
+	}else{
+		new_skb->protocol = chan->protocol;
+		chan->rx_skb = new_skb;
+	}
+
+	/* If qdm bit is set, more data is coming 
+         * thus, exit and wait for more data before
+         * sending the packet up. (Used by router only) 
+	 */
+	if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) 
+		return 1;	
+
+	*skb = new_skb; 
 
-/*============================================================================
- * Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thread' to allow for
- * time-dependent housekeeping work.
+	return 0;
+}
+
+/*===============================================================
+ * tx_intr
+ *  
+ * 	Transmit interrupt handler.
+ *	For each dev, check that there is something to send.
+ *	If data available, transmit. 	
  *
- * Notes:
- * 1. This routine may be called on interrupt context with all interrupts
- *    enabled. Beware!
- */
+ *===============================================================*/
 
-static void wpx_poll (sdla_t* card)
+static void tx_intr (sdla_t* card)
 {
-	unsigned long host_cpu_flags;
-
-	disable_irq(card->hw.irq);
-	++card->irq_dis_poll_count;
+	netdevice_t *dev;
+	TX25Status* status = card->flags;
+	unsigned char more_to_tx=0;
+	x25_channel_t *chan=NULL;
+	int i=0;	
 
-	if (test_and_set_bit(0, (void*)&card->wandev.critical)) 
-	{
- 		printk(KERN_INFO "%s: critical in polling!\n",card->devname);	
-		save_flags(host_cpu_flags);
-                cli();
-		if ((!card->irq_dis_if_send_count) &&
-                                (!(--card->irq_dis_poll_count)))
-                        enable_irq(card->hw.irq);
-                restore_flags(host_cpu_flags);
-		return;
+	if (card->u.x.tx_dev == NULL){
+		card->u.x.tx_dev = card->wandev.dev;
 	}
 
-	switch(card->wandev.state)
-	{
+	dev = card->u.x.tx_dev;
+
+	for (;;){
+
+		chan = dev->priv;
+		if (chan->transmit_length){
+			/* Device was set to transmit, check if the TX
+                         * buffers are available 
+			 */		
+			if (chan->common.state != WAN_CONNECTED){
+				chan->transmit_length = 0;
+				atomic_set(&chan->common.driver_busy,0);
+				chan->tx_offset=0;
+				if (is_queue_stopped(dev)){
+					if (chan->common.usedby == API){
+						start_net_queue(dev);
+						wakeup_sk_bh(dev);
+					}else{
+						wake_net_dev(dev);
+					}
+				}
+				dev = move_dev_to_next(card,dev);
+				break;
+			}				
+
+			if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && 
+			     (*card->u.x.hdlc_buf_status & 0x40) ){
+				/* Tx buffer available, we can send */
+				
+				if (tx_intr_send(card, dev)){
+					more_to_tx=1;
+				}
+
+				/* If more than one interface present, move the
+                                 * device pointer to the next interface, so on the 
+                                 * next TX interrupt we will try sending from it. 
+                                 */
+				dev = move_dev_to_next(card,dev);
+				break;
+			}else{
+				/* Tx buffers not available, but device set
+                                 * the TX interrupt.  Set more_to_tx and try  
+                                 * to transmit for other devices.
+				 */
+				more_to_tx=1;
+				dev = move_dev_to_next(card,dev);
+			}
+
+		}else{
+			/* This device was not set to transmit,
+                         * go to next 
+			 */
+			dev = move_dev_to_next(card,dev);
+		}	
+
+		if (++i == card->u.x.no_dev){
+			if (!more_to_tx){
+				DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n",
+					card->devname);
+			}
+			break;
+		}
+
+	} //End of FOR
+
+	card->u.x.tx_dev = dev;
+	
+	if (!more_to_tx){
+		/* if any other interfaces have transmit interrupts pending, */
+		/* do not disable the global transmit interrupt */
+		if (!(--card->u.x.tx_interrupts_pending)){
+			status->imask &= ~INTR_ON_TX_FRAME;
+		}
+	}
+	return;
+}
+
+/*===============================================================
+ * move_dev_to_next
+ *  
+ *
+ *===============================================================*/
+
+
+netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
+{
+	if (card->u.x.no_dev != 1){
+		if (*((netdevice_t**)dev->priv) == NULL){
+			return card->wandev.dev;
+		}else{
+			return *((netdevice_t**)dev->priv);
+		}
+	}
+	return dev;
+}
+
+/*===============================================================
+ *  tx_intr_send
+ *  
+ *
+ *===============================================================*/
+
+static int tx_intr_send(sdla_t *card, netdevice_t *dev)
+{
+	x25_channel_t* chan = dev->priv; 
+
+	if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){
+		 
+                /* Packet was split up due to its size, do not disable
+                 * tx_intr 
+                 */
+		return 1;
+	}
+
+	chan->transmit_length=0;
+	atomic_set(&chan->common.driver_busy,0);
+	chan->tx_offset=0;
+
+	/* If we are in API mode, wakeup the 
+         * sock BH handler, not the NET_BH */
+	if (is_queue_stopped(dev)){
+		if (chan->common.usedby == API){
+			start_net_queue(dev);
+			wakeup_sk_bh(dev);
+		}else{
+			wake_net_dev(dev);
+		}
+	}
+	return 0;
+}
+
+
+/*===============================================================
+ * timer_intr
+ *  
+ * 	Timer interrupt handler.
+ *	Check who called the timer interrupt and perform
+ *      action accordingly.
+ *
+ *===============================================================*/
+
+static void timer_intr (sdla_t *card)
+{
+	TX25Status* status = card->flags;
+
+	if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){
+
+		if (timer_intr_cmd_exec(card) == 0){
+			card->u.x.timer_int_enabled &=
+				~TMR_INT_ENABLED_CMD_EXEC;
+		}
+
+	}else  if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) {
+
+		if ((*card->u.x.hdlc_buf_status & 0x40) && 
+		    card->u.x.udp_type == UDP_XPIPE_TYPE){
+
+                    	if(process_udp_mgmt_pkt(card)) {
+		                card->u.x.timer_int_enabled &= 
+					~TMR_INT_ENABLED_UDP_PKT;
+			}
+		}
+
+	}else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) {
+
+		netdevice_t *dev = card->u.x.poll_device;
+		x25_channel_t *chan = NULL;
+
+		if (!dev){
+			card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE;
+			return;
+		}
+		chan = dev->priv;
+
+		printk(KERN_INFO 
+			"%s: Closing down Idle link %s on LCN %d\n",
+					card->devname,chan->name,chan->common.lcn); 
+		chan->i_timeout_sofar = jiffies;
+		chan_disc(dev);	
+         	card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE;
+		card->u.x.poll_device=NULL;
+
+	}else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) {
+
+		wanpipe_set_state(card, WAN_CONNECTED);
+		if (card->u.x.LAPB_hdlc){
+			netdevice_t *dev = card->wandev.dev;
+			set_chan_state(dev,WAN_CONNECTED);
+			send_delayed_cmd_result(card,dev,card->mbox);	
+		}
+
+		/* 0x8F enable all interrupts */
+		x25_set_intr_mode(card, INTR_ON_RX_FRAME|	
+					INTR_ON_TX_FRAME|
+					INTR_ON_MODEM_STATUS_CHANGE|
+					//INTR_ON_COMMAND_COMPLETE|
+					X25_ASY_TRANS_INTR_PENDING |
+					INTR_ON_TIMER |
+					DIRECT_RX_INTR_USAGE
+				); 
+
+		status->imask &= ~INTR_ON_TX_FRAME;	/* mask Tx interrupts */
+		card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON;
+
+	}else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) {
+
+		//printk(KERN_INFO "Poll connect, Turning OFF\n");
+		disconnect(card);
+		card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF;
+
+	}else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) {
+
+		//printk(KERN_INFO "POll disconnect, trying to connect\n");
+		connect(card);
+		card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT;
+
+	}else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){
+
+		if (*card->u.x.hdlc_buf_status & 0x40){
+			x25_get_err_stats(card);
+			x25_get_stats(card);
+			card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
+		}
+	}
+
+	if(!card->u.x.timer_int_enabled){
+		//printk(KERN_INFO "Turning Timer Off \n");
+                status->imask &= ~INTR_ON_TIMER;	
+	}
+}
+
+/*====================================================================
+ * 	Modem status interrupt handler.
+ *===================================================================*/
+static void status_intr (sdla_t* card)
+{
+
+	/* Added to avoid Modem status message flooding */
+	static TX25ModemStatus last_stat;
+
+	TX25Mbox* mbox = card->mbox;
+	TX25ModemStatus *modem_status;
+	netdevice_t *dev;
+	x25_channel_t *chan;
+	int err;
+
+	memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+	mbox->cmd.command = X25_READ_MODEM_STATUS;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	if (err){ 
+		x25_error(card, err, X25_READ_MODEM_STATUS, 0);
+	}else{
+	
+		modem_status = (TX25ModemStatus*)mbox->data;	
+	
+           	/* Check if the last status was the same
+           	 * if it was, do NOT print message again */
+	
+		if (last_stat.status != modem_status->status){
+
+	     		printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n",
+				card->devname,DCD(modem_status->status),CTS(modem_status->status));
+
+			last_stat.status = modem_status->status;
+		
+			if (card->u.x.oob_on_modem){
+
+				mbox->cmd.pktType = mbox->cmd.command;
+				mbox->cmd.result = 0x08;
+
+				/* Send a OOB to all connected sockets */
+				for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){
+					chan=dev->priv;
+					if (chan->common.usedby == API){
+						send_oob_msg(card,dev,mbox);				
+					}
+				}
+
+				/* The modem OOB message will probably kill the
+				 * the link. If we don't clear the flag here,
+				 * a deadlock could occur */ 
+				if (atomic_read(&card->u.x.command_busy)){
+					atomic_set(&card->u.x.command_busy,0);
+				}
+			}
+		}
+	}
+
+	memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+	mbox->cmd.command = X25_HDLC_LINK_STATUS;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	if (err){ 
+		x25_error(card, err, X25_HDLC_LINK_STATUS, 0);
+	}
+
+}
+
+/*====================================================================
+ * 	Network event interrupt handler.
+ *===================================================================*/
+static void event_intr (sdla_t* card)
+{
+	x25_fetch_events(card);
+}
+
+/*====================================================================
+ * 	Spurious interrupt handler.
+ * 	o print a warning
+ * 	o	 
+ *====================================================================*/
+
+static void spur_intr (sdla_t* card)
+{
+	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+}
+
+
+/*
+ *	Background Polling Routines  
+ */
+
+/*====================================================================
+ * 	Main polling routine.
+ * 	This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * 	time-dependent housekeeping work.
+ *
+ * 	Notes:
+ * 	1. This routine may be called on interrupt context with all interrupts
+ *    	enabled. Beware!
+ *====================================================================*/
+
+static void wpx_poll (sdla_t *card)
+{
+	if (!card->wandev.dev){
+		goto wpx_poll_exit;
+	}
+
+	if (card->open_cnt != card->u.x.num_of_ch){
+		goto wpx_poll_exit;
+	}
+	
+	if (test_bit(PERI_CRIT,&card->wandev.critical)){
+		goto wpx_poll_exit;
+	}
+
+	if (test_bit(SEND_CRIT,&card->wandev.critical)){
+		goto wpx_poll_exit;
+	}
+
+	switch(card->wandev.state){
 		case WAN_CONNECTED:
 			poll_active(card);
 			break;
@@ -1132,104 +2331,172 @@
 
 		case WAN_DISCONNECTED:
 			poll_disconnected(card);
+			break;
 	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-        cli();
-        if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
-                enable_irq(card->hw.irq);
-        restore_flags(host_cpu_flags);
+
+wpx_poll_exit:
+	clear_bit(POLL_CRIT,&card->wandev.critical);
+	return;
 }
 
-/*============================================================================
- * Handle physical link establishment phase.
- * o if connection timed out, disconnect the link.
- */
+static void trigger_x25_poll(sdla_t *card)
+{
+#ifdef LINUX_2_4
+	schedule_task(&card->u.x.x25_poll_task);
+#else
+	queue_task(&card->u.x.x25_poll_task, &tq_scheduler);
+#endif
+}
+
+/*====================================================================
+ * 	Handle physical link establishment phase.
+ * 	o if connection timed out, disconnect the link.
+ *===================================================================*/
+
 static void poll_connecting (sdla_t* card)
 {
-	TX25Status* status = card->flags;
+	volatile TX25Status* status = card->flags;
+
+	if (status->gflags & X25_HDLC_ABM){
+
+		timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON);
+
+	}else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){
+
+		timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF);
 
-	if (status->gflags & X25_HDLC_ABM)
-	{
-		wanpipe_set_state(card, WAN_CONNECTED);
-		x25_set_intr_mode(card, 0x83);	/* enable Rx interrupts */
-		status->imask &= ~0x2;		/* mask Tx interrupts */
 	}
-	else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
-	    disconnect(card);
 }
 
-/*============================================================================
- * Handle physical link disconnected phase.
- * o if hold-down timeout has expired and there are open interfaces, connect
- *   link.
- */
+/*====================================================================
+ * 	Handle physical link disconnected phase.
+ * 	o if hold-down timeout has expired and there are open interfaces, 
+ *	connect link.
+ *===================================================================*/
+
 static void poll_disconnected (sdla_t* card)
 {
-	if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
-		connect(card);
+	netdevice_t *dev; 
+	x25_channel_t *chan;
+	TX25Status* status = card->flags;
+
+	if (!card->u.x.LAPB_hdlc && card->open_cnt && 
+	    ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){
+		timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT);
+	}
+
+
+	if ((dev=card->wandev.dev) == NULL)
+		return;
+
+	if ((chan=dev->priv) == NULL)
+		return;
+
+	if (chan->common.usedby == API && 
+	    atomic_read(&chan->common.command) && 
+	    card->u.x.LAPB_hdlc){
+
+		if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) 
+			card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
+
+		if (!(status->imask & INTR_ON_TIMER))
+			status->imask |= INTR_ON_TIMER;
+	}	
+
 }
 
-/*============================================================================
- * Handle active link phase.
- * o fetch X.25 asynchronous events.
- * o kick off transmission on all interfaces.
- */
+/*====================================================================
+ * 	Handle active link phase.
+ * 	o fetch X.25 asynchronous events.
+ * 	o kick off transmission on all interfaces.
+ *===================================================================*/
+
 static void poll_active (sdla_t* card)
 {
-	struct net_device* dev;
-
-	/* Fetch X.25 asynchronous events */
-	x25_fetch_events(card);
+	netdevice_t* dev;
+	TX25Status* status = card->flags;
 
-	dev = card->wandev.dev;
-	while (dev) {
+	for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){
 		x25_channel_t* chan = dev->priv;
-		struct sk_buff* skb = chan->tx_skb;
-
-		/* If there is a packet queued for transmission then kick
-		 * the channel's send routine. When transmission is complete
-		 * or if error has occurred, release socket buffer and reset
-		 * 'tbusy' flag.
-		 */
-		if (skb && (chan_send(dev, skb) == 0))
-		{
-			chan->tx_skb = NULL;
-			dev->tbusy = 0;
-			dev_kfree_skb(skb);
-		}
 
 		/* If SVC has been idle long enough, close virtual circuit */
-
-		if(( chan->svc )&&( chan->state == WAN_CONNECTED ))
-		{
-			if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout )
-			{
+		if ( chan->common.svc && 
+		     chan->common.state == WAN_CONNECTED &&
+		     chan->common.usedby == WANPIPE ){
+		
+			if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){
 				/* Close svc */
-				printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); 
-				chan->i_timeout_sofar = jiffies;
-				chan_disc(dev);
+				card->u.x.poll_device=dev;
+				timer_intr_exec	(card, TMR_INT_ENABLED_POLL_ACTIVE);
 			}
 		}
 
-		dev = chan->slave;
+#ifdef PRINT_DEBUG
+		chan->ifstats.tx_compressed = atomic_read(&chan->common.command);
+		chan->ifstats.tx_errors = chan->common.state;
+		chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy);
+		++chan->ifstats.tx_bytes;
+
+		chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect);
+		chan->ifstats.multicast=atomic_read(&chan->bh_buff_used);
+		chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status;
+#endif	
+
+		if (chan->common.usedby == API && 
+		    atomic_read(&chan->common.command) && 
+	            !card->u.x.LAPB_hdlc){
+
+			if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) 
+				card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
+
+			if (!(status->imask & INTR_ON_TIMER))
+				status->imask |= INTR_ON_TIMER;
+		}	
+
+		if ((chan->common.usedby == API) && 
+		     atomic_read(&chan->common.disconnect)){
+
+			if (chan->common.state == WAN_DISCONNECTED){
+				atomic_set(&chan->common.disconnect,0);
+				return;
+			}
+
+			atomic_set(&chan->common.command,X25_CLEAR_CALL);
+			if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) 
+				card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
+
+			if (!(status->imask & INTR_ON_TIMER))
+				status->imask |= INTR_ON_TIMER;
+		}
 	}
 }
 
-/****** SDLA Firmware-Specific Functions *************************************
- * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
- * asynchronous events' such as restart, interrupt, incoming call request,
- * call clear request, etc.  They can't be ignored and have to be dealt with
- * immediately.  To tackle with this problem we execute each interface command
- * in a loop until good return code is received or maximum number of retries
- * is reached.  Each interface command returns non-zero return code, an
- * asynchronous event/error handler x25_error() is called.
- */
+static void timer_intr_exec(sdla_t *card, unsigned char TYPE)
+{
+	TX25Status* status = card->flags;
+	card->u.x.timer_int_enabled |= TYPE;
+	if (!(status->imask & INTR_ON_TIMER))
+		status->imask |= INTR_ON_TIMER;
+}
+
+
+/*==================================================================== 
+ * SDLA Firmware-Specific Functions 
+ *
+ *  Almost all X.25 commands can unexpetedly fail due to so called 'X.25
+ *  asynchronous events' such as restart, interrupt, incoming call request,
+ *  call clear request, etc.  They can't be ignored and have to be delt with
+ *  immediately.  To tackle with this problem we execute each interface 
+ *  command in a loop until good return code is received or maximum number 
+ *  of retries is reached.  Each interface command returns non-zero return 
+ *  code, an asynchronous event/error handler x25_error() is called.
+ *====================================================================*/
+
+/*====================================================================
+ * 	Read X.25 firmware version.
+ *		Put code version as ASCII string in str. 
+ *===================================================================*/
 
-/*============================================================================
- * Read X.25 firmware version.
- *	Put code version as ASCII string in str. 
- */
 static int x25_get_version (sdla_t* card, char* str)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1247,15 +2514,16 @@
 	if (!err && str)
 	{
 		int len = mbox->cmd.length;
+
 		memcpy(str, mbox->data, len);
 		str[len] = '\0';
 	}
 	return err;
 }
 
-/*============================================================================
- * Configure adapter.
- */
+/*====================================================================
+ * 	Configure adapter.
+ *===================================================================*/
 
 static int x25_configure (sdla_t* card, TX25Config* conf)
 {
@@ -1263,8 +2531,7 @@
   	int retry = MAX_CMD_RETRY;
 	int err;
 
-	do
-	{
+	do{
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
 		memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
 		mbox->cmd.length  = sizeof(TX25Config);
@@ -1274,9 +2541,51 @@
 	return err;
 }
 
-/*============================================================================
+/*====================================================================
+ * 	Configure adapter for HDLC only.
+ *===================================================================*/
+
+static int hdlc_configure (sdla_t* card, TX25Config* conf)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
+		mbox->cmd.length  = sizeof(TX25Config);
+		mbox->cmd.command = X25_HDLC_SET_CONFIG;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
+
+	return err;
+}
+
+static int set_hdlc_level (sdla_t* card)
+{
+
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = SET_PROTOCOL_LEVEL;
+		mbox->cmd.length = 1;
+		mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; 	
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0));
+
+	return err;
+}
+
+
+
+/*====================================================================
  * Get communications error statistics.
- */
+ *====================================================================*/
+
 static int x25_get_err_stats (sdla_t* card)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1289,7 +2598,7 @@
 		mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0));
-
+	
 	if (!err)
 	{
 		THdlcCommErr* stats = (void*)mbox->data;
@@ -1302,9 +2611,10 @@
 	return err;
 }
 
-/*============================================================================
- * Get protocol statistics.
- */
+/*====================================================================
+ * 	Get protocol statistics.
+ *===================================================================*/
+
 static int x25_get_stats (sdla_t* card)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1316,21 +2626,22 @@
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
 		mbox->cmd.command = X25_READ_STATISTICS;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0));
+	} while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ;
 	
 	if (!err)
 	{
 		TX25Stats* stats = (void*)mbox->data;
 
 		card->wandev.stats.rx_packets = stats->rxData;
-		card->wandev.stats.tx_packets = stats->rxData;
+		card->wandev.stats.tx_packets = stats->txData;
 	}
 	return err;
 }
 
-/*============================================================================
- * Close HDLC link.
- */
+/*====================================================================
+ * 	Close HDLC link.
+ *===================================================================*/
+
 static int x25_close_hdlc (sdla_t* card)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1343,13 +2654,15 @@
 		mbox->cmd.command = X25_HDLC_LINK_CLOSE;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0));
-
+	
 	return err;
 }
 
-/*============================================================================
- * Open HDLC link.
- */
+
+/*====================================================================
+ * 	Open HDLC link.
+ *===================================================================*/
+
 static int x25_open_hdlc (sdla_t* card)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1362,13 +2675,13 @@
 		mbox->cmd.command = X25_HDLC_LINK_OPEN;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0));
-	
+
 	return err;
 }
 
-/*============================================================================
+/*=====================================================================
  * Setup HDLC link.
- */
+ *====================================================================*/
 static int x25_setup_hdlc (sdla_t* card)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1385,9 +2698,10 @@
 	return err;
 }
 
-/*============================================================================
+/*====================================================================
  * Set (raise/drop) DTR.
- */
+ *===================================================================*/
+
 static int x25_set_dtr (sdla_t* card, int dtr)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1404,13 +2718,14 @@
 		mbox->cmd.command = X25_SET_GLOBAL_VARS;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0));
-
+	
 	return err;
 }
 
-/*============================================================================
- * Set interrupt mode.
- */
+/*====================================================================
+ * 	Set interrupt mode.
+ *===================================================================*/
+
 static int x25_set_intr_mode (sdla_t* card, int mode)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1421,30 +2736,32 @@
 	{
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
 		mbox->data[0] = mode;
-		if (card->hw.fwid == SFID_X25_508)
-		{
+		if (card->hw.fwid == SFID_X25_508){
 			mbox->data[1] = card->hw.irq;
-			mbox->cmd.length = 2;
+			mbox->data[2] = 2;
+			mbox->cmd.length = 3;
+		}else {
+		 	mbox->cmd.length  = 1;
 		}
-		else mbox->cmd.length  = 1;
 		mbox->cmd.command = X25_SET_INTERRUPT_MODE;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ;
+	} while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0));
+	
 	return err;
 }
 
-/*============================================================================
- * Read X.25 channel configuration.
- */
+/*====================================================================
+ * 	Read X.25 channel configuration.
+ *===================================================================*/
+
 static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
 {
 	TX25Mbox* mbox = card->mbox;
   	int retry = MAX_CMD_RETRY;
-	int lcn = chan->lcn;
+	int lcn = chan->common.lcn;
 	int err;
 
-	do
-	{
+	do{
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
 		mbox->cmd.lcn     = lcn;
 		mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
@@ -1456,19 +2773,25 @@
 		TX25Status* status = card->flags;
 
 		/* calculate an offset into the array of status bytes */
-		if (card->u.x.hi_svc <= 255) 
+		if (card->u.x.hi_svc <= X25_MAX_CHAN){ 
+
 			chan->ch_idx = lcn - 1;
-		else
-		{
+
+		}else{
 			int offset;
 
-			switch (mbox->data[0] && 0x1F)
+			/* FIX: Apr 14 2000 : Nenad Corbic
+			 * The data field was being compared to 0x1F using
+                         * '&&' instead of '&'. 
+			 * This caused X25API to fail for LCNs greater than 255.
+			 */
+			switch (mbox->data[0] & 0x1F)
 			{
-				case 0x01:
+				case 0x01: 
 					offset = status->pvc_map; break;
-				case 0x03:
+				case 0x03: 
 					offset = status->icc_map; break;
-				case 0x07:
+				case 0x07: 
 					offset = status->twc_map; break;
 				case 0x0B: 
 					offset = status->ogc_map; break;
@@ -1481,37 +2804,38 @@
 		/* get actual transmit packet size on this channel */
 		switch(mbox->data[1] & 0x38)
 		{
-			case 0x00:
-				chan->tx_pkt_size = 16;
+			case 0x00: 
+				chan->tx_pkt_size = 16; 
 				break;
-			case 0x08:
-				chan->tx_pkt_size = 32;
+			case 0x08: 
+				chan->tx_pkt_size = 32; 
 				break;
-			case 0x10:
-				chan->tx_pkt_size = 64;
+			case 0x10: 
+				chan->tx_pkt_size = 64; 
 				break;
-			case 0x18:
-				chan->tx_pkt_size = 128;
+			case 0x18: 
+				chan->tx_pkt_size = 128; 
 				break;
-			case 0x20:
-				chan->tx_pkt_size = 256;
+			case 0x20: 
+				chan->tx_pkt_size = 256; 
 				break;
-			case 0x28:
-				chan->tx_pkt_size = 512;
+			case 0x28: 
+				chan->tx_pkt_size = 512; 
 				break;
-			case 0x30:
-				chan->tx_pkt_size = 1024;
+			case 0x30: 
+				chan->tx_pkt_size = 1024; 
 				break;
 		}
-		printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
-			card->devname, lcn, chan->tx_pkt_size);
+		if (card->u.x.logging)
+			printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
+				card->devname, lcn, chan->tx_pkt_size);
 	}
 	return err;
 }
 
-/*============================================================================
- * Place X.25 call.
- */
+/*====================================================================
+ * 	Place X.25 call.
+ *====================================================================*/
 
 static int x25_place_call (sdla_t* card, x25_channel_t* chan)
 {
@@ -1520,7 +2844,15 @@
 	int err;
 	char str[64];
 
-	sprintf(str, "-d%s -uCC", chan->addr);
+
+	if (chan->protocol == htons(ETH_P_IP)){
+		sprintf(str, "-d%s -uCC", chan->addr);
+	
+	}else if (chan->protocol == htons(ETH_P_IPX)){
+		sprintf(str, "-d%s -u800000008137", chan->addr);
+	
+	}
+	
 	do
 	{
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
@@ -1530,17 +2862,15 @@
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0));
 
-	if (!err)
-	{
-		chan->lcn = mbox->cmd.lcn;
-		chan->protocol = ETH_P_IP;
+	if (!err){
+		bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn);
 	}
 	return err;
 }
 
-/*============================================================================
- * Accept X.25 call.
- */
+/*====================================================================
+ * 	Accept X.25 call.
+ *====================================================================*/
 
 static int x25_accept_call (sdla_t* card, int lcn, int qdm)
 {
@@ -1556,13 +2886,14 @@
 		mbox->cmd.command = X25_ACCEPT_CALL;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn));
-
+	
 	return err;
 }
 
-/*============================================================================
- * Clear X.25 call.
- */
+/*====================================================================
+ * 	Clear X.25 call.
+ *====================================================================*/
+
 static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
 {
 	TX25Mbox* mbox = card->mbox;
@@ -1578,35 +2909,59 @@
 		mbox->cmd.command = X25_CLEAR_CALL;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn));
-
+	
 	return err;
 }
 
-/*============================================================================
- * Send X.25 data packet.
- */
+/*====================================================================
+ * 	Send X.25 data packet.
+ *====================================================================*/
+
 static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
 {
 	TX25Mbox* mbox = card->mbox;
   	int retry = MAX_CMD_RETRY;
 	int err;
-	
+	unsigned char cmd;
+		
+	if (card->u.x.LAPB_hdlc)
+		cmd = X25_HDLC_WRITE;
+	else
+		cmd = X25_WRITE;
+
 	do
 	{
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
 		memcpy(mbox->data, buf, len);
 		mbox->cmd.length  = len;
 		mbox->cmd.lcn     = lcn;
-		mbox->cmd.qdm     = qdm;
-		mbox->cmd.command = X25_WRITE;
+
+		if (card->u.x.LAPB_hdlc){
+			mbox->cmd.pf = qdm;
+		}else{			
+			mbox->cmd.qdm = qdm;
+		}
+
+		mbox->cmd.command = cmd;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	} while (err && retry-- && x25_error(card, err, X25_WRITE, lcn));
+	} while (err && retry-- && x25_error(card, err, cmd , lcn));
+
+
+	/* If buffers are busy the return code for LAPB HDLC is
+         * 1. The above functions are looking for return code
+         * of X25RES_NOT_READY if busy. */
+
+	if (card->u.x.LAPB_hdlc && err == 1){
+		err = X25RES_NOT_READY;
+	}
+
 	return err;
 }
 
-/*============================================================================
- * Fetch X.25 asynchronous events.
- */
+/*====================================================================
+ * 	Fetch X.25 asynchronous events.
+ *===================================================================*/
+
 static int x25_fetch_events (sdla_t* card)
 {
 	TX25Status* status = card->flags;
@@ -1618,25 +2973,26 @@
 		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
 		mbox->cmd.command = X25_IS_DATA_AVAILABLE;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- 		if (err)
- 			x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
+ 		if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
 	}
 	return err;
 }
 
-/*============================================================================
- * X.25 asynchronous event/error handler.
- *	This routine is called each time interface command returns non-zero
- *	return code to handle X.25 asynchronous events and common errors.
- *	Return non-zero to repeat command or zero to cancel it.
- *
- * Notes:
- * 1. This function may be called recursively, as handling some of the
- *    asynchronous events (e.g. call request) requires execution of the
- *    interface command(s) that, in turn, may also return asynchronous
- *    events.  To avoid re-entrancy problems we copy mailbox to dynamically
- *    allocated memory before processing events.
- */
+/*====================================================================
+ * 	X.25 asynchronous event/error handler.
+ *		This routine is called each time interface command returns 
+ *		non-zero return code to handle X.25 asynchronous events and 
+ *		common errors. Return non-zero to repeat command or zero to 
+ *		cancel it.
+ *
+ * 	Notes:
+ * 	1. This function may be called recursively, as handling some of the
+ *    	asynchronous events (e.g. call request) requires execution of the
+ *    	interface command(s) that, in turn, may also return asynchronous
+ *    	events.  To avoid re-entrancy problems we copy mailbox to dynamically
+ *    	allocated memory before processing events.
+ *====================================================================*/
+
 static int x25_error (sdla_t* card, int err, int cmd, int lcn)
 {
 	int retry = 1;
@@ -1651,138 +3007,212 @@
 		return 0;
 	}
 	memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
-	switch (err)
-	{
-		case 0x40:	/* X.25 asynchronous packet was received */
-			mb->data[dlen] = '\0';
-			switch (mb->cmd.pktType & 0x7F)
-			{
-				case 0x30:		/* incoming call */
-					retry = incoming_call(card, cmd, lcn, mb);
-					break;
-
-				case 0x31:		/* connected */
-					retry = call_accepted(card, cmd, lcn, mb);
-					break;
+	switch (err){
 
-				case 0x02:		/* call clear request */
-					retry = call_cleared(card, cmd, lcn, mb);
-					break;
+	case X25RES_ASYNC_PACKET:	/* X.25 asynchronous packet was received */
 
-				case 0x04:		/* reset request */
-					printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
-						"Cause:0x%02X Diagn:0x%02X\n",
-						card->devname, mb->cmd.lcn, mb->cmd.cause,
-						mb->cmd.diagn);
-					break;
+		mb->data[dlen] = '\0';
 
-				case 0x08:		/* restart request */
-					retry = restart_event(card, cmd, lcn, mb);
-					break;
+		switch (mb->cmd.pktType & 0x7F){
 
-				default:
-					printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
-						"Cause:0x%02X Diagn:0x%02X\n",
-						card->devname, mb->cmd.pktType,
-						mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn);
-			}
+		case ASE_CALL_RQST:		/* incoming call */
+			retry = incoming_call(card, cmd, lcn, mb);
 			break;
 
-		case 0x41:	/* X.25 protocol violation indication */
-			printk(KERN_INFO
-				"%s: X.25 protocol violation on LCN %d! "
-				"Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
-				card->devname, mb->cmd.lcn,
-				mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn);
+		case ASE_CALL_ACCEPTED:		/* connected */
+			retry = call_accepted(card, cmd, lcn, mb);
 			break;
 
-		case 0x42:	/* X.25 timeout */
-			retry = timeout_event(card, cmd, lcn, mb);
+		case ASE_CLEAR_RQST:		/* call clear request */
+			retry = call_cleared(card, cmd, lcn, mb);
 			break;
 
-		case 0x43:	/* X.25 retry limit exceeded */
-			printk(KERN_INFO
-				"%s: exceeded X.25 retry limit on LCN %d! "
-				"Packet:0x%02X Diagn:0x%02X\n", card->devname,
-				mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn);
+		case ASE_RESET_RQST:		/* reset request */
+			printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
+				"Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.lcn, mb->cmd.cause,
+				mb->cmd.diagn);
+			api_oob_event (card,mb);
 			break;
 
-		case 0x08:	/* modem failure */
-			printk(KERN_INFO "%s: modem failure!\n", card->devname);
+		case ASE_RESTART_RQST:		/* restart request */
+			retry = restart_event(card, cmd, lcn, mb);
 			break;
 
-		case 0x09:	/* N2 retry limit */
-			printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
-				card->devname);
+		case ASE_CLEAR_CONFRM:
+			if (clear_confirm_event (card,mb))
+				break;
+
+			/* I use the goto statement here so if 
+	                 * somebody inserts code between the
+        	         * case and default, we will not have
+                	 * ghost problems */
+
+			goto dflt_1;
+
+		default:
+dflt_1:
+			printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
+				"Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.pktType,
+				mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn);
+		}
+		break;
+
+	case X25RES_PROTO_VIOLATION:	/* X.25 protocol violation indication */
+
+		/* Bug Fix: Mar 14 2000
+                 * The Protocol violation error conditions were  
+                 * not handeled previously */
+
+		switch (mb->cmd.pktType & 0x7F){
+
+		case PVE_CLEAR_RQST:	/* Clear request */		
+			retry = call_cleared(card, cmd, lcn, mb);
+			break;	
+
+		case PVE_RESET_RQST:	/* Reset request */
+			printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
+				"Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.lcn, mb->cmd.cause,
+				mb->cmd.diagn);
+			api_oob_event (card,mb);
 			break;
 
-		case 0x06:	/* unnumbered frame was received while in ABM */
-			printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
-				card->devname, mb->data[0]);
+		case PVE_RESTART_RQST:	/* Restart request */
+			retry = restart_event(card, cmd, lcn, mb);
 			break;
 
-		case CMD_TIMEOUT:
-			printk(KERN_ERR "%s: command 0x%02X timed out!\n",
-				card->devname, cmd);
-			retry = 0;	/* abort command */
+		default :
+			printk(KERN_INFO
+				"%s: X.25 protocol violation on LCN %d! "
+				"Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
+				card->devname, mb->cmd.lcn,
+				mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn);
+			api_oob_event(card,mb);
+		}
+		break;
+
+	case 0x42:	/* X.25 timeout */
+		retry = timeout_event(card, cmd, lcn, mb);
+		break;
+
+	case 0x43:	/* X.25 retry limit exceeded */
+		printk(KERN_INFO
+			"%s: exceeded X.25 retry limit on LCN %d! "
+			"Packet:0x%02X Diagn:0x%02X\n", card->devname,
+			mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn)
+		;
+		break;
+
+	case 0x08:	/* modem failure */
+#ifndef MODEM_NOT_LOG
+		printk(KERN_INFO "%s: modem failure!\n", card->devname);
+#endif MODEM_NOT_LOG
+		api_oob_event(card,mb);
+		break;
+
+	case 0x09:	/* N2 retry limit */
+		printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
+			card->devname);
+		api_oob_event(card,mb);
+		break;
+
+	case 0x06:	/* unnumbered frame was received while in ABM */
+		printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
+			card->devname, mb->data[0]);
+		api_oob_event(card,mb);
+		break;
+
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, cmd)
+		;
+		retry = 0;	/* abort command */
+		break;
+
+	case X25RES_NOT_READY:
+		retry = 1;
+		break;
+
+	case 0x01:
+		if (card->u.x.LAPB_hdlc)
 			break;
 
-		default:
-			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
-				card->devname, cmd, err);
-			retry = 0;	/* abort command */
+		if (mb->cmd.command == 0x16)
+			break;
+		/* I use the goto statement here so if 
+                 * somebody inserts code between the
+                 * case and default, we will not have
+                 * ghost problems */
+		goto dflt_2;
+
+	default:
+dflt_2:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n",
+			card->devname, cmd, err, mb->cmd.lcn)
+		;
+		retry = 0;	/* abort command */
 	}
 	kfree(mb);
 	return retry;
 }
 
-/****** X.25 Asynchronous Event Handlers *************************************
- * These functions are called by the x25_error() and should return 0, if
- * the command resulting in the asynchronous event must be aborted.
- */
+/*==================================================================== 
+ *	X.25 Asynchronous Event Handlers
+ * 	These functions are called by the x25_error() and should return 0, if
+ * 	the command resulting in the asynchronous event must be aborted.
+ *====================================================================*/
 
-/*============================================================================
- * Handle X.25 incoming call request.
+
+
+/*====================================================================
+ *Handle X.25 incoming call request.
  *	RFC 1356 establishes the following rules:
  *	1. The first octet in the Call User Data (CUD) field of the call
- *	   request packet contains NLPID identifying protocol encapsulation.
- *	2. Calls MUST NOT be accepted unless router supports requested
- *	   protocol encapsulation.
- *	3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when
- *	   clearing a call because protocol encapsulation is not supported.
- *	4. If an incoming call is received while a call request is pending
- *	   (i.e. call collision has occurred), the incoming call shall be
- *	   rejected and call request shall be retried.
- */
+ *     	   request packet contains NLPID identifying protocol encapsulation
+ * 	2. Calls MUST NOT be accepted unless router supports requested
+ *   	   protocol encapsulation.
+ *	3. A diagnostic code 249 defined by ISO/IEC 8208 may be used 
+ *	   when clearing a call because protocol encapsulation is not 
+ *	   supported.
+ *	4. If an incoming call is received while a call request is 
+ *	   pending (i.e. call collision has occured), the incoming call 
+ *	   shall be rejected and call request shall be retried.
+ *====================================================================*/
 
 static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	wan_device_t* wandev = &card->wandev;
 	int new_lcn = mb->cmd.lcn;
-	struct net_device* dev = get_dev_by_lcn(wandev, new_lcn);
+	netdevice_t* dev = get_dev_by_lcn(wandev, new_lcn);
 	x25_channel_t* chan = NULL;
 	int accept = 0;		/* set to '1' if o.k. to accept call */
+	unsigned int user_data;
 	x25_call_info_t* info;
-
+	
 	/* Make sure there is no call collision */
 	if (dev != NULL)
 	{
 		printk(KERN_INFO
 			"%s: X.25 incoming call collision on LCN %d!\n",
 			card->devname, new_lcn);
+
 		x25_clear_call(card, new_lcn, 0, 0);
 		return 1;
 	}
 
 	/* Make sure D bit is not set in call request */
-	if (mb->cmd.qdm & 0x02)
-	{
-		printk(KERN_INFO
-			"%s: X.25 incoming call on LCN %d with D-bit set!\n",
-			card->devname, new_lcn);
-		x25_clear_call(card, new_lcn, 0, 0);
-		return 1;
-	}
+//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT
+//	if (mb->cmd.qdm & 0x02)
+//	{
+//		printk(KERN_INFO
+//			"%s: X.25 incoming call on LCN %d with D-bit set!\n",
+//			card->devname, new_lcn);
+//
+//		x25_clear_call(card, new_lcn, 0, 0);
+//		return 1;
+//	}
 
 	/* Parse call request data */
 	info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC);
@@ -1794,90 +3224,120 @@
 		x25_clear_call(card, new_lcn, 0, 0);
 		return 1;
 	}
+ 
 	parse_call_info(mb->data, info);
-	printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n",
-		card->devname, new_lcn, mb->data);
+
+	if (card->u.x.logging)
+		printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n",
+			card->devname, new_lcn);
+
+	/* Conver the first two ASCII characters into an
+         * interger. Used to check the incoming protocol 
+         */
+	user_data = hex_to_uint(info->user,2);
 
 	/* Find available channel */
-	dev = wandev->dev;
-	while (dev) {
+	for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){
 		chan = dev->priv;
 
-		if (!chan->svc || (chan->state != WAN_DISCONNECTED))
+		if (chan->common.usedby == API)
+			continue;
+
+		if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED))
+			continue;
+
+		if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){
+			printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n",
+				       htons(chan->protocol), info->user[0]);
+			continue;
+		}
+	
+		if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){
+			printk(KERN_INFO "IPX packet but configured for IP: %x\n",
+				       htons(chan->protocol));
 			continue;
+		}
 		if (strcmp(info->src, chan->addr) == 0)
 			break;
+
 	        /* If just an '@' is specified, accept all incoming calls */
 	        if (strcmp(chan->addr, "") == 0)
 	                break;
-
-		dev = chan->slave;
 	}
 
-	if (dev == NULL)
-	{
-		printk(KERN_INFO "%s: no channels available!\n",
-			card->devname);
-		x25_clear_call(card, new_lcn, 0, 0);
-	}
+	if (dev == NULL){
+
+		/* If the call is not for any WANPIPE interfaces
+                 * check to see if there is an API listening queue
+                 * waiting for data. If there is send the packet
+                 * up the stack.
+                 */
+		if (card->sk != NULL && card->func != NULL){
+			if (api_incoming_call(card,mb,new_lcn)){
+				x25_clear_call(card, new_lcn, 0, 0);
+			}
+			accept = 0;
+		}else{
+			printk(KERN_INFO "%s: no channels available!\n",
+				card->devname);
+			
+			x25_clear_call(card, new_lcn, 0, 0);
+		}
+
+	}else if (info->nuser == 0){
 
-	/* Check requested protocol encapsulation */
-	else if (info->nuser == 0)
-	{
 		printk(KERN_INFO
 			"%s: no user data in incoming call on LCN %d!\n",
-			card->devname, new_lcn);
+			card->devname, new_lcn)
+		;
 		x25_clear_call(card, new_lcn, 0, 0);
-	}
-	else switch (info->user[0])
-	{
+
+	}else switch (info->user[0]){
+
 		case 0:		/* multiplexed */
-			chan->protocol = 0;
+			chan->protocol = htons(0);
 			accept = 1;
 			break;
 
 		case NLPID_IP:	/* IP datagrams */
-			chan->protocol = ETH_P_IP;
 			accept = 1;
 			break;
 
 		case NLPID_SNAP: /* IPX datagrams */
-			chan->protocol = ETH_P_IPX;
 			accept = 1;
 			break;
+
 		default:
 			printk(KERN_INFO
 				"%s: unsupported NLPID 0x%02X in incoming call "
 				"on LCN %d!\n", card->devname, info->user[0], new_lcn);
 			x25_clear_call(card, new_lcn, 0, 249);
 	}
+	
+	if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){
 
-	if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK))
-	{
-		chan->lcn = new_lcn;
+		bind_lcn_to_dev (card, chan->dev, new_lcn);
+		
 		if (x25_get_chan_conf(card, chan) == CMD_OK)
 			set_chan_state(dev, WAN_CONNECTED);
-		else
+		else 
 			x25_clear_call(card, new_lcn, 0, 0);
 	}
 	kfree(info);
 	return 1;
 }
 
-/*============================================================================
- * Handle accepted call.
- */
+/*====================================================================
+ * 	Handle accepted call.
+ *====================================================================*/
 
 static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	unsigned new_lcn = mb->cmd.lcn;
-	struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+	netdevice_t* dev = find_channel(card, new_lcn);
 	x25_channel_t* chan;
 
-	printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n",
-		card->devname, new_lcn);
-	if (dev == NULL)
-	{
+	if (dev == NULL){
 		printk(KERN_INFO
 			"%s: clearing orphaned connection on LCN %d!\n",
 			card->devname, new_lcn);
@@ -1885,6 +3345,10 @@
 		return 1;
 	}
 
+	if (card->u.x.logging)	
+		printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n",
+			card->devname, dev->name, new_lcn);
+
 	/* Get channel configuration and notify router */
 	chan = dev->priv;
 	if (x25_get_chan_conf(card, chan) != CMD_OK)
@@ -1892,178 +3356,256 @@
 		x25_clear_call(card, new_lcn, 0, 0);
 		return 1;
 	}
+
 	set_chan_state(dev, WAN_CONNECTED);
+
+	if (chan->common.usedby == API){
+		send_delayed_cmd_result(card,dev,mb);
+		bind_lcn_to_dev (card, dev, new_lcn);
+	}
+
 	return 1;
 }
 
-/*============================================================================
- * Handle cleared call.
- */
+/*====================================================================
+ * 	Handle cleared call.
+ *====================================================================*/
 
 static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	unsigned new_lcn = mb->cmd.lcn;
-	struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+	netdevice_t* dev = find_channel(card, new_lcn);
+	x25_channel_t *chan;
+	unsigned char old_state;
 
-	printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
+	if (card->u.x.logging){
+		printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
 		"Diagn:0x%02X\n",
 		card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn);
-	if (dev == NULL)
+	}
+
+	if (dev == NULL){ 
+		printk(KERN_INFO "%s: X.25 clear request : No device for clear\n",
+				card->devname);
 		return 1;
+	}
+
+	chan=dev->priv;
+
+	old_state = chan->common.state;
+
 	set_chan_state(dev, WAN_DISCONNECTED);
+
+	if (chan->common.usedby == API){
+
+		switch (old_state){
+		
+		case WAN_CONNECTING:
+			send_delayed_cmd_result(card,dev,mb);
+			break;
+		case WAN_CONNECTED:
+			send_oob_msg(card,dev,mb);				
+			break;
+		}
+	}
+	
 	return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
 }
 
-/*============================================================================
- * Handle X.25 restart event.
- */
- 
+/*====================================================================
+ * 	Handle X.25 restart event.
+ *====================================================================*/
+
 static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	wan_device_t* wandev = &card->wandev;
-	struct net_device* dev;
+	netdevice_t* dev;
+	x25_channel_t *chan;
+	unsigned char old_state;
 
 	printk(KERN_INFO
 		"%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
 		card->devname, mb->cmd.cause, mb->cmd.diagn);
 
 	/* down all logical channels */
-	dev = wandev->dev;
-	while (dev) {
-		x25_channel_t *chan = dev->priv;
+	for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){
+		chan=dev->priv;
+		old_state = chan->common.state;
 
 		set_chan_state(dev, WAN_DISCONNECTED);
-		dev = chan->slave;
-	}
 
+		if (chan->common.usedby == API){
+			switch (old_state){
+		
+			case WAN_CONNECTING:
+				send_delayed_cmd_result(card,dev,mb);
+				break;
+			case WAN_CONNECTED:
+				send_oob_msg(card,dev,mb);				
+				break;
+			}
+		}
+	}
 	return (cmd == X25_WRITE) ? 0 : 1;
 }
 
-/*============================================================================
+/*====================================================================
  * Handle timeout event.
- */
+ *====================================================================*/
+
 static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	unsigned new_lcn = mb->cmd.lcn;
 
 	if (mb->cmd.pktType == 0x05)	/* call request time out */
 	{
-		struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
+		netdevice_t* dev = find_channel(card,new_lcn);
 
 		printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
 			card->devname, new_lcn);
-		if (dev)
+
+		if (dev){
+			x25_channel_t *chan = dev->priv;
 			set_chan_state(dev, WAN_DISCONNECTED);
-	}
-	else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
+
+			if (chan->common.usedby == API){
+				send_delayed_cmd_result(card,dev,card->mbox);
+			}
+		}
+	}else{ 
+		printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
 		card->devname, mb->cmd.pktType, new_lcn);
+	}
 	return 1;
 }
 
-/******* Miscellaneous ******************************************************/
+/* 
+ *	Miscellaneous 
+ */
 
-/*============================================================================
- * Establish physical connection.
- * o open HDLC and raise DTR
+/*====================================================================
+ * 	Establish physical connection.
+ * 	o open HDLC and raise DTR
  *
- * Return:	0	connection established
- *		1	connection is in progress
- *		<0	error
- */
+ * 	Return:		0	connection established
+ *			1	connection is in progress
+ *			<0	error
+ *===================================================================*/
+
 static int connect (sdla_t* card)
 {
+	TX25Status* status = card->flags;
+
 	if (x25_open_hdlc(card) || x25_setup_hdlc(card))
 		return -EIO;
+
 	wanpipe_set_state(card, WAN_CONNECTING);
+
+	x25_set_intr_mode(card, INTR_ON_TIMER); 
+	status->imask &= ~INTR_ON_TIMER;
+
 	return 1;
 }
 
-/*============================================================================
- * Tear down physical connection.
- * o close HDLC link
- * o drop DTR
+/*
+ * 	Tear down physical connection.
+ * 	o close HDLC link
+ * 	o drop DTR
  *
- * Return:	0
- *		<0	error
+ * 	Return:		0
+ *			<0	error
  */
+
 static int disconnect (sdla_t* card)
 {
 	wanpipe_set_state(card, WAN_DISCONNECTED);
-	x25_set_intr_mode(card, 0);	/* disable interrupt generation */
-	x25_close_hdlc(card);		/* close HDLC link */
-	x25_set_dtr(card, 0);		/* drop DTR */
+	x25_set_intr_mode(card, INTR_ON_TIMER);	/* disable all interrupt except timer */
+	x25_close_hdlc(card);			/* close HDLC link */
+	x25_set_dtr(card, 0);			/* drop DTR */
 	return 0;
 }
 
-/*============================================================================
+/*
  * Find network device by its channel number.
  */
-static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
+
+static netdevice_t* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
 {
-	struct net_device* dev;
-	x25_channel_t *chan;
+	netdevice_t* dev;
 
-	dev = wandev->dev;
-	while (dev) {
-		if (chan->lcn == lcn)
+	for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv))
+		if (((x25_channel_t*)dev->priv)->common.lcn == lcn) 
 			break;
-		dev = chan->slave;
-	}
 	return dev;
 }
 
-/*============================================================================
- * Initiate connection on the logical channel.
- * o for PVC we just get channel configuration
- * o for SVCs place an X.25 call
- *
- * Return:	0	connected
- *		>0	connection in progress
- *		<0	failure
+/*
+ * 	Initiate connection on the logical channel.
+ * 	o for PVC we just get channel configuration
+ * 	o for SVCs place an X.25 call
+ *
+ * 	Return:		0	connected
+ *			>0	connection in progress
+ *			<0	failure
  */
-static int chan_connect (struct net_device* dev)
+
+static int chan_connect (netdevice_t* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
-	if (chan->svc)
-	{
-		if (!chan->addr[0])
+	if (chan->common.svc && chan->common.usedby == WANPIPE){
+		if (!chan->addr[0]){
+			printk(KERN_INFO "%s: No Destination Address\n",
+					card->devname);
 			return -EINVAL;	/* no destination address */
+		}
 		printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
 			card->devname, chan->addr);
+
 		if (x25_place_call(card, chan) != CMD_OK)
 			return -EIO;
+
 		set_chan_state(dev, WAN_CONNECTING);
 		return 1;
-	}
-	else
-	{
+	}else{
 		if (x25_get_chan_conf(card, chan) != CMD_OK)
 			return -EIO;
+
 		set_chan_state(dev, WAN_CONNECTED);
 	}
 	return 0;
 }
 
-/*============================================================================
- * Disconnect logical channel.
- * o if SVC then clear X.25 call
+/*
+ * 	Disconnect logical channel.
+ * 	o if SVC then clear X.25 call
  */
-static int chan_disc (struct net_device* dev)
+
+static int chan_disc (netdevice_t* dev)
 {
 	x25_channel_t* chan = dev->priv;
 
-	if (chan->svc)
-		x25_clear_call(chan->card, chan->lcn, 0, 0);
+	if (chan->common.svc){ 
+		x25_clear_call(chan->card, chan->common.lcn, 0, 0);
+
+		/* For API we disconnect on clear
+                 * confirmation. 
+                 */
+		if (chan->common.usedby == API)
+			return 0;
+	}
+
 	set_chan_state(dev, WAN_DISCONNECTED);
+	
 	return 0;
 }
 
-/*============================================================================
- * Set logical channel state.
+/*
+ * 	Set logical channel state.
  */
-static void set_chan_state (struct net_device* dev, int state)
+
+static void set_chan_state (netdevice_t* dev, int state)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -2071,99 +3613,257 @@
 
 	save_flags(flags);
 	cli();
-	if (chan->state != state)
+	if (chan->common.state != state)
 	{
 		switch (state)
 		{
 			case WAN_CONNECTED:
-				printk (KERN_INFO "%s: interface %s connected!\n",
-					card->devname, dev->name);
-				*(unsigned short*)dev->dev_addr = htons(chan->lcn);
+				if (card->u.x.logging){
+					printk (KERN_INFO 
+						"%s: interface %s connected, lcn %i !\n", 
+						card->devname, dev->name,chan->common.lcn);
+				}
+				*(unsigned short*)dev->dev_addr = htons(chan->common.lcn);
 				chan->i_timeout_sofar = jiffies;
+
+				/* LAPB is PVC Based */
+				if (card->u.x.LAPB_hdlc)
+					chan->common.svc=0;
 				break;
 
 			case WAN_CONNECTING:
-				printk (KERN_INFO "%s: interface %s connecting...\n",
-					card->devname, dev->name);
+				if (card->u.x.logging){
+					printk (KERN_INFO 
+						"%s: interface %s connecting, lcn %i ...\n", 
+						card->devname, dev->name, chan->common.lcn);
+				}
 				break;
 
 			case WAN_DISCONNECTED:
-				printk (KERN_INFO "%s: interface %s disconnected!\n",
-					card->devname, dev->name);
-				if (chan->svc) 
-				{
+				if (card->u.x.logging){
+					printk (KERN_INFO 
+						"%s: interface %s disconnected, lcn %i !\n", 
+						card->devname, dev->name,chan->common.lcn);
+				}
+				atomic_set(&chan->common.disconnect,0);
+				
+				if (chan->common.svc) {
 					*(unsigned short*)dev->dev_addr = 0;
-		                	chan->lcn = 0;
+					card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL;
+		                	chan->common.lcn = 0;
 				}
+
+				if (chan->transmit_length){
+					chan->transmit_length=0;
+					atomic_set(&chan->common.driver_busy,0);
+					chan->tx_offset=0;
+					if (is_queue_stopped(dev)){
+						wake_net_dev(dev);
+					}
+				}
+				atomic_set(&chan->common.command,0);
 				break;
-		}
-		chan->state = state;
-	}
+
+			case WAN_DISCONNECTING:
+				if (card->u.x.logging){
+					printk (KERN_INFO 
+					"\n%s: interface %s disconnecting, lcn %i ...\n", 
+					card->devname, dev->name,chan->common.lcn);
+				}
+				atomic_set(&chan->common.disconnect,0);
+				break;
+		}
+		chan->common.state = state;
+	}
 	chan->state_tick = jiffies;
 	restore_flags(flags);
 }
 
-/*============================================================================
- * Send packet on a logical channel.
- *	When this function is called, tx_skb field of the channel data space
- *	points to the transmit socket buffer.  When transmission is complete,
- *	release socket buffer and reset 'tbusy' flag.
- *
- * Return:	0	- transmission complete
- *		1	- busy
- *
- * Notes:
- * 1. If packet length is greater than MTU for this channel, we'll fragment
- *    the packet into 'complete sequence' using M-bit.
- * 2. When transmission is complete, an event notification should be issued
- *    to the router.
+/*
+ * 	Send packet on a logical channel.
+ *		When this function is called, tx_skb field of the channel data 
+ *		space points to the transmit socket buffer.  When transmission 
+ *		is complete, release socket buffer and reset 'tbusy' flag.
+ *
+ * 	Return:		0	- transmission complete
+ *			1	- busy
+ *
+ * 	Notes:
+ * 	1. If packet length is greater than MTU for this channel, we'll fragment
+ *    	the packet into 'complete sequence' using M-bit.
+ * 	2. When transmission is complete, an event notification should be issued
+ *    	to the router.
  */
-static int chan_send (struct net_device* dev, struct sk_buff* skb)
+
+static int chan_send (netdevice_t* dev, void* buff, unsigned data_len, unsigned char tx_intr)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 	TX25Status* status = card->flags;
-	unsigned len, qdm;
+	unsigned len=0, qdm=0, res=0, orig_len = 0;
+	void *data;
 
 	/* Check to see if channel is ready */
-	if (!(status->cflags[chan->ch_idx] & 0x40))
-		return 1;
-
-	if (skb->len > chan->tx_pkt_size)
-	{
-		len = chan->tx_pkt_size;
-		qdm = 0x01;		/* set M-bit (more data) */
+	if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc)  || 
+             !(*card->u.x.hdlc_buf_status & 0x40)){ 
+            
+		if (!tx_intr){
+			setup_for_delayed_transmit (dev, buff, data_len);
+			return 0;
+		}else{
+			/* By returning 0 to tx_intr the packet will be dropped */
+			++card->wandev.stats.tx_dropped;
+			++chan->ifstats.tx_dropped;
+			printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", 
+				card->devname,dev->name);
+			++chan->if_send_stat.if_send_bfr_not_passed_to_adptr;
+			return 0;
+		}
 	}
-	else	/* final packet */
-	{
-		len = skb->len;
-		qdm = 0;
+
+	if (chan->common.usedby == API){
+		/* Remove the API Header */
+		x25api_hdr_t *api_data = (x25api_hdr_t *)buff;
+
+		/* Set the qdm bits from the packet header 
+                 * User has the option to set the qdm bits
+                 */
+		qdm = api_data->qdm;
+
+		orig_len = len = data_len - sizeof(x25api_hdr_t);
+		data = (unsigned char*)buff + sizeof(x25api_hdr_t);
+	}else{
+		data = buff;
+		orig_len = len = data_len;
+	}	
+
+	if (tx_intr){
+		/* We are in tx_intr, minus the tx_offset from 
+                 * the total length. The tx_offset part of the
+		 * data has already been sent. Also, move the 
+		 * data pointer to proper offset location.
+                 */
+		len -= chan->tx_offset;
+		data = (unsigned char*)data + chan->tx_offset;
 	}
-	switch(x25_send(card, chan->lcn, qdm, len, skb->data))
-	{
+		
+	/* Check if the packet length is greater than MTU
+         * If YES: Cut the len to MTU and set the M bit 
+         */
+	if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){
+		len = chan->tx_pkt_size;
+		qdm |= M_BIT;		
+	} 
+
+
+	/* Pass only first three bits of the qdm byte to the send
+         * routine. In case user sets any other bit which might
+         * cause errors. 
+         */
+
+	switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){
 		case 0x00:	/* success */
 			chan->i_timeout_sofar = jiffies;
-			if (qdm)
-			{
-				skb_pull(skb, len);
-				return 1;
+
+#ifdef LINUX_2_4
+			dev->trans_start=jiffies;
+#endif
+			
+			if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){
+				if (!tx_intr){
+					/* The M bit was set, which means that part of the
+                                         * packet has been sent. Copy the packet into a buffer
+				         * and set the offset to len, so on next tx_inter 
+					 * the packet will be sent using the below offset.
+					 */
+					chan->tx_offset += len;
+
+					++chan->ifstats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+					chan->ifstats.tx_bytes += len;
+#endif
+					
+					if (chan->tx_offset < orig_len){
+						setup_for_delayed_transmit (dev, buff, data_len);
+					}
+					res=0;
+				}else{
+					/* We are already in tx_inter, thus data is already
+                                         * in the buffer. Update the offset and wait for
+                                         * next tx_intr. We add on to the offset, since data can
+                                         * be X number of times larger than max data size.
+					 */
+					++chan->ifstats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+					chan->ifstats.tx_bytes += len;
+#endif
+					
+					++chan->if_send_stat.if_send_bfr_passed_to_adptr;
+					chan->tx_offset += len;
+
+					/* The user can set the qdm bit as well.
+                                         * If the entire packet was sent and qdm is still
+                                         * set, than it's the user who has set the M bit. In that,
+                                         * case indicate that the packet was send by returning 
+					 * 0 and wait for a new packet. Otherwise, wait for next
+                                         * tx interrupt to send the rest of the packet */
+
+					if (chan->tx_offset < orig_len){
+						res=1;
+					}else{	
+						res=0;
+					}
+				}
+			}else{
+				++chan->ifstats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+				chan->ifstats.tx_bytes += len;
+#endif
+				++chan->if_send_stat.if_send_bfr_passed_to_adptr;
+				res=0;
 			}
-			++chan->ifstats.tx_packets;
-			chan->ifstats.tx_bytes += skb->len;
 			break;
 
 		case 0x33:	/* Tx busy */
-			return 1;
+			if (tx_intr){
+				printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n",
+						card->devname,dev->name);
+				++chan->ifstats.tx_dropped;
+				++card->wandev.stats.tx_dropped;
+				++chan->if_send_stat.if_send_bfr_not_passed_to_adptr;
+				res=0;
+			}else{
+				DBG_PRINTK(KERN_INFO 
+					"%s: Send: Big Error should have tx: storring %s\n",
+						card->devname,dev->name);
+				setup_for_delayed_transmit (dev, buff, data_len);	
+				res=1;
+			}
+			break;
 
 		default:	/* failure */
 			++chan->ifstats.tx_errors;
-/*			return 1; */
+			if (tx_intr){
+				printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n",
+					card->devname,dev->name);
+				++chan->ifstats.tx_dropped;
+				++card->wandev.stats.tx_dropped;
+				++chan->if_send_stat.if_send_bfr_not_passed_to_adptr;
+				res=0;
+			}else{
+				DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n",
+					card->devname,dev->name);			
+				setup_for_delayed_transmit (dev, buff, data_len);
+				res=1;
+			}
+			break;	
 	}
-	return 0;
+	return res;
 }
 
-/*============================================================================
- * Parse X.25 call request data and fill x25_call_info_t structure.
+
+/*
+ * 	Parse X.25 call request data and fill x25_call_info_t structure.
  */
 
 static void parse_call_info (unsigned char* str, x25_call_info_t* info)
@@ -2172,54 +3872,45 @@
 	for (; *str; ++str)
 	{
 		int i;
-		unsigned ch;
+		unsigned char ch;
+
+		if (*str == '-') switch (str[1]) {
+
+			/* Take minus 2 off the maximum size so that 
+                         * last byte is 0. This way we can use string
+                         * manipulaton functions on call information.
+                         */
 
-		if (*str == '-') switch (str[1])
-		{
 			case 'd':	/* destination address */
-				for (i = 0; i < 16; ++i)
-				{
+				for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){
 					ch = str[2+i];
-					if (!is_digit(ch)) 
-						break;
+					if (isspace(ch)) break;
 					info->dest[i] = ch;
 				}
 				break;
-	
+
 			case 's':	/* source address */
-				for (i = 0; i < 16; ++i)
-				{
+				for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){
 					ch = str[2+i];
-					if (!is_digit(ch))
-						break;
+					if (isspace(ch)) break;
 					info->src[i] = ch;
 				}
 				break;
 
 			case 'u':	/* user data */
-				for (i = 0; i < 127; ++i)
-				{
-					ch = str[2+2*i];
-					if (!is_hex_digit(ch)) 
-						break;
-					info->user[i] = hex_to_uint(&str[2+2*i], 2);
+				for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){
+					ch = str[2+i];
+					if (isspace(ch)) break;
+					info->user[i] = ch; 
 				}
 				info->nuser = i;
 				break;
 
 			case 'f':	/* facilities */
-				for (i = 0; i < 64; ++i)
-				{
-					ch = str[2+4*i];
-					if (!is_hex_digit(ch))
-						break;
-					info->facil[i].code =
-						hex_to_uint(&str[2+4*i], 2);
-					ch = str[4+4*i];
-					if (!is_hex_digit(ch))
-						break;
-					info->facil[i].parm =
-						hex_to_uint(&str[4+4*i], 2);
+				for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){
+					ch = str[2+i];
+					if (isspace(ch)) break;
+					info->facil[i] = ch;
 				}
 				info->nfacil = i;
 				break;
@@ -2227,14 +3918,15 @@
 	}
 }
 
-/*============================================================================
- * Convert line speed in bps to a number used by S502 code.
+/*
+ * 	Convert line speed in bps to a number used by S502 code.
  */
+
 static unsigned char bps_to_speed_code (unsigned long bps)
 {
 	unsigned char	number;
 
-	if (bps <= 1200)        number = 0x01 ;
+	if (bps <= 1200)        number = 0x01;
 	else if (bps <= 2400)   number = 0x02;
 	else if (bps <= 4800)   number = 0x03;
 	else if (bps <= 9600)   number = 0x04;
@@ -2251,29 +3943,36 @@
 	return number;
 }
 
-/*============================================================================
- * Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted.
+/*
+ * 	Convert decimal string to unsigned integer.
+ * 	If len != 0 then only 'len' characters of the string are converted.
  */
+
 static unsigned int dec_to_uint (unsigned char* str, int len)
 {
 	unsigned val;
 
-	if (!len) len = strlen(str);
+	if (!len) 
+		len = strlen(str);
+
 	for (val = 0; len && is_digit(*str); ++str, --len)
 		val = (val * 10) + (*str - (unsigned)'0');
+	
 	return val;
 }
 
-/*============================================================================
- * Convert hex string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are conferted.
+/*
+ * 	Convert hex string to unsigned integer.
+ * 	If len != 0 then only 'len' characters of the string are conferted.
  */
+
 static unsigned int hex_to_uint (unsigned char* str, int len)
 {
 	unsigned val, ch;
 
-	if (!len) len = strlen(str);
+	if (!len) 
+		len = strlen(str);
+
 	for (val = 0; len; ++str, --len)
 	{
 		ch = *str;
@@ -2281,8 +3980,7 @@
 			val = (val << 4) + (ch - (unsigned)'0');
 		else if (is_hex_digit(ch))
 			val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10);
-		else
-			break;
+		else break;
 	}
 	return val;
 }
@@ -2292,21 +3990,21 @@
 {
 	int i;
 
-	if( proto == htons(ETH_P_IPX) ) {
+	if( proto == ETH_P_IPX) {
 		/* It's an IPX packet */
 		if(!enable_IPX) {
 			/* Return 1 so we don't pass it up the stack. */
 			return 1;
 		}
 	} else {
-		/* It's not IPX so pass it up the stack. */
+		/* It's not IPX so pass it up the stack.*/ 
 		return 0;
 	}
 
 	if( sendpacket[16] == 0x90 &&
 	    sendpacket[17] == 0x04)
 	{
-		/* It's IPXWAN */
+		/* It's IPXWAN  */
 
 		if( sendpacket[2] == 0x02 &&
 		    sendpacket[34] == 0x00)
@@ -2315,19 +4013,24 @@
 			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
 
 			/* Go through the routing options and answer no to every
-			 * option except Unnumbered RIP/SAP */
+			 * option except Unnumbered RIP/SAP
+			 */
 			for(i = 41; sendpacket[i] == 0x00; i += 5)
 			{
 				/* 0x02 is the option for Unnumbered RIP/SAP */
 				if( sendpacket[i + 4] != 0x02)
+				{
 					sendpacket[i + 1] = 0;
+				}
 			}
 
 			/* Skip over the extended Node ID option */
 			if( sendpacket[i] == 0x04 )
+			{
 				i += 8;
+			}
 
-			/* We also want to turn off all header compression opt. */
+			/* We also want to turn off all header compression opt. 			 */ 
 			for(; sendpacket[i] == 0x80 ;)
 			{
 				sendpacket[i + 1] = 0;
@@ -2364,7 +4067,9 @@
 			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
 			sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
 			for(i = 66; i < 99; i+= 1)
+			{
 				sendpacket[i] = 0;
+			}
 
 			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
 		}
@@ -2382,18 +4087,18 @@
 
 		return 1;
 	} else {
-		/* If we get here its an IPX-data packet, so it'll get passed up the stack.
-		   switch the network numbers */
+		/*If we get here its an IPX-data packet, so it'll get passed up the stack.
+		 */
+		/* switch the network numbers */
 		switch_net_numbers(sendpacket, network_number, 1);	
 		return 0;
 	}
 }
 
 /*
-   If incoming is 0 (outgoing)- if the net numbers is ours make it 0
-   if incoming is 1 - if the net number is 0 make it ours 
-
-*/
+ *  	If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+ *  	if incoming is 1 - if the net number is 0 make it ours 
+ */
 
 static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
 {
@@ -2402,21 +4107,17 @@
 	pnetwork_number = (unsigned long)((sendpacket[6] << 24) + 
 			  (sendpacket[7] << 16) + (sendpacket[8] << 8) + 
 			  sendpacket[9]);
+	
 
-	if (!incoming) 
-	{
-		/* If the destination network number is ours, make it 0 */
-		if( pnetwork_number == network_number) 
-		{
+	if (!incoming) {
+		/*If the destination network number is ours, make it 0 */
+		if( pnetwork_number == network_number) {
 			sendpacket[6] = sendpacket[7] = sendpacket[8] = 
 					 sendpacket[9] = 0x00;
 		}
-	} 
-	else 
-	{
+	} else {
 		/* If the incoming network is 0, make it ours */
-		if( pnetwork_number == 0) 
-		{
+		if( pnetwork_number == 0) {
 			sendpacket[6] = (unsigned char)(network_number >> 24);
 			sendpacket[7] = (unsigned char)((network_number & 
 					 0x00FF0000) >> 16);
@@ -2431,21 +4132,17 @@
 	pnetwork_number = (unsigned long)((sendpacket[18] << 24) + 
 			  (sendpacket[19] << 16) + (sendpacket[20] << 8) + 
 			  sendpacket[21]);
-
-	if( !incoming ) 
-	{
+	
+	
+	if( !incoming ) {
 		/* If the source network is ours, make it 0 */
-		if( pnetwork_number == network_number) 
-		{
+		if( pnetwork_number == network_number) {
 			sendpacket[18] = sendpacket[19] = sendpacket[20] = 
-					 sendpacket[21] = 0x00;
+				 sendpacket[21] = 0x00;
 		}
-	}
-	else
-	{
+	} else {
 		/* If the source network is 0, make it ours */
-		if( pnetwork_number == 0 ) 
-		{
+		if( pnetwork_number == 0 ) {
 			sendpacket[18] = (unsigned char)(network_number >> 24);
 			sendpacket[19] = (unsigned char)((network_number & 
 					 0x00FF0000) >> 16);
@@ -2457,5 +4154,1419 @@
 	}
 } /* switch_net_numbers */
 
+
+
+
+/********************* X25API SPECIFIC FUNCTIONS ****************/
+
+
+/*===============================================================
+ *  find_channel
+ *
+ *	Manages the lcn to device map. It increases performance
+ *      because it eliminates the need to search through the link  
+ *      list for a device which is bounded to a specific lcn.
+ *
+ *===============================================================*/
+
+
+netdevice_t * find_channel(sdla_t *card, unsigned lcn)
+{
+	if (card->u.x.LAPB_hdlc){
+
+		return card->wandev.dev;
+
+	}else{
+		/* We don't know whether the incoming lcn
+                 * is a PVC or an SVC channel. But we do know that
+                 * the lcn cannot be for both the PVC and the SVC
+                 * channel.
+
+		 * If the lcn number is greater or equal to 255, 
+                 * take the modulo 255 of that number. We only have
+                 * 255 locations, thus higher numbers must be mapped
+                 * to a number between 0 and 245. 
+
+		 * We must separate pvc's and svc's since two don't
+                 * have to be contiguous.  Meaning pvc's can start
+                 * from 1 to 10 and svc's can start from 256 to 266.
+                 * But 256%255 is 1, i.e. CONFLICT.
+		 */
+
+
+		/* Highest LCN number must be less or equal to 4096 */
+		if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){
+
+			if (lcn < X25_MAX_CHAN){
+				if (card->u.x.svc_to_dev_map[lcn])
+					return card->u.x.svc_to_dev_map[lcn];
+
+				if (card->u.x.pvc_to_dev_map[lcn])
+					return card->u.x.pvc_to_dev_map[lcn];
+			
+			}else{
+				int new_lcn = lcn%X25_MAX_CHAN;
+				if (card->u.x.svc_to_dev_map[new_lcn])
+					return card->u.x.svc_to_dev_map[new_lcn];
+
+				if (card->u.x.pvc_to_dev_map[new_lcn])
+					return card->u.x.pvc_to_dev_map[new_lcn];
+			}
+		}
+		return NULL;
+	}
+}
+
+void bind_lcn_to_dev (sdla_t *card, netdevice_t *dev,unsigned lcn)
+{
+	x25_channel_t *chan = dev->priv;
+
+	/* Modulo the lcn number by X25_MAX_CHAN (255)
+	 * because the lcn number can be greater than 255 
+         *
+	 * We need to split svc and pvc since they don't have
+         * to be contigous. 
+	 */
+
+	if (chan->common.svc){
+		card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev;
+	}else{
+		card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev;
+	}
+	chan->common.lcn = lcn;
+}
+
+
+
+/*===============================================================
+ * x25api_bh 
+ *
+ *
+ *==============================================================*/
+
+static void x25api_bh (netdevice_t * dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	struct sk_buff *skb;
+
+	if (atomic_read(&chan->bh_buff_used) == 0){
+		printk(KERN_INFO "%s: BH Buffer Empty in BH\n",
+				card->devname);
+		clear_bit(0, &chan->tq_working);
+		return;
+	}
+
+	while (atomic_read(&chan->bh_buff_used)){
+
+		/* If the sock is in the process of unlinking the
+		 * driver from the socket, we must get out. 
+		 * This never happends but is a sanity check. */
+		if (test_bit(0,&chan->common.common_critical)){
+			clear_bit(0, &chan->tq_working);
+			return;
+		}
+		
+		/* If LAPB HDLC, do not drop packets if socket is
+                 * not connected.  Let the buffer fill up and
+                 * turn off rx interrupt */
+		if (card->u.x.LAPB_hdlc){
+			if (chan->common.sk == NULL || chan->common.func == NULL){
+				clear_bit(0, &chan->tq_working);			
+				return;
+			}
+		}
+
+		skb  = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
+
+		if (skb == NULL){
+			printk(KERN_INFO "%s: BH Skb empty for read %i\n",
+					card->devname,chan->bh_read);
+		}else{
+			
+			if (chan->common.sk == NULL || chan->common.func == NULL){
+				printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n",
+						card->devname);
+				wan_dev_kfree_skb(skb, FREE_READ);
+				x25api_bh_cleanup(dev);
+				++chan->ifstats.rx_dropped;
+				++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
+				continue;
+			}
+
+
+			if (chan->common.func(skb,dev,chan->common.sk) != 0){
+				/* Sock full cannot send, queue us for another
+                                 * try 
+				 */
+				printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n",
+						card->devname);
+				atomic_set(&chan->common.receive_block,1);
+				return;
+			}else{
+				x25api_bh_cleanup(dev);
+				++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack;
+			}
+		}
+	}	
+	clear_bit(0, &chan->tq_working);
+
+	return;
+}
+
+/*===============================================================
+ * x25api_bh_cleanup 
+ *
+ *
+ *==============================================================*/
+
+static int x25api_bh_cleanup (netdevice_t *dev)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	TX25Status* status = card->flags;
+
+
+	((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
+
+	if (chan->bh_read == MAX_BH_BUFF){
+		chan->bh_read=0;
+	}else{
+		++chan->bh_read;	
+	}
+
+	/* If the Receive interrupt was off, it means
+         * that we filled up our circular buffer. Check    
+         * that we have space in the buffer. If so 
+         * turn the RX interrupt back on. 
+	 */
+	if (!(status->imask & INTR_ON_RX_FRAME)){
+		if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){
+			printk(KERN_INFO "%s: BH: Turning on the interrupt\n",
+					card->devname);
+			status->imask |= INTR_ON_RX_FRAME;
+		}
+	}	
+
+	atomic_dec(&chan->bh_buff_used);
+	return 0;
+}
+
+
+/*===============================================================
+ * bh_enqueue 
+ *
+ *
+ *==============================================================*/
+
+static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+{
+	x25_channel_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	TX25Status* status = card->flags;
+
+	if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){
+		printk(KERN_INFO "%s: Bottom half buffer FULL\n",
+				card->devname);
+		return 1; 
+	}
+
+	((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
+
+	if (chan->bh_write == MAX_BH_BUFF){
+		chan->bh_write=0;
+	}else{
+		++chan->bh_write;
+	}
+
+	atomic_inc(&chan->bh_buff_used);
+
+	if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){
+		printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n",
+				card->devname);
+		status->imask &= ~INTR_ON_RX_FRAME;
+	}
+
+	return 0;
+}
+
+
+/*===============================================================
+ * timer_intr_cmd_exec
+ *  
+ *	Called by timer interrupt to execute a command
+ *===============================================================*/
+
+static int timer_intr_cmd_exec (sdla_t* card)
+{
+	netdevice_t *dev;
+	unsigned char more_to_exec=0;
+	volatile x25_channel_t *chan=NULL;
+	int i=0,bad_cmd=0,err=0;	
+
+	if (card->u.x.cmd_dev == NULL){
+		card->u.x.cmd_dev = card->wandev.dev;
+	}
+
+	dev = card->u.x.cmd_dev;
+
+	for (;;){
+
+		chan = dev->priv;
+		
+		if (atomic_read(&chan->common.command)){ 
+
+			bad_cmd = check_bad_command(card,dev);
+
+			if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && 
+			     !bad_cmd){
+
+				/* Socket has died or exited, We must bring the
+                                 * channel down before anybody else tries to 
+                                 * use it */
+				err = channel_disconnect(card,dev);
+			}else{
+			        err = execute_delayed_cmd(card, dev,
+							 (mbox_cmd_t*)chan->common.mbox,
+							  bad_cmd);
+			}
+
+			switch (err){
+
+			case RETURN_RESULT:
+
+				/* Return the result to the socket without
+                                 * delay. NO_WAIT Command */	
+				atomic_set(&chan->common.command,0);
+				if (atomic_read(&card->u.x.command_busy))
+					atomic_set(&card->u.x.command_busy,0);
+
+				send_delayed_cmd_result(card,dev,card->mbox);
+
+				more_to_exec=0;
+				break;
+			case DELAY_RESULT:
+		
+				/* Wait for the remote to respond, before
+                                 * sending the result up to the socket.
+                                 * WAIT command */
+				if (atomic_read(&card->u.x.command_busy))
+					atomic_set(&card->u.x.command_busy,0);
+				
+				atomic_set(&chan->common.command,0);
+				more_to_exec=0;
+				break;
+			default:
+
+				/* If command could not be executed for
+                                 * some reason (i.e return code 0x33 busy)
+                                 * set the more_to_exec bit which will
+                                 * indicate that this command must be exectued
+                                 * again during next timer interrupt 
+				 */
+				more_to_exec=1;
+				if (atomic_read(&card->u.x.command_busy) == 0)
+					atomic_set(&card->u.x.command_busy,1);
+				break;
+			}
+
+			bad_cmd=0;
+
+			/* If flags is set, there are no hdlc buffers,
+                         * thus, wait for the next pass and try the
+                         * same command again. Otherwise, start searching 
+                         * from next device on the next pass. 
+			 */
+			if (!more_to_exec){
+				dev = move_dev_to_next(card,dev);
+			}
+			break;
+		}else{
+			/* This device has nothing to execute,
+                         * go to next. 
+			 */
+			if (atomic_read(&card->u.x.command_busy))
+					atomic_set(&card->u.x.command_busy,0);
+			dev = move_dev_to_next(card,dev);
+		}	
+
+		if (++i == card->u.x.no_dev){
+			if (!more_to_exec){
+				DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n",
+					card->devname);
+				if (atomic_read(&card->u.x.command_busy)){
+					atomic_set(&card->u.x.command_busy,0);
+				}
+			}
+			break;
+		}
+
+	} //End of FOR
+
+	card->u.x.cmd_dev = dev;
+	
+	if (more_to_exec){
+		/* If more commands are pending, do not turn off timer 
+                 * interrupt */
+		return 1;
+	}else{
+		/* No more commands, turn off timer interrupt */
+		return 0;
+	}	
+}
+
+/*===============================================================
+ * execute_delayed_cmd 
+ *
+ *	Execute an API command which was passed down from the
+ *      sock.  Sock is very limited in which commands it can
+ *      execute.  Wait and No Wait commands are supported.  
+ *      Place Call, Clear Call and Reset wait commands, where
+ *      Accept Call is a no_wait command.
+ *
+ *===============================================================*/
+
+static int execute_delayed_cmd (sdla_t* card, netdevice_t *dev, mbox_cmd_t *usr_cmd,char bad_cmd)
+{
+	TX25Mbox* mbox = card->mbox;
+	int err;
+	x25_channel_t *chan = dev->priv;
+	int delay=RETURN_RESULT;
+
+	if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){
+		return TRY_CMD_AGAIN;
+	}
+
+	/* This way a command is guaranteed to be executed for
+         * a specific lcn, the network interface is bound to. */
+	usr_cmd->cmd.lcn = chan->common.lcn;
+	
+
+	/* If channel is pvc, instead of place call
+         * run x25_channel configuration. If running LAPB HDLC
+         * enable communications. 
+         */
+	if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){
+
+		if (card->u.x.LAPB_hdlc){
+			DBG_PRINTK(KERN_INFO "LAPB: Connecting\n");
+			connect(card);
+			set_chan_state(dev,WAN_CONNECTING);
+			return DELAY_RESULT;
+		}else{
+			DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname);
+			if (x25_get_chan_conf(card, chan) == CMD_OK){
+				set_chan_state(dev, WAN_CONNECTED);
+			}else{ 
+				set_chan_state(dev, WAN_DISCONNECTED);
+			}
+			return RETURN_RESULT;
+		}
+	}
+
+	/* Copy the socket mbox command onto the board */
+
+	memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd));
+	if (usr_cmd->cmd.length){
+		memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length);
+	}
+
+	/* Check if command is bad. We need to copy the cmd into
+         * the buffer regardless since we return the, mbox to
+         * the user */
+	if (bad_cmd){
+		mbox->cmd.result=0x01;
+		return RETURN_RESULT;
+	}
+
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+	if (err != CMD_OK && err != X25RES_NOT_READY)
+		x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn);
+
+	if (mbox->cmd.result == X25RES_NOT_READY){
+		return TRY_CMD_AGAIN;
+	}
+
+	switch (mbox->cmd.command){
+
+	case X25_PLACE_CALL:
+		
+		switch (mbox->cmd.result){
+
+		case CMD_OK:
+
+			/* Check if Place call is a wait command or a 
+               	  	 * no wait command */
+			if (atomic_read(&chan->common.command) & 0x80)
+ 				delay=RETURN_RESULT;
+			else
+				delay=DELAY_RESULT;
+		
+
+			DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n",
+					card->devname,dev->name, mbox->cmd.lcn);
+		
+			bind_lcn_to_dev (card, dev, mbox->cmd.lcn);
+			set_chan_state(dev, WAN_CONNECTING);
+			break;
+
+
+		default:
+			delay=RETURN_RESULT;
+			set_chan_state(dev, WAN_DISCONNECTED);
+			break;
+		}
+		break;
+
+	case X25_ACCEPT_CALL: 
+		
+		switch (mbox->cmd.result){
+
+		case CMD_OK:
+
+			DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n",
+				card->devname,dev->name,mbox->cmd.lcn);
+
+			bind_lcn_to_dev (card, dev, mbox->cmd.lcn);
+
+			if (x25_get_chan_conf(card, chan) == CMD_OK){
+
+				set_chan_state(dev, WAN_CONNECTED);
+				delay=RETURN_RESULT;
+
+			}else{ 
+				if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){
+					/* if clear is successful, wait for clear confirm 
+					 */ 
+					delay=DELAY_RESULT;
+				}else{
+					/* Do not change the state here. If we fail 
+					 * the accept the return code is send up 
+					 *the stack, which will ether retry
+                               	  	 * or clear the call 
+					 */
+					DBG_PRINTK(KERN_INFO 
+						"%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n",
+						card->devname);
+					delay=RETURN_RESULT;
+				}
+			}
+			break;
+
+
+		case X25RES_ASYNC_PACKET:
+			delay=TRY_CMD_AGAIN;
+			break;
+
+		default: 
+			DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname);
+			if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){
+				delay=DELAY_RESULT;
+			}else{
+				/* Do not change the state here. If we fail the accept. The
+                                 * return code is send up the stack, which will ether retry
+                                 * or clear the call */
+				DBG_PRINTK(KERN_INFO 
+					"%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n",
+						card->devname);
+				delay=RETURN_RESULT;
+			}
+		}
+		break;
+
+	case X25_CLEAR_CALL:
+
+		switch (mbox->cmd.result){
+
+		case CMD_OK:
+			DBG_PRINTK(KERN_INFO 
+					"CALL CLEAR OK: Dev %s Mbox Lcn %i  Chan Lcn %i\n",
+					dev->name,mbox->cmd.lcn,chan->common.lcn);
+			set_chan_state(dev, WAN_DISCONNECTING);
+			delay = DELAY_RESULT;
+			break;
+
+		case X25RES_CHANNEL_IN_USE:
+		case X25RES_ASYNC_PACKET:
+			delay = TRY_CMD_AGAIN;
+			break;
+			
+		case X25RES_LINK_NOT_IN_ABM:
+		case X25RES_INVAL_LCN:
+		case X25RES_INVAL_STATE:
+			set_chan_state(dev, WAN_DISCONNECTED);
+			delay = RETURN_RESULT;
+			break;
+		
+		default:
+			/* If command did not execute because of user
+                         * fault, do not change the state. This will
+                         * signal the socket that clear command failed.
+                         * User can retry or close the socket.
+                         * When socket gets killed, it will set the 
+                         * chan->disconnect which will signal
+                         * driver to clear the call */
+			printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n",
+				card->devname,mbox->cmd.command); 
+			delay = RETURN_RESULT;
+		}
+		break;
+	}	
+
+	return delay;
+}
+
+/*===============================================================
+ * api_incoming_call 
+ *
+ *	Pass an incoming call request up the the listening
+ *      sock.  If the API sock is not listening reject the
+ *      call.
+ *
+ *===============================================================*/
+
+static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn)
+{
+	struct sk_buff *skb;
+	int len = sizeof(TX25Cmd)+mbox->cmd.length;
+
+	if (alloc_and_init_skb_buf(card, &skb, len)){
+		printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname);
+		return 1;
+	}
+
+	memcpy(skb_put(skb,len),&mbox->cmd,len);
+
+	skb->mac.raw = skb->data;
+	skb->protocol = htons(X25_PROT);
+	skb->pkt_type = WAN_PACKET_ASYNC;
+
+	if (card->func(skb,card->sk) < 0){
+		printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname);
+                wan_dev_kfree_skb(skb, FREE_READ);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*===============================================================
+ * send_delayed_cmd_result
+ *
+ *	Wait commands like PLEACE CALL or CLEAR CALL must wait
+ *      untill the result arrivers. This function passes
+ *      the result to a waiting sock. 
+ *
+ *===============================================================*/
+static void send_delayed_cmd_result(sdla_t *card, netdevice_t *dev, TX25Mbox* mbox)
+{
+	x25_channel_t *chan = dev->priv;
+	mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox;
+	struct sk_buff *skb;
+	int len=sizeof(unsigned char);
+
+	atomic_set(&chan->common.command,0);
+
+	/* If the sock is in the process of unlinking the
+	 * driver from the socket, we must get out. 
+	 * This never happends but is a sanity check. */
+	if (test_bit(0,&chan->common.common_critical)){
+		return;
+	}
+
+	if (!usr_cmd || !chan->common.sk || !chan->common.func){
+		DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n",
+			(unsigned int)chan->common.sk,
+			(unsigned int)chan->common.func,
+			(unsigned int)usr_cmd); 
+		return;
+	}
+
+	memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); 
+	if (mbox->cmd.length > 0){
+		memcpy(usr_cmd->data, mbox->data, mbox->cmd.length);
+	}
+
+	if (alloc_and_init_skb_buf(card,&skb,len)){
+		printk(KERN_INFO "Delay result: No sock buffers\n");
+		return;
+	}
+
+	memcpy(skb_put(skb,len),&mbox->cmd.command,len);
+	
+	skb->mac.raw = skb->data;
+	skb->pkt_type = WAN_PACKET_CMD;
+			
+	chan->common.func(skb,dev,chan->common.sk);
+}
+
+/*===============================================================
+ * clear_confirm_event
+ *
+ * 	Pass the clear confirmation event up the sock. The
+ *      API will disconnect only after the clear confirmation
+ *      has been received. 
+ *
+ *      Depending on the state, clear confirmation could 
+ *      be an OOB event, or a result of an API command.
+ *===============================================================*/
+
+static int clear_confirm_event (sdla_t *card, TX25Mbox* mb)
+{
+	netdevice_t *dev;
+	x25_channel_t *chan;
+	unsigned char old_state;	
+
+	dev = find_channel(card,mb->cmd.lcn);
+	if (!dev){
+		DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n",
+				card->devname,mb->cmd.lcn);
+		return 0;
+	}
+
+	chan=dev->priv;
+	DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s:  Mbox lcn %i  Chan lcn %i\n",
+			card->devname, dev->name, mb->cmd.lcn, chan->common.lcn);
+
+	/* If not API fall through to default. 
+	 * If API, send the result to a waiting
+         * socket.
+	 */
+	
+	old_state = chan->common.state;
+	set_chan_state(dev, WAN_DISCONNECTED);
+
+	if (chan->common.usedby == API){
+		switch (old_state) {
+
+		case WAN_DISCONNECTING:
+		case WAN_CONNECTING:
+			send_delayed_cmd_result(card,dev,mb);
+			break;
+		case WAN_CONNECTED:
+			send_oob_msg(card,dev,mb);
+			break;
+		}
+		return 1;
+	}
+
+	return 0;
+}
+
+/*===============================================================
+ * send_oob_msg
+ *
+ *    Construct an NEM Message and pass it up the connected
+ *    sock. If the sock is not bounded discard the NEM.
+ *
+ *===============================================================*/
+
+static void send_oob_msg (sdla_t *card, netdevice_t *dev, TX25Mbox *mbox)
+{
+	x25_channel_t *chan = dev->priv;
+	mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox;
+	struct sk_buff *skb;
+	int len=sizeof(x25api_hdr_t)+mbox->cmd.length;
+	x25api_t *api_hdr;
+
+	/* If the sock is in the process of unlinking the
+	 * driver from the socket, we must get out. 
+	 * This never happends but is a sanity check. */
+	if (test_bit(0,&chan->common.common_critical)){
+		return;
+	}
+
+	if (!usr_cmd || !chan->common.sk || !chan->common.func){
+		DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); 
+		return;
+	}
+
+	memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); 
+	if (mbox->cmd.length > 0){
+		memcpy(usr_cmd->data, mbox->data, mbox->cmd.length);
+	}
+
+	if (alloc_and_init_skb_buf(card,&skb,len)){
+		printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname);
+		return;
+	}
+
+	api_hdr = (x25api_t*)skb_put(skb,len); 
+	api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F;
+	api_hdr->hdr.qdm     = mbox->cmd.qdm;
+	api_hdr->hdr.cause   = mbox->cmd.cause;
+	api_hdr->hdr.diagn   = mbox->cmd.diagn;
+	api_hdr->hdr.length  = mbox->cmd.length;
+	api_hdr->hdr.result  = mbox->cmd.result;
+	api_hdr->hdr.lcn     = mbox->cmd.lcn;
+
+	if (mbox->cmd.length > 0){
+		memcpy(api_hdr->data,mbox->data,mbox->cmd.length);
+	}
+	
+	skb->mac.raw = skb->data;
+	skb->pkt_type = WAN_PACKET_ERR;
+			
+	if (chan->common.func(skb,dev,chan->common.sk) < 0){
+		if (bh_enqueue(dev,skb)){
+			printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname);
+                	wan_dev_kfree_skb(skb, FREE_READ);
+		}
+	}
+
+	DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n",
+			card->devname, dev->name, mbox->cmd.lcn);
+}	
+
+/*===============================================================
+ *  alloc_and_init_skb_buf 
+ *
+ *	Allocate and initialize an skb buffer. 
+ *
+ *===============================================================*/
+
+static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len)
+{
+	struct sk_buff *new_skb = *skb;
+
+	new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ);
+	if (new_skb == NULL){
+		printk(KERN_INFO "%s: no socket buffers available!\n",
+			card->devname);
+		return 1;
+	}
+
+	if (skb_tailroom(new_skb) < len){
+		/* No room for the packet. Call off the whole thing! */
+                wan_dev_kfree_skb(new_skb, FREE_READ);
+		printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n"
+			,card->devname);
+		*skb = NULL;
+		return 1;
+	}
+
+	*skb = new_skb;
+	return 0;
+
+}
+
+/*===============================================================
+ *  api_oob_event 
+ *
+ *	Send an OOB event up to the sock 
+ *
+ *===============================================================*/
+
+static void api_oob_event (sdla_t *card,TX25Mbox *mbox)
+{
+	netdevice_t *dev = find_channel(card,mbox->cmd.lcn);
+	x25_channel_t *chan;
+
+	if (!dev)
+		return;
+
+	chan=dev->priv;
+
+	if (chan->common.usedby == API)
+		send_oob_msg(card,dev,mbox);
+	
+}
+
+
+
+
+static int channel_disconnect (sdla_t* card, netdevice_t *dev)
+{
+
+	int err;
+	x25_channel_t *chan = dev->priv;
+
+	DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n",
+				card->devname,dev->name);
+
+	if (chan->common.svc){
+		err = x25_clear_call(card,chan->common.lcn,0,0);
+	}else{
+		/* If channel is PVC or LAPB HDLC, there is no call
+                 * to be cleared, thus drop down to the default
+                 * area 
+	         */
+		err = 1;
+	}
+
+	switch (err){
+	
+		case X25RES_CHANNEL_IN_USE:	
+		case X25RES_NOT_READY:
+			err = TRY_CMD_AGAIN;
+			break;
+		case CMD_OK:
+			DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n",
+						dev->name,chan->common.lcn);
+
+			set_chan_state(dev,WAN_DISCONNECTING);
+			atomic_set(&chan->common.command,0);
+			err = DELAY_RESULT;
+			break;
+		default:
+			/* If LAPB HDLC protocol, bring the whole link down
+                         * once the application terminates 
+			 */
+
+			set_chan_state(dev,WAN_DISCONNECTED);
+
+			if (card->u.x.LAPB_hdlc){
+				DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n");
+				hdlc_link_down (card);
+			}
+			atomic_set(&chan->common.command,0);
+			err = RETURN_RESULT;
+			break;
+	}
+
+	return err;
+}
+
+static void hdlc_link_down (sdla_t *card)
+{
+	TX25Mbox* mbox = card->mbox;
+	int retry = 5;
+	int err=0;
+
+	do {
+		memset(mbox,0,sizeof(TX25Mbox));
+		mbox->cmd.command = X25_HDLC_LINK_DISC;
+		mbox->cmd.length = 1;
+		mbox->data[0]=0;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+	} while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0));
+
+	if (err)
+		printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err);
+
+	disconnect (card);
+	
+}
+
+static int check_bad_command (sdla_t* card, netdevice_t *dev)
+{
+	x25_channel_t *chan = dev->priv;
+	int bad_cmd = 0;
+
+	switch (atomic_read(&chan->common.command)&0x7F){
+
+		case X25_PLACE_CALL:
+			if (chan->common.state != WAN_DISCONNECTED)
+				bad_cmd=1;
+			break;
+		case X25_CLEAR_CALL:
+			if (chan->common.state == WAN_DISCONNECTED)
+				bad_cmd=1;
+			break;
+		case X25_ACCEPT_CALL:
+			if (chan->common.state != WAN_CONNECTING)
+				bad_cmd=1;
+			break;
+		case X25_RESET:
+			if (chan->common.state != WAN_CONNECTED)
+				bad_cmd=1;
+			break;
+		default:
+			bad_cmd=1;
+			break;
+	}
+
+	if (bad_cmd){
+		printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", 
+			card->devname,atomic_read(&chan->common.command),dev->name, 
+			chan->common.lcn, chan->common.state);
+	}
+
+	return bad_cmd;
+}
+
+
+
+/*************************** XPIPEMON FUNCTIONS **************************/
+
+/*==============================================================================
+ * Process UDP call of type XPIPE
+ */
+
+static int process_udp_mgmt_pkt(sdla_t *card)
+{
+	int            c_retry = MAX_CMD_RETRY;
+	unsigned int   len;
+	struct sk_buff *new_skb;
+	TX25Mbox       *mbox = card->mbox;
+	int            err;
+	int            udp_mgmt_req_valid = 1;
+	netdevice_t  *dev;
+        x25_channel_t  *chan;
+	unsigned short lcn;
+	struct timeval tv;
+	
+
+	x25_udp_pkt_t *x25_udp_pkt;
+	x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data;
+
+	dev = card->u.x.udp_dev;
+	chan = dev->priv;
+	lcn = chan->common.lcn;
+
+	switch(x25_udp_pkt->cblock.command) {
+            
+		/* XPIPE_ENABLE_TRACE */
+		case XPIPE_ENABLE_TRACING:
+
+		/* XPIPE_GET_TRACE_INFO */
+		case XPIPE_GET_TRACE_INFO:
+ 
+		/* SET FT1 MODE */
+		case XPIPE_SET_FT1_MODE:
+           
+			if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+                    		++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err;
+				udp_mgmt_req_valid = 0;
+				break;
+			}
+
+		/* XPIPE_FT1_READ_STATUS */
+		case XPIPE_FT1_READ_STATUS:
+
+		/* FT1 MONITOR STATUS */
+		case XPIPE_FT1_STATUS_CTRL:
+			if(card->hw.fwid !=  SFID_X25_508) {
+				++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err;
+				udp_mgmt_req_valid = 0;
+				break;
+			}
+		default:
+			break;
+       	}
+
+	if(!udp_mgmt_req_valid) {
+           	/* set length to 0 */
+		x25_udp_pkt->cblock.length = 0;
+		/* set return code */
+		x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD;
+		
+	} else {   
+        
+		switch (x25_udp_pkt->cblock.command) {
+    
+	
+		case XPIPE_FLUSH_DRIVER_STATS:
+			init_x25_channel_struct(chan);
+			init_global_statistics(card);
+			mbox->cmd.length = 0;
+			break;
+
+
+		case XPIPE_DRIVER_STAT_IFSEND:
+			memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t));
+			mbox->cmd.length = sizeof(if_send_stat_t);
+			x25_udp_pkt->cblock.length =  mbox->cmd.length;	
+			break;
+	
+		case XPIPE_DRIVER_STAT_INTR:
+			memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t));
+                        memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)],
+                                &chan->rx_intr_stat, sizeof(rx_intr_stat_t));
+			
+			mbox->cmd.length = sizeof(global_stats_t) +
+					sizeof(rx_intr_stat_t);
+			x25_udp_pkt->cblock.length =  mbox->cmd.length;
+			break;
+
+		case XPIPE_DRIVER_STAT_GEN:
+                        memcpy(x25_udp_pkt->data,
+                                &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,
+                                sizeof(pipe_mgmt_stat_t));
+
+                        memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
+                               &card->statistics, sizeof(global_stats_t));
+
+                        x25_udp_pkt->cblock.result = 0;
+                        x25_udp_pkt->cblock.length = sizeof(global_stats_t)+
+                                                     sizeof(rx_intr_stat_t);
+                        mbox->cmd.length = x25_udp_pkt->cblock.length;
+                        break;
+
+		case XPIPE_ROUTER_UP_TIME:
+			do_gettimeofday(&tv);
+			chan->router_up_time = tv.tv_sec - chan->router_start_time;
+    	                *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time;	
+			x25_udp_pkt->cblock.length = mbox->cmd.length = 4;
+			x25_udp_pkt->cblock.result = 0;
+			break;
+	
+		default :
+
+			do {
+				memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd));
+				if(mbox->cmd.length){ 
+					memcpy(&mbox->data, 
+					       (char *)x25_udp_pkt->data, 
+					       mbox->cmd.length);
+				}	
+		
+				err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+			} while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0));
+
+
+			if ( err == CMD_OK || 
+			    (err == 1 && 
+			     (mbox->cmd.command == 0x06 || 
+			      mbox->cmd.command == 0x16)  ) ){
+
+				++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK;
+			} else {
+				++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout;
+			}
+
+			  /* copy the result back to our buffer */
+			memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd));
+
+      	         	if(mbox->cmd.length) {
+        	               memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length);
+			}
+			break;
+
+		} //switch
+
+        }
+    
+        /* Fill UDP TTL */
+
+	x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
+        len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length);
+
+
+        if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		
+		err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data);
+		if (!err) 
+			++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed;
+		else
+			++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed;
+	
+	} else {
+
+		/* Allocate socket buffer */
+		if((new_skb = dev_alloc_skb(len)) != NULL) {
+			void *buf;
+
+			/* copy data into new_skb */
+			buf = skb_put(new_skb, len);
+			memcpy(buf, card->u.x.udp_pkt_data, len);
+        
+			/* Decapsulate packet and pass it up the protocol 
+			   stack */
+			new_skb->dev = dev;
+	
+			if (chan->common.usedby == API)
+                        	new_skb->protocol = htons(X25_PROT);
+			else 
+				new_skb->protocol = htons(ETH_P_IP);
+	
+                        new_skb->mac.raw = new_skb->data;
+
+			netif_rx(new_skb);
+			++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack;
+            	
+		} else {
+			++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket;
+			printk(KERN_INFO 
+			"%s: UDP mgmt cmnd, no socket buffers available!\n", 
+			card->devname);
+            	}
+        }
+
+	card->u.x.udp_pkt_lgth = 0;
+
+	return 1;
+}
+
+
+/*==============================================================================
+ * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ?
+ */
+static int udp_pkt_type( struct sk_buff *skb, sdla_t* card )
+{
+	x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data;
+
+        if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
+		(x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
+		(x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
+		(x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
+
+                        if(!strncmp(x25_udp_pkt->wp_mgmt.signature,
+                                UDPMGMT_XPIPE_SIGNATURE, 8)){
+                                return UDP_XPIPE_TYPE;
+			}else{
+				printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n",
+					card->devname);
+			}
+	}
+
+        return UDP_INVALID_TYPE;
+}
+
+
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return nothing.
+ */
+static int reply_udp( unsigned char *data, unsigned int mbox_len ) 
+{
+	unsigned short len, udp_length, temp, ip_length;
+	unsigned long ip_temp;
+	int even_bound = 0;
+
+  
+	x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; 
+
+	/* Set length of packet */
+	len = sizeof(ip_pkt_t)+ 
+	      sizeof(udp_pkt_t)+
+	      sizeof(wp_mgmt_t)+
+	      sizeof(cblock_t)+
+	      mbox_len;
+ 
+
+	/* fill in UDP reply */
+	x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
+  
+	/* fill in UDP length */
+	udp_length = sizeof(udp_pkt_t)+ 
+		     sizeof(wp_mgmt_t)+
+		     sizeof(cblock_t)+
+		     mbox_len; 
+
+
+	/* put it on an even boundary */
+	if ( udp_length & 0x0001 ) {
+		udp_length += 1;
+		len += 1;
+		even_bound = 1;
+	}
+
+	temp = (udp_length<<8)|(udp_length>>8);
+	x25_udp_pkt->udp_pkt.udp_length = temp;
+	 
+	/* swap UDP ports */
+	temp = x25_udp_pkt->udp_pkt.udp_src_port;
+	x25_udp_pkt->udp_pkt.udp_src_port = 
+			x25_udp_pkt->udp_pkt.udp_dst_port; 
+	x25_udp_pkt->udp_pkt.udp_dst_port = temp;
+
+
+
+	/* add UDP pseudo header */
+	temp = 0x1100;
+	*((unsigned short *)
+		(x25_udp_pkt->data+mbox_len+even_bound)) = temp;	
+	temp = (udp_length<<8)|(udp_length>>8);
+	*((unsigned short *)
+		(x25_udp_pkt->data+mbox_len+even_bound+2)) = temp;
+		 
+	/* calculate UDP checksum */
+	x25_udp_pkt->udp_pkt.udp_checksum = 0;
+
+	x25_udp_pkt->udp_pkt.udp_checksum = 
+		calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET);
+
+	/* fill in IP length */
+	ip_length = len;
+	temp = (ip_length<<8)|(ip_length>>8);
+	x25_udp_pkt->ip_pkt.total_length = temp;
+  
+	/* swap IP addresses */
+	ip_temp = x25_udp_pkt->ip_pkt.ip_src_address;
+	x25_udp_pkt->ip_pkt.ip_src_address = 
+				x25_udp_pkt->ip_pkt.ip_dst_address;
+	x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
+
+		 
+	/* fill in IP checksum */
+	x25_udp_pkt->ip_pkt.hdr_checksum = 0;
+	x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t));
+
+	return len;
+} /* reply_udp */
+
+unsigned short calc_checksum (char *data, int len)
+{
+	unsigned short temp; 
+	unsigned long sum=0;
+	int i;
+
+	for( i = 0; i <len; i+=2 ) {
+		memcpy(&temp,&data[i],2);
+		sum += (unsigned long)temp;
+	}
+
+	while (sum >> 16 ) {
+		sum = (sum & 0xffffUL) + (sum >> 16);
+	}
+
+	temp = (unsigned short)sum;
+	temp = ~temp;
+
+	if( temp == 0 ) 
+		temp = 0xffff;
+
+	return temp;	
+}
+
+/*=============================================================================
+ * Store a UDP management packet for later processing.
+ */
+
+static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
+                                netdevice_t *dev, struct sk_buff *skb, int lcn)
+{
+        int udp_pkt_stored = 0;
+
+        if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
+                card->u.x.udp_pkt_lgth = skb->len;
+                card->u.x.udp_type = udp_type;
+                card->u.x.udp_pkt_src = udp_pkt_src;
+                card->u.x.udp_lcn = lcn;
+		card->u.x.udp_dev = dev;
+                memcpy(card->u.x.udp_pkt_data, skb->data, skb->len);
+                card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT;
+                udp_pkt_stored = 1;
+
+        }else{
+                printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", 
+							card->devname,lcn);
+	}
+
+        if(udp_pkt_src == UDP_PKT_FRM_STACK){
+                wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+                wan_dev_kfree_skb(skb, FREE_READ);
+	}
+
+        return(udp_pkt_stored);
+}
+
+
+
+/*=============================================================================
+ * Initial the ppp_private_area structure.
+ */
+static void init_x25_channel_struct( x25_channel_t *chan )
+{
+	memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t));
+	memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t));
+	memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t));
+}
+
+/*============================================================================
+ * Initialize Global Statistics
+ */
+static void init_global_statistics( sdla_t *card )
+{
+	memset(&card->statistics.isr_entry,0,sizeof(global_stats_t));
+}
+
+
+/*===============================================================
+ * SMP Support
+ * ==============================================================*/
+
+static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags)
+{
+	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
+}
+static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags)
+{
+	spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
+}
+
+/*===============================================================
+ * x25_timer_routine
+ *
+ * 	A more efficient polling routine.  Each half a second
+ * 	queue a polling task. We want to do the polling in a 
+ * 	task not timer, because timer runs in interrupt time.
+ *
+ * 	FIXME Polling should be rethinked.
+ *==============================================================*/
+
+static void x25_timer_routine(unsigned long data)
+{
+	sdla_t *card = (sdla_t*)data;
+
+	if (!card->wandev.dev){
+		printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n",
+				card->devname);
+		return;
+	}
+
+	if (card->open_cnt != card->u.x.num_of_ch){
+		printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n",
+				card->devname);
+		return;
+	}
+
+	if (test_bit(PERI_CRIT,&card->wandev.critical)){
+		printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n",
+				card->devname);
+		return;
+	}
+	
+	if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){
+		trigger_x25_poll(card);
+	}
+	
+	card->u.x.x25_timer.expires=jiffies+(HZ>>1);
+	add_timer(&card->u.x.x25_timer);
+	return;
+}
+
+void disable_comm_shutdown(sdla_t *card)
+{
+	TX25Mbox* mbox = card->mbox;
+	int err;
+
+	/* Turn of interrutps */
+	mbox->data[0] = 0;
+	if (card->hw.fwid == SFID_X25_508){
+		mbox->data[1] = card->hw.irq;
+		mbox->data[2] = 2;
+		mbox->cmd.length = 3;
+	}else {
+	 	mbox->cmd.length  = 1;
+	}
+	mbox->cmd.command = X25_SET_INTERRUPT_MODE;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	if (err)
+		printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err);
+
+	/* Bring down HDLC */
+	mbox->cmd.command = X25_HDLC_LINK_CLOSE;
+	mbox->cmd.length  = 0;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	if (err)
+		printk(KERN_INFO "LINK CLOSED FAILED %x\n",err);
+
+
+	/* Brind down DTR */
+	mbox->data[0] = 0;
+	mbox->data[2] = 0;
+	mbox->data[1] = 0x01;
+	mbox->cmd.length  = 3;
+	mbox->cmd.command = X25_SET_GLOBAL_VARS;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	if (err)
+		printk(KERN_INFO "DTR DOWN FAILED %x\n",err);
+
+}
 
 /****** End *****************************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
--- v2.4.3/linux/drivers/net/wan/sdladrv.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/net/wan/sdladrv.c	Thu Apr 12 12:11:39 2001
@@ -6,13 +6,19 @@
 *
 * Author:	Gideon Hack	
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Mar 20, 2001  Nenad Corbic	Added the auto_pci_cfg filed, to support
+*                               the PCISLOT #0. 
+* Apr 04, 2000  Nenad Corbic	Fixed the auto memory detection code.
+*                               The memory test at address 0xC8000.
+* Mar 09, 2000  Nenad Corbic 	Added Gideon's Bug Fix: clear pci
+*                               interrupt flags on initial load.
 * Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
 *				Updates for Linux 2.2.X kernels.	
 * Sep 17, 1998	Jaspreet Singh	Updates for linux 2.2.X kernels
@@ -84,7 +90,6 @@
 
 #if	defined(_LINUX_)	/****** Linux *******************************/
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -102,7 +107,16 @@
 #define _OUTB(port, byte)	(outb((byte),(port)))
 #define	SYSTEM_TICK		jiffies
 
-#include <linux/init.h>
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+ #include <linux/init.h>
+#else
+ #include <linux/bios32.h>/* BIOS32, PCI BIOS functions and definitions */
+ #define ioremap vremap
+ #define iounmap vfree
+ extern void * vremap (unsigned long offset, unsigned long size);
+ extern void vfree (void *addr);
+#endif
 
 #elif	defined(_SCO_UNIX_)	/****** SCO Unix ****************************/
 
@@ -190,16 +204,21 @@
 static unsigned check_memregion (void* ptr, unsigned len);
 static unsigned	test_memregion (void* ptr, unsigned len);
 static unsigned short checksum (unsigned char* buf, unsigned len);
+static int init_pci_slot(sdlahw_t *);
+
+static int pci_probe(sdlahw_t *hw);
 
 /****** Global Data **********************************************************
  * Note: All data must be explicitly initialized!!!
  */
 
+#ifdef LINUX_2_4
 static struct pci_device_id sdladrv_pci_tbl[] __initdata = {
 	{ V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
 	{ }			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl);
+#endif
 
 /* private data */
 static char modname[]	= "sdladrv";
@@ -298,6 +317,8 @@
 	0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
 };
 
+static int pci_slot_ar[MAX_S514_CARDS];
+
 /******* Kernel Loadable Module Entry Points ********************************/
 
 /*============================================================================
@@ -314,15 +335,24 @@
 #ifdef MODULE
 int init_module (void)
 #else
-int __init wanpipe_init(void)
+int sdladrv_init(void)
 #endif
 {
+	int i=0;
+
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, MOD_VERSION, MOD_RELEASE, copyright);
 	exec_idle = calibrate_delay(EXEC_DELAY);
 #ifdef WANDEBUG	
 	printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
 #endif	
+
+	/* Initialize the PCI Card array, which
+         * will store flags, used to mark 
+         * card initialization state */
+	for (i=0; i<MAX_S514_CARDS; i++)
+		pci_slot_ar[i] = 0xFF;
+
 	return 0;
 }
 
@@ -350,7 +380,9 @@
  *		< 0	error
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
 EXPORT_SYMBOL(sdla_setup);
+#endif
 
 int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
 {
@@ -361,7 +393,7 @@
 
 	if (sdla_detect(hw)) {
                 if(hw->type != SDLA_S514)
-                        printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n",
+                        printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n",
                         modname, hw->port);
 		return -EINVAL;
 	}
@@ -410,7 +442,7 @@
 
                 /* Verify IRQ configuration options */
                 if (!get_option_index(irq_opt, hw->irq)) {
-                        printk(KERN_ERR "%s: IRQ %d is illegal!\n",
+                        printk(KERN_INFO "%s: IRQ %d is illegal!\n",
                         	modname, hw->irq);
                       return -EINVAL;
                 } 
@@ -420,7 +452,7 @@
                         hw->pclk = pclk_opt[1];  /* use default */
         
                 else if (!get_option_index(pclk_opt, hw->pclk)) {
-                        printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
+                        printk(KERN_INFO "%s: CPU clock %u is illegal!\n",
 				modname, hw->pclk);
                         return -EINVAL;
                 } 
@@ -431,7 +463,7 @@
                 if (hw->dpmbase == 0) {
                         err = sdla_autodpm(hw);
                         if (err) {
-                                printk(KERN_ERR
+                                printk(KERN_INFO
 				"%s: can't find available memory region!\n",
 					modname);
                                 return err;
@@ -439,13 +471,13 @@
                 }
                 else if (!get_option_index(dpmbase_opt,
 			virt_to_phys(hw->dpmbase))) {
-                        printk(KERN_ERR
+                        printk(KERN_INFO
 				"%s: memory address 0x%lX is illegal!\n",
 				modname, virt_to_phys(hw->dpmbase));
                         return -EINVAL;
                 }               
                 else if (sdla_setdpm(hw)) {
-                        printk(KERN_ERR
+                        printk(KERN_INFO
 			"%s: 8K memory region at 0x%lX is not available!\n",
 				modname, virt_to_phys(hw->dpmbase));
                         return -EINVAL;
@@ -453,13 +485,27 @@
                 printk(KERN_INFO
 			"%s: dual-port memory window is set at 0x%lX.\n",
 				modname, virt_to_phys(hw->dpmbase));
+
+
+		/* If we find memory in 0xE**** Memory region, 
+                 * warn the user to disable the SHADOW RAM.  
+                 * Since memory corruption can occur if SHADOW is
+                 * enabled. This can causes random crashes ! */
+		if (virt_to_phys(hw->dpmbase) >= 0xE0000){
+			printk(KERN_WARNING "\n%s: !!!!!!!!  WARNING !!!!!!!!\n",modname);
+			printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n",
+						modname, virt_to_phys(hw->dpmbase));
+			printk(KERN_WARNING "         Please disable the SHADOW RAM, otherwise\n");
+			printk(KERN_WARNING "         your system might crash randomly from time to time !\n");
+			printk(KERN_WARNING "%s: !!!!!!!!  WARNING !!!!!!!!\n\n",modname);
+		}
         }
 
 	else {
 		hw->memory = test_memregion((void*)hw->dpmbase, 
 			MAX_SIZEOF_S514_MEMORY);
 		if(hw->memory < (256 * 1024)) {
-			printk(KERN_ERR
+			printk(KERN_INFO
 				"%s: error in testing S514 memory (0x%lX)\n",
 				modname, hw->memory);
 			sdla_down(hw);
@@ -481,7 +527,9 @@
  * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_down);
+#endif
 
 int sdla_down (sdlahw_t* hw)
 {
@@ -523,9 +571,10 @@
                 *(char *)hw->vector = S514_CPU_HALT;
         	CPU_no = hw->S514_cpu_no[0];
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 		/* disable the PCI IRQ and disable memory access */
                 pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config);
-	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : 			~PCI_DISABLE_IRQ_CPU_B;
+	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A :	~PCI_DISABLE_IRQ_CPU_B;
                 pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config);
 		read_S514_int_stat(hw, &int_status);
 		S514_intack(hw, int_status);
@@ -535,6 +584,22 @@
 		else
                         pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD,
 				PCI_CPU_B_MEM_DISABLE);
+#else
+                /* disable the PCI IRQ and disable memory access */
+             	pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+			PCI_INT_CONFIG, &int_config);
+	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A :	~PCI_DISABLE_IRQ_CPU_B;
+        	pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+			PCI_INT_CONFIG, int_config);
+                read_S514_int_stat(hw, &int_status);
+                S514_intack(hw, int_status);
+     		// disable PCI memory access
+		if(CPU_no == S514_CPU_A)
+	     		pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func,
+				PCI_MAP0_DWORD, PCI_CPU_A_MEM_DISABLE);
+		else
+                        pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func,							PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE);
+#endif
 
 		/* free up the allocated virtual memory */
  		iounmap((void *)hw->dpmbase);
@@ -552,7 +617,9 @@
  * Map shared memory window into SDLA address space.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_mapmem);
+#endif
 
 int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
 {
@@ -613,7 +680,9 @@
  * Enable interrupt generation.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_inten);
+#endif
 
 int sdla_inten (sdlahw_t* hw)
 {
@@ -669,7 +738,9 @@
  * Disable interrupt generation.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_intde);
+#endif
 
 int sdla_intde (sdlahw_t* hw)
 {
@@ -724,7 +795,9 @@
  * Acknowledge SDLA hardware interrupt.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_intack);
+#endif
 
 int sdla_intack (sdlahw_t* hw)
 {
@@ -774,11 +847,18 @@
  * Acknowledge S514 hardware interrupt.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(S514_intack);
+#endif
 
 void S514_intack (sdlahw_t* hw, u32 int_status)
 {
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+#else
+	pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+                PCI_INT_STATUS, int_status);
+#endif
 }
 
 
@@ -786,11 +866,18 @@
  * Read the S514 hardware interrupt status.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(read_S514_int_stat);
+#endif
 
 void read_S514_int_stat (sdlahw_t* hw, u32* int_status)
 {
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+#else
+        pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_STATUS,
+		int_status);
+#endif
 }
 
 
@@ -798,7 +885,9 @@
  * Generate an interrupt to adapter's CPU.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_intr);
+#endif
 
 int sdla_intr (sdlahw_t* hw)
 {
@@ -842,7 +931,9 @@
  * o Return number of loops made, or 0 if command timed out.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_exec);
+#endif
 
 int sdla_exec (void* opflag)
 {
@@ -878,7 +969,9 @@
  * interrupt routines are accessing adapter shared memory.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_peek);
+#endif
 
 int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
 {
@@ -960,7 +1053,9 @@
  * interrupt routines are accessing adapter shared memory.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_poke);
+#endif
  
 int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
 {
@@ -1124,7 +1219,11 @@
 		return -EINVAL;
 	}
 
-	for (i = opt[0]; i && err; --i) {
+	/* Start testing from 8th position, address
+         * 0xC8000 from the 508 address table. 
+         * We don't want to test A**** addresses, since
+         * they are usually used for Video */
+	for (i = 8; i <= opt[0] && err; i++) {
 		hw->dpmbase = phys_to_virt(opt[i]);
 		err = sdla_setdpm(hw);
 	}
@@ -1176,14 +1275,14 @@
 
 	/* Verify firmware signature */
 	if (strcmp(sfm->signature, SFM_SIGNATURE)) {
-		printk(KERN_ERR "%s: not SDLA firmware!\n",
+		printk(KERN_INFO "%s: not SDLA firmware!\n",
 			modname);
 		return -EINVAL;
 	}
 
 	/* Verify firmware module format version */
 	if (sfm->version != SFM_VERSION) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"%s: firmware format %u rejected! Expecting %u.\n",
 			modname, sfm->version, SFM_VERSION);
 		return -EINVAL;
@@ -1193,7 +1292,7 @@
 	if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
 		(checksum((void*)&sfm->info,
 		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) {
-		printk(KERN_ERR "%s: firmware corrupted!\n", modname);
+		printk(KERN_INFO "%s: firmware corrupted!\n", modname);
 		return -EINVAL;
 	}
 
@@ -1211,19 +1310,18 @@
 	 */
 	for (i = 0;
 	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
-	     ++i)
-	;
+	     ++i);
+	
 	if (i == SFM_MAX_SDLA) {
-		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
+		printk(KERN_INFO "%s: firmware is not compatible with S%u!\n",
 			modname, hw->type);
-		;
 		return -EINVAL;
 	}
 
 
 	/* Make sure there is enough on-board memory */
 	if (hw->memory < sfm->info.memsize) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"%s: firmware needs %lu bytes of on-board memory!\n",
 			modname, sfm->info.memsize);
 		return -EINVAL;
@@ -1231,7 +1329,7 @@
 
 	/* Move code onto adapter */
 	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) {
-		printk(KERN_ERR "%s: failed to load code segment!\n",
+		printk(KERN_INFO "%s: failed to load code segment!\n",
 			modname);
 		return -EIO;
 	}
@@ -1239,14 +1337,14 @@
 	/* Prepare boot-time configuration data and kick-off CPU */
 	sdla_bootcfg(hw, &sfm->info);
 	if (sdla_start(hw, sfm->info.startoffs)) {
-		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
+		printk(KERN_INFO "%s: Damn... Adapter won't start!\n",
 			modname);
 		return -EIO;
 	}
 
 	/* position DPM window over the mailbox and enable interrupts */
         if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) {
-		printk(KERN_ERR "%s: adapter hardware failure!\n",
+		printk(KERN_INFO "%s: adapter hardware failure!\n",
 			modname);
 		return -EIO;
 	}
@@ -1858,22 +1956,30 @@
  */
 static int detect_s514 (sdlahw_t* hw)
 {
-	unsigned char CPU_no, slot_no;
+	unsigned char CPU_no, slot_no, auto_slot_cfg;
 	int number_S514_cards = 0;
 	u32 S514_mem_base_addr = 0;
 	u32 ut_u32;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct pci_dev *pci_dev;
+#else
+	u8 ut_u8;
+#endif
 
 
 #ifdef CONFIG_PCI
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         if(!pci_present())
+#else
+	if(!pcibios_present())
+#endif
         {
-                printk(KERN_ERR "%s: PCI BIOS not present!\n", modname);
+                printk(KERN_INFO "%s: PCI BIOS not present!\n", modname);
                 return 0;
         }
 #else
-        printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname);
+        printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname);
         return 0;
 #endif
 
@@ -1883,10 +1989,17 @@
 	*/
 	CPU_no = hw->S514_cpu_no[0];
 	slot_no = hw->S514_slot_no;
-	
-	printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n",
-		modname, CPU_no, slot_no);
+	auto_slot_cfg = hw->auto_pci_cfg;
 
+	if (auto_slot_cfg){
+		printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n",
+		modname, CPU_no);
+
+	}else{
+		printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n",
+		modname, CPU_no, slot_no);
+	}
+	
 	/* check to see that CPU A or B has been selected in 'router.conf' */
 	switch(CPU_no) {
 		case S514_CPU_A:
@@ -1894,9 +2007,9 @@
 			break;
 	
 		default:
-			printk(KERN_ERR "%s: S514 CPU definition invalid.\n", 
+			printk(KERN_INFO "%s: S514 CPU definition invalid.\n", 
 				modname);
-			printk(KERN_ERR "Must be 'A' or 'B'\n");
+			printk(KERN_INFO "Must be 'A' or 'B'\n");
 			return 0;
 	}
 
@@ -1904,50 +2017,110 @@
 	if(!number_S514_cards)
 		return 0;
 
-	/* we are using a single S514 adapter with a slot of 0 so re-read the */	/* location of this adapter */
-	if((number_S514_cards == 1) && !slot_no) {	
+	/* we are using a single S514 adapter with a slot of 0 so re-read the */	
+	/* location of this adapter */
+	if((number_S514_cards == 1) && auto_slot_cfg) {	
         	number_S514_cards = find_s514_adapter(hw, 1);
 		if(!number_S514_cards) {
-			printk(KERN_ERR "%s: Error finding PCI card\n",
+			printk(KERN_INFO "%s: Error finding PCI card\n",
 				modname);
 			return 0;
 		}
 	}
 
+      #if defined(LINUX_2_4)
 	pci_dev = hw->pci_dev;
 	/* read the physical memory base address */
 	S514_mem_base_addr = (CPU_no == S514_CPU_A) ? 
 		(pci_dev->resource[1].start) :
 		(pci_dev->resource[2].start);
+	
+      #elif defined (LINUX_2_1)
+	pci_dev = hw->pci_dev;
+	/* read the physical memory base address */
+	S514_mem_base_addr = (CPU_no == S514_CPU_A) ? 
+		(pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK) :
+		(pci_dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+	
+      #else
+	pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+		(CPU_no == S514_CPU_A) ? PCI_MEM_BASE0_DWORD :
+		PCI_MEM_BASE1_DWORD, &S514_mem_base_addr);
+      #endif
 
 	printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n",
 		modname, S514_mem_base_addr);
 	if(!S514_mem_base_addr) {
 		if(CPU_no == S514_CPU_B)
-			printk(KERN_ERR "%s: CPU #B not present on the card\n", 				modname);
+			printk(KERN_INFO "%s: CPU #B not present on the card\n", 				modname);
 		else
-			printk(KERN_ERR "%s: No PCI memory allocated to card\n",				modname);
+			printk(KERN_INFO "%s: No PCI memory allocated to card\n",				modname);
 		return 0;
 	}
 
 	/* enable the PCI memory */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	pci_read_config_dword(pci_dev, 
 		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
 		&ut_u32);
 	pci_write_config_dword(pci_dev,
 		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
 		(ut_u32 | PCI_MEMORY_ENABLE));
+#else
+        pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+		&ut_u32); 
+        pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+		(ut_u32 | PCI_MEMORY_ENABLE));
+#endif
 
 	/* check the IRQ allocated and enable IRQ usage */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	if(!(hw->irq = pci_dev->irq)) {
-		printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n",
+		printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
 			modname);
                 return 0;
 	}
+
+	/* BUG FIX : Mar 6 2000
+ 	 * On a initial loading of the card, we must check
+         * and clear PCI interrupt bits, due to a reset
+         * problem on some other boards.  i.e. An interrupt
+         * might be pending, even after system bootup, 
+         * in which case, when starting wanrouter the machine
+         * would crash. 
+	 */
+	if (init_pci_slot(hw))
+		return 0;
+
         pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32);
         ut_u32 |= (CPU_no == S514_CPU_A) ?
                 PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
         pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32);
+#else
+	/* the INTPIN must not be 0 - if it is, then the S514 adapter is not */
+	/* configured for IRQ usage */
+	pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+		PCI_INT_PIN_BYTE, &ut_u8);
+        if(!ut_u8) {
+                printk(KERN_INFO "%s: invalid setting for INTPIN on S514 card\n", modname);
+                printk(KERN_INFO "Please contact your Sangoma representative\n");
+                return 0;
+        }
+        pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+		PCI_INT_LINE_BYTE, (unsigned char *)&hw->irq);
+        if(hw->irq == PCI_IRQ_NOT_ALLOCATED) {
+                printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
+			modname);
+                return 0;
+        }
+	pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_CONFIG, &ut_u32);
+	ut_u32 |= (CPU_no == S514_CPU_A) ?
+		PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
+        pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, 
+		PCI_INT_CONFIG, ut_u32);
+#endif
 
 	printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n",
 		modname, hw->irq);
@@ -1961,7 +2134,7 @@
 		(unsigned long)16);
      
         if(!hw->dpmbase || !hw->vector) {
-		printk(KERN_ERR "%s: PCI virtual memory allocation failed\n",
+		printk(KERN_INFO "%s: PCI virtual memory allocation failed\n",
 			modname);
                 return 0;
 	}
@@ -1983,49 +2156,99 @@
 	char S514_found_in_slot = 0;
         u16 PCI_subsys_vendor;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         struct pci_dev *pci_dev = NULL;
+#else
+        int pci_index;
+#endif
  
        slot_no = hw->S514_slot_no;
   
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
         	!= NULL) {
-		if (pci_enable_device(pci_dev))
-			continue;
-		PCI_subsys_vendor = pci_dev->subsystem_vendor;
-                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                
+		pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+                        &PCI_subsys_vendor);
+                
+		if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
                 	continue;
-        	hw->pci_dev = pci_dev;
+        	
+		hw->pci_dev = pci_dev;
+		
 		if(find_first_S514_card)
 			return(1);
+		
                 number_S514_cards ++;
-                printk(KERN_INFO
+                
+		printk(KERN_INFO
 			"%s: S514 card found, slot #%d (devfn 0x%X)\n",
                         modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
 			pci_dev->devfn);
-                if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) ==
-                        slot_no)) {
+		
+		if (hw->auto_pci_cfg){
+			hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK);
+			slot_no = hw->S514_slot_no;
+			
+		}else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){
+                        S514_found_in_slot = 1;
+                        break;
+                }
+        }
+
+#else
+	//LINUX VERSION 2.0.X 
+        for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) {
+                if (pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index,
+                        &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) {
+                                break;
+                }
+                
+		pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func,
+                        PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor);
+                
+		if (PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                        continue;
+                
+		if (find_first_S514_card)
+                        return(1);
+           	
+		number_S514_cards ++;
+		
+                printk(KERN_INFO "%s: S514 card found, bus #%d, slot #%d\n",
+                        modname, hw->pci_bus,
+                        ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK));
+
+		if (hw->auto_pci_cfg){
+			hw->S514_slot_no = ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK)
+			slot_no = hw->S514_slot_no;
+				
+		}else if (((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) == slot_no) {
                         S514_found_in_slot = 1;
                         break;
                 }
         }
+#endif
 
 	/* if no S514 adapter has been found, then exit */
-        if(!number_S514_cards) {
-                printk(KERN_ERR "%s: no S514 adapters found\n", modname);
+        if (!number_S514_cards) {
+                printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname);
                 return 0;
         }
         /* if more than one S514 card has been found, then the user must have */        /* defined a slot number so that the correct adapter is used */
-        else if((number_S514_cards > 1) && !slot_no) {
-                printk(KERN_ERR "%s: More than one S514 adapter found\n",
-                        modname);
-                printk(KERN_ERR "Define a PCI slot number for this adapter\n");
+        else if ((number_S514_cards > 1) && hw->auto_pci_cfg) {
+                printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n"
+				 "%s:        More than one S514 adapter found.\n"
+				 "%s:        Disable the Autodetect feature and supply\n"
+				 "%s:        the PCISLOT numbers for each card.\n",
+                        modname,modname,modname,modname);
                 return 0;
         }
         /* if the user has specified a slot number and the S514 adapter has */
         /* not been found in that slot, then exit */
-        else if (slot_no && !S514_found_in_slot) {
-                printk(KERN_ERR
-			"%s: S514 card not found in specified slot #%d\n",
+        else if (!hw->auto_pci_cfg && !S514_found_in_slot) {
+                printk(KERN_INFO
+			"%s: Error, S514 card not found in specified slot #%d\n",
                         modname, slot_no);
                 return 0;
         }
@@ -2138,5 +2361,170 @@
 	return crc;
 }
 
+static int init_pci_slot(sdlahw_t *hw)
+{
+
+	u32 int_status;
+	int volatile found=0;
+	int i=0;
+
+	/* Check if this is a very first load for a specific
+         * pci card. If it is, clear the interrput bits, and
+         * set the flag indicating that this card was initialized.
+	 */
+	
+	for (i=0; (i<MAX_S514_CARDS) && !found; i++){
+		if (pci_slot_ar[i] == hw->S514_slot_no){
+			found=1;
+			break;
+		}
+		if (pci_slot_ar[i] == 0xFF){
+			break;
+		}
+	}
+
+	if (!found){
+		read_S514_int_stat(hw,&int_status);
+		S514_intack(hw,int_status);
+		if (i == MAX_S514_CARDS){
+			printk(KERN_INFO "%s: Critical Error !!!\n",modname);
+			printk(KERN_INFO 
+				"%s: Number of Sangoma PCI cards exceeded maximum limit.\n",
+					modname);
+			printk(KERN_INFO "Please contact Sangoma Technologies\n");
+			return 1;
+		}
+		pci_slot_ar[i] = hw->S514_slot_no;
+	}
+	return 0;
+}
+
+static int pci_probe(sdlahw_t *hw)
+{
+
+        unsigned char slot_no;
+        int number_S514_cards = 0;
+        u16 PCI_subsys_vendor;
+	u16 PCI_card_type;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+        struct pci_dev *pci_dev = NULL;
+	struct pci_bus *bus = NULL;
+#else
+        int pci_index;
+	u8 irq;
+#endif
+ 
+       slot_no = 0;
+  
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
+        	!= NULL) {
+		
+                pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+                        &PCI_subsys_vendor);
+		
+                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                	continue;
+
+		pci_read_config_word(pci_dev, PCI_CARD_TYPE,
+                        &PCI_card_type);
+	
+		bus = pci_dev->bus;
+		
+		/* A dual cpu card can support up to 4 physical connections,
+		 * where a single cpu card can support up to 2 physical
+		 * connections.  The FT1 card can only support a single 
+		 * connection, however we cannot distinguish between a Single
+		 * CPU card and an FT1 card. */
+		if (PCI_card_type == S514_DUAL_CPU){
+                	number_S514_cards += 4;
+			 printk(KERN_INFO
+				"wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+                        	bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+				pci_dev->irq);
+		}else{
+			number_S514_cards += 2;
+			printk(KERN_INFO
+				"wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+                        	bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+				pci_dev->irq);
+		}
+        }
+
+#else
+        for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) {
+		
+                if(pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index,
+                        &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) {
+                                break;
+                }
+                pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func,
+                        PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor);
+                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                        continue;
+		
+		pcibios_read_config_word(hw->pci_bus,hw->pci_dev_func,PCI_CARD_TYPE,
+                        &PCI_card_type);
+
+		pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+				PCI_INT_LINE_BYTE, &irq);
+
+		/* A dual cpu card can support up to 4 physical connections,
+		 * where a single cpu card can support up to 2 physical
+		 * connections.  The FT1 card can only support a single 
+		 * connection, however we cannot distinguish between a Single
+		 * CPU card and an FT1 card. */
+		if (PCI_card_type == S514_DUAL_CPU){
+                	number_S514_cards += 4;
+			 printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+                        	modname, hw->pci_bus,
+                        	((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq);
+		}else{
+			printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+                        	modname, hw->pci_bus,
+                        	((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq);
+			number_S514_cards += 2;
+		}
+        }
+#endif
+
+	return number_S514_cards;
+
+}
+
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+EXPORT_SYMBOL(wanpipe_hw_probe);
+#endif
+
+unsigned wanpipe_hw_probe(void)
+{
+	sdlahw_t hw;
+	unsigned* opt = s508_port_options; 
+	unsigned cardno=0;
+	int i;
+	
+	memset(&hw, 0, sizeof(hw));
+	
+	for (i = 1; i <= opt[0]; i++) {
+		if (detect_s508(opt[i])){
+			/* S508 card can support up to two physical links */
+			cardno+=2;
+			printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]);
+		}
+	}
+
+      #ifdef CONFIG_PCI
+	hw.S514_slot_no = 0;
+	cardno += pci_probe(&hw);
+      #else
+	printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n");
+	printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n");
+      #endif
+
+	return cardno;
+}
 
 /****** End *****************************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c
--- v2.4.3/linux/drivers/net/wan/sdlamain.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/sdlamain.c	Wed Apr 18 11:49:14 2001
@@ -1,16 +1,28 @@
-/*****************************************************************************
+/****************************************************************************
 * sdlamain.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  Main module.
 *
 * Author:	Nenad Corbic	<ncorbic@sangoma.com>
 *		Gideon Hack	
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Dec 22, 2000  Nenad Corbic	Updated for 2.4.X kernels.
+* 				Removed the polling routine.
+* Nov 13, 2000  Nenad Corbic	Added hw probing on module load and dynamic
+* 				device allocation. 
+* Nov 7,  2000  Nenad Corbic	Fixed the Multi-Port PPP for kernels
+*                               2.2.16 and above.
+* Aug 2,  2000  Nenad Corbic	Block the Multi-Port PPP from running on
+*  			        kernels 2.2.16 or greater.  The SyncPPP 
+*  			        has changed.
+* Jul 25, 2000  Nenad Corbic	Updated the Piggiback support for MultPPPP.
+* Jul 13, 2000	Nenad Corbic	Added Multi-PPP support.
+* Feb 02, 2000  Nenad Corbic    Fixed up piggyback probing and selection.
 * Sep 23, 1999  Nenad Corbic    Added support for SMP
 * Sep 13, 1999  Nenad Corbic	Each port is treated as a separate device.
 * Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
@@ -39,17 +51,125 @@
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/module.h>	/* support for loadable modules */
 #include <linux/ioport.h>	/* request_region(), release_region() */
-#include <linux/tqueue.h>	/* for kernel task queues */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
-#include <asm/uaccess.h>	/* kernel <-> user copy */
+
+#include <linux/in.h>
 #include <asm/io.h>		/* phys_to_virt() */
 #include <linux/pci.h>
 #include <linux/sdlapci.h>
+#include <linux/if_wanpipe_common.h>
+
+#if defined(LINUX_2_4)
+
+ #include <asm/uaccess.h>	/* kernel <-> user copy */
+ #include <linux/inetdevice.h>
+ #define netdevice_t struct net_device 
+
+#elif defined(LINUX_2_1)
+
+ #include <asm/uaccess.h>	/* kernel <-> user copy */
+ #include <linux/inetdevice.h>
+ #define netdevice_t struct device 
+
+#else
+
+ #include <asm/segment.h>
+ #define devinet_ioctl(x,y) dev_ioctl(x,y)
+ #define netdevice_t struct device 
+ #define test_and_set_bit set_bit
+ typedef unsigned long mm_segment_t; 
+#endif
+
+#include <linux/ip.h>
+#include <net/route.h>
+ 
+#define KMEM_SAFETYZONE 8
+
+
+#ifndef CONFIG_WANPIPE_FR
+  #define wpf_init(a,b) (-EPROTONOSUPPORT) 
+#endif
+
+#ifndef CONFIG_WANPIPE_CHDLC
+ #define wpc_init(a,b) (-EPROTONOSUPPORT) 
+#endif
+
+#ifndef CONFIG_WANPIPE_X25
+ #define wpx_init(a,b) (-EPROTONOSUPPORT) 
+#endif
+ 
+#ifndef CONFIG_WANPIPE_PPP
+ #define wpp_init(a,b) (-EPROTONOSUPPORT) 
+#endif
+
+#ifndef CONFIG_WANPIPE_MULTPPP 
+ #define wsppp_init(a,b) (-EPROTONOSUPPORT) 
+#endif
+ 
+ 
+/***********FOR DEBUGGING PURPOSES*********************************************
+static void * dbg_kmalloc(unsigned int size, int prio, int line) {
+	int i = 0;
+	void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio);
+	char * c1 = v;	
+	c1 += sizeof(unsigned int);
+	*((unsigned int *)v) = size;
+
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D';
+		c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F';
+		c1 += 8;
+	}
+	c1 += size;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G';
+		c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L';
+		c1 += 8;
+	}
+	v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8;
+	printk(KERN_INFO "line %d  kmalloc(%d,%d) = %p\n",line,size,prio,v);
+	return v;
+}
+static void dbg_kfree(void * v, int line) {
+	unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8));
+	unsigned int size = *sp;
+	char * c1 = ((char *)v) - KMEM_SAFETYZONE*8;
+	int i = 0;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		if (   c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D'
+		    || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') {
+			printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v);
+			printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
+			                c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
+		}
+		c1 += 8;
+	}
+	c1 += size;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		if (   c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G'
+		    || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L'
+		   ) {
+			printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v);
+			printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
+			                c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
+		}
+		c1 += 8;
+	}
+	printk(KERN_INFO "line %d  kfree(%p)\n",line,v);
+	v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8);
+	kfree(v);
+}
+
+#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
+#define kfree(x) dbg_kfree(x,__LINE__)
+******************************************************************************/
+
+
 
 /****** Defines & Macros ****************************************************/
 
@@ -61,7 +181,7 @@
 
 #define	DRV_VERSION	5		/* version number */
 #define	DRV_RELEASE	0		/* release (minor version) number */
-#define	MAX_CARDS	8		/* max number of adapters */
+#define	MAX_CARDS	16		/* max number of adapters */
 
 #ifndef	CONFIG_WANPIPE_CARDS		/* configurable option */
 #define	CONFIG_WANPIPE_CARDS 1
@@ -86,12 +206,16 @@
 
 /* IOCTL handlers */
 static int ioctl_dump	(sdla_t* card, sdla_dump_t* u_dump);
-static int ioctl_exec	(sdla_t* card, sdla_exec_t* u_exec);
+static int ioctl_exec	(sdla_t* card, sdla_exec_t* u_exec, int);
 
 /* Miscellaneous functions */
 STATIC void sdla_isr	(int irq, void* dev_id, struct pt_regs *regs);
-STATIC void sdla_poll	(void* data);
 static void release_hw  (sdla_t *card);
+static void run_wanpipe_tq (unsigned long);
+
+static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*);
+static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*);
+
 
 /****** Global Data **********************************************************
  * Note: All data must be explicitly initialized!!!
@@ -100,13 +224,41 @@
 /* private data */
 static char drvname[]	= "wanpipe";
 static char fullname[]	= "WANPIPE(tm) Multiprotocol Driver";
-static char copyright[]	= "(c) 1995-1999 Sangoma Technologies Inc.";
-static int ncards = CONFIG_WANPIPE_CARDS;
-static int active;			/* number of active cards */
-static sdla_t* card_array;	/* adapter data space */
+static char copyright[]	= "(c) 1995-2000 Sangoma Technologies Inc.";
+static int ncards = 0; 
+static sdla_t* card_array = NULL;	/* adapter data space */
+
+/* Wanpipe's own task queue, used for all API's.
+ * All protocol specific tasks will be instered
+ * into "wanpipe_tq_custom" task_queue. 
+
+ * On each rx_interrupt, the whole task queue
+ * (wanpipe_tq_custom) will be queued into 
+ * IMMEDIATE_BH via wanpipe_mark_bh() call. 
+ 
+ * The IMMEDIATE_BH will execute run_wanpipe_tq() 
+ * function, which will execute all pending,
+ * tasks in wanpipe_tq_custom queue */
+
+#ifdef LINUX_2_4
+DECLARE_TASK_QUEUE(wanpipe_tq_custom);
+static struct tq_struct wanpipe_tq_task = 
+{
+	routine: (void (*)(void *)) run_wanpipe_tq,
+	data: &wanpipe_tq_custom
+};
+#else
+static struct tq_struct *wanpipe_tq_custom = NULL;
+static struct tq_struct wanpipe_tq_task = 
+{
+	NULL,
+	0,
+	(void *)(void *) run_wanpipe_tq,
+	&wanpipe_tq_custom
+};
+#endif
 
-/* Task queue element for creating a 'thread' */
-static struct tq_struct sdla_tq = { routine: sdla_poll };
+static int wanpipe_bh_critical=0;
 
 /******* Kernel Loadable Module Entry Points ********************************/
 
@@ -126,7 +278,7 @@
 #ifdef MODULE
 int init_module (void)
 #else
-int wanpipe_init2(void)
+int wanpipe_init(void)
 #endif
 {
 	int cnt, err = 0;
@@ -134,9 +286,17 @@
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, DRV_VERSION, DRV_RELEASE, copyright);
 
+	/* Probe for wanpipe cards and return the number found */
+	printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n");
+	ncards = wanpipe_hw_probe();
+	if (ncards){
+		printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards);
+	}else{
+		printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n");
+		return -ENODEV;
+	}
+	
 	/* Verify number of cards and allocate adapter data space */
-	ncards = min(ncards, MAX_CARDS);
-	ncards = max(ncards, 1);
 	card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL);
 	if (card_array == NULL)
 		return -ENOMEM;
@@ -159,7 +319,7 @@
 		wandev->ioctl    = &ioctl;
 		err = register_wan_device(wandev);
 		if (err) {
-			printk(KERN_ERR
+			printk(KERN_INFO
 				"%s: %s registration failed with error %d!\n",
 				drvname, card->devname, err);
 			break;
@@ -172,6 +332,7 @@
 		printk(KERN_INFO "IN Init Module: NO Cards registered\n");
 		err = -ENODEV;
 	}
+
 	return err;
 }
 
@@ -185,11 +346,16 @@
 {
 	int i;
 
+	if (!ncards)
+		return;
+		
 	for (i = 0; i < ncards; ++i) {
 		sdla_t* card = &card_array[i];
 		unregister_wan_device(card->devname);
 	}
 	kfree(card_array);
+
+	printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n");
 }
 
 #endif
@@ -218,15 +384,25 @@
 	sdla_t* card;
 	int err = 0;
 	int irq=0;
-	int i;
 
 	/* Sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL))
+	if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){
+		printk(KERN_INFO 
+		      "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n",
+		      wandev->name,
+		      (unsigned int)wandev,(unsigned int)wandev->private,
+		      (unsigned int)conf); 
 		return -EFAULT;
-		
+	}
+
+	printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name);
+
 	card = wandev->private;
-	if (wandev->state != WAN_UNCONFIGURED)
+	if (wandev->state != WAN_UNCONFIGURED){
+		printk(KERN_INFO "%s: failed sdlamain setup, busy!\n",
+			wandev->name);
 		return -EBUSY;		/* already configured */
+	}
 
 	printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name);
 
@@ -239,84 +415,21 @@
 	wandev->config_id  = conf->config_id;
 
 	if (!conf->data_size || (conf->data == NULL)) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"%s: firmware not found in configuration data!\n",
 			wandev->name);
 		return -EINVAL;
 	}
 
-	/* only check I/O port and IRQ if not an S514 adapter */
+	/* Check for resource conflicts and setup the
+	 * card for piggibacking if necessary */
 	if(!conf->S514_CPU_no[0]) {
-
-                if (conf->ioport <= 0) {
-                        printk(KERN_ERR
-			"%s: can't configure without I/O port address!\n",
-			wandev->name);
-                        return -EINVAL;
-                }
-	
-                if (conf->irq <= 0) {
-                        printk(KERN_ERR "%s: can't configure without IRQ!\n",
-			wandev->name);
-                        return -EINVAL;
-                }
-
-		/* Check for already loaded card with the same IO port and IRQ 
-		 * If found, copy its hardware configuration and use its
-		 * resources (i.e. piggybacking)
-		 */
-		if (!card->configured){
-			for (i = 0; i < ncards; i ++) {
-				sdla_t *nxt_card = &card_array[i];
-				if (nxt_card->hw.port == conf->ioport && 
-				    nxt_card != card && 
-				    conf->config_id == WANCONFIG_CHDLC &&
-				    nxt_card->wandev.config_id == WANCONFIG_CHDLC){
-					irq = nxt_card->hw.irq;
-					memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
-					nxt_card->next = card;
-					card->next = nxt_card;
-					card->wandev.piggyback = WANOPT_YES;
-				}
-			}
-			
-
-			/* Make sure I/O port region is available */
-			if (check_region(conf->ioport, SDLA_MAXIORANGE) && 
-			    !card->wandev.piggyback) {
-				printk(KERN_ERR
-					"%s: I/O region 0x%X - 0x%X is in use!\n",
-					wandev->name, conf->ioport,
-					conf->ioport + SDLA_MAXIORANGE);
-				return -EINVAL;
-			}
+		if ((err=check_s508_conflicts(card,conf,&irq)) != 0){
+			return err;
 		}
-	}
-
-	/* 
-	For a S514 adapter, check for a possible configuration error in that
-	we are loading an adapter in the same slot as a previously loaded S514
-	card.
-	*/ 
-	else {
-		if (!card->configured){
-			for (i = 0; i < ncards; i ++) {
-				sdla_t* nxt_card = &card_array[i];
-				if(nxt_card == card)
-					continue;
-				if((nxt_card->hw.type == SDLA_S514) &&
-				   (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) &&
-				   (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&&
-				   (conf->config_id == WANCONFIG_CHDLC)&&
-				   (nxt_card->wandev.config_id == WANCONFIG_CHDLC)){
-
-					irq = nxt_card->hw.irq;
-					memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
-					nxt_card->next = card;
-					card->next = nxt_card;
-					card->wandev.piggyback = WANOPT_YES;
-				}
-			}
+	}else {
+		if ((err=check_s514_conflicts(card,conf,&irq)) != 0){
+			return err;
 		}
 	}
 
@@ -336,8 +449,15 @@
 
 			card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0];
 			card->hw.S514_slot_no = conf->PCI_slot_no;
-			printk(KERN_INFO "Setting CPU to %c and Slot to %i\n",
-				card->hw.S514_cpu_no[0], card->hw.S514_slot_no);
+			card->hw.auto_pci_cfg = conf->auto_pci_cfg;
+
+			if (card->hw.auto_pci_cfg == WANOPT_YES){
+				printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n",
+				card->devname, card->hw.S514_cpu_no[0]);
+			}else{
+				printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n",
+				card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no);
+			}
 
 		}else{
 			/* 508 Card io port and irq initialization */
@@ -347,18 +467,22 @@
 
 
 		/* Compute the virtual address of the card in kernel space */
-		if(conf->maddr)
+		if(conf->maddr){
 			card->hw.dpmbase = phys_to_virt(conf->maddr);
-		else	/* But 0 means NULL */
+		}else{	
 			card->hw.dpmbase = (void *)conf->maddr;
-
+		}
+			
 		card->hw.dpmsize = SDLA_WINDOWSIZE;
+		
 		/* set the adapter type if using an S514 adapter */
 		card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; 
 		card->hw.pclk = conf->hw_opt[1];
 
 		err = sdla_setup(&card->hw, conf->data, conf->data_size);
 		if (err){
+			printk(KERN_INFO "%s: Hardware setup Failed %i\n",
+					card->devname,err);
 			return err;
 		}
 
@@ -369,10 +493,12 @@
 
 		/* request an interrupt vector - note that interrupts may be shared */
 		/* when using the S514 PCI adapter */
+		
        		if(request_irq(irq, sdla_isr, 
-		      (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, wandev->name, card)){
+		      (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, 
+		       wandev->name, card)){
 
-			printk(KERN_ERR "%s: Can't reserve IRQ %d!\n", wandev->name, irq);
+			printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq);
 			return -EINVAL;
 		}
 
@@ -384,11 +510,16 @@
 
 	if (!card->configured){
 
-	#ifdef CONFIG_SMP
 		/* Initialize the Spin lock */
-		printk(KERN_INFO "%s: Initializing SMP\n",wandev->name);
-		spin_lock_init(&card->lock);
-	#endif
+#if defined(__SMP__) || defined(LINUX_2_4) 
+		printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name);
+#endif
+
+		/* Piggyback spin lock has already been initialized,
+		 * in check_s514/s508_conflicts() */
+		if (!card->wandev.piggyback){
+			spin_lock_init(&card->wandev.lock);
+		}
 		
 		/* Intialize WAN device data space */
 		wandev->irq       = irq;
@@ -409,63 +540,65 @@
 
 	/* Protocol-specific initialization */
 	switch (card->hw.fwid) {
-#ifdef	CONFIG_WANPIPE_X25
+
 	case SFID_X25_502:
 	case SFID_X25_508:
+		printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n",
+				card->devname);
 		err = wpx_init(card, conf);
 		break;
-#endif
-
-#ifdef	CONFIG_WANPIPE_FR
 	case SFID_FR502:
 	case SFID_FR508:
+		printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n",
+				card->devname);
 		err = wpf_init(card, conf);
 		break;
-#endif
-
-#ifdef	CONFIG_WANPIPE_PPP
 	case SFID_PPP502:
 	case SFID_PPP508:
+		printk(KERN_INFO "%s: Starting PPP Protocol Init.\n",
+				card->devname);
 		err = wpp_init(card, conf);
 		break;
-#endif
-
-#ifdef CONFIG_WANPIPE_CHDLC
+		
 	case SFID_CHDLC508:
 	case SFID_CHDLC514:
-//		if (conf->ft1){		
-//			printk(KERN_INFO "%s: Starting FT1 Configurator\n",
-//				card->devname);
-//			err = wpft1_init(card, conf);
-//		}else{
-			err = wpc_init(card, conf);
-//		}
-		break;
-#endif
-
-#ifdef CONFIG_WANPIPE_BSTRM
-	case SFID_BSC502:
-		err = bsc_init(card, conf);
-		break;
-#endif
-
-#ifdef CONFIG_WANPIPE_HDLC
-	case SFID_HDLC508:
-		err = hdlc_init(card, conf);
-		break;
-#endif
+		if (conf->ft1){		
+			printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n",
+				card->devname);
+			err = wpft1_init(card, conf);
+			break;
+			
+		}else if (conf->config_id == WANCONFIG_MPPP){
+			printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n",
+					card->devname);
+			err = wsppp_init(card,conf);
+			break;
 
+		}else{
+			printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n",
+					card->devname);
+			err = wpc_init(card, conf);
+			break;
+		}
 	default:
-		printk(KERN_ERR "%s: this firmware is not supported %X %X!\n",
+		printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n",
 			wandev->name,card->hw.fwid,SFID_CHDLC508);
-		err = -EINVAL;
+		err = -EPROTONOSUPPORT;
 	}
 
-
-	if (err){
+	if (err != 0){
+		if (err == -EPROTONOSUPPORT){
+			printk(KERN_INFO 
+				"%s: Error, Protocol selected has not been compiled!\n",
+					card->devname);
+			printk(KERN_INFO 
+				"%s:        Re-configure the kernel and re-build the modules!\n",
+					card->devname);
+		}
+		
 		release_hw(card);
+		wandev->state = WAN_UNCONFIGURED;
 		return err;
-		
 	}
 
 
@@ -473,16 +606,194 @@
         if(card->hw.type != SDLA_S514 && !card->wandev.piggyback)
                 request_region(card->hw.port, card->hw.io_range, wandev->name);
 
-	if (++active == 1) {
-		MOD_INC_USE_COUNT;
-		if (schedule_task(&sdla_tq) == 0)
-			MOD_DEC_USE_COUNT;
+	/* Only use the polling routine for the X25 protocol */
+	
+	card->wandev.critical=0;
+	return 0;
+}
+
+/*================================================================== 
+ * configure_s508_card
+ * 
+ * For a S508 adapter, check for a possible configuration error in that
+ * we are loading an adapter in the same IO port as a previously loaded S508
+ * card.
+ */ 
+
+static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq)
+{
+	unsigned long smp_flags;
+	int i;
+	
+	if (conf->ioport <= 0) {
+		printk(KERN_INFO
+		"%s: can't configure without I/O port address!\n",
+		card->wandev.name);
+		return -EINVAL;
+	}
+
+	if (conf->irq <= 0) {
+		printk(KERN_INFO "%s: can't configure without IRQ!\n",
+		card->wandev.name);
+		return -EINVAL;
 	}
+
+	if (test_bit(0,&card->configured))
+		return 0;
+
+
+	/* Check for already loaded card with the same IO port and IRQ 
+	 * If found, copy its hardware configuration and use its
+	 * resources (i.e. piggybacking)
+	 */
+	
+	for (i = 0; i < ncards; i++) {
+		sdla_t *nxt_card = &card_array[i];
+
+		/* Skip the current card ptr */
+		if (nxt_card == card)	
+			continue;
+
+
+		/* Find a card that is already configured with the
+		 * same IO Port */
+		if ((nxt_card->hw.type == SDLA_S508) &&
+		    (nxt_card->hw.port == conf->ioport) && 
+		    (nxt_card->next == NULL)){
+			
+			/* We found a card the card that has same configuration
+			 * as us. This means, that we must setup this card in 
+			 * piggibacking mode. However, only CHDLC and MPPP protocol
+			 * support this setup */
+		
+			if ((conf->config_id == WANCONFIG_CHDLC || 
+			     conf->config_id == WANCONFIG_MPPP) &&
+			    (nxt_card->wandev.config_id == WANCONFIG_CHDLC || 
+			     nxt_card->wandev.config_id == WANCONFIG_MPPP)){ 
+				
+				*irq = nxt_card->hw.irq;
+				memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
+			
+				/* The master could already be running, we must
+				 * set this as a critical area */
+				lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags);
+
+				nxt_card->next = card;
+				card->next = nxt_card;
+
+				card->wandev.piggyback = WANOPT_YES;
+
+				/* We must initialise the piggiback spin lock here
+				 * since isr will try to lock card->next if it
+				 * exists */
+				spin_lock_init(&card->wandev.lock);
+				
+				unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags);
+				break;
+			}else{
+				/* Trying to run piggibacking with a wrong protocol */
+				printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n"
+						 "%s:        This protocol doesn't support\n"
+						 "%s:        multi-port operation!\n",
+						 card->devname,nxt_card->hw.port,
+						 card->devname,card->devname);
+				return -EEXIST;
+			}
+		}
+	}
+	
+
+	/* Make sure I/O port region is available only if we are the
+	 * master device.  If we are running in piggibacking mode, 
+	 * we will use the resources of the master card */
+	if (check_region(conf->ioport, SDLA_MAXIORANGE) && 
+	    !card->wandev.piggyback) {
+		printk(KERN_INFO
+			"%s: I/O region 0x%X - 0x%X is in use!\n",
+			card->wandev.name, conf->ioport,
+			conf->ioport + SDLA_MAXIORANGE);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*================================================================== 
+ * configure_s514_card
+ * 
+ * For a S514 adapter, check for a possible configuration error in that
+ * we are loading an adapter in the same slot as a previously loaded S514
+ * card.
+ */ 
+
+
+static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq)
+{
+	unsigned long smp_flags;
+	int i;
+	
+	if (test_bit(0,&card->configured))
+		return 0;
+
+	
+	/* Check for already loaded card with the same IO port and IRQ 
+	 * If found, copy its hardware configuration and use its
+	 * resources (i.e. piggybacking)
+	 */
+
+	for (i = 0; i < ncards; i ++) {
+	
+		sdla_t* nxt_card = &card_array[i];
+		if(nxt_card == card)
+			continue;
 		
-	wandev->critical = 0;
+		if((nxt_card->hw.type == SDLA_S514) &&
+		   (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) &&
+		   (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&&
+		   (nxt_card->next == NULL)){
+
+
+			if ((conf->config_id == WANCONFIG_CHDLC || 
+			     conf->config_id == WANCONFIG_MPPP) &&
+			    (nxt_card->wandev.config_id == WANCONFIG_CHDLC || 
+			     nxt_card->wandev.config_id == WANCONFIG_MPPP)){ 
+				
+				*irq = nxt_card->hw.irq;
+				memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
+	
+				/* The master could already be running, we must
+				 * set this as a critical area */
+				lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags);
+				nxt_card->next = card;
+				card->next = nxt_card;
+
+				card->wandev.piggyback = WANOPT_YES;
+
+				/* We must initialise the piggiback spin lock here
+				 * since isr will try to lock card->next if it
+				 * exists */
+				spin_lock_init(&card->wandev.lock);
+
+				unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags);
+
+			}else{
+				/* Trying to run piggibacking with a wrong protocol */
+				printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n"
+						 "%s:        This protocol doesn't support\n"
+						 "%s:        multi-port operation!\n",
+						 card->devname,
+						 conf->S514_CPU_no[0],conf->PCI_slot_no,
+						 card->devname,card->devname);
+				return -EEXIST;
+			}
+		}
+	}
+
 	return 0;
 }
 
+
+
 /*============================================================================
  * Shut down WAN link driver. 
  * o shut down adapter hardware
@@ -494,23 +805,39 @@
 static int shutdown (wan_device_t* wandev)
 {
 	sdla_t *card;
-
+	int err=0;
+	
 	/* sanity checks */
-	if ((wandev == NULL) || (wandev->private == NULL))
+	if ((wandev == NULL) || (wandev->private == NULL)){
 		return -EFAULT;
+	}
 		
-	if (wandev->state == WAN_UNCONFIGURED)
+	if (wandev->state == WAN_UNCONFIGURED){
 		return 0;
-		
-	/* If we are in a critical section we lose */
-	if (test_and_set_bit(0, (void*)&wandev->critical))
-		return -EAGAIN;
-		
+	}
+
 	card = wandev->private;
+
+	if (card->tty_opt){
+		if (card->tty_open){
+			printk(KERN_INFO 
+				"%s: Shutdown Failed: TTY is still open\n",
+				  card->devname);
+			return -EBUSY;
+		}
+	}
+	
 	wandev->state = WAN_UNCONFIGURED;
 
-	if (--active == 0)
-		schedule();	/* stop background thread */
+	set_bit(PERI_CRIT,(void*)&wandev->critical);
+	
+	/* In case of piggibacking, make sure that 
+         * we never try to shutdown both devices at the same
+         * time, because they depend on one another */
+	
+	if (card->disable_comm){
+		card->disable_comm(card);
+	}
 
 	/* Release Resources */
 	release_hw(card);
@@ -526,15 +853,17 @@
 			memset(&card->next->hw, 0, sizeof(sdlahw_t));
 		}
 	}
+	
 
-	wandev->critical = 0;
-	return 0;
+	clear_bit(PERI_CRIT,(void*)&wandev->critical);
+	return err;
 }
 
 static void release_hw (sdla_t *card)
 {
 	sdla_t *nxt_card;
 
+	
 	/* Check if next device exists */
 	if (card->next){
 		nxt_card = card->next;
@@ -559,8 +888,9 @@
 				card->next->configured = 0;
 			}
 		}else{
-			printk(KERN_INFO "%s: Device still running\n",
-				nxt_card->devname);
+			printk(KERN_INFO "%s: Device still running %i\n",
+				nxt_card->devname,nxt_card->wandev.state);
+
 			card->configured = 1;
 		}
 	}else{
@@ -569,6 +899,7 @@
        		free_irq(card->wandev.irq, card);
 		card->configured = 0;
 	}
+	return;
 }
 
 
@@ -597,10 +928,7 @@
 		disable_irq(card->hw.irq);
 	}
 
-	if (test_and_set_bit(0, (void*)&wandev->critical)) {
-		if(card->hw.type != SDLA_S514){
-			enable_irq(card->hw.irq);
-		}
+	if (test_bit(SEND_CRIT, (void*)&wandev->critical)) {
 		return -EAGAIN;
 	}
 	
@@ -610,18 +938,12 @@
 		break;
 
 	case WANPIPE_EXEC:
-		err = ioctl_exec(wandev->private, (void*)arg);
+		err = ioctl_exec(wandev->private, (void*)arg, cmd);
 		break;
-
 	default:
 		err = -EINVAL;
 	}
  
-	clear_bit(0, (void*)&wandev->critical);
-        if(card->hw.type != SDLA_S514){
-		enable_irq(card->hw.irq);
-	}
- 
 	return err;
 }
 
@@ -635,7 +957,7 @@
  * o verify user buffer
  * o copy adapter memory image to user buffer
  *
- * Note: when dumping memory, this routine switches current dual-port memory
+ * Note: when dumping memory, this routine switches curent dual-port memory
  *	 vector, so care must be taken to avoid racing conditions.
  */
 static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
@@ -643,21 +965,35 @@
 	sdla_dump_t dump;
 	unsigned winsize;
 	unsigned long oldvec;	/* DPM window vector */
-	unsigned long flags;
+	unsigned long smp_flags;
 	int err = 0;
 
+      #if defined(LINUX_2_1) || defined(LINUX_2_4)
 	if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)))
 		return -EFAULT;
+      #else
+        if ((u_dump == NULL) ||
+            verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t)))
+                return -EFAULT;
+        memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t));
+      #endif
 		
 	if ((dump.magic != WANPIPE_MAGIC) ||
 	    (dump.offset + dump.length > card->hw.memory))
 		return -EINVAL;
 	
+      #ifdef LINUX_2_0
+        if ((dump.ptr == NULL) ||
+            verify_area(VERIFY_WRITE, dump.ptr, dump.length))
+                return -EFAULT;
+      #endif	
+
 	winsize = card->hw.dpmsize;
-	save_flags(flags);
-        cli();				/* >>> critical section start <<< */
 
 	if(card->hw.type != SDLA_S514) {
+
+		lock_adapter_irq(&card->wandev.lock, &smp_flags);
+		
                 oldvec = card->hw.vector;
                 while (dump.length) {
 			/* current offset */				
@@ -671,29 +1007,39 @@
                                 err = -EIO;
                                 break;
                         }
-                        /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
-                        sti();  /* Not ideal but tough we have to do this */
+			
+                      #if defined(LINUX_2_1) || defined(LINUX_2_4)
                         if(copy_to_user((void *)dump.ptr,
-                                (u8 *)card->hw.dpmbase + pos, len)) 
-                                return -EFAULT;
-                        cli();
+                                (u8 *)card->hw.dpmbase + pos, len)){ 
+				
+				unlock_adapter_irq(&card->wandev.lock, &smp_flags);
+				return -EFAULT;
+			}
+                      #else
+			memcpy_tofs((void*)(dump.ptr),
+                        	(void*)(card->hw.dpmbase + pos), len);
+                      #endif
                         dump.length     -= len;
                         dump.offset     += len;
                         (char*)dump.ptr += len;
                 }
+		
                 sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */
-        }
-	
-	else {
-		/* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
-                sti();  /* Not ideal but tough we have to do this */
+		unlock_adapter_irq(&card->wandev.lock, &smp_flags);
+        
+	}else {
+
+	     #if defined(LINUX_2_1) || defined(LINUX_2_4) 
                if(copy_to_user((void *)dump.ptr,
-	                (u8 *)card->hw.dpmbase + dump.offset, dump.length))
-                	return -EFAULT;
-               cli();
+			       (u8 *)card->hw.dpmbase + dump.offset, dump.length)){
+			return -EFAULT;
+		}
+             #else
+                memcpy_tofs((void*)(dump.ptr),
+                (void*)(card->hw.dpmbase + dump.offset), dump.length);
+             #endif
 	}
 
-	restore_flags(flags);		/* >>> critical section end <<< */
 	return err;
 }
 
@@ -703,19 +1049,34 @@
  * o copy request structure to kernel data space
  * o call protocol-specific 'exec' function
  */
-static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec)
+static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd)
 {
 	sdla_exec_t exec;
+	int err=0;
 
-	if (card->exec == NULL)
+	if (card->exec == NULL && cmd == WANPIPE_EXEC){
 		return -ENODEV;
-	
+	}
+
+      #if defined(LINUX_2_1) || defined(LINUX_2_4)	
 	if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)))
 		return -EFAULT;
+      #else
+        if ((u_exec == NULL) ||
+            verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t)))
+                return -EFAULT;
+        memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t));
+      #endif
 
 	if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
 		return -EINVAL;
-	return card->exec(card, exec.cmd, exec.data);
+
+	switch (cmd) {
+		case WANPIPE_EXEC:	
+			err = card->exec(card, exec.cmd, exec.data);
+			break;
+	}	
+	return err;
 }
 
 /******* Miscellaneous ******************************************************/
@@ -795,11 +1156,20 @@
  				return;
        			}
 
+			spin_lock(&card->wandev.lock);
+			if (card->next){
+				spin_lock(&card->next->wandev.lock);
+			}
+				
 	               	S514_intack(&card->hw, int_status);
- 
        			if (card->isr)
 				card->isr(card);
 
+			if (card->next){
+				spin_unlock(&card->next->wandev.lock);
+			}
+			spin_unlock(&card->wandev.lock);
+
 			/* handle a maximum of two interrupts (one for each */
 			/* CPU on the adapter) before returning */  
 			if((++ IRQ_count) == 2)
@@ -819,17 +1189,19 @@
 			return;
 		}
 
-		/* Use spin lock only for S508 */
-
-#ifdef CONFIG_SMP
-		spin_lock(&card->lock);
-#endif
+		spin_lock(&card->wandev.lock);
+		if (card->next){
+			spin_lock(&card->next->wandev.lock);
+		}
+	
 		sdla_intack(&card->hw);
 		if (card->isr)
 			card->isr(card);
-#ifdef CONFIG_SMP
-		spin_unlock(&card->lock);
-#endif
+		
+		if (card->next){
+			spin_unlock(&card->next->wandev.lock);
+		}
+		spin_unlock(&card->wandev.lock);
 
 	}
                 
@@ -837,33 +1209,6 @@
 }
 
 /*============================================================================
- * SDLA polling routine.
- * This routine simulates kernel thread to perform various housekeeping job.
- *
- * o for each configured device call its poll() routine
- * o if there is at least one active card, then reschedule itself once again
- */
-STATIC void sdla_poll (void* data)
-{
-	int i;
-
-	for (i = 0; i < ncards; ++i) {
-		sdla_t* card = &card_array[i];
-
-		if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
-			!card->wandev.critical) {
-			card->poll(card);
-		}
-	}
-	if (active) {
-		MOD_INC_USE_COUNT;
-		if (schedule_task(&sdla_tq) == 0)	/* Surely not? */
-			MOD_DEC_USE_COUNT;
-	}
-	MOD_DEC_USE_COUNT;
-}
-
-/*============================================================================
  * This routine is called by the protocol-specific modules when network
  * interface is being open.  The only reason we need this, is because we
  * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
@@ -892,10 +1237,6 @@
  */
 void wanpipe_set_state (sdla_t* card, int state)
 {
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 	if (card->wandev.state != state) {
 		switch (state) {
 		case WAN_CONNECTED:
@@ -916,7 +1257,187 @@
 		card->wandev.state = state;
 	}
 	card->state_tick = jiffies;
-	restore_flags(flags);
 }
 
-/****** End *****************************************************************/
+sdla_t * wanpipe_find_card (char *name)
+{
+	int cnt;
+	for (cnt = 0; cnt < ncards; ++ cnt) {
+		sdla_t* card = &card_array[cnt];
+		if (!strcmp(card->devname,name))
+			return card;
+	}
+	return NULL;
+}
+sdla_t * wanpipe_find_card_num (int num)
+{
+	if (num < 1 || num > ncards)
+		return NULL;	
+	num--;
+	return &card_array[num];
+}
+
+
+static void run_wanpipe_tq (unsigned long data)
+{
+	task_queue *tq_queue = (task_queue *)data;
+	if (test_and_set_bit(2,(void*)&wanpipe_bh_critical))
+		printk(KERN_INFO "CRITICAL IN RUNNING TASK QUEUE\n");
+	run_task_queue (tq_queue);
+	clear_bit(2,(void*)&wanpipe_bh_critical);
+
+}
+
+void wanpipe_queue_tq (struct tq_struct *bh_pointer)
+{
+	if (test_and_set_bit(1,(void*)&wanpipe_bh_critical))
+		printk(KERN_INFO "CRITICAL IN QUEUING TASK\n");
+
+	queue_task(bh_pointer,&wanpipe_tq_custom);
+	clear_bit(1,(void*)&wanpipe_bh_critical);
+}
+
+void wanpipe_mark_bh (void)
+{
+	if (!test_and_set_bit(0,(void*)&wanpipe_bh_critical)){
+		queue_task(&wanpipe_tq_task,&tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		clear_bit(0,(void*)&wanpipe_bh_critical);
+	}
+} 
+
+void wakeup_sk_bh (netdevice_t *dev)
+{
+	wanpipe_common_t *chan = dev->priv;
+
+	if (test_bit(0,&chan->common_critical))
+		return;
+	
+	if (chan->sk && chan->tx_timer){
+		chan->tx_timer->expires=jiffies+1;
+		add_timer(chan->tx_timer);
+	}
+}
+
+int change_dev_flags (netdevice_t *dev, unsigned flags)
+{
+	struct ifreq if_info;
+	mm_segment_t fs = get_fs();
+	int err;
+
+	memset(&if_info, 0, sizeof(if_info));
+	strcpy(if_info.ifr_name, dev->name);
+	if_info.ifr_flags = flags;	
+
+	set_fs(get_ds());     /* get user space block */ 
+	err = devinet_ioctl(SIOCSIFFLAGS, &if_info);
+	set_fs(fs);
+
+	return err;
+}
+
+unsigned long get_ip_address (netdevice_t *dev, int option)
+{
+	
+      #ifdef LINUX_2_4
+	struct in_ifaddr *ifaddr;
+	struct in_device *in_dev;
+
+	if ((in_dev = __in_dev_get(dev)) == NULL){
+		return 0;
+	}
+      #elif defined(LINUX_2_1)
+	struct in_ifaddr *ifaddr;
+	struct in_device *in_dev;
+	
+	if ((in_dev = dev->ip_ptr) == NULL){
+		return 0;
+	}
+      #endif
+
+      #if defined(LINUX_2_1) || defined(LINUX_2_4)
+	if ((ifaddr = in_dev->ifa_list)== NULL ){
+		return 0;
+	}
+      #endif
+	
+	switch (option){
+
+	case WAN_LOCAL_IP:
+	      #ifdef LINUX_2_0
+		return dev->pa_addr;
+	      #else	
+		return ifaddr->ifa_local;
+	      #endif	
+		break;
+	
+	case WAN_POINTOPOINT_IP:
+	      #ifdef LINUX_2_0
+		return dev->pa_dstaddr;
+	      #else	
+		return ifaddr->ifa_address;
+	      #endif	
+		break;	
+
+	case WAN_NETMASK_IP:
+	      #ifdef LINUX_2_0
+		return dev->pa_mask;
+	      #else	
+		return ifaddr->ifa_mask;
+	      #endif	
+		break;
+
+	case WAN_BROADCAST_IP:
+	      #ifdef LINUX_2_0
+		return dev->pa_brdaddr;
+	      #else	
+		return ifaddr->ifa_broadcast;
+	      #endif	
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}	
+
+void add_gateway(sdla_t *card, netdevice_t *dev)
+{
+	mm_segment_t oldfs;
+	struct rtentry route;
+	int res;
+
+	memset((char*)&route,0,sizeof(struct rtentry));
+
+	((struct sockaddr_in *)
+		&(route.rt_dst))->sin_addr.s_addr = 0;
+	((struct sockaddr_in *)
+		&(route.rt_dst))->sin_family = AF_INET;
+
+	((struct sockaddr_in *)
+		&(route.rt_genmask))->sin_addr.s_addr = 0;
+	((struct sockaddr_in *) 
+		&(route.rt_genmask)) ->sin_family = AF_INET;
+
+
+	route.rt_flags = 0;  
+	route.rt_dev = dev->name;
+
+	oldfs = get_fs();
+	set_fs(get_ds());
+      #if defined(LINUX_2_1) || defined(LINUX_2_4)
+	res = ip_rt_ioctl(SIOCADDRT,&route);
+      #else
+	res = ip_rt_new(&route);
+      #endif
+	set_fs(oldfs);
+
+	if (res == 0){
+		printk(KERN_INFO "%s: Gateway added for %s\n",
+			card->devname,dev->name);
+	}
+
+	return;
+}
+
+/****** End *********************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c
--- v2.4.3/linux/drivers/net/wan/sealevel.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/net/wan/sealevel.c	Wed Apr 18 14:40:07 2001
@@ -375,7 +375,6 @@
 			d->do_ioctl = sealevel_ioctl;
 #ifdef LINUX_21			
 			d->neigh_setup = sealevel_neigh_setup_dev;
-			dev_init_buffers(d);
 #else
 			d->init = return_0;
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c
--- v2.4.3/linux/drivers/net/wan/syncppp.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/net/wan/syncppp.c	Wed Apr 18 14:40:07 2001
@@ -1048,7 +1048,6 @@
 	dev->hard_header_cache = NULL;
 	dev->header_cache_update = NULL;
 	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
-	dev_init_buffers(dev);
 }
 
 EXPORT_SYMBOL(sppp_attach);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/wanpipe_multppp.c linux/drivers/net/wan/wanpipe_multppp.c
--- v2.4.3/linux/drivers/net/wan/wanpipe_multppp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/wanpipe_multppp.c	Fri Apr 20 11:54:22 2001
@@ -0,0 +1,2471 @@
+/*****************************************************************************
+* wanpipe_multppp.c Multi-Port PPP driver module.
+*
+* Authors: 	Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright:	(c) 1995-2001 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 15 2000   Updated for 2.4.X kernel
+* Nov 15 2000   Fixed the SyncPPP support for kernels 2.2.16 and higher.
+*   		The pppstruct has changed.
+* Jul 13 2000	Using the kernel Syncppp module on top of RAW Wanpipe CHDLC
+*  		module.
+*****************************************************************************/
+
+#include <linux/version.h>
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/stddef.h>	/* offsetof(), etc. */
+#include <linux/errno.h>	/* return codes */
+#include <linux/string.h>	/* inline memset(), etc. */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
+#include <linux/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+
+#include <linux/in.h>		/* sockaddr_in */
+#include <linux/inet.h>	
+#include <linux/if.h>
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <linux/sdlapci.h>
+#include <asm/io.h>
+
+#include <linux/sdla_chdlc.h>		/* CHDLC firmware API definitions */
+#include <linux/sdla_asy.h>           	/* CHDLC (async) API definitions */
+
+#include <linux/if_wanpipe_common.h>    /* Socket Driver common area */
+#include <linux/if_wanpipe.h>		
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+  #include <linux/inetdevice.h>
+  #include <asm/uaccess.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
+ #include <net/syncppp.h>
+#else
+ #include "syncppp.h"
+#endif
+
+#else
+  #include <net/route.h>          /* Adding new route entries */
+#endif
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef	_DEBUG_
+#define	STATIC
+#else
+#define	STATIC		static
+#endif
+
+/* reasons for enabling the timer interrupt on the adapter */
+#define TMR_INT_ENABLED_UDP   	0x01
+#define TMR_INT_ENABLED_UPDATE	0x02
+#define TMR_INT_ENABLED_CONFIG  0x04
+ 
+#define	CHDLC_DFLT_DATA_LEN	1500		/* default MTU */
+#define CHDLC_HDR_LEN		1
+
+#define IFF_POINTTOPOINT 0x10
+
+#define CHDLC_API 0x01
+
+#define PORT(x)   (x == 0 ? "PRIMARY" : "SECONDARY" )
+#define MAX_BH_BUFF	10
+
+#define CRC_LENGTH 	2 
+#define PPP_HEADER_LEN 	4
+ 
+/******Data Structures*****************************************************/
+
+/* This structure is placed in the private data area of the device structure.
+ * The card structure used to occupy the private area but now the following 
+ * structure will incorporate the card structure along with CHDLC specific data
+ */
+
+typedef struct chdlc_private_area
+{
+	void *if_ptr;				/* General Pointer used by SPPP */
+	wanpipe_common_t common;
+	sdla_t		*card;
+	int 		TracingEnabled;		/* For enabling Tracing */
+	unsigned long 	curr_trace_addr;	/* Used for Tracing */
+	unsigned long 	start_trace_addr;
+	unsigned long 	end_trace_addr;
+	unsigned long 	base_addr_trace_buffer;
+	unsigned long 	end_addr_trace_buffer;
+	unsigned short 	number_trace_elements;
+	unsigned  	available_buffer_space;
+	unsigned long 	router_start_time;
+	unsigned char 	route_status;
+	unsigned char 	route_removed;
+	unsigned long 	tick_counter;		/* For 5s timeout counter */
+	unsigned long 	router_up_time;
+        u32             IP_address;		/* IP addressing */
+        u32             IP_netmask;
+	unsigned char  mc;			/* Mulitcast support on/off */
+	unsigned short udp_pkt_lgth;		/* udp packet processing */
+	char udp_pkt_src;
+	char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+	unsigned short timer_int_enabled;
+	char update_comms_stats;		/* updating comms stats */
+
+	//FIXME: add driver stats as per frame relay!
+
+} chdlc_private_area_t;
+
+/* Route Status options */
+#define NO_ROUTE	0x00
+#define ADD_ROUTE	0x01
+#define ROUTE_ADDED	0x02
+#define REMOVE_ROUTE	0x03
+
+
+/* variable for keeping track of enabling/disabling FT1 monitor status */
+static int rCount = 0;
+
+/* variable for tracking how many interfaces to open for WANPIPE on the
+   two ports */
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+/****** Function Prototypes *************************************************/
+/* WAN link driver entry points. These are called by the WAN router module. */
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, netdevice_t* dev,
+	wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, netdevice_t* dev);
+
+/* Network device interface */
+static int if_init   (netdevice_t* dev);
+static int if_open   (netdevice_t* dev);
+static int if_close  (netdevice_t* dev);
+static int if_send (struct sk_buff* skb, netdevice_t* dev);
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats* if_stats (netdevice_t* dev);
+#else
+static struct enet_statistics* if_stats (netdevice_t* dev);
+#endif
+
+#ifdef LINUX_2_4
+static void if_tx_timeout (netdevice_t *dev);
+#endif
+
+/* CHDLC Firmware interface functions */
+static int chdlc_configure 	(sdla_t* card, void* data);
+static int chdlc_comm_enable 	(sdla_t* card);
+static int chdlc_comm_disable 	(sdla_t* card);
+static int chdlc_read_version 	(sdla_t* card, char* str);
+static int chdlc_set_intr_mode 	(sdla_t* card, unsigned mode);
+static int chdlc_send (sdla_t* card, void* data, unsigned len);
+static int chdlc_read_comm_err_stats (sdla_t* card);
+static int chdlc_read_op_stats (sdla_t* card);
+static int config_chdlc (sdla_t *card);
+
+
+/* Miscellaneous CHDLC Functions */
+static int set_chdlc_config (sdla_t* card);
+static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev );
+static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
+static int process_chdlc_exception(sdla_t *card);
+static int process_global_exception(sdla_t *card);
+static int update_comms_stats(sdla_t* card,
+        chdlc_private_area_t* chdlc_priv_area);
+static void port_set_state (sdla_t *card, int);
+
+/* Interrupt handlers */
+static void wsppp_isr (sdla_t* card);
+static void rx_intr (sdla_t* card);
+static void timer_intr(sdla_t *);
+
+/* Miscellaneous functions */
+static int reply_udp( unsigned char *data, unsigned int mbox_len );
+static int intr_test( sdla_t* card);
+static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
+static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, netdevice_t* dev,
+                                chdlc_private_area_t* chdlc_priv_area);
+static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,  
+				chdlc_private_area_t* chdlc_priv_area);
+static unsigned short calc_checksum (char *, int);
+static void s508_lock (sdla_t *card, unsigned long *smp_flags);
+static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
+static void send_ppp_term_request (netdevice_t*);
+
+
+static int  Intr_test_counter;
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * Cisco HDLC protocol initialization routine.
+ *
+ * This routine is called by the main WANPIPE module during setup.  At this
+ * point adapter is completely initialized and firmware is running.
+ *  o read firmware version (to make sure it's alive)
+ *  o configure adapter
+ *  o initialize protocol-specific fields of the adapter data space.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure.
+ */
+int wsppp_init (sdla_t* card, wandev_conf_t* conf)
+{
+	unsigned char port_num;
+	int err;
+	unsigned long max_permitted_baud = 0;
+	SHARED_MEMORY_INFO_STRUCT *flags;
+
+	union
+		{
+		char str[80];
+		} u;
+	volatile CHDLC_MAILBOX_STRUCT* mb;
+	CHDLC_MAILBOX_STRUCT* mb1;
+	unsigned long timeout;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_MPPP) {
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+				  card->devname, conf->config_id);
+		return -EINVAL;
+	}
+
+	/* Find out which Port to use */
+	if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){
+		if (card->next){
+
+			if (conf->comm_port != card->next->u.c.comm_port){
+				card->u.c.comm_port = conf->comm_port;
+			}else{
+				printk(KERN_ERR "%s: ERROR - %s port used!\n",
+        		        	card->wandev.name, PORT(conf->comm_port));
+				return -EINVAL;
+			}
+		}else{
+			card->u.c.comm_port = conf->comm_port;
+		}
+	}else{
+		printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n",
+                			card->wandev.name);
+		return -EINVAL;
+	}
+	
+
+	/* Initialize protocol-specific fields */
+	if(card->hw.type != SDLA_S514){
+
+		if (card->u.c.comm_port == WANOPT_PRI){	
+			card->mbox  = (void *) card->hw.dpmbase;
+		}else{
+			card->mbox  = (void *) card->hw.dpmbase + 
+				SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT;
+		}	
+	}else{ 
+		/* for a S514 adapter, set a pointer to the actual mailbox in the */
+		/* allocated virtual memory area */
+		if (card->u.c.comm_port == WANOPT_PRI){
+			card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT;
+		}else{
+			card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT;
+		}	
+	}
+
+	mb = mb1 = card->mbox;
+
+	if (!card->configured){
+
+		/* The board will place an 'I' in the return code to indicate that it is
+	   	ready to accept commands.  We expect this to be completed in less
+           	than 1 second. */
+
+		timeout = jiffies;
+		while (mb->return_code != 'I')	/* Wait 1s for board to initialize */
+			if ((jiffies - timeout) > 1*HZ) break;
+
+		if (mb->return_code != 'I') {
+			printk(KERN_INFO
+				"%s: Initialization not completed by adapter\n",
+				card->devname);
+			printk(KERN_INFO "Please contact Sangoma representative.\n");
+			return -EIO;
+		}
+	}
+
+	/* Read firmware version.  Note that when adapter initializes, it
+	 * clears the mailbox, so it may appear that the first command was
+	 * executed successfully when in fact it was merely erased. To work
+	 * around this, we execute the first command twice.
+	 */
+
+	if (chdlc_read_version(card, u.str))
+		return -EIO;
+
+	printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" 
+			 "%s: for Multi-Port PPP protocol.\n",
+			card->devname,u.str,card->devname); 
+
+	card->isr			= &wsppp_isr;
+	card->poll			= NULL;
+	card->exec			= NULL;
+	card->wandev.update		= &update;
+ 	card->wandev.new_if		= &new_if;
+	card->wandev.del_if		= &del_if;
+	card->wandev.udp_port   	= conf->udp_port;
+
+	card->wandev.new_if_cnt = 0;
+
+	/* reset the number of times the 'update()' proc has been called */
+	card->u.c.update_call_count = 0;
+	
+	card->wandev.ttl = conf->ttl;
+	card->wandev.interface = conf->interface; 
+
+	if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&&
+	    card->hw.type != SDLA_S514){
+		printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n",
+			card->devname, PORT(card->u.c.comm_port));
+		return -EIO;
+	}
+
+
+	card->wandev.clocking = conf->clocking;
+
+	port_num = card->u.c.comm_port;
+
+	/* Setup Port Bps */
+
+	if(card->wandev.clocking) {
+		if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
+			/* For Primary Port 0 */
+               		max_permitted_baud =
+				(card->hw.type == SDLA_S514) ?
+				PRI_MAX_BAUD_RATE_S514 : 
+				PRI_MAX_BAUD_RATE_S508;
+		}
+		else if(port_num == WANOPT_SEC) {
+			/* For Secondary Port 1 */
+                        max_permitted_baud =
+                               (card->hw.type == SDLA_S514) ?
+                                SEC_MAX_BAUD_RATE_S514 :
+                                SEC_MAX_BAUD_RATE_S508;
+                        }
+  
+			if(conf->bps > max_permitted_baud) {
+				conf->bps = max_permitted_baud;
+				printk(KERN_INFO "%s: Baud too high!\n",
+					card->wandev.name);
+ 				printk(KERN_INFO "%s: Baud rate set to %lu bps\n", 
+					card->wandev.name, max_permitted_baud);
+			}
+                             
+			card->wandev.bps = conf->bps;
+	}else{
+        	card->wandev.bps = 0;
+  	}
+
+	/* Setup the Port MTU */
+	if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
+
+		/* For Primary Port 0 */
+		card->wandev.mtu =
+			(conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
+			min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) :
+			CHDLC_DFLT_DATA_LEN;
+	} else if(port_num == WANOPT_SEC) { 
+		/* For Secondary Port 1 */
+		card->wandev.mtu =
+			(conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
+			min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) :
+			CHDLC_DFLT_DATA_LEN;
+	}
+
+	/* Add on a PPP Header */
+	card->wandev.mtu += PPP_HEADER_LEN;
+
+	/* Set up the interrupt status area */
+	/* Read the CHDLC Configuration and obtain: 
+	 *	Ptr to shared memory infor struct
+         * Use this pointer to calculate the value of card->u.c.flags !
+ 	 */
+	mb1->buffer_length = 0;
+	mb1->command = READ_CHDLC_CONFIGURATION;
+	err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
+	if(err != COMMAND_OK) {
+		clear_bit(1, (void*)&card->wandev.critical);
+
+                if(card->hw.type != SDLA_S514)
+                	enable_irq(card->hw.irq);
+
+		chdlc_error(card, err, mb1);
+		return -EIO;
+	}
+
+	if(card->hw.type == SDLA_S514){
+               	card->u.c.flags = (void *)(card->hw.dpmbase +
+               		(((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
+			ptr_shared_mem_info_struct));
+        }else{
+                card->u.c.flags = (void *)(card->hw.dpmbase +
+                        (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
+			ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
+	}
+	
+	flags = card->u.c.flags;
+	
+	/* This is for the ports link state */
+	card->wandev.state = WAN_DUALPORT;
+	card->u.c.state = WAN_DISCONNECTED;
+
+
+	if (!card->wandev.piggyback){
+		err = intr_test(card);
+
+		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { 
+			printk(KERN_ERR "%s: Interrupt test failed (%i)\n",
+					card->devname, Intr_test_counter);
+			printk(KERN_ERR "%s: Please choose another interrupt\n",
+					card->devname);
+			return  -EIO;
+		}
+			
+		printk(KERN_INFO "%s: Interrupt test passed (%i)\n", 
+				card->devname, Intr_test_counter);
+	}
+
+
+	if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){
+		printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
+				card->devname);
+		return -EIO;	
+        }
+	
+	/* Mask the Timer interrupt */
+	flags->interrupt_info_struct.interrupt_permission &= 
+		~APP_INT_ON_TIMER;
+
+	printk(KERN_INFO "\n");
+
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics
+ * This procedure is called when updating the PROC file system and returns
+ * various communications statistics. These statistics are accumulated from 3 
+ * different locations:
+ * 	1) The 'if_stats' recorded for the device.
+ * 	2) Communication error statistics on the adapter.
+ *      3) CHDLC operational statistics on the adapter.
+ * The board level statistics are read during a timer interrupt. Note that we 
+ * read the error and operational statistics during consecitive timer ticks so
+ * as to minimize the time that we are inside the interrupt handler.
+ *
+ */
+static int update (wan_device_t* wandev)
+{
+	sdla_t* card = wandev->private;
+ 	netdevice_t* dev;
+        volatile chdlc_private_area_t* chdlc_priv_area;
+        SHARED_MEMORY_INFO_STRUCT *flags;
+	unsigned long timeout;
+
+	/* sanity checks */
+	if((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT;
+	
+	if(wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+
+	/* more sanity checks */
+        if(!card->u.c.flags)
+                return -ENODEV;
+
+	if((dev=card->wandev.dev) == NULL)
+		return -ENODEV;
+
+	if((chdlc_priv_area=dev->priv) == NULL)
+		return -ENODEV;
+
+      	flags = card->u.c.flags;
+
+       	if(chdlc_priv_area->update_comms_stats){
+		return -EAGAIN;
+	}
+			
+	/* we will need 2 timer interrupts to complete the */
+	/* reading of the statistics */
+	chdlc_priv_area->update_comms_stats = 2;
+       	flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
+	chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE;
+  
+	/* wait a maximum of 1 second for the statistics to be updated */ 
+        timeout = jiffies;
+        for(;;) {
+		if(chdlc_priv_area->update_comms_stats == 0)
+			break;
+                if ((jiffies - timeout) > (1 * HZ)){
+    			chdlc_priv_area->update_comms_stats = 0;
+ 			chdlc_priv_area->timer_int_enabled &=
+				~TMR_INT_ENABLED_UPDATE; 
+ 			return -EAGAIN;
+		}
+        }
+
+	return 0;
+}
+
+
+/*============================================================================
+ * Create new logical channel.
+ * This routine is called by the router when ROUTER_IFNEW IOCTL is being
+ * handled.
+ * o parse media- and hardware-specific configuration
+ * o make sure that a new channel can be created
+ * o allocate resources, if necessary
+ * o prepare network device structure for registaration.
+ *
+ * Return:	0	o.k.
+ *		< 0	failure (channel will not be created)
+ */
+static int new_if (wan_device_t* wandev, netdevice_t* pdev, wanif_conf_t* conf)
+{
+
+	struct ppp_device *pppdev = (struct ppp_device *)pdev;
+	netdevice_t *dev=NULL;
+	struct sppp *sp;
+	sdla_t* card = wandev->private;
+	chdlc_private_area_t* chdlc_priv_area;
+	
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
+		printk(KERN_INFO "%s: invalid interface name!\n",
+			card->devname);
+		return -EINVAL;
+	}
+		
+	/* allocate and initialize private data */
+	chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL);
+	
+	if(chdlc_priv_area == NULL) 
+		return -ENOMEM;
+
+	memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t));
+
+	chdlc_priv_area->card = card; 
+
+	/* initialize data */
+	strcpy(card->u.c.if_name, conf->name);
+
+	if(card->wandev.new_if_cnt > 0) {
+                kfree(chdlc_priv_area);
+		return -EEXIST;
+	}
+
+	card->wandev.new_if_cnt++;
+
+	chdlc_priv_area->TracingEnabled = 0;
+
+	//We don't need this any more
+	chdlc_priv_area->route_status = NO_ROUTE;
+	chdlc_priv_area->route_removed = 0;
+
+	printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n",
+		wandev->name);
+	
+	/* Setup wanpipe as a router (WANPIPE) or as an API */
+	if( strcmp(conf->usedby, "WANPIPE") == 0) {
+		printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n",
+			wandev->name);
+		card->u.c.usedby = WANPIPE;
+	} else {
+		printk(KERN_INFO 
+			"%s: API Mode is not supported for SyncPPP!\n",
+			wandev->name);
+		kfree(chdlc_priv_area);
+		return -EINVAL;
+	}
+
+	/* Get Multicast Information */
+	chdlc_priv_area->mc = conf->mc;
+
+
+	chdlc_priv_area->if_ptr = pppdev;
+
+	/* prepare network device data space for registration */
+	
+	/* Attach PPP protocol layer to pppdev
+	 * The sppp_attach() will initilize the dev structure
+         * and setup ppp layer protocols.
+         * All we have to do is to bind in:
+         *        if_open(), if_close(), if_send() and get_stats() functions.
+         */
+	sppp_attach(pppdev);
+      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
+	dev = pppdev->dev;
+      #else
+	dev = &pppdev->dev;
+      #endif
+	sp = &pppdev->sppp;
+	
+	/* Enable PPP Debugging */
+	// FIXME Fix this up somehow
+	//sp->pp_flags |= PP_DEBUG; 	
+	sp->pp_flags &= ~PP_CISCO;
+	
+      #ifdef LINUX_2_4
+	strcpy(dev->name,card->u.c.if_name);
+      #else
+	dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); 
+	sprintf(dev->name, "%s", card->u.c.if_name);
+      #endif
+
+	dev->init = &if_init;
+	dev->priv = chdlc_priv_area;
+	
+	return 0;
+}
+
+
+
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, netdevice_t* dev)
+{
+	chdlc_private_area_t *chdlc_priv_area = dev->priv;
+	sdla_t *card = chdlc_priv_area->card;
+	unsigned long smp_lock;
+	
+	/* Detach the PPP layer */
+	printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n",
+			wandev->name,dev->name);
+
+	lock_adapter_irq(&wandev->lock,&smp_lock);
+
+	sppp_detach(dev);
+	chdlc_priv_area->if_ptr=NULL;
+	
+	chdlc_set_intr_mode(card, 0);
+	if (card->u.c.comm_enabled)
+		chdlc_comm_disable(card);
+	unlock_adapter_irq(&wandev->lock,&smp_lock);
+	
+	port_set_state(card, WAN_DISCONNECTED);
+
+	return 0;
+}
+
+
+/****** Network Device Interface ********************************************/
+
+/*============================================================================
+ * Initialize Linux network interface.
+ *
+ * This routine is called only once for each interface, during Linux network
+ * interface registration.  Returning anything but zero will fail interface
+ * registration.
+ */
+static int if_init (netdevice_t* dev)
+	{
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	sdla_t* card = chdlc_priv_area->card;
+	wan_device_t* wandev = &card->wandev;
+      #ifdef LINUX_2_0
+	int i;
+      #endif
+	
+	/* NOTE: Most of the dev initialization was
+         *       done in sppp_attach(), called by new_if() 
+         *       function. All we have to do here is
+         *       to link four major routines below. 
+         */
+
+	/* Initialize device driver entry points */
+	dev->open		= &if_open;
+	dev->stop		= &if_close;
+	dev->hard_start_xmit	= &if_send;
+	dev->get_stats		= &if_stats;
+      #ifdef LINUX_2_4
+	dev->tx_timeout		= &if_tx_timeout;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+      #endif
+
+
+      #ifdef LINUX_2_0
+	dev->family		= AF_INET;
+      #endif	
+ 
+	/* Initialize hardware parameters */
+	dev->irq	= wandev->irq;
+	dev->dma	= wandev->dma;
+	dev->base_addr	= wandev->ioport;
+	dev->mem_start	= wandev->maddr;
+	dev->mem_end	= wandev->maddr + wandev->msize - 1;
+
+	/* Set transmit buffer queue length 
+         * If we over fill this queue the packets will
+         * be droped by the kernel.
+         * sppp_attach() sets this to 10, but
+         * 100 will give us more room at low speeds.
+	 */
+        dev->tx_queue_len = 100;
+   
+	/* Initialize socket buffers */
+      #if !defined(LINUX_2_1) && !defined(LINUX_2_4)
+        for (i = 0; i < DEV_NUMBUFFS; ++i)
+                skb_queue_head_init(&dev->buffs[i]);
+      #endif
+
+	return 0;
+}
+
+
+#ifdef LINUX_2_4
+/*============================================================================
+ * Handle transmit timeout event from netif watchdog
+ */
+static void if_tx_timeout (netdevice_t *dev)
+{
+    	chdlc_private_area_t* chan = dev->priv;
+	sdla_t *card = chan->card;
+	
+	/* If our device stays busy for at least 5 seconds then we will
+	 * kick start the device by making dev->tbusy = 0.  We expect
+	 * that our device never stays busy more than 5 seconds. So this                 
+	 * is only used as a last resort.
+	 */
+
+	++card->wandev.stats.collisions;
+
+	printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
+	netif_wake_queue (dev);
+}
+#endif
+
+
+
+/*============================================================================
+ * Open network interface.
+ * o enable communications and interrupts.
+ * o prevent module from unloading by incrementing use count
+ *
+ * Return 0 if O.k. or errno.
+ */
+static int if_open (netdevice_t* dev)
+{
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	sdla_t* card = chdlc_priv_area->card;
+	struct timeval tv;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+
+	/* Only one open per interface is allowed */
+
+      #ifdef LINUX_2_4
+	if (netif_running(dev))
+		return -EBUSY;
+      #else
+	if (dev->start)
+		return -EBUSY;		/* only one open is allowed */
+      #endif
+
+	/* Start PPP Layer */
+	if (sppp_open(dev)){
+		return -EIO;
+	}
+
+	do_gettimeofday(&tv);
+	chdlc_priv_area->router_start_time = tv.tv_sec;
+ 
+      #ifdef LINUX_2_4
+	netif_start_queue(dev);
+      #else
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+      #endif
+	
+	wanpipe_open(card);
+
+	chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
+	flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
+	return 0;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last close, then disable communications and interrupts.
+ * o reset flags.
+ */
+static int if_close (netdevice_t* dev)
+{
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	sdla_t* card = chdlc_priv_area->card;
+
+	/* Stop the PPP Layer */
+	sppp_close(dev);
+	stop_net_queue(dev);
+
+      #ifndef LINUX_2_4
+	dev->start=0;
+      #endif
+
+	wanpipe_close(card);
+	
+	return 0;
+}
+
+/*============================================================================
+ * Send a packet on a network interface.
+ * o set tbusy flag (marks start of the transmission) to block a timer-based
+ *   transmit from overlapping.
+ * o check link state. If link is not up, then drop the packet.
+ * o execute adapter send command.
+ * o free socket buffer
+ *
+ * Return:	0	complete (socket buffer must be freed)
+ *		non-0	packet may be re-transmitted (tbusy must be set)
+ *
+ * Notes:
+ * 1. This routine is called either by the protocol stack or by the "net
+ *    bottom half" (with interrupts enabled).
+ * 2. Setting tbusy flag will inhibit further transmit requests from the
+ *    protocol stack and can be used for flow control with protocol layer.
+ */
+static int if_send (struct sk_buff* skb, netdevice_t* dev)
+{
+	chdlc_private_area_t *chdlc_priv_area = dev->priv;
+	sdla_t *card = chdlc_priv_area->card;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
+	int udp_type = 0;
+	unsigned long smp_flags;
+	int err=0;
+
+      #ifdef LINUX_2_4
+	netif_stop_queue(dev);
+      #endif
+
+	
+	if (skb == NULL){
+		/* If we get here, some higher layer thinks we've missed an
+		 * tx-done interrupt.
+		 */
+		printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n",
+			card->devname, dev->name);
+
+		wake_net_dev(dev);
+		return 0;
+	}
+
+      #ifndef LINUX_2_4
+	if (dev->tbusy){
+
+		/* If our device stays busy for at least 5 seconds then we will
+		 * kick start the device by making dev->tbusy = 0.  We expect 
+		 * that our device never stays busy more than 5 seconds. So this
+		 * is only used as a last resort. 
+		 */
+                ++card->wandev.stats.collisions;
+
+		if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) {
+			return 1;
+		}
+
+		printk (KERN_INFO "%s: Transmit (tbusy) timeout !\n",
+			card->devname);
+
+		/* unbusy the interface */
+		dev->tbusy = 0;
+	}
+      #endif
+
+   	if (ntohs(skb->protocol) != htons(PVC_PROT)){
+		/* check the udp packet type */
+		
+		udp_type = udp_pkt_type(skb, card);
+		if (udp_type == UDP_CPIPE_TYPE){
+                        if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
+                                chdlc_priv_area)){
+				chdlc_int->interrupt_permission |=
+					APP_INT_ON_TIMER;
+			}
+			start_net_queue(dev);
+			return 0;
+		}
+        }
+
+	/* Lock the 508 Card: SMP is supported */
+      	if(card->hw.type != SDLA_S514){
+		s508_lock(card,&smp_flags);
+	} 
+
+    	if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){
+	
+		printk(KERN_INFO "%s: Critical in if_send: %lx\n",
+					card->wandev.name,card->wandev.critical);
+                ++card->wandev.stats.tx_dropped;
+		start_net_queue(dev);
+		goto if_send_crit_exit;
+	}
+
+	if (card->wandev.state != WAN_CONNECTED){
+		++card->wandev.stats.tx_dropped;
+		start_net_queue(dev);
+		goto if_send_crit_exit;
+	}
+	
+	if (chdlc_send(card, skb->data, skb->len)){
+		stop_net_queue(dev);
+
+	}else{
+		++card->wandev.stats.tx_packets;
+              #if defined(LINUX_2_1) || defined(LINUX_2_4)
+       		card->wandev.stats.tx_bytes += skb->len;
+              #endif
+	      #ifdef LINUX_2_4
+		dev->trans_start = jiffies;
+	      #endif
+		start_net_queue(dev);
+	}	
+
+if_send_crit_exit:
+	if (!(err=is_queue_stopped(dev))){
+                wan_dev_kfree_skb(skb, FREE_WRITE);
+	}else{
+		chdlc_priv_area->tick_counter = jiffies;
+		chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
+	}
+
+	clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
+	if(card->hw.type != SDLA_S514){
+		s508_unlock(card,&smp_flags);
+	}
+
+	return err;
+}
+
+
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return length of reply.
+ */
+static int reply_udp( unsigned char *data, unsigned int mbox_len )
+{
+
+	unsigned short len, udp_length, temp, ip_length;
+	unsigned long ip_temp;
+	int even_bound = 0;
+  	chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data;
+	 
+	/* Set length of packet */
+	len = sizeof(ip_pkt_t)+ 
+	      sizeof(udp_pkt_t)+
+	      sizeof(wp_mgmt_t)+
+	      sizeof(cblock_t)+
+	      sizeof(trace_info_t)+ 
+	      mbox_len;
+
+	/* fill in UDP reply */
+	c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
+   
+	/* fill in UDP length */
+	udp_length = sizeof(udp_pkt_t)+ 
+		     sizeof(wp_mgmt_t)+
+		     sizeof(cblock_t)+
+	             sizeof(trace_info_t)+
+		     mbox_len; 
+
+ 	/* put it on an even boundary */
+	if ( udp_length & 0x0001 ) {
+		udp_length += 1;
+		len += 1;
+		even_bound = 1;
+	}  
+
+	temp = (udp_length<<8)|(udp_length>>8);
+	c_udp_pkt->udp_pkt.udp_length = temp;
+		 
+	/* swap UDP ports */
+	temp = c_udp_pkt->udp_pkt.udp_src_port;
+	c_udp_pkt->udp_pkt.udp_src_port = 
+			c_udp_pkt->udp_pkt.udp_dst_port; 
+	c_udp_pkt->udp_pkt.udp_dst_port = temp;
+
+	/* add UDP pseudo header */
+	temp = 0x1100;
+	*((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp;	
+	temp = (udp_length<<8)|(udp_length>>8);
+	*((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp;
+
+		 
+	/* calculate UDP checksum */
+	c_udp_pkt->udp_pkt.udp_checksum = 0;
+	c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET);
+
+	/* fill in IP length */
+	ip_length = len;
+	temp = (ip_length<<8)|(ip_length>>8);
+	c_udp_pkt->ip_pkt.total_length = temp;
+  
+	/* swap IP addresses */
+	ip_temp = c_udp_pkt->ip_pkt.ip_src_address;
+	c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address;
+	c_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
+
+	/* fill in IP checksum */
+	c_udp_pkt->ip_pkt.hdr_checksum = 0;
+	c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t));
+
+	return len;
+
+} /* reply_udp */
+
+unsigned short calc_checksum (char *data, int len)
+{
+	unsigned short temp; 
+	unsigned long sum=0;
+	int i;
+
+	for( i = 0; i <len; i+=2 ) {
+		memcpy(&temp,&data[i],2);
+		sum += (unsigned long)temp;
+	}
+
+	while (sum >> 16 ) {
+		sum = (sum & 0xffffUL) + (sum >> 16);
+	}
+
+	temp = (unsigned short)sum;
+	temp = ~temp;
+
+	if( temp == 0 ) 
+		temp = 0xffff;
+
+	return temp;	
+}
+
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats* if_stats (netdevice_t* dev)
+{
+	sdla_t *my_card;
+	chdlc_private_area_t* chdlc_priv_area;
+
+	/* Shutdown bug fix. In del_if() we kill
+         * dev->priv pointer. This function, gets
+         * called after del_if(), thus check
+         * if pointer has been deleted */
+	if ((chdlc_priv_area=dev->priv) == NULL)
+		return NULL;
+
+	my_card = chdlc_priv_area->card;
+	return &my_card->wandev.stats; 
+}
+#else
+static struct enet_statistics* if_stats (netdevice_t* dev)
+{
+        sdla_t *my_card;
+        chdlc_private_area_t* chdlc_priv_area = dev->priv;
+
+	/* Shutdown bug fix. In del_if() we kill
+         * dev->priv pointer. This function, gets
+         * called after del_if(), thus check
+         * if pointer has been deleted */
+	if ((chdlc_priv_area=dev->priv) == NULL)
+		return NULL;
+
+        my_card = chdlc_priv_area->card;
+        return &my_card->wandev.stats;
+}
+#endif
+
+/****** Cisco HDLC Firmware Interface Functions *******************************/
+
+/*============================================================================
+ * Read firmware code version.
+ *	Put code version as ASCII string in str. 
+ */
+static int chdlc_read_version (sdla_t* card, char* str)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int len;
+	char err;
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_CODE_VERSION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+	if(err != COMMAND_OK) {
+		chdlc_error(card,err,mb);
+	}
+	else if (str) {  /* is not null */
+		len = mb->buffer_length;
+		memcpy(str, mb->data, len);
+		str[len] = '\0';
+	}
+	return (err);
+}
+
+/*-----------------------------------------------------------------------------
+ *  Configure CHDLC firmware.
+ */
+static int chdlc_configure (sdla_t* card, void* data)
+{
+	int err;
+	CHDLC_MAILBOX_STRUCT *mailbox = card->mbox;
+	int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT);
+	
+	mailbox->buffer_length = data_length;  
+	memcpy(mailbox->data, data, data_length);
+	mailbox->command = SET_CHDLC_CONFIGURATION;
+	err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT;
+	
+	if (err != COMMAND_OK) chdlc_error (card, err, mailbox);
+                           
+	return err;
+}
+
+
+/*============================================================================
+ * Set interrupt mode -- HDLC Version.
+ */
+
+static int chdlc_set_intr_mode (sdla_t* card, unsigned mode)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	CHDLC_INT_TRIGGERS_STRUCT* int_data =
+		 (CHDLC_INT_TRIGGERS_STRUCT *)mb->data;
+	int err;
+
+	int_data->CHDLC_interrupt_triggers 	= mode;
+	int_data->IRQ				= card->hw.irq;
+	int_data->interrupt_timer               = 1;
+   
+	mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT);
+	mb->command = SET_CHDLC_INTERRUPT_TRIGGERS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error (card, err, mb);
+	return err;
+}
+
+
+/*============================================================================
+ * Enable communications.
+ */
+
+static int chdlc_comm_enable (sdla_t* card)
+{
+	int err;
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+	mb->buffer_length = 0;
+	mb->command = ENABLE_CHDLC_COMMUNICATIONS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error(card, err, mb);
+	else
+		card->u.c.comm_enabled=1;
+
+	return err;
+}
+
+/*============================================================================
+ * Disable communications and Drop the Modem lines (DCD and RTS).
+ */
+static int chdlc_comm_disable (sdla_t* card)
+{
+	int err;
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+	mb->buffer_length = 0;
+	mb->command = DISABLE_CHDLC_COMMUNICATIONS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error(card,err,mb);
+
+	return err;
+}
+
+/*============================================================================
+ * Read communication error statistics.
+ */
+static int chdlc_read_comm_err_stats (sdla_t* card)
+{
+        int err;
+        CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+        mb->buffer_length = 0;
+        mb->command = READ_COMMS_ERROR_STATS;
+        err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+        if (err != COMMAND_OK)
+                chdlc_error(card,err,mb);
+        return err;
+}
+
+
+/*============================================================================
+ * Read CHDLC operational statistics.
+ */
+static int chdlc_read_op_stats (sdla_t* card)
+{
+        int err;
+        CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+        mb->buffer_length = 0;
+        mb->command = READ_CHDLC_OPERATIONAL_STATS;
+        err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+        if (err != COMMAND_OK)
+                chdlc_error(card,err,mb);
+        return err;
+}
+
+
+/*============================================================================
+ * Update communications error and general packet statistics.
+ */
+static int update_comms_stats(sdla_t* card,
+	chdlc_private_area_t* chdlc_priv_area)
+{
+        CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+  	COMMS_ERROR_STATS_STRUCT* err_stats;
+        CHDLC_OPERATIONAL_STATS_STRUCT *op_stats;
+
+	/* on the first timer interrupt, read the comms error statistics */
+	if(chdlc_priv_area->update_comms_stats == 2) {
+		if(chdlc_read_comm_err_stats(card))
+			return 1;
+		err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data;
+		card->wandev.stats.rx_over_errors = 
+				err_stats->Rx_overrun_err_count;
+		card->wandev.stats.rx_crc_errors = 
+				err_stats->CRC_err_count;
+		card->wandev.stats.rx_frame_errors = 
+				err_stats->Rx_abort_count;
+		card->wandev.stats.rx_fifo_errors = 
+				err_stats->Rx_dis_pri_bfrs_full_count; 
+		card->wandev.stats.rx_missed_errors =
+				card->wandev.stats.rx_fifo_errors;
+		card->wandev.stats.tx_aborted_errors =
+				err_stats->sec_Tx_abort_count;
+	}
+
+        /* on the second timer interrupt, read the operational statistics */
+	else {
+        	if(chdlc_read_op_stats(card))
+                	return 1;
+		op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data;
+		card->wandev.stats.rx_length_errors =
+			(op_stats->Rx_Data_discard_short_count +
+			op_stats->Rx_Data_discard_long_count);
+	}
+
+	return 0;
+}
+
+/*============================================================================
+ * Send packet.
+ *	Return:	0 - o.k.
+ *		1 - no transmit buffers available
+ */
+static int chdlc_send (sdla_t* card, void* data, unsigned len)
+{
+	CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf;
+
+	if (txbuf->opp_flag)
+		return 1;
+	
+	sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len);
+
+	txbuf->frame_length = len;
+	txbuf->opp_flag = 1;		/* start transmission */
+	
+	/* Update transmit buffer control fields */
+	card->u.c.txbuf = ++txbuf;
+
+	if ((void*)txbuf > card->u.c.txbuf_last)
+		card->u.c.txbuf = card->u.c.txbuf_base;
+
+	return 0;
+}
+
+/****** Firmware Error Handler **********************************************/
+
+/*============================================================================
+ * Firmware error handler.
+ *	This routine is called whenever firmware command returns non-zero
+ *	return code.
+ *
+ * Return zero if previous command has to be cancelled.
+ */
+static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb)
+{
+	unsigned cmd = mb->command;
+
+	switch (err) {
+
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, cmd);
+		break;
+
+	case S514_BOTH_PORTS_SAME_CLK_MODE:
+		if(cmd == SET_CHDLC_CONFIGURATION) {
+			printk(KERN_INFO
+			 "%s: Configure both ports for the same clock source\n",
+				card->devname);
+			break;
+		}
+
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+			card->devname, cmd, err);
+	}
+
+	return 0;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * Cisco HDLC interrupt service routine.
+ */
+STATIC void wsppp_isr (sdla_t* card)
+{
+	netdevice_t* dev;
+	SHARED_MEMORY_INFO_STRUCT* flags = NULL;
+	int i;
+	sdla_t *my_card;
+
+
+	/* Check for which port the interrupt has been generated
+	 * Since Secondary Port is piggybacking on the Primary
+         * the check must be done here. 
+	 */
+
+	flags = card->u.c.flags;
+	if (!flags->interrupt_info_struct.interrupt_type){
+		/* Check for a second port (piggybacking) */
+		if((my_card = card->next)){
+			flags = my_card->u.c.flags;
+			if (flags->interrupt_info_struct.interrupt_type){
+				card = my_card;
+				card->isr(card);
+				return;
+			}
+		}
+	}
+
+	dev = card->wandev.dev;
+	card->in_isr = 1;
+	flags = card->u.c.flags;
+		
+	/* If we get an interrupt with no network device, stop the interrupts
+	 * and issue an error */
+	if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != 
+	    	COMMAND_COMPLETE_APP_INT_PEND){
+		goto isr_done;
+	}
+
+	
+	/* if critical due to peripheral operations
+	 * ie. update() or getstats() then reset the interrupt and
+	 * wait for the board to retrigger.
+	 */
+	if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
+		flags->interrupt_info_struct.
+					interrupt_type = 0;
+		goto isr_done;
+	}
+
+
+	/* On a 508 Card, if critical due to if_send 
+         * Major Error !!!
+	 */
+	if(card->hw.type != SDLA_S514) {
+		if(test_bit(0, (void*)&card->wandev.critical)) {
+			printk(KERN_INFO "%s: Critical while in ISR: %lx\n",
+				card->devname, card->wandev.critical);
+			goto isr_done;
+		}
+	}
+
+	switch(flags->interrupt_info_struct.interrupt_type) {
+
+		case RX_APP_INT_PEND:	/* 0x01: receive interrupt */
+			rx_intr(card);
+			break;
+
+		case TX_APP_INT_PEND:	/* 0x02: transmit interrupt */
+			flags->interrupt_info_struct.interrupt_permission &=
+				 ~APP_INT_ON_TX_FRAME;
+
+			wake_net_dev(dev);
+			break;
+
+		case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
+			++ Intr_test_counter;
+			break;
+
+		case CHDLC_EXCEP_COND_APP_INT_PEND:	/* 0x20 */
+			process_chdlc_exception(card);
+			break;
+
+		case GLOBAL_EXCEP_COND_APP_INT_PEND:
+			process_global_exception(card);
+			break;
+
+		case TIMER_APP_INT_PEND:
+			timer_intr(card);
+			break;
+
+		default:
+			printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", 
+				card->devname,
+				flags->interrupt_info_struct.interrupt_type);
+			printk(KERN_INFO "Code name: ");
+			for(i = 0; i < 4; i ++)
+				printk(KERN_INFO "%c",
+					flags->global_info_struct.codename[i]); 
+			printk(KERN_INFO "\nCode version: ");
+			for(i = 0; i < 4; i ++)
+				printk(KERN_INFO "%c", 
+					flags->global_info_struct.codeversion[i]); 
+			printk(KERN_INFO "\n");	
+			break;
+	}
+
+isr_done:
+	card->in_isr = 0;
+	flags->interrupt_info_struct.interrupt_type = 0;
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void rx_intr (sdla_t* card)
+{
+	netdevice_t *dev;
+	chdlc_private_area_t *chdlc_priv_area;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb;
+	struct sk_buff *skb;
+	unsigned len;
+	unsigned addr = rxbuf->ptr_data_bfr;
+	void *buf;
+	int i,udp_type;
+	
+	if (rxbuf->opp_flag != 0x01) {
+		printk(KERN_INFO 
+			"%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", 
+			card->devname, (unsigned)rxbuf, rxbuf->opp_flag);
+                printk(KERN_INFO "Code name: ");
+                for(i = 0; i < 4; i ++)
+                        printk(KERN_INFO "%c",
+                                flags->global_info_struct.codename[i]);
+                printk(KERN_INFO "\nCode version: ");
+                for(i = 0; i < 4; i ++)
+                        printk(KERN_INFO "%c",
+                                flags->global_info_struct.codeversion[i]);
+                printk(KERN_INFO "\n");
+
+
+		/* Bug Fix: Mar 6 2000
+                 * If we get a corrupted mailbox, it measn that driver 
+                 * is out of sync with the firmware. There is no recovery.
+                 * If we don't turn off all interrupts for this card
+                 * the machine will crash. 
+                 */
+		printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
+		printk(KERN_INFO "Please contact Sangoma Technologies !\n");
+		chdlc_set_intr_mode(card,0);	
+		return;
+	}
+
+	dev = card->wandev.dev;
+
+	if (!dev){ 
+		goto rx_exit;
+	}
+	
+      #ifdef LINUX_2_4
+	if (!netif_running(dev)){
+		goto rx_exit;
+	}
+      #else
+	if (!dev->start){ 
+		goto rx_exit;
+	}
+      #endif
+
+	chdlc_priv_area = dev->priv;
+
+	if (rxbuf->error_flag){	
+		goto rx_exit;
+	}
+	/* Take off two CRC bytes */
+
+	if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){
+		goto rx_exit;
+	}	
+
+	len = rxbuf->frame_length - CRC_LENGTH;
+
+	/* Allocate socket buffer */
+	skb = dev_alloc_skb(len);
+
+	if (skb == NULL) {
+		if (net_ratelimit()){
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+						card->devname);
+		}
+		++card->wandev.stats.rx_dropped;
+		goto rx_exit;
+	}
+
+	/* Copy data to the socket buffer */
+	if((addr + len) > card->u.c.rx_top + 1) {
+		unsigned tmp = card->u.c.rx_top - addr + 1;
+		buf = skb_put(skb, tmp);
+		sdla_peek(&card->hw, addr, buf, tmp);
+		addr = card->u.c.rx_base;
+		len -= tmp;
+	}
+		
+	buf = skb_put(skb, len);
+	sdla_peek(&card->hw, addr, buf, len);
+
+	skb->protocol = htons(ETH_P_WAN_PPP);
+
+	card->wandev.stats.rx_packets ++;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	card->wandev.stats.rx_bytes += skb->len;
+#endif
+	udp_type = udp_pkt_type( skb, card );
+
+	if(udp_type == UDP_CPIPE_TYPE) {
+		if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK,
+   				      card, skb, dev, chdlc_priv_area)) {
+     		        flags->interrupt_info_struct.
+						interrupt_permission |= 
+							APP_INT_ON_TIMER; 
+		}
+	}else{
+               	/* Pass it up the protocol stack */
+                skb->dev = dev;
+                skb->mac.raw  = skb->data;
+                netif_rx(skb);
+	}
+
+rx_exit:
+	/* Release buffer element and calculate a pointer to the next one */
+	rxbuf->opp_flag = 0x00;
+	card->u.c.rxmb = ++ rxbuf;
+	if((void*)rxbuf > card->u.c.rxbuf_last){
+		card->u.c.rxmb = card->u.c.rxbuf_base;
+	}
+}
+
+/*============================================================================
+ * Timer interrupt handler.
+ * The timer interrupt is used for two purposes:
+ *    1) Processing udp calls from 'cpipemon'.
+ *    2) Reading board-level statistics for updating the proc file system.
+ */
+void timer_intr(sdla_t *card)
+{
+        netdevice_t* dev;
+        chdlc_private_area_t* chdlc_priv_area = NULL;
+        SHARED_MEMORY_INFO_STRUCT* flags = NULL;
+
+        dev = card->wandev.dev; 
+        chdlc_priv_area = dev->priv;
+
+	if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) {
+		if (!config_chdlc(card)){
+			chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
+		}
+	}
+	
+	/* process a udp call if pending */
+       	if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) {
+               	process_udp_mgmt_pkt(card, dev,
+                       chdlc_priv_area);
+		chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
+        }
+	
+
+	/* read the communications statistics if required */
+	if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
+		update_comms_stats(card, chdlc_priv_area);
+                if(!(-- chdlc_priv_area->update_comms_stats)) {
+			chdlc_priv_area->timer_int_enabled &= 
+				~TMR_INT_ENABLED_UPDATE;
+		}
+        }
+
+	/* only disable the timer interrupt if there are no udp or statistic */
+	/* updates pending */
+        if(!chdlc_priv_area->timer_int_enabled) {
+                flags = card->u.c.flags;
+                flags->interrupt_info_struct.interrupt_permission &=
+                        ~APP_INT_ON_TIMER;
+        }
+}
+
+/*------------------------------------------------------------------------------
+  Miscellaneous Functions
+	- set_chdlc_config() used to set configuration options on the board
+------------------------------------------------------------------------------*/
+
+static int set_chdlc_config(sdla_t* card)
+{
+
+	CHDLC_CONFIGURATION_STRUCT cfg;
+
+	memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT));
+
+	if(card->wandev.clocking)
+		cfg.baud_rate = card->wandev.bps;
+
+	cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
+		INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
+
+	cfg.modem_config_options	= 0;
+	//API OPTIONS
+	cfg.CHDLC_API_options		= DISCARD_RX_ERROR_FRAMES;
+	cfg.modem_status_timer		= 100;
+	cfg.CHDLC_protocol_options	= HDLC_STREAMING_MODE;
+	cfg.percent_data_buffer_for_Tx  = 50;
+	cfg.CHDLC_statistics_options	= (CHDLC_TX_DATA_BYTE_COUNT_STAT |
+		CHDLC_RX_DATA_BYTE_COUNT_STAT);
+	cfg.max_CHDLC_data_field_length	= card->wandev.mtu;
+
+	cfg.transmit_keepalive_timer	= 0;
+	cfg.receive_keepalive_timer	= 0;
+	cfg.keepalive_error_tolerance	= 0;
+	cfg.SLARP_request_timer		= 0;
+
+	cfg.IP_address		= 0;
+	cfg.IP_netmask		= 0;
+	
+	return chdlc_configure(card, &cfg);
+}
+
+/*============================================================================
+ * Process global exception condition
+ */
+static int process_global_exception(sdla_t *card)
+{
+	CHDLC_MAILBOX_STRUCT* mbox = card->mbox;
+	int err;
+
+	mbox->buffer_length = 0;
+	mbox->command = READ_GLOBAL_EXCEPTION_CONDITION;
+	err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT;
+
+	if(err != CMD_TIMEOUT ){
+	
+		switch(mbox->return_code) {
+         
+	      	case EXCEP_MODEM_STATUS_CHANGE:
+
+			printk(KERN_INFO "%s: Modem status change\n",
+				card->devname);
+
+			switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) {
+				case (DCD_HIGH):
+					printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname);
+					break;
+				case (CTS_HIGH):
+                                        printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname);
+                                        break;
+                                case ((DCD_HIGH | CTS_HIGH)):
+                                        printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname);
+                                        break;
+				default:
+                                        printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname);
+                                        break;
+			}
+
+			if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){
+				//printk(KERN_INFO "Sending TERM Request Manually !\n");
+				send_ppp_term_request(card->wandev.dev);
+			}	
+			break;
+
+                case EXCEP_TRC_DISABLED:
+                        printk(KERN_INFO "%s: Line trace disabled\n",
+				card->devname);
+                        break;
+
+		case EXCEP_IRQ_TIMEOUT:
+			printk(KERN_INFO "%s: IRQ timeout occurred\n",
+				card->devname); 
+			break;
+
+                default:
+                        printk(KERN_INFO "%s: Global exception %x\n",
+				card->devname, mbox->return_code);
+                        break;
+                }
+	}
+	return 0;
+}
+
+
+/*============================================================================
+ * Process chdlc exception condition
+ */
+static int process_chdlc_exception(sdla_t *card)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int err;
+
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_EXCEPTION_CONDITION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if(err != CMD_TIMEOUT) {
+	
+		switch (err) {
+
+		case EXCEP_LINK_ACTIVE:
+			port_set_state(card, WAN_CONNECTED);
+			break;
+
+		case EXCEP_LINK_INACTIVE_MODEM:
+			port_set_state(card, WAN_DISCONNECTED);
+			break;
+
+		case EXCEP_LOOPBACK_CONDITION:
+			printk(KERN_INFO "%s: Loopback Condition Detected.\n",
+						card->devname);
+			break;
+
+		case NO_CHDLC_EXCEP_COND_TO_REPORT:
+			printk(KERN_INFO "%s: No exceptions reported.\n",
+						card->devname);
+			break;
+		default:
+			printk(KERN_INFO "%s: Exception Condition %x!\n",
+					card->devname,err);
+			break;
+		}
+
+	}
+	return 0;
+}
+
+
+/*=============================================================================
+ * Store a UDP management packet for later processing.
+ */
+
+static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, netdevice_t* dev,
+                                chdlc_private_area_t* chdlc_priv_area )
+{
+	int udp_pkt_stored = 0;
+
+	if(!chdlc_priv_area->udp_pkt_lgth &&
+	  (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) {
+        	chdlc_priv_area->udp_pkt_lgth = skb->len;
+		chdlc_priv_area->udp_pkt_src = udp_pkt_src;
+       		memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len);
+		chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP;
+		udp_pkt_stored = 1;
+	}
+
+	if(udp_pkt_src == UDP_PKT_FRM_STACK)
+		wan_dev_kfree_skb(skb, FREE_WRITE);
+	else
+                wan_dev_kfree_skb(skb, FREE_READ);
+	
+	return(udp_pkt_stored);
+}
+
+
+/*=============================================================================
+ * Process UDP management packet.
+ */
+
+static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,
+				chdlc_private_area_t* chdlc_priv_area ) 
+{
+	unsigned char *buf;
+	unsigned int frames, len;
+	struct sk_buff *new_skb;
+	unsigned short buffer_length, real_len;
+	unsigned long data_ptr;
+	unsigned data_length;
+	int udp_mgmt_req_valid = 1;
+	CHDLC_MAILBOX_STRUCT *mb = card->mbox;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	chdlc_udp_pkt_t *chdlc_udp_pkt;
+	struct timeval tv;
+	int err;
+	char ut_char;
+
+	chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data;
+
+	if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+
+		switch(chdlc_udp_pkt->cblock.command) {
+			case READ_GLOBAL_STATISTICS:
+			case READ_MODEM_STATUS:  
+			case READ_CHDLC_LINK_STATUS:
+			case CPIPE_ROUTER_UP_TIME:
+			case READ_COMMS_ERROR_STATS:
+			case READ_CHDLC_OPERATIONAL_STATS:
+
+			/* These two commands are executed for
+			 * each request */
+			case READ_CHDLC_CONFIGURATION:
+			case READ_CHDLC_CODE_VERSION:
+				udp_mgmt_req_valid = 1;
+				break;
+			default:
+				udp_mgmt_req_valid = 0;
+				break;
+		} 
+	}
+	
+  	if(!udp_mgmt_req_valid) {
+
+		/* set length to 0 */
+		chdlc_udp_pkt->cblock.buffer_length = 0;
+
+    		/* set return code */
+		chdlc_udp_pkt->cblock.return_code = 0xCD;
+
+		if (net_ratelimit()){	
+			printk(KERN_INFO 
+			"%s: Warning, Illegal UDP command attempted from network: %x\n",
+			card->devname,chdlc_udp_pkt->cblock.command);
+		}
+
+   	} else {
+	   	unsigned long trace_status_cfg_addr = 0;
+		TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct;
+		TRACE_STATUS_ELEMENT_STRUCT trace_element_struct;
+
+		switch(chdlc_udp_pkt->cblock.command) {
+
+		case CPIPE_ENABLE_TRACING:
+		     if (!chdlc_priv_area->TracingEnabled) {
+
+			/* OPERATE_DATALINE_MONITOR */
+
+			mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
+			mb->command = SET_TRACE_CONFIGURATION;
+
+    			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
+				trace_config = TRACE_ACTIVE;
+			/* Trace delay mode is not used because it slows
+			   down transfer and results in a standoff situation
+			   when there is a lot of data */
+
+			/* Configure the Trace based on user inputs */
+			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= 
+					chdlc_udp_pkt->data[0];
+
+			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
+			   trace_deactivation_timer = 4000;
+
+
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+			if (err != COMMAND_OK) {
+				chdlc_error(card,err,mb);
+				card->TracingEnabled = 0;
+				chdlc_udp_pkt->cblock.return_code = err;
+				mb->buffer_length = 0;
+				break;
+	    		} 
+
+			/* Get the base address of the trace element list */
+			mb->buffer_length = 0;
+			mb->command = READ_TRACE_CONFIGURATION;
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+			if (err != COMMAND_OK) {
+				chdlc_error(card,err,mb);
+				chdlc_priv_area->TracingEnabled = 0;
+				chdlc_udp_pkt->cblock.return_code = err;
+				mb->buffer_length = 0;
+				break;
+	    		} 	
+
+	   		trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *)
+				mb->data) -> ptr_trace_stat_el_cfg_struct;
+
+			sdla_peek(&card->hw, trace_status_cfg_addr,
+				 &trace_cfg_struct, sizeof(trace_cfg_struct));
+		    
+			chdlc_priv_area->start_trace_addr = trace_cfg_struct.
+				base_addr_trace_status_elements;
+
+			chdlc_priv_area->number_trace_elements = 
+					trace_cfg_struct.number_trace_status_elements;
+
+			chdlc_priv_area->end_trace_addr = (unsigned long)
+					((TRACE_STATUS_ELEMENT_STRUCT *)
+					 chdlc_priv_area->start_trace_addr + 
+					 (chdlc_priv_area->number_trace_elements - 1));
+
+			chdlc_priv_area->base_addr_trace_buffer = 
+					trace_cfg_struct.base_addr_trace_buffer;
+
+			chdlc_priv_area->end_addr_trace_buffer = 
+					trace_cfg_struct.end_addr_trace_buffer;
+
+		    	chdlc_priv_area->curr_trace_addr = 
+					trace_cfg_struct.next_trace_element_to_use;
+
+	    		chdlc_priv_area->available_buffer_space = 2000 - 
+								  sizeof(ip_pkt_t) -
+								  sizeof(udp_pkt_t) -
+							      	  sizeof(wp_mgmt_t) -
+								  sizeof(cblock_t) -
+							          sizeof(trace_info_t);	
+	       	     }
+		     chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+		     mb->buffer_length = 0;
+	       	     chdlc_priv_area->TracingEnabled = 1;
+	       	     break;
+	   
+
+		case CPIPE_DISABLE_TRACING:
+		     if (chdlc_priv_area->TracingEnabled) {
+
+			/* OPERATE_DATALINE_MONITOR */
+			mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
+			mb->command = SET_TRACE_CONFIGURATION;
+    			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
+				trace_config = TRACE_INACTIVE;
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+		     }		
+
+		     chdlc_priv_area->TracingEnabled = 0;
+		     chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+		     mb->buffer_length = 0;
+		     break;
+	   
+
+		case CPIPE_GET_TRACE_INFO:
+
+		     if (!chdlc_priv_area->TracingEnabled) {
+			chdlc_udp_pkt->cblock.return_code = 1;
+			mb->buffer_length = 0;
+			break;
+		     }
+
+  		     chdlc_udp_pkt->trace_info.ismoredata = 0x00;
+		     buffer_length = 0;	/* offset of packet already occupied */
+
+		     for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){
+
+			trace_pkt_t *trace_pkt = (trace_pkt_t *)
+				&chdlc_udp_pkt->data[buffer_length];
+
+			sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr,
+			   	  (unsigned char *)&trace_element_struct,
+			   	  sizeof(TRACE_STATUS_ELEMENT_STRUCT));
+
+     			if (trace_element_struct.opp_flag == 0x00) {
+			 	break;
+			}
+
+			/* get pointer to real data */
+			data_ptr = trace_element_struct.ptr_data_bfr;
+
+			/* See if there is actual data on the trace buffer */
+			if (data_ptr){
+				data_length = trace_element_struct.trace_length;
+			}else{
+				data_length = 0;
+				chdlc_udp_pkt->trace_info.ismoredata = 0x01;
+			}
+	
+   			if( (chdlc_priv_area->available_buffer_space - buffer_length)
+				< ( sizeof(trace_pkt_t) + data_length) ) {
+
+                            /* indicate there are more frames on board & exit */
+				chdlc_udp_pkt->trace_info.ismoredata = 0x01;
+                               	break;
+                         }
+
+			trace_pkt->status = trace_element_struct.trace_type;
+
+			trace_pkt->time_stamp =
+				trace_element_struct.trace_time_stamp;
+
+			trace_pkt->real_length =
+				trace_element_struct.trace_length;
+
+			/* see if we can fit the frame into the user buffer */
+			real_len = trace_pkt->real_length;
+
+			if (data_ptr == 0) {
+			     	trace_pkt->data_avail = 0x00;
+			} else {
+				unsigned tmp = 0;
+
+				/* get the data from circular buffer
+				    must check for end of buffer */
+			        trace_pkt->data_avail = 0x01;
+
+				if ((data_ptr + real_len) >
+					     chdlc_priv_area->end_addr_trace_buffer + 1){
+
+				    	tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1;
+				    	sdla_peek(&card->hw, data_ptr,
+					       	  trace_pkt->data,tmp);
+				    	data_ptr = chdlc_priv_area->base_addr_trace_buffer;
+				}
+	
+		        	sdla_peek(&card->hw, data_ptr,
+					  &trace_pkt->data[tmp], real_len - tmp);
+			}	
+
+			/* zero the opp flag to show we got the frame */
+			ut_char = 0x00;
+			sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1);
+
+       			/* now move onto the next frame */
+       			chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT);
+
+       			/* check if we went over the last address */
+			if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) {
+				chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr;
+       			}
+
+            		if(trace_pkt->data_avail == 0x01) {
+				buffer_length += real_len - 1;
+			}
+	 
+	       	    	/* for the header */
+	            	buffer_length += sizeof(trace_pkt_t);
+
+		     }  /* For Loop */
+
+		     if (frames == chdlc_priv_area->number_trace_elements){
+			chdlc_udp_pkt->trace_info.ismoredata = 0x01;
+	             }
+ 		     chdlc_udp_pkt->trace_info.num_frames = frames;
+		 
+    		     mb->buffer_length = buffer_length;
+		     chdlc_udp_pkt->cblock.buffer_length = buffer_length; 
+		 
+		     chdlc_udp_pkt->cblock.return_code = COMMAND_OK; 
+		     
+		     break;
+
+
+		case CPIPE_FT1_READ_STATUS:
+			((unsigned char *)chdlc_udp_pkt->data )[0] =
+				flags->FT1_info_struct.parallel_port_A_input;
+
+			((unsigned char *)chdlc_udp_pkt->data )[1] =
+				flags->FT1_info_struct.parallel_port_B_input;
+				 
+			chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+			mb->buffer_length = 2;
+			break;
+		
+		case CPIPE_ROUTER_UP_TIME:
+			do_gettimeofday( &tv );
+			chdlc_priv_area->router_up_time = tv.tv_sec - 
+					chdlc_priv_area->router_start_time;
+			*(unsigned long *)&chdlc_udp_pkt->data = 
+					chdlc_priv_area->router_up_time;	
+			mb->buffer_length = sizeof(unsigned long);
+			break;
+
+   		case FT1_MONITOR_STATUS_CTRL:
+			/* Enable FT1 MONITOR STATUS */
+	        	if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) ||  
+				(chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) {
+			
+			     	if( rCount++ != 0 ) {
+					chdlc_udp_pkt->cblock.
+					return_code = COMMAND_OK;
+					mb->buffer_length = 1;
+		  			break;
+		    	     	}
+	      		}
+
+	      		/* Disable FT1 MONITOR STATUS */
+	      		if( chdlc_udp_pkt->data[0] == 0) {
+
+	      	   	     	if( --rCount != 0) {
+		  			chdlc_udp_pkt->cblock.
+					return_code = COMMAND_OK;
+					mb->buffer_length = 1;
+		  			break;
+	   	    	     	} 
+	      		} 	
+	
+		default:
+			/* it's a board command */
+			mb->command = chdlc_udp_pkt->cblock.command;
+			mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length;
+			if (mb->buffer_length) {
+				memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt->
+							data, mb->buffer_length);
+	      		} 
+			/* run the command on the board */
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+			if (err != COMMAND_OK) {
+				break;
+			}
+
+			/* copy the result back to our buffer */
+	         	memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); 
+			
+			if (mb->buffer_length) {
+	         		memcpy(&chdlc_udp_pkt->data, &mb->data, 
+								mb->buffer_length); 
+	      		}
+
+		} /* end of switch */
+     	} /* end of else */
+
+     	/* Fill UDP TTL */
+	chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; 
+
+     	len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length);
+	
+     	if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) {
+			++ card->wandev.stats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+			card->wandev.stats.tx_bytes += len;
+#endif
+		}
+	} else {	
+	
+		/* Pass it up the stack
+    		   Allocate socket buffer */
+		if ((new_skb = dev_alloc_skb(len)) != NULL) {
+			/* copy data into new_skb */
+
+ 	    		buf = skb_put(new_skb, len);
+  	    		memcpy(buf, chdlc_priv_area->udp_pkt_data, len);
+
+            		/* Decapsulate pkt and pass it up the protocol stack */
+	    		new_skb->protocol = htons(ETH_P_IP);
+            		new_skb->dev = dev;
+	    		new_skb->mac.raw  = new_skb->data;
+	
+			netif_rx(new_skb);
+		} else {
+	    	
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+					card->devname);
+  		}
+    	}
+ 
+	chdlc_priv_area->udp_pkt_lgth = 0;
+ 	
+	return 0;
+}
+
+/*============================================================================
+ * Initialize Receive and Transmit Buffers.
+ */
+
+static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev )
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config;
+	CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config;
+	char err;
+	
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_CONFIGURATION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+	if(err != COMMAND_OK) {
+		chdlc_error(card,err,mb);
+		return;
+	}
+
+	if(card->hw.type == SDLA_S514) {
+		tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+                (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+                            ptr_CHDLC_Tx_stat_el_cfg_struct));
+        	rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+                (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+                            ptr_CHDLC_Rx_stat_el_cfg_struct));
+
+       		/* Setup Head and Tails for buffers */
+        	card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
+                tx_config->base_addr_Tx_status_elements);
+        	card->u.c.txbuf_last = 
+		(CHDLC_DATA_TX_STATUS_EL_STRUCT *)  
+                card->u.c.txbuf_base +
+		(tx_config->number_Tx_status_elements - 1);
+
+        	card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
+                rx_config->base_addr_Rx_status_elements);
+        	card->u.c.rxbuf_last =
+		(CHDLC_DATA_RX_STATUS_EL_STRUCT *)
+                card->u.c.rxbuf_base +
+		(rx_config->number_Rx_status_elements - 1);
+
+ 		/* Set up next pointer to be used */
+        	card->u.c.txbuf = (void *)(card->hw.dpmbase +
+                tx_config->next_Tx_status_element_to_use);
+        	card->u.c.rxmb = (void *)(card->hw.dpmbase +
+                rx_config->next_Rx_status_element_to_use);
+	}
+        else {
+                tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+			(((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+			ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
+
+                rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+			(((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+			ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
+
+                /* Setup Head and Tails for buffers */
+                card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
+		(tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE));
+                card->u.c.txbuf_last =
+		(CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base
+		+ (tx_config->number_Tx_status_elements - 1);
+                card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
+		(rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE));
+                card->u.c.rxbuf_last = 
+		(CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base
+		+ (rx_config->number_Rx_status_elements - 1);
+
+                 /* Set up next pointer to be used */
+                card->u.c.txbuf = (void *)(card->hw.dpmbase +
+		(tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE));
+                card->u.c.rxmb = (void *)(card->hw.dpmbase +
+		(rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE));
+        }
+
+        /* Setup Actual Buffer Start and end addresses */
+        card->u.c.rx_base = rx_config->base_addr_Rx_buffer;
+        card->u.c.rx_top  = rx_config->end_addr_Rx_buffer;
+
+}
+
+/*=============================================================================
+ * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR
+ * _TEST_COUNTER times.
+ */
+static int intr_test( sdla_t* card)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int err,i;
+
+	Intr_test_counter = 0;
+
+	/* The critical flag is unset because during intialization (if_open) 
+	 * we want the interrupts to be enabled so that when the wpc_isr is
+	 * called it does not exit due to critical flag set.
+	 */ 
+
+	err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE);
+
+	if (err == CMD_OK) { 
+		for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {	
+			mb->buffer_length  = 0;
+			mb->command = READ_CHDLC_CODE_VERSION;
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+		}
+	}
+	else {
+		return err;
+	}
+
+	err = chdlc_set_intr_mode(card, 0);
+
+	if (err != CMD_OK)
+		return err;
+
+	return 0;
+}
+
+/*==============================================================================
+ * Determine what type of UDP call it is. CPIPEAB ?
+ */
+static int udp_pkt_type(struct sk_buff *skb, sdla_t* card)
+{
+	 chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data;
+
+	if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) &&
+	   (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
+	   (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
+	   (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
+		return UDP_CPIPE_TYPE;
+	}
+	else return UDP_INVALID_TYPE;
+}
+
+/*============================================================================
+ * Set PORT state.
+ */
+static void port_set_state (sdla_t *card, int state)
+{
+	netdevice_t *dev = card->wandev.dev;
+	chdlc_private_area_t *chdlc_priv_area = dev->priv;
+
+        if (card->u.c.state != state)
+        {
+                switch (state)
+                {
+                case WAN_CONNECTED:
+                        printk (KERN_INFO "%s: HDLC link connected!\n",
+                                card->devname);
+                      break;
+
+                case WAN_CONNECTING:
+                        printk (KERN_INFO "%s: HDLC link connecting...\n",
+                                card->devname);
+                        break;
+
+                case WAN_DISCONNECTED:
+                        printk (KERN_INFO "%s: HDLC link disconnected!\n",
+                                card->devname);
+                        break;
+                }
+
+                card->wandev.state = card->u.c.state = state;
+		chdlc_priv_area->common.state = state;
+        }
+}
+
+void s508_lock (sdla_t *card, unsigned long *smp_flags)
+{
+      #if defined(__SMP__) || defined(LINUX_2_4)
+	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
+        if (card->next){
+		/* It is ok to use spin_lock here, since we
+		 * already turned off interrupts */
+        	spin_lock(&card->next->wandev.lock);
+	}
+      #else
+	disable_irq(card->hw.irq);
+      #endif
+}
+
+void s508_unlock (sdla_t *card, unsigned long *smp_flags)
+{
+      #if defined(__SMP__) || defined(LINUX_2_4)
+	if (card->next){
+		spin_unlock(&card->next->wandev.lock);
+	}
+	spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
+      #else
+	enable_irq(card->hw.irq);
+      #endif           
+}
+
+
+
+/*===========================================================================
+ * config_chdlc
+ *
+ *	Configure the chdlc protocol and enable communications.		
+ *
+ *   	The if_open() function binds this function to the poll routine.
+ *      Therefore, this function will run every time the chdlc interface
+ *      is brought up. We cannot run this function from the if_open 
+ *      because if_open does not have access to the remote IP address.
+ *      
+ *	If the communications are not enabled, proceed to configure
+ *      the card and enable communications.
+ *
+ *      If the communications are enabled, it means that the interface
+ *      was shutdown by ether the user or driver. In this case, we 
+ *      have to check that the IP addresses have not changed.  If
+ *      the IP addresses have changed, we have to reconfigure the firmware
+ *      and update the changed IP addresses.  Otherwise, just exit.
+ *
+ */
+
+static int config_chdlc (sdla_t *card)
+{
+	netdevice_t *dev = card->wandev.dev;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+
+	if (card->u.c.comm_enabled){
+		chdlc_comm_disable(card);
+		port_set_state(card, WAN_DISCONNECTED);
+	}
+
+	if (set_chdlc_config(card)) {
+		printk(KERN_INFO "%s: CHDLC Configuration Failed!\n",
+				card->devname);
+		return 0;
+	}
+	init_chdlc_tx_rx_buff(card, dev);
+
+	/* Set interrupt mode and mask */
+        if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
+                		APP_INT_ON_GLOBAL_EXCEP_COND |
+                		APP_INT_ON_TX_FRAME |
+                		APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
+		printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
+				card->devname);
+		return 0;	
+        }
+	
+
+	/* Mask the Transmit and Timer interrupt */
+	flags->interrupt_info_struct.interrupt_permission &= 
+		~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
+
+
+	if (chdlc_comm_enable(card) != 0) {
+		printk(KERN_INFO "%s: Failed to enable chdlc communications!\n",
+				card->devname);
+		flags->interrupt_info_struct.interrupt_permission = 0;
+		card->u.c.comm_enabled=0;
+		chdlc_set_intr_mode(card,0);
+		return 0;
+	}
+
+	/* Initialize Rx/Tx buffer control fields */
+	port_set_state(card, WAN_CONNECTING);
+	return 0; 
+}
+
+
+static void send_ppp_term_request (netdevice_t *dev)
+{
+	struct sk_buff *new_skb;
+	unsigned char *buf;
+
+	if ((new_skb = dev_alloc_skb(8)) != NULL) {
+		/* copy data into new_skb */
+
+		buf = skb_put(new_skb, 8);
+		sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07);
+
+		/* Decapsulate pkt and pass it up the protocol stack */
+		new_skb->protocol = htons(ETH_P_WAN_PPP);
+		new_skb->dev = dev;
+		new_skb->mac.raw  = new_skb->data;
+
+		netif_rx(new_skb);
+	}
+}
+
+
+/****** End ****************************************************************/
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- v2.4.3/linux/drivers/net/wan/x25_asy.c	Sat Nov 11 19:02:39 2000
+++ linux/drivers/net/wan/x25_asy.c	Wed Apr 18 14:40:07 2001
@@ -874,8 +874,6 @@
 	dev->type		= ARPHRD_X25;
 	dev->tx_queue_len	= 10;
 
-	dev_init_buffers(dev);
-	
 	/* New-style flags. */
 	dev->flags		= IFF_NOARP;
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.4.3/linux/drivers/net/wavelan.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/wavelan.c	Wed Apr 25 14:36:23 2001
@@ -2028,8 +2028,17 @@
 		if (wrq->u.data.pointer != (caddr_t) 0) {
 			struct iw_range range;
 
-			/* Set the length (useless:  it's constant). */
+			/* Set the length (very important for backward
+			 * compatibility) */
 			wrq->u.data.length = sizeof(struct iw_range);
+
+			/* Set all the info we don't care or don't know
+			 * about to zero */
+			memset(&range, 0, sizeof(range));
+
+			/* Set the Wireless Extension versions */
+			range.we_version_compiled = WIRELESS_EXT;
+			range.we_version_source = 9;
 
 			/* Set information in the range struct.  */
 			range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v2.4.3/linux/drivers/net/wd.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/wd.c	Thu Apr 19 09:34:52 2001
@@ -24,7 +24,7 @@
 
 */
 
-static const char *version =
+static const char version[] =
 	"wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
@@ -126,7 +126,7 @@
 	int ancient = 0;			/* An old card without config registers. */
 	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
 	const char *model_name;
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 
 	for (i = 0; i < 8; i++)
 		checksum += inb(ioaddr + 8 + i);
diff -u --recursive --new-file v2.4.3/linux/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c
--- v2.4.3/linux/drivers/net/winbond-840.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/winbond-840.c	Fri Apr 20 11:54:23 2001
@@ -38,12 +38,6 @@
 		descriptors. Remove cpu_to_le32, enable BE descriptors.
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"winbond-840.c:v1.01 (2.4 port) 5/15/2000  Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/drivers.html\n";
-
 /* Automatically extracted configuration info:
 probe-func: winbond840_probe
 config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840
@@ -67,7 +61,7 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
@@ -132,6 +126,11 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "winbond-840.c:v1.01 (2.4 port) 5/15/2000  Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
@@ -1412,6 +1411,10 @@
 
 static int __init w840_init(void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init(&w840_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.4.3/linux/drivers/net/yellowfin.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/yellowfin.c	Fri Apr 20 11:54:23 2001
@@ -31,14 +31,6 @@
 
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"yellowfin.c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/yellowfin.html\n";
-static const char version3[] =
-"  (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -115,6 +107,12 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "yellowfin.c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/yellowfin.html\n"
+KERN_INFO "  (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n";
+
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
@@ -386,11 +384,18 @@
 	struct yellowfin_private *np;
 	int irq;
 	int chip_idx = ent->driver_data;
-	static int find_cnt = 0;
+	static int find_cnt;
 	long ioaddr, real_ioaddr;
 	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	int drv_flags = pci_id_tbl[chip_idx].drv_flags;
 	
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	i = pci_enable_device(pdev);
 	if (i) return i;
 
@@ -1391,10 +1396,10 @@
 
 static int __init yellowfin_init (void)
 {
-	if (debug)					/* Emit version even if no cards detected. */
-		printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-		       version1, version2, version3);
-
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init (&yellowfin_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/net/zlib.c linux/drivers/net/zlib.c
--- v2.4.3/linux/drivers/net/zlib.c	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/zlib.c	Wed Apr 18 14:40:04 2001
@@ -2065,7 +2065,7 @@
  */
 local void tr_static_init()
 {
-    static int static_init_done = 0;
+    static int static_init_done;
     int n;        /* iterates over tree elements */
     int bits;     /* bit counter */
     int length;   /* length value */
diff -u --recursive --new-file v2.4.3/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v2.4.3/linux/drivers/net/znet.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/znet.c	Thu Apr 19 09:34:52 2001
@@ -1,6 +1,6 @@
 /* znet.c: An Zenith Z-Note ethernet driver for linux. */
 
-static const char *version = "znet.c:v1.02 9/23/94 becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "znet.c:v1.02 9/23/94 becker@cesdis.gsfc.nasa.gov\n";
 
 /*
 	Written by Donald Becker.
diff -u --recursive --new-file v2.4.3/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.4.3/linux/drivers/parport/ChangeLog	Sun Mar 25 18:22:01 2001
+++ linux/drivers/parport/ChangeLog	Fri Apr 20 16:23:12 2001
@@ -1,3 +1,42 @@
+2001-04-20  Paul Gortmaker  <p_gortmaker@yahoo.com>
+
+	* parport_pc.c: Cut down the size quite a bit (more than 4k off
+	the object, about 1k off the zImage) for the older non-PCI
+	machines which are typically resource starved anyway...
+
+2001-03-26  R Horn  <rjh@world.std.com>
+
+	* parport_pc.c: Some commentary changes.
+
+2001-04-19  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_pc_probe_port): Remove __devinit
+	attribute.  Export unconditionally.
+
+2001-04-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	Merged:  2001-03-30  Tim Waugh  <twaugh@redhat.com>
+
+        * drivers/parport/parport_pc.c: Make Via SuperIO chipsets behave
+        like everything else with respect to irq= and dma= parameters.
+
+2001-04-08  Tim Waugh  <twaugh@redhat.com>
+
+      * parport_pc.c (parport_pc_save_state): Read from the soft copy of
+      the control port.
+      (parport_pc_restore_state): Update the soft copy of the control
+      port.
+
+2001-03-26  Tim Waugh  <twaugh@redhat.com>
+
+	* share.c (parport_find_number, parport_find_base): Trigger
+	a lowlevel driver load if there are no ports yet.
+
+2001-03-26  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_ECP_supported): Remove the IRQ conflict
+	check since it seems totally unreliable.
+
 2001-03-02  Tim Waugh  <twaugh@redhat.com>
 
 	* ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd
diff -u --recursive --new-file v2.4.3/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.4.3/linux/drivers/parport/parport_pc.c	Mon Mar 26 15:41:19 2001
+++ linux/drivers/parport/parport_pc.c	Fri Apr 20 16:23:12 2001
@@ -11,6 +11,7 @@
  * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  * DMA support - Bert De Jonghe <bert@sophis.be>
  * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
+ * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -347,15 +348,16 @@
 void parport_pc_save_state(struct parport *p, struct parport_state *s)
 {
 	const struct parport_pc_private *priv = p->physport->private_data;
-	s->u.pc.ctr = inb (CONTROL (p));
+	s->u.pc.ctr = priv->ctr;
 	if (priv->ecr)
 		s->u.pc.ecr = inb (ECONTROL (p));
 }
 
 void parport_pc_restore_state(struct parport *p, struct parport_state *s)
 {
-	const struct parport_pc_private *priv = p->physport->private_data;
+	struct parport_pc_private *priv = p->physport->private_data;
 	outb (s->u.pc.ctr, CONTROL (p));
+	priv->ctr = s->u.pc.ctr;
 	if (priv->ecr)
 		outb (s->u.pc.ecr, ECONTROL (p));
 }
@@ -939,13 +941,11 @@
 			/* Can't yield the port. */
 			schedule ();
 
-		/* At this point, the FIFO may already be full.
-		 * Ideally, we'd be able to tell the port to hold on
-		 * for a second while we empty the FIFO, and we'd be
-		 * able to ensure that no data is lost.  I'm not sure
-		 * that's the case. :-(  It might be that you can play
-		 * games with STB, as in the forward case; someone should
-		 * look at a datasheet. */
+		/* At this point, the FIFO may already be full. In
+                 * that case ECP is already holding back the
+                 * peripheral (assuming proper design) with a delayed
+                 * handshake.  Work fast to avoid a peripheral
+                 * timeout.  */
 
 		if (ecrval & 0x01) {
 			/* FIFO is empty. Wait for interrupt. */
@@ -977,6 +977,10 @@
 				goto false_alarm;
 			}
 
+			/* Depending on how the FIFO threshold was
+                         * set, how long interrupt service took, and
+                         * how fast the peripheral is, we might be
+                         * lucky and have a just filled FIFO. */
 			continue;
 		}
 
@@ -988,6 +992,9 @@
 			continue;
 		}
 
+		/* FIFO not filled.  We will cycle this loop for a while
+                 * and either the peripheral will fill it faster,
+                 * tripping a fast empty with insb, or we empty it. */
 		*bufp++ = inb (fifo);
 		left--;
 	}
@@ -1982,10 +1989,10 @@
 
 /* --- Initialisation code -------------------------------- */
 
-struct parport *__devinit parport_pc_probe_port (unsigned long int base,
-						 unsigned long int base_hi,
-						 int irq, int dma,
-						 struct pci_dev *dev)
+struct parport *parport_pc_probe_port (unsigned long int base,
+				       unsigned long int base_hi,
+				       int irq, int dma,
+				       struct pci_dev *dev)
 {
 	struct parport_pc_private *priv;
 	struct parport_operations *ops;
@@ -2178,8 +2185,10 @@
 }
 
 
+#ifdef CONFIG_PCI
 /* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */
-static int __devinit sio_via_686a_probe (struct pci_dev *pdev)
+static int __devinit sio_via_686a_probe (struct pci_dev *pdev, int autoirq,
+					 int autodma)
 {
 	u8 tmp;
 	int dma, irq;
@@ -2214,7 +2223,7 @@
 	case 0x378: port2 = 0x778; break;
 	case 0x278: port2 = 0x678; break;
 	default:
-		printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n",
+		printk (KERN_INFO "parport_pc: Weird Via 686A parport base 0x%X, ignoring\n",
 			port1);
 		return 0;
 	}
@@ -2259,6 +2268,14 @@
 	if (!have_eppecp)
 		dma = PARPORT_DMA_NONE;
 
+	/* Let the user (or defaults) steer us away from interrupts and DMA */
+	if (autoirq != PARPORT_IRQ_AUTO) {
+		irq = PARPORT_IRQ_NONE;
+		dma = PARPORT_DMA_NONE;
+	}
+	if (autodma != PARPORT_DMA_AUTO)
+		dma = PARPORT_DMA_NONE;
+
 	/* finally, do the probe with values obtained */
 	if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) {
 		printk (KERN_INFO
@@ -2284,7 +2301,7 @@
 
 /* each element directly indexed from enum list, above */
 static struct parport_pc_superio {
-	int (*probe) (struct pci_dev *pdev);
+	int (*probe) (struct pci_dev *pdev, int autoirq, int autodma);
 } parport_pc_superio_info[] __devinitdata = {
 	{ sio_via_686a_probe, },
 };
@@ -2541,9 +2558,8 @@
 	probe:		parport_pc_pci_probe,
 };
 
-static int __init parport_pc_init_superio (void)
+static int __init parport_pc_init_superio (int autoirq, int autodma)
 {
-#ifdef CONFIG_PCI
 	const struct pci_device_id *id;
 	struct pci_dev *pdev;
 
@@ -2552,12 +2568,16 @@
 		if (id == NULL || id->driver_data >= last_sio)
 			continue;
 
-		return parport_pc_superio_info[id->driver_data].probe (pdev);
+		return parport_pc_superio_info[id->driver_data].probe
+			(pdev, autoirq, autodma);
 	}
-#endif /* CONFIG_PCI */
 
 	return 0; /* zero devices found */
 }
+#else
+static struct pci_driver parport_pc_pci_driver;
+static int __init parport_pc_init_superio(void) {return 0;}
+#endif /* CONFIG_PCI */
 
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
 static int __init __attribute__((unused))
@@ -2595,7 +2615,7 @@
 #endif
 
 	/* Onboard SuperIO chipsets that show themselves on the PCI bus. */
-	count += parport_pc_init_superio ();
+	count += parport_pc_init_superio (autoirq, autodma);
 
 	/* ISA ports and whatever (see asm/parport.h). */
 	count += parport_pc_find_nonpci_ports (autoirq, autodma);
@@ -2630,16 +2650,7 @@
 }
 
 /* Exported symbols. */
-#ifdef CONFIG_PARPORT_PC_PCMCIA
-
-/* parport_cs needs this in order to dyncamically get us to find ports. */
 EXPORT_SYMBOL (parport_pc_probe_port);
-
-#else
-
-EXPORT_NO_SYMBOLS;
-
-#endif
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
diff -u --recursive --new-file v2.4.3/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v2.4.3/linux/drivers/pci/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/pci/Makefile	Fri Apr 13 20:31:32 2001
@@ -21,6 +21,7 @@
 #
 obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
 obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
+obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
 
 ifndef CONFIG_X86
 obj-y += syscall.o
diff -u --recursive --new-file v2.4.3/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.4.3/linux/drivers/pci/pci.c	Tue Mar  6 22:44:15 2001
+++ linux/drivers/pci/pci.c	Thu Apr 19 08:38:48 2001
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/kmod.h>		/* for hotplug_path */
+#include <linux/bitops.h>
 
 #include <asm/page.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
@@ -286,12 +287,33 @@
 {
 	int err;
 
+	pci_set_power_state(dev, 0);
 	if ((err = pcibios_enable_device(dev)) < 0)
 		return err;
-	pci_set_power_state(dev, 0);
 	return 0;
 }
 
+/**
+ * pci_disable_device - Disable PCI device after use
+ * @dev: PCI device to be disabled
+ *
+ * Signal to the system that the PCI device is not in use by the system
+ * anymore.  Currently this only involves disabling PCI busmastering,
+ * if active.
+ */
+
+void
+pci_disable_device(struct pci_dev *dev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_MASTER) {
+		pci_command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_word(dev, PCI_COMMAND, pci_command);
+	}
+}
+
 int
 pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
 {
@@ -1339,6 +1361,352 @@
 }
 #endif
 
+/*
+ * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
+ * small blocks are easily used by drivers for bus mastering controllers.
+ * This should probably be sharing the guts of the slab allocator.
+ */
+
+struct pci_pool {	/* the pool */
+	struct list_head	page_list;
+	spinlock_t		lock;
+	size_t			blocks_per_page;
+	size_t			size;
+	int			flags;
+	struct pci_dev		*dev;
+	size_t			allocation;
+	char			name [32];
+	wait_queue_head_t	waitq;
+};
+
+struct pci_page {	/* cacheable header for 'allocation' bytes */
+	struct list_head	page_list;
+	void			*vaddr;
+	dma_addr_t		dma;
+	unsigned long		bitmap [0];
+};
+
+#define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
+#define	POOL_POISON_BYTE	0xa7
+
+// #define CONFIG_PCIPOOL_DEBUG
+
+
+/**
+ * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @pdev: pci device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ * @flags: SLAB_* flags (not all are supported).
+ *
+ * Returns a pci allocation pool with the requested characteristics, or
+ * null if one can't be created.  Given one of these pools, pci_pool_alloc()
+ * may be used to allocate memory.  Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives.  The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If allocation is nonzero, objects returned from pci_pool_alloc() won't
+ * cross that size boundary.  This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct pci_pool *
+pci_pool_create (const char *name, struct pci_dev *pdev,
+	size_t size, size_t align, size_t allocation, int flags)
+{
+	struct pci_pool		*retval;
+
+	if (align == 0)
+		align = 1;
+	if (size == 0)
+		return 0;
+	else if (size < align)
+		size = align;
+	else if ((size % align) != 0) {
+		size += align + 1;
+		size &= ~(align - 1);
+	}
+
+	if (allocation == 0) {
+		if (PAGE_SIZE < size)
+			allocation = size;
+		else
+			allocation = PAGE_SIZE;
+		// FIXME: round up for less fragmentation
+	} else if (allocation < size)
+		return 0;
+
+	if (!(retval = kmalloc (sizeof *retval, flags)))
+		return retval;
+
+#ifdef	CONFIG_PCIPOOL_DEBUG
+	flags |= SLAB_POISON;
+#endif
+
+	strncpy (retval->name, name, sizeof retval->name);
+	retval->name [sizeof retval->name - 1] = 0;
+
+	retval->dev = pdev;
+	INIT_LIST_HEAD (&retval->page_list);
+	spin_lock_init (&retval->lock);
+	retval->size = size;
+	retval->flags = flags;
+	retval->allocation = allocation;
+	retval->blocks_per_page = allocation / size;
+	init_waitqueue_head (&retval->waitq);
+
+#ifdef CONFIG_PCIPOOL_DEBUG
+	printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n",
+		pdev ? pdev->slot_name : NULL, retval->name, size,
+		retval->blocks_per_page, allocation);
+#endif
+
+	return retval;
+}
+
+
+static struct pci_page *
+pool_alloc_page (struct pci_pool *pool, int mem_flags)
+{
+	struct pci_page	*page;
+	int		mapsize;
+
+	mapsize = pool->blocks_per_page;
+	mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	mapsize *= sizeof (long);
+
+	page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
+	if (!page)
+		return 0;
+	page->vaddr = pci_alloc_consistent (pool->dev,
+				pool->allocation, &page->dma);
+	if (page->vaddr) {
+		memset (page->bitmap, ~0, mapsize);	// bit set == free
+		if (pool->flags & SLAB_POISON)
+			memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+		list_add (&page->page_list, &pool->page_list);
+	} else {
+		kfree (page);
+		page = 0;
+	}
+	return page;
+}
+
+
+static inline int
+is_page_busy (int blocks, unsigned long *bitmap)
+{
+	while (blocks > 0) {
+		if (*bitmap++ != ~0)
+			return 1;
+		blocks -= BITS_PER_LONG;
+	}
+	return 0;
+}
+
+static void
+pool_free_page (struct pci_pool *pool, struct pci_page *page)
+{
+	dma_addr_t	dma = page->dma;
+
+	if (pool->flags & SLAB_POISON)
+		memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+	pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
+	list_del (&page->page_list);
+	kfree (page);
+}
+
+
+/**
+ * pci_pool_destroy - destroys a pool of pci memory blocks.
+ * @pool: pci pool that will be destroyed
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void
+pci_pool_destroy (struct pci_pool *pool)
+{
+	unsigned long		flags;
+
+#ifdef CONFIG_PCIPOOL_DEBUG
+	printk (KERN_DEBUG "pcipool destroy %s/%s\n",
+		pool->dev ? pool->dev->slot_name : NULL,
+		pool->name);
+#endif
+
+	spin_lock_irqsave (&pool->lock, flags);
+	while (!list_empty (&pool->page_list)) {
+		struct pci_page		*page;
+		page = list_entry (pool->page_list.next,
+				struct pci_page, page_list);
+		if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
+			printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
+				pool->dev ? pool->dev->slot_name : NULL,
+				pool->name, page->vaddr);
+			/* leak the still-in-use consistent memory */
+			list_del (&page->page_list);
+			kfree (page);
+		} else
+			pool_free_page (pool, page);
+	}
+	spin_unlock_irqrestore (&pool->lock, flags);
+	kfree (pool);
+}
+
+
+/**
+ * pci_pool_alloc - get a block of consistent memory
+ * @pool: pci pool that will produce the block
+ * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, null is returned.
+ */
+void *
+pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
+{
+	unsigned long		flags;
+	struct list_head	*entry;
+	struct pci_page		*page;
+	int			map, block;
+	size_t			offset;
+	void			*retval;
+
+restart:
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each (entry, &pool->page_list) {
+		int		i;
+		page = list_entry (entry, struct pci_page, page_list);
+		/* only cachable accesses here ... */
+		for (map = 0, i = 0;
+				i < pool->blocks_per_page;
+				i += BITS_PER_LONG, map++) {
+			if (page->bitmap [map] == 0)
+				continue;
+			block = ffs (page->bitmap [map]);
+			if ((i + block) <= pool->blocks_per_page) {
+				block--;
+				clear_bit (block, &page->bitmap [map]);
+				offset = (BITS_PER_LONG * map) + block;
+				offset *= pool->size;
+				goto ready;
+			}
+		}
+	}
+	if (!(page = pool_alloc_page (pool, mem_flags))) {
+		if (mem_flags == SLAB_KERNEL) {
+			DECLARE_WAITQUEUE (wait, current);
+
+			current->state = TASK_INTERRUPTIBLE;
+			add_wait_queue (&pool->waitq, &wait);
+			spin_unlock_irqrestore (&pool->lock, flags);
+
+			schedule_timeout (POOL_TIMEOUT_JIFFIES);
+
+			current->state = TASK_RUNNING;
+			remove_wait_queue (&pool->waitq, &wait);
+			goto restart;
+		}
+		retval = 0;
+		goto done;
+	}
+
+	clear_bit (0, &page->bitmap [0]);
+	offset = 0;
+ready:
+	retval = offset + page->vaddr;
+	*handle = offset + page->dma;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return retval;
+}
+
+
+static struct pci_page *
+pool_find_page (struct pci_pool *pool, dma_addr_t dma)
+{
+	unsigned long		flags;
+	struct list_head	*entry;
+	struct pci_page		*page;
+
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each (entry, &pool->page_list) {
+		page = list_entry (entry, struct pci_page, page_list);
+		if (dma < page->dma)
+			continue;
+		if (dma < (page->dma + pool->allocation))
+			goto done;
+	}
+	page = 0;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return page;
+}
+
+
+/**
+ * pci_pool_free - put block back into pci pool
+ * @pool: the pci pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void
+pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
+{
+	struct pci_page		*page;
+	unsigned long		flags;
+	int			map, block;
+
+	if ((page = pool_find_page (pool, dma)) == 0) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, dma);
+		return;
+	}
+#ifdef	CONFIG_PCIPOOL_DEBUG
+	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, dma);
+		return;
+	}
+#endif
+
+	block = dma - page->dma;
+	block /= pool->size;
+	map = block / BITS_PER_LONG;
+	block %= BITS_PER_LONG;
+
+#ifdef	CONFIG_PCIPOOL_DEBUG
+	if (page->bitmap [map] & (1 << block)) {
+		printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, dma);
+		return;
+	}
+#endif
+	if (pool->flags & SLAB_POISON)
+		memset (vaddr, POOL_POISON_BYTE, pool->size);
+
+	spin_lock_irqsave (&pool->lock, flags);
+	set_bit (block, &page->bitmap [map]);
+	if (waitqueue_active (&pool->waitq))
+		wake_up (&pool->waitq);
+	else if (!is_page_busy (pool->blocks_per_page, page->bitmap))
+		pool_free_page (pool, page);
+	spin_unlock_irqrestore (&pool->lock, flags);
+}
+
+
 void __init pci_init(void)
 {
 	struct pci_dev *dev;
@@ -1381,6 +1749,7 @@
 EXPORT_SYMBOL(pci_devices);
 EXPORT_SYMBOL(pci_root_buses);
 EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pci_disable_device);
 EXPORT_SYMBOL(pci_find_capability);
 EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
@@ -1420,4 +1789,11 @@
 
 EXPORT_SYMBOL(isa_dma_bridge_buggy);
 EXPORT_SYMBOL(pci_pci_problems);
+
+/* Pool allocator */
+
+EXPORT_SYMBOL (pci_pool_create);
+EXPORT_SYMBOL (pci_pool_destroy);
+EXPORT_SYMBOL (pci_pool_alloc);
+EXPORT_SYMBOL (pci_pool_free);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.4.3/linux/drivers/pci/quirks.c	Sat Dec 30 11:23:13 2000
+++ linux/drivers/pci/quirks.c	Thu Apr 19 22:57:06 2001
@@ -85,6 +85,29 @@
 }
 
 /*
+ *	VIA Apollo KT133 needs PCI latency patch
+ *	Made according to a windows driver based patch by George E. Breese
+ *	see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
+ */
+static void __init quirk_vialatency(struct pci_dev *dev)
+{
+	u8 r70;
+
+	printk(KERN_INFO "Applying VIA PCI latency patch.\n");
+	/*
+	 *    In register 0x70, mask off bit 2 (PCI Master read caching)
+	 *    and 1 (Delay Transaction)
+	 */
+	pci_read_config_byte(dev, 0x70, &r70);
+	r70 &= 0xf9;
+	pci_write_config_byte(dev, 0x70, r70);
+	/*
+	 *    Turn off PCI Latency timeout (set to 0 clocks)
+	 */
+	pci_write_config_byte(dev, 0x75, 0x80);
+}
+
+/*
  *	VIA Apollo VP3 needs ETBF on BT848/878
  */
  
@@ -248,6 +271,20 @@
 }
 
 /*
+ * CardBus controllers have a legacy base address that enables them
+ * to respond as i82365 pcmcia controllers.  We don't want them to
+ * do this even if the Linux CardBus driver is not loaded, because
+ * the Linux i82365 driver does not (and should not) handle CardBus.
+ */
+static void __init quirk_cardbus_legacy(struct pci_dev *dev)
+{
+	if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
+		return;
+	pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
+}
+
+
+/*
  *  The main table of quirks.
  */
 
@@ -275,6 +312,7 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_vt82c586_acpi },
@@ -283,6 +321,7 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M7101,		quirk_ali7101_acpi },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371SB_2,	quirk_piix3_usb },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_2,	quirk_piix3_usb },
+	{ PCI_FIXUP_FINAL,	PCI_ANY_ID,		PCI_ANY_ID,			quirk_cardbus_legacy },
 	{ 0 }
 };
 
diff -u --recursive --new-file v2.4.3/linux/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c
--- v2.4.3/linux/drivers/pci/setup-res.c	Mon Dec 11 13:46:26 2000
+++ linux/drivers/pci/setup-res.c	Fri Apr  6 10:51:19 2001
@@ -163,6 +163,10 @@
 				size = ln->res->end - ln->res->start;
 			if (r_size > size) {
 				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+				if (!tmp) {
+					printk("pdev_sort_resources(): kmalloc() failed!\n");
+					continue;
+				}
 				tmp->next = ln;
 				tmp->res = r;
 				tmp->dev = dev;
diff -u --recursive --new-file v2.4.3/linux/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c
--- v2.4.3/linux/drivers/pcmcia/hd64465_ss.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/pcmcia/hd64465_ss.c	Thu Apr 12 12:16:35 2001
@@ -30,7 +30,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- v2.4.3/linux/drivers/pcmcia/pci_socket.c	Thu Nov 16 16:38:16 2000
+++ linux/drivers/pcmcia/pci_socket.c	Fri Apr  6 10:51:19 2001
@@ -172,13 +172,20 @@
 static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops)
 {
 	pci_socket_t *socket = nr + pci_socket_array;
-
+	int err;
+	
 	memset(socket, 0, sizeof(*socket));
 	socket->dev = dev;
 	socket->op = ops;
 	dev->driver_data = socket;
 	spin_lock_init(&socket->event_lock);
-	return socket->op->open(socket);
+	err = socket->op->open(socket);
+	if(err)
+	{
+		socket->dev = NULL;
+		dev->driver_data = NULL;
+	}
+	return err;
 }
 
 void cardbus_register(pci_socket_t *socket)
@@ -195,8 +202,7 @@
 
 	for (s = 0; s < MAX_SOCKETS; s++) {
 		if (pci_socket_array [s].dev == 0) {
-			add_pci_socket (s, dev, &yenta_operations);
-			return 0;
+			return add_pci_socket (s, dev, &yenta_operations);
 		}
 	}
 	return -ENODEV;
diff -u --recursive --new-file v2.4.3/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.4.3/linux/drivers/pcmcia/yenta.c	Thu Nov 16 18:25:16 2000
+++ linux/drivers/pcmcia/yenta.c	Fri Apr  6 10:51:19 2001
@@ -755,6 +755,9 @@
  */
 static void yenta_close(pci_socket_t *sock)
 {
+	/* Disable all events so we don't die in an IRQ storm */
+	cb_writel(sock, CB_SOCKET_MASK, 0x0);
+
 	if (sock->cb_irq)
 		free_irq(sock->cb_irq, sock);
 	else
diff -u --recursive --new-file v2.4.3/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.4.3/linux/drivers/pnp/isapnp.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/pnp/isapnp.c	Wed Apr 18 11:49:11 2001
@@ -55,7 +55,7 @@
 struct resource *isapnp_rdp_res;
 
 int isapnp_disable;			/* Disable ISA PnP */
-int isapnp_rdp;			/* Read Data Port */
+int isapnp_rdp;				/* Read Data Port */
 int isapnp_reset = 1;			/* reset all PnP cards (deactivate) */
 int isapnp_skip_pci_scan;		/* skip PCI resource scanning */
 int isapnp_verbose = 1;			/* verbose mode */
@@ -993,10 +993,15 @@
 			header[4], header[5], header[6], header[7], header[8]);
 		printk("checksum = 0x%x\n", checksum);
 #endif
-		if (checksum == 0x00 || checksum != header[8])	/* not valid CSN */
+		/* Don't be strict on the checksum, here !
+                   e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/
+		if (header[8] == 0)
+			;
+		else if (checksum == 0x00 || checksum != header[8])	/* not valid CSN */
 			continue;
 		if ((card = isapnp_alloc(sizeof(struct pci_bus))) == NULL)
 			continue;
+
 		card->number = csn;
 		card->vendor = (header[1] << 8) | header[0];
 		card->device = (header[3] << 8) | header[2];
@@ -2197,7 +2202,7 @@
 	 *	so let the user know where.
 	 */
 	 
-	printk("isapnp: Scanning for Pnp cards...\n");
+	printk("isapnp: Scanning for PnP cards...\n");
 	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
 		isapnp_rdp |= 3;
 		isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
@@ -2258,5 +2263,86 @@
 	if (isapnp_detected)
 		isapnp_free_all_resources();
 }
+
+#else
+
+/* format is: noisapnp */
+
+static int __init isapnp_setup_disable(char *str)
+{
+	isapnp_disable = 1;
+	return 1;
+}
+
+__setup("noisapnp", isapnp_setup_disable);
+
+/* format is: isapnp=rdp,reset,skip_pci_scan,verbose */
+
+static int __init isapnp_setup_isapnp(char *str)
+{
+	(void)((get_option(&str,&isapnp_rdp) == 2) &&
+	       (get_option(&str,&isapnp_reset) == 2) &&
+	       (get_option(&str,&isapnp_skip_pci_scan) == 2) &&
+	       (get_option(&str,&isapnp_verbose) == 2));
+	return 1;
+}
+
+__setup("isapnp=", isapnp_setup_isapnp);
+
+/* format is: isapnp_reserve_irq=irq1[,irq2] .... */
+
+static int __init isapnp_setup_reserve_irq(char *str)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		if (get_option(&str,&isapnp_reserve_irq[i]) != 2)
+			break;
+	return 1;
+}
+
+__setup("isapnp_reserve_irq=", isapnp_setup_reserve_irq);
+
+/* format is: isapnp_reserve_dma=dma1[,dma2] .... */
+
+static int __init isapnp_setup_reserve_dma(char *str)
+{
+	int i;
+
+	for (i = 0; i < 8; i++)
+		if (get_option(&str,&isapnp_reserve_dma[i]) != 2)
+			break;
+	return 1;
+}
+
+__setup("isapnp_reserve_dma=", isapnp_setup_reserve_dma);
+
+/* format is: isapnp_reserve_io=io1,size1[,io2,size2] .... */
+
+static int __init isapnp_setup_reserve_io(char *str)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		if (get_option(&str,&isapnp_reserve_io[i]) != 2)
+			break;
+	return 1;
+}
+
+__setup("isapnp_reserve_io=", isapnp_setup_reserve_io);
+
+/* format is: isapnp_reserve_mem=mem1,size1[,mem2,size2] .... */
+
+static int __init isapnp_setup_reserve_mem(char *str)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		if (get_option(&str,&isapnp_reserve_mem[i]) != 2)
+			break;
+	return 1;
+}
+
+__setup("isapnp_reserve_mem=", isapnp_setup_reserve_mem);
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/Config.in linux/drivers/s390/Config.in
--- v2.4.3/linux/drivers/s390/Config.in	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/Config.in	Wed Apr 11 19:02:29 2001
@@ -7,7 +7,7 @@
 if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
   int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 24576
 fi
-dep_bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+dep_bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 tristate 'XPRAM disk support' CONFIG_BLK_DEV_XPRAM
 
 comment 'S/390 block device drivers'
@@ -18,7 +18,7 @@
   bool '   Support for FBA  Disks' CONFIG_DASD_FBA
 #  bool '   Support for CKD  Disks' CONFIG_DASD_CKD
   if [ "$CONFIG_ARCH_S390" = "y" ]; then
-    bool '   Support for DIAG access to CMS reserved Disks' CONFIG_DASD_MDSK
+    bool '   Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG
   fi;
 fi
 
@@ -35,9 +35,15 @@
 
 comment 'S/390 character device drivers'
 
-bool 'Support for 3215 line mode terminal' CONFIG_3215
-if [ "$CONFIG_3215" = "y" ]; then
-  bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE
+tristate 'Support for locally attached 3270 tubes' CONFIG_3270
+if [ "$CONFIG_3270" = "y" ]; then
+  bool 'Support for console on 3270 line mode terminal' CONFIG_3270_CONSOLE
+fi
+if [ "$CONFIG_3270_CONSOLE" != "y" ]; then
+  bool 'Support for 3215 line mode terminal' CONFIG_3215
+  if [ "$CONFIG_3215" = "y" ]; then
+    bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE
+  fi
 fi
 bool 'Support for HWC line mode terminal' CONFIG_HWC
 if [ "$CONFIG_HWC" = "y" ]; then
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/Makefile linux/drivers/s390/Makefile
--- v2.4.3/linux/drivers/s390/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/Makefile	Wed Apr 11 19:02:29 2001
@@ -1,39 +1,14 @@
 #
-# Makefile for the linux i386-specific parts of the memory manager.
+# Makefile for the S/390 specific 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 definition is now in the main makefile...
-
-all: io.o
 
-CFLAGS += 
 O_TARGET := io.o
 
-obj-y	:= s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
-
 subdir-y := block char misc net
 subdir-m := $(subdir-y)
+obj-y := $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
 
-obj-y += block/s390-block.o \
-  char/s390-char.o \
-  misc/s390-misc.o \
-  net/s390-net.o 
-
-io.o: $(obj-y)
-
-block/s390-block.o: dummy
-	$(MAKE)  -C block
-
-char/s390-char.o: dummy
-	$(MAKE)  -C char
-
-misc/s390-misc.o: dummy
-	$(MAKE) -C misc
-
-net/s390-net.o: dummy
-	$(MAKE) -C net
+obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
+export-objs += ccwcache.o idals.o s390dyn.o s390io.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile
--- v2.4.3/linux/drivers/s390/block/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/Makefile	Wed Apr 11 19:02:28 2001
@@ -1,34 +1,22 @@
-all: s390-block.o
+#
+# S/390 block devices
+#
 
-CFLAGS += 
 O_TARGET := s390-block.o
 
-DASD_OBJS := dasd.o
-  ifeq ($(CONFIG_DASD_ECKD),y)
-    DASD_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
-  endif
-  ifeq ($(CONFIG_DASD_FBA),y)
-    DASD_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
-  endif
-  ifeq ($(CONFIG_DASD_MDSK),y)
-    DASD_OBJS += dasd_mdsk.o
-  endif
-#  ifeq ($(CONFIG_DASD_CKD),y)
-#    DASD_OBJS += dasd_ckd.o
-#  endif
-
-ifeq ($(CONFIG_DASD),y)
-  obj-y += $(DASD_OBJS)
-else
-  ifeq ($(CONFIG_DASD),m)
-    obj-m += dasd_mod.o
-    D_OBJS += $(DASD_OBJS)
-  endif
-endif
+list-multi := dasd_mod.o
+export-objs := dasd.o
 
-obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
+dasd_mod-$(CONFIG_DASD_ECKD) += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
+dasd_mod-$(CONFIG_DASD_FBA) += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+dasd_mod-$(CONFIG_DASD_DIAG) += dasd_diag.o
+dasd_mod-objs := dasd.o $(dasd_mod-y)
 
-dasd_mod.o: $(D_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS)
+obj-$(CONFIG_DASD) += dasd_mod.o
+obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
 
 include $(TOPDIR)/Rules.make
+
+dasd_mod.o: $(dasd_mod-objs)
+	$(LD) -r -o $@ $(dasd_mod-objs)
+
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- v2.4.3/linux/drivers/s390/block/dasd.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/s390/block/dasd.c	Wed Apr 11 19:02:28 2001
@@ -2,13 +2,27 @@
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  *                  Horst Hummel <Horst.Hummel@de.ibm.com>  
+ *                  Carsten Otte <Cotte@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
  * History of changes (starts July 2000)
  * 11/09/00 complete redesign after code review
+ * 02/01/01 removed some warnings
+ * 02/01/01 added dynamic registration of ioctls
+ *          fixed bug in registration of new majors
+ *          fixed handling of request during dasd_end_request
+ *          fixed handling of plugged queues
+ *          fixed partition handling and HDIO_GETGEO
+ *          fixed traditional naming scheme for devices beyond 702
+ *          fixed some race conditions related to modules
+ *          added devfs suupport
+ * 03/06/01 refined dynamic attach/detach for leaving devices which are online.
+ * 06/09/01 refined dynamic modifiaction of devices
+ *          renewed debug feature exploitation
  */
 
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/init.h>
@@ -17,7 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/tqueue.h>
 #include <linux/timer.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
@@ -25,13 +39,9 @@
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #endif				/* CONFIG_PROC_FS */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #include <linux/spinlock.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/blkpg.h>
-#else
-#include <asm/spinlock.h>
-#endif
 
 #include <asm/ccwcache.h>
 #include <asm/dasd.h>
@@ -54,17 +64,10 @@
 #ifdef CONFIG_DASD_FBA
 #include "dasd_fba.h"
 #endif				/*  CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
+#ifdef CONFIG_DASD_DIAG
 #include "dasd_diag.h"
-#endif				/*  CONFIG_DASD_MDSK */
-
-static struct block_device_operations dasd_device_operations;
+#endif				/*  CONFIG_DASD_DIAG */
 
-#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");
@@ -76,11 +79,10 @@
 EXPORT_SYMBOL (dasd_int_handler);
 EXPORT_SYMBOL (dasd_alloc_request);
 EXPORT_SYMBOL (dasd_free_request);
-
-#endif				/* MODULE */
+EXPORT_SYMBOL(dasd_ioctl_no_register);  
+EXPORT_SYMBOL(dasd_ioctl_no_unregister);
 
 /* SECTION: Constant definitions to be used within this file */
-#undef ERP_DEBUG
 
 #define PRINTK_HEADER DASD_NAME": "
 
@@ -89,20 +91,28 @@
 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
 #define DASD_CHANQ_MAX_SIZE 6
 
-
 /* SECTION: prototypes for static functions of dasd.c */
 
 static request_fn_proc do_dasd_request;
-void dasd_schedule_bh (dasd_device_t *);
 static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
 static request_queue_t *dasd_get_queue (kdev_t kdev);
+static void cleanup_dasd (void);
+int dasd_fillgeo(int kdev,struct hd_geometry *geo);
 
 static struct block_device_operations dasd_device_operations;
 
+/* SECTION: static variables of dasd.c */
+
+static devfs_handle_t dasd_devfs_handle;
+
+/* SECTION: exported variables of dasd.c */
+
+debug_info_t *dasd_debug_area;
+
 #ifdef CONFIG_DASD_DYNAMIC
 /* SECTION: managing dynamic configuration of dasd_driver */
 
-static dasd_devreg_t *dasd_devreg_head = NULL;
+static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head);
 
 /* 
  * function: dasd_create_devreg
@@ -149,6 +159,7 @@
 
 static dasd_range_t *dasd_range_head = NULL;	/* anchor for list of ranges */
 static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t dasd_open_count_lock;
 
 /* 
  * function: dasd_create_range
@@ -240,15 +251,14 @@
  * appends it to the list of ranges
  * additionally a devreg_t is created and added to the list of devregs 
  */
-static inline void
+static inline dasd_range_t*
 dasd_add_range (int from, int to)
 {
 	dasd_range_t *range;
 	range = dasd_create_range (from, to);
-	if (range)
-		dasd_append_range (range);
-	else
-		return;
+	if (!range) return NULL;
+
+	dasd_append_range (range);
 #ifdef CONFIG_DASD_DYNAMIC
 	/* allocate and chain devreg infos for the devnos... */
 	{
@@ -256,11 +266,11 @@
 		for (i = range->from; i <= range->to; i++) {
 			dasd_devreg_t *reg = dasd_create_devreg (i);
 			s390_device_register (&reg->devreg);
-			reg->next = dasd_devreg_head;
-			dasd_devreg_head = reg;
+                        list_add(&reg->list,&dasd_devreg_head);
 		}
 	}
 #endif				/* CONFIG_DASD_DYNAMIC */
+	return range;
 }
 
 /* 
@@ -277,28 +287,25 @@
 	{
 		int i;
 		for (i = range->from; i <= range->to; i++) {
-			dasd_devreg_t *reg, *prev = NULL;
-			for (reg = dasd_devreg_head; reg; reg = reg->next) {
+                        struct list_head *l;
+                        dasd_devreg_t *reg = NULL;
+			list_for_each (l, &dasd_devreg_head) {
+                                reg = list_entry(l,dasd_devreg_t,list);
 				if (reg->devreg.flag == DEVREG_TYPE_DEVNO &&
-				    reg->devreg.devno == i &&
+				    reg->devreg.ci.devno == i &&
 				    reg->devreg.oper_func == dasd_oper_handler)
 					break;
-				prev = reg;
 			}
-			if (!reg)
+			if (l == &dasd_devreg_head)
 				BUG ();
-			if (prev) {
-				prev->next = reg->next;
-			} else {
-				dasd_devreg_head = reg->next;
-			}
+                        list_del(&reg->list);
 			s390_device_unregister (&reg->devreg);
 			dasd_destroy_devreg (reg);
 		}
 	}
+#endif				/* CONFIG_DASD_DYNAMIC */
 	dasd_dechain_range (range);
 	dasd_destroy_range (range);
-#endif				/* CONFIG_DASD_DYNAMIC */
 }
 
 /* 
@@ -475,13 +482,18 @@
 /* SECTION: Dealing with devices registered to multiple major numbers */
 
 static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
+
 static major_info_t dasd_major_info[] =
 {
 	{
-		next:NULL,
+		list: LIST_HEAD_INIT(dasd_major_info[1].list )
+	},
+	{
+		list: LIST_HEAD_INIT(dasd_major_info[0].list ),
 		gendisk: {
                         INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
-		}
+		},
+		flags : DASD_MAJOR_INFO_IS_STATIC
 	}
 };
 
@@ -489,26 +501,16 @@
 get_new_major_info (void)
 {
 	major_info_t *major_info = NULL;
-	unsigned long flags;
 
 	major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
 	if (major_info) {
-		major_info_t *temp = dasd_major_info;
-                static major_info_t temp_major_info[] =
-                {
-                        {
-                                next:NULL,
-                                gendisk: {
-                                        INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
-                                }
-                        }
-                };
-		spin_lock_irqsave (&dasd_major_lock, flags);
-		while (temp->next)
-			temp = temp->next;
-		temp->next = major_info;
-		spin_unlock_irqrestore (&dasd_major_lock, flags);
-		memcpy (major_info, temp_major_info, sizeof (major_info_t));
+		static major_info_t temp_major_info =
+		{
+			gendisk: {
+				INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
+			}
+		};
+		memcpy (major_info, &temp_major_info, sizeof (major_info_t));
 	}
 	return major_info;
 }
@@ -518,6 +520,7 @@
 {
 	int rc = 0;
 	int major;
+	unsigned long flags;
 
 	if (major_info == NULL) {
 		major_info = get_new_major_info ();
@@ -531,12 +534,27 @@
 		}
 	}
 	major = major_info->gendisk.major;
+	major_info->gendisk.de_arr = (devfs_handle_t*)
+		kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL);
+	memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t));
+	major_info->gendisk.flags = (char*)
+		kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
+	memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char));
+
 	rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
 	if (rc < 0) {
 		printk (KERN_WARNING PRINTK_HEADER
 		      "Cannot register to major no %d, rc = %d\n", major, rc);
 		return rc;
+	} else {
+		major_info->flags |= DASD_MAJOR_INFO_REGISTERED;
 	}
+        /* Insert the new major info into dasd_major_info if needed */
+        if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){
+                spin_lock_irqsave (&dasd_major_lock, flags);
+		list_add_tail(&major_info->list,&dasd_major_info[0].list);
+		spin_unlock_irqrestore (&dasd_major_lock, flags);
+        }
 	if (major == 0) {
 		major = rc;
 		rc = 0;
@@ -604,6 +622,7 @@
 	int rc = 0;
 	int major;
 	struct gendisk *dd, *prev = NULL;
+	unsigned long flags;
 
 	if (major_info == NULL) {
 		return -EINVAL;
@@ -629,6 +648,8 @@
 	if (dd == NULL) {
 		return -ENOENT;
 	}
+	kfree (major_info->gendisk.de_arr);
+	kfree (major_info->gendisk.flags);
 	kfree (major_info->dasd_device);
 	kfree (blk_size[major]);
 	kfree (blksize_size[major]);
@@ -641,9 +662,16 @@
 		printk (KERN_WARNING PRINTK_HEADER
 		  "Cannot unregister from major no %d, rc = %d\n", major, rc);
 		return rc;
+	} else {
+		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
 	}
-	if (major_info->gendisk.major > 128)
+        /* Delete the new major info from dasd_major_info if needed */
+        if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+                spin_lock_irqsave (&dasd_major_lock, flags);
+		list_del(&major_info->list);
+		spin_unlock_irqrestore (&dasd_major_lock, flags);
 		kfree (major_info);
+        }
 	return rc;
 }
 
@@ -655,16 +683,18 @@
 static inline dasd_device_t *
 dasd_device_from_kdev (kdev_t kdev)
 {
-	major_info_t *major_info = dasd_major_info;
+	major_info_t *major_info = NULL;
+	struct list_head *l;
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	while (major_info &&
-	       major_info->gendisk.major != MAJOR (kdev)) {
-		major_info = major_info->next;
+	list_for_each(l,&dasd_major_info[0].list) {
+		major_info = list_entry(l,major_info_t,list);
+		if ( major_info->gendisk.major == MAJOR(kdev) )
+			break;
 	}
 	spin_unlock_irqrestore (&dasd_major_lock, flags);
-	if (major_info)
+	if (major_info != &dasd_major_info[0])
 		return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS];
 	return NULL;
 }
@@ -678,13 +708,14 @@
 static inline dasd_device_t **
 dasd_device_from_devno (int devno)
 {
-	major_info_t *major_info = dasd_major_info;
+	major_info_t *major_info;
+	struct list_head *l;
 	int devindex = dasd_devindex_from_devno (devno);
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	for (major_info = dasd_major_info; major_info;
-	     major_info = major_info->next) {
+	list_for_each(l,&dasd_major_info[0].list) {
+		major_info = list_entry(l,major_info_t,list);
 		if (devindex < DASD_PER_MAJOR) {
 			spin_unlock_irqrestore (&dasd_major_lock, flags);
 			return &major_info->dasd_device[devindex];
@@ -867,7 +898,7 @@
 	ccw_req_t *prev;
 
 	if (cqr == NULL)
-		BUG ();
+                BUG ();
 
 	if (cqr == q->head) {
 		q->head = cqr->next;
@@ -1111,20 +1142,11 @@
 static inline void
 dasd_end_request (struct request *req, int uptodate)
 {
-	struct buffer_head *bh;
-	while ((bh = req->bh) != NULL) {
-                int nsect = bh->b_size >> 9;
-                blk_finished_io (nsect);
-		req->bh = bh->b_reqnext;
-		bh->b_reqnext = NULL;
-		bh->b_end_io (bh, uptodate);
-	}
-	if (!end_that_request_first (req, uptodate, DASD_NAME)) {
+	while (end_that_request_first (req, uptodate, DASD_NAME)) {}
 #ifndef DEVICE_NO_RANDOM
-		add_blkdev_randomness (MAJOR (req->rq_dev));
+	add_blkdev_randomness (MAJOR (req->rq_dev));
 #endif
-		end_that_request_last (req);
-	}
+	end_that_request_last (req);
 	return;
 }
 
@@ -1151,9 +1173,10 @@
 	int rc = 0;
 
 	asm volatile ("STCK %0":"=m" (now));
-	if ( cqr->expires + cqr->startclk <  now) {
+	if ( cqr->expires && 
+             cqr->expires + cqr->startclk <  now) {
 		DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device),
-			      "IO timeout 0x%08lx%08lx usecs with req %p\n",
+			      "IO timeout 0x%08lx%08lx usecs in req %p\n",
 			      (long) (cqr->expires >> 44), 
                               (long) (cqr->expires >> 12), cqr);
 		cqr->expires <<=1;
@@ -1170,7 +1193,6 @@
 dasd_finalize_request (ccw_req_t * cqr)
 {
         dasd_device_t *device = cqr->device;
-	dasd_discipline_t *discipline = device->discipline;
         
 	asm volatile ("STCK %0":"=m" (cqr->endclk));
 	if (cqr->req) {
@@ -1225,9 +1247,11 @@
                                                 CQR_STATUS_FAILED);
                                 continue;
 			} else {
-				dasd_chanq_enq_head (qp, erp_cqr);
+                                if (erp_cqr != qp->head){
+                                        dasd_chanq_enq_head (qp, erp_cqr);
+                                }
 				/* chain of completed requests is now broken */
-				break; 
+				continue; 
 			}
 		} else if ( qp -> head -> refers ) { /* we deal with an ERP */
                         char *uptodatestr;
@@ -1266,7 +1290,8 @@
         for (temp = cqr; temp != NULL ;temp=temp-> next )
                 if ( temp ->status == CQR_STATUS_QUEUED)
                         chanq_max_size --;
-	while ( (! list_empty(&queue->queue_head)) && 
+	while ( (! queue->plugged) &&
+		(! list_empty(&queue->queue_head)) && 
                 (req=dasd_next_request(queue)) != NULL) {
                 /* queue empty or certain critera fulfilled -> transfer */
                 if ( qp -> head == NULL ||
@@ -1307,6 +1332,10 @@
                                 /* to be filled with MIH */
                         }
                         break;
+
+                case CQR_STATUS_PENDING:
+                        /* just wait */
+                        break;
                 default: 
                         BUG();
                 }
@@ -1390,8 +1419,54 @@
 }
 #endif				/* LINUX_IS_24 */
 
+/*
+ * 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' to reactivate
+ *   the device.
+ *
+ *  PARAMETER
+ *   stat               device status of state change pending interrupt.
+ */
+void 
+dasd_handle_state_change_pending (devstat_t *stat)
+{
+        dasd_device_t **device_addr;
+        ccw_req_t     *cqr;
+
+	device_addr = dasd_device_from_devno (stat->devno);
+
+        if (device_addr == NULL) {
+		printk (KERN_INFO PRINTK_HEADER
+                        "unable to find device for state change pending "
+                        "interrupt: devno%04X\n",
+                        stat->devno);
+        } else {
+                /* re-activate first request in queue */
+                cqr = (*device_addr)->queue.head;
+
+                if (cqr->status == CQR_STATUS_PENDING) {
+
+                        DASD_MESSAGE (KERN_INFO, (*device_addr),
+                                      "%s",
+                                      "device request queue restarted by "
+                                      "state change pending interrupt\n");
+
+                        del_timer(&(*device_addr)->timer);
+
+                        check_then_set(&cqr->status, 
+                                       CQR_STATUS_PENDING, 
+                                       CQR_STATUS_QUEUED);
 
+                        dasd_schedule_bh(*device_addr);
 
+                }
+        }
+} /* end dasd_handle_state_change_pending */
 
 /* 
  * function dasd_int_handler
@@ -1406,7 +1481,7 @@
 	dasd_device_t *device;
         unsigned long long now;
 #ifdef ERP_DEBUG
-	static int counter;
+	static int counter = 0;
 #endif
 	dasd_era_t era = dasd_era_none; /* default is everything is okay */
 	devstat_t *stat = (devstat_t *)ds;
@@ -1415,6 +1490,16 @@
         if (stat == NULL) {
                 BUG();
 	}
+
+        /* first of all 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; /* TBD */
+        }
+
 	ip = stat->intparm;
 	if (!ip) {		/* no intparm: unsolicited interrupt */
 		printk (KERN_INFO PRINTK_HEADER
@@ -1441,11 +1526,35 @@
                 BUG();
 	}
 #ifdef ERP_DEBUG
-	counter++;
-        if  ( counter % 137 == 0 ) {
-                stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-                stat->cstat = 0x00;
-                stat->dstat = 0x02;
+                if ((++counter % 937 >= 0) &&
+                    (  counter % 937 <= 10) &&
+                    (  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;
+// 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;
+//                        }
+
+/*
                 memset(stat->ii.sense.data,0,32);
                 stat->ii.sense.data[2] = 0x06;
                 stat->ii.sense.data[4] = 0x04;
@@ -1464,6 +1573,7 @@
                 stat->ii.sense.data[24] = 0x04;
                 stat->ii.sense.data[25] = 0x10;
                 stat->ii.sense.data[26] = 0x4e;
+*/
         }
 #endif
         /* first of all lets try to find out the appropriate era_action */
@@ -1545,13 +1655,13 @@
 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);
 
 	printk (KERN_WARNING PRINTK_HEADER
 		"Default ERP called... \n");
 
-	if (!erp)
-		return NULL;
+        if (erp == NULL)
+               return NULL;
 
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
 	erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr;
@@ -1562,6 +1672,7 @@
 	erp->retries = 16;
 
 	erp->status = CQR_STATUS_FILLED;
+
 	return erp;
 }
 
@@ -1582,8 +1693,8 @@
 ccw_req_t *
 default_erp_postaction (ccw_req_t * erp)
 {
+	ccw_req_t *cqr = NULL, *free_erp = NULL;
 	dasd_device_t *device = NULL;
-        ccw_req_t *free_erp;
         int success;
         
 	device = (dasd_device_t *) (erp->device);
@@ -1593,6 +1704,24 @@
 	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) {
                 BUG();
 	}
@@ -1606,39 +1735,46 @@
 	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;
+
+#ifdef ERP_DEBUG
+	printk (KERN_INFO PRINTK_HEADER
+		"default_erp_postaction - left original request = %p \n",cqr);
+#endif /* ERP_DEBUG */
 
-        /*
-         * printk (KERN_INFO PRINTK_HEADER
-         * "default_erp_postaction - left original request = %p \n",erp);
-         */
 	/* set corresponding status to original cqr */
 	if (success) {
-		check_then_set (&erp->status, CQR_STATUS_ERROR, 
+		check_then_set (&cqr->status, 
+                                CQR_STATUS_ERROR, 
                                 CQR_STATUS_DONE);
 	} else {
-		check_then_set (&erp->status, CQR_STATUS_ERROR,
+		check_then_set (&cqr->status,
+                                CQR_STATUS_ERROR,
                                 CQR_STATUS_FAILED);
 	}
-        
+
+#ifdef ERP_DEBUG
 	/* print current erp_chain */
-#if 0
 	printk (KERN_WARNING PRINTK_HEADER
 		"default ERP postaction finished with remaining chain:\n");
 	{
 		ccw_req_t *temp_erp = NULL;
-		for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) {
+		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
-	return erp;
+#endif /* ERP_DEBUG */
+
+	return cqr;
 }				/* end default_erp_postaction */
 
 /* SECTION: The helpers of the struct file_operations */
@@ -1655,6 +1791,7 @@
 dasd_format (dasd_device_t * device, format_data_t * fdata)
 {
 	int rc = 0;
+        int format_done = 0;
 	ccw_req_t *req = NULL;
 	format_data_t temp =
 	{
@@ -1663,29 +1800,41 @@
 		fdata->blksize,
 		fdata->intensity
 	};
-
+        
+        spin_lock (&dasd_open_count_lock);
 	if (device->open_count != 1) {
 		DASD_MESSAGE (KERN_INFO, device,
 			      "device is already open %d times",
 			      device->open_count);
+                spin_unlock(&dasd_open_count_lock);
 		return -EINVAL;
 	}
 	if (!device->discipline->format_device) {
+                spin_unlock(&dasd_open_count_lock);
 		return -EINVAL;
 	}
+        device->open_count = -1;
+        spin_unlock (&dasd_open_count_lock);
 	/* downgrade state of the device */
 	dasd_set_device_level (device->devinfo.irq,
 			       DASD_DEVICE_LEVEL_RECOGNIZED,
 			       device->discipline,
 			       0);
-	DASD_MESSAGE (KERN_INFO, device, "Starting format from %d to %d (%d B blocks flags %d",fdata->start_unit,fdata->stop_unit,fdata->blksize,fdata->intensity);
+	DASD_MESSAGE (KERN_INFO, device, 
+                      "Starting format from %d to %d (%d B blocks flags %d",
+                      fdata->start_unit,
+                      fdata->stop_unit,
+                      fdata->blksize,
+                      fdata->intensity);
 	/* Invalidate first track */
 	if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
-	    fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
-	    fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) {
+	    fdata->stop_unit  == DASD_FORMAT_DEFAULT_STOP_UNIT  &&
+	    fdata->intensity  == DASD_FORMAT_DEFAULT_INTENSITY    ) {
 		format_data_t temp2 =
-		{0, 0, DASD_FORMAT_DEFAULT_BLOCKSIZE, 0x04};
-		DASD_MESSAGE (KERN_INFO, device, "%s", "Invalidating first track...");
+		{0, 0, fdata->blksize, 0x04};
+		DASD_MESSAGE (KERN_INFO, device, 
+                              "%s", 
+                              "Invalidating first track...");
 		req = device->discipline->format_device (device, &temp2);
 		if (req) {
 			rc = sleep_on_req (req);
@@ -1694,32 +1843,43 @@
 			rc = -EINVAL;
 		}
 		if (rc) {
-			printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n");
-		}
+                        DASD_MESSAGE (KERN_WARNING, device, 
+                                      "%s",
+                                      "Can't invalidate Track 0\n");
+		} else {
+                        DASD_MESSAGE (KERN_INFO, device, 
+                                      "%s", 
+                                      "...Invalidation complete");
+                }
 		temp.start_unit++;
-		DASD_MESSAGE (KERN_INFO, device, "%s", "...Invalidation complete");
 	}
 	/* format remainnig tracks of device */
-	while (!rc &&
-	       ((req = device->discipline->format_device (device, &temp)) !=
-		NULL)) {
+	while (!rc                                                                 &&
+	       ((req = device->discipline->format_device (device, &temp)) != NULL)   ) {
+                                format_done=1;
 		if ((rc = sleep_on_req (req)) != 0) {
+
+
 			DASD_MESSAGE (KERN_WARNING, device,
 				      " Formatting failed with rc = %d\n",
 				      rc);
 			break;
 		}
+                
 		dasd_free_request (req);	/* request is no longer used */
 		temp.start_unit++;
 	}
-	if (!rc &&
-	    req == NULL) {
+
+	if (!rc         &&
+	    req == NULL   ) {
 		if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
-		    fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
-	    	    fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) {
+		    fdata->stop_unit  == DASD_FORMAT_DEFAULT_STOP_UNIT  &&
+	    	    fdata->intensity  == DASD_FORMAT_DEFAULT_INTENSITY    ) {
 			format_data_t temp2 =
 			{0, 0, fdata->blksize, fdata->intensity};
-			DASD_MESSAGE (KERN_INFO, device, "%s", "Revalidating first track...");
+			DASD_MESSAGE (KERN_INFO, device, 
+                                      "%s", 
+                                      "Revalidating first track...");
 			req = device->discipline->format_device (device, &temp2);
 			if (req) {
 				rc = sleep_on_req (req);
@@ -1728,12 +1888,22 @@
 				rc = -EINVAL;
 			}
 			if (rc) {
-				printk (KERN_WARNING PRINTK_HEADER
-					"Can't revalidate Track 0\n");
-			}
-			DASD_MESSAGE (KERN_INFO, device, "%s", "...Revalidation complete");
+				DASD_MESSAGE (KERN_WARNING, device,
+                                              "%s",
+                                              "Can't revalidate Track 0\n");
+			} else {
+                                DASD_MESSAGE (KERN_INFO, device, 
+                                              "%s", 
+                                              "...Revalidation complete");
+                        }
 		}
 	}			/* end if no more requests */
+
+        /* check if at least one format cp was build in discipline */
+        if (!format_done) {
+                rc = -EINVAL;
+        }
+
 	if (rc)
 		DASD_MESSAGE (KERN_WARNING, device,
 			      "%s", " Formatting finished unsuccessfully");
@@ -1741,22 +1911,75 @@
 		DASD_MESSAGE (KERN_INFO, device,
 			      "%s", " Formatting finished successfully");
 
-	/* re-activate device even if formatting was unsuccessful */
-	/* Horst Hummel - 17/10/00 - ITPM PL020062RSC             */
-	dasd_set_device_level (device->devinfo.irq,
-			       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-			       device->discipline,
-			       0);
-	udelay (1500000);
-
-	dasd_set_device_level (device->devinfo.irq,
-			       DASD_DEVICE_LEVEL_ANALYSED,
-			       device->discipline,
-			       0);
-
+        /* 
+         * re-analyse device
+         */
+        dasd_set_device_level (device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_ONLINE,
+                               device->discipline,
+                               0);
+        udelay (1500000);
+                
+        dasd_set_device_level (device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_ONLINE,
+                               device->discipline,
+                               0);
+
+        spin_lock (&dasd_open_count_lock);
+        device->open_count=1;
+        spin_unlock (&dasd_open_count_lock);
 	return rc;
 }				/* end dasd_format */
 
+static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls);
+
+static dasd_ioctl_list_t *
+dasd_find_ioctl( int no )
+{
+	struct list_head *curr;
+	list_for_each(curr,&dasd_ioctls){
+		if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){
+			return list_entry(curr,dasd_ioctl_list_t,list);
+		}
+	}
+	return NULL;
+}
+
+int
+dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler )
+{
+	dasd_ioctl_list_t *new;
+	if (dasd_find_ioctl(no))
+		return -EBUSY;
+	new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL);
+ 	if ( new ==  NULL )
+		return -ENOMEM;
+	new -> no = no;
+	new -> handler = handler;
+	list_add(&new->list,&dasd_ioctls);
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+int
+dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler )
+{	
+	dasd_ioctl_list_t *old = dasd_find_ioctl(no);
+	if ( old == NULL )
+		return -ENOENT;
+	if ( old->no != no ||
+	     old->handler != handler )
+		return -EINVAL;
+	list_del(&old->list);
+	kfree(old);
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
 static int
 do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 {
@@ -1809,10 +2032,11 @@
 			break;
 		}
 	case HDIO_GETGEO:{
-			struct hd_geometry geo =
-			{0,};
-			if (device->discipline->fill_geometry)
-				device->discipline->fill_geometry (device, &geo);
+			struct hd_geometry geo = {0,};
+			rc = dasd_fillgeo(inp->i_rdev, &geo);
+			if (rc)
+				break;
+
 			rc = copy_to_user ((struct hd_geometry *) data, &geo,
 					   sizeof (struct hd_geometry));
 			if (rc)
@@ -1944,17 +2168,23 @@
 			break;
 		}
 	default:{
-			DASD_MESSAGE (KERN_INFO, device,
-				    "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
-				      no,
-				      _IOC_DIR (no) == _IOC_NONE ? "0" :
-				      _IOC_DIR (no) == _IOC_READ ? "r" :
-				      _IOC_DIR (no) == _IOC_WRITE ? "w" :
-				   _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ?
-				      "rw" : "u",
-				 _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
-				      data);
-			rc = -EINVAL;
+
+			dasd_ioctl_list_t *old = dasd_find_ioctl(no);
+			if ( old ) {
+				rc = old->handler(inp,no,data);
+			} else {
+				DASD_MESSAGE (KERN_INFO, device,
+					    "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
+					      no,
+					      _IOC_DIR (no) == _IOC_NONE ? "0" :
+					      _IOC_DIR (no) == _IOC_READ ? "r" :
+					      _IOC_DIR (no) == _IOC_WRITE ? "w" :
+					   _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ?
+					      "rw" : "u",
+					 _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+					      data);
+				rc = -EINVAL;
+			}	
 			break;
 		}
 	}
@@ -2000,10 +2230,16 @@
 			      " %s", " Cannot open unrecognized device\n");
 		return -EINVAL;
 	}
+        spin_lock(&dasd_open_count_lock);
+        if (device->open_count == -1) {
+            spin_unlock (&dasd_open_count_lock);
+            return -EBUSY;
+        }
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
 #endif				/* MODULE */
 	device->open_count++;
+        spin_unlock (&dasd_open_count_lock);
 	return rc;
 }
 
@@ -2023,6 +2259,7 @@
 			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
 		return -EINVAL;
 	}
+        spin_lock(&dasd_open_count_lock);
 	if (device->open_count--) {
 #ifdef MODULE
 		MOD_DEC_USE_COUNT;
@@ -2031,6 +2268,7 @@
 	fsync_dev(inp->i_rdev); /* sync the device */
 	if (device->open_count == 0) /* finally invalidate buffers */
 		invalidate_buffers(inp->i_rdev);
+        spin_unlock(&dasd_open_count_lock);
 	return rc;
 }
 
@@ -2048,6 +2286,26 @@
 };
 
 /* SECTION: Management of device list */
+int
+dasd_fillgeo(int kdev,struct hd_geometry *geo)
+{
+	dasd_device_t *device = dasd_device_from_kdev (kdev);
+	if (!device->discipline->fill_geometry)
+		return -EINVAL;
+
+	device->discipline->fill_geometry (device, geo);
+	geo->start = device->major_info->
+			gendisk.part[MINOR(kdev)].start_sect;
+
+	/* This is a hack.  dasdfmt and ibm.c expect geo.start 
+	   to contain the block number of the label block when
+	   it calls HDIO_GETGEO on the first partition. */
+	if (geo->start == 0)
+                geo->start = device->sizes.pt_block;
+
+	return 0;
+} 
+
 
 /* This one is needed for naming 18000+ possible dasd devices */
 int
@@ -2057,27 +2315,30 @@
 	char first, second, third;
 
 	if (hd) {
-		major_info_t *major_info;
-		for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+		major_info_t *major_info=NULL;
+		struct list_head *l;
+
+		list_for_each(l,&dasd_major_info[0].list) {
+			major_info = list_entry(l,major_info_t,list); 
 			if (&major_info->gendisk == hd) {
 				break;
 			}
 			index += DASD_PER_MAJOR;
 		}
-		if (major_info == NULL) {
+		if (major_info == &dasd_major_info[0]) {
 			return -EINVAL;
 		}
 	}
 	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) {
@@ -2093,13 +2354,28 @@
 
 #ifdef CONFIG_DASD_DYNAMIC
 static void
+dasd_plug_device (dasd_device_t *device)
+{
+        device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+}
+
+static void
+dasd_unplug_device (dasd_device_t *device)
+{
+        generic_unplug_device(&device->request_queue);
+}
+
+static void
 dasd_not_oper_handler (int irq, int status)
 {
 	dasd_device_t *device = NULL;
-	major_info_t *major_info;
+	major_info_t *major_info = NULL;
+	struct list_head *l;
 	int i, devno = -ENODEV;
 
-	for (major_info = dasd_major_info; major_info != NULL; major_info = major_info->next) {
+        /* find out devno of leaving device: CIO has already deleted this information ! */
+	list_for_each(l,&dasd_major_info[0].list) {
+		major_info=list_entry(l, major_info_t,list);	
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			device = major_info->dasd_device[i];
 			if (device &&
@@ -2116,20 +2392,24 @@
 			"not_oper_handler called on irq %d no devno!\n", irq);
 		return;
 	}
-	printk (KERN_INFO PRINTK_HEADER
-		"not_oper_handler called on irq %d devno %04X\n", irq, devno);
+
 	if (device->open_count != 0) {
-		printk (KERN_ALERT PRINTK_HEADER
-			"Device %04X detached has still been open. expect errors\n", devno);
-	}
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0);
+                DASD_MESSAGE(KERN_ALERT,device,"%s",
+                             "open device has gone. please repair!");
+                dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, 
+                                       NULL, 0);
+	} else {
+                DASD_MESSAGE(KERN_INFO,device,"%s","device has gone");
+                dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, 
+                                       NULL, 0);
+        }
 }
 
 static int
 dasd_enable_single_volume (int irq)
 {
 	int rc = 0;
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
 			       NULL, 0);
 	printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
 	{
@@ -2137,8 +2417,7 @@
 		init_waitqueue_head (&wait_queue);
 		interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1);
 	}
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
-			       NULL, 0);
+	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
 	return rc;
 }
 
@@ -2148,12 +2427,13 @@
 	int devno;
 	int rc;
 	devno = get_devno_by_irq (irq);
-	if (devno == -ENODEV)
+        printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n");
+	if (devno == -ENODEV) {
+          printk (KERN_WARNING PRINTK_HEADER "NODEV\n");
 		return -ENODEV;
+        }
 	if (dasd_autodetect) {
 		dasd_add_range (devno, 0);
-	} else {
-		return -ENODEV;
 	}
 	rc = dasd_enable_single_volume (irq);
 	return rc;
@@ -2172,14 +2452,26 @@
 	dasd_device_t **device_addr, *device;
 	int current_level;
 	major_info_t *major_info = NULL;
+	struct list_head *l;
 	int i, minor, major;
 	ccw_req_t *cqr = NULL;
 	struct gendisk *dd;
 
 	devno = get_devno_by_irq (irq);
-	if (devno < 0) {
-		printk (KERN_WARNING PRINTK_HEADER " no device appears to be connected to SCH %d\n", irq);
-		return -ENODEV;
+	if (devno < 0) { /* e.g. when device has been detached before */
+		/* search in device list */
+		list_for_each(l,&dasd_major_info[0].list) {
+			major_info = list_entry(l,major_info_t,list);	
+			for (i = 0; i < DASD_PER_MAJOR; i++) {
+				device = major_info->dasd_device[i];
+				if (device && device->devinfo.irq == irq) {
+					devno = device->devinfo.devno;
+					break;
+				}
+			}
+			if (devno == -ENODEV)
+				return -ENODEV;
+		}
 	}
 	if (dasd_devindex_from_devno (devno) < 0) {
 		return -ENODEV;
@@ -2204,8 +2496,9 @@
 		memset (device, 0, sizeof (dasd_device_t));
 		*device_addr = device;
 	}
-	for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+	list_for_each(l,&dasd_major_info[0].list) {
 		int i;
+		major_info = list_entry(l,major_info_t,list);	
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			if (major_info->dasd_device[i] == device) {
 				device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS);
@@ -2215,21 +2508,21 @@
 		if (i < DASD_PER_MAJOR)
 			break;
 	}
-	if (major_info == NULL) {
+	if (major_info == &dasd_major_info[0]) {
 		return -ENODEV;
 	}
-	device->major_info = major_info;
-	dasd_device_name (device->name,
-			  ((long) device_addr -
-			   (long) device->major_info->dasd_device) /
-			  sizeof (dasd_device_t *),
-			  0, &major_info->gendisk);
 	minor = MINOR (device->kdev);
 	major = MAJOR (device->kdev);
 	current_level = device->level;
 	if (desired_level > current_level) {
 		switch (current_level) {
 		case DASD_DEVICE_LEVEL_UNKNOWN:	/* Find a discipline */
+                        device->major_info = major_info;
+                        dasd_device_name (device->name,
+                                          ((long) device_addr -
+                                           (long) device->major_info->dasd_device) /
+                                          sizeof (dasd_device_t *),
+                                          0, &major_info->gendisk);
 			rc = get_dev_info_by_irq (irq, &device->devinfo);
 			if (rc < 0) {
 				break;
@@ -2242,6 +2535,9 @@
                                 break;
 			}
 			device->discipline = discipline;
+                        device->debug_area = debug_register(device->name,0,2,3*sizeof(long));
+                        debug_register_view(device->debug_area,&debug_sprintf_view);
+                        debug_register_view(device->debug_area,&debug_hex_ascii_view);
 			if (device->discipline->int_handler) {
 #ifdef CONFIG_DASD_DYNAMIC
 				s390_request_irq_special (irq,
@@ -2276,8 +2572,6 @@
 				}
 			}
 			init_waitqueue_head (&device->wait_q);
-			blk_init_queue (&device->request_queue, do_dasd_request);
-			blk_queue_headactive (&device->request_queue, 0);
 			check_then_set (&device->level,
 				       DASD_DEVICE_LEVEL_UNKNOWN,
 				       DASD_DEVICE_LEVEL_RECOGNIZED);
@@ -2325,9 +2619,12 @@
 					return -EMEDIUMTYPE;
 				}
 			}
+			blk_init_queue (&device->request_queue, do_dasd_request);
+			blk_queue_headactive (&device->request_queue, 0);
+			elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP);
 			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-				if (i == 0)
-					blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
+                                if (i == 0)
+                                        blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
 				else
 					blk_size[major][minor + i] = 0;
 				hardsect_size[major][minor + i] = device->sizes.bp_block;
@@ -2336,7 +2633,7 @@
 					blksize_size[major][minor + i] = 1024;
 
 				max_sectors[major][minor + i] =
-                                        255 << device->sizes.s2b_shift;
+                                        device->discipline->max_blocks << device->sizes.s2b_shift;
 			}
 			check_then_set (&device->level,
 				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -2344,6 +2641,12 @@
 			dd = &major_info->gendisk;
 			dd->sizes[minor] = (device->sizes.blocks <<
 					    device->sizes.s2b_shift) >> 1;
+                        dd->part[minor].start_sect = 0;
+			{
+				char buffer[5];
+				sprintf(buffer,"%04X",device->devinfo.devno);
+				dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL);
+			}
 #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #ifndef MODULE
 			if (flags & 0x80)
@@ -2353,8 +2656,15 @@
 			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
 				break;
 		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
-
-			break;
+                        dasd_unplug_device(device);
+			check_then_set (&device->level,
+                                        DASD_DEVICE_LEVEL_ANALYSED,
+                                        DASD_DEVICE_LEVEL_ONLINE);
+                        
+			if (desired_level == DASD_DEVICE_LEVEL_ONLINE)
+                                break;
+		case DASD_DEVICE_LEVEL_ONLINE:	
+                        break;
 		default:
 			printk (KERN_WARNING PRINTK_HEADER
 				"Internal error in " __FILE__ " on line %d."
@@ -2368,20 +2678,29 @@
 		}
 	} else if (desired_level < current_level) {	/* donwgrade device status */
 		switch (current_level) {
-		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
+		case DASD_DEVICE_LEVEL_ONLINE:	/* Fallthrough ?? */
+                        dasd_plug_device(device); 
 			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSED,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
+                                        DASD_DEVICE_LEVEL_ONLINE,
+                                        DASD_DEVICE_LEVEL_ANALYSED);
+			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
+                                break;
+                case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
 			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-				blk_size[major][minor] = 0;
+                                __invalidate_buffers(MKDEV(major,minor),1);
+                                blk_size[major][minor] = 0;
 				hardsect_size[major][minor + i] = 0;
 				blksize_size[major][minor + i] = 0;
 				max_sectors[major][minor + i] = 0;
 			}
 			memset (&device->sizes, 0, sizeof (dasd_sizes_t));
+			blk_cleanup_queue (&device->request_queue);
+                        check_then_set (&device->level,
+                                        DASD_DEVICE_LEVEL_ANALYSED,
+                                        DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
+                        if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
+                                break;
+		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
 			check_then_set (&device->level,
 				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
 				       DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
@@ -2398,10 +2717,12 @@
 				free_irq (irq, &device->dev_status);
 			}
 			device->discipline = NULL;
-			blk_cleanup_queue (&device->request_queue);
+                        debug_unregister(device->debug_area);
 			check_then_set (&device->level,
 				       DASD_DEVICE_LEVEL_RECOGNIZED,
 				       DASD_DEVICE_LEVEL_UNKNOWN);
+                        *device_addr = NULL;
+                        kfree(device);
 			if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN)
 				break;
 		case DASD_DEVICE_LEVEL_UNKNOWN:
@@ -2433,6 +2754,13 @@
 	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
@@ -2445,7 +2773,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;
@@ -2458,7 +2787,9 @@
 	int size = 1;
 	int len = 0;
 	major_info_t *temp = dasd_major_info;
+	struct list_head *l;
 	tempinfo_t *info;
+	int i;
 
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
@@ -2467,15 +2798,14 @@
 	} else {
 		file->private_data = (void *) info;
 	}
-	while (temp) {
-		int i;
+	list_for_each(l,&dasd_major_info[0].list) {
+		temp = list_entry(l,major_info_t,list);	
 		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
 			dasd_device_t *device = temp->dasd_device[i];
 			if (device) {
 				size += 128;
 			}
 		}
-		temp = temp->next;
 	}
 	temp = dasd_major_info;
 	info->data = (char *) vmalloc (size);	/* FIXME! determine space needed in a better way */
@@ -2484,8 +2814,8 @@
 		vfree (info);
 		return -ENOMEM;
 	}
-	while (temp) {
-		int i;
+	list_for_each(l,&dasd_major_info[0].list) {
+		temp = list_entry(l,major_info_t,list);	
 		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
 			dasd_device_t *device = temp->dasd_device[i];
 			if (device) {
@@ -2519,15 +2849,24 @@
 							device->sizes.blocks,
 							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
 					break;
+				case DASD_DEVICE_LEVEL_ONLINE:
+					len += sprintf (info->data + len, "active ");
+					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
+							device->sizes.bp_block,
+							device->sizes.blocks,
+							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+					break;
 				default:
 					len += sprintf (info->data + len, "no stat\n");
 					break;
 				}
 			}
 		}
-		temp = temp->next;
 	}
 	info->len = len;
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
 	return rc;
 }
 
@@ -2554,6 +2893,11 @@
 dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset)
 {
 	char *buffer = vmalloc (user_len);
+	int off = 0;
+	char *temp;
+        int irq;
+        int j,target;
+        dasd_range_t *rptr, range;
 
 	if (buffer == NULL)
 		return -ENOMEM;
@@ -2563,17 +2907,68 @@
 	}
 	buffer[user_len] = 0;
 	printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer);
-	if (!strncmp (buffer, "add range", strlen ("add_range"))) {
-
-	} else if (!strncmp (buffer, "enable device", strlen ("enable device"))) {
-
-	} else if (!strncmp (buffer, "disable device", strlen ("disable device"))) {
-
-	} else {
-		printk (KERN_WARNING PRINTK_HEADER "unknown command %s",
-			buffer);
-	}
-	vfree (buffer);
+        if (strncmp ( buffer, "set ",4) &&
+            strncmp ( buffer, "add ",4)){
+                printk (KERN_WARNING PRINTK_HEADER 
+                        "/proc/dasd/devices: only 'set' and 'add' are supported verbs");
+                return -EINVAL;
+        }
+        off += 4;
+        while (!isalnum(buffer[off])) off++;
+	if (!strncmp (buffer + off, "device", strlen ("device"))) {
+		off += strlen("device");
+		while (!isalnum(buffer[off])) off++;
+        }
+	if (!strncmp (buffer + off, "range=", strlen ("range="))) {
+		off += strlen("range=");
+		while (!isalnum(buffer[off])) off++;
+        }
+        temp = buffer+off;
+        range.from = dasd_strtoul (temp, &temp);
+        range.to = range.from;
+        if (*temp == '-') {
+                temp++;
+                range.to = dasd_strtoul (temp, &temp);
+        }
+        off = (long)temp - (long)buffer;
+        if ( !strncmp ( buffer, "add",strlen("add"))) {
+                rptr = dasd_add_range (range.from, range.to);
+        } else {
+                rptr = &range;
+        }
+        while (!isalnum(buffer[off])) off++;
+        printk (KERN_INFO PRINTK_HEADER 
+                "varying device range %04X-%04X\n", rptr->from, rptr->to);
+        if ( !strncmp ( buffer, "add",strlen("add")) ||
+             !strncmp ( buffer+off, "on",strlen("on")) ) {
+                target = DASD_DEVICE_LEVEL_ONLINE;
+                for (j = rptr->from; j <= rptr->to; j++) {
+			irq = get_irq_by_devno (j);
+			if (irq >= 0) {
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
+			}
+		}
+		printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
+		{
+			static wait_queue_head_t wait_queue;
+			init_waitqueue_head (&wait_queue);
+			interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) );
+		}
+        } else if ( !strncmp ( buffer+off, "off",strlen("off"))) {
+                target = DASD_DEVICE_LEVEL_UNKNOWN;
+        } else {
+                printk (KERN_WARNING PRINTK_HEADER 
+                        "/proc/dasd/devices: parse error in '%s'", buffer);
+                vfree (buffer);
+                return -EINVAL;
+                
+        }
+        for (j = rptr->from; j <= rptr->to; j++) {
+                irq = get_irq_by_devno (j);
+                if (irq >= 0) {
+                        dasd_set_device_level (irq, target, NULL, 0);
+                }
+        }
 	return user_len;
 }
 
@@ -2587,6 +2982,9 @@
 			vfree (p_info->data);
 		vfree (p_info);
 	}
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
 	return rc;
 }
 
@@ -2693,6 +3091,9 @@
 	}
 	len += sprintf (info->data + len, "\n");
 	info->len = len;
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
 	return rc;
 }
 
@@ -2779,26 +3180,44 @@
 }
 
 /* SECTION: Initializing the driver */
-
 int __init
 dasd_init (void)
 {
 	int rc = 0;
 	int irq;
 	int j;
-	major_info_t *major_info;
+	major_info_t *major_info=NULL;
+	struct list_head *l;
 	dasd_range_t *range;
 
 	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
-	for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+        dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long));
+        debug_register_view(dasd_debug_area,&debug_sprintf_view);
+        debug_register_view(dasd_debug_area,&debug_hex_ascii_view);
+        
+        if ( dasd_debug_area == NULL ) {
+                goto failed;
+        }
+        DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY");
+	dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL);
+        if ( dasd_devfs_handle < 0 ) {
+                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs");
+                goto failed;
+        }
+	list_for_each(l,&dasd_major_info[0].list) {
+		major_info=list_entry(l,major_info_t,list);
                 if ((rc = dasd_register_major (major_info)) > 0) {
+                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                                "major %d: success",major_info->gendisk.major);
                         printk (KERN_INFO PRINTK_HEADER
                                 "Registered successfully to major no %u\n", major_info->gendisk.major);
 		} else {
+                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                                "major %d: failed",major_info->gendisk.major);
 			printk (KERN_WARNING PRINTK_HEADER
 				"Couldn't register successfully to major no %d\n", major_info->gendisk.major);
 			/* revert registration of major infos */
-			goto major_failed;
+                        goto failed;
 		}
 	}
 #ifndef MODULE
@@ -2809,57 +3228,77 @@
 
 	rc = dasd_proc_init ();
 	if (rc) {
-		goto proc_failed;
+                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                        "%s","no proc-FS");
+                goto failed;
 	}
 	genhd_dasd_name = dasd_device_name;
+	genhd_dasd_fillgeo = dasd_fillgeo;
 
 #ifdef CONFIG_DASD_ECKD
 	rc = dasd_eckd_init ();
 	if (rc == 0) {
+                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                        "ECKD discipline %s","success");
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered ECKD discipline successfully\n");
 	} else {
-		goto eckd_failed;
+                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                        "ECKD discipline %s","failed");
+                goto failed;
 	}
 #endif				/* CONFIG_DASD_ECKD */
 #ifdef CONFIG_DASD_FBA
 	rc = dasd_fba_init ();
 	if (rc == 0) {
+                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                        "FBA discipline %s","success");
+
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered FBA discipline successfully\n");
 	} else {
-		goto fba_failed;
+                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                        "FBA discipline %s","failed");
+                goto failed;
 	}
 #endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
+#ifdef CONFIG_DASD_DIAG
 	if (MACHINE_IS_VM) {
 		rc = dasd_diag_init ();
 		if (rc == 0) {
+                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                                "DIAG discipline %s","success");
 			printk (KERN_INFO PRINTK_HEADER
-				"Registered MDSK discipline successfully\n");
+				"Registered DIAG discipline successfully\n");
 		} else {
-			goto mdsk_failed;
+                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+                                                "DIAG discipline %s","failed");
+                        goto failed;
 		}
 	}
-#endif				/* CONFIG_DASD_MDSK */
+#endif				/* CONFIG_DASD_DIAG */
 	rc = 0;
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0)
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-						       NULL, 0);
-		}
-	}
-	if (dasd_autodetect) {
-		for (irq = get_irq_first (); irq != -ENODEV; irq = get_irq_next (irq)) {
+	if (dasd_autodetect) { /* update device range to all devices */
+		for (irq = get_irq_first (); irq != -ENODEV; 
+                     irq = get_irq_next (irq)) {
 			int devno = get_devno_by_irq (irq);
 			int index = dasd_devindex_from_devno (devno);
 			if (index == -ENODEV) {		/* not included in ranges */
+                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
+                                                        "add %04X to range",
+                                                        devno);
 				dasd_add_range (devno, 0);
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-						       NULL, 0);
-			}
+                        }
+                }
+        }
+	for (range = dasd_range_head; range; range = range->next) {
+		for (j = range->from; j <= range->to; j++) {
+			irq = get_irq_by_devno (j);
+                        if (irq >= 0)
+                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
+                                                        "1st step in initialization irq 0x%x",irq);
+                        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
+                                               NULL, 0);
 		}
 	}
 	printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
@@ -2873,99 +3312,117 @@
 		for (j = range->from; j <= range->to; j++) {
 			irq = get_irq_by_devno (j);
 			if (irq >= 0) {
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
+                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
+                                                        "2nd step in initialization irq 0x%x",irq);
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
 						       NULL, 0);
 			}
 		}
 	}
-	goto out;
-#ifdef CONFIG_DASD_MDSK
-      mdsk_failed:
-	dasd_diag_cleanup ();
-#endif				/* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_FBA
-      fba_failed:
-	dasd_fba_cleanup ();
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_ECKD
-      eckd_failed:
-	dasd_eckd_cleanup ();
-#endif				/* CONFIG_DASD_ECKD */
-      proc_failed:
-	dasd_proc_cleanup ();
-      major_failed:{
-                major_info_t * temp;
-		for (temp = dasd_major_info;
-		     temp && (temp != major_info);
-		     temp = temp->next) {
-			dasd_unregister_major (temp);
-		}
-	}
-	dasd_cleanup_emergency_req ();
+        goto out;
+ failed:
 	printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
-      out:
+        cleanup_dasd();
+ out:
+        DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE");
 	printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
 	return rc;
 }
 
-void
+static void
 cleanup_dasd (void)
 {
-	int j, rc = 0;
+	int i,j,rc;
 	int irq;
-	major_info_t *major_info;
+	major_info_t *major_info=NULL;
+	struct list_head *l;
 	dasd_range_t *range, *next;
 
 	printk (KERN_INFO PRINTK_HEADER "shutting down\n");
-
-	dasd_proc_cleanup ();
-
+        DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY");
 	for (range = dasd_range_head; range; range = range->next) {
 		for (j = range->from; j <= range->to; j++) {
 			irq = get_irq_by_devno (j);
 			if (irq >= 0) {
+                                DASD_DRIVER_DEBUG_EVENT(2,"cleanup_dasd",
+                                                        "shutdown irq 0x%x",irq);
 				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
 						       NULL, 0);
 			}
 		}
 	}
-	for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
-		int i;
+#ifdef CONFIG_DASD_DIAG
+	if (MACHINE_IS_VM) {
+		dasd_diag_cleanup ();
+                DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
+                                        "DIAG discipline %s","success");
+                printk (KERN_INFO PRINTK_HEADER
+                        "De-Registered DIAG discipline successfully\n");
+	}
+#endif				/* CONFIG_DASD_DIAG */
+#ifdef CONFIG_DASD_FBA
+	dasd_fba_cleanup ();
+        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
+                                "FBA discipline %s","success");
+        printk (KERN_INFO PRINTK_HEADER
+                "De-Registered FBA discipline successfully\n");
+#endif				/* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_ECKD
+	dasd_eckd_cleanup ();
+        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
+                                "ECKD discipline %s","success");
+        printk (KERN_INFO PRINTK_HEADER
+                "De-Registered ECKD discipline successfully\n");
+#endif				/* CONFIG_DASD_ECKD */
+        
+	dasd_proc_cleanup ();
+	dasd_cleanup_emergency_req ();
+
+	list_for_each(l,&dasd_major_info[0].list) {
+		major_info=list_entry(l,major_info_t,list);	
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			kfree (major_info->dasd_device[i]);
 		}
-		if ((rc = dasd_unregister_major (major_info)) == 0) {
+		if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) &&
+		    (rc = dasd_unregister_major (major_info)) == 0) {
+                        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
+                                                "major %d: success",major_info->gendisk.major);
 			printk (KERN_INFO PRINTK_HEADER
 				"Unregistered successfully from major no %u\n", major_info->gendisk.major);
 		} else {
+                        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
+                                                "major %d: failed",major_info->gendisk.major);
 			printk (KERN_WARNING PRINTK_HEADER
 				"Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc);
 		}
 	}
-	dasd_cleanup_emergency_req ();
+
 
 	range = dasd_range_head;
 	while (range) {
 		next = range->next;
-		kfree (range);
+                dasd_remove_range (range);
 		if (next == NULL)
 			break;
 		else
 			range = next;
 	}
 	dasd_range_head = NULL;
+        
+#ifndef MODULE
+        for( j = 0; j < 256; j++ )
+                if ( dasd[j] ) {
+                        kfree(dasd[j]);
+                        dasd[j] = NULL;
+                }
+#endif /* MODULE */
+        if (dasd_devfs_handle) 
+                devfs_unregister(dasd_devfs_handle);
+        if (dasd_debug_area != NULL )
+                debug_unregister(dasd_debug_area);
 
-#ifdef CONFIG_DASD_DYNAMIC
-	{
-		dasd_devreg_t *reg;
-		while (dasd_devreg_head) {
-			reg = dasd_devreg_head->next;
-			kfree (dasd_devreg_head);
-			dasd_devreg_head = reg;
-		}
-	}
-#endif	/* CONFIG_DASD_DYNAMIC */
 	printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
+        DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- v2.4.3/linux/drivers/s390/block/dasd_3990_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_3990_erp.c	Wed Apr 11 19:02:28 2001
@@ -1,46 +1,196 @@
 /* 
  * 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
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
  */
 
 #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 DEBUG ROUTINES
+ ***************************************************************************** 
  */
-dasd_era_t
-dasd_3990_erp_examine_32 (char *sense)
+#ifdef ERP_DEBUG
+void
+log_erp_chain (ccw_req_t *cqr,
+               int       caller,
+               __u32     cpa)
 {
 
-	switch (sense[25]) {
-	case 0x00:
-		return dasd_era_none;
-	case 0x01:
-		return dasd_era_fatal;
-	default:
-		return dasd_era_recover;
-	}
+        ccw_req_t     *loop_cqr = cqr;
+	dasd_device_t *device   = cqr->device;
 
-}				/* end dasd_3990_erp_examine_32 */
+        char    *page = (char *)get_free_page(GFP_ATOMIC);
+        int     len = 0;
+        int     i;
+        char    *nl, 
+                *end_cqr,
+                *begin, 
+                *end;
+
+        if ( page == NULL ) {
+                printk (KERN_WARNING PRINTK_HEADER
+                        "No memory to dump ERP chain\n");
+                return;
+        }        
+                        
+        while (loop_cqr != NULL) {
+                
+                memset (page, 0, 4096);
+                len = 0;
+
+                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                 "device %04X on irq %d: (%s) ERP chain report for req: %p\n",
+                                 device->devinfo.devno,
+                                 device->devinfo.irq,
+                                 caller == 0 ? "EXAMINE" : "ACTION",
+                                 loop_cqr);
+                
+                nl      = (char *) loop_cqr;
+                end_cqr = nl + sizeof (ccw_req_t); 
+
+                while (nl < end_cqr) {
+
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                         "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                         nl,
+                                         nl[0], nl[1], nl[2], nl[3],
+                                         nl[4], nl[5], nl[6], nl[7],
+                                         nl[8], nl[9], nl[10], nl[11],
+                                         nl[12], nl[13], nl[14], nl[15]);
+                        nl +=16;
+                }        
+                
+                nl  = (char *) loop_cqr->cpaddr;
+
+                if (loop_cqr->cplength > 40 ) { /* log only parts of the CP */
+
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "Start of channel program:\n");
+
+                        for (i = 0; i < 20; i += 2) { 
+
+                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                                 nl,
+                                                 nl[0], nl[1], nl[2], nl[3],
+                                                 nl[4], nl[5], nl[6], nl[7],
+                                                 nl[8], nl[9], nl[10], nl[11],
+                                                 nl[12], nl[13], nl[14], nl[15]);
+                                
+                                nl += 16;
+                        }
+                        
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "End of channel program:\n");
+                        
+                        nl  = (char *) loop_cqr->cpaddr;
+                        nl  += ((loop_cqr->cplength - 10) * 8);
+                        
+                        for (i = 0; i < 20; i += 2) { 
+                                
+                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                                 nl,
+                                                 nl[0], nl[1], nl[2], nl[3],
+                                                 nl[4], nl[5], nl[6], nl[7],
+                                                 nl[8], nl[9], nl[10], nl[11],
+                                                 nl[12], nl[13], nl[14], nl[15]);
+                                
+                                nl += 16;
+                        }
+                        
+                } else { /* log the whole CP */
+                        
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "Channel program (complete):\n");
+                        
+                        for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { 
+                                
+                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                                 nl,
+                                                 nl[0], nl[1], nl[2], nl[3],
+                                                 nl[4], nl[5], nl[6], nl[7],
+                                                 nl[8], nl[9], nl[10], nl[11],
+                                                 nl[12], nl[13], nl[14], nl[15]);
+                                
+                                nl += 16;
+                        }
+                }
+
+                /* log bytes arround failed CCW if not already done */ 
+                begin = (char *) loop_cqr->cpaddr;
+                end   = begin + ((loop_cqr->cplength+4) * 8);
+                nl = (void *)cpa;
+
+                if (loop_cqr == cqr) {  /* log only once */
+ 
+                        if ((loop_cqr->cplength > 40) ||     /* not whole CP was logged or */
+                            ((nl < begin ) &&                /* CCW is outside logged CP   */
+                             (nl > end   )          )   ) {
+                        
+                                nl -= 10*8;     /* start some bytes before */          
+                                
+                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                                 "Failed CCW (%p) (area):\n",
+                                                 (void *)cpa);
+                                
+                                for (i = 0; i < 20; i += 2) { 
+                                        
+                                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                                         "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                                         "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                                         nl,
+                                                         nl[0], nl[1], nl[2], nl[3],
+                                                         nl[4], nl[5], nl[6], nl[7],
+                                                         nl[8], nl[9], nl[10], nl[11],
+                                                         nl[12], nl[13], nl[14], nl[15]);
+                                        
+                                        nl += 16;
+                                }
+                                
+                        } else {
+                                
+                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                                 "Failed CCW (%p) already logged\n",
+                                                 (void *)cpa);
+                        }
+                }
+
+                printk ("%s", page);
+                loop_cqr = loop_cqr->refers;
+        }
+        
+        free_page ((unsigned long) page);
+
+} /* end log_erp_chain */
+#endif /* ERP_DEBUG */
+
+
+/*
+ ***************************************************************************** 
+ * SECTION ERP EXAMINATION
+ ***************************************************************************** 
+ */
 
 /*
  * DASD_3990_ERP_EXAMINE_24 
@@ -52,7 +202,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 +214,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) {
-		return dasd_era_fatal;
+	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 
@@ -107,10 +284,12 @@
  *   dasd_era_recover   for all others.
  */
 dasd_era_t
-dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+dasd_3990_erp_examine (ccw_req_t *cqr, 
+                       devstat_t *stat)
 {
 
-	char *sense = stat->ii.sense.data;
+	char       *sense = stat->ii.sense.data;
+        dasd_era_t era    = dasd_era_recover;
 
 	/* check for successful execution first */
 	if (stat->cstat == 0x00 &&
@@ -118,19 +297,2821 @@
 		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 */
+		era = dasd_3990_erp_examine_24 (sense);
+
+	} else {
 
 		/* examine the 32 byte sense data */
-		return dasd_3990_erp_examine_32 (sense);
+		era = dasd_3990_erp_examine_32 (sense);
+
+	} /* end distinguish between 24 and 32 byte sense data */
+
+#ifdef ERP_DEBUG
+        if (era == dasd_era_fatal) {
+
+                log_erp_chain (cqr, 
+                               0, 
+                               stat->cpa);
+        }
+#endif /* ERP_DEBUG */
+        
+        return era;
+
+} /* 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);
+
+        check_then_set (&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); 
+
+} /* 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;
+        
+        /* get the needed locks to modify the request queue */
+	s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                   flags);
+
+        /* 'restart' the device queue */
+        if (cqr->status == CQR_STATUS_PENDING){
+                
+                DASD_MESSAGE (KERN_INFO, device,
+                              "%s",
+                              "request queue restarted by MIH");
+
+                check_then_set (&cqr->status,
+                                CQR_STATUS_PENDING,
+                                CQR_STATUS_QUEUED);
+        }
+
+        /* release the lock */
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
+                                        flags);
+
+        dasd_schedule_bh(device);
+
+} /* end dasd_3990_erp_restart_queue */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_INT_REQ 
+ *
+ * DESCRIPTION
+ *   Handles 'Intervention Required' error.
+ *   This means either device offline or not installed.
+ *
+ * PARAMETER
+ *   erp                current erp
+ * RETURN VALUES
+ *   erp                modified erp
+ */
+ccw_req_t *
+dasd_3990_erp_int_req (ccw_req_t *erp)
+{
+	dasd_device_t *device = erp->device;
 
+        /* first time set initial retry counter and erp_function */
+        if (erp->function != dasd_3990_erp_int_req) {
+                erp->retries  = 256;
+                erp->function = dasd_3990_erp_int_req;
+        }
+
+        /* issue a message and wait for 'device ready' interrupt */
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "is offline or not installed - "
+                      "INTERVENTION REQUIRED!!\n");
+
+        dasd_3990_erp_block_queue (erp,
+                                   60);
+
+	return erp;
+
+} /* end dasd_3990_erp_int_req */
+#endif /* ERP_FULL_ERP */
+
+/*
+ * 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... */
+		check_then_set (&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 */
+                check_then_set (&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 */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_DCTL
+ *
+ * DESCRIPTION
+ *   Setup cqr to do the Diagnostic Control (DCTL) command with an 
+ *   Inhibit Write subcommand (0x20) and the given modifier.
+ *
+ *  PARAMETER
+ *   erp                pointer to the current ERP
+ *   modifier           subcommand modifier
+ *   
+ * RETURN VALUES
+ *   dctl_cqr           pointer to NEW dctl_cqr 
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_DCTL (ccw_req_t *erp,
+                    char      modifier)
+{
+	DCTL_data_t *DCTL_data;
+        ccw1_t      *ccw;
+        ccw_req_t   *dctl_cqr = dasd_alloc_request ((char *) &erp->magic,
+                                                    1,
+                                                    sizeof(DCTL_data_t));
+        
+	if (dctl_cqr == NULL) {
+		BUG();
+        }
+
+	DCTL_data = dctl_cqr->data;
+
+        DCTL_data->subcommand = 0x02; /* Inhibit Write */
+        DCTL_data->modifier   = modifier;
+
+	ccw = dctl_cqr->cpaddr;
+	memset (ccw, 0, sizeof (ccw1_t));
+        ccw->cmd_code = CCW_CMD_DCTL;
+        ccw->count    = 4;
+        set_normalized_cda(ccw, __pa (DCTL_data));
+
+        dctl_cqr->function = dasd_3990_erp_DCTL;
+        dctl_cqr->refers = erp;
+        dctl_cqr->device = erp->device;
+        dctl_cqr->magic = erp->magic;
+        dctl_cqr->lpm = LPM_ANYPATH;
+        dctl_cqr->expires = 5 * TOD_MIN;
+        dctl_cqr->retries = 2;
+	asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk));
+
+        dctl_cqr->status = CQR_STATUS_FILLED;
+
+	return dctl_cqr;
+
+} /* end dasd_3990_erp_DCTL */
+#endif /* ERP_FULL_ERP */  
+
+/*
+ * 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;
+
+        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; 
+                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,
+                                                   30);
+                        
+                } else {
+                        /* no state change pending - retry */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "no state change pending - retry");
+                        
+                        check_then_set (&erp->status,
+                                        CQR_STATUS_ERROR,
+                                        CQR_STATUS_QUEUED);
+                }
+        }
+
+	return erp;
+
+} /* end dasd_3990_erp_action_4 */
+
+/*
+ ***************************************************************************** 
+ * 24 byte sense ERP functions (only)
+ ***************************************************************************** 
+ */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_ACTION_5 
+ *
+ * DESCRIPTION
+ *   Setup ERP to do the ERP action 5 (see Reference manual).
+ *
+ *  PARAMETER
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_action_5 (ccw_req_t *erp)
+{
+        /* first of all retry */
+        erp->retries = 10;
+        erp->function = dasd_3990_erp_action_5;
+
+        check_then_set (&erp->status,
+                        CQR_STATUS_ERROR,
+                        CQR_STATUS_QUEUED);
+
+        /* further handling is done in xxx_further_erp after the retries */
+
+        return erp;
+
+} /* end dasd_3990_erp_action_5 */
+
+/*
+ * DASD_3990_HANDLE_ENV_DATA
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Enviromental data present'.
+ *   Does a analysis of the sense data (message Format)
+ *   and prints the error messages.
+ *
+ * PARAMETER
+ *   sense              current sense data
+ *   
+ * RETURN VALUES
+ *   void
+ */
+void
+dasd_3990_handle_env_data (char *sense)
+{
+	/* check bytes 7-23 for further information */
+
+	char msg_format = (sense[7] & 0xF0);
+	char msg_no = (sense[7] & 0x0F);
+
+	switch (msg_format) {
+	case 0x00:		/* Format 0 - Program or System Checks */
+
+		if (sense[1] & 0x10) {	/* check message to operator bit */
+
+			switch (msg_no) {
+			case 0x00:	/* No Message */
+				break;
+			case 0x01:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Invalid Command\n");
+				break;
+			case 0x02:
+				printk (KERN_WARNING PRINTK_HEADER
+				     "FORMAT 0 - Invalid Command Sequence\n");
+				break;
+			case 0x03:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - CCW Count less than "
+					"required\n");
+				break;
+			case 0x04:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Invalid Parameter\n");
+				break;
+			case 0x05:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Diagnostic of Sepecial "
+					"Command Violates File Mask\n");
+				break;
+			case 0x07:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Channel Returned with "
+					"Incorrect retry CCW\n");
+				break;
+			case 0x08:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Reset Notification\n");
+				break;
+			case 0x09:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Storage Path Restart\n");
+				break;
+			case 0x0A:
+				printk (KERN_WARNING PRINTK_HEADER
+				    "FORMAT 0 - Channel requested ... %02x\n",
+					sense[8]);
+				break;
+			case 0x0B:
+				printk (KERN_WARNING PRINTK_HEADER
+				     "FORMAT 0 - Invalid Defective/Alternate "
+					"Track Pointer\n");
+				break;
+			case 0x0C:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - DPS Installation Check\n");
+				break;
+			case 0x0E:
+				printk (KERN_WARNING PRINTK_HEADER
+				    "FORMAT 0 - Command Invalid on Secondary "
+					"Address\n");
+				break;
+			case 0x0F:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Status Not As Required: "
+					"reason %02x\n",
+					sense[8]);
+				break;
+			default:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Reseved\n");
+			}
+		} else {
+			switch (msg_no) {
+			case 0x00:	/* No Message */
+				break;
+			case 0x01:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Device Error Source\n");
+				break;
+			case 0x02:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Reserved\n");
+				break;
+			case 0x03:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Device Fenced - device = "
+					"%02x\n",
+					sense[4]);
+				break;
+			case 0x04:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Data Pinned for Device\n");
+				break;
+			default:
+				printk (KERN_WARNING PRINTK_HEADER
+					"FORMAT 0 - Reserved\n");
+			}
+                }
+                break;
+		
+	case 0x10:		/* Format 1 - Device Equipment Checks */
+		switch (msg_no) {
+		case 0x00:	/* No Message */
+			break;
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Device Status 1 not as "
+				"expected\n");
+			break;
+		case 0x03:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Index missing\n");
+			break;
+		case 0x04:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Interruption cannot be reset\n");
+			break;
+		case 0x05:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Device did not respond to "
+				"selection\n");
+			break;
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Device check-2 error or Set "
+				"Sector is not complete\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Head address does not compare\n");
+			break;
+		case 0x08:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Device status 1 not valid\n");
+			break;
+		case 0x09:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Device not ready\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Track physical address did "
+				"not compare\n");
+			break;
+		case 0x0B:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Missing device address bit\n");
+			break;
+		case 0x0C:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Drive motor switch is off\n");
+			break;
+		case 0x0D:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Seek incomplete\n");
+			break;
+		case 0x0E:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Cylinder address did not "
+				"compare\n");
+			break;
+		case 0x0F:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Offset active cannot be reset\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 1 - Reserved\n");
+		}
+                break;		
+                        
+	case 0x20:		/* Format 2 - 3990 Equipment Checks */
+		switch (msg_no) {
+		case 0x08:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 2 - 3990 check-2 error\n");
+			break;
+		case 0x0E:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 2 - Support facility errors\n");
+			break;
+		case 0x0F:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 2 - Microcode detected error %02x\n",
+				sense[8]);
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 2 - Reserved\n");
+		}
+                break;		
+
+	case 0x30:		/* Format 3 - 3990 Control Checks */
+		switch (msg_no) {
+		case 0x0F:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 3 - Allegiance terminated\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 3 - Reserved\n");
+		}
+                break;		
+
+	case 0x40:		/* Format 4 - Data Checks */
+		switch (msg_no) {
+		case 0x00:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Home address area error\n");
+			break;
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Count area error\n");
+			break;
+		case 0x02:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Key area error\n");
+			break;
+		case 0x03:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Data area error\n");
+			break;
+		case 0x04:
+			printk (KERN_WARNING PRINTK_HEADER
+			    "FORMAT 4 - No sync byte in home address area\n");
+			break;
+		case 0x05:
+			printk (KERN_WARNING PRINTK_HEADER
+			    "FORMAT 4 - No syn byte in count address area\n");
+			break;
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - No sync byte in key area\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - No syn byte in data area\n");
+			break;
+		case 0x08:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Home address area error; "
+				"offset active\n");
+			break;
+		case 0x09:
+			printk (KERN_WARNING PRINTK_HEADER
+			      "FORMAT 4 - Count area error; offset active\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Key area error; offset active\n");
+			break;
+		case 0x0B:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Data area error; offset active\n");
+			break;
+		case 0x0C:
+			printk (KERN_WARNING PRINTK_HEADER
+			      "FORMAT 4 - No sync byte in home address area; "
+				"offset active\n");
+			break;
+		case 0x0D:
+			printk (KERN_WARNING PRINTK_HEADER
+			      "FORMAT 4 - No syn byte in count address area; "
+				"offset active\n");
+			break;
+		case 0x0E:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - No sync byte in key area; "
+				"offset active\n");
+			break;
+		case 0x0F:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - No syn byte in data area; "
+				"offset active\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 4 - Reserved\n");
+		}
+                break;		
+
+	case 0x50:		/* Format 5 - Data Check with displacement information */
+		switch (msg_no) {
+		case 0x00:
+			printk (KERN_WARNING PRINTK_HEADER
+			  "FORMAT 5 - Data Check in the home address area\n");
+			break;
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Data Check in the count area\n");
+			break;
+		case 0x02:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Data Check in the key area\n");
+			break;
+		case 0x03:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Data Check in the data area\n");
+			break;
+		case 0x08:
+			printk (KERN_WARNING PRINTK_HEADER
+			    "FORMAT 5 - Data Check in the home address area; "
+				"offset active\n");
+			break;
+		case 0x09:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Data Check in the count area; "
+				"offset active\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Data Check in the key area; "
+				"offset active\n");
+			break;
+		case 0x0B:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Data Check in the data area; "
+				"offset active\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 5 - Reserved\n");
+		}
+                break;		
+
+	case 0x60:		/* Format 6 - Usage Statistics/Overrun Errors */
+		switch (msg_no) {
+		case 0x00:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel A\n");
+			break;
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel B\n");
+			break;
+		case 0x02:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel C\n");
+			break;
+		case 0x03:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel D\n");
+			break;
+		case 0x04:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel E\n");
+			break;
+		case 0x05:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel F\n");
+			break;
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel G\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Overrun on channel H\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 6 - Reserved\n");
+		}
+                break;		
+
+	case 0x70:		/* Format 7 - Device Connection Control Checks */
+		switch (msg_no) {
+		case 0x00:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - RCC initiated by a connection "
+				"check alert\n");
+			break;
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - RCC 1 sequence not successful\n");
+			break;
+		case 0x02:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - RCC 1 and RCC 2 sequences not "
+				"successful\n");
+			break;
+		case 0x03:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Invalid tag-in during selection "
+				"sequence\n");
+			break;
+		case 0x04:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - extra RCC required\n");
+			break;
+		case 0x05:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Invalid DCC selection response "
+				"or timeout\n");
+			break;
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Missing end operation; device "
+				"transfer complete\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Missing end operation; device "
+				"transfer incomplete\n");
+			break;
+		case 0x08:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Invalid tag-in for an immediate "
+				"command sequence\n");
+			break;
+		case 0x09:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Invalid tag-in for an extended "
+				"command sequence\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - 3990 microcode time out when "
+				"stopping selection\n");
+			break;
+		case 0x0B:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - No response to selection after "
+				"a poll interruption\n");
+			break;
+		case 0x0C:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Permanent path error (DASD "
+				"controller not available)\n");
+			break;
+		case 0x0D:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - DASD controller not available on "
+				"disconnected command chain\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 7 - Reserved\n");
+		}
+                break;		
+
+	case 0x80:		/* Format 8 - Additional Device Equipment Checks */
+		switch (msg_no) {
+		case 0x00:	/* No Message */
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - Error correction code hardware "
+				"fault\n");
+			break;
+		case 0x03:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - Unexpected end operation response "
+				"code\n");
+			break;
+		case 0x04:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - End operation with transfer count "
+				"not zero\n");
+			break;
+		case 0x05:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - End operation with transfer "
+				"count zero\n");
+			break;
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+			      "FORMAT 8 - DPS checks after a system reset or "
+				"selective reset\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - DPS cannot be filled\n");
+			break;
+		case 0x08:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - Short busy time-out during device "
+				"selection\n");
+			break;
+		case 0x09:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - DASD controller failed to set or "
+				"reset the long busy latch\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+			      "FORMAT 8 - No interruption from device during "
+				"a command chain\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 8 - Reserved\n");
+		}
+                break;		
+
+	case 0x90:		/* Format 9 - Device Read, Write, and Seek Checks */
+		switch (msg_no) {
+		case 0x00:
+			break;	/* No Message */
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 9 - Device check-2 error\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 9 - Head address did not compare\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 9 - Track physical address did not "
+				"compare while oriented\n");
+			break;
+		case 0x0E:
+			printk (KERN_WARNING PRINTK_HEADER
+			     "FORMAT 9 - Cylinder address did not compare\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT 9 - Reserved\n");
+		}
+                break;		
+
+	case 0xF0:		/* Format F - Cache Storage Checks */
+		switch (msg_no) {
+		case 0x00:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Operation Terminated\n");
+			break;
+		case 0x01:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Subsystem Processing Error\n");
+			break;
+		case 0x02:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Cache or nonvolatile storage "
+				"equipment failure\n");
+			break;
+		case 0x04:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Caching terminated\n");
+			break;
+		case 0x06:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Cache fast write access not "
+				"authorized\n");
+			break;
+		case 0x07:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Track format incorrect\n");
+			break;
+		case 0x09:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Caching reinitiated\n");
+			break;
+		case 0x0A:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Nonvolatile storage terminated\n");
+			break;
+		case 0x0B:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Volume is suspended duplex\n");
+			break;
+		case 0x0C:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - Subsystem status connot be "
+				"determined\n");
+			break;
+		case 0x0D:
+			printk (KERN_WARNING PRINTK_HEADER
+			      "FORMAT F - Caching status reset to default\n");
+			break;
+		case 0x0E:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT F - DASD Fast Write inhibited\n");
+			break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"FORMAT D - Reserved\n");
+		}
+                break;		
+
+	default:		/* unknown message format - should not happen */
+
+	} /* end switch message format */
+
+} /* end dasd_3990_handle_env_data */
+
+/*
+ * DASD_3990_ERP_COM_REJ
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Command Reject' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ *   sense              current sense data
+ * 
+ * RETURN VALUES
+ *   erp                'new' erp_head - pointer to new ERP 
+ */
+ccw_req_t *
+dasd_3990_erp_com_rej (ccw_req_t *erp,
+		       char      *sense)
+{
+	dasd_device_t *device = erp->device;
+        ccw_req_t     *cqr    = NULL;
+
+        erp->function = dasd_3990_erp_com_rej;
+
+	/* env data present (ACTION 10 - retry should work) */
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Command Reject - environmental data present\n");
+
+		dasd_3990_handle_env_data (sense);
+
+		erp->retries = 5;
+
+	} else {
+		/* fatal error -  set status to FAILED */
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Command Reject - Fatal error\n");
+
+                cqr = erp->refers;
+
+                dasd_free_request (erp);
+
+                erp = cqr;
+
+ 		check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_com_rej */
+
+/*
+ * DASD_3990_ERP_BUS_OUT 
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Bus Out Parity Check' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_bus_out (ccw_req_t *erp)
+{
+	dasd_device_t *device = erp->device;
+
+        /* first time set initial retry counter and erp_function */
+        if (erp->function != dasd_3990_erp_bus_out) {
+                erp->retries  = 256;
+                erp->function = dasd_3990_erp_bus_out;
+        }
+
+        /* issue a message and wait for 'device ready' interrupt */
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "bus out parity error or BOPC requested by channel\n");
+
+        dasd_3990_erp_block_queue (erp,
+                                   60);
+
+	return erp;
+
+} /* end dasd_3990_erp_bus_out */
+#endif /* ERP_FULL_ERP */
+
+/*
+ * 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;
+
+#ifdef ERP_FULL_ERP
+	if (sense[1] & SNS1_WRITE_INHIBITED) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Write inhibited path encountered");
+
+		/* vary path offline */
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Path should be varied off-line. "
+                              "This is not implemented yet \n - please report to "
+                              "linux390@de.ibm.com");
+
+		erp = dasd_3990_erp_action_1 (erp);
+
+	} else 
+#endif /* ERP_FULL_ERP */
+                if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+                        
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "Equipment Check - "
+                                      "environmental data present");
+#ifdef ERP_FULL_ERP
+                        dasd_3990_handle_env_data (sense);
+#endif /* ERP_FULL_ERP */
+                        
+                        erp = dasd_3990_erp_action_4 (erp,
+                                                      sense);
+
+#ifdef ERP_FULL_ERP
+                } else if (sense[1] & SNS1_PERM_ERR) {
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "Equipment Check - retry exhausted or "
+                                      "undesirable\n");
+                        
+                        erp = dasd_3990_erp_action_1 (erp);
+                        
+                } else {
+                        /* all other equipment checks - Action 5 */
+                        /* rest is done when retries == 0 */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "Equipment check or processing error\n");
+                        
+                        erp = dasd_3990_erp_action_5 (erp);
+#endif /* ERP_FULL_ERP */
+                }
+        
+        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;
+
+#ifdef ERP_FULL_ERP
+	if (sense[2] & SNS2_CORRECTABLE) {	/* correctable data check */
+
+		/* issue message that the data has been corrected */
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Data recovered during retry with PCI "
+                              "fetch mode active\n");
+
+                /* not possible to handle this situation in Linux */    
+                panic("No way to inform appliction about the possibly "
+                      "incorret data");
+
+	} else 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);
+
+	} else if (sense[1] & SNS1_PERM_ERR) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Uncorrectable data check with internal "
+                              "retry exhausted\n");
+
+		erp = dasd_3990_erp_action_1 (erp);
+
+	} else {
+		/* all other data checks */
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Uncorrectable data check with retry count "
+                              "exhausted...\n");
+
+		erp = dasd_3990_erp_action_5 (erp);
+	}
+
+#else
+	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);
+	}
+#endif /* ERP_FULL_ERP */
+
+	return erp;
+
+} /* end dasd_3990_erp_data_check */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_OVERRUN
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Overrun' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_overrun (ccw_req_t *erp,
+		       char      *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_overrun;
+
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Overrun - service overrun or overrun"
+                      " error requested by channel\n");
+
+        erp = dasd_3990_erp_action_5 (erp);
+
+	return erp;
+
+} /* end dasd_3990_erp_overrun */
+#endif /* ERP_FULL_ERP */
+
+/*
+ * 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");
+
+#ifdef ERP_FULL_ERP
+		dasd_3990_handle_env_data (sense);
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+
+	} else {
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Invalid Track Format - Fatal error should have "
+                              "been handled within the interrupt handler\n");
+
+		check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+        }
+#else
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+#endif /* ERP_FULL_ERP */
+
+	return erp;
+
+} /* end dasd_3990_erp_inv_format */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_EOC
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'End-of-Cylinder' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_EOC (ccw_req_t *erp,
+		   char      *sense)
+{
+
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_EOC;
+
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "End-of-Cylinder - must never happen\n");
+
+        /* implement action 7 */
+        BUG();
+
+	return erp;
+
+} /* end dasd_3990_erp_EOC */
+#endif /* ERP_FULL_ERP */  
+
+/*
+ * 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");
+#ifdef ERP_FULL_ERP
+        dasd_3990_handle_env_data (sense);
+#endif /* ERP_FULL_ERP */  
+
+	erp = dasd_3990_erp_action_4 (erp,
+				      sense);
+
+	return erp;
+
+} /* end dasd_3990_erp_env_data */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_NO_REC
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'No Record Found' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_no_rec (ccw_req_t *erp,
+		      char      *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_no_rec;
+        
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "No Record Found - Fatal error should "
+                      "have been handled within the interrupt handler\n");
+        
+        check_then_set (&erp->status,
+                        CQR_STATUS_ERROR,
+                        CQR_STATUS_FAILED);
+
+	return erp;
+
+} /* end dasd_3990_erp_no_rec */
+
+/*
+ * DASD_3990_ERP_FILE_PROT
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'File Protected' error.
+ *   Note: Seek related recovery is not implemented because
+ *         wee don't use the seek command yet.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_file_prot (ccw_req_t *erp)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_file_prot;
+
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "File Protected\n");
+
+        check_then_set (&erp->status,
+                        CQR_STATUS_ERROR,
+                        CQR_STATUS_FAILED);
+
+	return erp;
+
+} /* end dasd_3990_erp_file_prot */
+#endif /* ERP_FULL_ERP */  
+
+/*
+ * 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;
+	dasd_device_t *device = erp->device;
+
+	/* Check sense for ....    */
+#ifdef ERP_FULL_ERP
+	/* 'Command Reject'        */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_CMD_REJECT)) {
+		erp_filled = dasd_3990_erp_com_rej (erp,
+						    sense);
+	}
+	/* 'Intervention Required' */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_INTERVENTION_REQ)) {
+		erp_filled = dasd_3990_erp_int_req (erp);
+	}
+	/* 'Bus Out Parity Check'  */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_BUS_OUT_CHECK)) {
+		erp_filled = dasd_3990_erp_bus_out (erp);
+	}
+#endif /* ERP_FULL_ERP */  
+	/* '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);
+	}
+#ifdef ERP_FULL_ERP
+	/* 'Overrun'               */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_OVERRUN)) {
+		erp_filled = dasd_3990_erp_overrun (erp,
+						    sense);
+	}
+#endif /* ERP_FULL_ERP */  
+	/* 'Invalid Track Format'  */
+	if ((erp_filled == NULL) &&
+	    (sense[1] & SNS1_INV_TRACK_FORMAT)) {
+		erp_filled = dasd_3990_erp_inv_format (erp,
+						       sense);
+	}
+#ifdef ERP_FULL_ERP
+	/* 'End-of-Cylinder'       */
+	if ((erp_filled == NULL) &&
+	    (sense[1] & SNS1_EOC)) {
+		erp_filled = dasd_3990_erp_EOC (erp,
+						sense);
+	}
+#endif /* ERP_FULL_ERP */  
+	/* 'Environmental Data'    */
+	if ((erp_filled == NULL) &&
+	    (sense[2] & SNS2_ENV_DATA_PRESENT)) {
+		erp_filled = dasd_3990_erp_env_data (erp,
+						     sense);
+	}
+#ifdef ERP_FULL_ERP
+	/* 'No Record Found'       */
+	if ((erp_filled == NULL) &&
+	    (sense[1] & SNS1_NO_REC_FOUND)) {
+		erp_filled = dasd_3990_erp_no_rec (erp,
+						   sense);
+	}
+	/* 'File Protected'        */
+	if ((erp_filled == NULL) &&
+	    (sense[1] & SNS1_FILE_PROTECTED)) {
+		erp_filled = dasd_3990_erp_file_prot (erp);
+	}
+#endif /* ERP_FULL_ERP */  
+
+	/* other (unknown) error - do default ERP                     */
+	if (erp_filled == NULL) {
+
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "default ERP taken");
+
+		erp_filled = erp;	
+	}
+
+	return erp_filled;
+
+} /* END dasd_3990_erp_inspect_24 */
+
+/*
+ ***************************************************************************** 
+ * 32 byte sense ERP functions (only)
+ ***************************************************************************** 
+ */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERPACTION_10_32 
+ *
+ * DESCRIPTION
+ *   Handles 32 byte 'Action 10' of Single Program Action Codes.
+ *   Just retry and if retry doesn't work, return with error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ *   sense              current sense data 
+ * RETURN VALUES
+ *   erp                modified erp_head
+ */
+ccw_req_t *
+dasd_3990_erp_action_10_32 (ccw_req_t *erp,
+                            char      *sense)
+{
+	dasd_device_t *device = erp->device;
+
+        erp->retries  = 256;
+        erp->function = dasd_3990_erp_action_10_32;
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Perform logging requested\n");
+
+	return erp;
+
+} /* end dasd_3990_erp_action_10_32 */
+#endif /* ERP_FULL_ERP */  
+
+/*
+ * 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 imprecise ending or error
+ */
+ccw_req_t *
+dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
+                            char      *sense)
+{
+	dasd_device_t  *device = default_erp->device;
+        __u32          cpa     = 0;
+        ccw_req_t      *cqr;
+	ccw_req_t      *erp;
+	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");
+        
+        default_erp->function = dasd_3990_erp_action_1B_32;
+
+        /* determine the original cqr */
+        cqr = default_erp; 
+        while (cqr->refers != NULL){
+                cqr = cqr->refers;
+        }
+
+        /* for imprecise ending just do default erp */
+        if (sense[1] & 0x01) {
+
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Imprecise ending is set - just retry");
+
+                return default_erp;
+        } 
+         
+        /* determine the address of the CCW to be restarted */
+        /* Imprecise ending is not set -> addr from IRB-SCSW */
+        cpa = default_erp->refers->dstat->cpa;    
+        
+        if (cpa == 0) {
+                
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Unable to determine address of the CCW "
+                              "to be restarted");
+                
+                check_then_set (&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");
+                
+                check_then_set (&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. */
+        }
+
+        if ((sense[7] & 0x3F) == 0x01) {
+                /* operation code is WRITE DATA -> data area orientation */
+                LO_data[0] = 0x81;
+
+        } else if ((sense[7] & 0x3F) == 0x03) {
+                /* operation code is FORMAT WRITE -> index orientation */
+                LO_data[0] = 0xC3;
+
+        } else {
+                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;
+	set_normalized_cda (ccw, __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;
+	set_normalized_cda (ccw, __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  = 255;
+	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_UPDATE_1B
+ *
+ * DESCRIPTION
+ *   Handles the update to the 32 byte 'Action 1B' of Single Program 
+ *   Action Codes in case the first action was not successful.
+ *   The already created 'previous_erp' is the currently not successful
+ *   ERP. 
+ *
+ * PARAMETER
+ *   previous_erp       already created previous erp.
+ *   sense              current sense data 
+ * RETURN VALUES
+ *   erp                modified erp 
+ */
+ccw_req_t *
+dasd_3990_update_1B (ccw_req_t *previous_erp,
+                     char      *sense)
+{
+	dasd_device_t  *device = previous_erp->device;
+        __u32          cpa     = 0;
+        ccw_req_t      *cqr;
+	ccw_req_t      *erp;
+	char           *LO_data;   /* LO_eckd_data_t */
+        ccw1_t         *ccw;
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Write not finsihed because of unexpected condition"
+                      " - follow on");
+        
+        /* determine the original cqr */
+        cqr = previous_erp; 
+        while (cqr->refers != NULL){
+                cqr = cqr->refers;
+        }
+         
+        /* for imprecise ending just do default erp */
+        if (sense[1] & 0x01) {
+
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Imprecise ending is set - just retry");
+
+                check_then_set (&previous_erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_QUEUED);
+
+                return previous_erp;
+        } 
+         
+        /* determine the address of the CCW to be restarted */
+        /* Imprecise ending is not set -> addr from IRB-SCSW */
+        cpa = previous_erp->dstat->cpa;    
+        
+        if (cpa == 0) {
+                ccw = cqr->cpaddr;   /* addr of first data transfer */
+                ccw++;               /* command in domain           */
+                ccw++;
+                cpa = (__u32) ccw; 
+        }
+        
+        if (cpa == 0) {
+                
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Unable to determine address of the CCW "
+                              "to be restarted");
+                
+                check_then_set (&previous_erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+                
+                return previous_erp;
+        }
+        
+        erp = previous_erp;
+
+	/* update the LO with the new returned sense data  */
+	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. */
+        }
+
+        if ((sense[7] & 0x3F) == 0x01) {
+                /* operation code is WRITE DATA -> data area orientation */
+                LO_data[0] = 0x81;
+
+        } else if ((sense[7] & 0x3F) == 0x03) {
+                /* operation code is FORMAT WRITE -> index orientation */
+                LO_data[0] = 0xC3;
+
+        } else {
+                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);   
+
+        /* TIC to the failed ccw */
+        ccw = erp->cpaddr;  /* addr of DE ccw */
+        ccw++;              /* addr of LE ccw */
+        ccw++;              /* addr of TIC ccw */ 
+	ccw->cda = cpa;
+
+	check_then_set (&erp->status,
+                        CQR_STATUS_ERROR,
+                        CQR_STATUS_QUEUED);
+        
+	return erp;
+        
+} /* end dasd_3990_update_1B */
+
+#ifdef ERP_FULL_ERP
+/*
+ * DASD_3990_ERP_COMPOUND_RETRY 
+ *
+ * DESCRIPTION
+ *   Handles the compound ERP action retry code.
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created ERP
+ *
+ * RETURN VALUES
+ *   erp                modified ERP pointer
+ *
+ */
+void
+dasd_3990_erp_compound_retry (ccw_req_t *erp,
+                              char      *sense)
+{
+        switch (sense[25] & 0x03) { 
+        case 0x00:	/* no not retry */
+                erp->retries = 0;
+                break;
+                
+        case 0x01:	/* retry 2 times */
+                erp->retries = 2;
+
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_QUEUED);
+                break;
+                
+        case 0x02:	/* retry 10 times */
+                erp->retries = 10;
+
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_QUEUED);
+                break;
+                
+        case 0x03:	/* retry 255 times */
+                erp->retries = 255;
+
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_QUEUED);
+                break;
+                
+        default:
+                BUG();
+        }
+
+        erp->function = dasd_3990_erp_compound_retry;
+
+} /* end dasd_3990_erp_compound_retry */
+
+/*
+ * DASD_3990_ERP_COMPOUND_PATH 
+ *
+ * DESCRIPTION
+ *   Handles the compound ERP action for retry on alternate
+ *   channel path.
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created ERP
+ *
+ * RETURN VALUES
+ *   erp                modified ERP pointer
+ *
+ */
+void
+dasd_3990_erp_compound_path (ccw_req_t *erp,
+                             char      *sense)
+{
+
+        if (sense[25] & DASD_SENSE_BIT_3) {
+                dasd_3990_erp_alternate_path (erp);
+                
+                if (erp->status == CQR_STATUS_FAILED) {
+                        /* reset the lpm and the status to be able to 
+                         * try further actions. */
+        
+                        erp->lpm = LPM_ANYPATH;
+                        
+                        check_then_set (&erp->status,
+                                        CQR_STATUS_FAILED,
+                                        CQR_STATUS_ERROR);
+                        
+                }
+        }
+        
+        erp->function = dasd_3990_erp_compound_path;
+
+} /* end dasd_3990_erp_compound_path */
+
+/*
+ * DASD_3990_ERP_COMPOUND_CODE 
+ *
+ * DESCRIPTION
+ *   Handles the compound ERP action for retry code.
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created ERP
+ *
+ * RETURN VALUES
+ *   erp                NEW ERP pointer
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_compound_code (ccw_req_t *erp,
+                             char      *sense)
+{
+
+        
+        if (sense[25] & DASD_SENSE_BIT_2) {
+
+                switch (sense[28]) {
+                case 0x17:
+                        /* issue a Diagnostic Control command with an 
+                         * Inhibit Write subcommand and controler modifier */
+                        erp = dasd_3990_erp_DCTL (erp,
+                                                  0x20);
+                        break;
+                        
+                case 0x25:
+                        /* wait for 5 seconds and retry again */
+                        erp->retries = 1;
+                        
+                        dasd_3990_erp_block_queue (erp,
+                                                   5);
+                        break;
+                        
+                default:
+                        BUG();
+                }
+        }
+
+        erp->function = dasd_3990_erp_compound_code;
+
+        return erp;
+
+} /* end dasd_3990_erp_compound_code */
+
+/*
+ * DASD_3990_ERP_COMPOUND_CONFIG 
+ *
+ * DESCRIPTION
+ *   Handles the compound ERP action for configruation
+ *   dependent error.
+ *   Note: duplex handling is not implemented (yet).
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created ERP
+ *
+ * RETURN VALUES
+ *   erp                modified ERP pointer
+ *
+ */
+void
+dasd_3990_erp_compound_config (ccw_req_t *erp,
+                               char      *sense)
+{
+        if ((sense[25] & DASD_SENSE_BIT_1) && 
+            (sense[26] & DASD_SENSE_BIT_2)   ) {	
+
+                /* set to suspended duplex state then restart */
+                dasd_device_t *device  = erp->device;
+
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",      
+                              "Set device to suspended duplex state should be done!\n"
+                              "This is not implemented yet (for compound ERP)\n"
+                              " - please report to linux390@de.ibm.com");
+                
+        }
+
+        erp->function = dasd_3990_erp_compound_config;
+
+} /* end dasd_3990_erp_compound_config */
+
+/*
+ * DASD_3990_ERP_COMPOUND 
+ *
+ * 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 ERP
+ *
+ * RETURN VALUES
+ *   erp                (additional) ERP pointer
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_compound (ccw_req_t *erp,
+                        char      *sense)
+{
+        if ((erp->function != dasd_3990_erp_compound_retry ) &&
+            (erp->function != dasd_3990_erp_compound_path  ) &&
+            (erp->function != dasd_3990_erp_compound_code  ) &&
+            (erp->function != dasd_3990_erp_compound_config)   ) {
+
+                /* called first time */
+                dasd_3990_erp_compound_retry (erp,
+                                              sense);
+        }
+        
+        /* do further action if no retry is specified / left */
+        if ((erp->function == dasd_3990_erp_compound_retry) &&
+            (erp->status   == CQR_STATUS_ERROR            )   ){
+                
+                dasd_3990_erp_compound_path (erp,
+                                             sense);
+        }
+
+        if ((erp->function == dasd_3990_erp_compound_path) &&
+            (erp->status   == CQR_STATUS_ERROR           )   ){
+
+                erp = dasd_3990_erp_compound_code (erp,
+                                                   sense);
+        }
+
+        if ((erp->function == dasd_3990_erp_compound_code) && 
+            (erp->status   == CQR_STATUS_ERROR           )   ){
+                
+                dasd_3990_erp_compound_config (erp,
+                                               sense);
+        }
+
+        /* if no compound action ERP specified, the request failed */
+        if (erp->status == CQR_STATUS_ERROR) {
+
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+        }
+
+        return erp;
+        
+} /* end dasd_3990_erp_compound */
+#endif /* ERP_FULL_ERP */  
+
+/*
+ * 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') */
+#ifdef ERP_FULL_ERP
+                erp = dasd_3990_erp_compound (erp,
+                                              sense);
+#else
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "default ERP taken");
+#endif /* ERP_FULL_ERP */  
+
+	} else {
+
+		/* single program action codes (byte25 bit 0 == '0') */
+		switch (sense[25]) {
+#ifdef ERP_FULL_ERP
+		case 0x00:	/* success */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "ERP called for successful request %p"
+                                      " - NO ERP necessary",
+                                      erp);
+
+                        check_then_set (&erp->status,
+                                        CQR_STATUS_ERROR,
+                                        CQR_STATUS_DONE);
+                        break;
+                        
+		case 0x01:	/* fatal error */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "Fatal error should "
+                                      "have been handled within the interrupt handler\n");
+
+                        check_then_set (&erp->status,
+                                        CQR_STATUS_ERROR,
+                                        CQR_STATUS_FAILED);
+                        break;
+
+		case 0x02:	/* intervention required */
+		case 0x03:	/* intervention required during dual copy */
+                        erp = dasd_3990_erp_int_req (erp);
+                        break;
+
+		case 0x0F:	/* length mismatch during update write command */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "update write command error - should not happen; "
+                                      "Please send this message together with the above "
+                                      "sense data to linux390@de.ibm.com\n");
+
+                        check_then_set (&erp->status,
+                                        CQR_STATUS_ERROR,
+                                        CQR_STATUS_FAILED);
+                        break;
+
+		case 0x10:	/* logging required for other channel program */
+                        erp = dasd_3990_erp_action_10_32 (erp,
+                                                    sense);
+                        break;
+
+		case 0x15:	/* next track outside defined extend */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "next track outside defined extend - should not happen; "
+                                      "Please send this message together with the above "
+                                      "sense data to linux390@de.ibm.com\n");
+
+                        check_then_set (&erp->status,
+                                        CQR_STATUS_ERROR,
+                                        CQR_STATUS_FAILED);
+                        break;
+#endif /* ERP_FULL_ERP */  
+
+		case 0x1B:	/* unexpected condition during write */
+
+                        erp = dasd_3990_erp_action_1B_32 (erp,
+                                                          sense);
+                        break;
+
+#ifdef ERP_FULL_ERP
+		case 0x1C:	/* invalid data */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "Data recovered during retry with PCI "
+                                      "fetch mode active\n");
+                        
+                        /* not possible to handle this situation in Linux */    
+                        panic("No way to inform appliction about the possibly "
+                              "incorret data");
+			break;
+#endif /* ERP_FULL_ERP */  
+
+		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);
+			break;
+
+		default:	/* all others errors */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "default ERP taken");
+		}
+	}
+
+	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;
+
+	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 */
+        if (erp != NULL) {
+                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 */
+                printk(KERN_WARNING PRINTK_HEADER 
+                       "_error_match: CCW doesn't match -> ignore\n");
+	}
+	/* 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 occurred.
+ */
+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) {
+		return erp_match;	/* return address of matching erp */
+	} else {
+		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;
+        
+#ifdef ERP_FULL_ERP
+        /* check for 24 byte sense ERP */
+	if ((erp->function == dasd_3990_erp_bus_out ) ||
+            (erp->function == dasd_3990_erp_action_1) ||
+            (erp->function == dasd_3990_erp_action_4)   ){
+                
+                erp = dasd_3990_erp_action_1 (erp);
+                
+	} else if (erp->function == dasd_3990_erp_action_5) {
+                
+                /* retries have not been successful */
+                char *sense = erp->dstat->ii.sense.data;
+                
+                /* prepare erp for retry on different channel path */
+                erp = dasd_3990_erp_action_1 (erp);
+                
+                if (!(sense[ 2] & DASD_SENSE_BIT_0)) {
+
+                        /* issue a Diagnostic Control command with an 
+                         * Inhibit Write subcommand */
+
+                        switch (sense[25]) {
+                        case 0x17:
+                        case 0x57: { /* controller */
+                                erp = dasd_3990_erp_DCTL (erp,
+                                                          0x20);
+                                break;
+                        }
+                        case 0x18:
+                        case 0x58: { /* channel path */
+                                erp = dasd_3990_erp_DCTL (erp,
+                                                          0x40);
+                                break;
+                        }
+                        case 0x19:
+                        case 0x59: { /* storage director */
+                                erp = dasd_3990_erp_DCTL (erp,
+                                                          0x80);
+                                break;
+                        }
+                        default:
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "invalid subcommand modifier 0x%x for "
+                                              "Diagnostic Control Command",
+                                              sense[25]);
+                        }
+                } 
+
+//        /* check for 32 byte sense ERP */
+//	} else if ((erp->function == dasd_3990_erp_xxx){
+#else
+        /* 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);
+#endif /* ERP_FULL_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);
+
+		check_then_set (&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 occurred 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;
+        ccw_req_t     *erp_free = NULL;      /* req to be freed */    
+
+	/* loop over successful ERPs and remove them from chanq */
+	while ((erp_done != erp_match) &&
+	       (erp_done != NULL)) {
+
+#ifdef ERP_DEBUG
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "successful ERP - dequeue and free request %p",
+                              (void *) erp_done);
+#endif /* ERP_DEBUG */
+
+		check_then_set (&erp_done->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_DONE);
+
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,
+				erp_done);
+
+                erp_free = erp_done;
+		erp_done = erp_done->refers;
+                
+		/* free the finished erp request */
+		dasd_free_request (erp_free);
+
+	}
+
+	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 */
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "handle matching erp %p",
+                      (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 if (erp_done->function == dasd_3990_erp_action_1B_32) {
+                        char *sense = erp_done->dstat->ii.sense.data;
+                        erp_done = dasd_3990_update_1B (erp_done,
+                                                        sense);
+
+#ifdef ERP_FULL_ERP
+                } else if (erp_done->function == dasd_3990_erp_int_req) {
+                        erp_done = dasd_3990_erp_int_req (erp_done);
+#endif /* ERP_FULL_ERP */  
+                        
+                } else {
+                        /* simple retry   */
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%i retries left for erp %p",
+                                      erp_done->retries,
+                                      (void *) erp_done);
+                        
+                        /* handle the request again... */
+                        check_then_set (&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 
+        __u32 cpa = cqr->dstat->cpa;    
+#endif /* ERP_DEBUG */
+
+#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 */
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "ERP chain at BEGINNING of ERP-ACTION");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = cqr; 
+                     temp_erp != NULL; 
+                     temp_erp = temp_erp->refers){
+
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "      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);
+                
+                check_then_set (&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);
+
+                check_then_set (&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 */
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "ERP chain at END of ERP-ACTION");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = erp; 
+                     temp_erp != NULL; 
+                     temp_erp = temp_erp->refers){
+
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "      erp %p refers to %p \n",
+                                      temp_erp,
+                                      temp_erp->refers);
+                }
+        }
+#endif /* ERP_DEBUG */
+
+#ifdef ERP_DEBUG
+        if (erp->status == CQR_STATUS_FAILED) {
+                log_erp_chain (erp, 1, cpa);
+        }
+#endif /* ERP_DEBUG */
 
-	}			/* 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 --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_3990_erp.h linux/drivers/s390/block/dasd_3990_erp.h
--- v2.4.3/linux/drivers/s390/block/dasd_3990_erp.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_3990_erp.h	Wed Apr 11 19:02:28 2001
@@ -1,17 +1,28 @@
-ccw_req_t *dasd_3990_erp_com_rej (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_int_req (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_bus_out (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_equip_check (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_data_check (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_overrun (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_inv_format (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_EOC (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_env_data (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_no_rec (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_file_prot (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_perm (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_first_log (ccw_req_t *, devstat_t *);
-ccw_req_t *dasd_3990_erp_add_erp (ccw_req_t *, devstat_t *);	/* tbd - delete */
+/* 
+ * 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 July 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);
+
+typedef struct DCTL_data_t {
+	unsigned char  subcommand;  /* e.g Inhibit Write, Enable Write,... */
+	unsigned char  modifier;    /* Subcommand modifier                 */
+	unsigned short res;	    /* reserved */
+} __attribute__ ((packed)) DCTL_data_t;
+
+
+#endif /* DASD_3990_ERP_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_9343_erp.h linux/drivers/s390/block/dasd_9343_erp.h
--- v2.4.3/linux/drivers/s390/block/dasd_9343_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_9343_erp.h	Wed Apr 11 19:02:28 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 --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c
--- v2.4.3/linux/drivers/s390/block/dasd_diag.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_diag.c	Wed Apr 11 19:02:28 2001
@@ -10,6 +10,8 @@
  * 07/13/00 Added fixup sections for diagnoses ans saved some registers
  * 07/14/00 fixed constraints in newly generated inline asm
  * 10/05/00 adapted to 'new' DASD driver
+ *          fixed return codes of dia250()
+ *          fixed partition handling and HDIO_GETGEO
  */
 
 #include <linux/stddef.h>
@@ -73,10 +75,11 @@
 static __inline__ int
 dia250 (void *iob, int cmd)
 {
-	int rc;
-
-	__asm__ __volatile__ ("    lr    1,%1\n"
-			      "    diag  1,%2,0x250\n"
+ 	__asm__ __volatile__ ("    lr    0,%1\n"
+                              "    diag  0,%0,0x250\n"
+                              "0:  ipm   %0\n"
+                              "    srl   %0,28\n"
+ 			      "    or    %0,1\n"
 			      "1:\n"
 			      ".section .fixup,\"ax\"\n"
 			      "2:  lhi   %0,3\n"
@@ -87,12 +90,12 @@
 			      ".previous\n"
 			      ".section __ex_table,\"a\"\n"
 			      "    .align 4\n"
-			      "    .long 1b,2b\n"
-			      ".previous\n"
-			      :"=d"   (rc)
-			      :"d"    ((void *) __pa (iob)), "0" (cmd)
-			      :"1");
-	return rc;
+                              "    .long 0b,2b\n"
+                              ".previous\n"
+                              : "+d" (cmd)
+                              : "d" ((void *) __pa (iob))
+                              : "0", "1", "cc" );
+ 	return cmd;
 }
 
 static __inline__ int
@@ -112,7 +115,7 @@
 
 	rc = dia250 (iib, INIT_BIO);
 
-	return rc;
+	return rc&3;
 }
 
 static __inline__ int
@@ -125,7 +128,7 @@
 	memset (iib, 0, sizeof (diag_init_io_t));
 	iib->dev_nr = device->devinfo.devno;
 	rc = dia250 (iib, TERM_BIO);
-	return rc;
+	return rc&3;
 }
 
 int
@@ -153,7 +156,12 @@
 		check_then_set (&cqr->status,
 					       CQR_STATUS_QUEUED,
 					       CQR_STATUS_ERROR);
-	} else {
+        } else if (rc == 0 ) {                                     
+               check_then_set(&cqr->status,        
+                                             CQR_STATUS_QUEUED,   
+                                             CQR_STATUS_DONE);    
+               dasd_schedule_bh(device);                                
+	 } else {
 		if (cqr->expires) {
 			cqr->expires += cqr->startclk;
 		}
@@ -250,13 +258,14 @@
 		   "Null device pointer passed to characteristics checker\n");
 		return -ENODEV;
 	}
-	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;
-                }
+	if (device->private != NULL) {
+                kfree (device->private);
+        } 
+        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;
 	}
 	private = (dasd_diag_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
@@ -304,7 +313,7 @@
 		if (cqr == NULL) {
 			printk (KERN_WARNING PRINTK_HEADER
                                 "No memory to allocate initialization request\n");
-                        free_page(private->label);
+                        free_page((long)private->label);
                         kfree(private);
                         device->private = NULL;
                         return -ENOMEM;
@@ -319,7 +328,7 @@
 		memset (iob, 0, sizeof (diag_rw_io_t));
 		iob->dev_nr = rdc_data->dev_nr;
 		iob->block_count = 1;
-		iob->interrupt_params = cqr;
+		iob->interrupt_params = (u32)cqr;
 		iob->bio_list = __pa (bio);
 		rc = dia250 (iob, RW_BIO);
 		if (rc == 0) {
@@ -354,19 +363,26 @@
 static int
 dasd_diag_do_analysis (struct dasd_device_t *device)
 {
-	int sb;
 	dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
 
 	long *label = private->label;
 
 	/* real size of the volume */
 	device->sizes.blocks = label[7];
+        if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
+		device->sizes.pt_block = 1;
+	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
+		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
+		device->sizes.pt_block = 2;
+	} else {
+		return -EINVAL;
+        }
 	printk (KERN_INFO PRINTK_HEADER
 		"/dev/%s (%04X): capacity (%dkB blks): %ldkB\n",
 		device->name, device->devinfo.devno,
 		(device->sizes.bp_block >> 10),
 		(device->sizes.blocks << device->sizes.s2b_shift) >> 1);
-        free_page(private->label);
+        free_page((long)private->label);
 	return 0;
 }
 
@@ -393,14 +409,6 @@
 	geo->cylinders = cyls;
 	geo->heads = 16;
 	geo->sectors = 128 >> device->sizes.s2b_shift;
-	if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
-		geo->start = 1;
-	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
-		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
-		geo->start = 2;
-	} else {
-		return -EINVAL;
-	}
 	return rc;
 }
 
@@ -482,7 +490,7 @@
 		}
 	}
 	rw_cp->device = device;
-	rw_cp->expires = 5 * 0xf424000;		/* 5 seconds */
+	rw_cp->expires = 50 * TOD_SEC;		/* 50 seconds */
 	rw_cp->req = req;
 	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
 	return rw_cp;
@@ -507,6 +515,7 @@
 {
 	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 --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- v2.4.3/linux/drivers/s390/block/dasd_eckd.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_eckd.c	Wed Apr 11 19:02:28 2001
@@ -15,6 +15,8 @@
  * 10/10/00 reverted last change according to ESS exploitation
  * 10/10/00 now dequeuing init_cqr before freeing *ouch*
  * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF)
+ * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC
+ *          fixed partition handling and HDIO_GETGEO
  */
 
 #include <linux/config.h>
@@ -40,6 +42,8 @@
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
 #define PRINTK_HEADER DASD_NAME"(eckd): "
+#undef DASD_CDL // Support compatible disk layout
+#undef CDL_PRINTK
 
 #define ECKD_C0(i) (i->home_bytes)
 #define ECKD_F(i) (i->formula)
@@ -52,36 +56,21 @@
 #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_WRITE_KD 0x0d
-#define DASD_ECKD_CCW_READ_KD 0x0e
-#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_WRITE_KD_MT 0x8d
-#define DASD_ECKD_CCW_READ_KD_MT 0x8e
-#define DASD_ECKD_CCW_RELEASE 0x94
-#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
-#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
-#define DASD_ECKD_CCW_RESERVE 0xB4
-
 dasd_discipline_t dasd_eckd_discipline;
 
 typedef struct
 dasd_eckd_private_t {
 	dasd_eckd_characteristics_t rdc_data;
 	dasd_eckd_confdata_t conf_data;
+#ifdef DASD_CDL
+        eckd_count_t count_area[5];
+#else
 	eckd_count_t count_area;
+#endif
 	ccw_req_t *init_cqr;
+#ifdef DASD_CDL
+        int uses_cdl; 
+#endif
 } dasd_eckd_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
@@ -91,27 +80,38 @@
 	{
 		ci:
 		{hc:
-		 {ctype:0x3990, dtype:0x3390}},
-		flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+		 {ctype:0x3990}},
+		flag: (DEVREG_MATCH_CU_TYPE |
+                       DEVREG_NO_DEV_INFO| 
+                       DEVREG_TYPE_DEVCHARS),
 		oper_func:dasd_oper_handler
 	},
 	{
 		ci:
 		{hc:
-		 {ctype:0x3990, dtype:0x3380}},
-		flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+		 {ctype:0x2105}},
+		flag:(DEVREG_MATCH_CU_TYPE |
+                       DEVREG_NO_DEV_INFO| 
+                       DEVREG_TYPE_DEVCHARS),
 		oper_func:dasd_oper_handler
 	},
 	{
 		ci:
 		{hc:
-		 {ctype:0x9343, dtype:0x9345}},
-		flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+		 {ctype:0x9343}},
+		flag:(DEVREG_MATCH_CU_TYPE |
+                       DEVREG_NO_DEV_INFO| 
+                       DEVREG_TYPE_DEVCHARS),
 		oper_func:dasd_oper_handler
 	}
 };
 #endif
 
+#ifdef DASD_CDL
+int sizes_trk0[]={28,148,84};
+#define LABEL_SIZE 140
+#endif
+
 static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
 {
@@ -210,6 +210,7 @@
 	return rpt;
 }
 
+
 static inline void
 define_extent (ccw1_t * de_ccw,
 	       DE_eckd_data_t * data,
@@ -269,7 +270,11 @@
 		break;
 	}
 	data->attributes.mode = 0x3;
-	if (private->rdc_data.cu_type == 0x2105) {
+	if (private->rdc_data.cu_type == 0x2105 
+#ifdef DASD_CDL
+            && !(private->uses_cdl && trk < 2)
+#endif
+            ) {
 		data->reserved |= 0x40;
 	}
 	data->beg_ext.cyl = beg.cyl;
@@ -296,6 +301,9 @@
 	{trk / (geo.head), trk % (geo.head)};
 	int sector;
 
+#ifdef CDL_PRINTK
+        printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n",trk,rec_on_trk,no_rec,cmd,reclen);
+#endif
 	memset (lo_ccw, 0, sizeof (ccw1_t));
 	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	lo_ccw->count = 16;
@@ -411,13 +419,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);
@@ -468,6 +477,22 @@
 	return 0;
 }
 
+#ifdef DASD_CDL
+static inline int
+dasd_eckd_cdl_reclen (dasd_device_t* device,int recid) {
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+        int byt_per_blk = device->sizes.bp_block;
+        int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+        if (recid < 3) 
+                return sizes_trk0[recid];
+        if (recid < blk_per_trk)
+                return byt_per_blk;
+        if (recid < 2*blk_per_trk )
+                return LABEL_SIZE;
+        return byt_per_blk;
+}
+#endif
+
 static ccw_req_t *
 dasd_eckd_init_analysis (struct dasd_device_t *device)
 {
@@ -476,9 +501,20 @@
 	DE_eckd_data_t *DE_data;
 	LO_eckd_data_t *LO_data;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+#ifdef DASD_CDL
+        eckd_count_t *count_data = private->count_area;
+#else
 	eckd_count_t *count_data = &(private->count_area);
-
-	cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
+#endif
+#ifdef DASD_CDL
+        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 8 + 1, 
+                                 sizeof (DE_eckd_data_t) + 
+                                 2*sizeof (LO_eckd_data_t));
+#else
+	cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, 
+                                 sizeof (DE_eckd_data_t) + 
+                                 sizeof (LO_eckd_data_t));
+#endif
 	if (cqr == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No memory to allocate initialization request\n");
@@ -489,72 +525,159 @@
 	DE_data = cqr->data;
 	LO_data = cqr->data + sizeof (DE_eckd_data_t);
 	ccw = cqr->cpaddr;
+#ifdef DASD_CDL
+        define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device);
+#else
 	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
+#endif
 	ccw->flags |= CCW_FLAG_CC;
 	ccw++;
+#ifdef DASD_CDL
+        locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, device, 0);
+#else
 	locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0);
+#endif
+#ifdef DASD_CDL
 	ccw->flags |= CCW_FLAG_CC;
 	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
 	ccw->count = 8;
-	set_normalized_cda (ccw, __pa (count_data));
+        set_normalized_cda (ccw, __pa (count_data++));
+        ccw->flags |= CCW_FLAG_CC;
+        ccw++;
+        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+        ccw->count = 8;
+        set_normalized_cda (ccw, __pa (count_data++));
+        ccw->flags |= CCW_FLAG_CC;
+        ccw++;
+        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+        ccw->count = 8;
+        set_normalized_cda (ccw, __pa (count_data++));
+        ccw->flags |= CCW_FLAG_CC;
+        ccw++;
+        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+        ccw->count = 8;
+        set_normalized_cda (ccw, __pa (count_data++));
+        ccw->flags |= CCW_FLAG_CC;
+        ccw++;
+        locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0);
+#endif
+        ccw->flags |= CCW_FLAG_CC;
+        ccw++;
+        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+        ccw->count = 8;
+        set_normalized_cda (ccw, __pa (count_data));
 	cqr->device = device;
 	cqr->retries = 0;
 	cqr->status = CQR_STATUS_FILLED;
-
 	return cqr;
 }
 
 static int
 dasd_eckd_do_analysis (struct dasd_device_t *device)
 {
-	int rc = 0;
 	int sb, rpt;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	int bs = private->count_area.dl;
-
+        eckd_count_t *count_area = NULL;
+        char *cdl_msg;
+#ifdef DASD_CDL /* BAD HACK SO FIX ME UP */
+        int i;
+        private -> uses_cdl = 1;
+
+        /* Free the cqr and cleanup device->sizes */
+        dasd_chanq_deq (&device->queue, private->init_cqr);
+        ccw_free_request (private->init_cqr);
+        private->init_cqr = NULL;
+        memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
+        /* Check Track 0 for Compatible Disk Layout */
+        for (i = 0; i < 3; i++) { 
+                if ((i < 3) &&
+                    ((private->count_area[i].kl != 4) ||
+                     (private->count_area[i].dl != 
+                      dasd_eckd_cdl_reclen (device,i) - 4))) {
+                        private -> uses_cdl = 0;
+                        break;
+                } 
+        }
+        if ( i == 3 ) {
+                count_area = &private->count_area[4];
+        }
+        if (private->uses_cdl == 0) { 
+                for (i = 0; i < 5; i++) {
+                        if ((private->count_area[i].kl != 0) ||
+                            (private->count_area[i].dl != 
+                             private->count_area[0].dl)) {
+                                break;
+                        }
+                }
+                if ( i == 5 ) {
+                        count_area = &private->count_area[0];
+                }
+        } else {
+                if (private->count_area[3].record == 1) {
+                        DASD_MESSAGE(KERN_WARNING,device,"%s",
+                                     "Trk 0: no records after VTOC!");
+                }
+        }
+        if (count_area != NULL && /* we found notthing violating our disk layout */
+            count_area ->kl == 0) { 
+                /* find out blocksize */
+                switch (count_area->dl) {
+                case 512:
+                case 1024:
+                case 2048:
+                case 4096:
+                        device->sizes.bp_block = count_area->dl;
+                        break;
+                }
+        }
+#else
 	dasd_chanq_deq (&device->queue, private->init_cqr);
 	ccw_free_request (private->init_cqr);
 	private->init_cqr = NULL;
 	memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
-	switch (bs) {
+	switch (private->count_area.dl) {
 	case 512:
 	case 1024:
 	case 2048:
 	case 4096:
-		device->sizes.bp_block = bs;
+		device->sizes.bp_block = private->count_area.dl;
 		break;
-	default:
-		printk (KERN_INFO PRINTK_HEADER
-			"/dev/%s (%04X): invalid blocksize %d\n"
-			KERN_INFO PRINTK_HEADER
-		 "/dev/%s (%04X): capacity (at 4kB blks): %dkB at %dkB/trk\n",
-			device->name, device->devinfo.devno, bs,
-			device->name, device->devinfo.devno,
-		   (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
-		    recs_per_track (&private->rdc_data, 0, 4096)),
-			recs_per_track (&private->rdc_data, 0, 4096));
-		return -EMEDIUMTYPE;
 	}
+#endif
+        if ( device->sizes.bp_block == 0 ) {
+                DASD_MESSAGE(KERN_WARNING, device,"%s\n",
+                             "Volume has incompatible disk layout");
+                return -EMEDIUMTYPE;
+        }
 	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
-	for (sb = 512; sb < bs; sb = sb << 1)
+        device->sizes.pt_block = 2;
+	for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1)
 		device->sizes.s2b_shift++;
 
 	rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
-	device->sizes.blocks = (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
-	      recs_per_track (&private->rdc_data, 0, device->sizes.bp_block));
-
-	printk (KERN_INFO PRINTK_HEADER
-		"/dev/%s (%04X): capacity (%dkB blks): %dkB at %dkB/trk\n",
-		device->name, device->devinfo.devno,
-		(device->sizes.bp_block >> 10),
-		(private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
-	      recs_per_track (&private->rdc_data, 0, device->sizes.bp_block) *
-		 (device->sizes.bp_block >> 9)) >> 1,
-		(recs_per_track (&private->rdc_data, 0, device->sizes.bp_block) * device->sizes.bp_block) >> 10);
+	device->sizes.blocks = (private->rdc_data.no_cyl * 
+                                private->rdc_data.trk_per_cyl *
+                                recs_per_track (&private->rdc_data, 0, 
+                                                device->sizes.bp_block));
+#ifdef DASD_CDL
+        cdl_msg = private->uses_cdl?"compatible disk layout":"classic disk layout";
+#else
+        cdl_msg = "classic disk layout";
+#endif           
+                  
+        DASD_MESSAGE(KERN_INFO,device,"(%dkB blks): %dkB at %dkB/trk %s",
+                     (device->sizes.bp_block >> 10),
+                     (private->rdc_data.no_cyl * 
+                      private->rdc_data.trk_per_cyl *
+                      recs_per_track (&private->rdc_data, 0, 
+                                      device->sizes.bp_block) *
+                      (device->sizes.bp_block >> 9)) >> 1,
+                     (recs_per_track (&private->rdc_data, 0, 
+                                      device->sizes.bp_block) * 
+                      device->sizes.bp_block) >> 10,
+                     cdl_msg);
 	return 0;
-
-	return rc;
 }
 
 static int
@@ -574,7 +697,6 @@
 	geo->cylinders = private->rdc_data.no_cyl;
 	geo->heads = private->rdc_data.trk_per_cyl;
 	geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block);
-	geo->start = 2;
 	return rc;
 }
 
@@ -600,6 +722,9 @@
 	int head = trk % private->rdc_data.trk_per_cyl;
 	int wrccws = rpt;
 	int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
+#ifdef DASD_CDL
+        int formatCDL=0;
+#endif
 
 	if (((fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) &&
 	 trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) ||
@@ -623,7 +748,15 @@
 	case 0x01:
 	case 0x03:
 	case 0x04:		/* make track invalid */
+                break;
+#ifdef DASD_CDL /* Format compatible disk Layout */
+        case 0x08:
+        case 0x09:
+        case 0x0b:
+        case 0x0c:
+                formatCDL=1;
 		break;
+#endif
 	default:
 		printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n", flags);
 		return NULL;
@@ -678,6 +811,7 @@
 
 		switch (flags) {
 		case 0x03:
+                case 0x0b:
 			define_extent (last_ccw, DE_data, trk, trk,
 				    DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
 			last_ccw->flags |= CCW_FLAG_CC;
@@ -688,6 +822,7 @@
 			last_ccw++;
 			break;
 		case 0x01:
+                case 0x09:
 			define_extent (last_ccw, DE_data, trk, trk,
 				     DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
 			last_ccw->flags |= CCW_FLAG_CC;
@@ -699,6 +834,7 @@
 			memset (r0_data, 0, sizeof (eckd_count_t));
 			break;
 		case 0x00:
+                case 0x08:
 			define_extent (last_ccw, DE_data, trk, trk,
 				       DASD_ECKD_CCW_WRITE_CKD, device);
 			last_ccw->flags |= CCW_FLAG_CC;
@@ -710,6 +846,7 @@
 			last_ccw++;
 			break;
 		case 0x04:
+                case 0x0c:
 			define_extent (last_ccw, DE_data, trk, trk,
 				       DASD_ECKD_CCW_WRITE_CKD, device);
 			last_ccw->flags |= CCW_FLAG_CC;
@@ -747,7 +884,29 @@
 			(ct_data + i)->head = head;
 			(ct_data + i)->record = i + 1;
 			(ct_data + i)->kl = 0;
-			(ct_data + i)->dl = bs;
+#ifdef DASD_CDL
+                        if (formatCDL) { 
+                            // special handling when formatting CDL
+                            switch (trk) {
+                            case 0:
+                                if (i<3) {
+                                    (ct_data + i)->kl = 4;
+                                    (ct_data + i)->dl = sizes_trk0[i]-4;
+                                } else 
+                                    (ct_data + i)->dl = bs;
+                                break;
+                            case 1:
+                                (ct_data + i)->kl = 44;
+                                (ct_data + i)->dl = LABEL_SIZE-44;
+                                break;
+                            default:
+                                (ct_data + i)->dl = bs;
+                                break;
+                            }
+                        }
+                        else
+#endif                            
+                        (ct_data + i)->dl = bs;
 			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
 			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
 			last_ccw->count = 8;
@@ -791,7 +950,7 @@
 	switch (device->devinfo.sid_data.cu_type) {
 	case 0x3990:
 	case 0x2105:
-                /*  return dasd_3990_erp_action; */
+		return dasd_3990_erp_action;
 	case 0x9343:
                 /* Return dasd_9343_erp_action; */
 	default:
@@ -802,13 +961,42 @@
 static dasd_erp_postaction_fn_t
 dasd_eckd_erp_postaction (ccw_req_t * cqr)
 {
-	if (cqr->function != default_erp_action)
-                printk (KERN_WARNING PRINTK_HEADER
-                        "unknown ERP action [<%p>]\n",
-                        cqr->function);
 	return default_erp_postaction;
 }
 
+
+#ifdef DASD_CDL
+inline unsigned char
+dasd_eckd_cdl_cmd(dasd_device_t *device,int recid,int cmd) {
+    dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+    int byt_per_blk = device->sizes.bp_block;
+    int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+    switch (cmd) {
+    case READ:
+        if (recid < 3) 
+            return DASD_ECKD_CCW_READ_KD_MT;
+        if (recid < blk_per_trk)
+            return DASD_ECKD_CCW_READ_MT;
+        if (recid < 2*blk_per_trk)
+            return DASD_ECKD_CCW_READ_KD_MT;
+        return DASD_ECKD_CCW_READ_MT;
+        break;
+    case WRITE:
+        if (recid < 3)
+            return DASD_ECKD_CCW_WRITE_KD_MT;
+        if (recid < blk_per_trk)
+            return DASD_ECKD_CCW_WRITE_MT;
+        if (recid < 2*blk_per_trk)
+            return DASD_ECKD_CCW_WRITE_KD_MT;
+        return DASD_ECKD_CCW_WRITE_MT;
+        break;
+    default:
+        BUG();
+    }
+    return 0; // never executed
+}
+#endif
+
 static ccw_req_t *
 dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
 {
@@ -826,6 +1014,11 @@
 	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
 	int btrk = (req->sector >> shift) / blk_per_trk;
 	int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
+#ifdef DASD_CDL
+        int recid = req->sector >> shift;
+        int locate4k_set=0;
+        int nlocs=0;
+#endif
 
 	if (req->cmd == READ) {
 		rw_cmd = DASD_ECKD_CCW_READ_MT;
@@ -845,43 +1038,123 @@
 		else
 			bhct++;
 	}
-
+#ifndef DASD_CDL
 	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
 				    2 + bhct + 1,
 				    sizeof (DE_eckd_data_t) +
 				    sizeof (LO_eckd_data_t));
+#else
+        if (btrk<2 && private->uses_cdl) {
+            nlocs+= 2*blk_per_trk-recid;
+            if (etrk<2)
+                nlocs-=2*blk_per_trk-((req->sector + req->nr_sectors - 1) >> shift);
+        }
+        rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
+                                    2 + nlocs + bhct + 1,
+                                    sizeof (DE_eckd_data_t) +
+                                    (1+nlocs)*sizeof (LO_eckd_data_t));
+#endif
 	if (!rw_cp) {
 		return NULL;
 	}
 	DE_data = rw_cp->data;
 	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
 	ccw = rw_cp->cpaddr;
-
 	define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device);
 	ccw->flags |= CCW_FLAG_CC;
+#ifndef DASD_CDL
 	ccw++;
-	locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
-	    req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block);
+        locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
+                       req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block);
 	ccw->flags |= CCW_FLAG_CC;
+#endif
 	for (bh = req->bh; bh != NULL;) {
 		if (bh->b_size > byt_per_blk) {
 			for (size = 0; size < bh->b_size; size += byt_per_blk) {
+#ifdef DASD_CDL
+                                if (!locate4k_set) {
+                                    // we need to chain a locate record before our rw-ccw
+                                    ccw++;
+                                    if ((recid/blk_per_trk)<2 && private->uses_cdl) {
+                                        /* Do a locate record for our special blocks */
+                                        locate_record (ccw, LO_data++, recid/blk_per_trk, 
+                                                       recid % blk_per_trk + 1, 1, 
+                                                       dasd_eckd_cdl_cmd(device,recid,req->cmd), 
+                                                       device, 
+                                                       dasd_eckd_cdl_reclen(device,recid));
+                                    } else {
+                                        // Do a locate record for standard blocks */
+                                        locate_record (ccw, LO_data++, recid/blk_per_trk,
+                                                       recid % blk_per_trk + 1, 
+                                                       (((req->sector + req->nr_sectors) >> shift)-recid),
+                                                       rw_cmd,device, device->sizes.bp_block);
+                                        locate4k_set=1;
+                                    }                                        
+                                    ccw->flags |= CCW_FLAG_CC;
+                                }
+#endif
 				ccw++;
+#ifndef DASD_CDL
 				ccw->flags |= CCW_FLAG_CC;
-				ccw->cmd_code = rw_cmd;
-				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
+				ccw->cmd_code= rw_cmd;
+				ccw->count = bh->b_size;
+#else
+                                ccw->flags |= CCW_FLAG_CC;
+                                ccw->cmd_code=locate4k_set?rw_cmd:
+                                    dasd_eckd_cdl_cmd(device,recid,req->cmd);
+                                ccw->count =locate4k_set?bh->b_size:
+                                    dasd_eckd_cdl_reclen(device,recid);
+#endif
+				set_normalized_cda (ccw, __pa (bh->b_data));
+				size += bh->b_size;
+				bh = bh->b_reqnext;
+#ifdef DASD_CDL
+                                recid++;
+#endif
 			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
 			for (size = 0; bh != NULL && size < byt_per_blk;) {
+#ifdef DASD_CDL
+                                if (!locate4k_set) {
+                                    // we need to chain a locate record before our rw-ccw
+                                    ccw++;
+                                    if ((recid/blk_per_trk)<2 && private->uses_cdl) {
+                                        /* Do a locate record for our special blocks */
+                                        locate_record (ccw, LO_data++, recid/blk_per_trk, 
+                                                       recid % blk_per_trk + 1, 1, 
+                                                       dasd_eckd_cdl_cmd(device,recid,req->cmd), 
+                                                       device, 
+                                                       dasd_eckd_cdl_reclen(device,recid));
+                                    } else {
+                                        // Do a locate record for standard blocks */
+                                        locate_record (ccw, LO_data++, recid/blk_per_trk,
+                                                       recid % blk_per_trk + 1, 
+                                                       (((req->sector + req->nr_sectors) >> shift)-recid),
+                                                       rw_cmd,device, device->sizes.bp_block);
+                                        locate4k_set=1;
+                                    }                                        
+                                    ccw->flags |= CCW_FLAG_CC;
+                                }
+#endif
 				ccw++;
+#ifndef DASD_CDL
 				ccw->flags |= CCW_FLAG_DC;
-				ccw->cmd_code = rw_cmd;
+				ccw->cmd_code= rw_cmd;
 				ccw->count = bh->b_size;
+#else
+                                ccw->flags |= locate4k_set?CCW_FLAG_DC:CCW_FLAG_CC;
+                                ccw->cmd_code=locate4k_set?rw_cmd:
+                                    dasd_eckd_cdl_cmd(device,recid,req->cmd);
+                                ccw->count =locate4k_set?bh->b_size:
+                                    dasd_eckd_cdl_reclen(device,recid);
+#endif
 				set_normalized_cda (ccw, __pa (bh->b_data));
 				size += bh->b_size;
 				bh = bh->b_reqnext;
+#ifdef DASD_CDL
+                                recid++;
+#endif
 			}
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n",
@@ -1000,14 +1273,13 @@
 ccw_req_t *
 dasd_eckd_merge_cp ( dasd_device_t *device )
 {
-        ccw_req_t * cqr;
         return NULL;
 }
 
 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;
@@ -1027,13 +1299,13 @@
             ccw1_t *act = req -> cpaddr;
             int i = req -> cplength;
             do {
-#if 0
+#ifdef ERP_DEBUB
                 printk ( KERN_INFO "CCW %p: %08X %08X\n", 
                          act,((int*)act)[0],((int*)act)[1]);
                 printk ( KERN_INFO "DAT: %08X %08X %08X %08X\n", 
                          ((int*)act->cda)[0],((int*)act->cda)[1],
                          ((int*)act->cda)[2],((int*)act->cda)[3]);
-#endif
+#endif /* ERP_DEBUG */
                 act ++;
             } while ( --i );
         }
@@ -1071,6 +1343,7 @@
 {
 	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,
@@ -1101,14 +1374,12 @@
         {
 	int i;
 	for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) {
-		printk (KERN_INFO PRINTK_HEADER
-			"We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+                printk (KERN_INFO PRINTK_HEADER
+                        "We are interested in: CU %04X/%02x\n",
 			dasd_eckd_known_devices[i].ci.hc.ctype,
-			dasd_eckd_known_devices[i].ci.hc.cmode,
-			dasd_eckd_known_devices[i].ci.hc.dtype,
-			dasd_eckd_known_devices[i].ci.hc.dmode);
+			dasd_eckd_known_devices[i].ci.hc.cmode);
 		s390_device_register (&dasd_eckd_known_devices[i]);
-	}
+        }
         }
 #endif				/* CONFIG_DASD_DYNAMIC */
 	return rc;
@@ -1123,12 +1394,10 @@
 	int i;
         for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
 		printk (KERN_INFO PRINTK_HEADER
-			"We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+			"We were interested in: CU %04X/%02x\n",
 			dasd_eckd_known_devices[i].ci.hc.ctype,
-			dasd_eckd_known_devices[i].ci.hc.cmode,
-			dasd_eckd_known_devices[i].ci.hc.dtype,
-			dasd_eckd_known_devices[i].ci.hc.dmode);
-		s390_device_register(&dasd_eckd_known_devices[i]);
+			dasd_eckd_known_devices[i].ci.hc.cmode);
+		s390_device_unregister(&dasd_eckd_known_devices[i]);
 	}
         } 
 #endif /* CONFIG_DASD_DYNAMIC */
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h
--- v2.4.3/linux/drivers/s390/block/dasd_eckd.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_eckd.h	Wed Apr 11 19:02:28 2001
@@ -2,8 +2,32 @@
 #define DASD_ECKD_H
 
 #include "dasd_3990_erp.h"
+#include "dasd_9343_erp.h"
 
-typedef
+#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_WRITE_KD 0x0d
+#define DASD_ECKD_CCW_READ_KD 0x0e
+#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_WRITE_KD_MT 0x8d
+#define DASD_ECKD_CCW_READ_KD_MT 0x8e
+#define DASD_ECKD_CCW_RELEASE 0x94
+#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
+#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
+#define DASD_ECKD_CCW_RESERVE 0xB4
+
+
+typedef 
 struct eckd_count_t {
 	__u16 cyl;
 	__u16 head;
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
--- v2.4.3/linux/drivers/s390/block/dasd_fba.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_fba.c	Wed Apr 11 19:02:28 2001
@@ -4,6 +4,7 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ *          fixed partition handling and HDIO_GETGEO
  */
 
 #include <linux/config.h>
@@ -49,15 +50,21 @@
 	{
 		ci:
 		{hc:
-		 {ctype:0x6310, dtype:0x9336}},
-		flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+		 {ctype:0x6310,
+                  dtype:0x9336}},
+		flag:(DEVREG_MATCH_CU_TYPE |
+                      DEVREG_MATCH_DEV_TYPE| 
+                      DEVREG_TYPE_DEVCHARS),
 		oper_func:dasd_oper_handler
 	},
 	{
 		ci:
 		{hc:
-		 {ctype:0x3880, dtype:0x3370}},
-		flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+		 {ctype:0x3880,
+                  dtype:0x3370}},
+		flag:(DEVREG_MATCH_CU_TYPE |
+                      DEVREG_MATCH_DEV_TYPE| 
+                      DEVREG_TYPE_DEVCHARS),
 		oper_func:dasd_oper_handler
 	}
 };
@@ -123,13 +130,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);
@@ -179,6 +187,7 @@
 		device->sizes.s2b_shift++;
 
 	device->sizes.blocks = (private->rdc_data.blk_bdsa);
+        device->sizes.pt_block = 1;
 
 	return rc;
 }
@@ -203,7 +212,6 @@
 	geo->cylinders = cyls;
 	geo->heads = 16;
 	geo->sectors = 128 >> device->sizes.s2b_shift;
-	geo->start = 1;
 	return rc;
 }
 
@@ -247,7 +255,7 @@
 {
 	ccw_req_t *rw_cp = NULL;
 	int rw_cmd;
-	int bhct;
+	int bhct, i;
 	long size;
 	ccw1_t *ccw;
 	DE_fba_data_t *DE_data;
@@ -276,9 +284,9 @@
 	}
 
 	rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
-				    2 + bhct,
+				    1 + 2*bhct,
 				    sizeof (DE_fba_data_t) +
-				    sizeof (LO_fba_data_t));
+				    bhct*sizeof (LO_fba_data_t));
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -289,29 +297,30 @@
 	define_extent (ccw, DE_data, req->cmd, byt_per_blk,
 		       req->sector, req->nr_sectors);
 	ccw->flags |= CCW_FLAG_CC;
-	ccw++;
-	locate_record (ccw, LO_data, req->cmd, 0, req->nr_sectors);
-	ccw->flags |= CCW_FLAG_CC;
 
-	for (bh = req->bh; bh;) {
+	for (i = 0, bh = req->bh; bh;) {
 		if (bh->b_size > byt_per_blk) {
 			for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                                ccw++;
+                                locate_record (ccw, LO_data, req->cmd, i, 1);
+                                ccw->flags |= CCW_FLAG_CC;
 				ccw++;
-				if (private->rdc_data.mode.bits.data_chain) {
-					ccw->flags |= CCW_FLAG_DC;
-				} else {
-					ccw->flags |= CCW_FLAG_CC;
-				}
+                                ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
 				ccw->cmd_code = rw_cmd;
 				ccw->count = byt_per_blk;
 				set_normalized_cda (ccw, __pa (bh->b_data + size));
+                                i++;
+                                LO_data++;
 			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
 			for (size = 0; bh != NULL && size < byt_per_blk;) {
+                                ccw++;
+                                locate_record (ccw, LO_data, req->cmd, i, 1);
+                                ccw->flags |= CCW_FLAG_CC;
 				ccw++;
 				if (private->rdc_data.mode.bits.data_chain) {
-					ccw->flags |= CCW_FLAG_DC;
+					ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI;
 				} else {
 					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
 					ccw_free_request (rw_cp);
@@ -322,9 +331,11 @@
 				set_normalized_cda (ccw, __pa (bh->b_data));
 				size += bh->b_size;
 				bh = bh->b_reqnext;
+                                i++;
+                                LO_data++;
 			}
 			ccw->flags &= ~CCW_FLAG_DC;
-			ccw->flags |= CCW_FLAG_CC;
+			ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill request smaller than block\n");
 				ccw_free_request (rw_cp);
@@ -360,6 +371,7 @@
 {
 	name:"FBA ",
 	ebcname:"FBA ",
+	max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1),
 	id_check:dasd_fba_id_check,
 	check_characteristics:dasd_fba_check_characteristics,
 	do_analysis:dasd_fba_do_analysis,
@@ -387,11 +399,9 @@
             int i;
             for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) {
 		printk (KERN_INFO PRINTK_HEADER
-			"We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+			"We are interested in: CU %04X/%02x\n",
 			dasd_fba_known_devices[i].ci.hc.ctype,
-			dasd_fba_known_devices[i].ci.hc.cmode,
-			dasd_fba_known_devices[i].ci.hc.dtype,
-			dasd_fba_known_devices[i].ci.hc.dmode);
+			dasd_fba_known_devices[i].ci.hc.cmode);
 		s390_device_register (&dasd_fba_known_devices[i]);
             }
         }
@@ -408,12 +418,10 @@
 	int i;
         for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
                 printk (KERN_INFO PRINTK_HEADER
-                        "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+                        "We were interested in: CU %04X/%02x\n",
                         dasd_fba_known_devices[i].ci.hc.ctype,
-                        dasd_fba_known_devices[i].ci.hc.cmode,
-                        dasd_fba_known_devices[i].ci.hc.dtype,
-                        dasd_fba_known_devices[i].ci.hc.dmode);
-                s390_device_register(&dasd_fba_known_devices[i]);
+                        dasd_fba_known_devices[i].ci.hc.cmode);
+                s390_device_unregister(&dasd_fba_known_devices[i]);
         }
         }
 #endif /* CONFIG_DASD_DYNAMIC */
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- v2.4.3/linux/drivers/s390/block/xpram.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/xpram.c	Wed Apr 11 19:02:28 2001
@@ -658,7 +658,7 @@
 
 	case BLKFLSBUF: /* flush, 0x1261 */
 		fsync_dev(inode->i_rdev);
-		if ( suser() )invalidate_buffers(inode->i_rdev);
+		if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
 		return 0;
 
 	case BLKRAGET: /* return the readahead value, 0x1263 */
@@ -671,7 +671,7 @@
 		return 0;
 
 	case BLKRASET: /* set the readahead value, 0x1262 */
-		if (!suser()) return -EACCES;
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 		if (arg > 0xff) return -EINVAL; /* limit it */
 		read_ahead[MAJOR(inode->i_rdev)] = arg;
                 atomic_eieio();
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c
--- v2.4.3/linux/drivers/s390/ccwcache.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/ccwcache.c	Wed Apr 11 19:02:28 2001
@@ -9,6 +9,7 @@
  * 11/14/00 redesign by Martin Schwidefsky
  */
 
+#include <linux/module.h>
 #include <linux/malloc.h>
 #include <linux/version.h>
 
@@ -31,9 +32,7 @@
 #define kmem_cache_destroy(x) do {} while(0)
 #endif
 
-#ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
-#endif
 #define PRINTK_HEADER "ccwcache"
 
 /* pointer to list of allocated requests */
@@ -300,4 +299,7 @@
 	}
 	debug_unregister( debug_area );
 }
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/Makefile linux/drivers/s390/char/Makefile
--- v2.4.3/linux/drivers/s390/char/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/Makefile	Wed Apr 11 19:02:29 2001
@@ -1,33 +1,42 @@
-all: s390-char.o
+# Makefile for the S/390 supported character devices
+#
+# 4 January 2001 Richard Hitt
+# Modeled after similar files of Michael Elizabeth Chastain
+# Rewritten to use lists instead of if-statements.
 
-CFLAFS += 
-O_TARGET := s390-char.o
+O_TARGET	:= s390-char.o
 
-obj-$(CONFIG_3215_CONSOLE) += con3215.o
+export-objs     :=
+list-multi	:= tub3270.o tape390.o
 
-obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
 
-# stuff for building tape390.o
-T390_OBJS = tape.o
-ifeq ($(CONFIG_S390_TAPE_CHAR),y)
-  T390_OBJS += tapechar.o
-endif
-ifeq ($(CONFIG_S390_TAPE_BLOCK),y)
-  T390_OBJS += tapeblock.o
-endif
-ifeq ($(CONFIG_S390_TAPE_3480),y)
-  T390_OBJS += tape3480.o
-  CONFIG_S390_TAPE_NEED_34xx = y 
-endif
-ifeq ($(CONFIG_S390_TAPE_3490),y)
-  T390_OBJS += tape3490.o
-  CONFIG_S390_TAPE_NEED_34xx = y
-endif
-ifeq ($(CONFIG_S390_TAPE_NEED_34xx),y) 
-  T390_OBJS += tape34xx.o
-endif
-obj-$(CONFIG_S390_TAPE) += tape390.o
+tub3270-objs			:= tuball.o tubfs.o tubtty.o \
+					tubttyaid.o tubttybld.o tubttyrcl.o \
+					tubttyscl.o tubttysiz.o
+
+obj-y += ctrlchar.o
+obj-$(CONFIG_3215_CONSOLE)	+= con3215.o
+obj-$(CONFIG_HWC)		+= hwc_con.o hwc_rw.o hwc_tty.o
+obj-$(CONFIG_3270)		+= tub3270.o
+
+tape-y				:= tape.o
+tape-$(CONFIG_S390_TAPE_CHAR)	+= tapechar.o
+tape-$(CONFIG_S390_TAPE_BLOCK)	+= tapeblock.o
+tape-$(CONFIG_S390_TAPE_3480)	+= tape3480.o tape34xx.o
+tape-$(CONFIG_S390_TAPE_3490)	+= tape3490.o tape34xx.o
+tape390-objs			:= $(sort $(tape-y))
+obj-$(CONFIG_S390_TAPE)		+= tape390.o
+
+# Hand off to Rules.make.
 
-tape390.o: $(T390_OBJS)
-	$(LD) -r -o $@ $(T390_OBJS)
 include $(TOPDIR)/Rules.make
+
+tub3270.o:	$(tub3270-objs)
+	$(LD) -r -o $@ $(tub3270-objs)
+
+tape390.o:	$(tape390-objs)
+	$(LD) -r -o $@ $(tape390-objs)
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
--- v2.4.3/linux/drivers/s390/char/con3215.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/con3215.c	Wed Apr 11 19:02:29 2001
@@ -22,14 +22,17 @@
 
 #include <linux/slab.h>
 #include <linux/bootmem.h>
+#include <linux/devfs_fs_kernel.h>
+
 #include <asm/io.h>
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <asm/delay.h>
-
-#include "../../../arch/s390/kernel/cpcmd.h"
+#include <asm/cpcmd.h>
 #include <asm/irq.h>
 
+#include "ctrlchar.h"
+
 #define NR_3215		    1
 #define NR_3215_REQ	    (4*NR_3215)
 #define RAW3215_BUFFER_SIZE 65536     /* output buffer size */
@@ -116,7 +119,7 @@
 {
         int vdev;
 
-        vdev = simple_strtoul(str,&str,16);
+        vdev = simple_strtoul(str,&str,0);
         if (vdev >= 0 && vdev < 65536)
                 raw3215_condevice = vdev;
         return 1;
@@ -470,6 +473,8 @@
                 if ((raw = req->info) == NULL)
                         return;              /* That shouldn't happen ... */
 		if (req->type == RAW3215_READ && raw->tty != NULL) {
+			char *cchar;
+
 			tty = raw->tty;
                         count = 160 - req->residual;
                         if (MACHINE_IS_P390) {
@@ -480,33 +485,12 @@
 			if (count >= TTY_FLIPBUF_SIZE - tty->flip.count)
 				count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
 			EBCASC(raw->inbuf, count);
-			if (count == 2 && (
-			    /* hat is 0xb0 in codepage 037 (US etc.) and thus */
-			    /* converted to 0x5e in ascii ('^') */
-			    strncmp(raw->inbuf, "^c", 2) == 0 ||
-			    /* hat is 0xb0 in several other codepages (German,*/
-			    /* UK, ...) and thus converted to ascii octal 252 */
-			    strncmp(raw->inbuf, "\252c", 2) == 0) ) {
-				/* emulate a control C = break */
-				tty->flip.count++;
-				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-				*tty->flip.char_buf_ptr++ = INTR_CHAR(tty);
-				tty_flip_buffer_push(raw->tty);
-			} else if (count == 2 && (
-				   strncmp(raw->inbuf, "^d", 2) == 0 ||
-				    strncmp(raw->inbuf, "\252d", 2) == 0) ) {
-				/* emulate a control D = end of file */
+			if ((cchar = ctrlchar_handle(raw->inbuf, count, tty))) {
+				if (cchar == (char *)-1)
+					goto in_out;
 				tty->flip.count++;
 				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-				*tty->flip.char_buf_ptr++ = EOF_CHAR(tty);
-				tty_flip_buffer_push(raw->tty);
-			} else if (count == 2 && (
-				   strncmp(raw->inbuf, "^z", 2) == 0 ||
-				    strncmp(raw->inbuf, "\252z", 2) == 0) ) {
-				/* emulate a control Z = suspend */
-				tty->flip.count++;
-				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-				*tty->flip.char_buf_ptr++ = SUSP_CHAR(tty);
+				*tty->flip.char_buf_ptr++ = *cchar;
 				tty_flip_buffer_push(raw->tty);
 			} else {
 				memcpy(tty->flip.char_buf_ptr,
@@ -530,6 +514,7 @@
 			raw->count -= req->len;
                         raw->written -= req->len;
 		} 
+in_out:
 		raw->flags &= ~RAW3215_WORKING;
 		raw3215_free_req(req);
 		/* check for empty wait */
@@ -794,22 +779,6 @@
 #ifdef CONFIG_3215_CONSOLE
 
 /*
- * Try to request the console IRQ. Called from init/main.c
- */
-int con3215_activate(void)
-{
-	raw3215_info *raw;
-
-        if (!MACHINE_IS_VM && !MACHINE_IS_P390)
-                return 0;
-	raw = raw3215[0];  /* 3215 console is the first one */
-	if (raw == NULL || raw->irq == -1)
-                /* console device not found in con3215_init */
-		return -1;
-	return raw3215_startup(raw);
-}
-
-/*
  * Write a string to the 3215 console
  */
 static void
@@ -1092,12 +1061,10 @@
 	}
 }
 
+
 /*
- * 3215 console driver boottime initialization code.
- * Register console. We can't request the IRQ here, because
- * it's too early (kmalloc isn't working yet). We'll have to
- * buffer all the console requests until we can request the
- * irq. For this purpose we use some pages of fixed memory.
+ * 3215 console initialization code called from console_init().
+ * NOTE: This is called before kmalloc is available.
  */
 void __init con3215_init(void)
 {
@@ -1121,6 +1088,8 @@
 		raw3215_freelist = req;
 	}
 
+	ctrlchar_init();
+
 #ifdef CONFIG_3215_CONSOLE
         raw3215[0] = raw = (raw3215_info *)
                 alloc_bootmem_low(sizeof(raw3215_info));
@@ -1135,6 +1104,10 @@
 	raw->tqueue.data = raw;
         init_waitqueue_head(&raw->empty_wait);
 
+	/* Request the console irq */
+	if ( raw3215_startup(raw) != 0 )
+		raw->irq = -1;
+
 	if (raw->irq != -1) {
 		register_console(&con3215);
 	} else {
@@ -1145,7 +1118,16 @@
 		printk("Couldn't find a 3215 console device\n");
 	}
 #endif
+}
 
+/*
+ * 3215 tty registration code called from tty_init().
+ * Most kernel services (incl. kmalloc) are available at this poimt.
+ */
+void __init tty3215_init(void)
+{
+	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
+                return;
 	/*
 	 * Initialize the tty_driver structure
 	 * Entries in tty3215_driver that are NOT initialized:
@@ -1166,7 +1148,7 @@
 	tty3215_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
 	tty3215_driver.init_termios.c_oflag = ONLCR | XTABS;
 	tty3215_driver.init_termios.c_lflag = ISIG;
-	tty3215_driver.flags = TTY_DRIVER_REAL_RAW;
+	tty3215_driver.flags = TTY_DRIVER_REAL_RAW; 
 	tty3215_driver.refcount = &tty3215_refcount;
 	tty3215_driver.table = tty3215_table;
 	tty3215_driver.termios = tty3215_termios;
@@ -1194,5 +1176,4 @@
 
 	if (tty_register_driver(&tty3215_driver))
 		panic("Couldn't register tty3215 driver\n");
-
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/ctrlchar.c linux/drivers/s390/char/ctrlchar.c
--- v2.4.3/linux/drivers/s390/char/ctrlchar.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/ctrlchar.c	Wed Apr 11 19:02:29 2001
@@ -0,0 +1,96 @@
+/*
+ *  drivers/s390/char/controlchar.c
+ *  Unified handling of special chars.
+ *
+ *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+
+#include <linux/sysrq.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+#include <asm/cpcmd.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static int ctrlchar_sysrq_key;
+static struct tq_struct ctrlchar_tq;
+
+static void
+ctrlchar_handle_sysrq(struct tty_struct *tty) {
+	handle_sysrq(ctrlchar_sysrq_key, NULL, NULL, tty);
+}
+#endif
+
+void ctrlchar_init(void) {
+#ifdef CONFIG_MAGIC_SYSRQ
+	static int init_done = 0;
+
+	if (init_done++)
+		return;
+	INIT_LIST_HEAD(&ctrlchar_tq.list);
+	ctrlchar_tq.sync = 0;
+	ctrlchar_tq.routine = ctrlchar_handle_sysrq;
+#endif
+}
+
+/**
+ * Check for special chars at start of input.
+ *
+ * @param buf Console input buffer.
+ * @param len Length of valid data in buffer.
+ * @param tty The tty struct for this console.
+ * @return NULL, if nothing matched, (char *)-1, if buffer contents
+ *         should be ignored, otherwise pointer to char to be inserted.
+ */
+char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty) {
+
+	static char ret;
+
+	if ((len < 2) || (len > 3))
+		return NULL;
+	/* hat is 0xb1 in codepage 037 (US etc.) and thus */
+	/* converted to 0x5e in ascii ('^') */
+	if ((buf[0] != '^') && (buf[0] != '\252'))
+		return NULL;
+	switch (buf[1]) {
+#ifdef CONFIG_MAGIC_SYSRQ
+		case '-':
+			if (len == 3) {
+				ctrlchar_sysrq_key = buf[2];
+				ctrlchar_tq.data = tty;
+				queue_task(&ctrlchar_tq, &tq_immediate);
+				mark_bh(IMMEDIATE_BH);
+				return (char *)-1;
+			}
+			break;
+#endif
+		case 'c':
+			if (len == 2) {
+				ret = INTR_CHAR(tty);
+				return &ret;
+			}
+			break;
+		case 'd':
+			if (len == 2) {
+				ret = EOF_CHAR(tty);
+				return &ret;
+			}
+			break;
+		case 'z':
+			if (len == 2) {
+				ret = SUSP_CHAR(tty);
+				return &ret;
+			}
+			break;
+	}
+	return NULL;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/ctrlchar.h linux/drivers/s390/char/ctrlchar.h
--- v2.4.3/linux/drivers/s390/char/ctrlchar.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/ctrlchar.h	Thu Apr 12 12:16:35 2001
@@ -0,0 +1,14 @@
+/*
+ *  drivers/s390/char/controlchar.c
+ *  Unified handling of special chars.
+ *
+ *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/tty.h>
+
+extern void ctrlchar_init(void);
+extern char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty);
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h
--- v2.4.3/linux/drivers/s390/char/hwc.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/hwc.h	Wed Apr 11 19:02:29 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 --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_con.c linux/drivers/s390/char/hwc_con.c
--- v2.4.3/linux/drivers/s390/char/hwc_con.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/hwc_con.c	Wed Apr 11 19:02:29 2001
@@ -17,14 +17,13 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 
+#include "ctrlchar.h"
 #include "hwc_rw.h"
 
-extern void hwc_tty_init (void);
-
 #ifdef CONFIG_HWC_CONSOLE
 
 #define  hwc_console_major 4
-#define  hwc_console_minor 0
+#define  hwc_console_minor 64
 #define  hwc_console_name  "console"
 
 void hwc_console_write (struct console *, const char *, unsigned int);
@@ -84,17 +83,16 @@
 hwc_console_init (void)
 {
 
-#ifdef CONFIG_3215
+#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
 	if (MACHINE_IS_VM)
 		return;
 #endif
 	if (MACHINE_IS_P390)
 		return;
 
+	ctrlchar_init ();
+  
 	if (hwc_init () == 0) {
-
-		hwc_tty_init ();
-
 #ifdef CONFIG_HWC_CONSOLE
 
 		register_console (&hwc_console);
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
--- v2.4.3/linux/drivers/s390/char/hwc_rw.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/hwc_rw.c	Wed Apr 11 19:02:29 2001
@@ -30,9 +30,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
@@ -118,16 +122,16 @@
 static unsigned char
  _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
 
-/* pedantic: long because we use set_bit on it --RR */
-typedef long 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 +173,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 +182,8 @@
 	spinlock_t lock;
 
 	struct timer_list write_timer;
+
+	struct timer_list poll_timer;
 } hwc_data =
 {
 	{
@@ -186,7 +193,7 @@
 		    0,
 		    80,
 		    1,
-		    50,
+		    MAX_KMEM_PAGES,
 		    MAX_KMEM_PAGES,
 
 		    0,
@@ -214,6 +221,7 @@
 	    0,
 	    0,
 	    0,
+	    0,
 	    NULL
 
 };
@@ -345,9 +353,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;
 }
 
@@ -647,25 +652,58 @@
 	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
@@ -688,6 +726,8 @@
 	case HWC_BUSY:
 		retval = -EBUSY;
 		break;
+	case HWC_NOT_OPERATIONAL:
+		start_poll_hwc ();
 	default:
 		retval = -EIO;
 	}
@@ -710,7 +750,7 @@
 write_event_data_2 (void)
 {
 	write_hwcb_t *hwcb;
-	int retval;
+	int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	unsigned char *param;
@@ -765,11 +805,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
@@ -782,6 +833,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;
 
@@ -826,9 +884,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;
 
@@ -937,7 +995,7 @@
 				if (obuf_cursor < obuf_columns) {
 					hwc_data.obuf[hwc_data.obuf_start +
 						      obuf_cursor]
-					    = 0x20;
+					    = HWC_ASCEBC (' ');
 					obuf_cursor++;
 				} else
 					break;
@@ -955,7 +1013,7 @@
 			while (spaces) {
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor - spaces]
-				    = 0x20;
+				    = HWC_ASCEBC (' ');
 				spaces--;
 			}
 
@@ -985,9 +1043,7 @@
 			if (isprint (ch))
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor++]
-				    = (MACHINE_IS_VM) ?
-				    _ascebc[ch] :
-				    _ascebc_500[ch];
+				    = HWC_ASCEBC (ch);
 		}
 		if (obuf_cursor > obuf_count)
 			obuf_count = obuf_cursor;
@@ -1006,11 +1062,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);
@@ -1022,7 +1077,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;
 
@@ -1306,14 +1361,11 @@
 	if (hwc_data.ioctls.delim)
 		count = seperate_cases (start, count);
 
-	if (MACHINE_IS_VM)
-		EBCASC (start, count);
-	else
-		EBCASC_500 (start, count);
+	HWC_EBCASC_STR (start, count);
 
-	if (hwc_data.ioctls.echo) {
+	if (hwc_data.ioctls.echo)
 		do_hwc_write (0, start, count, IMMEDIATE_WRITE);
-	}
+
 	if (hwc_data.calls != NULL)
 		if (hwc_data.calls->move_input != NULL)
 			(hwc_data.calls->move_input) (start, count);
@@ -1416,7 +1468,7 @@
 	return retval;
 }
 
-inline static int 
+static int 
 eval_evbuf (gds_vector_t * start, void *end)
 {
 	gds_vector_t *vec;
@@ -1434,6 +1486,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)
 {
@@ -1466,17 +1640,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;
@@ -1491,11 +1665,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));
@@ -1601,26 +1778,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:
@@ -1677,27 +1849,7 @@
 	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)\n\t"
@@ -1707,8 +1859,24 @@
 	      :	 "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;
@@ -1934,6 +2102,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 ();
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c
--- v2.4.3/linux/drivers/s390/char/hwc_tty.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/hwc_tty.c	Thu Apr 12 12:16:35 2001
@@ -9,12 +9,15 @@
  *  Thanks to Martin Schwidefsky.
  */
 
+#include <linux/config.h>
 #include <linux/major.h>
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -184,29 +187,13 @@
 	struct tty_struct *tty = hwc_tty_data.tty;
 
 	if (tty != NULL) {
-
-		if (count == 2 && (
-		/* hat is 0xb0 in codepage 037 (US etc.) and thus */
-		/* converted to 0x5e in ascii ('^') */
-					  strncmp (buf, "^c", 2) == 0 ||
-		/* hat is 0xb0 in several other codepages (German, */
-		/* UK, ...) and thus converted to ascii octal 252 */
-					  strncmp (buf, "\0252c", 2) == 0)) {
-			tty->flip.count++;
-			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-			*tty->flip.char_buf_ptr++ = INTR_CHAR (tty);
-		} else if (count == 2 && (
-						 strncmp (buf, "^d", 2) == 0 ||
-					   strncmp (buf, "\0252d", 2) == 0)) {
-			tty->flip.count++;
-			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-			*tty->flip.char_buf_ptr++ = EOF_CHAR (tty);
-		} else if (count == 2 && (
-						 strncmp (buf, "^z", 2) == 0 ||
-					   strncmp (buf, "\0252z", 2) == 0)) {
+		char *cchar;
+		if ((cchar = ctrlchar_handle (buf, count, tty))) {
+			if (cchar == (char *) -1)
+				return;
 			tty->flip.count++;
 			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-			*tty->flip.char_buf_ptr++ = SUSP_CHAR (tty);
+			*tty->flip.char_buf_ptr++ = *cchar;
 		} else {
 
 			memcpy (tty->flip.char_buf_ptr, buf, count);
@@ -230,6 +217,13 @@
 void 
 hwc_tty_init (void)
 {
+#ifdef CONFIG_3215
+	if (MACHINE_IS_VM)
+		return;
+#endif
+	if (MACHINE_IS_P390)
+		return;
+
 	memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
 	memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
 	hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape.c linux/drivers/s390/char/tape.c
--- v2.4.3/linux/drivers/s390/char/tape.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape.c	Wed Apr 11 19:02:28 2001
@@ -1,14 +1,13 @@
 
 /***********************************************************************
  *  drivers/s390/char/tape.c
- *    tape device driver for S/390 tapes.
+ *    tape device driver for S/390 and zSeries tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress... :-)
  ***********************************************************************
  */
 
@@ -34,9 +33,21 @@
 #include <asm/s390dyn.h>
 #endif
 #include "tape.h"
+#ifdef CONFIG_S390_TAPE_3490
 #include "tape3490.h"
+#endif
+#ifdef CONFIG_S390_TAPE_3480
 #include "tape3480.h"
-
+#endif
+#ifdef CONFIG_S390_TAPE_BLOCK
+#include "tapeblock.h"
+#endif
+#ifdef CONFIG_S390_TAPE_CHAR
+#include "tapechar.h"
+#endif
+#ifdef CONFIG_PROC_FS
+#include <linux/vmalloc.h>
+#endif
 #define PRINTK_HEADER "T390:"
 
 /* state handling routines */
@@ -91,29 +102,118 @@
 char* event_verbose[TE_SIZE]= {
     "TE_START", "TE_DONE", "TE_FAILED", "TE_ERROR", "TE_OTHER"};
 
-#ifdef CONFIG_PROC_FS		/* don't waste space if unused */
-/*
- * The proc filesystem: function to read and entry
- */
-int
-tape_read_procmem (char *buf, char **start, off_t offset,
-		   int len, int unused)
+/* our root devfs handle */
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t tape_devfs_root_entry;
+
+inline void
+tape_mkdevfsroots (tape_info_t* tape) 
+{
+    char devno [5];
+    sprintf (devno,"%04X",tape->devinfo.devno);
+    tape->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, tape);
+}
+
+inline void
+tape_rmdevfsroots (tape_info_t* tape)
+{
+    devfs_unregister (tape->devfs_dir);
+}
+#endif
+
+#ifdef CONFIG_PROC_FS
+/* our proc tapedevices entry */
+static struct proc_dir_entry *tape_devices_entry;
+
+typedef struct {
+	char *data;
+	int len;
+} tempinfo_t;
+
+
+static int
+tape_devices_open (struct inode *inode, struct file *file)
+{
+    int size=80;
+    tape_info_t* tape;
+    tempinfo_t* tempinfo;
+    char* data;
+    int pos=0;
+    tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL);
+    if (!tempinfo)
+        return -ENOMEM;
+    for (tape=first_tape_info;tape!=NULL;tape=tape->next)
+        size+=80; // FIXME: Guess better!
+    data=vmalloc(size);
+    if (!data) {
+        kfree (tempinfo);
+        return -ENOMEM;
+    }
+    pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n");
+    for (tape=first_tape_info;tape!=NULL;tape=tape->next) {
+        pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",tape->rew_minor/2,
+                     tape->devinfo.devno,tape->devinfo.sid_data.cu_type,
+                     tape->devinfo.sid_data.cu_model,tape->devinfo.sid_data.dev_type,
+                     tape->devinfo.sid_data.dev_model,((tapestate_get(tape) >= 0) &&
+                                                       (tapestate_get(tape) < TS_SIZE)) ?
+                     state_verbose[tapestate_get (tape)] : "TS UNKNOWN");
+    }
+    tempinfo->len=pos;
+    tempinfo->data=data;
+    file->private_data= (void*) tempinfo;
+#ifdef MODULE
+    MOD_INC_USE_COUNT;
+#endif
+    return 0;
+}
+
+static ssize_t
+tape_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (*offset >= p_info->len) {
+		return 0;	/* EOF */
+	} else {
+		len =  user_len<(p_info->len - *offset)?user_len:(p_info->len - *offset);
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;	/* number of bytes "read" */
+	}
+}
+
+static int
+tape_devices_release (struct inode *inode, struct file *file)
 {
-	tape_info_t *tape = first_tape_info;
-	len = sprintf (buf, "minor\tstate\n");
-	do {
-		if (len >= PAGE_SIZE - 80)
-			len += sprintf (buf + len, "terminated...\n");
-		len += sprintf (buf + len,
-				"%d\t%s\n", tape->rew_minor,
-				((tapestate_get (tape) >= 0) && (tapestate_get (tape) < TS_SIZE)) ?
-				state_verbose[tapestate_get (tape)] :
-				"UNKNOWN STATE");
-	} while ((tape = (tape_info_t *) (tape->next)) != NULL);
-	return len;
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		kfree (p_info);
+	}
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
+	return rc;
 }
 
-#endif				/* CONFIG_PROC_FS */
+static struct file_operations tape_devices_file_ops =
+{
+	read:tape_devices_read,	/* read */
+	open:tape_devices_open,	/* open */
+	release:tape_devices_release,	/* close */
+};
+
+static struct inode_operations tape_devices_inode_ops =
+{
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	default_file_ops:&tape_devices_file_ops		/* file ops */
+#endif				/* LINUX_IS_24 */
+};
+#endif /* CONFIG_PROC_FS */
 
 /* SECTION: Managing wrappers for ccwcache */
 
@@ -258,7 +358,11 @@
     int rc,tape_num,retries=0;
     s390_dev_info_t dinfo;
     tape_discipline_t* disc;
+#ifdef CONFIG_DEVFS_FS
+    tape_frontend_t* frontend;
+#endif
     long lockflags;
+    PRINT_WARN ("oper handler was called\n");
     while ((tape!=NULL) && (tape->devinfo.irq!=irq)) 
         tape=tape->next;
     if (tape!=NULL) {
@@ -270,13 +374,19 @@
     rc = get_dev_info_by_irq (irq, &dinfo);
     if (rc == -ENODEV) {
         retries++;
-        if (retries > 5)
+        rc = get_dev_info_by_irq (irq, &dinfo);
+        if (retries > 5) {
+            PRINT_WARN ("No device information for new dev. could be retrieved.\n");
             return -ENODEV;
+        }
     }
     disc = first_discipline;
     while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
         disc = (tape_discipline_t *) (disc->next);
-    
+    if (disc == NULL)
+        PRINT_WARN ("No matching discipline for cu_type %x found\n",dinfo.sid_data.cu_type);
+    if (rc == -ENODEV) 
+        PRINT_WARN ("No device information for new dev. could be retrieved.\n");
     if ((disc == NULL) || (rc == -ENODEV))
         return -ENODEV;
     
@@ -287,6 +397,7 @@
                     "tape info structure\n");
         return -ENOBUFS;
     }
+    memset(tape,0,sizeof(tape_info_t));
     tape->discipline = disc;
     disc->tape = tape;
     tape_num=0;
@@ -306,6 +417,10 @@
         kfree (tape);
         return -ENOBUFS;
     }
+#ifdef CONFIG_DEVFS_FS
+    for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) 
+        frontend->mkdevfstree(tape);
+#endif
     s390irq_spin_lock_irqsave (irq,lockflags);
     if (first_tape_info == NULL) {
         first_tape_info = tape;
@@ -324,41 +439,61 @@
 tape_noper_handler ( int irq, int status ) {
     tape_info_t *ti=first_tape_info;
     tape_info_t *lastti;
+#ifdef CONFIG_DEVFS_FS
+    tape_frontend_t *frontend;
+#endif
     long lockflags;
     s390irq_spin_lock_irqsave(irq,lockflags);
-    while (ti!=NULL) {
-        if (ti->devinfo.irq==irq) {
-            tapestate_set(ti,TS_NOT_OPER);
-            if (tapestate_get(ti)!=TS_UNUSED) {
-                // device is in use!
-                PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor);
-                ti->rc=-ENXIO; 
-                wake_up_interruptible(&ti->wq);
-            } else {
-                // device is unused!
-                if (ti==first_tape_info) {
-                    first_tape_info=ti->next;
-                } else {
-                    lastti=first_tape_info;
-                    while (lastti->next!=ti) lastti=lastti->next;
-                    lastti->next=ti->next;
-                }
-                kfree(ti);
-            }
-            s390irq_spin_unlock_irqrestore(irq,lockflags);
-            return;
+    while (ti!=NULL && ti->devinfo.irq!=irq) ti=ti->next;
+    if (ti==NULL) return;
+    if (tapestate_get(ti)!=TS_UNUSED) {
+        // device is in use!
+        PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor/2);
+        tapestate_set(ti,TS_NOT_OPER);
+        ti->rc=-ENODEV; 
+	ti->wanna_wakeup=1;
+	switch (tapestate_get(ti)) {
+	case TS_REW_RELEASE_INIT:
+	    tapestate_set(ti,TS_NOT_OPER);
+	    wake_up (&ti->wq);
+	    break;
+#ifdef CONFIG_S390_TAPE_BLOCK
+	case TS_BLOCK_INIT:
+	    tapestate_set(ti,TS_NOT_OPER);
+	    schedule_tapeblock_exec_IO(ti);
+	    break;
+#endif
+	default:
+	    tapestate_set(ti,TS_NOT_OPER);
+	    wake_up_interruptible (&ti->wq);
+	}
+    } else {
+        // device is unused!
+        PRINT_WARN ("Tape #%d was detached.\n",ti->blk_minor/2);
+        if (ti==first_tape_info) {
+            first_tape_info=ti->next;
+        } else {
+            lastti=first_tape_info;
+            while (lastti->next!=ti) lastti=lastti->next;
+            lastti->next=ti->next;
         }
-        ti=ti->next;
+#ifdef CONFIG_DEVFS_FS
+        for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next)
+            frontend->rmdevfstree(ti);
+        tape_rmdevfsroots(ti);
+#endif
+        kfree(ti);
     }
     s390irq_spin_unlock_irqrestore(irq,lockflags);
-    PRINT_WARN ("Tape not found for irq %d. Device is detached.",irq);
+    return;
 }
 
 
 void
 tape_dump_sense (devstat_t * stat)
 {
-	int sl, sct;
+	int sl;
+#if 0
 	PRINT_WARN ("------------I/O resulted in unit check:-----------\n");
 	for (sl = 0; sl < 4; sl++) {
 		PRINT_WARN ("Sense:");
@@ -388,6 +523,7 @@
 		    stat->ii.sense.data[26], stat->ii.sense.data[27],
 		    stat->ii.sense.data[28], stat->ii.sense.data[29],
 		    stat->ii.sense.data[30], stat->ii.sense.data[31]);
+#endif
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"SENSE:");
         for (sl=0;sl<31;sl++) {
@@ -413,6 +549,9 @@
 	ti->rew_minor = minor;
 	ti->nor_minor = minor + 1;
 	ti->blk_minor = minor;
+#ifdef CONFIG_DEVFS_FS
+        tape_mkdevfsroots(ti);
+#endif
 	/* Register IRQ */
 #ifdef CONFIG_S390_TAPE_DYNAMIC
         rc = s390_request_irq_special (irq, tape_irq, tape_noper_handler,0, "tape", &(ti->devstat));
@@ -424,7 +563,7 @@
 	if (rc) {
 		PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
 	} else
-		PRINT_WARN ("Register irq %d for using with discipline %x\n", irq, ti->discipline->cu_type);
+		PRINT_WARN ("Register irq %d for using with discipline %x dev #%d\n", irq, ti->discipline->cu_type,ti->blk_minor/2);
 	init_waitqueue_head (&ti->wq);
 	ti->kernbuf = ti->userbuf = ti->discdata = NULL;
 	tapestate_set (ti, TS_UNUSED);
@@ -460,7 +599,7 @@
 #endif /* TAPE_DEBUG */
 
         /* print banner */        
-        PRINT_WARN ("IBM S/390 Tape Device Driver (ALPHA).\n");
+        PRINT_WARN ("IBM S/390 Tape Device Driver (BETA).\n");
         PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000\n");
         opt_char=opt_block=opt_3480=opt_3490="not present";
 #ifdef CONFIG_S390_TAPE_CHAR
@@ -496,6 +635,9 @@
             ((tape_discipline_t*) (first_discipline->next))->next=NULL;
         }
 #endif
+#ifdef CONFIG_DEVFS_FS
+        tape_devfs_root_entry=devfs_mk_dir (NULL, "tape", NULL);
+#endif CONFIG_DEVFS_FS
 
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"dev detect");
@@ -558,17 +700,40 @@
 
 	/* Allocate local buffer for the ccwcache       */
 	tape_init_emergency_req ();
-
-#if 0				// need to register s.th. for proc? FIXME!
-	if (proc_register_dynamic (&proc_root, &proc_root_tape))
-		PRINT_INFO (KERN_ERR "tape: registering "
-			    "/proc/tape failed\n");
+#ifdef CONFIG_PROC_FS
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	tape_devices_entry = create_proc_entry ("tapedevices",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						&proc_root);
+	tape_devices_entry->proc_fops = &tape_devices_file_ops;
+	tape_devices_entry->proc_iops = &tape_devices_inode_ops;
+#else
+	tape_devices_entry = (struct proc_dir_entry *) kmalloc 
+            (sizeof (struct proc_dir_entry), GFP_ATOMIC);
+        if (tape_devices_entry) {
+            memset (tape_devices_entry, 0, sizeof (struct proc_dir_entry));
+            tape_devices_entry->name = "tapedevices";
+            tape_devices_entry->namelen = strlen ("tapedevices");
+            tape_devices_entry->low_ino = 0;
+            tape_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
+            tape_devices_entry->nlink = 1;
+            tape_devices_entry->uid = 0;
+            tape_devices_entry->gid = 0;
+            tape_devices_entry->size = 0;
+            tape_devices_entry->get_info = NULL;
+            tape_devices_entry->ops = &tape_devices_inode_ops;
+            proc_register (&proc_root, tape_devices_entry);
+	}
 #endif
+#endif /* CONFIG_PROC_FS */
 
 	return 0;
 }
 
 #ifdef MODULE
+MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte (cotte@de.ibm.com)");
+MODULE_DESCRIPTION("Linux for S/390 channel attached tape device driver");
+
 int
 init_module (void)
 {
@@ -578,7 +743,7 @@
 #ifdef CONFIG_S390_TAPE_BLOCK
 	tapeblock_init ();
 #endif
-	return 0;
+        return 0;
 }
 
 void
@@ -591,10 +756,6 @@
         debug_text_event (tape_debug_area,6,"cleaup mod");
 #endif /* TAPE_DEBUG */
 
-#if 0				/* FIXME: Do we need to register s.th? */
-	proc_unregister (&proc_root, proc_root_tape.low_ino);
-#endif
-
 	tape = first_tape_info;
 	while (tape != NULL) {
 		temp = tape;
@@ -607,13 +768,25 @@
 		free_irq (temp->devinfo.irq, &(temp->devstat));
                 if (temp->discdata) kfree (temp->discdata);
                 if (temp->kernbuf) kfree (temp->kernbuf);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) // COMPAT:FIXME
-#else
-                kfree (temp->wq);
-#endif
                 if (temp->cqr) tape_free_request(temp->cqr);
+#ifdef CONFIG_DEVFS_FS
+                for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next)
+                    frontend->rmdevfstree(temp);
+                tape_rmdevfsroots(temp);
+#endif
 		kfree (temp);
 	}
+#ifdef CONFIG_DEVFS_FS
+        devfs_unregister (tape_devfs_root_entry);
+#endif CONFIG_DEVFS_FS
+#ifdef CONFIG_PROC_FS
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	remove_proc_entry ("devices", &proc_root);
+#else
+	proc_unregister (&proc_root, tape_devices_entry->low_ino);
+	kfree (tape_devices_entry);
+#endif				/* LINUX_IS_24 */
+#endif 
 #ifdef CONFIG_S390_TAPE_CHAR
 	tapechar_uninit();
 #endif
@@ -689,18 +862,22 @@
                          state_verbose[tapestate_get (tape)] :
                          "TS UNKNOWN");
 #endif /* TAPE_DEBUG */    
-	if ((event >= 0) &&
-	    (event < TE_SIZE) &&
-	    (tapestate_get (tape) >= 0) &&
-	    (tapestate_get (tape) < TS_SIZE) &&
-	    ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL))
+        if (event == TE_ERROR) { 
+            tape->discipline->error_recovery(tape);
+        } else {
+            if ((event >= 0) &&
+                (event < TE_SIZE) &&
+                (tapestate_get (tape) >= 0) &&
+                (tapestate_get (tape) < TS_SIZE) &&
+                ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL))
 		((*(tape->discipline->event_table))[tapestate_get (tape)][event]) (tape);
-	else {
+            else {
 #ifdef TAPE_DEBUG
                 debug_text_exception (tape_debug_area,3,"TE UNEXPEC");
 #endif /* TAPE_DEBUG */
 		tape->discipline->default_handler (tape);
-	}
+            }
+        }
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape.h linux/drivers/s390/char/tape.h
--- v2.4.3/linux/drivers/s390/char/tape.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape.h	Wed Apr 11 19:02:28 2001
@@ -1,15 +1,13 @@
-
 /***************************************************************************
  *
  *  drivers/s390/char/tape.h
  *    tape device driver for 3480/3490E tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
@@ -71,10 +69,14 @@
 typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* tape);
 typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* tape);
 typedef void (*tape_setup_assist_t) (struct _tape_info_t*);
+#ifdef CONFIG_DEVFS_FS
+typedef void (*tape_devfs_handler_t) (struct _tape_info_t*);
+#endif
 typedef tape_event_handler_t tape_event_table_t[TS_SIZE][TE_SIZE];
 typedef struct _tape_discipline_t {
     unsigned int cu_type;
     tape_setup_assist_t setup_assist;
+    tape_event_handler_t error_recovery;
     tape_reqgen_t bread;
     tape_freeblock_t free_bread;
     tape_rwblock_t write_block;
@@ -115,6 +117,10 @@
 
 typedef struct _tape_frontend_t {
     tape_setup_assist_t device_setup;
+#ifdef CONFIG_DEVFS_FS
+    tape_devfs_handler_t mkdevfstree;
+    tape_devfs_handler_t rmdevfstree;
+#endif
     void* next;
 } tape_frontend_t  __attribute__ ((aligned(8)));
 
@@ -142,6 +148,14 @@
     ccw_req_t* cqr;
     atomic_t bh_scheduled;
     struct tq_struct bh_tq;
+#ifdef CONFIG_DEVFS_FS
+    devfs_handle_t devfs_dir;             /* devfs handle for tape/DEVNO directory */
+    devfs_handle_t devfs_char_dir;        /* devfs handle for tape/DEVNO/char directory */
+    devfs_handle_t devfs_block_dir;       /* devfs handle for tape/DEVNO/block directory */
+    devfs_handle_t devfs_nonrewinding;    /* devfs handle for tape/DEVNO/char/nonrewinding device */
+    devfs_handle_t devfs_rewinding;       /* devfs handle for tape/DEVNO/char/rewinding device */
+    devfs_handle_t devfs_disc;            /* devfs handle for tape/DEVNO/block/disc device */
+#endif
     void* discdata;
     void* kernbuf;
     void* userbuf;
@@ -167,6 +181,7 @@
 /* functions for handling the status of a device */
 inline void tapestate_set (tape_info_t * tape, int newstate);
 inline int tapestate_get (tape_info_t * tape);
+void tapestate_event (tape_info_t * tape, int event);
 extern char* state_verbose[TS_SIZE];
 extern char* event_verbose[TE_SIZE];
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3480.c linux/drivers/s390/char/tape3480.c
--- v2.4.3/linux/drivers/s390/char/tape3480.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape3480.c	Wed Apr 11 19:02:28 2001
@@ -3,12 +3,11 @@
  *  drivers/s390/char/tape3480.c
  *    tape device discipline for 3480 tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
- *
- *  UNDER CONSTRUCTION: Work in progress...:-)
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ * 
  ****************************************************************************
  */
 
@@ -25,31 +24,31 @@
 tape_event_handler_t tape3480_event_handler_table[TS_SIZE][TE_SIZE] =
 {
     /* {START , DONE, FAILED, ERROR, OTHER } */
-	{NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL},	/* TS_UNUSED */
-	{NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL},	/* TS_IDLE */
+	{NULL, tape34xx_unused_done, NULL, NULL, NULL},	/* TS_UNUSED */
+	{NULL, tape34xx_idle_done, NULL, NULL, NULL},	/* TS_IDLE */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_DONE */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_FAILED */
-	{NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL},		/* TS_BLOCK_INIT */
+	{NULL, tape34xx_block_done, NULL, NULL, NULL},		/* TS_BLOCK_INIT */
 	{NULL, tape34xx_bsb_init_done, NULL, NULL, NULL},	/* TS_BSB_INIT */
 	{NULL, tape34xx_bsf_init_done, NULL, NULL, NULL},	/* TS_BSF_INIT */
 	{NULL, tape34xx_dse_init_done, NULL, NULL, NULL},	/* TS_DSE_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_EGA_INIT */
 	{NULL, tape34xx_fsb_init_done, NULL, NULL, NULL},	/* TS_FSB_INIT */
-	{NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL},	/* TS_FSF_INIT */
+	{NULL, tape34xx_fsf_init_done, NULL, NULL, NULL},	/* TS_FSF_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_LDI_INIT */
-	{NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL},	/* TS_LBL_INIT */
+	{NULL, tape34xx_lbl_init_done, NULL, NULL, NULL},	/* TS_LBL_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_MSE_INIT */
 	{NULL, tape34xx_nop_init_done, NULL, NULL, NULL},	/* TS_NOP_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBA_INIT */
+	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},		/* TS_RBA_INIT */
 	{NULL, tape34xx_rbi_init_done, NULL, NULL, NULL},	/* TS_RBI_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBU_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBL_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RDC_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL},	/* TS_RFO_INIT */
+	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},	/* TS_RFO_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RSD_INIT */
-	{NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL},	/* TS_REW_INIT */
-	{NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL},	/* TS_REW_RELEASE_IMIT */
-	{NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL},	/* TS_RUN_INIT */
+	{NULL, tape34xx_rew_init_done, NULL, NULL, NULL},	/* TS_REW_INIT */
+	{NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL},	/* TS_REW_RELEASE_IMIT */
+	{NULL, tape34xx_run_init_done, NULL, NULL, NULL},	/* TS_RUN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SEN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SID_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SNP_INIT */
@@ -59,14 +58,16 @@
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SYN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_TIO_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_UNA_INIT */
-	{NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL},	/* TS_WRI_INIT */
-	{NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL},	/* TS_WTM_INIT */
+	{NULL, tape34xx_wri_init_done, NULL, NULL, NULL},	/* TS_WRI_INIT */
+	{NULL, tape34xx_wtm_init_done, NULL, NULL, NULL},	/* TS_WTM_INIT */
         {NULL, NULL, NULL, NULL, NULL}};     /* TS_NOT_OPER */
 
 devreg_t tape3480_devreg = {
-    ci : { hc: { ctype: 0x3480, dtype: 0x3480 } }, 
-    flag: DEVREG_MATCH_CU_TYPE,
-    oper_func: tape_oper_handler
+    ci:
+    {hc:
+     {ctype:0x3480}},
+    flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS,
+    oper_func:tape_oper_handler
 };
 
 
@@ -101,6 +102,7 @@
 	}
 	disc->cu_type = 0x3480;
 	disc->setup_assist = tape3480_setup_assist;
+	disc->error_recovery = tape34xx_error_recovery;
 	disc->write_block = tape34xx_write_block;
 	disc->free_write_block = tape34xx_free_write_block;
 	disc->read_block = tape34xx_read_block;
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3480.h linux/drivers/s390/char/tape3480.h
--- v2.4.3/linux/drivers/s390/char/tape3480.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape3480.h	Wed Apr 11 19:02:28 2001
@@ -1,15 +1,13 @@
-
 /***************************************************************************
  *
  *  drivers/s390/char/tape3480.h
  *    tape device discipline for 3480 tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3490.c linux/drivers/s390/char/tape3490.c
--- v2.4.3/linux/drivers/s390/char/tape3490.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape3490.c	Wed Apr 11 19:02:28 2001
@@ -3,12 +3,11 @@
  *  drivers/s390/char/tape3490.c
  *    tape device discipline for 3490E tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
@@ -25,31 +24,31 @@
 tape_event_handler_t tape3490_event_handler_table[TS_SIZE][TE_SIZE] =
 {
     /* {START , DONE, FAILED, ERROR, OTHER } */
-	{NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL},	/* TS_UNUSED */
-	{NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL},	/* TS_IDLE */
+	{NULL, tape34xx_unused_done, NULL, NULL, NULL},	/* TS_UNUSED */
+	{NULL, tape34xx_idle_done, NULL, NULL, NULL},	/* TS_IDLE */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_DONE */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_FAILED */
-	{NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL},		/* TS_BLOCK_INIT */
+	{NULL, tape34xx_block_done, NULL, NULL, NULL},		/* TS_BLOCK_INIT */
 	{NULL, tape34xx_bsb_init_done, NULL, NULL, NULL},	/* TS_BSB_INIT */
 	{NULL, tape34xx_bsf_init_done, NULL, NULL, NULL},	/* TS_BSF_INIT */
 	{NULL, tape34xx_dse_init_done, NULL, NULL, NULL},	/* TS_DSE_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_EGA_INIT */
 	{NULL, tape34xx_fsb_init_done, NULL, NULL, NULL},	/* TS_FSB_INIT */
-	{NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL},	/* TS_FSF_INIT */
+	{NULL, tape34xx_fsf_init_done, NULL, NULL, NULL},	/* TS_FSF_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_LDI_INIT */
-	{NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL},	/* TS_LBL_INIT */
+	{NULL, tape34xx_lbl_init_done, NULL, NULL, NULL},	/* TS_LBL_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_MSE_INIT */
 	{NULL, tape34xx_nop_init_done, NULL, NULL, NULL},	/* TS_NOP_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBA_INIT */
+	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},		/* TS_RBA_INIT */
 	{NULL, tape34xx_rbi_init_done, NULL, NULL, NULL},	/* TS_RBI_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBU_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBL_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RDC_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL},	/* TS_RFO_INIT */
+	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},	/* TS_RFO_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RSD_INIT */
-	{NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL},	/* TS_REW_INIT */
-	{NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL},	/* TS_REW_RELEASE_IMIT */
-	{NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL},	/* TS_RUN_INIT */
+	{NULL, tape34xx_rew_init_done, NULL, NULL, NULL},	/* TS_REW_INIT */
+	{NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL},	/* TS_REW_RELEASE_IMIT */
+	{NULL, tape34xx_run_init_done, NULL, NULL, NULL},	/* TS_RUN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SEN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SID_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SNP_INIT */
@@ -59,14 +58,16 @@
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SYN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_TIO_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_UNA_INIT */
-	{NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL},	/* TS_WRI_INIT */
-	{NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL},	/* TS_WTM_INIT */
+	{NULL, tape34xx_wri_init_done, NULL, NULL, NULL},	/* TS_WRI_INIT */
+	{NULL, tape34xx_wtm_init_done, NULL, NULL, NULL},	/* TS_WTM_INIT */
         {NULL, NULL, NULL, NULL, NULL}};     /* TS_NOT_OPER */
 
 devreg_t tape3490_devreg = {
-    ci : { hc: { ctype: 0x3490, dtype: 0x3490 } }, 
-    flag: DEVREG_MATCH_CU_TYPE,
-    oper_func: tape_oper_handler
+    ci:
+    {hc:
+     {ctype:0x3490}},
+    flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS,
+    oper_func:tape_oper_handler
 };
 
 void
@@ -100,6 +101,7 @@
 	}
 	disc->cu_type = 0x3490;
 	disc->setup_assist = tape3490_setup_assist;
+	disc->error_recovery = tape34xx_error_recovery;
 	disc->write_block = tape34xx_write_block;
 	disc->free_write_block = tape34xx_free_write_block;
 	disc->read_block = tape34xx_read_block;
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3490.h linux/drivers/s390/char/tape3490.h
--- v2.4.3/linux/drivers/s390/char/tape3490.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape3490.h	Wed Apr 11 19:02:28 2001
@@ -4,12 +4,11 @@
  *  drivers/s390/char/tape3490.h
  *    tape device discipline for 3490E tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c
--- v2.4.3/linux/drivers/s390/char/tape34xx.c	Fri Mar  2 11:12:07 2001
+++ linux/drivers/s390/char/tape34xx.c	Wed Apr 11 19:02:28 2001
@@ -3,12 +3,11 @@
  *  drivers/s390/char/tape34xx.c
  *    common tape device discipline for 34xx tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
@@ -36,19 +35,19 @@
 tape_event_handler_t tape34xx_event_handler_table[TS_SIZE][TE_SIZE] =
 {
     /* {START , DONE, FAILED, ERROR, OTHER } */
-	{NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL},	/* TS_UNUSED */
-	{NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL},	/* TS_IDLE */
+	{NULL, tape34xx_unused_done, NULL, NULL, NULL},	/* TS_UNUSED */
+	{NULL, tape34xx_idle_done, NULL, NULL, NULL},	/* TS_IDLE */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_DONE */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_FAILED */
-	{NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL},		/* TS_BLOCK_INIT */
+	{NULL, tape34xx_block_done, NULL, NULL, NULL},		/* TS_BLOCK_INIT */
 	{NULL, tape34xx_bsb_init_done, NULL, NULL, NULL},	/* TS_BSB_INIT */
 	{NULL, tape34xx_bsf_init_done, NULL, NULL, NULL},	/* TS_BSF_INIT */
 	{NULL, tape34xx_dse_init_done, NULL, NULL, NULL},	/* TS_DSE_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_EGA_INIT */
 	{NULL, tape34xx_fsb_init_done, NULL, NULL, NULL},	/* TS_FSB_INIT */
-	{NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL},	/* TS_FSF_INIT */
+	{NULL, tape34xx_fsf_init_done, NULL, NULL, NULL},	/* TS_FSF_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_LDI_INIT */
-	{NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL},	/* TS_LBL_INIT */
+	{NULL, tape34xx_lbl_init_done, NULL, NULL, NULL},	/* TS_LBL_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_MSE_INIT */
 	{NULL, tape34xx_nop_init_done, NULL, NULL, NULL},	/* TS_NOP_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBA_INIT */
@@ -56,11 +55,11 @@
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBU_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBL_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RDC_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL},	/* TS_RFO_INIT */
+	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},	/* TS_RFO_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_RSD_INIT */
-	{NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL},	/* TS_REW_INIT */
-	{NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL},	/* TS_REW_RELEASE_IMIT */
-	{NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL},	/* TS_RUN_INIT */
+	{NULL, tape34xx_rew_init_done, NULL, NULL, NULL},	/* TS_REW_INIT */
+	{NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL},	/* TS_REW_RELEASE_IMIT */
+	{NULL, tape34xx_run_init_done, NULL, NULL, NULL},	/* TS_RUN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SEN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SID_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SNP_INIT */
@@ -70,8 +69,8 @@
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_SYN_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_TIO_INIT */
 	{NULL, NULL, NULL, NULL, NULL},		/* TS_UNA_INIT */
-	{NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL},	/* TS_WRI_INIT */
-	{NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL},	/* TS_WTM_INIT */
+	{NULL, tape34xx_wri_init_done, NULL, NULL, NULL},	/* TS_WRI_INIT */
+	{NULL, tape34xx_wtm_init_done, NULL, NULL, NULL},	/* TS_WTM_INIT */
 	{NULL, NULL, NULL, NULL, NULL}};        /* TS_NOT_OPER */
 
 
@@ -205,6 +204,59 @@
 #endif /* TAPE_DEBUG */
 	return cqr;
 }
+ccw_req_t *
+tape34xx_read_opposite (tape_info_t * tape,int novalue)
+{
+	ccw_req_t *cqr;
+	ccw1_t *ccw;
+	size_t count;
+	// first, retrieve the count from the old cqr.
+	cqr = tape->cqr;
+	ccw = cqr->cpaddr;
+	ccw++;
+	count=ccw->count;
+	// free old cqr.
+	clear_normalized_cda (ccw);
+	tape_free_request (cqr);
+	// build new cqr
+	cqr = tape_alloc_ccw_req (tape, 3, 0);
+	if (!cqr) {
+#ifdef TAPE_DEBUG
+	        debug_text_exception (tape_debug_area,6,"xrop nomem");
+#endif /* TAPE_DEBUG */
+		return NULL;
+	}
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = MODE_SET_DB;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = 1;
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	ccw++;
+
+	ccw->cmd_code = READ_BACKWARD;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = count;
+	set_normalized_cda (ccw, (unsigned long) tape->kernbuf);
+	if ((ccw->cda) == 0) {
+		tape_free_request (cqr);
+		return NULL;
+	}
+	ccw++;
+	ccw->cmd_code = FORSPACEBLOCK;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = 1;
+	ccw->cda = (unsigned long)ccw;
+	ccw++;
+	ccw->cmd_code = NOP;
+	ccw->flags = 0;
+	ccw->count = 1;
+	ccw->cda = (unsigned long)ccw;
+	tapestate_set (tape, TS_RBA_INIT);
+#ifdef TAPE_DEBUG
+	debug_text_event (tape_debug_area,6,"xrop ccwg");
+#endif /* TAPE_DEBUG */
+	return cqr;
+}
 
 void 
 tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape)
@@ -233,7 +285,6 @@
 #endif /* TAPE_DEBUG */
 }
 
-
 /*
  * The IOCTL interface is implemented in the following section,
  * excepted the MTRESET, MTSETBLK which are handled by tapechar.c
@@ -1329,7 +1380,7 @@
 		else
 			bhct++;
 	}
-	if ((data = kmalloc (4 * sizeof (__u8), GFP_KERNEL)) == NULL) {
+	if ((data = kmalloc (4 * sizeof (__u8), GFP_ATOMIC)) == NULL) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,3,"xBREDnomem");
 #endif /* TAPE_DEBUG */
@@ -1395,9 +1446,8 @@
 					    size,
 					    blksize_size[tapeblock_major][tape->blk_minor],
 					    req->nr_sectors);
-
-				tape_free_request (cqr);
 				kfree(data);
+				tape_free_request (cqr);
 				return NULL;
 			}
 		}
@@ -1506,17 +1556,6 @@
 	}
 }
 
-void
-tape34xx_unused_error (tape_info_t * tape)
-{
-#ifdef TAPE_DEBUG
-    debug_text_event (tape_debug_area,3,"unsol.irq!");
-    debug_text_event (tape_debug_area,3,"unit chk!");
-    debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
-#endif /* TAPE_DEBUG */
-    PRINT_WARN ("Unsolicited IRQ (Unit Check) caught in unused state.\n");
-    tape_dump_sense (&tape->devstat);
-}
 
 void
 tape34xx_idle_done (tape_info_t * tape)
@@ -1531,18 +1570,6 @@
 }
 
 void
-tape34xx_idle_error (tape_info_t * tape)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"unsol.irq!");
-	debug_text_event (tape_debug_area,3,"unit chk!");
-	debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
-#endif /* TAPE_DEBUG */
-	PRINT_WARN ("Unsolicited IRQ (Unit Check) caught in idle state.\n");
-	tape_dump_sense (&tape->devstat);
-}
-
-void
 tape34xx_block_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1553,16 +1580,6 @@
 }
 
 void
-tape34xx_block_error (tape_info_t * tape)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"x:xREQfail");
-#endif /* TAPE_DEBUG */
-	tapestate_set(tape,TS_FAILED);
-	schedule_tapeblock_exec_IO(tape);
-}
-
-void
 tape34xx_bsf_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1599,27 +1616,6 @@
 }
 
 void
-tape34xx_fsf_init_error (tape_info_t * tape)
-{
-	if (((tape->devstat.ii.sense.data[0] == 0x08) ||	// sense.data[0]=08 -> first time
-	      (tape->devstat.ii.sense.data[0] == 0x10) ||	// an alternate one...
-	      (tape->devstat.ii.sense.data[0] == 0x12)) &&	// sense.data[1]=12 -> repeated message
-	     (tape->devstat.ii.sense.data[1] == 0x40)) {
-		// end of recorded area!
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"fsf fail");
-        debug_text_exception (tape_debug_area,3,"eoRecArea");
-#endif	/* TAPE_DEBUG */
-		tape->rc = -EIO;
-		tapestate_set (tape, TS_FAILED);
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-	} else {
-		tape34xx_unexpect_uchk_handler (tape);
-	}
-}
-
-void
 tape34xx_fsb_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1657,29 +1653,6 @@
 }
 
 void
-tape34xx_lbl_init_error (tape_info_t * tape)
-{
-	if (((tape->devstat.ii.sense.data[0] == 0x00) ||	// sense.data[0]=00 -> first time
-	      (tape->devstat.ii.sense.data[0] == 0x08) ||	// an alternate one...
-	     (tape->devstat.ii.sense.data[0] == 0x10) ||        // alternate, too
-	      (tape->devstat.ii.sense.data[0] == 0x12)) &&	// sense.data[1]=12 -> repeated message
-	     ((tape->devstat.ii.sense.data[1] == 0x40) ||
-	      (tape->devstat.ii.sense.data[1] == 0xc0))) {
-		// block not found!
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"lbl fail");
-        debug_text_exception (tape_debug_area,3,"blk nfound");
-#endif	/* TAPE_DEBUG */
-		tape->rc = -EIO;
-		tapestate_set (tape, TS_FAILED);
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-	} else {
-		tape34xx_unexpect_uchk_handler (tape);
-	}
-}
-
-void
 tape34xx_nop_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1699,11 +1672,8 @@
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rfo done");
 #endif
-	//BH: use irqsave
-	//s390irq_spin_lock(tape->devinfo.irq);
 	tapestate_set (tape, TS_DONE);
 	tape->rc = 0;
-	//s390irq_spin_unlock(tape->devinfo.irq);
 	tape->wanna_wakeup=1;
 	wake_up_interruptible (&tape->wq);
 }
@@ -1729,50 +1699,6 @@
 }
 
 void
-tape34xx_rfo_init_error (tape_info_t * tape)
-{
-	if (((tape->devstat.ii.sense.data[0] == 0x08) ||	// sense.data[0]=08 -> first time
-	      (tape->devstat.ii.sense.data[0] == 0x10) ||	// an alternate one...
-	      (tape->devstat.ii.sense.data[0] == 0x12)) &&	// sense.data[1]=12 -> repeated message
-	     (tape->devstat.ii.sense.data[1] == 0x40)) {
-		// end of recorded area!
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"rfo fail");
-        debug_text_exception (tape_debug_area,3,"eoRecArea");
-#endif	/* TAPE_DEBUG */
-		tape->rc = 0;
-		tapestate_set (tape, TS_FAILED);
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-	} else {
-		switch (tape->devstat.ii.sense.data[3]) {
-		case 0x48:
-#ifdef TAPE_DEBUG
-		        debug_text_event (tape_debug_area,3,"rfo fail");
-                        debug_text_exception (tape_debug_area,3,"recov x48");
-#endif	/* TAPE_DEBUG */
-			//s390irq_spin_lock(tape->devinfo.irq);
-			do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) (tape->cqr), 0x00, tape->cqr->options);
-			//s390irq_spin_unlock(tape->devinfo.irq);
-			break;
-		case 0x2c:
-			PRINT_ERR ("TAPE: Permanent Unit Check. Please check your hardware!");
-#ifdef TAPE_DEBUG
-			debug_text_event (tape_debug_area,3,"rfo fail");
-			debug_text_exception (tape_debug_area,3,"Perm UCK");
-#endif
-			tape->rc = -EIO;
-			tapestate_set (tape, TS_FAILED);
-			tape->wanna_wakeup=1;
-			wake_up_interruptible (&tape->wq);
-			break;
-		default:
-			tape34xx_unexpect_uchk_handler (tape);
-		}
-	}
-}
-
-void
 tape34xx_rew_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1788,44 +1714,6 @@
 }
 
 void
-tape34xx_rew_release_init_error (tape_info_t * tape)
-{
-	if ((tape->devstat.ii.sense.data[0] == 0x40) &&
-	    (tape->devstat.ii.sense.data[1] == 0x40) &&
-	    (tape->devstat.ii.sense.data[3] == 0x43)) {
-		// no tape in the drive
-		PRINT_INFO ("Drive %d not ready. No volume loaded.\n", tape->rew_minor / 2);
-#ifdef TAPE_DEBUG
-		debug_text_event (tape_debug_area,3,"rewR fail");
-		debug_text_exception (tape_debug_area,3,"no medium");
-#endif
-		tapestate_set (tape, TS_FAILED);
-		tape->rc = -ENOMEDIUM;
-		tape->wanna_wakeup=1;
-		wake_up (&tape->wq);
-	} else {
-		PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
-		PRINT_ERR ("TAPE34XX: Please send the following 20 lines of output to cotte@de.ibm.com\n");
-		PRINT_ERR ("TAPE34XX: Current state is: %s",
-			   (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ?
-		  state_verbose[tapestate_get (tape)] : "->UNKNOWN STATE<-"));
-		tapestate_set (tape, TS_FAILED);
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,3,"rewR unexp");
-	        debug_text_event (tape_debug_area,3,"state:");
-	        debug_text_event (tape_debug_area,3,((tapestate_get (tape) < TS_SIZE) && 
-						     (tapestate_get (tape) >= 0)) ?
-				  state_verbose[tapestate_get (tape)] : 
-				  "TS UNKNOWN");
-#endif /* TAPE_DEBUG */
-		tape_dump_sense (&tape->devstat);
-		tape->rc = -EIO;
-		tape->wanna_wakeup=1;
-		wake_up (&tape->wq);
-	}
-}
-
-void
 tape34xx_rew_release_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1839,12 +1727,6 @@
 }
 
 void
-tape34xx_rew_init_error (tape_info_t * tape)
-{
-	tape34xx_unexpect_uchk_handler (tape);
-}
-
-void
 tape34xx_run_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1857,27 +1739,6 @@
 }
 
 void
-tape34xx_run_init_error (tape_info_t * tape)
-{
-
-	switch (tape->devstat.ii.sense.data[3]) {
-	case 0x52:
-	        // This error is fine for rewind and unload
-	        // It reports that no volume is loaded... 
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,6,"run done");
-#endif	/* TAPE_DEBUG */
-		tapestate_set (tape, TS_DONE);
-		tape->rc = 0;
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-		break;
-	default:
-		tape34xx_unexpect_uchk_handler (tape);
-	}
-}
-
-void
 tape34xx_wri_init_done (tape_info_t * tape)
 {
 #ifdef TAPE_DEBUG
@@ -1893,72 +1754,632 @@
 }
 
 void
-tape34xx_wri_init_error (tape_info_t * tape)
+tape34xx_wtm_init_done (tape_info_t * tape)
 {
-    if ((tape->devstat.ii.sense.data[0]==0x80)&&(tape->devstat.ii.sense.data[1]==0x4a)) {
-	// tape is write protected
 #ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"wri fail");
-        debug_text_exception (tape_debug_area,3,"writProte");
-#endif	/* TAPE_DEBUG */
-	tape->rc = -EACCES;
-	tapestate_set (tape, TS_FAILED);
+        debug_text_event (tape_debug_area,3,"wtm done");
+#endif
+	tapestate_set (tape, TS_DONE);
+	tape->rc = 0;
 	tape->wanna_wakeup=1;
 	wake_up_interruptible (&tape->wq);
-    } else {
-	switch (tape->devstat.ii.sense.data[3]) {
-	case 0x48:
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,3,"wri fail");
-		debug_text_exception (tape_debug_area,3,"recov x48");
-#endif	/* TAPE_DEBUG */
-		//s390irq_spin_lock(tape->devinfo.irq);
-		do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) (tape->cqr), 0x00, tape->cqr->options);
-		//s390irq_spin_unlock(tape->devinfo.irq);
-		break;
-	case 0x2c:
-		PRINT_ERR ("TAPE: Permanent Unit Check. Please check your hardware!\n");
-#ifdef TAPE_DEBUG
-		debug_text_event (tape_debug_area,3,"wri fail");
-		debug_text_exception (tape_debug_area,3,"Perm UCK");
-#endif
-		tape->rc = -EIO;
-		tapestate_set (tape, TS_FAILED);
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-		break;
-	case 0x38:		//end of tape
-#ifdef TAPE_DEBUG
-		PRINT_WARN ("TAPE: End of Tape reached.\n");
-		debug_text_event (tape_debug_area,3,"wri fail");
-		debug_text_exception (tape_debug_area,3,"EOT!");
-#endif
-		tape->rc = tape->devstat.rescnt;
-		tapestate_set (tape, TS_FAILED);
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-		break;
+}
+
+/* This function analyses the tape's sense-data in case of a unit-check. If possible,
+   it tries to recover from the error. Else the user is informed about the problem. */
+void
+tape34xx_error_recovery (tape_info_t* tape)
+{
+    __u8* sense=tape->devstat.ii.sense.data;
+    int inhibit_cu_recovery=0;
+    int cu_type=tape->discipline->cu_type;
+    if ((((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
+    if (tapestate_get(tape)==TS_BLOCK_INIT) {
+	// no recovery for block device, bottom half will retry...
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    }
+    if (sense[0]&SENSE_COMMAND_REJECT)
+	switch (tapestate_get(tape)) {
+	case TS_BLOCK_INIT:
+	case TS_DSE_INIT:
+	case TS_EGA_INIT:
+	case TS_WRI_INIT:
+	case TS_WTM_INIT:
+	    if (sense[1]&SENSE_WRITE_PROTECT) {
+		// trying to write, but medium is write protected
+		tape34xx_error_recovery_has_failed(tape,EACCES);
+		return;
+	    }
 	default:
-		tape34xx_unexpect_uchk_handler (tape);
+	    tape34xx_error_recovery_HWBUG(tape,1);
+	    return;
+	}
+    // special cases for various tape-states when reaching end of recorded area
+    if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) &&
+	((sense[1]==0x40) || (sense[1]==0x0c)))
+	switch (tapestate_get(tape)) {
+	case TS_FSF_INIT:
+	    // Trying to seek beyond end of recorded area
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	case TS_LBL_INIT:
+	    // Block could not be located.
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	case TS_RFO_INIT:
+	    // Try to read beyond end of recorded area -> 0 bytes read
+	    tape34xx_error_recovery_has_failed(tape,0);
+	    return;
+	}
+    // Sensing special bits
+    if (sense[0]&SENSE_BUS_OUT_CHECK) {
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    }
+    if (sense[0]&SENSE_DATA_CHECK) {
+	// hardware failure, damaged tape or improper operating conditions
+	switch (sense[3]) {
+	case 0x23:
+	    // a read data check occurred
+	    if ((sense[2]&SENSE_TAPE_SYNC_MODE) ||
+		(inhibit_cu_recovery)) {
+		// data check is not permanent, may be recovered. 
+		// We always use async-mode with cu-recovery, so this should *never* happen.
+		tape34xx_error_recovery_HWBUG(tape,2);
+		return;
+	    } else {
+		// data check is permanent, CU recovery has failed
+		PRINT_WARN("Permanent read error, recovery failed!\n");
+		tape34xx_error_recovery_has_failed(tape,EIO);
+		return;
+	    }
+	case 0x25:
+	    // a write data check occurred
+	    if ((sense[2]&SENSE_TAPE_SYNC_MODE) ||
+		(inhibit_cu_recovery)) {
+		// data check is not permanent, may be recovered.
+		// We always use async-mode with cu-recovery, so this should *never* happen.
+		tape34xx_error_recovery_HWBUG(tape,3);
+		return;
+	    } else {
+		// data check is permanent, cu-recovery has failed
+		PRINT_WARN("Permanent write error, recovery failed!\n");
+		tape34xx_error_recovery_has_failed(tape,EIO);
+		return;
+	    }
+	case 0x26:
+	    // Data Check (read opposite) occurred. We'll recover this.
+	    tape34xx_error_recovery_read_opposite(tape);
+	    return;
+	case 0x28:
+	    // The ID-Mark at the beginning of the tape could not be written. This is fatal, we'll report and exit.
+	    PRINT_WARN("ID-Mark could not be written. Check your hardware!\n");
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	case 0x31:
+	    // Tape void. Tried to read beyond end of device. We'll report and exit.
+	    PRINT_WARN("Try to read beyond end of recorded area!\n");
+	    tape34xx_error_recovery_has_failed(tape,ENOSPC);
+	    return;
+	case 0x41:
+	    // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
+	    PRINT_WARN("Illegal block-id sequence found!\n");
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	    default:
+	    // well, all data checks for 3480 should result in one of the above erpa-codes. if not -> bug
+	    // On 3490, other data-check conditions do exist.
+		if (cu_type==0x3480) {
+		    tape34xx_error_recovery_HWBUG(tape,4);
+		    return;
+		}
 	}
     }
+    if (sense[0]&SENSE_OVERRUN) {
+	// A data overrun between cu and drive occurred. The channel speed is to slow! We'll report this and exit!
+	switch (sense[3]) {
+	case 0x40: // overrun error
+	    PRINT_WARN ("Data overrun error between control-unit and drive. Use a faster channel connection, if possible! \n");
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	default:
+	    // Overrun bit is set, but erpa does not show overrun error. This is a bug.
+	    tape34xx_error_recovery_HWBUG(tape,5);
+	    return;
+	}
+    }
+    if (sense[1]&SENSE_RECORD_SEQUENCE_ERR) {
+	switch (sense[3]) {
+	case 0x41:
+	    // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
+	    PRINT_WARN("Illegal block-id sequence found!\n");
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	default:
+	    // Record sequence error bit is set, but erpa does not show record sequence error. This is a bug.
+	    tape34xx_error_recovery_HWBUG(tape,6);
+	    return;
+	}
+    }
+    // Sensing erpa codes
+    switch (sense[3]) {
+    case 0x00:
+	// Everything is fine, but we got a unit check. Report and ignore!
+	PRINT_WARN ("Non-error sense was found. Unit-check will be ignored, expect errors...\n");
+	return;
+    case 0x21:
+	// Data streaming not operational. Cu switches to interlock mode, we reissue the command.
+	PRINT_WARN ("Data streaming not operational. Switching to interlock-mode! \n");
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x22:
+	// Path equipment check. Might be drive adapter error, buffer error on the lower interface, internal path not useable, or error during cartridge load.
+	// All of the above are not recoverable
+	PRINT_WARN ("A path equipment check occurred. One of the following conditions occurred:\n");
+	PRINT_WARN ("drive adapter error,buffer error on the lower interface, internal path not useable, error during cartridge load.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x23:
+	// Read data check. Should have been be covered earlier -> Bug!
+	tape34xx_error_recovery_HWBUG(tape,7);
+	return;
+    case 0x24:
+	// Load display check. Load display was command was issued, but the drive is displaying a drive check message. Can be threated as "device end".
+	tape34xx_error_recovery_succeded(tape);
+	return;
+    case 0x25:
+	// Write data check. Should have been covered earlier -> Bug!
+	tape34xx_error_recovery_HWBUG(tape,8);
+	return;
+    case 0x26:
+	// Data check (read opposite). Should have been covered earlier -> Bug!
+	tape34xx_error_recovery_HWBUG(tape,9);
+	return;
+    case 0x27:
+	// Command reject. May indicate illegal channel program or buffer over/underrun. 
+	// Since all channel programms are issued by this driver and ought be correct,
+	// we assume a over/underrun situaltion and retry the channel program.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x28:
+	// Write id mark check. Should have beed covered earlier -> bug!
+	tape34xx_error_recovery_HWBUG(tape,10);
+	return;
+    case 0x29:
+	// Function incompatible. Either idrc is on but hardware not capable doing idrc 
+	// or a perform subsystem func is issued and the cu is not online. Anyway, this 
+	// cannot be recovered and is an I/O error.
+	PRINT_WARN ("Function incompatible. Try to switch off idrc! \n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x2a:
+	// Unsolicited environmental data. An internal counter overflows, we can ignore
+	// this and reissue the cmd.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x2b:
+	// Environmental data present. Indicates either unload completed ok or read buffered 
+	// log command completed ok. 
+	if (tapestate_get(tape)==TS_RUN_INIT) {
+	    // Rewind unload completed ok.
+	    tape34xx_error_recovery_succeded(tape);
+	    return;
+	}
+	// Since we do not issue read buffered log commands, this should never occur -> bug.
+	tape34xx_error_recovery_HWBUG(tape,11);
+	return;
+    case 0x2c:
+	// Permanent equipment check. cu has tried recovery, but did not succeed. This is an
+	// I/O error.
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x2d:
+	// Data security erase failure.
+	if (tapestate_get(tape)==TS_DSE_INIT) {
+	    // report an I/O error
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	}
+	// Data security erase failure, but no such command issued. This is a bug.
+	tape34xx_error_recovery_HWBUG(tape,12);
+	return;
+    case 0x2e:
+	// Not capable. This indicates either that the drive fails reading the format id mark
+	// or that that format specified is not supported by the drive. We write a message and
+	// return an I/O error.
+	PRINT_WARN("Drive not capable processing the tape format!");
+	tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+	return;
+    case 0x2f:
+	// This erpa is reserved. This is a bug.
+	tape34xx_error_recovery_HWBUG(tape,13);
+	return;
+    case 0x30:
+	// The medium is write protected, while trying to write on it. We'll report this.
+	PRINT_WARN("Medium is write protected!\n");
+	tape34xx_error_recovery_has_failed(tape,EACCES);
+	return;
+    case 0x31:
+	// Tape void. Should have beed covered ealier -> bug
+	tape34xx_error_recovery_HWBUG(tape,14);
+	return;
+    case 0x32:
+	// Tension loss. We cannot recover this, it's an I/O error.
+	PRINT_WARN("The drive lost tape tension.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x33:
+	// Load Failure. The catridge was not inserted correctly or the tape is not threaded
+	// correctly. We cannot recover this, the user has to reload the catridge.
+	PRINT_WARN("Cartridge load failure. Reload the cartridge and try again.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x34:
+	// Unload failure. The drive cannot maintain tape tension and control tape movement 
+	// during an unload operation. 
+	PRINT_WARN("Failure during cartridge unload. Please try manually.\n");
+	if (tapestate_get(tape)!=TS_RUN_INIT) {
+	    tape34xx_error_recovery_HWBUG(tape,15);
+	    return;
+	}
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x35:
+	// Drive equipment check. One of the following:
+	// - cu cannot recover from a drive detected error
+	// - a check code message is displayed on drive message/load displays
+	// - the cartridge loader does not respond correctly
+	// - a failure occurs during an index, load, or unload cycle
+	PRINT_WARN("Equipment check! Please check the drive and the cartridge loader.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x36:
+	switch (cu_type) {
+	case 0x3480:
+	    // This erpa is reserved for 3480 -> BUG
+	    tape34xx_error_recovery_HWBUG(tape,16);
+	    return;
+	case 0x3490:
+	    // End of data. This is a permanent I/O error, which cannot be recovered.
+	    // A read-type command has reached the end-of-data mark.
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    return;
+	}
+    case 0x37:
+	// Tape length error. The tape is shorter than reported in the beginning-of-tape data.
+	PRINT_WARN("Tape length error.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x38:
+	// Physical end of tape. A read/write operation reached the physical end of tape.
+	if (tapestate_get(tape)==TS_WRI_INIT) {
+ 	    tape34xx_error_recovery_has_failed(tape,ENOSPC);
+	}
+	return;
+    case 0x39:
+	// Backward at BOT. The drive is at BOT and is requestet to move backward.
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x3a:
+	// Drive switched not ready, but the command needs the drive to be ready.
+	PRINT_WARN("Drive not ready. Turn the ready/not ready switch to ready position and try again.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x3b:
+	// Manual rewind or unload. This causes an I/O error.
+	PRINT_WARN("Medium is rewinded or unloaded manually.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x3c:
+    case 0x3d:
+    case 0x3e:
+    case 0x3f:
+	// These erpas are reserved -> BUG
+	tape34xx_error_recovery_HWBUG(tape,17);
+	return;
+    case 0x40:
+	// Overrun error. This should have been covered earlier -> bug.
+	tape34xx_error_recovery_HWBUG(tape,18);
+	return;
+    case 0x41:
+	// Record sequence error. This should have been covered earlier -> bug.
+	tape34xx_error_recovery_HWBUG(tape,19);
+	return;
+    case 0x42:
+	// Degraded mode. A condition that can cause degraded performace is detected.
+	PRINT_WARN("Subsystem is running in degraded mode. This may compromise your performace.\n");
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x43:
+	// Drive not ready. Probably swith the ready/not ready switch to ready?
+	PRINT_WARN("The drive is not ready. Maybe no medium in?\n");
+	tape34xx_error_recovery_has_failed(tape,ENOMEDIUM);
+	return;
+    case 0x44:
+	// Locate Block unsuccessfull. We'll report this.
+	if ((tapestate_get(tape)!=TS_BLOCK_INIT) &&
+	    (tapestate_get(tape)!=TS_LBL_INIT)) {
+	    tape34xx_error_recovery_HWBUG(tape,20); // No locate block was issued...
+	    return;
+	}
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x45:
+	// The drive is assigned elsewhere [to a different channel path/computer].
+	PRINT_WARN("The drive is assigned elsewhere.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x46:
+	// Drive not online. Drive may be switched offline, the power supply may be switched off 
+	// or the drive address may not be set correctly.
+	PRINT_WARN("The drive is not online.");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x47:
+	// Volume fenced. cu reports volume integrity is lost! 
+	PRINT_WARN("Volume fenced. The volume integrity is lost! \n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x48:
+	// Log sense data and retry request. We'll do so...
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x49:
+	// Bus out check. A parity check error on the bus was found.	PRINT_WARN("Bus out check. A data transfer over the bus was corrupted.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x4a:
+	// Control unit erp failed. We'll report this.
+	PRINT_WARN("The control unit failed recovering an I/O error.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x4b:
+	// Cu and drive incompatible. The drive requests micro-program patches, which are not available on the cu.
+	PRINT_WARN("The drive needs microprogram patches from the control unit, which are not available.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x4c:
+	// Recovered Check-One failure. Cu develops a hardware error, but is able to recover. We'll reissue the command.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x4d:
+	switch (cu_type) {
+	case 0x3480:
+	    // This erpa is reserved for 3480 -> bug
+      	    tape34xx_error_recovery_HWBUG(tape,21);
+	    return;
+	case 0x3490:
+	    // Resetting event recieved. Since the driver does not support resetting event recovery
+	    // (which has to be handled by the I/O Layer), we'll report and retry our command.
+	    tape34xx_error_recovery_do_retry(tape);
+	    return;
+	}
+    case 0x4e:
+	switch (cu_type) {
+	case 0x3480:
+	    // This erpa is reserved for 3480 -> bug.
+	    tape34xx_error_recovery_HWBUG(tape,22);
+	    return;
+	case 0x3490:
+	    // Maximum block size exeeded. This indicates, that the block to be written is larger
+	    // than allowed for buffered mode. We'll report this...
+	    PRINT_WARN("Maximum block size for buffered mode exceeded.\n");
+	    tape34xx_error_recovery_has_failed(tape,ENOBUFS);
+	    return;
+	}
+    case 0x4f:
+	// These erpas are reserved -> bug
+	tape34xx_error_recovery_HWBUG(tape,23);
+	return;
+    case 0x50:
+	// Read buffered log (Overflow). Cu is running in extended beffered log mode, and a counter overflows.
+	// This should never happen, since we're never running in extended buffered log mode -> bug.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x51:
+	// Read buffered log (EOV). EOF processing occurs while the cu is in extended buffered log mode.
+	// This should never happen, since we're never running in extended buffered log mode -> bug.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x52:
+	// End of Volume complete. Rewind unload completed ok. We'll report to the user...
+	if (tapestate_get(tape)!=TS_RUN_INIT) {
+	    tape34xx_error_recovery_HWBUG(tape,24);
+	    return;
+	}
+	tape34xx_error_recovery_succeded(tape);
+	return;
+    case 0x53:
+	// Global command intercept. We'll have to reissue our command.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x54:
+	// Channel interface recovery (temporary). This can be recovered by reissuing the command.
+	tape34xx_error_recovery_do_retry(tape);
+	return;
+    case 0x55:
+	// Channel interface recovery (permanent). This cannot be recovered, we'll inform the user.
+	PRINT_WARN("A permanent channel interface error occurred.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x56:
+	// Channel protocol error. This cannot be recovered.
+	PRINT_WARN("A channel protocol error occurred.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x57:
+	switch (cu_type) {
+	case 0x3480:
+	    // Attention intercept. We have to reissue the command.
+	    PRINT_WARN("An attention intercept occurred, which will be recovered.\n");
+	    tape34xx_error_recovery_do_retry(tape);
+	    return;
+	case 0x3490:
+	    // Global status intercept. We have to reissue the command.
+	    PRINT_WARN("An global status intercept was recieved, which will be recovered.\n");
+	    tape34xx_error_recovery_do_retry(tape);
+	    return;
+	}
+    case 0x58:
+    case 0x59:
+	// These erpas are reserved -> bug.
+	tape34xx_error_recovery_HWBUG(tape,25);
+	return;
+    case 0x5a:
+	// Tape length incompatible. The tape inserted is too long, 
+	// which could cause damage to the tape or the drive.
+	PRINT_WARN("Tape length incompatible [should be IBM Cartridge System Tape]. May cause damage to drive or tape.n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x5b:
+	// Format 3480 XF incompatible
+	if (sense[1]&SENSE_BEGINNING_OF_TAPE) {
+	    // Everything is fine. The tape will be overwritten in a different format.
+	    tape34xx_error_recovery_do_retry(tape);
+	    return;
+	}
+	PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x5c:
+	// Format 3480-2 XF incompatible
+	PRINT_WARN("Tape format is incompatible to the drive. The drive cannot access 3480-2 XF volumes.\n");
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	return;
+    case 0x5d:
+	// Tape length violation. 
+	PRINT_WARN("Tape length violation [should be IBM Enhanced Capacity Cartridge System Tape]. May cause damage to drive or tape.\n");
+	tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+	return;
+    case 0x5e:
+	// Compaction algorithm incompatible.
+	PRINT_WARN("The volume is recorded using an incompatible compaction algorith, which is not supported by the control unit.\n");
+	tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+	return;
+    default:
+	// Reserved erpas -> bug
+	tape34xx_error_recovery_HWBUG(tape,26);
+	return;
+    }
 }
 
-void
-tape34xx_wtm_init_done (tape_info_t * tape)
-{
+void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id) {
 #ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"wtm done");
+    debug_text_event (tape_debug_area,3,"xerp fail");
+    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
+		      (tapestate_get (tape) >= 0)) ?
+	state_verbose[tapestate_get (tape)] : "UNKNOWN"));
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
+    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
+	tape_dump_sense(&tape->devstat);
+	tape->rc = -error_id;
 	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	switch (tapestate_get(tape)) {
+	case TS_REW_RELEASE_INIT:
+	    tapestate_set(tape,TS_FAILED);
+	    wake_up (&tape->wq);
+	    break;
+	case TS_BLOCK_INIT:
+	    tapestate_set(tape,TS_FAILED);
+	    schedule_tapeblock_exec_IO(tape);
+	    break;
+	default:
+	    tapestate_set(tape,TS_FAILED);
+	    wake_up_interruptible (&tape->wq);
+	}
+    } else {
+	PRINT_WARN("Recieved an unsolicited IRQ.\n");
+	tape_dump_sense(&tape->devstat);
+    }
+}    
+
+void tape34xx_error_recovery_succeded(tape_info_t* tape) {
+#ifdef TAPE_DEBUG
+    debug_text_event (tape_debug_area,3,"xerp done");
+    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
+		      (tapestate_get (tape) >= 0)) ?
+	state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+#endif
+    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_DONE)) {
+	tapestate_event (tape, TE_DONE);
+    } else {
+	PRINT_WARN("Recieved an unsolicited IRQ.\n");
+	tape_dump_sense(&tape->devstat);
+    }
 }
 
-void
-tape34xx_wtm_init_error (tape_info_t * tape)
-{
-        tape34xx_unexpect_uchk_handler (tape);
+void tape34xx_error_recovery_do_retry(tape_info_t* tape) {
+#ifdef TAPE_DEBUG
+    debug_text_event (tape_debug_area,3,"xerp retr");
+    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
+					  (tapestate_get (tape) >= 0)) ?
+					 state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+#endif
+    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
+	tape_dump_sense(&tape->devstat);
+	while (do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 0x00, tape->cqr->options));
+    } else {
+	PRINT_WARN("Recieved an unsolicited IRQ.\n");
+	tape_dump_sense(&tape->devstat);
+    }
+}
     
+void 
+tape34xx_error_recovery_read_opposite (tape_info_t* tape) {
+    switch (tapestate_get(tape)) {
+    case TS_RFO_INIT:
+	// We did read forward, but the data could not be read *correctly*.
+	// We will read backward and then skip forward again.
+	tape->cqr=tape34xx_read_opposite(tape,0);
+	if (tape->cqr==NULL)
+	    tape34xx_error_recovery_has_failed(tape,EIO);
+	else
+	    tape34xx_error_recovery_do_retry(tape);
+	break;
+    case TS_RBA_INIT:
+	// We tried to read forward and backward, but hat no success -> failed.
+	tape34xx_error_recovery_has_failed(tape,EIO);
+	break;
+    case TS_BLOCK_INIT:
+	tape34xx_error_recovery_do_retry(tape);
+	break;
+    default:
+	PRINT_WARN("read_opposite_recovery_called_with_state:%s\n",
+		   (((tapestate_get (tape) < TS_SIZE) && 
+		     (tapestate_get (tape) >= 0)) ?
+		    state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    }
+}
+
+void 
+tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) {
+    devstat_t* stat=&tape->devstat;
+    PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
+    PRINT_WARN("Please report this incident.\n");
+    PRINT_WARN("State of the tape:%s\n",
+	       (((tapestate_get (tape) < TS_SIZE) && 
+		 (tapestate_get (tape) >= 0)) ?
+		state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X "
+		" %02X%02X%02X%02X %02X%02X%02X%02X \n",
+		stat->ii.sense.data[0], stat->ii.sense.data[1],
+		stat->ii.sense.data[2], stat->ii.sense.data[3],
+		stat->ii.sense.data[4], stat->ii.sense.data[5],
+		stat->ii.sense.data[6], stat->ii.sense.data[7],
+		stat->ii.sense.data[8], stat->ii.sense.data[9],
+		stat->ii.sense.data[10], stat->ii.sense.data[11],
+		stat->ii.sense.data[12], stat->ii.sense.data[13],
+		stat->ii.sense.data[14], stat->ii.sense.data[15]);
+    PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X "
+		" %02X%02X%02X%02X %02X%02X%02X%02X \n",
+		stat->ii.sense.data[16], stat->ii.sense.data[17],
+		stat->ii.sense.data[18], stat->ii.sense.data[19],
+		stat->ii.sense.data[20], stat->ii.sense.data[21],
+		stat->ii.sense.data[22], stat->ii.sense.data[23],
+		stat->ii.sense.data[24], stat->ii.sense.data[25],
+		stat->ii.sense.data[26], stat->ii.sense.data[27],
+		stat->ii.sense.data[28], stat->ii.sense.data[29],
+		stat->ii.sense.data[30], stat->ii.sense.data[31]);
+    tape34xx_error_recovery_has_failed(tape,EIO);
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape34xx.h linux/drivers/s390/char/tape34xx.h
--- v2.4.3/linux/drivers/s390/char/tape34xx.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tape34xx.h	Wed Apr 11 19:02:28 2001
@@ -4,12 +4,11 @@
  *  drivers/s390/char/tape34xx.h
  *    common tape device discipline for 34xx tapes.
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
@@ -85,6 +84,31 @@
 #define CONTROL_UNIT_END DEV_STAT_CU_END      /* redefine from irq.h */
 #define INCORR_LEN       SCHN_STAT_INCORR_LEN /* redefine from irq.h */
 
+#define SENSE_COMMAND_REJECT        0x80
+#define SENSE_INTERVENTION_REQUIRED 0x40
+#define SENSE_BUS_OUT_CHECK         0x20
+#define SENSE_EQUIPMENT_CHECK       0x10
+#define SENSE_DATA_CHECK            0x08
+#define SENSE_OVERRUN               0x04
+#define SENSE_DEFERRED_UNIT_CHECK   0x02
+#define SENSE_ASSIGNED_ELSEWHERE    0x01
+
+#define SENSE_LOCATE_FAILURE        0x80
+#define SENSE_DRIVE_ONLINE          0x40
+#define SENSE_RESERVED              0x20
+#define SENSE_RECORD_SEQUENCE_ERR   0x10
+#define SENSE_BEGINNING_OF_TAPE     0x08
+#define SENSE_WRITE_MODE            0x04
+#define SENSE_WRITE_PROTECT         0x02
+#define SENSE_NOT_CAPABLE           0x01
+
+#define SENSE_CHANNEL_ADAPTER_CODE  0xE0
+#define SENSE_CHANNEL_ADAPTER_LOC   0x10
+#define SENSE_REPORTING_CU          0x08
+#define SENSE_AUTOMATIC_LOADER      0x04
+#define SENSE_TAPE_SYNC_MODE        0x02
+#define SENSE_TAPE_POSITIONING      0x01
+
 typedef struct _tape34xx_disc_data_t {
     __u8 modeset_byte;
 } tape34xx_disc_data_t  __attribute__ ((packed, aligned(8)));
@@ -130,33 +154,30 @@
 void tape34xx_default_handler (tape_info_t * tape);
 void tape34xx_unexpect_uchk_handler (tape_info_t * tape);
 void tape34xx_unused_done(tape_info_t* tape);
-void tape34xx_unused_error(tape_info_t* tape);
 void tape34xx_idle_done(tape_info_t* tape);
-void tape34xx_idle_error(tape_info_t* tape);
 void tape34xx_block_done(tape_info_t* tape);
-void tape34xx_block_error(tape_info_t* tape);
 void tape34xx_bsf_init_done(tape_info_t* tape);
 void tape34xx_dse_init_done(tape_info_t* tape);
 void tape34xx_fsf_init_done(tape_info_t* tape);
-void tape34xx_fsf_init_error(tape_info_t* tape);
 void tape34xx_bsb_init_done(tape_info_t* tape);
 void tape34xx_fsb_init_done(tape_info_t* tape);
 void tape34xx_lbl_init_done(tape_info_t* tape);
-void tape34xx_lbl_init_error(tape_info_t* tape);
 void tape34xx_nop_init_done(tape_info_t* tape);
 void tape34xx_rfo_init_done(tape_info_t* tape);
-void tape34xx_rfo_init_error(tape_info_t* tape);
 void tape34xx_rbi_init_done(tape_info_t* tape);
 void tape34xx_rew_init_done(tape_info_t* tape);
-void tape34xx_rew_init_error(tape_info_t* tape);
 void tape34xx_rew_release_init_done(tape_info_t* tape);
-void tape34xx_rew_release_init_error(tape_info_t* tape);
 void tape34xx_run_init_done(tape_info_t* tape);
-void tape34xx_run_init_error(tape_info_t* tape);
 void tape34xx_wri_init_done(tape_info_t* tape);
-void tape34xx_wri_init_error(tape_info_t* tape);
 void tape34xx_wtm_init_done(tape_info_t* tape);
-void tape34xx_wtm_init_error(tape_info_t* tape);
 
 extern void schedule_tapeblock_exec_IO (tape_info_t *tape);
+
+// the error recovery stuff:
+void tape34xx_error_recovery (tape_info_t* tape);
+void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id);
+void tape34xx_error_recovery_succeded(tape_info_t* tape);
+void tape34xx_error_recovery_do_retry(tape_info_t* tape);
+void tape34xx_error_recovery_read_opposite (tape_info_t* tape);
+void  tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno);
 #endif // _TAPE34XX_H
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapeblock.c linux/drivers/s390/char/tapeblock.c
--- v2.4.3/linux/drivers/s390/char/tapeblock.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tapeblock.c	Thu Apr 12 12:16:35 2001
@@ -4,15 +4,17 @@
  *  drivers/s390/char/tapeblock.c
  *    block device frontend for tape device driver
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ *
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
 #include "tapedefs.h"
+#include <linux/config.h>
 #include <linux/blkdev.h>
 #include <linux/blk.h>
 #include <linux/version.h>
@@ -22,6 +24,7 @@
 #include <asm/s390dyn.h>
 #include <linux/compatmac.h>
 #ifdef MODULE
+#define __NO_VERSION__
 #include <linux/module.h>
 #endif
 #include "tape.h"
@@ -51,6 +54,21 @@
 
 static request_queue_t* tapeblock_getqueue (kdev_t kdev);
 
+#ifdef CONFIG_DEVFS_FS
+void
+tapeblock_mkdevfstree (tape_info_t* tape) {
+    tape->devfs_block_dir=devfs_mk_dir (tape->devfs_dir, "block", tape);
+    tape->devfs_disc=devfs_register(tape->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
+				    tapeblock_major, tape->blk_minor,
+				    TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, tape);
+}
+
+void
+tapeblock_rmdevfstree (tape_info_t* tape) {
+    devfs_unregister(tape->devfs_disc);
+    devfs_unregister(tape->devfs_block_dir);
+}
+#endif
 
 void 
 tapeblock_setup(tape_info_t* tape) {
@@ -59,9 +77,12 @@
     hardsect_size[tapeblock_major][tape->blk_minor]=512;
     blk_init_queue (&tape->request_queue, tape_request_fn); 
     blk_queue_headactive (&tape->request_queue, 0); 
+#ifdef CONFIG_DEVFS_FS
+    tapeblock_mkdevfstree(tape);
+#endif
 }
 
-void
+int
 tapeblock_init(void) {
     int result;
     tape_frontend_t* blkfront,*temp;
@@ -69,7 +90,11 @@
 
     tape_init();
     /* Register the tape major number to the kernel */
+#ifdef CONFIG_DEVFS_FS
+    result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
+#else
     result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
+#endif
     if (result < 0) {
         PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major);
         panic ("cannot get major number for tape block device");
@@ -89,6 +114,10 @@
     blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL);
     if (blkfront==NULL) panic ("no mem for tape block device structure");
     blkfront->device_setup=tapeblock_setup;
+#ifdef CONFIG_DEVFS_FS
+    blkfront->mkdevfstree = tapeblock_mkdevfstree;
+    blkfront->rmdevfstree = tapeblock_rmdevfstree;
+#endif
     blkfront->next=NULL;
     if (first_frontend==NULL) {
 	first_frontend=blkfront;
@@ -103,6 +132,7 @@
 	tapeblock_setup(tape);
 	tape=tape->next;
     }
+    return 0;
 }
 
 
@@ -111,7 +141,7 @@
     unregister_blkdev(tapeblock_major, "tBLK");
 }
 
-static int
+int
 tapeblock_open(struct inode *inode, struct file *filp) {
     tape_info_t *ti;
     kdev_t dev;
@@ -140,7 +170,7 @@
         ti->position=-1;
         
 	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-    rc=tapeblock_mediumdetect(ti);
+        rc=tapeblock_mediumdetect(ti);
         if (rc) return rc; // in case of errors, we don't have a size of the medium
 	dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev));	/* Get the device */
 	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
@@ -155,12 +185,10 @@
 	return 0;
 }
 
-static int
+int
 tapeblock_release(struct inode *inode, struct file *filp) {
 	long lockflags;
 	tape_info_t *ti,*lastti;
-
-	inode = filp->f_dentry->d_inode;
 	ti = first_tape_info;
 	while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev)))
 		ti = (tape_info_t *) ti->next;
@@ -177,7 +205,7 @@
 	}
 	if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
 #ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"b:notidle!");
+	debug_text_event (tape_debug_area,3,"b:notidle!");
 #endif
 		return -ENXIO;	/* error in tape_release */
 	}
@@ -191,6 +219,7 @@
 #ifdef MODULE
 	MOD_DEC_USE_COUNT;
 #endif				/* MODULE */
+	invalidate_buffers(inode->i_rdev);
 	return 0;
 }
 
@@ -226,7 +255,7 @@
     tape->discipline->free_bread(tape->cqr,tape);
     tape->cqr=NULL;
     tape->current_request=NULL;
-    tapestate_set(tape,TS_IDLE);
+    if (tapestate_get(tape)!=TS_NOT_OPER) tapestate_set(tape,TS_IDLE);
     return;
 }
 
@@ -258,7 +287,17 @@
 	tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
     }
     if (tape->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
-    if (list_empty(&tape->request_queue.queue_head)) { // nothing more to do ;)
+    if (tapestate_get (tape) == TS_NOT_OPER) {
+	tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+	tape->devinfo.irq=-1;
+	return;
+    }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	if (list_empty (&tape->request_queue.queue_head)) {
+#else
+	if (tape->request_queue==NULL) {
+#endif
+	// nothing more to do or device has dissapeared;)
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"b:Qempty");
 #endif
@@ -342,8 +381,9 @@
         if (atomic_compare_and_swap(0,1,&tape->bh_scheduled)) {
                 return;
         }
-
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	INIT_LIST_HEAD(&tape->bh_tq.list);
+#endif
 	tape->bh_tq.sync = 0;
 	tape->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
 	tape->bh_tq.data = tape;
@@ -376,13 +416,14 @@
     return NULL;
 }
 
-static int tapeblock_mediumdetect(tape_info_t* tape) {
-    ccw_req_t* cqr;
+int tapeblock_mediumdetect(tape_info_t* tape) {
+        ccw_req_t* cqr;
     int losize=1,hisize=1,rc;
     long lockflags;
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"b:medDet");
 #endif
+    PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...\n");
     while (1) { //is interruped by break
 	hisize=hisize << 1; // try twice the size tested before 
 	cqr=tape->discipline->mtseek (tape, hisize);
@@ -415,6 +456,12 @@
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
 		break;
 	}
+	if (tapestate_get (tape) == TS_NOT_OPER) {
+	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+	    tape->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	    return -ENODEV;
+	}
 	if (tapestate_get (tape) != TS_DONE) {
 		tapestate_set (tape, TS_IDLE);
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
@@ -449,6 +496,12 @@
 	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
 	return -EIO;
     }
+    if (tapestate_get (tape) == TS_NOT_OPER) {
+	tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+	tape->devinfo.irq=-1;
+	s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	return -ENODEV;
+    }
     if (tapestate_get (tape) != TS_DONE) {
 	tapestate_set (tape, TS_IDLE);
 	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
@@ -482,6 +535,12 @@
 		return -ERESTARTSYS;
 	}
 	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+	if (tapestate_get (tape) == TS_NOT_OPER) {
+	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+	    tape->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	    return -ENODEV;
+	}
 	if (tapestate_get (tape) == TS_FAILED) {
 		tapestate_set (tape, TS_IDLE);
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapeblock.h linux/drivers/s390/char/tapeblock.h
--- v2.4.3/linux/drivers/s390/char/tapeblock.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tapeblock.h	Thu Apr 12 12:16:35 2001
@@ -4,23 +4,33 @@
  *  drivers/s390/char/tapechar.h
  *    character device frontend for tape device driver
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ *
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
 #ifndef TAPEBLOCK_H
 #define TAPEBLOCK_H
+#include <linux/config.h>
 #define PARTN_BITS 0
 
 #define TAPEBLOCK_READAHEAD 30
 #define TAPEBLOCK_MAJOR 0
-static int tapeblock_open(struct inode *, struct file *);
-static int tapeblock_release(struct inode *, struct file *);
+
+#define TAPEBLOCK_DEFAULTMODE 0060644
+
+int tapeblock_open(struct inode *, struct file *);
+int tapeblock_release(struct inode *, struct file *);
 void tapeblock_setup(tape_info_t* tape);
 void schedule_tapeblock_exec_IO (tape_info_t *tape);
-static int tapeblock_mediumdetect(tape_info_t* tape);
+int tapeblock_mediumdetect(tape_info_t* tape);
+#ifdef CONFIG_DEVFS_FS
+void tapeblock_mkdevfstree (tape_info_t* tape);
+#endif
+int tapeblock_init (void);
+void tapeblock_uninit (void);
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapechar.c linux/drivers/s390/char/tapechar.c
--- v2.4.3/linux/drivers/s390/char/tapechar.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tapechar.c	Thu Apr 12 12:16:35 2001
@@ -4,16 +4,17 @@
  *  drivers/s390/char/tapechar.c
  *    character device frontend for tape device driver
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ *
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
 #include "tapedefs.h"
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
@@ -24,6 +25,7 @@
 #include <asm/uaccess.h>
 #include <linux/compatmac.h>
 #ifdef MODULE
+#define __NO_VERSION__
 #include <linux/module.h>
 #endif
 #include "tape.h"
@@ -54,10 +56,33 @@
 
 int tape_major = TAPE_MAJOR;
 
+#ifdef CONFIG_DEVFS_FS
+void
+tapechar_mkdevfstree (tape_info_t* tape) {
+    tape->devfs_char_dir=devfs_mk_dir (tape->devfs_dir, "char", tape);
+    tape->devfs_nonrewinding=devfs_register(tape->devfs_char_dir, "nonrewinding",
+					    DEVFS_FL_DEFAULT,tape_major, 
+					    tape->nor_minor, TAPECHAR_DEFAULTMODE, 
+					    &tape_fops, tape);
+    tape->devfs_rewinding=devfs_register(tape->devfs_char_dir, "rewinding",
+					 DEVFS_FL_DEFAULT, tape_major, tape->rew_minor,
+					 TAPECHAR_DEFAULTMODE, &tape_fops, tape);
+}
+
+void
+tapechar_rmdevfstree (tape_info_t* tape) {
+    devfs_unregister(tape->devfs_nonrewinding);
+    devfs_unregister(tape->devfs_rewinding);
+    devfs_unregister(tape->devfs_char_dir);
+}
+#endif
+
 void
 tapechar_setup (tape_info_t * tape)
 {
-    // nothing to do
+#ifdef CONFIG_DEVFS_FS
+    tapechar_mkdevfstree(tape);
+#endif
 }
 
 void
@@ -70,7 +95,11 @@
 	tape_init();
 
 	/* Register the tape major number to the kernel */
+#ifdef CONFIG_DEVFS_FS
+	result = devfs_register_chrdev (tape_major, "tape", &tape_fops);
+#else
 	result = register_chrdev (tape_major, "tape", &tape_fops);
+#endif
 
 	if (result < 0) {
 		PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tape_major);
@@ -92,6 +121,10 @@
 		panic ("no major number available for tape char device");		
 	}
 	charfront->device_setup = tapechar_setup;
+#ifdef CONFIG_DEVFS_FS
+	charfront->mkdevfstree = tapechar_mkdevfstree;
+	charfront->rmdevfstree = tapechar_rmdevfstree;
+#endif
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"c:init ok");
 #endif /* TAPE_DEBUG */
@@ -120,7 +153,7 @@
 /*
  * Tape device read function
  */
-static ssize_t
+ssize_t
 tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
 {
 	long lockflags;
@@ -184,6 +217,12 @@
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
 		return tape->rc;
 	}
+	if (tapestate_get (tape) == TS_NOT_OPER) {
+	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+	    tape->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	    return -ENODEV;
+	}
 	if (tapestate_get (tape) != TS_DONE) {
 		tapestate_set (tape, TS_IDLE);
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
@@ -202,7 +241,7 @@
 /*
  * Tape device write function
  */
-static ssize_t
+ssize_t
 tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 {
 	long lockflags;
@@ -262,8 +301,16 @@
 		if (tapestate_get (tape) == TS_FAILED) {
 			tapestate_set (tape, TS_IDLE);
 			s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+                        if ((tape->rc==-ENOSPC) && (i!=0))
+			  return i*block_size;
 			return tape->rc;
 		}
+		if (tapestate_get (tape) == TS_NOT_OPER) {
+		    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+		    tape->devinfo.irq=-1;
+		    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+		    return -ENODEV;
+		}
 		if (tapestate_get (tape) != TS_DONE) {
 			tapestate_set (tape, TS_IDLE);
 			s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
@@ -446,6 +493,12 @@
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
 		return tape->rc;
 	}
+	if (tapestate_get (tape) == TS_NOT_OPER) {
+	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
+	    tape->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	    return -ENODEV;
+	}
 	if (tapestate_get (tape) != TS_DONE) {
 		tapestate_set (tape, TS_IDLE);
 		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
@@ -473,7 +526,7 @@
 /*
  * Tape device io controls.
  */
-static int
+int
 tape_ioctl (struct inode *inode, struct file *filp,
 	    unsigned int cmd, unsigned long arg)
 {
@@ -589,7 +642,7 @@
 /*
  * Tape device open function.
  */
-static int
+int
 tape_open (struct inode *inode, struct file *filp)
 {
 	tape_info_t *ti;
@@ -637,7 +690,7 @@
 /*
  * Tape device release function.
  */
-static int
+int
 tape_release (struct inode *inode, struct file *filp)
 {
 	long lockflags;
@@ -645,7 +698,6 @@
 	ccw_req_t *cqr = NULL;
 	int rc;
 
-	inode = filp->f_dentry->d_inode;
 	ti = first_tape_info;
 	while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev)))
 		ti = (tape_info_t *) ti->next;
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapechar.h linux/drivers/s390/char/tapechar.h
--- v2.4.3/linux/drivers/s390/char/tapechar.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tapechar.h	Thu Apr 12 12:16:35 2001
@@ -4,24 +4,31 @@
  *  drivers/s390/char/tapechar.h
  *    character device frontend for tape device driver
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ *
  *
- *  UNDER CONSTRUCTION: Work in progress...:-)
  ****************************************************************************
  */
 
 #ifndef TAPECHAR_H
 #define TAPECHAR_H
+#include <linux/config.h>
+#define TAPECHAR_DEFAULTMODE 0020644
 #define  TAPE_MAJOR                    0        /* get dynamic major since no major officialy defined for tape */
 /*
  * Prototypes for tape_fops
  */
-static ssize_t tape_read(struct file *, char *, size_t, loff_t *);
-static ssize_t tape_write(struct file *, const char *, size_t, loff_t *);
-static int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
-static int tape_open (struct inode *,struct file *);
-static int tape_release (struct inode *,struct file *);
+ssize_t tape_read(struct file *, char *, size_t, loff_t *);
+ssize_t tape_write(struct file *, const char *, size_t, loff_t *);
+int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
+int tape_open (struct inode *,struct file *);
+int tape_release (struct inode *,struct file *);
+#ifdef CONFIG_DEVFS_FS
+void tapechar_mkdevfstree (tape_info_t* tape);
+#endif
+void tapechar_init (void);
+void tapechar_uninit (void);
 #endif /* TAPECHAR_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapedefs.h linux/drivers/s390/char/tapedefs.h
--- v2.4.3/linux/drivers/s390/char/tapedefs.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/tapedefs.h	Wed Apr 11 19:02:28 2001
@@ -1,19 +1,19 @@
 /***********************************************************************
  *  drivers/s390/char/tapedefs.h
- *    tape device driver for S/390 tapes.
+ *    tape device driver for S/390 and zSeries tapes.
+ *
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s):  Carsten Otte <cotte@de.ibm.com>
+ *                Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *               Carsten Otte <cotte@de.ibm.com>
  *
- *  UNDER CONSTRUCTION: Work in progress... :-)
  ***********************************************************************
  */
 
-#define TAPE_DEBUG
-#define CONFIG_S390_TAPE_DYNAMIC //use dyn. dev. attach/detach
-#define TAPEBLOCK_RETRIES 20
+#define TAPE_DEBUG               // use s390 debug feature
+#define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly
+#define TAPEBLOCK_RETRIES 20     // number of retries, when a block-dev request fails.
 
 
 /* Kernel Version Compatibility section */
@@ -36,8 +36,11 @@
         blkdev_dequeue_request (req);
 }
 #else 
+#define s390_dev_info_t dev_info_t
 typedef struct request *request_queue_t;
+#ifndef init_waitqueue_head
 #define init_waitqueue_head(x) do { *x = NULL; } while(0)
+#endif
 #define blk_init_queue(x,y) do {} while(0)
 #define blk_queue_headactive(x,y) do {} while(0)
 #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tuball.c linux/drivers/s390/char/tuball.c
--- v2.4.3/linux/drivers/s390/char/tuball.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tuball.c	Wed Apr 18 11:49:11 2001
@@ -0,0 +1,625 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
+ *
+ *  tuball.c -- Initialization, termination, irq lookup
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include <linux/config.h>
+#include "tubio.h"
+#ifndef MODULE
+#include <linux/init.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#include <asm/cpcmd.h>
+#include <linux/bootmem.h>
+#else
+#include "../../../../arch/s390/kernel/cpcmd.h"
+#endif
+#endif
+
+/* Module parameters */
+int tubdebug;
+int tubscrolltime;
+int tubscrollparm;
+int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
+#ifdef MODULE
+MODULE_PARM(tubdebug, "i");
+MODULE_PARM(tubscrolltime, "i");
+MODULE_PARM(tubxcorrect, "i");
+#endif
+/*
+ * Values for tubdebug and their effects:
+ * 1 - print in hex on console the first 16 bytes received
+ * 2 - print address at which array tubminors is allocated
+ * 4 - attempt to register tty3270_driver
+ */
+int tubnummins;
+tub_t *(*tubminors)[TUBMAXMINS];
+tub_t *(*(*tubirqs)[256])[256];
+unsigned char tub_ascebc[256];
+unsigned char tub_ebcasc[256];
+int tubinitminors(void);
+void tubfiniminors(void);
+void tubint(int, void *, struct pt_regs *);
+
+/* Lookup-by-irq functions */
+int tubaddbyirq(tub_t *, int);
+tub_t *tubfindbyirq(int);
+void tubdelbyirq(tub_t *, int);
+void tubfiniirqs(void);
+
+extern int fs3270_init(void);
+extern void fs3270_fini(void);
+extern int tty3270_init(void);
+extern void tty3270_fini(void);
+
+unsigned char tub_ebcgraf[64] =
+	{ 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+	  0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+	  0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+	  0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+	  0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+	  0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+	  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+	  0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };
+
+static int tub3270_init(void);
+
+#ifndef MODULE
+
+/*
+ * Can't have this driver a module & support console at the same time
+ */
+#ifdef CONFIG_3270_CONSOLE
+static kdev_t tub3270_con_device(struct console *);
+static void tub3270_con_unblank(void);
+static void tub3270_con_write(struct console *, const char *,
+	unsigned int);
+
+static struct console tub3270_con = {
+	"tub3270",		/* name */
+	tub3270_con_write,	/* write */
+	NULL,			/* read */
+	tub3270_con_device,	/* device */
+	NULL,			/* wait_key */
+	tub3270_con_unblank,	/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,	/* flags */
+	0,			/* index */
+	0,			/* cflag */
+	NULL			/* next */
+};
+
+int tub3270_con_devno = -1;		/* set by tub3270_con_setup() */
+bcb_t tub3270_con_bcb;			/* Buffer that receives con writes */
+spinlock_t tub3270_con_bcblock;		/* Lock for the buffer */
+int tub3270_con_irq = -1;		/* set nonneg by _activate() */
+tub_t *tub3270_con_tubp;		/* set nonzero by _activate() */
+struct tty_driver tty3270_con_driver;	/* for /dev/console at 4, 64 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+__initfunc(void tub3270_con_setup(char *str, int *ints))
+#else
+static int __init tub3270_con_setup(char *str)
+#endif
+{
+	int vdev;
+
+	vdev = simple_strtoul(str, 0, 16);
+	if (vdev >= 0 && vdev < 65536)
+		tub3270_con_devno = vdev;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	return;
+#else
+	return 1;
+#endif
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+__setup("condev=", tub3270_con_setup);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+__initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
+#else
+void __init tub3270_con_init(void)
+#endif
+{
+	tub3270_con_bcb.bc_len = 65536;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
+		return kmem_start;
+	tub3270_con_bcb.bc_buf = (void *)kmem_start;
+	kmem_start += tub3270_con_bcb.bc_len;
+	register_console(&tub3270_con);
+	return kmem_start;
+#else
+	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
+		return;
+	tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
+		tub3270_con_bcb.bc_len);
+	register_console(&tub3270_con);
+#endif
+}
+
+static kdev_t
+tub3270_con_device(struct console *conp)
+{
+	return MKDEV(IBM_TTY3270_MAJOR, conp->index);
+}
+
+static void
+tub3270_con_unblank(void)
+{
+	/* flush everything:  panic has occurred */
+}
+
+int tub3270_con_write_deadlock_ct;
+int tub3270_con_write_deadlock_bytes;
+static void
+tub3270_con_write(struct console *conp,
+	const char *buf, unsigned int count)
+{
+	int flags;
+	tub_t *tubp = tub3270_con_tubp;
+	void tty3270_sched_bh(tub_t *);
+	int rc;
+	bcb_t obcb;
+
+	obcb.bc_buf = (char *)buf;
+	obcb.bc_len = obcb.bc_cnt = obcb.bc_wr =
+		MIN(count, tub3270_con_bcb.bc_len);
+	obcb.bc_rd = 0;
+
+	spin_lock_irqsave(&tub3270_con_bcblock, flags);
+	rc = tub3270_movedata(&obcb, &tub3270_con_bcb);
+	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
+
+	if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
+		tty3270_sched_bh(tubp);
+		TUBUNLOCK(tubp->irq, flags);
+	}
+}
+	
+int tub3270_con_copy(tub_t *tubp)
+{
+	int flags;
+	int rc;
+
+	spin_lock_irqsave(&tub3270_con_bcblock, flags);
+	rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb);
+	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
+	return rc;
+}
+#endif /* CONFIG_3270_CONSOLE */
+
+
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+__initfunc(void tub3270_initfunc(void))
+#else
+void __init tub3270_initfunc(void)
+#endif
+{
+	tub3270_init();
+}
+#else /* If generated as a MODULE */
+/*
+ * module init:  find tubes; get a major nbr
+ */
+int
+init_module(void)
+{
+	if (tubnummins != 0) {
+		printk(KERN_ERR "EEEK!!  Tube driver cobbigling!!\n");
+		return -1;
+	}
+	return tub3270_init();
+}
+
+/*
+ * remove driver:  unregister the major number
+ */
+void
+cleanup_module(void)
+{
+	fs3270_fini();
+	tty3270_fini();
+	tubfiniminors();
+}
+#endif /* Not a MODULE or a MODULE */
+
+void
+tub_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+void
+tub_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * tub3270_init() called by kernel or module initialization
+ */
+static int
+tub3270_init(void)
+{
+	s390_dev_info_t d;
+	int i, rc;
+
+	/*
+	 * Initialize default scrolltime to either -1 or the
+	 * module parameter tubscrolltime.
+	 */
+	if (tubscrolltime)
+		tubscrollparm = tubscrolltime;
+	else
+		tubscrollparm = -1;
+
+	/*
+	 * Copy and correct ebcdic - ascii translate tables
+	 */
+	memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc);
+	memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc);
+	if (tubxcorrect) {
+		/* correct brackets and circumflex */
+		tub_ascebc['['] = 0xad;
+		tub_ascebc[']'] = 0xbd;
+		tub_ebcasc[0xad] = '[';
+		tub_ebcasc[0xbd] = ']';
+		tub_ascebc['^'] = 0xb0;
+		tub_ebcasc[0x5f] = '^';
+	}
+
+	rc = tubinitminors();
+	if (rc != 0)
+		return rc;
+
+	for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
+		if ((rc = get_dev_info_by_irq(i, &d)))
+			continue;
+		if (d.status)
+			continue;
+#ifdef CONFIG_3270_CONSOLE
+		if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {
+			cpcmd("TERM CONMODE 3270", NULL, 0);
+			d.sid_data.cu_type = 0x3270;
+		}
+#endif /* CONFIG_3270_CONSOLE */
+		if ((d.sid_data.cu_type & 0xfff0) != 0x3270)
+			continue;
+
+		rc = tubmakemin(i, &d);
+		if (rc < 0) {
+			if (tubnummins == 1) {  /* if first time */
+				tubfiniminors();
+				printk(KERN_ERR "No kernel memory available"
+					" for 3270 tube devices.\n");
+				return rc;
+			}
+			printk(KERN_WARNING "3270 tube registration ran out of memory"
+				" after %d devices\n", tubnummins - 1);
+			break;
+		} else {
+			printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",
+				d.devno, d.irq, rc);
+		}
+	}
+
+	if (fs3270_init() || tty3270_init()) {
+		printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
+		fs3270_fini();
+		tty3270_fini();
+		tubfiniminors();
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
+ */
+int
+tub3270_movedata(bcb_t *ib, bcb_t *ob)
+{
+	int count;			/* Total move length */
+	int rc;
+
+	rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt);
+	while (count > 0) {
+		int len1;		/* Contig bytes avail in ib */
+
+		if (ib->bc_wr > ib->bc_rd)
+			len1 = ib->bc_wr - ib->bc_rd;
+		else
+			len1 = ib->bc_len - ib->bc_rd;
+		if (len1 > count)
+			len1 = count;
+
+		while (len1 > 0) {
+			int len2;	/* Contig space avail in ob */
+
+			if (ob->bc_rd > ob->bc_wr)
+				len2 = ob->bc_rd - ob->bc_wr;
+			else
+				len2 = ob->bc_len - ob->bc_wr;
+			if (len2 > len1)
+				len2 = len1;
+
+			memcpy(ob->bc_buf + ob->bc_wr,
+				ib->bc_buf + ib->bc_rd,
+				len2);
+
+			ib->bc_rd += len2;
+			if (ib->bc_rd == ib->bc_len)
+				ib->bc_rd = 0;
+			ib->bc_cnt -= len2;
+
+			ob->bc_wr += len2;
+			if (ob->bc_wr == ob->bc_len)
+				ob->bc_wr = 0;
+			ob->bc_cnt += len2;
+
+			len1 -= len2;
+			count -= len2;
+		}
+	}
+	return rc;
+}
+
+/*
+ * receive an interrupt
+ */
+void
+tubint(int irq, void *ipp, struct pt_regs *prp)
+{
+	devstat_t *dsp = ipp;
+	tub_t *tubp;
+
+	if ((tubp = IRQ2TUB(irq)) && (tubp->intv))
+		(tubp->intv)(tubp, dsp);
+}
+
+/*
+ * Initialize array of pointers to minor structures tub_t.
+ * Returns 0 or -ENOMEM.
+ */
+int
+tubinitminors(void)
+{
+	tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors,
+		GFP_KERNEL);
+	if (tubminors == NULL)
+		return -ENOMEM;
+	memset(tubminors, 0, sizeof *tubminors);
+	return 0;
+}
+
+/*
+ * Add a minor 327x device.  Argument is an irq value.
+ *
+ * Point elements of two arrays to the newly created tub_t:
+ * 1. (*tubminors)[minor]
+ * 2. (*(*tubirqs)[irqhi])[irqlo]
+ * The first looks up from minor number at context time; the second
+ * looks up from irq at interrupt time.
+ */
+int
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+tubmakemin(int irq, dev_info_t *dp)
+#else
+tubmakemin(int irq, s390_dev_info_t *dp)
+#endif
+{
+	tub_t *tubp;
+	int minor;
+	int flags;
+
+	if ((minor = ++tubnummins) == TUBMAXMINS)
+		return -ENODEV;
+
+	tubp = kmalloc(sizeof(tub_t), GFP_KERNEL);
+	if (tubp == NULL) {
+		return -ENOMEM;
+	}
+	if (tubaddbyirq(tubp, irq) != 0) {
+		kfree(tubp);
+		return -ENOMEM;
+	}
+	memset(tubp, 0, sizeof(tub_t));
+	tubp->minor = minor;
+	tubp->irq = irq;
+	TUBLOCK(tubp->irq, flags);
+	tubp->devno = dp->devno;
+	tubp->geom_rows = _GEOM_ROWS;
+	tubp->geom_cols = _GEOM_COLS;
+	init_waitqueue_head(&tubp->waitq);
+
+	tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
+	tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
+		GFP_KERNEL);
+	if (tubp->tty_bcb.bc_buf == NULL) {
+		TUBUNLOCK(tubp->irq, flags);
+		tubdelbyirq(tubp, irq);
+		kfree(tubp);
+		return -ENOMEM;
+	}
+	tubp->tty_bcb.bc_cnt = 0;
+	tubp->tty_bcb.bc_wr = 0;
+	tubp->tty_bcb.bc_rd = 0;
+	(*tubminors)[minor] = tubp;
+#ifdef CONFIG_3270_CONSOLE
+	if (tub3270_con_tubp == NULL && tub3270_con_bcb.bc_buf != NULL &&
+	    (tub3270_con_devno == -1 ||
+	     tub3270_con_devno == dp->devno)) {
+		extern void tty3270_int(tub_t *, devstat_t *);
+ 
+		tubp->cmd = TBC_CONOPEN;
+		tubp->flags |= TUB_OPEN_STET;
+		tty3270_size(tubp, &flags);
+		tty3270_aid_init(tubp);
+		tty3270_scl_init(tubp);
+		tub3270_con_irq = tubp->irq;
+		tub3270_con_tubp = tubp;
+		tubp->intv = tty3270_int;
+		tubp->cmd = TBC_UPDSTAT;
+		tty3270_build(tubp);
+	}
+#endif /* CONFIG_3270_CONSOLE */
+	TUBUNLOCK(tubp->irq, flags);
+	return minor;
+}
+
+/*
+ * Release array of pointers to minor structures tub_t, but first
+ * release any storage pointed to by them.
+ */
+void
+tubfiniminors(void)
+{
+	int i;
+	tub_t **tubpp, *tubp;
+
+	if (tubminors == NULL)
+		return;
+
+	for (i = 0; i < TUBMAXMINS; i++) {
+		tubpp = &(*tubminors)[i];
+		if ((tubp = *tubpp)) {
+			tubdelbyirq(tubp, tubp->irq);
+			tty3270_rcl_fini(tubp);
+			kfree(tubp->tty_bcb.bc_buf);
+			tubp->tty_bcb.bc_buf = NULL;
+			tubp->ttyscreen = NULL;
+			kfree(tubp);
+			*tubpp = NULL;
+		}
+	}
+	kfree(tubminors);
+	tubminors = NULL;
+	tubfiniirqs();
+}
+
+/*
+ * tubaddbyirq() -- Add tub_t for irq lookup in tubint()
+ */
+int
+tubaddbyirq(tub_t *tubp, int irq)
+{
+	int irqhi = (irq >> 8) & 255;
+	int irqlo = irq & 255;
+	tub_t *(*itubpp)[256];
+
+	/* Allocate array (*tubirqs)[] if first time */
+	if (tubirqs == NULL) {
+		tubirqs = (tub_t *(*(*)[256])[256])
+			kmalloc(sizeof *tubirqs, GFP_KERNEL);
+		if (tubirqs == NULL)
+			return -ENOMEM;
+		memset(tubirqs, 0, sizeof *tubirqs);
+	}
+
+	/* Allocate subarray (*(*tubirqs)[])[] if first use */
+	if ((itubpp = (*tubirqs)[irqhi]) == NULL) {
+		itubpp = (tub_t *(*)[256])
+			kmalloc(sizeof(*itubpp), GFP_KERNEL);
+		if (itubpp == NULL) {
+			if (tubnummins == 1) {  /* if first time */
+				kfree(tubirqs);
+				tubirqs = NULL;
+			}
+			return -ENOMEM;
+		} else {
+			memset(itubpp, 0, sizeof(*itubpp));
+			(*tubirqs)[irqhi] = itubpp;
+		}
+	}
+
+	/* Request interrupt service */
+	if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT,
+	    "3270 tube driver", &tubp->devstat)) != 0)
+		return tubp->irqrc;
+
+	/* Fill in the proper subarray element */
+	(*itubpp)[irqlo] = tubp;
+	return 0;
+}
+
+/*
+ * tubfindbyirq(irq)
+ */
+tub_t *
+tubfindbyirq(int irq)
+{
+	int irqhi = (irq >> 8) & 255;
+	int irqlo = irq & 255;
+	tub_t *tubp;
+
+	if (tubirqs == NULL)
+		return NULL;
+	if ((*tubirqs)[irqhi] == NULL)
+		return NULL;
+	tubp = (*(*tubirqs)[irqhi])[irqlo];
+	if (tubp->irq == irq)
+		return tubp;
+	return NULL;
+}
+
+/*
+ * tubdelbyirq(tub_t*, irq)
+ */
+void
+tubdelbyirq(tub_t *tubp, int irq)
+{
+	int irqhi = (irq >> 8) & 255;
+	int irqlo = irq & 255;
+	tub_t *(*itubpp)[256], *itubp;
+
+	if (tubirqs == NULL) {
+		printk(KERN_ERR "tubirqs is NULL\n");
+		return;
+	}
+	itubpp = (*tubirqs)[irqhi];
+	if (itubpp == NULL) {
+		printk(KERN_ERR "tubirqs[%d] is NULL\n", irqhi);
+		return;
+	}
+	itubp = (*itubpp)[irqlo];
+	if (itubp == NULL) {
+		printk(KERN_ERR "tubirqs[%d][%d] is NULL\n", irqhi, irqlo);
+		return;
+	}
+	if (itubp->irqrc == 0)
+		free_irq(irq, &itubp->devstat);
+	(*itubpp)[irqlo] = NULL;
+}
+
+/*
+ * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256]
+ */
+void
+tubfiniirqs(void)
+{
+	int i;
+	tub_t *(*itubpp)[256];
+
+	if (tubirqs != NULL) {
+		for (i = 0; i < 256; i++) {
+			if ((itubpp = (*tubirqs)[i])) {
+				kfree(itubpp);
+				(*tubirqs)[i] = NULL;
+			}
+		}
+		kfree(tubirqs);
+		tubirqs = NULL;
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubfs.c linux/drivers/s390/char/tubfs.c
--- v2.4.3/linux/drivers/s390/char/tubfs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubfs.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,404 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) UTS Global LLC
+ *
+ *  tubfs.c -- Fullscreen driver
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include "tubio.h"
+
+int fs3270_major = -1;			/* init to impossible -1 */
+
+static int fs3270_open(struct inode *, struct file *);
+static int fs3270_close(struct inode *, struct file *);
+static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+static int fs3270_read(struct file *, char *, size_t, loff_t *);
+static int fs3270_write(struct file *, const char *, size_t, loff_t *);
+static int fs3270_wait(tub_t *, int *);
+static void fs3270_int(tub_t *tubp, devstat_t *dsp);
+extern void tty3270_refresh(tub_t *);
+
+static struct file_operations fs3270_fops = {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+	owner: THIS_MODULE,		/* owner */
+#endif
+	read: 	fs3270_read,	/* read */
+	write:	fs3270_write,	/* write */
+	ioctl:	fs3270_ioctl,	/* ioctl */
+	open: 	fs3270_open,	/* open */
+	release:fs3270_close,	/* release */
+};
+
+/*
+ * fs3270_init() -- Initialize fullscreen tubes
+ */
+int
+fs3270_init(void)
+{
+	int rc;
+
+	rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
+	if (rc) {
+		printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
+			IBM_FS3270_MAJOR, rc);
+		return -1;
+	} else {
+		fs3270_major = IBM_FS3270_MAJOR;
+		return 0;
+	}
+}
+
+/*
+ * fs3270_fini() -- Uninitialize fullscreen tubes
+ */
+void
+fs3270_fini(void)
+{
+	if (fs3270_major != -1) {
+		unregister_chrdev(fs3270_major, "fs3270");
+		fs3270_major = -1;
+	}
+}
+
+/*
+ * fs3270_open
+ */
+static int
+fs3270_open(struct inode *ip, struct file *fp)
+{
+	tub_t *tubp;
+	int flags;
+
+	/* See INODE2TUB(ip) for handling of "/dev/3270/tub" */
+	if ((tubp = INODE2TUB(ip)) == NULL)
+		return -ENOENT;
+
+	TUBLOCK(tubp->irq, flags);
+	if (tubp->mode == TBM_FS || tubp->mode == TBM_FSLN) {
+		TUBUNLOCK(tubp->irq, flags);
+		return -EBUSY;
+	}
+
+	tub_inc_use_count();
+	fp->private_data = ip;
+	tubp->mode = TBM_FS;
+	tubp->intv = fs3270_int;
+	tubp->dstat = 0;
+	tubp->fs_pid = current->pid;
+	tubp->fsopen = 1;
+	TUBUNLOCK(tubp->irq, flags);
+	return 0;
+}
+
+/*
+ * fs3270_close aka release:  free the irq
+ */
+static int
+fs3270_close(struct inode *ip, struct file *fp)
+{
+	tub_t *tubp;
+	int flags;
+
+	if ((tubp = INODE2TUB(ip)) == NULL)
+		return -ENODEV;
+
+	fs3270_wait(tubp, &flags);
+	tubp->fsopen = 0;
+	tubp->fs_pid = 0;
+	tub_dec_use_count();
+	tubp->intv = NULL;
+	tubp->mode = 0;
+	tty3270_refresh(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+	return 0;
+}
+
+/*
+ * fs3270_release() called from tty3270_hangup()
+ */
+void
+fs3270_release(tub_t *tubp)
+{
+	int flags;
+
+	if (tubp->mode != TBM_FS)
+		return;
+	fs3270_wait(tubp, &flags);
+	tubp->fsopen = 0;
+	tubp->fs_pid = 0;
+	tub_dec_use_count();
+	tubp->intv = NULL;
+	tubp->mode = 0;
+	/*tty3270_refresh(tubp);*/
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+/*
+ * fs3270_wait(tub_t *tubp, int *flags) -- Wait to use tube
+ * Entered without irq lock
+ * On return:
+ *      * Lock is held
+ *      * Value is 0 or -ERESTARTSYS
+ */
+static int
+fs3270_wait(tub_t *tubp, int *flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	TUBLOCK(tubp->irq, *flags);
+	add_wait_queue(&tubp->waitq, &wait);
+	while (!signal_pending(current) &&
+	    ((tubp->mode != TBM_FS) ||
+	     (tubp->flags & (TUB_WORKING | TUB_RDPENDING)) != 0)) {
+		current->state = TASK_INTERRUPTIBLE;
+		TUBUNLOCK(tubp->irq, *flags);
+		schedule();
+		current->state = TASK_RUNNING;
+		TUBLOCK(tubp->irq, *flags);
+	}
+	remove_wait_queue(&tubp->waitq, &wait);
+	return signal_pending(current)? -ERESTARTSYS: 0;
+}
+
+/*
+ * fs3270_io(tubp, ccw1_t*) -- start I/O on the tube
+ * Entered with irq lock held, WORKING off
+ */
+static int
+fs3270_io(tub_t *tubp, ccw1_t *ccwp)
+{
+	int rc;
+
+	rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0);
+	tubp->flags |= TUB_WORKING;
+	tubp->dstat = 0;
+	return rc;
+}
+
+/*
+ * fs3270_bh(tubp) -- Perform back-half processing
+ */
+static void
+fs3270_bh(void *data)
+{
+	int flags;
+	tub_t *tubp;
+
+	tubp = data;
+	TUBLOCK(tubp->irq, flags);
+	tubp->flags &= ~TUB_BHPENDING;
+
+	if (tubp->wbuf) {       /* if we were writing */
+		kfree(tubp->wbuf);
+		tubp->wbuf = NULL;
+	}
+
+	if ((tubp->flags & (TUB_ATTN | TUB_RDPENDING)) ==
+	    (TUB_ATTN | TUB_RDPENDING)) {
+		fs3270_io(tubp, &tubp->rccw);
+		tubp->flags &= ~(TUB_ATTN | TUB_RDPENDING);
+	}
+
+	if ((tubp->flags & TUB_WORKING) == 0)
+		wake_up_interruptible(&tubp->waitq);
+
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+/*
+ * fs3270_sched_bh(tubp) -- Schedule the back half
+ * Irq lock must be held on entry and remains held on exit.
+ */
+static void
+fs3270_sched_bh(tub_t *tubp)
+{
+	if (tubp->flags & TUB_BHPENDING)
+		return;
+	tubp->flags |= TUB_BHPENDING;
+	tubp->tqueue.routine = fs3270_bh;
+	tubp->tqueue.data = tubp;
+	queue_task(&tubp->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * fs3270_int(tubp, prp) -- Process interrupt from tube in FS mode
+ * This routine is entered with irq lock held (see do_IRQ in s390io.c)
+ */
+static void
+fs3270_int(tub_t *tubp, devstat_t *dsp)
+{
+#define	DEV_UE_BUSY \
+	(DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
+
+	tubp->dstat = dsp->dstat;
+
+#ifdef RBHNOTYET
+	/* XXX needs more work; must save 2d arg to fs370_io() */
+	/* Handle CE-DE-UE and subsequent UDE */
+	if (dsp->dstat == DEV_UE_BUSY) {
+		tubp->flags |= TUB_UE_BUSY;
+		return;
+	} else if (tubp->flags & TUB_UE_BUSY) {
+		tubp->flags &= ~TUB_UE_BUSY;
+		if (dsp->dstat == DEV_STAT_DEV_END &&
+		    (tubp->flags & TUB_WORKING) != 0) {
+			fs3270_io(tubp);
+			return;
+		}
+	}
+#endif
+
+	/* Handle ATTN */
+	if (dsp->dstat & DEV_STAT_ATTENTION)
+		tubp->flags |= TUB_ATTN;
+
+	if (dsp->dstat & DEV_STAT_CHN_END) {
+		tubp->cswl = dsp->rescnt;
+		if ((dsp->dstat & DEV_STAT_DEV_END) == 0)
+			tubp->flags |= TUB_EXPECT_DE;
+		else
+			tubp->flags &= ~TUB_EXPECT_DE;
+	} else if (dsp->dstat & DEV_STAT_DEV_END) {
+		if ((tubp->flags & TUB_EXPECT_DE) == 0)
+			tubp->flags |= TUB_UNSOL_DE;
+		tubp->flags &= ~TUB_EXPECT_DE;
+	}
+	if (dsp->dstat & DEV_STAT_DEV_END)
+		tubp->flags &= ~TUB_WORKING;
+
+	if ((tubp->flags & TUB_WORKING) == 0)
+		fs3270_sched_bh(tubp);
+}
+
+/*
+ * process ioctl commands for the tube driver
+ */
+static int
+fs3270_ioctl(struct inode *ip, struct file *fp,
+	unsigned int cmd, unsigned long arg)
+{
+	tub_t *tubp;
+	int rc = 0, flags;
+
+	if ((tubp = INODE2TUB(ip)) == NULL)
+		return -ENODEV;
+	if ((rc = fs3270_wait(tubp, &flags))) {
+		TUBUNLOCK(tubp->irq, flags);
+		return rc;
+	}
+
+	switch(cmd) {
+	case TUBICMD: tubp->icmd = arg; break;
+	case TUBOCMD: tubp->ocmd = arg; break;
+	case TUBGETI: put_user(tubp->icmd, (char *)arg); break;
+	case TUBGETO: put_user(tubp->ocmd, (char *)arg); break;
+	case TUBGETMOD:
+		if (copy_to_user((char *)arg, &tubp->tubiocb,
+		    sizeof tubp->tubiocb))
+			rc = -EFAULT;
+		break;
+	}
+	TUBUNLOCK(tubp->irq, flags);
+	return rc;
+}
+
+/*
+ * process read commands for the tube driver
+ */
+static int
+fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
+{
+	tub_t *tubp;
+	char *kp;
+	ccw1_t *cp;
+	int rc, flags;
+
+	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
+		return -ENODEV;
+	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
+		TUBUNLOCK(tubp->irq, flags);
+		return rc;
+	}
+
+	kp = kmalloc(len, GFP_KERNEL);
+	if (kp == NULL) {
+		TUBUNLOCK(tubp->irq, flags);
+		return -ENOMEM;
+	}
+
+	cp = &tubp->rccw;
+	if (tubp->icmd == 0 && tubp->ocmd != 0)  tubp->icmd = 6;
+	cp->cmd_code = tubp->icmd?:2;
+	cp->flags = CCW_FLAG_SLI;
+	cp->count = len;
+	cp->cda = virt_to_phys(kp);
+	tubp->flags |= TUB_RDPENDING;
+	TUBUNLOCK(tubp->irq, flags);
+
+	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
+		tubp->flags &= ~TUB_RDPENDING;
+		TUBUNLOCK(tubp->irq, flags);
+		kfree(kp);
+		return rc;
+	}
+
+	len -= tubp->cswl;
+	TUBUNLOCK(tubp->irq, flags);
+	if (tubdebug & 1)
+		printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n",
+			tubp->minor,
+			*(int*)((int)kp + 0),
+			*(int*)((int)kp + 4),
+			*(int*)((int)kp + 8),
+			*(int*)((int)kp + 12));
+	copy_to_user(dp, kp, len);
+	kfree(kp);
+	return len;
+}
+
+/*
+ * process write commands for the tube driver
+ */
+static int
+fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
+{
+	tub_t *tubp;
+	ccw1_t *cp;
+	int rc, flags;
+	void *kb;
+
+	/* Locate the tube */
+	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
+		return -ENODEV;
+
+	/* Copy data to write from user address space */
+	if ((kb = kmalloc(len, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	if (copy_from_user(kb, dp, len) != 0) {
+		kfree(kb);
+		return -EFAULT;
+	}
+
+	/* Wait till tube's not working or signal is pending */
+	if ((rc = fs3270_wait(tubp, &flags))) {
+		TUBUNLOCK(tubp->irq, flags);
+		kfree(kb);
+		return rc;
+	}
+
+	/* Make CCW and start I/O.  Back end will free buffer. */
+	tubp->wbuf = kb;
+	cp = &tubp->wccw;
+	cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
+	cp->flags = CCW_FLAG_SLI;
+	cp->count = len;
+	cp->cda = virt_to_phys(tubp->wbuf);
+	fs3270_io(tubp, cp);
+	TUBUNLOCK(tubp->irq, flags);
+	return len;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubio.h linux/drivers/s390/char/tubio.h
--- v2.4.3/linux/drivers/s390/char/tubio.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubio.h	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,432 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
+ *
+ *  tubio.h -- All-Purpose header file
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/major.h>
+#ifndef IBM_TTY3270_MAJOR
+#  define IBM_TTY3270_MAJOR 212
+#endif /* IBM_TTY3270_MAJOR */
+#ifndef IBM_FS3270_MAJOR
+#  define IBM_FS3270_MAJOR 213
+#endif /* IBM_FS3270_MAJOR */
+
+
+#include <linux/malloc.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <asm/ebcdic.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+#define TUB(x) (('3'<<8)|(x))
+#define TUBICMD TUB(3)
+#define TUBOCMD TUB(4)
+#define TUBGETI TUB(7)
+#define TUBGETO TUB(8)
+#define TUBSETMOD TUB(12)
+#define TUBGETMOD TUB(13)
+#define TIOPOLL TUB(32)
+#define TIOPOKE TUB(33)
+#define TIONPOKE TUB(34)
+#define TIOTNORM TUB(35)
+
+/* Local Channel Commands */
+#define TC_WRITE   0x01
+#define TC_EWRITE  0x05
+#define TC_READMOD 0x06
+#define TC_EWRITEA 0x0d
+#define TC_WRITESF 0x11
+
+/* Buffer Control Orders */
+#define TO_SF 0x1d
+#define TO_SBA 0x11
+#define TO_IC 0x13
+#define TO_PT 0x05
+#define TO_RA 0x3c
+#define TO_SFE 0x29
+#define TO_EUA 0x12
+#define TO_MF 0x2c
+#define TO_SA 0x28
+
+/* Field Attribute Bytes */
+#define TF_INPUT 0x40           /* Visible input */
+#define TF_INPUTN 0x4c          /* Invisible input */
+#define TF_INMDT 0xc1           /* Visible, Set-MDT */
+#define TF_LOG 0x60
+#define TF_STAT 0x60
+
+/* Character Attribute Bytes */
+#define TAT_RESET 0x00
+#define TAT_FIELD 0xc0
+#define TAT_EXTHI 0x41
+#define TAT_COLOR 0x42
+#define TAT_CHARS 0x43
+#define TAT_TRANS 0x46
+
+/* Reset value */
+#define TAR_RESET 0x00
+
+/* Color values */
+#define TAC_BLUE 0xf1
+#define TAC_RED 0xf2
+#define TAC_PINK 0xf3
+#define TAC_GREEN 0xf4
+#define TAC_TURQ 0xf5
+#define TAC_YELLOW 0xf6
+#define TAC_WHITE 0xf7
+#define TAC_DEFAULT 0x00
+
+/* Write Control Characters */
+#define TW_NONE 0x40            /* No particular action */
+#define TW_KR 0xc2              /* Keyboard restore */
+#define TW_PLUSALARM 0x04       /* Add this bit for alarm */
+
+/* Attention-ID (AID) Characters */
+#define TA_CLEAR 0x6d
+#define TA_PA2 0x6e
+#define TA_ENTER 0x7d
+/* more to come */
+
+#define MIN(a, b) ((a) < (b)? (a): (b))
+
+#define TUB_BUFADR(adr, cpp) \
+	tty3270_tub_bufadr(tubp, adr, cpp)
+
+#define TUB_EBCASC(addr, nr) codepage_convert(tub_ebcasc, addr, nr)
+#define TUB_ASCEBC(addr, nr) codepage_convert(tub_ascebc, addr, nr)
+
+/*
+ *
+ * General global values for the tube driver
+ *
+ */
+enum tubmode {
+	TBM_LN,                 /* Line mode */
+	TBM_FS,                 /* Fullscreen mode */
+	TBM_FSLN                /* Line mode shelled out of fullscreen */
+};
+enum tubstat {              /* normal-mode status */
+	TBS_RUNNING,            /* none of the following */
+	TBS_MORE,               /* timed "MORE..." in status */
+	TBS_HOLD                /* untimed "HOLDING" in status */
+};
+enum tubcmd {           /* normal-mode actions to do */
+	TBC_CONOPEN,		/* Erase-write the console */
+	TBC_OPEN,               /* Open the tty screen */
+	TBC_UPDATE,             /* Add lines to the log, clear cmdline */
+	TBC_UPDLOG,             /* Add lines to log */
+	TBC_KRUPDLOG,           /* Add lines to log, reset kbd */
+	TBC_CLEAR,              /* Build screen from scratch */
+	TBC_CLRUPDLOG,          /* Do log & status, not cmdline */
+	TBC_UPDSTAT,            /* Do status update only */
+	TBC_CLRINPUT,           /* Clear input area only */
+	TBC_UPDINPUT            /* Update input area only */
+};
+enum tubwhat {          /* echo what= proc actions */
+	TW_BOGUS,               /* Nothing at all */
+	TW_CONFIG               /* Output configuration info */
+};
+
+
+
+
+
+#define TUBMAXMINS      256
+#define TUB_DEV MKDEV(IBM_FS3270_MAJ, 0)        /* Generic /dev/3270/tub */
+#define _GEOM_ROWS 24
+#define _GEOM_COLS 80
+#define GEOM_ROWS (tubp->geom_rows)
+#define GEOM_COLS (tubp->geom_cols)
+#define GEOM_MAXROWS 127
+#define GEOM_MAXCOLS 132
+#define GEOM_INPLEN (GEOM_COLS * 2 - 20)
+#define GEOM_MAXINPLEN (GEOM_MAXCOLS * 2 - 20)
+#define GEOM_INPUT (GEOM_COLS * (GEOM_ROWS - 2) - 1)  /* input atr posn */
+#define GEOM_STAT (GEOM_INPUT + 1 + GEOM_INPLEN)
+#define GEOM_LOG   (GEOM_COLS * GEOM_ROWS - 1)   /* log atr posn */
+#define TS_RUNNING "Linux Running     "
+#define TS_MORE    "Linux More...     "
+#define DEFAULT_SCROLLTIME 5
+#define TS_HOLD    "Linux Holding     "
+/* data length used by tty3270_set_status_area: SBA (3), SF (2), data */
+#define TS_LENGTH (sizeof TS_RUNNING + 3 + 2)
+
+typedef struct {
+	int aid;                        /* What-to-do flags */
+	char *string;                   /* Optional input string */
+} aid_t;
+#define AIDENTRY(ch, tubp)  (&((tubp)->tty_aid[(ch) & 0x3f]))
+
+/* For TUBGETMOD and TUBSETMOD.  Should include. */
+typedef struct tubiocb {
+	short model;
+	short line_cnt;
+	short col_cnt;
+	short pf_cnt;
+	short re_cnt;
+	short map;
+} tubiocb_t;
+
+/* Flags that go in int aid, above */
+#define TA_CLEARKEY     0x01            /* Key does hardware CLEAR */
+#define TA_SHORTREAD    0x02            /* Key does hardware shortread */
+/* If both are off, key does hardware Read Modified. */
+#define TA_DOENTER      0x04            /* Treat key like ENTER */
+#define TA_DOSTRING     0x08            /* Use string and ENTER */
+#define TA_DOSTRINGD    0x10            /* Display string & set MDT */
+#define TA_CLEARLOG     0x20            /* Make key cause clear of log */
+
+/*
+ * Tube driver buffer control block
+ */
+typedef struct bcb_s {
+	char	*bc_buf;		/* Pointer to buffer */
+	int	bc_len;			/* Length of buffer */
+	int	bc_cnt;			/* Count of bytes buffered */
+	int	bc_wr;			/* Posn to write next byte into */
+	int	bc_rd;			/* Posn to read next byte from */
+} bcb_t;
+
+typedef struct tub_s {
+	int             minor;
+	int             irq;
+	int             irqrc;
+	int             devno;
+	int             geom_rows;
+	int             geom_cols;
+	tubiocb_t       tubiocb;
+	int             lnopen;
+	int             fsopen;
+	int             icmd;
+	int             ocmd;
+	devstat_t       devstat;
+	ccw1_t          rccw;
+	ccw1_t          wccw;
+	void            *wbuf;
+	int             cswl;
+	void            (*intv)(struct tub_s *, devstat_t *);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	struct wait_queue	*waitq;
+#else
+	wait_queue_head_t waitq;
+#endif
+	int             dstat;
+	sense_t         sense;
+	enum tubmode    mode;
+	enum tubstat    stat;
+	enum tubcmd     cmd;
+	int             flags;		/* See below for values */
+	struct tq_struct tqueue;
+
+	/* Stuff for fs-driver support */
+	pid_t           fs_pid;         /* Pid if TBM_FS */
+
+
+	/* Stuff for tty-driver support */
+	struct tty_struct *tty;
+	char tty_input[GEOM_MAXINPLEN]; /* tty input area */
+	int tty_inattr;         	/* input-area field attribute */
+#define TTY_OUTPUT_SIZE 1024
+	bcb_t tty_bcb;			/* Output buffer control info */
+	int tty_oucol;                  /* Kludge */
+	int tty_nextlogx;               /* next screen-log position */
+	int tty_scrolltime;             /* scrollforward wait time, sec */
+	struct timer_list tty_stimer;   /* timer for scrolltime */
+	aid_t tty_aid[64];              /* Aid descriptors */
+	int tty_aidinit;                /* Boolean */
+	int tty_showaidx;               /* Last aid x to set_aid */
+	int tty_14bitadr;               /* 14-bit bufadrs okay */
+#define MAX_TTY_ESCA 24			/* Set-Attribute-Order array */
+	char tty_esca[MAX_TTY_ESCA];	/* SA array */
+	int tty_escx;			/* Current index within it */
+
+	/* For command recall --- */
+	char *(*tty_rclbufs)[];         /* Array of ptrs to recall bufs */
+	int tty_rclk;                   /* Size of array tty_rclbufs */
+	int tty_rclp;                   /* Index for most-recent cmd */
+	int tty_rclb;                   /* Index for backscrolling */
+
+	/* Work area to contain the hardware write stream */
+	char (*ttyscreen)[];            /* ptr to data stream area */
+	int ttyscreenl;			/* its length */
+	ccw1_t ttyccw;
+} tub_t;
+
+/* values for flags: */
+#define	TUB_WORKING	0x0001
+#define	TUB_BHPENDING	0x0002
+#define	TUB_RDPENDING	0x0004
+#define	TUB_ALARM	0x0008
+#define	TUB_SCROLLTIMING  0x0010
+#define	TUB_ATTN	0x0020
+#define	TUB_IACTIVE	0x0040
+#define	TUB_SIZED	0x0080
+#define	TUB_EXPECT_DE	0x0100
+#define	TUB_UNSOL_DE	0x0200
+#define	TUB_OPEN_STET	0x0400		/* No screen clear on open */
+#define	TUB_UE_BUSY	0x0800
+
+#ifdef CONFIG_3270_CONSOLE
+/*
+ * Extra stuff for 3270 console support
+ */
+#define	S390_CONSOLE_DEV MKDEV(TTY_MAJOR, 64)
+extern int tub3270_con_devno;
+extern char (*tub3270_con_output)[];
+extern int tub3270_con_outputl;
+extern int tub3270_con_ouwr;
+extern int tub3270_con_oucount;
+extern int tub3270_con_irq;
+extern tub_t *tub3270_con_tubp;
+extern struct tty_driver tty3270_con_driver;
+#endif /* CONFIG_3270_CONSOLE */
+
+extern int tubnummins;
+extern tub_t *(*tubminors)[TUBMAXMINS];
+extern tub_t *(*(*tubirqs)[256])[256];
+extern unsigned char tub_ascebc[256];
+extern unsigned char tub_ebcasc[256];
+extern unsigned char tub_ebcgraf[64];
+extern int tubdebug;
+extern int fs3270_major;
+extern int tty3270_major;
+extern int tty3270_proc_misc;
+extern enum tubwhat tty3270_proc_what;
+
+#ifndef spin_trylock_irqsave
+#define spin_trylock_irqsave(lock, flags) \
+({ \
+	int success; \
+	__save_flags(flags); \
+	__cli(); \
+	success = spin_trylock(lock); \
+	if (success == 0) \
+		__restore_flags(flags); \
+	success; \
+})
+#endif /* if not spin_trylock_irqsave */
+
+#ifndef s390irq_spin_trylock_irqsave
+#define s390irq_spin_trylock_irqsave(irq, flags) \
+	spin_trylock_irqsave(&(ioinfo[irq]->irq_lock), flags)
+#endif /* if not s390irq_spin_trylock_irqsave */
+
+#define TUBLOCK(irq, flags) \
+	s390irq_spin_lock_irqsave(irq, flags)
+
+#define TUBTRYLOCK(irq, flags) \
+	s390irq_spin_trylock_irqsave(irq, flags)
+
+#define TUBUNLOCK(irq, flags) \
+	s390irq_spin_unlock_irqrestore(irq, flags)
+
+/*
+ * Find tub_t * given fullscreen device's irq (subchannel number)
+ */
+extern tub_t *tubfindbyirq(int);
+#define IRQ2TUB(irq) tubfindbyirq(irq)
+/*
+ * Find tub_t * given fullscreen device's inode pointer
+ * This algorithm takes into account /dev/3270/tub.
+ */
+#ifdef CONFIG_3270_CONSOLE
+#define INODE2TUB(ip) \
+({ \
+	unsigned int minor; \
+	tub_t *tubp = NULL; \
+	minor = MINOR((ip)->i_rdev); \
+	if (minor == 0 && current->tty != NULL) { \
+		if (tub3270_con_tubp != NULL && \
+		    current->tty->device == S390_CONSOLE_DEV) \
+			minor = tub3270_con_tubp->minor; \
+		else if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
+			minor = MINOR(current->tty->device); \
+	} \
+	if (minor <= tubnummins && minor > 0) \
+		tubp = (*tubminors)[minor]; \
+	tubp; \
+})
+#else /* not CONFIG_3270_CONSOLE */
+#define INODE2TUB(ip) \
+({ \
+	unsigned int minor; \
+	tub_t *tubp = NULL; \
+	minor = MINOR((ip)->i_rdev); \
+	if (minor == 0 && current->tty != NULL && \
+	    MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
+		minor = MINOR(current->tty->device); \
+	if (minor <= tubnummins && minor > 0) \
+		tubp = (*tubminors)[minor]; \
+	tubp; \
+})
+#endif /* CONFIG_3270_CONSOLE or not */
+/*
+ * Find tub_t * given non-fullscreen (tty) device's tty_struct pointer
+ */
+#ifdef CONFIG_3270_CONSOLE
+#define TTY2TUB(tty) \
+({ \
+	unsigned int minor; \
+	tub_t *tubp = NULL; \
+	minor = MINOR(tty->device); \
+	if (tty->device == S390_CONSOLE_DEV) \
+		tubp = tub3270_con_tubp; \
+	else if (minor <= tubnummins && minor > 0) \
+		tubp = (*tubminors)[minor]; \
+	tubp; \
+})
+#else /* if not CONFIG_3270_CONSOLE */
+#define TTY2TUB(tty) \
+({ \
+	unsigned int minor; \
+	tub_t *tubp = NULL; \
+	minor = MINOR(tty->device); \
+	if (minor <= tubnummins && minor > 0) \
+		tubp = (*tubminors)[minor]; \
+	tubp; \
+})
+#endif /* CONFIG_3270_CONSOLE or not */
+
+extern void tub_inc_use_count(void);
+extern void tub_dec_use_count(void);
+extern int tub3270_movedata(bcb_t *, bcb_t *);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+extern int tubmakemin(int, dev_info_t *);
+#else
+extern int tubmakemin(int, s390_dev_info_t *);
+#endif
+extern int tub3270_con_copy(tub_t *);
+extern int tty3270_rcl_init(tub_t *);
+extern int tty3270_rcl_set(tub_t *, char *, int);
+extern void tty3270_rcl_fini(tub_t *);
+extern int tty3270_rcl_get(tub_t *, char *, int, int);
+extern void tty3270_rcl_put(tub_t *, char *, int);
+extern void tty3270_rcl_sync(tub_t *);
+extern void tty3270_rcl_purge(tub_t *);
+extern int tty3270_rcl_resize(tub_t *, int);
+extern int tty3270_size(tub_t *, int *);
+extern int tty3270_aid_init(tub_t *);
+extern void tty3270_aid_fini(tub_t *);
+extern void tty3270_aid_reinit(tub_t *);
+extern int tty3270_aid_get(tub_t *, int, int *, char **);
+extern int tty3270_aid_set(tub_t *, char *, int);
+extern int tty3270_build(tub_t *);
+extern void tty3270_scl_settimer(tub_t *);
+extern void tty3270_scl_resettimer(tub_t *);
+extern int tty3270_scl_set(tub_t *, char *, int);
+extern int tty3270_scl_init(tub_t *tubp);
+extern void tty3270_scl_fini(tub_t *tubp);
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubtty.c linux/drivers/s390/char/tubtty.c
--- v2.4.3/linux/drivers/s390/char/tubtty.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubtty.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,1001 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC
+ *
+ *  tubtty.c -- Linemode tty driver
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include <linux/config.h>
+#include "tubio.h"
+
+/* Initialization & uninitialization for tubtty */
+int tty3270_init(void);
+void tty3270_fini(void);
+
+/* Interface routines from the upper tty layer to the tty driver */
+static int tty3270_open(struct tty_struct *, struct file *);
+static void tty3270_close(struct tty_struct *, struct file *);
+static int tty3270_write(struct tty_struct *, int,
+        const unsigned char *, int);
+static void tty3270_put_char(struct tty_struct *, unsigned char);
+static void tty3270_flush_chars(struct tty_struct *);
+static int tty3270_write_room(struct tty_struct *);
+static int tty3270_chars_in_buffer(struct tty_struct *);
+static int tty3270_ioctl(struct tty_struct *, struct file *,
+	unsigned int cmd, unsigned long arg);
+static void tty3270_set_termios(struct tty_struct *, struct termios *);
+static void tty3270_hangup(struct tty_struct *);
+static void tty3270_flush_buffer(struct tty_struct *);
+static int tty3270_read_proc(char *, char **, off_t, int, int *, void *);
+static int tty3270_write_proc(struct file *, const char *,
+	unsigned long, void *);
+
+/* tty3270 utility functions */
+static void tty3270_bh(void *);
+       void tty3270_sched_bh(tub_t *);
+static int tty3270_wait(tub_t *, int *);
+       void tty3270_int(tub_t *, devstat_t *);
+       int tty3270_try_logging(tub_t *);
+static void tty3270_start_input(tub_t *);
+static void tty3270_do_input(tub_t *);
+static void tty3270_do_enter(tub_t *, char *, int);
+static void tty3270_do_showi(tub_t *, char *, int);
+       int tty3270_io(tub_t *);
+static int tty3270_show_tube(int, char *, int);
+
+int tty3270_major = -1;
+char tty3270_major_string[16];
+struct tty_driver tty3270_driver;
+int tty3270_refcount;
+struct tty_struct *tty3270_table[TUBMAXMINS];
+struct termios *tty3270_termios[TUBMAXMINS];
+struct termios *tty3270_termios_locked[TUBMAXMINS];
+#ifdef CONFIG_3270_CONSOLE
+int con3270_major = -1;
+struct tty_driver con3270_driver;
+int con3270_refcount;
+struct tty_struct *con3270_table[1];
+struct termios *con3270_termios[1];
+struct termios *con3270_termios_locked[1];
+#endif /* CONFIG_3270_CONSOLE */
+
+int tty3270_proc_index;
+int tty3270_proc_data;
+int tty3270_proc_misc;
+enum tubwhat tty3270_proc_what;
+
+/*
+ * tty3270_init() -- Register the tty3270 driver
+ */
+int
+tty3270_init(void)
+{
+	struct tty_driver *td = &tty3270_driver;
+	int rc;
+
+	/* Initialize for tty driver */
+	td->magic = TTY_DRIVER_MAGIC;
+	td->driver_name = "tty3270";
+	td->name = "tty3270";
+	td->major = IBM_TTY3270_MAJOR;
+	td->minor_start = 0;
+	td->num = TUBMAXMINS;
+	td->type = TTY_DRIVER_TYPE_SYSTEM;
+	td->subtype = SYSTEM_TYPE_TTY;
+	td->init_termios = tty_std_termios;
+	td->flags = TTY_DRIVER_RESET_TERMIOS;
+	td->refcount = &tty3270_refcount;
+	td->table = tty3270_table;
+	td->termios = tty3270_termios;
+	td->termios_locked = tty3270_termios_locked;
+
+	td->open = tty3270_open;
+	td->close = tty3270_close;
+	td->write = tty3270_write;
+	td->put_char = tty3270_put_char;
+	td->flush_chars = tty3270_flush_chars;
+	td->write_room = tty3270_write_room;
+	td->chars_in_buffer = tty3270_chars_in_buffer;
+	td->ioctl = tty3270_ioctl;
+	td->ioctl = NULL;
+	td->set_termios = tty3270_set_termios;
+	td->throttle = NULL;
+	td->unthrottle = NULL;
+	td->stop = NULL;
+	td->start = NULL;
+	td->hangup = tty3270_hangup;
+	td->break_ctl = NULL;
+	td->flush_buffer = tty3270_flush_buffer;
+	td->set_ldisc = NULL;
+	td->wait_until_sent = NULL;
+	td->send_xchar = NULL;
+	td->read_proc = tty3270_read_proc;
+	td->write_proc = tty3270_write_proc;
+
+	rc = tty_register_driver(td);
+	if (rc) {
+		printk(KERN_ERR "tty3270 registration failed with %d\n", rc);
+	} else {
+		tty3270_major = IBM_TTY3270_MAJOR;
+		sprintf(tty3270_major_string, "%d", tty3270_major);
+		if (td->proc_entry != NULL)
+			td->proc_entry->mode = S_IRUGO | S_IWUGO;
+	}
+#ifdef CONFIG_3270_CONSOLE
+	tty3270_con_driver = *td;
+	td = &tty3270_con_driver;
+	td->driver_name = "con3270";
+	td->name = "con3270";
+	td->major = MAJOR(S390_CONSOLE_DEV);
+	td->minor_start = MINOR(S390_CONSOLE_DEV);
+	td->num = 1;
+	td->refcount = &con3270_refcount;
+	td->table = con3270_table;
+	td->termios = con3270_termios;
+	td->termios_locked = con3270_termios_locked;
+
+	rc = tty_register_driver(td);
+	if (rc) {
+		printk(KERN_ERR "con3270 registration failed with %d\n", rc);
+	} else {
+		con3270_major = MAJOR(S390_CONSOLE_DEV);
+		if (td->proc_entry != NULL)
+			td->proc_entry->mode = S_IRUGO | S_IWUGO;
+	}
+#endif /* if CONFIG_3270_CONSOLE */
+
+	return rc;
+}
+
+/*
+ * tty3270_fini() -- Uninitialize linemode tubes
+ */
+void
+tty3270_fini(void)
+{
+	if (tty3270_major != -1) {
+		tty_unregister_driver(&tty3270_driver);
+		tty3270_major = -1;
+	}
+#ifdef CONFIG_3270_CONSOLE
+	if (con3270_major != -1) {
+		tty_unregister_driver(&con3270_driver);
+		con3270_major = -1;
+	}
+#endif
+}
+
+static int 
+tty3270_open(struct tty_struct *tty, struct file *filp)
+{
+	tub_t *tubp;
+	int flags;
+	int rc;
+	int cmd;
+
+	if ((tubp = TTY2TUB(tty)) == NULL) {
+		return -ENODEV;
+	}
+
+	tub_inc_use_count();
+	if ((rc = tty3270_wait(tubp, &flags)) != 0)
+		goto do_fail;
+	if (tubp->lnopen > 0) {
+		tubp->lnopen++;
+		TUBUNLOCK(tubp->irq, flags);
+		return 0;
+	}
+	if (tubp->flags & TUB_OPEN_STET) {
+		cmd = TBC_UPDLOG;
+	} else {
+		cmd = TBC_OPEN;
+		tubp->flags &= ~TUB_SIZED;
+	}
+	if ((rc = tty3270_size(tubp, &flags)) != 0)
+		goto do_fail;
+	if ((rc = tty3270_rcl_init(tubp)) != 0)
+		goto do_fail;
+	if ((rc = tty3270_aid_init(tubp)) != 0)
+		goto do_fail;
+	if ((rc = tty3270_scl_init(tubp)) != 0)
+		goto do_fail;
+	tubp->mode = TBM_LN;
+	tubp->intv = tty3270_int;
+	tubp->tty = tty;
+	tubp->lnopen = 1;
+	tty->driver_data = tubp;
+	tty->winsize.ws_row = tubp->geom_rows;
+	tty->winsize.ws_col = tubp->geom_cols;
+	tubp->tty_inattr = TF_INPUT;
+	tubp->cmd = cmd;
+	tty3270_build(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+	return 0;
+
+do_fail:
+	tty3270_scl_fini(tubp);
+	tty3270_aid_fini(tubp);
+	tty3270_rcl_fini(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+	tub_dec_use_count();
+	return rc;
+}
+
+static void
+tty3270_close(struct tty_struct *tty, struct file *filp)
+{
+	tub_t *tubp;
+	int flags;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return;
+
+	tty3270_wait(tubp, &flags);
+	if (--tubp->lnopen > 0)
+		goto do_return;
+	tubp->tty = NULL;
+	tty->driver_data = NULL;
+	tty3270_aid_fini(tubp);
+	tty3270_rcl_fini(tubp);
+	tty3270_scl_fini(tubp);
+do_return:
+	tub_dec_use_count();
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+static int 
+tty3270_write(struct tty_struct *tty, int fromuser,
+		const unsigned char *buf, int count)
+{
+	tub_t *tubp;
+	int flags;
+	bcb_t obcb;
+	int rc = 0;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return -1;
+
+#ifdef CONFIG_3270_CONSOLE
+	if (tub3270_con_tubp == tubp)
+		tub3270_con_copy(tubp);
+#endif /* CONFIG_3270_CONSOLE */
+
+	obcb.bc_buf = (char *)buf;
+	obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count;
+	obcb.bc_rd = 0;
+
+	TUBLOCK(tubp->irq, flags);
+	rc = tub3270_movedata(&obcb, &tubp->tty_bcb);
+	tty3270_try_logging(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+	return rc;
+} 
+
+static void
+tty3270_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	int flags;
+	tub_t *tubp;
+	bcb_t *ob;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return;
+
+	TUBLOCK(tubp->irq, flags);
+	ob = &tubp->tty_bcb;
+	if (ob->bc_cnt < ob->bc_len) {
+		ob->bc_buf[ob->bc_wr++] = ch;
+		if (ob->bc_wr == ob->bc_len)
+			ob->bc_wr = 0;
+		ob->bc_cnt++;
+	}
+	tty3270_try_logging(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+static void
+tty3270_flush_chars(struct tty_struct *tty)
+{
+	tub_t *tubp;
+	int flags;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return;
+
+	TUBLOCK(tubp->irq, flags);
+	tty3270_try_logging(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+static int 
+tty3270_write_room(struct tty_struct *tty)
+{
+	tub_t *tubp;
+	bcb_t *ob;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return -1;
+
+	ob = &tubp->tty_bcb;
+	return ob->bc_len - ob->bc_cnt;
+}
+
+static int
+tty3270_chars_in_buffer(struct tty_struct *tty)
+{
+	tub_t *tubp;
+	bcb_t *ob;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return -1;
+
+	ob = &tubp->tty_bcb;
+	return ob->bc_cnt;
+}
+
+static int
+tty3270_ioctl(struct tty_struct *tty, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	tub_t *tubp;
+	int flags;
+	int ret = 0;
+	struct termios termios;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return -ENODEV;
+
+	TUBLOCK(tubp->irq, flags);
+	if (tty->flags * (1 << TTY_IO_ERROR)) {
+		ret = -EIO;
+		goto do_return;
+	}
+	switch(cmd) {
+	case TCGETS:
+		ret = -ENOIOCTLCMD;
+		goto do_return;
+	case TCFLSH:            /* arg:  2 or 0 */
+		ret = -ENOIOCTLCMD;
+		goto do_return;
+	case TCSETSF:
+		if (user_termios_to_kernel_termios(&termios,
+		    (struct termios *)arg)) {
+			ret = -EFAULT;
+			goto do_return;
+		}
+		ret = -ENOIOCTLCMD;
+		goto do_return;
+	case TCGETA:
+		ret = -ENOIOCTLCMD;
+		goto do_return;
+	case TCSETA:
+		if (user_termio_to_kernel_termios(&termios,
+		    (struct termio *)arg)) {
+			ret = -EFAULT;
+			goto do_return;
+		}
+		ret = -ENOIOCTLCMD;
+		goto do_return;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+do_return:
+	TUBUNLOCK(tubp->irq, flags);
+	return ret;
+}
+
+static void
+tty3270_set_termios(struct tty_struct *tty, struct termios *old)
+{
+	tub_t *tubp;
+	int flags;
+	int new;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return;
+
+	if (tty3270_wait(tubp, &flags) != 0) {
+		TUBUNLOCK(tubp->irq, flags);
+		return;
+	}
+	new = L_ICANON(tty)? L_ECHO(tty)? TF_INPUT: TF_INPUTN:
+		tubp->tty_inattr;
+	if (new != tubp->tty_inattr) {
+		tubp->tty_inattr = new;
+		tubp->cmd = TBC_CLRINPUT;
+		tty3270_build(tubp);
+	}
+
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+static void
+tty3270_flush_buffer(struct tty_struct *tty)
+{
+	tub_t *tubp;
+	bcb_t *ob;
+	int flags;
+
+	if ((tubp = tty->driver_data) == NULL)
+		return;
+
+	if (tubp->mode == TBM_FS && tubp->fs_pid != 0) {
+		kill_proc(tubp->fs_pid, SIGHUP, 1);
+	}
+
+	if ((tubp->flags & TUB_OPEN_STET) == 0) {
+		ob = &tubp->tty_bcb;
+		TUBLOCK(tubp->irq, flags);
+		ob->bc_rd = 0;
+		ob->bc_wr = 0;
+		ob->bc_cnt = 0;
+		TUBUNLOCK(tubp->irq, flags);
+	}
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+static int
+tty3270_read_proc(char *buf, char **start, off_t off, int count,
+		int *eof, void *data)
+{
+	tub_t *tubp;
+	int begin = 0;
+	int i;
+	int rc;
+	int len = 0;
+	char *majstr;
+
+	if (tty3270_proc_what == TW_CONFIG) {
+		/*
+		 * Describe the 3270 configuration in ascii lines.
+		 * Line 1:		0 <fsmajor> 0
+		 * Console line:	<devnum> CONSOLE <minor>
+		 * Other lines:		<devnum> <ttymajor> <minor>
+		 */
+		len += sprintf(buf + len, "0 %d 0\n", fs3270_major);
+		for (i = 1; i <= tubnummins; i++) {
+			tubp = (*tubminors)[i];
+			majstr = tty3270_major_string;
+#ifdef CONFIG_3270_CONSOLE
+			if (tubp == tub3270_con_tubp)
+				majstr = "CONSOLE";
+#endif /* CONFIG_3270_CONSOLE */
+			len += sprintf(buf + len, "%.3x %s %d\n",
+				tubp->devno, majstr, i);
+			if (begin + len > off + count)
+				break;
+			if (begin + len < off) {
+				begin += len;
+				len = 0;
+			}
+		}
+		if (i > tubnummins)
+			*eof = 1;
+		if (off >= begin + len) {
+			rc = 0;
+		} else {
+			*start = buf + off - begin;
+			rc = MIN(count, begin + len - off);
+		}
+		if (*eof && rc == 0)
+			tty3270_proc_what = TW_BOGUS;
+		return rc;
+	}
+
+	len += sprintf(buf, "There are %d devices.  fs major is %d, "
+		"tty major is %d.\n", tubnummins, fs3270_major,
+		tty3270_major);
+	len += sprintf(buf+len, "        index=%d data=%d misc=%d\n",
+		tty3270_proc_index,
+		tty3270_proc_data,
+		tty3270_proc_misc);
+
+	/*
+	 * Display info for the tube with minor nr in index
+	 */
+	len += tty3270_show_tube(tty3270_proc_index, buf+len, count-len);
+
+	*eof = 1;
+	if (off >= begin + len)
+		return 0;
+	*start = buf + off - begin;
+	return MIN(count, begin + len - off);
+}
+
+static int
+tty3270_write_proc(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	char mybuf[GEOM_MAXINPLEN];
+	int mycount;
+	tub_t *tubp;
+	struct tty_struct *tty;
+	kdev_t device;
+	int rc;
+
+	mycount = MIN(count, sizeof mybuf - 1);
+	if (copy_from_user(mybuf, buffer, mycount) != 0)
+		return -EFAULT;
+	mybuf[mycount] = '\0';
+
+	/*
+	 * User-mode settings affect only the current tty ---
+	 */
+	tubp = NULL;
+	tty = current->tty;
+	device = tty? tty->device: 0;
+	if (device) {
+		if (MAJOR(device) == IBM_TTY3270_MAJOR)
+			tubp = (*tubminors)[MINOR(device)];
+#ifdef CONFIG_3270_CONSOLE
+		if (device == S390_CONSOLE_DEV)
+			tubp = tub3270_con_tubp;
+#endif /* CONFIG_3270_CONSOLE */
+	}
+	if (tubp) {
+		if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1)))
+			return rc > 0? count: rc;
+		if ((rc = tty3270_rcl_set(tubp, mybuf, mycount + 1)))
+			return rc > 0? count: rc;
+		if ((rc = tty3270_scl_set(tubp, mybuf, mycount + 1)))
+			return rc > 0? count: rc;
+	}
+
+	/*
+	 * Superuser-mode settings affect the driver overall ---
+	 */
+	if (!suser()) {
+		return -EPERM;
+	} else if (strncmp(mybuf, "index=", 6) == 0) {
+		tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0);
+		return count;
+	} else if (strncmp(mybuf, "data=", 5) == 0) {
+		tty3270_proc_data = simple_strtoul(mybuf + 5, 0, 0);
+		return count;
+	} else if (strncmp(mybuf, "misc=", 5) == 0) {
+		tty3270_proc_misc = simple_strtoul(mybuf + 5, 0, 0);
+		return count;
+	} else if (strncmp(mybuf, "what=", 5) == 0) {
+		if (strcmp(mybuf+5, "bogus") == 0)
+			tty3270_proc_what = 0;
+		else if (strncmp(mybuf+5, "config", 6) == 0)
+			tty3270_proc_what = TW_CONFIG;
+		return count;
+	} else {
+		return -EINVAL;
+	}
+}
+
+static void
+tty3270_hangup(struct tty_struct *tty)
+{
+	tub_t *tubp;
+	extern void fs3270_release(tub_t *);
+
+	if ((tubp = tty->driver_data) == NULL)
+		return;
+	tty3270_rcl_purge(tubp);
+	tty3270_aid_reinit(tubp);
+	fs3270_release(tubp);
+}
+
+
+/*
+ * tty3270_bh(tubp) -- Perform back-half processing
+ */
+static void
+tty3270_bh(void *data)
+{
+	int flags;
+	tub_t *tubp;
+	struct tty_struct *tty;
+
+	tubp = data;
+	TUBLOCK(tubp->irq, flags);
+	tubp->flags &= ~TUB_BHPENDING;
+	tty = tubp->tty;
+
+	if (tubp->flags & TUB_UNSOL_DE) {
+		tubp->flags &= ~TUB_UNSOL_DE;
+		if (tty != NULL) {
+			tty_hangup(tty);
+			wake_up_interruptible(&tubp->waitq);
+			goto do_unlock;
+		}
+	}
+
+	if (tubp->flags & TUB_IACTIVE) {        /* If read ended, */
+		tty3270_do_input(tubp);
+		tubp->flags &= ~TUB_IACTIVE;
+	}
+
+	if ((tubp->flags & TUB_WORKING) == 0) {
+		if (tubp->flags & TUB_ATTN) {
+			tty3270_start_input(tubp);
+			tubp->flags &= ~TUB_ATTN;
+		} else if (tty3270_try_logging(tubp) == 0) {
+			wake_up_interruptible(&tubp->waitq);
+		}
+	}
+
+	if (tty != NULL) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup != NULL)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+do_unlock:
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+/*
+ * tty3270_sched_bh(tubp) -- Schedule the back half
+ * Irq lock must be held on entry and remains held on exit.
+ */
+void
+tty3270_sched_bh(tub_t *tubp)
+{
+	if (tubp->flags & TUB_BHPENDING)
+		return;
+	tubp->flags |= TUB_BHPENDING;
+	tubp->tqueue.routine = tty3270_bh;
+	tubp->tqueue.data = tubp;
+	queue_task(&tubp->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * tty3270_io() -- Perform line-mode reads and writes here
+ */
+int 
+tty3270_io(tub_t *tubp)
+{
+	int rc;
+	ccw1_t *ccwp;
+
+	tubp->flags |= TUB_WORKING;
+	tubp->dstat = 0;
+	ccwp = &tubp->ttyccw;
+
+	rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0);
+	return rc;
+}
+
+/*
+ * tty3270_wait(tubp) -- Wait until TUB_WORKING is off
+ * On entry the lock must not be held; on exit it is held.
+ */
+static int
+tty3270_wait(tub_t *tubp, int *flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	TUBLOCK(tubp->irq, *flags);
+	add_wait_queue(&tubp->waitq, &wait);
+	while (!signal_pending(current) &&
+	    (tubp->flags & TUB_WORKING) != 0) {
+		current->state = TASK_INTERRUPTIBLE;
+		TUBUNLOCK(tubp->irq, *flags);
+		schedule();
+		current->state = TASK_RUNNING;
+		TUBLOCK(tubp->irq, *flags);
+	}
+	remove_wait_queue(&tubp->waitq, &wait);
+	return signal_pending(current)? -ERESTARTSYS: 0;
+}
+
+void
+tty3270_int(tub_t *tubp, devstat_t *dsp)
+{
+#define	DEV_UE_BUSY \
+	(DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
+#define DEV_NOT_WORKING \
+	(DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK)
+
+	tubp->dstat = dsp->dstat;
+
+	/* Handle CE-DE-UE and subsequent UDE */
+	if (dsp->dstat == DEV_UE_BUSY) {
+		tubp->flags |= TUB_UE_BUSY;
+		return;
+	} else if (tubp->flags & TUB_UE_BUSY) {
+		tubp->flags &= ~TUB_UE_BUSY;
+		if (dsp->dstat == DEV_STAT_DEV_END &&
+		    (tubp->flags & TUB_WORKING) != 0) {
+			tty3270_io(tubp);
+			return;
+		}
+	}
+
+	/* Handle ATTN */
+	if (dsp->dstat & DEV_STAT_ATTENTION)
+		tubp->flags |= TUB_ATTN;
+
+	if (dsp->dstat & DEV_STAT_CHN_END) {
+		tubp->cswl = dsp->rescnt;
+		if ((dsp->dstat & DEV_STAT_DEV_END) == 0)
+			tubp->flags |= TUB_EXPECT_DE;
+		else
+			tubp->flags &= ~TUB_EXPECT_DE;
+	} else if (dsp->dstat & DEV_STAT_DEV_END) {
+		if ((tubp->flags & TUB_EXPECT_DE) == 0)
+			tubp->flags |= TUB_UNSOL_DE;
+		tubp->flags &= ~TUB_EXPECT_DE;
+	}
+	if (dsp->dstat & DEV_NOT_WORKING)
+		tubp->flags &= ~TUB_WORKING;
+	if (dsp->dstat & DEV_STAT_UNIT_CHECK)
+		tubp->sense = dsp->ii.sense;
+	if ((tubp->flags & TUB_WORKING) == 0)
+		tty3270_sched_bh(tubp);
+}
+
+/*
+ * tty3270_refresh(), called by fs3270_close() when tubp->fsopen == 0.
+ * On entry, lock is held.
+ */
+void
+tty3270_refresh(tub_t *tubp)
+{
+	if (tubp->lnopen) {
+		tubp->mode = TBM_LN;
+		tubp->intv = tty3270_int;
+		tty3270_scl_resettimer(tubp);
+		tubp->cmd = TBC_UPDATE;
+		tty3270_build(tubp);
+	}
+}
+
+int
+tty3270_try_logging(tub_t *tubp)
+{
+	if (tubp->flags & TUB_WORKING)
+		return 0;
+	if (tubp->mode == TBM_FS)
+		return 0;
+	if (tubp->stat == TBS_HOLD)
+		return 0;
+	if (tubp->stat == TBS_MORE)
+		return 0;
+#ifdef CONFIG_3270_CONSOLE
+	if (tub3270_con_tubp == tubp)
+		tub3270_con_copy(tubp);
+#endif /* CONFIG_3270_CONSOLE */
+	if (tubp->tty_bcb.bc_cnt == 0)
+		return 0;
+	if (tubp->intv != tty3270_int)
+		return 0;
+	tubp->cmd = TBC_UPDLOG;
+	return tty3270_build(tubp);
+}
+
+/* tty3270 utility functions */
+
+static void
+tty3270_start_input(tub_t *tubp)
+{
+	tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input);
+	tubp->ttyccw.cmd_code = TC_READMOD;
+	tubp->ttyccw.count = GEOM_INPLEN;
+	tubp->ttyccw.flags = CCW_FLAG_SLI;
+	tty3270_io(tubp);
+	tubp->flags |= TUB_IACTIVE;
+}
+
+static void
+tty3270_do_input(tub_t *tubp)
+{
+	int count;
+	char *in;
+	int aidflags;
+	char *aidstring;
+
+	count = GEOM_INPLEN - tubp->cswl;
+	in = tubp->tty_input;
+	tty3270_aid_get(tubp, in[0], &aidflags, &aidstring);
+
+	if (aidflags & TA_CLEARKEY) {
+		tubp->stat = TBS_RUNNING;
+		tty3270_scl_resettimer(tubp);
+		tubp->cmd = TBC_UPDATE;
+	} else if (aidflags & TA_CLEARLOG) {
+		tubp->stat = TBS_RUNNING;
+		tty3270_scl_resettimer(tubp);
+		tubp->cmd = TBC_CLRUPDLOG;
+	} else if (aidflags & TA_DOENTER) {
+		if (count <= 6) {
+			switch(tubp->stat) {
+			case TBS_MORE:
+				tubp->stat = TBS_HOLD;
+				tty3270_scl_resettimer(tubp);
+				break;
+			case TBS_HOLD:
+				tubp->stat = TBS_MORE;
+				tty3270_scl_settimer(tubp);
+				break;
+			case TBS_RUNNING:
+                                tty3270_do_enter(tubp, in + 6, 0);
+				break;
+			}
+			tubp->cmd = TBC_UPDSTAT;
+			goto do_build;
+		}
+		in += 6;
+		count -= 6;
+		TUB_EBCASC(in, count);
+		tubp->cmd = TBC_CLRINPUT;
+		tty3270_do_enter(tubp, in, count);
+	} else if ((aidflags & TA_DOSTRING) != 0 && aidstring != NULL) {
+		tubp->cmd = TBC_KRUPDLOG;
+		tty3270_do_enter(tubp, aidstring, strlen(aidstring));
+	} else if ((aidflags & TA_DOSTRINGD) != 0 && aidstring != NULL) {
+		tty3270_do_showi(tubp, aidstring, strlen(aidstring));
+		tubp->cmd = TBC_UPDINPUT;
+	} else {
+		if (in[0] != 0x60)
+			tubp->flags |= TUB_ALARM;
+		tubp->cmd = TBC_KRUPDLOG;
+	}
+do_build:
+	tty3270_build(tubp);
+}
+
+static void
+tty3270_do_enter(tub_t *tubp, char *cp, int count)
+{
+	struct tty_struct *tty;
+	int func = -1;
+
+	if ((tty = tubp->tty) == NULL)
+		return;
+	if (count < 0)
+		return;
+	if (count == 2 && (cp[0] == '^' || cp[0] == '\252')) {
+		switch(cp[1]) {
+		case 'c':  case 'C':
+			func = INTR_CHAR(tty);
+			break;
+		case 'd':  case 'D':
+			func = EOF_CHAR(tty);
+			break;
+		case 'z':  case 'Z':
+			func = SUSP_CHAR(tty);
+			break;
+		}
+	} else if (count == 2 && cp[0] == 0x1b) {        /* if ESC */
+		int inc = 0;
+		char buf[GEOM_INPLEN + 1];
+		int len;
+
+		switch(cp[1]) {
+		case 'k':  case 'K':
+			inc = -1;
+			break;
+		case 'j':  case 'J':
+			inc = 1;
+			break;
+		}
+		if (inc == 0)
+			goto not_rcl;
+		len = tty3270_rcl_get(tubp, buf, sizeof buf, inc);
+		if (len == 0) {
+			tubp->flags |= TUB_ALARM;
+			return;
+		}
+		tty3270_do_showi(tubp, buf, len);
+		tubp->cmd = TBC_UPDINPUT;
+		return;
+	}
+not_rcl:
+	if (func != -1) {
+		*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+		*tty->flip.char_buf_ptr++ = func;
+		tty->flip.count++;
+	} else {
+		tty3270_rcl_put(tubp, cp, count);
+		memcpy(tty->flip.char_buf_ptr, cp, count);
+		/* Add newline unless line ends with "^n" */
+		if (count < 2 || cp[count - 1] != 'n' ||
+		    (cp[count - 2] != '^' && cp[count - 2] != '\252')) {
+			tty->flip.char_buf_ptr[count] = '\n';
+			count++;
+		} else {
+			count -= 2;     /* Lop trailing "^n" from text */
+		}
+		memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
+		tty->flip.char_buf_ptr += count;
+		tty->flip.flag_buf_ptr += count;
+		tty->flip.count += count;
+	}
+	tty_flip_buffer_push(tty);
+}
+
+static void
+tty3270_do_showi(tub_t *tubp, char *cp, int cl)
+{
+	if (cl > GEOM_INPLEN)
+		cl = GEOM_INPLEN;
+	memset(tubp->tty_input, 0, GEOM_INPLEN);
+	memcpy(tubp->tty_input, cp, cl);
+	TUB_ASCEBC(tubp->tty_input, cl);
+}
+
+
+
+/* Debugging routine */
+static int
+tty3270_show_tube(int minor, char *buf, int count)
+{
+	tub_t *tubp;
+	struct tty_struct *tty;
+	struct termios *mp;
+	int len;
+
+/*012345678901234567890123456789012345678901234567890123456789       */
+/*Info for tub_t[dd] at xxxxxxxx:                                    */
+/*    geom:  rows=dd cols=dd model=d                                 */
+/*    lnopen=dd     fsopen=dd   waitq=xxxxxxxx                       */
+/*    dstat=xx      mode=dd     stat=dd     flags=xxxx               */
+/*    oucount=dddd  ourd=ddddd  ouwr=ddddd  nextlogx=ddddd           */
+/*    tty=xxxxxxxx                                                   */
+/*    write_wait=xxxxxxxx read_wait=xxxxxxxx                         */
+/*    iflag=xxxxxxxx oflag=xxxxxxxx cflag=xxxxxxxx lflag=xxxxxxxx    */
+
+	if (minor < 0 || minor > tubnummins ||
+	    (tubp = (*tubminors)[minor]) == NULL)
+		return sprintf(buf, "No tube at index=%d\n", minor);
+
+	tty = tubp->tty;
+	len = 0;
+
+	len += sprintf(buf+len,
+"Info for tub_t[%d] at %.8x:\n",
+	minor, (int)tubp);
+
+	len += sprintf(buf+len, "inattr is at %.8x\n",
+		(int)&tubp->tty_inattr);
+
+
+	len += sprintf(buf+len,
+"    geom:  rows=%.2d cols=%.2d model=%.1d\n",
+	tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
+
+	len += sprintf(buf+len,
+"    lnopen=%-2d     fsopen=%-2d   waitq=%.8x\n",
+	tubp->lnopen, tubp->fsopen, (int)&tubp->waitq);
+
+	len += sprintf(buf+len,
+"    dstat=%.2x      mode=%-2d     stat=%-2d     flags=%-4x\n",
+	tubp->dstat, tubp->mode, tubp->stat, tubp->flags);
+
+#ifdef RBH_FIXTHIS
+	len += sprintf(buf+len,
+"    oucount=%-4d  ourd=%-5d  ouwr=%-5d  nextlogx=%-5d\n",
+	tubp->tty_oucount, tubp->tty_ourd, tubp->tty_ouwr,
+	tubp->tty_nextlogx);
+#endif
+
+	len += sprintf(buf+len,
+"    tty=%.8x\n",
+	(int)tubp->tty);
+
+	if (tty) len += sprintf(buf+len,
+"    write_wait=%.8x read_wait=%.8x\n",
+	(int)&tty->write_wait, (int)&tty->read_wait);
+
+	if (tty && ((mp = tty->termios))) len += sprintf(buf+len,
+"    iflag=%.8x oflag=%.8x cflag=%.8x lflag=%.8x\n",
+	mp->c_iflag, mp->c_oflag, mp->c_cflag, mp->c_lflag);
+
+
+	return len;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttyaid.c linux/drivers/s390/char/tubttyaid.c
--- v2.4.3/linux/drivers/s390/char/tubttyaid.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubttyaid.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,205 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
+ *
+ *  tubttyaid.c -- Linemode Attention-ID functionality
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include "tubio.h"
+
+#define PA1_STR "^C"
+#define PF3_STR "^D"
+#define PF9_STR "\033j"
+#define PF10_STR "\033k"
+#define PF11_STR "\033j"
+/* other AID-key default strings */
+
+aid_t aidtab[64] = {
+/* 00         */	{ 0, 0 },
+/* C1 = PF13  */	{ TA_DOSTRING, 0 },
+/* C2 = PF14  */	{ TA_DOSTRING, 0 },
+/* C3 = PF15  */	{ TA_DOSTRING, 0 },
+/* C4 = PF16  */	{ TA_DOSTRING, 0 },
+/* C5 = PF17  */	{ TA_DOSTRING, 0 },
+/* C6 = PF18  */	{ TA_DOSTRING, 0 },
+/* C7 = PF19  */	{ TA_DOSTRING, 0 },
+/* C8 = PF20  */	{ TA_DOSTRING, 0 },
+/* C9 = PF21  */	{ TA_DOSTRING, 0 },
+/* 4A = PF22  */	{ TA_DOSTRING, 0 },
+/* 4B = PF23  */	{ TA_DOSTRING, 0 },
+/* 4C = PF24  */	{ TA_DOSTRING, 0 },
+/* 0D         */	{ 0, 0 },
+/* 0E         */	{ 0, 0 },
+/* 0F         */	{ 0, 0 },
+/* 10         */	{ 0, 0 },
+/* 11         */	{ 0, 0 },
+/* 12         */	{ 0, 0 },
+/* 13         */	{ 0, 0 },
+/* 14         */	{ 0, 0 },
+/* 15         */	{ 0, 0 },
+/* 16         */	{ 0, 0 },
+/* 17         */	{ 0, 0 },
+/* 18         */	{ 0, 0 },
+/* 19         */	{ 0, 0 },
+/* 1A         */	{ 0, 0 },
+/* 1B         */	{ 0, 0 },
+/* 1C         */	{ 0, 0 },
+/* 1D         */	{ 0, 0 },
+/* 1E         */	{ 0, 0 },
+/* 1F         */	{ 0, 0 },
+/* 60 = NoAID */	{ 0, 0 },
+/* 21         */	{ 0, 0 },
+/* 22         */	{ 0, 0 },
+/* 23         */	{ 0, 0 },
+/* 24         */	{ 0, 0 },
+/* 25         */	{ 0, 0 },
+/* E6 = OpRdr */	{ 0, 0 },
+/* E7 = MSRdr */	{ 0, 0 },
+/* E8 = NoAID */	{ 0, 0 },
+/* 29         */	{ 0, 0 },
+/* 2A         */	{ 0, 0 },
+/* 6B =  PA3  */        { TA_SHORTREAD, 0 },
+/* 6C =  PA1  */        { TA_SHORTREAD | TA_DOSTRING, PA1_STR },
+/* 6D = CLEAR */        { TA_SHORTREAD | TA_CLEARKEY, 0 },
+/* 6E =  PA2  */        { TA_SHORTREAD | TA_CLEARLOG, 0 },
+/* 2F         */	{ 0, 0 },
+/* F0 = TstRq */        { 0, 0 },
+/* F1 =  PF1  */	{ TA_DOSTRING, 0 },
+/* F2 =  PF2  */	{ TA_DOSTRING, 0 },
+/* F3 =  PF3  */        { TA_DOSTRING, PF3_STR },
+/* F4 =  PF4  */	{ TA_DOSTRING, 0 },
+/* F5 =  PF5  */	{ TA_DOSTRING, 0 },
+/* F6 =  PF6  */	{ TA_DOSTRING, 0 },
+/* F7 =  PF7  */	{ TA_DOSTRING, 0 },
+/* F8 =  PF8  */	{ TA_DOSTRING, 0 },
+/* F9 =  PF9  */        { TA_DOSTRING, PF9_STR },
+/* 7A = PF10  */        { TA_DOSTRING, PF10_STR },
+/* 7B = PF11  */        { TA_DOSTRING, PF11_STR },
+/* 7C = PF12  */	{ TA_DOSTRING, 0 },
+/* 7D = ENTER */        { TA_DOENTER, 0 },
+/* 7E = Pen   */        { 0, 0 },
+/* 3F         */	{ 0, 0 },
+};
+
+int
+tty3270_aid_init(tub_t *tubp)
+{
+	memcpy(tubp->tty_aid, aidtab, sizeof aidtab);
+	tubp->tty_aidinit = 1;
+	return 0;
+}
+
+void
+tty3270_aid_fini(tub_t *tubp)
+{
+	int i;
+	char *sp;
+
+	if (tubp->tty_aidinit == 0)
+		return;
+	for (i = 0; i < 64; i++) {
+		if ((sp = tubp->tty_aid[i].string) == NULL)
+			continue;
+		if (sp == aidtab[i].string)
+			continue;
+		kfree(sp);
+	}
+	tubp->tty_aidinit = 0;
+}
+
+void
+tty3270_aid_reinit(tub_t *tubp)
+{
+	tty3270_aid_fini(tubp);
+	tty3270_aid_init(tubp);
+}
+
+int
+tty3270_aid_get(tub_t *tubp, int aid, int *aidflags, char **aidstring)
+{
+	aid_t *ap;
+
+	ap = AIDENTRY(aid, tubp);
+	*aidflags = ap->aid;
+	*aidstring = ap->string;
+	return 0;
+}
+
+/*
+ * tty3270_aid_set() -- write_proc extension
+ * Parse written string as an AID name.  Return 0 if it's not.
+ * Otherwise absorb the string and return count or -error.
+ */
+int
+tty3270_aid_set(tub_t *tubp, char *buf, int count)
+{
+	char name[8];
+	char *sp;
+	int aidn, aidx;
+	aid_t *ap;
+	int len;
+	char *pfp;
+
+	if (tubp->tty_aidinit == 0)
+		return 0;
+	if (count < 3)          /* If AID-key name too short */
+		return 0;
+	name[0] = buf[0] < 0x60? buf[0]: (buf[0] & 0x5f);
+	name[1] = buf[1] < 0x60? buf[1]: (buf[1] & 0x5f);
+	if (name[0] == 'P' && name[1] == 'F') {
+		aidn = simple_strtoul(buf+2, &sp, 10);
+		if (aidn < 1 || aidn > 24)
+			return 0;
+		aidx = aidn > 12? aidn - 12: aidn + 0x30;
+		ap = &tubp->tty_aid[aidx];
+	} else if (name[0] == 'P' && name[1] == 'A') {
+		aidn = simple_strtoul(buf+2, &sp, 10);
+		if (aidn < 1 || aidn > 3)
+			return 0;
+		switch(aidn) {
+		case 1:  aidx = 0x2c; break;
+		case 2:  aidx = 0x2e; break;
+		case 3:  aidx = 0x2b; break;
+		default:  aidx = 0; break;
+		}
+		ap = &tubp->tty_aid[aidx];
+	} else {
+		return 0;
+	}
+
+	if (*sp == '\0') {
+		tubp->tty_showaidx = ap - tubp->tty_aid;
+		return count;
+	} else if (*sp == '=') {
+		len = strlen(++sp);
+		if (len == 0) {
+			if (ap->string != NULL &&
+			    ap->string != aidtab[aidx].string)
+				kfree(ap->string);
+			ap->string = aidtab[aidx].string;
+			ap->aid = aidtab[aidx].aid;
+			return count;
+		}
+		if ((pfp = kmalloc(len + 1, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		if (ap->string != NULL &&
+		    ap->string != aidtab[aidx].string)
+			kfree(ap->string);
+		if (sp[len - 1] == '\n') {
+			ap->aid = TA_DOSTRING;
+			sp[len - 1] = '\0';
+			len--;
+		} else {
+			ap->aid = TA_DOSTRINGD;
+		}
+		memcpy(pfp, sp, len + 1);
+		ap->string = pfp;
+		return count;
+	} else {
+		return -EINVAL;
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttybld.c linux/drivers/s390/char/tubttybld.c
--- v2.4.3/linux/drivers/s390/char/tubttybld.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubttybld.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,448 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
+ *
+ *  tubttybld.c -- Linemode tty driver screen-building functions
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+
+#include "tubio.h"
+
+extern int tty3270_io(tub_t *);
+static void tty3270_set_status_area(tub_t *, char **);
+static int tty3270_next_char(tub_t *);
+static void tty3270_update_log_area(tub_t *, char **);
+static void tty3270_update_log_area_esc(tub_t *, char **);
+static void tty3270_clear_log_area(tub_t *, char **);
+static void tty3270_tub_bufadr(tub_t *, int, char **);
+
+/*
+ * tty3270_clear_log_area(tub_t *tubp, char **cpp)
+ */
+static void
+tty3270_clear_log_area(tub_t *tubp, char **cpp)
+{
+	*(*cpp)++ = TO_SBA;
+	TUB_BUFADR(GEOM_LOG, cpp);
+	*(*cpp)++ = TO_SF;
+	*(*cpp)++ = TF_LOG;
+	*(*cpp)++ = TO_RA;
+	TUB_BUFADR(GEOM_INPUT, cpp);
+	*(*cpp)++ = '\0';
+	tubp->tty_oucol = tubp->tty_nextlogx = 0;
+}
+
+static void
+tty3270_update_log_area(tub_t *tubp, char **cpp)
+{
+	int lastx = GEOM_INPUT;
+	int c;
+	int next, fill, i;
+	int sba_needed = 1;
+	char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
+
+	/* Place characters */
+	while (tubp->tty_bcb.bc_cnt != 0) {
+		if (tubp->tty_nextlogx >= lastx) {
+			if (sba_needed == 0 || tubp->stat == TBS_RUNNING) {
+				tubp->stat = TBS_MORE;
+				tty3270_set_status_area(tubp, cpp);
+				tty3270_scl_settimer(tubp);
+			}
+			break;
+		}
+
+		/* Check for room for another char + possible ESCs */
+		if (&(*cpp)[tubp->tty_escx + 1] >= overrun)
+			break;
+
+		/* Fetch a character */
+		if ((c = tty3270_next_char(tubp)) == -1)
+			break;
+
+		/* Add a Set-Buffer-Address Order if we haven't */
+		if (sba_needed) {
+			sba_needed = 0;
+			*(*cpp)++ = TO_SBA;
+			TUB_BUFADR(tubp->tty_nextlogx, cpp);
+		}
+
+		switch(c) {
+		default:
+			if (c < ' ')    /* Blank it if we don't know it */
+				c = ' ';
+			for (i = 0; i < tubp->tty_escx; i++)
+				*(*cpp)++ = tubp->tty_esca[i];
+			tubp->tty_escx = 0;
+			*(*cpp)++ = tub_ascebc[(int)c];
+			tubp->tty_nextlogx++;
+			tubp->tty_oucol++;
+			break;
+		case 0x1b:              /* ESC */
+			tty3270_update_log_area_esc(tubp, cpp);
+			break;
+		case '\r':
+			break;          /* completely ignore 0x0d = CR. */
+		case '\n':
+			if (tubp->tty_oucol == GEOM_COLS) {
+				tubp->tty_oucol = 0;
+				break;
+			}
+			next = (tubp->tty_nextlogx + GEOM_COLS) /
+				GEOM_COLS * GEOM_COLS;
+			next = MIN(next, lastx);
+			fill = next - tubp->tty_nextlogx;
+			if (fill < 5) {
+				for (i = 0; i < fill; i++)
+					*(*cpp)++ = tub_ascebc[' '];
+			} else {
+				*(*cpp)++ = TO_RA;
+				TUB_BUFADR(next, cpp);
+				*(*cpp)++ = tub_ascebc[' '];
+			}
+			tubp->tty_nextlogx = next;
+			tubp->tty_oucol = 0;
+			break;
+		case '\t':
+			fill = (tubp->tty_nextlogx % GEOM_COLS) % 8;
+			for (; fill < 8; fill++) {
+				if (tubp->tty_nextlogx >= lastx)
+					break;
+				*(*cpp)++ = tub_ascebc[' '];
+				tubp->tty_nextlogx++;
+				tubp->tty_oucol++;
+			}
+			break;
+		case '\a':
+			tubp->flags |= TUB_ALARM;
+			break;
+		case '\f':
+			tty3270_clear_log_area(tubp, cpp);
+			break;
+		}
+	}
+}
+
+#define NUMQUANT 8
+static void
+tty3270_update_log_area_esc(tub_t *tubp, char **cpp)
+{
+	int lastx = GEOM_INPUT;
+	int c;
+	int i;
+	int start, next, fill;
+	int quant[NUMQUANT];
+
+	if ((c = tty3270_next_char(tubp)) != '[') {
+		return;
+	}
+
+	/*
+	 * Parse potentially empty string "nn;nn;nn..."
+	 */
+	i = -1;
+	c = ';';
+	do {
+		if (c == ';') {
+			if (++i == NUMQUANT)
+				break;
+			quant[i] = 0;
+		} else if (c < '0' || c > '9') {
+			break;
+		} else {
+			quant[i] = quant[i] * 10 + c - '0';
+		}
+	} while ((c = tty3270_next_char(tubp)) != -1);
+	if (c == -1) {
+		return;
+	}
+	if (i >= NUMQUANT) {
+		return;
+	}
+	switch(c) {
+	case -1:
+		return;
+	case 'm':		/* Set Attribute */
+		for (next = 0; next <= i; next++) {
+			int type = -1, value = 0;
+
+			if (tubp->tty_escx + 3 > MAX_TTY_ESCA)
+				break;
+			switch(quant[next]) {
+			case 0:		/* Reset */
+				tubp->tty_esca[tubp->tty_escx++] = TO_SA;
+				tubp->tty_esca[tubp->tty_escx++] = TAT_RESET;
+				tubp->tty_esca[tubp->tty_escx++] = TAR_RESET;
+				break;
+			case 1:		/* Bright */
+			case 2:		/* Dim */
+			case 4:		/* Underscore */
+			case 5:		/* Blink */
+			case 7:		/* Reverse */
+			case 8:		/* Hidden */
+				break;		/* For now ... */
+			/* Foreground Colors */
+			case 30:	/* Black */
+				type = TAT_COLOR; value = TAC_DEFAULT;
+				break;
+			case 31:	/* Red */
+				type = TAT_COLOR; value = TAC_RED;
+				break;
+			case 32:	/* Green */
+				type = TAT_COLOR; value = TAC_GREEN;
+				break;
+			case 33:	/* Yellow */
+				type = TAT_COLOR; value = TAC_YELLOW;
+				break;
+			case 34:	/* Blue */
+				type = TAT_COLOR; value = TAC_BLUE;
+				break;
+			case 35:	/* Magenta */
+				type = TAT_COLOR; value = TAC_PINK;
+				break;
+			case 36:	/* Cyan */
+				type = TAT_COLOR; value = TAC_TURQ;
+				break;
+			case 37:	/* White */
+				type = TAT_COLOR; value = TAC_WHITE;
+				break;
+			case 39:	/* Black */
+				type = TAT_COLOR; value = TAC_DEFAULT;
+				break;
+			/* Background Colors */
+			case 40:	/* Black */
+			case 41:	/* Red */
+			case 42:	/* Green */
+			case 43:	/* Yellow */
+			case 44:	/* Blue */
+			case 45:	/* Magenta */
+			case 46:	/* Cyan */
+			case 47:	/* White */
+				break;		/* For now ... */
+			/* Oops */
+			default:
+				break;
+			}
+			if (type != -1) {
+				tubp->tty_esca[tubp->tty_escx++] = TO_SA;
+				tubp->tty_esca[tubp->tty_escx++] = type;
+				tubp->tty_esca[tubp->tty_escx++] = value;
+			}
+		}
+		break;
+	case 'H':		/* Cursor Home */
+	case 'f':		/* Force Cursor Position */
+		return;
+	case 'A':		/* Cursor Up */
+		return;
+	case 'B':		/* Cursor Down */
+		return;
+	case 'C':		/* Cursor Forward */
+		next = tubp->tty_nextlogx % GEOM_COLS;
+		start = tubp->tty_nextlogx - next;
+		next = start + MIN(next + quant[i], GEOM_COLS - 1);
+		next = MIN(next, lastx);
+do_fill:
+		fill = next - tubp->tty_nextlogx;
+		if (fill < 5) {
+			for (i = 0; i < fill; i++)
+				*(*cpp)++ = tub_ascebc[' '];
+		} else {
+			*(*cpp)++ = TO_RA;
+			TUB_BUFADR(next, cpp);
+			*(*cpp)++ = tub_ascebc[' '];
+		}
+		tubp->tty_nextlogx = next;
+		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+		break;
+	case 'D':		/* Cursor Backward */
+		next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS);
+		tubp->tty_nextlogx -= next;
+		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+		*(*cpp)++ = TO_SBA;
+		TUB_BUFADR(tubp->tty_nextlogx, cpp);
+		break;
+	case 'G':
+		start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS;
+		next = MIN(quant[i], GEOM_COLS - 1) + start;
+		next = MIN(next, lastx);
+		goto do_fill;
+	}
+}
+
+
+static int
+tty3270_next_char(tub_t *tubp)
+{
+	int c;
+	bcb_t *ib;
+
+	ib = &tubp->tty_bcb;
+	if (ib->bc_cnt == 0)
+		return -1;
+	c = ib->bc_buf[ib->bc_rd++];
+	if (ib->bc_rd == ib->bc_len)
+		ib->bc_rd = 0;
+	ib->bc_cnt--;
+	return c;
+}
+
+
+static void
+tty3270_clear_input_area(tub_t *tubp, char **cpp)
+{
+	*(*cpp)++ = TO_SBA;
+	TUB_BUFADR(GEOM_INPUT, cpp);
+	*(*cpp)++ = TO_SF;
+	*(*cpp)++ = tubp->tty_inattr;
+	*(*cpp)++ = TO_IC;
+	*(*cpp)++ = TO_RA;
+	TUB_BUFADR(GEOM_STAT, cpp);
+	*(*cpp)++ = '\0';
+}
+
+static void
+tty3270_update_input_area(tub_t *tubp, char **cpp)
+{
+	int len;
+
+	*(*cpp)++ = TO_SBA;
+	TUB_BUFADR(GEOM_INPUT, cpp);
+	*(*cpp)++ = TO_SF;
+	*(*cpp)++ = TF_INMDT;
+	len = strlen(tubp->tty_input);
+	memcpy(*cpp, tubp->tty_input, len);
+	*cpp += len;
+	*(*cpp)++ = TO_IC;
+	len = GEOM_INPLEN - len;
+	if (len > 4) {
+		*(*cpp)++ = TO_RA;
+		TUB_BUFADR(GEOM_STAT, cpp);
+		*(*cpp)++ = '\0';
+	} else {
+		for (; len > 0; len--)
+			*(*cpp)++ = '\0';
+	}
+}
+
+/*
+ * tty3270_set_status_area(tub_t *tubp, char **cpp)
+ */
+static void
+tty3270_set_status_area(tub_t *tubp, char **cpp)
+{
+	char *sp;
+
+	if (tubp->stat == TBS_RUNNING)
+		sp = TS_RUNNING;
+	else if (tubp->stat == TBS_MORE)
+		sp = TS_MORE;
+	else if (tubp->stat == TBS_HOLD)
+		sp = TS_HOLD;
+	else
+		sp = "Linux Whatstat";
+
+	*(*cpp)++ = TO_SBA;
+	TUB_BUFADR(GEOM_STAT, cpp);
+	*(*cpp)++ = TO_SF;
+	*(*cpp)++ = TF_STAT;
+	memcpy(*cpp, sp, sizeof TS_RUNNING);
+	TUB_ASCEBC(*cpp, sizeof TS_RUNNING);
+	*cpp += sizeof TS_RUNNING;
+}
+
+/*
+ * tty3270_build() -- build an output stream
+ */
+int
+tty3270_build(tub_t *tubp)
+{
+	char *cp, *startcp;
+	int chancmd;
+	int writecc = TW_KR;
+	int force = 0;
+
+	if (tubp->mode == TBM_FS)
+		return 0;
+
+	cp = startcp = *tubp->ttyscreen + 1;
+
+	switch(tubp->cmd) {
+	default:
+		printk(KERN_WARNING "tty3270_build unknown command %d\n", tubp->cmd);
+		return 0;
+	case TBC_OPEN:
+		chancmd = TC_EWRITEA;
+		tty3270_clear_input_area(tubp, &cp);
+		tty3270_set_status_area(tubp, &cp);
+		tty3270_clear_log_area(tubp, &cp);
+		break;
+	case TBC_UPDLOG:
+		chancmd = TC_WRITE;
+		writecc = TW_NONE;
+		tty3270_update_log_area(tubp, &cp);
+		break;
+	case TBC_KRUPDLOG:
+		chancmd = TC_WRITE;
+		force = 1;
+		tty3270_update_log_area(tubp, &cp);
+		break;
+	case TBC_CLRUPDLOG:
+		chancmd = TC_WRITE;
+		tty3270_set_status_area(tubp, &cp);
+		tty3270_clear_log_area(tubp, &cp);
+		tty3270_update_log_area(tubp, &cp);
+		break;
+	case TBC_UPDATE:
+		chancmd = TC_EWRITEA;
+		tubp->tty_oucol = tubp->tty_nextlogx = 0;
+		tty3270_clear_input_area(tubp, &cp);
+		tty3270_set_status_area(tubp, &cp);
+		tty3270_update_log_area(tubp, &cp);
+		break;
+	case TBC_UPDSTAT:
+		chancmd = TC_WRITE;
+		tty3270_set_status_area(tubp, &cp);
+		break;
+	case TBC_CLRINPUT:
+		chancmd = TC_WRITE;
+		tty3270_clear_input_area(tubp, &cp);
+		break;
+	case TBC_UPDINPUT:
+		chancmd = TC_WRITE;
+		tty3270_update_input_area(tubp, &cp);
+		break;
+	}
+
+	/* Set Write Control Character and start I/O */
+	if (force == 0 && cp == startcp &&
+	    (tubp->flags & TUB_ALARM) == 0)
+		return 0;
+	if (tubp->flags & TUB_ALARM) {
+		tubp->flags &= ~TUB_ALARM;
+		writecc |= TW_PLUSALARM;
+	}
+	**tubp->ttyscreen = writecc;
+	tubp->ttyccw.cmd_code = chancmd;
+	tubp->ttyccw.flags = CCW_FLAG_SLI;
+	tubp->ttyccw.cda = virt_to_phys(*tubp->ttyscreen);
+	tubp->ttyccw.count = cp - *tubp->ttyscreen;
+	tty3270_io(tubp);
+	return 1;
+}
+
+static void
+tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp)
+{
+	if (tubp->tty_14bitadr) {
+		*(*cpp)++ = (adr >> 8) & 0x3f;
+		*(*cpp)++ = adr & 0xff;
+	} else {
+		*(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f];
+		*(*cpp)++ = tub_ebcgraf[adr & 0x3f];
+	}
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttyrcl.c linux/drivers/s390/char/tubttyrcl.c
--- v2.4.3/linux/drivers/s390/char/tubttyrcl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubttyrcl.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,199 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
+ *
+ *  tubttyrcl.c -- Linemode Command-recall functionality
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include "tubio.h"
+
+int
+tty3270_rcl_init(tub_t *tubp)
+{
+	return tty3270_rcl_resize(tubp, 20);
+}
+
+int
+tty3270_rcl_resize(tub_t *tubp, int newrclk)
+{
+	char *(*newrclb)[];
+
+	if (newrclk > 1000)
+		return -EINVAL;
+	if (newrclk <= 0) {
+		tty3270_rcl_purge(tubp),
+		kfree(tubp->tty_rclbufs);
+		tubp->tty_rclbufs = NULL;
+		return 0;
+	}
+	if ((newrclb = (char *(*)[])kmalloc(
+	    newrclk * sizeof (char *), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(newrclb, 0, newrclk * sizeof (char *));
+	if (tubp->tty_rclbufs != NULL) {
+		int i, j, k;
+		char *data;
+
+		i = tubp->tty_rclp;
+		j = newrclk;
+		k = tubp->tty_rclk;
+		while (j-- && k--) {
+			if ((data = (*tubp->tty_rclbufs)[i]) == NULL)
+				break;
+			(*newrclb)[j] = data;
+			(*tubp->tty_rclbufs)[i] = NULL;
+			if (--i < 0)
+				i = tubp->tty_rclk - 1;
+		}
+		tty3270_rcl_purge(tubp);
+		kfree(tubp->tty_rclbufs);
+	}
+	tubp->tty_rclbufs = newrclb;
+	tubp->tty_rclk = newrclk;
+	tubp->tty_rclp = newrclk - 1;
+	tty3270_rcl_sync(tubp);
+	return 0;
+}
+
+int
+tty3270_rcl_set(tub_t *tubp, char *buf, int count)
+{
+#define RCL_SIZ "recallsize="
+#define L_RCL_SIZ (strlen(RCL_SIZ))
+	int newsize;
+	int len;
+	int rc;
+	char *rcl_siz = RCL_SIZ;
+	int l_rcl_siz = L_RCL_SIZ;
+
+	if (count < l_rcl_siz || strncmp(buf, rcl_siz, l_rcl_siz) != 0)
+		return 0;
+	if ((len = count - l_rcl_siz) == 0)
+		return count;
+	newsize = simple_strtoul(buf + l_rcl_siz, 0, 0);
+	rc = tty3270_rcl_resize(tubp, newsize);
+	return rc < 0? rc: count;
+}
+
+void
+tty3270_rcl_fini(tub_t *tubp)
+{
+	if (tubp->tty_rclbufs != NULL) {
+		tty3270_rcl_purge(tubp);
+		kfree(tubp->tty_rclbufs);
+		tubp->tty_rclbufs = NULL;
+	}
+}
+
+void
+tty3270_rcl_purge(tub_t *tubp)
+{
+	int i;
+	char *buf;
+
+	if (tubp->tty_rclbufs == NULL)
+		return;
+	for (i = 0; i < tubp->tty_rclk; i++) {
+		if ((buf = (*tubp->tty_rclbufs)[i]) == NULL)
+			continue;
+		kfree(buf);
+		(*tubp->tty_rclbufs)[i] = NULL;
+	}
+}
+
+int
+tty3270_rcl_get(tub_t *tubp, char *buf, int len, int inc)
+{
+	int iter;
+	int i;
+	char *data;
+
+	if (tubp->tty_rclbufs == NULL)
+		return 0;
+	if (tubp->tty_rclk <= 0)	/* overcautious */
+		return 0;
+	if (inc != 1 && inc != -1)	/* overcautious */
+		return 0;
+
+	if ((i = tubp->tty_rclb) == -1) {
+		i = tubp->tty_rclp;
+		if (inc == 1)
+			i++;
+	} else {
+		i += inc;
+	}
+	for (iter = tubp->tty_rclk; iter; iter--, i += inc) {
+		if (i < 0)
+			i = tubp->tty_rclk - 1;
+		else if (i >= tubp->tty_rclk)
+			i = 0;
+		if ((*tubp->tty_rclbufs)[i] != NULL)
+			break;
+	}
+	if (iter < 0 || (data = (*tubp->tty_rclbufs)[i]) == NULL)
+		return 0;
+	tubp->tty_rclb = i;
+	if ((len = MIN(len - 1, strlen(data))) <= 0)
+		return 0;
+	memcpy(buf, data, len);
+	buf[len] = '\0';
+	return len;
+}
+
+void
+tty3270_rcl_put(tub_t *tubp, char *data, int len)
+{
+	char *buf, **bufp;
+	int i;
+
+	if (tubp->tty_rclbufs == NULL)
+		return;
+
+	if (tubp->tty_rclk <= 0)        /* overcautious */
+		return;
+
+	/* If input area is invisible, don't log */
+	if (tubp->tty_inattr == TF_INPUTN)
+		return;
+
+	/* If this & most recent cmd text match, don't log */
+	if ((buf = (*tubp->tty_rclbufs)[tubp->tty_rclp]) != NULL &&
+	    strlen(buf) == len && memcmp(buf, data, len) == 0) {
+		tty3270_rcl_sync(tubp);
+		return;
+	}
+
+	/* Don't stack zero-length commands */
+	if (len == 0) {
+		tty3270_rcl_sync(tubp);
+		return;
+	}
+
+	i = tubp->tty_rclp;
+	if (++i == tubp->tty_rclk)
+		i = 0;
+	bufp = &(*tubp->tty_rclbufs)[i];
+	if (*bufp == NULL || strlen(*bufp) < len + 1) {
+		if (*bufp) {
+			kfree(*bufp);
+			*bufp = NULL;
+		}
+		if ((*bufp = kmalloc(len + 1, GFP_ATOMIC)) == NULL)
+			return;
+	}
+	memcpy(*bufp, data, len);
+	(*bufp)[len] = '\0';
+	tubp->tty_rclp = i;
+	tty3270_rcl_sync(tubp);
+}
+
+void
+tty3270_rcl_sync(tub_t *tubp)
+{
+	tubp->tty_rclb = -1;
+}
+
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttyscl.c linux/drivers/s390/char/tubttyscl.c
--- v2.4.3/linux/drivers/s390/char/tubttyscl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubttyscl.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,88 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC
+ *
+ *  tubttyscl.c -- Linemode tty driver scroll-timing functions
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include "tubio.h"
+       void tty3270_scl_settimer(tub_t *);
+       void tty3270_scl_resettimer(tub_t *);
+static void tty3270_scl_timeout(unsigned long);
+
+void
+tty3270_scl_settimer(tub_t *tubp)
+{
+	struct timer_list *tp = &tubp->tty_stimer;
+
+	if (tubp->flags & TUB_SCROLLTIMING)
+		return;
+	if (tubp->tty_scrolltime == 0)
+		return;
+
+	init_timer(tp);
+	tp->expires = jiffies + HZ * tubp->tty_scrolltime;
+	tp->data = (unsigned long)tubp;
+	tp->function = tty3270_scl_timeout;
+	add_timer(tp);
+	tubp->flags |= TUB_SCROLLTIMING;
+}
+
+void
+tty3270_scl_resettimer(tub_t *tubp)
+{
+	struct timer_list *tp = &tubp->tty_stimer;
+
+	if ((tubp->flags & TUB_SCROLLTIMING) == 0)
+		return;
+
+	del_timer(tp);
+	tubp->flags &= ~TUB_SCROLLTIMING;
+}
+
+static void
+tty3270_scl_timeout(unsigned long data)
+{
+	tub_t *tubp = (void *)data;
+	int flags;
+
+	TUBLOCK(tubp->irq, flags);
+	tubp->stat = TBS_RUNNING;
+	tty3270_scl_resettimer(tubp);
+	tubp->cmd = TBC_CLRUPDLOG;
+	tty3270_build(tubp);
+	TUBUNLOCK(tubp->irq, flags);
+}
+
+int
+tty3270_scl_set(tub_t *tubp, char *buf, int count)
+{
+	if (strncmp(buf, "scrolltime=", 11) == 0) {
+		tubp->tty_scrolltime =
+			simple_strtoul(buf + 11, 0, 0);
+		return count;
+	}
+	return 0;
+}
+
+int
+tty3270_scl_init(tub_t *tubp)
+{
+	extern int tubscrollparm;
+
+	tubp->tty_scrolltime = tubscrollparm;
+	if (tubp->tty_scrolltime < 0)
+		tubp->tty_scrolltime = DEFAULT_SCROLLTIME;
+	return 0;
+}
+
+void
+tty3270_scl_fini(tub_t *tubp)
+{
+	if ((tubp->flags & TUB_OPEN_STET) == 0)
+		tty3270_scl_resettimer(tubp);
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttysiz.c linux/drivers/s390/char/tubttysiz.c
--- v2.4.3/linux/drivers/s390/char/tubttysiz.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tubttysiz.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,304 @@
+/*
+ *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
+ *
+ *  tubttysiz.c -- Linemode screen-size determiner
+ *
+ *
+ *
+ *
+ *
+ *  Author:  Richard Hitt
+ */
+#include "tubio.h"
+static int tty3270_size_io(tub_t *tubp);
+static void tty3270_size_int(tub_t *tubp, devstat_t *dsp);
+static int tty3270_size_wait(tub_t *tubp, int *flags, int stat);
+
+/*
+ * Structure representing Usable Area Query Reply Base
+ */
+typedef struct {
+	short l;                /* Length of this structured field */
+	char sfid;              /* 0x81 if Query Reply */
+	char qcode;             /* 0x81 if Usable Area */
+#define QCODE_UA 0x81
+	char flags0;
+#define FLAGS0_ADDR 0x0f
+#define FLAGS0_ADDR_12_14       1       /* 12/14-bit adrs ok */
+#define FLAGS0_ADDR_12_14_16    3       /* 12/14/16-bit adrs ok */
+	char flags1;
+	short w;                /* Width of usable area */
+	short h;                /* Heigth of usavle area */
+	char units;             /* 0x00:in; 0x01:mm */
+	int xr;
+	int yr;
+	char aw;
+	char ah;
+	short buffsz;           /* Character buffer size, bytes */
+	char xmin;
+	char ymin;
+	char xmax;
+	char ymax;
+} __attribute__ ((packed)) uab_t;
+
+/*
+ * Structure representing Alternate Usable Area Self-Defining Parameter
+ */
+typedef struct {
+	char l;                 /* Length of this Self-Defining Parm */
+	char sdpid;             /* 0x02 if Alternate Usable Area */
+#define SDPID_AUA 0x02
+	char res;
+	char auaid;             /* 0x01 is Id for the A U A */
+	short wauai;            /* Width of AUAi */
+	short hauai;            /* Height of AUAi */
+	char auaunits;          /* 0x00:in, 0x01:mm */
+	int auaxr;
+	int auayr;
+	char awauai;
+	char ahauai;
+} __attribute__ ((packed)) aua_t;
+
+/*
+ * Structure representing one followed by the other
+ */
+typedef struct {
+	uab_t uab;
+	aua_t aua;
+} __attribute__ ((packed)) ua_t;
+
+/*
+ * Try to determine screen size using Read Partition (Query)
+ */
+int
+tty3270_size(tub_t *tubp, int *flags)
+{
+	char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
+	int     rc = 0;
+	int     count;
+	unsigned char *cp;
+	ua_t *uap;
+	char miniscreen[256];
+	char (*screen)[];
+	int screenl;
+	int geom_rows, geom_cols, fourteenbitadr;
+	void (*oldint)(struct tub_s *, devstat_t *);
+
+	if (tubp->flags & TUB_SIZED)
+		return 0;
+	fourteenbitadr = 0;
+	geom_rows = tubp->geom_rows;
+	geom_cols = tubp->geom_cols;
+
+	oldint = tubp->intv;
+	tubp->intv = tty3270_size_int;
+
+	if (tubp->cmd == TBC_CONOPEN) {
+		tubp->ttyccw.cmd_code = TC_EWRITEA;
+		cp = miniscreen;
+		*cp++ = TW_KR;
+		/* more? */
+		tubp->ttyccw.flags = CCW_FLAG_SLI;
+		tubp->ttyccw.cda = virt_to_phys(miniscreen);
+		tubp->ttyccw.count = (char *)cp - miniscreen;
+		rc = tty3270_size_io(tubp);
+		rc = tty3270_size_wait(tubp, flags, 0);
+	}
+
+	tubp->ttyccw.cmd_code = TC_WRITESF;
+	tubp->ttyccw.flags = CCW_FLAG_SLI;
+	tubp->ttyccw.cda = virt_to_phys(wbuf);
+	tubp->ttyccw.count = sizeof wbuf;
+
+try_again:
+	rc = tty3270_size_io(tubp);
+	if (rc)
+		printk("tty3270_size_io returned %d\n", rc);
+
+	rc = tty3270_size_wait(tubp, flags, 0);
+	if (rc != 0) {
+		goto do_return;
+	}
+
+	/*
+	 * Unit-Check Processing:
+	 * Expect Command Reject or Intervention Required.
+	 * For Command Reject assume old hdwe/software and
+	 * set a default size of 80x24.
+	 * For Intervention Required, wait for signal pending
+	 * or Unsolicited Device End; if the latter, retry.
+	 */
+	if (tubp->dstat & DEV_STAT_UNIT_CHECK) {
+		if (tubp->sense.data[0] & SNS0_CMD_REJECT) {
+			goto use_diag210; /* perhaps it's tn3270 */
+		} else if (tubp->sense.data[0] & SNS0_INTERVENTION_REQ) {
+			if ((rc = tty3270_size_wait(tubp, flags,
+			    DEV_STAT_DEV_END)))
+				goto do_return;
+			goto try_again;
+		} else {
+			printk("tty3270_size(): unkn sense %.2x\n",
+				tubp->sense.data[0]);
+			goto do_return;
+		}
+	}
+	if ((rc = tty3270_size_wait(tubp, flags, DEV_STAT_ATTENTION)))
+		goto do_return;
+
+	/* Set up a read ccw and issue it */
+	tubp->ttyccw.cmd_code = TC_READMOD;
+	tubp->ttyccw.flags = CCW_FLAG_SLI;
+	tubp->ttyccw.cda = virt_to_phys(miniscreen);
+	tubp->ttyccw.count = sizeof miniscreen;
+	tty3270_size_io(tubp);
+	rc = tty3270_size_wait(tubp, flags, 0);
+	if (rc != 0)
+		goto do_return;
+
+	count = sizeof miniscreen - tubp->cswl;
+	cp = miniscreen;
+	if (*cp++ != 0x88)
+		goto do_return;
+	uap = (void *)cp;
+	if (uap->uab.qcode != QCODE_UA)
+		goto do_return;
+	geom_rows = uap->uab.h;
+	geom_cols = uap->uab.w;
+	if ((uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14 ||
+	    (uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14_16)
+		fourteenbitadr = 1;
+	if (uap->uab.l <= sizeof uap->uab)
+		goto do_return;
+	if (uap->aua.sdpid != SDPID_AUA) {
+		printk("AUA sdpid was 0x%.2x, expecting 0x%.2x\n",
+			uap->aua.sdpid, SDPID_AUA);
+		goto do_return;
+	}
+	geom_rows = uap->aua.hauai;
+	geom_cols = uap->aua.wauai;
+	goto do_return;
+
+use_diag210:
+	if (MACHINE_IS_VM) {
+		diag210_t d210;
+
+		d210.vrdcdvno = tubp->devno;
+		d210.vrdclen = sizeof d210;
+		rc = diag210(&d210);
+		if (rc) {
+			printk("tty3270_size: diag210 for 0x%.4x "
+				"returned %d\n", tubp->devno, rc);
+			goto do_return;
+		}
+		switch(d210.vrdccrmd) {
+		case 2:
+			geom_rows = 24;
+			geom_cols = 80;
+			goto do_return;
+		case 3:
+			geom_rows = 32;
+			geom_cols = 80;
+			goto do_return;
+		case 4:
+			geom_rows = 43;
+			geom_cols = 80;
+			goto do_return;
+		case 5:
+			geom_rows = 27;
+			geom_cols = 132;
+			goto do_return;
+		default:
+			printk("vrdccrmd is 0x%.8x\n", d210.vrdccrmd);
+		}
+	}
+
+do_return:
+	if (geom_rows == 0) {
+		geom_rows = _GEOM_ROWS;
+		geom_cols = _GEOM_COLS;
+	}
+	tubp->tubiocb.pf_cnt = 24;
+	tubp->tubiocb.re_cnt = 20;
+	tubp->tubiocb.map = 0;
+
+	screenl = geom_rows * geom_cols + 100;
+	screen = (char (*)[])kmalloc(screenl, GFP_KERNEL);
+	if (screen == NULL) {
+		printk("ttyscreen size %d unavailable\n", screenl);
+	} else {
+		if (tubp->ttyscreen)
+			kfree(tubp->ttyscreen);
+		tubp->tubiocb.line_cnt = tubp->geom_rows = geom_rows;
+		tubp->tubiocb.col_cnt = tubp->geom_cols = geom_cols;
+		tubp->tty_14bitadr = fourteenbitadr;
+		tubp->ttyscreen = screen;
+		tubp->ttyscreenl = screenl;
+		if (geom_rows == 24 && geom_cols == 80)
+			tubp->tubiocb.model = 2;
+		else if (geom_rows == 32 && geom_cols == 80)
+			tubp->tubiocb.model = 3;
+		else if (geom_rows == 43 && geom_cols == 80)
+			tubp->tubiocb.model = 4;
+		else if (geom_rows == 27 && geom_cols == 132)
+			tubp->tubiocb.model = 5;
+		else
+			tubp->tubiocb.model = 0;
+		tubp->flags |= TUB_SIZED;
+	}
+	if (rc == 0 && tubp->ttyscreen == NULL)
+		rc = -ENOMEM;
+	tubp->intv = oldint;
+	return rc;
+}
+
+static int
+tty3270_size_io(tub_t *tubp)
+{
+	tubp->flags |= TUB_WORKING;
+	tubp->dstat = 0;
+
+	return do_IO(tubp->irq, &tubp->ttyccw, tubp->irq, 0, 0);
+}
+
+static void
+tty3270_size_int(tub_t *tubp, devstat_t *dsp)
+{
+#define DEV_NOT_WORKING \
+  (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK)
+
+	tubp->dstat = dsp->dstat;
+	if (dsp->dstat & DEV_STAT_CHN_END)
+		tubp->cswl = dsp->rescnt;
+	if (dsp->dstat & DEV_NOT_WORKING)
+		tubp->flags &= ~TUB_WORKING;
+	if (dsp->dstat & DEV_STAT_UNIT_CHECK)
+		tubp->sense = dsp->ii.sense;
+
+	wake_up_interruptible(&tubp->waitq);
+}
+
+/*
+ * Wait for something.  If the third arg is zero, wait until
+ * tty3270_size_int() turns off TUB_WORKING.  If the third arg
+ * is not zero, it is a device-status bit; wait until dstat
+ * has the bit turned on.  Never wait if signal is pending.
+ * Return 0 unless signal pending, in which case -ERESTARTSYS.
+ */
+static int
+tty3270_size_wait(tub_t *tubp, int *flags, int stat)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&tubp->waitq, &wait);
+	while (!signal_pending(current) &&
+	    (stat? (tubp->dstat & stat) == 0:
+	     (tubp->flags & TUB_WORKING) != 0)) {
+		current->state = TASK_INTERRUPTIBLE;
+		TUBUNLOCK(tubp->irq, *flags);
+		schedule();
+		current->state = TASK_RUNNING;
+		TUBLOCK(tubp->irq, *flags);
+	}
+	remove_wait_queue(&tubp->waitq, &wait);
+	return signal_pending(current)? -ERESTARTSYS: 0;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/idals.c linux/drivers/s390/idals.c
--- v2.4.3/linux/drivers/s390/idals.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/idals.c	Wed Apr 11 19:02:28 2001
@@ -9,6 +9,7 @@
    * 12/13/00 changed IDALs to 4kByte-IDALs
  */
 
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/malloc.h>
 
@@ -16,6 +17,8 @@
 #include <asm/idals.h>
 
 #ifdef CONFIG_ARCH_S390X
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 void 
 set_normalized_cda ( ccw1_t * cp, unsigned long address )
 {
@@ -25,11 +28,12 @@
 
 	if (cp->flags & CCW_FLAG_IDA)
 		BUG();
-	if (((address + count) >> 31) == 0) { /* do we really need  '+count'? */
+	if (((address + count) >> 31) == 0) { 
 		cp -> cda = address;
 		return;
 	}
-        nridaws = ((address & 4095L) + count + 4095L) >> 12;
+        nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
+		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
 	idal = idal_alloc(nridaws);
 	if ( idal == NULL ) {
 		/* probably we should have a fallback here */
@@ -39,9 +43,12 @@
 	cp->cda = (__u32)(unsigned long)(idaw_t *)idal;
         do {
 		*idal++ = address;
-		address = (address & -4096L) + 4096;
+		address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
 		nridaws --;
         } while ( nridaws > 0 );
 	return;
 }
+
+EXPORT_SYMBOL (set_normalized_cda);
+
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/misc/Makefile linux/drivers/s390/misc/Makefile
--- v2.4.3/linux/drivers/s390/misc/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/misc/Makefile	Wed Apr 11 19:02:28 2001
@@ -1,9 +1,10 @@
-all: s390-misc.o
+#
+# S/390 miscellaneous devices
+#
 
-CFLAFS += 
 O_TARGET := s390-misc.o
 
 obj-$(CONFIG_CHANDEV) += chandev.o
+export-objs += chandev.o
 
 include $(TOPDIR)/Rules.make
-
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/misc/chandev.c linux/drivers/s390/misc/chandev.c
--- v2.4.3/linux/drivers/s390/misc/chandev.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/misc/chandev.c	Wed Apr 11 19:02:28 2001
@@ -6,7 +6,10 @@
  * 
  *  Generic channel device initialisation support. 
  */
+#define TRUE 1
+#define FALSE 0
 #define __KERNEL_SYSCALLS__
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/ctype.h>
@@ -20,6 +23,7 @@
 #include <linux/vmalloc.h>
 #include <asm/s390dyn.h>
 #include <asm/queue.h>
+#include <linux/kmod.h>
 
 typedef struct chandev_model_info chandev_model_info;
 struct chandev_model_info
@@ -229,6 +233,7 @@
 static long                 chandev_lock_owner;
 static int                  chandev_lock_cnt; 
 static spinlock_t           chandev_spinlock;
+void                        *chandev_firstlock_addr,*chandev_lastlock_addr; 
 
 typedef struct chandev_not_oper_struct chandev_not_oper_struct;
 
@@ -256,24 +261,6 @@
 for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next)
 
 
-#define CHANDEV_USE_KERNEL_THREADS (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0))
-
-#if CHANDEV_USE_KERNEL_THREADS
-static void chandev_start_msck_thread(void *unused);
-#if LINUX_VERSION_CODE<KERNEL_VERSION(2,3,0)
-#define chandev_daemonize(name,mask,use_init_fs) s390_daemonize(name,mask)
-#else
-#define chandev_daemonize(args...) s390_daemonize(args)
-#endif
-typedef int chandev_task_retval;
-#define chandev_task_return(val) return(val)       
-#else
-#define chandev_daemonize(noargs...)
-#define chandev_task_retval void
-#define chandev_task_return(val) return
-#endif
-
-
 static void chandev_lock(void)
 {
 	chandev_interrupt_check();
@@ -283,18 +270,33 @@
 		spin_lock(&chandev_spinlock);
 		chandev_lock_cnt=1;
 		chandev_lock_owner=(long)current;
+		chandev_firstlock_addr=__builtin_return_address(0);
 	}
 	else
+	{
 		chandev_lock_cnt++;
+		chandev_lastlock_addr=__builtin_return_address(0);
+	}
 	if(chandev_lock_cnt<0||chandev_lock_cnt>100)
-			panic("odd lock_cnt in lcs %d lcs_chan_lock",chandev_lock_cnt);
+	{
+		printk("odd lock_cnt %d lcs_chan_lock",chandev_lock_cnt);
+		chandev_lock_cnt=1;
+	}
 }
 
+static int chandev_full_unlock(void)
+{
+	int ret_lock_cnt=chandev_lock_cnt;
+	chandev_lock_cnt=0;
+	chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
+	spin_unlock(&chandev_spinlock);
+	return(ret_lock_cnt);
+}
 
 static void chandev_unlock(void)
 {
 	if(chandev_lock_owner!=(long)current)
-		panic("chandev_unlock: current=%lx"
+		printk("chandev_unlock: current=%lx"
 		      " chandev_lock_owner=%lx chandev_lock_cnt=%d\n",
 		      (long)current,
 		      chandev_lock_owner,
@@ -305,19 +307,20 @@
 		spin_unlock(&chandev_spinlock);
 	}
 	if(chandev_lock_cnt<0)
-		panic("odd lock_cnt in lcs %d lcs_chan_unlock",chandev_lock_cnt);
-}
+	{
+		printk("odd lock_cnt=%d in chan_unlock",chandev_lock_cnt);
+		chandev_full_unlock();
+	}
 
-int chandev_full_unlock(void)
-{
-	int ret_lock_cnt=chandev_lock_cnt;
-	chandev_lock_cnt=0;
-	chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
-	spin_unlock(&chandev_spinlock);
-	return(ret_lock_cnt);
 }
 
 
+void chandev_relock(int saved_lock_cnt)
+{
+	
+	chandev_lock();
+	chandev_lock_cnt=saved_lock_cnt;
+}
 
 
 void *chandev_alloc(size_t size)
@@ -405,145 +408,8 @@
 }
 
 
-struct files_struct *chandev_new_files_struct(void)
-{
-        struct files_struct *newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
-	if (!newf) 
-		return(NULL);
-	memset(newf,0,sizeof(struct files_struct));
-	atomic_set(&newf->count, 1);
-	newf->file_lock	    = RW_LOCK_UNLOCKED;
-	newf->next_fd	    = 0;
-	newf->max_fds	    = NR_OPEN_DEFAULT;
-	newf->max_fdset	    = __FD_SETSIZE;
-	newf->close_on_exec = &newf->close_on_exec_init;
-	newf->open_fds	    = &newf->open_fds_init;
-	newf->fd	    = &newf->fd_array[0];
-	return(newf);
-}
-/*
- * Mostly robbed from kmod.c
- */
 
-static inline void
-use_init_fs_context(void)
-{
-	struct fs_struct *our_fs, *init_fs;
-	struct dentry *root, *pwd;
-	struct vfsmount *rootmnt, *pwdmnt;
-
-	/*
-	 * Make modprobe's fs context be a copy of init's.
-	 *
-	 * We cannot use the user's fs context, because it
-	 * may have a different root than init.
-	 * Since init was created with CLONE_FS, we can grab
-	 * its fs context from "init_task".
-	 *
-	 * The fs context has to be a copy. If it is shared
-	 * with init, then any chdir() call in modprobe will
-	 * also affect init and the other threads sharing
-	 * init_task's fs context.
-	 *
-	 * We created the exec_modprobe thread without CLONE_FS,
-	 * so we can update the fields in our fs context freely.
-	 */
-
-	init_fs = init_task.fs;
-	read_lock(&init_fs->lock);
-	rootmnt = mntget(init_fs->rootmnt);
-	root = dget(init_fs->root);
-	pwdmnt = mntget(init_fs->pwdmnt);
-	pwd = dget(init_fs->pwd);
-	read_unlock(&init_fs->lock);
-
-	/* FIXME - unsafe ->fs access */
-	our_fs = current->fs;
-	our_fs->umask = init_fs->umask;
-	set_fs_root(our_fs, rootmnt, root);
-	set_fs_pwd(our_fs, pwdmnt, pwd);
-	write_lock(&our_fs->lock);
-	if (our_fs->altroot) {
-		struct vfsmount *mnt = our_fs->altrootmnt;
-		struct dentry *dentry = our_fs->altroot;
-		our_fs->altrootmnt = NULL;
-		our_fs->altroot = NULL;
-		write_unlock(&our_fs->lock);
-		dput(dentry);
-		mntput(mnt);
-	} else 
-		write_unlock(&our_fs->lock);
-	dput(root);
-	mntput(rootmnt);
-	dput(pwd);
-	mntput(pwdmnt);
-}
-
-
-static int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
-{
-	int err;
-	wait_queue_head_t    wait;
-
-
-	current->session = 1;
-	current->pgrp = 1;
-
-	/* We copy this off init & can't go until this is set up */
-	init_waitqueue_head(&wait);
-	while(init_task.fs->root==NULL)
-	{
-		sleep_on_timeout(&wait,HZ);
-	}
-	use_init_fs_context();
-
-	/* Prevent parent user process from sending signals to child.
-	   Otherwise, if the modprobe program does not exist, it might
-	   be possible to get a user defined signal handler to execute
-	   as the super user right after the execve fails if you time
-	   the signal just right.
-	*/
-	spin_lock_irq(&current->sigmask_lock);
-	flush_signals(current);
-	flush_signal_handlers(current);
-	spin_unlock_irq(&current->sigmask_lock);
-	 /* current->files sometimes was null this means we need */
-	 /* to build our own */
-	 exit_files(current);
-	 if((current->files=chandev_new_files_struct())==NULL)
-	 {
-		 printk("chandev_new_files_struct allocation failed\n");
-		 return(0);
-	 }
-	 
-	/* Drop the "current user" thing */
-	{
-		struct user_struct *user = current->user;
-		current->user = INIT_USER;
-		atomic_inc(&INIT_USER->__count);
-		atomic_inc(&INIT_USER->processes);
-		atomic_dec(&user->processes);
-		free_uid(user);
-	}
-
-	/* Take all effective privileges.. */
-	current->uid = current->euid = current->fsuid = 0;
-	cap_set_full(current->cap_effective);
-	/* Allow execve & open args to be in kernel space. */
-	set_fs(KERNEL_DS);
-	/* We need stdin out & err for scripts */
-	if (open("/dev/console", O_RDWR, 0)< 0)
-		printk("chandev exec_usermode_helper unable to open an initial console.\n");
-	(void) dup(0);
-	(void) dup(0);
-
-	
-        /* Go, go, go... */
-        err=execve(program_path, argv, envp);
-	return err;
-}
-
-static int exec_start_script(void *unused)
+static int chandev_exec_start_script(void *unused)
 {
 	
 	char **argv,*tempname;
@@ -555,7 +421,8 @@
 	static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
 	
 	init_waitqueue_head(&wait);
-	s390_daemonize("chandev_script",0,FALSE);
+	strcpy(current->comm,"chandev_script");
+
 	for(loopcnt=0;loopcnt<10&&(jiffies-chandev_last_startmsck_list_update)<HZ;loopcnt++)
 	{
 		sleep_on_timeout(&wait,HZ);
@@ -612,6 +479,12 @@
 		chandev_free_all_list((list **)&startlist_head);
 		chandev_free_all_list((list **)&mscklist_head);
 		chandev_unlock();
+
+		/* We need to wait till there is a root filesystem */
+		while(init_task.fs->root==NULL)
+		{
+			sleep_on_timeout(&wait,HZ);
+		}
 		/* We are basically execve'ing here there normally is no */
 		/* return */
 		retval=exec_usermodehelper(exec_script, argv, envp);
@@ -623,7 +496,7 @@
  Fail2:
 	/* We don't really need to report /bin/chandev not existing */
 	if(retval!=-ENOENT)
-	   printk("exec_start_script failed retval=%d\n",retval);
+	   printk("chandev_exec_start_script failed retval=%d\n",retval);
 	return(0);
 }
 
@@ -643,7 +516,6 @@
 static int chandev_add_to_startmsck_list(chandev_startmsck_list **listhead,char *devname,
 chandev_msck_status pre_recovery_action_status,chandev_msck_status post_recovery_action_status)
 {
-	int retval;
 	chandev_startmsck_list *member;
 	int pid;
 	
@@ -664,14 +536,11 @@
 		add_to_list((list **)listhead,(list *)member);
 		chandev_last_startmsck_list_update=jiffies;
 		chandev_unlock();
-		/* We do CLONE_FILES so we can exit_files to get rid of it */
-                /* cheaply & allocate a new one we need current->files &  */
-                /* some tasks have current->files==NULL */
-		pid = kernel_thread(exec_start_script,NULL,CLONE_FILES|SIGCHLD);
+		pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD);
 		if(pid<0)
 		{
-			printk("error making kernel thread for exec_start_script\n");
-			retval=pid;
+			printk("error making kernel thread for chandev_exec_start_script\n");
+			return(pid);
 		}
 		else
 			return(0);
@@ -679,11 +548,10 @@
 	}
 	else
 	{
+		chandev_unlock();
 		printk("chandev_add_to_startmscklist memory allocation failed devname=%s\n",devname);
-		retval=-ENOMEM;
+		return(-ENOMEM);
 	}
-	chandev_unlock();
-	return(retval);
 }
 
 
@@ -695,11 +563,7 @@
 	chandev_last_machine_check=jiffies;
 	if(atomic_dec_and_test(&chandev_msck_thread_lock))
 	{
-#if CHANDEV_USE_KERNEL_THREADS
-		queue_task(&chandev_msck_task_tq,&tq_scheduler);
-#else
 		schedule_task(&chandev_msck_task_tq);
-#endif
 	}
 	atomic_set(&chandev_new_msck,TRUE);
 	return(0);
@@ -719,11 +583,7 @@
 		spin_unlock(&chandev_not_oper_spinlock);
 		if(atomic_dec_and_test(&chandev_msck_thread_lock))
 		{
-#if CHANDEV_USE_KERNEL_THREADS
-			queue_task(&chandev_msck_task_tq,&tq_scheduler);
-#else
 			schedule_task(&chandev_msck_task_tq);
-#endif
 		}
 	}
 	else
@@ -767,6 +627,18 @@
 }
 
 
+void chandev_remove_irqinfo_by_irq(unsigned int irq)
+{
+	chandev_irqinfo *remove_irqinfo;
+
+	chandev_lock();
+	/* remove any orphan irqinfo left lying around. */
+        if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq)))
+		chandev_remove_from_list((list **)&chandev_irqinfo_head,
+					 (list *)remove_irqinfo);
+	chandev_unlock();
+	
+}
 
 int chandev_request_irq(unsigned int   irq,
                       void           (*handler)(int, void *, struct pt_regs *),
@@ -790,9 +662,7 @@
 		return(-EPERM);
 	}
 	/* remove any orphan irqinfo left lying around. */
-        if((new_irqinfo=chandev_get_irqinfo_by_irq(irq)))
-		chandev_remove_from_list((list **)chandev_irqinfo_head,
-					 (list *)new_irqinfo);
+	chandev_remove_irqinfo_by_irq(irq);
 	chandev_unlock();
 	if((new_irqinfo=chandev_allocstr(devname,offsetof(chandev_irqinfo,devname))))
 	{
@@ -819,6 +689,12 @@
 	return(retval);
 }
 
+void chandev_free_irq(unsigned int irq, void *dev_id)
+{
+	/* remove any orphan irqinfo left lying around. */
+	chandev_remove_irqinfo_by_irq(irq);
+	free_irq(irq,dev_id);
+}
 
 
 void chandev_sprint_type_model(char *buff,s32 type,s16 model)
@@ -1148,6 +1024,7 @@
 
 void chandev_shutdown(chandev_activelist *curr_device)
 {
+	int saved_lock_cnt;
 	chandev_lock();
 
 	if(curr_device->category==network_device)
@@ -1155,12 +1032,16 @@
 		/* unregister_netdev calls the dev->close so we shouldn't do this */
 		/* this otherwise we crash */
 		if(curr_device->unreg_dev)
-			curr_device->unreg_dev(curr_device->dev_ptr); 
+		{
+			saved_lock_cnt=chandev_full_unlock();
+			curr_device->unreg_dev(curr_device->dev_ptr);
+			chandev_relock(saved_lock_cnt);
+		}
 	}
+	saved_lock_cnt=chandev_full_unlock();
 	curr_device->shutdownfunc(curr_device->dev_ptr);
+	chandev_relock(saved_lock_cnt);
 	kfree(curr_device->dev_ptr);
-	chandev_free_listmember((list **)&chandev_irqinfo_head,(list *)curr_device->read_irqinfo);
-	chandev_free_listmember((list **)&chandev_irqinfo_head,(list *)curr_device->write_irqinfo);
 	chandev_free_listmember((list **)&chandev_activelist_head,
 				(list *)curr_device);
 	chandev_unlock();
@@ -1492,8 +1373,7 @@
 			/* as probefunctions can call schedule & */
                         /* reenter to do a kernel thread & we may deadlock */
 			rc=probefunc(&probeinfo);
-			chandev_lock();
-			chandev_lock_cnt=saved_lock_cnt;
+			chandev_relock(saved_lock_cnt);
 			if(rc==0)
 			{
 				newdevice=probeinfo.newdevice;
@@ -1619,9 +1499,13 @@
 			if(curr_irqinfo->msck_status==good&&prevstatus!=good)
 			{
 				if(curr_device->reoperfunc)
+				{
+					int saved_lock_cnt=chandev_full_unlock();
 					curr_device->reoperfunc(curr_device->dev_ptr,
 								(curr_device->read_irqinfo==curr_irqinfo),
 								prevstatus);
+					chandev_relock(saved_lock_cnt);
+				}
 				if(curr_device->category==network_device&&
 				   curr_device->write_irqinfo==curr_irqinfo)
 				{
@@ -1743,13 +1627,12 @@
 }
 
 
-static chandev_task_retval chandev_msck_task(void *unused)
+static void chandev_msck_task(void *unused)
 {
 	int loopcnt,not_oper_probe_required=FALSE;
 	wait_queue_head_t    wait;
 	chandev_not_oper_struct *new_not_oper;
 
-	chandev_daemonize("chandev_msck_kernel_thread",0,TRUE);
 	/* This loop exists because machine checks tend to come in groups & we have
            to wait for the other devnos to appear also */
 	init_waitqueue_head(&wait);
@@ -1780,21 +1663,10 @@
 	}
 	if(not_oper_probe_required)
 		chandev_probe();
-	chandev_task_return(0);
 }
 
 
 
-#if CHANDEV_USE_KERNEL_THREADS
-static void chandev_start_msck_thread(void *unused)
-{
-	/* tq_scheduler sometimes leaves interrupts disabled from do bottom half */
-	__sti();
-	kernel_thread((int (*)(void *))chandev_msck_task,
-		      (void*)NULL,0);
-}
-#endif
-
 
 
 static char *argstrs[]=
@@ -1953,6 +1825,7 @@
 	chandev_type     chan_type;
 	char             *str,*currstr,*interpretstr=NULL;
 	int              cnt,strcnt;
+	int              retval=0;
 #define CHANDEV_MAX_EXTRA_INTS 8
 	chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1];
 	memset(ints,0,sizeof(ints));
@@ -2182,17 +2055,29 @@
 		else
 			goto BadArgs;
 	}
-	return(1);
+	retval=1;
  BadArgs:
-	printk("chandev_setup bad argument %s",instr);
-	if(errstr)
+	if(!retval)
 	{
-                printk("%s %d interpreted as %s",errstr,lineno,interpretstr);
-		if(strcnt>1)
-			printk(" before semicolon no %d",cnt);
+		printk("chandev_setup bad argument %s",instr);
+		if(errstr)
+		{
+			printk("%s %d interpreted as %s",errstr,lineno,interpretstr);
+			if(strcnt>1)
+				printk(" before semicolon no %d",cnt);
+		}
+		printk(".\n Type man chandev for more info.\n\n");
 	}
-	printk(".\n Type man chandev for more info.\n\n");
-	return(0);
+	eieio();
+	if(chandev_lock_owner==(long)current)
+	{
+		printk("chandev_setup bug chandev_lock_cnt=%d lock_owner=%lx\n"
+                       "firstlock_retaddr=%p last_lock_returnaddr=%p\n",
+		       chandev_lock_cnt,chandev_lock_owner,chandev_firstlock_addr,
+		       chandev_lastlock_addr);
+		chandev_full_unlock();
+        }
+	return(retval);
 }
 #define CHANDEV_KEYWORD "chandev="
 static int chandev_setup_bootargs(char *str,int paramno)
@@ -2608,11 +2493,7 @@
 		chandev_create_proc();
 #endif
 		chandev_msck_task_tq.routine=
-#if CHANDEV_USE_KERNEL_THREADS
-		chandev_start_msck_thread;
-#else
 		chandev_msck_task;
-#endif
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
 		INIT_LIST_HEAD(&chandev_msck_task_tq.list);
 		chandev_msck_task_tq.sync=0;
@@ -2684,4 +2565,13 @@
 	}
 	chandev_unlock();
 }
+
+EXPORT_SYMBOL(chandev_register_and_probe);
+EXPORT_SYMBOL(chandev_request_irq);
+EXPORT_SYMBOL(chandev_free_irq);
+EXPORT_SYMBOL(chandev_unregister);
+EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_initnetdevice);
+
+
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile
--- v2.4.3/linux/drivers/s390/net/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/net/Makefile	Wed Apr 11 19:02:28 2001
@@ -1,20 +1,20 @@
-all: s390-net.o
+#
+# S/390 network devices
+#
 
-CFLAGS += 
 O_TARGET := s390-net.o
 
-obj-y    := iucv.o
+list-multi := ctc.o
+export-objs := iucv.o
 
-ifeq ($(CONFIG_CTC),y)
-  obj-y += ctcmain.o fsm.o
-else
-  ifeq ($(CONFIG_CTC),m)
-  obj-m += ctc.o
-ctc.o: ctcmain.o fsm.o
-	$(LD) -r ctcmain.o fsm.o -o $@
-  endif
-endif
+ctc-objs := ctcmain.o ctctty.o fsm.o
 
-obj-$(CONFIG_IUCV) += iucv.o netiucv.o
+obj-y += iucv.o
+obj-$(CONFIG_CTC) += ctc.o
+obj-$(CONFIG_IUCV) += netiucv.o
 
 include $(TOPDIR)/Rules.make
+
+ctc.o: $(ctc-objs)
+	$(LD) -r -o $@ $(ctc-objs)
+
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- v2.4.3/linux/drivers/s390/net/ctc.c	Fri Mar  2 11:12:07 2001
+++ linux/drivers/s390/net/ctc.c	Wed Dec 31 16:00:00 1969
@@ -1,1582 +0,0 @@
-/*
- *  drivers/s390/net/ctc.c 
- *    CTC / ESCON network driver
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Dieter Wellerdiek (wel@de.ibm.com)
- *
- *     2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com)
- *                 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *
- *
- *  Description of the Kernel Parameter
- *    Normally the CTC driver selects the channels in order (automatic channel 
- *    selection). If your installation needs to use the channels in a different 
- *    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
- *
- *     Where:
- *
- *       "rrrr" is the read channel address
- *       "wwww" is the write channel address
- *       "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
- *              to escon7 for ESCON channels).
- *
- *     To switch the automatic channel selection off use the ctc= keyword with 
- *     parameter "noauto". This may be necessary if you 3271 devices or other devices 
- *     which use the ctc device type and model, but operate with a different protocol. 
- *     
- *       ctc=noauto
- *
- *  Change History
- *    0.50  Initial release shipped
- *    0.51  Bug fixes
- *          - CTC / ESCON network device can now handle up to 64 channels 
- *          - 3088-61 info message supperssed - CISCO 7206 - CLAW - ESCON 
- *          - 3088-62 info message suppressed - OSA/D   
- *          - channel: def ffffffed ... error message suppressed 
- *          - CTC / ESCON device was not recoverable after a lost connection with 
- *            IFCONFIG dev DOWN and IFCONFIG dev UP 
- *          - Possibility to switch the automatic selection off
- *          - Minor bug fixes 
- */
-#include <linux/version.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-
-#include <linux/signal.h>
-#include <linux/string.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ip.h>
-#include <linux/if_arp.h>
-#include <linux/tcp.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-#include <asm/bitops.h>
- 
-#include <asm/irq.h>
-
-
-//#define DEBUG 
-
-/* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */
-#ifdef DEBUG                
-        #undef  KERN_INFO
-        #undef  KERN_WARNING
-        #undef  KERN_DEBUG
-        #define KERN_INFO    KERN_EMERG
-        #define KERN_WARNING KERN_EMERG
-        #define KERN_DEBUG   KERN_EMERG
-#endif  
-//#undef DEBUG
-
-#define CCW_CMD_WRITE           0x01
-#define CCW_CMD_READ            0x02
-#define CCW_CMD_SET_EXTENDED    0xc3
-#define CCW_CMD_PREPARE         0xe3
-
-#define MAX_CHANNEL_DEVICES     64 
-#define MAX_ADAPTERS            8
-#define CTC_DEFAULT_MTU_SIZE    1500
-#define READ                    0
-#define WRITE                   1
-#define CTC                     0
-#define ESCON                   1
-#define CHANNEL_MEDIA           2
-#define CTC_BLOCKS              8          /* 8 blocks * 2 times * 64k = 1M */
-
-#define TB_TX                   0          /* sk buffer handling in process */
-#define TB_STOP                 1          /* network device stop in process */
-#define TB_RETRY                2          /* retry in process */
-#define TB_NOBUFFER             3          /* no buffer on free queue */ 
-
-/* state machine codes used in ctc_irq_handler */
-#define CTC_STOP                0
-#define CTC_START_HALT_IO       1
-#define CTC_START_SET_X_MODE    2
-#define CTC_START_SELECT        4 
-#define CTC_START_READ_TEST     32
-#define CTC_START_READ          33
-#define CTC_START_WRITE_TEST    64
-#define CTC_START_WRITE         65
-
-
-typedef enum { 
-        channel_type_none,           /* Device is not a channel */
-        channel_type_undefined,      /* Device is a channel but we don't know anything about it */
-        channel_type_ctca,           /* Device is a CTC/A and we can deal with it */
-        channel_type_escon,          /* Device is a ESCON channel and we can deal with it */
-        channel_type_unsupported     /* Device is a unsupported model */
-} channel_type_t; 
-  
-
-
-/* 
- *   Structures needed in the initial phase 
- *
- */  
-
-/* long req'd by set_bit --RR */
-static long channel_tab_initialized = 0;     /* channel[] structure initialized */
-
-struct devicelist {  
-        unsigned int  devno;
-        __u8          flag;
-#define CHANNEL_IN_USE   0x08               /* - Show that channel is in use */
-}; 
-
-static struct {
-        struct devicelist  list[MAX_CHANNEL_DEVICES]; 
-        int                count;
-        int                left;
-} channel[CHANNEL_MEDIA];
-
-
-
-static int ctc_no_auto = 0;
-
-struct adapterlist{ 
-        unsigned int       devno[2];
-        __u16              protocol;
-};
-
-static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS];  /* 0 = CTC  / 1 = ESCON */
-
-
-/* 
- *   Structure used after the initial phase 
- *
- */
-    
-struct buffer {
-        struct buffer       *next;
-        int                 packets;
-        struct block        *block;
-};
-
-#if LINUX_VERSION_CODE>=0x020300
-typedef struct net_device  net_device;
-#else
-typedef struct device  net_device;
-typedef struct wait_queue* wait_queue_head_t;
-#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue  waitqname = {waitqtask, NULL }
-#define init_waitqueue_head(nothing)
-#endif
-
-
-struct channel {
-        unsigned int        devno;
-        int                 irq;
-        unsigned long       IO_active;
-        ccw1_t              ccw[3];
-        __u32               state; 
-        int                 buffer_count;
-        struct buffer       *free_anchor;
-        struct buffer       *proc_anchor;
-        devstat_t           *devstat;
-        net_device   *dev;      /* backward pointer to the network device */ 
-	wait_queue_head_t   wait;
-        struct tq_struct    tq;
-        struct timer_list   timer;
-        unsigned long       flag_a;    /* atomic flags */
-#define CTC_BH_ACTIVE       0   
-        __u8                last_dstat;
-        __u8                flag;
-#define CTC_WRITE            0x01      /* - Set if this is a write channel */
-#define CTC_TIMER            0x80      /* - Set if timer made the wake_up  */ 
-};
-
-
-struct ctc_priv {                                                                    
-        struct net_device_stats  stats;
-#if LINUX_VERSION_CODE>=0x02032D
-	int                      tbusy;
-#endif
-        struct channel           channel[2]; 
-        __u16                    protocol;
-};  
-
-/*
- *   This structure works as shuttle between two systems 
- *    - A block can contain one or more packets 
- */
-
-#define PACKET_HEADER_LENGTH  6
-struct packet {
-        __u16         length;
-        __u16         type;
-        __u16         unused;
-        __u8          data;
-}; 
-
-#define BLOCK_HEADER_LENGTH   2
-struct block {
-        __u16         length;
-        struct packet data;
-};
-
-#if LINUX_VERSION_CODE>=0x02032D
-#define ctc_protect_busy(dev) \
-s390irq_spin_lock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq)
-#define ctc_unprotect_busy(dev) \
-s390irq_spin_unlock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq)
-
-#define ctc_protect_busy_irqsave(dev,flags) \
-s390irq_spin_lock_irqsave(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags)
-#define ctc_unprotect_busy_irqrestore(dev,flags) \
-s390irq_spin_unlock_irqrestore(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags)
-
-static __inline__ void ctc_set_busy(net_device *dev)
-{
-	((struct ctc_priv *)dev->priv)->tbusy=1;
-	netif_stop_queue(dev);
-}
-
-static __inline__ void ctc_clear_busy(net_device *dev)
-{
-	((struct ctc_priv *)dev->priv)->tbusy=0;
-	netif_start_queue(dev);
-}
-
-static __inline__ int ctc_check_busy(net_device *dev)
-{
-	eieio();
-	return(((struct ctc_priv *)dev->priv)->tbusy);
-}
-
-
-static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
-{
-	set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy));
-	netif_stop_queue(dev);	
-}
-
-static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
-{
-	clear_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy));
-	if(((struct ctc_priv *)dev->priv)->tbusy==0)
-		netif_start_queue(dev);
-}
-
-static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev)
-{
-	netif_stop_queue(dev);
-	return(test_and_set_bit(nr,&((struct ctc_priv *)dev->priv)->tbusy));
-}
-#else
-
-#define ctc_protect_busy(dev)
-#define ctc_unprotect_busy(dev)
-#define ctc_protect_busy_irqsave(dev,flags)
-#define ctc_unprotect_busy_irqrestore(dev,flags)
-
-static __inline__ void ctc_set_busy(net_device *dev)
-{
-	dev->tbusy=1;
-	eieio();
-}
-
-static __inline__ void ctc_clear_busy(net_device *dev)
-{
-	dev->tbusy=0;
-	eieio();
-}
-
-static __inline__ int ctc_check_busy(net_device *dev)
-{
-	eieio();
-	return(dev->tbusy);
-}
-
-
-static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
-{
-	set_bit(nr,(void *)&dev->tbusy);
-}
-
-static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
-{
-	clear_bit(nr,(void *)&dev->tbusy);
-}
-
-static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev)
-{
-	return(test_and_set_bit(nr,(void *)&dev->tbusy));
-}
-#endif
-
-
-
-
-
-/* Interrupt handler */
-static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs);
-static void ctc_irq_bh(struct channel *ctc); 
-static void ctc_read_retry (struct channel *ctc);
-static void ctc_write_retry (struct channel *ctc);
-
-
-/* Functions for the DEV methods */
-int ctc_probe(net_device *dev);
- 
-
-static int ctc_open(net_device *dev); 
-static void ctc_timer (struct channel *ctc);
-static int ctc_release(net_device *dev);
-static int ctc_tx(struct sk_buff *skb, net_device *dev);
-static int ctc_change_mtu(net_device *dev, int new_mtu);
-struct net_device_stats* ctc_stats(net_device *dev); 
-
-
-/*
- *   Channel Routines 
- *
- */ 
-
-static void channel_init(void);
-static void channel_scan(void);
-static int channel_get(int media, int devno);
-static int channel_get_next(int media); 
-static int channel_free(int media, int devno);
-static channel_type_t channel_check_for_type (senseid_t *id);
-static void channel_sort(struct devicelist list[], int n);
-
-
-/*
- * initialize the channel[].list 
- */   
-static void channel_init(void) 
-{
-        int     m;
-#ifdef DEBUG
-        int     c;
-#endif
-
-        if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){
-                channel_scan(); 
-                for (m = 0; m < CHANNEL_MEDIA; m++) { 
-                        channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); 
-                        channel[m].left = channel[m].count;   
-                }
-                if (channel[CTC].count == 0 && channel[ESCON].count == 0) 
-                        printk(KERN_INFO "channel: no Channel devices recognized\n");
-                else
-                        printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n",
-                            channel[CTC].count, channel[ESCON].count);  
-#ifdef DEBUG 
-                for (m = 0; m < CHANNEL_MEDIA;  m++) { 
-                        for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
-                                printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", 
-                                     m, c, channel[m].list[c].devno);
-                        }
-                }
-#endif
-         }
-}
-
-
-/*
-* scan for all channels and put the device numbers into the channel[].list 
-*/  
-static void channel_scan(void)
-{
-        int        m;
-        int        c;
-        int        irq;
-        s390_dev_info_t temp;
-        
-        for (m = 0; m < CHANNEL_MEDIA;  m++) { 
-                for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
-                        channel[m].list[c].devno = -ENODEV;
-                }
-        }
-        
-        for (irq = 0; irq < NR_IRQS; irq++) {
-                /* CTC/A */
-                if (channel[CTC].count < MAX_CHANNEL_DEVICES ) {
-                        if (get_dev_info(irq, &temp) == 0 && 
-                            channel_check_for_type(&temp.sid_data) == channel_type_ctca) {
-                                channel[CTC].list[channel[CTC].count].devno = temp.devno; 
-                                channel[CTC].count++; 
-                        }
-                }
-
-                /* ESCON */
-                if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) {
-                        if (get_dev_info(irq, &temp) == 0 && 
-                            channel_check_for_type(&temp.sid_data) == channel_type_escon) {
-                                channel[ESCON].list[channel[ESCON].count].devno = temp.devno; 
-                                channel[ESCON].count++; 
-
-                        }
-                }
-        }
-} 
- 
-
-/*
- * free specific channel from the channel[].list 
- */  
-static int channel_free(int media, int devno)
-{
-        int     i;
-
-        for (i = 0; i < channel[media].count; i++) {       
-                if ((devno == channel[media].list[i].devno) &&
-                    ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
-                        channel[media].list[i].flag &= ~CHANNEL_IN_USE;
-                        return 0;
-                }
-        }
-        printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
-        return -ENODEV; 
-}
-
-
-/*
- * get specific channel from the channel[].list 
- */  
-static int channel_get(int media, int devno)
-{
-        int     i;
-
-        for (i = 0; i < channel[media].count; i++) {       
-                if ((devno == channel[media].list[i].devno) &&
-                    ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
-                        channel[media].list[i].flag |= CHANNEL_IN_USE;
-                        return channel[media].list[i].devno;             
-                }
-        }
-        printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
-        return -ENODEV; 
-
-}
-
-
-/*
- * get the next free channel from the channel[].list 
- */  
-static int channel_get_next(int media)
-{
-        int     i;
-
-        for (i = 0; i < channel[media].count; i++) {
-                if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
-#ifdef DEBUG
-                        printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
-#endif
-                        channel[media].list[i].flag |= CHANNEL_IN_USE;
-                        return channel[media].list[i].devno;        
-                }
-        }
-        return -ENODEV; 
-}
- 
-
-/*
- * picks the next free channel from the channel[].list 
- */  
-static int channel_left(int media)
-{
-        return channel[media].left; 
-}
-
-
-/*
- * defines all devices which are channels
- */
-static channel_type_t channel_check_for_type (senseid_t *id)
- {
-        channel_type_t type;
-
-        switch (id->cu_type) {
-                case 0x3088: 
-
-                        switch (id->cu_model) {
-                                case 0x08:    
-                                        type = channel_type_ctca;  /* 3088-08  ==> CTCA */
-                                        break; 
-
-                                case 0x1F:   
-                                        type = channel_type_escon; /* 3088-1F  ==> ESCON channel */
-                                        break;
- 
-                                case 0x01:                         /* 3088-01  ==> P390 OSA emulation */
-                                case 0x60:                         /* 3088-60  ==> OSA/2 adapter */
-                                case 0x61:                         /* 3088-61  ==> CISCO 7206 CLAW protocol ESCON connected */
-                                case 0x62:                         /* 3088-62  ==> OSA/D device */ 
-                                        type = channel_type_unsupported;
-                                         break; 
-
-                                default:
-                                        type = channel_type_undefined;
-                                        printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
-                        }
-                        break;
-
-                default:
-                        type = channel_type_none;
-
-        }
-        return type;
-}
-
-
-/*
- *  sort the channel[].list
- */
-static void channel_sort(struct devicelist list[], int n)
-{
-        int               i;
-        int               sorted = 0;
-        struct devicelist tmp;
-
-        while (!sorted) { 
-                sorted = 1;
-
-                for (i = 0; i < n-1; i++) {  
-                        if (list[i].devno > list[i+1].devno) {  
-                                tmp = list[i];
-                                list[i] = list[i+1];
-                                list[i+1] = tmp;
-                                sorted = 0;
-                        }
-                }
-        }
-} 
-
-
-/*
- *   General routines 
- *
- */
-
-static int inline extract_channel_id(char *name)
-{
-        if (name[0] == 'c') 
-                return (name[3]-'0');
-        else
-                return (name[5]-'0');
-}
-
-
-static int inline extract_channel_media(char *name)
-{
-        if (name[0] == 'c') 
-                return CTC;
-        else
-                return ESCON;
-}
-
-
-static void ctc_tab_init(void)
-{                                    
-        int          m;
-        int          i;
-        static int   t;
-
-        if (t == 0){
-                for (m = 0; m < CHANNEL_MEDIA;  m++) {
-                        for (i = 0; i < MAX_ADAPTERS;  i++) {
-                                ctc_adapter[m][i].devno[WRITE] = -ENODEV;
-                                ctc_adapter[m][i].devno[READ] = -ENODEV;
-                        }
-                }
-                t = 1; 
-        }
-} 
-
-
-static int ctc_buffer_alloc(struct channel *ctc) {
-        
-        struct buffer    *p;
-        struct buffer    *q;
-
-        p = kmalloc(sizeof(p), GFP_KERNEL);
-        if (p == NULL) 
-                return -ENOMEM;
-        else {  
-                p->next = NULL;  
-                p->packets = 0;
-                p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
-                if (p->block == NULL) {
-                        kfree(p);
-                        return -ENOMEM;
-                }
-        }
-   
-        if (ctc->free_anchor == NULL) 
-                ctc->free_anchor = p;  
-        else {  
-                 q = ctc->free_anchor;
-                 while (q->next != NULL) 
-                        q = q->next;
-                 q->next = p;
-        }
-        ctc->buffer_count++;   
-   return 0;
-}
-
-
-static int ctc_buffer_free(struct channel *ctc) {
-        
-        struct buffer    *p;
-
-           
-        if (ctc->free_anchor == NULL)
-                return -ENOMEM;
-        
-        p = ctc->free_anchor; 
-        ctc->free_anchor = p->next;
-        free_pages((__u32)p->block, 4);
-        kfree(p);
-
-        return 0;
-}
-
-
-static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) {
-        
-        struct buffer    *p = NULL;
-        struct buffer    *q = NULL;
- 
-        if (*from == NULL)
-                return -ENOMEM; 
-
-        p = *from;
-        *from = p->next;
-        p->next = NULL;
-
-        if (*to == NULL)
-                *to = p;
-        else {
-                q = *to;
-                while (q->next != NULL)
-                        q = q->next;
-                q->next = p;
-
-        }
-        return 0;
-}
-
-
-/*
- *   ctc_setup function 
- *     this function is called for each ctc= keyword passed into the kernel 
- *
- *     valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx 
- *     where n      is the channel protocol always 0 
- *           0xnnnn is the cu number  read 
- *           0xnnnn is the cu number  write 
- *           ctcx can be ctc0 to ctc7 or escon0 to escon7 
- */
-#if LINUX_VERSION_CODE>=0x020300
-static int __init ctc_setup(char *dev_name)
-#else
-__initfunc(void ctc_setup(char *dev_name,int *ints))
-#endif
-{
-        struct adapterlist tmp;
-#if  LINUX_VERSION_CODE>=0x020300
-	#define CTC_MAX_PARMS 4
-	int ints[CTC_MAX_PARMS+1];	
-	get_options(dev_name,CTC_MAX_PARMS,ints);
-	#define ctc_setup_return return(1)
-#else
-	#define ctc_setup_return return
-#endif
-        ctc_tab_init();
-        
-        ctc_no_auto = 1;
-
-        if (!strcmp(dev_name,"noauto")) { 
-                printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); 
-                ctc_setup_return;
-        }
-
-        tmp.devno[WRITE] = -ENODEV;
-        tmp.devno[READ] = -ENODEV; 
-
-        switch (ints[0]) {
-              
-                case 3: /* write channel passed */
-                        tmp.devno[WRITE] = ints[3]; 
-                        
-                case 2: /* read channel passed */
-                        tmp.devno[READ] = ints[2];
-                        if (tmp.devno[WRITE] == -ENODEV)
-                                tmp.devno[WRITE] = tmp.devno[READ] + 1; 
-
-                case 1: /* protocol type passed */
-                        tmp.protocol    = ints[1];
-                        if (tmp.protocol == 0) {
-                                break;    
-                        } else {
-                                printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
-                                ctc_setup_return;
-                        }
-			break;
-
-                default: 
-                        printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
-                        ctc_setup_return;
-        }
-        ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp; 
-#ifdef DEBUG
-        printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n",
-             dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
-#endif  
-        ctc_setup_return;
-        
-}
-#if LINUX_VERSION_CODE>=0x020300
-__setup("ctc=", ctc_setup);
-#endif
-
-/*
- *   ctc_probe 
- *      this function is called for each channel network device, 
- *      which is defined in the /init/main.c 
- */
-int ctc_probe(net_device *dev)
-{       
-        int                rc;
-        int                c;
-        int                i;
-        int                m;
-
-        struct ctc_priv    *privptr;
-
-        /* Only the first time the ctc_probe gets control */
-        if (channel_tab_initialized == 0) {  
-                channel_init();  
-
-
-        }
-        
-        ctc_tab_init();
-
-        m = extract_channel_media(dev->name);
-        i = extract_channel_id(dev->name);
-        
-        if (channel_left(m) <=1) 
-                return -ENODEV;
-
-        if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
-                return -ENODEV;
-
-        dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL);
-        if (dev->priv == NULL)
-                return -ENOMEM;
-        memset(dev->priv, 0, sizeof(struct ctc_priv));  
-        privptr = (struct ctc_priv *) (dev->priv);
-
-        
-        for (c = 0; c < 2; c++) {
-
-                privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
-                if (privptr->channel[c].devstat == NULL){
-                        if (i == WRITE)
-                                kfree(privptr->channel[READ].devstat);
-                        return -ENOMEM;  
-                }
-                memset(privptr->channel[c].devstat, 0, sizeof(devstat_t));
-
-                if (ctc_no_auto == 0) 
-                         ctc_adapter[m][i].devno[c] = channel_get_next(m);
-                else 
-                         ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
-
-                if ( ctc_adapter[m][i].devno[c] != -ENODEV){
-                         rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]),
-                              (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, 
-                              privptr->channel[c].devstat);
-                         if (rc) { 
-                                 printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
-                                 return -EBUSY;
-                         }
-                } else {        
-                        if (i == WRITE) {
-                                free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat);
-                                channel_free(m, ctc_adapter[m][i].devno[READ]);
-                                kfree(privptr->channel[READ].devstat);
-                        } 
-                        kfree(privptr->channel[i].devstat);
-                        return -ENODEV;
-                }
-        }
-
-        privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
-        privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
-        privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
-        privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
-        privptr->protocol = ctc_adapter[m][i].protocol;
-        channel[m].left = channel[m].left - 2;
-
-        printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
-            dev->name, privptr->channel[READ].devno,   privptr->channel[READ].irq,
-            privptr->channel[WRITE].devno,  privptr->channel[WRITE].irq); 
-
-        dev->mtu             = CTC_DEFAULT_MTU_SIZE;
-        dev->hard_start_xmit = ctc_tx;
-        dev->open            = ctc_open;
-        dev->stop            = ctc_release;
-        dev->get_stats       = ctc_stats;
-        dev->change_mtu      = ctc_change_mtu;
-        dev->hard_header_len = 0;
-        dev->addr_len        = 0;
-        dev->type            = ARPHRD_SLIP;
-        dev->tx_queue_len    = 100;
-        dev_init_buffers(dev);
-        dev->flags           = IFF_POINTOPOINT | IFF_NOARP;   
-
-        return 0;
-} 
-
-
-/*
- *   Interrupt processing 
- *
- */
-
-static void inline ccw_check_return_code (net_device *dev, int return_code)
-{
-        if (return_code != 0) {
-                switch (return_code) {
-                        case -EBUSY:  
-                                printk(KERN_INFO "%s: Busy !\n", dev->name);
-                                break;
-                        case -ENODEV:
-                                printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name);
-                                break;
-                        case -EIO:
-                                printk(KERN_EMERG "%s: Status pending... \n", dev->name);
-                                break;
-                        default:
-                                printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", 
-                                    dev->name, return_code);
-                }
-        }
-} 
-
-
-static void inline ccw_check_unit_check (net_device *dev, char sense)
-{
-#ifdef DEBUG
-        printk(KERN_INFO "%s: Unit Check with sense code: %02x\n",
-            dev->name, sense);
-#endif
-
-        if (sense & 0x40) {
-#ifdef DEBUG
-                if (sense & 0x01) 
-                        printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name);
-                else 
-                        printk(KERN_DEBUG "%s: System reset occurred (remote side)\n", dev->name);
-#endif
-        } else if (sense & 0x20) {
-                if (sense & 0x04)
-                        printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name);
-                else 
-                        printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name);
-        } else if (sense & 0x10) {
-                if (sense & 0x20)
-                        printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name);
-                else 
-                        printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name);
-        }
-
-} 
-
-
-static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
-{
-        int               rc = 0;
-        __u32             parm;
-        __u8              flags = 0x00;
-        struct  channel   *ctc = NULL;
-        struct  ctc_priv  *privptr = NULL;
-        net_device        *dev = NULL;    
-        
-        ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
-                                               {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; 
-
-        devstat_t *devstat = ((devstat_t *)initparm);
-
-        /* Bypass all 'unsolited interrupts' */
-        if (devstat->intparm == 0) {
-#ifdef DEBUG
-                printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
-                    devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
-#endif 
-                /* FIXME - find the related intparm!!! No IO outstanding!!!! */
-                return;
-        }
-
-        ctc = (struct channel *) (devstat->intparm);
-        dev = (net_device *) ctc->dev;
-        privptr = dev->priv;
-
-#ifdef DEBUG
-        printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
-            dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
-#endif 
-
-        /* Check for good subchannel return code, otherwise error message */
-        if (devstat->cstat) {
-                printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", 
-                    dev->name, ctc->devno, devstat->cstat);
-                return;
-        }
-
-
-        /* Check the reason-code of a unit check */
-        if (devstat->dstat & DEV_STAT_UNIT_CHECK)
-                ccw_check_unit_check(dev, devstat->ii.sense.data[0]);
-
-
-        /* State machine to bring the connection up / down and to restart */ 
-
-        ctc->last_dstat = devstat->dstat;
-
-        switch (ctc->state) {   
-
-                case CTC_STOP:           /* HALT_IO issued by ctc_release (halt sequence) */
-                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return;
-                        wake_up(&ctc->wait);   /* wake up ctc_release */
-                        return;
- 
-
-                case CTC_START_HALT_IO:  /* HALT_IO issued by ctc_open (start sequence) */
-                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return;
-
-                        ctc->state = CTC_START_SET_X_MODE;
-                        parm = (__u32) ctc;
-                        rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
-                        if (rc != 0)
-                                ccw_check_return_code(dev, rc);
-                        return;
- 
-        
-                case CTC_START_SET_X_MODE:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) != 0x40) {
-                                        wake_up(&ctc->wait);  /* wake up ctc_open (READ or WRITE) */
-                                        return; 
-                                }        
-                        }
-                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return;
-                        ctc->state =  CTC_START_SELECT;
- 
-
-                case CTC_START_SELECT:
-                        if (!ctc->flag & CTC_WRITE) {
-                                ctc->state = CTC_START_READ_TEST;
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                                parm = (__u32) ctc;
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                if (rc != 0) 
-                                        ccw_check_return_code(dev, rc);
-                                wake_up(&ctc->wait);  /* wake up ctc_open (READ) */
-
-                        } else {
-                                ctc->state = CTC_START_WRITE_TEST;
-                                /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
-                                ctc->ccw[1].count = 0;
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                                parm = (__u32) ctc; 
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
-                                if (rc != 0)
-                                        ccw_check_return_code(dev, rc);
-                        }
-                        return;
-
-
-                case CTC_START_READ_TEST:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
-                                    devstat->ii.sense.data[0] == 0                ) {
-                                        init_timer(&ctc->timer);
-                                        ctc->timer.function = (void *)ctc_read_retry; 
-                                        ctc->timer.data = (__u32)ctc;
-                                        ctc->timer.expires = jiffies + 10*HZ;
-                                        add_timer(&ctc->timer);
-#ifdef DEBUG 
-                                        printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); 
-#endif
-                                }
-                                return;
-                        }
-
-                        if ((devstat->dstat &  ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
-                                if ((devstat->dstat & DEV_STAT_ATTENTION) && 
-                                    (devstat->dstat & DEV_STAT_BUSY)) {
-                                        printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
-                                } 
-                                wake_up(&privptr->channel[WRITE].wait);  /* wake up ctc_open (WRITE) */
-                                return;
-                        }
-
-                        ctc->state = CTC_START_READ;
-                        set_bit(0, (void *)&ctc->IO_active);
-
-                        /* 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: 
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
-                                    devstat->ii.sense.data[0] == 0               ) {
-                                        privptr->stats.rx_errors++;
-					/* Need protection here cos we are in the read irq */
-					/*  handler the tbusy is for the write subchannel */
-					ctc_protect_busy(dev);
-				        ctc_setbit_busy(TB_RETRY,dev);
-					ctc_unprotect_busy(dev);
-				        init_timer(&ctc->timer);
-                                        ctc->timer.function = (void *)ctc_read_retry; 
-                                        ctc->timer.data = (__u32)ctc;
-                                        ctc->timer.expires = jiffies + 30*HZ;
-                                        add_timer(&ctc->timer); 
-                                        printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
-                                }
-                                return;
-                        }
-
-                        if(!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return; 
-			ctc_protect_busy(dev);
-			ctc_clearbit_busy(TB_RETRY,dev);
-			ctc_unprotect_busy(dev);
-                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-
-                        if (ctc->free_anchor != NULL) {  
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                                parm = (__u32) ctc;
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                if (rc != 0) 
-                                        ccw_check_return_code(dev, rc);
-                        } else {
-                                clear_bit(0, (void *)&ctc->IO_active);    
-#ifdef DEBUG
-                                printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
-#endif
-                        }
-                        
-                        if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) {
-                                queue_task(&ctc->tq, &tq_immediate);
-                                mark_bh(IMMEDIATE_BH);
-                        }
-                        return;
-
-
-                case CTC_START_WRITE_TEST:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
-                                    devstat->ii.sense.data[0] == 0                ) {
-                                        init_timer(&ctc->timer);
-                                        ctc->timer.function = (void *)ctc_write_retry; 
-                                        ctc->timer.data = (__u32)ctc;
-                                        ctc->timer.expires = jiffies + 10*HZ;
-                                        add_timer(&ctc->timer);
-#ifdef DEBUG
-                                        printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
-#endif
-                                }
-                                return;
-                        }
-
-                        ctc->state = CTC_START_WRITE;
-                        wake_up(&ctc->wait);  /* wake up ctc_open (WRITE) */
-                        return;
- 
-
-                case CTC_START_WRITE:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                privptr->stats.tx_errors += ctc->proc_anchor->packets;
-#ifdef DEBUG
-                                printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
-#endif
-                        } else { 
-                                if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                        return; 
-                                privptr->stats.tx_packets += ctc->proc_anchor->packets;
-                        } 
-
-                        ctc->proc_anchor->block->length = 0;
-                        ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-                        ctc_clearbit_busy(TB_NOBUFFER,dev);      
-                        if (ctc->proc_anchor != NULL) {  
-#ifdef DEBUG
-                                printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); 
-#endif
-                                ctc->ccw[1].count = ctc->proc_anchor->block->length;
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
-                                parm = (__u32) ctc;
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                if (rc != 0) 
-                                        ccw_check_return_code(dev, rc);
-                                dev->trans_start = jiffies;
-                                return;
-
-                        }
-
-                        if (ctc->free_anchor->block->length != 0) {
-                                if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {     
-                                       /* set transmission to busy */
-                                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-                                        ctc_clearbit_busy(TB_TX,dev);
-#ifdef DEBUG
-                                        printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); 
-#endif
-                                        ctc->ccw[1].count = ctc->proc_anchor->block->length;
-                                        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
-                                        parm = (__u32) ctc;
-                                        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                        if (rc != 0) 
-                                                ccw_check_return_code(dev, rc);
-                                        dev->trans_start = jiffies;
-                                        return;
-                                }
-                        } 
-
-                        clear_bit(0, (void *)&ctc->IO_active);              /* set by ctc_tx or ctc_bh */
-                        return;
-
- 
-                default: 
-                        printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
-                        return;  
-        }
-} 
-
-
-static void ctc_irq_bh (struct channel *ctc)
-{
-        int                rc = 0;
-        __u16              data_len;
-        __u32              parm;
-
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        net_device  *dev;
-        struct ctc_priv    *privptr;             
-        struct packet      *lp;
-        struct sk_buff     *skb;
-
-        dev = (net_device *) ctc->dev; 
-        privptr = (struct ctc_priv *) dev->priv; 
-   
-#ifdef DEBUG
-        printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
-#endif 
-
-        while (ctc->proc_anchor != NULL) { 
-
-                lp = &ctc->proc_anchor->block->data;
-
-                while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
-                        data_len = lp->length - PACKET_HEADER_LENGTH;
-                        skb = dev_alloc_skb(data_len); 
-                        if (skb) { 
-                                memcpy(skb_put(skb, data_len),&lp->data, data_len);
-                                skb->mac.raw = skb->data;
-                                skb->dev = dev;
-                                skb->protocol = htons(ETH_P_IP);
-                                skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
-                                netif_rx(skb);
-                                privptr->stats.rx_packets++;
-                        } else {
-                                privptr->stats.rx_dropped++; 
-                                printk(KERN_WARNING "%s: is low on memory\n",dev->name);
-                        }
-                        (__u8 *)lp += lp->length;
-                }
-
-                s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-
-                if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) {
-#ifdef DEBUG
-                        printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
-#endif 
-                        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                        parm = (__u32) ctc; 
-                        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                        if (rc != 0) 
-                                 ccw_check_return_code(dev, rc);
-                } 
-                s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); 
-        }
-        clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a);
-        return;
-}  
-
-
-static void ctc_read_retry (struct channel *ctc)
-{
-        int                rc = 0;
-        __u32              parm;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        net_device  *dev;
-
-        dev = (net_device *) ctc->dev; 
-   
-#ifdef DEBUG
-        printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
-#endif 
-        s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-        parm = (__u32) ctc; 
-        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-        s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
-        if (rc != 0) 
-                ccw_check_return_code(dev, rc);
-        return;
-}  
- 
-
-static void ctc_write_retry (struct channel *ctc)
-{
-        int                rc = 0;
-        __u32              parm;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        net_device  *dev;
-
-        dev = (net_device *) ctc->dev; 
-   
-#ifdef DEBUG
-        printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
-#endif 
-        s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-        ctc->ccw[1].count = 0;
-        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
-        parm = (__u32) ctc; 
-        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-        s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
-        if (rc != 0) 
-                ccw_check_return_code(dev, rc);
-        return;
-}  
-
-
-
-/*
- *   ctc_open
- *
- */
-static int ctc_open(net_device *dev)
-{
-        int                rc;
-        int                i;
-        int                j;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        __u32              parm;
-        struct ctc_priv    *privptr;
-	DECLARE_WAITQUEUE(wait, current);
-        struct timer_list  timer;
-
-
-        ctc_set_busy(dev);
-
-        privptr = (struct ctc_priv *) (dev->priv);
-        
-        privptr->channel[READ].flag  = 0x00;
-        privptr->channel[WRITE].flag = CTC_WRITE;
-
-        for (i = 0; i < 2;  i++) { 
-                for (j = 0; j < CTC_BLOCKS;  j++) { 
-                        rc = ctc_buffer_alloc(&privptr->channel[i]);
-                        if (rc != 0)
-                                return -ENOMEM;
-                }
-                init_waitqueue_head(&privptr->channel[i].wait);
-                INIT_LIST_HEAD(&privptr->channel[i].tq.list);
-                privptr->channel[i].tq.sync = 0;
-                privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh;
-                privptr->channel[i].tq.data = &privptr->channel[i]; 
-
-                privptr->channel[i].dev = dev;
-                
-                privptr->channel[i].flag_a = 0;
-                privptr->channel[i].IO_active = 0;
-
-                privptr->channel[i].ccw[0].cmd_code  = CCW_CMD_PREPARE;
-                privptr->channel[i].ccw[0].flags     = CCW_FLAG_SLI | CCW_FLAG_CC;
-                privptr->channel[i].ccw[0].count     = 0;
-                privptr->channel[i].ccw[0].cda       = NULL;
-                if (i == READ) {  
-                        privptr->channel[i].ccw[1].cmd_code  = CCW_CMD_READ;
-                        privptr->channel[i].ccw[1].flags     = CCW_FLAG_SLI;
-                        privptr->channel[i].ccw[1].count     = 0xffff;   /* MAX size */
-                        privptr->channel[i].ccw[1].cda       = NULL;
-                } else {
-                        privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
-                        privptr->channel[i].ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-                        privptr->channel[i].ccw[1].count    = 0;
-                        privptr->channel[i].ccw[1].cda      = NULL;
-                }
-                privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP;      /* jointed CE+DE */
-                privptr->channel[i].ccw[2].flags    = CCW_FLAG_SLI;
-                privptr->channel[i].ccw[2].count    = 0;
-                privptr->channel[i].ccw[2].cda      = NULL;
-                
-                privptr->channel[i].flag  &= ~CTC_TIMER;
-                init_timer(&timer);
-                timer.function = (void *)ctc_timer; 
-                timer.data = (__u32)&privptr->channel[i];
-                timer.expires = jiffies + 150*HZ;                        /* time to connect with the remote side */
-                add_timer(&timer);
-
-                s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
-                parm = (unsigned long) &privptr->channel[i]; 
-                privptr->channel[i].state = CTC_START_HALT_IO;
-                rc = halt_IO(privptr->channel[i].irq, parm, flags);
-                add_wait_queue(&privptr->channel[i].wait, &wait);
-                current->state = TASK_INTERRUPTIBLE;
-                s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
-                schedule();
-                remove_wait_queue(&privptr->channel[i].wait, &wait);
-                if(rc != 0)
-                        ccw_check_return_code(dev, rc);
-                if((privptr->channel[i].flag & CTC_TIMER) == 0x00)
-                        del_timer(&timer);
-        }
-
-        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)) {
-#ifdef DEBUG
-                printk(KERN_DEBUG "%s: channel problems during open - read: %02x -  write: %02x\n",
-                    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
-#endif 
-                printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
-                
-                for (i = 0; i < 2;  i++) {
-                        s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
-                        parm = (unsigned long) &privptr->channel[i];
-                        privptr->channel[i].state = CTC_STOP;
-                        rc = halt_IO(privptr->channel[i].irq, parm, flags);
-                        s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
-                        if (rc != 0)
-                                ccw_check_return_code(dev, rc);
-                        for (j = 0; j < CTC_BLOCKS;  j++) 
-                                ctc_buffer_free(&privptr->channel[i]);
-                }
-                return -EIO;
-        }
-
-        printk(KERN_INFO "%s: connected with remote side\n",dev->name);
-        ctc_clear_busy(dev);
-        return 0;
-}
-
-
-static void ctc_timer (struct channel *ctc)
-{
-#ifdef DEBUG
-        net_device  *dev;
-
-        dev = (net_device *) ctc->dev; 
-        printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
-#endif
-        ctc->flag |= CTC_TIMER;
-        wake_up(&ctc->wait);  
-        return;
-}  
-
-/*
- *   ctc_release 
- *
- */
-static int ctc_release(net_device *dev)
-{   
-        int                rc;
-        int                i;
-        int                j;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        __u32              parm;
-        struct ctc_priv    *privptr;
-	DECLARE_WAITQUEUE(wait, current);
-
-        privptr = (struct ctc_priv *) dev->priv;  
-   
-	ctc_protect_busy_irqsave(dev,saveflags);
-        ctc_setbit_busy(TB_STOP,dev);    
-	ctc_unprotect_busy_irqrestore(dev,flags);
-        for (i = 0; i < 2;  i++) {
-                s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
-                privptr->channel[i].state = CTC_STOP;
-                parm = (__u32) &privptr->channel[i]; 
-                rc = halt_IO (privptr->channel[i].irq, parm, flags );
-                add_wait_queue(&privptr->channel[i].wait, &wait);
-                current->state = TASK_INTERRUPTIBLE;
-                s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); 
-                schedule();
-                remove_wait_queue(&privptr->channel[i].wait, &wait);
-                if (rc != 0) {
-                        ccw_check_return_code(dev, rc);
-                }
-                 
-                for (j = 0; j < CTC_BLOCKS;  j++) {  
-                        ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor);
-                        ctc_buffer_free(&privptr->channel[i]); 
-                }
-        }
-
-        if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
-            ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
-                printk(KERN_WARNING "%s: channel problems during close - read: %02x -  write: %02x\n",
-                    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
-                return -EIO;
-        }
-
-        return 0;
-}  
-
-
-/*
- *   ctc_tx 
- *
- *
- */
-static int ctc_tx(struct sk_buff *skb, net_device *dev)
-{
-        int                rc=0,rc2;
-        __u32              parm;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        struct ctc_priv    *privptr;
-        struct packet      *lp;
-
-   
-        privptr = (struct ctc_priv *) (dev->priv);
-
-        if (skb == NULL) { 
-                printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
-                privptr->stats.tx_dropped++;
-                return -EIO;
-        }
-        
-        s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
-        if (ctc_check_busy(dev)) {
-                rc=-EBUSY;
-		goto Done;
-        } 
-
-        if (ctc_test_and_setbit_busy(TB_TX,dev)) {                /* set transmission to busy */
-                rc=-EBUSY;
-		goto Done;
-        } 
-
-        if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) {
-#ifdef DEBUG
-                printk(KERN_DEBUG "%s: early swap\n", dev->name);
-#endif
-               
-                ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor);
-                if (privptr->channel[WRITE].free_anchor == NULL){
-                        ctc_setbit_busy(TB_NOBUFFER,dev);
-                        rc=-EBUSY;
-			goto Done2;
-                }
-        }
-        
-        if (privptr->channel[WRITE].free_anchor->block->length == 0) {
-                privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; 
-                privptr->channel[WRITE].free_anchor->packets = 0;
-        } 
-
-
-        (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + 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; 
-        lp->type = 0x0800; 
-        lp->unused = 0;
-        memcpy(&lp->data, skb->data, skb->len); 
-        (__u8 *) lp += lp->length; 
-        lp->length = 0;
-        dev_kfree_skb(skb);
-        privptr->channel[WRITE].free_anchor->packets++;
-
-        if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) {
-	       ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor); 
-                privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
-                privptr->channel[WRITE].ccw[1].cda   = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block);
-                parm = (__u32) &privptr->channel[WRITE];  
-                rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
-                if (rc2 != 0) 
-                        ccw_check_return_code(dev, rc2);
-                dev->trans_start = jiffies;
-        }
-        if (privptr->channel[WRITE].free_anchor == NULL)
-                ctc_setbit_busy(TB_NOBUFFER,dev);
-Done2:
-        ctc_clearbit_busy(TB_TX,dev);
-Done:
-	s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
-        return(rc);
-} 
-
-
-/*
- *   ctc_change_mtu 
- *
- *   S/390 can handle MTU sizes from 576 to 32760 for VM, VSE
- *                                   576 to 65527 for OS/390
- *
- */
-static int ctc_change_mtu(net_device *dev, int new_mtu)
-{
-        if ((new_mtu < 576) || (new_mtu > 65528))
-                return -EINVAL;
-        dev->mtu = new_mtu;
-        return 0;
-}
-
-
-/*
- *   ctc_stats
- *
- */
-struct net_device_stats *ctc_stats(net_device *dev)
-{
-         struct ctc_priv *privptr;
-   
-         privptr = dev->priv;
-         return &privptr->stats;
-}  
-
-
-/* Module code goes here */
-
-/*
-                free_irq(privptr->channel[i].irq, privptr->channel[i].devstat);
-                kfree(privptr->channel[i].devstat); 
-
-*/
-/* --- This is the END my friend --- */
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctcmain.c linux/drivers/s390/net/ctcmain.c
--- v2.4.3/linux/drivers/s390/net/ctcmain.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/net/ctcmain.c	Wed Apr 18 14:40:07 2001
@@ -1,12 +1,12 @@
 /*
- * $Id: ctcmain.c,v 1.11 2000/12/15 19:34:54 bird Exp $
+ * $Id: ctcmain.c,v 1.17 2001/01/23 14:23:51 felfert Exp $
  *
  * CTC / ESCON network driver
  *
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
- * 	      Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
  * Documentation used:
  *  - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -36,6 +36,26 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: ctcmain.c,v $
+ * Revision 1.17  2001/01/23 14:23:51  felfert
+ * Added ctc based tty.
+ *
+ * Revision 1.16  2001/01/18 16:10:53  felfert
+ * Added fixes by acme@conectiva.com.br.
+ *
+ * Revision 1.15  2001/01/12 15:40:11  felfert
+ * Fixed ITPM# PL030052IME (Unitchecks when using real escon).
+ *
+ * Revision 1.14  2001/01/11 17:43:52  felfert
+ * Fixed ITPM# PL030051IME (Initialization of escon).
+ *
+ * Revision 1.13  2001/01/11 16:40:26  smolinsk
+ * resolved name space conflict with LVM and renamed
+ *  dev_info_t to s390_dev_info_t
+ * worked around a bug in OSA microcode by stepping back to 2k IDALS in idals.c
+ *
+ * Revision 1.12  2000/12/27 09:40:45  tonn
+ * upgrade to test12
+ *
  * Revision 1.11  2000/12/15 19:34:54  bird
  * struct ctc_priv_t: set type of tbusy to "unsigned long"
  *
@@ -89,8 +109,6 @@
 #include <linux/string.h>
 #include <linux/proc_fs.h>
 
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
 #include <linux/tcp.h>
@@ -112,6 +130,7 @@
 
 #include <asm/irq.h>
 
+#include "ctctty.h"
 #include "fsm.h"
 
 #ifdef MODULE
@@ -142,7 +161,8 @@
 
 #define CTC_PROTO_S390          0
 #define CTC_PROTO_LINUX         1
-#define CTC_PROTO_MAX           1
+#define CTC_PROTO_LINUX_TTY     2
+#define CTC_PROTO_MAX           2
 
 #define CTC_BUFSIZE_LIMIT       65535
 #define CTC_BUFSIZE_DEFAULT     32768
@@ -186,19 +206,13 @@
 
 typedef enum channel_types channel_type_t;
 
-static int ctc_no_auto;
+static int ctc_no_auto = 0;
 
 /**
  * If running on 64 bit, this must be changed. XXX Why? (bird)
  */
 typedef unsigned long intparm_t;
 
-#if LINUX_VERSION_CODE < 0x020300
-typedef struct device      net_device;
-#else
-typedef struct net_device  net_device;
-#endif
-
 /**
  * Definition of a per device parameter block
  */
@@ -211,7 +225,7 @@
 	char           name[MAX_PARAM_NAME_LEN];
 } param;
 
-static param *params;
+static param *params = NULL;
 
 typedef struct {
 	unsigned long maxmulti;
@@ -248,7 +262,7 @@
 	__u32               flags;
 
 	/**
-	 * The protocol of this channel (currently always 0)
+	 * The protocol of this channel
 	 */
 	__u16               protocol;
 
@@ -342,7 +356,7 @@
 /**
  * Linked list of all detected channels.
  */
-static channel *channels;
+static channel *channels = NULL;
 
 typedef struct ctc_priv_t {
 	struct net_device_stats stats;
@@ -353,6 +367,10 @@
 	 * The finite state machine of this interface.
 	 */
 	fsm_instance            *fsm;
+	/**
+	 * The protocol of this device
+	 */
+	__u16                   protocol;
 	channel                 *channel[2];
 	struct proc_dir_entry   *proc_dentry;
 	struct proc_dir_entry   *proc_stat_entry;
@@ -406,8 +424,8 @@
  * Print Banner.
  */
 static void print_banner(void) {
-	static int printed;
-	char vbuf[] = "$Revision: 1.11 $";
+	static int printed = 0;
+	char vbuf[] = "$Revision: 1.17 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -796,7 +814,10 @@
 					dev_kfree_skb(skb);
 					goto again;
 				}
-				netif_rx(skb2);
+				if (ch->protocol == CTC_PROTO_LINUX_TTY)
+					ctc_tty_netif_rx(skb2);
+				else
+					netif_rx(skb2);
 				privptr->stats.rx_packets++;
 				privptr->stats.rx_bytes += skb2->len;
 				/**
@@ -805,7 +826,10 @@
 				skb_pull(skb, header->length);
 				skb_put(skb, LL_HEADER_LENGTH);
 			} else {
-				netif_rx(skb);
+				if (ch->protocol == CTC_PROTO_LINUX_TTY)
+					ctc_tty_netif_rx(skb);
+				else
+					netif_rx(skb);
 				privptr->stats.rx_packets++;
 				privptr->stats.rx_bytes += skb->len;
 			}
@@ -892,8 +916,10 @@
 			       ch->devno);
 			fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch);
 		}
+	} else if (sense & SNS0_CMD_REJECT) {
+			printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno);
 	} else if (sense == 0) {
-		printk(KERN_DEBUG "ch-%04x: Unit check\n", ch->devno);
+		printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno);
 		fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch);
 	} else {
 		printk(KERN_WARNING
@@ -1078,15 +1104,15 @@
 
 	fsm_deltimer(&ch->timer);
 	if (len < 8) {
-		printk(KERN_WARNING "%s: got packet with length < 8\n",
-		       dev->name);
+		printk(KERN_WARNING "%s: got packet with length %d < 8\n",
+		       dev->name, len);
 		privptr->stats.rx_dropped++;
 		privptr->stats.rx_length_errors++;
 		goto again;
 	}
 	if (len > ch->max_bufsize) {
-		printk(KERN_WARNING "%s: got packet with length > %d\n",
-		       dev->name, ch->max_bufsize);
+		printk(KERN_WARNING "%s: got packet with length %d > %d\n",
+		       dev->name, len, ch->max_bufsize);
 		privptr->stats.rx_dropped++;
 		privptr->stats.rx_length_errors++;
 		goto again;
@@ -1764,14 +1790,18 @@
 	channel **c = &channels;
 	channel *ch;
 	char name[10];
-	int ret = -1;
 
-	if ((ch = (channel *)kmalloc(sizeof(channel), GFP_KERNEL)) == NULL)
-		goto out;
+	if ((ch = (channel *)kmalloc(sizeof(channel), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
+		return -1;
+	}
 	memset(ch, 0, sizeof(channel));
 	if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 5,
-					 GFP_KERNEL|GFP_DMA)) == NULL)
-		goto out_ch;
+					 GFP_KERNEL|GFP_DMA)) == NULL) {
+		kfree(ch);
+		printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
+		return -1;
+	}
 
 	/**
 	 * "static" ccws are used in the following way:
@@ -1804,12 +1834,19 @@
 	ch->fsm = init_fsm(name, ch_state_names,
 			ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
 			ch_fsm, CH_FSM_LEN, GFP_KERNEL);
-	if (ch->fsm == NULL)
-		goto out_ccw;
+	if (ch->fsm == NULL) {
+		printk(KERN_WARNING "ctc: Could not create FSM in add_channel\n");
+		kfree(ch);
+		return -1;
+	}
 	fsm_newstate(ch->fsm, CH_STATE_IDLE);
 	if ((ch->devstat = (devstat_t*)kmalloc(sizeof(devstat_t), GFP_KERNEL))
-	    == NULL)
-		goto out_ccw;
+	    == NULL) {
+		printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
+		kfree_fsm(ch->fsm);
+		kfree(ch);
+		return -1;
+	}
 	memset(ch->devstat, 0, sizeof(devstat_t));
 	while (*c && ((*c)->devno < devno))
 		c = &(*c)->next;
@@ -1817,8 +1854,10 @@
 		printk(KERN_DEBUG
 		       "ctc: add_channel: device %04x already in list\n",
 		       (*c)->devno);
-		ret = 0;
-		goto out_devstat;
+		kfree(ch->devstat);
+		kfree_fsm(ch->fsm);
+		kfree(ch);
+		return 0;
 	}
 	fsm_settimer(ch->fsm, &ch->timer);
 	skb_queue_head_init(&ch->io_queue);
@@ -1826,16 +1865,6 @@
 	ch->next = *c;
 	*c = ch;
 	return 0;
-out_devstat:
-	kfree(ch->devstat);
-out_ccw:
-	kfree(ch->ccw);
-out_ch:
-	kfree(ch);
-out:
-	if (ret)
-		printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
-	return ret;
 }
 
 /**
@@ -1846,9 +1875,9 @@
  */
 static void channel_scan(int print_result)
 {
-	int	   irq;
-	int        nr_escon = 0;
-	int        nr_ctca  = 0;
+	int	        irq;
+	int             nr_escon = 0;
+	int             nr_ctca  = 0;
 	s390_dev_info_t di;
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
@@ -2284,6 +2313,8 @@
 	if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
 		int l = skb->len + LL_HEADER_LENGTH;
 
+		if (ch->type == channel_type_escon)
+			return -EBUSY;
 		spin_lock_irqsave(&ch->collect_lock, saveflags);
 		if (ch->collect_len + l > ch->max_bufsize - 2)
 			rc = -EBUSY;
@@ -3141,7 +3172,7 @@
  *
  * @param dev Pointer to net_device to be initialized.
  *
- * @return 0 on success, !0 on failure.
+ * @returns 0 on success, !0 on failure.
  */
 int ctc_probe(net_device *dev)
 {
@@ -3190,6 +3221,7 @@
 		return -ENOMEM;
 	memset(dev->priv, 0, sizeof(ctc_priv));
 	privptr = (ctc_priv *)dev->priv;
+	privptr->protocol = proto;
         privptr->proc_dentry = (struct proc_dir_entry *)
 		(((char *)privptr) + sizeof(ctc_priv));
         privptr->proc_stat_entry = (struct proc_dir_entry *)
@@ -3220,7 +3252,6 @@
 	dev->type                = ARPHRD_SLIP;
 	dev->tx_queue_len        = 100;
 	SET_DEVICE_START(dev, 1);
-	dev_init_buffers(dev);
 	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
 	for (direction = READ; direction <= WRITE; direction++) {
 		if ((ctc_no_auto == 0) || (devno[direction] == -1))
@@ -3295,6 +3326,7 @@
 void cleanup_module(void) {
 	channel *c = channels;
 
+	ctc_tty_cleanup();
 	/* we are called if all interfaces are down only, so no need
 	 * to bother around with locking stuff
 	 */
@@ -3313,7 +3345,10 @@
 				 privptr->channel[WRITE]->devstat);
 			kfree_fsm(privptr->channel[READ]->fsm);
 			kfree_fsm(privptr->channel[WRITE]->fsm);
-			unregister_netdev(nd);
+			if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+				unregister_netdev(nd);
+			else
+				ctc_tty_unregister_netdev(nd);
 			kfree_fsm(privptr->fsm);
 			privptr->channel[READ]->netdev = NULL;
 			privptr->channel[WRITE]->netdev = NULL;
@@ -3345,6 +3380,7 @@
 	int   cnt[2];
 	int   itype;
 	int   activated;
+	int   ret = 0;
 	param *par;
 
 	print_banner();
@@ -3359,10 +3395,11 @@
 #endif
 	activated = 0;
 	par = params;
+	ctc_tty_init();
 	for (itype = 0; itype < 2; itype++) {
 		net_device *dev = NULL;
 		char       *bname = (itype) ? "escon" : "ctc";
-		int        nlen = strlen(bname);
+
 		cnt[itype] = 0;
 		do {
 			dev = kmalloc(sizeof(net_device)
@@ -3370,8 +3407,10 @@
 				      + 11 /* name + zero */
 #endif
 				      , GFP_KERNEL);
-			if (!dev)
-				return -ENOMEM;
+			if (!dev) {
+				ret = -ENOMEM;
+				break;
+			}
 			memset(dev, 0, sizeof(net_device));
 #if LINUX_VERSION_CODE < 0x020300
 			dev->name = (unsigned char *)dev + sizeof(net_device);
@@ -3386,10 +3425,10 @@
 					if (isdigit(*p))
 						break;
 				if (p && *p) {
+					int it = (strncmp(dev->name, "escon", 5)) ? 1 : 0;
 					n = simple_strtoul(p, NULL, 0);
-					if (n >= cnt[itype] &&
-					    (!strncmp(par->name, bname, nlen)))
-						cnt[itype] = n + 1;
+					if (n >= cnt[it])
+						cnt[it] = n + 1;
 				}
 			} else {
 				if (ctc_no_auto) {
@@ -3406,6 +3445,7 @@
 						 __FUNCTION__, dev->name);
 #endif			
 			if (ctc_probe(dev) == 0) {
+				ctc_priv *privptr = (ctc_priv *)dev->priv;
 #ifdef DEBUG
 				printk(KERN_DEBUG
 				       "ctc: %s(): probing succeeded\n",
@@ -3413,28 +3453,49 @@
 				printk(KERN_DEBUG
 				       "ctc: %s(): registering device %s\n",
 				       __FUNCTION__, dev->name);
+#endif
+				if (privptr->protocol != CTC_PROTO_LINUX_TTY) {
+					if (register_netdev(dev) != 0) {
+						printk(KERN_WARNING
+						       "ctc: Couldn't register netdev %s\n",
+						       dev->name);
+						free_irq(privptr->channel[READ]->irq,
+							 privptr->channel[READ]->devstat);
+						free_irq(privptr->channel[WRITE]->irq,
+							 privptr->channel[WRITE]->devstat);
+						channel_free(privptr->channel[READ]);
+						channel_free(privptr->channel[WRITE]);
+						kfree(dev->priv);
+						kfree(dev);
+					} else {
+#ifdef DEBUG
+						printk(KERN_DEBUG
+						       "ctc: %s(): register succeed\n",
+						       __FUNCTION__);
 #endif			
-				if (register_netdev(dev) != 0) {
-					ctc_priv *privptr =
-						(ctc_priv *)dev->priv;
-					printk(KERN_WARNING
-					       "ctc: Couldn't register %s\n",
-					       dev->name);
-					free_irq(privptr->channel[READ]->irq,
-						 privptr->channel[READ]->devstat);
-					free_irq(privptr->channel[WRITE]->irq,
-						 privptr->channel[WRITE]->devstat);
-					channel_free(privptr->channel[READ]);
-					channel_free(privptr->channel[WRITE]);
-					kfree(dev->priv);
-					kfree(dev);
+						activated++;
+					}
 				} else {
+					if (ctc_tty_register_netdev(dev) != 0) {
+						printk(KERN_WARNING
+						       "ctc: Couldn't register ttydev %s\n",
+						       dev->name);
+						free_irq(privptr->channel[READ]->irq,
+							 privptr->channel[READ]->devstat);
+						free_irq(privptr->channel[WRITE]->irq,
+							 privptr->channel[WRITE]->devstat);
+						channel_free(privptr->channel[READ]);
+						channel_free(privptr->channel[WRITE]);
+						kfree(dev->priv);
+						kfree(dev);
+					} else {
 #ifdef DEBUG
-					printk(KERN_DEBUG
-					       "ctc: %s(): register succeed\n",
-					       __FUNCTION__);
+						printk(KERN_DEBUG
+						       "ctc: %s(): register succeed\n",
+						       __FUNCTION__);
 #endif			
-					activated++;
+						activated++;
+					}
 				}
 				
 			} else {
@@ -3446,13 +3507,15 @@
 				kfree(dev);
 				dev = NULL;
 			}
-		} while (dev);
+		} while (dev && (ret == 0));
 	}
 	if (!activated) {
 		printk(KERN_WARNING "ctc: No devices registered\n");
-		return -ENODEV;
+		ret = -ENODEV;
 	}
-	return 0;
+	if (ret)
+		ctc_tty_cleanup();
+	return ret;
 }
 
 #ifndef MODULE
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctctty.c linux/drivers/s390/net/ctctty.c
--- v2.4.3/linux/drivers/s390/net/ctctty.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/net/ctctty.c	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,1139 @@
+/*
+ * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $
+ *
+ * CTC / ESCON network driver, tty interface.
+ *
+ * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.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, 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/tty.h>
+#include <linux/serial_reg.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_DEVFS_FS
+#  include <linux/devfs_fs_kernel.h>
+#endif
+#include "ctctty.h"
+#include <net/dst.h>
+
+#define CTC_TTY_MAJOR       43
+#define CTC_TTY_MAX_DEVICES 64
+
+#define CTC_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */
+#define CTC_ASYNC_INITIALIZED    0x80000000 /* port was initialized         */
+#define CTC_ASYNC_NORMAL_ACTIVE  0x20000000 /* Normal device active         */
+#define CTC_ASYNC_CLOSING        0x08000000 /* Serial port is closing       */
+#define CTC_ASYNC_CTS_FLOW       0x04000000 /* Do CTS flow control          */
+#define CTC_ASYNC_CHECK_CD       0x02000000 /* i.e., CLOCAL                 */
+#define CTC_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */
+#define CTC_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
+#define CTC_TTY_XMIT_SIZE              1024 /* Default bufsize for write    */
+#define CTC_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
+#define CTC_SERIAL_TYPE_NORMAL            1
+
+/* Private data (similar to async_struct in <linux/serial.h>) */
+typedef struct {
+  int			magic;
+  int			flags;		 /* defined in tty.h               */
+  int			x_char;		 /* xon/xoff character             */
+  int			mcr;		 /* Modem control register         */
+  int                   msr;             /* Modem status register          */
+  int                   lsr;             /* Line status register           */
+  int			line;
+  int			count;		 /* # of fd on device              */
+  int			blocked_open;	 /* # of blocked opens             */
+	net_device            *netdev;
+  struct sk_buff_head   tx_queue;        /* transmit queue                 */
+  struct sk_buff_head   rx_queue;        /* receive queue                  */
+  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
+  struct termios	normal_termios;  /* For saving termios structs     */
+  wait_queue_head_t	open_wait;
+  wait_queue_head_t	close_wait;
+  struct semaphore      write_sem;
+	struct tq_struct tq;
+} ctc_tty_info;
+
+/* Description of one CTC-tty */
+typedef struct {
+  int                refcount;			   /* Number of opens        */
+  struct tty_driver  ctc_tty_device;		   /* tty-device             */
+  struct tty_struct  *modem_table[CTC_TTY_MAX_DEVICES];
+  struct termios     *modem_termios[CTC_TTY_MAX_DEVICES];
+  struct termios     *modem_termios_locked[CTC_TTY_MAX_DEVICES];
+  ctc_tty_info       info[CTC_TTY_MAX_DEVICES];	   /* Private data           */
+} ctc_tty_driver;
+
+static ctc_tty_driver *driver;
+
+/* Leave this unchanged unless you know what you do! */
+#define MODEM_PARANOIA_CHECK
+#define MODEM_DO_RESTART
+
+#define CTC_TTY_NAME "ttyZ"
+
+#ifdef CONFIG_DEVFS_FS
+static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";
+#else
+static char *ctc_ttyname = CTC_TTY_NAME;
+#endif
+
+char *ctc_tty_revision = "$Revision: 1.1 $";
+
+/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
+ * to stuff incoming data directly into a tty's flip-buffer. If the
+ * flip buffer is full, the packet gets queued up.
+ *
+ * Return:
+ *  1 = Success
+ *  0 = Failure, data has to be buffered and later processed by
+ *      ctc_tty_readmodem().
+ */
+static int
+ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
+{
+	int c;
+	int len;
+	struct tty_struct *tty;
+
+	if ((tty = info->tty)) {
+		if (info->mcr & UART_MCR_RTS) {
+			c = TTY_FLIPBUF_SIZE - tty->flip.count;
+			len = skb->len;
+			if (c >= len) {
+				memcpy(tty->flip.char_buf_ptr, skb->data, len);
+				tty->flip.count += len;
+				tty->flip.char_buf_ptr += len;
+				memset(tty->flip.flag_buf_ptr, 0, len);
+				tty->flip.flag_buf_ptr += len;
+				queue_task(&tty->flip.tqueue, &tq_timer);
+				kfree_skb(skb);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/* ctc_tty_readmodem() is called periodically from within timer-interrupt.
+ * It tries getting received data from the receive queue an stuff it into
+ * the tty's flip-buffer.
+ */
+static int
+ctc_tty_readmodem(ctc_tty_info *info)
+{
+	int ret = 0;
+	struct tty_struct *tty;
+
+	if ((tty = info->tty)) {
+		if (info->mcr & UART_MCR_RTS) {
+			int c = TTY_FLIPBUF_SIZE - tty->flip.count;
+			struct sk_buff *skb;
+			
+			if ((c > 0) && (skb = skb_dequeue(&info->rx_queue))) {
+				int len = skb->len;
+				if (len > c)
+					len = c;
+				memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len);
+				tty->flip.count += len;
+				memset(tty->flip.flag_buf_ptr, 0, len);
+				tty->flip.flag_buf_ptr += len;
+				queue_task(&tty->flip.tqueue, &tq_timer);
+				if (skb->len) {
+					skb_queue_head(&info->rx_queue, skb);
+					ret = 1;
+				} else
+					kfree_skb(skb);
+			}
+		}
+	}
+	return ret;
+}
+
+void
+ctc_tty_netif_rx(struct sk_buff *skb)
+{
+	int i;
+	ctc_tty_info *info = NULL;
+
+	if (!skb)
+		return;
+	if (!skb->dev) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+		if (driver->info[i].netdev == skb->dev) {
+			info = &driver->info[i];
+			break;
+		}
+	if (!info) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	skb_pull(skb, sizeof(int));
+	/* Try to deliver directly via tty-flip-buf if queue is empty */
+	if (skb_queue_empty(&info->rx_queue))
+		if (ctc_tty_try_read(info, skb))
+			return;
+	/* Direct deliver failed or queue wasn't empty.
+	 * Queue up for later dequeueing via timer-irq.
+	 */
+	skb_queue_tail(&info->rx_queue, skb);
+	/* Schedule dequeuing */
+	queue_task(&info->tq, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
+ctc_tty_dstfail(struct sk_buff *skb) {
+	if (!skb)
+		return;
+	dev_kfree_skb(skb);
+	return;
+}
+
+static struct dst_entry dst_e;
+static struct dst_ops   dst_o;
+
+static int
+ctc_tty_tint(ctc_tty_info * info)
+{
+	struct sk_buff *skb = skb_dequeue(&info->tx_queue);
+	int rc;
+	int l;
+	char c;
+
+	if (!skb)
+		return 0;
+	if (!info->netdev) {
+		kfree(skb);
+		return 0;
+	}
+	skb->dst = &dst_e;
+	l = skb->len;
+	c = *(skb->data);
+	rc = info->netdev->hard_start_xmit(skb, info->netdev);
+printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c);
+	if (rc) {
+		skb_queue_head(&info->tx_queue, skb);
+		return 1;
+	} else {
+		struct tty_struct *tty = info->tty;
+		info->lsr |= UART_LSR_TEMT;
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+	return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
+}
+
+/************************************************************
+ *
+ * Modem-functions
+ *
+ * mostly "stolen" from original Linux-serial.c and friends.
+ *
+ ************************************************************/
+
+static inline int
+ctc_tty_paranoia_check(ctc_tty_info * info, kdev_t device, const char *routine)
+{
+#ifdef MODEM_PARANOIA_CHECK
+	if (!info) {
+		printk(KERN_WARNING "ctc_tty: null info_struct for (%d, %d) in %s\n",
+		       MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+	if (info->magic != CTC_ASYNC_MAGIC) {
+		printk(KERN_WARNING "ctc_tty: bad magic for info struct (%d, %d) in %s\n",
+		       MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+static void
+ctc_tty_change_speed(ctc_tty_info * info)
+{
+	unsigned int cflag;
+	unsigned int quot;
+	int i;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+
+	quot = i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i < 1 || i > 2)
+			info->tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			i += 15;
+	}
+	if (quot) {
+		info->mcr |= UART_MCR_DTR;
+	} else {
+		info->mcr &= ~UART_MCR_DTR;
+		return;
+	}
+
+	/* CTS flow control flag and modem status interrupts */
+	if (cflag & CRTSCTS) {
+		info->flags |= CTC_ASYNC_CTS_FLOW;
+	} else
+		info->flags &= ~CTC_ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~CTC_ASYNC_CHECK_CD;
+	else {
+		info->flags |= CTC_ASYNC_CHECK_CD;
+	}
+}
+
+static int
+ctc_tty_startup(ctc_tty_info * info)
+{
+	if (info->flags & CTC_ASYNC_INITIALIZED)
+		return 0;
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "starting up %s%d ...\n", CTC_TTY_NAME, info->line);
+#endif
+	/*
+	 * Now, initialize the UART
+	 */
+	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	/*
+	 * and set the speed of the serial port
+	 */
+	ctc_tty_change_speed(info);
+
+	info->flags |= CTC_ASYNC_INITIALIZED;
+	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
+	info->netdev->open(info->netdev);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void
+ctc_tty_shutdown(ctc_tty_info * info)
+{
+	if (!(info->flags & CTC_ASYNC_INITIALIZED))
+		return;
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
+#endif
+	info->msr &= ~UART_MSR_RI;
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
+	}
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->netdev->stop(info->netdev);
+	skb_queue_purge(&info->tx_queue);
+	skb_queue_purge(&info->rx_queue);
+	info->flags &= ~CTC_ASYNC_INITIALIZED;
+}
+
+/* ctc_tty_write() is the main send-routine. It is called from the upper
+ * levels within the kernel to perform sending data. Depending on the
+ * online-flag it either directs output to the at-command-interpreter or
+ * to the lower level. Additional tasks done here:
+ *  - If online, check for escape-sequence (+++)
+ *  - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes.
+ *  - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed.
+ *  - If dialing, abort dial.
+ */
+static int
+ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
+{
+	int c;
+	int total = 0;
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write"))
+		return 0;
+	if (!tty)
+		return 0;
+	if (!info->netdev)
+		return -ENODEV;
+	if (from_user)
+		down(&info->write_sem);
+	while (1) {
+		struct sk_buff *skb;
+		int skb_res;
+
+		c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE;
+		if (c <= 0)
+			break;
+		
+		skb_res = info->netdev->hard_header_len + sizeof(int);
+		skb = dev_alloc_skb(skb_res + c);
+		if (!skb) {
+			printk(KERN_WARNING
+			       "ctc_tty: Out of memory in %s%d write\n",
+			       CTC_TTY_NAME, info->line);
+			break;
+		}
+		skb_reserve(skb, skb_res);
+		if (from_user)
+			copy_from_user(skb_put(skb, c), buf, c);
+		else
+			memcpy(skb_put(skb, c), buf, c);
+		skb_queue_tail(&info->tx_queue, skb);
+		buf += c;
+		total += c;
+		count -= c;
+	}
+	if (skb_queue_len(&info->tx_queue)) {
+		queue_task(&info->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+	if (from_user)
+		up(&info->write_sem);
+	return total;
+}
+
+static int
+ctc_tty_write_room(struct tty_struct *tty)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write_room"))
+		return 0;
+	return CTC_TTY_XMIT_SIZE;
+}
+
+static int
+ctc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_chars_in_buffer"))
+		return 0;
+	return 0;
+}
+
+static void
+ctc_tty_flush_buffer(struct tty_struct *tty)
+{
+	ctc_tty_info *info;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (!tty) {
+		restore_flags(flags);
+		return;
+	}
+	info = (ctc_tty_info *) tty->driver_data;
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_buffer")) {
+		restore_flags(flags);
+		return;
+	}
+	skb_queue_purge(&info->tx_queue);
+	restore_flags(flags);
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup) (tty);
+}
+
+static void
+ctc_tty_flush_chars(struct tty_struct *tty)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars"))
+		return;
+	if (skb_queue_len(&info->tx_queue)) {
+		queue_task(&info->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * ctc_tty_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+ctc_tty_throttle(struct tty_struct *tty)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle"))
+		return;
+	if (I_IXOFF(tty))
+		info->x_char = STOP_CHAR(tty);
+	info->mcr &= ~UART_MCR_RTS;
+}
+
+static void
+ctc_tty_unthrottle(struct tty_struct *tty)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle"))
+		return;
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			info->x_char = START_CHAR(tty);
+	}
+	info->mcr |= UART_MCR_RTS;
+}
+
+/*
+ * ------------------------------------------------------------
+ * ctc_tty_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+/*
+ * ctc_tty_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *          is emptied.  On bus types like RS485, the transmitter must
+ *          release the bus after transmitting. This must be done when
+ *          the transmit shift register is empty, not be done when the
+ *          transmit holding register is empty.  This functionality
+ *          allows RS485 driver to be written in user space.
+ */
+static int
+ctc_tty_get_lsr_info(ctc_tty_info * info, uint * value)
+{
+	u_char status;
+	uint result;
+	ulong flags;
+
+	save_flags(flags);
+	cli();
+	status = info->lsr;
+	restore_flags(flags);
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+	put_user(result, (uint *) value);
+	return 0;
+}
+
+
+static int
+ctc_tty_get_ctc_tty_info(ctc_tty_info * info, uint * value)
+{
+	u_char control,
+	 status;
+	uint result;
+	ulong flags;
+
+	control = info->mcr;
+	save_flags(flags);
+	cli();
+	status = info->msr;
+	restore_flags(flags);
+	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+	    | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+	    | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
+	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
+	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
+	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+	put_user(result, (uint *) value);
+	return 0;
+}
+
+static int
+ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
+{
+	uint arg;
+
+	get_user(arg, (uint *) value);
+	switch (cmd) {
+		case TIOCMBIS:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			if (arg & TIOCM_RTS) {
+				info->mcr |= UART_MCR_RTS;
+			}
+			if (arg & TIOCM_DTR) {
+				info->mcr |= UART_MCR_DTR;
+			}
+			break;
+		case TIOCMBIC:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			if (arg & TIOCM_RTS) {
+				info->mcr &= ~UART_MCR_RTS;
+			}
+			if (arg & TIOCM_DTR) {
+				info->mcr &= ~UART_MCR_DTR;
+			}
+			break;
+		case TIOCMSET:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCMSET\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
+				 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+			       | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+ctc_tty_ioctl(struct tty_struct *tty, struct file *file,
+	       uint cmd, ulong arg)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+	int error;
+	int retval;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+	switch (cmd) {
+		case TCSBRK:   /* SVID version: non-zero arg --> no break */
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line);
+#endif
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			return 0;
+		case TCSBRKP:  /* support for POSIX tcsendbreak() */
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line);
+#endif
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			return 0;
+		case TIOCGSOFTCAR:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+			if (error)
+				return error;
+			put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
+			if (error)
+				return error;
+			get_user(arg, (ulong *) arg);
+			tty->termios->c_cflag =
+			    ((tty->termios->c_cflag & ~CLOCAL) |
+			     (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCMGET:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCMGET\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+			if (error)
+				return error;
+			return ctc_tty_get_ctc_tty_info(info, (uint *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
+			if (error)
+				return error;
+			return ctc_tty_set_ctc_tty_info(info, cmd, (uint *) arg);
+		case TIOCSERGETLSR:	/* Get line status register */
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME,
+			       info->line);
+#endif
+			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+			if (error)
+				return error;
+			else
+				return ctc_tty_get_lsr_info(info, (uint *) arg);
+		default:
+#ifdef CTC_DEBUG_MODEM_IOCTL
+			printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd,
+			       CTC_TTY_NAME, info->line);
+#endif
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static void
+ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+
+	if (!old_termios)
+		ctc_tty_change_speed(info);
+	else {
+		if (tty->termios->c_cflag == old_termios->c_cflag)
+			return;
+		ctc_tty_change_speed(info);
+		if ((old_termios->c_cflag & CRTSCTS) &&
+		    !(tty->termios->c_cflag & CRTSCTS)) {
+			tty->hw_stopped = 0;
+		}
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * ctc_tty_open() and friends
+ * ------------------------------------------------------------
+ */
+static int
+ctc_tty_block_til_ready(struct tty_struct *tty, struct file *filp, ctc_tty_info *info)
+{
+	DECLARE_WAITQUEUE(wait, NULL);
+	int do_clocal = 0;
+	unsigned long flags;
+	int retval;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & CTC_ASYNC_CLOSING)) {
+		if (info->flags & CTC_ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef MODEM_DO_RESTART
+		if (info->flags & CTC_ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+	/*
+	 * If non-blocking mode is set, then make the check up front
+	 * and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		info->flags |= CTC_ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * ctc_tty_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "ctc_tty_block_til_ready before block: %s%d, count = %d\n",
+	       CTC_TTY_NAME, info->line, info->count);
+#endif
+	save_flags(flags);
+	cli();
+	if (!(tty_hung_up_p(filp)))
+		info->count--;
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & CTC_ASYNC_INITIALIZED)) {
+#ifdef MODEM_DO_RESTART
+			if (info->flags & CTC_ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & CTC_ASYNC_CLOSING) &&
+		    (do_clocal || (info->msr & UART_MSR_DCD))) {
+			break;
+		}
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef CTC_DEBUG_MODEM_OPEN
+		printk(KERN_DEBUG "ctc_tty_block_til_ready blocking: %s%d, count = %d\n",
+		       CTC_TTY_NAME, info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "ctc_tty_block_til_ready after blocking: %s%d, count = %d\n",
+	       CTC_TTY_NAME, info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= CTC_ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int
+ctc_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	ctc_tty_info *info;
+	int retval,
+	 line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if (line < 0 || line > CTC_TTY_MAX_DEVICES)
+		return -ENODEV;
+	info = &driver->info[line];
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_open"))
+		return -ENODEV;
+	if (!info->netdev)
+		return -ENODEV;
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name,
+	       info->line, info->count);
+#endif
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+	/*
+	 * Start up serial port
+	 */
+	retval = ctc_tty_startup(info);
+	if (retval) {
+#ifdef CTC_DEBUG_MODEM_OPEN
+		printk(KERN_DEBUG "ctc_tty_open return after startup\n");
+#endif
+		return retval;
+	}
+	retval = ctc_tty_block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef CTC_DEBUG_MODEM_OPEN
+		printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n");
+#endif
+		return retval;
+	}
+	if ((info->count == 1) && (info->flags & CTC_ASYNC_SPLIT_TERMIOS)) {
+		*tty->termios = info->normal_termios;
+		ctc_tty_change_speed(info);
+	}
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "ctc_tty_open %s%d successful...\n", CTC_TTY_NAME, info->line);
+#endif
+	return 0;
+}
+
+static void
+ctc_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+	ulong flags;
+	ulong timeout;
+
+	if (!info || ctc_tty_paranoia_check(info, tty->device, "ctc_tty_close"))
+		return;
+	save_flags(flags);
+	cli();
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+#ifdef CTC_DEBUG_MODEM_OPEN
+		printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n");
+#endif
+		return;
+	}
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n",
+		       CTC_TTY_NAME, info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+#ifdef CTC_DEBUG_MODEM_OPEN
+		printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n");
+#endif
+		return;
+	}
+	info->flags |= CTC_ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & CTC_ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+
+	tty->closing = 1;
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	if (info->flags & CTC_ASYNC_INITIALIZED) {
+		tty_wait_until_sent(tty, 3000);	/* 30 seconds timeout */
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		timeout = jiffies + HZ;
+		while (!(info->lsr & UART_LSR_TEMT)) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(20);
+			if (time_after(jiffies,timeout))
+				break;
+		}
+	}
+	ctc_tty_shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	info->tty = 0;
+	tty->closing = 0;
+	if (info->blocked_open) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(50);
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+#ifdef CTC_DEBUG_MODEM_OPEN
+	printk(KERN_DEBUG "ctc_tty_close normal exit\n");
+#endif
+}
+
+/*
+ * ctc_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void
+ctc_tty_hangup(struct tty_struct *tty)
+{
+	ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
+
+	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup"))
+		return;
+	ctc_tty_shutdown(info);
+	info->count = 0;
+	info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+
+/*
+ * For all online tty's, try sending data to
+ * the lower levels.
+ */
+static void
+ctc_tty_task(ctc_tty_info *info)
+{
+	int again;
+
+	again = ctc_tty_tint(info);
+	again |= ctc_tty_readmodem(info);
+	if (again) {
+		queue_task(&info->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+int
+ctc_tty_init(void)
+{
+	int i;
+	ctc_tty_info *info;
+	struct tty_driver *device;
+
+	dst_e.ops = &dst_o;
+	dst_o.link_failure = ctc_tty_dstfail;
+	driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
+	if (driver == NULL) {
+		printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
+		return -ENOMEM;
+	}
+	memset(driver, 0, sizeof(ctc_tty_driver));
+	device = &driver->ctc_tty_device;
+
+	device->magic = TTY_DRIVER_MAGIC;
+	device->name = ctc_ttyname;
+	device->major = CTC_TTY_MAJOR;
+	device->minor_start = 0;
+	device->num = CTC_TTY_MAX_DEVICES;
+	device->type = TTY_DRIVER_TYPE_SERIAL;
+	device->subtype = CTC_SERIAL_TYPE_NORMAL;
+	device->init_termios = tty_std_termios;
+	device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	device->flags = TTY_DRIVER_REAL_RAW;
+	device->refcount = &driver->refcount;
+	device->table = driver->modem_table;
+	device->termios = driver->modem_termios;
+	device->termios_locked = driver->modem_termios_locked;
+	device->open = ctc_tty_open;
+	device->close = ctc_tty_close;
+	device->write = ctc_tty_write;
+	device->put_char = NULL;
+	device->flush_chars = ctc_tty_flush_chars;
+	device->write_room = ctc_tty_write_room;
+	device->chars_in_buffer = ctc_tty_chars_in_buffer;
+	device->flush_buffer = ctc_tty_flush_buffer;
+	device->ioctl = ctc_tty_ioctl;
+	device->throttle = ctc_tty_throttle;
+	device->unthrottle = ctc_tty_unthrottle;
+	device->set_termios = ctc_tty_set_termios;
+	device->stop = NULL;
+	device->start = NULL;
+	device->hangup = ctc_tty_hangup;
+	device->driver_name = "ctc_tty";
+
+	if (tty_register_driver(device)) {
+		printk(KERN_WARNING "ctc_tty: Couldn't register serial-device\n");
+		kfree(driver);
+		return -1;
+	}
+	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
+		info = &driver->info[i];
+		init_MUTEX(&info->write_sem);
+		INIT_LIST_HEAD(&info->tq.list);
+		info->tq.sync    = 0;
+		info->tq.routine = (void *)(void *)ctc_tty_task;
+		info->tq.data    = info;
+		info->magic = CTC_ASYNC_MAGIC;
+		info->line = i;
+		info->tty = 0;
+		info->x_char = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		info->normal_termios = device->init_termios;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		skb_queue_head_init(&info->tx_queue);
+		skb_queue_head_init(&info->rx_queue);
+	}
+	return 0;
+}
+
+int
+ctc_tty_register_netdev(net_device *dev) {
+	int ttynum;
+	char *err;
+	char *p;
+
+	if ((!dev) || (!dev->name)) {
+		printk(KERN_WARNING
+		       "ctc_tty_register_netdev called "
+		       "with NULL dev or NULL dev-name\n");
+		return -1;
+	}
+	for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++);
+	ttynum = simple_strtoul(p, &err, 0);
+	if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) ||
+	    (err && *err)) {
+		printk(KERN_WARNING
+		       "ctc_tty_register_netdev called "
+		       "with number in name '%s'\n", dev->name);
+		return -1;
+	}
+	if (driver->info[ttynum].netdev) {
+		printk(KERN_WARNING
+		       "ctc_tty_register_netdev called "
+		       "for already registered device '%s'\n",
+		       dev->name);
+		return -1;
+	}
+	driver->info[ttynum].netdev = dev;
+	return 0;
+}
+
+void
+ctc_tty_unregister_netdev(net_device *dev) {
+	int i;
+	ctc_tty_info *info = NULL;
+
+	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+		if (driver->info[i].netdev == dev) {
+			info = &driver->info[i];
+			break;
+		}
+	if (info) {
+		info->netdev = NULL;
+		skb_queue_purge(&info->tx_queue);
+		skb_queue_purge(&info->rx_queue);
+	}
+}
+
+void
+ctc_tty_cleanup(void) {
+	tty_unregister_driver(&driver->ctc_tty_device);
+	kfree(driver);
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctctty.h linux/drivers/s390/net/ctctty.h
--- v2.4.3/linux/drivers/s390/net/ctctty.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/net/ctctty.h	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,43 @@
+/*
+ * $Id: ctctty.h,v 1.2 2001/01/30 22:09:28 uweigand Exp $
+ *
+ * CTC / ESCON network driver, tty interface.
+ *
+ * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.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, 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 _CTCTTY_H_
+#define _CTCTTY_H_
+
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#if LINUX_VERSION_CODE < 0x020300
+typedef struct device      net_device;
+#else
+typedef struct net_device  net_device;
+#endif
+
+extern int  ctc_tty_register_netdev(net_device *dev);
+extern void ctc_tty_unregister_netdev(net_device *dev);
+extern void ctc_tty_netif_rx(struct sk_buff *skb);
+extern int  ctc_tty_init(void);
+extern void ctc_tty_cleanup(void);
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- v2.4.3/linux/drivers/s390/net/iucv.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/net/iucv.c	Thu Apr 12 12:16:35 2001
@@ -9,7 +9,7 @@
  *               Alan Altmark (Alan_Altmark@us.ibm.com)
  */
 
-#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
@@ -29,10 +29,6 @@
 //#define DEBUG         /* Turns Printk's on                         */
 //#define DEBUG2        /* This prints the parameter list before and */
 		      /* after the b2f0 call to cp                 */
-#ifdef CONFIG_MODULES
-#define EXPORT_SYMTAB
-#include <linux/module.h>
-#endif
 #undef NULL
 #define NULL 0
 #define ADDED_STOR 64		/* ADDITIONAL STORAGE FOR PATHID @'S */
@@ -2021,7 +2017,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_MODULES
 EXPORT_SYMBOL (iucv_accept);
 EXPORT_SYMBOL (iucv_connect);
 EXPORT_SYMBOL (iucv_purge);
@@ -2046,5 +2041,4 @@
 EXPORT_SYMBOL (iucv_sever);
 EXPORT_SYMBOL (iucv_register_program);
 EXPORT_SYMBOL (iucv_unregister);
-#endif
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c
--- v2.4.3/linux/drivers/s390/net/netiucv.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/s390/net/netiucv.c	Wed Apr 18 14:40:07 2001
@@ -489,7 +489,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;
@@ -707,7 +707,6 @@
 	dev->flags = IFF_NOARP | IFF_POINTOPOINT;
 	dev->mtu = 9216;
 
-	dev_init_buffers (dev);
 	pr_debug ("%s: iucv_init  dev@=%p\n", dev->name, dev);
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/s390dyn.c linux/drivers/s390/s390dyn.c
--- v2.4.3/linux/drivers/s390/s390dyn.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/s390dyn.c	Wed Apr 11 19:02:28 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>
 
@@ -14,200 +15,149 @@
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 
-static devreg_t   *devreg_anchor = NULL;
-static spinlock_t  dyn_lock      = SPIN_LOCK_UNLOCKED;
+static struct list_head devreg_anchor = LIST_HEAD_INIT(devreg_anchor);
+static spinlock_t  dyn_lock           = SPIN_LOCK_UNLOCKED;
 
-
-int s390_device_register( devreg_t *drinfo )
+static inline int s390_device_register_internal(devreg_t *drinfo)
 {
-	unsigned long  flags;
-	int            pdevflag,drflag;
-
-	int            ret     = 0;
-	devreg_t      *pdevreg = devreg_anchor;
-
-	if ( drinfo == NULL )
-		return( -EINVAL );
+	struct list_head *p;
 
-	drflag = drinfo->flag;
-
-	if ( (drflag & DEVREG_TYPE_DEVNO) == (drflag & DEVREG_TYPE_DEVCHARS) )
-		return( -EINVAL ); 
-
-	spin_lock_irqsave( &dyn_lock, flags ); 	
-
-	while ( (pdevreg != NULL) && (ret ==0) )
-	{
-		if ( pdevreg == drinfo )
-		{
-			ret = -EINVAL;
-		}
-		else
-		{
-			pdevflag = pdevreg->flag;
-
-			/*
-			 * we don't allow multiple drivers to register 
-			 *  for the same device number 
-			 */
-			if (    (    (pdevflag & DEVREG_TYPE_DEVNO)
-			          && (pdevreg->ci.devno                ) )
-			     && (    (drflag & DEVREG_TYPE_DEVNO )
-			          && (drinfo->ci.devno                 ) ) )
-			{
-				ret = -EBUSY;
-			}           	
-			else if ( drflag == (   DEVREG_TYPE_DEVCHARS 
-			                      | DEVREG_EXACT_MATCH   )) 
-			{
-				if ( !memcmp(&drinfo->ci.hc,
-				             &pdevreg->ci.hc,
-				             sizeof(devreg_hc_t)))
-					ret=-EBUSY;
-			} /* endif */
-
-		} /* endif */
-
-		pdevreg = pdevreg->next;
+        list_for_each(p, &devreg_anchor) {
+                devreg_t *pdevreg = list_entry(p, devreg_t, list);
+                
+                if (pdevreg == drinfo)
+                        return -EINVAL;
+                /*
+                 * We don't allow multiple drivers to register
+                 * for the same device number
+                 */
+                if (pdevreg->ci.devno == drinfo->ci.devno &&
+                    (pdevreg->flag & DEVREG_TYPE_DEVNO) &&
+                    (drinfo->flag & DEVREG_TYPE_DEVNO))
+			return -EBUSY;
+
+                if (drinfo->flag == (DEVREG_TYPE_DEVCHARS | 
+				     DEVREG_EXACT_MATCH) &&
+                    !memcmp(&drinfo->ci.hc, &pdevreg->ci.hc,
+		            sizeof(devreg_hc_t))) 
+			return -EBUSY;
+        }
+
+        /*
+         * no collision found, enqueue
+         */
+        list_add (&drinfo->list, &devreg_anchor);
 	
-	} /* endwhile */          	
+	return 0;
+}
 
-	/*
-	 * only enqueue if no collision was found ...	
-	 */
-	if(ret==0)	
-	{
-		drinfo->next = devreg_anchor;
-		drinfo->prev = NULL;
-
-		if ( devreg_anchor != NULL )
-		{
-			devreg_anchor->prev = drinfo;       	
-
-		} /* endif */
-		
-		devreg_anchor=drinfo;
+int s390_device_register( devreg_t *drinfo )
+{
+	unsigned long flags;
+	int ret;
 
-	} /* endif */
+	if (drinfo == NULL ||
+            !(drinfo->flag & (DEVREG_TYPE_DEVNO | DEVREG_TYPE_DEVCHARS)))
+		return -EINVAL;
 
+	spin_lock_irqsave (&dyn_lock, flags); 	
+	ret = s390_device_register_internal(drinfo);
 	spin_unlock_irqrestore( &dyn_lock, flags ); 	
  	
-	return( ret);
+	return ret;
 }
 
-
-int s390_device_unregister( devreg_t *dreg )
+static inline int s390_device_unregister_internal(devreg_t *dreg)
 {
-	unsigned long  flags;
-
-	int            ret     = -EINVAL;
-	devreg_t      *pdevreg = devreg_anchor;
+	struct list_head *p;
 
-	if ( dreg == NULL )
-		return( -EINVAL );
+        list_for_each(p, &devreg_anchor) {
+                devreg_t *pdevreg = list_entry(p, devreg_t, list);
 
-	spin_lock_irqsave( &dyn_lock, flags ); 	
-
-	while (    (pdevreg != NULL )
-	        && (    ret != 0    ) )
-	{
-		if ( pdevreg == dreg )
-		{
-			devreg_t *dprev = pdevreg->prev;
-			devreg_t *dnext = pdevreg->next;
-
-			if ( (dprev != NULL) && (dnext != NULL) )
-			{
-				dnext->prev = dprev;
-				dprev->next = dnext;
-			}
-			if ( (dprev != NULL) && (dnext == NULL) )
-			{
-				dprev->next = NULL;
-			}
-			if ( (dprev == NULL) && (dnext != NULL) )
-			{
-				dnext->prev = NULL;
-
-			} /* else */
-
-			ret = 0;
+		if (pdevreg == dreg) {
+			list_del (&dreg->list);
+			return 0;
 		}
-		else
-		{
-			pdevreg = pdevreg->next;
+        }
+	return -EINVAL;
+}
 
-		} /* endif */
+int s390_device_unregister(devreg_t *dreg)
+{
+	unsigned long  flags;
+	int ret;
 
-	} /* endwhile */          	
+	if (dreg == NULL)
+		return -EINVAL;
 
-	spin_unlock_irqrestore( &dyn_lock, flags ); 	
+	spin_lock_irqsave(&dyn_lock, flags); 	
+	ret = s390_device_unregister_internal(dreg);
+	spin_unlock_irqrestore(&dyn_lock, flags); 	
  	
-	return( ret);
+	return ret;
 }
 
+static inline devreg_t *s390_search_devreg_internal(ioinfo_t *ioinfo)
+{
+	struct list_head *p;
+	
+        list_for_each(p, &devreg_anchor) {
+                devreg_t *pdevreg = list_entry(p, devreg_t, list);
+		senseid_t *sid;
+		int flag;
+
+		flag = pdevreg->flag;
+		sid = &ioinfo->senseid;
+		if (flag & DEVREG_TYPE_DEVNO) {
+                        if (ioinfo->ui.flags.dval != 1 ||
+		            ioinfo->devno != pdevreg->ci.devno)
+				continue;
+                } else if ((flag & DEVREG_TYPE_DEVCHARS) &&
+		           (flag & DEVREG_EXACT_MATCH)) {
+			if (pdevreg->ci.hc.ctype != sid->cu_type ||
+			    pdevreg->ci.hc.cmode != sid->cu_model ||
+			    pdevreg->ci.hc.dtype != sid->dev_type ||
+			    pdevreg->ci.hc.dmode != sid->dev_model)
+				continue;
+		} else if (flag & DEVREG_TYPE_DEVCHARS) {
+			if (!(flag & DEVREG_NO_CU_INFO) &&
+			    pdevreg->ci.hc.ctype != sid->cu_type)
+				continue;
+
+                        if (!(flag & DEVREG_NO_CU_INFO) &&
+			    !(flag & DEVREG_MATCH_CU_TYPE) &&
+                            pdevreg->ci.hc.cmode != sid->cu_model)
+                                continue;
+
+                        if (!(flag & DEVREG_NO_DEV_INFO) &&
+                            pdevreg->ci.hc.dtype != sid->dev_type)
+                                continue;
+
+                        if (!(flag & DEVREG_NO_DEV_INFO) &&
+                            !(flag & DEVREG_MATCH_DEV_TYPE) &&
+                            pdevreg->ci.hc.dmode != sid->dev_model)
+                                continue;
+		}
+		return pdevreg;
+	}
+	return NULL;
+}
 
 devreg_t * s390_search_devreg( ioinfo_t *ioinfo )
 {
 	unsigned long  flags;
-	devreg_hc_t    match;
-	devreg_t *pdevreg = devreg_anchor;
-
-	if ( ioinfo == NULL )
-		return( NULL );
-
-	spin_lock_irqsave( &dyn_lock, flags ); 	
+	devreg_t *pdevreg;
 
-	while ( pdevreg != NULL )
-	{
-		int flag = pdevreg->flag;
-
-		if (    (flag & DEVREG_TYPE_DEVNO )
-		     && (ioinfo->ui.flags.dval == 1        )
-		     && (ioinfo->devno == pdevreg->ci.devno) )
-		{
-			break;
-		}           	
-		else if (flag & DEVREG_TYPE_DEVCHARS )
-		{
-			if ( flag & DEVREG_EXACT_MATCH ) 
-			{
-				if ( !memcmp( &pdevreg->ci.hc, 
-				              &ioinfo->senseid.cu_type,
-				              sizeof(devreg_hc_t)))
-					break; 
-			} 
-			else
-			{			
-				memcpy( &match, &ioinfo->senseid.cu_type, 
-				        sizeof(match));
-
-				if( flag & DEVREG_NO_CU_INFO )
-				{
-					match.ctype = pdevreg->ci.hc.ctype;
-					match.cmode = pdevreg->ci.hc.cmode;
-				}
-				if( flag & DEVREG_NO_DEV_INFO )
-				{
-					match.dtype = pdevreg->ci.hc.dtype;
-					match.dmode = pdevreg->ci.hc.dmode;
-				}
-				if ( flag & DEVREG_MATCH_CU_TYPE )
-					match.cmode = pdevreg->ci.hc.cmode;
-				if( flag & DEVREG_MATCH_DEV_TYPE)
-					match.dmode = pdevreg->ci.hc.dmode;
-				if ( !memcmp( &pdevreg->ci.hc,
-				              &match, sizeof(match)))
-					break;
-			} /* endif */
-		} /* endif */
+	if (ioinfo == NULL)
+		return NULL;
 
-		pdevreg = pdevreg->next;
-
-	} /* endwhile */          	
-
-	spin_unlock_irqrestore( &dyn_lock, flags ); 	
+	spin_lock_irqsave(&dyn_lock, flags); 	
+	pdevreg = s390_search_devreg_internal(ioinfo);
+	spin_unlock_irqrestore(&dyn_lock, flags); 	
  	
-	return( pdevreg);
+	return pdevreg;
 }
+
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c
--- v2.4.3/linux/drivers/s390/s390io.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/s390io.c	Wed Apr 11 19:02:29 2001
@@ -8,8 +8,16 @@
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  *    ChangeLog: 01/04/2001 Holger Smolinski (smolinsk@de.ibm.com)
  *                          Fixed lost interrupts and do_adapter_IO
+ *               xx/xx/xxxx nnn          multiple changes not reflected
+ *               03/12/2001 Ingo Adlung  blacklist= - changed to cio_ignore=  
+ *               03/14/2001 Ingo Adlung  disable interrupts before start_IO
+ *                                        in Path Group processing 
+ *                                       decrease retry2 on busy while 
+ *                                        disabling sync_isc; reset isc_cnt
+ *                                        on io error during sync_isc enablement
  */
 
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -23,7 +31,9 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
-
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -34,6 +44,7 @@
 #include <asm/processor.h>
 #include <asm/lowcore.h>
 #include <asm/idals.h>
+#include <asm/uaccess.h> 
 
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
@@ -47,9 +58,6 @@
 #undef  CONFIG_DEBUG_IO
 #define CONFIG_DEBUG_CRW
 
-#define REIPL_DEVID_MAGIC 0x87654321
-
-struct s390_irqaction  init_IRQ_action;
 unsigned int           highest_subchannel;
 ioinfo_t              *ioinfo_head = NULL;
 ioinfo_t              *ioinfo_tail = NULL;
@@ -58,7 +66,8 @@
 };
 
 static atomic_t    sync_isc     = ATOMIC_INIT(-1);
-                                          // synchronous irq processing lock
+static int         sync_isc_cnt = 0;      // synchronous irq processing lock
+
 static spinlock_t  adapter_lock = SPIN_LOCK_UNLOCKED;
                                           // adapter interrupt lock
 static psw_t      io_sync_wait;           // wait PSW for sync IO, prot. by sync_isc
@@ -70,22 +79,7 @@
 static __u64      irq_IPL_TOD;
 static adapter_int_handler_t adapter_handler   = NULL;
 
-/*
- * Dummy controller type for unused interrupts
- */
-int  do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;}
-int  enable_none(unsigned int irq) { return(-ENODEV); }
-int  disable_none(unsigned int irq) { return(-ENODEV); }
-
-struct hw_interrupt_type no_irq_type = {
-	"none",
-	do_none,
-	enable_none,
-	disable_none
-};
-
 static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
-static int  s390_setup_irq(unsigned int irq, struct s390_irqaction * new);
 static void s390_process_subchannels( void);
 static void s390_device_recognition_all( void);
 static void s390_device_recognition_irq( int irq);
@@ -94,8 +88,11 @@
 static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
 static int  s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
 static int  s390_process_IRQ( unsigned int irq );
+static int  enable_subchannel( unsigned int irq);
 static int  disable_subchannel( unsigned int irq);
 
+void chan_proc_init( void );
+
 static inline void do_adapter_IO( __u32 intparm );
 
 int  s390_DevicePathVerification( int irq, __u8 domask );
@@ -108,6 +105,305 @@
 
 asmlinkage void do_IRQ( struct pt_regs regs );
 
+
+/* 
+ * "Blacklisting" of certain devices:
+ * Device numbers given in the commandline as blacklist=... won't be known to Linux
+ * These can be single devices or ranges of devices
+ *
+ * Introduced by Cornelia Huck <cohuck@de.ibm.com>
+ * Most of it shamelessly taken from dasd.c 
+ */
+
+typedef struct dev_blacklist_range_t {
+     unsigned int from;                   /* beginning of range */
+     unsigned int to;                     /* end of range */
+     struct dev_blacklist_range_t *next;  /* next range in list */
+} dev_blacklist_range_t;
+
+static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
+static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
+
+/* Handling of the blacklist ranges */
+
+/* 
+ * Function: blacklist_range_create
+ * Creates a range from the given parameters
+ */
+static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
+{
+     dev_blacklist_range_t *range = NULL;
+     range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+     if (range == NULL)
+	  return NULL;
+     memset( range, 0, sizeof( dev_blacklist_range_t ));
+     range->from = from;
+     if (to == 0) {           /* only a single device is given */
+	  range->to = from;
+     } else {
+	  range->to = to;
+     }
+     return range;
+}
+
+/* 
+ * Function: blacklist_range_destroy
+ * Free the given range
+ */
+
+static inline void blacklist_range_destroy( dev_blacklist_range_t *range )
+{
+     kfree( range );
+}
+
+/*
+ * Function: blacklist_range_append
+ * Append a range to the list of blacklisted ranges anchored at dev_blacklist_range_head
+ */
+
+static inline void blacklist_range_append( dev_blacklist_range_t *range )
+{
+     dev_blacklist_range_t *temp;
+     long flags;
+
+     spin_lock_irqsave( &blacklist_lock, flags );
+     if (dev_blacklist_range_head == NULL) {
+	  dev_blacklist_range_head = range;
+     } else {
+	  for ( temp = dev_blacklist_range_head;
+		temp && temp->next;
+		temp = temp->next );
+	  temp->next = range;
+     }
+     spin_unlock_irqrestore( &blacklist_lock, flags );
+}
+
+/*
+ * Function: blacklist_range_dechain
+ * Remove a range from the list of blacklisted ranges
+ */
+
+static inline void blacklist_range_dechain( dev_blacklist_range_t *range )
+{
+     dev_blacklist_range_t *temp, *prev = NULL;
+     long flags;
+     
+     spin_lock_irqsave( &blacklist_lock, flags );
+     for ( temp = dev_blacklist_range_head; temp != NULL; temp = temp->next ) {
+	  if ( temp == range )
+	       break;
+	  prev = temp;
+     }
+     if (!temp)
+	  BUG();
+     if (prev) {
+	  prev->next = range->next;
+     } else {
+	  dev_blacklist_range_head = range->next;
+     }
+     spin_unlock_irqrestore( &blacklist_lock, flags );
+}
+
+/* 
+ * Function: blacklist_range_add
+ * Creates a range from the specified arguments and appends it to the list of
+ * blacklisted devices 
+ */
+
+static inline dev_blacklist_range_t *blacklist_range_add( int from, int to )
+{
+     dev_blacklist_range_t *temp;
+
+     temp = blacklist_range_create( from, to );
+     if (!temp) 
+	  return NULL;
+     blacklist_range_append( temp );
+     return temp;
+}
+
+/* 
+ * Function: blacklist_range_remove
+ * Removes a range from the blacklist chain
+ */
+
+static inline void blacklist_range_remove( int from, int to )
+{
+     dev_blacklist_range_t *temp;
+
+     for ( temp = dev_blacklist_range_head; 
+	   (temp->from != from) && (temp->to != to);
+	   temp = temp->next );
+     blacklist_range_dechain( temp );
+     blacklist_range_destroy( temp );
+}
+
+/* Parsing the commandline for blacklist parameters */
+
+/* 
+ * Variable to hold the blacklisted devices given by the parameter line
+ * blacklist=...
+ */
+char *blacklist[256] = {NULL, };
+
+/*
+ * Get the blacklist=... items from the parameter line
+ */
+
+static void blacklist_split_parm_string (char *str)
+{
+	char *tmp = str;
+	int count = 0;
+	do {
+		char *end;
+		int len;
+		end = strchr (tmp, ',');
+		if (end == NULL) {
+			len = strlen (tmp) + 1;
+		} else {
+			len = (long) end - (long) tmp + 1;
+			*end = '\0';
+			end++;
+		}
+		blacklist[count] = alloc_bootmem (len * sizeof (char) );
+		if (blacklist == NULL) {
+			printk (KERN_WARNING "can't store blacklist= parameter no %d\n", count + 1);
+			break;
+		}
+		memset (blacklist[count], 0, len * sizeof (char));
+		memcpy (blacklist[count], tmp, len * sizeof (char));
+		count++;
+		tmp = end;
+	} while (tmp != NULL && *tmp != '\0');
+}
+
+/*
+ * The blacklist parameters as one concatenated string
+ */
+
+static char blacklist_parm_string[1024] __initdata = {0,};
+
+
+/* 
+ * function: blacklist_strtoul
+ * Strip leading '0x' and interpret the values as Hex
+ */
+static inline int blacklist_strtoul (char *str, char **stra)
+{
+	char *temp = str;
+	int val;
+	if (*temp == '0') {
+		temp++;		                /* strip leading zero */
+		if (*temp == 'x')
+			temp++;	                /* strip leading x */
+	}
+	val = simple_strtoul (temp, &temp, 16);	/* interpret anything as hex */
+	*stra = temp;
+	return val;
+}
+
+/*
+ * Function: blacklist_parse
+ * Parse the parameters given to blacklist=... 
+ * Add the blacklisted devices to the blacklist chain
+ */
+
+static inline void blacklist_parse( char **str )
+{
+     char *temp;
+     int from, to;
+
+     while (*str) {
+	  temp = *str;
+	  from = 0;
+	  to = 0;
+	  
+	  from = blacklist_strtoul( temp, &temp );
+	  if (*temp == '-') {
+	       temp++;
+	       to = blacklist_strtoul( temp, &temp );
+	  }
+	  if (!blacklist_range_add( from, to )) {
+	       printk( KERN_WARNING "Blacklisting range from %X to %X failed!\n", from, to);
+	  }
+#ifdef CONFIG_DEBUG_IO
+	  printk( "Blacklisted range from %X to %X\n", from, to );
+#endif
+	  str++;
+     }
+}
+
+
+/*
+ * Initialisation of blacklist 
+ */
+
+void __init blacklist_init( void )
+{
+#ifdef CONFIG_DEBUG_IO     
+     printk( "Reading blacklist...\n");
+#endif
+     blacklist_split_parm_string( blacklist_parm_string );
+     blacklist_parse( blacklist );
+}
+
+
+/*
+ * Get all the blacklist parameters from parameter line
+ */
+
+void __init blacklist_setup (char *str, int *ints)
+{
+	int len = strlen (blacklist_parm_string);
+	if (len != 0) {
+		strcat (blacklist_parm_string, ",");
+	}
+	strcat (blacklist_parm_string, str);
+}
+
+int __init blacklist_call_setup (char *str)
+{
+        int dummy;
+#ifdef CONFIG_DEBUG_IO
+	printk( "Reading blacklist parameters...\n" );
+#endif
+        blacklist_setup(str,&dummy);
+	
+	blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
+       
+	return 1;
+}
+
+__setup ("cio_ignore=", blacklist_call_setup);
+
+/* Checking if devices are blacklisted */
+
+/*
+ * Function: is_blacklisted
+ * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0.
+ */
+
+static inline int is_blacklisted( int devno )
+{
+     dev_blacklist_range_t *temp;
+
+     if (dev_blacklist_range_head == NULL) {  
+	  /* no blacklist */
+	  return 0;
+     }
+
+     temp = dev_blacklist_range_head;
+     while (temp) {
+	  if ((temp->from <= devno) && (temp->to >= devno)) {
+	       return 1;                      /* Deviceno is blacklisted */
+	  }
+	  temp = temp->next;
+     }
+     return 0;
+}
+
+/* End of blacklist handling */
+
+
 void s390_displayhex(char *str,void *ptr,s32 cnt);
 
 void s390_displayhex(char *str,void *ptr,s32 cnt)
@@ -129,7 +425,7 @@
 	}
 }
 
-static int __init cio_setup( char *parm, int *ints)
+static int __init cio_setup( char *parm )
 {
 	if ( !strcmp( parm, "yes") )
 	{
@@ -219,8 +515,8 @@
                               const char              *devname,
                               void                    *dev_id)
 {
-	int               retval;
-	struct s390_irqaction *action;
+	int		retval = 0;
+	unsigned long	flags;
 
 	if (irq >= __MAX_SUBCHANNELS)
 		return -EINVAL;
@@ -228,52 +524,42 @@
 	if ( !io_handler || !dev_id )
 		return -EINVAL;
 
+	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+		return -ENODEV;
+
+
 	/*
-	 * during init_IRQ() processing we don't have memory
-	 *  management yet, thus need to use a statically
-	 *  allocated irqaction control block
+	 * The following block of code has to be executed atomically
 	 */
-	if ( init_IRQ_complete )
+	s390irq_spin_lock_irqsave( irq, flags);
+
+	if ( !ioinfo[irq]->ui.flags.ready )
 	{
-		action = (struct s390_irqaction *)
-		            kmalloc( sizeof(struct s390_irqaction),
-		                     GFP_KERNEL);
+		ioinfo[irq]->irq_desc.handler = io_handler;
+		ioinfo[irq]->irq_desc.name    = devname;
+		ioinfo[irq]->irq_desc.dev_id  = dev_id;
+		ioinfo[irq]->ui.flags.ready   = 1;
+
+		enable_subchannel(irq);
 	}
 	else
 	{
-		action = &init_IRQ_action;
-
-	} /* endif */
-
-	if (!action)
-	{
-		return -ENOMEM;
+		/*
+		 *  interrupt already owned, and shared interrupts
+		 *   aren't supported on S/390.
+		 */
+		retval = -EBUSY;
 
 	} /* endif */
 
-	action->handler = io_handler;
-	action->flags   = irqflags;
-	action->name    = devname;
-	action->dev_id  = dev_id;
-
-	retval = s390_setup_irq( irq, action);
-
-	if ( init_IRQ_complete )
-	{
-		if ( !retval )
-		{
-			s390_DevicePathVerification( irq, 0 );
-		}
-		else
-		{
-			kfree(action);
+	s390irq_spin_unlock_irqrestore(irq,flags);
 
-		} /* endif */
 
-	} /* endif */
 
 	if ( retval == 0 )
 	{
+		s390_DevicePathVerification( irq, 0 );
+
 		ioinfo[irq]->ui.flags.newreq = 1;
 		ioinfo[irq]->nopfunc         = not_oper_handler;  	
 	}
@@ -333,10 +619,9 @@
 	 * disable the device and reset all IRQ info if
 	 *  the IRQ is actually owned by the handler ...
 	 */
-	if ( ioinfo[irq]->irq_desc.action )
+	if ( ioinfo[irq]->ui.flags.ready )
 	{
-		if (    (dev_id == ioinfo[irq]->irq_desc.action->dev_id  )
-		     || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) )
+		if ( dev_id == ioinfo[irq]->irq_desc.dev_id  )
 		{
 			/* start deregister */
 			ioinfo[irq]->ui.flags.unready = 1;
@@ -413,14 +698,8 @@
 		
 			} while ( ret == -EBUSY );
 
-			if ( init_IRQ_complete )
-				kfree( ioinfo[irq]->irq_desc.action );
-
-			ioinfo[irq]->irq_desc.action           = NULL;
-			ioinfo[irq]->ui.flags.ready            = 0;
-			ioinfo[irq]->irq_desc.handler->enable  = enable_none;
-			ioinfo[irq]->irq_desc.handler->disable = disable_none;
-			ioinfo[irq]->ui.flags.unready          = 0; /* deregister ended */
+			ioinfo[irq]->ui.flags.ready   = 0;
+			ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
 
 			ioinfo[irq]->nopfunc = NULL;
 
@@ -458,14 +737,11 @@
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 		return( -ENODEV);
 
-	s390irq_spin_lock_irqsave(irq, flags);
+	if ( !ioinfo[irq]->ui.flags.ready )
+		return -ENODEV;
 
-	/*
-	 * At this point we may actually have a pending interrupt being active
-	 * on another CPU. So don't touch the IRQ_INPROGRESS bit..
-	 */
-	ioinfo[irq]->irq_desc.status |= IRQ_DISABLED;
-	ret = ioinfo[irq]->irq_desc.handler->disable(irq);
+	s390irq_spin_lock_irqsave(irq, flags);
+	ret = disable_subchannel(irq);
 	s390irq_spin_unlock_irqrestore(irq, flags);
 
 	synchronize_irq();
@@ -481,11 +757,11 @@
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 		return( -ENODEV);
 
-	s390irq_spin_lock_irqsave(irq, flags);
-
-	ioinfo[irq]->irq_desc.status = 0;
-	ret = ioinfo[irq]->irq_desc.handler->enable(irq);
+	if ( !ioinfo[irq]->ui.flags.ready )
+		return -ENODEV;
 
+	s390irq_spin_lock_irqsave(irq, flags);
+	ret = enable_subchannel(irq);
 	s390irq_spin_unlock_irqrestore(irq, flags);
 
 	return(ret);
@@ -717,48 +993,6 @@
 }
 
 
-int s390_setup_irq( unsigned int irq, struct s390_irqaction * new)
-{
-	unsigned long      flags;
-	int                rc = 0;
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
-
-	/*
-	 * The following block of code has to be executed atomically
-	 */
-	s390irq_spin_lock_irqsave( irq, flags);
-
-	if ( ioinfo[irq]->irq_desc.action == NULL )
-	{
-		ioinfo[irq]->irq_desc.action           = new;
-		ioinfo[irq]->irq_desc.status           = 0;
-		ioinfo[irq]->irq_desc.handler->enable  = enable_subchannel;
-		ioinfo[irq]->irq_desc.handler->disable = disable_subchannel;
-		ioinfo[irq]->irq_desc.handler->handle  = handle_IRQ_event;
-
-		ioinfo[irq]->ui.flags.ready            = 1;
-
-		ioinfo[irq]->irq_desc.handler->enable(irq);
-	}
-	else
-	{
-		/*
-		 *  interrupt already owned, and shared interrupts
-		 *   aren't supported on S/390.
-		 */
-		rc = -EBUSY;
-
-	} /* endif */
-
-	s390irq_spin_unlock_irqrestore(irq,flags);
-
-	return( rc);
-}
-
 void s390_init_IRQ( void )
 {
 	unsigned long flags;     /* PSW flags */
@@ -776,7 +1010,8 @@
 
 	p_init_schib = alloc_bootmem_low( sizeof(schib_t));
 	p_init_irb   = alloc_bootmem_low( sizeof(irb_t));
-
+	
+	
 	/*
 	 * As we don't know about the calling environment
 	 *  we assure running disabled. Before leaving the
@@ -844,7 +1079,7 @@
 	/*
 	 * setup ORB
 	 */
-  	ioinfo[irq]->orb.intparm = (__u32)(__u64)&ioinfo[irq]->u_intparm;
+  	ioinfo[irq]->orb.intparm = (__u32)(long)&ioinfo[irq]->u_intparm;
 	ioinfo[irq]->orb.fmt     = 1;
 
 	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
@@ -864,13 +1099,10 @@
 
 #ifdef CONFIG_ARCH_S390X
 	/* 
-	 * for 64 bit we always support 64 bit IDAWs with 2k page
-	 *  size only
-	 * FIXTHEM: OSA microcode currently has problems with 4k
-         *          we would like to use 4k.
+	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
 	 */
 	ioinfo[irq]->orb.c64 = 1;
-	ioinfo[irq]->orb.i2k = 1;
+	ioinfo[irq]->orb.i2k = 0;
 #endif
 
 	ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
@@ -912,7 +1144,7 @@
 			 *
 			 * Note : don´t clear saved irb info in case of sense !
 			 */
-			memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
+			memset( &((devstat_t *)ioinfo[irq]->irq_desc.dev_id)->ii.irb,
 				'\0', sizeof( irb_t) );
 		} /* endif */
 
@@ -1086,7 +1318,7 @@
 		/*
 		 * initialize the device driver specific devstat irb area
 		 */
-		memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
+		memset( &((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
 		        '\0', sizeof( irb_t) );
 
 		/*
@@ -1178,8 +1410,8 @@
 				         ioinfo[irq]->devstat.devno );
 
 				s390_displayhex( buffer,
-		((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data,
-		((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);
+					ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
+					ioinfo[irq]->irq_desc.dev_id->rescnt);
 
 			} /* endif */
 			}
@@ -1221,7 +1453,7 @@
 
 		ret = -ENODEV;
 
-		memcpy( ioinfo[irq]->irq_desc.action->dev_id,
+		memcpy( ioinfo[irq]->irq_desc.dev_id,
 		        &(ioinfo[irq]->devstat),
 		        sizeof( devstat_t) );
 
@@ -1579,7 +1811,7 @@
 			/*
 			 * initialize the device driver specific devstat irb area
 			 */
-			memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
+			memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb,
 			        '\0', sizeof( irb_t) );
 
 			/*
@@ -1840,7 +2072,7 @@
 			/*
 			 * initialize the device driver specific devstat irb area
 			 */
-			memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
+			memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb,
 			        '\0', sizeof( irb_t) );
 
 			/*
@@ -2007,7 +2239,6 @@
 	unsigned int           fctl;       /* function control */
 	unsigned int           stctl;      /* status   control */
 	unsigned int           actl;       /* activity control */
-	struct s390_irqaction *action;
 	struct pt_regs         regs;       /* for interface compatibility only */
 
 	int               issense         = 0;
@@ -2015,6 +2246,7 @@
 	int               allow4handler   = 1;
 	int               chnchk          = 0;
 	devstat_t        *dp;
+	devstat_t        *udp;
 #if 0
 	int               cpu             = smp_processor_id();
 
@@ -2029,8 +2261,8 @@
 
 	} /* endif */
 
-	action = ioinfo[irq]->irq_desc.action;
-	dp     = &ioinfo[irq]->devstat;
+	dp  = &ioinfo[irq]->devstat;
+	udp = ioinfo[irq]->irq_desc.dev_id;
 	
 
 #ifdef CONFIG_DEBUG_IO
@@ -2040,7 +2272,7 @@
 	 *  available when the device possibly becomes ready again. In
 	 *  this case we perform delayed disable_subchannel() processing.
 	 */
-	if ( action == NULL )
+	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 		if ( !ioinfo[irq]->ui.flags.d_disable )
 		{
@@ -2151,7 +2383,11 @@
 
 	} /* endif */
 
-	if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
+	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;
@@ -2262,7 +2498,7 @@
 		/*
 		 * take fast exit if no handler is available
 		 */
-		if ( !action )
+		if ( !ioinfo[irq]->ui.flags.ready )
 			return( ending_status );     		
 
 		/*
@@ -2291,9 +2527,7 @@
 				 *  sensing. When finally calling the IRQ handler we must not overlay
 				 *  the original device status but copy the sense data only.
 				 */
-				memcpy( action->dev_id,
-				        dp,
-				        sizeof( devstat_t) );
+				memcpy( udp, dp, sizeof( devstat_t) );
 
 				s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
 				s_ccw->cda      = (__u32)virt_to_phys( ioinfo[irq]->sense_data );
@@ -2405,14 +2639,14 @@
                  "BASIC SENSE bytes avail %d\n",
                  irq, sense_count );
 #endif
-				ioinfo[irq]->ui.flags.w4sense          = 0;
-				((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-				((devstat_t *)(action->dev_id))->scnt  = sense_count;
+				ioinfo[irq]->ui.flags.w4sense = 0;
+				udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+				udp->scnt  = sense_count;
 
 				if ( sense_count >= 0 )
 				{
-					memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data,
-					        &(ioinfo[irq]->sense_data),
+					memcpy( udp->ii.sense.data,
+					        ioinfo[irq]->sense_data,
 					        sense_count);
 				}
 				else
@@ -2430,7 +2664,7 @@
 			}
 			else
 			{
-				memcpy( action->dev_id, dp, sdevstat );
+				memcpy( udp, dp, sdevstat );
 
 			}  /* endif */
 
@@ -2456,8 +2690,8 @@
 				ioinfo[irq]->ui.flags.repall   = 0;
 				ioinfo[irq]->ui.flags.w4final  = 0;
 
-				dp->flag             |= DEVSTAT_FINAL_STATUS;
-				action->dev_id->flag |= DEVSTAT_FINAL_STATUS;
+				dp->flag  |= DEVSTAT_FINAL_STATUS;
+				udp->flag |= DEVSTAT_FINAL_STATUS;
 
 			} /* endif */
 
@@ -2486,10 +2720,10 @@
 				ioinfo[irq]->ui.flags.repall   = 0;
 				ioinfo[irq]->ui.flags.w4final  = 0;
 
-				dp->flag             |= DEVSTAT_FINAL_STATUS;
-				action->dev_id->flag |= DEVSTAT_FINAL_STATUS;
+				dp->flag  |= DEVSTAT_FINAL_STATUS;
+				udp->flag |= DEVSTAT_FINAL_STATUS;
 
-				action->handler( irq, action->dev_id, &regs );
+				ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
 
 				//
 				// reset intparm after final status or we will badly present unsolicited
@@ -2521,7 +2755,7 @@
 					 */
 					if ( ret )
 					{
-						action->handler( irq, action->dev_id, &regs );
+						ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
 
 					} /* endif */
 
@@ -2539,17 +2773,17 @@
 				 */
 				if ( dp->cstat & SCHN_STAT_PCI )
 				{
-					action->dev_id->flag |= DEVSTAT_PCI;
-					dp->cstat            &= ~SCHN_STAT_PCI;
+					udp->flag |= DEVSTAT_PCI;
+					dp->cstat &= ~SCHN_STAT_PCI;
 				}
 
 				if ( actl & SCSW_ACTL_SUSPENDED )
 				{
-					action->dev_id->flag |= DEVSTAT_SUSPENDED;
+					udp->flag |= DEVSTAT_SUSPENDED;
 
 				} /* endif */
 
-				action->handler( irq, action->dev_id, &regs );
+				ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
 
 			} /* endif */
 
@@ -2623,16 +2857,16 @@
 		/*
 		 * take fast exit if no handler is available
 		 */
-		if ( !action )
+		if ( !ioinfo[irq]->ui.flags.ready )
 			return( ending_status );     		
 
-		memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat );
+		memcpy( udp, &(ioinfo[irq]->devstat), sdevstat );
 
 		ioinfo[irq]->devstat.intparm  = 0;
 
 		if ( !ioinfo[irq]->ui.flags.s_pend )
 		{
-			action->handler( irq, action->dev_id, &regs );
+			ioinfo[irq]->irq_desc.handler( irq, udp, &regs );
 
 		} /* endif */
 
@@ -2856,9 +3090,9 @@
 		if ( atomic_read( &sync_isc ) != irq )
 			atomic_compare_and_swap_spin( -1, irq, &sync_isc );
 
-		ioinfo[irq]->syncnt++;
+		sync_isc_cnt++;
 		
-		if ( ioinfo[irq]->syncnt > 255 ) /* fixme : magic number */
+		if ( sync_isc_cnt > 255 ) /* fixme : magic number */
 		{
 			panic("Too many recursive calls to enable_sync_isc");
 
@@ -2866,7 +3100,7 @@
 		/*
 		 * we only run the STSCH/MSCH path for the first enablement
 		 */
-		else if ( ioinfo[irq]->syncnt == 1)
+		else if ( sync_isc_cnt == 1 )
 		{
 			ioinfo[irq]->ui.flags.syncio = 1;
 
@@ -2931,9 +3165,16 @@
 			} /* endif */
 
 		} /* endif */
+
+		if ( rc )	// can only happen if stsch/msch fails
+			sync_isc_cnt = 0;
 	}
 	else
 	{
+#ifdef CONFIG_SYNC_ISC_PARANOIA
+		panic( "enable_sync_isc: called with invalid %x\n", irq );
+#endif
+
 		rc = -EINVAL;
 
 	} /* endif */
@@ -2960,7 +3201,14 @@
 		 *  msch() processing we may face another pending
 		 *  status we have to process recursively (sync).
 		 */
-		if ( (ioinfo[irq]->syncnt-1) == 0 )
+
+#ifdef CONFIG_SYNC_ISC_PARANOIA
+		if ( atomic_read( &sync_isc ) != irq )
+			panic( "disable_sync_isc: called for %x while %x locked\n",
+				irq, atomic_read( &sync_isc ) );
+#endif
+
+		if ( sync_isc_cnt == 1 )
 		{
 			ccode = stsch( irq, &(ioinfo[irq]->schib) );
 
@@ -2989,6 +3237,8 @@
 						retry2--;
 						break;
 					case 2:
+					        retry2--;
+						udelay( 100); // give it time
 						break;
 					default:
 						retry2 = 0;
@@ -3011,20 +3261,26 @@
 
 			} while ( retry1 && ccode );
 
-			ioinfo[irq]->syncnt          = 0;
 			ioinfo[irq]->ui.flags.syncio = 0;
-			
+		
+			sync_isc_cnt = 0;	
 			atomic_set( &sync_isc, -1);
 
 		}
 		else
 		{
-			ioinfo[irq]->syncnt--;
+			sync_isc_cnt--;
 
-   	} /* endif */
+		} /* endif */
 	}
 	else
 	{
+#ifdef CONFIG_SYNC_ISC_PARANOIA
+		if ( atomic_read( &sync_isc ) != -1 )
+			panic( "disable_sync_isc: called with invalid %x while %x locked\n", 
+				irq, atomic_read( &sync_isc ) );
+#endif
+
 		rc = -EINVAL;
 
 	} /* endif */
@@ -3446,7 +3702,7 @@
 				rdc_ccw->flags    = CCW_FLAG_SLI;
 				set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
 
-				memset( (devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id),
+				memset( ioinfo[irq]->irq_desc.dev_id,
 				        '\0',
 				        sizeof( devstat_t));
 
@@ -3457,7 +3713,7 @@
 				                     DOIO_WAIT_FOR_INTERRUPT
 				                      | DOIO_DONT_CALL_INTHDLR );
 				retry--;
-				devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;   
+				devflag = ioinfo[irq]->irq_desc.dev_id->flag;   
     
 				clear_normalized_cda( rdc_ccw);  
 
@@ -3579,7 +3835,7 @@
 		}
 		else
 		{
-			pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
+			pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
 		} /* endif */
 
@@ -3998,7 +4254,6 @@
 void s390_device_recognition_irq( int irq )
 {
 	int           ret;
-	unsigned long psw_flags;
 
 	/*
 	 * We issue the SenseID command on I/O subchannels we think are
@@ -4194,7 +4449,17 @@
 
 		if ( p_schib->pmcw.dnv )
 		{
-			if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+		     if ( is_blacklisted( p_schib->pmcw.dev )) {
+			  /* 
+			   * This device must not be known to Linux. So we simply say that 
+			   * there is no device and return ENODEV.
+			   */
+#ifdef CONFIG_DEBUG_IO
+			  printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
+#endif
+			  ret = -ENODEV;
+		     } else {
+		        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 			{	
 				if ( !init_IRQ_complete )
 				{
@@ -4213,8 +4478,6 @@
 				memcpy( &ioinfo[irq]->schib,
 			           p_init_schib,
 			           sizeof( schib_t));
-				ioinfo[irq]->irq_desc.status  = IRQ_DISABLED;
-				ioinfo[irq]->irq_desc.handler = &no_irq_type;
 			
 				/*
 				 * We have to insert the new ioinfo element
@@ -4438,6 +4701,7 @@
 				ret                        = -ENODEV;    	
 
 			} /* endif */
+		     }
 		}
 		else
 		{
@@ -4520,7 +4784,7 @@
 	{
 		inlreq   = 0;
 		irq_ret  = 0;
-		pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
   	} /* endif */
 
@@ -5045,6 +5309,8 @@
 	ccw1_t    *spid_ccw;    /* ccw area for SPID command */
 	devstat_t  devstat;     /* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
+        unsigned long flags;
+
 
 	int        irq_ret = 0; /* return code */
 	int        retry   = 5; /* retry count */
@@ -5087,13 +5353,13 @@
    }
 	else
 	{
-		pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
 	} /* endif */
 
 	if ( irq_ret == 0 )
 	{
-		s390irq_spin_lock( irq);
+		s390irq_spin_lock_irqsave( irq, flags);
 
 		if ( init_IRQ_complete )
 		{
@@ -5233,7 +5499,7 @@
 
 		} /* endif */
 
-		s390irq_spin_unlock( irq);
+		s390irq_spin_unlock_irqrestore( irq, flags);
 
 		/*
 		 * If we installed the irq action handler we have to
@@ -5301,7 +5567,7 @@
    }
 	else
 	{
-		pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
 	} /* endif */
 
@@ -5547,7 +5813,7 @@
 					     && ( nopfunc != NULL ) )
 					{
 						
-						free_irq( irq,ioinfo[irq]->irq_desc.action->dev_id );
+						free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
 						nopfunc( irq,DEVSTAT_DEVICE_GONE );			
 
 					} /* endif */
@@ -5659,10 +5925,170 @@
 reipl ( int sch )
 {
 	int i;
+	s390_dev_info_t dev_info;
 
-	for ( i = 0; i < highest_subchannel; i ++ ) {
-	    free_irq ( i, (void*)REIPL_DEVID_MAGIC );
+	for ( i = 0; i <= highest_subchannel; i ++ ) 
+	{
+		if (    get_dev_info_by_irq( i, &dev_info ) == 0
+                    && (dev_info.status & DEVSTAT_DEVICE_OWNED) )
+		{
+			free_irq ( i, ioinfo[i]->irq_desc.dev_id );
+		}
 	}
+
 	do_reipl( 0x10000 | sch );
 }
 
+/* Display info on subchannels in /proc/subchannels. *
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      */
+
+typedef struct {
+     char *data;
+     int len;
+} tempinfo_t;
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+static struct proc_dir_entry *chan_subch_entry;
+
+static int chan_subch_open( struct inode *inode, struct file *file)
+{
+     int rc = 0;
+     int size = 1;
+     int len = 0;
+     int i = 0;
+     int j = 0;
+     tempinfo_t *info;
+     
+     info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t));
+     if (info == NULL) {
+	  printk( KERN_WARNING "No memory available for data\n");
+	  return -ENOMEM;
+     } else {
+	  file->private_data = ( void * ) info;
+     }
+
+     size += (highest_subchannel+1) * 128;
+     info->data = (char *) vmalloc( size );
+     
+     if (size && info->data == NULL) {
+		printk (KERN_WARNING "No memory available for data\n");
+		vfree (info);
+		return -ENOMEM;
+	}
+     
+     len += sprintf( info->data+len, 
+		     "Device sch.  Dev Type/Model CU  in use  PIM PAM POM LPUM CHPIDs\n");
+     len += sprintf( info->data+len, 
+		     "--------------------------------------------------------------------------\n");
+
+     for ( i=0; i <= highest_subchannel; i++) {
+	  if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) {
+	       len += sprintf( info->data+len, 
+			       "%04X   %04X  ", 
+			       ioinfo[i]->schib.pmcw.dev, 
+			       i );
+	       if ( ioinfo[i]->senseid.dev_type != 0 ) {
+		    len += sprintf( info->data+len, 
+				    "%04X/%02X   %04X/%02X", 
+				    ioinfo[i]->senseid.dev_type,
+				    ioinfo[i]->senseid.dev_model, 
+				    ioinfo[i]->senseid.cu_type,
+				    ioinfo[i]->senseid.cu_model );
+	       } else {
+		    len += sprintf( info->data+len, 
+				    "%04X/%02X          ", 
+				    ioinfo[i]->senseid.cu_type, 
+				    ioinfo[i]->senseid.cu_model );
+	       }
+	       if (ioinfo[i]->ui.flags.ready) {
+		    len += sprintf( info->data+len, "  yes " );
+	       } else {
+		    len += sprintf( info->data+len, "      " );
+	       }
+	       len += sprintf( info->data+len,
+			       "    %02X  %02X  %02X  %02X   ",
+			       ioinfo[i]->schib.pmcw.pim,
+			       ioinfo[i]->schib.pmcw.pam,
+			       ioinfo[i]->schib.pmcw.pom,
+			       ioinfo[i]->schib.pmcw.lpum );
+	       for ( j=0; j < 8; j++ ) {
+		    len += sprintf( info->data+len,
+				    "%02X",
+				    ioinfo[i]->schib.pmcw.chpid[j] );
+		    if (j==3) {
+			 len += sprintf( info->data+len, " " );
+		    }
+	       }
+	       len += sprintf( info->data+len, "\n" );
+	  }
+     }
+     info->len = len;
+
+     return rc;
+}
+
+static int chan_subch_close( struct inode *inode, struct file *file)
+{
+     int rc = 0;
+     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+     if (p_info) {
+	  if (p_info->data)
+	       vfree( p_info->data );
+	  vfree( p_info );
+     }
+     
+     return rc;
+}
+
+static ssize_t chan_subch_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+     loff_t len;
+     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+     
+     if ( *offset>=p_info->len) {
+	  return 0;
+     } else {
+	  len = MIN(user_len, (p_info->len - *offset));
+	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+	       return -EFAULT; 
+	  (* offset) += len;
+	  return len;
+     }
+}
+
+static struct file_operations chan_subch_file_ops =
+{
+     read:chan_subch_read,
+     open:chan_subch_open,
+     release:chan_subch_close,
+};
+
+void chan_proc_init( void )
+{
+     chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
+     chan_subch_entry->proc_fops = &chan_subch_file_ops;
+}
+
+__initcall(chan_proc_init);
+
+void chan_proc_cleanup( void )
+{
+     remove_proc_entry( "subchannels", &proc_root);
+}
+
+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 --recursive --new-file v2.4.3/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.4.3/linux/drivers/sbus/char/Makefile	Sun Mar 25 18:14:20 2001
+++ linux/drivers/sbus/char/Makefile	Thu Apr 12 12:10:25 2001
@@ -9,10 +9,11 @@
 
 O_TARGET := sunchar.o
 
-export-objs := su.o
+export-objs := su.o bbc_i2c.o
 obj-y := sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o
 
 vfc-objs := vfc_dev.o vfc_i2c.o
+bbc-objs := bbc_i2c.o bbc_envctrl.o
 
 obj-$(CONFIG_PCI) += su.o pcikbd.o
 
@@ -29,6 +30,7 @@
 obj-$(CONFIG_SUN_AURORA)		+= aurora.o
 obj-$(CONFIG_TADPOLE_TS102_UCTRL)	+= uctrl.o
 obj-$(CONFIG_SUN_JSFLASH)		+= jsflash.o
+obj-$(CONFIG_BBC_I2C)			+= bbc.o
 
 include $(TOPDIR)/Rules.make
 
@@ -36,3 +38,6 @@
 
 vfc.o: $(vfc-objs)
 	$(LD) -r -o $@ $(vfc-objs)
+
+bbc.o: $(bbc-objs)
+	$(LD) -r -o $@ $(bbc-objs)
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/bbc_envctrl.c linux/drivers/sbus/char/bbc_envctrl.c
--- v2.4.3/linux/drivers/sbus/char/bbc_envctrl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/bbc_envctrl.c	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,646 @@
+/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
+ * bbc_envctrl.c: UltraSPARC-III environment control driver.
+ *
+ * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/oplib.h>
+#include <asm/ebus.h>
+#define __KERNEL_SYSCALLS__
+static int errno;
+#include <asm/unistd.h>
+
+#include "bbc_i2c.h"
+#include "max1617.h"
+
+#undef ENVCTRL_TRACE
+
+/* WARNING: Making changes to this driver is very dangerous.
+ *          If you misprogram the sensor chips they can
+ *          cut the power on you instantly.
+ */
+
+/* Two temperature sensors exist in the SunBLADE-1000 enclosure.
+ * Both are implemented using max1617 i2c devices.  Each max1617
+ * monitors 2 temperatures, one for one of the cpu dies and the other
+ * for the ambient temperature.
+ *
+ * The max1617 is capable of being programmed with power-off
+ * temperature values, one low limit and one high limit.  These
+ * can be controlled independantly for the cpu or ambient temperature.
+ * If a limit is violated, the power is simply shut off.  The frequency
+ * with which the max1617 does temperature sampling can be controlled
+ * as well.
+ *
+ * Three fans exist inside the machine, all three are controlled with
+ * an i2c digital to analog converter.  There is a fan directed at the
+ * two processor slots, another for the rest of the enclosure, and the
+ * third is for the power supply.  The first two fans may be speed
+ * controlled by changing the voltage fed to them.  The third fan may
+ * only be completely off or on.  The third fan is meant to only be
+ * disabled/enabled when entering/exiting the lowest power-saving
+ * mode of the machine.
+ *
+ * An environmental control kernel thread periodically monitors all
+ * temperature sensors.  Based upon the samples it will adjust the
+ * fan speeds to try and keep the system within a certain temperature
+ * range (the goal being to make the fans as quiet as possible without
+ * allowing the system to get too hot).
+ *
+ * If the temperature begins to rise/fall outside of the acceptable
+ * operating range, a periodic warning will be sent to the kernel log.
+ * The fans will be put on full blast to attempt to deal with this
+ * situation.  After exceeding the acceptable operating range by a
+ * certain threshold, the kernel thread will shut down the system.
+ * Here, the thread is attempting to shut the machine down cleanly
+ * before the hardware based power-off event is triggered.
+ */
+
+/* These settings are in celcius.  We use these defaults only
+ * if we cannot interrogate the cpu-fru SEEPROM.
+ */
+struct temp_limits {
+	s8 high_pwroff, high_shutdown, high_warn;
+	s8 low_warn, low_shutdown, low_pwroff;
+};
+
+static struct temp_limits cpu_temp_limits[2] = {
+	{ 100, 85, 80, 5, -5, -10 },
+	{ 100, 85, 80, 5, -5, -10 },
+};
+
+static struct temp_limits amb_temp_limits[2] = {
+	{ 65, 55, 40, 5, -5, -10 },
+	{ 65, 55, 40, 5, -5, -10 },
+};
+
+enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
+
+struct bbc_cpu_temperature {
+	struct bbc_cpu_temperature	*next;
+
+	struct bbc_i2c_client		*client;
+	int				index;
+
+	/* Current readings, and history. */
+	s8				curr_cpu_temp;
+	s8				curr_amb_temp;
+	s8				prev_cpu_temp;
+	s8				prev_amb_temp;
+	s8				avg_cpu_temp;
+	s8				avg_amb_temp;
+
+	int				sample_tick;
+
+	enum fan_action			fan_todo[2];
+#define FAN_AMBIENT	0
+#define FAN_CPU		1
+};
+
+struct bbc_cpu_temperature *all_bbc_temps;
+
+struct bbc_fan_control {
+	struct bbc_fan_control 	*next;
+
+	struct bbc_i2c_client 	*client;
+	int 			index;
+
+	int			psupply_fan_on;
+	int			cpu_fan_speed;
+	int			system_fan_speed;
+};
+
+struct bbc_fan_control *all_bbc_fans;
+
+#define CPU_FAN_REG	0xf0
+#define SYS_FAN_REG	0xf2
+#define PSUPPLY_FAN_REG	0xf4
+
+#define FAN_SPEED_MIN	0x0c
+#define FAN_SPEED_MAX	0x3f
+
+#define PSUPPLY_FAN_ON	0x1f
+#define PSUPPLY_FAN_OFF	0x00
+
+static void set_fan_speeds(struct bbc_fan_control *fp)
+{
+	/* Put temperatures into range so we don't mis-program
+	 * the hardware.
+	 */
+	if (fp->cpu_fan_speed < FAN_SPEED_MIN)
+		fp->cpu_fan_speed = FAN_SPEED_MIN;
+	if (fp->cpu_fan_speed > FAN_SPEED_MAX)
+		fp->cpu_fan_speed = FAN_SPEED_MAX;
+	if (fp->system_fan_speed < FAN_SPEED_MIN)
+		fp->system_fan_speed = FAN_SPEED_MIN;
+	if (fp->system_fan_speed > FAN_SPEED_MAX)
+		fp->system_fan_speed = FAN_SPEED_MAX;
+#ifdef ENVCTRL_TRACE
+	printk("fan%d: Changed fan speed to cpu(%02x) sys(%02x)\n",
+	       fp->index,
+	       fp->cpu_fan_speed, fp->system_fan_speed);
+#endif
+
+	bbc_i2c_writeb(fp->client, fp->cpu_fan_speed, CPU_FAN_REG);
+	bbc_i2c_writeb(fp->client, fp->system_fan_speed, SYS_FAN_REG);
+	bbc_i2c_writeb(fp->client,
+		       (fp->psupply_fan_on ?
+			PSUPPLY_FAN_ON : PSUPPLY_FAN_OFF),
+		       PSUPPLY_FAN_REG);
+}
+
+static void get_current_temps(struct bbc_cpu_temperature *tp)
+{
+	tp->prev_amb_temp = tp->curr_amb_temp;
+	bbc_i2c_readb(tp->client,
+		      (unsigned char *) &tp->curr_amb_temp,
+		      MAX1617_AMB_TEMP);
+	tp->prev_cpu_temp = tp->curr_cpu_temp;
+	bbc_i2c_readb(tp->client,
+		      (unsigned char *) &tp->curr_cpu_temp,
+		      MAX1617_CPU_TEMP);
+#ifdef ENVCTRL_TRACE
+	printk("temp%d: cpu(%d C) amb(%d C)\n",
+	       tp->index,
+	       (int) tp->curr_cpu_temp, (int) tp->curr_amb_temp);
+#endif
+}
+
+
+static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
+{
+	static int shutting_down = 0;
+	static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+	char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
+	char *type = "???";
+	s8 val = -1;
+
+	if (shutting_down != 0)
+		return;
+
+	if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
+	    tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
+		type = "ambient";
+		val = tp->curr_amb_temp;
+	} else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
+		   tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
+		type = "CPU";
+		val = tp->curr_cpu_temp;
+	}
+
+	printk(KERN_CRIT "temp%d: Outside of safe %s "
+	       "operating temperature, %d C.\n",
+	       tp->index, type, val);
+
+	printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
+
+	shutting_down = 1;
+	if (execve("/sbin/shutdown", argv, envp) < 0)
+		printk(KERN_CRIT "envctrl: shutdown execution failed\n");
+}
+
+#define WARN_INTERVAL	(30 * HZ)
+
+static void analyze_ambient_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
+{
+	int ret = 0;
+
+	if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
+		if (tp->curr_amb_temp >=
+		    amb_temp_limits[tp->index].high_warn) {
+			printk(KERN_WARNING "temp%d: "
+			       "Above safe ambient operating temperature, %d C.\n",
+			       tp->index, (int) tp->curr_amb_temp);
+			ret = 1;
+		} else if (tp->curr_amb_temp <
+			   amb_temp_limits[tp->index].low_warn) {
+			printk(KERN_WARNING "temp%d: "
+			       "Below safe ambient operating temperature, %d C.\n",
+			       tp->index, (int) tp->curr_amb_temp);
+			ret = 1;
+		}
+		if (ret)
+			*last_warn = jiffies;
+	} else if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_warn ||
+		   tp->curr_amb_temp < amb_temp_limits[tp->index].low_warn)
+		ret = 1;
+
+	/* Now check the shutdown limits. */
+	if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
+	    tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
+		do_envctrl_shutdown(tp);
+		ret = 1;
+	}
+
+	if (ret) {
+		tp->fan_todo[FAN_AMBIENT] = FAN_FULLBLAST;
+	} else if ((tick & (8 - 1)) == 0) {
+		s8 amb_goal_hi = amb_temp_limits[tp->index].high_warn - 10;
+		s8 amb_goal_lo;
+
+		amb_goal_lo = amb_goal_hi - 3;
+
+		/* We do not try to avoid 'too cold' events.  Basically we
+		 * only try to deal with over-heating and fan noise reduction.
+		 */
+		if (tp->avg_amb_temp < amb_goal_hi) {
+			if (tp->avg_amb_temp >= amb_goal_lo)
+				tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
+			else
+				tp->fan_todo[FAN_AMBIENT] = FAN_SLOWER;
+		} else {
+			tp->fan_todo[FAN_AMBIENT] = FAN_FASTER;
+		}
+	} else {
+		tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
+	}
+}
+
+static void analyze_cpu_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
+{
+	int ret = 0;
+
+	if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
+		if (tp->curr_cpu_temp >=
+		    cpu_temp_limits[tp->index].high_warn) {
+			printk(KERN_WARNING "temp%d: "
+			       "Above safe CPU operating temperature, %d C.\n",
+			       tp->index, (int) tp->curr_cpu_temp);
+			ret = 1;
+		} else if (tp->curr_cpu_temp <
+			   cpu_temp_limits[tp->index].low_warn) {
+			printk(KERN_WARNING "temp%d: "
+			       "Below safe CPU operating temperature, %d C.\n",
+			       tp->index, (int) tp->curr_cpu_temp);
+			ret = 1;
+		}
+		if (ret)
+			*last_warn = jiffies;
+	} else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_warn ||
+		   tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_warn)
+		ret = 1;
+
+	/* Now check the shutdown limits. */
+	if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
+	    tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
+		do_envctrl_shutdown(tp);
+		ret = 1;
+	}
+
+	if (ret) {
+		tp->fan_todo[FAN_CPU] = FAN_FULLBLAST;
+	} else if ((tick & (8 - 1)) == 0) {
+		s8 cpu_goal_hi = cpu_temp_limits[tp->index].high_warn - 10;
+		s8 cpu_goal_lo;
+
+		cpu_goal_lo = cpu_goal_hi - 3;
+
+		/* We do not try to avoid 'too cold' events.  Basically we
+		 * only try to deal with over-heating and fan noise reduction.
+		 */
+		if (tp->avg_cpu_temp < cpu_goal_hi) {
+			if (tp->avg_cpu_temp >= cpu_goal_lo)
+				tp->fan_todo[FAN_CPU] = FAN_SAME;
+			else
+				tp->fan_todo[FAN_CPU] = FAN_SLOWER;
+		} else {
+			tp->fan_todo[FAN_CPU] = FAN_FASTER;
+		}
+	} else {
+		tp->fan_todo[FAN_CPU] = FAN_SAME;
+	}
+}
+
+static void analyze_temps(struct bbc_cpu_temperature *tp, unsigned long *last_warn)
+{
+	tp->avg_amb_temp = (s8)((int)((int)tp->avg_amb_temp + (int)tp->curr_amb_temp) / 2);
+	tp->avg_cpu_temp = (s8)((int)((int)tp->avg_cpu_temp + (int)tp->curr_cpu_temp) / 2);
+
+	analyze_ambient_temp(tp, last_warn, tp->sample_tick);
+	analyze_cpu_temp(tp, last_warn, tp->sample_tick);
+
+	tp->sample_tick++;
+}
+
+static enum fan_action prioritize_fan_action(int which_fan)
+{
+	struct bbc_cpu_temperature *tp;
+	enum fan_action decision = FAN_STATE_MAX;
+
+	/* Basically, prioritize what the temperature sensors
+	 * recommend we do, and perform that action on all the
+	 * fans.
+	 */
+	for (tp = all_bbc_temps; tp; tp = tp->next) {
+		if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
+			decision = FAN_FULLBLAST;
+			break;
+		}
+		if (tp->fan_todo[which_fan] == FAN_SAME &&
+		    decision != FAN_FASTER)
+			decision = FAN_SAME;
+		else if (tp->fan_todo[which_fan] == FAN_FASTER)
+			decision = FAN_FASTER;
+		else if (decision != FAN_FASTER &&
+			 decision != FAN_SAME &&
+			 tp->fan_todo[which_fan] == FAN_SLOWER)
+			decision = FAN_SLOWER;
+	}
+	if (decision == FAN_STATE_MAX)
+		decision = FAN_SAME;
+
+	return decision;
+}
+
+static int maybe_new_ambient_fan_speed(struct bbc_fan_control *fp)
+{
+	enum fan_action decision = prioritize_fan_action(FAN_AMBIENT);
+	int ret;
+
+	if (decision == FAN_SAME)
+		return 0;
+
+	ret = 1;
+	if (decision == FAN_FULLBLAST) {
+		if (fp->system_fan_speed >= FAN_SPEED_MAX)
+			ret = 0;
+		else
+			fp->system_fan_speed = FAN_SPEED_MAX;
+	} else {
+		if (decision == FAN_FASTER) {
+			if (fp->system_fan_speed >= FAN_SPEED_MAX)
+				ret = 0;
+			else
+				fp->system_fan_speed += 2;
+		} else {
+			int orig_speed = fp->system_fan_speed;
+
+			if (orig_speed <= FAN_SPEED_MIN ||
+			    orig_speed <= (fp->cpu_fan_speed - 3))
+				ret = 0;
+			else
+				fp->system_fan_speed -= 1;
+		}
+	}
+
+	return ret;
+}
+
+static int maybe_new_cpu_fan_speed(struct bbc_fan_control *fp)
+{
+	enum fan_action decision = prioritize_fan_action(FAN_CPU);
+	int ret;
+
+	if (decision == FAN_SAME)
+		return 0;
+
+	ret = 1;
+	if (decision == FAN_FULLBLAST) {
+		if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
+			ret = 0;
+		else
+			fp->cpu_fan_speed = FAN_SPEED_MAX;
+	} else {
+		if (decision == FAN_FASTER) {
+			if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
+				ret = 0;
+			else {
+				fp->cpu_fan_speed += 2;
+				if (fp->system_fan_speed <
+				    (fp->cpu_fan_speed - 3))
+					fp->system_fan_speed =
+						fp->cpu_fan_speed - 3;
+			}
+		} else {
+			if (fp->cpu_fan_speed <= FAN_SPEED_MIN)
+				ret = 0;
+			else
+				fp->cpu_fan_speed -= 1;
+		}
+	}
+
+	return ret;
+}
+
+static void maybe_new_fan_speeds(struct bbc_fan_control *fp)
+{
+	int new;
+
+	new  = maybe_new_ambient_fan_speed(fp);
+	new |= maybe_new_cpu_fan_speed(fp);
+
+	if (new)
+		set_fan_speeds(fp);
+}
+
+static void fans_full_blast(void)
+{
+	struct bbc_fan_control *fp;
+
+	/* Since we will not be monitoring things anymore, put
+	 * the fans on full blast.
+	 */
+	for (fp = all_bbc_fans; fp; fp = fp->next) {
+		fp->cpu_fan_speed = FAN_SPEED_MAX;
+		fp->system_fan_speed = FAN_SPEED_MAX;
+		fp->psupply_fan_on = 1;
+		set_fan_speeds(fp);
+	}
+}
+
+#define POLL_INTERVAL	(5 * HZ)
+static unsigned long last_warning_jiffies;
+static struct task_struct *kenvctrld_task;
+
+static int kenvctrld(void *__unused)
+{
+	daemonize();
+	strcpy(current->comm, "kenvctrld");
+	kenvctrld_task = current;
+
+	printk(KERN_INFO "bbc_envctrl: kenvctrld starting...\n");
+	last_warning_jiffies = jiffies - WARN_INTERVAL;
+	for (;;) {
+		struct bbc_cpu_temperature *tp;
+		struct bbc_fan_control *fp;
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(POLL_INTERVAL);
+		current->state = TASK_RUNNING;
+		if (signal_pending(current))
+			break;
+
+		for (tp = all_bbc_temps; tp; tp = tp->next) {
+			get_current_temps(tp);
+			analyze_temps(tp, &last_warning_jiffies);
+		}
+		for (fp = all_bbc_fans; fp; fp = fp->next)
+			maybe_new_fan_speeds(fp);
+	}
+	printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
+
+	fans_full_blast();
+
+	return 0;
+}
+
+static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
+{
+	struct bbc_cpu_temperature *tp = kmalloc(sizeof(*tp), GFP_KERNEL);
+
+	if (!tp)
+		return;
+	memset(tp, 0, sizeof(*tp));
+	tp->client = bbc_i2c_attach(echild);
+	if (!tp->client) {
+		kfree(tp);
+		return;
+	}
+
+	tp->index = temp_idx;
+	{
+		struct bbc_cpu_temperature **tpp = &all_bbc_temps;
+		while (*tpp)
+			tpp = &((*tpp)->next);
+		tp->next = NULL;
+		*tpp = tp;
+	}
+
+	/* Tell it to convert once every 5 seconds, clear all cfg
+	 * bits.
+	 */
+	bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE);
+	bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE);
+
+	/* Program the hard temperature limits into the chip. */
+	bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff,
+		       MAX1617_WR_AMB_HIGHLIM);
+	bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff,
+		       MAX1617_WR_AMB_LOWLIM);
+	bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff,
+		       MAX1617_WR_CPU_HIGHLIM);
+	bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff,
+		       MAX1617_WR_CPU_LOWLIM);
+
+	get_current_temps(tp);
+	tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp;
+	tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp;
+
+	tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
+	tp->fan_todo[FAN_CPU] = FAN_SAME;
+}
+
+static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
+{
+	struct bbc_fan_control *fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+
+	if (!fp)
+		return;
+	memset(fp, 0, sizeof(*fp));
+	fp->client = bbc_i2c_attach(echild);
+	if (!fp->client) {
+		kfree(fp);
+		return;
+	}
+
+	fp->index = fan_idx;
+
+	{
+		struct bbc_fan_control **fpp = &all_bbc_fans;
+		while (*fpp)
+			fpp = &((*fpp)->next);
+		fp->next = NULL;
+		*fpp = fp;
+	}
+
+	/* The i2c device controlling the fans is write-only.
+	 * So the only way to keep track of the current power
+	 * level fed to the fans is via software.  Choose half
+	 * power for cpu/system and 'on' fo the powersupply fan
+	 * and set it now.
+	 */
+	fp->psupply_fan_on = 1;
+	fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
+	fp->cpu_fan_speed += FAN_SPEED_MIN;
+	fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
+	fp->system_fan_speed += FAN_SPEED_MIN;
+
+	set_fan_speeds(fp);
+}
+
+void bbc_envctrl_init(void)
+{
+	struct linux_ebus_child *echild;
+	int temp_index = 0;
+	int fan_index = 0;
+	int devidx = 0;
+
+	while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
+		if (!strcmp(echild->prom_name, "temperature"))
+			attach_one_temp(echild, temp_index++);
+		if (!strcmp(echild->prom_name, "fan-control"))
+			attach_one_fan(echild, fan_index++);
+	}
+	if (temp_index != 0 && fan_index != 0)
+		kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES);
+}
+
+static void destroy_one_temp(struct bbc_cpu_temperature *tp)
+{
+	bbc_i2c_detach(tp->client);
+	kfree(tp);
+}
+
+static void destroy_one_fan(struct bbc_fan_control *fp)
+{
+	bbc_i2c_detach(fp->client);
+	kfree(fp);
+}
+
+void bbc_envctrl_cleanup(void)
+{
+	struct bbc_cpu_temperature *tp;
+	struct bbc_fan_control *fp;
+
+	if (kenvctrld_task != NULL) {
+		force_sig(SIGKILL, kenvctrld_task);
+		for (;;) {
+			struct task_struct *p;
+			int found = 0;
+
+			read_lock(&tasklist_lock);
+			for_each_task(p) {
+				if (p == kenvctrld_task) {
+					found = 1;
+					break;
+				}
+			}
+			read_unlock(&tasklist_lock);
+			if (!found)
+				break;
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ);
+			current->state = TASK_RUNNING;
+		}
+		kenvctrld_task = NULL;
+	}
+
+	tp = all_bbc_temps;
+	while (tp != NULL) {
+		struct bbc_cpu_temperature *next = tp->next;
+		destroy_one_temp(tp);
+		tp = next;
+	}
+	all_bbc_temps = NULL;
+
+	fp = all_bbc_fans;
+	while (fp != NULL) {
+		struct bbc_fan_control *next = fp->next;
+		destroy_one_fan(fp);
+		fp = next;
+	}
+	all_bbc_fans = NULL;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/bbc_i2c.c linux/drivers/sbus/char/bbc_i2c.c
--- v2.4.3/linux/drivers/sbus/char/bbc_i2c.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/bbc_i2c.c	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,482 @@
+/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $
+ * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
+ *            platforms.
+ *
+ * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/oplib.h>
+#include <asm/ebus.h>
+#include <asm/spitfire.h>
+#include <asm/bbc.h>
+
+#include "bbc_i2c.h"
+
+/* Convert this driver to use i2c bus layer someday... */
+#define I2C_PCF_PIN	0x80
+#define I2C_PCF_ESO	0x40
+#define I2C_PCF_ES1	0x20
+#define I2C_PCF_ES2	0x10
+#define I2C_PCF_ENI	0x08
+#define I2C_PCF_STA	0x04
+#define I2C_PCF_STO	0x02
+#define I2C_PCF_ACK	0x01
+
+#define I2C_PCF_START    (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_STOP     (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
+#define I2C_PCF_REPSTART (              I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_IDLE     (I2C_PCF_PIN | I2C_PCF_ESO               | I2C_PCF_ACK)
+
+#define I2C_PCF_INI 0x40   /* 1 if not initialized */
+#define I2C_PCF_STS 0x20
+#define I2C_PCF_BER 0x10
+#define I2C_PCF_AD0 0x08
+#define I2C_PCF_LRB 0x08
+#define I2C_PCF_AAS 0x04
+#define I2C_PCF_LAB 0x02
+#define I2C_PCF_BB  0x01
+
+/* The BBC devices have two I2C controllers.  The first I2C controller
+ * connects mainly to configuration proms (NVRAM, cpu configuration,
+ * dimm types, etc.).  Whereas the second I2C controller connects to
+ * environmental control devices such as fans and temperature sensors.
+ * The second controller also connects to the smartcard reader, if present.
+ */
+
+#define NUM_CHILDREN	8
+struct bbc_i2c_bus {
+	struct bbc_i2c_bus		*next;
+	int				index;
+	spinlock_t			lock;
+	void				*i2c_bussel_reg;
+	void				*i2c_control_regs;
+	unsigned char			own, clock;
+
+	wait_queue_head_t		wq;
+	volatile int			waiting;
+
+	struct linux_ebus_device	*bus_edev;
+	struct {
+		struct linux_ebus_child	*device;
+		int			client_claimed;
+	} devs[NUM_CHILDREN];
+};
+
+static struct bbc_i2c_bus *all_bbc_i2c;
+
+struct bbc_i2c_client {
+	struct bbc_i2c_bus	*bp;
+	struct linux_ebus_child	*echild;
+	int			bus;
+	int			address;
+};
+
+static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild)
+{
+	int i;
+
+	for (i = 0; i < NUM_CHILDREN; i++) {
+		if (bp->devs[i].device == echild) {
+			if (bp->devs[i].client_claimed)
+				return 0;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val)
+{
+	int i;
+
+	for (i = 0; i < NUM_CHILDREN; i++) {
+		if (bp->devs[i].device == echild) {
+			bp->devs[i].client_claimed = val;
+			return;
+		}
+	}
+}
+
+#define claim_device(BP,ECHILD)		set_device_claimage(BP,ECHILD,1)
+#define release_device(BP,ECHILD)	set_device_claimage(BP,ECHILD,0)
+
+static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild)
+{
+	struct bbc_i2c_bus *bp = all_bbc_i2c;
+
+	while (bp != NULL) {
+		if (find_device(bp, echild) != 0)
+			break;
+		bp = bp->next;
+	}
+
+	return bp;
+}
+
+struct linux_ebus_child *bbc_i2c_getdev(int index)
+{
+	struct bbc_i2c_bus *bp = all_bbc_i2c;
+	struct linux_ebus_child *echild = NULL;
+	int curidx = 0;
+
+	while (bp != NULL) {
+		struct bbc_i2c_bus *next = bp->next;
+		int i;
+
+		for (i = 0; i < NUM_CHILDREN; i++) {
+			if (!(echild = bp->devs[i].device))
+				break;
+			if (curidx == index)
+				goto out;
+			echild = NULL;
+			curidx++;
+		}
+		bp = next;
+	}
+out:
+	if (curidx == index)
+		return echild;
+	return NULL;
+}
+
+struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
+{
+	struct bbc_i2c_bus *bp = find_bus_for_device(echild);
+	struct bbc_i2c_client *client;
+
+	if (!bp)
+		return NULL;
+	client = kmalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return NULL;
+	memset(client, 0, sizeof(*client));
+	client->bp = bp;
+	client->echild = echild;
+	client->bus = echild->resource[0].start;
+	client->address = echild->resource[1].start;
+
+	claim_device(bp, echild);
+
+	return client;
+}
+
+void bbc_i2c_detach(struct bbc_i2c_client *client)
+{
+	struct bbc_i2c_bus *bp = client->bp;
+	struct linux_ebus_child *echild = client->echild;
+
+	release_device(bp, echild);
+	kfree(client);
+}
+
+static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int limit = 32;
+	int ret = 1;
+
+	bp->waiting = 1;
+	add_wait_queue(&bp->wq, &wait);
+	while (limit-- > 0) {
+		u8 val;
+
+		current->state = TASK_INTERRUPTIBLE;
+		*status = val = readb(bp->i2c_control_regs + 0);
+		if ((val & I2C_PCF_PIN) == 0) {
+			ret = 0;
+			break;
+		}
+		schedule_timeout(HZ/4);
+	}
+	remove_wait_queue(&bp->wq, &wait);
+	bp->waiting = 0;
+	current->state = TASK_RUNNING;
+
+	return ret;
+}
+
+int bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off)
+{
+	struct bbc_i2c_bus *bp = client->bp;
+	int address = client->address;
+	u8 status;
+	int ret = -1;
+
+	if (bp->i2c_bussel_reg != NULL)
+		writeb(client->bus, bp->i2c_bussel_reg);
+
+	writeb(address, bp->i2c_control_regs + 0x1);
+	writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
+	if (wait_for_pin(bp, &status))
+		goto out;
+
+	writeb(off, bp->i2c_control_regs + 0x1);
+	if (wait_for_pin(bp, &status) ||
+	    (status & I2C_PCF_LRB) != 0)
+		goto out;
+
+	writeb(val, bp->i2c_control_regs + 0x1);
+	if (wait_for_pin(bp, &status))
+		goto out;
+
+	ret = 0;
+
+out:
+	writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
+	return ret;
+}
+
+int bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off)
+{
+	struct bbc_i2c_bus *bp = client->bp;
+	unsigned char address = client->address, status;
+	int ret = -1;
+
+	if (bp->i2c_bussel_reg != NULL)
+		writeb(client->bus, bp->i2c_bussel_reg);
+
+	writeb(address, bp->i2c_control_regs + 0x1);
+	writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
+	if (wait_for_pin(bp, &status))
+		goto out;
+
+	writeb(off, bp->i2c_control_regs + 0x1);
+	if (wait_for_pin(bp, &status) ||
+	    (status & I2C_PCF_LRB) != 0)
+		goto out;
+
+	writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
+
+	address |= 0x1; /* READ */
+
+	writeb(address, bp->i2c_control_regs + 0x1);
+	writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
+	if (wait_for_pin(bp, &status))
+		goto out;
+
+	/* Set PIN back to one so the device sends the first
+	 * byte.
+	 */
+	(void) readb(bp->i2c_control_regs + 0x1);
+	if (wait_for_pin(bp, &status))
+		goto out;
+
+	writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0);
+	*byte = readb(bp->i2c_control_regs + 0x1);
+	if (wait_for_pin(bp, &status))
+		goto out;
+
+	ret = 0;
+
+out:
+	writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
+	(void) readb(bp->i2c_control_regs + 0x1);
+
+	return ret;
+}
+
+int bbc_i2c_write_buf(struct bbc_i2c_client *client,
+		      char *buf, int len, int off)
+{
+	int ret = 0;
+
+	while (len > 0) {
+		int err = bbc_i2c_writeb(client, *buf, off);
+
+		if (err < 0) {
+			ret = err;
+			break;
+		}
+
+		len--;
+		buf++;
+		off++;
+	}
+	return ret;
+}
+
+int bbc_i2c_read_buf(struct bbc_i2c_client *client,
+		     char *buf, int len, int off)
+{
+	int ret = 0;
+
+	while (len > 0) {
+		int err = bbc_i2c_readb(client, buf, off);
+		if (err < 0) {
+			ret = err;
+			break;
+		}
+		len--;
+		buf++;
+		off++;
+	}
+
+	return ret;
+}
+
+EXPORT_SYMBOL(bbc_i2c_getdev);
+EXPORT_SYMBOL(bbc_i2c_attach);
+EXPORT_SYMBOL(bbc_i2c_detach);
+EXPORT_SYMBOL(bbc_i2c_writeb);
+EXPORT_SYMBOL(bbc_i2c_readb);
+EXPORT_SYMBOL(bbc_i2c_write_buf);
+EXPORT_SYMBOL(bbc_i2c_read_buf);
+
+static void bbc_i2c_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct bbc_i2c_bus *bp = dev_id;
+
+	/* PIN going from set to clear is the only event which
+	 * makes the i2c assert an interrupt.
+	 */
+	if (bp->waiting &&
+	    !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
+		wake_up(&bp->wq);
+}
+
+static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
+{
+	writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
+	writeb(bp->own, bp->i2c_control_regs + 0x1);
+	writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0);
+	writeb(bp->clock, bp->i2c_control_regs + 0x1);
+	writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
+}
+
+static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
+{
+	struct bbc_i2c_bus *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
+	struct linux_ebus_child *echild;
+	int entry;
+
+	if (!bp)
+		return -ENOMEM;
+	memset(bp, 0, sizeof(*bp));
+
+	bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
+	if (!bp->i2c_control_regs)
+		goto fail;
+
+	if (edev->num_addrs == 2) {
+		bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1);
+		if (!bp->i2c_bussel_reg)
+			goto fail;
+	}
+
+	bp->waiting = 0;
+	init_waitqueue_head(&bp->wq);
+	if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
+			SA_SHIRQ, "bbc_i2c", bp))
+		goto fail;
+
+	bp->index = index;
+	bp->bus_edev = edev;
+
+	spin_lock_init(&bp->lock);
+	bp->next = all_bbc_i2c;
+	all_bbc_i2c = bp;
+
+	entry = 0;
+	for (echild = edev->children;
+	     echild && entry < 8;
+	     echild = echild->next, entry++) {
+		bp->devs[entry].device = echild;
+		bp->devs[entry].client_claimed = 0;
+	}
+
+	writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
+	bp->own = readb(bp->i2c_control_regs + 0x01);
+	writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0);
+	bp->clock = readb(bp->i2c_control_regs + 0x01);
+
+	printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n",
+	       bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock);
+
+	reset_one_i2c(bp);
+
+	return 0;
+
+fail:
+	if (bp->i2c_bussel_reg)
+		iounmap(bp->i2c_bussel_reg);
+	if (bp->i2c_control_regs)
+		iounmap(bp->i2c_control_regs);
+	kfree(bp);
+	return -EINVAL;
+}
+
+static int __init bbc_present(void)
+{
+	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, "bbc"))
+				return 1;
+		}
+	}
+	return 0;
+}
+
+extern void bbc_envctrl_init(void);
+extern void bbc_envctrl_cleanup(void);
+
+static int __init bbc_i2c_init(void)
+{
+	struct linux_ebus *ebus = NULL;
+	struct linux_ebus_device *edev = NULL;
+	int index = 0;
+
+	if (tlb_type != cheetah || !bbc_present())
+		return -ENODEV;
+
+	for_each_ebus(ebus) {
+		for_each_ebusdev(edev, ebus) {
+			if (!strcmp(edev->prom_name, "i2c")) {
+				if (!attach_one_i2c(edev, index))
+					index++;
+			}
+		}
+	}
+
+	if (!index)
+		return -ENODEV;
+
+	bbc_envctrl_init();
+	return 0;
+}
+
+static void __exit bbc_i2c_cleanup(void)
+{
+	struct bbc_i2c_bus *bp = all_bbc_i2c;
+
+	bbc_envctrl_cleanup();
+
+	while (bp != NULL) {
+		struct bbc_i2c_bus *next = bp->next;
+
+		free_irq(bp->bus_edev->irqs[0], bp);
+
+		if (bp->i2c_bussel_reg)
+			iounmap(bp->i2c_bussel_reg);
+		if (bp->i2c_control_regs)
+			iounmap(bp->i2c_control_regs);
+
+		kfree(bp);
+
+		bp = next;
+	}
+	all_bbc_i2c = NULL;
+}
+
+module_init(bbc_i2c_init);
+module_exit(bbc_i2c_cleanup);
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/bbc_i2c.h linux/drivers/sbus/char/bbc_i2c.h
--- v2.4.3/linux/drivers/sbus/char/bbc_i2c.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/bbc_i2c.h	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,20 @@
+/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */
+#ifndef _BBC_I2C_H
+#define _BBC_I2C_H
+
+#include <asm/ebus.h>
+
+struct bbc_i2c_client;
+
+/* Probing and attachment. */
+extern struct linux_ebus_child *bbc_i2c_getdev(int);
+extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *);
+extern void bbc_i2c_detach(struct bbc_i2c_client *);
+
+/* Register read/write.  NOTE: Blocking! */
+extern int bbc_i2c_writeb(struct bbc_i2c_client *, unsigned char val, int off);
+extern int bbc_i2c_readb(struct bbc_i2c_client *, unsigned char *byte, int off);
+extern int bbc_i2c_write_buf(struct bbc_i2c_client *, char *buf, int len, int off);
+extern int bbc_i2c_read_buf(struct bbc_i2c_client *, char *buf, int len, int off);
+
+#endif /* _BBC_I2C_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/cpwatchdog.c linux/drivers/sbus/char/cpwatchdog.c
--- v2.4.3/linux/drivers/sbus/char/cpwatchdog.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/sbus/char/cpwatchdog.c	Thu Apr 12 12:10:25 2001
@@ -199,7 +199,9 @@
 
 /* Forward declarations of internal methods
  */
+#ifdef WD_DEBUG
 static void wd_dumpregs(void);
+#endif
 static void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void wd_toggleintr(struct wd_timer* pTimer, int enable);
 static void wd_pingtimer(struct wd_timer* pTimer);
@@ -471,6 +473,7 @@
 static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
 static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
 
+#ifdef WD_DEBUG
 static void wd_dumpregs(void)
 {
 	/* Reading from downcounters initiates watchdog countdown--
@@ -507,6 +510,7 @@
 		(unsigned long)(&wd_dev.regs->pld_regs.status), 
 		readb(&wd_dev.regs->pld_regs.status));
 }
+#endif
 
 /* Enable or disable watchdog interrupts
  * Because of the CP1400 defect this should only be
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/max1617.h linux/drivers/sbus/char/max1617.h
--- v2.4.3/linux/drivers/sbus/char/max1617.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/max1617.h	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,27 @@
+/* $Id: max1617.h,v 1.1 2001/04/02 09:59:08 davem Exp $ */
+#ifndef _MAX1617_H
+#define _MAX1617_H
+
+#define MAX1617_AMB_TEMP	0x00 /* Ambient temp in C	*/
+#define MAX1617_CPU_TEMP	0x01 /* Processor die temp in C	*/
+#define MAX1617_STATUS		0x02 /* Chip status bits	*/
+
+/* Read-only versions of changable registers. */
+#define MAX1617_RD_CFG_BYTE	0x03 /* Config register		*/
+#define MAX1617_RD_CVRATE_BYTE	0x04 /* Temp conversion rate	*/
+#define MAX1617_RD_AMB_HIGHLIM	0x05 /* Ambient high limit	*/
+#define MAX1617_RD_AMB_LOWLIM	0x06 /* Ambient low limit	*/
+#define MAX1617_RD_CPU_HIGHLIM	0x07 /* Processor high limit	*/
+#define MAX1617_RD_CPU_LOWLIM	0x08 /* Processor low limit	*/
+
+/* Write-only versions of the same. */
+#define MAX1617_WR_CFG_BYTE	0x09
+#define MAX1617_WR_CVRATE_BYTE	0x0a
+#define MAX1617_WR_AMB_HIGHLIM	0x0b
+#define MAX1617_WR_AMB_LOWLIM	0x0c
+#define MAX1617_WR_CPU_HIGHLIM	0x0d
+#define MAX1617_WR_CPU_LOWLIM	0x0e
+
+#define MAX1617_ONESHOT		0x0f
+
+#endif /* _MAX1617_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/riowatchdog.c linux/drivers/sbus/char/riowatchdog.c
--- v2.4.3/linux/drivers/sbus/char/riowatchdog.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/sbus/char/riowatchdog.c	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: riowatchdog.c,v 1.1 2001/03/24 06:04:24 davem Exp $
+/* $Id: riowatchdog.c,v 1.2 2001/03/26 23:47:18 davem Exp $
  * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -24,10 +24,9 @@
  * as its' watchdog.
  *
  * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
- * Controller) of the machine.  The BBC can be configured to treat the
- * assertion of this signal in different ways.  It can trigger an XIR
- * (external CPU reset) to all the processors or it can trigger a true
- * power-on reset which triggers the RST signal of all devices in the machine.
+ * Controller) of the machine.  The BBC can only be configured to
+ * trigger a power-on reset when the signal is asserted.  The BBC
+ * can be configured to ignore the signal entirely as well.
  *
  * The only Super I/O device register we care about is at index
  * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
@@ -54,15 +53,13 @@
 
 static spinlock_t riowd_lock = SPIN_LOCK_UNLOCKED;
 
+static void *bbc_regs;
 static void *riowd_regs;
 #define WDTO_INDEX	0x05
 
 static int riowd_timeout = 1;		/* in minutes */
-static int riowd_xir = 1;		/* watchdog generates XIR? */
 MODULE_PARM(riowd_timeout,"i");
 MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
-MODULE_PARM(riowd_xir,"i");
-MODULE_PARM_DESC(riowd_xir, "Watchdog generates XIR reset if non-zero");
 
 #if 0 /* Currently unused. */
 static u8 riowd_readreg(int index)
@@ -96,12 +93,24 @@
 
 static void riowd_stoptimer(void)
 {
+	u8 val;
+
 	riowd_writereg(0, WDTO_INDEX);
+
+	val = readb(bbc_regs + BBC_WDACTION);
+	val &= ~BBC_WDACTION_RST;
+	writeb(val, bbc_regs + BBC_WDACTION);
 }
 
 static void riowd_starttimer(void)
 {
+	u8 val;
+
 	riowd_writereg(riowd_timeout, WDTO_INDEX);
+
+	val = readb(bbc_regs + BBC_WDACTION);
+	val |= BBC_WDACTION_RST;
+	writeb(val, bbc_regs + BBC_WDACTION);
 }
 
 static int riowd_open(struct inode *inode, struct file *filp)
@@ -189,7 +198,6 @@
 {
 	struct 	linux_ebus *ebus = NULL;
 	struct 	linux_ebus_device *edev = NULL;
-	void *bbc_regs;
 	u8 val;
 
 	for_each_ebus(ebus) {
@@ -206,14 +214,11 @@
 	if (!bbc_regs)
 		return -ENODEV;
 
+	/* Turn it off. */
 	val = readb(bbc_regs + BBC_WDACTION);
-	if (riowd_xir != 0)
-		val &= ~BBC_WDACTION_RST;
-	else
-		val |= BBC_WDACTION_RST;
+	val &= ~BBC_WDACTION_RST;
 	writeb(val, bbc_regs + BBC_WDACTION);
 
-	iounmap(bbc_regs);
 	return 0;
 }
 
@@ -249,10 +254,8 @@
 		goto fail;
 	}
 
-	printk(KERN_INFO "pmc: Hardware watchdog [%i minutes, %s reset], "
-	       "regs at %p\n",
-	       riowd_timeout, (riowd_xir ? "XIR" : "POR"),
-	       riowd_regs);
+	printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], "
+	       "regs at %p\n", riowd_timeout, riowd_regs);
 
 	return 0;
 
@@ -261,6 +264,10 @@
 		iounmap(riowd_regs);
 		riowd_regs = NULL;
 	}
+	if (bbc_regs) {
+		iounmap(bbc_regs);
+		bbc_regs = NULL;
+	}
 	return -ENODEV;
 }
 
@@ -269,6 +276,8 @@
 	misc_deregister(&riowd_miscdev);
 	iounmap(riowd_regs);
 	riowd_regs = NULL;
+	iounmap(bbc_regs);
+	bbc_regs = NULL;
 }
 
 module_init(riowd_init);
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.4.3/linux/drivers/sbus/char/sab82532.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/sbus/char/sab82532.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.56 2001/03/15 02:11:10 davem Exp $
+/* $Id: sab82532.c,v 1.58 2001/04/17 06:30:36 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -49,7 +49,7 @@
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-#define SERIAL_PARANOIA_CHECK
+#undef SERIAL_PARANOIA_CHECK
 #define SERIAL_DO_RESTART
 
 /* Set of debugging defines */
@@ -299,15 +299,15 @@
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
  */
-static inline void sab82532_sched_event(struct sab82532 *info, int event)
+static void sab82532_sched_event(struct sab82532 *info, int event)
 {
 	info->event |= 1 << event;
 	queue_task(&info->tqueue, &tq_serial);
 	mark_bh(SERIAL_BH);
 }
 
-static inline void receive_chars(struct sab82532 *info,
-				 union sab82532_irq_status *stat)
+static void receive_chars(struct sab82532 *info,
+			  union sab82532_irq_status *stat)
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char buf[32];
@@ -389,8 +389,8 @@
 	queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
-static inline void transmit_chars(struct sab82532 *info,
-				  union sab82532_irq_status *stat)
+static void transmit_chars(struct sab82532 *info,
+			   union sab82532_irq_status *stat)
 {
 	int i;
 
@@ -446,8 +446,8 @@
 	}
 }
 
-static inline void check_status(struct sab82532 *info,
-				union sab82532_irq_status *stat)
+static void check_status(struct sab82532 *info,
+			 union sab82532_irq_status *stat)
 {
 	struct tty_struct *tty = info->tty;
 	int modem_change = 0;
@@ -1887,10 +1887,6 @@
 	       info->count);
 #endif
 
-	info->count++;
-	tty->driver_data = info;
-	info->tty = tty;
-
 	if (!tmp_buf) {
 		page = get_free_page(GFP_KERNEL);
 		if (!page)
@@ -1901,6 +1897,10 @@
 			tmp_buf = (unsigned char *) page;
 	}
 
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
 	/*
 	 * If the port is in the middle of closing, bail out now.
 	 */
@@ -2151,7 +2151,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.56 $";
+	char *revision = "$Revision: 1.58 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.4.3/linux/drivers/sbus/char/su.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/sbus/char/su.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.45 2001/03/15 02:11:10 davem Exp $
+/* $Id: su.c,v 1.47 2001/04/18 21:06:15 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -11,7 +11,7 @@
 /*
  * Configuration section.
  */
-#define SERIAL_PARANOIA_CHECK
+#undef SERIAL_PARANOIA_CHECK
 #define CONFIG_SERIAL_NOPAUSE_IO	/* Unused on sparc */
 #define SERIAL_DO_RESTART
 
@@ -335,7 +335,7 @@
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
  */
-static __inline__ void
+static void
 su_sched_event(struct su_struct *info, int event)
 {
 	info->event |= 1 << event;
@@ -343,7 +343,7 @@
 	mark_bh(SERIAL_BH);
 }
 
-static __inline__ void
+static void
 receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs, int is_brk)
 {
 	unsigned char status = 0;
@@ -378,7 +378,7 @@
 	} while (status & UART_LSR_DR);
 }
 
-static __inline__ void
+static void
 receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs)
 {
 	struct tty_struct *tty = info->tty;
@@ -471,7 +471,7 @@
 		batten_down_hatches();
 }
 
-static __inline__ void
+static void
 transmit_chars(struct su_struct *info, int *intr_done)
 {
 	int count;
@@ -515,7 +515,7 @@
 	}
 }
 
-static __inline__ void
+static void
 check_modem_status(struct su_struct *info)
 {
 	int	status;
@@ -929,7 +929,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int
+static int
 su_get_baud_rate(struct su_struct *info)
 {
 	static int baud_table[] = {
@@ -2117,7 +2117,7 @@
 /*
  * /proc fs routines....
  */
-static __inline__ int
+static int
 line_info(char *buf, struct su_struct *info)
 {
 	char		stat_buf[30], control, status;
@@ -2220,7 +2220,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.45 $";
+	char *revision = "$Revision: 1.47 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2900,6 +2900,7 @@
 		case 9600:
 		default:
 			cflag |= B9600;
+			baud = 9600;
 			break;
 	}
 	switch (bits) {
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.4.3/linux/drivers/sbus/char/sunserial.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/sbus/char/sunserial.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.78 2001/03/21 22:43:11 davem Exp $
+/* $Id: sunserial.c,v 1.79 2001/04/18 21:06:17 davem Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -308,7 +308,7 @@
 		case 9600: cflag |= B9600; break;
 		case 19200: cflag |= B19200; break;
 		case 38400: cflag |= B38400; break;
-		default: cflag |= B9600; break;
+		default: baud = 9600; cflag |= B9600; break;
 	}
 
 	switch (bits) {
diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.4.3/linux/drivers/sbus/char/zs.c	Thu Jan  4 12:50:17 2001
+++ linux/drivers/sbus/char/zs.c	Thu Apr 19 08:38:49 2001
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.61 2001/01/03 08:08:49 ecd Exp $
+/* $Id: zs.c,v 1.63 2001/04/17 06:30:36 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -217,7 +217,7 @@
  * buffer across all the serial ports, since it significantly saves
  * memory if large numbers of serial ports are open.
  */
-static unsigned char tmp_buf[4096]; /* This is cheating */
+static unsigned char *tmp_buf = 0;
 static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct sun_serial *info,
@@ -252,8 +252,8 @@
  * register access, other machines handle this in hardware via auxiliary
  * flip-flops which implement the settle time we do in software.
  */
-static inline unsigned char read_zsreg(struct sun_zschannel *channel,
-				       unsigned char reg)
+static unsigned char read_zsreg(struct sun_zschannel *channel,
+				unsigned char reg)
 {
 	unsigned char retval;
 
@@ -265,8 +265,8 @@
 	return retval;
 }
 
-static inline void write_zsreg(struct sun_zschannel *channel,
-			       unsigned char reg, unsigned char value)
+static void write_zsreg(struct sun_zschannel *channel,
+			unsigned char reg, unsigned char value)
 {
 	ZSLOG(reg, value, 1);
 	sbus_writeb(reg, &channel->control);
@@ -275,7 +275,7 @@
 	ZSDELAY();
 }
 
-static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
+static void load_zsregs(struct sun_serial *info, unsigned char *regs)
 {
 	struct sun_zschannel *channel = info->zs_channel;
 	unsigned long flags;
@@ -323,7 +323,7 @@
 
 #define ZS_PUT_CHAR_MAX_DELAY	2000	/* 10 ms */
 
-static inline void zs_put_char(struct sun_zschannel *channel, char ch)
+static void zs_put_char(struct sun_zschannel *channel, char ch)
 {
 	int loops = ZS_PUT_CHAR_MAX_DELAY;
 
@@ -346,7 +346,7 @@
 }
 
 /* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct sun_serial *ss, int set)
+static void zs_rtsdtr(struct sun_serial *ss, int set)
 {
 	unsigned long flags;
 
@@ -362,7 +362,7 @@
 	return;
 }
 
-static inline void kgdb_chaninit(struct sun_serial *ss, int intson, int bps)
+static void kgdb_chaninit(struct sun_serial *ss, int intson, int bps)
 {
 	int brg;
 
@@ -475,8 +475,7 @@
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
  */
-static _INLINE_ void zs_sched_event(struct sun_serial *info,
-				    int event)
+static void zs_sched_event(struct sun_serial *info, int event)
 {
 	info->event |= 1 << event;
 	queue_task(&info->tqueue, &tq_serial);
@@ -487,7 +486,7 @@
 extern void breakpoint(void);  /* For the KGDB frame character */
 #endif
 
-static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs)
+static void receive_chars(struct sun_serial *info, struct pt_regs *regs)
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat;
@@ -575,7 +574,7 @@
 		queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
-static _INLINE_ void transmit_chars(struct sun_serial *info)
+static void transmit_chars(struct sun_serial *info)
 {
 	struct tty_struct *tty = info->tty;
 
@@ -611,7 +610,7 @@
 	}
 }
 
-static _INLINE_ void status_handle(struct sun_serial *info)
+static void status_handle(struct sun_serial *info)
 {
 	unsigned char status;
 
@@ -655,7 +654,7 @@
 	return;
 }
 
-static _INLINE_ void special_receive(struct sun_serial *info)
+static void special_receive(struct sun_serial *info)
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat;
@@ -1153,7 +1152,7 @@
 	if (serial_paranoia_check(info, tty->device, "zs_write"))
 		return 0;
 
-	if (!info || !info->xmit_buf)
+	if (!info || !info->xmit_buf || !tmp_buf)
 		return 0;
 
 	save_flags(flags);
@@ -1863,6 +1862,17 @@
 		printk("zs_open %s%d, tty overwrite.\n", tty->driver.name, info->line);
 		return -EBUSY;
 	}
+
+	if (!tmp_buf) {
+		unsigned long page = get_free_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+
 	info->count++;
 	tty->driver_data = info;
 	info->tty = tty;
@@ -1912,7 +1922,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.61 $";
+	char *revision = "$Revision: 1.63 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.4.3/linux/drivers/scsi/53c7,8xx.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/53c7,8xx.c	Wed Apr 11 19:02:36 2001
@@ -175,7 +175,7 @@
  * Architecture : 
  * This driver is built around a Linux queue of commands waiting to 
  * be executed, and a shared Linux/NCR array of commands to start.  Commands
- * are transfered to the array  by the run_process_issue_queue() function 
+ * are transferred to the array  by the run_process_issue_queue() function 
  * which is called whenever a command completes.
  *
  * As commands are completed, the interrupt routine is triggered,
@@ -1899,7 +1899,6 @@
 		hostdata->script, start);
 	    printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
 		NCR53c7x0_read32(DSPS_REG));
-	    restore_flags(flags);
 	    return -1;
 	}
     	hostdata->test_running = 0;
@@ -5272,7 +5271,7 @@
      * chances of this happening, and handle it if it occurs anyway.
      *
      * Simply continue with what we were doing, and control should
-     * be transfered to the schedule routine which will ultimately
+     * be transferred to the schedule routine which will ultimately
      * pass control onto the reselection or selection (not yet)
      * code.
      */
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h
--- v2.4.3/linux/drivers/scsi/53c7,8xx.h	Mon Dec 11 13:19:31 2000
+++ linux/drivers/scsi/53c7,8xx.h	Wed Apr 11 19:02:37 2001
@@ -1515,11 +1515,11 @@
 /* Patch field in dsa structure (assignment should be +=?) */
 #define patch_dsa_32(dsa, symbol, word, value)				\
 	{								\
-	(dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32)	\
+	(dsa)[(hostdata->symbol - hostdata->dsa_start) / sizeof(u32)	\
 	    + (word)] = (value);					\
 	if (hostdata->options & OPTION_DEBUG_DSA)			\
 	    printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",	\
-		#dsa, #symbol, hostdata->##symbol, 			\
+		#dsa, #symbol, hostdata->symbol, 			\
 		(word), (u32) le32_to_cpu(value));			\
 	}
 
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.4.3/linux/drivers/scsi/53c7xx.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/53c7xx.c	Fri Apr 13 20:26:07 2001
@@ -198,7 +198,7 @@
  * Architecture : 
  * This driver is built around a Linux queue of commands waiting to 
  * be executed, and a shared Linux/NCR array of commands to start.  Commands
- * are transfered to the array  by the run_process_issue_queue() function 
+ * are transferred to the array  by the run_process_issue_queue() function 
  * which is called whenever a command completes.
  *
  * As commands are completed, the interrupt routine is triggered,
@@ -1077,19 +1077,18 @@
     {
 	printk("scsi%d : IRQ%d not free, detaching\n",
 		host->host_no, host->irq);
-	scsi_unregister (host);
-	return -1;
+	goto err_unregister;
     } 
 
     if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
         (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
     	/* XXX Should disable interrupts, etc. here */
-	scsi_unregister (host);
-    	return -1;
+	goto err_free_irq;
     } else {
 	if (host->io_port)  {
 	    host->n_io_port = 128;
-	    request_region (host->io_port, host->n_io_port, "ncr53c7xx");
+	    if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx"))
+		goto err_free_irq;
 	}
     }
     
@@ -1098,6 +1097,12 @@
 	hard_reset (host);
     }
     return 0;
+
+ err_free_irq:
+    free_irq(host->irq,  NCR53c7x0_intr);
+ err_unregister:
+    scsi_unregister(host);
+    return -1;
 }
 
 /* 
@@ -1206,8 +1211,11 @@
     size += 256;
 #endif
     /* Size should be < 8K, so we can fit it in two pages. */
-    if (size > 8192)
-      panic("53c7xx: hostdata > 8K");
+    if (size > 8192) {
+      printk(KERN_ERR "53c7xx: hostdata > 8K\n");
+      return -1;
+    }
+
     instance = scsi_register (tpnt, 4);
     if (!instance)
     {
@@ -3091,8 +3099,10 @@
 #endif
 /* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
 
-        if (size > 4096)
-            panic ("53c7xx: allocate_cmd size > 4K");
+        if (size > 4096) {
+            printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
+	    return NULL;
+	}
         real = get_free_page(GFP_ATOMIC);
         if (real == 0)
         	return NULL;
@@ -3272,7 +3282,7 @@
 
     /*
      * The saved data pointer is set up so that a RESTORE POINTERS message 
-     * will start the data transfer over at the begining.
+     * will start the data transfer over at the beginning.
      */
 
     tmp->saved_data_pointer = virt_to_bus (hostdata->script) + 
@@ -4965,7 +4975,7 @@
      * chances of this happening, and handle it if it occurs anyway.
      *
      * Simply continue with what we were doing, and control should
-     * be transfered to the schedule routine which will ultimately
+     * be transferred to the schedule routine which will ultimately
      * pass control onto the reselection or selection (not yet)
      * code.
      */
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7xx.scr linux/drivers/scsi/53c7xx.scr
--- v2.4.3/linux/drivers/scsi/53c7xx.scr	Sat Mar 21 11:09:47 1998
+++ linux/drivers/scsi/53c7xx.scr	Fri Apr 13 20:26:07 2001
@@ -1136,7 +1136,7 @@
 #if (CHIP == 710)
 #if defined(MVME16x_INTFLY)
 ; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software
-; interupt (SW7).  We can use SCRATCH, as we are about to jump to
+; interrupt (SW7).  We can use SCRATCH, as we are about to jump to
 ; schedule, which corrupts it anyway.  Will probably remove this later,
 ; but want to check performance effects first.
 
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.4.3/linux/drivers/scsi/advansys.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/advansys.c	Thu Apr 12 12:16:35 2001
@@ -1,10 +1,10 @@
-/* $Id: advansys.c,v 1.69 1999/11/29 18:37:53 bobf Exp bobf $ */
-#define ASC_VERSION "3.2M"    /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3G"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
- * 
- * Copyright (c) 1995-1999 Advanced System Products, Inc.
+ *
+ * Copyright (c) 1995-2000 Advanced System Products, Inc.
+ * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
  * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,52 +12,51 @@
  * code retain the above copyright notice and this comment without
  * modification.
  *
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ *
  * There is an AdvanSys Linux WWW page at:
+ *  http://www.connectcom.net/downloads/software/os/linux.html
  *  http://www.advansys.com/linux.html
  *
- * The latest version of the AdvanSys driver is available at:
+ * The latest released version of the AdvanSys driver is available at:
  *  ftp://ftp.advansys.com/pub/linux/linux.tgz
+ *  ftp://ftp.connectcom.net/pub/linux/linux.tgz
  *
  * Please send questions, comments, bug reports to:
- *  linux@advansys.com
+ *  support@connectcom.net
  */
 
 /*
 
   Documentation for the AdvanSys Driver
 
-  A. Linux Kernel Testing
+  A. Linux Kernels Supported by this Driver
   B. Adapters Supported by this Driver
-  C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
-  D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
-  E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
-  F. Source Comments
-  G. Driver Compile Time Options and Debugging
-  H. Driver LILO Option
-  I. Release History
-  J. Known Problems/Fix List
-  K. Credits
-  L. AdvanSys Contact Information
-
-  A. Linux Kernel Testing
-
-     This driver has been tested in the following Linux kernels: v1.2.13,
-     v1.3.57, v2.0.38, v2.2.13, and v2.3.28. These kernel versions are major
-     releases of Linux or the latest Linux kernel versions available when
-     this version of the driver was released. The driver should also work
-     in earlier versions of the Linux kernel. Beginning with v1.3.58 the
-     AdvanSys driver is included with all Linux kernels. Please refer to
-     sections C, D, and E for instructions on adding or upgrading the
-     AdvanSys driver. The driver is supported for x86 and alpha systems.
+  C. Linux source files modified by AdvanSys Driver
+  D. Source Comments
+  E. Driver Compile Time Options and Debugging
+  F. Driver LILO Option
+  G. Tests to run before releasing new driver
+  H. Release History
+  I. Known Problems/Fix List
+  J. Credits (Chronological Order)
+  K. ConnectCom (AdvanSys) Contact Information
+
+  A. Linux Kernels Supported by this Driver
+
+     This driver has been tested in the following Linux kernels: v2.2.18
+     v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
+     alpha, and PowerPC platforms.
 
   B. Adapters Supported by this Driver
- 
+
      AdvanSys (Advanced System Products, Inc.) manufactures the following
      RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
      (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
      buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
      transfer) SCSI Host Adapters for the PCI bus.
-     
+
      The CDB counts below indicate the number of SCSI CDB (Command
      Descriptor Block) requests that can be stored in the RISC chip
      cache and board LRAM. A CDB is a single SCSI command. The driver
@@ -65,6 +64,9 @@
      adapter detected. The number of CDBs used by the driver can be
      lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
 
+     Laptop Products:
+        ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
+
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB)
         ABP5140 - Bus-Master ISA PnP (16 CDB)
@@ -80,7 +82,7 @@
         ABP930UA - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB)
         ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
-     
+
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
         ABP742 - Bus-Master EISA (240 CDB)
@@ -94,7 +96,7 @@
         ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
         ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
         ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
-     
+
      Multi-Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
         ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
@@ -104,37 +106,33 @@
         ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
         ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
         ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
-     
-  C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
+        ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
+
+  C. Linux source files modified by AdvanSys Driver
+
+     This section for historical purposes documents the changes
+     originally made to the Linux kernel source to add the advansys
+     driver. As Linux has changed some of these files have also
+     been modified.
+
+     1. linux/arch/i386/config.in:
 
-     These directions apply to v1.2.13. For versions that follow v1.2.13.
-     but precede v1.3.57 some of the changes for Linux v1.3.X listed
-     below may need to be modified or included. A patch is available
-     for v1.2.13 from the AdvanSys WWW and FTP sites.
- 
-     There are two source files: advansys.h and advansys.c. Copy
-     both of these files to the directory /usr/src/linux/drivers/scsi.
-    
-     1. Add the following line to /usr/src/linux/arch/i386/config.in
-        after "comment 'SCSI low-level drivers'":
-    
           bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
-    
-     2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c
-        after "#include "hosts.h"":
-    
+
+     2. linux/drivers/scsi/hosts.c:
+
           #ifdef CONFIG_SCSI_ADVANSYS
           #include "advansys.h"
           #endif
-    
+
         and after "static Scsi_Host_Template builtin_scsi_hosts[] =":
-    
+
           #ifdef CONFIG_SCSI_ADVANSYS
           ADVANSYS,
           #endif
-    
-     3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile:
-    
+
+     3. linux/drivers/scsi/Makefile:
+
           ifdef CONFIG_SCSI_ADVANSYS
           SCSI_SRCS := $(SCSI_SRCS) advansys.c
           SCSI_OBJS := $(SCSI_OBJS) advansys.o
@@ -142,12 +140,7 @@
           SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
           endif
 
-     4. (Optional) If you would like to enable the LILO command line
-        and /etc/lilo.conf 'advansys' option, make the following changes.
-        This option can be used to disable I/O port scanning or to limit
-        I/O port scanning to specific addresses. Refer to the 'Driver
-        LILO Option' section below. Add the following lines to
-        /usr/src/linux/init/main.c in the prototype section:
+     4. linux/init/main.c:
 
           extern void advansys_setup(char *str, int *ints);
 
@@ -157,118 +150,19 @@
              { "advansys=", advansys_setup },
           #endif
 
-     5. If you have the HP 4020i CD-R driver and Linux v1.2.X you should
-        add a fix to the CD-ROM target driver. This fix will allow
-        you to mount CDs with the iso9660 file system. Linux v1.3.X
-        already has this fix. In the file /usr/src/linux/drivers/scsi/sr.c
-        and function get_sectorsize() after the line:
-
-        if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048;
-
-        add the following line:
-
-        if(scsi_CDs[i].sector_size == 2340) scsi_CDs[i].sector_size = 2048;
-
-     6. In the directory /usr/src/linux run 'make config' to configure
-        the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to
-        make the kernel. If the AdvanSys driver is not configured, then
-        a loadable module can be built by running 'make modules' and
-        'make modules_install'. Use 'insmod' and 'rmmod' to install
-        and remove advansys.o.
- 
-  D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
-
-     These directions apply to v1.3.57. For versions that precede v1.3.57
-     some of these changes may need to be modified or eliminated. A patch
-     is available for v1.3.57 from the AdvanSys WWW and FTP sites.
-     Beginning with v1.3.58 this driver is included with the Linux
-     distribution eliminating the need for making any changes.
-
-     There are two source files: advansys.h and advansys.c. Copy
-     both of these files to the directory /usr/src/linux/drivers/scsi.
-   
-     1. Add the following line to /usr/src/linux/drivers/scsi/Config.in
-        after "comment 'SCSI low-level drivers'":
-   
-          dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
-   
-     2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c
-        after "#include "hosts.h"":
-   
-          #ifdef CONFIG_SCSI_ADVANSYS
-          #include "advansys.h"
-          #endif
-   
-        and after "static Scsi_Host_Template builtin_scsi_hosts[] =":
-   
-          #ifdef CONFIG_SCSI_ADVANSYS
-          ADVANSYS,
-          #endif
-   
-     3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile:
-   
-          ifeq ($(CONFIG_SCSI_ADVANSYS),y)
-          L_OBJS += advansys.o
-          else
-            ifeq ($(CONFIG_SCSI_ADVANSYS),m)
-            M_OBJS += advansys.o
-            endif
-          endif
-   
-     4. Add the following line to /usr/src/linux/include/linux/proc_fs.h
-        in the enum scsi_directory_inos array:
-   
-          PROC_SCSI_ADVANSYS,
-   
-     5. (Optional) If you would like to enable the LILO command line
-        and /etc/lilo.conf 'advansys' option, make the following changes.
-        This option can be used to disable I/O port scanning or to limit
-        I/O port scanning to specific addresses. Refer to the 'Driver
-        LILO Option' section below. Add the following lines to
-        /usr/src/linux/init/main.c in the prototype section:
-   
-          extern void advansys_setup(char *str, int *ints);
-   
-        and add the following lines to the bootsetups[] array.
-   
-          #ifdef CONFIG_SCSI_ADVANSYS
-             { "advansys=", advansys_setup },
-          #endif
-   
-     6. In the directory /usr/src/linux run 'make config' to configure
-        the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to
-        make the kernel. If the AdvanSys driver is not configured, then
-        a loadable module can be built by running 'make modules' and
-        'make modules_install'. Use 'insmod' and 'rmmod' to install
-        and remove advansys.o.
-
-  E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
-
-     To upgrade the AdvanSys driver in a Linux v1.3.58 and newer
-     kernel, first check the version of the current driver. The
-     version is defined by the manifest constant ASC_VERSION at
-     the beginning of advansys.c. The new driver should have a
-     ASC_VERSION value greater than the current version. To install
-     the new driver rename advansys.c and advansys.h in the Linux
-     kernel source tree drivers/scsi directory to different names
-     or save them to a different directory in case you want to revert
-     to the old version of the driver. After the old driver is saved
-     copy the new advansys.c and advansys.h to drivers/scsi, rebuild
-     the kernel, and install the new kernel. No other changes are needed.
+  D. Source Comments
 
-  F. Source Comments
- 
      1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
- 
+
      2. This driver should be maintained in multiple files. But to make
         it easier to include with Linux and to follow Linux conventions,
         the whole driver is maintained in the source files advansys.h and
         advansys.c. In this file logical sections of the driver begin with
         a comment that contains '---'. The following are the logical sections
         of the driver below.
- 
+
            --- Linux Version
-           --- Linux Include Files 
+           --- Linux Include File
            --- Driver Options
            --- Debugging Header
            --- Asc Library Constants and Macros
@@ -285,27 +179,27 @@
            --- Tracing and Debugging Functions
            --- Asc Library Functions
            --- Adv Library Functions
- 
+
      3. The string 'XXX' is used to flag code that needs to be re-written
         or that contains a problem that needs to be addressed.
- 
+
      4. I have stripped comments from and reformatted the source for the
         Asc Library and Adv Library to reduce the size of this file. This
         source can be found under the following headings. The Asc Library
         is used to support Narrow Boards. The Adv Library is used to
         support Wide Boards.
- 
+
            --- Asc Library Constants and Macros
            --- Adv Library Constants and Macros
            --- Asc Library Functions
            --- Adv Library Functions
- 
-  G. Driver Compile Time Options and Debugging
- 
+
+  E. Driver Compile Time Options and Debugging
+
      In this source file the following constants can be defined. They are
      defined in the source below. Both of these options are enabled by
      default.
- 
+
      1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
 
         Enabling this option adds assertion logic statements to the
@@ -325,11 +219,11 @@
         the kernel name space. This option is very useful for debugging
         the driver, but it will add to the size of the driver execution
         image and add overhead to the execution of the driver.
- 
+
         The amount of debugging output can be controlled with the global
         variable 'asc_dbglvl'. The higher the number the more output. By
         default the debug level is 0.
-        
+
         If the driver is loaded at boot time and the LILO Driver Option
         is included in the system, the debug level can be changed by
         specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
@@ -343,28 +237,44 @@
         If the driver is built as a loadable module this variable can be
         defined when the driver is loaded. The following insmod command
         will set the debug level to one.
-  
+
            insmod advansys.o asc_dbglvl=1
- 
+
         Debugging Message Levels:
            0: Errors Only
            1: High-Level Tracing
            2-N: Verbose Tracing
- 
-        I don't know the approved way for turning on printk()s to the
-        console. Here's a program I use to do this. Debug output is
-        logged in /var/adm/messages.
- 
+
+        To enable debug output to console, please make sure that:
+
+        a. System and kernel logging is enabled (syslogd, klogd running).
+        b. Kernel messages are routed to console output. Check
+           /etc/syslog.conf for an entry similar to this:
+
+                kern.*                  /dev/console
+
+        c. klogd is started with the appropriate -c parameter
+           (e.g. klogd -c 8)
+
+        This will cause printk() messages to be be displayed on the
+        current console. Refer to the klogd(8) and syslogd(8) man pages
+        for details.
+
+        Alternatively you can enable printk() to console with this
+        program. However, this is not the 'official' way to do this.
+        Debug output is logged in /var/log/messages.
+
           main()
           {
                   syscall(103, 7, 0, 0);
           }
- 
-        I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c
-        prevents most level 1 debug messages from being lost.
+
+        Increasing LOG_BUF_LEN in kernel/printk.c to something like
+        40960 allows more debug messages to be buffered in the kernel
+        and written to the console or log file.
 
      3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
- 
+
         Enabling this option adds statistics collection and display
         through /proc to the driver. The information is useful for
         monitoring driver and device performance. It will add to the
@@ -387,8 +297,8 @@
         When ADVANSYS_STATS is not defined the AdvanSys /proc files only
         contain adapter and device configuration information.
 
-  H. Driver LILO Option
- 
+  F. Driver LILO Option
+
      If init/main.c is modified as described in the 'Directions for Adding
      the AdvanSys Driver to Linux' section (B.4.) above, the driver will
      recognize the 'advansys' LILO command line and /etc/lilo.conf option.
@@ -418,9 +328,24 @@
      the 'Driver Compile Time Options and Debugging' section above for
      more information.
 
-  I. Release History
+  G. Tests to run before releasing new driver
+
+     1. In the supported kernels verify there are no warning or compile
+        errors when the kernel is built as both a driver and as a module
+        and with the following options:
+
+        ADVANSYS_DEBUG - enabled and disabled
+        CONFIG_SMP - enabled and disabled
+        CONFIG_PROC_FS - enabled and disabled
+
+     2. Run tests on an x86, alpha, and PowerPC with at least one narrow
+        card and one wide card attached to a hard disk and CD-ROM drive:
+        fdisk, mkfs, fsck, bonnie, copy/compare test from the
+        CD-ROM to the hard drive.
+
+  H. Release History
 
-     BETA-1.0 (12/23/95): 
+     BETA-1.0 (12/23/95):
          First Release
 
      BETA-1.1 (12/28/95):
@@ -454,7 +379,7 @@
          4. Remove reset request loop problem from the "Known Problems or
             Issues" section. This problem was isolated and fixed in the
             mid-level SCSI driver.
-        
+
      1.5 (8/8/96):
          1. Add support for ABP-940U (PCI Ultra) adapter.
          2. Add support for IRQ sharing by setting the SA_SHIRQ flag for
@@ -677,7 +602,75 @@
          1. Really fix bug in adv_get_sglist().
          2. Incorporate v2.3.29 changes into driver.
 
-  J. Known Problems/Fix List (XXX)
+     3.2N (4/1/00):
+         1. Add CONFIG_ISA ifdef code.
+         2. Include advansys_interrupts_enabled name change patch.
+         3. For >= v2.3.28 use new SCSI error handling with new function
+            advansys_eh_bus_reset(). Don't include an abort function
+            because of base library limitations.
+         4. For >= v2.3.28 use per board lock instead of io_request_lock.
+         5. For >= v2.3.28 eliminate advansys_command() and
+            advansys_command_done().
+         6. Add some changes for PowerPC (Big Endian) support, but it isn't
+            working yet.
+         7. Fix "nonexistent resource free" problem that occurred on a module
+            unload for boards with an I/O space >= 255. The 'n_io_port' field
+            is only one byte and can not be used to hold an ioport length more
+            than 255.
+
+     3.3A (4/4/00):
+         1. Update to Adv Library 5.8.
+         2. For wide cards add support for CDBs up to 16 bytes.
+         3. Eliminate warnings when CONFIG_PROC_FS is not defined.
+
+     3.3B (5/1/00):
+         1. Support for PowerPC (Big Endian) wide cards. Narrow cards
+            still need work.
+         2. Change bitfields to shift and mask access for endian
+            portability.
+
+     3.3C (10/13/00):
+         1. Update for latest 2.4 kernel.
+         2. Test ABP-480 CardBus support in 2.4 kernel - works!
+         3. Update to Asc Library S123.
+         4. Update to Adv Library 5.12.
+
+     3.3D (11/22/00):
+         1. Update for latest 2.4 kernel.
+         2. Create patches for 2.2 and 2.4 kernels.
+
+     3.3E (1/9/01):
+         1. Now that 2.4 is released remove ifdef code for kernel versions
+            less than 2.2. The driver is now only supported in kernels 2.2,
+            2.4, and greater.
+         2. Add code to release and acquire the io_request_lock in
+            the driver entrypoint functions: advansys_detect and
+            advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
+            still holds the io_request_lock on entry to SCSI low-level drivers.
+            This was supposed to be removed before 2.4 was released but never
+            happened. When the mid-level SCSI driver is changed all references
+            to the io_request_lock should be removed from the driver.
+         3. Simplify error handling by removing advansys_abort(),
+            AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
+            now handled by resetting the SCSI bus and fully re-initializing
+            the chip. This simple method of error recovery has proven to work
+            most reliably after attempts at different methods. Also now only
+            support the "new" error handling method and remove the obsolete
+            error handling interface.
+         4. Fix debug build errors.
+
+     3.3F (1/24/01):
+         1. Merge with ConnectCom version from Andy Kellner which
+            updates Adv Library to 5.14.
+         2. Make PowerPC (Big Endian) work for narrow cards and
+            fix problems writing EEPROM for wide cards.
+         3. Remove interrupts_enabled assertion function.
+
+     3.3G (2/16/01):
+         1. Return an error from narrow boards if passed a 16 byte
+            CDB. The wide board can already handle 16 byte CDBs.
+
+  I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
         If it doesn't work revert to I/O port access. Can a test be done
@@ -687,12 +680,12 @@
         has not occurred then print a message and run in polled mode.
      3. Allow bus type scanning order to be changed.
      4. Need to add support for target mode commands, cf. CAM XPT.
-     5  Need to add support for new Linux SCSI error handling method.
-     6. Need to fix sti/cli code in Asc Library.
-     7. Need to fix abort code in Adv Library.
-     8. Reduce io_request_lock hold time.
 
-  K. Credits
+  J. Credits (Chronological Order)
+
+     Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
+     and maintained it up to 3.3F. He continues to answer questions
+     and help maintain the driver.
 
      Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
      basis for the Linux v1.3.X changes which were included in the
@@ -712,22 +705,47 @@
      support in the 3.1A driver.
 
      Doug Gilbert <dgilbert@interlog.com> has made changes and
-     suggestions to improve the driver and done testing.
+     suggestions to improve the driver and done a lot of testing.
 
      Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
      in 3.2K.
 
-  L. AdvanSys Contact Information
- 
-     Mail:                   Advanced System Products, Inc.
+     Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
+     patch and helped with PowerPC wide and narrow board support.
+
+     Philip Blundell <philip.blundell@pobox.com> provided an
+     advansys_interrupts_enabled patch.
+
+     Dave Jones <dave@denial.force9.co.uk> reported the compiler
+     warnings generated when CONFIG_PROC_FS was not defined in
+     the 3.2M driver.
+
+     Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
+     problems) for wide cards.
+
+     Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
+     card error handling.
+
+     Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
+     board support and fixed a bug in AscGetEEPConfig().
+
+     Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
+     save_flags/restore_flags changes.
+
+     Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
+     driver development for ConnectCom (Version > 3.3F).
+
+  K. ConnectCom (AdvanSys) Contact Information
+
+     Mail:                   ConnectCom Solutions, Inc.
                              1150 Ringwood Court
                              San Jose, CA 95131
      Operator/Sales:         1-408-383-9400
      FAX:                    1-408-383-9612
      Tech Support:           1-408-467-2930
-     Tech Support E-Mail:    support@advansys.com
-     FTP Site:               ftp.advansys.com (login: anonymous)
-     Web Site:               http://www.advansys.com
+     Tech Support E-Mail:    linux@connectcom.net
+     FTP Site:               ftp.connectcom.net (login: anonymous)
+     Web Site:               http://www.connectcom.net
 
 */
 
@@ -736,78 +754,62 @@
  * --- Linux Version
  */
 
-/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
-#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
-
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
+/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
+#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
+#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0))
+#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0))
+
+/* Driver supported only in version 2.2 and version >= 2.4. */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \
+    (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \
+     LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0))
+#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels."
+#endif
 
 /*
- * --- Linux Include Files 
+ * --- Linux Include Files
  */
 
 #include <linux/config.h>
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 #ifdef MODULE
 #include <linux/module.h>
 #endif /* MODULE */
-#endif /* version >= v1.3.0 */
+
+#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
+#define CONFIG_ISA
+#endif /* CONFIG_X86 && !CONFIG_ISA */
+
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-#include <linux/head.h>
-#endif /* verions < v2.1.0 */
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/mm.h>
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 #include <linux/proc_fs.h>
-#endif /* version >= v1.3.0 */
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
-#endif /* version >= v2.1.23 */
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/dma.h>
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-#include "../block/blk.h"
-#else /* version >= v1.3.0 */
 #include <linux/blk.h>
 #include <linux/stat.h>
-#endif /* version >= v1.3.0 */
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,18)
+#if ASC_LINUX_KERNEL24
 #include <linux/spinlock.h>
-#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+#elif ASC_LINUX_KERNEL22
 #include <asm/spinlock.h>
-#endif /* version >= 2.1.95 */
+#endif
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
 #include "advansys.h"
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,93)
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif /* CONFIG_PCI */
-#else /* version < v2.1.93 */
-/*
- * For earlier than v2.1.93 the driver has its own PCI configuration.
- * If PCI is not needed in a kernel before v2.1.93 this define can be
- * turned-off to make the driver object smaller.
- */
-#define ASC_CONFIG_PCI
-#endif /* version < v2.1.93 */
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-#define cpu_to_le16(word)       (word)
-#define le16_to_cpu(word)       (word)
-#define cpu_to_le32(dword)      (dword)
-#define le32_to_cpu(dword)      (dword)
-#endif /* version < v2.1.0 */
 
 
 /*
@@ -817,19 +819,12 @@
 /* Enable driver assertions. */
 #define ADVANSYS_ASSERT
 
+/* Enable driver /proc statistics. */
+#define ADVANSYS_STATS
+
 /* Enable driver tracing. */
 /* #define ADVANSYS_DEBUG */
 
-/*
- * Because of no /proc to display them, statistics are disabled
- * for versions prior to v1.3.0.
- */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-#undef ADVANSYS_STATS /* Disable statistics */
-#else /* version >= v1.3.0 */
-#define ADVANSYS_STATS /* Enable statistics. */
-#endif /* version >= v1.3.0 */
-
 
 /*
  * --- Debugging Header
@@ -848,7 +843,7 @@
 
 #define ASC_LIB_VERSION_MAJOR  1
 #define ASC_LIB_VERSION_MINOR  24
-#define ASC_LIB_SERIAL_NUMBER  121
+#define ASC_LIB_SERIAL_NUMBER  123
 
 /*
  * Portable Data Types
@@ -858,7 +853,7 @@
  * types must be used. In Linux the char, short, and int types
  * are all consistent at 8, 16, and 32 bits respectively. Pointers
  * and long types are 64 bits on Alpha and UltraSPARC.
- */ 
+ */
 #define ASC_PADDR __u32         /* Physical/Bus address data type. */
 #define ASC_VADDR __u32         /* Virtual address data type. */
 #define ASC_DCNT  __u32         /* Unsigned Data count type. */
@@ -907,7 +902,7 @@
 #define ASC_PCI_VENDORID                  0x10CD
 #define ASC_PCI_DEVICEID_1200A            0x1100
 #define ASC_PCI_DEVICEID_1200B            0x1200
-#define ASC_PCI_DEVICEID_ULTRA            0x1300 
+#define ASC_PCI_DEVICEID_ULTRA            0x1300
 #define ASC_PCI_REVISION_3150             0x02
 #define ASC_PCI_REVISION_3050             0x03
 
@@ -924,13 +919,13 @@
 #define CC_VERY_LONG_SG_LIST 0
 #define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
 
-#define PortAddr            unsigned short    /* port address size  */
-#define inp(port)           inb(port)
-#define inpw(port)          inw(port)
-#define inpl(port)          inl(port)
-#define outp(port, byte)    outb((byte), (port))
-#define outpw(port, word)   outw((word), (port))
-#define outpl(port, dword) outl((dword), (port))
+#define PortAddr                 unsigned short    /* port address size  */
+#define inp(port)                inb(port)
+#define outp(port, byte)         outb((byte), (port))
+
+#define inpw(port)               inw(port)
+#define outpw(port, word)        outw((word), (port))
+
 #define ASC_MAX_SG_QUEUE    7
 #define ASC_MAX_SG_LIST     255
 
@@ -977,12 +972,7 @@
 #define ASC_MAX_ISA_DMA_COUNT   (0x00FFFFFFL)
 #define ASC_MAX_EISA_DMA_ADDR   (0x07FFFFFFL)
 #define ASC_MAX_EISA_DMA_COUNT  (0x07FFFFFFL)
-#ifndef inpw_noswap
-#define inpw_noswap(port)         inpw(port)
-#endif
-#ifndef outpw_noswap
-#define outpw_noswap(port, data)  outpw(port, data)
-#endif
+
 #define ASC_SCSI_ID_BITS  3
 #define ASC_SCSI_TIX_TYPE     uchar
 #define ASC_ALL_DEVICE_BIT_SET  0xFF
@@ -1024,6 +1014,8 @@
 #define SCSICMD_ReadHeader        0x44
 #define SCSICMD_ModeSelect10      0x55
 #define SCSICMD_ModeSense10       0x5A
+
+/* Inquiry Data Peripheral Device Types */
 #define SCSI_TYPE_DASD     0x00
 #define SCSI_TYPE_SASD     0x01
 #define SCSI_TYPE_PRN      0x02
@@ -1035,10 +1027,20 @@
 #define SCSI_TYPE_MED_CHG  0x08
 #define SCSI_TYPE_COMM     0x09
 #define SCSI_TYPE_UNKNOWN  0x1F
-#define SCSI_TYPE_NO_DVC   0xFF
-#define INQ_CLOCKING_ST_ONLY    0x0
-#define INQ_CLOCKING_DT_ONLY    0x1
-#define INQ_CLOCKING_ST_AND_DT  0x3
+
+#define ADV_INQ_CLOCKING_ST_ONLY    0x0
+#define ADV_INQ_CLOCKING_DT_ONLY    0x1
+#define ADV_INQ_CLOCKING_ST_AND_DT  0x3
+
+/*
+ * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
+ * and CmdDt (Command Support Data) field bit definitions.
+ */
+#define ADV_INQ_RTN_VPD_AND_CMDDT           0x3
+#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE       0x2
+#define ADV_INQ_RTN_VPD_FOR_PG_CODE         0x1
+#define ADV_INQ_RTN_STD_INQUIRY_DATA        0x0
+
 #define ASC_SCSIDIR_NOCHK    0x00
 #define ASC_SCSIDIR_T2H      0x08
 #define ASC_SCSIDIR_H2T      0x10
@@ -1102,77 +1104,49 @@
 #define M2_QTAG_MSG_ORDERED     0x22
 #define M2_IGNORE_WIDE_RESIDUE  0x23
 
-typedef struct {
-    uchar               peri_dvc_type:5;
-    uchar               peri_qualifier:3;
-} ASC_SCSI_INQ0;
-
-typedef struct {
-    uchar               dvc_type_modifier:7;
-    uchar               rmb:1;
-} ASC_SCSI_INQ1;
-
-typedef struct {
-    uchar               ansi_apr_ver:3;
-    uchar               ecma_ver:3;
-    uchar               iso_ver:2;
-} ASC_SCSI_INQ2;
-
-typedef struct {
-    uchar               rsp_data_fmt:4;
-    uchar               res:2;
-    uchar               TemIOP:1;
-    uchar               aenc:1;
-} ASC_SCSI_INQ3;
-
-typedef struct {
-    uchar               StfRe:1;
-    uchar               CmdQue:1;
-    uchar               Reserved:1;
-    uchar               Linked:1;
-    uchar               Sync:1;
-    uchar               WBus16:1;
-    uchar               WBus32:1;
-    uchar               RelAdr:1;
-} ASC_SCSI_INQ7;
+/*
+ * Inquiry data structure and bitfield macros
+ *
+ * Only quantities of more than 1 bit are shifted, since the others are
+ * just tested for true or false. C bitfields aren't portable between big
+ * and little-endian platforms so they are not used.
+ */
+
+#define ASC_INQ_DVC_TYPE(inq)       ((inq)->periph & 0x1f)
+#define ASC_INQ_QUALIFIER(inq)      (((inq)->periph & 0xe0) >> 5)
+#define ASC_INQ_DVC_TYPE_MOD(inq)   ((inq)->devtype & 0x7f)
+#define ASC_INQ_REMOVABLE(inq)      ((inq)->devtype & 0x80)
+#define ASC_INQ_ANSI_VER(inq)       ((inq)->ver & 0x07)
+#define ASC_INQ_ECMA_VER(inq)       (((inq)->ver & 0x38) >> 3)
+#define ASC_INQ_ISO_VER(inq)        (((inq)->ver & 0xc0) >> 6)
+#define ASC_INQ_RESPONSE_FMT(inq)   ((inq)->byte3 & 0x0f)
+#define ASC_INQ_TERM_IO(inq)        ((inq)->byte3 & 0x40)
+#define ASC_INQ_ASYNC_NOTIF(inq)    ((inq)->byte3 & 0x80)
+#define ASC_INQ_SOFT_RESET(inq)     ((inq)->flags & 0x01)
+#define ASC_INQ_CMD_QUEUE(inq)      ((inq)->flags & 0x02)
+#define ASC_INQ_LINK_CMD(inq)       ((inq)->flags & 0x08)
+#define ASC_INQ_SYNC(inq)           ((inq)->flags & 0x10)
+#define ASC_INQ_WIDE16(inq)         ((inq)->flags & 0x20)
+#define ASC_INQ_WIDE32(inq)         ((inq)->flags & 0x40)
+#define ASC_INQ_REL_ADDR(inq)       ((inq)->flags & 0x80)
+#define ASC_INQ_INFO_UNIT(inq)      ((inq)->info & 0x01)
+#define ASC_INQ_QUICK_ARB(inq)      ((inq)->info & 0x02)
+#define ASC_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
 
 typedef struct {
-    ASC_SCSI_INQ0       byte0;
-    ASC_SCSI_INQ1       byte1;
-    ASC_SCSI_INQ2       byte2;
-    ASC_SCSI_INQ3       byte3;
+    uchar               periph;
+    uchar               devtype;
+    uchar               ver;
+    uchar               byte3;
     uchar               add_len;
     uchar               res1;
     uchar               res2;
-    ASC_SCSI_INQ7       byte7;
+    uchar               flags;
     uchar               vendor_id[8];
     uchar               product_id[16];
     uchar               product_rev_level[4];
 } ASC_SCSI_INQUIRY;
 
-typedef struct asc_req_sense {
-    uchar               err_code:7;
-    uchar               info_valid:1;
-    uchar               segment_no;
-    uchar               sense_key:4;
-    uchar               reserved_bit:1;
-    uchar               sense_ILI:1;
-    uchar               sense_EOM:1;
-    uchar               file_mark:1;
-    uchar               info1[4];
-    uchar               add_sense_len;
-    uchar               cmd_sp_info[4];
-    uchar               asc;
-    uchar               ascq;
-    uchar               fruc;
-    uchar               sks_byte0:7;
-    uchar               sks_valid:1;
-    uchar               sks_bytes[2];
-    uchar               notused[2];
-    uchar               ex_sense_code;
-    uchar               info2[4];
-} ASC_REQ_SENSE;
-
 #define ASC_SG_LIST_PER_Q   7
 #define QS_FREE        0x00
 #define QS_READY       0x01
@@ -1286,7 +1260,7 @@
 #define ASC_TIX_TO_LUN(tix)         (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
 #define ASC_QNO_TO_QADDR(q_no)      ((ASC_QADR_BEG)+((int)(q_no) << 6))
 
-typedef struct asc_scisq_1 {
+typedef struct asc_scsiq_1 {
     uchar               status;
     uchar               q_no;
     uchar               cntl;
@@ -1300,7 +1274,7 @@
     uchar               extra_bytes;
 } ASC_SCSIQ_1;
 
-typedef struct asc_scisq_2 {
+typedef struct asc_scsiq_2 {
     ASC_VADDR           srb_ptr;
     uchar               target_ix;
     uchar               flag;
@@ -1378,8 +1352,8 @@
 typedef struct asc_scsi_req_q {
     ASC_SCSIQ_1         r1;
     ASC_SCSIQ_2         r2;
-    uchar       *cdbptr;
-    ASC_SG_HEAD *sg_head;
+    uchar               *cdbptr;
+    ASC_SG_HEAD         *sg_head;
     uchar               *sense_ptr;
     ASC_SCSIQ_3         r3;
     uchar               cdb[ASC_MAX_CDB_LEN];
@@ -1461,6 +1435,10 @@
 #define ASCQ_ERR_SEND_SCSI_Q          0x22
 #define ASCQ_ERR_HOST_REQ_RISC_HALT   0x23
 #define ASCQ_ERR_RESET_SDTR           0x24
+
+/*
+ * Warning code values are set in ASC_DVC_VAR  'warn_code'.
+ */
 #define ASC_WARN_NO_ERROR             0x0000
 #define ASC_WARN_IO_PORT_ROTATE       0x0001
 #define ASC_WARN_EEPROM_CHKSUM        0x0002
@@ -1470,6 +1448,10 @@
 #define ASC_WARN_EEPROM_RECOVER       0x0020
 #define ASC_WARN_CFG_MSW_RECOVER      0x0040
 #define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
+
+/*
+ * Error code values are set in ASC_DVC_VAR  'err_code'.
+ */
 #define ASC_IERR_WRITE_EEPROM         0x0001
 #define ASC_IERR_MCODE_CHKSUM         0x0002
 #define ASC_IERR_SET_PC_ADDR          0x0004
@@ -1484,6 +1466,7 @@
 #define ASC_IERR_SCAM                 0x0800
 #define ASC_IERR_SET_SDTR             0x1000
 #define ASC_IERR_RW_LRAM              0x8000
+
 #define ASC_DEF_IRQ_NO  10
 #define ASC_MAX_IRQ_NO  15
 #define ASC_MIN_IRQ_NO  10
@@ -1578,8 +1561,8 @@
     ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
     ASC_SCSI_BIT_ID_TYPE disc_enable;
     ASC_SCSI_BIT_ID_TYPE sdtr_enable;
-    uchar               chip_scsi_id:4;
-    uchar               isa_dma_speed:4;
+    uchar               chip_scsi_id;
+    uchar               isa_dma_speed;
     uchar               isa_dma_channel;
     uchar               chip_version;
     ushort              pci_device_id;
@@ -1703,6 +1686,20 @@
 #define ASC_MAX_INIT_BUSY_RETRY   8
 #define ASC_EEP_ISA_PNP_WSIZE    16
 
+/*
+ * These macros keep the chip SCSI id and ISA DMA speed
+ * bitfields in board order. C bitfields aren't portable
+ * between big and little-endian platforms so they are
+ * not used.
+ */
+
+#define ASC_EEP_GET_CHIP_ID(cfg)    ((cfg)->id_speed & 0x0f)
+#define ASC_EEP_GET_DMA_SPD(cfg)    (((cfg)->id_speed & 0xf0) >> 4)
+#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
+   ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
+#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
+   ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
+
 typedef struct asceep_config {
     ushort              cfg_lsw;
     ushort              cfg_msw;
@@ -1715,8 +1712,8 @@
     uchar               bios_scan;
     uchar               power_up_wait;
     uchar               no_scam;
-    uchar               chip_scsi_id:4;
-    uchar               isa_dma_speed:4;
+    uchar               id_speed; /* low order 4 bits is chip scsi id */
+                                  /* high order 4 bits is isa dma speed */
     uchar               dos_int13_table[ASC_MAX_TID + 1];
     uchar               adapter_info[6];
     ushort              cntl;
@@ -1962,8 +1959,6 @@
 #define AscSetChipLramAddr(port, addr)    outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
 #define AscGetChipLramData(port)          (ushort)inpw((port)+IOP_RAM_DATA)
 #define AscSetChipLramData(port, data)    outpw((port)+IOP_RAM_DATA, data)
-#define AscGetChipLramDataNoSwap(port)         (ushort)inpw_noswap((port)+IOP_RAM_DATA)
-#define AscSetChipLramDataNoSwap(port, data)   outpw_noswap((port)+IOP_RAM_DATA, data)
 #define AscGetChipIFC(port)               (uchar)inp((port)+IOP_REG_IFC)
 #define AscSetChipIFC(port, data)          outp((port)+IOP_REG_IFC, data)
 #define AscGetChipStatus(port)            (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
@@ -2021,21 +2016,24 @@
 STATIC void      AscEnableInterrupt(PortAddr);
 STATIC void      AscSetBank(PortAddr, uchar);
 STATIC int       AscResetChipAndScsiBus(ASC_DVC_VAR *);
+#ifdef CONFIG_ISA
 STATIC ushort    AscGetIsaDmaChannel(PortAddr);
 STATIC ushort    AscSetIsaDmaChannel(PortAddr, ushort);
 STATIC uchar     AscSetIsaDmaSpeed(PortAddr, uchar);
 STATIC uchar     AscGetIsaDmaSpeed(PortAddr);
+#endif /* CONFIG_ISA */
 STATIC uchar     AscReadLramByte(PortAddr, ushort);
 STATIC ushort    AscReadLramWord(PortAddr, ushort);
+#if CC_VERY_LONG_SG_LIST
 STATIC ASC_DCNT  AscReadLramDWord(PortAddr, ushort);
+#endif /* CC_VERY_LONG_SG_LIST */
 STATIC void      AscWriteLramWord(PortAddr, ushort, ushort);
-STATIC void      AscWriteLramDWord(PortAddr, ushort, ASC_DCNT);
 STATIC void      AscWriteLramByte(PortAddr, ushort, uchar);
 STATIC ASC_DCNT  AscMemSumLramWord(PortAddr, ushort, int);
 STATIC void      AscMemWordSetLram(PortAddr, ushort, ushort, int);
-STATIC void      AscMemWordCopyToLram(PortAddr, ushort, ushort *, int);
-STATIC void      AscMemDWordCopyToLram(PortAddr, ushort, ASC_DCNT *, int);
-STATIC void      AscMemWordCopyFromLram(PortAddr, ushort, ushort *, int);
+STATIC void      AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+STATIC void      AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+STATIC void      AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
 STATIC ushort    AscInitAscDvcVar(ASC_DVC_VAR *);
 STATIC ushort    AscInitFromEEP(ASC_DVC_VAR *);
 STATIC ushort    AscInitFromAscDvcVar(ASC_DVC_VAR *);
@@ -2047,21 +2045,8 @@
 STATIC uchar     AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
 STATIC uchar     AscAllocFreeQueue(PortAddr, uchar);
 STATIC uchar     AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-STATIC int       AscRiscHaltedAbortSRB(ASC_DVC_VAR *, ASC_DCNT);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int       AscRiscHaltedAbortTIX(ASC_DVC_VAR *, uchar);
-#endif /* version >= v1.3.89 */
 STATIC int       AscHostReqRiscHalt(PortAddr);
 STATIC int       AscStopQueueExe(PortAddr);
-STATIC int       AscStartQueueExe(PortAddr);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int       AscCleanUpDiscQueue(PortAddr);
-#endif /* version >= v1.3.89 */
-STATIC int       AscCleanUpBusyQueue(PortAddr);
-STATIC int       AscWaitTixISRDone(ASC_DVC_VAR *, uchar);
-STATIC int       AscWaitISRDone(ASC_DVC_VAR *);
-STATIC ASC_PADDR AscGetOnePhyAddr(ASC_DVC_VAR *, uchar *,
-                    ASC_DCNT);
 STATIC int       AscSendScsiQueue(ASC_DVC_VAR *,
                     ASC_SCSI_Q * scsiq,
                     uchar n_q_required);
@@ -2072,48 +2057,43 @@
 STATIC int       AscSetChipSynRegAtID(PortAddr, uchar, uchar);
 STATIC int       AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
 STATIC ushort    AscInitLram(ASC_DVC_VAR *);
-STATIC int       AscReInitLram(ASC_DVC_VAR *);
 STATIC ushort    AscInitQLinkVar(ASC_DVC_VAR *);
 STATIC int       AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int       _AscWaitQDone(PortAddr, ASC_SCSI_Q *);
-#endif /* version >= v1.3.89 */
 STATIC int       AscIsrChipHalted(ASC_DVC_VAR *);
 STATIC uchar     _AscCopyLramScsiDoneQ(PortAddr, ushort,
                     ASC_QDONE_INFO *, ASC_DCNT);
 STATIC int       AscIsrQDone(ASC_DVC_VAR *);
 STATIC int       AscCompareString(uchar *, uchar *, int);
+#ifdef CONFIG_ISA
 STATIC ushort    AscGetEisaChipCfg(PortAddr);
 STATIC ASC_DCNT  AscGetEisaProductID(PortAddr);
 STATIC PortAddr  AscSearchIOPortAddrEISA(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddr11(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddr(PortAddr, ushort);
+STATIC void      AscSetISAPNPWaitForKey(void);
+#endif /* CONFIG_ISA */
 STATIC uchar     AscGetChipScsiCtrl(PortAddr);
 STATIC uchar     AscSetChipScsiID(PortAddr, uchar);
 STATIC uchar     AscGetChipVersion(PortAddr, ushort);
 STATIC ushort    AscGetChipBusType(PortAddr);
-STATIC ASC_DCNT  AscLoadMicroCode(PortAddr, ushort, ushort *, ushort);
+STATIC ASC_DCNT  AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
 STATIC int       AscFindSignature(PortAddr);
-STATIC PortAddr  AscSearchIOPortAddr11(PortAddr);
 STATIC void      AscToggleIRQAct(PortAddr);
-STATIC void      AscSetISAPNPWaitForKey(void);
 STATIC uchar     AscGetChipIRQ(PortAddr, ushort);
 STATIC uchar     AscSetChipIRQ(PortAddr, uchar, ushort);
 STATIC ushort    AscGetChipBiosAddress(PortAddr, ushort);
-STATIC int       DvcEnterCritical(void);
-STATIC void      DvcLeaveCritical(int);
-STATIC void      DvcInPortWords(PortAddr, ushort *, int);
-STATIC void      DvcOutPortWords(PortAddr, ushort *, int);
-STATIC void      DvcOutPortDWords(PortAddr, ASC_DCNT *, int);
+STATIC inline ulong DvcEnterCritical(void);
+STATIC inline void DvcLeaveCritical(ulong);
+#ifdef CONFIG_PCI
 STATIC uchar     DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
 STATIC void      DvcWritePCIConfigByte(ASC_DVC_VAR *,
                     ushort, uchar);
+#endif /* CONFIG_PCI */
 STATIC ushort      AscGetChipBiosAddress(PortAddr, ushort);
 STATIC void      DvcSleepMilliSecond(ASC_DCNT);
 STATIC void      DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
-STATIC ASC_DCNT  DvcGetSGList(ASC_DVC_VAR *, uchar *,
-                    ASC_DCNT, ASC_SG_HEAD *);
-STATIC void      DvcPutScsiQ(PortAddr, ushort, ushort *, int);
-STATIC void      DvcGetQinfo(PortAddr, ushort, ushort *, int);
-STATIC PortAddr  AscSearchIOPortAddr(PortAddr, ushort);
+STATIC void      DvcPutScsiQ(PortAddr, ushort, uchar *, int);
+STATIC void      DvcGetQinfo(PortAddr, ushort, uchar *, int);
 STATIC ushort    AscInitGetConfig(ASC_DVC_VAR *);
 STATIC ushort    AscInitSetConfig(ASC_DVC_VAR *);
 STATIC ushort    AscInitAsc1000Driver(ASC_DVC_VAR *);
@@ -2127,12 +2107,9 @@
 STATIC uint      AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar,
                     uchar);
 STATIC int       AscSgListToQueue(int);
-STATIC int       AscAbortSRB(ASC_DVC_VAR *, ASC_VADDR);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int       AscResetDevice(ASC_DVC_VAR *, uchar);
-#endif /* version >= v1.3.89 */
-STATIC int       AscResetSB(ASC_DVC_VAR *);
+#ifdef CONFIG_ISA
 STATIC void      AscEnableIsaDma(uchar);
+#endif /* CONFIG_ISA */
 STATIC ASC_DCNT  AscGetMaxDmaCount(ushort);
 
 
@@ -2141,7 +2118,7 @@
  */
 
 #define ADV_LIB_VERSION_MAJOR  5
-#define ADV_LIB_VERSION_MINOR  5
+#define ADV_LIB_VERSION_MINOR  14
 
 /* d_os_dep.h */
 #define ADV_OS_LINUX
@@ -2158,7 +2135,7 @@
  * types must be used. In Linux the char, short, and int types
  * are all consistent at 8, 16, and 32 bits respectively. Pointers
  * and long types are 64 bits on Alpha and UltraSPARC.
- */ 
+ */
 #define ADV_PADDR __u32         /* Physical address data type. */
 #define ADV_VADDR __u32         /* Virtual address data type. */
 #define ADV_DCNT  __u32         /* Unsigned Data count type. */
@@ -2175,11 +2152,7 @@
 #define ADV_VADDR_TO_U32   virt_to_bus
 #define ADV_U32_TO_VADDR   bus_to_virt
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-#define AdvPortAddr  unsigned short     /* I/O Port address size */
-#else /* version >= v1,3,0 */
 #define AdvPortAddr  ulong              /* Virtual memory address size */
-#endif /* version >= v1,3,0 */
 
 /*
  * Define Adv Library required memory access macros.
@@ -2188,16 +2161,15 @@
 #define ADV_MEM_READW(addr) readw(addr)
 #define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
 #define ADV_MEM_WRITEW(addr, word) writew(word, addr)
+#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
+
+#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
 
 /*
- * The I/O memory mapping function names changed in 2.1.X.
+ * For wide  boards a CDB length maximum of 16 bytes
+ * is supported.
  */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-#define ioremap vremap
-#define iounmap vfree
-#endif /* version < v2.1.0 */
-
-#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
+#define ADV_MAX_CDB_LEN     16
 
 /*
  * Define total number of simultaneous maximum element scatter-gather
@@ -2207,7 +2179,7 @@
  * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
  * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
  * structures or 255 scatter-gather elements.
- * 
+ *
  */
 #define ADV_TOT_SG_BLOCK        ASC_DEF_MAX_HOST_QNG
 
@@ -2225,10 +2197,10 @@
 #define ADV_SG_TOTAL_MEM_SIZE \
     (sizeof(ADV_SG_BLOCK) *  ADV_NUM_SG_BLOCK)
 
-#define ASC_PAGE_SIZE PAGE_SIZE
+#define ADV_PAGE_SIZE PAGE_SIZE
 
 #define ADV_NUM_PAGE_CROSSING \
-    ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
+    ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
 
 /* a_condor.h */
 #define ADV_PCI_VENDOR_ID               0x10CD
@@ -2236,12 +2208,12 @@
 #define ADV_PCI_DEVID_38C0800_REV1      0x2500
 #define ADV_PCI_DEVID_38C1600_REV1      0x2700
 
-#define ASC_EEP_DVC_CFG_BEGIN           (0x00)
-#define ASC_EEP_DVC_CFG_END             (0x15)
-#define ASC_EEP_DVC_CTL_BEGIN           (0x16)  /* location of OEM name */
-#define ASC_EEP_MAX_WORD_ADDR           (0x1E)
+#define ADV_EEP_DVC_CFG_BEGIN           (0x00)
+#define ADV_EEP_DVC_CFG_END             (0x15)
+#define ADV_EEP_DVC_CTL_BEGIN           (0x16)  /* location of OEM name */
+#define ADV_EEP_MAX_WORD_ADDR           (0x1E)
 
-#define ASC_EEP_DELAY_MS                100
+#define ADV_EEP_DELAY_MS                100
 
 #define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
 #define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
@@ -2252,6 +2224,18 @@
  */
 #define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
 #define ADV_EEPROM_CIS_LD              0x2000   /* EEPROM Bit 13 */
+/*
+ * ASC38C1600 Bit 11
+ *
+ * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
+ * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
+ * Function 0 will specify INT B.
+ *
+ * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
+ * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
+ * Function 1 will specify INT A.
+ */
+#define ADV_EEPROM_INTAB               0x0800   /* EEPROM Bit 11 */
 
 typedef struct adveep_3550_config
 {
@@ -2262,20 +2246,20 @@
                                 /*  bit 14 set - BIOS Enable */
                                 /*  bit 15 set - Big Endian Mode */
   ushort cfg_msw;               /* 01 unused      */
-  ushort disc_enable;           /* 02 disconnect enable */         
+  ushort disc_enable;           /* 02 disconnect enable */
   ushort wdtr_able;             /* 03 Wide DTR able */
   ushort sdtr_able;             /* 04 Synchronous DTR able */
-  ushort start_motor;           /* 05 send start up motor */      
+  ushort start_motor;           /* 05 send start up motor */
   ushort tagqng_able;           /* 06 tag queuing able */
-  ushort bios_scan;             /* 07 BIOS device control */   
-  ushort scam_tolerant;         /* 08 no scam */  
- 
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
   uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
   uchar  bios_boot_delay;       /*    power up wait */
- 
+
   uchar  scsi_reset_delay;      /* 10 reset delay */
   uchar  bios_id_lun;           /*    first boot device scsi id & lun */
-                                /*    high nibble is lun */  
+                                /*    high nibble is lun */
                                 /*    low nibble is scsi id */
 
   uchar  termination;           /* 11 0 - automatic */
@@ -2284,33 +2268,33 @@
                                 /*    3 - low on  / high on */
                                 /*    There is no low on  / high off */
 
-  uchar  reserved1;             /*    reserved byte (not used) */                                  
+  uchar  reserved1;             /*    reserved byte (not used) */
 
   ushort bios_ctrl;             /* 12 BIOS control bits */
-                                /*  bit 0  set: BIOS don't act as initiator. */
-                                /*  bit 1  set: BIOS > 1 GB support */
-                                /*  bit 2  set: BIOS > 2 Disk Support */
-                                /*  bit 3  set: BIOS don't support removables */
-                                /*  bit 4  set: BIOS support bootable CD */
-                                /*  bit 5  set: */
-                                /*  bit 6  set: BIOS support multiple LUNs */
-                                /*  bit 7  set: BIOS display of message */
-                                /*  bit 8  set: */
-                                /*  bit 9  set: Reset SCSI bus during init. */
-                                /*  bit 10 set: */
-                                /*  bit 11 set: No verbose initialization. */
-                                /*  bit 12 set: SCSI parity enabled */
-                                /*  bit 13 set: */
-                                /*  bit 14 set: */
-                                /*  bit 15 set: */
-  ushort  ultra_able;           /* 13 ULTRA speed able */ 
+                                /*  bit 0  BIOS don't act as initiator. */
+                                /*  bit 1  BIOS > 1 GB support */
+                                /*  bit 2  BIOS > 2 Disk Support */
+                                /*  bit 3  BIOS don't support removables */
+                                /*  bit 4  BIOS support bootable CD */
+                                /*  bit 5  BIOS scan enabled */
+                                /*  bit 6  BIOS support multiple LUNs */
+                                /*  bit 7  BIOS display of message */
+                                /*  bit 8  SCAM disabled */
+                                /*  bit 9  Reset SCSI bus during init. */
+                                /*  bit 10 */
+                                /*  bit 11 No verbose initialization. */
+                                /*  bit 12 SCSI parity enabled */
+                                /*  bit 13 */
+                                /*  bit 14 */
+                                /*  bit 15 */
+  ushort  ultra_able;           /* 13 ULTRA speed able */
   ushort  reserved2;            /* 14 reserved */
   uchar   max_host_qng;         /* 15 maximum host queuing */
   uchar   max_dvc_qng;          /*    maximum per device queuing */
   ushort  dvc_cntl;             /* 16 control bit for driver */
   ushort  bug_fix;              /* 17 control bit for bug fix */
-  ushort  serial_number_word1;  /* 18 Board serial number word 1 */  
-  ushort  serial_number_word2;  /* 19 Board serial number word 2 */  
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
   ushort  serial_number_word3;  /* 20 Board serial number word 3 */
   ushort  check_sum;            /* 21 EEP check sum */
   uchar   oem_name[16];         /* 22 OEM name */
@@ -2319,9 +2303,9 @@
   ushort  adv_err_addr;         /* 32 last uc error address */
   ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
   ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
-  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */  
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
   ushort  num_of_err;           /* 36 number of error */
-} ADVEEP_3550_CONFIG; 
+} ADVEEP_3550_CONFIG;
 
 typedef struct adveep_38C0800_config
 {
@@ -2361,22 +2345,22 @@
                                 /*    There is no low on  / high off */
 
   ushort bios_ctrl;             /* 12 BIOS control bits */
-                                /*  bit 0  set: BIOS don't act as initiator. */
-                                /*  bit 1  set: BIOS > 1 GB support */
-                                /*  bit 2  set: BIOS > 2 Disk Support */
-                                /*  bit 3  set: BIOS don't support removables */
-                                /*  bit 4  set: BIOS support bootable CD */
-                                /*  bit 5  set: BIOS scan enabled */
-                                /*  bit 6  set: BIOS support multiple LUNs */
-                                /*  bit 7  set: BIOS display of message */
-                                /*  bit 8  set: */
-                                /*  bit 9  set: Reset SCSI bus during init. */
-                                /*  bit 10 set: */
-                                /*  bit 11 set: No verbose initialization. */
-                                /*  bit 12 set: SCSI parity enabled */
-                                /*  bit 13 set: */
-                                /*  bit 14 set: */
-                                /*  bit 15 set: */
+                                /*  bit 0  BIOS don't act as initiator. */
+                                /*  bit 1  BIOS > 1 GB support */
+                                /*  bit 2  BIOS > 2 Disk Support */
+                                /*  bit 3  BIOS don't support removables */
+                                /*  bit 4  BIOS support bootable CD */
+                                /*  bit 5  BIOS scan enabled */
+                                /*  bit 6  BIOS support multiple LUNs */
+                                /*  bit 7  BIOS display of message */
+                                /*  bit 8  SCAM disabled */
+                                /*  bit 9  Reset SCSI bus during init. */
+                                /*  bit 10 */
+                                /*  bit 11 No verbose initialization. */
+                                /*  bit 12 SCSI parity enabled */
+                                /*  bit 13 */
+                                /*  bit 14 */
+                                /*  bit 15 */
   ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
   ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
   uchar   max_host_qng;         /* 15 maximum host queueing */
@@ -2424,6 +2408,109 @@
   ushort  reserved63;           /* 63 reserved */
 } ADVEEP_38C0800_CONFIG;
 
+typedef struct adveep_38C1600_config
+{
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 11 set - Func. 0 INTB, Func. 1 INTA */
+                                /*       clear - Func. 0 INTA, Func. 1 INTB */
+                                /*  bit 13 set - Load CIS */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused */
+  ushort disc_enable;           /* 02 disconnect enable */
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
+  ushort start_motor;           /* 05 send start up motor */
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */
+                                /*    low nibble is scsi id */
+
+  uchar  termination_se;        /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  termination_lvd;       /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  BIOS don't act as initiator. */
+                                /*  bit 1  BIOS > 1 GB support */
+                                /*  bit 2  BIOS > 2 Disk Support */
+                                /*  bit 3  BIOS don't support removables */
+                                /*  bit 4  BIOS support bootable CD */
+                                /*  bit 5  BIOS scan enabled */
+                                /*  bit 6  BIOS support multiple LUNs */
+                                /*  bit 7  BIOS display of message */
+                                /*  bit 8  SCAM disabled */
+                                /*  bit 9  Reset SCSI bus during init. */
+                                /*  bit 10 Basic Integrity Checking disabled */
+                                /*  bit 11 No verbose initialization. */
+                                /*  bit 12 SCSI parity enabled */
+                                /*  bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
+                                /*  bit 14 */
+                                /*  bit 15 */
+  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
+  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
+  uchar   max_host_qng;         /* 15 maximum host queueing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
+  ushort  reserved36;           /* 36 reserved */
+  ushort  reserved37;           /* 37 reserved */
+  ushort  reserved38;           /* 38 reserved */
+  ushort  reserved39;           /* 39 reserved */
+  ushort  reserved40;           /* 40 reserved */
+  ushort  reserved41;           /* 41 reserved */
+  ushort  reserved42;           /* 42 reserved */
+  ushort  reserved43;           /* 43 reserved */
+  ushort  reserved44;           /* 44 reserved */
+  ushort  reserved45;           /* 45 reserved */
+  ushort  reserved46;           /* 46 reserved */
+  ushort  reserved47;           /* 47 reserved */
+  ushort  reserved48;           /* 48 reserved */
+  ushort  reserved49;           /* 49 reserved */
+  ushort  reserved50;           /* 50 reserved */
+  ushort  reserved51;           /* 51 reserved */
+  ushort  reserved52;           /* 52 reserved */
+  ushort  reserved53;           /* 53 reserved */
+  ushort  reserved54;           /* 54 reserved */
+  ushort  reserved55;           /* 55 reserved */
+  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
+  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
+  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
+  ushort  subsysid;             /* 59 SubSystem ID */
+  ushort  reserved60;           /* 60 reserved */
+  ushort  reserved61;           /* 61 reserved */
+  ushort  reserved62;           /* 62 reserved */
+  ushort  reserved63;           /* 63 reserved */
+} ADVEEP_38C1600_CONFIG;
+
 /*
  * EEPROM Commands
  */
@@ -2445,6 +2532,7 @@
 #define BIOS_CTRL_RESET_SCSI_BUS     0x0200
 #define BIOS_CTRL_INIT_VERBOSE       0x0800
 #define BIOS_CTRL_SCSI_PARITY        0x1000
+#define BIOS_CTRL_AIPP_DIS           0x2000
 
 #define ADV_3550_MEMSIZE   0x2000       /* 8 KB Internal Memory */
 #define ADV_3550_IOLEN     0x40         /* I/O Port Range in bytes */
@@ -2452,7 +2540,14 @@
 #define ADV_38C0800_MEMSIZE  0x4000     /* 16 KB Internal Memory */
 #define ADV_38C0800_IOLEN    0x100      /* I/O Port Range in bytes */
 
-#define ADV_38C1600_MEMSIZE  0x4000    /* 16 KB Internal Memory */
+/*
+ * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
+ * a special 16K Adv Library and Microcode version. After the issue is
+ * resolved, should restore 32K support.
+ *
+ * #define ADV_38C1600_MEMSIZE  0x8000L   * 32 KB Internal Memory *
+ */
+#define ADV_38C1600_MEMSIZE  0x4000   /* 16 KB Internal Memory */
 #define ADV_38C1600_IOLEN    0x100     /* I/O Port Range 256 bytes */
 #define ADV_38C1600_MEMLEN   0x1000    /* Memory Range 4KB bytes */
 
@@ -2653,8 +2748,8 @@
 #define SLEW_RATE       0x1000  /* SCSI output buffer slew rate */
 #define FILTER_SEL      0x0C00  /* Filter Period Selection */
 #define  FLTR_DISABLE    0x0000  /* Input Filtering Disabled */
-#define  FLTR_11_TO_20NS 0x0800  /* Input Filtering 11ns to 20ns */          
-#define  FLTR_21_TO_39NS 0x0C00  /* Input Filtering 21ns to 39ns */          
+#define  FLTR_11_TO_20NS 0x0800  /* Input Filtering 11ns to 20ns */
+#define  FLTR_21_TO_39NS 0x0C00  /* Input Filtering 21ns to 39ns */
 #define ACTIVE_DBL      0x0200  /* Disable Active Negation */
 #define DIFF_MODE       0x0100  /* SCSI differential Mode (Read-Only) */
 #define DIFF_SENSE      0x0080  /* 1: No SE cables, 0: SE cable (Read-Only) */
@@ -2666,6 +2761,14 @@
 
 /*
  * Addendum for ASC-38C0800 Chip
+ *
+ * The ASC-38C1600 Chip uses the same definitions except that the
+ * bus mode override bits [12:10] have been moved to byte register
+ * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
+ * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
+ * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
+ * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
+ * and [1:0]. Bits [14], [7:6], [3:2] are unused.
  */
 #define DIS_TERM_DRV    0x4000  /* 1: Read c_det[3:0], 0: cannot read */
 #define HVD_LVD_SE      0x1C00  /* Device Detect Bits */
@@ -2745,6 +2848,33 @@
 #define PRE_TEST_VALUE        0x05
 #define NORMAL_VALUE          0x00
 
+/*
+ * ASC38C1600 Definitions
+ *
+ * IOPB_PCI_INT_CFG Bit Field Definitions
+ */
+
+#define INTAB_LD        0x80    /* Value loaded from EEPROM Bit 11. */
+
+/*
+ * Bit 1 can be set to change the interrupt for the Function to operate in
+ * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
+ * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
+ * mode, otherwise the operating mode is undefined.
+ */
+#define TOTEMPOLE       0x02
+
+/*
+ * Bit 0 can be used to change the Int Pin for the Function. The value is
+ * 0 by default for both Functions with Function 0 using INT A and Function
+ * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
+ * INT A is used.
+ *
+ * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
+ * value specified in the PCI Configuration Space.
+ */
+#define INTAB           0x01
+
 /* a_advlib.h */
 
 /*
@@ -2759,7 +2889,7 @@
 
 
 /*
- * ASC_DVC_VAR 'warn_code' values
+ * ADV_DVC_VAR 'warn_code' values
  */
 #define ASC_WARN_BUSRESET_ERROR         0x0001 /* SCSI Bus Reset error */
 #define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
@@ -2770,11 +2900,8 @@
 #define ADV_MAX_TID                     15 /* max. target identifier */
 #define ADV_MAX_LUN                     7  /* max. logical unit number */
 
-
 /*
- * AscInitGetConfig() and AscInitAsc1000Driver() Definitions
- *
- * Error code values are set in ASC_DVC_VAR 'err_code'.
+ * Error code values are set in ADV_DVC_VAR 'err_code'.
  */
 #define ASC_IERR_WRITE_EEPROM       0x0001 /* write EEPROM error */
 #define ASC_IERR_MCODE_CHKSUM       0x0002 /* micro code check sum error */
@@ -2829,6 +2956,7 @@
 #define ASC_MC_CAM_MODE_MASK            0x015E /* CAM mode TID bitmask. */
 #define ASC_MC_ICQ                      0x0160
 #define ASC_MC_IRQ                      0x0164
+#define ASC_MC_PPR_ABLE                 0x017A
 
 /*
  * BIOS LRAM variable absolute offsets.
@@ -2845,6 +2973,7 @@
  * and handled by the microcode.
  */
 #define CONTROL_FLAG_IGNORE_PERR        0x0001 /* Ignore DMA Parity Errors */
+#define CONTROL_FLAG_ENABLE_AIPP        0x0002 /* Enabled AIPP checking. */
 
 /*
  * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
@@ -2876,6 +3005,10 @@
 #define ASC_QSC_HEAD_TAG    0x40 /* Use Head Tag Message (0x21). */
 #define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
 
+/*
+ * All fields here are accessed by the board microcode and need to be
+ * little-endian.
+ */
 typedef struct adv_carr_t
 {
     ADV_VADDR   carr_va;       /* Carrier Virtual Address */
@@ -2896,12 +3029,11 @@
 #define ASC_NEXT_VPA_MASK       0xFFFFFFF0
 
 #define ASC_RQ_DONE             0x00000001
+#define ASC_RQ_GOOD             0x00000002
 #define ASC_CQ_STOPPER          0x00000000
 
 #define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
 
-#define ADV_PAGE_SIZE   4096    /* Assume 4KB page size. */
-
 #define ADV_CARRIER_NUM_PAGE_CROSSING \
     (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
         (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
@@ -2929,7 +3061,7 @@
  * This structure can be discarded after initialization. Don't add
  * fields here needed after initialization.
  *
- * Field naming convention: 
+ * Field naming convention:
  *
  *  *_enable indicates the field enables or disables a feature. The
  *  value of the field is never reset.
@@ -2949,7 +3081,7 @@
   ushort serial1;           /* EEPROM serial number word 1 */
   ushort serial2;           /* EEPROM serial number word 2 */
   ushort serial3;           /* EEPROM serial number word 3 */
-} ADV_DVC_CFG; 
+} ADV_DVC_CFG;
 
 struct adv_dvc_var;
 struct adv_scsi_req_q;
@@ -2965,7 +3097,7 @@
  *
  * One structure is required per host adapter.
  *
- * Field naming convention: 
+ * Field naming convention:
  *
  *  *_able indicates both whether a feature should be enabled or disabled
  *  and whether a device isi capable of the feature. At initialization
@@ -2986,6 +3118,7 @@
   ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
   ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
   ushort tagqng_able;     /* try tagged queuing with a device */
+  ushort ppr_able;        /* PPR message capable per TID bitmask. */
   uchar  max_dvc_qng;     /* maximum number of tagged commands per device */
   ushort start_motor;     /* start motor command allowed */
   uchar  scsi_reset_wait; /* delay in seconds after scsi bus reset */
@@ -3007,13 +3140,13 @@
   * driver may discard the buffer after initialization is done.
   */
   ADV_DVC_CFG *cfg; /* temporary configuration structure  */
-} ADV_DVC_VAR; 
+} ADV_DVC_VAR;
 
 #define NO_OF_SG_PER_BLOCK              15
 
 typedef struct asc_sg_block {
-    uchar reserved1; 
-    uchar reserved2; 
+    uchar reserved1;
+    uchar reserved2;
     uchar reserved3;
     uchar sg_cnt;                     /* Valid entries in block. */
     ADV_PADDR sg_ptr;                 /* Pointer to next sg block. */
@@ -3030,6 +3163,9 @@
  * The microcode makes assumptions about the size and ordering of fields
  * in this structure. Do not change the structure definition here without
  * coordinating the change with the microcode.
+ *
+ * All fields accessed by microcode must be maintained in little_endian
+ * order.
  */
 typedef struct adv_scsi_req_q {
     uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
@@ -3042,16 +3178,16 @@
     ADV_PADDR   carr_pa;
     uchar       mflag;
     uchar       sense_len;
-    uchar       cdb_len;        /* SCSI CDB length. */
+    uchar       cdb_len;        /* SCSI CDB length. Must <= 16 bytes. */
     uchar       scsi_cntl;
     uchar       done_status;    /* Completion status. */
     uchar       scsi_status;    /* SCSI status byte. */
     uchar       host_status;    /* Ucode host status. */
     uchar       sg_working_ix;
-    uchar       cdb[12];        /* SCSI command block. */
+    uchar       cdb[12];        /* SCSI CDB bytes 0-11. */
     ADV_PADDR   sg_real_addr;   /* SG list physical address. */
     ADV_PADDR   scsiq_rptr;
-    ADV_DCNT    sg_working_data_cnt;
+    uchar       cdb16[4];       /* SCSI CDB bytes 12-15. */
     ADV_VADDR   scsiq_ptr;
     ADV_VADDR   carr_va;
     /*
@@ -3062,6 +3198,7 @@
     ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
     char        *vdata_addr;   /* Data buffer virtual address. */
     uchar       a_flag;
+    uchar       pad[2];        /* Pad out to a word boundary. */
 } ADV_SCSI_REQ_Q;
 
 /*
@@ -3097,14 +3234,16 @@
 #define ADV_ASYNC_RDMA_FAILURE          0x01 /* Fatal RDMA failure. */
 #define ADV_ASYNC_SCSI_BUS_RESET_DET    0x02 /* Detected SCSI Bus Reset. */
 #define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
+#define ADV_RDMA_IN_CARR_AND_Q_INVALID  0x04 /* RDMAed-in data invalid. */
+
 
 #define ADV_HOST_SCSI_BUS_RESET      0x80 /* Host Initiated SCSI Bus Reset. */
 
 /*
  * Device drivers must define the following functions.
  */
-STATIC int   DvcEnterCritical(void);
-STATIC void  DvcLeaveCritical(int);
+STATIC inline ulong DvcEnterCritical(void);
+STATIC inline void  DvcLeaveCritical(ulong);
 STATIC void  DvcSleepMilliSecond(ADV_DCNT);
 STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
 STATIC void  DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
@@ -3120,6 +3259,7 @@
 STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
 STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
 STATIC int     AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
 STATIC int     AdvResetChipAndSB(ADV_DVC_VAR *);
 STATIC int     AdvResetSB(ADV_DVC_VAR *asc_dvc);
 
@@ -3130,10 +3270,13 @@
 STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC int    AdvInitFrom3550EEP(ADV_DVC_VAR *);
 STATIC int    AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+STATIC int    AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
 STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
 STATIC void   AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
 STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
 STATIC void   AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+STATIC ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+STATIC void   AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
 STATIC void   AdvWaitEEPCmd(AdvPortAddr);
 STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
 
@@ -3143,71 +3286,9 @@
 #define AscPCICmdRegBits_BusMastering     0x0007
 #define AscPCICmdRegBits_ParErrRespCtrl   0x0040
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-
 /* Read byte from a register. */
 #define AdvReadByteRegister(iop_base, reg_off) \
-    (inp((iop_base) + (reg_off)))
-
-/* Write byte to a register. */
-#define AdvWriteByteRegister(iop_base, reg_off, byte) \
-    (outp((iop_base) + (reg_off), (byte)))
-
-/* Read word (2 bytes) from a register. */
-#define AdvReadWordRegister(iop_base, reg_off) \
-    (le16_to_cpu(inpw((iop_base) + (reg_off))))
-
-/* Write word (2 bytes) to a register. */
-#define AdvWriteWordRegister(iop_base, reg_off, word) \
-    (outpw((iop_base) + (reg_off), cpu_to_le16(word)))
-
-/* Read byte from LRAM. */
-#define AdvReadByteLram(iop_base, addr, byte) \
-do { \
-    outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \
-    (byte) = inp((iop_base) + IOPB_RAM_DATA); \
-} while (0)
-
-/* Write byte to LRAM. */
-#define AdvWriteByteLram(iop_base, addr, byte) \
-    (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
-     outp((iop_base) + IOPB_RAM_DATA, (byte)))
-
-/* Read word (2 bytes) from LRAM. */
-#define AdvReadWordLram(iop_base, addr, word) \
-do { \
-    outpw((iop_base) + IOPW_RAM_ADDR, (addr));  \
-    (word) = le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA)); \
-} while (0)
-
-/* Write word (2 bytes) to LRAM. */
-#define AdvWriteWordLram(iop_base, addr, word) \
-    (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
-     outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
-
-/* Write double word (4 bytes) to LRAM */
-/* Because of unspecified C language ordering don't use auto-increment. */
-#define AdvWriteDWordLram(iop_base, addr, dword) \
-    ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
-      outpw((iop_base) + IOPW_RAM_DATA, \
-        cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
-     (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
-      outpw((iop_base) + IOPW_RAM_DATA, \
-        cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
-
-/* Read word (2 bytes) from LRAM assuming that the address is already set. */
-#define AdvReadWordAutoIncLram(iop_base) \
-     (le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA)))
-
-/* Write word (2 bytes) to LRAM assuming that the address is already set. */
-#define AdvWriteWordAutoIncLram(iop_base, word) \
-     (outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
-
-#else /* version >= v1,3,0 */
-
-/* Read byte from a register. */
-#define AdvReadByteRegister(iop_base, reg_off) \
-     (ADV_MEM_READB((iop_base) + (reg_off)))
+     (ADV_MEM_READB((iop_base) + (reg_off)))
 
 /* Write byte to a register. */
 #define AdvWriteByteRegister(iop_base, reg_off, byte) \
@@ -3215,11 +3296,15 @@
 
 /* Read word (2 bytes) from a register. */
 #define AdvReadWordRegister(iop_base, reg_off) \
-     le16_to_cpu(ADV_MEM_READW((iop_base) + (reg_off)))
+     (ADV_MEM_READW((iop_base) + (reg_off)))
 
 /* Write word (2 bytes) to a register. */
 #define AdvWriteWordRegister(iop_base, reg_off, word) \
-     (ADV_MEM_WRITEW((iop_base) + (reg_off), cpu_to_le16(word)))
+     (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
+
+/* Write dword (4 bytes) to a register. */
+#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
+     (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
 
 /* Read byte from LRAM. */
 #define AdvReadByteLram(iop_base, addr, byte) \
@@ -3237,17 +3322,17 @@
 #define AdvReadWordLram(iop_base, addr, word) \
 do { \
     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
-    (word) = le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
+    (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
 } while (0)
 
 /* Write word (2 bytes) to LRAM. */
 #define AdvWriteWordLram(iop_base, addr, word) \
     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
-     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
+     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
 
-/* Write double word (4 bytes) to LRAM */
+/* Write little-endian double word (4 bytes) to LRAM */
 /* Because of unspecified C language ordering don't use auto-increment. */
-#define AdvWriteDWordLram(iop_base, addr, dword) \
+#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
     ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
       ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
                      cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
@@ -3257,13 +3342,12 @@
 
 /* Read word (2 bytes) from LRAM assuming that the address is already set. */
 #define AdvReadWordAutoIncLram(iop_base) \
-     le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
+     (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
 
 /* Write word (2 bytes) to LRAM assuming that the address is already set. */
 #define AdvWriteWordAutoIncLram(iop_base, word) \
-     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
+     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
 
-#endif /* version >= v1,3,0 */
 
 /*
  * Define macro to check for Condor signature.
@@ -3288,7 +3372,7 @@
 /*
  * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
  * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
- * 
+ *
  * If the request has not yet been sent to the device it will simply be
  * aborted from RISC memory. If the request is disconnected it will be
  * aborted on reselection by sending an Abort Message to the target ID.
@@ -3376,6 +3460,7 @@
  */
 extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
 extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
+extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
 
 /*
  * DvcGetPhyAddr() flag arguments
@@ -3388,8 +3473,9 @@
 #define ADV_IS_CARRIER_FLAG     0x20 /* 'addr' is ADV_CARR_T pointer */
 
 /* Return the address that is aligned at the next doubleword >= to 'addr'. */
-#define ADV_DWALIGN(addr)       (((ulong) (addr) + 0x3) & ~0x3)
+#define ADV_8BALIGN(addr)      (((ulong) (addr) + 0x7) & ~0x7)
 #define ADV_16BALIGN(addr)     (((ulong) (addr) + 0xF) & ~0xF)
+#define ADV_32BALIGN(addr)     (((ulong) (addr) + 0x1F) & ~0x1F)
 
 /*
  * Total contiguous memory needed for driver SG blocks.
@@ -3399,50 +3485,76 @@
  * single request.
  */
 
-#ifndef ADV_MAX_SG_LIST
-Forced Error: Driver must define ADV_MAX_SG_LIST.
-#endif /* ADV_MAX_SG_LIST */
-
 #define ADV_SG_LIST_MAX_BYTE_SIZE \
          (sizeof(ADV_SG_BLOCK) * \
           ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
 
+/*
+ * Inquiry data structure and bitfield macros
+ *
+ * Using bitfields to access the subchar data isn't portable across
+ * endianness, so instead mask and shift. Only quantities of more
+ * than 1 bit are shifted, since the others are just tested for true
+ * or false.
+ */
+
+#define ADV_INQ_DVC_TYPE(inq)       ((inq)->periph & 0x1f)
+#define ADV_INQ_QUALIFIER(inq)      (((inq)->periph & 0xe0) >> 5)
+#define ADV_INQ_DVC_TYPE_MOD(inq)   ((inq)->devtype & 0x7f)
+#define ADV_INQ_REMOVABLE(inq)      ((inq)->devtype & 0x80)
+#define ADV_INQ_ANSI_VER(inq)       ((inq)->ver & 0x07)
+#define ADV_INQ_ECMA_VER(inq)       (((inq)->ver & 0x38) >> 3)
+#define ADV_INQ_ISO_VER(inq)        (((inq)->ver & 0xc0) >> 6)
+#define ADV_INQ_RESPONSE_FMT(inq)   ((inq)->byte3 & 0x0f)
+#define ADV_INQ_TERM_IO(inq)        ((inq)->byte3 & 0x40)
+#define ADV_INQ_ASYNC_NOTIF(inq)    ((inq)->byte3 & 0x80)
+#define ADV_INQ_SOFT_RESET(inq)     ((inq)->flags & 0x01)
+#define ADV_INQ_CMD_QUEUE(inq)      ((inq)->flags & 0x02)
+#define ADV_INQ_LINK_CMD(inq)       ((inq)->flags & 0x08)
+#define ADV_INQ_SYNC(inq)           ((inq)->flags & 0x10)
+#define ADV_INQ_WIDE16(inq)         ((inq)->flags & 0x20)
+#define ADV_INQ_WIDE32(inq)         ((inq)->flags & 0x40)
+#define ADV_INQ_REL_ADDR(inq)       ((inq)->flags & 0x80)
+#define ADV_INQ_INFO_UNIT(inq)      ((inq)->info & 0x01)
+#define ADV_INQ_QUICK_ARB(inq)      ((inq)->info & 0x02)
+#define ADV_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
+
 typedef struct {
-  uchar peri_dvc_type   : 5;    /* peripheral device type */
-  uchar peri_qualifier  : 3;    /* peripheral qualifier */
-  uchar dvc_type_modifier : 7;  /* device type modifier (for SCSI I) */
-  uchar rmb      : 1;           /* RMB - removable medium bit */
-  uchar ansi_apr_ver : 3;       /* ANSI approved version */
-  uchar ecma_ver : 3;           /* ECMA version */
-  uchar iso_ver  : 2;           /* ISO version */
-  uchar rsp_data_fmt : 4;       /* response data format */
+  uchar periph;                 /* peripheral device type [0:4] */
+                                /* peripheral qualifier [5:7] */
+  uchar devtype;                /* device type modifier (for SCSI I) [0:6] */
+                                /* RMB - removable medium bit [7] */
+  uchar ver;                    /* ANSI approved version [0:2] */
+                                /* ECMA version [3:5] */
+                                /* ISO version [6:7] */
+  uchar byte3;                  /* response data format [0:3] */
                                 /* 0 SCSI 1 */
                                 /* 1 CCS */
                                 /* 2 SCSI-2 */
                                 /* 3-F reserved */
-  uchar res1     : 2;           /* reserved */
-  uchar TemIOP   : 1;           /* terminate I/O process bit (see 5.6.22) */
-  uchar aenc     : 1;           /* asynch. event notification (processor) */
+                                /* reserved [4:5] */
+                                /* terminate I/O process bit (see 5.6.22) [6] */
+                                /* asynch. event notification (processor) [7] */
   uchar add_len;                /* additional length */
+  uchar res1;                   /* reserved */
   uchar res2;                   /* reserved */
-  uchar res3;                   /* reserved */
-  uchar StfRe   : 1;            /* soft reset implemented */
-  uchar CmdQue  : 1;            /* command queuing */
-  uchar res4    : 1;            /* reserved */
-  uchar Linked  : 1;            /* linked command for this logical unit */
-  uchar Sync    : 1;            /* synchronous data transfer */
-  uchar WBus16  : 1;            /* wide bus 16 bit data transfer */
-  uchar WBus32  : 1;            /* wide bus 32 bit data transfer */
-  uchar RelAdr  : 1;            /* relative addressing mode */
+  uchar flags;                  /* soft reset implemented [0] */
+                                /* command queuing [1] */
+                                /* reserved [2] */
+                                /* linked command for this logical unit [3] */
+                                /* synchronous data transfer [4] */
+                                /* wide bus 16 bit data transfer [5] */
+                                /* wide bus 32 bit data transfer [6] */
+                                /* relative addressing mode [7] */
   uchar vendor_id[8];           /* vendor identification */
   uchar product_id[16];         /* product identification */
   uchar product_rev_level[4];   /* product revision level */
   uchar vendor_specific[20];    /* vendor specific */
-  uchar IUS      : 1;           /* information unit supported */
-  uchar QAS      : 1;           /* quick arbitrate supported */
-  uchar Clocking : 2;           /* clocking field */
-  uchar res5     : 4;           /* reserved */
-  uchar res6;                   /* reserved */
+  uchar info;                   /* information unit supported [0] */
+                                /* quick arbitrate supported [1] */
+                                /* clocking field [2:3] */
+                                /* reserved [4:7] */
+  uchar res3;                   /* reserved */
 } ADV_SCSI_INQUIRY; /* 58 bytes */
 
 
@@ -3459,7 +3571,6 @@
 
 /* asc_board_t flags */
 #define ASC_HOST_IN_RESET       0x01
-#define ASC_HOST_IN_ABORT       0x02
 #define ASC_IS_WIDE_BOARD       0x04    /* AdvanSys Wide Board */
 #define ASC_SELECT_QUEUE_DEPTHS 0x08
 
@@ -3473,22 +3584,17 @@
  * and data after loading, define macros for this purpose. These macros
  * are not used when the driver is built as a module, cf. linux/init.h.
  */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23)
-#define ASC_INITFUNC(type, func)        type func
-#define ASC_INITDATA
-#define ASC_INIT
-#else /* version >= v2.1.23 */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16)
-#define ASC_INITFUNC(type, func)        __initfunc(type func)
-#else /* version >= v2.3.16 */
+#if ASC_LINUX_KERNEL24
 #define ASC_INITFUNC(type, func)        type __init func
-#endif /* version >= v2.3.16 */
+#elif ASC_LINUX_KERNEL22
+#define ASC_INITFUNC(type, func)        __initfunc(type func)
+#endif
 #define ASC_INITDATA                    __initdata
 #define ASC_INIT                        __init
-#endif /* version >= v2.1.23 */
 
 #define ASC_INFO_SIZE           128            /* advansys_info() line size */
 
+#ifdef CONFIG_PROC_FS
 /* /proc/scsi/advansys/[0...] related definitions */
 #define ASC_PRTBUF_SIZE         2048
 #define ASC_PRTLINE_SIZE        160
@@ -3504,6 +3610,37 @@
     }
 
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * XXX - Release and acquire the io_request_lock. These macros are needed
+ * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
+ * on entry to SCSI low-level drivers.
+ *
+ * These definitions and all code that uses code should be removed when the
+ * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
+ * SCSI low-level driver detect, queuecommand, and reset entrypoints.
+ *
+ * The interrupt flags values doesn't matter in the macros because the
+ * SCSI mid-level will save and restore the flags values before and after
+ * calling advansys_detect, advansys_queuecommand, and advansys_reset where
+ * these macros are used. We do want interrupts enabled after the lock is
+ * released so an explicit sti() is done. The driver only needs interrupts
+ * disabled when it acquires the per board lock.
+ */
+#define ASC_UNLOCK_IO_REQUEST_LOCK \
+    { \
+        ulong flags; /* flags value not needed, cf. comment above. */ \
+        save_flags(flags); \
+        spin_unlock_irqrestore(&io_request_lock, flags); \
+        sti(); /* enable interrupts */ \
+    }
+
+#define ASC_LOCK_IO_REQUEST_LOCK \
+    { \
+        ulong flags; /* flags value not needed, cf. comment above. */ \
+        spin_lock_irqsave(&io_request_lock, flags); \
+    }
 
 /* Asc Library return codes */
 #define ASC_TRUE        1
@@ -3627,12 +3764,13 @@
 #define PCI_MAX_BUS             0xFF
 #define PCI_IOADDRESS_MASK      0xFFFE
 #define ASC_PCI_VENDORID        0x10CD
-#define ASC_PCI_DEVICE_ID_CNT   5       /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_CNT   6       /* PCI Device ID count. */
 #define ASC_PCI_DEVICE_ID_1100  0x1100
 #define ASC_PCI_DEVICE_ID_1200  0x1200
 #define ASC_PCI_DEVICE_ID_1300  0x1300
 #define ASC_PCI_DEVICE_ID_2300  0x2300  /* ASC-3550 */
 #define ASC_PCI_DEVICE_ID_2500  0x2500  /* ASC-38C0800 */
+#define ASC_PCI_DEVICE_ID_2700  0x2700  /* ASC-38C1600 */
 
 /* PCI IO Port Addresses to generate special cycle */
 
@@ -3843,10 +3981,8 @@
 /* Per board statistics structure */
 struct asc_stats {
     /* Driver Entrypoint Statistics */
-    ADV_DCNT command;         /* # calls to advansys_command() */
     ADV_DCNT queuecommand;    /* # calls to advansys_queuecommand() */
-    ADV_DCNT abort;           /* # calls to advansys_abort() */
-    ADV_DCNT reset;           /* # calls to advansys_reset() */
+    ADV_DCNT reset;           /* # calls to advansys_eh_bus_reset() */
     ADV_DCNT biosparam;       /* # calls to advansys_biosparam() */
     ADV_DCNT interrupt;       /* # advansys_interrupt() calls */
     ADV_DCNT callback;        /* # calls to asc/adv_isr_callback() */
@@ -3899,16 +4035,18 @@
  * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
  * up to 255 scatter-gather elements may be used per request or
  * ADV_SCSI_REQ_Q.
+ *
+ * Both structures must be 32 byte aligned.
  */
 typedef struct adv_sgblk {
-    ADV_SG_BLOCK        sg_block;        /* Sgblock structure. */
-    uchar               align2[4];       /* Sgblock structure padding. */
-    struct adv_sgblk    *next_sgblkp;    /* Next scatter-gather structure. */
+    ADV_SG_BLOCK        sg_block;     /* Sgblock structure. */
+    uchar               align[32];    /* Sgblock structure padding. */
+    struct adv_sgblk    *next_sgblkp; /* Next scatter-gather structure. */
 } adv_sgblk_t;
 
 typedef struct adv_req {
     ADV_SCSI_REQ_Q      scsi_req_q;   /* Adv Library request structure. */
-    uchar               align1[4];    /* Request structure padding. */
+    uchar               align[32];    /* Request structure padding. */
     Scsi_Cmnd           *cmndp;       /* Mid-Level SCSI command pointer. */
     adv_sgblk_t         *sgblkp;      /* Adv Library scatter-gather pointer. */
     struct adv_req      *next_reqp;   /* Next Request Structure. */
@@ -3932,6 +4070,7 @@
         ASC_DVC_CFG      asc_dvc_cfg;           /* Narrow board */
         ADV_DVC_CFG      adv_dvc_cfg;           /* Wide board */
     } dvc_cfg;
+    ushort               asc_n_io_port;         /* Number I/O ports. */
     asc_queue_t          active;                /* Active command queue */
     asc_queue_t          waiting;               /* Waiting command queue */
     asc_queue_t          done;                  /* Done command queue */
@@ -3944,12 +4083,14 @@
         ASCEEP_CONFIG         asc_eep;          /* Narrow EEPROM config. */
         ADVEEP_3550_CONFIG    adv_3550_eep;     /* 3550 EEPROM config. */
         ADVEEP_38C0800_CONFIG adv_38C0800_eep;  /* 38C0800 EEPROM config. */
+        ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+    spinlock_t lock;                            /* Board spinlock */
+#ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
-    char                 *prtbuf;               /* Statistics Print Buffer */
-#endif /* version >= v1.3.0 */
+    char                 *prtbuf;               /* /proc print buffer */
+#endif /* CONFIG_PROC_FS */
 #ifdef ADVANSYS_STATS
     struct asc_stats     asc_stats;             /* Board statistics */
 #endif /* ADVANSYS_STATS */
@@ -4032,8 +4173,8 @@
 
 /* Note: All driver global data should be initialized. */
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) && \
-    LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#if ASC_LINUX_KERNEL22
+#ifdef CONFIG_PROC_FS
 struct proc_dir_entry proc_scsi_advansys =
 {
     PROC_SCSI_ADVANSYS,              /* unsigned short low_ino */
@@ -4042,13 +4183,14 @@
     S_IFDIR | S_IRUGO | S_IXUGO,     /* mode_t mode */
     2                                /* nlink_t nlink */
 };
-#endif /* v2.3.28 > version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
+#endif /* ASC_LINUX_KERNEL22 */
 
 /* Number of boards detected in system. */
 STATIC int asc_board_count = 0;
 STATIC struct Scsi_Host    *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
 
-/* Overrun buffer shared between all boards. */
+/* Overrun buffer used by all narrow boards. */
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
 /*
@@ -4065,12 +4207,6 @@
     ASC_IS_PCI,
 };
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-STATIC int pci_scan_method ASC_INITDATA = -1;
-#endif /* ASC_CONFIG_PCI */
-#endif /* version < v2.1.93 */
-
 /*
  * Used with the LILO 'advansys' option to eliminate or
  * limit I/O port probing at boot time, cf. advansys_setup().
@@ -4078,19 +4214,6 @@
 STATIC int asc_iopflag = ASC_FALSE;
 STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-/*
- * In kernels earlier than v1.3.0, kmalloc() does not work
- * during driver initialization. Therefore statically declare
- * 16 elements of each structure. v1.3.0 kernels will probably
- * not need any more than this number.
- */
-uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 };
-uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
-#define ADV_SGBLK_BUF_CNT       32
-uchar adv_sgblk_buf[ADV_SGBLK_BUF_CNT * sizeof(adv_sgblk_t)] = { 0 };
-#endif /* version >= v1,3,0 */
-
 #ifdef ADVANSYS_DEBUG
 STATIC char *
 asc_bus_name[ASC_NUM_BUS] = {
@@ -4100,7 +4223,7 @@
     "ASC_IS_PCI",
 };
 
-STATIC int          asc_dbglvl = 2;
+STATIC int          asc_dbglvl = 3;
 #endif /* ADVANSYS_DEBUG */
 
 /* Declaration for Asc Library internal data referenced by driver. */
@@ -4113,19 +4236,9 @@
  * advansys.h contains function prototypes for functions global to Linux.
  */
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-STATIC int          asc_proc_copy(off_t, off_t, char *, int , char *, int);
-#endif /* version >= v1.3.0 */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-STATIC void         advansys_interrupt(int, struct pt_regs *);
-#else /* version >= v1.3.70 */
-STATIC void         advansys_interrupt(int, void *, struct pt_regs *);
-#endif /* version >= v1.3.70 */
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC void         advansys_select_queue_depths(struct Scsi_Host *,
-                                                Scsi_Device *);
-#endif /* version >= v1.3.89 */
-STATIC void       advansys_command_done(Scsi_Cmnd *);
+STATIC void       advansys_interrupt(int, void *, struct pt_regs *);
+STATIC void       advansys_select_queue_depths(struct Scsi_Host *,
+                                               Scsi_Device *);
 STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
@@ -4134,24 +4247,13 @@
 STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-STATIC int        asc_srch_pci_dev(PCI_DEVICE *);
-STATIC uchar      asc_scan_method(void);
-STATIC int        asc_pci_find_dev(PCI_DEVICE *);
-STATIC void       asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *);
-STATIC ushort     asc_get_cfg_word(PCI_DATA *);
-STATIC uchar      asc_get_cfg_byte(PCI_DATA *);
-STATIC void       asc_put_cfg_byte(PCI_DATA *, uchar);
-#endif /* ASC_CONFIG_PCI */
-#endif /* version < v2.1.93 */
 STATIC void       asc_enqueue(asc_queue_t *, REQP, int);
 STATIC REQP       asc_dequeue(asc_queue_t *, int);
 STATIC REQP       asc_dequeue_list(asc_queue_t *, REQP *, int);
 STATIC int        asc_rmqueue(asc_queue_t *, REQP);
-STATIC int        asc_isqueued(asc_queue_t *, REQP);
 STATIC void       asc_execute_queue(asc_queue_t *);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
+STATIC int        asc_proc_copy(off_t, off_t, char *, int , char *, int);
 STATIC int        asc_prt_board_devices(struct Scsi_Host *, char *, int);
 STATIC int        asc_prt_adv_bios(struct Scsi_Host *, char *, int);
 STATIC int        asc_get_eeprom_string(ushort *serialnum, uchar *cp);
@@ -4161,16 +4263,21 @@
 STATIC int        asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
 STATIC int        asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
 STATIC int        asc_prt_line(char *, int, char *fmt, ...);
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
 
 /* Declaration for Asc Library internal functions referenced by driver. */
 STATIC int          AscFindSignature(PortAddr);
 STATIC ushort       AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
 
+/* Statistics function prototypes. */
 #ifdef ADVANSYS_STATS
+#ifdef CONFIG_PROC_FS
 STATIC int          asc_prt_board_stats(struct Scsi_Host *, char *, int);
+STATIC int          asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
+#endif /* CONFIG_PROC_FS */
 #endif /* ADVANSYS_STATS */
 
+/* Debug function prototypes. */
 #ifdef ADVANSYS_DEBUG
 STATIC void         asc_prt_scsi_host(struct Scsi_Host *);
 STATIC void         asc_prt_scsi_cmnd(Scsi_Cmnd *);
@@ -4185,16 +4292,12 @@
 STATIC void         asc_prt_hex(char *f, uchar *, int);
 #endif /* ADVANSYS_DEBUG */
 
-#ifdef ADVANSYS_ASSERT
-STATIC int             advansys_interrupts_enabled(void);
-#endif /* ADVANSYS_ASSERT */
-
 
 /*
  * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
  */
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
 /*
  * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
  *
@@ -4216,10 +4319,9 @@
  * user just won't get all the available statistics.
  */
 int
-advansys_proc_info(char *buffer, char **start, off_t offset, int length, 
+advansys_proc_info(char *buffer, char **start, off_t offset, int length,
                    int hostno, int inout)
 {
-#ifdef CONFIG_PROC_FS
     struct Scsi_Host    *shp;
     asc_board_t         *boardp;
     int                 i;
@@ -4231,6 +4333,9 @@
     char                *curbuf;
     off_t               advoffset;
     Scsi_Device         *scd;
+#ifdef ADVANSYS_STATS
+    int                 tgt_id;
+#endif /* ADVANSYS_STATS */
 
     ASC_DBG(1, "advansys_proc_info: begin\n");
 
@@ -4322,11 +4427,7 @@
      * Display target driver information for each device attached
      * to the board.
      */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
-    for (scd = scsi_devices; scd; scd = scd->next)
-#else /* version >= v2.1.75 */
     for (scd = shp->host_queue; scd; scd = scd->next)
-#endif /* version >= v2.1.75 */
     {
         if (scd->host == shp) {
             cp = boardp->prtbuf;
@@ -4347,7 +4448,7 @@
             curbuf += cnt;
         }
     }
-    
+
     /*
      * Display EEPROM configuration for the board.
      */
@@ -4390,7 +4491,7 @@
      */
     cp = boardp->prtbuf;
     cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
-    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
     cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
     totcnt += cnt;
     leftlen -= cnt;
@@ -4400,6 +4501,24 @@
     }
     advoffset += cplen;
     curbuf += cnt;
+
+    /*
+     * Display driver statistics for each target.
+     */
+    for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
+      cp = boardp->prtbuf;
+      cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
+      ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+      cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+      totcnt += cnt;
+      leftlen -= cnt;
+      if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+      }
+      advoffset += cplen;
+      curbuf += cnt;
+    }
 #endif /* ADVANSYS_STATS */
 
     /*
@@ -4426,11 +4545,8 @@
     ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
 
     return totcnt;
-#else /* CONFIG_PROC_FS */
-    return 0;
-#endif /* CONFIG_PROC_FS */
 }
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
 
 /*
  * advansys_detect()
@@ -4461,19 +4577,6 @@
     int                 ioport = 0;
     int                 share_irq = FALSE;
     int                 iolen = 0;
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-    int                 pci_init_search = 0;
-    PCI_DEVICE          pci_device[ASC_NUM_BOARD_SUPPORTED];
-    int                 pci_card_cnt_max = 0;
-    int                 pci_card_cnt = 0;
-    PCI_DEVICE          pciDevice;
-    PCI_CONFIG_SPACE    pciConfig;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-    ADV_PADDR           pci_memory_address;
-#endif /* version >= v1,3,0 */
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
     int                 pci_init_search = 0;
     struct pci_dev      *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
@@ -4486,11 +4589,11 @@
                                     ASC_PCI_DEVICE_ID_1200,
                                     ASC_PCI_DEVICE_ID_1300,
                                     ASC_PCI_DEVICE_ID_2300,
-                                    ASC_PCI_DEVICE_ID_2500
+                                    ASC_PCI_DEVICE_ID_2500,
+                                    ASC_PCI_DEVICE_ID_2700
                         };
     ADV_PADDR           pci_memory_address;
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
     int                 warn_code, err_code;
     int                 ret;
 
@@ -4503,11 +4606,18 @@
 
     ASC_DBG(1, "advansys_detect: begin\n");
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,28)
+    /*
+     * XXX - Remove this comment and the next line when SCSI mid-level
+     * no longer acquires 'io_request_lock' before calling the SCSI
+     * low-level detect entrypoint.
+     */
+    ASC_UNLOCK_IO_REQUEST_LOCK
+
+#if ASC_LINUX_KERNEL24
     tpnt->proc_name = "advansys";
-#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#elif ASC_LINUX_KERNEL22
     tpnt->proc_dir = &proc_scsi_advansys;
-#endif /* version >= v1.3.0 */
+#endif
 
     asc_board_count = 0;
 
@@ -4517,7 +4627,7 @@
      */
     if (asc_iopflag == ASC_TRUE) {
         for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
-            ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n",
+            ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
                 ioport, asc_ioport[ioport]);
             if (asc_ioport[ioport] != 0) {
                 for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
@@ -4536,15 +4646,6 @@
         ioport = 0;
     }
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-    memset(&pciDevice, 0, sizeof(PCI_DEVICE));
-    memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE));
-    pciDevice.maxBusNumber = PCI_MAX_BUS;
-    pciDevice.endSlot = PCI_MAX_SLOT;
-#endif /* ASC_CONFIG_PCI */
-#endif /* version < v2.1.93 */ 
-
     for (bus = 0; bus < ASC_NUM_BUS; bus++) {
 
         ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
@@ -4559,6 +4660,7 @@
             switch (asc_bus[bus]) {
             case ASC_IS_ISA:
             case ASC_IS_VL:
+#ifdef CONFIG_ISA
                 if (asc_iopflag == ASC_FALSE) {
                     iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
                 } else {
@@ -4577,7 +4679,8 @@
                         }
                     }
                     if (iop) {
-                        ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n",
+                        ASC_DBG1(1,
+                                "advansys_detect: probing I/O port 0x%x...\n",
                             iop);
                         if (check_region(iop, ASC_IOADR_GAP) != 0) {
                             printk(
@@ -4618,74 +4721,16 @@
                         asc_ioport[ioport++] = 0;
                     }
                 }
+#endif /* CONFIG_ISA */
                 break;
 
             case ASC_IS_EISA:
+#ifdef CONFIG_ISA
                 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+#endif /* CONFIG_ISA */
                 break;
 
             case ASC_IS_PCI:
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-                if (pci_init_search == 0) {
-                    int i, j;
-
-                    pci_init_search = 1;
-
-                    /* Find all PCI cards. */
-                    while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) {
-                        pci_device[pci_card_cnt_max++] = pciDevice;
-                    }
-
-                    /*
-                     * Sort PCI cards in ascending order by PCI Bus, Slot,
-                     * and Device Number.
-                     */
-                    for (i = 0; i < pci_card_cnt_max - 1; i++)
-                    {
-                        for (j = i + 1; j < pci_card_cnt_max; j++) {
-                            if ((pci_device[j].busNumber <
-                                 pci_device[i].busNumber) ||
-                                ((pci_device[j].busNumber ==
-                                  pci_device[i].busNumber) &&
-                                  (pci_device[j].slotNumber <
-                                   pci_device[i].slotNumber)) ||
-                                ((pci_device[j].busNumber ==
-                                  pci_device[i].busNumber) &&
-                                  (pci_device[j].slotNumber ==
-                                   pci_device[i].slotNumber) &&
-                                  (pci_device[j].devFunc <
-                                   pci_device[i].devFunc))) {
-                                pciDevice = pci_device[i];
-                                pci_device[i] = pci_device[j];
-                                pci_device[j] = pciDevice;
-                            }
-                        }
-                    }
-
-                    pci_card_cnt = 0;
-                } else {
-                    pci_card_cnt++;
-                }
-
-                if (pci_card_cnt == pci_card_cnt_max) {
-                    iop = 0;
-                } else {
-                    pciDevice = pci_device[pci_card_cnt];
-                    ASC_DBG2(2,
-                        "advansys_detect: slotFound %d, busNumber %d\n",
-                        pciDevice.slotFound, pciDevice.busNumber);
-                    asc_get_pci_cfg(&pciDevice, &pciConfig);
-                    iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK;
-                    ASC_DBG2(1,
-                        "advansys_detect: vendorID %X, deviceID %X\n",
-                        pciConfig.vendorID, pciConfig.deviceID);
-                    ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
-                        iop, pciConfig.irqLine);
-                }
-                break;
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
                 if (pci_init_search == 0) {
                     int i, j;
@@ -4699,8 +4744,13 @@
                             NULL) {
                             pci_device_id_cnt++;
                         } else {
-			    if (pci_enable_device(pci_devp) == 0)
-                            	pci_devicep[pci_card_cnt_max++] = pci_devp;
+#if ASC_LINUX_KERNEL24
+                            if (pci_enable_device(pci_devp) == 0) {
+                                pci_devicep[pci_card_cnt_max++] = pci_devp;
+                            }
+#elif ASC_LINUX_KERNEL22
+                            pci_devicep[pci_card_cnt_max++] = pci_devp;
+#endif
                         }
                     }
 
@@ -4737,11 +4787,11 @@
                     ASC_DBG2(2,
                         "advansys_detect: devfn %d, bus number %d\n",
                         pci_devp->devfn, pci_devp->bus->number);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
-                    iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
-#else /* version >= v2.3.13 */ 
+#if ASC_LINUX_KERNEL24
                     iop = pci_resource_start(pci_devp, 0);
-#endif /* version >= v2.3.13 */ 
+#elif ASC_LINUX_KERNEL22
+                    iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
+#endif
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
                         pci_devp->vendor, pci_devp->device);
@@ -4749,7 +4799,6 @@
                         iop, pci_devp->irq);
                 }
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
                 break;
 
             default:
@@ -4757,7 +4806,7 @@
                     asc_bus[bus]);
                 break;
             }
-            ASC_DBG1(1, "advansys_detect: iop %x\n", iop);
+            ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
 
             /*
              * Adapter not found, try next bus type.
@@ -4774,9 +4823,10 @@
              */
             ASC_DBG(2, "advansys_detect: scsi_register()\n");
             shp = scsi_register(tpnt, sizeof(asc_board_t));
-            
-            if(shp==NULL)
-            	continue;
+
+            if (shp == NULL) {
+                continue;
+            }
 
             /* Save a pointer to the Scsi_host of each board found. */
             asc_host[asc_board_count++] = shp;
@@ -4786,6 +4836,9 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+            /* Initialize spinlock. */
+            boardp->lock = SPIN_LOCK_UNLOCKED;
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -4793,25 +4846,15 @@
              * wide board flag. Set-up the board structure based on
              * the board type.
              */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-            if (asc_bus[bus] == ASC_IS_PCI &&
-                (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 ||
-                 pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500))
-            {
-                boardp->flags |= ASC_IS_WIDE_BOARD;
-            }
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
             if (asc_bus[bus] == ASC_IS_PCI &&
                 (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
-                 pci_devp->device == ASC_PCI_DEVICE_ID_2500))
+                 pci_devp->device == ASC_PCI_DEVICE_ID_2500 ||
+                 pci_devp->device == ASC_PCI_DEVICE_ID_2700))
             {
                 boardp->flags |= ASC_IS_WIDE_BOARD;
             }
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
 
             if (ASC_NARROW_BOARD(boardp)) {
                 ASC_DBG(1, "advansys_detect: narrow board\n");
@@ -4829,36 +4872,22 @@
                 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
                 adv_dvc_varp->isr_callback = adv_isr_callback;
                 adv_dvc_varp->async_callback = adv_async_callback;
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-                if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300)
-                {
-                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
-                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
-                } else
-                {
-                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
-                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
-                }
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
                 if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
                 {
                     ASC_DBG(1, "advansys_detect: ASC-3550\n");
                     adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
-                } else
+                } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500)
                 {
                     ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
                     adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+                } else
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C1600\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
                 }
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-                adv_dvc_varp->iop_base = iop;
-#else /* version >= v1,3,0 */
                 /*
                  * Map the board's registers into virtual memory for
                  * PCI slave access. Only memory accesses are used to
@@ -4873,76 +4902,53 @@
                 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
                 {
                     iolen = ADV_3550_IOLEN;
-                } else {
+                } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+                {
                     iolen = ADV_38C0800_IOLEN;
+                } else
+                {
+                    iolen = ADV_38C1600_IOLEN;
                 }
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-                pci_memory_address = pciConfig.baseAddress[1];
-                ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
-                    (ulong) pci_memory_address);
-                if ((boardp->ioremap_addr =
-                    ioremap(pci_memory_address & PAGE_MASK,
-                         PAGE_SIZE)) == 0) {
-                   ASC_PRINT3(
-"advansys_detect: board %d: ioremap(%lu, %x) returned NULL\n",
-                   boardp->id, (ulong) pci_memory_address, iolen);
-                   scsi_unregister(shp);
-                   asc_board_count--;
-                   continue;
-                }
-                ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
-                    (ulong) boardp->ioremap_addr);
-                adv_dvc_varp->iop_base = (AdvPortAddr)
-                    (boardp->ioremap_addr +
-                     (pci_memory_address - (pci_memory_address & PAGE_MASK)));
-                ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
-                    adv_dvc_varp->iop_base);
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
-                pci_memory_address = pci_devp->base_address[1];
-#else /* version >= v2.3.13 */ 
+#if ASC_LINUX_KERNEL24
                 pci_memory_address = pci_resource_start(pci_devp, 1);
-#endif /* version >= v2.3.13 */ 
-                ASC_DBG1(1, "advansys_detect: pci_memory_address: %x\n",
-                    pci_memory_address);
+#elif ASC_LINUX_KERNEL22
+                pci_memory_address = pci_devp->base_address[1];
+#endif
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n",
+                    (ulong) pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
 "advansys_detect: board %d: ioremap(%x, %d) returned NULL\n",
-                   boardp->id, pci_memory_address, iolen);
+                       boardp->id, pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
                    continue;
                 }
-                ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+                ASC_DBG1(1, "advansys_detect: ioremap_addr: 0x%lx\n",
                     (ulong) boardp->ioremap_addr);
                 adv_dvc_varp->iop_base = (AdvPortAddr)
                     (boardp->ioremap_addr +
                      (pci_memory_address - (pci_memory_address & PAGE_MASK)));
-                ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+                ASC_DBG1(1, "advansys_detect: iop_base: 0x%lx\n",
                     adv_dvc_varp->iop_base);
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
-#endif /* version >= v1,3,0 */
 
                 /*
-                 * Even though it isn't used to access the board in
-                 * kernels greater than or equal to v1.3.0, save
-                 * the I/O Port address so that it can be reported and
-                 * displayed.
+                 * Even though it isn't used to access wide boards, other
+                 * than for the debug line below, save I/O Port address so
+                 * that it can be reported.
                  */
                 boardp->ioport = iop;
 
                 ASC_DBG2(1,
-                    "advansys_detect: iopb_chip_id_1 %x, iopw_chip_id_0 %x\n",
+"advansys_detect: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
                     (ushort) inp(iop + 1), (ushort) inpw(iop));
             }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
             /*
              * Allocate buffer for printing information from
              * /proc/scsi/advansys/[0...].
@@ -4956,7 +4962,7 @@
                 asc_board_count--;
                 continue;
             }
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
 
             if (ASC_NARROW_BOARD(boardp)) {
                 /*
@@ -4964,6 +4970,7 @@
                  * calling AscInitGetConfig().
                  */
                 switch (asc_dvc_varp->bus_type) {
+#ifdef CONFIG_ISA
                 case ASC_IS_ISA:
                     shp->unchecked_isa_dma = TRUE;
                     share_irq = FALSE;
@@ -4976,20 +4983,7 @@
                     shp->unchecked_isa_dma = FALSE;
                     share_irq = TRUE;
                     break;
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-                case ASC_IS_PCI:
-                    shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine;
-                    asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
-                    asc_dvc_varp->cfg->pci_slot_info =
-                        ASC_PCI_MKID(pciDevice.busNumber,
-                            pciDevice.slotFound,
-                            pciDevice.devFunc);
-                    shp->unchecked_isa_dma = FALSE;
-                    share_irq = TRUE;
-                    break;
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
+#endif /* CONFIG_ISA */
 #ifdef CONFIG_PCI
                 case ASC_IS_PCI:
                     shp->irq = asc_dvc_varp->irq_no = pci_devp->irq;
@@ -5002,7 +4996,6 @@
                     share_irq = TRUE;
                     break;
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
                 default:
                     ASC_PRINT2(
 "advansys_detect: board %d: unknown adapter type: %d\n",
@@ -5016,18 +5009,6 @@
                  * For Wide boards set PCI information before calling
                  * AdvInitGetConfig().
                  */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-                shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine;
-                adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
-                adv_dvc_varp->cfg->pci_slot_info =
-                    ASC_PCI_MKID(pciDevice.busNumber,
-                        pciDevice.slotFound,
-                        pciDevice.devFunc);
-                shp->unchecked_isa_dma = FALSE;
-                share_irq = TRUE;
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
                 shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
                 adv_dvc_varp->cfg->pci_device_id = pci_devp->device;
@@ -5038,7 +5019,6 @@
                 shp->unchecked_isa_dma = FALSE;
                 share_irq = TRUE;
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
             }
 
             /*
@@ -5082,33 +5062,33 @@
                     break;
                 default:
                     ASC_PRINT2(
-"AscInitGetConfig: board %d: unknown warning: %x\n",
+"AscInitGetConfig: board %d: unknown warning: 0x%x\n",
                         boardp->id, ret);
                     break;
                 }
                 if ((err_code = asc_dvc_varp->err_code) != 0) {
                     ASC_PRINT3(
-"AscInitGetConfig: board %d error: init_state %x, err_code %x\n",
+"AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
                         boardp->id, asc_dvc_varp->init_state,
                         asc_dvc_varp->err_code);
                 }
             } else {
                 ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n");
                 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
-                    ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n",
+                    ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
                         boardp->id, ret);
                 }
                 if ((err_code = adv_dvc_varp->err_code) != 0) {
                     ASC_PRINT2(
-"AdvInitGetConfig: board %d error: err_code %x\n",
+"AdvInitGetConfig: board %d error: err_code 0x%x\n",
                         boardp->id, adv_dvc_varp->err_code);
                 }
             }
-        
+
             if (err_code != 0) {
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
                 kfree(boardp->prtbuf);
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
                 scsi_unregister(shp);
                 asc_board_count--;
                 continue;
@@ -5136,12 +5116,12 @@
                 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
                 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
                 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
-                ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed;
+                ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
                 ep->start_motor = asc_dvc_varp->start_motor;
                 ep->cntl = asc_dvc_varp->dvc_cntl;
                 ep->no_scam = asc_dvc_varp->no_scam;
                 ep->max_total_qng = asc_dvc_varp->max_total_qng;
-                ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id;
+                ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
                 /* 'max_tag_qng' is set to the same value for every device. */
                 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
                 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
@@ -5186,18 +5166,18 @@
                     break;
                 default:
                     ASC_PRINT2(
-"AscInitSetConfig: board %d: unknown warning: %x\n",
+"AscInitSetConfig: board %d: unknown warning: 0x%x\n",
                         boardp->id, ret);
                     break;
                 }
                 if (asc_dvc_varp->err_code != 0) {
                     ASC_PRINT3(
-"AscInitSetConfig: board %d error: init_state %x, err_code %x\n",
+"AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
                         boardp->id, asc_dvc_varp->init_state,
                         asc_dvc_varp->err_code);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
                     kfree(boardp->prtbuf);
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
                     scsi_unregister(shp);
                     asc_board_count--;
                     continue;
@@ -5213,6 +5193,7 @@
             } else {
                 ADVEEP_3550_CONFIG      *ep_3550;
                 ADVEEP_38C0800_CONFIG   *ep_38C0800;
+                ADVEEP_38C1600_CONFIG   *ep_38C1600;
 
                 /*
                  * Save Wide EEP Configuration Information.
@@ -5239,7 +5220,7 @@
                         adv_dvc_varp->cfg->serial2;
                     ep_3550->serial_number_word3 =
                         adv_dvc_varp->cfg->serial3;
-                } else
+                } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
                 {
                     ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
 
@@ -5266,6 +5247,33 @@
                         adv_dvc_varp->cfg->serial2;
                     ep_38C0800->serial_number_word3 =
                         adv_dvc_varp->cfg->serial3;
+                } else
+                {
+                    ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+
+                    ep_38C1600->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_38C1600->termination_lvd =
+                        adv_dvc_varp->cfg->termination;
+                    ep_38C1600->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+                    ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+                    ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+                    ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+                    ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C1600->start_motor = adv_dvc_varp->start_motor;
+                    ep_38C1600->scsi_reset_delay =
+                        adv_dvc_varp->scsi_reset_wait;
+                    ep_38C1600->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_38C1600->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_38C1600->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
                 }
 
                 /*
@@ -5280,20 +5288,18 @@
                 shp->irq = adv_dvc_varp->irq_no;
             }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
             /*
-             * Channels are numbered beginning with 0. For AdvanSys One host
+             * Channels are numbered beginning with 0. For AdvanSys one host
              * structure supports one channel. Multi-channel boards have a
-             * separate host structure for each channel. 
+             * separate host structure for each channel.
              */
             shp->max_channel = 0;
-#endif /* version >= v1.3.89 */
             if (ASC_NARROW_BOARD(boardp)) {
                 shp->max_id = ASC_MAX_TID + 1;
                 shp->max_lun = ASC_MAX_LUN + 1;
 
                 shp->io_port = asc_dvc_varp->iop_base;
-                shp->n_io_port = ASC_IOADR_GAP;
+                boardp->asc_n_io_port = ASC_IOADR_GAP;
                 shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
 
                 /* Set maximum number of queues the adapter can handle. */
@@ -5303,13 +5309,13 @@
                 shp->max_lun = ADV_MAX_LUN + 1;
 
                 /*
-                 * Save the I/O Port address and length even though the
-                 * in v1.3.0 and greater kernels the region is not used
-                 * by a Wide board. Instead the board is accessed with
-                 * Memory Mapped I/O.
+                 * Save the I/O Port address and length even though
+                 * I/O ports are not used to access Wide boards.
+                 * Instead the Wide boards are accessed with
+                 * PCI Memory Mapped I/O.
                  */
                 shp->io_port = iop;
-                shp->n_io_port = iolen;
+                boardp->asc_n_io_port = iolen;
 
                 shp->this_id = adv_dvc_varp->chip_scsi_id;
 
@@ -5317,18 +5323,15 @@
                 shp->can_queue = adv_dvc_varp->max_host_qng;
             }
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
             /*
-             * In old kernels without tag queuing support and with memory
-             * allocation problems set a conservative 'cmd_per_lun' value.
+             * 'n_io_port' currently is one byte.
+             *
+             * Set a value to 'n_io_port', but never referenced it because
+             * it may be truncated.
              */
-#ifdef MODULE
-            shp->cmd_per_lun = 1;
-#else /* MODULE */
-            shp->cmd_per_lun = 4;
-#endif /* MODULE */
-            ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun);
-#else /* version >= v1.3.89 */
+            shp->n_io_port = boardp->asc_n_io_port <= 255 ?
+                boardp->asc_n_io_port : 255;
+
             /*
              * Following v1.3.89, 'cmd_per_lun' is no longer needed
              * and should be set to zero.
@@ -5348,7 +5351,6 @@
              * the number of commands to queue per device.
              */
             shp->select_queue_depths = advansys_select_queue_depths;
-#endif /* version >= v1.3.89 */
 
             /*
              * Set the maximum number of scatter-gather elements the
@@ -5368,20 +5370,6 @@
                 shp->sg_tablesize = ADV_MAX_SG_LIST;
             }
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-#ifdef MODULE
-            /*
-             * If the driver is compiled as a module, set a limit on the
-             * 'sg_tablesize' value to prevent memory allocation failures.
-             * Memory allocation errors are more likely to occur at module
-             * load time, then at driver initialization time.
-             */
-            if (shp->sg_tablesize > 64) {
-                shp->sg_tablesize = 64;
-            }
-#endif /* MODULE */
-#endif /* version < v2.0.0 */
-
             /*
              * The value of 'sg_tablesize' can not exceed the SCSI
              * mid-level driver definition of SG_ALL. SG_ALL also
@@ -5397,11 +5385,11 @@
 
             /* BIOS start address. */
             if (ASC_NARROW_BOARD(boardp)) {
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+#if ASC_LINUX_KERNEL24
                 shp->base =
-#else /* version >= v2.3.29 */
+#elif ASC_LINUX_KERNEL22
                 shp->base = (char *)
-#endif /* version < v2.3.29 */
+#endif
                         ((ulong) AscGetChipBiosAddress(
                             asc_dvc_varp->iop_base,
                             asc_dvc_varp->bus_type));
@@ -5420,11 +5408,11 @@
                     boardp->bios_codelen);
 
                 ASC_DBG2(1,
-                    "advansys_detect: bios_signature %x, bios_version %x\n",
+                    "advansys_detect: bios_signature 0x%x, bios_version 0x%x\n",
                     boardp->bios_signature, boardp->bios_version);
 
                 ASC_DBG2(1,
-                    "advansys_detect: bios_codeseg %x, bios_codelen %x\n",
+                    "advansys_detect: bios_codeseg 0x%x, bios_codelen 0x%x\n",
                     boardp->bios_codeseg, boardp->bios_codelen);
 
                 /*
@@ -5436,11 +5424,10 @@
                      * Convert x86 realmode code segment to a linear
                      * address by shifting left 4.
                      */
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
                     shp->base =
-#else /* version >= v2.3.29 */
-                    shp->base = (char *)
-#endif /* version < v2.3.29 */
+#if ASC_LINUX_KERNEL22
+                        (char *)
+#endif
                         ((ulong) boardp->bios_codeseg << 4);
                 } else {
                     shp->base = 0;
@@ -5451,12 +5438,37 @@
              * Register Board Resources - I/O Port, DMA, IRQ
              */
 
-            /* Register I/O port range. */
-            ASC_DBG(2, "advansys_detect: request_region()\n");
-            request_region(shp->io_port, shp->n_io_port, "advansys");
+            /*
+             * Register I/O port range.
+             *
+             * For Wide boards the I/O ports are not used to access
+             * the board, but request the region anyway.
+             *
+             * 'shp->n_io_port' is not referenced, because it may be truncated.
+             */
+            ASC_DBG2(2,
+                "advansys_detect: request_region port 0x%lx, len 0x%x\n",
+                (ulong) shp->io_port, boardp->asc_n_io_port);
+#if ASC_LINUX_KERNEL24
+            if (request_region(shp->io_port, boardp->asc_n_io_port,
+                               "advansys") == NULL) {
+                ASC_PRINT3(
+"advansys_detect: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
+                    boardp->id, (ulong) shp->io_port, boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+                kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+#elif ASC_LINUX_KERNEL22
+            request_region(shp->io_port, boardp->asc_n_io_port, "advansys");
+#endif
 
             /* Register DMA Channel for Narrow boards. */
             shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
+#ifdef CONFIG_ISA
             if (ASC_NARROW_BOARD(boardp)) {
                 /* Register DMA channel for ISA bus. */
                 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
@@ -5466,10 +5478,10 @@
                         ASC_PRINT3(
 "advansys_detect: board %d: request_dma() %d failed %d\n",
                             boardp->id, shp->dma_channel, ret);
-                        release_region(shp->io_port, shp->n_io_port);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                        release_region(shp->io_port, boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
                         kfree(boardp->prtbuf);
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
                         scsi_unregister(shp);
                         asc_board_count--;
                         continue;
@@ -5477,13 +5489,10 @@
                     AscEnableIsaDma(shp->dma_channel);
                 }
             }
+#endif /* CONFIG_ISA */
 
             /* Register IRQ Number. */
             ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-            if ((ret = request_irq(shp->irq, advansys_interrupt,
-                            SA_INTERRUPT, "advansys")) != 0)
-#else /* version >= v1.3.70 */
            /*
             * If request_irq() fails with the SA_INTERRUPT flag set,
             * then try again without the SA_INTERRUPT flag set. This
@@ -5499,31 +5508,28 @@
                 ((ret = request_irq(shp->irq, advansys_interrupt,
                             (share_irq == TRUE ? SA_SHIRQ : 0),
                             "advansys", boardp)) != 0))
-#endif /* version >= v1.3.70 */
             {
                 if (ret == -EBUSY) {
                     ASC_PRINT2(
-"advansys_detect: board %d: request_irq(): IRQ %d already in use.\n",
+"advansys_detect: board %d: request_irq(): IRQ 0x%x already in use.\n",
                         boardp->id, shp->irq);
                 } else if (ret == -EINVAL) {
                     ASC_PRINT2(
-"advansys_detect: board %d: request_irq(): IRQ %d not valid.\n",
+"advansys_detect: board %d: request_irq(): IRQ 0x%x not valid.\n",
                         boardp->id, shp->irq);
                 } else {
                     ASC_PRINT3(
-"advansys_detect: board %d: request_irq(): IRQ %d failed with %d\n",
+"advansys_detect: board %d: request_irq(): IRQ 0x%x failed with %d\n",
                         boardp->id, shp->irq, ret);
                 }
-                release_region(shp->io_port, shp->n_io_port);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                release_region(shp->io_port, boardp->asc_n_io_port);
                 iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
                 if (shp->dma_channel != NO_ISA_DMA) {
                     free_dma(shp->dma_channel);
                 }
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
                 kfree(boardp->prtbuf);
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
                 scsi_unregister(shp);
                 asc_board_count--;
                 continue;
@@ -5539,7 +5545,7 @@
 
                 if (warn_code || err_code) {
                     ASC_PRINT4(
-"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n",
+"advansys_detect: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
                         boardp->id, asc_dvc_varp->init_state,
                         warn_code, err_code);
                 }
@@ -5549,25 +5555,13 @@
                 adv_req_t       *reqp = NULL;
                 int             sg_cnt = 0;
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-                carrp = (ADV_CARR_T *) &adv_carr_buf[0];
-                req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
-                sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
-                reqp = (adv_req_t *) &adv_req_buf[0];
-                boardp->adv_sgblkp = NULL;
-                for (sg_cnt = 0; sg_cnt < ADV_SGBLK_BUF_CNT; sg_cnt++) {
-                    sgp = (adv_sgblk_t *) &adv_sgblk_buf[sg_cnt];
-                    sgp->next_sgblkp = boardp->adv_sgblkp;
-                    boardp->adv_sgblkp = sgp;
-                }
-#else /* version >= v1.3.0 */
                 /*
                  * Allocate buffer carrier structures. The total size
                  * is about 4 KB, so allocate all at once.
                  */
                 carrp =
                     (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
-                ASC_DBG1(1, "advansys_detect: carrp %lx\n", (ulong) carrp);
+                ASC_DBG1(1, "advansys_detect: carrp 0x%lx\n", (ulong) carrp);
 
                 if (carrp == NULL) {
                     goto kmalloc_error;
@@ -5586,7 +5580,7 @@
                         kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
 
                     ASC_DBG3(1,
-                        "advansys_detect: reqp %lx, req_cnt %d, bytes %lu\n",
+                        "advansys_detect: reqp 0x%lx, req_cnt %d, bytes %lu\n",
                         (ulong) reqp, req_cnt,
                         (ulong) sizeof(adv_req_t) * req_cnt);
 
@@ -5631,24 +5625,24 @@
                 if (carrp == NULL)
                 {
                     ASC_PRINT1(
-"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n",
+"advansys_detect: board %d error: failed to kmalloc() carrier buffer.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
                 } else if (reqp == NULL) {
                     kfree(carrp);
                     ASC_PRINT1(
-"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
+"advansys_detect: board %d error: failed to kmalloc() adv_req_t buffer.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
                 } else if (boardp->adv_sgblkp == NULL) {
                     kfree(carrp);
                     kfree(reqp);
                     ASC_PRINT1(
-"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffers.\n",
+"advansys_detect: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
                 } else {
-                    
+
                     /* Save carrier buffer pointer. */
                     boardp->orig_carrp = carrp;
 
@@ -5657,7 +5651,6 @@
                      * driver is built as a module and can be unloaded.
                      */
                     boardp->orig_reqp = reqp;
-#endif /* version >= v1.3.0 */
 
                     adv_dvc_varp->carrier_buf = carrp;
 
@@ -5677,26 +5670,27 @@
                         ASC_DBG(2,
                             "advansys_detect: AdvInitAsc3550Driver()\n");
                         warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
-                    } else {
+                    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
                         ASC_DBG(2,
                             "advansys_detect: AdvInitAsc38C0800Driver()\n");
                         warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
+                    } else {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc38C1600Driver()\n");
+                        warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
                     }
                     err_code = adv_dvc_varp->err_code;
 
                     if (warn_code || err_code) {
                         ASC_PRINT3(
-"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n",
+"advansys_detect: board %d error: warn 0x%x, error 0x%x\n",
                             boardp->id, warn_code, err_code);
                     }
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
                 }
-#endif /* version >= v1,3,0 */
             }
 
             if (err_code != 0) {
-                release_region(shp->io_port, shp->n_io_port);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                release_region(shp->io_port, boardp->asc_n_io_port);
                 if (ASC_WIDE_BOARD(boardp)) {
                     iounmap(boardp->ioremap_addr);
                     if (boardp->orig_carrp) {
@@ -5713,18 +5707,13 @@
                         kfree(sgp);
                     }
                 }
-#endif /* version >= v1,3,0 */
                 if (shp->dma_channel != NO_ISA_DMA) {
                     free_dma(shp->dma_channel);
                 }
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
                 kfree(boardp->prtbuf);
-#endif /* version >= v1.3.0 */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-                free_irq(shp->irq);
-#else /* version >= v1.3.70 */
+#endif /* CONFIG_PROC_FS */
                 free_irq(shp->irq, boardp);
-#endif /* version >= v1.3.70 */
                 scsi_unregister(shp);
                 asc_board_count--;
                 continue;
@@ -5732,6 +5721,14 @@
             ASC_DBG_PRT_SCSI_HOST(2, shp);
         }
     }
+
+    /*
+     * XXX - Remove this comment and the next line when SCSI mid-level
+     * no longer acquires 'io_request_lock' before calling the SCSI
+     * low-level detect entrypoint.
+     */
+    ASC_LOCK_IO_REQUEST_LOCK
+
     ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
     return asc_board_count;
 }
@@ -5748,17 +5745,12 @@
 
     ASC_DBG(1, "advansys_release: begin\n");
     boardp = ASC_BOARDP(shp);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-    free_irq(shp->irq);
-#else /* version >= v1.3.70 */
     free_irq(shp->irq, boardp);
-#endif /* version >= v1.3.70 */
     if (shp->dma_channel != NO_ISA_DMA) {
         ASC_DBG(1, "advansys_release: free_dma()\n");
         free_dma(shp->dma_channel);
     }
-    release_region(shp->io_port, shp->n_io_port);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+    release_region(shp->io_port, boardp->asc_n_io_port);
     if (ASC_WIDE_BOARD(boardp)) {
         adv_sgblk_t    *sgp = NULL;
 
@@ -5777,9 +5769,10 @@
             kfree(sgp);
         }
     }
+#ifdef CONFIG_PROC_FS
     ASC_ASSERT(boardp->prtbuf != NULL);
     kfree(boardp->prtbuf);
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
     scsi_unregister(shp);
     ASC_DBG(1, "advansys_release: end\n");
     return 0;
@@ -5815,51 +5808,37 @@
             } else {
                 busname = "ISA";
             }
+            /* Don't reference 'shp->n_io_port'; It may be truncated. */
             sprintf(info,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92)
-"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u",
-#else /* version >= v2.1.92 */ 
-"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u",
-#endif /* version >= v2.1.92 */ 
-                ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
-                (ulong) shp->base,
-                (ulong) shp->io_port, shp->n_io_port - 1,
+"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+                ASC_VERSION, busname,
+                (ulong) shp->io_port,
+                (ulong) shp->io_port + boardp->asc_n_io_port - 1,
                 shp->irq, shp->dma_channel);
-        } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-            if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-                == ASC_IS_PCI_ULTRA) {
-                busname = "PCI Ultra";
-            } else {
-                busname = "PCI";
-            }
-            sprintf(info,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92)
-                "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u",
-#else /* version >= v2.1.92 */ 
-                "AdvanSys SCSI %s: %s %u CDB: IO %lX/%X, IRQ %u",
-#endif /* version >= v2.1.92 */ 
-                ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
-                shp->io_port, shp->n_io_port - 1, shp->irq);
         } else {
             if (asc_dvc_varp->bus_type & ASC_IS_VL) {
                 busname = "VL";
             } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
                 busname = "EISA";
+            } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+                if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+                    == ASC_IS_PCI_ULTRA) {
+                    busname = "PCI Ultra";
+                } else {
+                    busname = "PCI";
+                }
             } else {
                 busname = "?";
-                ASC_PRINT2(
-    "advansys_info: board %d: unknown bus type %d\n",
+                ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n",
                     boardp->id, asc_dvc_varp->bus_type);
             }
+            /* Don't reference 'shp->n_io_port'; It may be truncated. */
             sprintf(info,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92)
-                "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %X/%X, IRQ %u",
-#else /* version >= v2.1.92 */ 
-                "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u",
-#endif /* version >= v2.1.92 */ 
-                ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
-                (ulong) shp->base, shp->io_port - 1,
-                shp->n_io_port, shp->irq);
+                "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+                ASC_VERSION, busname,
+                (ulong) shp->io_port,
+                (ulong) shp->io_port + boardp->asc_n_io_port - 1,
+                shp->irq);
         }
     } else {
         /*
@@ -5874,29 +5853,21 @@
         {
             iolen = ADV_3550_IOLEN;
             widename = "Ultra-Wide";
-        } else {
+        } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+        {
             iolen = ADV_38C0800_IOLEN;
             widename = "Ultra2-Wide";
+        } else
+        {
+            iolen = ADV_38C1600_IOLEN;
+            widename = "Ultra3-Wide";
         }
-        if (boardp->bios_signature == 0x55AA) {
-            sprintf(info,
-"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u",
-                ASC_VERSION,
-                widename,
-                boardp->bios_codeseg << 4,
-                boardp->bios_codelen > 0 ?
-                (boardp->bios_codelen << 9) - 1 : 0,
-                (unsigned) boardp->ioport, iolen - 1,
-                shp->irq);
-        } else {
-            sprintf(info,
-"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u",
-                ASC_VERSION,
-                widename,
-                (unsigned) boardp->ioport,
-                (iolen - 1),
-                shp->irq);
-        }
+        sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+            ASC_VERSION,
+            widename,
+            (ulong) adv_dvc_varp->iop_base,
+            (ulong) adv_dvc_varp->iop_base + iolen - 1,
+            shp->irq);
     }
     ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
     ASC_DBG(1, "advansys_info: end\n");
@@ -5904,30 +5875,6 @@
 }
 
 /*
- * advansys_command() - polled I/O entrypoint.
- *
- * Apparently host drivers shouldn't return until the command
- * is finished.
- *
- * Note: This is an old interface that is no longer used by the SCSI
- * mid-level driver. The new interface, advansys_queuecommand(),
- * currently handles all requests.
- */
-int
-advansys_command(Scsi_Cmnd *scp)
-{
-    ASC_DBG1(1, "advansys_command: scp %lx\n", (ulong) scp);
-    ASC_STATS(scp->host, command);
-    scp->SCp.Status = 0; /* Set to a known state */
-    advansys_queuecommand(scp, advansys_command_done);
-    while (scp->SCp.Status == 0) {
-        continue;
-    }
-    ASC_DBG1(1, "advansys_command: result %x\n", scp->result);
-    return scp->result;
-}
-
-/*
  * advansys_queuecommand() - interrupt-driven I/O entrypoint.
  *
  * This function always returns 0. Command return status is saved
@@ -5938,7 +5885,7 @@
 {
     struct Scsi_Host    *shp;
     asc_board_t         *boardp;
-    int                 flags;
+    ulong               flags;
     Scsi_Cmnd           *done_scp;
 
     shp = scp->host;
@@ -5946,28 +5893,22 @@
     ASC_STATS(shp, queuecommand);
 
     /*
-     * Disable interrupts to preserve request ordering and provide
-     * mutually exclusive access to global structures used to initiate
-     * a request.
+     * XXX - Remove this comment and the next line when SCSI mid-level
+     * no longer acquires 'io_request_lock' before calling the SCSI
+     * low-level queuecommand entrypoint.
      */
-    save_flags(flags);
-    cli();
+    ASC_UNLOCK_IO_REQUEST_LOCK
+
+    spin_lock_irqsave(&boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
      */
-    if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
-        if (boardp->flags & ASC_HOST_IN_RESET) {
-            ASC_DBG1(1,
-                "advansys_queuecommand: scp %lx blocked for reset request\n",
-                (ulong) scp);
-            scp->result = HOST_BYTE(DID_RESET);
-        } else {
-            ASC_DBG1(1,
-                "advansys_queuecommand: scp %lx blocked for abort request\n",
-                (ulong) scp);
-            scp->result = HOST_BYTE(DID_ABORT);
-        }
+    if (boardp->flags & ASC_HOST_IN_RESET) {
+        ASC_DBG1(1,
+            "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
+            (ulong) scp);
+        scp->result = HOST_BYTE(DID_RESET);
 
         /*
          * Add blocked requests to the board's 'done' queue. The queued
@@ -5975,7 +5916,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
-        restore_flags(flags);
+        spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5992,13 +5933,15 @@
      * Save the function pointer to Linux mid-level 'done' function
      * and attempt to execute the command.
      *
-     * If ASC_ERROR is returned the request has been added to the
+     * If ASC_NOERROR is returned the request has been added to the
      * board's 'active' queue and will be completed by the interrupt
      * handler.
      *
      * If ASC_BUSY is returned add the request to the board's per
-     * target waiting list.
-     * 
+     * target waiting list. This is the first time the request has
+     * been tried. Add it to the back of the waiting list. It will be
+     * retried later.
+     *
      * If an error occurred, the request will have been placed on the
      * board's 'done' queue and must be completed before returning.
      */
@@ -6017,645 +5960,223 @@
         break;
     }
 
-    restore_flags(flags);
-    return 0;
-}
-
-/*
- * advansys_abort()
- *
- * Abort the command specified by 'scp'.
- */
-int
-advansys_abort(Scsi_Cmnd *scp)
-{
-    struct Scsi_Host    *shp;
-    asc_board_t         *boardp;
-    ASC_DVC_VAR         *asc_dvc_varp;
-    ADV_DVC_VAR         *adv_dvc_varp;
-    int                 flags;
-    int                 do_scsi_done;
-    int                 scp_found;
-    Scsi_Cmnd           *done_scp = NULL;
-    int                 ret;
-
-    /* Save current flags and disable interrupts. */
-    save_flags(flags);
-    cli();
-
-    ASC_DBG1(1, "advansys_abort: scp %lx\n", (ulong) scp);
-
-#ifdef ADVANSYS_STATS
-    if (scp->host != NULL) {
-        ASC_STATS(scp->host, abort);
-    }    
-#endif /* ADVANSYS_STATS */
-
-#ifdef ADVANSYS_ASSERT
-    do_scsi_done = ASC_ERROR;
-    scp_found = ASC_ERROR;
-    ret = ASC_ERROR;
-#endif /* ADVANSYS_ASSERT */
-
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-    if (scp->serial_number != scp->serial_number_at_timeout) {
-        ASC_PRINT1(
-"advansys_abort: timeout serial number changed for request %lx\n",
-            (ulong) scp);
-        do_scsi_done = ASC_FALSE;
-        scp_found = ASC_FALSE;
-        ret = SCSI_ABORT_NOT_RUNNING;
-    } else
-#endif /* version >= v1.3.89 */
-    if ((shp = scp->host) == NULL) {
-        scp->result = HOST_BYTE(DID_ERROR);
-        do_scsi_done = ASC_TRUE;
-        scp_found = ASC_FALSE;
-        ret = SCSI_ABORT_ERROR;
-    } else if ((boardp = ASC_BOARDP(shp))->flags & 
-                (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
-        ASC_PRINT2(
-"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n",
-            boardp->id, boardp->flags);
-        do_scsi_done = ASC_TRUE;
-        if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
-            (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
-            scp_found = ASC_TRUE;
-        } else {
-            scp_found = ASC_FALSE;
-        }
-        scp->result = HOST_BYTE(DID_ERROR);
-        ret = SCSI_ABORT_ERROR;
-    } else {
-        /* Set abort flag to avoid nested reset or abort requests. */
-        boardp->flags |= ASC_HOST_IN_ABORT;
-
-        do_scsi_done = ASC_TRUE;
-        if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
-            /*
-             * If asc_rmqueue() found the command on the waiting
-             * queue, it had not been sent to the device. After
-             * the queue is removed, no other handling is required.
-             */
-            ASC_DBG1(1, "advansys_abort: scp %lx found on waiting queue\n",
-                (ulong) scp);
-            scp_found = ASC_TRUE;
-            scp->result = HOST_BYTE(DID_ABORT);
-            ret = SCSI_ABORT_SUCCESS;
-        } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
-            /*
-             * If asc_isqueued() found the command on the active
-             * queue, it has been sent to the device. The command
-             * will be returned through the interrupt handler after
-             * it has been aborted.
-             */
-
-            if (ASC_NARROW_BOARD(boardp)) {
-                /*
-                 * Narrow Board
-                 */
-                asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-                scp->result = HOST_BYTE(DID_ABORT);
-
-                /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */
-                ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %lx\n",
-                    (ulong) scp);
-                /* XXX */
-                switch (AscAbortSRB(asc_dvc_varp, ASC_VADDR_TO_U32(scp))) {
-                case ASC_TRUE:
-                    /* asc_isr_callback() will be called */
-                    ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
-                    ret = SCSI_ABORT_PENDING;
-                    break;
-                case ASC_FALSE:
-                    /* Request has apparently already completed. */
-                    ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n");
-                    ret = SCSI_ABORT_NOT_RUNNING;
-                    break;
-                case ASC_ERROR:
-                default:
-                    ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n");
-                    ret = SCSI_ABORT_ERROR;
-                    break;
-                }
-                cli();
-            } else {
-                /*
-                 * Wide Board
-                 */
-                adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-                scp->result = HOST_BYTE(DID_ABORT);
-
-                ASC_DBG1(1,
-                    "advansys_abort: before AdvAbortQueue(), scp %lx\n",
-                    (ulong) scp);
-#if 0 /* XXX */
-                switch (AdvAbortQueue(adv_dvc_varp, (ADV_VADDR) XXX)) {
-                case ASC_TRUE:
-                    /* asc_isr_callback() will be called */
-                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n");
-                    ret = SCSI_ABORT_PENDING;
-                    break;
-                case ASC_FALSE:
-                    /* Request has apparently already completed. */
-                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n");
-                    ret = SCSI_ABORT_NOT_RUNNING;
-                    break;
-                case ASC_ERROR:
-                default:
-                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n");
-                    ret = SCSI_ABORT_ERROR;
-                    break;
-                }
-                /*
-                 * Ensure all requests completed by the microcode have
-                 * been processed by calling AdvISR().
-                 */
-                (void) AdvISR(adv_dvc_varp);
-#else /* XXX */
-                (void) AdvResetChipAndSB(adv_dvc_varp);
-                ret = SCSI_ABORT_SUCCESS;
-#endif /* XXX */
-            }
-
-            /*
-             * The request will either still be on the active queue
-             * or have been added to the board's done queue.
-             */
-            if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
-                scp->result = HOST_BYTE(DID_ABORT);
-                scp_found = ASC_TRUE;
-            } else {
-                scp_found = asc_rmqueue(&boardp->done, scp);
-                ASC_ASSERT(scp_found == ASC_TRUE);
-            }
-        } else {
-            /*
-             * The command was not found on the active or waiting queues.
-             */
-            do_scsi_done = ASC_TRUE;
-            scp_found = ASC_FALSE;
-            ret = SCSI_ABORT_NOT_RUNNING;
-        }
-
-        /* Clear abort flag. */
-        boardp->flags &= ~ASC_HOST_IN_ABORT;
-
-        /*
-         * Because the ASC_HOST_IN_ABORT flag causes both
-         * 'advansys_interrupt' and 'asc_isr_callback' to
-         * queue requests to the board's 'done' queue and
-         * prevents waiting commands from being executed,
-         * these queued requests must be handled here.
-         */
-        done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
-
-        /*
-         * Start any waiting commands for the board.
-         */
-        if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-            ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
-            asc_execute_queue(&boardp->waiting);
-        }
-    }
-
-    /* Interrupts could be enabled here. */
-
-    /*
-     * Complete the request to be aborted, unless it has been
-     * restarted as detected above, even if it was not found on
-     * the device active or waiting queues.
-     */
-    ASC_ASSERT(do_scsi_done != ASC_ERROR);
-    ASC_ASSERT(scp_found != ASC_ERROR);
-    if (do_scsi_done == ASC_TRUE) {
-        if (scp->scsi_done == NULL) {
-            ASC_PRINT1(
-"advansys_abort: aborted request scsi_done() is NULL, %lx\n",
-                (ulong) scp);
-        } else {
-            if (scp_found == ASC_FALSE) {
-                ASC_PRINT1(
-"advansys_abort: abort request not active or waiting, completing anyway %lx\n",
-                    (ulong) scp);
-            }
-            ASC_STATS(scp->host, done);
-            scp->scsi_done(scp);
-        }
-    }
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
-     * It is possible for the request done function to re-enable
-     * interrupts without confusing the driver. But here interrupts
-     * aren't enabled until all requests have been completed.
+     * XXX - Remove this comment and the next line when SCSI mid-level
+     * no longer acquires 'io_request_lock' before calling the SCSI
+     * low-level queuecommand entrypoint.
      */
-    if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp);
-    }
-
-    ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
-
-    /* Re-enable interrupts, if they were enabled on entry. */
-    restore_flags(flags);
+    ASC_LOCK_IO_REQUEST_LOCK
 
-    ASC_ASSERT(ret != ASC_ERROR);
-    return ret;
+    return 0;
 }
 
 /*
  * advansys_reset()
  *
- * Reset the device associated with the command 'scp'.
+ * Reset the bus associated with the command 'scp'.
+ *
+ * This function runs its own thread. Interrupts must be blocked but
+ * sleeping is allowed and no locking other than for host structures is
+ * required. Returns SUCCESS or FAILED.
  */
 int
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
 advansys_reset(Scsi_Cmnd *scp)
-#else /* version >= v1.3.89 */
-advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
-#endif /* version >= v1.3.89 */
 {
     struct Scsi_Host     *shp;
     asc_board_t          *boardp;
     ASC_DVC_VAR          *asc_dvc_varp;
     ADV_DVC_VAR          *adv_dvc_varp;
-    int                  flags;
+    ulong                flags;
     Scsi_Cmnd            *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd            *tscp, *new_last_scp;
-    int                  do_scsi_done;
-    int                  scp_found;
     int                  status;
-    int                  target;
-    int                  ret;
-    int                  device_reset = ASC_FALSE;
-
-    /* Save current flags and disable interrupts. */
-    save_flags(flags);
-    cli();
+    int                  ret = SUCCESS;
 
-    ASC_DBG1(1, "advansys_reset: %lx\n", (ulong) scp);
+    ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong) scp);
 
 #ifdef ADVANSYS_STATS
     if (scp->host != NULL) {
         ASC_STATS(scp->host, reset);
-    }    
+    }
 #endif /* ADVANSYS_STATS */
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-    if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) &&
-        (scp->serial_number != scp->serial_number_at_timeout)) {
-        ASC_PRINT1(
-"advansys_reset: timeout serial number changed for request %lx\n",
-            (ulong) scp);
-        do_scsi_done = ASC_FALSE;
-        scp_found = ASC_FALSE;
-        ret = SCSI_RESET_NOT_RUNNING;
-    } else
-#endif /* version >= v1.3.89 */
     if ((shp = scp->host) == NULL) {
         scp->result = HOST_BYTE(DID_ERROR);
-        do_scsi_done = ASC_TRUE;
-        scp_found = ASC_FALSE;
-        ret = SCSI_RESET_ERROR;
-    } else if ((boardp = ASC_BOARDP(shp))->flags & 
-                (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
-        ASC_PRINT2(
-"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n",
-            boardp->id, boardp->flags);
-        do_scsi_done = ASC_TRUE;
-        if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
-            (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
-            scp_found = ASC_TRUE;
-        } else {
-            scp_found = ASC_FALSE;
-        }
-        scp->result = HOST_BYTE(DID_ERROR);
-        ret = SCSI_RESET_ERROR;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
-    } else if (time_after_eq(jiffies, boardp->last_reset) &&
-               time_before(jiffies, boardp->last_reset + (10 * HZ))) {
-#else /* version < v2.1.0 */
-    } else if (jiffies >= boardp->last_reset &&
-               jiffies < (boardp->last_reset + (10 * HZ))) {
-#endif /* version < v2.1.0 */
-        /*
-         * Don't allow a reset to be attempted within 10 seconds
-         * of the last reset.
-         *
-         * If 'jiffies' wrapping occurs, the reset request will go
-         * through, because a wrapped 'jiffies' would not pass the
-         * test above.
-         */
-        ASC_DBG(1,
-            "advansys_reset: reset within 10 sec of last reset ignored\n");
-        do_scsi_done = ASC_TRUE;
-        if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
-            (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
-            scp_found = ASC_TRUE;
-        } else {
-            scp_found = ASC_FALSE;
-        }
-        scp->result = HOST_BYTE(DID_ERROR);
-        ret = SCSI_RESET_ERROR;
-    } else {
-        do_scsi_done = ASC_TRUE;
-
-        /* Set reset flag to avoid nested reset or abort requests. */
-        boardp->flags |= ASC_HOST_IN_RESET;
+        return FAILED;
+    }
 
-        /*
-          * If the request is on the target waiting or active queue
-         * or the board done queue, then remove it and note that it
-         * was found.
-         */
-        if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
-            ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
-            scp_found = ASC_TRUE;
-        } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
-            ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
-            scp_found = ASC_TRUE;
-        } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) {
-            scp_found = ASC_TRUE;
-        } else {
-            scp_found = ASC_FALSE;
-        }
+    boardp = ASC_BOARDP(shp);
 
+    ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
+        boardp->id);
+    /*
+     * Check for re-entrancy.
+     */
+    spin_lock_irqsave(&boardp->lock, flags);
+    if (boardp->flags & ASC_HOST_IN_RESET) {
+        spin_unlock_irqrestore(&boardp->lock, flags);
+        return FAILED;
+    }
+    boardp->flags |= ASC_HOST_IN_RESET;
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
-        if (ASC_NARROW_BOARD(boardp)) {
-            /*
-             * Narrow Board
-             *
-             * If the suggest reset bus flags are set, then reset the bus.
-             * Otherwise only reset the device.
-             */
-            asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-            if (reset_flags &
-                (SCSI_RESET_SUGGEST_BUS_RESET |
-                 SCSI_RESET_SUGGEST_HOST_RESET)) {
-#endif /* version >= v1.3.89 */
+    /*
+     * XXX - Remove this comment and the next line when SCSI mid-level
+     * no longer acquires 'io_request_lock' before calling the SCSI
+     * low-level reset entrypoint.
+     */
+    ASC_UNLOCK_IO_REQUEST_LOCK
 
-                /*
-                 * Reset the target's SCSI bus.
-                 */
-                ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
-                /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
-                status = AscResetSB(asc_dvc_varp);
-                /* cli(); XXX */
-                switch (status) {
-                case ASC_TRUE:
-                    ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
-                    ret = SCSI_RESET_SUCCESS;
-                    break;
-                case ASC_ERROR:
-                default:
-                    ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
-                    ret = SCSI_RESET_ERROR;
-                    break;
-                }
+    if (ASC_NARROW_BOARD(boardp)) {
+        /*
+         * Narrow Board
+         */
+        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-            } else {
-                /*
-                 * Reset the specified device. If the device reset fails,
-                 * then reset the SCSI bus.
-                 */
+        /*
+         * Reset the chip and SCSI bus.
+         */
+        ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
+        status = AscInitAsc1000Driver(asc_dvc_varp);
 
-                ASC_DBG1(1,
-                    "advansys_reset: before AscResetDevice(), target %d\n",
-                    scp->target);
-                /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */
-                status = AscResetDevice(asc_dvc_varp, scp->target);
-                /* cli(); XXX */
-
-                switch (status) {
-                case ASC_TRUE:
-                    ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
-                    device_reset = ASC_TRUE;
-                    ret = SCSI_RESET_SUCCESS;
-                    break;
-                case ASC_ERROR:
-                default:
-                    ASC_DBG(1,
-"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
-                    /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
-                    status = AscResetSB(asc_dvc_varp);
-                    /* cli(); XXX */
-                    switch (status) {
-                    case ASC_TRUE:
-                        ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
-                        ret = SCSI_RESET_SUCCESS;
-                        break;
-                    case ASC_ERROR:
-                    default:
-                        ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
-                        ret = SCSI_RESET_ERROR;
-                        break;
-                    }
-                    break;
-                }
-            }
-#endif /* version >= v1.3.89 */
+        /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+        if (asc_dvc_varp->err_code) {
+            ASC_PRINT2(
+                "advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
+                boardp->id, asc_dvc_varp->err_code);
+            ret = FAILED;
+        } else if (status) {
+            ASC_PRINT2(
+                "advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
+                boardp->id, status);
         } else {
-            /*
-             * Wide Board
-             *
-             * If the suggest reset bus flags are set, then reset the bus.
-             * Otherwise only reset the device.
-             */
-            adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-            if (reset_flags &
-                (SCSI_RESET_SUGGEST_BUS_RESET |
-                 SCSI_RESET_SUGGEST_HOST_RESET)) {
-#endif /* version >= v1.3.89 */
-
-                /*
-                 * Reset the target's SCSI bus.
-                 */
-                ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
-                switch (AdvResetChipAndSB(adv_dvc_varp)) {
-                case ASC_TRUE:
-                    ASC_DBG(1,
-                        "advansys_reset: AdvResetChipAndSB() success\n");
-                    ret = SCSI_RESET_SUCCESS;
-                    break;
-                case ASC_FALSE:
-                default:
-                    ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n");
-                    ret = SCSI_RESET_ERROR;
-                    break;
-                }
-                /*
-                 * Ensure all requests completed by the microcode have
-                 * been processed by calling AdvISR().
-                 */
-                (void) AdvISR(adv_dvc_varp);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-            } else {
-                /*
-                 * Reset the specified device. If the device reset fails,
-                 * then reset the SCSI bus.
-                 */
-
-                ASC_DBG1(1,
-                    "advansys_reset: before AdvResetDevice(), target %d\n",
-                    scp->target);
-                
-                switch (AdvResetDevice(adv_dvc_varp, scp->target)) {
-                case ASC_TRUE:
-                    ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n");
-                    device_reset = ASC_TRUE;
-                    ret = SCSI_RESET_SUCCESS;
-                    break;
-                case ASC_FALSE:
-                default:
-                    ASC_DBG(1,
-"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n");
-                    
-                    switch (AdvResetChipAndSB(adv_dvc_varp)) {
-                    case ASC_TRUE:
-                        ASC_DBG(1,
-                            "advansys_reset: AdvResetChipAndSB() TRUE\n");
-                        ret = SCSI_RESET_SUCCESS;
-                        break;
-                    case ASC_FALSE:
-                    default:
-                        ASC_DBG(1,
-                            "advansys_reset: AdvResetChipAndSB() ERROR\n");
-                        ret = SCSI_RESET_ERROR;
-                        break;
-                    }
-                    break;
-                }
-                /*
-                 * Ensure all requests completed by the microcode have
-                 * been processed by calling AdvISR().
-                 */
-                (void) AdvISR(adv_dvc_varp);
-            }
-#endif /* version >= v1.3.89 */
+            ASC_PRINT1(
+                "advansys_reset: board %d: SCSI bus reset successful.\n",
+                boardp->id);
         }
 
+        ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
+
         /*
-         * Because the ASC_HOST_IN_RESET flag causes both
-         * 'advansys_interrupt' and 'asc_isr_callback' to
-         * queue requests to the board's 'done' queue and
-         * prevents waiting commands from being executed,
-         * these queued requests must be handled here.
+         * Acquire the board lock.
          */
-        done_scp = asc_dequeue_list(&boardp->done, &last_scp,
-                                    ASC_TID_ALL);
+        spin_lock_irqsave(&boardp->lock, flags);
 
+    } else {
         /*
-         * If a device reset was performed dequeue all waiting
-         * and active requests for the device and set the request
-         * status to DID_RESET.
+         * Wide Board
          *
-         * If a SCSI bus reset was performed dequeue all waiting
-         * and active requests for all devices and set the request
-         * status to DID_RESET.
+         * If the suggest reset bus flags are set, then reset the bus.
+         * Otherwise only reset the device.
          */
-        if (device_reset == ASC_TRUE) {
-            target = scp->target;
-        } else {
-            target = ASC_TID_ALL;
-        }
+        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
 
         /*
-         * Add active requests to 'done_scp' and set the request status
-         * to DID_RESET.
+         * Reset the target's SCSI bus.
          */
-        if (done_scp == NULL) {
-            done_scp = asc_dequeue_list(&boardp->active, &last_scp, target);
-            for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-                tscp->result = HOST_BYTE(DID_RESET);
-            }
-        } else {
-            ASC_ASSERT(last_scp != NULL);
-            REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
-                &new_last_scp, target);
-            if (new_last_scp != NULL) {
-                ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-                for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
-                    tscp->result = HOST_BYTE(DID_RESET);
-                }
-                last_scp = new_last_scp;
-            }
+        ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+        switch (AdvResetChipAndSB(adv_dvc_varp)) {
+        case ASC_TRUE:
+            ASC_PRINT1("advansys_reset: board %d: SCSI bus reset successful.\n",
+                boardp->id);
+            break;
+        case ASC_FALSE:
+        default:
+            ASC_PRINT1("advansys_reset: board %d: SCSI bus reset error.\n",
+                boardp->id);
+            ret = FAILED;
+            break;
         }
-
         /*
-         * Add waiting requests to 'done_scp' and set the request status
-         * to DID_RESET.
+         * Acquire the board lock and ensure all requests completed by the
+         * microcode have been processed by calling AdvISR().
          */
-        if (done_scp == NULL) {
-            done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target);
-            for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-                tscp->result = HOST_BYTE(DID_RESET);
-            }
-        } else {
-            ASC_ASSERT(last_scp != NULL);
-            REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
-                &new_last_scp, target);
-            if (new_last_scp != NULL) {
-                ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-                for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
-                    tscp->result = HOST_BYTE(DID_RESET);
-                }
-                last_scp = new_last_scp;
-            }
-        }
+        spin_lock_irqsave(&boardp->lock, flags);
+        (void) AdvISR(adv_dvc_varp);
+    }
 
-        /* Save the time of the most recently completed reset. */
-        boardp->last_reset = jiffies;
+    /* Board lock is held. */
 
-        /* Clear reset flag. */
-        boardp->flags &= ~ASC_HOST_IN_RESET;
+    /*
+     * Dequeue all board 'done' requests. A pointer to the last request
+     * is returned in 'last_scp'.
+     */
+    done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
 
-        /*
-         * Start any waiting commands for the board.
-         */
-        if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-            ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
-            asc_execute_queue(&boardp->waiting);
+    /*
+     * Dequeue all board 'active' requests for all devices and set
+     * the request status to DID_RESET. A pointer to the last request
+     * is returned in 'last_scp'.
+     */
+    if (done_scp == NULL) {
+        done_scp = asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
+        for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+            tscp->result = HOST_BYTE(DID_RESET);
+        }
+    } else {
+        /* Append to 'done_scp' at the end with 'last_scp'. */
+        ASC_ASSERT(last_scp != NULL);
+        REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
+            &new_last_scp, ASC_TID_ALL);
+        if (new_last_scp != NULL) {
+            ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+            for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                tscp->result = HOST_BYTE(DID_RESET);
+            }
+            last_scp = new_last_scp;
         }
-        ret = SCSI_RESET_SUCCESS;
     }
 
-    /* Interrupts could be enabled here. */
-
-    ASC_ASSERT(do_scsi_done != ASC_ERROR);
-    ASC_ASSERT(scp_found != ASC_ERROR);
-    if (do_scsi_done == ASC_TRUE) {
-        if (scp->scsi_done == NULL) {
-            ASC_PRINT1(
-"advansys_reset: reset request scsi_done() is NULL, %lx\n",
-                (ulong) scp);
-        } else {
-            if (scp_found == ASC_FALSE) {
-                ASC_PRINT1(
-"advansys_reset: reset request not active or waiting, completing anyway %lx\n",
-                    (ulong) scp);
+    /*
+     * Dequeue all 'waiting' requests and set the request status
+     * to DID_RESET.
+     */
+    if (done_scp == NULL) {
+        done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
+        for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+            tscp->result = HOST_BYTE(DID_RESET);
+        }
+    } else {
+        /* Append to 'done_scp' at the end with 'last_scp'. */
+        ASC_ASSERT(last_scp != NULL);
+        REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
+            &new_last_scp, ASC_TID_ALL);
+        if (new_last_scp != NULL) {
+            ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+            for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                tscp->result = HOST_BYTE(DID_RESET);
             }
-            ASC_STATS(scp->host, done);
-            scp->scsi_done(scp);
+            last_scp = new_last_scp;
         }
     }
 
+    /* Save the time of the most recently completed reset. */
+    boardp->last_reset = jiffies;
+
+    /* Clear reset flag. */
+    boardp->flags &= ~ASC_HOST_IN_RESET;
+
+    /* Release the board. */
+    spin_unlock_irqrestore(&boardp->lock, flags);
+
     /*
-     * It is possible for the request done function to re-enable
-     * interrupts without confusing the driver. But here interrupts
-     * aren't enabled until requests have been completed.
+     * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
         asc_scsi_done_list(done_scp);
     }
 
-    ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+    /*
+     * XXX - Remove this comment and the next line when SCSI mid-level
+     * no longer acquires 'io_request_lock' before calling the SCSI
+     * low-level reset entrypoint.
+     */
+    ASC_LOCK_IO_REQUEST_LOCK
 
-    /* Re-enable interrupts, if they were enabled on entry. */
-    restore_flags(flags);
+    ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
 
-    ASC_ASSERT(ret != ASC_ERROR);
     return ret;
 }
 
@@ -6671,11 +6192,7 @@
  * ip[2]: cylinders
  */
 int
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-advansys_biosparam(Disk *dp, int dep, int ip[])
-#else /* version >= v1.3.0 */
 advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
-#endif /* version >= v1.3.0 */
 {
     asc_board_t     *boardp;
 
@@ -6771,14 +6288,14 @@
 #ifdef ADVANSYS_DEBUG
     ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
     for (i = 1; i < ints[0]; i++) {
-        ASC_DBG2(1, " ints[%d] %x", i, ints[i]);
+        ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]);
     }
     ASC_DBG(1, "\n");
 #endif /* ADVANSYS_DEBUG */
 
     for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
         asc_ioport[i-1] = ints[i];
-        ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n",
+        ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%x\n",
             i - 1, asc_ioport[i-1]);
     }
 }
@@ -6788,8 +6305,13 @@
  * --- Loadable Driver Support
  */
 
-static Scsi_Host_Template driver_template = ADVANSYS;
+#if ASC_LINUX_KERNEL24
+static
+#endif
+#if ASC_LINUX_KERNEL24 || (ASC_LINUX_KERNEL22 && defined(MODULE))
+Scsi_Host_Template driver_template = ADVANSYS;
 # include "scsi_module.c"
+#endif
 
 
 /*
@@ -6799,42 +6321,22 @@
 /*
  * First-level interrupt handler.
  *
- * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting
- * adapter's asc_board_t. Because all boards are currently checked
- * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id'
- * could be used to identify an interrupt passed to the AdvanSys driver,
- * which is for a device sharing an interrupt with an AdvanSys adapter.
+ * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
+ * all boards are currently checked for interrupts on each interrupt, 'dev_id'
+ * is not referenced. 'dev_id' could be used to identify an interrupt passed
+ * to the AdvanSys driver which is for a device sharing an interrupt with
+ * an AdvanSys adapter.
  */
 STATIC void
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
-advansys_interrupt(int irq, struct pt_regs *regs)
-#else /* version >= v1.3.70 */
 advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-#endif /* version >= v1.3.70 */
 {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
-    int             flags;
-#else /* version >= v2.1.95 */
-    unsigned long   flags;
-#endif /* version >= v2.1.95 */
+    ulong           flags;
     int             i;
     asc_board_t     *boardp;
     Scsi_Cmnd       *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd       *new_last_scp;
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
-    /* Disable interrupts, if they aren't already disabled. */
-    save_flags(flags);
-    cli();
-#else /* version >= v2.1.95 */
-    /*
-     * Disable interrupts, if they aren't already disabled and acquire
-     * the I/O spinlock.
-     */
-    spin_lock_irqsave(&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
-
-    ASC_DBG(1, "advansys_interrupt: begin\n");
+
+    ASC_DBG(1, "advansys_interrupt: begin\n");
 
     /*
      * Check for interrupts on all boards.
@@ -6842,8 +6344,9 @@
      */
     for (i = 0; i < asc_board_count; i++) {
         boardp = ASC_BOARDP(asc_host[i]);
-        ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n",
-            i, (ulong) boardp)            
+        ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
+            i, (ulong) boardp);
+        spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
@@ -6865,13 +6368,12 @@
 
         /*
          * Start waiting requests and create a list of completed requests.
-         * 
-         * If a reset or abort request is being performed for the board,
-         * the reset or abort handler will complete pending requests after
-         * it has completed.
+         *
+         * If a reset request is being performed for the board, the reset
+         * handler will complete pending requests after it has completed.
          */
-        if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
-            ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n",
+        if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
+            ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
                 (ulong) done_scp, (ulong) last_scp);
 
             /* Start any waiting commands for the board. */
@@ -6900,38 +6402,21 @@
                 }
             }
         }
+        spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
-    /* Interrupts could be enabled here. */
-
     /*
-     * It is possible for the request done function to re-enable
-     * interrupts without confusing the driver. But here the
-     * original flags aren't restored until all requests have been
-     * completed.
+     * If interrupts were enabled on entry, then they
+     * are now enabled here.
+     *
+     * Complete all requests on the done list.
      */
     asc_scsi_done_list(done_scp);
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
-    /*
-     * Restore the original flags which will enable interrupts
-     * if and only if they were enabled on entry.
-     */
-    restore_flags(flags);
-#else /* version >= v2.1.95 */
-    /*
-     * Release the I/O spinlock and restore the original flags
-     * which will enable interrupts if and only if they were
-     * enabled on entry.
-     */
-    spin_unlock_irqrestore(&io_request_lock, flags);
-#endif /* version >= v2.1.95 */
-
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
 }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 /*
  * Set the number of commands to queue per device for the
  * specified host adapter.
@@ -6960,22 +6445,11 @@
             device->queue_depth =
                 boardp->dvc_var.adv_dvc_var.max_dvc_qng;
         }
-        ASC_DBG3(1, "advansys_select_queue_depths: shp %lx, id %d, depth %d\n",
+        ASC_DBG3(1,
+            "advansys_select_queue_depths: shp 0x%lx, id %d, depth %d\n",
             (ulong) shp, device->id, device->queue_depth);
     }
 }
-#endif /* version >= v1.3.89 */
-
-/*
- * Function used only with polled I/O requests that are initiated by
- * advansys_command().
- */
-STATIC void
-advansys_command_done(Scsi_Cmnd *scp)
-{
-    ASC_DBG1(1, "advansys_command_done: scp %lx\n", (ulong) scp);
-    scp->SCp.Status = 1;
-}
 
 /*
  * Complete all requests on the singly linked list pointed
@@ -6990,7 +6464,7 @@
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
-        ASC_DBG1(3, "asc_scsi_done_list: scp %lx\n", (ulong) scp);
+        ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp);
         tscp = REQPNEXT(scp);
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
@@ -7038,12 +6512,15 @@
  *    scsi_done - used to save caller's done function
  *    host_scribble - used for pointer to another Scsi_Cmnd
  *
- * If this function returns ASC_NOERROR or ASC_ERROR the request
- * has been enqueued on the board's 'done' queue and must be
- * completed by the caller.
+ * If this function returns ASC_NOERROR the request has been enqueued
+ * on the board's 'active' queue and will be completed from the
+ * interrupt handler.
+ *
+ * If this function returns ASC_NOERROR the request has been enqueued
+ * on the board's 'done' queue and must be completed by the caller.
  *
- * If ASC_BUSY is returned the request must be enqueued by the
- * caller and re-tried later.
+ * If ASC_BUSY is returned the request will be enqueued by the
+ * caller on the target's waiting queue and re-tried later.
  */
 STATIC int
 asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
@@ -7055,8 +6532,7 @@
     Scsi_Device        *device;
     int                ret;
 
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
-    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n",
+    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
         (ulong) scp, (ulong) scp->scsi_done);
 
     boardp = ASC_BOARDP(scp->host);
@@ -7073,6 +6549,10 @@
          * Build Asc Library request structure using the
          * global structures 'asc_scsi_req' and 'asc_sg_head'.
          *
+         * If an error is returned, then the request has been
+         * queued on the board done queue. It will be completed
+         * by the caller.
+         *
          * asc_build_req() can not return ASC_BUSY.
          */
         if (asc_build_req(boardp, scp) == ASC_ERROR) {
@@ -7092,18 +6572,20 @@
              * request counter. Wrapping doesn't matter.
              */
             boardp->reqcnt[scp->target]++;
-
             asc_enqueue(&boardp->active, scp, ASC_BACK);
             ASC_DBG(1,
                 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
             break;
         case ASC_BUSY:
-            /* Caller must enqueue request and retry later. */
+            /*
+             * Caller will enqueue request on the target's waiting queue
+             * and retry later.
+             */
             ASC_STATS(scp->host, exe_busy);
             break;
         case ASC_ERROR:
             ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
                 boardp->id, asc_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_error);
             scp->result = HOST_BYTE(DID_ERROR);
@@ -7111,7 +6593,7 @@
             break;
         default:
             ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
                 boardp->id, asc_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_unknown);
             scp->result = HOST_BYTE(DID_ERROR);
@@ -7127,7 +6609,7 @@
         /*
          * Build and get a pointer to an Adv Library request structure.
          *
-         * If the request is successfully built then send  it below,
+         * If the request is successfully built then send it below,
          * otherwise return with an error.
          */
         switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
@@ -7136,14 +6618,28 @@
             break;
         case ASC_BUSY:
             ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
+            /*
+             * If busy is returned the request has not been enqueued.
+             * It will be enqueued by the caller on the target's waiting
+             * queue and retried later.
+             *
+             * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
+             * count wide board busy conditions. They are updated in
+             * adv_build_req and adv_get_sglist, respectively.
+             */
             return ASC_BUSY;
         case ASC_ERROR:
+             /* 
+              * If an error is returned, then the request has been
+              * queued on the board done queue. It will be completed
+              * by the caller.
+              */
         default:
             ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
             ASC_STATS(scp->host, build_error);
             return ASC_ERROR;
         }
-    
+
         /*
          * Execute the command. If there is no error, add the command
          * to the active queue.
@@ -7161,12 +6657,15 @@
                 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
             break;
         case ASC_BUSY:
-            /* Caller must enqueue request and retry later. */
+            /*
+             * Caller will enqueue request on the target's waiting queue
+             * and retry later.
+             */
             ASC_STATS(scp->host, exe_busy);
             break;
         case ASC_ERROR:
             ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
                 boardp->id, adv_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_error);
             scp->result = HOST_BYTE(DID_ERROR);
@@ -7174,7 +6673,7 @@
             break;
         default:
             ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
                 boardp->id, adv_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_unknown);
             scp->result = HOST_BYTE(DID_ERROR);
@@ -7184,7 +6683,6 @@
     }
 
     ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
     return ret;
 }
 
@@ -7194,7 +6692,8 @@
  * The global structures 'asc_scsi_q' and 'asc_sg_head' are
  * used to build the request.
  *
- * If an error occurs, then return ASC_ERROR.
+ * If an error occurs, then queue the request on the board done
+ * queue and return ASC_ERROR.
  */
 STATIC int
 asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
@@ -7212,21 +6711,24 @@
 
     /*
      * Build the ASC_SCSI_Q request.
+     *
+     * For narrow boards a CDB length maximum of 12 bytes
+     * is supported.
      */
-    ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN);
     if (scp->cmd_len > ASC_MAX_CDB_LEN) {
-        scp->cmd_len = ASC_MAX_CDB_LEN;
+        ASC_PRINT3(
+"asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN  %d\n",
+            boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
+        scp->result = HOST_BYTE(DID_ERROR);
+        asc_enqueue(&boardp->done, scp, ASC_BACK);
+        return ASC_ERROR;
     }
     asc_scsi_q.cdbptr = &scp->cmnd[0];
     asc_scsi_q.q2.cdb_len = scp->cmd_len;
     asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
     asc_scsi_q.q1.target_lun = scp->lun;
     asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    asc_scsi_q.q1.sense_addr = (ADV_PADDR) &scp->sense_buffer[0];
-#else /* version >= v2.0.0 */
     asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-#endif /* version >= v2.0.0 */
     asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
 
     /*
@@ -7238,7 +6740,7 @@
      *
      * The request count is incremented below for every successfully
      * started request.
-     * 
+     *
      */
     if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) &&
         (boardp->reqcnt[scp->target] % 255) == 0) {
@@ -7256,13 +6758,9 @@
          * CDB request of single contiguous buffer.
          */
         ASC_STATS(scp->host, cont_cnt);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-        asc_scsi_q.q1.data_addr = (ADV_PADDR) scp->request_buffer;
-#else /* version >= v2.0.0 */
         asc_scsi_q.q1.data_addr =
             cpu_to_le32(virt_to_bus(scp->request_buffer));
-#endif /* version >= v2.0.0 */
-        asc_scsi_q.q1.data_cnt = scp->request_bufflen;
+        asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
         ASC_STATS_ADD(scp->host, cont_xfer,
                       ASC_CEILING(scp->request_bufflen, 512));
         asc_scsi_q.q1.sg_queue_cnt = 0;
@@ -7295,6 +6793,7 @@
         asc_scsi_q.sg_head = &asc_sg_head;
         asc_scsi_q.q1.data_cnt = 0;
         asc_scsi_q.q1.data_addr = 0;
+        /* This is a byte value, otherwise it would need to be swapped. */
         asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
         ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
 
@@ -7303,12 +6802,8 @@
          */
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-            asc_sg_head.sg_list[sgcnt].addr = (ADV_PADDR) slp->address;
-#else /* version >= v2.0.0 */
             asc_sg_head.sg_list[sgcnt].addr =
                 cpu_to_le32(virt_to_bus(slp->address));
-#endif /* version >= v2.0.0 */
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -7354,9 +6849,9 @@
     }
 
     /*
-     * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+     * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
      */
-    scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q);
+    scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
 
     /*
      * Initialize the structure.
@@ -7379,24 +6874,31 @@
 
     /*
      * Set CDB length and copy it to the request structure.
+     * For wide  boards a CDB length maximum of 16 bytes
+     * is supported.
      */
-    ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN);
-    if (scp->cmd_len > ASC_MAX_CDB_LEN) {
-        scp->cmd_len = ASC_MAX_CDB_LEN;
+    if (scp->cmd_len > ADV_MAX_CDB_LEN) {
+        ASC_PRINT3(
+"adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN  %d\n",
+            boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
+        scp->result = HOST_BYTE(DID_ERROR);
+        asc_enqueue(&boardp->done, scp, ASC_BACK);
+        return ASC_ERROR;
     }
     scsiqp->cdb_len = scp->cmd_len;
-    for (i = 0; i < scp->cmd_len; i++) {
+    /* Copy first 12 CDB bytes to cdb[]. */
+    for (i = 0; i < scp->cmd_len && i < 12; i++) {
         scsiqp->cdb[i] = scp->cmnd[i];
     }
+    /* Copy last 4 CDB bytes, if present, to cdb16[]. */
+    for (; i < scp->cmd_len; i++) {
+        scsiqp->cdb16[i - 12] = scp->cmnd[i];
+    }
 
     scsiqp->target_id = scp->target;
     scsiqp->target_lun = scp->lun;
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    scsiqp->sense_addr = (ADV_PADDR) &scp->sense_buffer[0];
-#else /* version >= v2.0.0 */
     scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-#endif /* version >= v2.0.0 */
     scsiqp->sense_len = sizeof(scp->sense_buffer);
 
     /*
@@ -7405,11 +6907,7 @@
      */
     scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
     scsiqp->vdata_addr = scp->request_buffer;
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    scsiqp->data_addr = (ADV_PADDR) scp->request_buffer;
-#else /* version >= v2.0.0 */
     scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
-#endif /* version >= v2.0.0 */
 
     if (scp->use_sg == 0) {
         /*
@@ -7488,7 +6986,7 @@
     ADV_PADDR           sg_block_paddr;
     int                 i;
 
-    scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q);
+    scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
     slp = (struct scatterlist *) scp->request_buffer;
     sg_elem_cnt = scp->use_sg;
     prev_sg_block = NULL;
@@ -7525,16 +7023,11 @@
             sgblkp->next_sgblkp = NULL;
 
             /*
-             * Get 4 byte aligned virtual and physical addresses for
+             * Get 8 byte aligned virtual and physical addresses for
              * the allocated ADV_SG_BLOCK structure.
              */
-            sg_block = (ADV_SG_BLOCK *) ADV_DWALIGN(&sgblkp->sg_block);
-            sg_block_paddr =
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-                (ADV_PADDR) sg_block;
-#else /* version >= v2.0.0 */
-                virt_to_bus(sg_block);
-#endif /* version >= v2.0.0 */
+            sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block);
+            sg_block_paddr = virt_to_bus(sg_block);
 
             /*
              * Check if this is the first 'adv_sgblk_t' for the request.
@@ -7568,11 +7061,7 @@
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-                (ADV_PADDR) slp->address;
-#else /* version >= v2.0.0 */
                 cpu_to_le32(virt_to_bus(slp->address));
-#endif /* version >= v2.0.0 */
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
@@ -7604,8 +7093,7 @@
     struct Scsi_Host    *shp;
     int                 i;
 
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
-    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n",
+    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
         (ulong) asc_dvc_varp, (ulong) qdonep);
     ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
 
@@ -7614,7 +7102,7 @@
      * command that has been completed.
      */
     scp = (Scsi_Cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
-    ASC_DBG1(1, "asc_isr_callback: scp %lx\n", (ulong) scp);
+    ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong) scp);
 
     if (scp == NULL) {
         ASC_PRINT("asc_isr_callback: scp is NULL\n");
@@ -7634,24 +7122,24 @@
     }
     if (i == asc_board_count) {
         ASC_PRINT2(
-            "asc_isr_callback: scp %lx has bad host pointer, host %lx\n",
+            "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
             (ulong) scp, (ulong) shp);
         return;
     }
 
     ASC_STATS(shp, callback);
-    ASC_DBG1(1, "asc_isr_callback: shp %lx\n", (ulong) shp);
+    ASC_DBG1(1, "asc_isr_callback: shp 0x%lx\n", (ulong) shp);
 
     /*
      * If the request isn't found on the active queue, it may
-     * have been removed to handle a reset or abort request.
+     * have been removed to handle a reset request.
      * Display a message and return.
      */
     boardp = ASC_BOARDP(shp);
     ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
     if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
         ASC_PRINT2(
-            "asc_isr_callback: board %d: scp %lx not on active queue\n",
+            "asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
             boardp->id, (ulong) scp);
         return;
     }
@@ -7675,20 +7163,20 @@
                 (ASC_SCSI_INQUIRY *) scp->request_buffer);
         }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19)
+#if ASC_LINUX_KERNEL24
         /*
          * Check for an underrun condition.
          *
          * If there was no error and an underrun condition, then
          * then return the number of underrun bytes.
          */
-        if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && 
+        if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
             qdonep->remain_bytes <= scp->request_bufflen != 0) {
             ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
             (unsigned) qdonep->remain_bytes);
             scp->resid = qdonep->remain_bytes;
         }
-#endif /* version >= v2.3.19 */
+#endif
         break;
 
     case QD_WITH_ERROR:
@@ -7710,15 +7198,15 @@
                  * byte as it is defined by SCSI.
                  */
                 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
-                    STATUS_BYTE(qdonep->d3.scsi_stat); 
+                    STATUS_BYTE(qdonep->d3.scsi_stat);
             } else {
-                scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); 
+                scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
             }
             break;
 
         default:
             /* QHSTA error occurred */
-            ASC_DBG1(1, "asc_isr_callback: host_stat %x\n",
+            ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
                 qdonep->d3.host_stat);
             scp->result = HOST_BYTE(DID_BAD_TARGET);
             break;
@@ -7732,7 +7220,7 @@
         break;
 
     default:
-        ASC_DBG1(1, "asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat);
+        ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", qdonep->d3.done_stat);
         scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
                 STATUS_BYTE(qdonep->d3.scsi_stat);
         break;
@@ -7749,7 +7237,7 @@
         boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
     }
 
-    /* 
+    /*
      * Because interrupts may be enabled by the 'Scsi_Cmnd' done
      * function, add the command to the end of the board's done queue.
      * The done function for the command will be called from
@@ -7774,9 +7262,12 @@
     Scsi_Cmnd           *scp;
     struct Scsi_Host    *shp;
     int                 i;
+#if ASC_LINUX_KERNEL24
+    ADV_DCNT            resid_cnt;
+#endif
 
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
-    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n",
+
+    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
         (ulong) adv_dvc_varp, (ulong) scsiqp);
     ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
 
@@ -7786,7 +7277,7 @@
      * completed ADV_SCSI_REQ_Q structure.
      */
     reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr);
-    ASC_DBG1(1, "adv_isr_callback: reqp %lx\n", (ulong) reqp);
+    ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong) reqp);
     if (reqp == NULL) {
         ASC_PRINT("adv_isr_callback: reqp is NULL\n");
         return;
@@ -7801,7 +7292,7 @@
      * determined.
      */
     scp = reqp->cmndp;
-    ASC_DBG1(1, "adv_isr_callback: scp %lx\n", (ulong) scp);
+    ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong) scp);
     if (scp == NULL) {
         ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
         return;
@@ -7824,18 +7315,17 @@
      */
     if (i == asc_board_count) {
         ASC_PRINT2(
-            "adv_isr_callback: scp %lx has bad host pointer, host %lx\n",
+            "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
             (ulong) scp, (ulong) shp);
         return;
     }
 
     ASC_STATS(shp, callback);
-    ASC_DBG1(1, "adv_isr_callback: shp %lx\n", (ulong) shp);
+    ASC_DBG1(1, "adv_isr_callback: shp 0x%lx\n", (ulong) shp);
 
     /*
      * If the request isn't found on the active queue, it may have been
-     * removed to handle a reset or abort request. Display a message and
-     * return.
+     * removed to handle a reset request. Display a message and return.
      *
      * Note: Because the structure may still be in use don't attempt
      * to free the adv_req_t and adv_sgblk_t, if any, structures.
@@ -7844,7 +7334,7 @@
     ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
     if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
         ASC_PRINT2(
-            "adv_isr_callback: board %d: scp %lx not on active queue\n",
+            "adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
             boardp->id, (ulong) scp);
         return;
     }
@@ -7857,20 +7347,21 @@
         ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
         scp->result = 0;
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19)
+#if ASC_LINUX_KERNEL24
         /*
          * Check for an underrun condition.
          *
          * If there was no error and an underrun condition, then
          * then return the number of underrun bytes.
          */
-        if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0 &&
-            scsiqp->data_cnt <= scp->request_bufflen) {
+        resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+        if (scp->request_bufflen != 0 && resid_cnt != 0 &&
+            resid_cnt <= scp->request_bufflen) {
             ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
-            (ulong) scsiqp->data_cnt);
-            scp->resid = scsiqp->data_cnt;
+                (ulong) resid_cnt);
+            scp->resid = resid_cnt;
         }
-#endif /* version >= v2.3.19 */
+#endif
         break;
 
     case QD_WITH_ERROR:
@@ -7900,7 +7391,7 @@
 
         default:
             /* Some other QHSTA error occurred. */
-            ASC_DBG1(1, "adv_isr_callback: host_status %x\n",
+            ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
                 scsiqp->host_status);
             scp->result = HOST_BYTE(DID_BAD_TARGET);
             break;
@@ -7913,7 +7404,7 @@
         break;
 
     default:
-        ASC_DBG1(1, "adv_isr_callback: done_status %x\n", scsiqp->done_status);
+        ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", scsiqp->done_status);
         scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
         break;
     }
@@ -7929,7 +7420,7 @@
         boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
     }
 
-    /* 
+    /*
      * Because interrupts may be enabled by the 'Scsi_Cmnd' done
      * function, add the command to the end of the board's done queue.
      * The done function for the command will be called from
@@ -8000,415 +7491,6 @@
     }
 }
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-/*
- * Search for an AdvanSys PCI device in the PCI configuration space.
- */
-ASC_INITFUNC(
-STATIC int,
-asc_srch_pci_dev(PCI_DEVICE *pciDevice)
-)
-{
-    int                        ret = PCI_DEVICE_NOT_FOUND;
-
-    ASC_DBG(2, "asc_srch_pci_dev: begin\n");
-
-    if (pci_scan_method == -1) {
-        pci_scan_method = asc_scan_method();
-    }
-    pciDevice->type = pci_scan_method;
-    ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type);
-
-    ret = asc_pci_find_dev(pciDevice);
-    ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret);
-    if (ret == PCI_DEVICE_FOUND) {
-        pciDevice->slotNumber = pciDevice->slotFound + 1;
-        pciDevice->startSlot = pciDevice->slotFound + 1;
-    } else {
-        if (pciDevice->bridge > pciDevice->busNumber) {
-            ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n",
-                pciDevice->bridge, pciDevice->busNumber);
-            pciDevice->busNumber++;
-            pciDevice->slotNumber = 0;
-            pciDevice->startSlot = 0;
-            pciDevice->endSlot = 0x0f;
-            ret = asc_srch_pci_dev(pciDevice);
-            ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret);
-        }
-    }
-
-    ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret);
-    return ret;
-}
-
-/*
- * Determine the access method to be used for 'pciDevice'.
- */
-ASC_INITFUNC(
-STATIC uchar,
-asc_scan_method(void)
-)
-{
-    ushort      data;
-    PCI_DATA    pciData;
-    uchar       type;
-    uchar       slot;
-
-    ASC_DBG(2, "asc_scan_method: begin\n");
-    memset(&pciData, 0, sizeof(pciData));
-    for (type = 1; type < 3; type++) {
-        pciData.type = type;
-        for (slot = 0; slot < PCI_MAX_SLOT; slot++) {
-            pciData.slot = slot;
-            data = asc_get_cfg_word(&pciData);
-            if ((data != 0xFFFF) && (data != 0x0000)) {
-                ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type);
-                return (type);
-            }
-        }
-    }
-    ASC_DBG1(4, "asc_scan_method: type %d\n", type);
-    return (type);
-}
-
-/*
- * Check for an AdvanSys PCI device in 'pciDevice'.
- *
- * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
- */
-ASC_INITFUNC(
-STATIC int,
-asc_pci_find_dev(PCI_DEVICE *pciDevice)
-)
-{
-    PCI_DATA    pciData;
-    ushort      vendorid, deviceid;
-    uchar       classcode, subclass;
-    uchar       lslot;
-
-    ASC_DBG(3, "asc_pci_find_dev: begin\n");
-    pciData.type = pciDevice->type;
-    pciData.bus = pciDevice->busNumber;
-    pciData.func = pciDevice->devFunc;
-    lslot = pciDevice->startSlot;
-    for (; lslot < pciDevice->endSlot; lslot++) {
-        pciData.slot = lslot;
-        pciData.offset = VENDORID_OFFSET;
-        vendorid = asc_get_cfg_word(&pciData);
-        ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid);
-        if (vendorid != 0xffff) {
-            pciData.offset = DEVICEID_OFFSET;
-            deviceid = asc_get_cfg_word(&pciData);
-            ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid);
-            if ((vendorid == ASC_PCI_VENDORID) &&
-                ((deviceid == ASC_PCI_DEVICE_ID_1100) ||
-                 (deviceid == ASC_PCI_DEVICE_ID_1200) ||
-                 (deviceid == ASC_PCI_DEVICE_ID_1300) ||
-                 (deviceid == ASC_PCI_DEVICE_ID_2300) ||
-                 (deviceid == ASC_PCI_DEVICE_ID_2500))) {
-                pciDevice->slotFound = lslot;
-                ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
-                return PCI_DEVICE_FOUND;
-            } else {
-                pciData.offset = SUBCLASS_OFFSET;
-                subclass = asc_get_cfg_byte(&pciData);
-                pciData.offset = CLASSCODE_OFFSET;
-                classcode = asc_get_cfg_byte(&pciData);
-                if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) &&
-                    (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) {
-                    pciDevice->bridge++;
-                }
-                ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n",
-                    subclass, classcode);
-            }
-        }
-    }
-    return PCI_DEVICE_NOT_FOUND;
-}
-
-/*
- * Read PCI configuration data into 'pciConfig'.
- */
-ASC_INITFUNC(
-STATIC void,
-asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
-)
-{
-    PCI_DATA    pciData;
-    uchar       counter;
-    uchar       *localConfig;
-
-    ASC_DBG1(4, "asc_get_pci_cfg: slotFound %d\n ",
-        pciDevice->slotFound);
-
-    pciData.type = pciDevice->type;
-    pciData.bus = pciDevice->busNumber;
-    pciData.slot = pciDevice->slotFound;
-    pciData.func = pciDevice->devFunc;
-    localConfig = (uchar *) pciConfig;
-
-    for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) {
-        pciData.offset = counter;
-        *localConfig = asc_get_cfg_byte(&pciData);
-        ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig);
-        localConfig++;
-    }
-    ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter);
-}
-
-/*
- * Read a word (16 bits) from the PCI configuration space.
- *
- * The configuration mechanism is checked for the correct access method.
- */
-ASC_INITFUNC(
-STATIC ushort,
-asc_get_cfg_word(PCI_DATA *pciData)
-)
-{
-    ushort   tmp;
-    ADV_DCNT address;
-    ADV_DCNT lbus = pciData->bus;
-    ADV_DCNT lslot = pciData->slot;
-    ADV_DCNT lfunc = pciData->func;
-    uchar    t2CFA, t2CF8;
-    ADV_DCNT t1CF8, t1CFC;
-
-    ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %u, slot %u, func %u\n",
-        pciData->type, (unsigned) lbus, (unsigned) lslot, (unsigned) lfunc);
-
-    /*
-     * Check type of configuration mechanism.
-     */
-    if (pciData->type == 2) {
-        /*
-         * Save registers to be restored later.
-         */
-        t2CFA = inp(0xCFA);    /* save PCI bus register */
-        t2CF8 = inp(0xCF8);    /* save config space enable register */
-
-        /*
-         * Write the bus and enable registers.
-         */
-        /* set for type 1 cycle, if needed */
-        outp(0xCFA, pciData->bus);
-        /* set the function number */
-        outp(0xCF8, 0x10 | (pciData->func << 1));
-
-        /*
-         * Read the configuration space type 2 locations.
-         */
-        tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset));
-
-        outp(0xCFA, t2CFA);    /* save PCI bus register */
-        outp(0xCF8, t2CF8);    /* save config space enable register */
-    } else {
-        /*
-         * Type 1 or 3 configuration mechanism.
-         *
-         * Save the CONFIG_ADDRESS and CONFIG_DATA register values.
-         */
-        t1CF8 = inpl(0xCF8);
-        t1CFC = inpl(0xCFC);
-
-        /*
-         * enable <31>, bus = <23:16>, slot = <15:11>,
-         * func = <10:8>, reg = <7:2>
-         */
-        address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) |
-            (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
-
-        /*
-         * Write out the address to CONFIG_ADDRESS.
-         */
-        outpl(0xCF8, address);
-
-        /*
-         * Read in word from CONFIG_DATA.
-         */
-        tmp = (ushort) ((inpl(0xCFC) >>
-                 ((pciData->offset & 2) * 8)) & 0xFFFF);
-
-        /*
-         * Restore registers.
-         */
-        outpl(0xCF8, t1CF8);
-        outpl(0xCFC, t1CFC);
-    }
-    ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp);
-    return tmp;
-}
-
-/*
- * Reads a byte from the PCI configuration space.
- *
- * The configuration mechanism is checked for the correct access method.
- */
-ASC_INITFUNC(
-STATIC uchar,
-asc_get_cfg_byte(PCI_DATA *pciData)
-)
-{
-    uchar    tmp;
-    ADV_DCNT address;
-    ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
-    ADV_DCNT t2CFA, t2CF8;
-    ADV_DCNT t1CF8, t1CFC;
-
-    ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type);
-
-    /*
-     * Check type of configuration mechanism.
-     */
-    if (pciData->type == 2) {
-        /*
-         * Save registers to be restored later.
-         */
-        t2CFA = inp(0xCFA);    /* save PCI bus register */
-        t2CF8 = inp(0xCF8);    /* save config space enable register */
-
-        /*
-         * Write the bus and enable registers.
-         */
-        /* set for type 1 cycle, if needed */
-        outp(0xCFA, pciData->bus);
-        /* set the function number */
-        outp(0xCF8, 0x10 | (pciData->func << 1));
-
-        /*
-         * Read configuration space type 2 locations.
-         */
-        tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset));
-
-        /*
-         * Restore registers.
-         */
-        outp(0xCF8, t2CF8);    /* restore the enable register */
-        outp(0xCFA, t2CFA);    /* restore PCI bus register */
-    } else {
-        /*
-         * Type 1 or 3 configuration mechanism.
-         *
-         * Save CONFIG_ADDRESS and CONFIG_DATA register values.
-         */
-        t1CF8 = inpl(0xCF8);
-        t1CFC = inpl(0xCFC);
-
-        /*
-         * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
-         * reg = <7:2>
-         */
-        address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) |
-            (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
-
-        /*
-         * Write out address to CONFIG_ADDRESS.
-         */
-        outpl(0xCF8, address);
-
-        /*
-         * Read in word from CONFIG_DATA.
-         */
-        tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF);
-
-        /*
-         * Restore registers.
-         */
-        outpl(0xCF8, t1CF8);
-        outpl(0xCFC, t1CFC);
-    }
-    ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp);
-    return tmp;
-}
-
-/*
- * Write a byte to the PCI configuration space.
- */
-ASC_INITFUNC(
-STATIC void,
-asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
-)
-{
-    ADV_DCNT tmpl;
-    ADV_DCNT address;
-    ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
-    uchar    t2CFA, t2CF8;
-    ADV_DCNT t1CF8, t1CFC;
-
-    ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n",
-        pciData->type, byte_data);
-
-    /*
-     * Check type of configuration mechanism.
-     */
-    if (pciData->type == 2) {
-
-        /*
-         * Save registers to be restored later.
-         */
-        t2CFA = inp(0xCFA);    /* save PCI bus register */
-        t2CF8 = inp(0xCF8);    /* save config space enable register */
-
-        /*
-         * Write bus and enable registers.
-         */
-        outp(0xCFA, pciData->bus);
-
-        /*
-         * Set the function number.
-         */
-        outp(0xCF8, 0x10 | (pciData->func << 1));
-
-        /*
-         * Write the configuration space type 2 locations.
-         */
-        outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data);
-
-        /*
-         * Restore registers.
-         */
-        outp(0xCF8, t2CF8);    /* restore the enable register */
-        outp(0xCFA, t2CFA);    /* restore PCI bus register    */
-    } else {
-
-        /*
-         * Type 1 or 3 configuration mechanism.
-         *
-         * Save the CONFIG_ADDRESS and CONFIG_DATA register values.
-         */
-        t1CF8 = inpl(0xCF8);
-        t1CFC = inpl(0xCFC);
-
-        /*
-         * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
-         * reg = <7:2>
-         */
-        address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | (lfunc << 8) |
-                (pciData->offset & 0xFC) | 0x80000000L);
-        /*
-         * Write out address to CONFIG_ADDRESS.
-         */
-        outpl(0xCF8, address);
-
-        /*
-         * Write double word to CONFIG_DATA preserving the bytes
-         * in the double not written.
-         */
-        tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8));
-        outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8)));
-
-        /*
-         * Restore registers.
-         */
-        outpl(0xCF8, t1CF8);
-        outpl(0xCFC, t1CFC);
-    }
-    ASC_DBG(4, "asc_put_cfg_byte: end\n");
-}
-#endif /* ASC_CONFIG_PCI */
-#endif /* version < v2.1.93 */
-
 /*
  * Add a 'REQP' to the end of specified queue. Set 'tidmask'
  * to indicate a command is queued for the device.
@@ -8422,9 +7504,8 @@
 {
     int        tid;
 
-    ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n",
+    ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
         (ulong) ascq, (ulong) reqp, flag);
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT(reqp != NULL);
     ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
     tid = REQPTID(reqp);
@@ -8460,7 +7541,7 @@
     }
     REQPTIME(reqp) = REQTIMESTAMP();
 #endif /* ADVANSYS_STATS */
-    ASC_DBG1(3, "asc_enqueue: reqp %lx\n", (ulong) reqp);
+    ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong) reqp);
     return;
 }
 
@@ -8476,8 +7557,7 @@
 {
     REQP    reqp;
 
-    ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid);
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
+    ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
     ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
     if ((reqp = ascq->q_first[tid]) != NULL) {
         ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
@@ -8495,7 +7575,7 @@
         REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
 #endif /* ADVANSYS_STATS */
     }
-    ASC_DBG1(3, "asc_dequeue: reqp %lx\n", (ulong) reqp);
+    ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong) reqp);
     return reqp;
 }
 
@@ -8503,7 +7583,7 @@
  * Return a pointer to a singly linked list of all the requests queued
  * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
  *
- * If 'lastpp' is not NULL, '*lastpp' will be set to point to the 
+ * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
  * the last request returned in the singly linked list.
  *
  * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
@@ -8525,8 +7605,7 @@
     REQP    firstp, lastp;
     int     i;
 
-    ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid);
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
+    ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
     ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
 
     /*
@@ -8586,7 +7665,7 @@
     if (lastpp) {
         *lastpp = lastp;
     }
-    ASC_DBG1(3, "asc_dequeue_list: firstp %lx\n", (ulong) firstp);
+    ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong) firstp);
     return firstp;
 }
 
@@ -8607,9 +7686,8 @@
     int         tid;
     int         ret = ASC_FALSE;
 
-    ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n",
+    ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
         (ulong) ascq, (ulong) reqp);
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT(reqp != NULL);
 
     tid = REQPTID(reqp);
@@ -8660,37 +7738,7 @@
     }
     ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
-    ASC_DBG2(3, "asc_rmqueue: reqp %lx, ret %d\n", (ulong) reqp, ret);
-    return ret;
-}
-
-/*
- * If the specified 'REQP' is queued on the specified queue for
- * the specified target device, return ASC_TRUE.
- */
-STATIC int
-asc_isqueued(asc_queue_t *ascq, REQP reqp)
-{
-    REQP        treqp;
-    int            tid;
-    int            ret = ASC_FALSE;
-
-    ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n",
-        (ulong) ascq, (ulong) reqp);
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
-    ASC_ASSERT(reqp != NULL);
-
-    tid = REQPTID(reqp);
-    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-
-    for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
-        ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
-        if (treqp == reqp) {
-            ret = ASC_TRUE;
-            break;
-        }
-    }
-    ASC_DBG1(3, "asc_isqueued: ret %x\n", ret);
+    ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong) reqp, ret);
     return ret;
 }
 
@@ -8706,8 +7754,7 @@
     REQP                    reqp;
     int                     i;
 
-    ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq);
-    ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
+    ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong) ascq);
     /*
      * Execute queued commands for devices attached to
      * the current board in round-robin fashion.
@@ -8721,7 +7768,10 @@
                 } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp)
                             == ASC_BUSY) {
                     scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-                    /* Put the request back at front of the list. */
+                    /*
+                     * The request returned ASC_BUSY. Enqueue at the front of
+                     * target's waiting list to maintain correct ordering.
+                     */
                     asc_enqueue(ascq, reqp, ASC_FRONT);
                 }
             }
@@ -8730,7 +7780,7 @@
     return;
 }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#ifdef CONFIG_PROC_FS
 /*
  * asc_prt_board_devices()
  *
@@ -8810,7 +7860,7 @@
 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
         ASC_PRT_NEXT();
         len = asc_prt_line(cp, leftlen,
-"can be found at the AdvanSys FTP site: ftp://ftp.advansys.com/pub\n");
+"can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
         ASC_PRT_NEXT();
     } else {
         major = (boardp->bios_version >> 12) & 0xF;
@@ -8829,10 +7879,10 @@
         if (major < 3 || (major <= 3 && minor < 1) ||
             (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) {
             len = asc_prt_line(cp, leftlen,
-"Newer version of ROM BIOS is available at the AdvanSys FTP site:\n");
+"Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
             ASC_PRT_NEXT();
             len = asc_prt_line(cp, leftlen,
-"ftp://ftp.advansys.com/pub\n");
+"ftp://ftp.connectcom.net/pub\n");
             ASC_PRT_NEXT();
         }
     }
@@ -8960,7 +8010,9 @@
     int                len;
     ASCEEP_CONFIG      *ep;
     int                i;
+#ifdef CONFIG_ISA
     int                isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+#endif /* CONFIG_ISA */
     uchar              serialstr[13];
 
     boardp = ASC_BOARDP(shp);
@@ -8992,11 +8044,11 @@
 
     len = asc_prt_line(cp, leftlen,
 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-        ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng);
+        ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" cntl %x, no_scam %x\n",
+" cntl 0x%x, no_scam 0x%x\n",
         ep->cntl, ep->no_scam);
     ASC_PRT_NEXT();
 
@@ -9054,12 +8106,14 @@
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+#ifdef CONFIG_ISA
     if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
         len = asc_prt_line(cp, leftlen,
 " Host ISA DMA speed:   %d MB/S\n",
-            isa_dma_speed[ep->isa_dma_speed]);
+            isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
         ASC_PRT_NEXT();
     }
+#endif /* CONFIG_ISA */
 
      return totlen;
 }
@@ -9088,6 +8142,7 @@
     uchar                       serialstr[13];
     ADVEEP_3550_CONFIG          *ep_3550 = NULL;
     ADVEEP_38C0800_CONFIG       *ep_38C0800 = NULL;
+    ADVEEP_38C1600_CONFIG       *ep_38C1600 = NULL;
     ushort                      word;
     ushort                      *wordp;
     ushort                      sdtr_speed = 0;
@@ -9097,9 +8152,12 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         ep_3550 = &boardp->eep_config.adv_3550_eep;
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+    } else
+    {
+        ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
     }
 
     leftlen = cplen;
@@ -9112,9 +8170,12 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         wordp = &ep_3550->serial_number_word1;
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         wordp = &ep_38C0800->serial_number_word1;
+    } else
+    {
+        wordp = &ep_38C1600->serial_number_word1;
     }
 
     if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
@@ -9133,20 +8194,30 @@
             ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
             ep_3550->max_dvc_qng);
         ASC_PRT_NEXT();
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         len = asc_prt_line(cp, leftlen,
 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
             ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
             ep_38C0800->max_dvc_qng);
         ASC_PRT_NEXT();
-    }
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        word = ep_3550->termination;
     } else
     {
+        len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+            ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng,
+            ep_38C1600->max_dvc_qng);
+        ASC_PRT_NEXT();
+    }
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->termination;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
         word = ep_38C0800->termination_lvd;
+    } else
+    {
+        word = ep_38C1600->termination_lvd;
     }
     switch (word) {
         case 1:
@@ -9167,15 +8238,21 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: %x\n",
+" termination: %u (%s), bios_ctrl: 0x%x\n",
             ep_3550->termination, termstr, ep_3550->bios_ctrl);
         ASC_PRT_NEXT();
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: %x\n",
+" termination: %u (%s), bios_ctrl: 0x%x\n",
             ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
         ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: 0x%x\n",
+            ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl);
+        ASC_PRT_NEXT();
     }
 
     len = asc_prt_line(cp, leftlen,
@@ -9191,9 +8268,12 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         word = ep_3550->disc_enable;
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         word = ep_38C0800->disc_enable;
+    } else
+    {
+        word = ep_38C1600->disc_enable;
     }
     len = asc_prt_line(cp, leftlen,
 " Disconnects:         ");
@@ -9209,9 +8289,12 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         word = ep_3550->tagqng_able;
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         word = ep_38C0800->tagqng_able;
+    } else
+    {
+        word = ep_38C1600->tagqng_able;
     }
     len = asc_prt_line(cp, leftlen,
 " Command Queuing:     ");
@@ -9227,9 +8310,12 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         word = ep_3550->start_motor;
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         word = ep_38C0800->start_motor;
+    } else
+    {
+        word = ep_38C1600->start_motor;
     }
     len = asc_prt_line(cp, leftlen,
 " Start Motor:         ");
@@ -9273,9 +8359,12 @@
     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
     {
         word = ep_3550->wdtr_able;
-    } else
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
     {
         word = ep_38C0800->wdtr_able;
+    } else
+    {
+        word = ep_38C1600->wdtr_able;
     }
     len = asc_prt_line(cp, leftlen,
 " Wide Transfer:       ");
@@ -9288,7 +8377,8 @@
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
+        adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600)
     {
         len = asc_prt_line(cp, leftlen,
 " Synchronous Transfer Speed (Mhz):\n  ");
@@ -9352,9 +8442,7 @@
     int                    totlen;
     int                    len;
     int                    chip_scsi_id;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
     int                    i;
-#endif /* version >= v1.3.89 */
 
     boardp = ASC_BOARDP(shp);
 
@@ -9367,39 +8455,31 @@
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
-" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
-        shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
-#else /* version >= v1.3.89 */
 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
         shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
         shp->max_channel);
-#endif /* version >= v1.3.89 */
     ASC_PRT_NEXT();
-    
+
     len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
-" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-        shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
-#else /* version >= v1.3.57 */
 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
         shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
         shp->cmd_per_lun);
-#endif /* version >= v1.3.57 */
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
-" unchecked_isa_dma %d, loaded_as_module %d\n",
-        shp->unchecked_isa_dma, shp->loaded_as_module);
-#else /* version >= v1.3.57 */
 " unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
         shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
-#endif /* version >= v1.3.57 */
     ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n",
-        boardp->flags, boardp->last_reset, jiffies);
+    len = asc_prt_line(cp, leftlen,
+" flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
+        boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port);
+    ASC_PRT_NEXT();
+
+     /* 'shp->n_io_port' may be truncated because it is only one byte. */
+    len = asc_prt_line(cp, leftlen,
+" io_port 0x%x, n_io_port 0x%x\n",
+        shp->io_port, shp->n_io_port);
     ASC_PRT_NEXT();
 
     if (ASC_NARROW_BOARD(boardp)) {
@@ -9408,7 +8488,6 @@
         chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
     }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
     if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) {
         len = asc_prt_line(cp, leftlen, " queue_depth:");
         ASC_PRT_NEXT();
@@ -9427,7 +8506,6 @@
         len = asc_prt_line(cp, leftlen, "\n");
         ASC_PRT_NEXT();
     }
-#endif /* version >= v1.3.89 */
 
     return totlen;
 }
@@ -9470,12 +8548,12 @@
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %x, lib_serial_no %u, mcode_date %x\n",
+" chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
         c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" mcode_version %x, err_code %u\n",
+" mcode_version 0x%x, err_code %u\n",
          c->mcode_version, v->err_code);
     ASC_PRT_NEXT();
 
@@ -9663,14 +8741,14 @@
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" iop_base %lx, cable_detect: %X, err_code %u\n",
+" iop_base 0x%lx, cable_detect: %X, err_code %u\n",
          v->iop_base,
          AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
          v->err_code);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n",
+" chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
         c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
     ASC_PRT_NEXT();
 
@@ -9862,7 +8940,7 @@
 }
 
 /*
- * asc_proc_copy() 
+ * asc_proc_copy()
  *
  * Copy proc information to a read buffer taking into account the current
  * read offset in the file and the remaining space in the read buffer.
@@ -9872,13 +8950,13 @@
               char *cp, int cplen)
 {
     int cnt = 0;
-    
+
     ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
             (unsigned) offset, (unsigned) advoffset, cplen);
     if (offset <= advoffset) {
         /* Read offset below current offset, copy everything. */
         cnt = ASC_MIN(cplen, leftlen);
-        ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n",
+        ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
                 (ulong) curbuf, (ulong) cp, cnt);
         memcpy(curbuf, cp, cnt);
     } else if (offset < advoffset + cplen) {
@@ -9886,7 +8964,7 @@
         cnt = (advoffset + cplen) - offset;
         cp = (cp + cplen) - cnt;
         cnt = ASC_MIN(cnt, leftlen);
-        ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n",
+        ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
                 (ulong) curbuf, (ulong) cp, cnt);
         memcpy(curbuf, cp, cnt);
     }
@@ -9924,7 +9002,7 @@
     va_end(args);
     return ret;
 }
-#endif /* version >= v1.3.0 */
+#endif /* CONFIG_PROC_FS */
 
 
 /*
@@ -9940,56 +9018,33 @@
 STATIC void
 DvcSleepMilliSecond(ADV_DCNT n)
 {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-    ADV_DCNT i;
-#endif /* version < v2.1.0 */ 
-
     ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n);
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
     mdelay(n);
-#else /* version < v2.1.0 */ 
-    for (i = 0; i < n; i++) {
-        udelay(1000);
-    }
-#endif /* version < v2.1.0 */ 
 }
 
-STATIC int
+/*
+ * Currently and inline noop but leave as a placeholder.
+ * Leave DvcEnterCritical() as a noop placeholder.
+ */
+STATIC inline ulong
 DvcEnterCritical(void)
 {
-    int    flags;
-
-    save_flags(flags);
-    cli();
-    return flags;
+    return 0;
 }
 
-STATIC void
-DvcLeaveCritical(int flags)
+/*
+ * Critical sections are all protected by the board spinlock.
+ * Leave DvcLeaveCritical() as a noop placeholder.
+ */
+STATIC inline void
+DvcLeaveCritical(ulong flags)
 {
-    restore_flags(flags);
-}
-
-STATIC ADV_DCNT
-DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ADV_DCNT buf_len,
-             ASC_SG_HEAD *asc_sg_head_ptr)
-{
-    ADV_DCNT buf_size;
-
-    buf_size = buf_len;
-    asc_sg_head_ptr->entry_cnt = 1;
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    asc_sg_head_ptr->sg_list[0].addr = (ADV_PADDR) buf_addr;
-#else /* version >= v2.0.0 */
-    asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
-#endif /* version >= v2.0.0 */
-    asc_sg_head_ptr->sg_list[0].bytes = buf_size;
-    return buf_size;
+    return;
 }
 
 /*
  * void
- * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words)
+ * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
  *
  * Calling/Exit State:
  *    none
@@ -9998,23 +9053,24 @@
  *     Output an ASC_SCSI_Q structure to the chip
  */
 STATIC void
-DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words)
+DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
 {
     int    i;
 
-    ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words);
+    ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
     AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < words; i++, outbuf++) {
-        if (i == 2 || i == 10) {
+    for (i = 0; i < 2 * words; i += 2) {
+        if (i == 4 || i == 20) {
             continue;
         }
-        AscSetChipLramDataNoSwap(iop_base, *outbuf);
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) outbuf[i + 1] << 8) | outbuf[i]);
     }
 }
 
 /*
  * void
- * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words)
+ * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
  *
  * Calling/Exit State:
  *    none
@@ -10023,79 +9079,21 @@
  *     Input an ASC_QDONE_INFO structure from the chip
  */
 STATIC void
-DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words)
+DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
 {
     int    i;
+    ushort word;
 
     AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < words; i++, inbuf++) {
-        if (i == 5) {
+    for (i = 0; i < 2 * words; i += 2) {
+        if (i == 10) {
             continue;
         }
-        *inbuf = AscGetChipLramDataNoSwap(iop_base);
-    }
-    ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words);
-}
-
-/*
- * void    DvcOutPortWords(ushort iop_base, ushort &outbuf, int words)
- *
- * Calling/Exit State:
- *    none
- *
- * Description:
- *     output a buffer to an i/o port address
- */
-STATIC void
-DvcOutPortWords(ushort iop_base, ushort *outbuf, int words)
-{
-    int    i;
-
-    for (i = 0; i < words; i++, outbuf++)
-        outpw(iop_base, *outbuf);
-}
-
-/*
- * void    DvcInPortWords(ushort iop_base, ushort &outbuf, int words)
- *
- * Calling/Exit State:
- *    none
- *
- * Description:
- *     input a buffer from an i/o port address
- */
-STATIC void
-DvcInPortWords(ushort iop_base, ushort *inbuf, int words)
-{
-    int    i;
-
-    for (i = 0; i < words; i++, inbuf++)
-        *inbuf = inpw(iop_base);
-}
-
-/*
- * void DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords)
- *
- * Calling/Exit State:
- *    none
- *
- * Description:
- *     output a buffer of 32-bit integers to an i/o port address in
- *  16 bit integer units
- */
-STATIC void  
-DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords)
-{
-    int       i;
-    int       words;
-    ushort    *pw;
-
-    pw = (ushort *) pdw;
-    words = dwords << 1;
-    for(i = 0; i < words; i++, pw++) {
-        outpw(port, *pw);
+        word = inpw(iop_base + IOP_RAM_DATA);
+        inbuf[i] = word & 0xff;
+        inbuf[i + 1] = (word >> 8) & 0xff;
     }
-    return;
+    ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
 }
 
 /*
@@ -10104,24 +9102,10 @@
 ASC_INITFUNC(
 STATIC uchar,
 DvcReadPCIConfigByte(
-        ASC_DVC_VAR *asc_dvc, 
+        ASC_DVC_VAR *asc_dvc,
         ushort offset)
 )
 {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-    PCI_DATA    pciData;
-
-    pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
-    pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
-    pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
-    pciData.offset = offset;
-    pciData.type = pci_scan_method;
-    return asc_get_cfg_byte(&pciData);
-#else /* ASC_CONFIG_PCI */
-    return 0;
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
     uchar byte_data;
     pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
@@ -10129,10 +9113,9 @@
             ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
         offset, &byte_data);
     return byte_data;
-#else /* CONFIG_PCI */
+#else /* !defined(CONFIG_PCI) */
     return 0;
-#endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
+#endif /* !defined(CONFIG_PCI) */
 }
 
 /*
@@ -10141,30 +9124,17 @@
 ASC_INITFUNC(
 STATIC void,
 DvcWritePCIConfigByte(
-        ASC_DVC_VAR *asc_dvc, 
-        ushort offset, 
+        ASC_DVC_VAR *asc_dvc,
+        ushort offset,
         uchar  byte_data)
 )
 {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-    PCI_DATA    pciData;
-
-    pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
-    pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
-    pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
-    pciData.offset = offset;
-    pciData.type = pci_scan_method;
-    asc_put_cfg_byte(&pciData, byte_data);
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
     pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
         PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info),
             ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
         offset, byte_data);
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
 }
 
 /*
@@ -10192,6 +9162,7 @@
         return(0);
     }
 
+#ifdef CONFIG_ISA
     if((bus_type & ASC_IS_EISA) != 0)
     {
         cfg_lsw = AscGetEisaChipCfg(iop_base);
@@ -10200,6 +9171,7 @@
                                 (cfg_lsw * ASC_BIOS_BANK_SIZE));
         return(bios_addr);
     }/* if */
+#endif /* CONFIG_ISA */
 
     cfg_lsw = AscGetChipCfgLsw(iop_base);
 
@@ -10238,14 +9210,10 @@
 {
     ADV_PADDR           paddr;
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    paddr = (ADV_PADDR) vaddr;
-#else /* version >= v2.0.0 */
     paddr = virt_to_bus(vaddr);
-#endif /* version >= v2.0.0 */
 
     ASC_DBG4(4,
-        "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", 
+        "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
         (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr);
 
     return paddr;
@@ -10257,24 +9225,10 @@
 ASC_INITFUNC(
 STATIC uchar,
 DvcAdvReadPCIConfigByte(
-        ADV_DVC_VAR *asc_dvc, 
+        ADV_DVC_VAR *asc_dvc,
         ushort offset)
 )
 {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-    PCI_DATA    pciData;
-
-    pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
-    pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
-    pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
-    pciData.offset = offset;
-    pciData.type = pci_scan_method;
-    return asc_get_cfg_byte(&pciData);
-#else /* ASC_CONFIG_PCI */
-    return 0;
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
     uchar byte_data;
     pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
@@ -10285,7 +9239,6 @@
 #else /* CONFIG_PCI */
     return 0;
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
 }
 
 /*
@@ -10294,30 +9247,19 @@
 ASC_INITFUNC(
 STATIC void,
 DvcAdvWritePCIConfigByte(
-        ADV_DVC_VAR *asc_dvc, 
-        ushort offset, 
+        ADV_DVC_VAR *asc_dvc,
+        ushort offset,
         uchar  byte_data)
 )
 {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
-    PCI_DATA    pciData;
-
-    pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
-    pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
-    pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
-    pciData.offset = offset;
-    pciData.type = pci_scan_method;
-    asc_put_cfg_byte(&pciData, byte_data);
-#endif /* ASC_CONFIG_PCI */
-#else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
     pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
         PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info),
             ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
         offset, byte_data);
+#else /* CONFIG_PCI */
+    return 0;
 #endif /* CONFIG_PCI */
-#endif /* version >= v2.1.93 */ 
 }
 
 /*
@@ -10325,6 +9267,7 @@
  */
 
 #ifdef ADVANSYS_STATS
+#ifdef CONFIG_PROC_FS
 /*
  * asc_prt_board_stats()
  *
@@ -10341,11 +9284,7 @@
     int                    totlen;
     int                    len;
     struct asc_stats       *s;
-    int                    i;
-    ushort                 chip_scsi_id;
     asc_board_t            *boardp;
-    asc_queue_t            *active;
-    asc_queue_t            *waiting;
 
     leftlen = cplen;
     totlen = len = 0;
@@ -10356,15 +9295,16 @@
     len = asc_prt_line(cp, leftlen,
 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no);
     ASC_PRT_NEXT();
-    
+
     len = asc_prt_line(cp, leftlen,
-" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n",
-        s->command, s->queuecommand, s->abort, s->reset, s->biosparam);
+" queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+        s->queuecommand, s->reset, s->biosparam, s->interrupt);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" interrupt %lu, callback %lu, done %lu\n",
-        s->interrupt, s->callback, s->done);
+" callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+        s->callback, s->done, s->build_error, s->adv_build_noreq,
+        s->adv_build_nosg);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
@@ -10372,17 +9312,6 @@
         s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
     ASC_PRT_NEXT();
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        len = asc_prt_line(cp, leftlen,
-" build_error %lu\n",
-         s->build_error);
-    } else {
-        len = asc_prt_line(cp, leftlen,
-" build_error %lu, build_noreq %lu, build_nosg %lu\n",
-         s->build_error, s->adv_build_noreq, s->adv_build_nosg);
-    }
-    ASC_PRT_NEXT();
-
     /*
      * Display data transfer statistics.
      */
@@ -10437,6 +9366,40 @@
 " Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ);
     ASC_PRT_NEXT();
 
+
+     return totlen;
+}
+
+/*
+ * asc_prt_target_stats()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * This is separated from asc_prt_board_stats because a full set
+ * of targets will overflow ASC_PRTBUF_SIZE.
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen)
+{
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    struct asc_stats       *s;
+    ushort                 chip_scsi_id;
+    asc_board_t            *boardp;
+    asc_queue_t            *active;
+    asc_queue_t            *waiting;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    boardp = ASC_BOARDP(shp);
+    s = &boardp->asc_stats;
+
     active = &ASC_BOARDP(shp)->active;
     waiting = &ASC_BOARDP(shp)->waiting;
 
@@ -10446,70 +9409,77 @@
         chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
     }
 
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+    if ((chip_scsi_id == tgt_id) ||
+        ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
+        return 0;
+    }
 
-        if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) {
-            len = asc_prt_line(cp, leftlen, " target %d\n", i);
+    do {
+        if (active->q_tot_cnt[tgt_id] > 0 || waiting->q_tot_cnt[tgt_id] > 0) {
+            len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
             ASC_PRT_NEXT();
 
             len = asc_prt_line(cp, leftlen,
 "   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
-                active->q_cur_cnt[i], active->q_max_cnt[i],
-                active->q_tot_cnt[i],
-                active->q_min_tim[i], active->q_max_tim[i],
-                (active->q_tot_cnt[i] == 0) ? 0 :
-                (active->q_tot_tim[i]/active->q_tot_cnt[i]),
-                (active->q_tot_cnt[i] == 0) ? 0 :
-                ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i]));
-            ASC_PRT_NEXT();
+                active->q_cur_cnt[tgt_id], active->q_max_cnt[tgt_id],
+                active->q_tot_cnt[tgt_id],
+                active->q_min_tim[tgt_id], active->q_max_tim[tgt_id],
+                (active->q_tot_cnt[tgt_id] == 0) ? 0 :
+                (active->q_tot_tim[tgt_id]/active->q_tot_cnt[tgt_id]),
+                (active->q_tot_cnt[tgt_id] == 0) ? 0 :
+                ASC_TENTHS(active->q_tot_tim[tgt_id],
+                active->q_tot_cnt[tgt_id]));
+             ASC_PRT_NEXT();
 
-            len = asc_prt_line(cp, leftlen,
+             len = asc_prt_line(cp, leftlen,
 "   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
-                waiting->q_cur_cnt[i], waiting->q_max_cnt[i],
-                waiting->q_tot_cnt[i],
-                waiting->q_min_tim[i], waiting->q_max_tim[i],
-                (waiting->q_tot_cnt[i] == 0) ? 0 :
-                (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]),
-                (waiting->q_tot_cnt[i] == 0) ? 0 :
-                ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i]));
-            ASC_PRT_NEXT();
+                waiting->q_cur_cnt[tgt_id], waiting->q_max_cnt[tgt_id],
+                waiting->q_tot_cnt[tgt_id],
+                waiting->q_min_tim[tgt_id], waiting->q_max_tim[tgt_id],
+                (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
+                (waiting->q_tot_tim[tgt_id]/waiting->q_tot_cnt[tgt_id]),
+                (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
+                ASC_TENTHS(waiting->q_tot_tim[tgt_id],
+                waiting->q_tot_cnt[tgt_id]));
+             ASC_PRT_NEXT();
         }
-    }
+    } while (0);
 
      return totlen;
 }
+#endif /* CONFIG_PROC_FS */
 #endif /* ADVANSYS_STATS */
 
 #ifdef ADVANSYS_DEBUG
 /*
  * asc_prt_scsi_host()
  */
-STATIC void 
+STATIC void
 asc_prt_scsi_host(struct Scsi_Host *s)
 {
     asc_board_t         *boardp;
 
     boardp = ASC_BOARDP(s);
 
-    printk("Scsi_Host at addr %lx\n", (ulong) s);
+    printk("Scsi_Host at addr 0x%lx\n", (ulong) s);
     printk(
-" next %lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
+" next 0x%lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
         (ulong) s->next, s->extra_bytes, s->host_busy, s->host_no,
         (unsigned) s->last_reset);
 
+#if ASC_LINUX_KERNEL24
+    printk(
+" host_queue 0x%lx, hostt 0x%lx\n",
+        (ulong) s->host_queue, (ulong) s->hostt);
+#elif ASC_LINUX_KERNEL22
     printk(
-" host_queue %lx, hostt %lx, block %lx,\n",
+" host_queue 0x%lx, hostt 0x%lx, block 0x%lx,\n",
         (ulong) s->host_queue, (ulong) s->hostt, (ulong) s->block);
+#endif
 
     printk(
-" base %lu, io_port %lu, n_io_port %u, irq %d,\n",
-	(ulong) s->base, (ulong) s->io_port, s->n_io_port,
-        s->irq);
+" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
+        (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq);
 
     printk(
 " dma_channel %d, this_id %d, can_queue %d,\n",
@@ -10532,49 +9502,49 @@
 /*
  * asc_prt_scsi_cmnd()
  */
-STATIC void 
+STATIC void
 asc_prt_scsi_cmnd(Scsi_Cmnd *s)
 {
-    printk("Scsi_Cmnd at addr %lx\n", (ulong) s);
+    printk("Scsi_Cmnd at addr 0x%lx\n", (ulong) s);
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
     printk(
-" host %x, device %x, target %u, lun %u\n",
-        (unsigned) s->host, (unsigned) s->device, s->target, s->lun);
-#else /* version >= v1.3.0 */
-    printk(
-" host %lx, device %lx, target %u, lun %u, channel %u,\n",
+" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
         (ulong) s->host, (ulong) s->device, s->target, s->lun,
         s->channel);
-#endif /* version >= v1.3.0 */
 
     asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
 
+#if ASC_LINUX_KERNEL24
+    printk (
+"sc_data_direction %u, resid %d\n",
+        s->sc_data_direction, s->resid);
+#endif
+
     printk(
-" use_sg %u, sglist_len %u, abort_reason %x\n",
+" use_sg %u, sglist_len %u, abort_reason 0x%x\n",
         s->use_sg, s->sglist_len, s->abort_reason);
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
-    printk(
-" retries %d, allowed %d\n",
-         s->retries, s->allowed);
-#else /* version >= v1.3.89 */
     printk(
-" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n",
+" serial_number 0x%x, serial_number_at_timeout 0x%x, retries %d, allowed %d\n",
         (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
          s->retries, s->allowed);
-#endif /* version >= v1.3.89 */
 
     printk(
 " timeout_per_command %d, timeout_total %d, timeout %d\n",
         s->timeout_per_command, s->timeout_total, s->timeout);
 
+#if ASC_LINUX_KERNEL24
+    printk(
+" internal_timeout %u, flags %u\n",
+        s->internal_timeout, s->flags);
+#elif ASC_LINUX_KERNEL22
     printk(
 " internal_timeout %u, flags %u, this_count %d\n",
-        s->internal_timeout, s->flags, s->this_count);
+        s->internal_timeout, s->flags,s->this_count);
+#endif
 
     printk(
-" scsi_done %lx, done %lx, host_scribble %lx, result %x\n",
+" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
         (ulong) s->scsi_done, (ulong) s->done,
         (ulong) s->host_scribble, s->result);
 
@@ -10586,57 +9556,59 @@
 /*
  * asc_prt_asc_dvc_var()
  */
-STATIC void 
+STATIC void
 asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
 {
-    printk("ASC_DVC_VAR at addr %lx\n", (ulong) h);
+    printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong) h);
 
     printk(
-" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n",
+" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
         h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
 
     printk(
-" bus_type %d, isr_callback %lx, exe_callback %lx, init_sdtr %x,\n",
+" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
         h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback,
         (unsigned) h->init_sdtr);
 
     printk(
-" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n",
+" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
         (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
         (unsigned) h->unit_not_ready, (unsigned) h->chip_no);
-        
+
     printk(
-" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n",
+" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
         (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
-        (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+        (unsigned) h->scsi_reset_wait);
 
     printk(
-" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n",
+" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
         (unsigned) h->is_in_int, (unsigned) h->max_total_qng,
         (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
 
     printk(
-" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n",
+" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
         (unsigned) h->last_q_shortage, (unsigned) h->init_state,
         (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
 
     printk(
-" cfg %lx\n",
-        (ulong) h->cfg);
+" cfg 0x%lx, irq_no 0x%x\n",
+        (ulong) h->cfg, (unsigned) h->irq_no);
 }
 
 /*
  * asc_prt_asc_dvc_cfg()
  */
-STATIC void 
+STATIC void
 asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
 {
-    printk("ASC_DVC_CFG at addr %lx\n", (ulong) h);
+    printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong) h);
 
     printk(
-" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, sdtr_enable %x,\n",
-            h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable,
-            h->sdtr_enable);
+" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+            h->can_tagged_qng, h->cmd_qng_enabled);
+    printk(
+" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+            h->disc_enable, h->sdtr_enable);
 
     printk(
 " chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
@@ -10644,48 +9616,49 @@
              h->chip_version);
 
     printk(
-" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n",
+" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
           h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date);
 
     printk(
-" mcode_version %d, overrun_buf %lx\n",
+" mcode_version %d, overrun_buf 0x%lx\n",
             h->mcode_version, (ulong) h->overrun_buf);
 }
 
 /*
  * asc_prt_asc_scsi_q()
  */
-STATIC void 
+STATIC void
 asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
 {
     ASC_SG_HEAD    *sgp;
     int i;
 
-    printk("ASC_SCSI_Q at addr %lx\n", (ulong) q);
+    printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong) q);
 
     printk(
-" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n",
+" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
             q->q2.target_ix, q->q1.target_lun,
-            (unsigned) q->q2.srb_ptr, q->q2.tag_code);
+            (ulong) q->q2.srb_ptr, q->q2.tag_code);
 
     printk(
-" data_addr %lx, data_cnt %lu, sense_addr %lx, sense_len %u,\n",
-            (ulong) q->q1.data_addr, (ulong) q->q1.data_cnt,
-            (ulong) q->q1.sense_addr, q->q1.sense_len);
+" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+            (ulong) le32_to_cpu(q->q1.data_addr),
+            (ulong) le32_to_cpu(q->q1.data_cnt),
+            (ulong) le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
 
     printk(
-" cdbptr %lx, cdb_len %u, sg_head %lx, sg_queue_cnt %u\n",
+" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
             (ulong) q->cdbptr, q->q2.cdb_len,
             (ulong) q->sg_head, q->q1.sg_queue_cnt);
 
     if (q->sg_head) {
         sgp = q->sg_head;
-        printk("ASC_SG_HEAD at addr %lx\n", (ulong) sgp);
+        printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong) sgp);
         printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
         for (i = 0; i < sgp->entry_cnt; i++) {
-            printk(" [%u]: addr %lx, bytes %lu\n",
-                i, (ulong) sgp->sg_list[i].addr,
-                (ulong) sgp->sg_list[i].bytes);
+            printk(" [%u]: addr 0x%lx, bytes %lu\n",
+                i, (ulong) le32_to_cpu(sgp->sg_list[i].addr),
+                (ulong) le32_to_cpu(sgp->sg_list[i].bytes));
         }
 
     }
@@ -10694,17 +9667,17 @@
 /*
  * asc_prt_asc_qdone_info()
  */
-STATIC void 
+STATIC void
 asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
 {
-    printk("ASC_QDONE_INFO at addr %lx\n", (ulong) q);
+    printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong) q);
     printk(
-" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n",
-            (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
-            q->d2.tag_code, q->d3.done_stat);
+" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+            (ulong) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+            q->d2.tag_code);
     printk(
-" host_stat %x, scsi_stat %x, scsi_msg %x\n",
-            q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+            q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
 }
 
 /*
@@ -10712,7 +9685,7 @@
  *
  * Display an ADV_DVC_VAR structure.
  */
-STATIC void 
+STATIC void
 asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
 {
     printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h);
@@ -10723,8 +9696,8 @@
 
     printk(
 "  isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
-        (ulong) h->isr_callback, (unsigned) h->wdtr_able,
-        (unsigned) h->sdtr_able);
+        (ulong) h->isr_callback, (unsigned) h->sdtr_able,
+        (unsigned) h->wdtr_able);
 
     printk(
 "  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
@@ -10732,12 +9705,12 @@
         (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
 
     printk(
-"  max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n",
+"  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
         (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
         (ulong) h->carr_freelist);
 
     printk(
-"  icq_sp %lx, irq_sp %lx\n",
+"  icq_sp 0x%lx, irq_sp 0x%lx\n",
         (ulong) h->icq_sp, (ulong) h->irq_sp);
 
     printk(
@@ -10745,7 +9718,7 @@
         (unsigned) h->no_scam, (unsigned) h->tagqng_able);
 
     printk(
-"  chip_scsi_id 0x%x, cfg %lx\n",
+"  chip_scsi_id 0x%x, cfg 0x%lx\n",
         (unsigned) h->chip_scsi_id, (ulong) h->cfg);
 }
 
@@ -10754,7 +9727,7 @@
  *
  * Display an ADV_DVC_CFG structure.
  */
-STATIC void 
+STATIC void
 asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
 {
     printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h);
@@ -10768,7 +9741,7 @@
         h->chip_version, h->mcode_date);
 
     printk(
-"  mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n",
+"  mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
        h->mcode_version, h->pci_device_id, h->lib_version);
 
     printk(
@@ -10781,37 +9754,38 @@
  *
  * Display an ADV_SCSI_REQ_Q structure.
  */
-STATIC void 
+STATIC void
 asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 {
     int                 sg_blk_cnt;
     struct asc_sg_block *sg_ptr;
 
-    printk("ADV_SCSI_REQ_Q at addr %lx\n", (ulong) q);
+    printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong) q);
 
     printk(
 "  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
             q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag);
 
     printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
-            q->cntl, (ulong) q->data_addr, (ulong) q->vdata_addr);
+            q->cntl, (ulong) le32_to_cpu(q->data_addr), (ulong) q->vdata_addr);
 
     printk(
 "  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
-            (ulong) q->data_cnt, (ulong) q->sense_addr, q->sense_len);
+            (ulong) le32_to_cpu(q->data_cnt),
+            (ulong) le32_to_cpu(q->sense_addr), q->sense_len);
 
     printk(
 "  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
             q->cdb_len, q->done_status, q->host_status, q->scsi_status);
 
     printk(
-"  sg_working_ix %x, sg_working_data_cnt %lx, target_cmd %u\n",
-            q->sg_working_ix, (ulong) q->sg_working_data_cnt, q->target_cmd);
+"  sg_working_ix 0x%x, target_cmd %u\n",
+            q->sg_working_ix, q->target_cmd);
 
     printk(
-"  scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n",
-            (ulong) q->scsiq_rptr, (ulong) q->sg_real_addr,
-            (ulong) q->sg_list_ptr);
+"  scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+            (ulong) le32_to_cpu(q->scsiq_rptr),
+            (ulong) le32_to_cpu(q->sg_real_addr), (ulong) q->sg_list_ptr);
 
     /* Display the request's ADV_SG_BLOCK structures. */
     if (q->sg_list_ptr != NULL)
@@ -10846,17 +9820,17 @@
 {
     int i;
 
-    printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n",
+    printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
         (ulong) b, sgblockno);
-    printk("  sg_cnt %u, sg_ptr %lx\n",
-        b->sg_cnt, (ulong) b->sg_ptr);
+    printk("  sg_cnt %u, sg_ptr 0x%lx\n",
+        b->sg_cnt, (ulong) le32_to_cpu(b->sg_ptr));
     ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
     if (b->sg_ptr != 0)
     {
         ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
     }
     for (i = 0; i < b->sg_cnt; i++) {
-        printk("  [%u]: sg_addr %lx, sg_count %lx\n",
+        printk("  [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
             i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count);
     }
 }
@@ -10864,10 +9838,10 @@
 /*
  * asc_prt_hex()
  *
- * Print hexadecimal output in 4 byte groupings 32 bytes 
+ * Print hexadecimal output in 4 byte groupings 32 bytes
  * or 8 double-words per line.
  */
-STATIC void 
+STATIC void
 asc_prt_hex(char *f, uchar *s, int l)
 {
     int            i;
@@ -10878,7 +9852,7 @@
     printk("%s: (%d bytes)\n", f, l);
 
     for (i = 0; i < l; i += 32) {
-        
+
         /* Display a maximum of 8 double-words per line. */
         if ((k = (l - i) / 4) >= 8) {
             k = 8;
@@ -10919,27 +9893,6 @@
 }
 #endif /* ADVANSYS_DEBUG */
 
-#ifdef ADVANSYS_ASSERT
-/*
- * advansys_interrupts_enabled()
- *
- * Return 1 if interrupts are enabled, otherwise return 0.
- */
-STATIC int
-advansys_interrupts_enabled(void)
-{
-    int flags;
-
-    save_flags(flags);
-    if (flags & 0x0200) {
-        return ASC_TRUE;
-    } else {
-        return ASC_FALSE;
-    }
-}
-#endif /* ADVANSYS_ASSERT */
-
-
 /*
  * --- Asc Library Functions
  */
@@ -11047,42 +10000,47 @@
     return (0);
 }
 
-ASC_INITFUNC(
-STATIC ASC_DCNT,
+STATIC ASC_DCNT
 AscLoadMicroCode(
                     PortAddr iop_base,
                     ushort s_addr,
-                    ushort *mcode_buf,
+                    uchar *mcode_buf,
                     ushort mcode_size
 )
-)
 {
     ASC_DCNT            chksum;
     ushort              mcode_word_size;
     ushort              mcode_chksum;
 
+    /* Write the microcode buffer starting at LRAM address 0. */
     mcode_word_size = (ushort) (mcode_size >> 1);
     AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
-    AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+    AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+
     chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+    ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong) chksum);
     mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
-                                              (ushort) ASC_CODE_SEC_BEG,
+          (ushort) ASC_CODE_SEC_BEG,
           (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
+    ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
+        (ulong) mcode_chksum);
     AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
     AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
     return (chksum);
 }
 
-ASC_INITFUNC(
-STATIC int,
+STATIC int
 AscFindSignature(
                     PortAddr iop_base
 )
-)
 {
     ushort              sig_word;
 
+    ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
+        iop_base, AscGetChipSignatureByte(iop_base));
     if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
+        ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
+            iop_base, AscGetChipSignatureWord(iop_base));
         sig_word = AscGetChipSignatureWord(iop_base);
         if ((sig_word == (ushort) ASC_1000_ID0W) ||
             (sig_word == (ushort) ASC_1000_ID0W_FIX)) {
@@ -11092,13 +10050,15 @@
     return (0);
 }
 
-STATIC uchar _isa_pnp_inited ASC_INITDATA = 0;
 STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA =
 {
     0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
     ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
 };
 
+#ifdef CONFIG_ISA
+STATIC uchar _isa_pnp_inited ASC_INITDATA = 0;
+
 ASC_INITFUNC(
 STATIC PortAddr,
 AscSearchIOPortAddr(
@@ -11155,11 +10115,11 @@
         iop_base = _asc_def_iop_base[i];
         if (check_region(iop_base, ASC_IOADR_GAP) != 0) {
             ASC_DBG1(1,
-               "AscSearchIOPortAddr11: check_region() failed I/O port %x\n",
+               "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
                      iop_base);
             continue;
         }
-        ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base);
+        ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base);
         if (AscFindSignature(iop_base)) {
             return (iop_base);
         }
@@ -11169,24 +10129,25 @@
 
 ASC_INITFUNC(
 STATIC void,
-AscToggleIRQAct(
-                   PortAddr iop_base
-)
+AscSetISAPNPWaitForKey(
+    void)
 )
 {
-    AscSetChipStatus(iop_base, CIW_IRQ_ACT);
-    AscSetChipStatus(iop_base, 0);
+    outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
+    outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
     return;
 }
+#endif /* CONFIG_ISA */
 
 ASC_INITFUNC(
 STATIC void,
-AscSetISAPNPWaitForKey(
-    void)
+AscToggleIRQAct(
+                   PortAddr iop_base
+)
 )
 {
-    outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
-    outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
+    AscSetChipStatus(iop_base, CIW_IRQ_ACT);
+    AscSetChipStatus(iop_base, 0);
     return;
 }
 
@@ -11267,6 +10228,7 @@
     return (0);
 }
 
+#ifdef CONFIG_ISA
 ASC_INITFUNC(
 STATIC void,
 AscEnableIsaDma(
@@ -11283,8 +10245,9 @@
     }
     return;
 }
+#endif /* CONFIG_ISA */
 
-STATIC int 
+STATIC int
 AscIsrChipHalted(
                     ASC_DVC_VAR *asc_dvc
 )
@@ -11343,10 +10306,10 @@
         return (0);
     } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
 
-        AscMemWordCopyFromLram(iop_base,
+        AscMemWordCopyPtrFromLram(iop_base,
                                ASCV_MSGIN_BEG,
-                               (ushort *) & ext_msg,
-                               (ushort) (sizeof (EXT_MSG) >> 1));
+                               (uchar *) &ext_msg,
+                               sizeof(EXT_MSG) >> 1);
 
         if (ext_msg.msg_type == MS_EXTEND &&
             ext_msg.msg_req == MS_SDTR_CODE &&
@@ -11420,10 +10383,10 @@
                    ext_msg.msg_len == MS_WDTR_LEN) {
 
             ext_msg.wdtr_width = 0;
-            AscMemWordCopyToLram(iop_base,
+            AscMemWordCopyPtrToLram(iop_base,
                                  ASCV_MSGOUT_BEG,
-                                 (ushort *) & ext_msg,
-                                 (ushort) (sizeof (EXT_MSG) >> 1));
+                                 (uchar *) &ext_msg,
+                                 sizeof(EXT_MSG) >> 1);
             q_cntl |= QC_MSG_OUT;
             AscWriteLramByte(iop_base,
                          (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
@@ -11433,10 +10396,10 @@
         } else {
 
             ext_msg.msg_type = M1_MSG_REJECT;
-            AscMemWordCopyToLram(iop_base,
+            AscMemWordCopyPtrToLram(iop_base,
                                  ASCV_MSGOUT_BEG,
-                                 (ushort *) & ext_msg,
-                                 (ushort) (sizeof (EXT_MSG) >> 1));
+                                 (uchar *) &ext_msg,
+                                 sizeof(EXT_MSG) >> 1);
             q_cntl |= QC_MSG_OUT;
             AscWriteLramByte(iop_base,
                          (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
@@ -11496,10 +10459,10 @@
         return (0);
     } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
 
-        AscMemWordCopyFromLram(iop_base,
+        AscMemWordCopyPtrFromLram(iop_base,
                                ASCV_MSGOUT_BEG,
-                               (ushort *) & out_msg,
-                               (ushort) (sizeof (EXT_MSG) >> 1));
+                               (uchar *) &out_msg,
+                               sizeof(EXT_MSG) >> 1);
 
         if ((out_msg.msg_type == MS_EXTEND) &&
             (out_msg.msg_len == MS_SDTR_LEN) &&
@@ -11554,7 +10517,9 @@
         }
         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
         return (0);
-    } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
+    }
+#if CC_VERY_LONG_SG_LIST
+    else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
     {
         uchar              q_no;
         ushort             q_addr;
@@ -11678,16 +10643,15 @@
              }
 
              scsi_sg_q.q_no = next_qp;
-             AscMemWordCopyToLram(iop_base,
-                          (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG),
-                          (ushort *) &scsi_sg_q,
-                          (ushort) (sizeof(ASC_SG_LIST_Q) >> 1));
-
-             AscMemDWordCopyToLram( iop_base,
-                          (ushort) (q_addr+ASC_SGQ_LIST_BEG ),
-                          (ADV_PADDR *)
-                               &sg_head->sg_list[scsiq->next_sg_index],
-                          (ushort) sg_list_dwords);
+             AscMemWordCopyPtrToLram(iop_base,
+                          q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+                          (uchar *) &scsi_sg_q,
+                          sizeof(ASC_SG_LIST_Q) >> 1);
+
+             AscMemDWordCopyPtrToLram(iop_base,
+                          q_addr + ASC_SGQ_LIST_BEG,
+                          (uchar *) &sg_head->sg_list[scsiq->next_sg_index],
+                          sg_list_dwords);
 
              scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
 
@@ -11713,6 +10677,7 @@
         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
         return(0);
     }
+#endif /* CC_VERY_LONG_SG_LIST */
     return (0);
 }
 
@@ -11728,9 +10693,10 @@
     uchar               sg_queue_cnt;
 
     DvcGetQinfo(iop_base,
-                (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG),
-                (ushort *) scsiq,
-              (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2));
+                q_addr + ASC_SCSIQ_DONE_INFO_BEG,
+                (uchar *) scsiq,
+                (sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2);
+
     _val = AscReadLramWord(iop_base,
                            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
     scsiq->q_status = (uchar) _val;
@@ -11994,7 +10960,8 @@
     return (int_pending);
 }
 
-STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
+/* Microcode buffer is kept after initialization for error recovery. */
+STATIC uchar _asc_mcode_buf[] =
 {
   0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
@@ -12142,8 +11109,8 @@
   0xF1,  0xC7,  0x41,  0x23,  0xF8,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
 };
 
-STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
-STATIC ADV_DCNT _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL;
+STATIC ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
+STATIC ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
 
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
@@ -12173,7 +11140,7 @@
 )
 {
     PortAddr            iop_base;
-    int                 last_int_level;
+    ulong               last_int_level;
     int                 sta;
     int                 n_q_required;
     int                 disable_syn_offset_one_fix;
@@ -12235,6 +11202,8 @@
 #if !CC_VERY_LONG_SG_LIST
         if (sg_entry_cnt > ASC_MAX_SG_LIST)
         {
+            asc_dvc->in_critical_cnt--;
+            DvcLeaveCritical(last_int_level);
             return(ERR);
         }
 #endif /* !CC_VERY_LONG_SG_LIST */
@@ -12252,10 +11221,10 @@
         if (scsiq->q1.cntl & QC_SG_HEAD) {
             data_cnt = 0;
             for (i = 0; i < sg_entry_cnt; i++) {
-                data_cnt += (ADV_DCNT) sg_head->sg_list[i].bytes;
+                data_cnt += (ADV_DCNT) le32_to_cpu(sg_head->sg_list[i].bytes);
             }
         } else {
-            data_cnt = scsiq->q1.data_cnt;
+            data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
         }
         if (data_cnt != 0UL) {
             if (data_cnt < 512UL) {
@@ -12279,7 +11248,7 @@
         scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
                                ASC_TAG_FLAG_DISABLE_DISCONNECT);
     } else {
-        scsiq->q2.tag_code &= 0x23;
+        scsiq->q2.tag_code &= 0x27;
     }
     if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
         if (asc_dvc->bug_fix_cntl) {
@@ -12287,23 +11256,27 @@
                 if ((scsi_cmd == SCSICMD_Read6) ||
                     (scsi_cmd == SCSICMD_Read10)) {
                     addr =
-                        (ADV_PADDR)
-                            sg_head->sg_list[sg_entry_cnt_minus_one].addr +
-                        (ADV_DCNT)
-                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+                        (ADV_PADDR) le32_to_cpu(
+                            sg_head->sg_list[sg_entry_cnt_minus_one].addr) +
+                        (ADV_DCNT) le32_to_cpu(
+                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
                     extra_bytes = (uchar) ((ushort) addr & 0x0003);
                     if ((extra_bytes != 0) &&
                         ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
                          == 0)) {
                         scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
                         scsiq->q1.extra_bytes = extra_bytes;
-                        sg_head->sg_list[sg_entry_cnt_minus_one].bytes -=
-                            (ASC_DCNT) extra_bytes;
+                        data_cnt = le32_to_cpu(
+                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
+                        data_cnt -= (ASC_DCNT) extra_bytes;
+                        sg_head->sg_list[sg_entry_cnt_minus_one].bytes =
+                            cpu_to_le32(data_cnt);
                     }
                 }
             }
         }
         sg_head->entry_to_copy = sg_head->entry_cnt;
+#if CC_VERY_LONG_SG_LIST
         /*
          * Set the sg_entry_cnt to the maximum possible. The rest of
          * the SG elements will be copied when the RISC completes the
@@ -12313,6 +11286,7 @@
         {
              sg_entry_cnt = ASC_MAX_SG_LIST;
         }
+#endif /* CC_VERY_LONG_SG_LIST */
         n_q_required = AscSgListToQueue(sg_entry_cnt);
         if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
             (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
@@ -12331,14 +11305,17 @@
             if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
                 if ((scsi_cmd == SCSICMD_Read6) ||
                     (scsi_cmd == SCSICMD_Read10)) {
-                    addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
+                    addr = le32_to_cpu(scsiq->q1.data_addr) +
+                        le32_to_cpu(scsiq->q1.data_cnt);
                     extra_bytes = (uchar) ((ushort) addr & 0x0003);
                     if ((extra_bytes != 0) &&
                         ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
                           == 0)) {
-                        if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
+                        data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+                        if (((ushort) data_cnt & 0x01FF) == 0) {
                             scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
-                            scsiq->q1.data_cnt -= (ASC_DCNT) extra_bytes;
+                            data_cnt -= (ASC_DCNT) extra_bytes;
+                            scsiq->q1.data_cnt = cpu_to_le32(data_cnt);
                             scsiq->q1.extra_bytes = extra_bytes;
                         }
                     }
@@ -12501,14 +11478,15 @@
         scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
     }
     scsiq->q1.status = QS_FREE;
-    AscMemWordCopyToLram(iop_base,
-                         (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
-                         (ushort *) scsiq->cdbptr,
-                         (ushort) ((ushort) scsiq->q2.cdb_len >> 1));
+    AscMemWordCopyPtrToLram(iop_base,
+                         q_addr + ASC_SCSIQ_CDB_BEG,
+                         (uchar *) scsiq->cdbptr,
+                         scsiq->q2.cdb_len >> 1);
+
     DvcPutScsiQ(iop_base,
-                (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
-                (ushort *) & scsiq->q1.cntl,
-      (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)));
+                q_addr + ASC_SCSIQ_CPY_BEG,
+                (uchar *) &scsiq->q1.cntl,
+                ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
     AscWriteLramWord(iop_base,
                      (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
              (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
@@ -12541,6 +11519,7 @@
     saved_data_cnt = scsiq->q1.data_cnt;
     scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
     scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
+#if CC_VERY_LONG_SG_LIST
     /*
      * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
      * then not all SG elements will fit in the allocated queues.
@@ -12551,10 +11530,10 @@
     {
          /*
           * Set sg_entry_cnt to be the number of SG elements that
-          * will fit in the allocated SG queues. It is minus 1 because
-          * first SG element handled above. ASC_MAX_SG_LIST is already
-          * inflated by 1 to account for this. For example it may
-          * be 50 which is 1 + 7 queues * 7 SG elements.
+          * will fit in the allocated SG queues. It is minus 1, because
+          * the first SG element is handled above. ASC_MAX_SG_LIST is
+          * already inflated by 1 to account for this. For example it
+          * may be 50 which is 1 + 7 queues * 7 SG elements.
           */
          sg_entry_cnt = ASC_MAX_SG_LIST - 1;
 
@@ -12565,13 +11544,16 @@
          scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
     } else
     {
+#endif /* CC_VERY_LONG_SG_LIST */
          /*
           * Set sg_entry_cnt to be the number of SG elements that
-          * will fit in the allocated SG queues. Refer to comment
-          * above regarding why it is - 1.
+          * will fit in the allocated SG queues. It is minus 1, because
+          * the first SG element is handled above.
           */
          sg_entry_cnt = sg_head->entry_cnt - 1;
+#if CC_VERY_LONG_SG_LIST
     }
+#endif /* CC_VERY_LONG_SG_LIST */
     if (sg_entry_cnt != 0) {
         scsiq->q1.cntl |= QC_SG_HEAD;
         q_addr = ASC_QNO_TO_QADDR(q_no);
@@ -12592,6 +11574,7 @@
                     scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
                 }
             } else {
+#if CC_VERY_LONG_SG_LIST
                 /*
                  * This is the last SG queue in the list of
                  * allocated SG queues. If there are more
@@ -12603,8 +11586,11 @@
                     scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
                 } else
                 {
+#endif /* CC_VERY_LONG_SG_LIST */
                     scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+#if CC_VERY_LONG_SG_LIST
                 }
+#endif /* CC_VERY_LONG_SG_LIST */
                 sg_list_dwords = sg_entry_cnt << 1;
                 if (i == 0) {
                     scsi_sg_q.sg_list_cnt = sg_entry_cnt;
@@ -12619,14 +11605,14 @@
                                       (ushort) (q_addr + ASC_SCSIQ_B_FWD));
             scsi_sg_q.q_no = next_qp;
             q_addr = ASC_QNO_TO_QADDR(next_qp);
-            AscMemWordCopyToLram(iop_base,
-                                 (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG),
-                                 (ushort *) & scsi_sg_q,
-                                 (ushort) (sizeof (ASC_SG_LIST_Q) >> 1));
-            AscMemDWordCopyToLram(iop_base,
-                                  (ushort) (q_addr + ASC_SGQ_LIST_BEG),
-                                  (ADV_PADDR *) &sg_head->sg_list[sg_index],
-                                  (ushort) sg_list_dwords);
+            AscMemWordCopyPtrToLram(iop_base,
+                                q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+                                (uchar *) &scsi_sg_q,
+                                sizeof(ASC_SG_LIST_Q) >> 1);
+            AscMemDWordCopyPtrToLram(iop_base,
+                                q_addr + ASC_SGQ_LIST_BEG,
+                                (uchar *) &sg_head->sg_list[sg_index],
+                                sg_list_dwords);
             sg_index += ASC_SG_LIST_PER_Q;
             scsiq->next_sg_index = sg_index;
         }
@@ -12640,171 +11626,30 @@
 }
 
 STATIC int
-AscAbortSRB(
-               ASC_DVC_VAR *asc_dvc,
-               ADV_VADDR srb_ptr
+AscSetRunChipSynRegAtID(
+                           PortAddr iop_base,
+                           uchar tid_no,
+                           uchar sdtr_data
 )
 {
-    int                 sta;
-    ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
-    PortAddr            iop_base;
+    int                 sta = FALSE;
 
-    iop_base = asc_dvc->iop_base;
-    sta = ERR;
-    saved_unit_not_ready = asc_dvc->unit_not_ready;
-    asc_dvc->unit_not_ready = 0xFF;
-    AscWaitISRDone(asc_dvc);
-    if (AscStopQueueExe(iop_base) == 1) {
-        if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) {
-            sta = 1;
-            AscCleanUpBusyQueue(iop_base);
-            AscStartQueueExe(iop_base);
-        } else {
-            sta = 0;
-            AscStartQueueExe(iop_base);
-        }
+    if (AscHostReqRiscHalt(iop_base)) {
+        sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+        AscStartChip(iop_base);
+        return (sta);
     }
-    asc_dvc->unit_not_ready = saved_unit_not_ready;
     return (sta);
 }
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 STATIC int
-AscResetDevice(
-                  ASC_DVC_VAR *asc_dvc,
-                  uchar target_ix
+AscSetChipSynRegAtID(
+                        PortAddr iop_base,
+                        uchar id,
+                        uchar sdtr_data
 )
 {
-    PortAddr            iop_base;
-    int                 sta;
-    uchar               tid_no;
-
-    ASC_SCSI_BIT_ID_TYPE target_id;
-    int                 i;
-    ASC_SCSI_REQ_Q      scsiq_buf;
-    ASC_SCSI_REQ_Q *scsiq;
-    uchar       *buf;
-    ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
-    iop_base = asc_dvc->iop_base;
-    tid_no = ASC_TIX_TO_TID(target_ix);
-    target_id = ASC_TID_TO_TARGET_ID(tid_no);
-    saved_unit_not_ready = asc_dvc->unit_not_ready;
-    asc_dvc->unit_not_ready = target_id;
-    sta = ERR;
-    AscWaitTixISRDone(asc_dvc, target_ix);
-    if (AscStopQueueExe(iop_base) == 1) {
-        if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) {
-            AscCleanUpBusyQueue(iop_base);
-            AscStartQueueExe(iop_base);
-            AscWaitTixISRDone(asc_dvc, target_ix);
-            sta = TRUE;
-            scsiq = (ASC_SCSI_REQ_Q *) & scsiq_buf;
-            buf = (uchar *) & scsiq_buf;
-            for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) {
-                *buf++ = 0x00;
-            }
-            scsiq->r1.status = (uchar) QS_READY;
-            scsiq->r2.cdb_len = 6;
-            scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE;
-            scsiq->r1.target_id = target_id;
-            scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0);
-            scsiq->cdbptr = (uchar *) scsiq->cdb;
-            scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT;
-            AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG,
-                             M1_BUS_DVC_RESET);
-            asc_dvc->unit_not_ready &= ~target_id;
-            asc_dvc->sdtr_done |= target_id;
-            if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q *) scsiq)
-                == 1) {
-                asc_dvc->unit_not_ready = target_id;
-                DvcSleepMilliSecond(1000);
-                _AscWaitQDone(iop_base, (ASC_SCSI_Q *) scsiq);
-                if (AscStopQueueExe(iop_base) == 1) {
-                    AscCleanUpDiscQueue(iop_base);
-                    AscStartQueueExe(iop_base);
-                    if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-                        AscSetRunChipSynRegAtID(iop_base, tid_no,
-                                             ASYN_SDTR_DATA_FIX_PCI_REV_AB);
-                    }
-                    AscWaitTixISRDone(asc_dvc, target_ix);
-                }
-            } else {
-                sta = 0;
-            }
-            asc_dvc->sdtr_done &= ~target_id;
-        } else {
-            sta = ERR;
-            AscStartQueueExe(iop_base);
-        }
-    }
-    asc_dvc->unit_not_ready = saved_unit_not_ready;
-    return (sta);
-}
-#endif /* version >= v1.3.89 */
-
-STATIC int
-AscResetSB(
-              ASC_DVC_VAR *asc_dvc
-)
-{
-    int                 sta;
-    int                 i;
-    PortAddr            iop_base;
-
-    iop_base = asc_dvc->iop_base;
-    asc_dvc->unit_not_ready = 0xFF;
-    sta = TRUE;
-    AscWaitISRDone(asc_dvc);
-    AscStopQueueExe(iop_base);
-    asc_dvc->sdtr_done = 0;
-    AscResetChipAndScsiBus(asc_dvc);
-    DvcSleepMilliSecond((ASC_DCNT) ((ushort) asc_dvc->scsi_reset_wait * 1000));
-    AscReInitLram(asc_dvc);
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        asc_dvc->cur_dvc_qng[i] = 0;
-        if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) {
-            AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB);
-        }
-    }
-    asc_dvc->err_code = 0;
-    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-        sta = ERR;
-    }
-    if (AscStartChip(iop_base) == 0) {
-        sta = ERR;
-    }
-    AscStartQueueExe(iop_base);
-    asc_dvc->unit_not_ready = 0;
-    asc_dvc->queue_full_or_busy = 0;
-    return (sta);
-}
-
-STATIC int
-AscSetRunChipSynRegAtID(
-                           PortAddr iop_base,
-                           uchar tid_no,
-                           uchar sdtr_data
-)
-{
-    int                 sta = FALSE;
-
-    if (AscHostReqRiscHalt(iop_base)) {
-        sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-        AscStartChip(iop_base);
-        return (sta);
-    }
-    return (sta);
-}
-
-STATIC int
-AscSetChipSynRegAtID(
-                        PortAddr iop_base,
-                        uchar id,
-                        uchar sdtr_data
-)
-{
-    ASC_SCSI_BIT_ID_TYPE org_id;
+    ASC_SCSI_BIT_ID_TYPE org_id;
     int                 i;
     int                 sta = TRUE;
 
@@ -12831,16 +11676,6 @@
     return (sta);
 }
 
-STATIC int
-AscReInitLram(
-                 ASC_DVC_VAR *asc_dvc
-)
-{
-    AscInitLram(asc_dvc);
-    AscInitQLinkVar(asc_dvc);
-    return (0);
-}
-
 STATIC ushort
 AscInitLram(
                ASC_DVC_VAR *asc_dvc
@@ -12942,31 +11777,7 @@
 }
 
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int
-_AscWaitQDone(
-                 PortAddr iop_base,
-                 ASC_SCSI_Q * scsiq
-)
-{
-    ushort              q_addr;
-    uchar               q_status;
-    int                 count = 0;
-
-    while (scsiq->q1.q_no == 0);
-    q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
-    do {
-        q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
-        DvcSleepMilliSecond(100L);
-        if (count++ > 30) {
-            return (0);
-        }
-    } while ((q_status & QS_READY) != 0);
-    return (1);
-}
-#endif /* version >= v1.3.89 */
-
-STATIC uchar 
+STATIC uchar
 AscMsgOutSDTR(
                  ASC_DVC_VAR *asc_dvc,
                  uchar sdtr_period,
@@ -12987,18 +11798,18 @@
     if ((sdtr_period_index =
          AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
         asc_dvc->max_sdtr_index) {
-        AscMemWordCopyToLram(iop_base,
+        AscMemWordCopyPtrToLram(iop_base,
                              ASCV_MSGOUT_BEG,
-                             (ushort *) & sdtr_buf,
-                             (ushort) (sizeof (EXT_MSG) >> 1));
+                             (uchar *) &sdtr_buf,
+                             sizeof (EXT_MSG) >> 1);
         return ((sdtr_period_index << 4) | sdtr_offset);
     } else {
 
         sdtr_buf.req_ack_offset = 0;
-        AscMemWordCopyToLram(iop_base,
+        AscMemWordCopyPtrToLram(iop_base,
                              ASCV_MSGOUT_BEG,
-                             (ushort *) & sdtr_buf,
-                             (ushort) (sizeof (EXT_MSG) >> 1));
+                             (uchar *) &sdtr_buf,
+                             sizeof (EXT_MSG) >> 1);
         return (0);
     }
 }
@@ -13101,95 +11912,6 @@
 }
 
 STATIC int
-AscRiscHaltedAbortSRB(
-                         ASC_DVC_VAR *asc_dvc,
-                         ASC_VADDR srb_ptr
-)
-{
-    PortAddr            iop_base;
-    ushort              q_addr;
-    uchar               q_no;
-    ASC_QDONE_INFO      scsiq_buf;
-    ASC_QDONE_INFO *scsiq;
-    ASC_ISR_CALLBACK    asc_isr_callback;
-    int                 last_int_level;
-
-    iop_base = asc_dvc->iop_base;
-    asc_isr_callback = asc_dvc->isr_callback;
-    last_int_level = DvcEnterCritical();
-    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
-    for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
-         q_no++) {
-        q_addr = ASC_QNO_TO_QADDR(q_no);
-        scsiq->d2.srb_ptr = AscReadLramDWord(iop_base,
-                           (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR));
-        if (scsiq->d2.srb_ptr == srb_ptr) {
-            _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
-            if (((scsiq->q_status & QS_READY) != 0)
-                 && ((scsiq->q_status & QS_ABORTED) == 0)
-                 && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) {
-                scsiq->q_status |= QS_ABORTED;
-                scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
-                AscWriteLramDWord(iop_base,
-                            (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
-                                  0L);
-                AscWriteLramByte(iop_base,
-                            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-                                 scsiq->q_status);
-                (*asc_isr_callback) (asc_dvc, scsiq);
-                return (1);
-            }
-        }
-    }
-    DvcLeaveCritical(last_int_level);
-    return (0);
-}
-
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int
-AscRiscHaltedAbortTIX(
-                         ASC_DVC_VAR *asc_dvc,
-                         uchar target_ix
-)
-{
-    PortAddr            iop_base;
-    ushort              q_addr;
-    uchar               q_no;
-    ASC_QDONE_INFO      scsiq_buf;
-    ASC_QDONE_INFO *scsiq;
-    ASC_ISR_CALLBACK    asc_isr_callback;
-    int                 last_int_level;
-
-    iop_base = asc_dvc->iop_base;
-    asc_isr_callback = asc_dvc->isr_callback;
-    last_int_level = DvcEnterCritical();
-    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
-    for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
-         q_no++) {
-        q_addr = ASC_QNO_TO_QADDR(q_no);
-        _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
-        if (((scsiq->q_status & QS_READY) != 0) &&
-            ((scsiq->q_status & QS_ABORTED) == 0) &&
-            ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) {
-            if (scsiq->d2.target_ix == target_ix) {
-                scsiq->q_status |= QS_ABORTED;
-                scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
-                AscWriteLramDWord(iop_base,
-                            (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
-                                  0L);
-                AscWriteLramByte(iop_base,
-                            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-                                 scsiq->q_status);
-                (*asc_isr_callback) (asc_dvc, scsiq);
-            }
-        }
-    }
-    DvcLeaveCritical(last_int_level);
-    return (1);
-}
-#endif /* version >= v1.3.89 */
-
-STATIC int
 AscHostReqRiscHalt(
                       PortAddr iop_base
 )
@@ -13237,119 +11959,6 @@
     return (0);
 }
 
-STATIC int
-AscStartQueueExe(
-                    PortAddr iop_base
-)
-{
-    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
-        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
-    }
-    return (1);
-}
-
-STATIC int
-AscCleanUpBusyQueue(
-                       PortAddr iop_base
-)
-{
-    int                 count;
-    uchar               stop_code;
-
-    count = 0;
-    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
-        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-                         ASC_STOP_CLEAN_UP_BUSY_Q);
-        do {
-            stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-            if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0)
-                break;
-            DvcSleepMilliSecond(100);
-        } while (count++ < 20);
-    }
-    return (1);
-}
-
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int
-AscCleanUpDiscQueue(
-                       PortAddr iop_base
-)
-{
-    int                 count;
-    uchar               stop_code;
-
-    count = 0;
-    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
-        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-                         ASC_STOP_CLEAN_UP_DISC_Q);
-        do {
-            stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-            if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0)
-                break;
-            DvcSleepMilliSecond(100);
-        } while (count++ < 20);
-    }
-    return (1);
-}
-#endif /* version >= v1.3.89 */
-
-STATIC int
-AscWaitTixISRDone(
-                     ASC_DVC_VAR *asc_dvc,
-                     uchar target_ix
-)
-{
-    uchar               cur_req;
-    uchar               tid_no;
-    int                 i = 0;
-
-    tid_no = ASC_TIX_TO_TID(target_ix);
-    while (i++ < 10) {
-        if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) {
-            break;
-        }
-        DvcSleepMilliSecond(1000L);
-        if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) {
-            break;
-        }
-    }
-    return (1);
-}
-
-STATIC int
-AscWaitISRDone(
-                  ASC_DVC_VAR *asc_dvc
-)
-{
-    int                 tid;
-
-    for (tid = 0; tid <= ASC_MAX_TID; tid++) {
-        AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid));
-    }
-    return (1);
-}
-
-STATIC ASC_PADDR
-AscGetOnePhyAddr(
-                    ASC_DVC_VAR *asc_dvc,
-                    uchar * buf_addr,
-                    ASC_DCNT buf_size
-)
-{
-    ASC_MIN_SG_HEAD     sg_head;
-
-    sg_head.entry_cnt = ASC_MIN_SG_LIST;
-    if (DvcGetSGList(asc_dvc, (uchar *) buf_addr,
-                  buf_size, (ASC_SG_HEAD *) &sg_head) != buf_size) {
-        return (0L);
-    }
-    if (sg_head.entry_cnt > 1) {
-        return (0L);
-    }
-    return ((ASC_PADDR) sg_head.sg_list[0].addr);
-}
-
 STATIC void
 DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
 {
@@ -13362,6 +11971,7 @@
     udelay((nano_sec + 999)/1000);
 }
 
+#ifdef CONFIG_ISA
 ASC_INITFUNC(
 STATIC ASC_DCNT,
 AscGetEisaProductID(
@@ -13420,6 +12030,7 @@
     }
     return (0);
 }
+#endif /* CONFIG_ISA */
 
 STATIC int
 AscStartChip(
@@ -13593,6 +12204,7 @@
     return (ASC_MAX_PCI_DMA_COUNT);
 }
 
+#ifdef CONFIG_ISA
 ASC_INITFUNC(
 STATIC ushort,
 AscGetIsaDmaChannel(
@@ -13664,6 +12276,7 @@
     AscSetBank(iop_base, 0);
     return (speed_value);
 }
+#endif /* CONFIG_ISA */
 
 ASC_INITFUNC(
 STATIC ushort,
@@ -13841,19 +12454,19 @@
         asc_dvc->cfg->chip_scsi_id) {
         asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
     }
+#ifdef CONFIG_ISA
     if (asc_dvc->bus_type & ASC_IS_ISA) {
         AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
         AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
     }
+#endif /* CONFIG_ISA */
     return (warn_code);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort
 AscInitAsc1000Driver(
                         ASC_DVC_VAR *asc_dvc
 )
-)
 {
     ushort              warn_code;
     PortAddr            iop_base;
@@ -13877,7 +12490,9 @@
     warn_code |= AscInitLram(asc_dvc);
     if (asc_dvc->err_code != 0)
         return (UW_ERR);
-    if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf,
+    ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
+        (ulong) _asc_mcode_chksum);
+    if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
                          _asc_mcode_size) != _asc_mcode_chksum) {
         asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
         return (warn_code);
@@ -13912,7 +12527,7 @@
     asc_dvc->bug_fix_cntl = 0;
     asc_dvc->pci_fix_asyn_xfer = 0;
     asc_dvc->pci_fix_asyn_xfer_always = 0;
-    asc_dvc->init_state = 0;
+    /* asc_dvc->init_state initalized in AscInitGetConfig(). */
     asc_dvc->sdtr_done = 0;
     asc_dvc->cur_total_qng = 0;
     asc_dvc->is_in_int = 0;
@@ -13988,9 +12603,11 @@
         AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
         asc_dvc->bus_type = ASC_IS_ISAPNP;
     }
+#ifdef CONFIG_ISA
     if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
         asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
     }
+#endif /* CONFIG_ISA */
     for (i = 0; i <= ASC_MAX_TID; i++) {
         asc_dvc->cur_dvc_qng[i] = 0;
         asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
@@ -14037,7 +12654,7 @@
         asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
         return (warn_code);
     }
-    eep_config = (ASCEEP_CONFIG *) & eep_config_buf;
+    eep_config = (ASCEEP_CONFIG *) &eep_config_buf;
     cfg_msw = AscGetChipCfgMsw(iop_base);
     cfg_lsw = AscGetChipCfgLsw(iop_base);
     if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
@@ -14046,6 +12663,7 @@
         AscSetChipCfgMsw(iop_base, cfg_msw);
     }
     chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+    ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
     if (chksum == 0) {
         chksum = 0xaa55;
     }
@@ -14064,10 +12682,14 @@
     }
     eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
     eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+    ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
+        eep_config->chksum);
     if (chksum != eep_config->chksum) {
             if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
                     ASC_CHIP_VER_PCI_ULTRA_3050 )
             {
+                ASC_DBG(1,
+"AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
                 eep_config->init_sdtr = 0xFF;
                 eep_config->disc_enable = 0xFF;
                 eep_config->start_motor = 0xFF;
@@ -14075,7 +12697,7 @@
                 eep_config->max_total_qng = 0xF0;
                 eep_config->max_tag_qng = 0x20;
                 eep_config->cntl = 0xBFFF;
-                eep_config->chip_scsi_id = 7;
+                ASC_EEP_SET_CHIP_ID(eep_config, 7);
                 eep_config->no_scam = 0;
                 eep_config->adapter_info[0] = 0;
                 eep_config->adapter_info[1] = 0;
@@ -14085,6 +12707,8 @@
                 /* Indicate EEPROM-less board. */
                 eep_config->adapter_info[5] = 0xBB;
             } else {
+                ASC_PRINT(
+"AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
                 write_eep = 1;
                 warn_code |= ASC_WARN_EEPROM_CHKSUM;
             }
@@ -14092,7 +12716,7 @@
     asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
     asc_dvc->cfg->disc_enable = eep_config->disc_enable;
     asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
-    asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
+    asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
     asc_dvc->start_motor = eep_config->start_motor;
     asc_dvc->dvc_cntl = eep_config->cntl;
     asc_dvc->no_scam = eep_config->no_scam;
@@ -14136,8 +12760,8 @@
     if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
         asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
     }
-    eep_config->chip_scsi_id &= ASC_MAX_TID;
-    asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
+    ASC_EEP_SET_CHIP_ID(eep_config, ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+    asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
     if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
         !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
         asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
@@ -14152,22 +12776,27 @@
     }
     eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
     if (write_eep) {
-        (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+        if ((i = AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type)) !=
+             0) {
+                ASC_PRINT1(
+"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
+        } else {
+                ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM.");
+        }
     }
     return (warn_code);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort
 AscInitMicroCodeVar(
                        ASC_DVC_VAR *asc_dvc
 )
-)
 {
     int                 i;
     ushort              warn_code;
     PortAddr            iop_base;
     ASC_PADDR           phy_addr;
+    ASC_DCNT            phy_size;
 
     iop_base = asc_dvc->iop_base;
     warn_code = 0;
@@ -14176,26 +12805,27 @@
                                 asc_dvc->cfg->sdtr_period_offset[i]
 );
     }
+
     AscInitQLinkVar(asc_dvc);
     AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
                      asc_dvc->cfg->disc_enable);
     AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
                      ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
-    if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
-                                 (uchar *) asc_dvc->cfg->overrun_buf,
-                                     ASC_OVERRUN_BSIZE)) == 0L) {
-        asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR;
-    } else {
-        /* Align on an 8 byte boundary. */
-        phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
-        AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr);
-        AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D,
-                          ASC_OVERRUN_BSIZE - 8);
-    }
-    asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base,
-                                               (ushort) ASCV_MC_DATE_W);
-    asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base,
-                                                  (ushort) ASCV_MC_VER_W);
+
+    /* Align overrun buffer on an 8 byte boundary. */
+    phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
+    phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
+    AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+        (uchar *) &phy_addr, 1);
+    phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
+    AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+        (uchar *) &phy_size, 1);
+
+    asc_dvc->cfg->mcode_date =
+        AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W);
+    asc_dvc->cfg->mcode_version =
+        AscReadLramWord(iop_base, (ushort) ASCV_MC_VER_W);
+
     AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
     if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
         asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
@@ -14205,6 +12835,7 @@
         asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
         return (warn_code);
     }
+
     return (warn_code);
 }
 
@@ -14368,16 +12999,15 @@
     ushort              *wbuf;
     int                 cfg_beg;
     int                 cfg_end;
+    int                 uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
     int                 s_addr;
-    int                 isa_pnp_wsize;
 
     wbuf = (ushort *) cfg_buf;
     sum = 0;
-    isa_pnp_wsize = 0;
-    for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) {
-        wval = AscReadEEPWord(iop_base, (uchar) s_addr);
-        sum += wval;
-        *wbuf = wval;
+    /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+        *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
+        sum += *wbuf;
     }
     if (bus_type & ASC_IS_VL) {
         cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
@@ -14386,12 +13016,24 @@
         cfg_beg = ASC_EEP_DVC_CFG_BEG;
         cfg_end = ASC_EEP_MAX_DVC_ADDR;
     }
-    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
-         s_addr++, wbuf++) {
-        wval = AscReadEEPWord(iop_base, (uchar) s_addr);
-        sum += wval;
-        *wbuf = wval;
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+        wval = AscReadEEPWord( iop_base, ( uchar )s_addr ) ;
+        if (s_addr <= uchar_end_in_config) {
+            /*
+             * Swap all char fields - must unswap bytes already swapped
+             * by AscReadEEPWord().
+             */
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            /* Don't swap word field at the end - cntl field. */
+            *wbuf = wval;
+        }
+        sum += wval; /* Checksum treats all EEPROM data as words. */
     }
+    /*
+     * Read the checksum word which will be compared against 'sum'
+     * by the caller. Word field already swapped.
+     */
     *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
     return (sum);
 }
@@ -14405,15 +13047,19 @@
 )
 {
     int                 n_error;
-    ushort      *wbuf;
+    ushort              *wbuf;
+    ushort              word;
     ushort              sum;
     int                 s_addr;
     int                 cfg_beg;
     int                 cfg_end;
+    int                 uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+
 
     wbuf = (ushort *) cfg_buf;
     n_error = 0;
     sum = 0;
+    /* Write two config words; AscWriteEEPWord() will swap bytes. */
     for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
         sum += *wbuf;
         if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
@@ -14427,29 +13073,66 @@
         cfg_beg = ASC_EEP_DVC_CFG_BEG;
         cfg_end = ASC_EEP_MAX_DVC_ADDR;
     }
-    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
-         s_addr++, wbuf++) {
-        sum += *wbuf;
-        if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
-            n_error++;
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+        if (s_addr <= uchar_end_in_config) {
+            /*
+             * This is a char field. Swap char fields before they are
+             * swapped again by AscWriteEEPWord().
+             */
+            word = cpu_to_le16(*wbuf);
+            if (word != AscWriteEEPWord( iop_base, (uchar) s_addr, word)) {
+                n_error++;
+            }
+        } else {
+            /* Don't swap word field at the end - cntl field. */
+            if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+                n_error++;
+            }
         }
+        sum += *wbuf; /* Checksum calculated from word values. */
     }
+    /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
     *wbuf = sum;
     if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
         n_error++;
     }
+
+    /* Read EEPROM back again. */
     wbuf = (ushort *) cfg_buf;
+    /*
+     * Read two config words; Byte-swapping done by AscReadEEPWord().
+     */
     for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
         if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
             n_error++;
         }
     }
-    for (s_addr = cfg_beg; s_addr <= cfg_end;
-         s_addr++, wbuf++) {
-        if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
+    if (bus_type & ASC_IS_VL) {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+    } else {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR;
+    }
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+        if (s_addr <= uchar_end_in_config) {
+            /*
+             * Swap all char fields. Must unswap bytes already swapped
+             * by AscReadEEPWord().
+             */
+            word = le16_to_cpu(AscReadEEPWord(iop_base, (uchar) s_addr));
+        } else {
+            /* Don't swap word field at the end - cntl field. */
+            word = AscReadEEPWord(iop_base, (uchar) s_addr);
+        }
+        if (*wbuf != word) {
             n_error++;
         }
     }
+    /* Read checksum; Byte swapping not needed. */
+    if (AscReadEEPWord(iop_base, (uchar) s_addr) != sum) {
+        n_error++;
+    }
     return (n_error);
 }
 
@@ -14486,7 +13169,7 @@
     uchar                       dvc_type;
     ASC_SCSI_BIT_ID_TYPE        tid_bits;
 
-    dvc_type = inq->byte0.peri_dvc_type;
+    dvc_type = ASC_INQ_DVC_TYPE(inq);
     tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
 
     if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
@@ -14546,11 +13229,12 @@
     asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
     asc_dvc->use_tagged_qng &= ~tid_bit;
 
-    if (inq->byte3.rsp_data_fmt >= 2 || inq->byte2.ansi_apr_ver >= 2) {
-        if ((asc_dvc->cfg->sdtr_enable & tid_bit) && inq->byte7.Sync) {
+    if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
+        if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
             asc_dvc->init_sdtr |= tid_bit;
         }
-        if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) && inq->byte7.CmdQue) {
+        if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
+             ASC_INQ_CMD_QUEUE(inq)) {
             if (AscTagQueuingSafe(inq)) {
                 asc_dvc->use_tagged_qng |= tid_bit;
                 asc_dvc->cfg->can_tagged_qng |= tid_bit;
@@ -14615,7 +13299,6 @@
     }
     return (byte_data);
 }
-
 STATIC ushort
 AscReadLramWord(
                    PortAddr iop_base,
@@ -14629,6 +13312,7 @@
     return (word_data);
 }
 
+#if CC_VERY_LONG_SG_LIST
 STATIC ASC_DCNT
 AscReadLramDWord(
                     PortAddr iop_base,
@@ -14644,6 +13328,7 @@
     dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
     return (dword_data);
 }
+#endif /* CC_VERY_LONG_SG_LIST */
 
 STATIC void
 AscWriteLramWord(
@@ -14658,30 +13343,13 @@
 }
 
 STATIC void
-AscWriteLramDWord(
-                     PortAddr iop_base,
-                     ushort addr,
-                     ASC_DCNT dword_val
+AscWriteLramByte(
+                    PortAddr iop_base,
+                    ushort addr,
+                    uchar byte_val
 )
 {
-    ushort              word_val;
-
-    AscSetChipLramAddr(iop_base, addr);
-    word_val = (ushort) dword_val;
-    AscSetChipLramData(iop_base, word_val);
-    word_val = (ushort) (dword_val >> 16);
-    AscSetChipLramData(iop_base, word_val);
-    return;
-}
-
-STATIC void
-AscWriteLramByte(
-                    PortAddr iop_base,
-                    ushort addr,
-                    uchar byte_val
-)
-{
-    ushort              word_data;
+    ushort              word_data;
 
     if (isodd_word(addr)) {
         addr--;
@@ -14697,42 +13365,87 @@
     return;
 }
 
+/*
+ * Copy 2 bytes to LRAM.
+ *
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when written to LRAM.
+ */
 STATIC void
-AscMemWordCopyToLram(
+AscMemWordCopyPtrToLram(
                         PortAddr iop_base,
                         ushort s_addr,
-                        ushort * s_buffer,
+                        uchar *s_buffer,
                         int words
 )
 {
+    int    i;
+
     AscSetChipLramAddr(iop_base, s_addr);
-    DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words);
+    for (i = 0; i < 2 * words; i += 2) {
+        /*
+         * On a little-endian system the second argument below
+         * produces a little-endian ushort which is written to
+         * LRAM in little-endian order. On a big-endian system
+         * the second argument produces a big-endian ushort which
+         * is "transparently" byte-swapped by outpw() and written
+         * in little-endian order to LRAM.
+         */
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]);
+    }
     return;
 }
 
+/*
+ * Copy 4 bytes to LRAM.
+ *
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when writen to LRAM.
+ */
 STATIC void
-AscMemDWordCopyToLram(
+AscMemDWordCopyPtrToLram(
                          PortAddr iop_base,
                          ushort s_addr,
-                         ASC_DCNT *s_buffer,
+                         uchar *s_buffer,
                          int dwords
 )
 {
+    int       i;
+
     AscSetChipLramAddr(iop_base, s_addr);
-    DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords);
+    for (i = 0; i < 4 * dwords; i += 4) {
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
+    }
     return;
 }
 
+/*
+ * Copy 2 bytes from LRAM.
+ *
+ * The source data is assumed to be in little-endian order in LRAM
+ * and is maintained in little-endian order when written to memory.
+ */
 STATIC void
-AscMemWordCopyFromLram(
+AscMemWordCopyPtrFromLram(
                           PortAddr iop_base,
                           ushort s_addr,
-                          ushort * d_buffer,
+                          uchar *d_buffer,
                           int words
 )
 {
+    int i;
+    ushort word;
+
     AscSetChipLramAddr(iop_base, s_addr);
-    DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words);
+    for (i = 0; i < 2 * words; i += 2) {
+        word = inpw(iop_base + IOP_RAM_DATA);
+        d_buffer[i] = word & 0xff;
+        d_buffer[i + 1] = (word >> 8) & 0xff;
+    }
     return;
 }
 
@@ -14776,676 +13489,1078 @@
  */
 
 /* a_mcode.h */
+
+/* Microcode buffer is kept after initialization for error recovery. */
 STATIC unsigned char _adv_asc3550_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x18,  0xe4,
-  0x00,  0xf6,  0x01,  0xf6,  0x18,  0x80,  0x48,  0x19,  0x02,  0x00,  0xff,  0xff,  0x03,  0xf6,  0x00,  0xfa,
-  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0x3a,  0x0e,  0x00,  0xea,  0x01,  0xe6,
-  0x55,  0xf0,  0x03,  0x00,  0x08,  0x00,  0x18,  0xf4,  0x3e,  0x01,  0x3e,  0x57,  0x04,  0x00,  0x85,  0xf0,
-  0x00,  0xe6,  0x00,  0xec,  0x1e,  0xf0,  0x32,  0xf0,  0x34,  0x19,  0x86,  0xf0,  0xd0,  0x01,  0xd5,  0xf0,
-  0xde,  0x0c,  0x98,  0x57,  0xbc,  0x00,  0x0c,  0x1c,  0x0e,  0x13,  0x38,  0x54,  0xb1,  0xf0,  0xb4,  0x00,
-  0x01,  0xfc,  0x03,  0xfc,  0xd8,  0x0c,  0x00,  0x57,  0x01,  0xf0,  0x02,  0x13,  0x03,  0xe6,  0x10,  0x00,
-  0x18,  0x40,  0x3e,  0x1c,  0x6c,  0x01,  0x6e,  0x01,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x48,  0x02,  0x80,
-  0x08,  0x12,  0x30,  0xe4,  0x3c,  0x00,  0x4e,  0x01,  0x64,  0x12,  0x80,  0x00,  0x9c,  0x15,  0xbb,  0x00,
-  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x04,  0x12,  0x9e,  0x0f,  0xb6,  0x00,  0xb9,  0x54,  0xe2,  0x0f,
-  0x00,  0x80,  0x06,  0xf7,  0x10,  0x44,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x3c,  0x56,
-  0x3e,  0x00,  0x4b,  0xe4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,
-  0x76,  0x01,  0x78,  0x01,  0xe2,  0x0c,  0x00,  0x01,  0x02,  0xee,  0x02,  0xfc,  0x03,  0x58,  0x03,  0xf7,
-  0x04,  0x80,  0x05,  0xfc,  0x08,  0x44,  0x09,  0xf0,  0x0f,  0x00,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,
-  0x40,  0x00,  0x40,  0x15,  0x4b,  0xf4,  0x4e,  0x1c,  0x5b,  0xf0,  0x5d,  0xf0,  0xaa,  0x00,  0xbb,  0x55,
-  0xbe,  0x00,  0xc0,  0x00,  0xe0,  0x08,  0xe0,  0x14,  0xec,  0x0f,  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,
-  0x05,  0x00,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x08,  0x13,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,
-  0x19,  0x00,  0x20,  0x00,  0x2a,  0x01,  0x30,  0x0e,  0x32,  0x1c,  0x36,  0x00,  0x45,  0x5a,  0x59,  0xf0,
-  0x62,  0x0a,  0x69,  0x08,  0x72,  0x0b,  0x83,  0x59,  0xb8,  0xf0,  0xbd,  0x56,  0xcc,  0x12,  0xec,  0x17,
-  0xee,  0x0f,  0xf0,  0x00,  0xf8,  0x17,  0x01,  0x48,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0x10,  0x04,  0xea,
-  0x04,  0xf6,  0x04,  0xfc,  0x05,  0x80,  0x05,  0xe6,  0x06,  0x00,  0x06,  0x12,  0x0a,  0x10,  0x0b,  0xf0,
-  0x0c,  0x10,  0x0c,  0xf0,  0x12,  0x10,  0x26,  0x0e,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,
-  0x40,  0x5c,  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x83,  0x55,  0x83,  0x5a,  0x8c,  0x14,
-  0x8e,  0x0a,  0x90,  0x14,  0x91,  0x44,  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xce,  0x45,
-  0xd0,  0x00,  0xd8,  0x16,  0xe1,  0x00,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
-  0x03,  0xa1,  0x04,  0x13,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
-  0x0c,  0x04,  0x0c,  0x12,  0x0c,  0x90,  0x10,  0x10,  0x10,  0x13,  0x12,  0x1c,  0x17,  0x00,  0x19,  0xe4,
-  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
-  0x26,  0x01,  0x2a,  0x12,  0x30,  0xe7,  0x34,  0x1c,  0x36,  0x1c,  0x38,  0x12,  0x41,  0x58,  0x43,  0x48,
-  0x44,  0x55,  0x46,  0x1c,  0x4c,  0x0e,  0x4e,  0xe4,  0x52,  0x14,  0x5c,  0xf0,  0x72,  0x02,  0x74,  0x03,
-  0x77,  0x57,  0x89,  0x48,  0x8e,  0x90,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0x9e,  0x00,  0xa8,  0x00,
-  0xb9,  0x00,  0xba,  0x06,  0xbc,  0x12,  0xbf,  0x57,  0xc0,  0x01,  0xfe,  0x9c,  0xf0,  0x26,  0x02,  0xfe,
-  0x00,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc2,  0x01,  0xfe,  0x56,  0x19,  0x00,  0xfc,  0xfe,  0x80,
-  0x01,  0xff,  0x03,  0x00,  0x00,  0xfe,  0x6a,  0x13,  0xfe,  0x05,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,
-  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,
-  0xff,  0x10,  0xff,  0xff,  0xff,  0x0f,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,
-  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfc,  0x2b,  0x51,  0x0c,  0x01,  0xfe,  0xea,  0x0e,  0xfe,  0x04,  0xf7,
-  0xfc,  0x51,  0x0c,  0x1d,  0x2b,  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x20,  0xf0,  0xd0,  0x04,
-  0x56,  0x4b,  0x02,  0xfe,  0x1c,  0x0d,  0x01,  0xfe,  0x7c,  0x0d,  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x04,
-  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x4e,  0x12,  0xfe,  0xa6,  0x00,
-  0xc5,  0xfe,  0x48,  0xf0,  0xfe,  0x7c,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x96,  0x02,  0xfe,  0x4a,  0xf0,
-  0xfe,  0xb4,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x46,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x4c,  0x02,  0xfe,
-  0x43,  0xf0,  0xfe,  0x3a,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x42,
-  0x02,  0x09,  0x0c,  0x9e,  0x09,  0x06,  0x12,  0xbb,  0x02,  0x26,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,
-  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0xfe,  0x4c,  0x17,
-  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xf7,  0x0e,  0x78,  0x01,  0xab,  0x02,  0x26,  0x17,  0x55,  0x4a,
-  0xbd,  0x01,  0xfe,  0x60,  0x0f,  0x0e,  0x78,  0x01,  0x8b,  0xfe,  0xbd,  0x10,  0x0e,  0x78,  0x01,  0x8b,
-  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x09,  0x06,  0x12,  0xbb,  0x2b,  0x22,  0x26,
-  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0x27,  0xfe,  0x8a,  0x02,  0xfe,  0x5a,  0x1c,  0xd5,  0xfe,  0x14,
-  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4a,  0xbd,  0x01,  0xfe,  0x50,  0x0f,  0x09,  0x06,  0x12,  0xbb,  0x02,
-  0xfe,  0xc2,  0x01,  0x21,  0x2a,  0x05,  0x10,  0x35,  0xfe,  0x69,  0x10,  0x09,  0x06,  0x12,  0xbb,  0xfe,
-  0x04,  0xec,  0x2a,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x01,  0x46,  0x7f,  0xfe,  0x05,  0xf6,  0xf7,  0x01,
-  0xfe,  0x76,  0x16,  0x0a,  0x41,  0x89,  0x38,  0x11,  0x47,  0x1d,  0xca,  0x08,  0x1c,  0x09,  0x43,  0x01,
-  0x71,  0x02,  0x26,  0x0e,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x2c,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x7b,
-  0xfe,  0x28,  0x10,  0x0e,  0xc0,  0x01,  0x15,  0xe6,  0x0e,  0x79,  0x01,  0x15,  0xfe,  0x49,  0x54,  0x74,
-  0xfe,  0x12,  0x03,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x71,  0x02,  0x26,  0x2b,  0x7f,  0xfe,  0x02,  0xe8,
-  0x2f,  0xfb,  0xfe,  0x9e,  0x43,  0xf0,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xd0,  0xfe,  0x40,  0x1c,
-  0x22,  0xef,  0xfe,  0x26,  0xf0,  0xfe,  0x70,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x5e,  0x03,  0xfe,  0x11,
-  0xf0,  0xd0,  0xfe,  0x0e,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x7e,  0x03,  0xe9,  0x13,  0xfe,  0x11,  0x00,
-  0x02,  0x62,  0x2b,  0xfe,  0x48,  0x1c,  0xe9,  0x22,  0xef,  0x34,  0xef,  0xfe,  0x82,  0xf0,  0xfe,  0x84,
-  0x03,  0x2d,  0x21,  0xbe,  0x6a,  0x16,  0xbe,  0x0e,  0x79,  0x01,  0x15,  0x6a,  0x7d,  0x08,  0x1c,  0x09,
-  0x43,  0x01,  0x46,  0x11,  0x3d,  0x08,  0x3d,  0x09,  0x99,  0x01,  0x71,  0xf5,  0x11,  0xfe,  0xe4,  0x00,
-  0x2e,  0xfe,  0xca,  0x03,  0x22,  0x32,  0x1f,  0xfe,  0xda,  0x03,  0x01,  0x4c,  0xcb,  0xfe,  0xea,  0x03,
-  0x6b,  0x92,  0xcf,  0xfe,  0xaa,  0x06,  0x02,  0x28,  0x04,  0x78,  0x29,  0x18,  0xfe,  0x1c,  0x05,  0x17,
-  0x85,  0x01,  0x44,  0x01,  0x97,  0x01,  0x9a,  0x34,  0xfe,  0x5c,  0x02,  0x02,  0xee,  0xe9,  0x2b,  0x51,
-  0x19,  0xfe,  0x67,  0x1b,  0xfb,  0xf0,  0xfe,  0x48,  0x1c,  0x8c,  0x01,  0xfa,  0xac,  0xfe,  0x96,  0xf0,
-  0xfe,  0x24,  0x04,  0x2e,  0xfe,  0x28,  0x04,  0x34,  0x26,  0x0e,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x18,
-  0xfe,  0x08,  0x05,  0x3e,  0x90,  0x9f,  0x2f,  0x82,  0x6e,  0x22,  0x32,  0x1f,  0x28,  0x04,  0x78,  0x29,
-  0xfe,  0x10,  0x12,  0x17,  0x85,  0x01,  0x44,  0x34,  0xfe,  0x5c,  0x02,  0x02,  0xee,  0x31,  0xfe,  0xa0,
-  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,  0x12,  0x0a,  0x07,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x24,  0x91,
-  0x01,  0x0b,  0x82,  0x6e,  0x1f,  0xfe,  0xd8,  0x04,  0x23,  0x24,  0x91,  0x01,  0x0b,  0x1f,  0x28,  0x23,
-  0x24,  0xb3,  0xfe,  0x4c,  0x44,  0xfe,  0x32,  0x12,  0x57,  0xfe,  0x44,  0x48,  0x08,  0xd6,  0xfe,  0x4c,
-  0x54,  0x74,  0xfe,  0x08,  0x05,  0x7f,  0x9f,  0x2f,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,
-  0x13,  0x3f,  0x05,  0xfe,  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x07,  0x06,  0xe5,  0xfe,  0x06,  0x10,
-  0x23,  0x24,  0xb3,  0x0a,  0x07,  0x37,  0xda,  0x17,  0xa4,  0x0a,  0x07,  0x06,  0x4b,  0x17,  0xfe,  0x0d,
-  0x00,  0x01,  0x44,  0x34,  0xfe,  0xc0,  0x0c,  0x02,  0x28,  0x39,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,
-  0x90,  0xb0,  0x03,  0x17,  0xa4,  0x01,  0x44,  0x34,  0x26,  0x22,  0x26,  0x02,  0xfe,  0x10,  0x05,  0xfe,
-  0x42,  0x5b,  0x51,  0x19,  0xfe,  0x46,  0x59,  0xfb,  0xf0,  0x17,  0x45,  0xfe,  0x07,  0x80,  0xfe,  0x31,
-  0x44,  0x0a,  0x07,  0x0c,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,  0x05,  0x19,  0xfe,  0x70,  0x12,  0x6d,
-  0x07,  0x06,  0xfe,  0x60,  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x29,  0x18,  0xfe,  0xa8,  0x05,  0xfe,  0x31,
-  0xe4,  0x70,  0x6d,  0x07,  0x0c,  0xfe,  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x29,  0xfe,  0x42,  0x12,
-  0x5a,  0x2e,  0xfe,  0x68,  0x05,  0x22,  0x32,  0xf1,  0x01,  0x0b,  0x25,  0xfe,  0xc0,  0x05,  0x11,  0xfe,
-  0xe3,  0x00,  0x2d,  0x6d,  0xfe,  0x4a,  0xf0,  0xfe,  0x92,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x8c,  0x05,
-  0xa8,  0x20,  0xfe,  0x21,  0x00,  0xa6,  0x20,  0xfe,  0x22,  0x00,  0x9e,  0x20,  0x89,  0xfe,  0x09,  0x48,
-  0x01,  0x0b,  0x25,  0xfe,  0xc0,  0x05,  0xfe,  0xe2,  0x08,  0x6d,  0x07,  0xd9,  0x4b,  0x01,  0x96,  0x20,
-  0x06,  0x16,  0xe0,  0x4a,  0xfe,  0x27,  0x01,  0x0a,  0x07,  0x37,  0xe1,  0x4e,  0x01,  0xb9,  0x17,  0xa4,
-  0x0a,  0x07,  0x06,  0x4b,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x44,  0x01,  0x97,  0x01,  0x9a,  0x34,  0xfe,
-  0xc0,  0x0c,  0x02,  0x28,  0x04,  0xfe,  0x9c,  0x00,  0x29,  0xfe,  0x3e,  0x12,  0x04,  0x53,  0x29,  0xfe,
-  0x36,  0x13,  0x4e,  0x01,  0xb9,  0x25,  0xfe,  0x38,  0x06,  0x0e,  0x06,  0x6d,  0x07,  0x1a,  0xfe,  0x02,
-  0x12,  0x77,  0x01,  0xfe,  0x26,  0x14,  0x1f,  0xfe,  0x2e,  0x06,  0x11,  0xc2,  0x01,  0x4c,  0x11,  0xfe,
-  0xe5,  0x00,  0x04,  0x53,  0xbc,  0x0f,  0x53,  0x04,  0xf6,  0x29,  0xfe,  0x62,  0x12,  0x04,  0x4d,  0x29,
-  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x9e,  0x18,  0x01,  0xfe,  0xf0,  0x18,  0xe7,  0xa3,  0x1a,  0x08,  0x63,
-  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0x1b,  0x50,  0xc9,  0xa3,  0x6c,  0x4e,  0x01,  0xb9,  0x25,  0xfe,
-  0xa2,  0x06,  0x6d,  0x07,  0x1e,  0xa5,  0x95,  0x0e,  0x55,  0x01,  0xfe,  0x54,  0x14,  0x1f,  0xfe,  0x98,
-  0x06,  0x11,  0xc2,  0x01,  0x4c,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x4d,  0xbc,  0x0f,  0x4d,  0x09,  0x06,
-  0x01,  0xb9,  0xf5,  0x73,  0x8c,  0x01,  0xfa,  0xac,  0x11,  0xfe,  0xe2,  0x00,  0x2e,  0xf9,  0x22,  0x32,
-  0xcf,  0xfe,  0xd6,  0x06,  0x81,  0xfe,  0x74,  0x07,  0xcb,  0xfe,  0x7c,  0x07,  0x6b,  0x92,  0x02,  0x28,
-  0x0a,  0x07,  0x0c,  0xfe,  0x2e,  0x12,  0x14,  0x19,  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x00,
-  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0xfe,  0x99,  0xa4,  0x01,  0x0b,  0x14,  0x00,  0x02,  0xfe,  0x4c,
-  0x08,  0x68,  0x07,  0x1e,  0xe5,  0x0a,  0x07,  0x1e,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,
-  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x06,  0x01,
-  0x0b,  0x14,  0x00,  0x02,  0xfe,  0x2a,  0x0b,  0x77,  0xfe,  0x9a,  0x81,  0x67,  0x89,  0xfe,  0x09,  0x6f,
-  0xfe,  0x93,  0x45,  0x18,  0xfe,  0x84,  0x07,  0x2e,  0xfe,  0x5c,  0x07,  0x22,  0x32,  0xcf,  0xfe,  0x54,
-  0x07,  0x6b,  0x92,  0x81,  0xfe,  0x74,  0x07,  0x02,  0x28,  0x01,  0x4c,  0x02,  0xf9,  0x14,  0x1a,  0x02,
-  0xf9,  0xfe,  0x9c,  0xf7,  0xfe,  0xec,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x75,  0xfe,  0xd2,
-  0x07,  0x0f,  0x5d,  0x12,  0x5e,  0x0a,  0x41,  0x70,  0x38,  0x01,  0xfe,  0x34,  0x18,  0x05,  0x10,  0x83,
-  0xfe,  0x83,  0xe7,  0x88,  0xa6,  0xfe,  0x03,  0x40,  0x0a,  0x41,  0x45,  0x38,  0x01,  0xc1,  0xaf,  0xfe,
-  0x1f,  0x40,  0x16,  0x61,  0x01,  0xfe,  0xde,  0x12,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x34,
-  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0f,  0x5b,  0x12,  0x5c,  0xd2,  0xf2,
-  0x0f,  0x3a,  0x12,  0x3b,  0xfe,  0x60,  0x10,  0x0a,  0x07,  0x70,  0xe1,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
-  0x90,  0x0f,  0x5d,  0x12,  0x5e,  0x0a,  0x07,  0x45,  0xc9,  0x01,  0xc1,  0xfe,  0x1f,  0x80,  0x16,  0x61,
-  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0f,  0x5f,  0x12,  0x60,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
-  0x0f,  0x5b,  0x12,  0x5c,  0xa2,  0x07,  0x45,  0x2c,  0xd2,  0xf2,  0x0f,  0x3a,  0x12,  0x3b,  0xa8,  0xfe,
-  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0f,  0x3a,  0x12,  0x3b,  0x0f,  0x42,  0x12,  0x58,  0x0a,  0x41,  0x1a,
-  0x38,  0x2b,  0x08,  0x80,  0x2e,  0xfe,  0x62,  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x76,  0x08,  0x9b,  0x18,
-  0x32,  0x2b,  0x52,  0xfe,  0xed,  0x10,  0xa7,  0xfe,  0x9a,  0x08,  0xa9,  0xfe,  0xb6,  0x08,  0x81,  0xfe,
-  0x8e,  0x08,  0xcb,  0xfe,  0x94,  0x08,  0x6b,  0x92,  0x02,  0x28,  0x01,  0x4c,  0xfe,  0xc9,  0x10,  0x14,
-  0x1a,  0xfe,  0xc9,  0x10,  0x68,  0x07,  0x06,  0xfe,  0x10,  0x12,  0x68,  0x07,  0x0c,  0x40,  0x0a,  0x07,
-  0x0c,  0xfe,  0x7e,  0x12,  0xfe,  0x2e,  0x1c,  0xaa,  0x68,  0x07,  0x06,  0x40,  0x68,  0x07,  0x0c,  0xfe,
-  0x6a,  0x12,  0xfe,  0x2c,  0x1c,  0xa2,  0x07,  0x45,  0xd4,  0xa2,  0x41,  0x45,  0xfe,  0x05,  0x40,  0xd2,
-  0xf2,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0xfe,  0xaa,  0xf0,  0xfe,  0x4e,  0x09,  0xfe,  0xac,  0xf0,
-  0xfe,  0xee,  0x08,  0xfe,  0x92,  0x10,  0xe3,  0xfe,  0xf3,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0xfa,  0x08,
-  0x02,  0xfe,  0x5c,  0x0a,  0xe4,  0xfe,  0xe7,  0x10,  0xfe,  0x2b,  0xf0,  0xb8,  0xfe,  0x6b,  0x18,  0x1b,
-  0xfe,  0x00,  0xfe,  0xda,  0xc5,  0xfe,  0xd2,  0xf0,  0xb8,  0xfe,  0x76,  0x18,  0x1b,  0x19,  0x18,  0xb8,
-  0x04,  0xdf,  0x1b,  0x06,  0x18,  0xb8,  0xa7,  0x7a,  0xa9,  0x7a,  0xe3,  0xe4,  0xfe,  0xb1,  0x10,  0x8c,
-  0x5a,  0x39,  0x17,  0xa4,  0x01,  0x44,  0x13,  0xfe,  0x35,  0x00,  0x34,  0x62,  0x13,  0x8d,  0x02,  0x62,
-  0xfe,  0x74,  0x18,  0x1b,  0xfe,  0x00,  0xf8,  0x18,  0x7a,  0x51,  0x1e,  0x01,  0xfe,  0x7c,  0x0d,  0xd1,
-  0x08,  0x1c,  0x09,  0x43,  0x01,  0x71,  0x21,  0x2f,  0x3e,  0x51,  0x19,  0x02,  0x7a,  0xfe,  0x98,  0x80,
-  0xd7,  0x0c,  0x27,  0xfe,  0x3e,  0x0a,  0x0a,  0x07,  0x70,  0xfe,  0x82,  0x12,  0x0a,  0x07,  0x1a,  0xfe,
-  0x66,  0x13,  0x21,  0x61,  0x6a,  0xc8,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,
-  0x04,  0x91,  0xfe,  0x86,  0x91,  0x64,  0x2f,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x75,  0xfe,  0xea,
-  0x08,  0x04,  0x5d,  0x30,  0x5e,  0x0f,  0xae,  0x12,  0x8d,  0x9c,  0x5d,  0x9d,  0x5e,  0x01,  0xc1,  0xaf,
-  0x64,  0x2f,  0x16,  0x61,  0xa1,  0x42,  0x69,  0x58,  0x65,  0x5f,  0x31,  0x60,  0xe8,  0xfe,  0xe5,  0x55,
-  0xfe,  0x04,  0xfa,  0x42,  0xfe,  0x05,  0xfa,  0x58,  0x01,  0xfe,  0xde,  0x12,  0xfe,  0x36,  0x10,  0x2d,
-  0x0f,  0xae,  0x0f,  0x8d,  0x65,  0x5f,  0x31,  0x60,  0xaa,  0x0a,  0x07,  0x1a,  0x18,  0xfe,  0xea,  0x08,
-  0x65,  0x3a,  0x31,  0x3b,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x38,  0x04,  0x5b,  0x30,  0x5c,  0xfe,  0x10,
-  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,  0x7a,  0x0a,  0x07,  0x1a,  0x18,
-  0xfe,  0xea,  0x08,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x38,  0xfe,  0x3a,  0x55,  0xfe,  0x19,  0x81,  0x77,
-  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x3f,  0x05,  0xc3,  0x18,  0xfe,  0xf6,  0x08,
-  0x11,  0xc3,  0xfe,  0x98,  0x80,  0xd7,  0x0c,  0xfe,  0x14,  0x13,  0x04,  0x3a,  0x30,  0x3b,  0x75,  0xfe,
-  0xf6,  0x08,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x7a,  0x2d,  0x4e,  0xfe,  0x19,  0x80,  0xfe,
-  0xf1,  0x10,  0x0a,  0x07,  0x0c,  0xa5,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x8e,  0x10,  0xfe,
-  0x6c,  0x19,  0x9c,  0x3a,  0xfe,  0xed,  0x19,  0x9d,  0x3b,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,
-  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xff,  0x35,  0xfe,  0x74,  0x10,  0xc5,  0xfe,  0xd2,  0xf0,  0xfe,  0xd6,
-  0x0a,  0xfe,  0x76,  0x18,  0x1b,  0x19,  0xce,  0x04,  0xdf,  0x1b,  0x06,  0x84,  0x13,  0xfe,  0x16,  0x00,
-  0x02,  0x62,  0xfe,  0xd1,  0xf0,  0xfe,  0xe8,  0x0a,  0x17,  0x80,  0x01,  0x44,  0x13,  0xd6,  0xfe,  0x42,
-  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xee,  0x0a,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xfa,  0x0a,
-  0x13,  0xfe,  0x22,  0x00,  0x02,  0x62,  0xfe,  0xcb,  0xf0,  0xfe,  0x06,  0x0b,  0x13,  0xfe,  0x24,  0x00,
-  0x02,  0x62,  0xfe,  0xd0,  0xf0,  0xfe,  0x10,  0x0b,  0x13,  0x88,  0xd8,  0xfe,  0xcf,  0xf0,  0xfe,  0x1a,
-  0x0b,  0x13,  0x89,  0xd3,  0xfe,  0xcc,  0xf0,  0xfe,  0x2a,  0x0b,  0xfe,  0x84,  0x80,  0xd7,  0x1a,  0x4b,
-  0x13,  0xfe,  0x12,  0x00,  0x2b,  0x08,  0x80,  0x2e,  0xfe,  0x30,  0x0b,  0xfe,  0x9e,  0xf0,  0xfe,  0x44,
-  0x0b,  0x9b,  0x18,  0x32,  0x2b,  0x52,  0xfe,  0xed,  0x10,  0xa7,  0x28,  0xa9,  0x28,  0x2b,  0xf5,  0x2e,
-  0xfe,  0x50,  0x0b,  0x22,  0x32,  0x81,  0xfe,  0x6c,  0x0b,  0x6b,  0x92,  0xa7,  0xfe,  0xec,  0x07,  0xa9,
-  0xfe,  0xec,  0x07,  0x02,  0x28,  0x01,  0x4c,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0xe3,  0xe4,
-  0x8c,  0x82,  0x6e,  0xfe,  0x89,  0xf0,  0x28,  0x23,  0x24,  0xfe,  0xe9,  0x09,  0x01,  0x0b,  0x82,  0x6e,
-  0x1f,  0x28,  0x23,  0x24,  0x91,  0x34,  0xfe,  0xa8,  0x0b,  0x22,  0x32,  0x02,  0xfe,  0x9c,  0x0b,  0x9b,
-  0x40,  0x13,  0xfe,  0x42,  0x00,  0x02,  0x62,  0xa0,  0x06,  0xfe,  0x81,  0x49,  0x96,  0x0a,  0x07,  0x0c,
-  0xfe,  0x5a,  0x13,  0x13,  0x00,  0x59,  0x0c,  0xfe,  0x6a,  0x12,  0x59,  0xfe,  0x28,  0x00,  0x27,  0xfe,
-  0xee,  0x0c,  0x0e,  0x79,  0x01,  0x15,  0x05,  0x00,  0x84,  0x36,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0xee,
-  0x0c,  0x01,  0x97,  0x01,  0x9a,  0x0e,  0xc0,  0x01,  0xfe,  0x44,  0x0e,  0xb2,  0x08,  0x3d,  0x09,  0x99,
-  0x01,  0x46,  0x11,  0x47,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x7b,  0x02,  0x26,  0x13,  0xfe,  0x44,  0x00,
-  0x59,  0x0c,  0xa5,  0x36,  0x0c,  0xfe,  0xc0,  0x10,  0x01,  0x96,  0x36,  0x0c,  0xfe,  0xb6,  0x10,  0x01,
-  0x96,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x36,  0x0c,  0x13,  0xfe,  0x43,  0x00,
-  0xfe,  0xa2,  0x10,  0x0a,  0x41,  0x0c,  0x38,  0x01,  0x97,  0x01,  0x9a,  0xb2,  0x08,  0x3d,  0x09,  0x99,
-  0x01,  0x46,  0x11,  0x47,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x7b,  0x51,  0x0c,  0xb2,  0x1d,  0xca,  0x02,
-  0xfe,  0x48,  0x03,  0x0a,  0x07,  0x0c,  0xce,  0x36,  0x0c,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x68,  0x07,
-  0x1e,  0xfe,  0x50,  0x12,  0x0a,  0x07,  0x1e,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,
-  0xfe,  0xac,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0xb2,  0x0c,  0x0a,  0x41,  0x1e,  0x38,
-  0xfe,  0x95,  0x10,  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0c,  0x77,  0xfe,  0x26,  0x10,  0x13,
-  0xfe,  0x13,  0x00,  0xd3,  0x13,  0xfe,  0x47,  0x00,  0xa6,  0x13,  0xfe,  0x41,  0x00,  0x9e,  0x13,  0xfe,
-  0x24,  0x00,  0x04,  0x78,  0x29,  0x27,  0xee,  0x77,  0xfe,  0x04,  0xe6,  0x1e,  0xfe,  0x9d,  0x41,  0xfe,
-  0x1c,  0x42,  0xb2,  0x01,  0xea,  0x02,  0x26,  0xd5,  0x17,  0x0c,  0x4a,  0xf4,  0xdd,  0x17,  0xfe,  0x31,
-  0x00,  0x4a,  0xbd,  0x01,  0xfe,  0x50,  0x0f,  0x02,  0xfe,  0xc2,  0x01,  0x1d,  0xfe,  0x06,  0xec,  0xf8,
-  0x86,  0x36,  0x37,  0xbf,  0x35,  0x1d,  0xfe,  0x06,  0xea,  0xf8,  0xfe,  0x47,  0x4b,  0x95,  0xfe,  0x75,
-  0x57,  0x04,  0x56,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0e,  0x79,  0xfe,  0xf4,  0x14,  0x4e,  0xe6,
-  0x0e,  0xc0,  0xfe,  0xea,  0x14,  0xfe,  0x49,  0x54,  0x8f,  0xfe,  0x62,  0x0d,  0x0e,  0x1c,  0xfe,  0xde,
-  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x48,  0x03,  0x0e,  0x56,  0xfe,  0xc8,  0x14,  0x86,  0x36,  0x37,
-  0xbf,  0x35,  0x1d,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x26,  0x21,  0x2a,  0x05,  0x10,  0xfe,
-  0x78,  0x12,  0x2d,  0x16,  0x55,  0x16,  0xad,  0x21,  0x47,  0x4e,  0x4a,  0x47,  0x9b,  0xfe,  0x0c,  0x13,
-  0xfe,  0xbc,  0xf0,  0xfe,  0xfe,  0x0d,  0x08,  0x06,  0x16,  0x55,  0x01,  0xfe,  0x06,  0x16,  0x04,  0xfe,
-  0x38,  0x01,  0x30,  0xfe,  0x3a,  0x01,  0x75,  0xfe,  0x02,  0x0e,  0x04,  0xfe,  0x38,  0x01,  0x1b,  0xfe,
-  0xf0,  0xff,  0x0f,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0f,  0xfe,  0x62,  0x01,  0x20,  0x06,
-  0x16,  0x47,  0xfe,  0x04,  0xec,  0x2a,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x01,  0x46,  0x7f,  0xfe,  0x05,
-  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x76,  0x16,  0x11,  0x47,  0xca,  0x08,  0x06,  0x03,  0x2d,  0x03,
-  0x21,  0x55,  0xfe,  0xf7,  0x12,  0x21,  0xad,  0x6a,  0x16,  0xad,  0x05,  0x80,  0xfe,  0x93,  0x13,  0xfe,
-  0x24,  0x1c,  0x17,  0x19,  0x4a,  0xf4,  0xdd,  0xfe,  0xd9,  0x10,  0x93,  0xfe,  0x03,  0xdc,  0xfe,  0x73,
-  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x93,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x03,
-  0xfe,  0x03,  0x57,  0x93,  0x2d,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0x93,  0x7d,  0x03,  0x01,
-  0xfe,  0xae,  0x16,  0x3f,  0x05,  0x47,  0xfe,  0x0a,  0x13,  0x08,  0x1c,  0x09,  0x43,  0xd3,  0x01,  0x97,
-  0x01,  0x9a,  0x08,  0x3d,  0x09,  0x99,  0x01,  0x46,  0x11,  0xfe,  0xe9,  0x00,  0x0a,  0x07,  0x89,  0xfe,
-  0x52,  0x13,  0x01,  0xfe,  0x38,  0x16,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0x0f,  0xfe,  0x64,  0x01,
-  0xfe,  0x16,  0x90,  0x0f,  0xfe,  0x66,  0x01,  0x0a,  0x07,  0x45,  0xe5,  0xfe,  0x03,  0x80,  0x52,  0x3e,
-  0x11,  0x76,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x90,  0x01,  0x71,  0xfe,  0x62,  0x08,  0x6a,  0x3e,  0x11,
-  0x76,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x90,  0x01,  0x71,  0x64,  0x2f,  0x11,  0x76,  0x08,  0x2a,  0x09,
-  0x3c,  0x1d,  0x90,  0x01,  0x7b,  0x03,  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,
-  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,
-  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x20,  0x6c,  0x16,  0xf8,  0x2d,  0x0f,  0x53,  0x0f,
-  0x4d,  0x20,  0x10,  0x16,  0x2a,  0x16,  0x3c,  0x57,  0xa0,  0xd6,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x01,
-  0x7b,  0x7f,  0x11,  0x76,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x2a,  0x0f,  0xd5,  0x8c,  0xfe,
-  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1d,  0xfe,  0x0c,  0x14,  0x86,  0xfe,  0x07,
-  0xe6,  0x37,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x96,  0x0e,  0x3d,  0x01,  0x15,  0x05,
-  0x10,  0x2c,  0x0e,  0x1c,  0x01,  0x15,  0x05,  0x10,  0xda,  0xfe,  0x44,  0x58,  0x3e,  0xfe,  0x01,  0xec,
-  0xbd,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1e,  0x9f,  0x2f,  0x01,  0xea,
-  0xfe,  0xc9,  0x10,  0x03,  0x2b,  0x82,  0x6e,  0x23,  0x24,  0xb3,  0x05,  0x1e,  0xfe,  0x48,  0x12,  0x05,
-  0x0c,  0xfe,  0x4c,  0x12,  0x05,  0x19,  0xfe,  0x30,  0x12,  0x05,  0xcc,  0x18,  0xfe,  0xf4,  0x10,  0x05,
-  0xfe,  0x23,  0x00,  0x18,  0xfe,  0x00,  0x11,  0x05,  0x06,  0x18,  0xfe,  0x5e,  0x11,  0x05,  0x1a,  0xfe,
-  0x12,  0x12,  0x05,  0x00,  0x18,  0x28,  0x17,  0xcc,  0x01,  0x44,  0xc6,  0x39,  0x01,  0x0b,  0x81,  0x4c,
-  0x03,  0x39,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x26,  0x39,  0x3f,  0x05,  0xc3,  0xfe,  0xe3,  0x13,  0x65,
-  0x3a,  0x31,  0x3b,  0x75,  0xfe,  0xb2,  0x10,  0x0a,  0x07,  0x70,  0xfe,  0x72,  0x12,  0xa1,  0x42,  0x69,
-  0x58,  0xe8,  0xfe,  0xe5,  0x55,  0x8f,  0xfe,  0x7c,  0x10,  0x21,  0x61,  0xfe,  0x26,  0x13,  0x04,  0xae,
-  0x30,  0x8d,  0x75,  0xfe,  0xd2,  0x0c,  0x0f,  0x5d,  0x12,  0x5e,  0x2d,  0x0f,  0xae,  0x0f,  0x8d,  0x01,
-  0xc1,  0x20,  0x6c,  0x52,  0x16,  0x61,  0x01,  0xfe,  0xde,  0x12,  0xa1,  0x42,  0x69,  0x58,  0xfe,  0x04,
-  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x42,  0xfe,  0x05,  0xfa,  0x58,  0xfe,  0x91,  0x10,  0x04,
-  0x5f,  0x30,  0x60,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0f,  0x5f,  0x12,  0x60,  0xa8,  0xa1,  0x42,
-  0x69,  0x58,  0xe8,  0xfe,  0xe5,  0x55,  0x04,  0x5b,  0x30,  0x5c,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,
-  0x0f,  0x5b,  0x12,  0x5c,  0x0a,  0x07,  0x70,  0xfe,  0x1e,  0x12,  0x21,  0x61,  0xfe,  0x1f,  0x40,  0x04,
-  0x5d,  0x30,  0x5e,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,  0x5f,  0x30,  0x60,  0xfe,  0x34,  0x50,
-  0xfe,  0xb6,  0x50,  0x04,  0x5b,  0x30,  0x5c,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x04,  0x3a,  0x30,
-  0x3b,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x98,  0x20,  0x06,  0x16,  0xf3,  0x02,  0x7c,  0x39,
-  0x01,  0x0b,  0x1f,  0x4f,  0x23,  0x24,  0xb3,  0x05,  0x06,  0x27,  0x4f,  0x3f,  0x05,  0xc3,  0x27,  0x7c,
-  0x01,  0xfa,  0x1b,  0x50,  0x18,  0x4f,  0x0a,  0x07,  0x0c,  0xdc,  0x65,  0x3a,  0x31,  0x3b,  0xfe,  0x0a,
-  0x55,  0x35,  0xfe,  0x8b,  0x55,  0x9c,  0x3a,  0x9d,  0x3b,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,
-  0x7c,  0xfe,  0x19,  0x81,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7c,  0x39,  0x01,  0x0b,  0x1f,
-  0xfe,  0xf6,  0x0f,  0x23,  0x24,  0xfe,  0xe9,  0x09,  0x59,  0x19,  0xfe,  0x94,  0x12,  0x59,  0x0c,  0x4b,
-  0x02,  0x4f,  0x2e,  0xfe,  0x7e,  0x11,  0x22,  0x32,  0x1f,  0xfe,  0xf6,  0x0f,  0x23,  0x24,  0x91,  0x05,
-  0x19,  0x27,  0x4f,  0x01,  0x0b,  0x1f,  0xfe,  0xf6,  0x0f,  0x23,  0x24,  0xfe,  0xe8,  0x09,  0x57,  0x04,
-  0xfe,  0x9c,  0x00,  0x29,  0x35,  0xfe,  0xbb,  0x45,  0x59,  0x00,  0x40,  0x36,  0x06,  0xa0,  0x50,  0xfe,
-  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xac,  0x3f,  0x05,  0xc2,  0xfe,  0x16,  0x13,  0x04,  0xf6,  0x29,  0xce,
-  0x04,  0x4d,  0x29,  0x35,  0x5a,  0x02,  0x7c,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,
-  0x04,  0x53,  0xbc,  0x0f,  0x53,  0x5a,  0x39,  0x01,  0x0b,  0x25,  0x98,  0x01,  0xfe,  0x26,  0x14,  0x02,
-  0x98,  0x2e,  0x40,  0x22,  0x32,  0x1f,  0x4f,  0x23,  0x24,  0x91,  0x05,  0x06,  0x27,  0x4f,  0xfe,  0xf6,
-  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,  0xac,  0xfe,  0x4a,  0xf4,  0x0c,  0x18,
-  0x4f,  0xfe,  0x4a,  0xf4,  0x06,  0xd1,  0x3f,  0x05,  0xc2,  0xc9,  0x02,  0x7c,  0x04,  0x4d,  0xbc,  0x0f,
-  0x4d,  0x5a,  0x39,  0x01,  0x0b,  0x25,  0x98,  0x01,  0xfe,  0x54,  0x14,  0x02,  0x98,  0x25,  0xfe,  0x70,
-  0x12,  0x73,  0xf1,  0x73,  0x03,  0x34,  0xfe,  0x6c,  0x12,  0x6b,  0xfe,  0x6c,  0x12,  0x5a,  0x39,  0x01,
-  0x0b,  0xfe,  0xe3,  0x10,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0x1b,  0xfe,  0xff,  0x7f,
-  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0x1b,
-  0x50,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,
-  0x03,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0xfe,  0x0b,  0x58,  0x03,  0x0e,  0x53,  0x01,
-  0x8b,  0x0e,  0x4d,  0x01,  0x8b,  0x03,  0xc8,  0x1b,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,
-  0x1a,  0x66,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x64,  0x2f,
-  0x0f,  0x5b,  0x12,  0x5c,  0x9c,  0x5f,  0x9d,  0x60,  0x03,  0xfe,  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,
-  0xe1,  0x1a,  0xb6,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x9e,  0x18,  0xfe,  0x42,  0x48,  0x77,  0x57,
-  0x95,  0x01,  0x0b,  0x1f,  0xfe,  0x1e,  0x14,  0x23,  0x24,  0xfe,  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,
-  0x0b,  0x1f,  0xfe,  0x1e,  0x14,  0x23,  0x24,  0xfe,  0xe8,  0x0a,  0x04,  0xf6,  0x29,  0xfe,  0xc4,  0x12,
-  0x2d,  0xb1,  0x1e,  0xdc,  0x59,  0xcd,  0x74,  0xfe,  0x6c,  0x13,  0x4b,  0x08,  0x06,  0x09,  0xcd,  0xa0,
-  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa6,  0xff,  0x02,  0x83,  0x55,  0xb1,
-  0x19,  0xfe,  0x12,  0x13,  0x72,  0xfe,  0x30,  0x00,  0x8f,  0xfe,  0xc6,  0x13,  0x09,  0x85,  0x08,  0x06,
-  0xfe,  0x56,  0x10,  0xb1,  0x0c,  0xfe,  0x16,  0x13,  0x72,  0xfe,  0x64,  0x00,  0x8f,  0xfe,  0xc6,  0x13,
-  0x0e,  0xfe,  0x64,  0x00,  0x09,  0x88,  0x08,  0x06,  0xfe,  0x28,  0x10,  0xb1,  0x06,  0xfe,  0x60,  0x13,
-  0x72,  0xfe,  0xc8,  0x00,  0x8f,  0xfe,  0xc6,  0x13,  0x0e,  0xfe,  0xc8,  0x00,  0x09,  0x55,  0x08,  0x06,
-  0xa8,  0x72,  0xfe,  0x90,  0x01,  0xed,  0xfe,  0xd2,  0x13,  0x95,  0xaa,  0xfe,  0x43,  0xf4,  0xad,  0xfe,
-  0x56,  0xf0,  0xfe,  0xe4,  0x13,  0xfe,  0x04,  0xf4,  0x63,  0xfe,  0x43,  0xf4,  0x88,  0xfe,  0xf3,  0x10,
-  0xb0,  0x01,  0xfe,  0xae,  0x12,  0x1b,  0x50,  0xd4,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x6c,  0xed,
-  0xfe,  0x18,  0x14,  0xa3,  0x6c,  0xfe,  0x14,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x1a,  0xed,
-  0xfe,  0x18,  0x14,  0xa3,  0x1a,  0x9e,  0x57,  0x95,  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,
-  0x03,  0x57,  0x08,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0b,  0x25,  0xec,  0x14,  0x0c,  0x01,  0x0b,  0x25,
-  0xec,  0x14,  0x19,  0x01,  0x0b,  0x25,  0xec,  0x73,  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x03,  0x14,  0x06,
-  0x01,  0x0b,  0x25,  0xb7,  0x14,  0x19,  0x01,  0x0b,  0x25,  0xb7,  0x14,  0x06,  0x01,  0x0b,  0x25,  0xb7,
-  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x25,  0xb7,  0x73,  0xfe,  0x89,  0x4a,  0x01,  0x0b,  0x03,  0x57,  0x03,
-  0x21,  0xe0,  0x05,  0x06,  0xfe,  0x44,  0x13,  0xaf,  0x16,  0xe0,  0xfe,  0x49,  0xf4,  0x00,  0x4b,  0x73,
-  0xc6,  0x5a,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf1,  0x01,  0x0b,  0x3f,  0x05,  0xfe,  0xe3,  0x00,
-  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0xd6,  0x14,  0x2d,  0x16,  0xf3,  0x01,  0x4c,  0x21,  0xf3,  0x05,  0x06,
-  0x40,  0x0a,  0x41,  0x06,  0x38,  0x03,  0x0f,  0x54,  0x12,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,
-  0x10,  0xfe,  0x1e,  0x12,  0x48,  0xe7,  0x8e,  0x01,  0x2c,  0xfe,  0x90,  0x4d,  0xde,  0x10,  0xfe,  0xc5,
-  0x59,  0x01,  0x2c,  0xfe,  0x8d,  0x56,  0xb6,  0x48,  0x03,  0x48,  0x31,  0x8a,  0x01,  0x15,  0x48,  0x8e,
-  0x01,  0x2c,  0xe2,  0x10,  0xde,  0x10,  0x31,  0x54,  0x72,  0x1c,  0x84,  0x0e,  0x56,  0x01,  0xab,  0x03,
-  0x0f,  0x54,  0x12,  0x8a,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x48,  0xe7,
-  0x8e,  0x01,  0x2c,  0xe2,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x2c,  0x48,  0x03,  0x48,
-  0x31,  0x54,  0x01,  0x15,  0x48,  0x8e,  0x01,  0x2c,  0xe2,  0x10,  0xde,  0x10,  0x31,  0x54,  0x72,  0x1c,
-  0x84,  0x0e,  0x56,  0x01,  0xab,  0x03,  0x0f,  0x54,  0x12,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,
-  0x42,  0x48,  0x8e,  0x01,  0x2c,  0xfe,  0xc0,  0x5a,  0xb0,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,
-  0x4a,  0x46,  0xdc,  0x93,  0x7d,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x69,  0x54,  0xfe,  0x4d,  0xf4,  0x1c,
-  0xfe,  0x1c,  0x13,  0x0e,  0x56,  0x01,  0x8b,  0xaa,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x2c,
-  0xfe,  0x00,  0x07,  0x7d,  0x05,  0x10,  0x84,  0x69,  0x8a,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,
-  0x45,  0x58,  0x01,  0x2c,  0xfe,  0x8d,  0x56,  0xb6,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,
-  0x10,  0x6f,  0x67,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xdb,
-  0x37,  0x94,  0xfe,  0x1a,  0x16,  0x01,  0xfe,  0x28,  0x17,  0xfe,  0x0c,  0x13,  0x87,  0x37,  0x67,  0xfe,
-  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xba,  0x27,  0xfe,  0x0a,  0x16,  0xfe,  0xe2,  0x10,  0x09,  0x10,
-  0x6f,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x1a,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,
-  0xfe,  0x19,  0x58,  0x87,  0x1a,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x67,
-  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x1a,  0x94,  0xfe,  0x64,  0x16,  0xfe,  0xbe,
-  0x14,  0x35,  0x03,  0xba,  0x27,  0xfe,  0x3c,  0x16,  0xfe,  0xa4,  0x10,  0x09,  0x10,  0x6f,  0xb6,  0xfe,
-  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xdb,  0x42,  0x94,  0xfe,  0x86,  0x16,  0xfe,  0x9c,  0x14,  0xfe,  0x18,
-  0x13,  0x87,  0x42,  0x67,  0x1e,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,  0xa2,  0x07,  0xfe,  0x7f,
-  0x00,  0xfe,  0x05,  0x40,  0x03,  0xba,  0x27,  0xfe,  0x7a,  0x16,  0xfe,  0x6c,  0x10,  0x09,  0x10,  0x6f,
-  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x87,  0xd9,  0x67,  0x1e,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,
-  0xd9,  0x94,  0xfe,  0xc6,  0x16,  0xfe,  0x5c,  0x14,  0x35,  0x03,  0xba,  0x27,  0xfe,  0xb2,  0x16,  0xfe,
-  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x6f,  0xfe,  0x18,  0xfe,  0x5d,  0xfe,  0x19,  0xfe,  0x5e,  0xc8,
-  0xdb,  0x45,  0x94,  0xfe,  0xec,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x87,  0x45,  0x4e,  0xfe,
-  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,
-  0x00,  0x64,  0x2f,  0x03,  0x64,  0x2f,  0xfe,  0x12,  0x45,  0x27,  0xfe,  0xdc,  0x16,  0x17,  0x06,  0x4a,
-  0xf4,  0xdd,  0x02,  0x26,  0xfe,  0x39,  0xf0,  0xfe,  0x30,  0x17,  0x2d,  0x03,  0xfe,  0x7e,  0x18,  0x1b,
-  0x19,  0x83,  0x08,  0x0d,  0x03,  0x6f,  0x04,  0xdf,  0x1b,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,
-  0x1d,  0x0e,  0x1c,  0x01,  0x15,  0x05,  0x10,  0x40,  0x3e,  0xfe,  0x78,  0x14,  0xfe,  0x34,  0x12,  0x50,
-  0x86,  0x36,  0x37,  0xbf,  0xfe,  0xe9,  0x13,  0x1d,  0x0e,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x40,  0x3e,
-  0xfe,  0x56,  0x14,  0xe1,  0x50,  0x86,  0x36,  0x37,  0xbf,  0xfe,  0xe9,  0x13,  0x09,  0x0c,  0x03,  0xfe,
-  0x9c,  0xe7,  0x0c,  0x13,  0xfe,  0x15,  0x00,  0x90,  0x9f,  0x2f,  0x01,  0xea,  0x09,  0x06,  0x03,  0x0a,
-  0x41,  0x37,  0x38,  0x08,  0x3d,  0x09,  0x99,  0x01,  0x46,  0x11,  0x47,  0x08,  0x1c,  0x09,  0x43,  0x01,
-  0x7b,  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x65,  0xf7,  0x31,  0x76,  0xfe,  0x48,
-  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x03,  0x21,  0xbe,  0x52,  0x16,  0xbe,  0x03,  0x0e,  0xc0,  0x01,  0x15,
-  0xe6,  0x0e,  0x79,  0x01,  0x15,  0xfe,  0x49,  0x44,  0x27,  0xfe,  0x26,  0x18,  0x0e,  0x1c,  0x01,  0x15,
-  0x05,  0x10,  0x40,  0x0e,  0x56,  0x01,  0xab,  0x0e,  0x79,  0x01,  0x15,  0x52,  0x7d,  0x03,  0xfe,  0x40,
-  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x21,  0x3c,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x3e,  0x05,
-  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0xd4,  0xfe,  0xe2,
-  0x08,  0x52,  0x3e,  0x3f,  0x05,  0x76,  0xa5,  0xfe,  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,  0x10,
-  0xfe,  0xc4,  0x48,  0x08,  0x2a,  0x09,  0x3c,  0xfe,  0x40,  0x5f,  0x1d,  0x01,  0x46,  0x11,  0xfe,  0xdd,
-  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2a,  0x09,  0x3c,  0x01,  0x46,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x40,
-  0x4a,  0x6a,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,  0xeb,
-  0x19,  0x74,  0xfe,  0xae,  0x18,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xeb,
-  0xcc,  0x74,  0xfe,  0xc0,  0x18,  0x04,  0xfe,  0x92,  0x00,  0xc7,  0x1e,  0xd8,  0xeb,  0xfe,  0x0b,  0x00,
-  0x74,  0xfe,  0xd2,  0x18,  0x04,  0xfe,  0x94,  0x00,  0xc7,  0x1a,  0xfe,  0x08,  0x10,  0x04,  0xfe,  0x96,
-  0x00,  0xc7,  0x85,  0xfe,  0x4e,  0x45,  0xd1,  0xfe,  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,
-  0x10,  0x1b,  0x6c,  0x03,  0x05,  0x80,  0xfe,  0x5a,  0xf0,  0xfe,  0xfe,  0x18,  0x20,  0xfe,  0x09,  0x00,
-  0xfe,  0x34,  0x10,  0x05,  0x1e,  0xfe,  0x5a,  0xf0,  0xfe,  0x0c,  0x19,  0x20,  0xcd,  0xfe,  0x26,  0x10,
-  0x05,  0x19,  0x83,  0x20,  0x85,  0xd8,  0x05,  0x0c,  0x83,  0x20,  0x88,  0xfe,  0x0e,  0x10,  0x05,  0x06,
-  0x83,  0x20,  0x55,  0xc6,  0xaf,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x44,  0x2e,  0xfe,  0x3c,  0x19,
-  0x04,  0x6e,  0xb0,  0x03,  0x22,  0xfe,  0x54,  0x19,  0xfe,  0x14,  0xf0,  0x0b,  0x2e,  0xfe,  0x50,  0x19,
-  0x03,  0xff,  0x15,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x18,  0xe4,  0x00,  0xfc,  0x01,  0x00,  0x48,  0xe4,
+  0xbe,  0x18,  0x18,  0x80,  0x03,  0xf6,  0x02,  0x00,  0x00,  0xfa,  0xff,  0xff,  0x28,  0x0e,  0x9e,  0xe7,
+  0xff,  0x00,  0x82,  0xe7,  0x00,  0xea,  0x00,  0xf6,  0x01,  0xe6,  0x09,  0xe7,  0x55,  0xf0,  0x01,  0xf6,
+  0x01,  0xfa,  0x08,  0x00,  0x03,  0x00,  0x04,  0x00,  0x18,  0xf4,  0x10,  0x00,  0x00,  0xec,  0x85,  0xf0,
+  0xbc,  0x00,  0xd5,  0xf0,  0x8e,  0x0c,  0x38,  0x54,  0x00,  0xe6,  0x1e,  0xf0,  0x86,  0xf0,  0xb4,  0x00,
+  0x98,  0x57,  0xd0,  0x01,  0x0c,  0x1c,  0x3e,  0x1c,  0x0c,  0x00,  0xbb,  0x00,  0xaa,  0x18,  0x02,  0x80,
+  0x32,  0xf0,  0x01,  0xfc,  0x88,  0x0c,  0xc6,  0x12,  0x02,  0x13,  0x18,  0x40,  0x00,  0x57,  0x01,  0xea,
+  0x3c,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x04,  0x12,  0x3e,  0x57,  0x00,  0x80,  0x03,  0xe6,  0xb6,  0x00,
+  0xc0,  0x00,  0x01,  0x01,  0x3e,  0x01,  0xda,  0x0f,  0x22,  0x10,  0x08,  0x12,  0x02,  0x4a,  0xb9,  0x54,
+  0x03,  0x58,  0x1b,  0x80,  0x30,  0xe4,  0x4b,  0xe4,  0x20,  0x00,  0x32,  0x00,  0x3e,  0x00,  0x80,  0x00,
+  0x24,  0x01,  0x3c,  0x01,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,
+  0x78,  0x01,  0x62,  0x0a,  0x92,  0x0c,  0x2c,  0x10,  0x2e,  0x10,  0x06,  0x13,  0x4c,  0x1c,  0xbb,  0x55,
+  0x3c,  0x56,  0x04,  0x80,  0x4a,  0xe4,  0x02,  0xee,  0x5b,  0xf0,  0xb1,  0xf0,  0x03,  0xf7,  0x06,  0xf7,
+  0x03,  0xfc,  0x0f,  0x00,  0x40,  0x00,  0xbe,  0x00,  0x00,  0x01,  0xb0,  0x08,  0x30,  0x13,  0x64,  0x15,
+  0x32,  0x1c,  0x38,  0x1c,  0x4e,  0x1c,  0x10,  0x44,  0x02,  0x48,  0x00,  0x4c,  0x04,  0xea,  0x5d,  0xf0,
+  0x04,  0xf6,  0x02,  0xfc,  0x05,  0x00,  0x34,  0x00,  0x36,  0x00,  0x98,  0x00,  0xcc,  0x00,  0x20,  0x01,
+  0x4e,  0x01,  0x4e,  0x0b,  0x1e,  0x0e,  0x0c,  0x10,  0x0a,  0x12,  0x04,  0x13,  0x40,  0x13,  0x30,  0x1c,
+  0x00,  0x4e,  0xbd,  0x56,  0x06,  0x83,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,  0x59,  0xf0,  0xa7,  0xf0,
+  0xb8,  0xf0,  0x0e,  0xf7,  0x06,  0x00,  0x19,  0x00,  0x33,  0x00,  0x9b,  0x00,  0xa4,  0x00,  0xb5,  0x00,
+  0xba,  0x00,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,  0xde,  0x03,  0x56,  0x0a,  0x14,  0x0e,  0x02,  0x10,
+  0x04,  0x10,  0x0a,  0x10,  0x36,  0x10,  0x0a,  0x13,  0x12,  0x13,  0x52,  0x13,  0x10,  0x15,  0x14,  0x15,
+  0xac,  0x16,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x08,  0x44,  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,
+  0x48,  0x46,  0x01,  0x48,  0x68,  0x54,  0x83,  0x55,  0xb0,  0x57,  0x01,  0x58,  0x83,  0x59,  0x05,  0xe6,
+  0x0b,  0xf0,  0x0c,  0xf0,  0x5c,  0xf0,  0x4b,  0xf4,  0x04,  0xf8,  0x05,  0xf8,  0x02,  0xfa,  0x03,  0xfa,
+  0x04,  0xfc,  0x05,  0xfc,  0x07,  0x00,  0x0a,  0x00,  0x0d,  0x00,  0x1c,  0x00,  0x9e,  0x00,  0xa8,  0x00,
+  0xaa,  0x00,  0xb9,  0x00,  0xe0,  0x00,  0x22,  0x01,  0x26,  0x01,  0x79,  0x01,  0x7a,  0x01,  0xc0,  0x01,
+  0xc2,  0x01,  0x7c,  0x02,  0x5a,  0x03,  0xea,  0x04,  0xe8,  0x07,  0x68,  0x08,  0x69,  0x08,  0xba,  0x08,
+  0xe9,  0x09,  0x06,  0x0b,  0x3a,  0x0e,  0x00,  0x10,  0x1a,  0x10,  0xed,  0x10,  0xf1,  0x10,  0x06,  0x12,
+  0x0c,  0x13,  0x16,  0x13,  0x1e,  0x13,  0x82,  0x13,  0x42,  0x14,  0xd6,  0x14,  0x8a,  0x15,  0xc6,  0x17,
+  0xd2,  0x17,  0x6b,  0x18,  0x12,  0x1c,  0x46,  0x1c,  0x9c,  0x32,  0x00,  0x40,  0x0e,  0x47,  0x48,  0x47,
+  0x41,  0x48,  0x89,  0x48,  0x80,  0x4c,  0x00,  0x54,  0x44,  0x55,  0xe5,  0x55,  0x14,  0x56,  0x77,  0x57,
+  0xbf,  0x57,  0x40,  0x5c,  0x06,  0x80,  0x08,  0x90,  0x03,  0xa1,  0xfe,  0x9c,  0xf0,  0x29,  0x02,  0xfe,
+  0xb8,  0x0c,  0xff,  0x10,  0x00,  0x00,  0xd0,  0xfe,  0xcc,  0x18,  0x00,  0xcf,  0xfe,  0x80,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
+  0x00,  0xfe,  0x48,  0x00,  0x4f,  0xff,  0x04,  0x00,  0x00,  0x10,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
+  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x0f,
+  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xcf,
+  0x2a,  0x67,  0x0b,  0x01,  0xfe,  0xce,  0x0e,  0xfe,  0x04,  0xf7,  0xcf,  0x67,  0x0b,  0x3c,  0x2a,  0xfe,
+  0x3d,  0xf0,  0xfe,  0x02,  0x02,  0xfe,  0x20,  0xf0,  0x9c,  0xfe,  0x91,  0xf0,  0xfe,  0xf0,  0x01,  0xfe,
+  0x90,  0xf0,  0xfe,  0xf0,  0x01,  0xfe,  0x8f,  0xf0,  0x9c,  0x05,  0x51,  0x3b,  0x02,  0xfe,  0xd4,  0x0c,
+  0x01,  0xfe,  0x44,  0x0d,  0xfe,  0xdd,  0x12,  0xfe,  0xfc,  0x10,  0xfe,  0x28,  0x1c,  0x05,  0xfe,  0xa6,
+  0x00,  0xfe,  0xd3,  0x12,  0x47,  0x18,  0xfe,  0xa6,  0x00,  0xb5,  0xfe,  0x48,  0xf0,  0xfe,  0x86,  0x02,
+  0xfe,  0x49,  0xf0,  0xfe,  0xa0,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xbe,  0x02,  0xfe,  0x46,  0xf0,  0xfe,
+  0x50,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x56,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x44,  0x02,  0xfe,  0x44,
+  0xf0,  0xfe,  0x48,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x4c,  0x02,  0x17,  0x0b,  0xa0,  0x17,  0x06,  0x18,
+  0x96,  0x02,  0x29,  0xfe,  0x00,  0x1c,  0xde,  0xfe,  0x02,  0x1c,  0xdd,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,
+  0x10,  0x01,  0xfe,  0x20,  0x17,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xc7,  0x0a,  0x6b,  0x01,  0x9e,
+  0x02,  0x29,  0x14,  0x4d,  0x37,  0x97,  0x01,  0xfe,  0x64,  0x0f,  0x0a,  0x6b,  0x01,  0x82,  0xfe,  0xbd,
+  0x10,  0x0a,  0x6b,  0x01,  0x82,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x17,  0x06,
+  0x18,  0x96,  0x2a,  0x25,  0x29,  0xfe,  0x3d,  0xf0,  0xfe,  0x02,  0x02,  0x21,  0xfe,  0x94,  0x02,  0xfe,
+  0x5a,  0x1c,  0xea,  0xfe,  0x14,  0x1c,  0x14,  0xfe,  0x30,  0x00,  0x37,  0x97,  0x01,  0xfe,  0x54,  0x0f,
+  0x17,  0x06,  0x18,  0x96,  0x02,  0xd0,  0x1e,  0x20,  0x07,  0x10,  0x34,  0xfe,  0x69,  0x10,  0x17,  0x06,
+  0x18,  0x96,  0xfe,  0x04,  0xec,  0x20,  0x46,  0x3d,  0x12,  0x20,  0xfe,  0x05,  0xf6,  0xc7,  0x01,  0xfe,
+  0x52,  0x16,  0x09,  0x4a,  0x4c,  0x35,  0x11,  0x2d,  0x3c,  0x8a,  0x01,  0xe6,  0x02,  0x29,  0x0a,  0x40,
+  0x01,  0x0e,  0x07,  0x00,  0x5d,  0x01,  0x6f,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x0a,  0x99,  0x01,
+  0x0e,  0xfe,  0xc8,  0x54,  0x64,  0xfe,  0x0c,  0x03,  0x01,  0xe6,  0x02,  0x29,  0x2a,  0x46,  0xfe,  0x02,
+  0xe8,  0x27,  0xf8,  0xfe,  0x9e,  0x43,  0xf7,  0xfe,  0x27,  0xf0,  0xfe,  0xdc,  0x01,  0xfe,  0x07,  0x4b,
+  0xfe,  0x20,  0xf0,  0x9c,  0xfe,  0x40,  0x1c,  0x25,  0xd2,  0xfe,  0x26,  0xf0,  0xfe,  0x56,  0x03,  0xfe,
+  0xa0,  0xf0,  0xfe,  0x44,  0x03,  0xfe,  0x11,  0xf0,  0x9c,  0xfe,  0xef,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,
+  0x64,  0x03,  0xeb,  0x0f,  0xfe,  0x11,  0x00,  0x02,  0x5a,  0x2a,  0xfe,  0x48,  0x1c,  0xeb,  0x09,  0x04,
+  0x1d,  0xfe,  0x18,  0x13,  0x23,  0x1e,  0x98,  0xac,  0x12,  0x98,  0x0a,  0x40,  0x01,  0x0e,  0xac,  0x75,
+  0x01,  0xfe,  0xbc,  0x15,  0x11,  0xca,  0x25,  0xd2,  0xfe,  0x01,  0xf0,  0xd2,  0xfe,  0x82,  0xf0,  0xfe,
+  0x92,  0x03,  0xec,  0x11,  0xfe,  0xe4,  0x00,  0x65,  0xfe,  0xa4,  0x03,  0x25,  0x32,  0x1f,  0xfe,  0xb4,
+  0x03,  0x01,  0x43,  0xfe,  0x06,  0xf0,  0xfe,  0xc4,  0x03,  0x8d,  0x81,  0xfe,  0x0a,  0xf0,  0xfe,  0x7a,
+  0x06,  0x02,  0x22,  0x05,  0x6b,  0x28,  0x16,  0xfe,  0xf6,  0x04,  0x14,  0x2c,  0x01,  0x33,  0x8f,  0xfe,
+  0x66,  0x02,  0x02,  0xd1,  0xeb,  0x2a,  0x67,  0x1a,  0xfe,  0x67,  0x1b,  0xf8,  0xf7,  0xfe,  0x48,  0x1c,
+  0x70,  0x01,  0x6e,  0x87,  0x0a,  0x40,  0x01,  0x0e,  0x07,  0x00,  0x16,  0xd3,  0x0a,  0xca,  0x01,  0x0e,
+  0x74,  0x60,  0x59,  0x76,  0x27,  0x05,  0x6b,  0x28,  0xfe,  0x10,  0x12,  0x14,  0x2c,  0x01,  0x33,  0x8f,
+  0xfe,  0x66,  0x02,  0x02,  0xd1,  0xbc,  0x7d,  0xbd,  0x7f,  0x25,  0x22,  0x65,  0xfe,  0x3c,  0x04,  0x1f,
+  0xfe,  0x38,  0x04,  0x68,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x4e,  0x12,  0x2b,  0xff,  0x02,
+  0x00,  0x10,  0x01,  0x08,  0x1f,  0xfe,  0xe0,  0x04,  0x2b,  0x01,  0x08,  0x1f,  0x22,  0x30,  0x2e,  0xd5,
+  0xfe,  0x4c,  0x44,  0xfe,  0x4c,  0x12,  0x60,  0xfe,  0x44,  0x48,  0x13,  0x2c,  0xfe,  0x4c,  0x54,  0x64,
+  0xd3,  0x46,  0x76,  0x27,  0xfa,  0xef,  0xfe,  0x62,  0x13,  0x09,  0x04,  0x1d,  0xfe,  0x2a,  0x13,  0x2f,
+  0x07,  0x7e,  0xa5,  0xfe,  0x20,  0x10,  0x13,  0x2c,  0xfe,  0x4c,  0x54,  0x64,  0xd3,  0xfa,  0xef,  0x86,
+  0x09,  0x04,  0x1d,  0xfe,  0x08,  0x13,  0x2f,  0x07,  0x7e,  0x6e,  0x09,  0x04,  0x1d,  0xfe,  0x1c,  0x12,
+  0x14,  0x92,  0x09,  0x04,  0x06,  0x3b,  0x14,  0xc4,  0x01,  0x33,  0x8f,  0xfe,  0x70,  0x0c,  0x02,  0x22,
+  0x2b,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xf9,  0x03,  0x14,  0x92,  0x01,  0x33,  0x02,  0x29,
+  0xfe,  0x42,  0x5b,  0x67,  0x1a,  0xfe,  0x46,  0x59,  0xf8,  0xf7,  0xfe,  0x87,  0x80,  0xfe,  0x31,  0xe4,
+  0x4f,  0x09,  0x04,  0x0b,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,  0x07,  0x1a,  0xfe,  0x70,  0x12,  0x49,
+  0x04,  0x06,  0xfe,  0x60,  0x13,  0x05,  0xfe,  0xa2,  0x00,  0x28,  0x16,  0xfe,  0x80,  0x05,  0xfe,  0x31,
+  0xe4,  0x6a,  0x49,  0x04,  0x0b,  0xfe,  0x4a,  0x13,  0x05,  0xfe,  0xa0,  0x00,  0x28,  0xfe,  0x42,  0x12,
+  0x5e,  0x01,  0x08,  0x25,  0x32,  0xf1,  0x01,  0x08,  0x26,  0xfe,  0x98,  0x05,  0x11,  0xfe,  0xe3,  0x00,
+  0x23,  0x49,  0xfe,  0x4a,  0xf0,  0xfe,  0x6a,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x64,  0x05,  0x83,  0x24,
+  0xfe,  0x21,  0x00,  0xa1,  0x24,  0xfe,  0x22,  0x00,  0xa0,  0x24,  0x4c,  0xfe,  0x09,  0x48,  0x01,  0x08,
+  0x26,  0xfe,  0x98,  0x05,  0xfe,  0xe2,  0x08,  0x49,  0x04,  0xc5,  0x3b,  0x01,  0x86,  0x24,  0x06,  0x12,
+  0xcc,  0x37,  0xfe,  0x27,  0x01,  0x09,  0x04,  0x1d,  0xfe,  0x22,  0x12,  0x47,  0x01,  0xa7,  0x14,  0x92,
+  0x09,  0x04,  0x06,  0x3b,  0x14,  0xc4,  0x01,  0x33,  0x8f,  0xfe,  0x70,  0x0c,  0x02,  0x22,  0x05,  0xfe,
+  0x9c,  0x00,  0x28,  0xfe,  0x3e,  0x12,  0x05,  0x50,  0x28,  0xfe,  0x36,  0x13,  0x47,  0x01,  0xa7,  0x26,
+  0xfe,  0x08,  0x06,  0x0a,  0x06,  0x49,  0x04,  0x19,  0xfe,  0x02,  0x12,  0x5f,  0x01,  0xfe,  0xaa,  0x14,
+  0x1f,  0xfe,  0xfe,  0x05,  0x11,  0x9a,  0x01,  0x43,  0x11,  0xfe,  0xe5,  0x00,  0x05,  0x50,  0xb4,  0x0c,
+  0x50,  0x05,  0xc6,  0x28,  0xfe,  0x62,  0x12,  0x05,  0x3f,  0x28,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x14,
+  0x18,  0x01,  0xfe,  0x66,  0x18,  0xfe,  0x43,  0x48,  0xb7,  0x19,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,
+  0x48,  0x8b,  0x1c,  0x3d,  0x85,  0xb7,  0x69,  0x47,  0x01,  0xa7,  0x26,  0xfe,  0x72,  0x06,  0x49,  0x04,
+  0x1b,  0xdf,  0x89,  0x0a,  0x4d,  0x01,  0xfe,  0xd8,  0x14,  0x1f,  0xfe,  0x68,  0x06,  0x11,  0x9a,  0x01,
+  0x43,  0x11,  0xfe,  0xe5,  0x00,  0x05,  0x3f,  0xb4,  0x0c,  0x3f,  0x17,  0x06,  0x01,  0xa7,  0xec,  0x72,
+  0x70,  0x01,  0x6e,  0x87,  0x11,  0xfe,  0xe2,  0x00,  0x01,  0x08,  0x25,  0x32,  0xfe,  0x0a,  0xf0,  0xfe,
+  0xa6,  0x06,  0x8c,  0xfe,  0x5c,  0x07,  0xfe,  0x06,  0xf0,  0xfe,  0x64,  0x07,  0x8d,  0x81,  0x02,  0x22,
+  0x09,  0x04,  0x0b,  0xfe,  0x2e,  0x12,  0x15,  0x1a,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,
+  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0xfe,  0x99,  0xa4,  0x01,  0x08,  0x15,  0x00,  0x02,  0xfe,  0x32,
+  0x08,  0x61,  0x04,  0x1b,  0xfe,  0x38,  0x12,  0x09,  0x04,  0x1b,  0x6e,  0x15,  0xfe,  0x1b,  0x00,  0x01,
+  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x06,  0x01,
+  0x08,  0x15,  0x00,  0x02,  0xd9,  0x66,  0x4c,  0xfe,  0x3a,  0x55,  0x5f,  0xfe,  0x9a,  0x81,  0x4b,  0x1d,
+  0xba,  0xfe,  0x32,  0x07,  0x0a,  0x1d,  0xfe,  0x09,  0x6f,  0xaf,  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,
+  0x62,  0x2c,  0x85,  0x66,  0x7b,  0x01,  0x08,  0x25,  0x32,  0xfe,  0x0a,  0xf0,  0xfe,  0x32,  0x07,  0x8d,
+  0x81,  0x8c,  0xfe,  0x5c,  0x07,  0x02,  0x22,  0x01,  0x43,  0x02,  0xfe,  0x8a,  0x06,  0x15,  0x19,  0x02,
+  0xfe,  0x8a,  0x06,  0xfe,  0x9c,  0xf7,  0xd4,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x77,  0xfe,  0xca,
+  0x07,  0x0c,  0x54,  0x18,  0x55,  0x09,  0x4a,  0x6a,  0x35,  0x1e,  0x20,  0x07,  0x10,  0xfe,  0x0e,  0x12,
+  0x74,  0xfe,  0x80,  0x80,  0x37,  0x20,  0x63,  0x27,  0xfe,  0x06,  0x10,  0xfe,  0x83,  0xe7,  0xc4,  0xa1,
+  0xfe,  0x03,  0x40,  0x09,  0x4a,  0x4f,  0x35,  0x01,  0xa8,  0xad,  0xfe,  0x1f,  0x40,  0x12,  0x58,  0x01,
+  0xa5,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,  0xfe,  0xc6,  0x51,  0x83,  0xfb,  0xfe,
+  0x8a,  0x90,  0x0c,  0x52,  0x18,  0x53,  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x40,  0x50,  0xfe,
+  0xc2,  0x50,  0x0c,  0x39,  0x18,  0x3a,  0xfe,  0x4a,  0x10,  0x09,  0x04,  0x6a,  0xfe,  0x2a,  0x12,  0xfe,
+  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0c,  0x54,  0x18,  0x55,  0x09,  0x04,  0x4f,  0x85,  0x01,  0xa8,  0xfe,
+  0x1f,  0x80,  0x12,  0x58,  0xfe,  0x44,  0x90,  0xfe,  0xc6,  0x90,  0x0c,  0x56,  0x18,  0x57,  0xfb,  0xfe,
+  0x8a,  0x90,  0x0c,  0x52,  0x18,  0x53,  0xfe,  0x40,  0x90,  0xfe,  0xc2,  0x90,  0x0c,  0x39,  0x18,  0x3a,
+  0x0c,  0x38,  0x18,  0x4e,  0x09,  0x4a,  0x19,  0x35,  0x2a,  0x13,  0xfe,  0x4e,  0x11,  0x65,  0xfe,  0x48,
+  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x5c,  0x08,  0xb1,  0x16,  0x32,  0x2a,  0x73,  0xdd,  0xb8,  0xfe,  0x80,
+  0x08,  0xb9,  0xfe,  0x9e,  0x08,  0x8c,  0xfe,  0x74,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x7a,  0x08,  0x8d,
+  0x81,  0x02,  0x22,  0x01,  0x43,  0xfe,  0xc9,  0x10,  0x15,  0x19,  0xfe,  0xc9,  0x10,  0x61,  0x04,  0x06,
+  0xfe,  0x10,  0x12,  0x61,  0x04,  0x0b,  0x45,  0x09,  0x04,  0x0b,  0xfe,  0x68,  0x12,  0xfe,  0x2e,  0x1c,
+  0x02,  0xfe,  0x24,  0x0a,  0x61,  0x04,  0x06,  0x45,  0x61,  0x04,  0x0b,  0xfe,  0x52,  0x12,  0xfe,  0x2c,
+  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0x1e,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0xbe,  0x08,  0xfe,  0x8a,  0x10,
+  0xaa,  0xfe,  0xf3,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0xca,  0x08,  0x02,  0xfe,  0x24,  0x0a,  0xab,  0xfe,
+  0xe7,  0x10,  0xfe,  0x2b,  0xf0,  0x9d,  0xe9,  0x1c,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xb5,  0xfe,
+  0xd2,  0xf0,  0x9d,  0xfe,  0x76,  0x18,  0x1c,  0x1a,  0x16,  0x9d,  0x05,  0xcb,  0x1c,  0x06,  0x16,  0x9d,
+  0xb8,  0x6d,  0xb9,  0x6d,  0xaa,  0xab,  0xfe,  0xb1,  0x10,  0x70,  0x5e,  0x2b,  0x14,  0x92,  0x01,  0x33,
+  0x0f,  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x5a,  0x0f,  0x7c,  0x02,  0x5a,  0xfe,  0x74,  0x18,  0x1c,
+  0xfe,  0x00,  0xf8,  0x16,  0x6d,  0x67,  0x1b,  0x01,  0xfe,  0x44,  0x0d,  0x3b,  0x01,  0xe6,  0x1e,  0x27,
+  0x74,  0x67,  0x1a,  0x02,  0x6d,  0x09,  0x04,  0x0b,  0x21,  0xfe,  0x06,  0x0a,  0x09,  0x04,  0x6a,  0xfe,
+  0x82,  0x12,  0x09,  0x04,  0x19,  0xfe,  0x66,  0x13,  0x1e,  0x58,  0xac,  0xfc,  0xfe,  0x83,  0x80,  0xfe,
+  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x63,  0x27,  0xfe,  0x40,  0x59,
+  0xfe,  0xc1,  0x59,  0x77,  0xd7,  0x05,  0x54,  0x31,  0x55,  0x0c,  0x7b,  0x18,  0x7c,  0xbe,  0x54,  0xbf,
+  0x55,  0x01,  0xa8,  0xad,  0x63,  0x27,  0x12,  0x58,  0xc0,  0x38,  0xc1,  0x4e,  0x79,  0x56,  0x68,  0x57,
+  0xf4,  0xf5,  0xfe,  0x04,  0xfa,  0x38,  0xfe,  0x05,  0xfa,  0x4e,  0x01,  0xa5,  0xa2,  0x23,  0x0c,  0x7b,
+  0x0c,  0x7c,  0x79,  0x56,  0x68,  0x57,  0xfe,  0x12,  0x10,  0x09,  0x04,  0x19,  0x16,  0xd7,  0x79,  0x39,
+  0x68,  0x3a,  0x09,  0x04,  0xfe,  0xf7,  0x00,  0x35,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x10,  0x58,  0xfe,
+  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,  0x6d,  0x09,  0x04,  0x19,  0x16,  0xd7,  0x09,
+  0x04,  0xfe,  0xf7,  0x00,  0x35,  0xfe,  0x3a,  0x55,  0xfe,  0x19,  0x81,  0x5f,  0xfe,  0x10,  0x90,  0xfe,
+  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x2f,  0x07,  0x9b,  0x16,  0xfe,  0xc6,  0x08,  0x11,  0x9b,  0x09,  0x04,
+  0x0b,  0xfe,  0x14,  0x13,  0x05,  0x39,  0x31,  0x3a,  0x77,  0xfe,  0xc6,  0x08,  0xfe,  0x0c,  0x58,  0xfe,
+  0x8d,  0x58,  0x02,  0x6d,  0x23,  0x47,  0xfe,  0x19,  0x80,  0xde,  0x09,  0x04,  0x0b,  0xfe,  0x1a,  0x12,
+  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xe9,  0xb5,  0xfe,  0xd1,  0xf0,  0xd9,  0x14,  0x7a,  0x01,  0x33,
+  0x0f,  0xfe,  0x44,  0x00,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0xbe,  0x39,  0xfe,  0xed,  0x19,  0xbf,
+  0x3a,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xe9,  0x1c,  0xfe,  0x00,  0xff,  0x34,  0xfe,  0x74,  0x10,
+  0xb5,  0xfe,  0xd2,  0xf0,  0xfe,  0xb2,  0x0a,  0xfe,  0x76,  0x18,  0x1c,  0x1a,  0x84,  0x05,  0xcb,  0x1c,
+  0x06,  0xfe,  0x08,  0x13,  0x0f,  0xfe,  0x16,  0x00,  0x02,  0x5a,  0xfe,  0xd1,  0xf0,  0xfe,  0xc4,  0x0a,
+  0x14,  0x7a,  0x01,  0x33,  0x0f,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xca,
+  0x0a,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xd6,  0x0a,  0x0f,  0xfe,  0x22,  0x00,  0x02,  0x5a,
+  0xfe,  0xcb,  0xf0,  0xfe,  0xe2,  0x0a,  0x0f,  0xfe,  0x24,  0x00,  0x02,  0x5a,  0xfe,  0xd0,  0xf0,  0xfe,
+  0xec,  0x0a,  0x0f,  0x93,  0xdc,  0xfe,  0xcf,  0xf0,  0xfe,  0xf6,  0x0a,  0x0f,  0x4c,  0xfe,  0x10,  0x10,
+  0xfe,  0xcc,  0xf0,  0xd9,  0x61,  0x04,  0x19,  0x3b,  0x0f,  0xfe,  0x12,  0x00,  0x2a,  0x13,  0xfe,  0x4e,
+  0x11,  0x65,  0xfe,  0x0c,  0x0b,  0xfe,  0x9e,  0xf0,  0xfe,  0x20,  0x0b,  0xb1,  0x16,  0x32,  0x2a,  0x73,
+  0xdd,  0xb8,  0x22,  0xb9,  0x22,  0x2a,  0xec,  0x65,  0xfe,  0x2c,  0x0b,  0x25,  0x32,  0x8c,  0xfe,  0x48,
+  0x0b,  0x8d,  0x81,  0xb8,  0xd4,  0xb9,  0xd4,  0x02,  0x22,  0x01,  0x43,  0xfe,  0xdb,  0x10,  0x11,  0xfe,
+  0xe8,  0x00,  0xaa,  0xab,  0x70,  0xbc,  0x7d,  0xbd,  0x7f,  0xfe,  0x89,  0xf0,  0x22,  0x30,  0x2e,  0xd8,
+  0xbc,  0x7d,  0xbd,  0x7f,  0x01,  0x08,  0x1f,  0x22,  0x30,  0x2e,  0xd6,  0xb1,  0x45,  0x0f,  0xfe,  0x42,
+  0x00,  0x02,  0x5a,  0x78,  0x06,  0xfe,  0x81,  0x49,  0x16,  0xfe,  0x38,  0x0c,  0x09,  0x04,  0x0b,  0xfe,
+  0x44,  0x13,  0x0f,  0x00,  0x4b,  0x0b,  0xfe,  0x54,  0x12,  0x4b,  0xfe,  0x28,  0x00,  0x21,  0xfe,  0xa6,
+  0x0c,  0x0a,  0x40,  0x01,  0x0e,  0x07,  0x00,  0x5d,  0x3e,  0xfe,  0x28,  0x00,  0xfe,  0xe2,  0x10,  0x01,
+  0xe7,  0x01,  0xe8,  0x0a,  0x99,  0x01,  0xfe,  0x32,  0x0e,  0x59,  0x11,  0x2d,  0x01,  0x6f,  0x02,  0x29,
+  0x0f,  0xfe,  0x44,  0x00,  0x4b,  0x0b,  0xdf,  0x3e,  0x0b,  0xfe,  0xb4,  0x10,  0x01,  0x86,  0x3e,  0x0b,
+  0xfe,  0xaa,  0x10,  0x01,  0x86,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xa3,  0x3e,  0x0b,  0x0f,  0xfe,
+  0x43,  0x00,  0xfe,  0x96,  0x10,  0x09,  0x4a,  0x0b,  0x35,  0x01,  0xe7,  0x01,  0xe8,  0x59,  0x11,  0x2d,
+  0x01,  0x6f,  0x67,  0x0b,  0x59,  0x3c,  0x8a,  0x02,  0xfe,  0x2a,  0x03,  0x09,  0x04,  0x0b,  0x84,  0x3e,
+  0x0b,  0x0f,  0x00,  0xfe,  0x5c,  0x10,  0x61,  0x04,  0x1b,  0xfe,  0x58,  0x12,  0x09,  0x04,  0x1b,  0xfe,
+  0x50,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x5c,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,
+  0xf0,  0xfe,  0x62,  0x0c,  0x09,  0x4a,  0x1b,  0x35,  0xfe,  0xa9,  0x10,  0x0f,  0xfe,  0x15,  0x00,  0xfe,
+  0x04,  0xe6,  0x0b,  0x5f,  0x5c,  0x0f,  0xfe,  0x13,  0x00,  0xfe,  0x10,  0x10,  0x0f,  0xfe,  0x47,  0x00,
+  0xa1,  0x0f,  0xfe,  0x41,  0x00,  0xa0,  0x0f,  0xfe,  0x24,  0x00,  0x87,  0xaa,  0xab,  0x70,  0x05,  0x6b,
+  0x28,  0x21,  0xd1,  0x5f,  0xfe,  0x04,  0xe6,  0x1b,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0x59,  0x01,
+  0xda,  0x02,  0x29,  0xea,  0x14,  0x0b,  0x37,  0x95,  0xa9,  0x14,  0xfe,  0x31,  0x00,  0x37,  0x97,  0x01,
+  0xfe,  0x54,  0x0f,  0x02,  0xd0,  0x3c,  0xfe,  0x06,  0xec,  0xc9,  0xee,  0x3e,  0x1d,  0xfe,  0xce,  0x45,
+  0x34,  0x3c,  0xfe,  0x06,  0xea,  0xc9,  0xfe,  0x47,  0x4b,  0x89,  0xfe,  0x75,  0x57,  0x05,  0x51,  0xfe,
+  0x98,  0x56,  0xfe,  0x38,  0x12,  0x0a,  0x42,  0x01,  0x0e,  0xfe,  0x44,  0x48,  0x46,  0x09,  0x04,  0x1d,
+  0xfe,  0x1a,  0x13,  0x0a,  0x40,  0x01,  0x0e,  0x47,  0xfe,  0x41,  0x58,  0x0a,  0x99,  0x01,  0x0e,  0xfe,
+  0x49,  0x54,  0x8e,  0xfe,  0x2a,  0x0d,  0x02,  0xfe,  0x2a,  0x03,  0x0a,  0x51,  0xfe,  0xee,  0x14,  0xee,
+  0x3e,  0x1d,  0xfe,  0xce,  0x45,  0x34,  0x3c,  0xfe,  0xce,  0x47,  0xfe,  0xad,  0x13,  0x02,  0x29,  0x1e,
+  0x20,  0x07,  0x10,  0xfe,  0x9e,  0x12,  0x23,  0x12,  0x4d,  0x12,  0x94,  0x12,  0xce,  0x1e,  0x2d,  0x47,
+  0x37,  0x2d,  0xb1,  0xe0,  0xfe,  0xbc,  0xf0,  0xfe,  0xec,  0x0d,  0x13,  0x06,  0x12,  0x4d,  0x01,  0xfe,
+  0xe2,  0x15,  0x05,  0xfe,  0x38,  0x01,  0x31,  0xfe,  0x3a,  0x01,  0x77,  0xfe,  0xf0,  0x0d,  0xfe,  0x02,
+  0xec,  0xce,  0x62,  0x00,  0x5d,  0xfe,  0x04,  0xec,  0x20,  0x46,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,
+  0x01,  0xfe,  0x52,  0x16,  0xfb,  0xfe,  0x48,  0xf4,  0x0d,  0xfe,  0x18,  0x13,  0xaf,  0xfe,  0x02,  0xea,
+  0xce,  0x62,  0x7a,  0xfe,  0xc5,  0x13,  0x14,  0x1b,  0x37,  0x95,  0xa9,  0x5c,  0x05,  0xfe,  0x38,  0x01,
+  0x1c,  0xfe,  0xf0,  0xff,  0x0c,  0xfe,  0x60,  0x01,  0x05,  0xfe,  0x3a,  0x01,  0x0c,  0xfe,  0x62,  0x01,
+  0x3d,  0x12,  0x20,  0x24,  0x06,  0x12,  0x2d,  0x11,  0x2d,  0x8a,  0x13,  0x06,  0x03,  0x23,  0x03,  0x1e,
+  0x4d,  0xfe,  0xf7,  0x12,  0x1e,  0x94,  0xac,  0x12,  0x94,  0x07,  0x7a,  0xfe,  0x71,  0x13,  0xfe,  0x24,
+  0x1c,  0x14,  0x1a,  0x37,  0x95,  0xa9,  0xfe,  0xd9,  0x10,  0xb6,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,
+  0xfe,  0x80,  0x5d,  0x03,  0xb6,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0xfe,
+  0x03,  0x57,  0xb6,  0x23,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0xb6,  0x75,  0x03,  0x09,  0x04,
+  0x4c,  0xfe,  0x22,  0x13,  0xfe,  0x1c,  0x80,  0x07,  0x06,  0xfe,  0x1a,  0x13,  0xfe,  0x1e,  0x80,  0xe1,
+  0xfe,  0x1d,  0x80,  0xa4,  0xfe,  0x0c,  0x90,  0xfe,  0x0e,  0x13,  0xfe,  0x0e,  0x90,  0xa3,  0xfe,  0x3c,
+  0x90,  0xfe,  0x30,  0xf4,  0x0b,  0xfe,  0x3c,  0x50,  0xa0,  0x01,  0xfe,  0x82,  0x16,  0x2f,  0x07,  0x2d,
+  0xe0,  0x01,  0xfe,  0xbc,  0x15,  0x09,  0x04,  0x1d,  0x45,  0x01,  0xe7,  0x01,  0xe8,  0x11,  0xfe,  0xe9,
+  0x00,  0x09,  0x04,  0x4c,  0xfe,  0x2c,  0x13,  0x01,  0xfe,  0x14,  0x16,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,
+  0x90,  0xfe,  0x96,  0x90,  0x0c,  0xfe,  0x64,  0x01,  0x18,  0xfe,  0x66,  0x01,  0x09,  0x04,  0x4f,  0xfe,
+  0x12,  0x12,  0xfe,  0x03,  0x80,  0x74,  0xfe,  0x01,  0xec,  0x20,  0xfe,  0x80,  0x40,  0x12,  0x20,  0x63,
+  0x27,  0x11,  0xc8,  0x59,  0x1e,  0x20,  0xed,  0x76,  0x20,  0x03,  0xfe,  0x08,  0x1c,  0x05,  0xfe,  0xac,
+  0x00,  0xfe,  0x06,  0x58,  0x05,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x05,  0xfe,  0xb0,  0x00,  0xfe,
+  0x08,  0x58,  0x05,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x24,  0x69,  0x12,  0xc9,
+  0x23,  0x0c,  0x50,  0x0c,  0x3f,  0x13,  0x40,  0x48,  0x5f,  0x17,  0x1d,  0xfe,  0x90,  0x4d,  0xfe,  0x91,
+  0x54,  0x21,  0xfe,  0x08,  0x0f,  0x3e,  0x10,  0x13,  0x42,  0x48,  0x17,  0x4c,  0xfe,  0x90,  0x4d,  0xfe,
+  0x91,  0x54,  0x21,  0xfe,  0x1e,  0x0f,  0x24,  0x10,  0x12,  0x20,  0x78,  0x2c,  0x46,  0x1e,  0x20,  0xed,
+  0x76,  0x20,  0x11,  0xc8,  0xf6,  0xfe,  0xd6,  0xf0,  0xfe,  0x32,  0x0f,  0xea,  0x70,  0xfe,  0x14,  0x1c,
+  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x3c,  0xfe,  0x0c,  0x14,  0xee,  0xfe,  0x07,  0xe6,  0x1d,
+  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x86,  0x78,  0x2c,  0x46,  0xfa,  0xef,  0xfe,  0x42,
+  0x13,  0x2f,  0x07,  0x2d,  0xfe,  0x34,  0x13,  0x0a,  0x42,  0x01,  0x0e,  0xb0,  0xfe,  0x36,  0x12,  0xf0,
+  0xfe,  0x45,  0x48,  0x01,  0xe3,  0xfe,  0x00,  0xcc,  0xb0,  0xfe,  0xf3,  0x13,  0x3d,  0x75,  0x07,  0x10,
+  0xa3,  0x0a,  0x80,  0x01,  0x0e,  0xfe,  0x80,  0x5c,  0x01,  0x6f,  0xfe,  0x0e,  0x10,  0x07,  0x7e,  0x45,
+  0xf6,  0xfe,  0xd6,  0xf0,  0xfe,  0x6c,  0x0f,  0x03,  0xfe,  0x44,  0x58,  0x74,  0xfe,  0x01,  0xec,  0x97,
+  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1b,  0x76,  0x27,  0x01,  0xda,  0xfe,
+  0xdd,  0x10,  0x2a,  0xbc,  0x7d,  0xbd,  0x7f,  0x30,  0x2e,  0xd5,  0x07,  0x1b,  0xfe,  0x48,  0x12,  0x07,
+  0x0b,  0xfe,  0x56,  0x12,  0x07,  0x1a,  0xfe,  0x30,  0x12,  0x07,  0xc2,  0x16,  0xfe,  0x3e,  0x11,  0x07,
+  0xfe,  0x23,  0x00,  0x16,  0xfe,  0x4a,  0x11,  0x07,  0x06,  0x16,  0xfe,  0xa8,  0x11,  0x07,  0x19,  0xfe,
+  0x12,  0x12,  0x07,  0x00,  0x16,  0x22,  0x14,  0xc2,  0x01,  0x33,  0x9f,  0x2b,  0x01,  0x08,  0x8c,  0x43,
+  0x03,  0x2b,  0xfe,  0x62,  0x08,  0x0a,  0xca,  0x01,  0xfe,  0x32,  0x0e,  0x11,  0x7e,  0x02,  0x29,  0x2b,
+  0x2f,  0x07,  0x9b,  0xfe,  0xd9,  0x13,  0x79,  0x39,  0x68,  0x3a,  0x77,  0xfe,  0xfc,  0x10,  0x09,  0x04,
+  0x6a,  0xfe,  0x72,  0x12,  0xc0,  0x38,  0xc1,  0x4e,  0xf4,  0xf5,  0x8e,  0xfe,  0xc6,  0x10,  0x1e,  0x58,
+  0xfe,  0x26,  0x13,  0x05,  0x7b,  0x31,  0x7c,  0x77,  0xfe,  0x82,  0x0c,  0x0c,  0x54,  0x18,  0x55,  0x23,
+  0x0c,  0x7b,  0x0c,  0x7c,  0x01,  0xa8,  0x24,  0x69,  0x73,  0x12,  0x58,  0x01,  0xa5,  0xc0,  0x38,  0xc1,
+  0x4e,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x38,  0xfe,  0x05,  0xfa,  0x4e,  0xfe,
+  0x91,  0x10,  0x05,  0x56,  0x31,  0x57,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0c,  0x56,  0x18,  0x57,
+  0x83,  0xc0,  0x38,  0xc1,  0x4e,  0xf4,  0xf5,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x00,  0x56,  0xfe,  0xa1,
+  0x56,  0x0c,  0x52,  0x18,  0x53,  0x09,  0x04,  0x6a,  0xfe,  0x1e,  0x12,  0x1e,  0x58,  0xfe,  0x1f,  0x40,
+  0x05,  0x54,  0x31,  0x55,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x05,  0x56,  0x31,  0x57,  0xfe,  0x44,
+  0x50,  0xfe,  0xc6,  0x50,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x05,  0x39,
+  0x31,  0x3a,  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x02,  0x5c,  0x24,  0x06,  0x12,  0xcd,  0x02,  0x5b,
+  0x2b,  0x01,  0x08,  0x1f,  0x44,  0x30,  0x2e,  0xd5,  0x07,  0x06,  0x21,  0x44,  0x2f,  0x07,  0x9b,  0x21,
+  0x5b,  0x01,  0x6e,  0x1c,  0x3d,  0x16,  0x44,  0x09,  0x04,  0x0b,  0xe2,  0x79,  0x39,  0x68,  0x3a,  0xfe,
+  0x0a,  0x55,  0x34,  0xfe,  0x8b,  0x55,  0xbe,  0x39,  0xbf,  0x3a,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,
+  0x02,  0x5b,  0xfe,  0x19,  0x81,  0xaf,  0xfe,  0x19,  0x41,  0x02,  0x5b,  0x2b,  0x01,  0x08,  0x25,  0x32,
+  0x1f,  0xa2,  0x30,  0x2e,  0xd8,  0x4b,  0x1a,  0xfe,  0xa6,  0x12,  0x4b,  0x0b,  0x3b,  0x02,  0x44,  0x01,
+  0x08,  0x25,  0x32,  0x1f,  0xa2,  0x30,  0x2e,  0xd6,  0x07,  0x1a,  0x21,  0x44,  0x01,  0x08,  0x1f,  0xa2,
+  0x30,  0x2e,  0xfe,  0xe8,  0x09,  0xfe,  0xc2,  0x49,  0x60,  0x05,  0xfe,  0x9c,  0x00,  0x28,  0x84,  0x49,
+  0x04,  0x19,  0x34,  0x9f,  0xfe,  0xbb,  0x45,  0x4b,  0x00,  0x45,  0x3e,  0x06,  0x78,  0x3d,  0xfe,  0xda,
+  0x14,  0x01,  0x6e,  0x87,  0xfe,  0x4b,  0x45,  0xe2,  0x2f,  0x07,  0x9a,  0xe1,  0x05,  0xc6,  0x28,  0x84,
+  0x05,  0x3f,  0x28,  0x34,  0x5e,  0x02,  0x5b,  0xfe,  0xc0,  0x5d,  0xfe,  0xf8,  0x14,  0xfe,  0x03,  0x17,
+  0x05,  0x50,  0xb4,  0x0c,  0x50,  0x5e,  0x2b,  0x01,  0x08,  0x26,  0x5c,  0x01,  0xfe,  0xaa,  0x14,  0x02,
+  0x5c,  0x01,  0x08,  0x25,  0x32,  0x1f,  0x44,  0x30,  0x2e,  0xd6,  0x07,  0x06,  0x21,  0x44,  0x01,  0xfe,
+  0x8e,  0x13,  0xfe,  0x42,  0x58,  0xfe,  0x82,  0x14,  0xfe,  0xa4,  0x14,  0x87,  0xfe,  0x4a,  0xf4,  0x0b,
+  0x16,  0x44,  0xfe,  0x4a,  0xf4,  0x06,  0xfe,  0x0c,  0x12,  0x2f,  0x07,  0x9a,  0x85,  0x02,  0x5b,  0x05,
+  0x3f,  0xb4,  0x0c,  0x3f,  0x5e,  0x2b,  0x01,  0x08,  0x26,  0x5c,  0x01,  0xfe,  0xd8,  0x14,  0x02,  0x5c,
+  0x13,  0x06,  0x65,  0xfe,  0xca,  0x12,  0x26,  0xfe,  0xe0,  0x12,  0x72,  0xf1,  0x01,  0x08,  0x23,  0x72,
+  0x03,  0x8f,  0xfe,  0xdc,  0x12,  0x25,  0xfe,  0xdc,  0x12,  0x1f,  0xfe,  0xca,  0x12,  0x5e,  0x2b,  0x01,
+  0x08,  0xfe,  0xd5,  0x10,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0x1c,  0xfe,  0xff,  0x7f,
+  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0x1c,
+  0x3d,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,
+  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0xfe,  0x0b,  0x58,  0x03,  0x0a,  0x50,  0x01,
+  0x82,  0x0a,  0x3f,  0x01,  0x82,  0x03,  0xfc,  0x1c,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,
+  0x19,  0x48,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x63,  0x27,
+  0x0c,  0x52,  0x18,  0x53,  0xbe,  0x56,  0xbf,  0x57,  0x03,  0xfe,  0x62,  0x08,  0xfe,  0x82,  0x4a,  0xfe,
+  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x74,  0x03,  0x01,  0xfe,  0x14,  0x18,  0xfe,  0x42,  0x48,  0x5f,  0x60,
+  0x89,  0x01,  0x08,  0x1f,  0xfe,  0xa2,  0x14,  0x30,  0x2e,  0xd8,  0x01,  0x08,  0x1f,  0xfe,  0xa2,  0x14,
+  0x30,  0x2e,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,  0x05,  0xc6,  0x28,  0xfe,  0xcc,  0x12,  0x49,  0x04,
+  0x1b,  0xfe,  0xc4,  0x13,  0x23,  0x62,  0x1b,  0xe2,  0x4b,  0xc3,  0x64,  0xfe,  0xe8,  0x13,  0x3b,  0x13,
+  0x06,  0x17,  0xc3,  0x78,  0xdb,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa1,  0xff,  0x02,  0x83,
+  0x55,  0x62,  0x1a,  0xa4,  0xbb,  0xfe,  0x30,  0x00,  0x8e,  0xe4,  0x17,  0x2c,  0x13,  0x06,  0xfe,  0x56,
+  0x10,  0x62,  0x0b,  0xe1,  0xbb,  0xfe,  0x64,  0x00,  0x8e,  0xe4,  0x0a,  0xfe,  0x64,  0x00,  0x17,  0x93,
+  0x13,  0x06,  0xfe,  0x28,  0x10,  0x62,  0x06,  0xfe,  0x60,  0x13,  0xbb,  0xfe,  0xc8,  0x00,  0x8e,  0xe4,
+  0x0a,  0xfe,  0xc8,  0x00,  0x17,  0x4d,  0x13,  0x06,  0x83,  0xbb,  0xfe,  0x90,  0x01,  0xba,  0xfe,  0x4e,
+  0x14,  0x89,  0xfe,  0x12,  0x10,  0xfe,  0x43,  0xf4,  0x94,  0xfe,  0x56,  0xf0,  0xfe,  0x60,  0x14,  0xfe,
+  0x04,  0xf4,  0x6c,  0xfe,  0x43,  0xf4,  0x93,  0xfe,  0xf3,  0x10,  0xf9,  0x01,  0xfe,  0x22,  0x13,  0x1c,
+  0x3d,  0xfe,  0x10,  0x13,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x69,  0xba,  0xfe,  0x9c,  0x14,  0xb7,
+  0x69,  0xfe,  0x1c,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x19,  0xba,  0xfe,  0x9c,  0x14,  0xb7,
+  0x19,  0x83,  0x60,  0x23,  0xfe,  0x4d,  0xf4,  0x00,  0xdf,  0x89,  0x13,  0x06,  0xfe,  0xb4,  0x56,  0xfe,
+  0xc3,  0x58,  0x03,  0x60,  0x13,  0x0b,  0x03,  0x15,  0x06,  0x01,  0x08,  0x26,  0xe5,  0x15,  0x0b,  0x01,
+  0x08,  0x26,  0xe5,  0x15,  0x1a,  0x01,  0x08,  0x26,  0xe5,  0x72,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x03,
+  0x15,  0x06,  0x01,  0x08,  0x26,  0xa6,  0x15,  0x1a,  0x01,  0x08,  0x26,  0xa6,  0x15,  0x06,  0x01,  0x08,
+  0x26,  0xa6,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x26,  0xa6,  0x72,  0xfe,  0x89,  0x4a,  0x01,  0x08,  0x03,
+  0x60,  0x03,  0x1e,  0xcc,  0x07,  0x06,  0xfe,  0x44,  0x13,  0xad,  0x12,  0xcc,  0xfe,  0x49,  0xf4,  0x00,
+  0x3b,  0x72,  0x9f,  0x5e,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf1,  0x01,  0x08,  0x2f,  0x07,  0xfe,
+  0xe3,  0x00,  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0x5a,  0x15,  0x23,  0x12,  0xcd,  0x01,  0x43,  0x1e,  0xcd,
+  0x07,  0x06,  0x45,  0x09,  0x4a,  0x06,  0x35,  0x03,  0x0a,  0x42,  0x01,  0x0e,  0xed,  0x88,  0x07,  0x10,
+  0xa4,  0x0a,  0x80,  0x01,  0x0e,  0x88,  0x0a,  0x51,  0x01,  0x9e,  0x03,  0x0a,  0x80,  0x01,  0x0e,  0x88,
+  0xfe,  0x80,  0xe7,  0x10,  0x07,  0x10,  0x84,  0xfe,  0x45,  0x58,  0x01,  0xe3,  0x88,  0x03,  0x0a,  0x42,
+  0x01,  0x0e,  0x88,  0x0a,  0x51,  0x01,  0x9e,  0x03,  0x0a,  0x42,  0x01,  0x0e,  0xfe,  0x80,  0x80,  0xf2,
+  0xfe,  0x49,  0xe4,  0x10,  0xa4,  0x0a,  0x80,  0x01,  0x0e,  0xf2,  0x0a,  0x51,  0x01,  0x82,  0x03,  0x17,
+  0x10,  0x71,  0x66,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xfe,
+  0x1d,  0xf7,  0x1d,  0x90,  0xfe,  0xf6,  0x15,  0x01,  0xfe,  0xfc,  0x16,  0xe0,  0x91,  0x1d,  0x66,  0xfe,
+  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xae,  0x21,  0xfe,  0xe6,  0x15,  0xfe,  0xda,  0x10,  0x17,  0x10,
+  0x71,  0x05,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x19,  0xfe,  0x18,  0x58,  0x05,  0xfe,  0x66,  0x01,
+  0xfe,  0x19,  0x58,  0x91,  0x19,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x66,
+  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x19,  0x90,  0xfe,  0x40,  0x16,  0xfe,  0xb6,
+  0x14,  0x34,  0x03,  0xae,  0x21,  0xfe,  0x18,  0x16,  0xfe,  0x9c,  0x10,  0x17,  0x10,  0x71,  0xfe,  0x83,
+  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x38,  0x90,  0xfe,  0x62,  0x16,  0xfe,
+  0x94,  0x14,  0xfe,  0x10,  0x13,  0x91,  0x38,  0x66,  0x1b,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
+  0x03,  0xae,  0x21,  0xfe,  0x56,  0x16,  0xfe,  0x6c,  0x10,  0x17,  0x10,  0x71,  0xfe,  0x30,  0xbc,  0xfe,
+  0xb2,  0xbc,  0x91,  0xc5,  0x66,  0x1b,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xc5,  0x90,  0xfe,  0x9a,
+  0x16,  0xfe,  0x5c,  0x14,  0x34,  0x03,  0xae,  0x21,  0xfe,  0x86,  0x16,  0xfe,  0x42,  0x10,  0xfe,  0x02,
+  0xf6,  0x10,  0x71,  0xfe,  0x18,  0xfe,  0x54,  0xfe,  0x19,  0xfe,  0x55,  0xfc,  0xfe,  0x1d,  0xf7,  0x4f,
+  0x90,  0xfe,  0xc0,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x91,  0x4f,  0x47,  0xfe,  0x83,  0x58,
+  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x63,
+  0x27,  0x03,  0x63,  0x27,  0xfe,  0x12,  0x45,  0x21,  0xfe,  0xb0,  0x16,  0x14,  0x06,  0x37,  0x95,  0xa9,
+  0x02,  0x29,  0xfe,  0x39,  0xf0,  0xfe,  0x04,  0x17,  0x23,  0x03,  0xfe,  0x7e,  0x18,  0x1c,  0x1a,  0x5d,
+  0x13,  0x0d,  0x03,  0x71,  0x05,  0xcb,  0x1c,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x78,  0x2c,
+  0x46,  0x2f,  0x07,  0x2d,  0xfe,  0x3c,  0x13,  0xfe,  0x82,  0x14,  0xfe,  0x42,  0x13,  0x3c,  0x8a,  0x0a,
+  0x42,  0x01,  0x0e,  0xb0,  0xfe,  0x3e,  0x12,  0xf0,  0xfe,  0x45,  0x48,  0x01,  0xe3,  0xfe,  0x00,  0xcc,
+  0xb0,  0xfe,  0xf3,  0x13,  0x3d,  0x75,  0x07,  0x10,  0xa3,  0x0a,  0x80,  0x01,  0x0e,  0xf2,  0x01,  0x6f,
+  0xfe,  0x16,  0x10,  0x07,  0x7e,  0x85,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xf6,  0xfe,  0xd6,  0xf0,
+  0xfe,  0x24,  0x17,  0x17,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,  0x0f,  0xfe,  0x15,  0x00,  0x59,  0x76,
+  0x27,  0x01,  0xda,  0x17,  0x06,  0x03,  0x3c,  0x8a,  0x09,  0x4a,  0x1d,  0x35,  0x11,  0x2d,  0x01,  0x6f,
+  0x17,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x79,  0xc7,  0x68,  0xc8,  0xfe,  0x48,  0x55,
+  0x34,  0xfe,  0xc9,  0x55,  0x03,  0x1e,  0x98,  0x73,  0x12,  0x98,  0x03,  0x0a,  0x99,  0x01,  0x0e,  0xf0,
+  0x0a,  0x40,  0x01,  0x0e,  0xfe,  0x49,  0x44,  0x16,  0xfe,  0xf0,  0x17,  0x73,  0x75,  0x03,  0x0a,  0x42,
+  0x01,  0x0e,  0x07,  0x10,  0x45,  0x0a,  0x51,  0x01,  0x9e,  0x0a,  0x40,  0x01,  0x0e,  0x73,  0x75,  0x03,
+  0xfe,  0x4e,  0xe4,  0x1a,  0x64,  0xfe,  0x24,  0x18,  0x05,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0x5b,
+  0xfe,  0x4e,  0xe4,  0xc2,  0x64,  0xfe,  0x36,  0x18,  0x05,  0xfe,  0x92,  0x00,  0xfe,  0x02,  0xe6,  0x1b,
+  0xdc,  0xfe,  0x4e,  0xe4,  0xfe,  0x0b,  0x00,  0x64,  0xfe,  0x48,  0x18,  0x05,  0xfe,  0x94,  0x00,  0xfe,
+  0x02,  0xe6,  0x19,  0xfe,  0x08,  0x10,  0x05,  0xfe,  0x96,  0x00,  0xfe,  0x02,  0xe6,  0x2c,  0xfe,  0x4e,
+  0x45,  0xfe,  0x0c,  0x12,  0xaf,  0xff,  0x04,  0x68,  0x54,  0xde,  0x1c,  0x69,  0x03,  0x07,  0x7a,  0xfe,
+  0x5a,  0xf0,  0xfe,  0x74,  0x18,  0x24,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x07,  0x1b,  0xfe,  0x5a,
+  0xf0,  0xfe,  0x82,  0x18,  0x24,  0xc3,  0xfe,  0x26,  0x10,  0x07,  0x1a,  0x5d,  0x24,  0x2c,  0xdc,  0x07,
+  0x0b,  0x5d,  0x24,  0x93,  0xfe,  0x0e,  0x10,  0x07,  0x06,  0x5d,  0x24,  0x4d,  0x9f,  0xad,  0x03,  0x14,
+  0xfe,  0x09,  0x00,  0x01,  0x33,  0xfe,  0x04,  0xfe,  0x7d,  0x05,  0x7f,  0xf9,  0x03,  0x25,  0xfe,  0xca,
+  0x18,  0xfe,  0x14,  0xf0,  0x08,  0x65,  0xfe,  0xc6,  0x18,  0x03,  0xff,  0x1a,  0x00,  0x00,
 };
 
 STATIC unsigned short _adv_asc3550_size =
-    sizeof(_adv_asc3550_buf); /* 0x13E5 */
+        sizeof(_adv_asc3550_buf); /* 0x13AD */
 STATIC ADV_DCNT _adv_asc3550_chksum =
-    0x04FFFF0E; /* Expanded checksum. */
+        0x04D52DDDUL; /* Expanded little-endian checksum. */
 
+/* Microcode buffer is kept after initialization for error recovery. */
 STATIC unsigned char _adv_asc38C0800_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x18,  0xe4,
-  0x00,  0xf6,  0x01,  0xf6,  0x18,  0x80,  0x02,  0x00,  0x40,  0x1a,  0x00,  0xfa,  0xff,  0xff,  0x03,  0xf6,
-  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0x1a,  0x0f,  0x00,  0xea,  0x01,  0xe6,
-  0x03,  0x00,  0x55,  0xf0,  0x18,  0xf4,  0x1e,  0xf0,  0x3e,  0x57,  0x04,  0x00,  0x3e,  0x01,  0x85,  0xf0,
-  0x00,  0xe6,  0x03,  0xfc,  0x08,  0x00,  0x2c,  0x1a,  0x32,  0xf0,  0x86,  0xf0,  0xbe,  0x0d,  0xd4,  0x01,
-  0xd5,  0xf0,  0x00,  0xec,  0x01,  0xfc,  0x38,  0x54,  0x98,  0x57,  0xbc,  0x00,  0x0c,  0x1c,  0xb1,  0xf0,
-  0x3c,  0x00,  0xb4,  0x00,  0xb8,  0x0d,  0x00,  0x57,  0x01,  0xf0,  0x02,  0x13,  0x02,  0xfc,  0x03,  0xe6,
-  0x10,  0x00,  0x18,  0x40,  0x3e,  0x1c,  0x44,  0x13,  0x6c,  0x01,  0x6e,  0x01,  0xbd,  0x00,  0xe0,  0x00,
-  0x02,  0x80,  0x30,  0xe4,  0x3e,  0x00,  0x74,  0x01,  0x76,  0x01,  0x7c,  0x16,  0x80,  0x00,  0xb9,  0x54,
-  0xbb,  0x00,  0xee,  0x13,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x02,  0x48,  0x02,  0xfa,  0x04,  0x12,
-  0x08,  0x12,  0x3c,  0x56,  0x4e,  0x01,  0x5d,  0xf0,  0x7a,  0x01,  0x7e,  0x10,  0xb6,  0x00,  0xc2,  0x10,
-  0xee,  0x08,  0x00,  0x80,  0x05,  0xfc,  0x10,  0x44,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,
-  0x40,  0x00,  0x4b,  0xe4,  0x4b,  0xf4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,
-  0x78,  0x01,  0x7c,  0x01,  0xbb,  0x55,  0xc2,  0x0d,  0x00,  0x01,  0x02,  0xee,  0x03,  0x58,  0x03,  0xf7,
-  0x03,  0xfa,  0x04,  0x80,  0x08,  0x44,  0x09,  0xf0,  0x0f,  0x00,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,
-  0x4e,  0x1c,  0x5b,  0xf0,  0x62,  0x0a,  0xaa,  0x00,  0xbe,  0x00,  0xc0,  0x00,  0xc0,  0x15,  0xcc,  0x10,
-  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,  0x04,  0xfc,  0x05,  0x00,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,
-  0x06,  0xf7,  0x08,  0x13,  0x0a,  0x10,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x10,  0x0f,  0x20,  0x00,
-  0x20,  0x16,  0x2a,  0x01,  0x32,  0x1c,  0x36,  0x00,  0x42,  0x54,  0x44,  0x55,  0x45,  0x5a,  0x52,  0x0c,
-  0x59,  0xf0,  0x5c,  0xf0,  0x69,  0x08,  0x6e,  0x0b,  0x83,  0x59,  0xb8,  0xf0,  0xbd,  0x56,  0xcc,  0x18,
-  0xce,  0x10,  0xd8,  0x18,  0xf0,  0x00,  0x01,  0x48,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,  0x05,  0x80,
-  0x05,  0xe6,  0x06,  0x00,  0x06,  0x0f,  0x06,  0x12,  0x0b,  0xf0,  0x0c,  0x10,  0x0c,  0xf0,  0x10,  0x13,
-  0x12,  0x10,  0x19,  0x00,  0x19,  0xe4,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,  0x40,  0x5c,
-  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x6c,  0x15,  0x70,  0x15,  0x83,  0x55,  0x83,  0x5a,
-  0x91,  0x44,  0xa4,  0x00,  0xac,  0x13,  0xb0,  0x57,  0xb5,  0x00,  0xb8,  0x17,  0xba,  0x00,  0xce,  0x45,
-  0xd0,  0x00,  0xe1,  0x00,  0xe5,  0x55,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
-  0x03,  0xa1,  0x04,  0x13,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
-  0x0c,  0x12,  0x0c,  0x13,  0x0c,  0x90,  0x0e,  0x13,  0x10,  0x04,  0x10,  0x10,  0x12,  0x1c,  0x19,  0x81,
-  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
-  0x26,  0x01,  0x2a,  0x12,  0x2c,  0x0f,  0x30,  0xe7,  0x32,  0x15,  0x34,  0x1c,  0x36,  0x1c,  0x38,  0x12,
-  0x3a,  0x55,  0x3f,  0x00,  0x41,  0x58,  0x43,  0x48,  0x46,  0x1c,  0x4e,  0xe4,  0x76,  0x02,  0x77,  0x57,
-  0x78,  0x03,  0x89,  0x48,  0x8e,  0x90,  0x98,  0x80,  0x99,  0x00,  0xfe,  0x9c,  0xf0,  0x27,  0x02,  0xfe,
-  0xe0,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc6,  0x01,  0xfe,  0x56,  0x1a,  0x00,  0xfe,  0xc4,  0x01,
-  0xfe,  0x84,  0x01,  0xff,  0x03,  0x00,  0x00,  0xfe,  0x6a,  0x13,  0xfe,  0x05,  0x05,  0xff,  0x40,  0x00,
-  0x00,  0x0e,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,
-  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,
-  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x2e,  0x88,  0x0b,  0x01,  0xfe,  0xca,
-  0x0f,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x88,  0x0b,  0x1c,  0x2e,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,
-  0x01,  0xfe,  0x20,  0xf0,  0xdc,  0x04,  0x5f,  0x4f,  0x02,  0xfe,  0xfc,  0x0d,  0x01,  0xfe,  0x5c,  0x0e,
-  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x08,  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,
-  0x12,  0x47,  0x12,  0xfe,  0xa6,  0x00,  0xcd,  0xfe,  0x48,  0xf0,  0xfe,  0x80,  0x02,  0xfe,  0x49,  0xf0,
-  0xfe,  0x9a,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb8,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x4a,  0x02,  0xfe,
-  0x47,  0xf0,  0xfe,  0x50,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x42,
-  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x46,  0x02,  0x09,  0x0b,  0xa4,  0x09,  0x06,  0x12,  0xc1,  0x02,  0x27,
-  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,
-  0xe9,  0x10,  0x01,  0xfe,  0x2c,  0x18,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xfe,  0xa8,  0x00,  0x0f,
-  0x7c,  0x01,  0xaa,  0x02,  0x27,  0x17,  0x5e,  0x4c,  0xc4,  0x01,  0xfe,  0x40,  0x10,  0x0f,  0x7c,  0x01,
-  0x8e,  0xfe,  0xbd,  0x10,  0x0f,  0x7c,  0x01,  0x8e,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,
-  0x1c,  0x09,  0x06,  0x12,  0xc1,  0x2e,  0x1b,  0x27,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0x28,  0xfe,
-  0x8e,  0x02,  0xfe,  0x5a,  0x1c,  0xde,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4c,  0xc4,  0x01,
-  0xfe,  0x30,  0x10,  0x09,  0x06,  0x12,  0xc1,  0x02,  0xfe,  0xc6,  0x01,  0x29,  0x2d,  0x05,  0x10,  0x35,
-  0xfe,  0x69,  0x10,  0x09,  0x06,  0x12,  0xc1,  0xfe,  0x04,  0xec,  0x2d,  0x08,  0x2d,  0x09,  0x3e,  0x1c,
-  0x01,  0x45,  0x82,  0xfe,  0x05,  0xf6,  0xfe,  0xa8,  0x00,  0x01,  0xfe,  0x56,  0x17,  0x0a,  0x41,  0x8f,
-  0x39,  0x11,  0x48,  0x1c,  0xd2,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x90,  0x02,  0x27,  0x0f,  0x3f,  0x01,
-  0x15,  0x05,  0x10,  0xdb,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0xfe,  0x28,  0x10,  0x0f,  0xc8,  0x01,
-  0x15,  0xf2,  0x0f,  0x7d,  0x01,  0x15,  0xfe,  0x49,  0x54,  0x79,  0xfe,  0x16,  0x03,  0x08,  0x1e,  0x09,
-  0x52,  0x01,  0x90,  0x02,  0x27,  0x2e,  0x82,  0xfe,  0x02,  0xe8,  0x31,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,
-  0x43,  0xf7,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xdc,  0xfe,  0x40,  0x1c,  0x1b,  0xf8,  0xfe,  0x26,
-  0xf0,  0xfe,  0x74,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x62,  0x03,  0xfe,  0x11,  0xf0,  0xdc,  0xfe,  0x0e,
-  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x82,  0x03,  0xf4,  0x13,  0xfe,  0x11,  0x00,  0x02,  0x6b,  0x2e,  0xfe,
-  0x48,  0x1c,  0xf4,  0x1b,  0xf8,  0x34,  0xf8,  0xfe,  0x82,  0xf0,  0xfe,  0x88,  0x03,  0x2b,  0x29,  0xc6,
-  0x72,  0x16,  0xc6,  0x0f,  0x7d,  0x01,  0x15,  0x72,  0x80,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x45,  0x11,
-  0x3f,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x90,  0xfe,  0x9c,  0x32,  0x11,  0xfe,  0xe4,  0x00,  0x2f,  0xfe,
-  0xce,  0x03,  0x1b,  0x32,  0x1f,  0xfe,  0xde,  0x03,  0x01,  0x55,  0xd3,  0xfe,  0xee,  0x03,  0x73,  0x97,
-  0xd7,  0xfe,  0xae,  0x06,  0x02,  0x26,  0x04,  0x7c,  0x2c,  0x19,  0xfe,  0x20,  0x05,  0x17,  0x8b,  0x01,
-  0x3b,  0x01,  0x9f,  0x01,  0xa1,  0x34,  0xfe,  0x60,  0x02,  0x02,  0xf6,  0xf4,  0x2e,  0x88,  0x18,  0xfe,
-  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xf7,  0xfe,  0x48,  0x1c,  0x92,  0x01,  0xfe,  0x9c,  0x13,  0xb3,  0xfe,
-  0x96,  0xf0,  0xfe,  0x28,  0x04,  0x2f,  0xfe,  0x2c,  0x04,  0x34,  0x27,  0x0f,  0x3f,  0x01,  0x15,  0x05,
-  0x10,  0x19,  0xfe,  0x0c,  0x05,  0x4d,  0x7a,  0xa5,  0x31,  0x86,  0x76,  0x1b,  0x32,  0x1f,  0x26,  0x04,
-  0x7c,  0x2c,  0xfe,  0x10,  0x12,  0x17,  0x8b,  0x01,  0x3b,  0x34,  0xfe,  0x60,  0x02,  0x02,  0xf6,  0x21,
-  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,  0x12,  0x0a,  0x07,  0x06,  0xfe,  0x56,  0x12,  0x24,
-  0x23,  0x9a,  0x01,  0x0c,  0x86,  0x76,  0x1f,  0xfe,  0xdc,  0x04,  0x24,  0x23,  0x9a,  0x01,  0x0c,  0x1f,
-  0x26,  0x24,  0x23,  0xba,  0xfe,  0x4c,  0x44,  0xfe,  0x32,  0x12,  0x51,  0xfe,  0x44,  0x48,  0x08,  0xfe,
-  0x93,  0x00,  0xfe,  0x4c,  0x54,  0x79,  0xfe,  0x0c,  0x05,  0x82,  0xa5,  0x31,  0xfe,  0x06,  0x80,  0xfe,
-  0x48,  0x47,  0xfe,  0x48,  0x13,  0x40,  0x05,  0xfe,  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x07,  0x06,
-  0xef,  0xfe,  0x06,  0x10,  0x24,  0x23,  0xba,  0x0a,  0x07,  0x38,  0xe2,  0x17,  0xa9,  0x0a,  0x07,  0x06,
-  0x4f,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x3b,  0x34,  0xfe,  0xa0,  0x0d,  0x02,  0x26,  0x3a,  0x11,  0xfe,
-  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xb7,  0x03,  0x17,  0xa9,  0x01,  0x3b,  0x34,  0x27,  0x1b,  0x27,  0x02,
-  0xfe,  0x14,  0x05,  0xfe,  0x42,  0x5b,  0x88,  0x18,  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xf7,  0x17,
-  0x46,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0a,  0x07,  0x0b,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,
-  0x05,  0x18,  0xfe,  0x70,  0x12,  0x75,  0x07,  0x06,  0xfe,  0x60,  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x2c,
-  0x19,  0xfe,  0xac,  0x05,  0xfe,  0x31,  0xe4,  0x60,  0x75,  0x07,  0x0b,  0xfe,  0x4a,  0x13,  0x04,  0xfe,
-  0xa0,  0x00,  0x2c,  0xfe,  0x42,  0x12,  0x63,  0x2f,  0xfe,  0x6c,  0x05,  0x1b,  0x32,  0xf9,  0x01,  0x0c,
-  0x25,  0xfe,  0xc4,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x2b,  0x75,  0xfe,  0x4a,  0xf0,  0xfe,  0x96,  0x05,
-  0xfe,  0x49,  0xf0,  0xfe,  0x90,  0x05,  0xad,  0x20,  0xfe,  0x21,  0x00,  0x8a,  0x20,  0xfe,  0x22,  0x00,
-  0xa4,  0x20,  0x8f,  0xfe,  0x09,  0x48,  0x01,  0x0c,  0x25,  0xfe,  0xc4,  0x05,  0xfe,  0xe2,  0x08,  0x75,
-  0x07,  0xe1,  0x4f,  0x01,  0xc2,  0x20,  0x06,  0x16,  0xe8,  0x4c,  0xfe,  0x27,  0x01,  0x0a,  0x07,  0x38,
-  0xe9,  0x47,  0x01,  0xbd,  0x17,  0xa9,  0x0a,  0x07,  0x06,  0x4f,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x3b,
-  0x01,  0x9f,  0x01,  0xa1,  0x34,  0xfe,  0xa0,  0x0d,  0x02,  0x26,  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0xfe,
-  0x3e,  0x12,  0x04,  0x5c,  0x2c,  0xfe,  0x36,  0x13,  0x47,  0x01,  0xbd,  0x25,  0xfe,  0x3c,  0x06,  0x0f,
-  0x06,  0x75,  0x07,  0x22,  0xfe,  0x02,  0x12,  0x6a,  0x01,  0xfe,  0x06,  0x15,  0x1f,  0xfe,  0x32,  0x06,
-  0x11,  0xc9,  0x01,  0x55,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x5c,  0xc3,  0x0d,  0x5c,  0x04,  0xfe,  0x9e,
-  0x00,  0x2c,  0xfe,  0x62,  0x12,  0x04,  0x56,  0x2c,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x7e,  0x19,  0x01,
-  0xfe,  0xe8,  0x19,  0xf3,  0xa8,  0xf1,  0x08,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x6e,  0x81,  0x1a,  0x59,
-  0xd1,  0xa8,  0x74,  0x47,  0x01,  0xbd,  0x25,  0xfe,  0xa6,  0x06,  0x75,  0x07,  0x1d,  0xab,  0x9e,  0x0f,
-  0x5e,  0x01,  0xfe,  0x34,  0x15,  0x1f,  0xfe,  0x9c,  0x06,  0x11,  0xc9,  0x01,  0x55,  0x11,  0xfe,  0xe5,
-  0x00,  0x04,  0x56,  0xc3,  0x0d,  0x56,  0x09,  0x06,  0x01,  0xbd,  0xfe,  0x9c,  0x32,  0x78,  0x92,  0x01,
-  0xfe,  0x9c,  0x13,  0xb3,  0x11,  0xfe,  0xe2,  0x00,  0x2f,  0xfe,  0xbe,  0x06,  0x1b,  0x32,  0xd7,  0xfe,
-  0xda,  0x06,  0x85,  0xfe,  0x78,  0x07,  0xd3,  0xfe,  0x80,  0x07,  0x73,  0x97,  0x02,  0x26,  0x0a,  0x07,
-  0x0b,  0xfe,  0x2e,  0x12,  0x14,  0x18,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,
-  0x14,  0x00,  0x01,  0x0c,  0xfe,  0x99,  0xa4,  0x01,  0x0c,  0x14,  0x00,  0x02,  0xfe,  0x50,  0x08,  0x71,
-  0x07,  0x1d,  0xef,  0x0a,  0x07,  0x1d,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x0c,  0x14,
-  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x06,  0x01,  0x0c,  0x14,
-  0x00,  0x02,  0xfe,  0x0a,  0x0c,  0x6a,  0xfe,  0x9a,  0x81,  0x6f,  0x8f,  0xfe,  0x09,  0x6f,  0xfe,  0x93,
-  0x45,  0x19,  0xfe,  0x88,  0x07,  0x2f,  0xfe,  0x60,  0x07,  0x1b,  0x32,  0xd7,  0xfe,  0x58,  0x07,  0x73,
-  0x97,  0x85,  0xfe,  0x78,  0x07,  0x02,  0x26,  0x01,  0x55,  0x02,  0xfe,  0xbe,  0x06,  0x14,  0x22,  0x02,
-  0xfe,  0xbe,  0x06,  0xfe,  0x9c,  0xf7,  0xfe,  0xf0,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x53,
-  0xfe,  0xd6,  0x07,  0x0d,  0x66,  0x12,  0x67,  0x0a,  0x41,  0x60,  0x39,  0x01,  0xfe,  0x14,  0x19,  0x05,
-  0x10,  0x87,  0xfe,  0x83,  0xe7,  0xfe,  0x95,  0x00,  0x8a,  0xfe,  0x03,  0x40,  0x0a,  0x41,  0x46,  0x39,
-  0x01,  0xc5,  0xb6,  0xfe,  0x1f,  0x40,  0x16,  0x68,  0x01,  0xfe,  0xbe,  0x13,  0xfe,  0x08,  0x50,  0xfe,
-  0x8a,  0x50,  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0d,  0x64,
-  0x12,  0x65,  0xda,  0xfa,  0x0d,  0x3c,  0x12,  0x3d,  0xfe,  0x60,  0x10,  0x0a,  0x07,  0x60,  0xe9,  0xfe,
-  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0d,  0x66,  0x12,  0x67,  0x0a,  0x07,  0x46,  0xd1,  0x01,  0xc5,  0xfe,
-  0x1f,  0x80,  0x16,  0x68,  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0d,  0x43,  0x12,  0x44,  0xfe,  0x08,
-  0x90,  0xfe,  0x8a,  0x90,  0x0d,  0x64,  0x12,  0x65,  0xa7,  0x07,  0x46,  0xdb,  0xda,  0xfa,  0x0d,  0x3c,
-  0x12,  0x3d,  0xad,  0xfe,  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0d,  0x3c,  0x12,  0x3d,  0x0d,  0x30,  0x12,
-  0x42,  0x2b,  0x0d,  0x54,  0x0d,  0x69,  0x0a,  0x41,  0x22,  0x39,  0x2e,  0x08,  0x84,  0x2f,  0xfe,  0x70,
-  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x84,  0x08,  0xa3,  0x19,  0x32,  0x2e,  0x5b,  0xfe,  0xed,  0x10,  0xac,
-  0xfe,  0xa8,  0x08,  0xae,  0xfe,  0xc4,  0x08,  0x85,  0xfe,  0x9c,  0x08,  0xd3,  0xfe,  0xa2,  0x08,  0x73,
-  0x97,  0x02,  0x26,  0x01,  0x55,  0xfe,  0xc9,  0x10,  0x14,  0x22,  0xfe,  0xc9,  0x10,  0x71,  0x07,  0x06,
-  0xfe,  0x10,  0x12,  0x71,  0x07,  0x0b,  0x50,  0x0a,  0x07,  0x0b,  0xfe,  0xa6,  0x12,  0xfe,  0x2e,  0x1c,
-  0xb0,  0x71,  0x07,  0x06,  0x50,  0x71,  0x07,  0x0b,  0xfe,  0x92,  0x12,  0xfe,  0x2c,  0x1c,  0xa7,  0x07,
-  0x46,  0xaf,  0xa7,  0x41,  0x46,  0xfe,  0x05,  0x40,  0xda,  0xfa,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,
-  0xfe,  0xaa,  0xf0,  0xfe,  0xf6,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x24,  0x09,  0x02,  0xfe,  0x02,  0x0a,
-  0xfe,  0xb7,  0xf0,  0xfe,  0x20,  0x09,  0xfe,  0x02,  0xf6,  0x1d,  0x6a,  0xfe,  0x70,  0x18,  0xfe,  0xf1,
-  0x18,  0xfe,  0x40,  0x55,  0xfe,  0xe1,  0x55,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,
-  0xfe,  0x95,  0x59,  0x1b,  0x9b,  0xfe,  0x8c,  0xf0,  0xfe,  0x20,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x14,
-  0x09,  0xed,  0xfe,  0xcb,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0x30,  0x09,  0x02,  0xfe,  0x3c,  0x0b,  0xee,
-  0xfe,  0xbf,  0x10,  0xfe,  0x2b,  0xf0,  0x9b,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xfe,  0xe2,  0xcd,
-  0xfe,  0xd2,  0xf0,  0x9b,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0x19,  0x9b,  0x04,  0xe7,  0x1a,  0x06,  0x19,
-  0x9b,  0xac,  0x58,  0xae,  0x58,  0xed,  0xee,  0xfe,  0x89,  0x10,  0x92,  0x63,  0x3a,  0x17,  0xa9,  0x01,
-  0x3b,  0x13,  0xfe,  0x35,  0x00,  0x34,  0x6b,  0x13,  0x93,  0x02,  0x6b,  0xfb,  0xb2,  0x0b,  0xfe,  0x1a,
-  0x12,  0x51,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xf0,  0xdf,  0xfe,  0x74,  0x18,
-  0x94,  0x95,  0x19,  0xfe,  0xf2,  0x08,  0x02,  0x58,  0x0a,  0x07,  0x60,  0xaf,  0x04,  0x30,  0x2a,  0x42,
-  0x0d,  0x43,  0x12,  0x44,  0x83,  0x30,  0x5a,  0x42,  0xfe,  0x6c,  0x18,  0xfe,  0xed,  0x18,  0xfe,  0x44,
-  0x54,  0xfe,  0xe5,  0x54,  0x36,  0x43,  0x21,  0x44,  0x04,  0x54,  0x2a,  0x69,  0x94,  0xfe,  0xe3,  0x54,
-  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x94,  0xfe,  0xe3,  0x54,  0x95,  0xca,  0x53,  0xfe,  0xf2,  0x08,
-  0x02,  0x58,  0xfe,  0x37,  0xf0,  0xfe,  0xfe,  0x09,  0xfe,  0x8b,  0xf0,  0xfe,  0x84,  0x09,  0x02,  0x58,
-  0xfb,  0xb2,  0x0b,  0x28,  0xfe,  0x1e,  0x0b,  0x36,  0x54,  0x21,  0x69,  0x53,  0x7a,  0x08,  0xfe,  0xc0,
-  0x07,  0x47,  0x62,  0x00,  0xd9,  0xfe,  0x01,  0x59,  0xfe,  0x52,  0xf0,  0xfe,  0x30,  0x0a,  0x94,  0x99,
-  0xfe,  0x48,  0x0a,  0x36,  0x54,  0x94,  0xfe,  0xe3,  0x54,  0x4e,  0x54,  0x70,  0x69,  0xfe,  0x14,  0x58,
-  0xfe,  0x95,  0x58,  0x02,  0x58,  0x36,  0x54,  0x21,  0x69,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0xf0,
-  0x4e,  0x54,  0x4e,  0x69,  0x02,  0x58,  0x0a,  0x07,  0x60,  0xfe,  0x82,  0x12,  0x0a,  0x07,  0x22,  0xfe,
-  0x66,  0x13,  0x29,  0x68,  0x72,  0xd0,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,
-  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6d,  0x31,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x53,  0xfe,  0xfa,
-  0x08,  0x04,  0x66,  0x2a,  0x67,  0x0d,  0xb5,  0x12,  0x93,  0x4e,  0x66,  0x70,  0x67,  0x01,  0xc5,  0xb6,
-  0x6d,  0x31,  0x16,  0x68,  0x83,  0x30,  0x5a,  0x42,  0x36,  0x43,  0x21,  0x44,  0x95,  0xca,  0xfe,  0x04,
-  0xfa,  0x30,  0xfe,  0x05,  0xfa,  0x42,  0x01,  0xfe,  0xbe,  0x13,  0xfe,  0x36,  0x10,  0x2b,  0x0d,  0xb5,
-  0x0d,  0x93,  0x36,  0x43,  0x21,  0x44,  0xb0,  0x0a,  0x07,  0x22,  0x19,  0xfe,  0xfa,  0x08,  0x36,  0x3c,
-  0x21,  0x3d,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x39,  0x04,  0x64,  0x2a,  0x65,  0xfe,  0x10,  0x58,  0xfe,
-  0x91,  0x58,  0x4e,  0x54,  0x70,  0x69,  0x02,  0xfe,  0x18,  0x0a,  0x0a,  0x07,  0x22,  0x19,  0xfe,  0xfa,
-  0x08,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x39,  0xf0,  0xdf,  0x6a,  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,
-  0xfe,  0xd3,  0x10,  0x40,  0x05,  0xcb,  0x19,  0xfe,  0x2c,  0x09,  0x11,  0xcb,  0xfb,  0xb2,  0x0b,  0xfe,
-  0x14,  0x13,  0x04,  0x3c,  0x2a,  0x3d,  0x53,  0xfe,  0x2c,  0x09,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,
-  0x02,  0x58,  0x2b,  0x47,  0xfe,  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0a,  0x07,  0x0b,  0xab,  0xfe,  0x6c,
-  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0x4e,  0x3c,  0xfe,  0xed,  0x19,  0x70,
-  0x3d,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xff,  0x35,  0xfe,
-  0x74,  0x10,  0xcd,  0xfe,  0xd2,  0xf0,  0xfe,  0xb6,  0x0b,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0xd6,  0x04,
-  0xe7,  0x1a,  0x06,  0x89,  0x13,  0xfe,  0x16,  0x00,  0x02,  0x6b,  0xfe,  0xd1,  0xf0,  0xfe,  0xc8,  0x0b,
-  0x17,  0x84,  0x01,  0x3b,  0x13,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xce,
-  0x0b,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xda,  0x0b,  0x13,  0xfe,  0x22,  0x00,  0x02,  0x6b,
-  0xfe,  0xcb,  0xf0,  0xfe,  0xe6,  0x0b,  0x13,  0xfe,  0x24,  0x00,  0x02,  0x6b,  0xfe,  0xd0,  0xf0,  0xfe,
-  0xf0,  0x0b,  0x13,  0xb1,  0xe0,  0xfe,  0xcf,  0xf0,  0xfe,  0xfa,  0x0b,  0x13,  0x8f,  0xdd,  0xfe,  0xcc,
-  0xf0,  0xfe,  0x0a,  0x0c,  0xfe,  0x84,  0x80,  0xb2,  0x22,  0x4f,  0x13,  0xfe,  0x12,  0x00,  0x2e,  0x08,
-  0x84,  0x2f,  0xfe,  0x10,  0x0c,  0xfe,  0x9e,  0xf0,  0xfe,  0x24,  0x0c,  0xa3,  0x19,  0x32,  0x2e,  0x5b,
-  0xfe,  0xed,  0x10,  0xac,  0x26,  0xae,  0x26,  0x2e,  0xfe,  0x9c,  0x32,  0x2f,  0xfe,  0x30,  0x0c,  0x1b,
-  0x32,  0x85,  0xfe,  0x4c,  0x0c,  0x73,  0x97,  0xac,  0xfe,  0xf0,  0x07,  0xae,  0xfe,  0xf0,  0x07,  0x02,
-  0x26,  0x01,  0x55,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0xed,  0xee,  0x92,  0x86,  0x76,  0xfe,
-  0x89,  0xf0,  0x26,  0x24,  0x23,  0xfe,  0xe9,  0x09,  0x01,  0x0c,  0x86,  0x76,  0x1f,  0x26,  0x24,  0x23,
-  0x9a,  0x34,  0xfe,  0x88,  0x0c,  0x1b,  0x32,  0x02,  0xfe,  0x7c,  0x0c,  0xa3,  0x50,  0x13,  0xfe,  0x42,
-  0x00,  0x02,  0x6b,  0xa6,  0x06,  0xfe,  0x81,  0x49,  0xfe,  0xcc,  0x12,  0x0a,  0x07,  0x0b,  0xfe,  0x5a,
-  0x13,  0x13,  0x00,  0x61,  0x0b,  0xfe,  0x6a,  0x12,  0x61,  0xfe,  0x28,  0x00,  0x28,  0xfe,  0xce,  0x0d,
-  0x0f,  0x7d,  0x01,  0x15,  0x05,  0x00,  0x89,  0x37,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0xce,  0x0d,  0x01,
-  0x9f,  0x01,  0xa1,  0x0f,  0xc8,  0x01,  0xfe,  0x24,  0x0f,  0xb9,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,
-  0x11,  0x48,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0x02,  0x27,  0x13,  0xfe,  0x44,  0x00,  0x61,  0x0b,
-  0xab,  0x37,  0x0b,  0xfe,  0xc0,  0x10,  0x01,  0xc2,  0x37,  0x0b,  0xfe,  0xb6,  0x10,  0x01,  0xc2,  0xfe,
-  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x37,  0x0b,  0x13,  0xfe,  0x43,  0x00,  0xfe,  0xa2,
-  0x10,  0x0a,  0x41,  0x0b,  0x39,  0x01,  0x9f,  0x01,  0xa1,  0xb9,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,
-  0x11,  0x48,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0x88,  0x0b,  0xb9,  0x1c,  0xd2,  0x02,  0xfe,  0x4c,
-  0x03,  0x0a,  0x07,  0x0b,  0xd6,  0x37,  0x0b,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x71,  0x07,  0x1d,  0xfe,
-  0x50,  0x12,  0x0a,  0x07,  0x1d,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x8c,
-  0x0d,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x92,  0x0d,  0x0a,  0x41,  0x1d,  0x39,  0xfe,  0x95,
-  0x10,  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0b,  0x6a,  0xfe,  0x26,  0x10,  0x13,  0xfe,  0x13,
-  0x00,  0xdd,  0x13,  0xfe,  0x47,  0x00,  0x8a,  0x13,  0xfe,  0x41,  0x00,  0xa4,  0x13,  0xfe,  0x24,  0x00,
-  0x04,  0x7c,  0x2c,  0x28,  0xf6,  0x6a,  0xfe,  0x04,  0xe6,  0x1d,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,
-  0xb9,  0x01,  0xea,  0x02,  0x27,  0xde,  0x17,  0x0b,  0x4c,  0xfe,  0x9b,  0x00,  0xe5,  0x17,  0xfe,  0x31,
-  0x00,  0x4c,  0xc4,  0x01,  0xfe,  0x30,  0x10,  0x02,  0xfe,  0xc6,  0x01,  0x1c,  0xfe,  0x06,  0xec,  0xfe,
-  0xb9,  0x00,  0x8c,  0x37,  0x38,  0xc7,  0x35,  0x1c,  0xfe,  0x06,  0xea,  0xfe,  0xb9,  0x00,  0xfe,  0x47,
-  0x4b,  0x9e,  0xfe,  0x75,  0x57,  0x04,  0x5f,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0f,  0x7d,  0xfe,
-  0xf4,  0x14,  0x47,  0xf2,  0x0f,  0xc8,  0xfe,  0xea,  0x14,  0xfe,  0x49,  0x54,  0x98,  0xfe,  0x42,  0x0e,
-  0x0f,  0x1e,  0xfe,  0xde,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x4c,  0x03,  0x0f,  0x5f,  0xfe,  0xc8,
-  0x14,  0x8c,  0x37,  0x38,  0xc7,  0x35,  0x1c,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x27,  0x29,
-  0x2d,  0x05,  0x10,  0xfe,  0x78,  0x12,  0x2b,  0x16,  0x5e,  0x16,  0xb4,  0x29,  0x48,  0x47,  0x4c,  0x48,
-  0xa3,  0xd9,  0xfe,  0xbc,  0xf0,  0xfe,  0xde,  0x0e,  0x08,  0x06,  0x16,  0x5e,  0x01,  0xfe,  0xe6,  0x16,
-  0x04,  0xfe,  0x38,  0x01,  0x2a,  0xfe,  0x3a,  0x01,  0x53,  0xfe,  0xe2,  0x0e,  0x04,  0xfe,  0x38,  0x01,
-  0x1a,  0xfe,  0xf0,  0xff,  0x0d,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0d,  0xfe,  0x62,  0x01,
-  0x20,  0x06,  0x16,  0x48,  0xfe,  0x04,  0xec,  0x2d,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x01,  0x45,  0x82,
-  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x56,  0x17,  0x11,  0x48,  0xd2,  0x08,  0x06,  0x03,
-  0x2b,  0x03,  0x29,  0x5e,  0xfe,  0xf7,  0x12,  0x29,  0xb4,  0x72,  0x16,  0xb4,  0x05,  0x84,  0xfe,  0x93,
-  0x13,  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x4c,  0xfe,  0x9b,  0x00,  0xe5,  0xfe,  0xd9,  0x10,  0x9c,  0xfe,
-  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x9c,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,
-  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x9c,  0x2b,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,
-  0x9c,  0x80,  0x03,  0x01,  0xfe,  0x8e,  0x17,  0x40,  0x05,  0x48,  0xfe,  0x0a,  0x13,  0x08,  0x1e,  0x09,
-  0x52,  0xdd,  0x01,  0x9f,  0x01,  0xa1,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,  0x11,  0xfe,  0xe9,  0x00,
-  0x0a,  0x07,  0x8f,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0x18,  0x17,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,
-  0x0d,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0d,  0xfe,  0x66,  0x01,  0x0a,  0x07,  0x46,  0xef,  0xfe,
-  0x03,  0x80,  0x5b,  0x4d,  0x11,  0x7b,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x7a,  0x01,  0x90,  0xfe,  0x62,
-  0x08,  0x72,  0x4d,  0x11,  0x7b,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x7a,  0x01,  0x90,  0x6d,  0x31,  0x11,
-  0x7b,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x7a,  0x01,  0x7e,  0x03,  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,
-  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,
-  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x20,  0x74,  0x16,  0xfe,
-  0xb9,  0x00,  0x2b,  0x0d,  0x5c,  0x0d,  0x56,  0x20,  0x10,  0x16,  0x2d,  0x16,  0x3e,  0x51,  0xa6,  0xfe,
-  0x93,  0x00,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x01,  0x7e,  0x82,  0x11,  0x7b,  0xfe,  0x14,  0x56,  0xfe,
-  0xd6,  0xf0,  0x8a,  0xde,  0x92,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1c,
-  0xfe,  0x0c,  0x14,  0x8c,  0xfe,  0x07,  0xe6,  0x38,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,
-  0xc2,  0x0f,  0x3f,  0x01,  0x15,  0x05,  0x10,  0xdb,  0x0f,  0x1e,  0x01,  0x15,  0x05,  0x10,  0xe2,  0xfe,
-  0x44,  0x58,  0x4d,  0xfe,  0x01,  0xec,  0xc4,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,
-  0xe7,  0x1d,  0xa5,  0x31,  0x01,  0xea,  0xfe,  0xc9,  0x10,  0x03,  0x2e,  0x86,  0x76,  0x24,  0x23,  0xba,
-  0x05,  0x1d,  0xfe,  0x48,  0x12,  0x05,  0x0b,  0xfe,  0x4c,  0x12,  0x05,  0x18,  0xfe,  0x30,  0x12,  0x05,
-  0xd4,  0x19,  0xfe,  0xd4,  0x11,  0x05,  0xfe,  0x23,  0x00,  0x19,  0xfe,  0xe0,  0x11,  0x05,  0x06,  0x19,
-  0xfe,  0x3e,  0x12,  0x05,  0x22,  0xfe,  0x12,  0x12,  0x05,  0x00,  0x19,  0x26,  0x17,  0xd4,  0x01,  0x3b,
-  0xce,  0x3a,  0x01,  0x0c,  0x85,  0x55,  0x03,  0x3a,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x27,  0x3a,  0x40,
-  0x05,  0xcb,  0xfe,  0xe3,  0x13,  0x36,  0x3c,  0x21,  0x3d,  0x53,  0xfe,  0x92,  0x11,  0x0a,  0x07,  0x60,
-  0xfe,  0x72,  0x12,  0x83,  0x30,  0x5a,  0x42,  0x95,  0xca,  0x98,  0xfe,  0x5c,  0x11,  0x29,  0x68,  0xfe,
-  0x26,  0x13,  0x04,  0xb5,  0x2a,  0x93,  0x53,  0xfe,  0xb2,  0x0d,  0x0d,  0x66,  0x12,  0x67,  0x2b,  0x0d,
-  0xb5,  0x0d,  0x93,  0x01,  0xc5,  0x20,  0x74,  0x5b,  0x16,  0x68,  0x01,  0xfe,  0xbe,  0x13,  0x83,  0x30,
-  0x5a,  0x42,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x30,  0xfe,  0x05,  0xfa,  0x42,
-  0xfe,  0x91,  0x10,  0x04,  0x43,  0x2a,  0x44,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0d,  0x43,  0x12,
-  0x44,  0xad,  0x83,  0x30,  0x5a,  0x42,  0x95,  0xca,  0x04,  0x64,  0x2a,  0x65,  0xfe,  0x00,  0x56,  0xfe,
-  0xa1,  0x56,  0x0d,  0x64,  0x12,  0x65,  0x0a,  0x07,  0x60,  0xfe,  0x1e,  0x12,  0x29,  0x68,  0xfe,  0x1f,
-  0x40,  0x04,  0x66,  0x2a,  0x67,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,  0x43,  0x2a,  0x44,  0xfe,
-  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x64,  0x2a,  0x65,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x04,
-  0x3c,  0x2a,  0x3d,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0xa0,  0x20,  0x06,  0x16,  0xfc,  0x02,
-  0x7f,  0x3a,  0x01,  0x0c,  0x1f,  0x57,  0x24,  0x23,  0xba,  0x05,  0x06,  0x28,  0x57,  0x40,  0x05,  0xcb,
-  0x28,  0x7f,  0x01,  0xfe,  0x9c,  0x13,  0x1a,  0x59,  0x19,  0x57,  0x0a,  0x07,  0x0b,  0xe4,  0x36,  0x3c,
-  0x21,  0x3d,  0xfe,  0x0a,  0x55,  0x35,  0xfe,  0x8b,  0x55,  0x4e,  0x3c,  0x70,  0x3d,  0xfe,  0x0c,  0x51,
-  0xfe,  0x8e,  0x51,  0x02,  0x7f,  0xdf,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7f,  0x3a,  0x01,
-  0x0c,  0x1f,  0xfe,  0xd6,  0x10,  0x24,  0x23,  0xfe,  0xe9,  0x09,  0x61,  0x18,  0xfe,  0x94,  0x12,  0x61,
-  0x0b,  0x4f,  0x02,  0x57,  0x2f,  0xfe,  0x5e,  0x12,  0x1b,  0x32,  0x1f,  0xfe,  0xd6,  0x10,  0x24,  0x23,
-  0x9a,  0x05,  0x18,  0x28,  0x57,  0x01,  0x0c,  0x1f,  0xfe,  0xd6,  0x10,  0x24,  0x23,  0xfe,  0xe8,  0x09,
-  0x51,  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0x35,  0xfe,  0xbb,  0x45,  0x61,  0x00,  0x50,  0x37,  0x06,  0xa6,
-  0x59,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xb3,  0x40,  0x05,  0xc9,  0xfe,  0x16,  0x13,  0x04,  0xfe,
-  0x9e,  0x00,  0x2c,  0xd6,  0x04,  0x56,  0x2c,  0x35,  0x63,  0x02,  0x7f,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,
-  0x14,  0xfe,  0x03,  0x17,  0x04,  0x5c,  0xc3,  0x0d,  0x5c,  0x63,  0x3a,  0x01,  0x0c,  0x25,  0xa0,  0x01,
-  0xfe,  0x06,  0x15,  0x02,  0xa0,  0x2f,  0xfe,  0xe8,  0x12,  0x1b,  0x32,  0x1f,  0x57,  0x24,  0x23,  0x9a,
-  0x05,  0x06,  0x28,  0x57,  0xfe,  0xf6,  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,
-  0xb3,  0xfe,  0x4a,  0xf4,  0x0b,  0x19,  0x57,  0xfe,  0x4a,  0xf4,  0x06,  0xd8,  0x40,  0x05,  0xc9,  0xd1,
-  0x02,  0x7f,  0x04,  0x56,  0xc3,  0x0d,  0x56,  0x63,  0x3a,  0x01,  0x0c,  0x25,  0xa0,  0x01,  0xfe,  0x34,
-  0x15,  0x02,  0xa0,  0x25,  0xfe,  0x50,  0x13,  0x78,  0xf9,  0x78,  0x03,  0x34,  0xfe,  0x4c,  0x13,  0x73,
-  0xfe,  0x4c,  0x13,  0x63,  0x3a,  0x01,  0x0c,  0xfe,  0xe3,  0x10,  0x08,  0x6c,  0xff,  0x02,  0x00,  0x57,
-  0x6e,  0x81,  0x1a,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x6c,  0xff,
-  0x02,  0x00,  0x57,  0x6e,  0x81,  0x1a,  0x59,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x6c,
-  0xff,  0x02,  0x00,  0x57,  0x6e,  0x81,  0x03,  0x08,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x6e,  0x81,  0xfe,
-  0x0b,  0x58,  0x03,  0x0f,  0x5c,  0x01,  0x8e,  0x0f,  0x56,  0x01,  0x8e,  0x03,  0xd0,  0x1a,  0x10,  0xff,
-  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x22,  0x6e,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,
-  0x7d,  0xfe,  0x03,  0x7c,  0x6d,  0x31,  0x0d,  0x64,  0x12,  0x65,  0x4e,  0x43,  0x70,  0x44,  0x03,  0xfe,
-  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,  0xbf,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x7e,
-  0x19,  0xfe,  0x42,  0x48,  0x6a,  0x51,  0x9e,  0x01,  0x0c,  0x1f,  0xfe,  0xfe,  0x14,  0x24,  0x23,  0xfe,
-  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,  0x0c,  0x1f,  0xfe,  0xfe,  0x14,  0x24,  0x23,  0xfe,  0xe8,  0x0a,
-  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0xc4,  0x12,  0x2b,  0xb8,  0x1d,  0xe4,  0x61,  0xd5,  0x79,  0xfe,
-  0x4c,  0x14,  0x4f,  0x08,  0x06,  0x09,  0xd5,  0xa6,  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,
-  0x83,  0x55,  0x8a,  0xff,  0x02,  0x83,  0x55,  0xb8,  0x18,  0xfe,  0x12,  0x13,  0x62,  0xfe,  0x30,  0x00,
-  0x98,  0xfe,  0xa6,  0x14,  0x09,  0x8b,  0x08,  0x06,  0xfe,  0x56,  0x10,  0xb8,  0x0b,  0xfe,  0x16,  0x13,
-  0x62,  0xfe,  0x64,  0x00,  0x98,  0xfe,  0xa6,  0x14,  0x0f,  0xfe,  0x64,  0x00,  0x09,  0xb1,  0x08,  0x06,
-  0xfe,  0x28,  0x10,  0xb8,  0x06,  0xfe,  0x60,  0x13,  0x62,  0xfe,  0xc8,  0x00,  0x98,  0xfe,  0xa6,  0x14,
-  0x0f,  0xfe,  0xc8,  0x00,  0x09,  0x5e,  0x08,  0x06,  0xad,  0x62,  0xfe,  0x90,  0x01,  0x99,  0xfe,  0xb2,
-  0x14,  0x9e,  0xb0,  0xfe,  0x43,  0xf4,  0xb4,  0xfe,  0x56,  0xf0,  0xfe,  0xc4,  0x14,  0xfe,  0x04,  0xf4,
-  0x6c,  0xfe,  0x43,  0xf4,  0xb1,  0xfe,  0xf3,  0x10,  0xb7,  0x01,  0xfe,  0x8e,  0x13,  0x1a,  0x59,  0xaf,
-  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x74,  0x99,  0xfe,  0xf8,  0x14,  0xa8,  0x74,  0xfe,  0x14,  0x10,
-  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0xf1,  0x99,  0xfe,  0xf8,  0x14,  0xa8,  0xf1,  0xa4,  0x51,  0x9e,
-  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x51,  0x08,  0x0b,  0x03,  0x14,  0x06,  0x01,
-  0x0c,  0x25,  0xec,  0x14,  0x0b,  0x01,  0x0c,  0x25,  0xec,  0x14,  0x18,  0x01,  0x0c,  0x25,  0xec,  0x78,
-  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0c,  0x25,  0xbc,  0x14,  0x18,  0x01,  0x0c,
-  0x25,  0xbc,  0x14,  0x06,  0x01,  0x0c,  0x25,  0xbc,  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x25,  0xbc,  0x78,
-  0xfe,  0x89,  0x4a,  0x01,  0x0c,  0x03,  0x51,  0x03,  0x29,  0xe8,  0x05,  0x06,  0x3b,  0xb6,  0x16,  0xe8,
-  0xfe,  0x49,  0xf4,  0x00,  0x4f,  0x78,  0xce,  0x63,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf9,  0x01,
-  0x0c,  0x40,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0xb6,  0x15,  0x2b,  0x16,  0xfc,
-  0x01,  0x55,  0x29,  0xfc,  0x05,  0x06,  0x50,  0x0a,  0x41,  0x06,  0x39,  0x03,  0x0d,  0x5d,  0x12,  0x91,
-  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1e,  0x12,  0x4a,  0xf3,  0x96,  0x01,  0x49,  0xfe,
-  0x90,  0x4d,  0xe6,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x49,  0xfe,  0x8d,  0x56,  0xbf,  0x4a,  0x03,  0x4a,
-  0x21,  0x91,  0x01,  0x15,  0x4a,  0x96,  0x01,  0x49,  0xeb,  0x10,  0xe6,  0x10,  0x21,  0x5d,  0x62,  0x1e,
-  0x89,  0x0f,  0x5f,  0x01,  0xaa,  0x03,  0x0d,  0x5d,  0x12,  0x91,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,
-  0x10,  0xfe,  0x1a,  0x12,  0x4a,  0xf3,  0x96,  0x01,  0x49,  0xeb,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,
-  0x59,  0x01,  0x49,  0x4a,  0x03,  0x4a,  0x21,  0x5d,  0x01,  0x15,  0x4a,  0x96,  0x01,  0x49,  0xeb,  0x10,
-  0xe6,  0x10,  0x21,  0x5d,  0x62,  0x1e,  0x89,  0x0f,  0x5f,  0x01,  0xaa,  0x03,  0x0d,  0x5d,  0x12,  0x91,
-  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,  0x42,  0x48,  0x96,  0x01,  0x49,  0xfe,  0xc0,  0x5a,  0xb7,  0xfe,
-  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xe4,  0x9c,  0x80,  0x05,  0x10,  0xfe,  0x2e,  0x13,
-  0x5a,  0x5d,  0xfe,  0x4d,  0xf4,  0x1e,  0xfe,  0x1c,  0x13,  0x0f,  0x5f,  0x01,  0x8e,  0xb0,  0xfe,  0x40,
-  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x49,  0xfe,  0x00,  0x07,  0x80,  0x05,  0x10,  0x89,  0x5a,  0x91,  0xfe,
-  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,  0x49,  0xfe,  0x8d,  0x56,  0xbf,  0xfe,  0x80,
-  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,  0x10,  0x77,  0x6f,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,
-  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xe3,  0x38,  0x9d,  0xfe,  0xfa,  0x16,  0x01,  0xfe,  0x08,  0x18,  0xd9,
-  0x8d,  0x38,  0x6f,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xc0,  0x28,  0xfe,  0xea,  0x16,  0xfe,
-  0xe2,  0x10,  0x09,  0x10,  0x77,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x22,  0xfe,  0x18,  0x58,
-  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0x8d,  0x22,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,
-  0xfe,  0x3c,  0x50,  0x6f,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x22,  0x9d,  0xfe,
-  0x44,  0x17,  0xfe,  0xbe,  0x14,  0x35,  0x03,  0xc0,  0x28,  0xfe,  0x1c,  0x17,  0xfe,  0xa4,  0x10,  0x09,
-  0x10,  0x77,  0xbf,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xe3,  0x30,  0x9d,  0xfe,  0x66,  0x17,  0xfe,
-  0x9c,  0x14,  0xfe,  0x18,  0x13,  0x8d,  0x30,  0x6f,  0x1d,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
-  0xa7,  0x07,  0xfe,  0x7f,  0x00,  0xfe,  0x05,  0x40,  0x03,  0xc0,  0x28,  0xfe,  0x5a,  0x17,  0xfe,  0x6c,
-  0x10,  0x09,  0x10,  0x77,  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x8d,  0xe1,  0x6f,  0x1d,  0xfe,  0x0f,
-  0x79,  0xfe,  0x1c,  0xf7,  0xe1,  0x9d,  0xfe,  0xa6,  0x17,  0xfe,  0x5c,  0x14,  0x35,  0x03,  0xc0,  0x28,
-  0xfe,  0x92,  0x17,  0xfe,  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x77,  0xfe,  0x18,  0xfe,  0x66,  0xfe,
-  0x19,  0xfe,  0x67,  0xd0,  0xe3,  0x46,  0x9d,  0xfe,  0xcc,  0x17,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,
-  0x8d,  0x46,  0x47,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,
-  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x6d,  0x31,  0x03,  0x6d,  0x31,  0xfe,  0x12,  0x45,  0x28,  0xfe,  0xbc,
-  0x17,  0x17,  0x06,  0x4c,  0xfe,  0x9b,  0x00,  0xe5,  0x02,  0x27,  0xfe,  0x39,  0xf0,  0xfe,  0x10,  0x18,
-  0x2b,  0x03,  0xfe,  0x7e,  0x18,  0x1a,  0x18,  0x87,  0x08,  0x0e,  0x03,  0x77,  0x04,  0xe7,  0x1a,  0x06,
-  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1c,  0x0f,  0x1e,  0x01,  0x15,  0x05,  0x10,  0x50,  0x4d,  0xfe,
-  0x78,  0x14,  0xfe,  0x34,  0x12,  0x59,  0x8c,  0x37,  0x38,  0xc7,  0xfe,  0xe9,  0x13,  0x1c,  0x0f,  0x3f,
-  0x01,  0x15,  0x05,  0x10,  0x50,  0x4d,  0xfe,  0x56,  0x14,  0xe9,  0x59,  0x8c,  0x37,  0x38,  0xc7,  0xfe,
-  0xe9,  0x13,  0x09,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,  0x13,  0xfe,  0x15,  0x00,  0x7a,  0xa5,  0x31,
-  0x01,  0xea,  0x09,  0x06,  0x03,  0x0a,  0x41,  0x38,  0x39,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,  0x11,
-  0x48,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,
-  0x36,  0xfe,  0xa8,  0x00,  0x21,  0x7b,  0xfe,  0x48,  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x03,  0x29,  0xc6,
-  0x5b,  0x16,  0xc6,  0x03,  0x0f,  0xc8,  0x01,  0x15,  0xf2,  0x0f,  0x7d,  0x01,  0x15,  0xfe,  0x49,  0x44,
-  0x28,  0xfe,  0x06,  0x19,  0x0f,  0x1e,  0x01,  0x15,  0x05,  0x10,  0x50,  0x0f,  0x5f,  0x01,  0xaa,  0x0f,
-  0x7d,  0x01,  0x15,  0x5b,  0x80,  0x03,  0xfe,  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x29,
-  0x3e,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x4d,  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,
-  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0xaf,  0xfe,  0xe2,  0x08,  0x5b,  0x4d,  0x40,  0x05,  0x7b,  0xab,  0xfe,
-  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,  0x10,  0xfe,  0xc4,  0x48,  0x08,  0x2d,  0x09,  0x3e,  0xfe,
-  0x40,  0x5f,  0x1c,  0x01,  0x45,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2d,  0x09,  0x3e,
-  0x01,  0x45,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x40,  0x4a,  0x72,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,
-  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,  0xf5,  0x18,  0x79,  0xfe,  0x8e,  0x19,  0x04,  0xfe,  0x90,
-  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xf5,  0xd4,  0x79,  0xfe,  0xa0,  0x19,  0x04,  0xfe,  0x92,
-  0x00,  0xcf,  0x1d,  0xe0,  0xf5,  0xfe,  0x0b,  0x00,  0x79,  0xfe,  0xb2,  0x19,  0x04,  0xfe,  0x94,  0x00,
-  0xcf,  0x22,  0xfe,  0x08,  0x10,  0x04,  0xfe,  0x96,  0x00,  0xcf,  0x8b,  0xfe,  0x4e,  0x45,  0xd8,  0xfe,
-  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,  0x10,  0x1a,  0x74,  0xfe,  0x08,  0x1c,  0xfe,  0x67,
-  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,  0x00,  0x04,  0xd8,  0xfe,  0x48,  0xf4,  0x18,  0x99,
-  0xfe,  0xe6,  0x19,  0x08,  0x18,  0x03,  0x05,  0x84,  0xfe,  0x5a,  0xf0,  0xfe,  0xf6,  0x19,  0x20,  0xfe,
-  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1d,  0xfe,  0x5a,  0xf0,  0xfe,  0x04,  0x1a,  0x20,  0xd5,  0xfe,
-  0x26,  0x10,  0x05,  0x18,  0x87,  0x20,  0x8b,  0xe0,  0x05,  0x0b,  0x87,  0x20,  0xb1,  0xfe,  0x0e,  0x10,
-  0x05,  0x06,  0x87,  0x20,  0x5e,  0xce,  0xb6,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x3b,  0x2f,  0xfe,
-  0x34,  0x1a,  0x04,  0x76,  0xb7,  0x03,  0x1b,  0xfe,  0x54,  0x1a,  0xfe,  0x14,  0xf0,  0x0c,  0x2f,  0xfe,
-  0x48,  0x1a,  0x1b,  0xfe,  0x54,  0x1a,  0xfe,  0x82,  0xf0,  0xfe,  0x4c,  0x1a,  0x03,  0xff,  0x15,  0x00,
-  0x00,
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0xfc,  0x00,  0x16,  0x18,  0xe4,  0x01,  0x00,  0x48,  0xe4,
+  0x18,  0x80,  0x03,  0xf6,  0x02,  0x00,  0xce,  0x19,  0x00,  0xfa,  0xff,  0xff,  0x1c,  0x0f,  0x00,  0xf6,
+  0x9e,  0xe7,  0xff,  0x00,  0x82,  0xe7,  0x00,  0xea,  0x01,  0xfa,  0x01,  0xe6,  0x09,  0xe7,  0x55,  0xf0,
+  0x01,  0xf6,  0x03,  0x00,  0x04,  0x00,  0x10,  0x00,  0x1e,  0xf0,  0x85,  0xf0,  0x18,  0xf4,  0x08,  0x00,
+  0xbc,  0x00,  0x38,  0x54,  0x00,  0xec,  0xd5,  0xf0,  0x82,  0x0d,  0x00,  0xe6,  0x86,  0xf0,  0xb1,  0xf0,
+  0x98,  0x57,  0x01,  0xfc,  0xb4,  0x00,  0xd4,  0x01,  0x0c,  0x1c,  0x3e,  0x1c,  0x3c,  0x00,  0xbb,  0x00,
+  0x00,  0x10,  0xba,  0x19,  0x02,  0x80,  0x32,  0xf0,  0x7c,  0x0d,  0x02,  0x13,  0xba,  0x13,  0x18,  0x40,
+  0x00,  0x57,  0x01,  0xea,  0x02,  0xfc,  0x03,  0xfc,  0x3e,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x74,  0x01,
+  0x76,  0x01,  0xb9,  0x54,  0x3e,  0x57,  0x00,  0x80,  0x03,  0xe6,  0xb6,  0x00,  0xc0,  0x00,  0x01,  0x01,
+  0x3e,  0x01,  0x7a,  0x01,  0xca,  0x08,  0xce,  0x10,  0x16,  0x11,  0x04,  0x12,  0x08,  0x12,  0x02,  0x4a,
+  0xbb,  0x55,  0x3c,  0x56,  0x03,  0x58,  0x1b,  0x80,  0x30,  0xe4,  0x4b,  0xe4,  0x5d,  0xf0,  0x02,  0xfa,
+  0x20,  0x00,  0x32,  0x00,  0x40,  0x00,  0x80,  0x00,  0x24,  0x01,  0x3c,  0x01,  0x68,  0x01,  0x6a,  0x01,
+  0x70,  0x01,  0x72,  0x01,  0x78,  0x01,  0x7c,  0x01,  0x62,  0x0a,  0x86,  0x0d,  0x06,  0x13,  0x4c,  0x1c,
+  0x04,  0x80,  0x4a,  0xe4,  0x02,  0xee,  0x5b,  0xf0,  0x03,  0xf7,  0x0c,  0x00,  0x0f,  0x00,  0x47,  0x00,
+  0xbe,  0x00,  0x00,  0x01,  0x20,  0x11,  0x5c,  0x16,  0x32,  0x1c,  0x38,  0x1c,  0x4e,  0x1c,  0x10,  0x44,
+  0x00,  0x4c,  0x04,  0xea,  0x5c,  0xf0,  0xa7,  0xf0,  0x04,  0xf6,  0x03,  0xfa,  0x05,  0x00,  0x34,  0x00,
+  0x36,  0x00,  0x98,  0x00,  0xcc,  0x00,  0x20,  0x01,  0x4e,  0x01,  0x4a,  0x0b,  0x42,  0x0c,  0x12,  0x0f,
+  0x0c,  0x10,  0x22,  0x11,  0x0a,  0x12,  0x04,  0x13,  0x30,  0x1c,  0x02,  0x48,  0x00,  0x4e,  0x42,  0x54,
+  0x44,  0x55,  0xbd,  0x56,  0x06,  0x83,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,  0x59,  0xf0,  0xb8,  0xf0,
+  0x4b,  0xf4,  0x06,  0xf7,  0x0e,  0xf7,  0x04,  0xfc,  0x05,  0xfc,  0x06,  0x00,  0x19,  0x00,  0x33,  0x00,
+  0x9b,  0x00,  0xa4,  0x00,  0xb5,  0x00,  0xba,  0x00,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,  0xe2,  0x03,
+  0x08,  0x0f,  0x02,  0x10,  0x04,  0x10,  0x0a,  0x10,  0x0a,  0x13,  0x0c,  0x13,  0x12,  0x13,  0x24,  0x14,
+  0x34,  0x14,  0x04,  0x16,  0x08,  0x16,  0xa4,  0x17,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x08,  0x44,
+  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,  0x48,  0x46,  0x01,  0x48,  0x68,  0x54,  0x3a,  0x55,  0x83,  0x55,
+  0xe5,  0x55,  0xb0,  0x57,  0x01,  0x58,  0x83,  0x59,  0x05,  0xe6,  0x0b,  0xf0,  0x0c,  0xf0,  0x04,  0xf8,
+  0x05,  0xf8,  0x07,  0x00,  0x0a,  0x00,  0x1c,  0x00,  0x1e,  0x00,  0x9e,  0x00,  0xa8,  0x00,  0xaa,  0x00,
+  0xb9,  0x00,  0xe0,  0x00,  0x22,  0x01,  0x26,  0x01,  0x79,  0x01,  0x7e,  0x01,  0xc4,  0x01,  0xc6,  0x01,
+  0x80,  0x02,  0x5e,  0x03,  0xee,  0x04,  0x9a,  0x06,  0xf8,  0x07,  0x62,  0x08,  0x68,  0x08,  0x69,  0x08,
+  0xd6,  0x08,  0xe9,  0x09,  0xfa,  0x0b,  0x2e,  0x0f,  0x12,  0x10,  0x1a,  0x10,  0xed,  0x10,  0xf1,  0x10,
+  0x2a,  0x11,  0x06,  0x12,  0x0c,  0x12,  0x3e,  0x12,  0x10,  0x13,  0x16,  0x13,  0x1e,  0x13,  0x46,  0x14,
+  0x76,  0x14,  0x82,  0x14,  0x36,  0x15,  0xca,  0x15,  0x6b,  0x18,  0xbe,  0x18,  0xca,  0x18,  0xe6,  0x19,
+  0x12,  0x1c,  0x46,  0x1c,  0x9c,  0x32,  0x00,  0x40,  0x0e,  0x47,  0xfe,  0x9c,  0xf0,  0x2b,  0x02,  0xfe,
+  0xac,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xd7,  0xfe,  0xe8,  0x19,  0x00,  0xd6,  0xfe,  0x84,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
+  0x00,  0xfe,  0x4c,  0x00,  0x5b,  0xff,  0x04,  0x00,  0x00,  0x11,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
+  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,
+  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xd6,
+  0x2c,  0x99,  0x0a,  0x01,  0xfe,  0xc2,  0x0f,  0xfe,  0x04,  0xf7,  0xd6,  0x99,  0x0a,  0x42,  0x2c,  0xfe,
+  0x3d,  0xf0,  0xfe,  0x06,  0x02,  0xfe,  0x20,  0xf0,  0xa7,  0xfe,  0x91,  0xf0,  0xfe,  0xf4,  0x01,  0xfe,
+  0x90,  0xf0,  0xfe,  0xf4,  0x01,  0xfe,  0x8f,  0xf0,  0xa7,  0x03,  0x5d,  0x4d,  0x02,  0xfe,  0xc8,  0x0d,
+  0x01,  0xfe,  0x38,  0x0e,  0xfe,  0xdd,  0x12,  0xfe,  0xfc,  0x10,  0xfe,  0x28,  0x1c,  0x03,  0xfe,  0xa6,
+  0x00,  0xfe,  0xd3,  0x12,  0x41,  0x14,  0xfe,  0xa6,  0x00,  0xc2,  0xfe,  0x48,  0xf0,  0xfe,  0x8a,  0x02,
+  0xfe,  0x49,  0xf0,  0xfe,  0xa4,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xc2,  0x02,  0xfe,  0x46,  0xf0,  0xfe,
+  0x54,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x5a,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x48,  0x02,  0xfe,  0x44,
+  0xf0,  0xfe,  0x4c,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x50,  0x02,  0x18,  0x0a,  0xaa,  0x18,  0x06,  0x14,
+  0xa1,  0x02,  0x2b,  0xfe,  0x00,  0x1c,  0xe7,  0xfe,  0x02,  0x1c,  0xe6,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,
+  0x10,  0x01,  0xfe,  0x18,  0x18,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xce,  0x09,  0x70,  0x01,  0xa8,
+  0x02,  0x2b,  0x15,  0x59,  0x39,  0xa2,  0x01,  0xfe,  0x58,  0x10,  0x09,  0x70,  0x01,  0x87,  0xfe,  0xbd,
+  0x10,  0x09,  0x70,  0x01,  0x87,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x18,  0x06,
+  0x14,  0xa1,  0x2c,  0x1c,  0x2b,  0xfe,  0x3d,  0xf0,  0xfe,  0x06,  0x02,  0x23,  0xfe,  0x98,  0x02,  0xfe,
+  0x5a,  0x1c,  0xf8,  0xfe,  0x14,  0x1c,  0x15,  0xfe,  0x30,  0x00,  0x39,  0xa2,  0x01,  0xfe,  0x48,  0x10,
+  0x18,  0x06,  0x14,  0xa1,  0x02,  0xd7,  0x22,  0x20,  0x07,  0x11,  0x35,  0xfe,  0x69,  0x10,  0x18,  0x06,
+  0x14,  0xa1,  0xfe,  0x04,  0xec,  0x20,  0x4f,  0x43,  0x13,  0x20,  0xfe,  0x05,  0xf6,  0xce,  0x01,  0xfe,
+  0x4a,  0x17,  0x08,  0x54,  0x58,  0x37,  0x12,  0x2f,  0x42,  0x92,  0x01,  0xfe,  0x82,  0x16,  0x02,  0x2b,
+  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x66,  0x01,  0x73,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x09,
+  0xa4,  0x01,  0x0e,  0xfe,  0xc8,  0x54,  0x6b,  0xfe,  0x10,  0x03,  0x01,  0xfe,  0x82,  0x16,  0x02,  0x2b,
+  0x2c,  0x4f,  0xfe,  0x02,  0xe8,  0x2a,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xfe,  0x77,  0x57,  0xfe,
+  0x27,  0xf0,  0xfe,  0xe0,  0x01,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xa7,  0xfe,  0x40,  0x1c,  0x1c,
+  0xd9,  0xfe,  0x26,  0xf0,  0xfe,  0x5a,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x48,  0x03,  0xfe,  0x11,  0xf0,
+  0xa7,  0xfe,  0xef,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x68,  0x03,  0xf9,  0x10,  0xfe,  0x11,  0x00,  0x02,
+  0x65,  0x2c,  0xfe,  0x48,  0x1c,  0xf9,  0x08,  0x05,  0x1b,  0xfe,  0x18,  0x13,  0x21,  0x22,  0xa3,  0xb7,
+  0x13,  0xa3,  0x09,  0x46,  0x01,  0x0e,  0xb7,  0x78,  0x01,  0xfe,  0xb4,  0x16,  0x12,  0xd1,  0x1c,  0xd9,
+  0xfe,  0x01,  0xf0,  0xd9,  0xfe,  0x82,  0xf0,  0xfe,  0x96,  0x03,  0xfa,  0x12,  0xfe,  0xe4,  0x00,  0x27,
+  0xfe,  0xa8,  0x03,  0x1c,  0x34,  0x1d,  0xfe,  0xb8,  0x03,  0x01,  0x4b,  0xfe,  0x06,  0xf0,  0xfe,  0xc8,
+  0x03,  0x95,  0x86,  0xfe,  0x0a,  0xf0,  0xfe,  0x8a,  0x06,  0x02,  0x24,  0x03,  0x70,  0x28,  0x17,  0xfe,
+  0xfa,  0x04,  0x15,  0x6d,  0x01,  0x36,  0x7b,  0xfe,  0x6a,  0x02,  0x02,  0xd8,  0xf9,  0x2c,  0x99,  0x19,
+  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x48,  0x1c,  0x74,  0x01,  0xaf,  0x8c,
+  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x17,  0xda,  0x09,  0xd1,  0x01,  0x0e,  0x8d,  0x51,  0x64,  0x79,
+  0x2a,  0x03,  0x70,  0x28,  0xfe,  0x10,  0x12,  0x15,  0x6d,  0x01,  0x36,  0x7b,  0xfe,  0x6a,  0x02,  0x02,
+  0xd8,  0xc7,  0x81,  0xc8,  0x83,  0x1c,  0x24,  0x27,  0xfe,  0x40,  0x04,  0x1d,  0xfe,  0x3c,  0x04,  0x3b,
+  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x4e,  0x12,  0x2d,  0xff,  0x02,  0x00,  0x10,  0x01,  0x0b,
+  0x1d,  0xfe,  0xe4,  0x04,  0x2d,  0x01,  0x0b,  0x1d,  0x24,  0x33,  0x31,  0xde,  0xfe,  0x4c,  0x44,  0xfe,
+  0x4c,  0x12,  0x51,  0xfe,  0x44,  0x48,  0x0f,  0x6f,  0xfe,  0x4c,  0x54,  0x6b,  0xda,  0x4f,  0x79,  0x2a,
+  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x62,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x2a,  0x13,  0x32,
+  0x07,  0x82,  0xfe,  0x52,  0x13,  0xfe,  0x20,  0x10,  0x0f,  0x6f,  0xfe,  0x4c,  0x54,  0x6b,  0xda,  0xfe,
+  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x40,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x08,  0x13,  0x32,  0x07,
+  0x82,  0xfe,  0x30,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x1c,  0x12,  0x15,  0x9d,  0x08,  0x05,  0x06,  0x4d,
+  0x15,  0xfe,  0x0d,  0x00,  0x01,  0x36,  0x7b,  0xfe,  0x64,  0x0d,  0x02,  0x24,  0x2d,  0x12,  0xfe,  0xe6,
+  0x00,  0xfe,  0x1c,  0x90,  0xfe,  0x40,  0x5c,  0x04,  0x15,  0x9d,  0x01,  0x36,  0x02,  0x2b,  0xfe,  0x42,
+  0x5b,  0x99,  0x19,  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x87,  0x80,  0xfe,
+  0x31,  0xe4,  0x5b,  0x08,  0x05,  0x0a,  0xfe,  0x84,  0x13,  0xfe,  0x20,  0x80,  0x07,  0x19,  0xfe,  0x7c,
+  0x12,  0x53,  0x05,  0x06,  0xfe,  0x6c,  0x13,  0x03,  0xfe,  0xa2,  0x00,  0x28,  0x17,  0xfe,  0x90,  0x05,
+  0xfe,  0x31,  0xe4,  0x5a,  0x53,  0x05,  0x0a,  0xfe,  0x56,  0x13,  0x03,  0xfe,  0xa0,  0x00,  0x28,  0xfe,
+  0x4e,  0x12,  0x67,  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x48,  0x05,  0x1c,  0x34,  0xfe,  0x89,  0x48,
+  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x56,  0x05,  0x26,  0xfe,  0xa8,  0x05,  0x12,  0xfe,  0xe3,  0x00,
+  0x21,  0x53,  0xfe,  0x4a,  0xf0,  0xfe,  0x76,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x70,  0x05,  0x88,  0x25,
+  0xfe,  0x21,  0x00,  0xab,  0x25,  0xfe,  0x22,  0x00,  0xaa,  0x25,  0x58,  0xfe,  0x09,  0x48,  0xff,  0x02,
+  0x00,  0x10,  0x27,  0xfe,  0x86,  0x05,  0x26,  0xfe,  0xa8,  0x05,  0xfe,  0xe2,  0x08,  0x53,  0x05,  0xcb,
+  0x4d,  0x01,  0xb0,  0x25,  0x06,  0x13,  0xd3,  0x39,  0xfe,  0x27,  0x01,  0x08,  0x05,  0x1b,  0xfe,  0x22,
+  0x12,  0x41,  0x01,  0xb2,  0x15,  0x9d,  0x08,  0x05,  0x06,  0x4d,  0x15,  0xfe,  0x0d,  0x00,  0x01,  0x36,
+  0x7b,  0xfe,  0x64,  0x0d,  0x02,  0x24,  0x03,  0xfe,  0x9c,  0x00,  0x28,  0xeb,  0x03,  0x5c,  0x28,  0xfe,
+  0x36,  0x13,  0x41,  0x01,  0xb2,  0x26,  0xfe,  0x18,  0x06,  0x09,  0x06,  0x53,  0x05,  0x1f,  0xfe,  0x02,
+  0x12,  0x50,  0x01,  0xfe,  0x9e,  0x15,  0x1d,  0xfe,  0x0e,  0x06,  0x12,  0xa5,  0x01,  0x4b,  0x12,  0xfe,
+  0xe5,  0x00,  0x03,  0x5c,  0xc1,  0x0c,  0x5c,  0x03,  0xcd,  0x28,  0xfe,  0x62,  0x12,  0x03,  0x45,  0x28,
+  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x0c,  0x19,  0x01,  0xfe,  0x76,  0x19,  0xfe,  0x43,  0x48,  0xc4,  0xcc,
+  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x1e,  0x43,  0x8b,  0xc4,  0x6e,  0x41,  0x01,  0xb2,
+  0x26,  0xfe,  0x82,  0x06,  0x53,  0x05,  0x1a,  0xe9,  0x91,  0x09,  0x59,  0x01,  0xfe,  0xcc,  0x15,  0x1d,
+  0xfe,  0x78,  0x06,  0x12,  0xa5,  0x01,  0x4b,  0x12,  0xfe,  0xe5,  0x00,  0x03,  0x45,  0xc1,  0x0c,  0x45,
+  0x18,  0x06,  0x01,  0xb2,  0xfa,  0x76,  0x74,  0x01,  0xaf,  0x8c,  0x12,  0xfe,  0xe2,  0x00,  0x27,  0xdb,
+  0x1c,  0x34,  0xfe,  0x0a,  0xf0,  0xfe,  0xb6,  0x06,  0x94,  0xfe,  0x6c,  0x07,  0xfe,  0x06,  0xf0,  0xfe,
+  0x74,  0x07,  0x95,  0x86,  0x02,  0x24,  0x08,  0x05,  0x0a,  0xfe,  0x2e,  0x12,  0x16,  0x19,  0x01,  0x0b,
+  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0xfe,  0x99,  0xa4,  0x01,
+  0x0b,  0x16,  0x00,  0x02,  0xfe,  0x42,  0x08,  0x68,  0x05,  0x1a,  0xfe,  0x38,  0x12,  0x08,  0x05,  0x1a,
+  0xfe,  0x30,  0x13,  0x16,  0xfe,  0x1b,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,
+  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x06,  0x01,  0x0b,  0x16,  0x00,  0x02,  0xe2,  0x6c,  0x58,  0xbe,
+  0x50,  0xfe,  0x9a,  0x81,  0x55,  0x1b,  0x7a,  0xfe,  0x42,  0x07,  0x09,  0x1b,  0xfe,  0x09,  0x6f,  0xba,
+  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,  0x69,  0x6d,  0x8b,  0x6c,  0x7f,  0x27,  0xfe,  0x54,  0x07,  0x1c,
+  0x34,  0xfe,  0x0a,  0xf0,  0xfe,  0x42,  0x07,  0x95,  0x86,  0x94,  0xfe,  0x6c,  0x07,  0x02,  0x24,  0x01,
+  0x4b,  0x02,  0xdb,  0x16,  0x1f,  0x02,  0xdb,  0xfe,  0x9c,  0xf7,  0xdc,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
+  0x90,  0x56,  0xfe,  0xda,  0x07,  0x0c,  0x60,  0x14,  0x61,  0x08,  0x54,  0x5a,  0x37,  0x22,  0x20,  0x07,
+  0x11,  0xfe,  0x0e,  0x12,  0x8d,  0xfe,  0x80,  0x80,  0x39,  0x20,  0x6a,  0x2a,  0xfe,  0x06,  0x10,  0xfe,
+  0x83,  0xe7,  0xfe,  0x48,  0x00,  0xab,  0xfe,  0x03,  0x40,  0x08,  0x54,  0x5b,  0x37,  0x01,  0xb3,  0xb8,
+  0xfe,  0x1f,  0x40,  0x13,  0x62,  0x01,  0xef,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,
+  0xfe,  0xc6,  0x51,  0x88,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0c,  0x5e,  0x14,  0x5f,  0xfe,  0x0c,
+  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x0c,  0x3d,  0x14,  0x3e,  0xfe,  0x4a,
+  0x10,  0x08,  0x05,  0x5a,  0xfe,  0x2a,  0x12,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0c,  0x60,  0x14,
+  0x61,  0x08,  0x05,  0x5b,  0x8b,  0x01,  0xb3,  0xfe,  0x1f,  0x80,  0x13,  0x62,  0xfe,  0x44,  0x90,  0xfe,
+  0xc6,  0x90,  0x0c,  0x3f,  0x14,  0x40,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0c,  0x5e,  0x14,  0x5f,
+  0xfe,  0x40,  0x90,  0xfe,  0xc2,  0x90,  0x0c,  0x3d,  0x14,  0x3e,  0x0c,  0x2e,  0x14,  0x3c,  0x21,  0x0c,
+  0x49,  0x0c,  0x63,  0x08,  0x54,  0x1f,  0x37,  0x2c,  0x0f,  0xfe,  0x4e,  0x11,  0x27,  0xdd,  0xfe,  0x9e,
+  0xf0,  0xfe,  0x76,  0x08,  0xbc,  0x17,  0x34,  0x2c,  0x77,  0xe6,  0xc5,  0xfe,  0x9a,  0x08,  0xc6,  0xfe,
+  0xb8,  0x08,  0x94,  0xfe,  0x8e,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x94,  0x08,  0x95,  0x86,  0x02,  0x24,
+  0x01,  0x4b,  0xfe,  0xc9,  0x10,  0x16,  0x1f,  0xfe,  0xc9,  0x10,  0x68,  0x05,  0x06,  0xfe,  0x10,  0x12,
+  0x68,  0x05,  0x0a,  0x4e,  0x08,  0x05,  0x0a,  0xfe,  0x90,  0x12,  0xfe,  0x2e,  0x1c,  0x02,  0xfe,  0x18,
+  0x0b,  0x68,  0x05,  0x06,  0x4e,  0x68,  0x05,  0x0a,  0xfe,  0x7a,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,
+  0xf0,  0xfe,  0xd2,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x00,  0x09,  0x02,  0xfe,  0xde,  0x09,  0xfe,  0xb7,
+  0xf0,  0xfe,  0xfc,  0x08,  0xfe,  0x02,  0xf6,  0x1a,  0x50,  0xfe,  0x70,  0x18,  0xfe,  0xf1,  0x18,  0xfe,
+  0x40,  0x55,  0xfe,  0xe1,  0x55,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,
+  0x59,  0x1c,  0x85,  0xfe,  0x8c,  0xf0,  0xfe,  0xfc,  0x08,  0xfe,  0xac,  0xf0,  0xfe,  0xf0,  0x08,  0xb5,
+  0xfe,  0xcb,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0x0c,  0x09,  0x02,  0xfe,  0x18,  0x0b,  0xb6,  0xfe,  0xbf,
+  0x10,  0xfe,  0x2b,  0xf0,  0x85,  0xf4,  0x1e,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xc2,  0xfe,  0xd2,
+  0xf0,  0x85,  0xfe,  0x76,  0x18,  0x1e,  0x19,  0x17,  0x85,  0x03,  0xd2,  0x1e,  0x06,  0x17,  0x85,  0xc5,
+  0x4a,  0xc6,  0x4a,  0xb5,  0xb6,  0xfe,  0x89,  0x10,  0x74,  0x67,  0x2d,  0x15,  0x9d,  0x01,  0x36,  0x10,
+  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x65,  0x10,  0x80,  0x02,  0x65,  0xfe,  0x98,  0x80,  0xfe,  0x19,
+  0xe4,  0x0a,  0xfe,  0x1a,  0x12,  0x51,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xbe,
+  0xfe,  0x19,  0x81,  0xfe,  0x74,  0x18,  0x8f,  0x90,  0x17,  0xfe,  0xce,  0x08,  0x02,  0x4a,  0x08,  0x05,
+  0x5a,  0xec,  0x03,  0x2e,  0x29,  0x3c,  0x0c,  0x3f,  0x14,  0x40,  0x9b,  0x2e,  0x9c,  0x3c,  0xfe,  0x6c,
+  0x18,  0xfe,  0xed,  0x18,  0xfe,  0x44,  0x54,  0xfe,  0xe5,  0x54,  0x3a,  0x3f,  0x3b,  0x40,  0x03,  0x49,
+  0x29,  0x63,  0x8f,  0xfe,  0xe3,  0x54,  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x8f,  0xfe,  0xe3,  0x54,
+  0x90,  0xc0,  0x56,  0xfe,  0xce,  0x08,  0x02,  0x4a,  0xfe,  0x37,  0xf0,  0xfe,  0xda,  0x09,  0xfe,  0x8b,
+  0xf0,  0xfe,  0x60,  0x09,  0x02,  0x4a,  0x08,  0x05,  0x0a,  0x23,  0xfe,  0xfa,  0x0a,  0x3a,  0x49,  0x3b,
+  0x63,  0x56,  0xfe,  0x3e,  0x0a,  0x0f,  0xfe,  0xc0,  0x07,  0x41,  0x98,  0x00,  0xad,  0xfe,  0x01,  0x59,
+  0xfe,  0x52,  0xf0,  0xfe,  0x0c,  0x0a,  0x8f,  0x7a,  0xfe,  0x24,  0x0a,  0x3a,  0x49,  0x8f,  0xfe,  0xe3,
+  0x54,  0x57,  0x49,  0x7d,  0x63,  0xfe,  0x14,  0x58,  0xfe,  0x95,  0x58,  0x02,  0x4a,  0x3a,  0x49,  0x3b,
+  0x63,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0xbe,  0x57,  0x49,  0x57,  0x63,  0x02,  0x4a,  0x08,  0x05,
+  0x5a,  0xfe,  0x82,  0x12,  0x08,  0x05,  0x1f,  0xfe,  0x66,  0x13,  0x22,  0x62,  0xb7,  0xfe,  0x03,  0xa1,
+  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6a,
+  0x2a,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x56,  0xe0,  0x03,  0x60,  0x29,  0x61,  0x0c,  0x7f,  0x14,
+  0x80,  0x57,  0x60,  0x7d,  0x61,  0x01,  0xb3,  0xb8,  0x6a,  0x2a,  0x13,  0x62,  0x9b,  0x2e,  0x9c,  0x3c,
+  0x3a,  0x3f,  0x3b,  0x40,  0x90,  0xc0,  0xfe,  0x04,  0xfa,  0x2e,  0xfe,  0x05,  0xfa,  0x3c,  0x01,  0xef,
+  0xfe,  0x36,  0x10,  0x21,  0x0c,  0x7f,  0x0c,  0x80,  0x3a,  0x3f,  0x3b,  0x40,  0xe4,  0x08,  0x05,  0x1f,
+  0x17,  0xe0,  0x3a,  0x3d,  0x3b,  0x3e,  0x08,  0x05,  0xfe,  0xf7,  0x00,  0x37,  0x03,  0x5e,  0x29,  0x5f,
+  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0x57,  0x49,  0x7d,  0x63,  0x02,  0xfe,  0xf4,  0x09,  0x08,  0x05,
+  0x1f,  0x17,  0xe0,  0x08,  0x05,  0xfe,  0xf7,  0x00,  0x37,  0xbe,  0xfe,  0x19,  0x81,  0x50,  0xfe,  0x10,
+  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd3,  0x10,  0x32,  0x07,  0xa6,  0x17,  0xfe,  0x08,  0x09,  0x12,  0xa6,
+  0x08,  0x05,  0x0a,  0xfe,  0x14,  0x13,  0x03,  0x3d,  0x29,  0x3e,  0x56,  0xfe,  0x08,  0x09,  0xfe,  0x0c,
+  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x4a,  0x21,  0x41,  0xfe,  0x19,  0x80,  0xe7,  0x08,  0x05,  0x0a,  0xfe,
+  0x1a,  0x12,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xf4,  0xc2,  0xfe,  0xd1,  0xf0,  0xe2,  0x15,  0x7e,
+  0x01,  0x36,  0x10,  0xfe,  0x44,  0x00,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0x57,  0x3d,  0xfe,  0xed,
+  0x19,  0x7d,  0x3e,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xf4,  0x1e,  0xfe,  0x00,  0xff,  0x35,  0xfe,
+  0x74,  0x10,  0xc2,  0xfe,  0xd2,  0xf0,  0xfe,  0xa6,  0x0b,  0xfe,  0x76,  0x18,  0x1e,  0x19,  0x8a,  0x03,
+  0xd2,  0x1e,  0x06,  0xfe,  0x08,  0x13,  0x10,  0xfe,  0x16,  0x00,  0x02,  0x65,  0xfe,  0xd1,  0xf0,  0xfe,
+  0xb8,  0x0b,  0x15,  0x7e,  0x01,  0x36,  0x10,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,
+  0xfe,  0xbe,  0x0b,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xca,  0x0b,  0x10,  0xfe,  0x22,  0x00,
+  0x02,  0x65,  0xfe,  0xcb,  0xf0,  0xfe,  0xd6,  0x0b,  0x10,  0xfe,  0x24,  0x00,  0x02,  0x65,  0xfe,  0xd0,
+  0xf0,  0xfe,  0xe0,  0x0b,  0x10,  0x9e,  0xe5,  0xfe,  0xcf,  0xf0,  0xfe,  0xea,  0x0b,  0x10,  0x58,  0xfe,
+  0x10,  0x10,  0xfe,  0xcc,  0xf0,  0xe2,  0x68,  0x05,  0x1f,  0x4d,  0x10,  0xfe,  0x12,  0x00,  0x2c,  0x0f,
+  0xfe,  0x4e,  0x11,  0x27,  0xfe,  0x00,  0x0c,  0xfe,  0x9e,  0xf0,  0xfe,  0x14,  0x0c,  0xbc,  0x17,  0x34,
+  0x2c,  0x77,  0xe6,  0xc5,  0x24,  0xc6,  0x24,  0x2c,  0xfa,  0x27,  0xfe,  0x20,  0x0c,  0x1c,  0x34,  0x94,
+  0xfe,  0x3c,  0x0c,  0x95,  0x86,  0xc5,  0xdc,  0xc6,  0xdc,  0x02,  0x24,  0x01,  0x4b,  0xfe,  0xdb,  0x10,
+  0x12,  0xfe,  0xe8,  0x00,  0xb5,  0xb6,  0x74,  0xc7,  0x81,  0xc8,  0x83,  0xfe,  0x89,  0xf0,  0x24,  0x33,
+  0x31,  0xe1,  0xc7,  0x81,  0xc8,  0x83,  0x27,  0xfe,  0x66,  0x0c,  0x1d,  0x24,  0x33,  0x31,  0xdf,  0xbc,
+  0x4e,  0x10,  0xfe,  0x42,  0x00,  0x02,  0x65,  0x7c,  0x06,  0xfe,  0x81,  0x49,  0x17,  0xfe,  0x2c,  0x0d,
+  0x08,  0x05,  0x0a,  0xfe,  0x44,  0x13,  0x10,  0x00,  0x55,  0x0a,  0xfe,  0x54,  0x12,  0x55,  0xfe,  0x28,
+  0x00,  0x23,  0xfe,  0x9a,  0x0d,  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x66,  0x44,  0xfe,  0x28,  0x00,
+  0xfe,  0xe2,  0x10,  0x01,  0xf5,  0x01,  0xf6,  0x09,  0xa4,  0x01,  0xfe,  0x26,  0x0f,  0x64,  0x12,  0x2f,
+  0x01,  0x73,  0x02,  0x2b,  0x10,  0xfe,  0x44,  0x00,  0x55,  0x0a,  0xe9,  0x44,  0x0a,  0xfe,  0xb4,  0x10,
+  0x01,  0xb0,  0x44,  0x0a,  0xfe,  0xaa,  0x10,  0x01,  0xb0,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xac,
+  0x44,  0x0a,  0x10,  0xfe,  0x43,  0x00,  0xfe,  0x96,  0x10,  0x08,  0x54,  0x0a,  0x37,  0x01,  0xf5,  0x01,
+  0xf6,  0x64,  0x12,  0x2f,  0x01,  0x73,  0x99,  0x0a,  0x64,  0x42,  0x92,  0x02,  0xfe,  0x2e,  0x03,  0x08,
+  0x05,  0x0a,  0x8a,  0x44,  0x0a,  0x10,  0x00,  0xfe,  0x5c,  0x10,  0x68,  0x05,  0x1a,  0xfe,  0x58,  0x12,
+  0x08,  0x05,  0x1a,  0xfe,  0x50,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x50,  0x0d,  0xfe,
+  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x56,  0x0d,  0x08,  0x54,  0x1a,  0x37,  0xfe,  0xa9,  0x10,  0x10,
+  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0a,  0x50,  0xfe,  0x2e,  0x10,  0x10,  0xfe,  0x13,  0x00,  0xfe,
+  0x10,  0x10,  0x10,  0x6f,  0xab,  0x10,  0xfe,  0x41,  0x00,  0xaa,  0x10,  0xfe,  0x24,  0x00,  0x8c,  0xb5,
+  0xb6,  0x74,  0x03,  0x70,  0x28,  0x23,  0xd8,  0x50,  0xfe,  0x04,  0xe6,  0x1a,  0xfe,  0x9d,  0x41,  0xfe,
+  0x1c,  0x42,  0x64,  0x01,  0xe3,  0x02,  0x2b,  0xf8,  0x15,  0x0a,  0x39,  0xa0,  0xb4,  0x15,  0xfe,  0x31,
+  0x00,  0x39,  0xa2,  0x01,  0xfe,  0x48,  0x10,  0x02,  0xd7,  0x42,  0xfe,  0x06,  0xec,  0xd0,  0xfc,  0x44,
+  0x1b,  0xfe,  0xce,  0x45,  0x35,  0x42,  0xfe,  0x06,  0xea,  0xd0,  0xfe,  0x47,  0x4b,  0x91,  0xfe,  0x75,
+  0x57,  0x03,  0x5d,  0xfe,  0x98,  0x56,  0xfe,  0x38,  0x12,  0x09,  0x48,  0x01,  0x0e,  0xfe,  0x44,  0x48,
+  0x4f,  0x08,  0x05,  0x1b,  0xfe,  0x1a,  0x13,  0x09,  0x46,  0x01,  0x0e,  0x41,  0xfe,  0x41,  0x58,  0x09,
+  0xa4,  0x01,  0x0e,  0xfe,  0x49,  0x54,  0x96,  0xfe,  0x1e,  0x0e,  0x02,  0xfe,  0x2e,  0x03,  0x09,  0x5d,
+  0xfe,  0xee,  0x14,  0xfc,  0x44,  0x1b,  0xfe,  0xce,  0x45,  0x35,  0x42,  0xfe,  0xce,  0x47,  0xfe,  0xad,
+  0x13,  0x02,  0x2b,  0x22,  0x20,  0x07,  0x11,  0xfe,  0x9e,  0x12,  0x21,  0x13,  0x59,  0x13,  0x9f,  0x13,
+  0xd5,  0x22,  0x2f,  0x41,  0x39,  0x2f,  0xbc,  0xad,  0xfe,  0xbc,  0xf0,  0xfe,  0xe0,  0x0e,  0x0f,  0x06,
+  0x13,  0x59,  0x01,  0xfe,  0xda,  0x16,  0x03,  0xfe,  0x38,  0x01,  0x29,  0xfe,  0x3a,  0x01,  0x56,  0xfe,
+  0xe4,  0x0e,  0xfe,  0x02,  0xec,  0xd5,  0x69,  0x00,  0x66,  0xfe,  0x04,  0xec,  0x20,  0x4f,  0xfe,  0x05,
+  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x4a,  0x17,  0xfe,  0x08,  0x90,  0xfe,  0x48,  0xf4,  0x0d,  0xfe,
+  0x18,  0x13,  0xba,  0xfe,  0x02,  0xea,  0xd5,  0x69,  0x7e,  0xfe,  0xc5,  0x13,  0x15,  0x1a,  0x39,  0xa0,
+  0xb4,  0xfe,  0x2e,  0x10,  0x03,  0xfe,  0x38,  0x01,  0x1e,  0xfe,  0xf0,  0xff,  0x0c,  0xfe,  0x60,  0x01,
+  0x03,  0xfe,  0x3a,  0x01,  0x0c,  0xfe,  0x62,  0x01,  0x43,  0x13,  0x20,  0x25,  0x06,  0x13,  0x2f,  0x12,
+  0x2f,  0x92,  0x0f,  0x06,  0x04,  0x21,  0x04,  0x22,  0x59,  0xfe,  0xf7,  0x12,  0x22,  0x9f,  0xb7,  0x13,
+  0x9f,  0x07,  0x7e,  0xfe,  0x71,  0x13,  0xfe,  0x24,  0x1c,  0x15,  0x19,  0x39,  0xa0,  0xb4,  0xfe,  0xd9,
+  0x10,  0xc3,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x04,  0xc3,  0xfe,  0x03,  0xdc,
+  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x04,  0xfe,  0x03,  0x57,  0xc3,  0x21,  0xfe,  0x00,  0xcc,  0x04,
+  0xfe,  0x03,  0x57,  0xc3,  0x78,  0x04,  0x08,  0x05,  0x58,  0xfe,  0x22,  0x13,  0xfe,  0x1c,  0x80,  0x07,
+  0x06,  0xfe,  0x1a,  0x13,  0xfe,  0x1e,  0x80,  0xed,  0xfe,  0x1d,  0x80,  0xae,  0xfe,  0x0c,  0x90,  0xfe,
+  0x0e,  0x13,  0xfe,  0x0e,  0x90,  0xac,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x0a,  0xfe,  0x3c,  0x50,
+  0xaa,  0x01,  0xfe,  0x7a,  0x17,  0x32,  0x07,  0x2f,  0xad,  0x01,  0xfe,  0xb4,  0x16,  0x08,  0x05,  0x1b,
+  0x4e,  0x01,  0xf5,  0x01,  0xf6,  0x12,  0xfe,  0xe9,  0x00,  0x08,  0x05,  0x58,  0xfe,  0x2c,  0x13,  0x01,
+  0xfe,  0x0c,  0x17,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0xfe,  0x96,  0x90,  0x0c,  0xfe,  0x64,  0x01,
+  0x14,  0xfe,  0x66,  0x01,  0x08,  0x05,  0x5b,  0xfe,  0x12,  0x12,  0xfe,  0x03,  0x80,  0x8d,  0xfe,  0x01,
+  0xec,  0x20,  0xfe,  0x80,  0x40,  0x13,  0x20,  0x6a,  0x2a,  0x12,  0xcf,  0x64,  0x22,  0x20,  0xfb,  0x79,
+  0x20,  0x04,  0xfe,  0x08,  0x1c,  0x03,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x03,  0xfe,  0xae,  0x00,
+
+  0xfe,  0x07,  0x58,  0x03,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x03,  0xfe,  0xb2,  0x00,  0xfe,  0x09,
+  0x58,  0xfe,  0x0a,  0x1c,  0x25,  0x6e,  0x13,  0xd0,  0x21,  0x0c,  0x5c,  0x0c,  0x45,  0x0f,  0x46,  0x52,
+  0x50,  0x18,  0x1b,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x23,  0xfe,  0xfc,  0x0f,  0x44,  0x11,  0x0f,
+  0x48,  0x52,  0x18,  0x58,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x23,  0xe4,  0x25,  0x11,  0x13,  0x20,
+  0x7c,  0x6f,  0x4f,  0x22,  0x20,  0xfb,  0x79,  0x20,  0x12,  0xcf,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,
+  0xfe,  0x26,  0x10,  0xf8,  0x74,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x04,  0x42,
+  0xfe,  0x0c,  0x14,  0xfc,  0xfe,  0x07,  0xe6,  0x1b,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x04,  0x01,
+  0xb0,  0x7c,  0x6f,  0x4f,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x42,  0x13,  0x32,  0x07,  0x2f,
+  0xfe,  0x34,  0x13,  0x09,  0x48,  0x01,  0x0e,  0xbb,  0xfe,  0x36,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,
+  0x48,  0x01,  0xf0,  0xfe,  0x00,  0xcc,  0xbb,  0xfe,  0xf3,  0x13,  0x43,  0x78,  0x07,  0x11,  0xac,  0x09,
+  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x5c,  0x01,  0x73,  0xfe,  0x0e,  0x10,  0x07,  0x82,  0x4e,  0xfe,  0x14,
+  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x60,  0x10,  0x04,  0xfe,  0x44,  0x58,  0x8d,  0xfe,  0x01,  0xec,  0xa2,
+  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1a,  0x79,  0x2a,  0x01,  0xe3,  0xfe,
+  0xdd,  0x10,  0x2c,  0xc7,  0x81,  0xc8,  0x83,  0x33,  0x31,  0xde,  0x07,  0x1a,  0xfe,  0x48,  0x12,  0x07,
+  0x0a,  0xfe,  0x56,  0x12,  0x07,  0x19,  0xfe,  0x30,  0x12,  0x07,  0xc9,  0x17,  0xfe,  0x32,  0x12,  0x07,
+  0xfe,  0x23,  0x00,  0x17,  0xeb,  0x07,  0x06,  0x17,  0xfe,  0x9c,  0x12,  0x07,  0x1f,  0xfe,  0x12,  0x12,
+  0x07,  0x00,  0x17,  0x24,  0x15,  0xc9,  0x01,  0x36,  0xa9,  0x2d,  0x01,  0x0b,  0x94,  0x4b,  0x04,  0x2d,
+  0xdd,  0x09,  0xd1,  0x01,  0xfe,  0x26,  0x0f,  0x12,  0x82,  0x02,  0x2b,  0x2d,  0x32,  0x07,  0xa6,  0xfe,
+  0xd9,  0x13,  0x3a,  0x3d,  0x3b,  0x3e,  0x56,  0xfe,  0xf0,  0x11,  0x08,  0x05,  0x5a,  0xfe,  0x72,  0x12,
+  0x9b,  0x2e,  0x9c,  0x3c,  0x90,  0xc0,  0x96,  0xfe,  0xba,  0x11,  0x22,  0x62,  0xfe,  0x26,  0x13,  0x03,
+  0x7f,  0x29,  0x80,  0x56,  0xfe,  0x76,  0x0d,  0x0c,  0x60,  0x14,  0x61,  0x21,  0x0c,  0x7f,  0x0c,  0x80,
+  0x01,  0xb3,  0x25,  0x6e,  0x77,  0x13,  0x62,  0x01,  0xef,  0x9b,  0x2e,  0x9c,  0x3c,  0xfe,  0x04,  0x55,
+  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x2e,  0xfe,  0x05,  0xfa,  0x3c,  0xfe,  0x91,  0x10,  0x03,  0x3f,
+  0x29,  0x40,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0c,  0x3f,  0x14,  0x40,  0x88,  0x9b,  0x2e,  0x9c,
+  0x3c,  0x90,  0xc0,  0x03,  0x5e,  0x29,  0x5f,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0c,  0x5e,  0x14,
+  0x5f,  0x08,  0x05,  0x5a,  0xfe,  0x1e,  0x12,  0x22,  0x62,  0xfe,  0x1f,  0x40,  0x03,  0x60,  0x29,  0x61,
+  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x03,  0x3f,  0x29,  0x40,  0xfe,  0x44,  0x50,  0xfe,  0xc6,  0x50,
+  0x03,  0x5e,  0x29,  0x5f,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x03,  0x3d,  0x29,  0x3e,  0xfe,  0x40,
+  0x50,  0xfe,  0xc2,  0x50,  0x02,  0x89,  0x25,  0x06,  0x13,  0xd4,  0x02,  0x72,  0x2d,  0x01,  0x0b,  0x1d,
+  0x4c,  0x33,  0x31,  0xde,  0x07,  0x06,  0x23,  0x4c,  0x32,  0x07,  0xa6,  0x23,  0x72,  0x01,  0xaf,  0x1e,
+  0x43,  0x17,  0x4c,  0x08,  0x05,  0x0a,  0xee,  0x3a,  0x3d,  0x3b,  0x3e,  0xfe,  0x0a,  0x55,  0x35,  0xfe,
+  0x8b,  0x55,  0x57,  0x3d,  0x7d,  0x3e,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x72,  0xfe,  0x19,
+  0x81,  0xba,  0xfe,  0x19,  0x41,  0x02,  0x72,  0x2d,  0x01,  0x0b,  0x1c,  0x34,  0x1d,  0xe8,  0x33,  0x31,
+  0xe1,  0x55,  0x19,  0xfe,  0xa6,  0x12,  0x55,  0x0a,  0x4d,  0x02,  0x4c,  0x01,  0x0b,  0x1c,  0x34,  0x1d,
+  0xe8,  0x33,  0x31,  0xdf,  0x07,  0x19,  0x23,  0x4c,  0x01,  0x0b,  0x1d,  0xe8,  0x33,  0x31,  0xfe,  0xe8,
+  0x09,  0xfe,  0xc2,  0x49,  0x51,  0x03,  0xfe,  0x9c,  0x00,  0x28,  0x8a,  0x53,  0x05,  0x1f,  0x35,  0xa9,
+  0xfe,  0xbb,  0x45,  0x55,  0x00,  0x4e,  0x44,  0x06,  0x7c,  0x43,  0xfe,  0xda,  0x14,  0x01,  0xaf,  0x8c,
+  0xfe,  0x4b,  0x45,  0xee,  0x32,  0x07,  0xa5,  0xed,  0x03,  0xcd,  0x28,  0x8a,  0x03,  0x45,  0x28,  0x35,
+  0x67,  0x02,  0x72,  0xfe,  0xc0,  0x5d,  0xfe,  0xf8,  0x14,  0xfe,  0x03,  0x17,  0x03,  0x5c,  0xc1,  0x0c,
+  0x5c,  0x67,  0x2d,  0x01,  0x0b,  0x26,  0x89,  0x01,  0xfe,  0x9e,  0x15,  0x02,  0x89,  0x01,  0x0b,  0x1c,
+  0x34,  0x1d,  0x4c,  0x33,  0x31,  0xdf,  0x07,  0x06,  0x23,  0x4c,  0x01,  0xf1,  0xfe,  0x42,  0x58,  0xf1,
+  0xfe,  0xa4,  0x14,  0x8c,  0xfe,  0x4a,  0xf4,  0x0a,  0x17,  0x4c,  0xfe,  0x4a,  0xf4,  0x06,  0xea,  0x32,
+  0x07,  0xa5,  0x8b,  0x02,  0x72,  0x03,  0x45,  0xc1,  0x0c,  0x45,  0x67,  0x2d,  0x01,  0x0b,  0x26,  0x89,
+  0x01,  0xfe,  0xcc,  0x15,  0x02,  0x89,  0x0f,  0x06,  0x27,  0xfe,  0xbe,  0x13,  0x26,  0xfe,  0xd4,  0x13,
+  0x76,  0xfe,  0x89,  0x48,  0x01,  0x0b,  0x21,  0x76,  0x04,  0x7b,  0xfe,  0xd0,  0x13,  0x1c,  0xfe,  0xd0,
+  0x13,  0x1d,  0xfe,  0xbe,  0x13,  0x67,  0x2d,  0x01,  0x0b,  0xfe,  0xd5,  0x10,  0x0f,  0x71,  0xff,  0x02,
+  0x00,  0x57,  0x52,  0x93,  0x1e,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x04,  0x0f,
+  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x1e,  0x43,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x04,
+  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x04,  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,
+  0x93,  0xfe,  0x0b,  0x58,  0x04,  0x09,  0x5c,  0x01,  0x87,  0x09,  0x45,  0x01,  0x87,  0x04,  0xfe,  0x03,
+  0xa1,  0x1e,  0x11,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x1f,  0x52,  0xfe,  0x00,  0x7d,  0xfe,
+  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x6a,  0x2a,  0x0c,  0x5e,  0x14,  0x5f,  0x57,  0x3f,
+  0x7d,  0x40,  0x04,  0xdd,  0xfe,  0x82,  0x4a,  0xfe,  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x8d,  0x04,  0x01,
+  0xfe,  0x0c,  0x19,  0xfe,  0x42,  0x48,  0x50,  0x51,  0x91,  0x01,  0x0b,  0x1d,  0xfe,  0x96,  0x15,  0x33,
+  0x31,  0xe1,  0x01,  0x0b,  0x1d,  0xfe,  0x96,  0x15,  0x33,  0x31,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,
+  0x03,  0xcd,  0x28,  0xfe,  0xcc,  0x12,  0x53,  0x05,  0x1a,  0xfe,  0xc4,  0x13,  0x21,  0x69,  0x1a,  0xee,
+  0x55,  0xca,  0x6b,  0xfe,  0xdc,  0x14,  0x4d,  0x0f,  0x06,  0x18,  0xca,  0x7c,  0x30,  0xfe,  0x78,  0x10,
+  0xff,  0x02,  0x83,  0x55,  0xab,  0xff,  0x02,  0x83,  0x55,  0x69,  0x19,  0xae,  0x98,  0xfe,  0x30,  0x00,
+  0x96,  0xf2,  0x18,  0x6d,  0x0f,  0x06,  0xfe,  0x56,  0x10,  0x69,  0x0a,  0xed,  0x98,  0xfe,  0x64,  0x00,
+  0x96,  0xf2,  0x09,  0xfe,  0x64,  0x00,  0x18,  0x9e,  0x0f,  0x06,  0xfe,  0x28,  0x10,  0x69,  0x06,  0xfe,
+  0x60,  0x13,  0x98,  0xfe,  0xc8,  0x00,  0x96,  0xf2,  0x09,  0xfe,  0xc8,  0x00,  0x18,  0x59,  0x0f,  0x06,
+  0x88,  0x98,  0xfe,  0x90,  0x01,  0x7a,  0xfe,  0x42,  0x15,  0x91,  0xe4,  0xfe,  0x43,  0xf4,  0x9f,  0xfe,
+  0x56,  0xf0,  0xfe,  0x54,  0x15,  0xfe,  0x04,  0xf4,  0x71,  0xfe,  0x43,  0xf4,  0x9e,  0xfe,  0xf3,  0x10,
+  0xfe,  0x40,  0x5c,  0x01,  0xfe,  0x16,  0x14,  0x1e,  0x43,  0xec,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,
+  0x6e,  0x7a,  0xfe,  0x90,  0x15,  0xc4,  0x6e,  0xfe,  0x1c,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,
+  0xcc,  0x7a,  0xfe,  0x90,  0x15,  0xc4,  0xcc,  0x88,  0x51,  0x21,  0xfe,  0x4d,  0xf4,  0x00,  0xe9,  0x91,
+  0x0f,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x04,  0x51,  0x0f,  0x0a,  0x04,  0x16,  0x06,  0x01,
+  0x0b,  0x26,  0xf3,  0x16,  0x0a,  0x01,  0x0b,  0x26,  0xf3,  0x16,  0x19,  0x01,  0x0b,  0x26,  0xf3,  0x76,
+  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x04,  0x16,  0x06,  0x01,  0x0b,  0x26,  0xb1,  0x16,  0x19,  0x01,  0x0b,
+  0x26,  0xb1,  0x16,  0x06,  0x01,  0x0b,  0x26,  0xb1,  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x26,  0xb1,  0x76,
+  0xfe,  0x89,  0x4a,  0x01,  0x0b,  0x04,  0x51,  0x04,  0x22,  0xd3,  0x07,  0x06,  0xfe,  0x48,  0x13,  0xb8,
+  0x13,  0xd3,  0xfe,  0x49,  0xf4,  0x00,  0x4d,  0x76,  0xa9,  0x67,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,
+  0xfe,  0x89,  0x48,  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x2e,  0x16,  0x32,  0x07,  0xfe,  0xe3,  0x00,
+  0xfe,  0x20,  0x13,  0x1d,  0xfe,  0x52,  0x16,  0x21,  0x13,  0xd4,  0x01,  0x4b,  0x22,  0xd4,  0x07,  0x06,
+  0x4e,  0x08,  0x54,  0x06,  0x37,  0x04,  0x09,  0x48,  0x01,  0x0e,  0xfb,  0x8e,  0x07,  0x11,  0xae,  0x09,
+  0x84,  0x01,  0x0e,  0x8e,  0x09,  0x5d,  0x01,  0xa8,  0x04,  0x09,  0x84,  0x01,  0x0e,  0x8e,  0xfe,  0x80,
+  0xe7,  0x11,  0x07,  0x11,  0x8a,  0xfe,  0x45,  0x58,  0x01,  0xf0,  0x8e,  0x04,  0x09,  0x48,  0x01,  0x0e,
+  0x8e,  0x09,  0x5d,  0x01,  0xa8,  0x04,  0x09,  0x48,  0x01,  0x0e,  0xfe,  0x80,  0x80,  0xfe,  0x80,  0x4c,
+  0xfe,  0x49,  0xe4,  0x11,  0xae,  0x09,  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x4c,  0x09,  0x5d,  0x01,  0x87,
+  0x04,  0x18,  0x11,  0x75,  0x6c,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,
+  0x1c,  0xfe,  0x1d,  0xf7,  0x1b,  0x97,  0xfe,  0xee,  0x16,  0x01,  0xfe,  0xf4,  0x17,  0xad,  0x9a,  0x1b,
+  0x6c,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x04,  0xb9,  0x23,  0xfe,  0xde,  0x16,  0xfe,  0xda,  0x10,
+  0x18,  0x11,  0x75,  0x03,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x1f,  0xfe,  0x18,  0x58,  0x03,  0xfe,
+  0x66,  0x01,  0xfe,  0x19,  0x58,  0x9a,  0x1f,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,
+  0x50,  0x6c,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x1f,  0x97,  0xfe,  0x38,  0x17,
+  0xfe,  0xb6,  0x14,  0x35,  0x04,  0xb9,  0x23,  0xfe,  0x10,  0x17,  0xfe,  0x9c,  0x10,  0x18,  0x11,  0x75,
+  0xfe,  0x83,  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x2e,  0x97,  0xfe,  0x5a,
+  0x17,  0xfe,  0x94,  0x14,  0xec,  0x9a,  0x2e,  0x6c,  0x1a,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
+  0x04,  0xb9,  0x23,  0xfe,  0x4e,  0x17,  0xfe,  0x6c,  0x10,  0x18,  0x11,  0x75,  0xfe,  0x30,  0xbc,  0xfe,
+  0xb2,  0xbc,  0x9a,  0xcb,  0x6c,  0x1a,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xcb,  0x97,  0xfe,  0x92,
+  0x17,  0xfe,  0x5c,  0x14,  0x35,  0x04,  0xb9,  0x23,  0xfe,  0x7e,  0x17,  0xfe,  0x42,  0x10,  0xfe,  0x02,
+  0xf6,  0x11,  0x75,  0xfe,  0x18,  0xfe,  0x60,  0xfe,  0x19,  0xfe,  0x61,  0xfe,  0x03,  0xa1,  0xfe,  0x1d,
+  0xf7,  0x5b,  0x97,  0xfe,  0xb8,  0x17,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x9a,  0x5b,  0x41,  0xfe,
+  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x11,  0xfe,  0x81,  0xe7,  0x11,  0x12,  0xfe,  0xdd,
+  0x00,  0x6a,  0x2a,  0x04,  0x6a,  0x2a,  0xfe,  0x12,  0x45,  0x23,  0xfe,  0xa8,  0x17,  0x15,  0x06,  0x39,
+  0xa0,  0xb4,  0x02,  0x2b,  0xfe,  0x39,  0xf0,  0xfe,  0xfc,  0x17,  0x21,  0x04,  0xfe,  0x7e,  0x18,  0x1e,
+  0x19,  0x66,  0x0f,  0x0d,  0x04,  0x75,  0x03,  0xd2,  0x1e,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,
+  0x7c,  0x6f,  0x4f,  0x32,  0x07,  0x2f,  0xfe,  0x3c,  0x13,  0xf1,  0xfe,  0x42,  0x13,  0x42,  0x92,  0x09,
+  0x48,  0x01,  0x0e,  0xbb,  0xeb,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,  0xf0,  0xfe,  0x00,  0xcc,
+  0xbb,  0xfe,  0xf3,  0x13,  0x43,  0x78,  0x07,  0x11,  0xac,  0x09,  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x4c,
+  0x01,  0x73,  0xfe,  0x16,  0x10,  0x07,  0x82,  0x8b,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xfe,  0x14,
+  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x1c,  0x18,  0x18,  0x0a,  0x04,  0xfe,  0x9c,  0xe7,  0x0a,  0x10,  0xfe,
+  0x15,  0x00,  0x64,  0x79,  0x2a,  0x01,  0xe3,  0x18,  0x06,  0x04,  0x42,  0x92,  0x08,  0x54,  0x1b,  0x37,
+  0x12,  0x2f,  0x01,  0x73,  0x18,  0x06,  0x04,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x3a,  0xce,  0x3b,
+  0xcf,  0xfe,  0x48,  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x04,  0x22,  0xa3,  0x77,  0x13,  0xa3,  0x04,  0x09,
+  0xa4,  0x01,  0x0e,  0xfe,  0x41,  0x48,  0x09,  0x46,  0x01,  0x0e,  0xfe,  0x49,  0x44,  0x17,  0xfe,  0xe8,
+  0x18,  0x77,  0x78,  0x04,  0x09,  0x48,  0x01,  0x0e,  0x07,  0x11,  0x4e,  0x09,  0x5d,  0x01,  0xa8,  0x09,
+  0x46,  0x01,  0x0e,  0x77,  0x78,  0x04,  0xfe,  0x4e,  0xe4,  0x19,  0x6b,  0xfe,  0x1c,  0x19,  0x03,  0xfe,
+  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xfe,  0x4e,  0xe4,  0xc9,  0x6b,  0xfe,  0x2e,  0x19,
+  0x03,  0xfe,  0x92,  0x00,  0xfe,  0x02,  0xe6,  0x1a,  0xe5,  0xfe,  0x4e,  0xe4,  0xfe,  0x0b,  0x00,  0x6b,
+  0xfe,  0x40,  0x19,  0x03,  0xfe,  0x94,  0x00,  0xfe,  0x02,  0xe6,  0x1f,  0xfe,  0x08,  0x10,  0x03,  0xfe,
+  0x96,  0x00,  0xfe,  0x02,  0xe6,  0x6d,  0xfe,  0x4e,  0x45,  0xea,  0xba,  0xff,  0x04,  0x68,  0x54,  0xe7,
+  0x1e,  0x6e,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,  0x00,
+  0x04,  0xea,  0xfe,  0x48,  0xf4,  0x19,  0x7a,  0xfe,  0x74,  0x19,  0x0f,  0x19,  0x04,  0x07,  0x7e,  0xfe,
+  0x5a,  0xf0,  0xfe,  0x84,  0x19,  0x25,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x07,  0x1a,  0xfe,  0x5a,
+  0xf0,  0xfe,  0x92,  0x19,  0x25,  0xca,  0xfe,  0x26,  0x10,  0x07,  0x19,  0x66,  0x25,  0x6d,  0xe5,  0x07,
+  0x0a,  0x66,  0x25,  0x9e,  0xfe,  0x0e,  0x10,  0x07,  0x06,  0x66,  0x25,  0x59,  0xa9,  0xb8,  0x04,  0x15,
+  0xfe,  0x09,  0x00,  0x01,  0x36,  0xfe,  0x04,  0xfe,  0x81,  0x03,  0x83,  0xfe,  0x40,  0x5c,  0x04,  0x1c,
+  0xf7,  0xfe,  0x14,  0xf0,  0x0b,  0x27,  0xfe,  0xd6,  0x19,  0x1c,  0xf7,  0x7b,  0xf7,  0xfe,  0x82,  0xf0,
+  0xfe,  0xda,  0x19,  0x04,  0xff,  0xcc,  0x00,  0x00,
 };
 
 STATIC unsigned short _adv_asc38C0800_size =
-    sizeof(_adv_asc38C0800_buf); /* 0x14F1 */
+        sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
 STATIC ADV_DCNT _adv_asc38C0800_chksum =
-    0x053503A5; /* Expanded checksum. */
+        0x050D3FD8UL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+STATIC unsigned char _adv_asc38C1600_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0x16,  0x00,  0xfc,  0x00,  0x10,  0x00,  0xf0,  0x18,  0xe4,  0x01,  0x00,
+  0x04,  0x1e,  0x48,  0xe4,  0x03,  0xf6,  0xf7,  0x13,  0x2e,  0x1e,  0x02,  0x00,  0x07,  0x17,  0xc0,  0x5f,
+  0x00,  0xfa,  0xff,  0xff,  0x04,  0x00,  0x00,  0xf6,  0x09,  0xe7,  0x82,  0xe7,  0x85,  0xf0,  0x86,  0xf0,
+  0x4e,  0x10,  0x9e,  0xe7,  0xff,  0x00,  0x55,  0xf0,  0x01,  0xf6,  0x03,  0x00,  0x98,  0x57,  0x01,  0xe6,
+  0x00,  0xea,  0x00,  0xec,  0x01,  0xfa,  0x18,  0xf4,  0x08,  0x00,  0xf0,  0x1d,  0x38,  0x54,  0x32,  0xf0,
+  0x10,  0x00,  0xc2,  0x0e,  0x1e,  0xf0,  0xd5,  0xf0,  0xbc,  0x00,  0x4b,  0xe4,  0x00,  0xe6,  0xb1,  0xf0,
+  0xb4,  0x00,  0x02,  0x13,  0x3e,  0x1c,  0xc8,  0x47,  0x3e,  0x00,  0xd8,  0x01,  0x06,  0x13,  0x0c,  0x1c,
+  0x5e,  0x1e,  0x00,  0x57,  0xc8,  0x57,  0x01,  0xfc,  0xbc,  0x0e,  0xa2,  0x12,  0xb9,  0x54,  0x00,  0x80,
+  0x62,  0x0a,  0x5a,  0x12,  0xc8,  0x15,  0x3e,  0x1e,  0x18,  0x40,  0xbd,  0x56,  0x03,  0xe6,  0x01,  0xea,
+  0x5c,  0xf0,  0x0f,  0x00,  0x20,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x04,  0x12,  0x04,  0x13,  0xbb,  0x55,
+  0x3c,  0x56,  0x3e,  0x57,  0x03,  0x58,  0x4a,  0xe4,  0x40,  0x00,  0xb6,  0x00,  0xbb,  0x00,  0xc0,  0x00,
+  0x00,  0x01,  0x01,  0x01,  0x3e,  0x01,  0x58,  0x0a,  0x44,  0x10,  0x0a,  0x12,  0x4c,  0x1c,  0x4e,  0x1c,
+  0x02,  0x4a,  0x30,  0xe4,  0x05,  0xe6,  0x0c,  0x00,  0x3c,  0x00,  0x80,  0x00,  0x24,  0x01,  0x3c,  0x01,
+  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,  0x78,  0x01,  0x7c,  0x01,
+  0xc6,  0x0e,  0x0c,  0x10,  0xac,  0x12,  0xae,  0x12,  0x16,  0x1a,  0x32,  0x1c,  0x6e,  0x1e,  0x02,  0x48,
+  0x3a,  0x55,  0xc9,  0x57,  0x02,  0xee,  0x5b,  0xf0,  0x03,  0xf7,  0x06,  0xf7,  0x03,  0xfc,  0x06,  0x00,
+  0x1e,  0x00,  0xbe,  0x00,  0xe1,  0x00,  0x0c,  0x12,  0x18,  0x1a,  0x70,  0x1a,  0x30,  0x1c,  0x38,  0x1c,
+  0x10,  0x44,  0x00,  0x4c,  0xb0,  0x57,  0x40,  0x5c,  0x4d,  0xe4,  0x04,  0xea,  0x5d,  0xf0,  0xa7,  0xf0,
+  0x04,  0xf6,  0x02,  0xfc,  0x05,  0x00,  0x09,  0x00,  0x19,  0x00,  0x32,  0x00,  0x33,  0x00,  0x34,  0x00,
+  0x36,  0x00,  0x98,  0x00,  0x9e,  0x00,  0xcc,  0x00,  0x20,  0x01,  0x4e,  0x01,  0x79,  0x01,  0x3c,  0x09,
+  0x68,  0x0d,  0x02,  0x10,  0x04,  0x10,  0x3a,  0x10,  0x08,  0x12,  0x0a,  0x13,  0x40,  0x16,  0x50,  0x16,
+  0x00,  0x17,  0x4a,  0x19,  0x00,  0x4e,  0x00,  0x54,  0x01,  0x58,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,
+  0x59,  0xf0,  0xb8,  0xf0,  0x48,  0xf4,  0x0e,  0xf7,  0x0a,  0x00,  0x9b,  0x00,  0x9c,  0x00,  0xa4,  0x00,
+  0xb5,  0x00,  0xba,  0x00,  0xd0,  0x00,  0xe7,  0x00,  0xf0,  0x03,  0x69,  0x08,  0xe9,  0x09,  0x5c,  0x0c,
+  0xb6,  0x12,  0xbc,  0x19,  0xd8,  0x1b,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x42,  0x1d,  0x08,  0x44,
+  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,  0x48,  0x46,  0x89,  0x48,  0x68,  0x54,  0x83,  0x55,  0x83,  0x59,
+  0x31,  0xe4,  0x02,  0xe6,  0x07,  0xf0,  0x08,  0xf0,  0x0b,  0xf0,  0x0c,  0xf0,  0x4b,  0xf4,  0x04,  0xf8,
+  0x05,  0xf8,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0xfc,  0x05,  0xfc,  0x07,  0x00,  0xa8,  0x00,  0xaa,  0x00,
+  0xb9,  0x00,  0xe0,  0x00,  0xe5,  0x00,  0x22,  0x01,  0x26,  0x01,  0x60,  0x01,  0x7a,  0x01,  0x82,  0x01,
+  0xc8,  0x01,  0xca,  0x01,  0x86,  0x02,  0x6a,  0x03,  0x18,  0x05,  0xb2,  0x07,  0x68,  0x08,  0x10,  0x0d,
+  0x06,  0x10,  0x0a,  0x10,  0x0e,  0x10,  0x12,  0x10,  0x60,  0x10,  0xed,  0x10,  0xf3,  0x10,  0x06,  0x12,
+  0x10,  0x12,  0x1e,  0x12,  0x0c,  0x13,  0x0e,  0x13,  0x10,  0x13,  0xfe,  0x9c,  0xf0,  0x35,  0x05,  0xfe,
+  0xec,  0x0e,  0xff,  0x10,  0x00,  0x00,  0xe9,  0xfe,  0x34,  0x1f,  0x00,  0xe8,  0xfe,  0x88,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
+  0x00,  0xfe,  0x4c,  0x00,  0x65,  0xff,  0x04,  0x00,  0x00,  0x1a,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
+  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x13,
+  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xe8,
+  0x37,  0x7d,  0x0d,  0x01,  0xfe,  0x4a,  0x11,  0xfe,  0x04,  0xf7,  0xe8,  0x7d,  0x0d,  0x51,  0x37,  0xfe,
+  0x3d,  0xf0,  0xfe,  0x0c,  0x02,  0xfe,  0x20,  0xf0,  0xbc,  0xfe,  0x91,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,
+  0x90,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x8f,  0xf0,  0xbc,  0x03,  0x67,  0x4d,  0x05,  0xfe,  0x08,  0x0f,
+  0x01,  0xfe,  0x78,  0x0f,  0xfe,  0xdd,  0x12,  0x05,  0xfe,  0x0e,  0x03,  0xfe,  0x28,  0x1c,  0x03,  0xfe,
+  0xa6,  0x00,  0xfe,  0xd1,  0x12,  0x3e,  0x22,  0xfe,  0xa6,  0x00,  0xac,  0xfe,  0x48,  0xf0,  0xfe,  0x90,
+  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0xaa,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xc8,  0x02,  0xfe,  0x46,  0xf0,
+  0xfe,  0x5a,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x60,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x4e,  0x02,  0xfe,
+  0x44,  0xf0,  0xfe,  0x52,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x56,  0x02,  0x1c,  0x0d,  0xa2,  0x1c,  0x07,
+  0x22,  0xb7,  0x05,  0x35,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xf5,  0xfe,  0x1e,
+  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0x5f,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xde,  0x0a,  0x81,  0x01,
+  0xa3,  0x05,  0x35,  0x1f,  0x95,  0x47,  0xb8,  0x01,  0xfe,  0xe4,  0x11,  0x0a,  0x81,  0x01,  0x5c,  0xfe,
+  0xbd,  0x10,  0x0a,  0x81,  0x01,  0x5c,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x1c,
+  0x07,  0x22,  0xb7,  0x37,  0x2a,  0x35,  0xfe,  0x3d,  0xf0,  0xfe,  0x0c,  0x02,  0x2b,  0xfe,  0x9e,  0x02,
+  0xfe,  0x5a,  0x1c,  0xfe,  0x12,  0x1c,  0xfe,  0x14,  0x1c,  0x1f,  0xfe,  0x30,  0x00,  0x47,  0xb8,  0x01,
+  0xfe,  0xd4,  0x11,  0x1c,  0x07,  0x22,  0xb7,  0x05,  0xe9,  0x21,  0x2c,  0x09,  0x1a,  0x31,  0xfe,  0x69,
+  0x10,  0x1c,  0x07,  0x22,  0xb7,  0xfe,  0x04,  0xec,  0x2c,  0x60,  0x01,  0xfe,  0x1e,  0x1e,  0x20,  0x2c,
+  0xfe,  0x05,  0xf6,  0xde,  0x01,  0xfe,  0x62,  0x1b,  0x01,  0x0c,  0x61,  0x4a,  0x44,  0x15,  0x56,  0x51,
+  0x01,  0xfe,  0x9e,  0x1e,  0x01,  0xfe,  0x96,  0x1a,  0x05,  0x35,  0x0a,  0x57,  0x01,  0x18,  0x09,  0x00,
+  0x36,  0x01,  0x85,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x0a,  0xba,  0x01,  0x18,  0xfe,  0xc8,  0x54,
+  0x7b,  0xfe,  0x1c,  0x03,  0x01,  0xfe,  0x96,  0x1a,  0x05,  0x35,  0x37,  0x60,  0xfe,  0x02,  0xe8,  0x30,
+  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xfe,  0x77,  0x57,  0xfe,  0x27,  0xf0,  0xfe,  0xe4,  0x01,  0xfe,
+  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xbc,  0xfe,  0x40,  0x1c,  0x2a,  0xeb,  0xfe,  0x26,  0xf0,  0xfe,  0x66,
+  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x54,  0x03,  0xfe,  0x11,  0xf0,  0xbc,  0xfe,  0xef,  0x10,  0xfe,  0x9f,
+  0xf0,  0xfe,  0x74,  0x03,  0xfe,  0x46,  0x1c,  0x19,  0xfe,  0x11,  0x00,  0x05,  0x70,  0x37,  0xfe,  0x48,
+  0x1c,  0xfe,  0x46,  0x1c,  0x01,  0x0c,  0x06,  0x28,  0xfe,  0x18,  0x13,  0x26,  0x21,  0xb9,  0xc7,  0x20,
+  0xb9,  0x0a,  0x57,  0x01,  0x18,  0xc7,  0x89,  0x01,  0xfe,  0xc8,  0x1a,  0x15,  0xe1,  0x2a,  0xeb,  0xfe,
+  0x01,  0xf0,  0xeb,  0xfe,  0x82,  0xf0,  0xfe,  0xa4,  0x03,  0xfe,  0x9c,  0x32,  0x15,  0xfe,  0xe4,  0x00,
+  0x2f,  0xfe,  0xb6,  0x03,  0x2a,  0x3c,  0x16,  0xfe,  0xc6,  0x03,  0x01,  0x41,  0xfe,  0x06,  0xf0,  0xfe,
+  0xd6,  0x03,  0xaf,  0xa0,  0xfe,  0x0a,  0xf0,  0xfe,  0xa2,  0x07,  0x05,  0x29,  0x03,  0x81,  0x1e,  0x1b,
+  0xfe,  0x24,  0x05,  0x1f,  0x63,  0x01,  0x42,  0x8f,  0xfe,  0x70,  0x02,  0x05,  0xea,  0xfe,  0x46,  0x1c,
+  0x37,  0x7d,  0x1d,  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x48,  0x1c,  0x75,
+  0x01,  0xa6,  0x86,  0x0a,  0x57,  0x01,  0x18,  0x09,  0x00,  0x1b,  0xec,  0x0a,  0xe1,  0x01,  0x18,  0x77,
+  0x50,  0x40,  0x8d,  0x30,  0x03,  0x81,  0x1e,  0xf8,  0x1f,  0x63,  0x01,  0x42,  0x8f,  0xfe,  0x70,  0x02,
+  0x05,  0xea,  0xd7,  0x99,  0xd8,  0x9c,  0x2a,  0x29,  0x2f,  0xfe,  0x4e,  0x04,  0x16,  0xfe,  0x4a,  0x04,
+  0x7e,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x54,  0x12,  0x32,  0xff,  0x02,  0x00,  0x10,  0x01,
+  0x08,  0x16,  0xfe,  0x02,  0x05,  0x32,  0x01,  0x08,  0x16,  0x29,  0x27,  0x25,  0xee,  0xfe,  0x4c,  0x44,
+  0xfe,  0x58,  0x12,  0x50,  0xfe,  0x44,  0x48,  0x13,  0x34,  0xfe,  0x4c,  0x54,  0x7b,  0xec,  0x60,  0x8d,
+  0x30,  0x01,  0xfe,  0x4e,  0x1e,  0xfe,  0x48,  0x47,  0xfe,  0x7c,  0x13,  0x01,  0x0c,  0x06,  0x28,  0xfe,
+  0x32,  0x13,  0x01,  0x43,  0x09,  0x9b,  0xfe,  0x68,  0x13,  0xfe,  0x26,  0x10,  0x13,  0x34,  0xfe,  0x4c,
+  0x54,  0x7b,  0xec,  0x01,  0xfe,  0x4e,  0x1e,  0xfe,  0x48,  0x47,  0xfe,  0x54,  0x13,  0x01,  0x0c,  0x06,
+  0x28,  0xa5,  0x01,  0x43,  0x09,  0x9b,  0xfe,  0x40,  0x13,  0x01,  0x0c,  0x06,  0x28,  0xf9,  0x1f,  0x7f,
+  0x01,  0x0c,  0x06,  0x07,  0x4d,  0x1f,  0xfe,  0x0d,  0x00,  0x01,  0x42,  0x8f,  0xfe,  0xa4,  0x0e,  0x05,
+  0x29,  0x32,  0x15,  0xfe,  0xe6,  0x00,  0x0f,  0xfe,  0x1c,  0x90,  0x04,  0xfe,  0x9c,  0x93,  0x3a,  0x0b,
+  0x0e,  0x8b,  0x02,  0x1f,  0x7f,  0x01,  0x42,  0x05,  0x35,  0xfe,  0x42,  0x5b,  0x7d,  0x1d,  0xfe,  0x46,
+  0x59,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0x0f,  0xfe,  0x87,  0x80,  0x04,  0xfe,  0x87,  0x83,  0xfe,
+  0xc9,  0x47,  0x0b,  0x0e,  0xd0,  0x65,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x98,  0x13,  0x0f,  0xfe,  0x20,
+  0x80,  0x04,  0xfe,  0xa0,  0x83,  0x33,  0x0b,  0x0e,  0x09,  0x1d,  0xfe,  0x84,  0x12,  0x01,  0x38,  0x06,
+  0x07,  0xfe,  0x70,  0x13,  0x03,  0xfe,  0xa2,  0x00,  0x1e,  0x1b,  0xfe,  0xda,  0x05,  0xd0,  0x54,  0x01,
+  0x38,  0x06,  0x0d,  0xfe,  0x58,  0x13,  0x03,  0xfe,  0xa0,  0x00,  0x1e,  0xfe,  0x50,  0x12,  0x5e,  0xff,
+  0x02,  0x00,  0x10,  0x2f,  0xfe,  0x90,  0x05,  0x2a,  0x3c,  0xcc,  0xff,  0x02,  0x00,  0x10,  0x2f,  0xfe,
+  0x9e,  0x05,  0x17,  0xfe,  0xf4,  0x05,  0x15,  0xfe,  0xe3,  0x00,  0x26,  0x01,  0x38,  0xfe,  0x4a,  0xf0,
+  0xfe,  0xc0,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0xba,  0x05,  0x71,  0x2e,  0xfe,  0x21,  0x00,  0xf1,  0x2e,
+  0xfe,  0x22,  0x00,  0xa2,  0x2e,  0x4a,  0xfe,  0x09,  0x48,  0xff,  0x02,  0x00,  0x10,  0x2f,  0xfe,  0xd0,
+  0x05,  0x17,  0xfe,  0xf4,  0x05,  0xfe,  0xe2,  0x08,  0x01,  0x38,  0x06,  0xfe,  0x1c,  0x00,  0x4d,  0x01,
+  0xa7,  0x2e,  0x07,  0x20,  0xe4,  0x47,  0xfe,  0x27,  0x01,  0x01,  0x0c,  0x06,  0x28,  0xfe,  0x24,  0x12,
+  0x3e,  0x01,  0x84,  0x1f,  0x7f,  0x01,  0x0c,  0x06,  0x07,  0x4d,  0x1f,  0xfe,  0x0d,  0x00,  0x01,  0x42,
+  0x8f,  0xfe,  0xa4,  0x0e,  0x05,  0x29,  0x03,  0xe6,  0x1e,  0xfe,  0xca,  0x13,  0x03,  0xb6,  0x1e,  0xfe,
+  0x40,  0x12,  0x03,  0x66,  0x1e,  0xfe,  0x38,  0x13,  0x3e,  0x01,  0x84,  0x17,  0xfe,  0x72,  0x06,  0x0a,
+  0x07,  0x01,  0x38,  0x06,  0x24,  0xfe,  0x02,  0x12,  0x4f,  0x01,  0xfe,  0x56,  0x19,  0x16,  0xfe,  0x68,
+  0x06,  0x15,  0x82,  0x01,  0x41,  0x15,  0xe2,  0x03,  0x66,  0x8a,  0x10,  0x66,  0x03,  0x9a,  0x1e,  0xfe,
+  0x70,  0x12,  0x03,  0x55,  0x1e,  0xfe,  0x68,  0x13,  0x01,  0xc6,  0x09,  0x12,  0x48,  0xfe,  0x92,  0x06,
+  0x2e,  0x12,  0x01,  0xfe,  0xac,  0x1d,  0xfe,  0x43,  0x48,  0x62,  0x80,  0x13,  0x58,  0xff,  0x02,  0x00,
+  0x57,  0x52,  0xad,  0x23,  0x3f,  0x4e,  0x62,  0x49,  0x3e,  0x01,  0x84,  0x17,  0xfe,  0xea,  0x06,  0x01,
+  0x38,  0x06,  0x12,  0xf7,  0x45,  0x0a,  0x95,  0x01,  0xfe,  0x84,  0x19,  0x16,  0xfe,  0xe0,  0x06,  0x15,
+  0x82,  0x01,  0x41,  0x15,  0xe2,  0x03,  0x55,  0x8a,  0x10,  0x55,  0x1c,  0x07,  0x01,  0x84,  0xfe,  0xae,
+  0x10,  0x03,  0x6f,  0x1e,  0xfe,  0x9e,  0x13,  0x3e,  0x01,  0x84,  0x03,  0x9a,  0x1e,  0xfe,  0x1a,  0x12,
+  0x01,  0x38,  0x06,  0x12,  0xfc,  0x01,  0xc6,  0x01,  0xfe,  0xac,  0x1d,  0xfe,  0x43,  0x48,  0x62,  0x80,
+  0xf0,  0x45,  0x0a,  0x95,  0x03,  0xb6,  0x1e,  0xf8,  0x01,  0x38,  0x06,  0x24,  0x36,  0xfe,  0x02,  0xf6,
+  0x07,  0x71,  0x78,  0x8c,  0x00,  0x4d,  0x62,  0x49,  0x3e,  0x2d,  0x93,  0x4e,  0xd0,  0x0d,  0x17,  0xfe,
+  0x9a,  0x07,  0x01,  0xfe,  0xc0,  0x19,  0x16,  0xfe,  0x90,  0x07,  0x26,  0x20,  0x9e,  0x15,  0x82,  0x01,
+  0x41,  0x15,  0xe2,  0x21,  0x9e,  0x09,  0x07,  0xfb,  0x03,  0xe6,  0xfe,  0x58,  0x57,  0x10,  0xe6,  0x05,
+  0xfe,  0x2a,  0x06,  0x03,  0x6f,  0x8a,  0x10,  0x6f,  0x1c,  0x07,  0x01,  0x84,  0xfe,  0x9c,  0x32,  0x5f,
+  0x75,  0x01,  0xa6,  0x86,  0x15,  0xfe,  0xe2,  0x00,  0x2f,  0xed,  0x2a,  0x3c,  0xfe,  0x0a,  0xf0,  0xfe,
+  0xce,  0x07,  0xae,  0xfe,  0x96,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x9e,  0x08,  0xaf,  0xa0,  0x05,  0x29,
+  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x2e,  0x12,  0x14,  0x1d,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,
+  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0xfe,  0x99,  0xa4,  0x01,  0x08,  0x14,  0x00,  0x05,  0xfe,
+  0xc6,  0x09,  0x01,  0x76,  0x06,  0x12,  0xfe,  0x3a,  0x12,  0x01,  0x0c,  0x06,  0x12,  0xfe,  0x30,  0x13,
+  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,  0x00,
+  0x01,  0x08,  0x14,  0x07,  0x01,  0x08,  0x14,  0x00,  0x05,  0xef,  0x7c,  0x4a,  0x78,  0x4f,  0x0f,  0xfe,
+  0x9a,  0x81,  0x04,  0xfe,  0x9a,  0x83,  0xfe,  0xcb,  0x47,  0x0b,  0x0e,  0x2d,  0x28,  0x48,  0xfe,  0x6c,
+  0x08,  0x0a,  0x28,  0xfe,  0x09,  0x6f,  0xca,  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,  0x53,  0x63,  0x4e,
+  0x7c,  0x97,  0x2f,  0xfe,  0x7e,  0x08,  0x2a,  0x3c,  0xfe,  0x0a,  0xf0,  0xfe,  0x6c,  0x08,  0xaf,  0xa0,
+  0xae,  0xfe,  0x96,  0x08,  0x05,  0x29,  0x01,  0x41,  0x05,  0xed,  0x14,  0x24,  0x05,  0xed,  0xfe,  0x9c,
+  0xf7,  0x9f,  0x01,  0xfe,  0xae,  0x1e,  0xfe,  0x18,  0x58,  0x01,  0xfe,  0xbe,  0x1e,  0xfe,  0x99,  0x58,
+  0xfe,  0x78,  0x18,  0xfe,  0xf9,  0x18,  0x8e,  0xfe,  0x16,  0x09,  0x10,  0x6a,  0x22,  0x6b,  0x01,  0x0c,
+  0x61,  0x54,  0x44,  0x21,  0x2c,  0x09,  0x1a,  0xf8,  0x77,  0x01,  0xfe,  0x7e,  0x1e,  0x47,  0x2c,  0x7a,
+  0x30,  0xf0,  0xfe,  0x83,  0xe7,  0xfe,  0x3f,  0x00,  0x71,  0xfe,  0x03,  0x40,  0x01,  0x0c,  0x61,  0x65,
+  0x44,  0x01,  0xc2,  0xc8,  0xfe,  0x1f,  0x40,  0x20,  0x6e,  0x01,  0xfe,  0x6a,  0x16,  0xfe,  0x08,  0x50,
+  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,  0xfe,  0xc6,  0x51,  0xfe,  0x10,  0x10,  0x01,  0xfe,  0xce,  0x1e,
+  0x01,  0xfe,  0xde,  0x1e,  0x10,  0x68,  0x22,  0x69,  0x01,  0xfe,  0xee,  0x1e,  0x01,  0xfe,  0xfe,  0x1e,
+  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x10,  0x4b,  0x22,  0x4c,  0xfe,  0x8a,  0x10,  0x01,  0x0c,  0x06,
+  0x54,  0xfe,  0x50,  0x12,  0x01,  0xfe,  0xae,  0x1e,  0x01,  0xfe,  0xbe,  0x1e,  0x10,  0x6a,  0x22,  0x6b,
+  0x01,  0x0c,  0x06,  0x65,  0x4e,  0x01,  0xc2,  0x0f,  0xfe,  0x1f,  0x80,  0x04,  0xfe,  0x9f,  0x83,  0x33,
+  0x0b,  0x0e,  0x20,  0x6e,  0x0f,  0xfe,  0x44,  0x90,  0x04,  0xfe,  0xc4,  0x93,  0x3a,  0x0b,  0xfe,  0xc6,
+  0x90,  0x04,  0xfe,  0xc6,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0x6c,  0x22,  0x6d,  0x01,  0xfe,  0xce,  0x1e,
+  0x01,  0xfe,  0xde,  0x1e,  0x10,  0x68,  0x22,  0x69,  0x0f,  0xfe,  0x40,  0x90,  0x04,  0xfe,  0xc0,  0x93,
+  0x3a,  0x0b,  0xfe,  0xc2,  0x90,  0x04,  0xfe,  0xc2,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0x4b,  0x22,  0x4c,
+  0x10,  0x64,  0x22,  0x34,  0x01,  0x0c,  0x61,  0x24,  0x44,  0x37,  0x13,  0xfe,  0x4e,  0x11,  0x2f,  0xfe,
+  0xde,  0x09,  0xfe,  0x9e,  0xf0,  0xfe,  0xf2,  0x09,  0xfe,  0x01,  0x48,  0x1b,  0x3c,  0x37,  0x88,  0xf5,
+  0xd4,  0xfe,  0x1e,  0x0a,  0xd5,  0xfe,  0x42,  0x0a,  0xd2,  0xfe,  0x1e,  0x0a,  0xd3,  0xfe,  0x42,  0x0a,
+  0xae,  0xfe,  0x12,  0x0a,  0xfe,  0x06,  0xf0,  0xfe,  0x18,  0x0a,  0xaf,  0xa0,  0x05,  0x29,  0x01,  0x41,
+  0xfe,  0xc1,  0x10,  0x14,  0x24,  0xfe,  0xc1,  0x10,  0x01,  0x76,  0x06,  0x07,  0xfe,  0x14,  0x12,  0x01,
+  0x76,  0x06,  0x0d,  0x5d,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x74,  0x12,  0xfe,  0x2e,  0x1c,  0x05,  0xfe,
+  0x1a,  0x0c,  0x01,  0x76,  0x06,  0x07,  0x5d,  0x01,  0x76,  0x06,  0x0d,  0x41,  0xfe,  0x2c,  0x1c,  0xfe,
+  0xaa,  0xf0,  0xfe,  0xce,  0x0a,  0xfe,  0xac,  0xf0,  0xfe,  0x66,  0x0a,  0xfe,  0x92,  0x10,  0xc4,  0xf6,
+  0xfe,  0xad,  0xf0,  0xfe,  0x72,  0x0a,  0x05,  0xfe,  0x1a,  0x0c,  0xc5,  0xfe,  0xe7,  0x10,  0xfe,  0x2b,
+  0xf0,  0xbf,  0xfe,  0x6b,  0x18,  0x23,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xac,  0xfe,  0xd2,  0xf0,
+  0xbf,  0xfe,  0x76,  0x18,  0x23,  0x1d,  0x1b,  0xbf,  0x03,  0xe3,  0x23,  0x07,  0x1b,  0xbf,  0xd4,  0x5b,
+  0xd5,  0x5b,  0xd2,  0x5b,  0xd3,  0x5b,  0xc4,  0xc5,  0xfe,  0xa9,  0x10,  0x75,  0x5e,  0x32,  0x1f,  0x7f,
+  0x01,  0x42,  0x19,  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x70,  0x19,  0x98,  0x05,  0x70,  0xfe,  0x74,
+  0x18,  0x23,  0xfe,  0x00,  0xf8,  0x1b,  0x5b,  0x7d,  0x12,  0x01,  0xfe,  0x78,  0x0f,  0x4d,  0x01,  0xfe,
+  0x96,  0x1a,  0x21,  0x30,  0x77,  0x7d,  0x1d,  0x05,  0x5b,  0x01,  0x0c,  0x06,  0x0d,  0x2b,  0xfe,  0xe2,
+  0x0b,  0x01,  0x0c,  0x06,  0x54,  0xfe,  0xa6,  0x12,  0x01,  0x0c,  0x06,  0x24,  0xfe,  0x88,  0x13,  0x21,
+  0x6e,  0xc7,  0x01,  0xfe,  0x1e,  0x1f,  0x0f,  0xfe,  0x83,  0x80,  0x04,  0xfe,  0x83,  0x83,  0xfe,  0xc9,
+  0x47,  0x0b,  0x0e,  0xfe,  0xc8,  0x44,  0xfe,  0x42,  0x13,  0x0f,  0xfe,  0x04,  0x91,  0x04,  0xfe,  0x84,
+  0x93,  0xfe,  0xca,  0x57,  0x0b,  0xfe,  0x86,  0x91,  0x04,  0xfe,  0x86,  0x93,  0xfe,  0xcb,  0x57,  0x0b,
+  0x0e,  0x7a,  0x30,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x8e,  0x40,  0x03,  0x6a,  0x3b,  0x6b,  0x10,
+  0x97,  0x22,  0x98,  0xd9,  0x6a,  0xda,  0x6b,  0x01,  0xc2,  0xc8,  0x7a,  0x30,  0x20,  0x6e,  0xdb,  0x64,
+  0xdc,  0x34,  0x91,  0x6c,  0x7e,  0x6d,  0xfe,  0x44,  0x55,  0xfe,  0xe5,  0x55,  0xfe,  0x04,  0xfa,  0x64,
+  0xfe,  0x05,  0xfa,  0x34,  0x01,  0xfe,  0x6a,  0x16,  0xa3,  0x26,  0x10,  0x97,  0x10,  0x98,  0x91,  0x6c,
+  0x7e,  0x6d,  0xfe,  0x14,  0x10,  0x01,  0x0c,  0x06,  0x24,  0x1b,  0x40,  0x91,  0x4b,  0x7e,  0x4c,  0x01,
+  0x0c,  0x06,  0xfe,  0xf7,  0x00,  0x44,  0x03,  0x68,  0x3b,  0x69,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,
+  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x05,  0x5b,  0x01,  0x0c,  0x06,  0x24,  0x1b,  0x40,  0x01,  0x0c,
+  0x06,  0xfe,  0xf7,  0x00,  0x44,  0x78,  0x01,  0xfe,  0x8e,  0x1e,  0x4f,  0x0f,  0xfe,  0x10,  0x90,  0x04,
+  0xfe,  0x90,  0x93,  0x3a,  0x0b,  0xfe,  0x92,  0x90,  0x04,  0xfe,  0x92,  0x93,  0x79,  0x0b,  0x0e,  0xfe,
+  0xbd,  0x10,  0x01,  0x43,  0x09,  0xbb,  0x1b,  0xfe,  0x6e,  0x0a,  0x15,  0xbb,  0x01,  0x0c,  0x06,  0x0d,
+  0xfe,  0x14,  0x13,  0x03,  0x4b,  0x3b,  0x4c,  0x8e,  0xfe,  0x6e,  0x0a,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,
+  0x58,  0x05,  0x5b,  0x26,  0x3e,  0x0f,  0xfe,  0x19,  0x80,  0x04,  0xfe,  0x99,  0x83,  0x33,  0x0b,  0x0e,
+  0xfe,  0xe5,  0x10,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x1a,  0x12,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,
+  0xfe,  0x6b,  0x18,  0xac,  0xfe,  0xd1,  0xf0,  0xef,  0x1f,  0x92,  0x01,  0x42,  0x19,  0xfe,  0x44,  0x00,
+  0xfe,  0x90,  0x10,  0xfe,  0x6c,  0x19,  0xd9,  0x4b,  0xfe,  0xed,  0x19,  0xda,  0x4c,  0xfe,  0x0c,  0x51,
+  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x23,  0xfe,  0x00,  0xff,  0x31,  0xfe,  0x76,  0x10,  0xac,  0xfe,
+  0xd2,  0xf0,  0xfe,  0xba,  0x0c,  0xfe,  0x76,  0x18,  0x23,  0x1d,  0x5d,  0x03,  0xe3,  0x23,  0x07,  0xfe,
+  0x08,  0x13,  0x19,  0xfe,  0x16,  0x00,  0x05,  0x70,  0xfe,  0xd1,  0xf0,  0xfe,  0xcc,  0x0c,  0x1f,  0x92,
+  0x01,  0x42,  0x19,  0xfe,  0x17,  0x00,  0x5c,  0xfe,  0xce,  0xf0,  0xfe,  0xd2,  0x0c,  0xfe,  0x3e,  0x10,
+  0xfe,  0xcd,  0xf0,  0xfe,  0xde,  0x0c,  0x19,  0xfe,  0x22,  0x00,  0x05,  0x70,  0xfe,  0xcb,  0xf0,  0xfe,
+  0xea,  0x0c,  0x19,  0xfe,  0x24,  0x00,  0x05,  0x70,  0xfe,  0xd0,  0xf0,  0xfe,  0xf4,  0x0c,  0x19,  0x94,
+  0xfe,  0x1c,  0x10,  0xfe,  0xcf,  0xf0,  0xfe,  0xfe,  0x0c,  0x19,  0x4a,  0xf3,  0xfe,  0xcc,  0xf0,  0xef,
+  0x01,  0x76,  0x06,  0x24,  0x4d,  0x19,  0xfe,  0x12,  0x00,  0x37,  0x13,  0xfe,  0x4e,  0x11,  0x2f,  0xfe,
+  0x16,  0x0d,  0xfe,  0x9e,  0xf0,  0xfe,  0x2a,  0x0d,  0xfe,  0x01,  0x48,  0x1b,  0x3c,  0x37,  0x88,  0xf5,
+  0xd4,  0x29,  0xd5,  0x29,  0xd2,  0x29,  0xd3,  0x29,  0x37,  0xfe,  0x9c,  0x32,  0x2f,  0xfe,  0x3e,  0x0d,
+  0x2a,  0x3c,  0xae,  0xfe,  0x62,  0x0d,  0xaf,  0xa0,  0xd4,  0x9f,  0xd5,  0x9f,  0xd2,  0x9f,  0xd3,  0x9f,
+  0x05,  0x29,  0x01,  0x41,  0xfe,  0xd3,  0x10,  0x15,  0xfe,  0xe8,  0x00,  0xc4,  0xc5,  0x75,  0xd7,  0x99,
+  0xd8,  0x9c,  0xfe,  0x89,  0xf0,  0x29,  0x27,  0x25,  0xbe,  0xd7,  0x99,  0xd8,  0x9c,  0x2f,  0xfe,  0x8c,
+  0x0d,  0x16,  0x29,  0x27,  0x25,  0xbd,  0xfe,  0x01,  0x48,  0xa4,  0x19,  0xfe,  0x42,  0x00,  0x05,  0x70,
+  0x90,  0x07,  0xfe,  0x81,  0x49,  0x1b,  0xfe,  0x64,  0x0e,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x44,  0x13,
+  0x19,  0x00,  0x2d,  0x0d,  0xfe,  0x54,  0x12,  0x2d,  0xfe,  0x28,  0x00,  0x2b,  0xfe,  0xda,  0x0e,  0x0a,
+  0x57,  0x01,  0x18,  0x09,  0x00,  0x36,  0x46,  0xfe,  0x28,  0x00,  0xfe,  0xfa,  0x10,  0x01,  0xfe,  0xf4,
+  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x0a,  0xba,  0x01,  0xfe,  0x58,  0x10,  0x40,  0x15,  0x56,  0x01,  0x85,
+  0x05,  0x35,  0x19,  0xfe,  0x44,  0x00,  0x2d,  0x0d,  0xf7,  0x46,  0x0d,  0xfe,  0xcc,  0x10,  0x01,  0xa7,
+  0x46,  0x0d,  0xfe,  0xc2,  0x10,  0x01,  0xa7,  0x0f,  0xfe,  0x19,  0x82,  0x04,  0xfe,  0x99,  0x83,  0xfe,
+  0xcc,  0x47,  0x0b,  0x0e,  0xfe,  0x34,  0x46,  0xa5,  0x46,  0x0d,  0x19,  0xfe,  0x43,  0x00,  0xfe,  0xa2,
+  0x10,  0x01,  0x0c,  0x61,  0x0d,  0x44,  0x01,  0xfe,  0xf4,  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x40,  0x15,
+  0x56,  0x01,  0x85,  0x7d,  0x0d,  0x40,  0x51,  0x01,  0xfe,  0x9e,  0x1e,  0x05,  0xfe,  0x3a,  0x03,  0x01,
+  0x0c,  0x06,  0x0d,  0x5d,  0x46,  0x0d,  0x19,  0x00,  0xfe,  0x62,  0x10,  0x01,  0x76,  0x06,  0x12,  0xfe,
+  0x5c,  0x12,  0x01,  0x0c,  0x06,  0x12,  0xfe,  0x52,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,
+  0x8e,  0x0e,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x94,  0x0e,  0x01,  0x0c,  0x61,  0x12,  0x44,
+  0xfe,  0x9f,  0x10,  0x19,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0d,  0x4f,  0xfe,  0x2e,  0x10,  0x19,
+  0xfe,  0x13,  0x00,  0xfe,  0x10,  0x10,  0x19,  0xfe,  0x47,  0x00,  0xf1,  0x19,  0xfe,  0x41,  0x00,  0xa2,
+  0x19,  0xfe,  0x24,  0x00,  0x86,  0xc4,  0xc5,  0x75,  0x03,  0x81,  0x1e,  0x2b,  0xea,  0x4f,  0xfe,  0x04,
+  0xe6,  0x12,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0x40,  0x01,  0xf4,  0x05,  0x35,  0xfe,  0x12,  0x1c,
+  0x1f,  0x0d,  0x47,  0xb5,  0xc3,  0x1f,  0xfe,  0x31,  0x00,  0x47,  0xb8,  0x01,  0xfe,  0xd4,  0x11,  0x05,
+  0xe9,  0x51,  0xfe,  0x06,  0xec,  0xe0,  0xfe,  0x0e,  0x47,  0x46,  0x28,  0xfe,  0xce,  0x45,  0x31,  0x51,
+  0xfe,  0x06,  0xea,  0xe0,  0xfe,  0x47,  0x4b,  0x45,  0xfe,  0x75,  0x57,  0x03,  0x67,  0xfe,  0x98,  0x56,
+  0xfe,  0x38,  0x12,  0x0a,  0x5a,  0x01,  0x18,  0xfe,  0x44,  0x48,  0x60,  0x01,  0x0c,  0x06,  0x28,  0xfe,
+  0x18,  0x13,  0x0a,  0x57,  0x01,  0x18,  0x3e,  0xfe,  0x41,  0x58,  0x0a,  0xba,  0xfe,  0xfa,  0x14,  0xfe,
+  0x49,  0x54,  0xb0,  0xfe,  0x5e,  0x0f,  0x05,  0xfe,  0x3a,  0x03,  0x0a,  0x67,  0xfe,  0xe0,  0x14,  0xfe,
+  0x0e,  0x47,  0x46,  0x28,  0xfe,  0xce,  0x45,  0x31,  0x51,  0xfe,  0xce,  0x47,  0xfe,  0xad,  0x13,  0x05,
+  0x35,  0x21,  0x2c,  0x09,  0x1a,  0xfe,  0x98,  0x12,  0x26,  0x20,  0x96,  0x20,  0xe7,  0xfe,  0x08,  0x1c,
+  0xfe,  0x7c,  0x19,  0xfe,  0xfd,  0x19,  0xfe,  0x0a,  0x1c,  0x03,  0xe5,  0xfe,  0x48,  0x55,  0xa5,  0x3b,
+  0xfe,  0x62,  0x01,  0xfe,  0xc9,  0x55,  0x31,  0xfe,  0x74,  0x10,  0x01,  0xfe,  0xf0,  0x1a,  0x03,  0xfe,
+  0x38,  0x01,  0x3b,  0xfe,  0x3a,  0x01,  0x8e,  0xfe,  0x1e,  0x10,  0xfe,  0x02,  0xec,  0xe7,  0x53,  0x00,
+  0x36,  0xfe,  0x04,  0xec,  0x2c,  0x60,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x62,  0x1b,
+  0x01,  0xfe,  0xce,  0x1e,  0xb2,  0x11,  0xfe,  0x18,  0x13,  0xca,  0xfe,  0x02,  0xea,  0xe7,  0x53,  0x92,
+  0xfe,  0xc3,  0x13,  0x1f,  0x12,  0x47,  0xb5,  0xc3,  0xfe,  0x2a,  0x10,  0x03,  0xfe,  0x38,  0x01,  0x23,
+  0xfe,  0xf0,  0xff,  0x10,  0xe5,  0x03,  0xfe,  0x3a,  0x01,  0x10,  0xfe,  0x62,  0x01,  0x01,  0xfe,  0x1e,
+  0x1e,  0x20,  0x2c,  0x15,  0x56,  0x01,  0xfe,  0x9e,  0x1e,  0x13,  0x07,  0x02,  0x26,  0x02,  0x21,  0x96,
+  0xc7,  0x20,  0x96,  0x09,  0x92,  0xfe,  0x79,  0x13,  0x1f,  0x1d,  0x47,  0xb5,  0xc3,  0xfe,  0xe1,  0x10,
+  0xcf,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x02,  0xcf,  0xfe,  0x03,  0xdc,  0xfe,
+  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x02,  0xfe,  0x03,  0x57,  0xcf,  0x26,  0xfe,  0x00,  0xcc,  0x02,  0xfe,
+  0x03,  0x57,  0xcf,  0x89,  0x02,  0x01,  0x0c,  0x06,  0x4a,  0xfe,  0x4e,  0x13,  0x0f,  0xfe,  0x1c,  0x80,
+  0x04,  0xfe,  0x9c,  0x83,  0x33,  0x0b,  0x0e,  0x09,  0x07,  0xfe,  0x3a,  0x13,  0x0f,  0xfe,  0x1e,  0x80,
+  0x04,  0xfe,  0x9e,  0x83,  0x33,  0x0b,  0x0e,  0xfe,  0x2a,  0x13,  0x0f,  0xfe,  0x1d,  0x80,  0x04,  0xfe,
+  0x9d,  0x83,  0xfe,  0xf9,  0x13,  0x0e,  0xfe,  0x1c,  0x13,  0x01,  0xfe,  0xee,  0x1e,  0xac,  0xfe,  0x14,
+  0x13,  0x01,  0xfe,  0xfe,  0x1e,  0xfe,  0x81,  0x58,  0xfa,  0x01,  0xfe,  0x0e,  0x1f,  0xfe,  0x30,  0xf4,
+  0x0d,  0xfe,  0x3c,  0x50,  0xa2,  0x01,  0xfe,  0x92,  0x1b,  0x01,  0x43,  0x09,  0x56,  0xfb,  0x01,  0xfe,
+  0xc8,  0x1a,  0x01,  0x0c,  0x06,  0x28,  0xa4,  0x01,  0xfe,  0xf4,  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x15,
+  0xfe,  0xe9,  0x00,  0x01,  0x0c,  0x06,  0x4a,  0xfe,  0x4e,  0x13,  0x01,  0xfe,  0x22,  0x1b,  0xfe,  0x1e,
+  0x1c,  0x0f,  0xfe,  0x14,  0x90,  0x04,  0xfe,  0x94,  0x93,  0x3a,  0x0b,  0xfe,  0x96,  0x90,  0x04,  0xfe,
+  0x96,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0xfe,  0x64,  0x01,  0x22,  0xfe,  0x66,  0x01,  0x01,  0x0c,  0x06,
+  0x65,  0xf9,  0x0f,  0xfe,  0x03,  0x80,  0x04,  0xfe,  0x83,  0x83,  0x33,  0x0b,  0x0e,  0x77,  0xfe,  0x01,
+  0xec,  0x2c,  0xfe,  0x80,  0x40,  0x20,  0x2c,  0x7a,  0x30,  0x15,  0xdf,  0x40,  0x21,  0x2c,  0xfe,  0x00,
+  0x40,  0x8d,  0x2c,  0x02,  0xfe,  0x08,  0x1c,  0x03,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x03,  0xfe,
+  0xae,  0x00,  0xfe,  0x07,  0x58,  0x03,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x03,  0xfe,  0xb2,  0x00,
+  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x2e,  0x49,  0x20,  0xe0,  0x26,  0x10,  0x66,  0x10,  0x55,  0x10,
+  0x6f,  0x13,  0x57,  0x52,  0x4f,  0x1c,  0x28,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x2b,  0xfe,  0x88,
+  0x11,  0x46,  0x1a,  0x13,  0x5a,  0x52,  0x1c,  0x4a,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x2b,  0xfe,
+  0x9e,  0x11,  0x2e,  0x1a,  0x20,  0x2c,  0x90,  0x34,  0x60,  0x21,  0x2c,  0xfe,  0x00,  0x40,  0x8d,  0x2c,
+  0x15,  0xdf,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xb2,  0x11,  0xfe,  0x12,  0x1c,  0x75,  0xfe,
+  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x02,  0x51,  0xfe,  0x0c,  0x14,  0xfe,  0x0e,  0x47,
+  0xfe,  0x07,  0xe6,  0x28,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x02,  0x01,  0xa7,  0x90,  0x34,  0x60,
+  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x42,  0x13,  0xfe,  0x02,  0x80,  0x09,  0x56,  0xfe,  0x34,
+  0x13,  0x0a,  0x5a,  0x01,  0x18,  0xcb,  0xfe,  0x36,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,
+  0xfe,  0xb2,  0x16,  0xfe,  0x00,  0xcc,  0xcb,  0xfe,  0xf3,  0x13,  0x3f,  0x89,  0x09,  0x1a,  0xa5,  0x0a,
+  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x5c,  0x01,  0x85,  0xf2,  0x09,  0x9b,  0xa4,  0xfe,  0x14,  0x56,  0xfe,
+  0xd6,  0xf0,  0xfe,  0xec,  0x11,  0x02,  0xfe,  0x44,  0x58,  0x77,  0xfe,  0x01,  0xec,  0xb8,  0xfe,  0x9e,
+  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x12,  0x8d,  0x30,  0x01,  0xf4,  0xfe,  0xdd,  0x10,
+  0x37,  0xd7,  0x99,  0xd8,  0x9c,  0x27,  0x25,  0xee,  0x09,  0x12,  0xfe,  0x48,  0x12,  0x09,  0x0d,  0xfe,
+  0x56,  0x12,  0x09,  0x1d,  0xfe,  0x30,  0x12,  0x09,  0xdd,  0x1b,  0xfe,  0xc4,  0x13,  0x09,  0xfe,  0x23,
+  0x00,  0x1b,  0xfe,  0xd0,  0x13,  0x09,  0x07,  0x1b,  0xfe,  0x34,  0x14,  0x09,  0x24,  0xfe,  0x12,  0x12,
+  0x09,  0x00,  0x1b,  0x29,  0x1f,  0xdd,  0x01,  0x42,  0xa1,  0x32,  0x01,  0x08,  0xae,  0x41,  0x02,  0x32,
+  0xfe,  0x62,  0x08,  0x0a,  0xe1,  0x01,  0xfe,  0x58,  0x10,  0x15,  0x9b,  0x05,  0x35,  0x32,  0x01,  0x43,
+  0x09,  0xbb,  0xfe,  0xd7,  0x13,  0x91,  0x4b,  0x7e,  0x4c,  0x8e,  0xfe,  0x80,  0x13,  0x01,  0x0c,  0x06,
+  0x54,  0xfe,  0x72,  0x12,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x44,  0x55,  0xfe,  0xe5,  0x55,  0xb0,  0xfe,
+  0x4a,  0x13,  0x21,  0x6e,  0xfe,  0x26,  0x13,  0x03,  0x97,  0x3b,  0x98,  0x8e,  0xfe,  0xb6,  0x0e,  0x10,
+  0x6a,  0x22,  0x6b,  0x26,  0x10,  0x97,  0x10,  0x98,  0x01,  0xc2,  0x2e,  0x49,  0x88,  0x20,  0x6e,  0x01,
+  0xfe,  0x6a,  0x16,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,
+  0x64,  0xfe,  0x05,  0xfa,  0x34,  0xfe,  0x8f,  0x10,  0x03,  0x6c,  0x3b,  0x6d,  0xfe,  0x40,  0x56,  0xfe,
+  0xe1,  0x56,  0x10,  0x6c,  0x22,  0x6d,  0x71,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x44,  0x55,  0xfe,  0xe5,
+  0x55,  0x03,  0x68,  0x3b,  0x69,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x10,  0x68,  0x22,  0x69,  0x01,
+  0x0c,  0x06,  0x54,  0xf9,  0x21,  0x6e,  0xfe,  0x1f,  0x40,  0x03,  0x6a,  0x3b,  0x6b,  0xfe,  0x2c,  0x50,
+  0xfe,  0xae,  0x50,  0x03,  0x6c,  0x3b,  0x6d,  0xfe,  0x44,  0x50,  0xfe,  0xc6,  0x50,  0x03,  0x68,  0x3b,
+  0x69,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x03,  0x4b,  0x3b,  0x4c,  0xfe,  0x40,  0x50,  0xfe,  0xc2,
+  0x50,  0x05,  0x73,  0x2e,  0x07,  0x20,  0x9e,  0x05,  0x72,  0x32,  0x01,  0x08,  0x16,  0x3d,  0x27,  0x25,
+  0xee,  0x09,  0x07,  0x2b,  0x3d,  0x01,  0x43,  0x09,  0xbb,  0x2b,  0x72,  0x01,  0xa6,  0x23,  0x3f,  0x1b,
+  0x3d,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x1e,  0x13,  0x91,  0x4b,  0x7e,  0x4c,  0xfe,  0x0a,  0x55,  0x31,
+  0xfe,  0x8b,  0x55,  0xd9,  0x4b,  0xda,  0x4c,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x05,  0x72,  0x01,
+  0xfe,  0x8e,  0x1e,  0xca,  0xfe,  0x19,  0x41,  0x05,  0x72,  0x32,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0xc0,
+  0x27,  0x25,  0xbe,  0x2d,  0x1d,  0xc0,  0x2d,  0x0d,  0x83,  0x2d,  0x7f,  0x1b,  0xfe,  0x66,  0x15,  0x05,
+  0x3d,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0xc0,  0x27,  0x25,  0xbd,  0x09,  0x1d,  0x2b,  0x3d,  0x01,  0x08,
+  0x16,  0xc0,  0x27,  0x25,  0xfe,  0xe8,  0x09,  0xfe,  0xc2,  0x49,  0x50,  0x03,  0xb6,  0x1e,  0x83,  0x01,
+  0x38,  0x06,  0x24,  0x31,  0xa1,  0xfe,  0xbb,  0x45,  0x2d,  0x00,  0xa4,  0x46,  0x07,  0x90,  0x3f,  0x01,
+  0xfe,  0xf8,  0x15,  0x01,  0xa6,  0x86,  0xfe,  0x4b,  0x45,  0xfe,  0x20,  0x13,  0x01,  0x43,  0x09,  0x82,
+  0xfe,  0x16,  0x13,  0x03,  0x9a,  0x1e,  0x5d,  0x03,  0x55,  0x1e,  0x31,  0x5e,  0x05,  0x72,  0xfe,  0xc0,
+  0x5d,  0x01,  0xa7,  0xfe,  0x03,  0x17,  0x03,  0x66,  0x8a,  0x10,  0x66,  0x5e,  0x32,  0x01,  0x08,  0x17,
+  0x73,  0x01,  0xfe,  0x56,  0x19,  0x05,  0x73,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0x3d,  0x27,  0x25,  0xbd,
+  0x09,  0x07,  0x2b,  0x3d,  0x01,  0xfe,  0xbe,  0x16,  0xfe,  0x42,  0x58,  0xfe,  0xe8,  0x14,  0x01,  0xa6,
+  0x86,  0xfe,  0x4a,  0xf4,  0x0d,  0x1b,  0x3d,  0xfe,  0x4a,  0xf4,  0x07,  0xfe,  0x0e,  0x12,  0x01,  0x43,
+  0x09,  0x82,  0x4e,  0x05,  0x72,  0x03,  0x55,  0x8a,  0x10,  0x55,  0x5e,  0x32,  0x01,  0x08,  0x17,  0x73,
+  0x01,  0xfe,  0x84,  0x19,  0x05,  0x73,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0x3d,  0x27,  0x25,  0xbd,  0x09,
+  0x12,  0x2b,  0x3d,  0x01,  0xfe,  0xe8,  0x17,  0x8b,  0xfe,  0xaa,  0x14,  0xfe,  0xb6,  0x14,  0x86,  0xa8,
+  0xb2,  0x0d,  0x1b,  0x3d,  0xb2,  0x07,  0xfe,  0x0e,  0x12,  0x01,  0x43,  0x09,  0x82,  0x4e,  0x05,  0x72,
+  0x03,  0x6f,  0x8a,  0x10,  0x6f,  0x5e,  0x32,  0x01,  0x08,  0x17,  0x73,  0x01,  0xfe,  0xc0,  0x19,  0x05,
+  0x73,  0x13,  0x07,  0x2f,  0xfe,  0xcc,  0x15,  0x17,  0xfe,  0xe2,  0x15,  0x5f,  0xcc,  0x01,  0x08,  0x26,
+  0x5f,  0x02,  0x8f,  0xfe,  0xde,  0x15,  0x2a,  0xfe,  0xde,  0x15,  0x16,  0xfe,  0xcc,  0x15,  0x5e,  0x32,
+  0x01,  0x08,  0xfe,  0xd5,  0x10,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xad,  0x23,  0xfe,  0xff,
+  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xad,
+  0x23,  0x3f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,
+  0xad,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xfe,  0x00,  0x5e,  0x02,  0x13,  0x58,  0xff,
+  0x02,  0x00,  0x57,  0x52,  0xad,  0xfe,  0x0b,  0x58,  0x02,  0x0a,  0x66,  0x01,  0x5c,  0x0a,  0x55,  0x01,
+  0x5c,  0x0a,  0x6f,  0x01,  0x5c,  0x02,  0x01,  0xfe,  0x1e,  0x1f,  0x23,  0x1a,  0xff,  0x03,  0x00,  0x54,
+  0xfe,  0x00,  0xf4,  0x24,  0x52,  0x0f,  0xfe,  0x00,  0x7c,  0x04,  0xfe,  0x07,  0x7c,  0x3a,  0x0b,  0x0e,
+  0xfe,  0x00,  0x71,  0xfe,  0xf9,  0x18,  0xfe,  0x7a,  0x19,  0xfe,  0xfb,  0x19,  0xfe,  0x1a,  0xf7,  0x00,
+  0xfe,  0x1b,  0xf7,  0x00,  0x7a,  0x30,  0x10,  0x68,  0x22,  0x69,  0xd9,  0x6c,  0xda,  0x6d,  0x02,  0xfe,
+  0x62,  0x08,  0xfe,  0x82,  0x4a,  0xfe,  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x77,  0x02,  0x01,  0xc6,  0xfe,
+  0x42,  0x48,  0x4f,  0x50,  0x45,  0x01,  0x08,  0x16,  0xfe,  0xe0,  0x17,  0x27,  0x25,  0xbe,  0x01,  0x08,
+  0x16,  0xfe,  0xe0,  0x17,  0x27,  0x25,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,  0x03,  0x9a,  0x1e,  0xfe,
+  0xda,  0x12,  0x01,  0x38,  0x06,  0x12,  0xfe,  0xd0,  0x13,  0x26,  0x53,  0x12,  0x48,  0xfe,  0x08,  0x17,
+  0xd1,  0x12,  0x53,  0x12,  0xfe,  0x1e,  0x13,  0x2d,  0xb4,  0x7b,  0xfe,  0x26,  0x17,  0x4d,  0x13,  0x07,
+  0x1c,  0xb4,  0x90,  0x04,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xf1,  0xff,  0x02,  0x83,  0x55,
+  0x53,  0x1d,  0xfe,  0x12,  0x13,  0xd6,  0xfe,  0x30,  0x00,  0xb0,  0xfe,  0x80,  0x17,  0x1c,  0x63,  0x13,
+  0x07,  0xfe,  0x56,  0x10,  0x53,  0x0d,  0xfe,  0x16,  0x13,  0xd6,  0xfe,  0x64,  0x00,  0xb0,  0xfe,  0x80,
+  0x17,  0x0a,  0xfe,  0x64,  0x00,  0x1c,  0x94,  0x13,  0x07,  0xfe,  0x28,  0x10,  0x53,  0x07,  0xfe,  0x60,
+  0x13,  0xd6,  0xfe,  0xc8,  0x00,  0xb0,  0xfe,  0x80,  0x17,  0x0a,  0xfe,  0xc8,  0x00,  0x1c,  0x95,  0x13,
+  0x07,  0x71,  0xd6,  0xfe,  0x90,  0x01,  0x48,  0xfe,  0x8c,  0x17,  0x45,  0xf3,  0xfe,  0x43,  0xf4,  0x96,
+  0xfe,  0x56,  0xf0,  0xfe,  0x9e,  0x17,  0xfe,  0x04,  0xf4,  0x58,  0xfe,  0x43,  0xf4,  0x94,  0xf6,  0x8b,
+  0x01,  0xfe,  0x24,  0x16,  0x23,  0x3f,  0xfc,  0xa8,  0x8c,  0x49,  0x48,  0xfe,  0xda,  0x17,  0x62,  0x49,
+  0xfe,  0x1c,  0x10,  0xa8,  0x8c,  0x80,  0x48,  0xfe,  0xda,  0x17,  0x62,  0x80,  0x71,  0x50,  0x26,  0xfe,
+  0x4d,  0xf4,  0x00,  0xf7,  0x45,  0x13,  0x07,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x02,  0x50,  0x13,
+  0x0d,  0x02,  0x50,  0x3e,  0x78,  0x4f,  0x45,  0x01,  0x08,  0x16,  0xa9,  0x27,  0x25,  0xbe,  0xfe,  0x03,
+  0xea,  0xfe,  0x7e,  0x01,  0x01,  0x08,  0x16,  0xa9,  0x27,  0x25,  0xfe,  0xe9,  0x0a,  0x01,  0x08,  0x16,
+  0xa9,  0x27,  0x25,  0xfe,  0xe9,  0x0a,  0xfe,  0x05,  0xea,  0xfe,  0x7f,  0x01,  0x01,  0x08,  0x16,  0xa9,
+  0x27,  0x25,  0xfe,  0x69,  0x09,  0xfe,  0x02,  0xea,  0xfe,  0x80,  0x01,  0x01,  0x08,  0x16,  0xa9,  0x27,
+  0x25,  0xfe,  0xe8,  0x08,  0x47,  0xfe,  0x81,  0x01,  0x03,  0xb6,  0x1e,  0x83,  0x01,  0x38,  0x06,  0x24,
+  0x31,  0xa2,  0x78,  0xf2,  0x53,  0x07,  0x36,  0xfe,  0x34,  0xf4,  0x3f,  0xa1,  0x78,  0x03,  0x9a,  0x1e,
+  0x83,  0x01,  0x38,  0x06,  0x12,  0x31,  0xf0,  0x4f,  0x45,  0xfe,  0x90,  0x10,  0xfe,  0x40,  0x5a,  0x23,
+  0x3f,  0xfb,  0x8c,  0x49,  0x48,  0xfe,  0xaa,  0x18,  0x62,  0x49,  0x71,  0x8c,  0x80,  0x48,  0xfe,  0xaa,
+  0x18,  0x62,  0x80,  0xfe,  0xb4,  0x56,  0xfe,  0x40,  0x5d,  0x01,  0xc6,  0x01,  0xfe,  0xac,  0x1d,  0xfe,
+  0x02,  0x17,  0xfe,  0xc8,  0x45,  0xfe,  0x5a,  0xf0,  0xfe,  0xc0,  0x18,  0xfe,  0x43,  0x48,  0x2d,  0x93,
+  0x36,  0xfe,  0x34,  0xf4,  0xfe,  0x00,  0x11,  0xfe,  0x40,  0x10,  0x2d,  0xb4,  0x36,  0xfe,  0x34,  0xf4,
+  0x04,  0xfe,  0x34,  0x10,  0x2d,  0xfe,  0x0b,  0x00,  0x36,  0x46,  0x63,  0xfe,  0x28,  0x10,  0xfe,  0xc0,
+  0x49,  0xff,  0x02,  0x00,  0x54,  0xb2,  0xfe,  0x90,  0x01,  0x48,  0xfe,  0xfa,  0x18,  0x45,  0xfe,  0x1c,
+  0xf4,  0x3f,  0xf3,  0xfe,  0x40,  0xf4,  0x96,  0xfe,  0x56,  0xf0,  0xfe,  0x0c,  0x19,  0xfe,  0x04,  0xf4,
+  0x58,  0xfe,  0x40,  0xf4,  0x94,  0xf6,  0x3e,  0x2d,  0x93,  0x4e,  0xd0,  0x0d,  0x21,  0xfe,  0x7f,  0x01,
+  0xfe,  0xc8,  0x46,  0xfe,  0x24,  0x13,  0x8c,  0x00,  0x5d,  0x26,  0x21,  0xfe,  0x7e,  0x01,  0xfe,  0xc8,
+  0x45,  0xfe,  0x14,  0x13,  0x21,  0xfe,  0x80,  0x01,  0xfe,  0x48,  0x45,  0xfa,  0x21,  0xfe,  0x81,  0x01,
+  0xfe,  0xc8,  0x44,  0x4e,  0x26,  0x02,  0x13,  0x07,  0x02,  0x78,  0x45,  0x50,  0x13,  0x0d,  0x02,  0x14,
+  0x07,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x14,  0x0d,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x14,
+  0x1d,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x5f,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x02,  0x14,  0x07,
+  0x01,  0x08,  0x17,  0xc1,  0x14,  0x1d,  0x01,  0x08,  0x17,  0xc1,  0x14,  0x07,  0x01,  0x08,  0x17,  0xc1,
+  0xfe,  0x89,  0x49,  0x01,  0x08,  0x17,  0xc1,  0x5f,  0xfe,  0x89,  0x4a,  0x01,  0x08,  0x02,  0x50,  0x02,
+  0x14,  0x07,  0x01,  0x08,  0x17,  0x74,  0x14,  0x7f,  0x01,  0x08,  0x17,  0x74,  0x14,  0x12,  0x01,  0x08,
+  0x17,  0x74,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x17,  0x74,  0x14,  0x00,  0x01,  0x08,  0x17,  0x74,  0xfe,
+  0x89,  0x4a,  0x01,  0x08,  0x17,  0x74,  0xfe,  0x09,  0x49,  0x01,  0x08,  0x17,  0x74,  0x5f,  0xcc,  0x01,
+  0x08,  0x02,  0x21,  0xe4,  0x09,  0x07,  0xfe,  0x4c,  0x13,  0xc8,  0x20,  0xe4,  0xfe,  0x49,  0xf4,  0x00,
+  0x4d,  0x5f,  0xa1,  0x5e,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xcc,  0xff,  0x02,  0x00,  0x10,  0x2f,
+  0xfe,  0x3e,  0x1a,  0x01,  0x43,  0x09,  0xfe,  0xe3,  0x00,  0xfe,  0x22,  0x13,  0x16,  0xfe,  0x64,  0x1a,
+  0x26,  0x20,  0x9e,  0x01,  0x41,  0x21,  0x9e,  0x09,  0x07,  0x5d,  0x01,  0x0c,  0x61,  0x07,  0x44,  0x02,
+  0x0a,  0x5a,  0x01,  0x18,  0xfe,  0x00,  0x40,  0xaa,  0x09,  0x1a,  0xfe,  0x12,  0x13,  0x0a,  0x9d,  0x01,
+  0x18,  0xaa,  0x0a,  0x67,  0x01,  0xa3,  0x02,  0x0a,  0x9d,  0x01,  0x18,  0xaa,  0xfe,  0x80,  0xe7,  0x1a,
+  0x09,  0x1a,  0x5d,  0xfe,  0x45,  0x58,  0x01,  0xfe,  0xb2,  0x16,  0xaa,  0x02,  0x0a,  0x5a,  0x01,  0x18,
+  0xaa,  0x0a,  0x67,  0x01,  0xa3,  0x02,  0x0a,  0x5a,  0x01,  0x18,  0x01,  0xfe,  0x7e,  0x1e,  0xfe,  0x80,
+  0x4c,  0xfe,  0x49,  0xe4,  0x1a,  0xfe,  0x12,  0x13,  0x0a,  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x4c,  0x0a,
+  0x67,  0x01,  0x5c,  0x02,  0x1c,  0x1a,  0x87,  0x7c,  0xe5,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,
+  0x24,  0x1c,  0xfe,  0x1d,  0xf7,  0x28,  0xb1,  0xfe,  0x04,  0x1b,  0x01,  0xfe,  0x2a,  0x1c,  0xfa,  0xb3,
+  0x28,  0x7c,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x02,  0xc9,  0x2b,  0xfe,  0xf4,  0x1a,  0xfe,  0xfa,
+  0x10,  0x1c,  0x1a,  0x87,  0x03,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x24,  0xfe,  0x18,  0x58,  0x03,
+  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0xb3,  0x24,  0x01,  0xfe,  0x0e,  0x1f,  0xfe,  0x30,  0xf4,  0x07,
+  0xfe,  0x3c,  0x50,  0x7c,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x24,  0xb1,  0xfe,
+  0x50,  0x1b,  0xfe,  0xd4,  0x14,  0x31,  0x02,  0xc9,  0x2b,  0xfe,  0x26,  0x1b,  0xfe,  0xba,  0x10,  0x1c,
+  0x1a,  0x87,  0xfe,  0x83,  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x54,  0xb1,
+  0xfe,  0x72,  0x1b,  0xfe,  0xb2,  0x14,  0xfc,  0xb3,  0x54,  0x7c,  0x12,  0xfe,  0xaf,  0x19,  0xfe,  0x98,
+  0xe7,  0x00,  0x02,  0xc9,  0x2b,  0xfe,  0x66,  0x1b,  0xfe,  0x8a,  0x10,  0x1c,  0x1a,  0x87,  0x8b,  0x0f,
+  0xfe,  0x30,  0x90,  0x04,  0xfe,  0xb0,  0x93,  0x3a,  0x0b,  0xfe,  0x18,  0x58,  0xfe,  0x32,  0x90,  0x04,
+  0xfe,  0xb2,  0x93,  0x3a,  0x0b,  0xfe,  0x19,  0x58,  0x0e,  0xa8,  0xb3,  0x4a,  0x7c,  0x12,  0xfe,  0x0f,
+  0x79,  0xfe,  0x1c,  0xf7,  0x4a,  0xb1,  0xfe,  0xc6,  0x1b,  0xfe,  0x5e,  0x14,  0x31,  0x02,  0xc9,  0x2b,
+  0xfe,  0x96,  0x1b,  0x5c,  0xfe,  0x02,  0xf6,  0x1a,  0x87,  0xfe,  0x18,  0xfe,  0x6a,  0xfe,  0x19,  0xfe,
+  0x6b,  0x01,  0xfe,  0x1e,  0x1f,  0xfe,  0x1d,  0xf7,  0x65,  0xb1,  0xfe,  0xee,  0x1b,  0xfe,  0x36,  0x14,
+  0xfe,  0x1c,  0x13,  0xb3,  0x65,  0x3e,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x1a,
+  0xfe,  0x81,  0xe7,  0x1a,  0x15,  0xfe,  0xdd,  0x00,  0x7a,  0x30,  0x02,  0x7a,  0x30,  0xfe,  0x12,  0x45,
+  0x2b,  0xfe,  0xdc,  0x1b,  0x1f,  0x07,  0x47,  0xb5,  0xc3,  0x05,  0x35,  0xfe,  0x39,  0xf0,  0x75,  0x26,
+  0x02,  0xfe,  0x7e,  0x18,  0x23,  0x1d,  0x36,  0x13,  0x11,  0x02,  0x87,  0x03,  0xe3,  0x23,  0x07,  0xfe,
+  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x90,  0x34,  0x60,  0xfe,  0x02,  0x80,  0x09,  0x56,  0xfe,  0x3c,  0x13,
+  0xfe,  0x82,  0x14,  0xfe,  0x42,  0x13,  0x51,  0xfe,  0x06,  0x83,  0x0a,  0x5a,  0x01,  0x18,  0xcb,  0xfe,
+  0x3e,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,  0xfe,  0xb2,  0x16,  0xfe,  0x00,  0xcc,  0xcb,
+  0xfe,  0xf3,  0x13,  0x3f,  0x89,  0x09,  0x1a,  0xa5,  0x0a,  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x4c,  0x01,
+  0x85,  0xfe,  0x16,  0x10,  0x09,  0x9b,  0x4e,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xfe,  0x14,  0x56,
+  0xfe,  0xd6,  0xf0,  0xfe,  0x52,  0x1c,  0x1c,  0x0d,  0x02,  0xfe,  0x9c,  0xe7,  0x0d,  0x19,  0xfe,  0x15,
+  0x00,  0x40,  0x8d,  0x30,  0x01,  0xf4,  0x1c,  0x07,  0x02,  0x51,  0xfe,  0x06,  0x83,  0xfe,  0x18,  0x80,
+  0x61,  0x28,  0x44,  0x15,  0x56,  0x01,  0x85,  0x1c,  0x07,  0x02,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,
+  0x91,  0xde,  0x7e,  0xdf,  0xfe,  0x48,  0x55,  0x31,  0xfe,  0xc9,  0x55,  0x02,  0x21,  0xb9,  0x88,  0x20,
+  0xb9,  0x02,  0x0a,  0xba,  0x01,  0x18,  0xfe,  0x41,  0x48,  0x0a,  0x57,  0x01,  0x18,  0xfe,  0x49,  0x44,
+  0x1b,  0xfe,  0x1e,  0x1d,  0x88,  0x89,  0x02,  0x0a,  0x5a,  0x01,  0x18,  0x09,  0x1a,  0xa4,  0x0a,  0x67,
+  0x01,  0xa3,  0x0a,  0x57,  0x01,  0x18,  0x88,  0x89,  0x02,  0xfe,  0x4e,  0xe4,  0x1d,  0x7b,  0xfe,  0x52,
+  0x1d,  0x03,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xfe,  0x4e,  0xe4,  0xdd,  0x7b,
+  0xfe,  0x64,  0x1d,  0x03,  0xfe,  0x92,  0x00,  0xd1,  0x12,  0xfe,  0x1a,  0x10,  0xfe,  0x4e,  0xe4,  0xfe,
+  0x0b,  0x00,  0x7b,  0xfe,  0x76,  0x1d,  0x03,  0xfe,  0x94,  0x00,  0xd1,  0x24,  0xfe,  0x08,  0x10,  0x03,
+  0xfe,  0x96,  0x00,  0xd1,  0x63,  0xfe,  0x4e,  0x45,  0x83,  0xca,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,
+  0x10,  0x23,  0x49,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,
+  0x00,  0x04,  0x83,  0xb2,  0x1d,  0x48,  0xfe,  0xaa,  0x1d,  0x13,  0x1d,  0x02,  0x09,  0x92,  0xfe,  0x5a,
+  0xf0,  0xfe,  0xba,  0x1d,  0x2e,  0x93,  0xfe,  0x34,  0x10,  0x09,  0x12,  0xfe,  0x5a,  0xf0,  0xfe,  0xc8,
+  0x1d,  0x2e,  0xb4,  0xfe,  0x26,  0x10,  0x09,  0x1d,  0x36,  0x2e,  0x63,  0xfe,  0x1a,  0x10,  0x09,  0x0d,
+  0x36,  0x2e,  0x94,  0xf2,  0x09,  0x07,  0x36,  0x2e,  0x95,  0xa1,  0xc8,  0x02,  0x1f,  0x93,  0x01,  0x42,
+  0xfe,  0x04,  0xfe,  0x99,  0x03,  0x9c,  0x8b,  0x02,  0x2a,  0xfe,  0x1c,  0x1e,  0xfe,  0x14,  0xf0,  0x08,
+  0x2f,  0xfe,  0x0c,  0x1e,  0x2a,  0xfe,  0x1c,  0x1e,  0x8f,  0xfe,  0x1c,  0x1e,  0xfe,  0x82,  0xf0,  0xfe,
+  0x10,  0x1e,  0x02,  0x0f,  0x3f,  0x04,  0xfe,  0x80,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x18,
+  0x80,  0x04,  0xfe,  0x98,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x02,  0x80,  0x04,  0xfe,  0x82,
+  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x06,  0x80,  0x04,  0xfe,  0x86,  0x83,  0x33,  0x0b,  0x0e,
+  0x02,  0x0f,  0xfe,  0x1b,  0x80,  0x04,  0xfe,  0x9b,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x04,
+  0x80,  0x04,  0xfe,  0x84,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x80,  0x80,  0x04,  0xfe,  0x80,
+  0x83,  0xfe,  0xc9,  0x47,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x19,  0x81,  0x04,  0xfe,  0x99,  0x83,  0xfe,
+  0xca,  0x47,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x06,  0x83,  0x04,  0xfe,  0x86,  0x83,  0xfe,  0xce,  0x47,
+  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x2c,  0x90,  0x04,  0xfe,  0xac,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,
+  0xfe,  0xae,  0x90,  0x04,  0xfe,  0xae,  0x93,  0x79,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x08,  0x90,  0x04,
+  0xfe,  0x88,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x8a,  0x90,  0x04,  0xfe,  0x8a,  0x93,  0x79,
+  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x0c,  0x90,  0x04,  0xfe,  0x8c,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,
+  0xfe,  0x8e,  0x90,  0x04,  0xfe,  0x8e,  0x93,  0x79,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x3c,  0x90,  0x04,
+  0xfe,  0xbc,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x8b,  0x0f,  0xfe,  0x03,  0x80,  0x04,  0xfe,  0x83,  0x83,
+  0x33,  0x0b,  0x77,  0x0e,  0xa8,  0x02,  0xff,  0x66,  0x00,  0x00,
+};
+
+STATIC unsigned short _adv_asc38C1600_size =
+        sizeof(_adv_asc38C1600_buf); /* 0x1673 */
+STATIC ADV_DCNT _adv_asc38C1600_chksum =
+        0x0604EF77UL; /* Expanded little-endian checksum. */
 
 /* a_init.c */
 /*
@@ -15455,6 +14570,14 @@
  * configuration. The BIOS now uses this structure when it is built.
  * Additional structure information can be found in a_condor.h where
  * the structure is defined.
+ *
+ * The *_Field_IsChar structs are needed to correct for endianness.
+ * These values are read from the board 16 bits at a time directly
+ * into the structs. Because some fields are char, the values will be
+ * in the wrong order. The *_Field_IsChar tells when to flip the
+ * bytes. Data read and written to PCI memory is automatically swapped
+ * on big-endian platforms so char fields read as words are actually being
+ * unswapped on big-endian platforms.
  */
 STATIC ADVEEP_3550_CONFIG
 Default_3550_EEPROM_Config ASC_INITDATA = {
@@ -15494,6 +14617,44 @@
     0                           /* num_of_err */
 };
 
+STATIC ADVEEP_3550_CONFIG
+ADVEEP_3550_Config_Field_IsChar ASC_INITDATA = {
+    0,                          /* cfg_lsw */
+    0,                          /* cfg_msw */
+    0,                          /* -disc_enable */
+    0,                          /* wdtr_able */
+    0,                          /* sdtr_able */
+    0,                          /* start_motor */
+    0,                          /* tagqng_able */
+    0,                          /* bios_scan */
+    0,                          /* scam_tolerant */
+    1,                          /* adapter_scsi_id */
+    1,                          /* bios_boot_delay */
+    1,                          /* scsi_reset_delay */
+    1,                          /* bios_id_lun */
+    1,                          /* termination */
+    1,                          /* reserved1 */
+    0,                          /* bios_ctrl */
+    0,                          /* ultra_able */
+    0,                          /* reserved2 */
+    1,                          /* max_host_qng */
+    1,                          /* max_dvc_qng */
+    0,                          /* dvc_cntl */
+    0,                          /* bug_fix */
+    0,                          /* serial_number_word1 */
+    0,                          /* serial_number_word2 */
+    0,                          /* serial_number_word3 */
+    0,                          /* check_sum */
+    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* oem_name[16] */
+    0,                          /* dvc_err_code */
+    0,                          /* adv_err_code */
+    0,                          /* adv_err_addr */
+    0,                          /* saved_dvc_err_code */
+    0,                          /* saved_adv_err_code */
+    0,                          /* saved_adv_err_addr */
+    0                           /* num_of_err */
+};
+
 STATIC ADVEEP_38C0800_CONFIG
 Default_38C0800_EEPROM_Config ASC_INITDATA = {
     ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
@@ -15559,6 +14720,201 @@
     0                           /* 63 reserved */
 };
 
+STATIC ADVEEP_38C0800_CONFIG
+ADVEEP_38C0800_Config_Field_IsChar ASC_INITDATA = {
+    0,                          /* 00 cfg_lsw */
+    0,                          /* 01 cfg_msw */
+    0,                          /* 02 disc_enable */
+    0,                          /* 03 wdtr_able */
+    0,                          /* 04 sdtr_speed1 */
+    0,                          /* 05 start_motor */
+    0,                          /* 06 tagqng_able */
+    0,                          /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    1,                          /* 09 adapter_scsi_id */
+    1,                          /*    bios_boot_delay */
+    1,                          /* 10 scsi_reset_delay */
+    1,                          /*    bios_id_lun */
+    1,                          /* 11 termination_se */
+    1,                          /*    termination_lvd */
+    0,                          /* 12 bios_ctrl */
+    0,                          /* 13 sdtr_speed2 */
+    0,                          /* 14 sdtr_speed3 */
+    1,                          /* 15 max_host_qng */
+    1,                          /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0,                          /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    0,                          /* 58 subsysvid */
+    0,                          /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
+STATIC ADVEEP_38C1600_CONFIG
+Default_38C1600_EEPROM_Config ASC_INITDATA = {
+    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
+    0x0000,                     /* 01 cfg_msw */
+    0xFFFF,                     /* 02 disc_enable */
+    0xFFFF,                     /* 03 wdtr_able */
+    0x5555,                     /* 04 sdtr_speed1 */
+    0xFFFF,                     /* 05 start_motor */
+    0xFFFF,                     /* 06 tagqng_able */
+    0xFFFF,                     /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    7,                          /* 09 adapter_scsi_id */
+    0,                          /*    bios_boot_delay */
+    3,                          /* 10 scsi_reset_delay */
+    0,                          /*    bios_id_lun */
+    0,                          /* 11 termination_se */
+    0,                          /*    termination_lvd */
+    0xFFE7,                     /* 12 bios_ctrl */
+    0x5555,                     /* 13 sdtr_speed2 */
+    0x5555,                     /* 14 sdtr_speed3 */
+    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0x5555,                     /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    ADV_PCI_VENDOR_ID,          /* 58 subsysvid */
+    ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
+STATIC ADVEEP_38C1600_CONFIG
+ADVEEP_38C1600_Config_Field_IsChar ASC_INITDATA = {
+    0,                          /* 00 cfg_lsw */
+    0,                          /* 01 cfg_msw */
+    0,                          /* 02 disc_enable */
+    0,                          /* 03 wdtr_able */
+    0,                          /* 04 sdtr_speed1 */
+    0,                          /* 05 start_motor */
+    0,                          /* 06 tagqng_able */
+    0,                          /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    1,                          /* 09 adapter_scsi_id */
+    1,                          /*    bios_boot_delay */
+    1,                          /* 10 scsi_reset_delay */
+    1,                          /*    bios_id_lun */
+    1,                          /* 11 termination_se */
+    1,                          /*    termination_lvd */
+    0,                          /* 12 bios_ctrl */
+    0,                          /* 13 sdtr_speed2 */
+    0,                          /* 14 sdtr_speed3 */
+    1,                          /* 15 max_host_qng */
+    1,                          /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0,                          /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    0,                          /* 58 subsysvid */
+    0,                          /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
 /*
  * Initialize the ADV_DVC_VAR structure.
  *
@@ -15639,11 +14995,11 @@
     asc_dvc->cfg->chip_version =
       AdvGetChipVersion(iop_base, asc_dvc->bus_type);
 
-    ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: %x %x\n",
+    ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
         (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
         (ushort) ADV_CHIP_ID_BYTE);
 
-    ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: %x %x\n",
+    ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
         (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
         (ushort) ADV_CHIP_ID_WORD);
 
@@ -15676,7 +15032,13 @@
         AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
             ADV_CTRL_REG_CMD_WR_IO_REG);
 
-        if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+        if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+        {
+            if ((status = AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
+        } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
         {
             if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
             {
@@ -15702,6 +15064,8 @@
  *
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
  */
 STATIC int
 AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
@@ -15814,22 +15178,662 @@
             {
                 AdvWriteWordAutoIncLram(iop_base, (((ushort)
                     _adv_asc3550_buf[i + 3] << 8) |
-                    _adv_asc3550_buf[i + 2]));
+                _adv_asc3550_buf[i + 2]));
                 word++;
             }
             i += 3;
         } else if (_adv_asc3550_buf[i] == 0xfe)
         {
             AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc3550_buf[i + 2] << 8) |
-                _adv_asc3550_buf[i + 1]));
+                _adv_asc3550_buf[i + 2] << 8) |
+                _adv_asc3550_buf[i + 1]));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) |
+                _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+            word++;
+        }
+    }
+
+    /*
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc3550_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-3550 Internal RAM (8KB).
+     */
+    for (; word < ADV_3550_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    for (word = 0; word < adv_asc3550_expanded_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+
+    if (sum != _adv_asc3550_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read and save microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Set the chip type to indicate the ASC3550.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+     * threshold of 128 bytes. This register is only accessible to the host.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        START_CTL_EMFU | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
+     *
+     * If SCSI Bus Resets have been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
+
+    /*
+     * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+     * bitmask. These values determine the maximum SDTR speed negotiated
+     * with a device.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     *
+     * 4-bit speed  SDTR speed name
+     * ===========  ===============
+     * 0000b (0x0)  SDTR disabled
+     * 0001b (0x1)  5 Mhz
+     * 0010b (0x2)  10 Mhz
+     * 0011b (0x3)  20 Mhz (Ultra)
+     * 0100b (0x4)  40 Mhz (LVD/Ultra2)
+     * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
+     * 0110b (0x6)  Undefined
+     * .
+     * 1111b (0xF)  Undefined
+     */
+    word = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
+        {
+            /* Set Ultra speed for TID 'tid'. */
+            word |= (0x3 << (4 * (tid % 4)));
+        } else
+        {
+            /* Set Fast speed for TID 'tid'. */
+            word |= (0x2 << (4 * (tid % 4)));
+        }
+        if (tid == 3) /* Check if done with sdtr_speed1. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+            word = 0;
+        } else if (tid == 7) /* Check if done with sdtr_speed2. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+            word = 0;
+        } else if (tid == 11) /* Check if done with sdtr_speed3. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+            word = 0;
+        } else if (tid == 15) /* Check if done with sdtr_speed4. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+            /* End of loop. */
+        }
+    }
+
+    /*
+     * Set microcode operating variable for the disconnect per TID bitmask.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+        asc_dvc->chip_scsi_id);
+
+    /*
+     * Determine SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+
+    /* Read current SCSI_CFG1 Register value. */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If all three connectors are in use, return an error.
+     */
+    if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+        (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
+    {
+            asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+            return ADV_ERROR;
+    }
+
+    /*
+     * If the internal narrow cable is reversed all of the SCSI_CTRL
+     * register signals will be set. Check for and return an error if
+     * this condition is found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If this is a differential board and a single-ended device
+     * is attached to one of the connectors, return an error.
+     */
+    if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
+    {
+        asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If automatic termination control is enabled, then set the
+     * termination value based on a table listed in a_condor.h.
+     *
+     * If manual termination was specified with an EEPROM setting
+     * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+     * is ready to be 'ored' into SCSI_CFG1.
+     */
+    if (asc_dvc->cfg->termination == 0)
+    {
+        /*
+         * The software always controls termination by setting TERM_CTL_SEL.
+         * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+         */
+        asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+        switch(scsi_cfg1 & CABLE_DETECT)
+        {
+            /* TERM_CTL_H: on, TERM_CTL_L: on */
+            case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
+                asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+                break;
+
+            /* TERM_CTL_H: on, TERM_CTL_L: off */
+            case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
+                asc_dvc->cfg->termination |= TERM_CTL_H;
+                break;
+
+            /* TERM_CTL_H: off, TERM_CTL_L: off */
+            case 0x2: case 0x6:
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+     */
+    scsi_cfg1 &= ~TERM_CTL;
+
+    /*
+     * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+     * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+     * referenced, because the hardware internally inverts
+     * the Termination High and Low bits if TERM_POL is set.
+     */
+    scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set filter value and possibly modified termination control
+     * bits in the Microcode SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+        FLTR_DISABLE | scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-3550 has 8KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_8KB);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Build carrier freelist.
+     *
+     * Driver must have already allocated memory and set 'carrier_buf'.
+     */
+    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+    {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address of the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+        /*
+         * Insert the carrier at the beginning of the freelist.
+         */
+        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
+    }
+    while (buf_size > 0);
+
+    /*
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC ICQ physical address start value.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+         ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC IRQ physical address start value.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC-38C0800.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+STATIC int
+AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ADV_DCNT    sum;
+    int         begin_addr;
+    int         end_addr;
+    ushort      code_sum;
+    int         word;
+    int         j;
+    int         adv_asc38C0800_expanded_size;
+    ADV_CARR_T  *carrp;
+    ADV_DCNT    contig_len;
+    ADV_SDCNT   buf_size;
+    ADV_PADDR   carr_paddr;
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       byte;
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * RAM BIST (RAM Built-In Self Test)
+     *
+     * Address : I/O base + offset 0x38h register (byte).
+     * Function: Bit 7-6(RW) : RAM mode
+     *                          Normal Mode   : 0x00
+     *                          Pre-test Mode : 0x40
+     *                          RAM Test Mode : 0x80
+     *           Bit 5       : unused
+     *           Bit 4(RO)   : Done bit
+     *           Bit 3-0(RO) : Status
+     *                          Host Error    : 0x08
+     *                          Int_RAM Error : 0x04
+     *                          RISC Error    : 0x02
+     *                          SCSI Error    : 0x01
+     *                          No Error      : 0x00
+     *
+     * Note: RAM BIST code should be put right here, before loading the
+     * microcode and after saving the RISC memory BIOS region.
+     */
+
+    /*
+     * LRAM Pre-test
+     *
+     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+     * to NORMAL_MODE, return an error too.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+            != NORMAL_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+    }
+
+    /*
+     * LRAM Test - It takes about 1.5 ms to run through the test.
+     *
+     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+     * If Done bit not set or Status not 0, save register byte, set the
+     * err_code, and return an error.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+
+    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
+    {
+        /* Get here if Done bit not set or Status not 0. */
+        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+        return ADV_ERROR;
+    }
+
+    /* We need to reset back to normal mode after LRAM test passes. */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     *
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
+    {
+        if (_adv_asc38C0800_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                    _adv_asc38C0800_buf[i + 3] << 8) |
+                    _adv_asc38C0800_buf[i + 2]));
+                word++;
+            }
+            i += 3;
+        } else if (_adv_asc38C0800_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc38C0800_buf[i + 2] << 8) |
+                _adv_asc38C0800_buf[i + 1]));
             i += 2;
             word++;
         } else
         {
             AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) |
-                _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+                _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) |
+                _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
             word++;
         }
     }
@@ -15839,12 +15843,12 @@
      * the expanded mcode size.
      */
     word *= 2;
-    adv_asc3550_expanded_size = word;
+    adv_asc38C0800_expanded_size = word;
 
     /*
-     * Clear the rest of ASC-3550 Internal RAM (8KB).
+     * Clear the rest of ASC-38C0800 Internal RAM (16KB).
      */
-    for (; word < ADV_3550_MEMSIZE; word += 2)
+    for (; word < ADV_38C0800_MEMSIZE; word += 2)
     {
         AdvWriteWordAutoIncLram(iop_base, 0);
     }
@@ -15855,12 +15859,17 @@
     sum = 0;
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    for (word = 0; word < adv_asc3550_expanded_size; word += 2)
+    for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
     {
         sum += AdvReadWordAutoIncLram(iop_base);
     }
+    ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
 
-    if (sum != _adv_asc3550_chksum)
+    ASC_DBG2(1,
+        "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
+        (ulong) sum, (ulong) _adv_asc38C0800_chksum);
+
+    if (sum != _adv_asc38C0800_chksum)
     {
         asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
         return ADV_ERROR;
@@ -15871,7 +15880,7 @@
      */
     for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
     {
-        AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
     }
 
     /*
@@ -15889,15 +15898,26 @@
     AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
     /*
-     * Read and save microcode version and date.
+     * Read microcode version and date.
      */
     AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
     AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
 
     /*
-     * Set the chip type to indicate the ASC3550.
+     * Set the chip type to indicate the ASC38C0800.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+    /*
+     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+     * cable detection and then we are able to read C_DET[3:0].
+     *
+     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+     * Microcode Default Value' section below.
+     */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
 
     /*
      * If the PCI Configuration Command Register "Parity Error Response
@@ -15907,22 +15927,21 @@
      */
     if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
     {
-        /*
-         * Note: Don't remove the use of a temporary variable in
-         * the following code, otherwise the Microsoft C compiler
-         * will turn the following lines into a no-op.
-         */
         AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
         word |= CONTROL_FLAG_IGNORE_PERR;
         AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
     }
 
     /*
-     * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
-     * threshold of 128 bytes. This register is only accessible to the host.
+     * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+     * bits for the default FIFO threshold.
+     *
+     * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+     *
+     * For DMA Errata #4 set the BC_THRESH_ENB bit.
      */
     AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        START_CTL_EMFU | READ_CMD_MRM);
+        BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
 
     /*
      * Microcode operating variables for WDTR, SDTR, and command tag
@@ -15943,63 +15962,19 @@
     }
 
     /*
-     * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
-     * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
-     * bitmask. These values determine the maximum SDTR speed negotiated
-     * with a device.
+     * Set microcode operating variables for DISC and SDTR_SPEED1,
+     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+     * configuration values.
      *
      * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
      * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
      * without determining here whether the device supports SDTR.
-     *
-     * 4-bit speed  SDTR speed name
-     * ===========  ===============
-     * 0000b (0x0)  SDTR disabled
-     * 0001b (0x1)  5 Mhz
-     * 0010b (0x2)  10 Mhz
-     * 0011b (0x3)  20 Mhz (Ultra)
-     * 0100b (0x4)  40 Mhz (LVD/Ultra2)
-     * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
-     * 0110b (0x6)  Undefined
-     * .
-     * 1111b (0xF)  Undefined
-     */
-    word = 0;
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
-        {
-            /* Set Ultra speed for TID 'tid'. */
-            word |= (0x3 << (4 * (tid % 4)));
-        } else
-        {
-            /* Set Fast speed for TID 'tid'. */
-            word |= (0x2 << (4 * (tid % 4)));
-        }
-        if (tid == 3) /* Check if done with sdtr_speed1. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
-            word = 0;
-        } else if (tid == 7) /* Check if done with sdtr_speed2. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
-            word = 0;
-        } else if (tid == 11) /* Check if done with sdtr_speed3. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
-            word = 0;
-        } else if (tid == 15) /* Check if done with sdtr_speed4. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
-            /* End of loop. */
-        }
-    }
-
-    /*
-     * Set microcode operating variable for the disconnect per TID bitmask.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
-
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
 
     /*
      * Set SCSI_CFG0 Microcode Default Value.
@@ -16008,7 +15983,8 @@
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-        PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+        asc_dvc->chip_scsi_id);
 
     /*
      * Determine SCSI_CFG1 Microcode Default Value.
@@ -16021,16 +15997,6 @@
     scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
 
     /*
-     * If all three connectors are in use, return an error.
-     */
-    if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
-        (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
-    {
-            asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
-            return ADV_ERROR;
-    }
-
-    /*
      * If the internal narrow cable is reversed all of the SCSI_CTRL
      * register signals will be set. Check for and return an error if
      * this condition is found.
@@ -16042,73 +16008,88 @@
     }
 
     /*
-     * If this is a differential board and a single-ended device
-     * is attached to one of the connectors, return an error.
+     * All kind of combinations of devices attached to one of four connectors
+     * are acceptable except HVD device attached. For example, LVD device can
+     * be attached to SE connector while SE device attached to LVD connector.
+     * If LVD device attached to SE connector, it only runs up to Ultra speed.
+     *
+     * If an HVD device is attached to one of LVD connectors, return an error.
+     * However, there is no way to detect HVD device attached to SE connectors.
      */
-    if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
+    if (scsi_cfg1 & HVD)
     {
-        asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
         return ADV_ERROR;
     }
 
     /*
-     * If automatic termination control is enabled, then set the
-     * termination value based on a table listed in a_condor.h.
+     * If either SE or LVD automatic termination control is enabled, then
+     * set the termination value based on a table listed in a_condor.h.
      *
-     * If manual termination was specified with an EEPROM setting
-     * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
-     * is ready to be 'ored' into SCSI_CFG1.
+     * If manual termination was specified with an EEPROM setting then
+     * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+     * be 'ored' into SCSI_CFG1.
      */
-    if (asc_dvc->cfg->termination == 0)
+    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
     {
-        /*
-         * The software always controls termination by setting TERM_CTL_SEL.
-         * If TERM_CTL_SEL were set to 0, the hardware would set termination.
-         */
-        asc_dvc->cfg->termination |= TERM_CTL_SEL;
-
-        switch(scsi_cfg1 & CABLE_DETECT)
+        /* SE automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_SE)
         {
-            /* TERM_CTL_H: on, TERM_CTL_L: on */
-            case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
-                asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+            /* TERM_SE_HI: on, TERM_SE_LO: on */
+            case 0x1: case 0x2: case 0x3:
+                asc_dvc->cfg->termination |= TERM_SE;
                 break;
 
-            /* TERM_CTL_H: on, TERM_CTL_L: off */
-            case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
-                asc_dvc->cfg->termination |= TERM_CTL_H;
+            /* TERM_SE_HI: on, TERM_SE_LO: off */
+            case 0x0:
+                asc_dvc->cfg->termination |= TERM_SE_HI;
                 break;
+        }
+    }
 
-            /* TERM_CTL_H: off, TERM_CTL_L: off */
-            case 0x2: case 0x6:
+    if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
+    {
+        /* LVD automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_LVD)
+        {
+            /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+            case 0x4: case 0x8: case 0xC:
+                asc_dvc->cfg->termination |= TERM_LVD;
+                break;
+
+            /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+            case 0x0:
                 break;
         }
     }
 
     /*
-     * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+     * Clear any set TERM_SE and TERM_LVD bits.
      */
-    scsi_cfg1 &= ~TERM_CTL;
+    scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
 
     /*
-     * Invert the TERM_CTL_H and TERM_CTL_L bits and then
-     * set 'scsi_cfg1'. The TERM_POL bit does not need to be
-     * referenced, because the hardware internally inverts
-     * the Termination High and Low bits if TERM_POL is set.
+     * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
      */
-    scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+    scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+
+    /*
+     * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+     * and set possibly modified termination control bits in the Microcode
+     * SCSI_CFG1 Register Value.
+     */
+    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
 
     /*
      * Set SCSI_CFG1 Microcode Default Value
      *
-     * Set filter value and possibly modified termination control
+     * Set possibly modified termination control and reset DIS_TERM_DRV
      * bits in the Microcode SCSI_CFG1 Register Value.
      *
      * The microcode will set the SCSI_CFG1 register using this value
      * after it is started below.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
-        FLTR_DISABLE | scsi_cfg1);
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
 
     /*
      * Set MEM_CFG Microcode Default Value
@@ -16119,10 +16100,10 @@
      * MEM_CFG may be accessed as a word or byte, but only bits 0-7
      * are defined.
      *
-     * ASC-3550 has 8KB internal memory.
+     * ASC-38C0800 has 16KB internal memory.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-        BIOS_EN | RAM_SZ_8KB);
+        BIOS_EN | RAM_SZ_16KB);
 
     /*
      * Set SEL_MASK Microcode Default Value
@@ -16134,7 +16115,7 @@
         ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
     /*
-     * Build carrier freelist.
+     * Build the carrier freelist.
      *
      * Driver must have already allocated memory and set 'carrier_buf'.
      */
@@ -16152,7 +16133,7 @@
 
     do {
         /*
-         * Get physical address of the carrier 'carrp'.
+         * Get physical address for the carrier 'carrp'.
          */
         contig_len = sizeof(ADV_CARR_T);
         carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
@@ -16172,12 +16153,12 @@
         }
 
         carrp->carr_pa = carr_paddr;
-        carrp->carr_va = ADV_VADDR_TO_U32(carrp);
+        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
 
         /*
          * Insert the carrier at the beginning of the freelist.
          */
-        carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist);
+        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
         asc_dvc->carr_freelist = carrp;
 
         carrp++;
@@ -16193,19 +16174,19 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist =
-        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa);
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
     /*
      * The first command issued will be placed in the stopper carrier.
      */
-    asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
     /*
      * Set RISC ICQ physical address start value.
+     * carr_pa is LE, must be native before write
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_ICQ,
-        cpu_to_le32(asc_dvc->icq_sp->carr_pa));
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
 
     /*
      * Set-up the RISC->Host Initiator Response Queue (IRQ).
@@ -16215,8 +16196,8 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist =
-        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa);
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
     /*
      * The first command completed by the RISC will be placed in
@@ -16225,23 +16206,19 @@
      * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
      * completed the RISC will set the ASC_RQ_STOPPER bit.
      */
-    asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
+    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
     /*
      * Set RISC IRQ physical address start value.
+     *
+     * carr_pa is LE, must be native before write *
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IRQ,
-        cpu_to_le32(asc_dvc->irq_sp->carr_pa));
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
     asc_dvc->carr_pending_cnt = 0;
 
     AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
         (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
 
-    /*
-     * Note: Don't remove the use of a temporary variable in
-     * the following code, otherwise the Microsoft C compiler
-     * will turn the following lines into a no-op.
-     */
     AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
     AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
@@ -16286,15 +16263,17 @@
 }
 
 /*
- * Initialize the ASC-38C0800.
+ * Initialize the ASC-38C1600.
  *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
  */
 STATIC int
-AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
 {
     AdvPortAddr iop_base;
     ushort      warn_code;
@@ -16302,9 +16281,9 @@
     int         begin_addr;
     int         end_addr;
     ushort      code_sum;
-    int         word;
+    long        word;
     int         j;
-    int         adv_asc38C0800_expanded_size;
+    int         adv_asc38C1600_expanded_size;
     ADV_CARR_T  *carrp;
     ADV_DCNT    contig_len;
     ADV_SDCNT   buf_size;
@@ -16314,8 +16293,8 @@
     uchar       byte;
     uchar       tid;
     ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
-    ushort      wdtr_able, sdtr_able, tagqng_able;
-    uchar       max_cmd[ADV_MAX_TID + 1];
+    ushort      wdtr_able, sdtr_able, ppr_able, tagqng_able;
+    uchar       max_cmd[ASC_MAX_TID + 1];
 
     /* If there is already an error, don't continue. */
     if (asc_dvc->err_code != 0)
@@ -16324,9 +16303,9 @@
     }
 
     /*
-     * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+     * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
      */
-    if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
+    if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
     {
         asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
         return ADV_ERROR;
@@ -16353,15 +16332,16 @@
      */
     AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
     AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
     AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    for (tid = 0; tid <= ASC_MAX_TID; tid++)
     {
         AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
             max_cmd[tid]);
     }
 
     /*
-     * RAM BIST (RAM Built-In Self Test)
+     * RAM BIST (Built-In Self Test)
      *
      * Address : I/O base + offset 0x38h register (byte).
      * Function: Bit 7-6(RW) : RAM mode
@@ -16440,7 +16420,8 @@
      */
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    /* Assume the following compressed format of the microcode buffer:
+    /*
+     * Assume the following compressed format of the microcode buffer:
      *
      *  254 word (508 byte) table indexed by byte code followed
      *  by the following byte codes:
@@ -16456,30 +16437,30 @@
      *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
      */
     word = 0;
-    for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
+    for (i = 253 * 2; i < _adv_asc38C1600_size; i++)
     {
-        if (_adv_asc38C0800_buf[i] == 0xff)
+        if (_adv_asc38C1600_buf[i] == 0xff)
         {
-            for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
+            for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++)
             {
                 AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                    _adv_asc38C0800_buf[i + 3] << 8) |
-                    _adv_asc38C0800_buf[i + 2]));
+                     _adv_asc38C1600_buf[i + 3] << 8) |
+                     _adv_asc38C1600_buf[i + 2]));
                 word++;
             }
-            i += 3;
-        } else if (_adv_asc38C0800_buf[i] == 0xfe)
+           i += 3;
+        } else if (_adv_asc38C1600_buf[i] == 0xfe)
         {
-            AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc38C0800_buf[i + 2] << 8) |
-                _adv_asc38C0800_buf[i + 1]));
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                     _adv_asc38C1600_buf[i + 2] << 8) |
+                     _adv_asc38C1600_buf[i + 1]));
             i += 2;
             word++;
         } else
         {
             AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) |
-                _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+                 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) |
+                 _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
             word++;
         }
     }
@@ -16489,12 +16470,12 @@
      * the expanded mcode size.
      */
     word *= 2;
-    adv_asc38C0800_expanded_size = word;
+    adv_asc38C1600_expanded_size = word;
 
     /*
-     * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+     * Clear the rest of ASC-38C1600 Internal RAM (32KB).
      */
-    for (; word < ADV_38C0800_MEMSIZE; word += 2)
+    for (; word < ADV_38C1600_MEMSIZE; word += 2)
     {
         AdvWriteWordAutoIncLram(iop_base, 0);
     }
@@ -16505,17 +16486,12 @@
     sum = 0;
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
+    for (word = 0; word < adv_asc38C1600_expanded_size; word += 2)
     {
         sum += AdvReadWordAutoIncLram(iop_base);
     }
-    ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
-
-    ASC_DBG2(1,
-        "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
-        (ulong) sum, (ulong) _adv_asc38C0800_chksum);
 
-    if (sum != _adv_asc38C0800_chksum)
+    if (sum != _adv_asc38C1600_chksum)
     {
         asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
         return ADV_ERROR;
@@ -16550,9 +16526,9 @@
     AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
 
     /*
-     * Set the chip type to indicate the ASC38C0800.
+     * Set the chip type to indicate the ASC38C1600.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
 
     /*
      * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
@@ -16573,26 +16549,30 @@
      */
     if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
     {
-        /*
-         * Note: Don't remove the use of a temporary variable in
-         * the following code, otherwise the Microsoft C compiler
-         * will turn the following lines into a no-op.
-         */
         AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
         word |= CONTROL_FLAG_IGNORE_PERR;
         AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
     }
 
     /*
-     * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
-     * bits for the default FIFO threshold.
-     *
-     * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
-     *
-     * For DMA Errata #4 set the BC_THRESH_ENB bit.
+     * If the BIOS control flag AIPP (Asynchronous Information
+     * Phase Protection) disable bit is not set, then set the firmware
+     * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+     * AIPP checking and encoding.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_ENABLE_AIPP;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+     * and START_CTL_TH [3:2].
      */
     AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+        FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
 
     /*
      * Microcode operating variables for WDTR, SDTR, and command tag
@@ -16634,22 +16614,24 @@
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-        PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+        asc_dvc->chip_scsi_id);
 
     /*
-     * Determine SCSI_CFG1 Microcode Default Value.
+     * Calculate SCSI_CFG1 Microcode Default Value.
      *
      * The microcode will set the SCSI_CFG1 register using this value
      * after it is started below.
+     *
+     * Each ASC-38C1600 function has only two cable detect bits.
+     * The bus mode override bits are in IOPB_SOFT_OVER_WR.
      */
-
-    /* Read current SCSI_CFG1 Register value. */
     scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
 
     /*
-     * If the internal narrow cable is reversed all of the SCSI_CTRL
-     * register signals will be set. Check for and return an error if
-     * this condition is found.
+     * If the cable is reversed all of the SCSI_CTRL register signals
+     * will be set. Check for and return an error if this condition is
+     * found.
      */
     if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
     {
@@ -16658,13 +16640,12 @@
     }
 
     /*
-     * All kind of combinations of devices attached to one of four connectors
-     * are acceptable except HVD device attached. For example, LVD device can
-     * be attached to SE connector while SE device attached to LVD connector.
-     * If LVD device attached to SE connector, it only runs up to Ultra speed.
+     * Each ASC-38C1600 function has two connectors. Only an HVD device
+     * can not be connected to either connector. An LVD device or SE device
+     * may be connected to either connecor. If an SE device is connected,
+     * then at most Ultra speed (20 Mhz) can be used on both connectors.
      *
-     * If an HVD device is attached to one of LVD connectors, return an error.
-     * However, there is no way to detect HVD device attached to SE connectors.
+     * If an HVD device is attached, return an error.
      */
     if (scsi_cfg1 & HVD)
     {
@@ -16673,12 +16654,17 @@
     }
 
     /*
-     * If either SE or LVD automatic termination control is enabled, then
-     * set the termination value based on a table listed in a_condor.h.
+     * Each function in the ASC-38C1600 uses only the SE cable detect and
+     * termination because there are two connectors for each function. Each
+     * function may use either LVD or SE mode. Corresponding the SE automatic
+     * termination control EEPROM bits are used for each function. Each
+     * function has its own EEPROM. If SE automatic control is enabled for
+     * the function, then set the termination value based on a table listed
+     * in a_condor.h.
      *
-     * If manual termination was specified with an EEPROM setting then
-     * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
-     * be 'ored' into SCSI_CFG1.
+     * If manual termination is specified in the EEPROM for the function,
+     * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+     * ready to be 'ored' into SCSI_CFG1.
      */
     if ((asc_dvc->cfg->termination & TERM_SE) == 0)
     {
@@ -16690,51 +16676,44 @@
                 asc_dvc->cfg->termination |= TERM_SE;
                 break;
 
-            /* TERM_SE_HI: on, TERM_SE_LO: off */
-            case 0x0:
-                asc_dvc->cfg->termination |= TERM_SE_HI;
-                break;
-        }
-    }
-
-    if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
-    {
-        /* LVD automatic termination control is enabled. */
-        switch(scsi_cfg1 & C_DET_LVD)
-        {
-            /* TERM_LVD_HI: on, TERM_LVD_LO: on */
-            case 0x4: case 0x8: case 0xC:
-                asc_dvc->cfg->termination |= TERM_LVD;
-                break;
-
-            /* TERM_LVD_HI: off, TERM_LVD_LO: off */
             case 0x0:
+                if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0)
+                {
+                    /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+                }
+                else
+                {
+                    /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+                    asc_dvc->cfg->termination |= TERM_SE_HI;
+                }
                 break;
         }
     }
 
     /*
-     * Clear any set TERM_SE and TERM_LVD bits.
+     * Clear any set TERM_SE bits.
      */
-    scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+    scsi_cfg1 &= ~TERM_SE;
 
     /*
-     * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+     * Invert the TERM_SE bits and then set 'scsi_cfg1'.
      */
-    scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+    scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
 
     /*
-     * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
-     * and set possibly modified termination control bits in the Microcode
-     * SCSI_CFG1 Register Value.
+     * Clear Big Endian and Terminator Polarity bits and set possibly
+     * modified termination control bits in the Microcode SCSI_CFG1
+     * Register Value.
+     *
+     * Big Endian bit is not used even on big endian machines.
      */
-    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
 
     /*
      * Set SCSI_CFG1 Microcode Default Value
      *
-     * Set possibly modified termination control and reset DIS_TERM_DRV
-     * bits in the Microcode SCSI_CFG1 Register Value.
+     * Set possibly modified termination control bits in the Microcode
+     * SCSI_CFG1 Register Value.
      *
      * The microcode will set the SCSI_CFG1 register using this value
      * after it is started below.
@@ -16750,10 +16729,17 @@
      * MEM_CFG may be accessed as a word or byte, but only bits 0-7
      * are defined.
      *
-     * ASC-38C0800 has 16KB internal memory.
+     * ASC-38C1600 has 32KB internal memory.
+     *
+     * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+     * out a special 16K Adv Library and Microcode version. After the issue
+     * resolved, we should turn back to the 32K support. Both a_condor.h and
+     * mcode.sas files also need to be updated.
+     *
+     * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+     *  BIOS_EN | RAM_SZ_32KB);
      */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-        BIOS_EN | RAM_SZ_16KB);
+     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, BIOS_EN | RAM_SZ_16KB);
 
     /*
      * Set SEL_MASK Microcode Default Value
@@ -16769,6 +16755,7 @@
      *
      * Driver must have already allocated memory and set 'carrier_buf'.
      */
+
     ASC_ASSERT(asc_dvc->carrier_buf != NULL);
 
     carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
@@ -16803,12 +16790,12 @@
         }
 
         carrp->carr_pa = carr_paddr;
-        carrp->carr_va = ADV_VADDR_TO_U32(carrp);
+        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
 
         /*
          * Insert the carrier at the beginning of the freelist.
          */
-        carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist);
+        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
         asc_dvc->carr_freelist = carrp;
 
         carrp++;
@@ -16818,25 +16805,27 @@
     /*
      * Set-up the Host->RISC Initiator Command Queue (ICQ).
      */
-
     if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
     {
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist =
-        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa);
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
     /*
      * The first command issued will be placed in the stopper carrier.
      */
-    asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
     /*
-     * Set RISC ICQ physical address start value.
+     * Set RISC ICQ physical address start value. Initialize the
+     * COMMA register to the same value otherwise the RISC will
+     * prematurely detect a command is available.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_ICQ,
-        cpu_to_le32(asc_dvc->icq_sp->carr_pa));
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+    AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+        le32_to_cpu(asc_dvc->icq_sp->carr_pa));
 
     /*
      * Set-up the RISC->Host Initiator Response Queue (IRQ).
@@ -16846,8 +16835,8 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist =
-        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa);
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
     /*
      * The first command completed by the RISC will be placed in
@@ -16856,22 +16845,16 @@
      * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
      * completed the RISC will set the ASC_RQ_STOPPER bit.
      */
-    asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
+    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
     /*
      * Set RISC IRQ physical address start value.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IRQ,
-        cpu_to_le32(asc_dvc->irq_sp->carr_pa));
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
     asc_dvc->carr_pending_cnt = 0;
 
     AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
         (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
-    /*
-     * Note: Don't remove the use of a temporary variable in
-     * the following code, otherwise the Microsoft C compiler
-     * will turn the following lines into a no-op.
-     */
     AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
     AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
@@ -16887,8 +16870,7 @@
     {
         /*
          * If the BIOS Signature is present in memory, restore the
-         * BIOS Handshake Configuration Table and do not perform
-         * a SCSI Bus Reset.
+         * per TID microcode operating variables.
          */
         if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
         {
@@ -16897,8 +16879,9 @@
              */
             AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
             AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
             AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            for (tid = 0; tid <= ASC_MAX_TID; tid++)
             {
                 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
                     max_cmd[tid]);
@@ -16945,8 +16928,6 @@
      * Read the board's EEPROM configuration.
      *
      * Set default values if a bad checksum is found.
-     *
-     * XXX - Don't handle big-endian access to EEPROM yet.
      */
     if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
     {
@@ -16967,13 +16948,13 @@
          * failed.
          */
         eep_config.serial_number_word3 =
-            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
 
         eep_config.serial_number_word2 =
-            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
 
         eep_config.serial_number_word1 =
-            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
         AdvSet3550EEPConfig(iop_base, &eep_config);
     }
@@ -17049,7 +17030,211 @@
     asc_dvc->max_host_qng = eep_config.max_host_qng;
     asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
-
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ADV_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ADV_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination == 0)
+    {
+        asc_dvc->cfg->termination = 0;    /* auto termination */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination == 1)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination == 2)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination == 3)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+        } else
+        {
+            /*
+             * The EEPROM 'termination' field contains a bad value. Use
+             * automatic termination instead.
+             */
+            asc_dvc->cfg->termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+)
+{
+    AdvPortAddr              iop_base;
+    ushort                   warn_code;
+    ADVEEP_38C0800_CONFIG    eep_config;
+    int                      i;
+    uchar                    tid, termination;
+    ushort                   sdtr_speed = 0;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+        {
+            *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_38C0800_EEPROM_Config + i);
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+
+        AdvSet38C0800EEPConfig(iop_base, &eep_config);
+    }
+    /*
+     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+    /*
+     * For every Target ID if any of its 'sdtr_speed[1234]' bits
+     * are set, then set an 'sdtr_able' bit for it.
+     */
+    asc_dvc->sdtr_able = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (tid == 0)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed1;
+        } else if (tid == 4)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed2;
+        } else if (tid == 8)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed3;
+        } else if (tid == 12)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed4;
+        }
+        if (sdtr_speed & ADV_MAX_TID)
+        {
+            asc_dvc->sdtr_able |= (1 << tid);
+        }
+        sdtr_speed >>= 4;
+    }
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
     /*
      * If the EEPROM 'termination' field is set to automatic (0), then set
      * the ADV_DVC_CFG 'termination' field to automatic also.
@@ -17058,32 +17243,63 @@
      * value check that a legal value is set and set the ADV_DVC_CFG
      * 'termination' field appropriately.
      */
-    if (eep_config.termination == 0)
+    if (eep_config.termination_se == 0)
     {
-        asc_dvc->cfg->termination = 0;    /* auto termination */
+        termination = 0;                         /* auto termination for SE */
     } else
     {
         /* Enable manual control with low off / high off. */
-        if (eep_config.termination == 1)
+        if (eep_config.termination_se == 1)
         {
-            asc_dvc->cfg->termination = TERM_CTL_SEL;
+            termination = 0;
 
         /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination == 2)
+        } else if (eep_config.termination_se == 2)
         {
-            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+            termination = TERM_SE_HI;
 
         /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination == 3)
+        } else if (eep_config.termination_se == 3)
         {
-            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+            termination = TERM_SE;
         } else
         {
             /*
-             * The EEPROM 'termination' field contains a bad value. Use
-             * automatic termination instead.
+             * The EEPROM 'termination_se' field contains a bad value.
+             * Use automatic termination instead.
              */
-            asc_dvc->cfg->termination = 0;
+            termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    if (eep_config.termination_lvd == 0)
+    {
+        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_lvd == 1)
+        {
+            asc_dvc->cfg->termination = termination;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_lvd == 2)
+        {
+            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_lvd == 3)
+        {
+            asc_dvc->cfg->termination =
+                termination | TERM_LVD;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_lvd' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            asc_dvc->cfg->termination = termination;
             warn_code |= ASC_WARN_EEPROM_TERMINATION;
         }
     }
@@ -17092,11 +17308,11 @@
 }
 
 /*
- * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
- * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
+ * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
  * all of this is done.
  *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
@@ -17105,12 +17321,12 @@
  */
 ASC_INITFUNC(
 STATIC int,
-AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
 )
 {
     AdvPortAddr              iop_base;
     ushort                   warn_code;
-    ADVEEP_38C0800_CONFIG    eep_config;
+    ADVEEP_38C1600_CONFIG    eep_config;
     int                      i;
     uchar                    tid, termination;
     ushort                   sdtr_speed = 0;
@@ -17123,20 +17339,59 @@
      * Read the board's EEPROM configuration.
      *
      * Set default values if a bad checksum is found.
-     *
-     * XXX - Don't handle big-endian access to EEPROM yet.
      */
-    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
     {
         warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
         /*
          * Set EEPROM default values.
          */
-        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+        for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++)
         {
-            *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_38C0800_EEPROM_Config + i);
+            if (i == 1 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != 0)
+            {
+                /*
+                 * Set Function 1 EEPROM Word 0 MSB
+                 *
+                 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
+                 * EEPROM bits.
+                 *
+                 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
+                 * old Mac system booting problem. The Expansion ROM must
+                 * be disabled in Function 1 for these systems.
+                 *
+                 */
+                *((uchar *) &eep_config + i) =
+                ((*((uchar *) &Default_38C1600_EEPROM_Config + i)) &
+                    (~(((ADV_EEPROM_BIOS_ENABLE | ADV_EEPROM_INTAB) >> 8) &
+                     0xFF)));
+
+                /*
+                 * Set the INTAB (bit 11) if the GPIO 0 input indicates
+                 * the Function 1 interrupt line is wired to INTA.
+                 *
+                 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+                 *   1 - Function 1 interrupt line wired to INT A.
+                 *   0 - Function 1 interrupt line wired to INT B.
+                 *
+                 * Note: Adapter boards always have Function 0 wired to INTA.
+                 * Put all 5 GPIO bits in input mode and then read
+                 * their input values.
+                 */
+                AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
+                if (AdvReadByteRegister(iop_base, IOPB_GPIO_DATA) & 0x01)
+                {
+                    /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
+                *((uchar *) &eep_config + i) |=
+                    ((ADV_EEPROM_INTAB >> 8) & 0xFF);
+                }
+            }
+            else
+            {
+                *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_38C1600_EEPROM_Config + i);
+            }
         }
 
         /*
@@ -17145,18 +17400,19 @@
          * failed.
          */
         eep_config.serial_number_word3 =
-            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
 
         eep_config.serial_number_word2 =
-            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
 
         eep_config.serial_number_word1 =
-            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
-        AdvSet38C0800EEPConfig(iop_base, &eep_config);
+        AdvSet38C1600EEPConfig(iop_base, &eep_config);
     }
+
     /*
-     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
      * EEPROM configuration that was read.
      *
      * This is the mapping of EEPROM fields to Adv Library fields.
@@ -17166,25 +17422,23 @@
     asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
     asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
     asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->ppr_able = 0;
     asc_dvc->tagqng_able = eep_config.tagqng_able;
     asc_dvc->cfg->disc_enable = eep_config.disc_enable;
     asc_dvc->max_host_qng = eep_config.max_host_qng;
     asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
     asc_dvc->start_motor = eep_config.start_motor;
     asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
     asc_dvc->bios_ctrl = eep_config.bios_ctrl;
     asc_dvc->no_scam = eep_config.scam_tolerant;
-    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
-    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
-    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
     /*
      * For every Target ID if any of its 'sdtr_speed[1234]' bits
      * are set, then set an 'sdtr_able' bit for it.
      */
     asc_dvc->sdtr_able = 0;
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    for (tid = 0; tid <= ASC_MAX_TID; tid++)
     {
         if (tid == 0)
         {
@@ -17199,7 +17453,7 @@
         {
             sdtr_speed = asc_dvc->sdtr_speed4;
         }
-        if (sdtr_speed & ADV_MAX_TID)
+        if (sdtr_speed & ASC_MAX_TID)
         {
             asc_dvc->sdtr_able |= (1 << tid);
         }
@@ -17250,7 +17504,7 @@
     }
 
     /*
-     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+     * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
      * values based on possibly adjusted EEPROM values.
      */
     asc_dvc->max_host_qng = eep_config.max_host_qng;
@@ -17258,10 +17512,10 @@
 
     /*
      * If the EEPROM 'termination' field is set to automatic (0), then set
-     * the ADV_DVC_CFG 'termination' field to automatic also.
+     * the ASC_DVC_CFG 'termination' field to automatic also.
      *
      * If the termination is specified with a non-zero 'termination'
-     * value check that a legal value is set and set the ADV_DVC_CFG
+     * value check that a legal value is set and set the ASC_DVC_CFG
      * 'termination' field appropriately.
      */
     if (eep_config.termination_se == 0)
@@ -17341,25 +17595,37 @@
     ushort              wval, chksum;
     ushort              *wbuf;
     int                 eep_addr;
+    ushort              *charfields;
 
+    charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
     wbuf = (ushort *) cfg_buf;
     chksum = 0;
 
-    for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
-         eep_addr < ASC_EEP_DVC_CFG_END;
+    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+         eep_addr < ADV_EEP_DVC_CFG_END;
          eep_addr++, wbuf++)
     {
         wval = AdvReadEEPWord(iop_base, eep_addr);
-        chksum += wval;
-        *wbuf = wval;
+        chksum += wval; /* Checksum is calculated from word values. */
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            *wbuf = wval;
+        }
     }
+    /* Read checksum word. */
     *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-    wbuf++;
-    for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
-         eep_addr < ASC_EEP_MAX_WORD_ADDR;
+    wbuf++; charfields++;
+
+    /* Read rest of EEPROM not covered by the checksum. */
+    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+         eep_addr < ADV_EEP_MAX_WORD_ADDR;
          eep_addr++, wbuf++)
     {
         *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(*wbuf);
+        }
     }
     return chksum;
 }
@@ -17378,29 +17644,89 @@
     ushort              wval, chksum;
     ushort              *wbuf;
     int                 eep_addr;
+    ushort              *charfields;
 
+    charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
     wbuf = (ushort *) cfg_buf;
     chksum = 0;
 
-    for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
-         eep_addr < ASC_EEP_DVC_CFG_END;
+    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+         eep_addr < ADV_EEP_DVC_CFG_END;
          eep_addr++, wbuf++)
     {
         wval = AdvReadEEPWord(iop_base, eep_addr);
-        chksum += wval;
-        *wbuf = wval;
+        chksum += wval; /* Checksum is calculated from word values. */
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            *wbuf = wval;
+        }
     }
+    /* Read checksum word. */
     *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-    wbuf++;
-    for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
-         eep_addr < ASC_EEP_MAX_WORD_ADDR;
+    wbuf++; charfields++;
+
+    /* Read rest of EEPROM not covered by the checksum. */
+    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+         eep_addr < ADV_EEP_MAX_WORD_ADDR;
          eep_addr++, wbuf++)
     {
         *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(*wbuf);
+        }
     }
     return chksum;
 }
 
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C1600_CONFIG *cfg_buf)
+)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+    ushort              *charfields;
+
+    charfields = (ushort*) &ADVEEP_38C1600_Config_Field_IsChar;
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+         eep_addr < ADV_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval; /* Checksum is calculated from word values. */
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            *wbuf = wval;
+        }
+    }
+    /* Read checksum word. */
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++; charfields++;
+
+    /* Read rest of EEPROM not covered by the checksum. */
+    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+         eep_addr < ADV_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(*wbuf);
+        }
+    }
+    return chksum;
+}
 
 /*
  * Read the EEPROM from specified location
@@ -17426,7 +17752,7 @@
 {
     int eep_delay_ms;
 
-    for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++)
+    for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++)
     {
         if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE)
         {
@@ -17449,41 +17775,57 @@
 {
     ushort *wbuf;
     ushort addr, chksum;
+    ushort *charfields;
 
     wbuf = (ushort *) cfg_buf;
+    charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
     chksum = 0;
 
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
     AdvWaitEEPCmd(iop_base);
 
     /*
-     * Write EEPROM from word 0 to word 20
+     * Write EEPROM from word 0 to word 20.
      */
-    for (addr = ASC_EEP_DVC_CFG_BEGIN;
-         addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+    for (addr = ADV_EEP_DVC_CFG_BEGIN;
+         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
     {
-        chksum += *wbuf;
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        chksum += *wbuf; /* Checksum is calculated from word values. */
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
         AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
         AdvWaitEEPCmd(iop_base);
-        DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
     }
 
     /*
-     * Write EEPROM checksum at word 21
+     * Write EEPROM checksum at word 21.
      */
     AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
     AdvWaitEEPCmd(iop_base);
-    wbuf++;        /* skip over check_sum */
+    wbuf++; charfields++;
 
     /*
-     * Write EEPROM OEM name at words 22 to 29
+     * Write EEPROM OEM name at words 22 to 29.
      */
-    for (addr = ASC_EEP_DVC_CTL_BEGIN;
-         addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    for (addr = ADV_EEP_DVC_CTL_BEGIN;
+         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
     {
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
         AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
         AdvWaitEEPCmd(iop_base);
     }
@@ -17500,42 +17842,126 @@
                        ADVEEP_38C0800_CONFIG *cfg_buf)
 {
     ushort *wbuf;
+    ushort *charfields;
     ushort addr, chksum;
 
     wbuf = (ushort *) cfg_buf;
+    charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 20.
+     */
+    for (addr = ADV_EEP_DVC_CFG_BEGIN;
+         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        chksum += *wbuf; /* Checksum is calculated from word values. */
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 21.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++; charfields++;
+
+    /*
+     * Write EEPROM OEM name at words 22 to 29.
+     */
+    for (addr = ADV_EEP_DVC_CTL_BEGIN;
+         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C1600_CONFIG *cfg_buf)
+{
+    ushort              *wbuf;
+    ushort              *charfields;
+    ushort              addr, chksum;
+
+    wbuf = (ushort *) cfg_buf;
+    charfields = (ushort *) &ADVEEP_38C1600_Config_Field_IsChar;
     chksum = 0;
 
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
     AdvWaitEEPCmd(iop_base);
 
     /*
-     * Write EEPROM from word 0 to word 20
+     * Write EEPROM from word 0 to word 20.
      */
-    for (addr = ASC_EEP_DVC_CFG_BEGIN;
-         addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+    for (addr = ADV_EEP_DVC_CFG_BEGIN;
+         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
     {
-        chksum += *wbuf;
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        chksum += *wbuf; /* Checksum is calculated from word values. */
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
         AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
         AdvWaitEEPCmd(iop_base);
-        DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
     }
 
     /*
-     * Write EEPROM checksum at word 21
+     * Write EEPROM checksum at word 21.
      */
     AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
     AdvWaitEEPCmd(iop_base);
-    wbuf++;        /* skip over check_sum */
+    wbuf++; charfields++;
 
     /*
-     * Write EEPROM OEM name at words 22 to 29
+     * Write EEPROM OEM name at words 22 to 29.
      */
-    for (addr = ASC_EEP_DVC_CTL_BEGIN;
-         addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    for (addr = ADV_EEP_DVC_CTL_BEGIN;
+         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
     {
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
         AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
         AdvWaitEEPCmd(iop_base);
     }
@@ -17570,7 +17996,7 @@
 AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
                 ADV_SCSI_REQ_Q *scsiq)
 {
-    int                    last_int_level;
+    ulong                  last_int_level;
     AdvPortAddr            iop_base;
     ADV_DCNT               req_size;
     ADV_PADDR              req_paddr;
@@ -17598,10 +18024,11 @@
      */
     if ((new_carrp = asc_dvc->carr_freelist) == NULL)
     {
+       DvcLeaveCritical(last_int_level);
        return ADV_BUSY;
     }
-    asc_dvc->carr_freelist =
-        (ADV_CARR_T *) ADV_U32_TO_VADDR(new_carrp->next_vpa);
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
     asc_dvc->carr_pending_cnt++;
 
     /*
@@ -17609,7 +18036,7 @@
      * to the stopper value. The current stopper will be changed
      * below to point to the new stopper.
      */
-    new_carrp->next_vpa = ASC_CQ_STOPPER;
+    new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
     /*
      * Clear the ADV_SCSI_REQ_Q done flag.
@@ -17617,17 +18044,20 @@
     scsiq->a_flag &= ~ADV_SCSIQ_DONE;
 
     req_size = sizeof(ADV_SCSI_REQ_Q);
-    req_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
-        (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG));
+    req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
+        (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG);
 
-    ASC_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr);
+    ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
     ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
 
+    /* Wait for assertion before making little-endian */
+    req_paddr = cpu_to_le32(req_paddr);
+
     /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
-    scsiq->scsiq_ptr = ADV_VADDR_TO_U32(scsiq);
+    scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
     scsiq->scsiq_rptr = req_paddr;
 
-    scsiq->carr_va = ADV_VADDR_TO_U32(asc_dvc->icq_sp);
+    scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
     /*
      * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
      * order during initialization.
@@ -17653,18 +18083,30 @@
      */
     asc_dvc->icq_sp = new_carrp;
 
-    /*
-     * Tickle the RISC to tell it to read its Command Queue Head pointer.
-     */
-    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
-    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+        asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
     {
         /*
-         * Clear the tickle value. In the ASC-3550 the RISC flag
-         * command 'clr_tickle_a' does not work unless the host
-         * value is cleared.
+         * Tickle the RISC to tell it to read its Command Queue Head pointer.
          */
-        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+        if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+        {
+            /*
+             * Clear the tickle value. In the ASC-3550 the RISC flag
+             * command 'clr_tickle_a' does not work unless the host
+             * value is cleared.
+             */
+            AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+        }
+    } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        /*
+         * Notify the RISC a carrier is ready by writing the physical
+         * address of the new carrier stopper to the COMMA register.
+         */
+        AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+                le32_to_cpu(new_carrp->carr_pa));
     }
 
     DvcLeaveCritical(last_int_level);
@@ -17731,6 +18173,7 @@
 {
     int         status;
     ushort      wdtr_able, sdtr_able, tagqng_able;
+    ushort      ppr_able = 0;
     uchar       tid, max_cmd[ADV_MAX_TID + 1];
     AdvPortAddr iop_base;
     ushort      bios_sig;
@@ -17742,6 +18185,10 @@
      */
     AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
     AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+    }
     AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
     for (tid = 0; tid <= ADV_MAX_TID; tid++)
     {
@@ -17771,7 +18218,11 @@
      * re-initializing the chip.
      */
     asc_dvc->err_code = 0;
-    if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        status = AdvInitAsc38C1600Driver(asc_dvc);
+    }
+    else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
     {
         status = AdvInitAsc38C0800Driver(asc_dvc);
     } else
@@ -17798,6 +18249,10 @@
      */
     AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
     AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+    }
     AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
     for (tid = 0; tid <= ADV_MAX_TID; tid++)
     {
@@ -17848,6 +18303,7 @@
     if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
          ADV_INTR_STATUS_INTRC)) == 0)
     {
+        DvcLeaveCritical(flags);
         return ADV_FALSE;
     }
 
@@ -17861,13 +18317,18 @@
         uchar intrb_code;
 
         AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-        if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
-            asc_dvc->carr_pending_cnt != 0)
+
+        if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+            asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
         {
-            AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
-            if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+            if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+                asc_dvc->carr_pending_cnt != 0)
             {
-                AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+                AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+                if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+                {
+                    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+                }
             }
         }
 
@@ -17880,7 +18341,8 @@
     /*
      * Check if the IRQ stopper carrier contains a completed request.
      */
-    while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0)
+    while (((irq_next_vpa =
+             le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0)
     {
         /*
          * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
@@ -17891,7 +18353,20 @@
          * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
          * in AdvExeScsiQueue().
          */
-        scsiq = (ADV_SCSI_REQ_Q *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->areq_vpa);
+        scsiq = (ADV_SCSI_REQ_Q *)
+            ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+
+        /*
+         * Request finished with good status and the queue was not
+         * DMAed to host memory by the firmware. Set all status fields
+         * to indicate good status.
+         */
+        if ((irq_next_vpa & ASC_RQ_GOOD) != 0)
+        {
+            scsiq->done_status = QD_NO_ERROR;
+            scsiq->host_status = scsiq->scsi_status = 0;
+            scsiq->data_cnt = 0L;
+        }
 
         /*
          * Advance the stopper pointer to the next carrier
@@ -17902,7 +18377,8 @@
         asc_dvc->irq_sp = (ADV_CARR_T *)
             ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
 
-        free_carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist);
+        free_carrp->next_vpa =
+                cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
         asc_dvc->carr_freelist = free_carrp;
         asc_dvc->carr_pending_cnt--;
 
@@ -17914,23 +18390,20 @@
          */
         scsiq->cntl = 0;
 
-#if __BIG_ENDIAN
-        /*
-         * After the request completes the only field in the ASC_SCSI_REQ_Q
-         * structure needs to be byte swapped from little endian order to
-         * big endian order is the residual data count.
-         */
-        scsiqp->data_cnt = le32_to_cpu(scsiqp->data_cnt);
-#endif /* __BIG_ENDIAN */
-
         /*
          * If the command that completed was a SCSI INQUIRY and
          * LUN 0 was sent the command, then process the INQUIRY
          * command information for the device.
+         *
+         * Note: If data returned were either VPD or CmdDt data,
+         * don't process the INQUIRY command information for
+         * the device, otherwise may erroneously set *_able bits.
          */
         if (scsiq->done_status == QD_NO_ERROR &&
             scsiq->cdb[0] == SCSICMD_Inquiry &&
-            scsiq->target_lun == 0)
+            scsiq->target_lun == 0 &&
+            (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
+                == ADV_INQ_RTN_STD_INQUIRY_DATA)
         {
             AdvInquiryHandling(asc_dvc, scsiq);
         }
@@ -17982,7 +18455,7 @@
                ushort idle_cmd,
                ADV_DCNT idle_cmd_parameter)
 {
-    int         last_int_level;
+    ulong       last_int_level;
     int         result;
     ADV_DCNT    i, j;
     AdvPortAddr iop_base;
@@ -18005,8 +18478,8 @@
      * followed, the microcode may process the idle command before the
      * parameters have been written to LRAM.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
-        idle_cmd_parameter);
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+        cpu_to_le32(idle_cmd_parameter));
     AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
 
     /*
@@ -18072,7 +18545,8 @@
      * microcode to the transfer residual count.
      */
 
-    if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8)
+    if (scsiq->cdb[4] < 8 ||
+        (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8)
     {
         return;
     }
@@ -18085,7 +18559,7 @@
     /*
      * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
      */
-    if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2)
+    if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2)
     {
         return;
     } else
@@ -18109,7 +18583,7 @@
          * device's 'wdtr_able' bit and write the new value to the
          * microcode.
          */
-        if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16)
+        if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq))
         {
             AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
             if ((cfg_word & tidmask) == 0)
@@ -18140,7 +18614,7 @@
          * supports synchronous transfers, then turn on the device's
          * 'sdtr_able' bit. Write the new value to the microcode.
          */
-        if ((asc_dvc->sdtr_able & tidmask) && inq->Sync)
+        if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq))
         {
             AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
             if ((cfg_word & tidmask) == 0)
@@ -18158,6 +18632,29 @@
                 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
             }
         }
+        /*
+         * If the Inquiry data included enough space for the SPI-3
+         * Clocking field, then check if DT mode is supported.
+         */
+        if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
+            (scsiq->cdb[4] >= 57 ||
+            (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57))
+        {
+            /*
+             * PPR (Parallel Protocol Request) Capable
+             *
+             * If the device supports DT mode, then it must be PPR capable.
+             * The PPR message will be used in place of the SDTR and WDTR
+             * messages to negotiate synchronous speed and offset, transfer
+             * width, and protocol options.
+             */
+            if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY)
+            {
+                AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
+                asc_dvc->ppr_able |= tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
+            }
+        }
 
         /*
          * If the EEPROM enabled Tag Queuing for the device and the
@@ -18171,7 +18668,7 @@
          * disabling Tag Queuing in the BIOS devices with Tag Queuing
          * bugs will at least work with the BIOS.
          */
-        if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue)
+        if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq))
         {
             AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
             cfg_word |= tidmask;
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h
--- v2.4.3/linux/drivers/scsi/advansys.h	Mon Dec 11 13:18:51 2000
+++ linux/drivers/scsi/advansys.h	Thu Apr 12 12:16:35 2001
@@ -1,9 +1,8 @@
-/* $Id: advansys.h,v 1.18 1999/11/29 21:47:16 bobf Exp bobf $ */
-
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
  * 
- * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * Copyright (c) 1995-2000 Advanced System Products, Inc.
+ * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
  * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -11,49 +10,57 @@
  * code retain the above copyright notice and this comment without
  * modification.
  *
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ *
  * There is an AdvanSys Linux WWW page at:
+ *  http://www.connectcom.net/downloads/software/os/linux.html
  *  http://www.advansys.com/linux.html
  *
- * The latest version of the AdvanSys driver is available at:
- *  ftp://ftp.advansys.com/pub/linux
+ * The latest released version of the AdvanSys driver is available at:
+ *  ftp://ftp.advansys.com/pub/linux/linux.tgz
+ *  ftp://ftp.connectcom.net/pub/linux/linux.tgz
  *
  * Please send questions, comments, bug reports to:
- *  bobf@advansys.com (Bob Frey)
+ *  linux@connectcom.net or bfrey@turbolinux.com.cn
  */
 
 #ifndef _ADVANSYS_H
 #define _ADVANSYS_H
 
-/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
-#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
-
+#include <linux/config.h>
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
+/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
+#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
+/* Driver supported only in version 2.2 and version >= 2.4. */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \
+    (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \
+     LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0))
+#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels."
+#endif
+#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0))
+#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0))
+
 /*
  * Scsi_Host_Template function prototypes.
  */
 int advansys_detect(Scsi_Host_Template *);
 int advansys_release(struct Scsi_Host *);
 const char *advansys_info(struct Scsi_Host *);
-int advansys_command(Scsi_Cmnd *);
 int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-int advansys_abort(Scsi_Cmnd *);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
 int advansys_reset(Scsi_Cmnd *);
-#else /* version >= v1.3.89 */
-int advansys_reset(Scsi_Cmnd *, unsigned int);
-#endif /* version >= v1.3.89 */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-int advansys_biosparam(Disk *, int, int[]);
-#else /* version >= v1.3.0 */
 int advansys_biosparam(Disk *, kdev_t, int[]);
+#ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
 extern struct proc_dir_entry proc_scsi_advansys;
 #endif /* version < v2.3.28 */
 int advansys_proc_info(char *, char **, off_t, int, int, int);
-#endif /* version >= v1.3.0 */
+#else /* !defined(CONFIG_PROC_FS) */
+#define advansys_proc_info      NULL
+#endif /* !defined(CONFIG_PROC_FS) */
 
 /* init/main.c setup function */
 void advansys_setup(char *, int *);
@@ -61,108 +68,24 @@
 /*
  * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
  */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-#define ADVANSYS { \
-    NULL,                     /* struct SHT *next */ \
-    NULL,                     /* int *usage_count */ \
-    "advansys",               /* char *name */ \
-    advansys_detect,          /* int (*detect)(struct SHT *) */ \
-    advansys_release,         /* int (*release)(struct Scsi_Host *) */ \
-    advansys_info,            /* const char *(*info)(struct Scsi_Host *) */ \
-    advansys_command,         /* int (*command)(Scsi_Cmnd *) */ \
-    advansys_queuecommand, \
-            /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
-    advansys_abort,           /* int (*abort)(Scsi_Cmnd *) */ \
-    advansys_reset,           /* int (*reset)(Scsi_Cmnd *) */ \
-    NULL,                     /* int (*slave_attach)(int, int) */ \
-    advansys_biosparam,       /* int (* bios_param)(Disk *, int, int []) */ \
-    /* \
-     * The following fields are set per adapter in advansys_detect(). \
-     */ \
-    0,                        /* int can_queue */ \
-    0,                        /* int this_id */ \
-    0,                        /* short unsigned int sg_tablesize */ \
-    0,                        /* short cmd_per_lun */ \
-    0,                        /* unsigned char present */    \
-    /* \
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
-     * must be set. The flag will be cleared in advansys_detect for non-ISA \
-     * adapters. Refer to the comment in scsi_module.c for more information. \
-     */ \
-    1,                        /* unsigned unchecked_isa_dma:1 */ \
-    /* \
-     * All adapters controlled by this driver are capable of large \
-     * scatter-gather lists. According to the mid-level SCSI documentation \
-     * this obviates any performance gain provided by setting \
-     * 'use_clustering'. But empirically while CPU utilization is increased \
-     * by enabling clustering, I/O throughput increases as well. \
-     */ \
-    ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
-}
-#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
-#define ADVANSYS { \
-    NULL,                    /* struct SHT *next */ \
-    NULL, \
-        /* version < v2.1.23 long *usage_count */ \
-        /* version >= v2.1.23 struct module * */ \
-    &proc_scsi_advansys,     /* struct proc_dir_entry *proc_dir */ \
-    advansys_proc_info,    \
-        /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
-    "advansys",              /* const char *name */ \
-    advansys_detect,         /* int (*detect)(struct SHT *) */ \
-    advansys_release,        /* int (*release)(struct Scsi_Host *) */ \
-    advansys_info,           /* const char *(*info)(struct Scsi_Host *) */ \
-    advansys_command,        /* int (*command)(Scsi_Cmnd *) */ \
-    advansys_queuecommand, \
-        /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
-    advansys_abort,          /* int (*abort)(Scsi_Cmnd *) */ \
-    advansys_reset, \
-        /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \
-        /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \
-    NULL,                    /* int (*slave_attach)(int, int) */ \
-    advansys_biosparam,      /* int (* bios_param)(Disk *, kdev_t, int []) */ \
-    /* \
-     * The following fields are set per adapter in advansys_detect(). \
-     */ \
-    0,                        /* int can_queue */ \
-    0,                        /* int this_id */ \
-    0,                        /* short unsigned int sg_tablesize */ \
-    0,                        /* short cmd_per_lun */ \
-    0,                        /* unsigned char present */    \
-    /* \
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
-     * must be set. The flag will be cleared in advansys_detect for non-ISA \
-     * adapters. Refer to the comment in scsi_module.c for more information. \
-     */ \
-    1,                        /* unsigned unchecked_isa_dma:1 */ \
-    /* \
-     * All adapters controlled by this driver are capable of large \
-     * scatter-gather lists. According to the mid-level SCSI documentation \
-     * this obviates any performance gain provided by setting \
-     * 'use_clustering'. But empirically while CPU utilization is increased \
-     * by enabling clustering, I/O throughput increases as well. \
-     */ \
-    ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
-}
-#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
+#if ASC_LINUX_KERNEL24
 #define ADVANSYS { \
-    proc_dir:     &proc_scsi_advansys, \
-    proc_info:    advansys_proc_info, \
-    name:         "advansys", \
-    detect:       advansys_detect, \
-    release:      advansys_release, \
-    info:         advansys_info, \
-    command:      advansys_command, \
-    queuecommand: advansys_queuecommand, \
-    abort:        advansys_abort, \
-    reset:        advansys_reset, \
-    bios_param:   advansys_biosparam, \
+    proc_name:                  "advansys", \
+    proc_info:                  advansys_proc_info, \
+    name:                       "advansys", \
+    detect:                     advansys_detect, \
+    release:                    advansys_release, \
+    info:                       advansys_info, \
+    queuecommand:               advansys_queuecommand, \
+    use_new_eh_code:		1, \
+    eh_bus_reset_handler:	advansys_reset, \
+    bios_param:                 advansys_biosparam, \
     /* \
      * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
      * must be set. The flag will be cleared in advansys_detect for non-ISA \
      * adapters. Refer to the comment in scsi_module.c for more information. \
      */ \
-    unchecked_isa_dma: 1, \
+    unchecked_isa_dma:          1, \
     /* \
      * All adapters controlled by this driver are capable of large \
      * scatter-gather lists. According to the mid-level SCSI documentation \
@@ -170,27 +93,25 @@
      * 'use_clustering'. But empirically while CPU utilization is increased \
      * by enabling clustering, I/O throughput increases as well. \
      */ \
-    use_clustering: ENABLE_CLUSTERING, \
+    use_clustering:             ENABLE_CLUSTERING, \
 }
-#else /* version >= v2.3.28 */
+#elif ASC_LINUX_KERNEL22
 #define ADVANSYS { \
-    proc_name:    "advansys", \
-    proc_info:    advansys_proc_info, \
-    name:         "advansys", \
-    detect:       advansys_detect, \
-    release:      advansys_release, \
-    info:         advansys_info, \
-    command:      advansys_command, \
-    queuecommand: advansys_queuecommand, \
-    abort:        advansys_abort, \
-    reset:        advansys_reset, \
-    bios_param:   advansys_biosparam, \
+    proc_info:                  advansys_proc_info, \
+    name:                       "advansys", \
+    detect:                     advansys_detect, \
+    release:                    advansys_release, \
+    info:                       advansys_info, \
+    queuecommand:               advansys_queuecommand, \
+    use_new_eh_code:		1, \
+    eh_bus_reset_handler:	advansys_reset, \
+    bios_param:                 advansys_biosparam, \
     /* \
      * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
      * must be set. The flag will be cleared in advansys_detect for non-ISA \
      * adapters. Refer to the comment in scsi_module.c for more information. \
      */ \
-    unchecked_isa_dma: 1, \
+    unchecked_isa_dma:          1, \
     /* \
      * All adapters controlled by this driver are capable of large \
      * scatter-gather lists. According to the mid-level SCSI documentation \
@@ -198,7 +119,7 @@
      * 'use_clustering'. But empirically while CPU utilization is increased \
      * by enabling clustering, I/O throughput increases as well. \
      */ \
-    use_clustering: ENABLE_CLUSTERING, \
+    use_clustering:             ENABLE_CLUSTERING, \
 }
-#endif /* version >= v2.3.28 */
+#endif
 #endif /* _ADVANSYS_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Thu Apr 12 12:16:35 2001
@@ -112,6 +112,7 @@
  *  8: SMP friendliness has been improved
  *
  */
+#include <linux/config.h>
 
 /*
  * The next three defines are user configurable.  These should be the only
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h	Tue Mar  6 22:44:16 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h	Thu Apr 12 12:16:35 2001
@@ -355,10 +355,6 @@
 
 #define AIC7XXX_DRIVER_VERSION  "6.1.5"
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
 #ifndef KERNEL_VERSION
 #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg linux/drivers/scsi/aic7xxx_old/aic7xxx.reg
--- v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.reg	Fri Apr  6 10:51:19 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq linux/drivers/scsi/aic7xxx_old/aic7xxx.seq
--- v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.seq	Fri Apr  6 10:51:19 2001
@@ -14,7 +14,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License (GPL) and the terms of the GPL would require the 
+ * the GNU General Public License (GPL) and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old/sequencer.h linux/drivers/scsi/aic7xxx_old/sequencer.h
--- v2.4.3/linux/drivers/scsi/aic7xxx_old/sequencer.h	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old/sequencer.h	Fri Apr  6 10:51:19 2001
@@ -15,7 +15,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.4.3/linux/drivers/scsi/aic7xxx_old.c	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Fri Apr  6 10:51:19 2001
@@ -55,7 +55,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c
--- v2.4.3/linux/drivers/scsi/fastlane.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/fastlane.c	Wed Apr 11 19:02:37 2001
@@ -76,7 +76,7 @@
 
 volatile unsigned char cmd_buffer[16];
 				/* This is where all commands are put
-				 * before they are transfered to the ESP chip
+				 * before they are transferred to the ESP chip
 				 * via PIO.
 				 */
 
@@ -96,9 +96,7 @@
 		 * this ID value. Fortunately only Fastlane maps in Z3 space
 		 */
 		if (board < 0x1000000) {
-			release_mem_region(board+FASTLANE_ESP_ADDR,
-					   sizeof(struct ESP_regs));
-			return 0;
+			goto err_release;
 		}
 		esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
 
@@ -146,10 +144,7 @@
 
 		if(!address){
 			printk("Could not remap Fastlane controller memory!");
-			scsi_unregister (esp->ehost);
-			release_mem_region(board+FASTLANE_ESP_ADDR,
-					   sizeof(struct ESP_regs));
-			return 0;
+			goto err_unregister;
 		}
 
 
@@ -171,8 +166,11 @@
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+FASTLANE_ESP_ADDR;
-		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-			    "Fastlane SCSI", esp_intr);
+		if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+				"Fastlane SCSI", esp_intr)) {
+			printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
+			goto err_unmap;
+		}			
 
 		/* Controller ID */
 		esp->scsi_id = 7;
@@ -188,6 +186,15 @@
 		return esps_in_use;
 	    }
 	}
+	return 0;
+
+ err_unmap:
+	iounmap((void *)address);
+ err_unregister:
+	scsi_unregister (esp->ehost);
+ err_release:
+	release_mem_region(z->resource.start+FASTLANE_ESP_ADDR,
+			   sizeof(struct ESP_regs));
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.4.3/linux/drivers/scsi/megaraid.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/scsi/megaraid.c	Fri Apr 13 20:26:07 2001
@@ -75,7 +75,7 @@
  *     Changed megaraid_command to use wait_queue.
  *
  * Version 1.00:
- *     Checks to see if an irq ocurred while in isr, and runs through
+ *     Checks to see if an irq occurred while in isr, and runs through
  *       routine again.
  *     Copies mailbox to temp area before processing in isr
  *     Added barrier() in busy wait to fix volatility bug
@@ -293,6 +293,9 @@
  *	Left 2.0 support but removed 2.1.x support.
  *	Collected much of the compat glue into one spot
  *
+ *	Version 1.14g-ac2 - 22/03/01
+ *	Fixed a non obvious dereference after free in the driver unload path
+ *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
@@ -391,6 +394,11 @@
 	writel (value, megaCfg->base + 0x2C);
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)	/* 0x020200 */
+#include <linux/smp.h>
+#define cpuid smp_processor_id()
+#endif
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
 
 /*
@@ -401,9 +409,6 @@
  *	queue task is a simple api without irq forms
  */
 
-#include <linux/smp.h>
-#define cpuid smp_processor_id()
-
 MODULE_AUTHOR ("American Megatrends Inc.");
 MODULE_DESCRIPTION ("AMI MegaRAID driver");
 
@@ -428,10 +433,8 @@
  *	No pci region api
  *	queue_task is now a single simple API
  */
- 
-#include <linux/smp.h>
-#define cpuid smp_processor_id()
 
+static char kernel_version[] = UTS_RELEASE;
 MODULE_AUTHOR ("American Megatrends Inc.");
 MODULE_DESCRIPTION ("AMI MegaRAID driver");
 
@@ -2764,7 +2767,6 @@
 			     sizeof (mega_mailbox64),
 			     (void *) megaCfg->mailbox64ptr,
 			     megaCfg->dma_handle64);
-	scsi_unregister (pSHost);
 
 #ifdef CONFIG_PROC_FS
 	if (megaCfg->controller_proc_dir_entry) {
@@ -2785,12 +2787,21 @@
 #endif
 
 	/*
+	 *	Release the controller memory. A word of warning this frees
+	 *	hostdata and that includes megaCfg-> so be careful what you
+	 *	dereference beyond this point
+	 */
+	 
+	scsi_unregister (pSHost);
+
+	/*
 	 * Unregister the character device interface to the driver. Ideally this
 	 * should have been done in cleanup_module routine. Since this is hidden
 	 * in file "scsi_module.c", we do it here.
 	 * major is the major number of the character device returned by call to
 	 * register_chrdev() routine.
 	 */
+
 	unregister_chrdev (major, "megadev");
 	unregister_reboot_notifier (&mega_notifier);
 
@@ -4299,12 +4310,10 @@
 }
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static Scsi_Host_Template driver_template = MEGARAID;
-#include "scsi_module.c"
-#else
-#ifdef MODULE
+static
+#endif				/* LINUX VERSION 2.4.XX */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE)
 Scsi_Host_Template driver_template = MEGARAID;
 
 #include "scsi_module.c"
-#endif				/* MODULE */
-#endif				/* LINUX VERSION 2.4.XX  test */
+#endif				/* LINUX VERSION 2.4.XX || MODULE */
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.4.3/linux/drivers/scsi/megaraid.h	Tue Mar  6 19:44:37 2001
+++ linux/drivers/scsi/megaraid.h	Fri Apr 13 20:26:07 2001
@@ -27,7 +27,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.14g (Release Date: Feb 5, 2001; 11:42)"
+#define MEGARAID_VERSION "v1.14g-ac2 (Release Date: Mar 22, 2001; 19:34:02)"
 #define MEGARAID_IOCTL_VERSION 	114
 
 /* Methods */
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.4.3/linux/drivers/scsi/ncr53c8xx.c	Tue Mar  6 19:34:25 2001
+++ linux/drivers/scsi/ncr53c8xx.c	Thu Apr 12 12:16:35 2001
@@ -9271,9 +9271,9 @@
 */
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-static Scsi_Host_Template driver_template = NCR53C8XX;
-#include "scsi_module.c"
-#elif defined(MODULE)
+static
+#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE)
 Scsi_Host_Template driver_template = NCR53C8XX;
 #include "scsi_module.c"
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- v2.4.3/linux/drivers/scsi/qlogicfas.c	Mon Sep 18 13:36:25 2000
+++ linux/drivers/scsi/qlogicfas.c	Wed Apr 11 19:02:37 2001
@@ -23,7 +23,7 @@
    Functions as standalone, loadable, and PCMCIA driver, the latter from
    Dave Hinds' PCMCIA package.
 
-   Redistributable under terms of the GNU Public License
+   Redistributable under terms of the GNU General Public License
 
 */
 /*----------------------------------------------------------------*/
@@ -118,6 +118,7 @@
 #include <linux/blk.h>	/* to get disk capacity */
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -128,11 +129,11 @@
 #include "sd.h"
 #include "hosts.h"
 #include "qlogicfas.h"
-#include<linux/stat.h>
+#include <linux/stat.h>
 
 /*----------------------------------------------------------------*/
 /* driver state info, local to driver */
-static int	    qbase = 0;	/* Port */
+static int	    qbase;	/* Port */
 static int	    qinitid;	/* initiator ID */
 static int	    qabort;	/* Flag to cause an abort */
 static int	    qlirq = -1;	/* IRQ being used */
@@ -537,7 +538,7 @@
 
 /*----------------------------------------------------------------*/
 /* look for qlogic card and init if found */
-int	qlogicfas_detect(Scsi_Host_Template * host)
+int __QLINIT qlogicfas_detect(Scsi_Host_Template * host)
 {
 int	i, j;			/* these are only used by IRQ detect */
 int	qltyp;			/* type of chip */
@@ -556,7 +557,7 @@
 
 	if( !qbase ) {
 		for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
-			if( check_region( qbase , 0x10 ) )
+			if( !request_region( qbase , 0x10, "qlogicfas" ) )
 				continue;
 			REG1;
 			if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
@@ -616,8 +617,9 @@
 	if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL))
 		host->can_queue = 1;
 #endif
-	request_region( qbase , 0x10 ,"qlogicfas");
 	hreg = scsi_register( host , 0 );	/* no host data */
+	if (!hreg)
+		goto err_release_mem;
 	hreg->io_port = qbase;
 	hreg->n_io_port = 16;
 	hreg->dma_channel = -1;
@@ -629,6 +631,13 @@
 	host->name = qinfo;
 
 	return 1;
+
+ err_release_mem:
+	release_region(qbase, 0x10);
+	if (host->can_queue)
+		free_irq(qlirq, do_ql_ihandl);
+	return 0;
+
 }
 
 /*----------------------------------------------------------------*/
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/qlogicfas.h linux/drivers/scsi/qlogicfas.h
--- v2.4.3/linux/drivers/scsi/qlogicfas.h	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/qlogicfas.h	Wed Apr 11 19:02:37 2001
@@ -13,6 +13,12 @@
 #define NULL (0)
 #endif
 
+#ifdef PCMCIA
+#define __QLINIT __devinit
+#else
+#define __QLINIT __init
+#endif
+
 #define QLOGICFAS {		\
 	detect:         qlogicfas_detect,	\
 	info:           qlogicfas_info,		\
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.4.3/linux/drivers/scsi/qlogicfc.c	Tue Mar 20 15:05:46 2001
+++ linux/drivers/scsi/qlogicfc.c	Thu Apr 19 08:38:47 2001
@@ -195,8 +195,8 @@
 #define FLASH_BIOS_ADDR	0x00
 #define FLASH_BIOS_DATA	0x02
 #define ISP_CTRL_STATUS	0x06	/* configuration register #1 */
-#define PCI_INTER_CTL	0x08	/* pci interupt control */
-#define PCI_INTER_STS	0x0a	/* pci interupt status */
+#define PCI_INTER_CTL	0x08	/* pci interrupt control */
+#define PCI_INTER_STS	0x0a	/* pci interrupt status */
 #define PCI_SEMAPHORE	0x0c	/* pci semaphore */
 #define PCI_NVRAM	0x0e	/* pci nvram interface */
 
@@ -227,7 +227,7 @@
 #define REQUEST_TRANSFER_ERROR		0x8003
 #define RESPONSE_TRANSFER_ERROR		0x8004
 #define REQUEST_QUEUE_WAKEUP		0x8005
-#define LIP_OCCURED                     0x8010
+#define LIP_OCCURRED                     0x8010
 #define LOOP_UP                         0x8011
 #define LOOP_DOWN                       0x8012
 #define LIP_RECEIVED                    0x8013
@@ -369,7 +369,7 @@
 #define STF_ABORTED			0x0020
 #define STF_TIMEOUT			0x0040
 
-/* interupt control commands */
+/* interrupt control commands */
 #define ISP_EN_INT			0x8000
 #define ISP_EN_RISC			0x0008
 
@@ -757,6 +757,10 @@
 				continue;
 
 		        host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata));
+			if (!host) {
+			        printk("qlogicfc%d : could not register host.\n", hosts);
+				continue;
+			}
 			host->max_id = QLOGICFC_MAX_ID + 1;
 			host->max_lun = QLOGICFC_MAX_LUN;
 			host->hostt->use_new_eh_code = 1;
@@ -767,7 +771,8 @@
 			hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr);
 
 			if (!hostdata->res){
-			        printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id);
+			        printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hosts);
+				pci64_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
 			        scsi_unregister(host);
 				continue;
 			}
@@ -813,7 +818,7 @@
 				scsi_unregister(host);
 				continue;
 			}
-			if (check_region(host->io_port, 0xff)) {
+			if (!request_region(host->io_port, 0xff, "qlogicfc")) {
 			        printk("qlogicfc%d : i/o region 0x%lx-0x%lx already "
 				       "in use\n",
 				       hostdata->host_id, host->io_port, host->io_port + 0xff);
@@ -822,7 +827,6 @@
 				scsi_unregister(host);
 				continue;
 			}
-			request_region(host->io_port, 0xff, "qlogicfc");
 
 			outw(0x0, host->io_port + PCI_SEMAPHORE);
 			outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
@@ -1520,7 +1524,7 @@
 			if (hostdata->adapter_state == AS_LOOP_GOOD)
 				hostdata->adapter_state = AS_REDO_FABRIC_PORTDB;
 			break;		        
-		case LIP_OCCURED:
+		case LIP_OCCURRED:
 		case LIP_RECEIVED:
 		        printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id);
 			if (hostdata->adapter_state == AS_LOOP_GOOD)
@@ -1866,7 +1870,9 @@
 	hostdata = (struct isp2x00_hostdata *) host->hostdata;
 
 	outw(0x01, host->io_port + ISP_CTRL_STATUS);
+	udelay(100);
 	outw(HCCR_RESET, host->io_port + HOST_HCCR);
+	udelay(100);
 	outw(HCCR_RELEASE, host->io_port + HOST_HCCR);
 	outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.4.3/linux/drivers/scsi/scsi.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/scsi.c	Wed Apr 25 16:18:54 2001
@@ -104,7 +104,7 @@
 const unsigned char scsi_command_size[8] =
 {
 	6, 10, 10, 12,
-	12, 12, 10, 10
+	16, 12, 10, 10
 };
 static unsigned long serial_number;
 static Scsi_Cmnd *scsi_bh_queue_head;
@@ -832,9 +832,6 @@
 	SRpnt->sr_allowed = retries;
 	SRpnt->sr_done = done;
 	SRpnt->sr_timeout_per_command = timeout;
-
-	memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, 
-	       sizeof(SRpnt->sr_cmnd));
 
 	if (SRpnt->sr_cmd_len == 0)
 		SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]);
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.4.3/linux/drivers/scsi/scsi_scan.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/scsi/scsi_scan.c	Sun Apr  8 10:10:01 2001
@@ -139,6 +139,7 @@
 	{"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
  	{"TOSHIBA","CDROM","*", BLIST_ISROM},
+ 	{"TOSHIBA","CD-ROM","*", BLIST_ISROM},
 	{"MegaRAID", "LD", "*", BLIST_FORCELUN},
 	{"DGC",  "RAID",      "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
 	{"DGC",  "DISK",      "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) 
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.4.3/linux/drivers/scsi/sym53c8xx.c	Tue Mar 20 12:04:58 2001
+++ linux/drivers/scsi/sym53c8xx.c	Thu Apr 12 12:16:35 2001
@@ -14672,9 +14672,9 @@
 */
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-static Scsi_Host_Template driver_template = SYM53C8XX;
-#include "scsi_module.c"
-#elif defined(MODULE)
+static
+#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE)
 Scsi_Host_Template driver_template = SYM53C8XX;
 #include "scsi_module.c"
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.4.3/linux/drivers/scsi/tmscsim.c	Fri Feb 16 16:06:17 2001
+++ linux/drivers/scsi/tmscsim.c	Wed Apr 11 19:02:37 2001
@@ -206,10 +206,7 @@
 #define DCBDEBUG1(x)
 
 /* Includes */
-#ifdef MODULE
-# include <linux/module.h>
-#endif
-
+#include <linux/module.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -663,16 +660,30 @@
  * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
  */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
-void __init dc390_setup (char *str)
+int __init dc390_setup (char *str)
 {	
 	int ints[8];
 	int i, im;
 	(void)get_options (str, ARRAY_SIZE(ints), ints);
+	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 (); */
+	return 1;
+};
+#ifndef MODULE
+__setup("tmscsim=", dc390_setup);
+#endif
+
 #else
 void __init dc390_setup (char *str, int *ints)
 {
 	int i, im;
-#endif
 	im = ints[0];
 	if (im > 6)
 	{
@@ -683,14 +694,10 @@
 		tmscsim[i] = ints[i+1];
 	/* dc390_checkparams (); */
 };
-
-#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 )
 {
     UCHAR bval;
@@ -828,7 +835,7 @@
 /* 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!)
+ *   (Note: For new EH, it is unnecessary!)
  * - Waiting: Contains a list of SRBs not yet sent (per DCB)
  * - Free: List of free SRB slots
  * 
@@ -2852,7 +2859,7 @@
 {
   int dev, spd, spd1;
   char *pos = buffer;
-  PSH shpnt;
+  PSH shpnt = 0;
   PACB pACB;
   PDCB pDCB;
   PSCSICMD pcmd;
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h
--- v2.4.3/linux/drivers/scsi/tmscsim.h	Sun Dec 31 11:06:00 2000
+++ linux/drivers/scsi/tmscsim.h	Wed Apr 11 19:02:37 2001
@@ -10,15 +10,6 @@
 
 #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
 
diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.4.3/linux/drivers/scsi/wd7000.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/wd7000.c	Wed Apr 11 19:02:37 2001
@@ -863,7 +863,7 @@
 	 */
 	if (freescbs < needed) {
 	    busy = 0;
-	    panic ("wd7000: can't get enough free SCBs.\n");
+	    printk (KERN_ERR "wd7000: can't get enough free SCBs.\n");
 	    restore_flags (flags);
 	    return (NULL);
 	}
@@ -1593,7 +1593,7 @@
 	printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
 #endif
 
-	if (!check_region (iobase, 4)) {
+	if (request_region (iobase, 4, "wd7000")) {
 
 #ifdef WD7000_DEBUG
 	    printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
@@ -1609,12 +1609,12 @@
 #ifdef WD7000_DEBUG
 	    {
 		printk ("failed!\n");
-		continue;
+		goto err_release;
 	    }
-	    else
+	    else 
 		printk ("ok!\n");
 #else
-		continue;
+	    goto err_release;
 #endif
 
 	    if (inb (iobase + ASC_INTR_STAT) == 1) {
@@ -1627,7 +1627,8 @@
 		 */
 		sh = scsi_register (tpnt, sizeof (Adapter));
 		if(sh==NULL)
-			continue;
+		    goto err_release;
+
 		host = (Adapter *) sh->hostdata;
 
 #ifdef WD7000_DEBUG
@@ -1650,11 +1651,8 @@
 			host->iobase, host->irq, host->dma);
 #endif
 
-		if (!wd7000_init (host)) {	/* Initialization failed */
-		    scsi_unregister (sh);
-
-		    continue;
-		}
+		if (!wd7000_init (host)) 	/* Initialization failed */
+		    goto err_unregister;
 
 		/*
 		 *  OK from here - we'll use this adapter/configuration.
@@ -1662,11 +1660,6 @@
 		wd7000_revision (host);		/* important for scatter/gather */
 
 		/*
-		 * Register our ports.
-		 */
-		request_region (host->iobase, 4, "wd7000");
-
-		/*
 		 *  For boards before rev 6.0, scatter/gather isn't supported.
 		 */
 		if (host->rev1 < 6)
@@ -1690,6 +1683,13 @@
 	else
 	    printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
 #endif
+
+	continue;
+
+    err_unregister:
+	scsi_unregister (sh);
+    err_release:
+	release_region(iobase, 4);
 
     }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/sgi/Makefile linux/drivers/sgi/Makefile
--- v2.4.3/linux/drivers/sgi/Makefile	Sun Aug  6 11:23:40 2000
+++ linux/drivers/sgi/Makefile	Fri Apr 13 20:26:07 2001
@@ -7,17 +7,13 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-SUB_DIRS     :=
-MOD_SUB_DIRS := $(SUB_DIRS) char
-ALL_SUB_DIRS := $(SUB_DIRS) char
-
-
-L_OBJS   := 
 L_TARGET := sgi.a
 
+#
 # Character and Audio devices for SGI machines.
 #
-SUB_DIRS += char
-L_OBJS += char/sgichar.o
+subdir-y	+= char
+subdir-m	+= char
+obj-y		+= char/sgichar.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/drivers/sgi/char/Makefile linux/drivers/sgi/char/Makefile
--- v2.4.3/linux/drivers/sgi/char/Makefile	Fri Jun 25 17:39:34 1999
+++ linux/drivers/sgi/char/Makefile	Fri Apr 13 20:26:07 2001
@@ -8,25 +8,12 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := sgichar.o
-OX_OBJS := newport.o
-O_OBJS   := sgicons.o \
-	usema.o shmiq.o streamable.o
 
-ifeq ($(CONFIG_SGI_SERIAL),y)
-  O_OBJS += sgiserial.o
-endif
+export-objs	:= newport.o shmiq.o sgicons.o usema.o
+obj-y		:= newport.o shmiq.o sgicons.o usema.o streamable.o
 
-ifeq ($(CONFIG_SGI_DS1286),y)
-  O_OBJS += ds1286.o
-endif
-
-ifeq ($(CONFIG_SGI_NEWPORT_GFX),y)
-  O_OBJS +=  graphics.o rrm.o
-else 
-ifeq ($(CONFIG_SGI_NEWPORT_GFX),m)
-  OX_OBJS  +=  graphics_syms.o
-  MX_OBJS +=  graphics.o rrm.o
-endif
-endif
+obj-$(CONFIG_SGI_SERIAL)	+= sgiserial.o
+obj-$(CONFIG_SGI_DS1286)	+= ds1286.o
+obj-$(CONFIG_SGI_NEWPORT_GFX)	+= graphics.o rrm.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.4.3/linux/drivers/sound/Config.in	Tue Mar  6 19:28:32 2001
+++ linux/drivers/sound/Config.in	Wed Apr 18 11:49:11 2001
@@ -14,11 +14,11 @@
         bool '    Separate rear out jack' CONFIG_SOUND_CMPCI_REAR
     fi
 fi
-dep_tristate '  Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
+dep_tristate '  Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
 dep_tristate '  Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
-dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
-dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
+dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI
+dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
 dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
 dep_tristate '  ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
@@ -93,7 +93,7 @@
    fi
    dep_tristate '    Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
    dep_tristate '    Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
-   dep_tristate '    ACI mixer (miroPCM12)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS
+   dep_tristate '    ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS
    dep_tristate '    Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS
    dep_tristate '    Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS
    dep_tristate '    Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
@@ -171,8 +171,10 @@
    fi
 	 
    if [ "$CONFIG_ARM" = "y" ]; then
-      dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
-      dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS
+      if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
+         dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
+      fi
+      dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
    fi
 
 fi
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.4.3/linux/drivers/sound/Makefile	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/Makefile	Fri Apr 13 20:26:07 2001
@@ -10,7 +10,7 @@
 export-objs	:=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
 		    msnd.o opl3.o sb_common.o sequencer_syms.o \
 		    sound_core.o sound_syms.o uart401.o	\
-		    nm256_audio.o ac97.o ac97_codec.o
+		    nm256_audio.o ac97.o ac97_codec.o aci.o
 
 # Each configuration option enables a list of files.
 
@@ -29,7 +29,7 @@
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o uart401.o
 obj-$(CONFIG_SOUND_OPL3SA2)	+= opl3sa2.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_MSS)		+= ad1848.o
-obj-$(CONFIG_SOUND_PAS)		+= pas2.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_PAS)		+= pas2.o sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SB)		+= sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_WAVEFRONT)	+= wavefront.o
 obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- v2.4.3/linux/drivers/sound/ac97_codec.c	Thu Dec  7 00:21:37 2000
+++ linux/drivers/sound/ac97_codec.c	Thu Apr 19 22:58:20 2001
@@ -20,6 +20,16 @@
  *	along with this program; if not, write to the Free Software
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ **************************************************************************
+ *
+ * The Intel Audio Codec '97 specification is available at the Intel
+ * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/
+ *
+ * The specification itself is currently available at:
+ * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf
+ *
+ **************************************************************************
+ *
  * History
  * v0.4 Mar 15 2000 Ollie Lho
  *	dual codecs support verified with 4 channels output
@@ -49,41 +59,61 @@
 
 static int ac97_init_mixer(struct ac97_codec *codec);
 
-static int sigmatel_init(struct ac97_codec *codec);
+static int wolfson_init(struct ac97_codec * codec);
+static int tritech_init(struct ac97_codec * codec);
+static int tritech_maestro_init(struct ac97_codec * codec);
+static int sigmatel_9708_init(struct ac97_codec *codec);
+static int sigmatel_9721_init(struct ac97_codec *codec);
+static int sigmatel_9744_init(struct ac97_codec *codec);
 static int enable_eapd(struct ac97_codec *codec);
 
-#define arraysize(x)   (sizeof(x)/sizeof((x)[0]))
-
-static struct {
-	unsigned int id;
+/* sorted by vendor/device id */
+static const struct {
+	u32 id;
 	char *name;
 	int  (*init)  (struct ac97_codec *codec);
 } ac97_codec_ids[] = {
-	{0x414B4D00, "Asahi Kasei AK4540 rev 0", NULL},
-	{0x414B4D01, "Asahi Kasei AK4540 rev 1", NULL},
-	{0x41445340, "Analog Devices AD1881"  , NULL},
-	{0x41445360, "Analog Devices AD1885"  , enable_eapd},
-	{0x43525900, "Cirrus Logic CS4297"    , NULL},
-	{0x43525903, "Cirrus Logic CS4297"  ,	NULL},
-	{0x43525913, "Cirrus Logic CS4297A"   , NULL},
-	{0x43525923, "Cirrus Logic CS4298"    , NULL},
-	{0x4352592B, "Cirrus Logic CS4294"    , NULL},
-	{0x43525931, "Cirrus Logic CS4299"    , NULL},
-	{0x43525934, "Cirrus Logic CS4299"    , NULL},
-	{0x4e534331, "National Semiconductor LM4549" ,	NULL},
-	{0x53494c22, "Silicon Laboratory Si3036"     ,	NULL},
-	{0x53494c23, "Silicon Laboratory Si3038"     ,  NULL},
-	{0x83847600, "SigmaTel STAC????"      , NULL},
+	{0x41445303, "Analog Devices AD1819",	NULL},
+	{0x41445340, "Analog Devices AD1881",	NULL},
+	{0x41445348, "Analog Devices AD1881A",	NULL},
+	{0x41445460, "Analog Devices AD1885",	enable_eapd},
+	{0x414B4D00, "Asahi Kasei AK4540",	NULL},
+	{0x414B4D01, "Asahi Kasei AK4542",	NULL},
+	{0x414B4D02, "Asahi Kasei AK4543",	NULL},
+	{0x414C4710, "ALC200/200P",		NULL},
+	{0x43525900, "Cirrus Logic CS4297",	enable_eapd},
+	{0x43525903, "Cirrus Logic CS4297",	enable_eapd},
+	{0x43525913, "Cirrus Logic CS4297A rev A", enable_eapd},
+	{0x43525914, "Cirrus Logic CS4297A rev B", NULL},
+	{0x43525923, "Cirrus Logic CS4298",	NULL},
+	{0x4352592B, "Cirrus Logic CS4294",	NULL},
+	{0x4352592D, "Cirrus Logic CS4294",	NULL},
+	{0x43525931, "Cirrus Logic CS4299 rev A", NULL},
+	{0x43525933, "Cirrus Logic CS4299 rev C", NULL},
+	{0x43525934, "Cirrus Logic CS4299 rev D", NULL},
+	{0x45838308, "ESS Allegro ES1988",	NULL},
+	{0x49434511, "ICE1232",			NULL}, /* I hope --jk */
+	{0x4e534331, "National Semiconductor LM4549", NULL},
+	{0x53494c22, "Silicon Laboratory Si3036", NULL},
+	{0x53494c23, "Silicon Laboratory Si3038", NULL},
+	{0x545200FF, "TriTech TR?????",		tritech_maestro_init},
+	{0x54524102, "TriTech TR28022",		NULL},
+	{0x54524103, "TriTech TR28023",		NULL},
+	{0x54524106, "TriTech TR28026",		NULL},
+	{0x54524108, "TriTech TR28028",		tritech_init},
+	{0x54524123, "TriTech TR?????",		NULL},
+	{0x574D4C00, "Wolfson WM9704",		wolfson_init},
+	{0x574D4C03, "Wolfson WM9703/9704",	wolfson_init},
+	{0x574D4C04, "Wolfson WM9704 (quad)",	wolfson_init},
+	{0x83847600, "SigmaTel STAC????",	NULL},
 	{0x83847604, "SigmaTel STAC9701/3/4/5", NULL},
-	{0x83847605, "SigmaTel STAC9704"      , NULL},
-	{0x83847608, "SigmaTel STAC9708"      , NULL},
-	{0x83847609, "SigmaTel STAC9721/23"   , sigmatel_init},
-	{0x54524103, "TriTech TR?????"	      , NULL},
-	{0x54524106, "TriTech TR28026"        , NULL},
-	{0x54524108, "TriTech TR28028"        , NULL},
-	{0x54524123, "TriTech TR?????"	      , NULL},	
-	{0x574D4C00, "Wolfson WM9704"         , NULL},
-	{0x00000000, NULL, NULL}
+	{0x83847605, "SigmaTel STAC9704",	NULL},
+	{0x83847608, "SigmaTel STAC9708",	sigmatel_9708_init},
+	{0x83847609, "SigmaTel STAC9721/23",	sigmatel_9721_init},
+	{0x83847644, "SigmaTel STAC9744/45",	sigmatel_9744_init},
+	{0x83847656, "SigmaTel STAC9756/57",	sigmatel_9744_init},
+	{0x83847684, "SigmaTel STAC9783/84?",	NULL},
+	{0,}
 };
 
 static const char *ac97_stereo_enhancements[] =
@@ -175,10 +205,10 @@
 	AC97_REC_LINE,
 	AC97_REC_STEREO, /* combination of all enabled outputs..  */
 	AC97_REC_MONO,	      /*.. or the mono equivalent */
-	AC97_REC_PHONE	      
+	AC97_REC_PHONE
 };
 
-static unsigned int ac97_rm2oss[] = {
+static const unsigned int ac97_rm2oss[] = {
 	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC,
 	[AC97_REC_CD] 	 = SOUND_MIXER_CD,
 	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
@@ -189,7 +219,7 @@
 };
 
 /* indexed by bit position */
-static unsigned int ac97_oss_rm[] = {
+static const unsigned int ac97_oss_rm[] = {
 	[SOUND_MIXER_MIC] 	= AC97_REC_MIC,
 	[SOUND_MIXER_CD] 	= AC97_REC_CD,
 	[SOUND_MIXER_VIDEO] 	= AC97_REC_VIDEO,
@@ -431,13 +461,13 @@
 		return 0;
 	}
 
-	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
 		return -EINVAL;
 
 	if (cmd == OSS_GETVERSION)
 		return put_user(SOUND_VERSION, (int *)arg);
 
-	if (_IOC_DIR(cmd) == _IOC_READ) {
+	if (_SIOC_DIR(cmd) == _SIOC_READ) {
 		switch (_IOC_NR(cmd)) {
 		case SOUND_MIXER_RECSRC: /* give them the current record source */
 			if (!codec->recmask_io) {
@@ -477,7 +507,7 @@
 		return put_user(val, (int *)arg);
 	}
 
-	if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+	if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
 		codec->modcnt++;
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
@@ -640,7 +670,7 @@
 
 	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
 	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-	for (i = 0; i < arraysize(ac97_codec_ids); i++) {
+	for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
 		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
 			codec->type = ac97_codec_ids[i].id;
 			codec->name = ac97_codec_ids[i].name;
@@ -691,7 +721,7 @@
 		codec->codec_init(codec);
 	}
 
-	/* initilize mixer channel volumes */
+	/* initialize mixer channel volumes */
 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
 		struct mixer_defaults *md = &mixer_defaults[i];
 		if (md->mixer == -1) 
@@ -704,40 +734,151 @@
 	return 1;
 }
 
-static int sigmatel_init(struct ac97_codec * codec)
+#define AC97_SIGMATEL_ANALOG    0x6c	/* Analog Special */
+#define AC97_SIGMATEL_DAC2INVERT 0x6e
+#define AC97_SIGMATEL_BIAS1     0x70
+#define AC97_SIGMATEL_BIAS2     0x72
+#define AC97_SIGMATEL_MULTICHN  0x74	/* Multi-Channel programming */
+#define AC97_SIGMATEL_CIC1      0x76
+#define AC97_SIGMATEL_CIC2      0x78
+
+
+static int sigmatel_9708_init(struct ac97_codec * codec)
+{
+	u16 codec72, codec6c;
+
+	codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
+	codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
+
+	if ((codec72==0) && (codec6c==0)) {
+		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
+		codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
+		codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
+	} else if ((codec72==0x8000) && (codec6c==0)) {
+		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
+		codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
+	} else if ((codec72==0x8000) && (codec6c==0x0080)) {
+		/* nothing */
+	}
+	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
+	return 0;
+}
+
+
+static int sigmatel_9721_init(struct ac97_codec * codec)
 {
 	/* Only set up secondary codec */
 	if (codec->id == 0)
-		return 1;
+		return 0;
 
 	codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
 
 	/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
 	   sloc 3,4 = 0x01, slot 7,8 = 0x00, */
-	codec->codec_write(codec, 0x74, 0x00);
+	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
 
 	/* we don't have the crystal when we are on an AMR card, so use
 	   BIT_CLK as our clock source. Write the magic word ABBA and read
 	   back to enable register 0x78 */
-	codec->codec_write(codec, 0x76, 0xabba);
-	codec->codec_read(codec, 0x76);
+	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+	codec->codec_read(codec, AC97_SIGMATEL_CIC1);
 
 	/* sync all the clocks*/
-	codec->codec_write(codec, 0x78, 0x3802);
+	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
 
-	return 1;
+	return 0;
+}
+
+
+static int sigmatel_9744_init(struct ac97_codec * codec)
+{
+	// patch for SigmaTel
+	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
+	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
+	codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
+	codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
+	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
+	return 0;
+}
+
+
+static int wolfson_init(struct ac97_codec * codec)
+{
+	codec->codec_write(codec, 0x72, 0x0808);
+	codec->codec_write(codec, 0x74, 0x0808);
+
+	// patch for DVD noise
+	codec->codec_write(codec, 0x5a, 0x0200);
+
+	// init vol as PCM vol
+	codec->codec_write(codec, 0x70,
+		codec->codec_read(codec, AC97_PCMOUT_VOL));
+
+	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
+	return 0;
+}
+
+
+static int tritech_init(struct ac97_codec * codec)
+{
+	codec->codec_write(codec, 0x26, 0x0300);
+	codec->codec_write(codec, 0x26, 0x0000);
+	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
+	codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
+	return 0;
+}
+
+
+/* copied from drivers/sound/maestro.c */
+static int tritech_maestro_init(struct ac97_codec * codec)
+{
+	/* no idea what this does */
+	codec->codec_write(codec, 0x2A, 0x0001);
+	codec->codec_write(codec, 0x2C, 0x0000);
+	codec->codec_write(codec, 0x2C, 0XFFFF);
+	return 0;
 }
 
+
 /*
- *	Bring up an AD1885
+ *	External AMP management for EAPD using codecs
+ *	(CS4279A, AD1885, ...)
  */
- 
+
 static int enable_eapd(struct ac97_codec * codec)
 {
 	codec->codec_write(codec, AC97_POWER_CONTROL,
 		codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
 	return 0;
 }
+
+
+/* copied from drivers/sound/maestro.c */
+#if 0  /* there has been 1 person on the planet with a pt101 that we
+        know of.  If they care, they can put this back in :) */
+static int pt101_init(struct ac97_codec * codec)
+{
+	printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
+	/* who knows.. */
+	codec->codec_write(codec, 0x2A, 0x0001);
+	codec->codec_write(codec, 0x2C, 0x0000);
+	codec->codec_write(codec, 0x2C, 0xFFFF);
+	codec->codec_write(codec, 0x10, 0x9F1F);
+	codec->codec_write(codec, 0x12, 0x0808);
+	codec->codec_write(codec, 0x14, 0x9F1F);
+	codec->codec_write(codec, 0x16, 0x9F1F);
+	codec->codec_write(codec, 0x18, 0x0404);
+	codec->codec_write(codec, 0x1A, 0x0000);
+	codec->codec_write(codec, 0x1C, 0x0000);
+	codec->codec_write(codec, 0x02, 0x0404);
+	codec->codec_write(codec, 0x04, 0x0808);
+	codec->codec_write(codec, 0x0C, 0x801F);
+	codec->codec_write(codec, 0x0E, 0x801F);
+	return 0;
+}
+#endif
 	
 
 EXPORT_SYMBOL(ac97_read_proc);
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/aci.c linux/drivers/sound/aci.c
--- v2.4.3/linux/drivers/sound/aci.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/sound/aci.c	Fri Apr 13 20:26:07 2001
@@ -10,15 +10,17 @@
  * The main function of the ACI is to control the mixer and to get a
  * product identification. On the PCM20, ACI also controls the radio
  * tuner on this card, this is supported in the Video for Linux 
- * radio-miropcm20 driver.
- * 
- * This Voxware ACI driver currently only supports the ACI functions
- * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards 
- * with additional ACI functions can easily be added later.
- *
- * / NOTE / When compiling as a module, make sure to load the module 
- * after loading the mad16 module. The initialisation code expects the
- * MAD16 default mixer to be already available.
+ * miropcm20 driver.
+ * -
+ * This is a fullfeatured implementation. Unsupported features
+ * are bugs... (:
+ *
+ * It is not longer necessary to load the mad16 module first. The
+ * user is currently responsible to set the mad16 mixer correctly.
+ *
+ * To toggle the solo mode for full duplex operation just use the OSS
+ * record switch for the pcm ('wave') controller.           Robert
+ * -
  *
  * Revision history:
  *
@@ -34,72 +36,78 @@
  *   1998-08-18  Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
  *	  Small modification to export ACI functions and 
  *	  complete modularisation.
+ *   2000-06-20  Robert Siemer <Robert.Siemer@gmx.de>
+ *        Don't initialize the CS4231A mixer anymore, so the code is
+ *        working again, and other small changes to fit in todays
+ *        kernels.
+ *   2000-08-26  Robert Siemer
+ *        Clean up and rewrite for 2.4.x. Maybe it's SMP safe now... (:
+ *        ioctl bugfix, and integration of solo-mode into OSS-API,
+ *        added (OSS-limited) equalizer support, return value bugfix,
+ *        changed param aci_reset to reset, new params: ide, wss.
  */
 
-/*
- * Some driver specific information and features:
- *
- * This mixer driver identifies itself to applications as "ACI" in
- * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
- *
- * Proprietary mixer features that go beyond the standard OSS mixer
- * interface are:
- * 
- * Full duplex solo configuration:
- *
- *   int solo_mode;
- *   ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
- *
- *   solo_mode = 0: deactivate solo mode (default)
- *   solo_mode > 0: activate solo mode
- *                  With activated solo mode, the PCM input can not any
- *                  longer hear the signals produced by the PCM output.
- *                  Activating solo mode is important in duplex mode in order
- *                  to avoid feedback distortions.
- *   solo_mode < 0: do not change solo mode (just retrieve the status)
- *
- *   When the ioctl() returns 0, solo_mode contains the previous
- *   status (0 = deactivated, 1 = activated). If solo mode is not
- *   implemented on this card, ioctl() returns -1 and sets errno to
- *   EINVAL.
- *
- */
-
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h> 
-
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
 #include "sound_config.h"
 
-#undef  DEBUG		/* if defined, produce a verbose report via syslog */
+int aci_port;	/* as determined by bit 4 in the OPTi 929 MC4 register */
+int aci_idcode[2];	/* manufacturer and product ID */
+int aci_version;	/* ACI firmware version	*/
+
+EXPORT_SYMBOL(aci_port);
+EXPORT_SYMBOL(aci_idcode);
+EXPORT_SYMBOL(aci_version);
 
-int aci_port = 0x354;	/* as determined by bit 4 in the OPTi 929 MC4 register */
-unsigned char aci_idcode[2] = {0, 0};	/* manufacturer and product ID */
-unsigned char aci_version = 0;		/* ACI firmware version	*/
-int aci_solo;		/* status bit of the card that can't be		*
+#include "aci.h"
+
+
+static int aci_solo=0;	/* status bit of the card that can't be		*
+			 * checked with ACI versions prior to 0xb0	*/
+static int aci_amp=0;   /* status bit for power-amp/line-out level
+			   but I have no docs about what is what... */
+static int aci_micpreamp=3; /* microphone preamp-level that can't be    *
 			 * checked with ACI versions prior to 0xb0	*/
 
-static int aci_present = 0;
+static int mixer_device;
+static struct semaphore aci_sem;
 
-#ifdef MODULE                  /* Whether the aci mixer is to be reset.    */
-int aci_reset = 0;             /* Default: don't reset if the driver is a  */
-MODULE_PARM(aci_reset,"i");
-#else                          /* module; use "insmod aci.o aci_reset=1" */
-int aci_reset = 1;             /* to override.                             */
+#ifdef MODULE
+static int reset = 0;
+MODULE_PARM(reset,"i");
+MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer.");
+#else
+static int reset = 1;
 #endif
 
+static int ide=-1;
+MODULE_PARM(ide,"i");
+MODULE_PARM_DESC(ide,"1 enable, 0 disable ide-port - untested"
+		 " default: do nothing");
+static int wss=-1;
+MODULE_PARM(wss,"i");
+MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested"
+		 " default: do nothing; for PCM1-pro only");
+
+static void print_bits(unsigned char c)
+{
+	int j;
+	printk(KERN_DEBUG "aci: ");
+
+	for (j=7; j>=0; j--) {
+		printk(KERN_DEBUG "%d", (c >> j) & 0x1);
+	}
 
-#define COMMAND_REGISTER    (aci_port)
-#define STATUS_REGISTER     (aci_port + 1)
-#define BUSY_REGISTER       (aci_port + 2)
+	printk(KERN_DEBUG "\n");
+}
 
 /*
- * Wait until the ACI microcontroller has set the READYFLAG in the
- * Busy/IRQ Source Register to 0. This is required to avoid
- * overrunning the sound card microcontroller. We do a busy wait here,
- * because the microcontroller is not supposed to signal a busy
- * condition for more than a few clock cycles. In case of a time-out,
- * this function returns -1.
- *
  * This busy wait code normally requires less than 15 loops and
  * practically always less than 100 loops on my i486/DX2 66 MHz.
  *
@@ -107,459 +115,476 @@
  * function can take a VERY long time, because the PCM12 does some kind
  * of fade-in effect. For this reason, access to the MUTE function has
  * not been implemented at all.
+ *
+ * - The OSS interface has no mute option. It takes about 3 seconds to
+ * fade-in on my PCM20. busy_wait() handles it great now...     Robert
  */
 
 static int busy_wait(void)
 {
+	#define MINTIME 500
 	long timeout;
+	unsigned char byte;
 
-	for (timeout = 0; timeout < 10000000L; timeout++)
-		if ((inb_p(BUSY_REGISTER) & 1) == 0)
-			return 0;
-
-#ifdef DEBUG
-	printk("ACI: READYFLAG timed out.\n");
-#endif
-
-	return -1;
-}
-
-
-/*
- * Read the GENERAL STATUS register.
- */
-
-static int read_general_status(void)
-{
-	unsigned long flags;
-	int status;
-
-	save_flags(flags);
-	cli();
-	
-	if (busy_wait()) {
-		restore_flags(flags);
-		return -1;
+	for (timeout = 1; timeout <= MINTIME+30; timeout++) {
+		if (((byte=inb(BUSY_REGISTER)) & 1) == 0) {
+			if (timeout >= MINTIME)
+				printk(KERN_DEBUG "aci: Got READYFLAG in round %ld.\n", timeout-MINTIME);
+			return byte;
+		}
+		if (timeout >= MINTIME) {
+			long out=10*HZ;
+			switch (timeout-MINTIME) {
+			case 0 ... 9:
+				out /= 10;
+			case 10 ... 19:
+				out /= 10;
+			case 20 ... 30:
+				out /= 10;
+			default:
+				current->state=TASK_UNINTERRUPTIBLE;
+				schedule_timeout(out);
+				break;
+			}
+		}
 	}
-	
-	status = (unsigned) inb_p(STATUS_REGISTER);
-	restore_flags(flags);
-	return status;
+	printk(KERN_WARNING "aci: busy_wait() time out.\n");
+	return -EBUSY;
 }
 
+/* The four ACI command types are fucked up. [-:
+ * implied is: 1w      - special case for INIT
+ * write   is: 2w1r
+ * read    is: x(1w1r) where x is 1 or 2 (1 CHECK_SIG, 1 CHECK_STER,
+ *                                        1 VERSION, 2 IDCODE)
+ *  the command is only in the first write, rest is protocol overhead
+ *
+ * indexed is technically a write and used for STATUS
+ * and the special case for TUNE is: 3w1r
+ * 
+ * Here the new general sheme: TUNE --> aci_rw_cmd(x,  y,  z)
+ *                indexed and write --> aci_rw_cmd(x,  y, -1)
+ *           implied and read (x=1) --> aci_rw_cmd(x, -1, -1)
+ *
+ * Read (x>=2) is not implemented (only used during initialization).
+ * Use aci_idcode[2] and aci_version...                    Robert
+ */
 
-/*
- * The four ACI command types (implied, write, read and indexed) can
- * be sent to the microcontroller using the following four functions.
- * If a problem occurred, they return -1.
+/* Some notes for error detection: theoretically it is possible.
+ * But it doubles the I/O-traffic from ww(r) to wwwrw(r) in the normal 
+ * case and doesn't seem to be designed for that...        Robert
  */
 
-int aci_implied_cmd(unsigned char opcode)
+static inline int aci_rawwrite(unsigned char byte)
 {
-	unsigned long flags;
-
-#ifdef DEBUG
-	printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
+	if (busy_wait() >= 0) {
+#if DEBUG
+		printk(KERN_DEBUG "aci_rawwrite(%d)\n", byte);
 #endif
-
-	save_flags(flags);
-	cli();
-  
-  	if (read_general_status() < 0 || busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
-	
-	outb_p(opcode, COMMAND_REGISTER);
-
-	restore_flags(flags);
-	return 0;
+		outb(byte, COMMAND_REGISTER);
+		return 0;
+	} else
+		return -EBUSY;
 }
 
-
-int aci_write_cmd(unsigned char opcode, unsigned char parameter)
+static inline int aci_rawread(void)
 {
-	unsigned long flags;
-	int status;
+	unsigned char byte;
 
-#ifdef DEBUG
-	printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
+	if (busy_wait() >= 0) {
+		byte=inb(STATUS_REGISTER);
+#if DEBUG
+		printk(KERN_DEBUG "%d = aci_rawread()\n", byte);
 #endif
+		return byte;
+	} else
+		return -EBUSY;
+}
 
-	save_flags(flags);
-	cli();
-	
-	if (read_general_status() < 0 || busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
 
-	outb_p(opcode, COMMAND_REGISTER);
-	if (busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
+int aci_rw_cmd(int write1, int write2, int write3)
+{
+	int write[] = {write1, write2, write3};
+	int read, i;
 
-	outb_p(parameter, COMMAND_REGISTER);
+	if (down_interruptible(&aci_sem))
+		return -EINTR;
 
-	if ((status = read_general_status()) < 0) {
-		restore_flags(flags);
-		return -1;
+	for (i=0; i<3; i++) {
+		if (write[i]< 0 || write[i] > 255)
+			break;
+		else
+			if (aci_rawwrite(write[i])<0) {
+				up(&aci_sem);
+				return -EBUSY;
+			}
 	}
-
-	/* polarity of the INVALID flag depends on ACI version */
-	if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
-	  (aci_version >= 0xb0 && (status & 0x40) == 0)) {
-	  	restore_flags(flags);
-		printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
-			opcode, parameter);
-		return -1;
+	
+	if ((read=aci_rawread())<0) {
+		up(&aci_sem);
+		return -EBUSY;
 	}
 
-	restore_flags(flags);
-	return 0;
+	up(&aci_sem);
+	return read;
 }
 
-/*
- * This write command send 2 parameters instead of one.
- * Only used in PCM20 radio frequency tuning control
- */
+EXPORT_SYMBOL(aci_rw_cmd);
 
-int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
+static int setvolume(caddr_t arg, 
+		     unsigned char left_index, unsigned char right_index)
 {
-	unsigned long flags;
-	int status;
+	int vol, ret, uservol, buf;
 
-#ifdef DEBUG
-	printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
-#endif
-
-	save_flags(flags);
-	cli();
-	
-	if (read_general_status() < 0 || busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
+	__get_user(uservol, (int *)arg);
 
-	outb_p(opcode, COMMAND_REGISTER);
-	if (busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
+	/* left channel */
+	vol = uservol & 0xff;
+	if (vol > 100)
+		vol = 100;
+	vol = SCALE(100, 0x20, vol);
+	if ((buf=aci_write_cmd(left_index, 0x20 - vol))<0)
+		return buf;
+	ret = SCALE(0x20, 100, vol);
 
-	outb_p(parameter, COMMAND_REGISTER);
-	if (busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
-	
-	outb_p(parameter2, COMMAND_REGISTER);
-	
-	if ((status = read_general_status()) < 0) {
-		restore_flags(flags);
-		return -1;
-	}
-	
-	/* polarity of the INVALID flag depends on ACI version */
-	if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
-	  (aci_version >= 0xb0 && (status & 0x40) == 0)) {
-		restore_flags(flags);
-#if 0	/* Frequency tuning works, but the INVALID flag is set ??? */
-		printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
-			opcode, parameter, parameter2);
-#endif
-		return -1;
-  	}
-	
-	restore_flags(flags);
-	return 0;
-}
 
-int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
-{
-	unsigned long flags;
-	int i = 0;
-	
-	save_flags(flags);
-	cli();
+	/* right channel */
+	vol = (uservol >> 8) & 0xff;
+	if (vol > 100)
+		vol = 100;
+	vol = SCALE(100, 0x20, vol);
+	if ((buf=aci_write_cmd(right_index, 0x20 - vol))<0)
+		return buf;
+	ret |= SCALE(0x20, 100, vol) << 8;
  
- 	if (read_general_status() < 0) {
-		restore_flags(flags);
-		return -1;
-	}
-	while (i < length) {
-		if (busy_wait()) {
-			restore_flags(flags);
-			return -1;
-		}
-			
-		outb_p(opcode, COMMAND_REGISTER);
-		if (busy_wait()) {
-			restore_flags(flags);
-			return -1;
-		}
-			
-		parameter[i++] = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
-		if (i == 1)
-			printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n",
-				opcode, length, parameter[i-1]);
-		else
-			printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
-#endif
-	}
+	__put_user(ret, (int *)arg);
 
-	restore_flags(flags);
 	return 0;
 }
 
-
-int aci_indexed_cmd(unsigned char opcode, unsigned char index,
-		       unsigned char *parameter)
+static int getvolume(caddr_t arg,
+		     unsigned char left_index, unsigned char right_index)
 {
-	unsigned long flags;
+	int vol;
+	int buf;
 
-	save_flags(flags);
-	cli();
-  
-	if (read_general_status() < 0 || busy_wait()) {
-	  	restore_flags(flags);
-		return -1;
-	}
-	
-	outb_p(opcode, COMMAND_REGISTER);
-	if (busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
-	
-	outb_p(index, COMMAND_REGISTER);
-	if (busy_wait()) {
-		restore_flags(flags);
-		return -1;
-	}
+	/* left channel */
+	if ((buf=aci_indexed_cmd(0xf0, left_index))<0)
+		return buf;
+	vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
 	
-	*parameter = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
-	printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
-		*parameter);
-#endif
+	/* right channel */
+	if ((buf=aci_indexed_cmd(0xf0, right_index))<0)
+		return buf;
+	vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+
+	__put_user(vol, (int *)arg);
 
-	restore_flags(flags);
 	return 0;
 }
 
 
-/*
- * The following macro SCALE can be used to scale one integer volume
- * value into another one using only integer arithmetic. If the input
- * value x is in the range 0 <= x <= xmax, then the result will be in
- * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
- *
- * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
- * following nice properties:
- *
- * - SCALE(xmax,ymax,xmax) = ymax
- * - SCALE(xmax,ymax,0) = 0
- * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
- *
- * In addition, the rounding error is minimal and nicely distributed.
- * The proofs are left as an exercise to the reader.
+/* The equalizer is somewhat strange on the ACI. From -12dB to +12dB
+ * write:  0xff..down.to..0x80==0x00..up.to..0x7f
  */
 
-#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+static inline unsigned int eq_oss2aci(unsigned int vol)
+{
+	int boost=0;
+	unsigned int ret;
+
+	if (vol > 100)
+		vol = 100;
+	if (vol > 50) {
+		vol -= 51;
+		boost=1;
+	}
+	if (boost)
+		ret=SCALE(49, 0x7e, vol)+1;
+	else
+		ret=0xff - SCALE(50, 0x7f, vol);
+	return ret;
+}
+
+static inline unsigned int eq_aci2oss(unsigned int vol)
+{
+	if (vol < 0x80)
+		return SCALE(0x7f, 50, vol) + 50;
+	else
+		return SCALE(0x7f, 50, 0xff-vol);
+}
 
 
-static int getvolume(caddr_t arg,
-		     unsigned char left_index, unsigned char right_index)
+static int setequalizer(caddr_t arg, 
+			unsigned char left_index, unsigned char right_index)
 {
-	int vol;
-	unsigned char buf;
+	int buf;
+	unsigned int vol;
+
+	__get_user(vol, (int *)arg);
 
 	/* left channel */
-	if (aci_indexed_cmd(0xf0, left_index, &buf))
-		return -EIO;
-	vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
-	
+	if ((buf=aci_write_cmd(left_index, eq_oss2aci(vol & 0xff)))<0)
+		return buf;
+
 	/* right channel */
-	if (aci_indexed_cmd(0xf0, right_index, &buf))
-		return -EIO;
-	vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+	if ((buf=aci_write_cmd(right_index, eq_oss2aci((vol>>8) & 0xff)))<0)
+		return buf;
 
-	return (*(int *) arg = vol);
+	/* the ACI equalizer is more precise */
+	return 0;
 }
 
-
-static int setvolume(caddr_t arg, 
-		     unsigned char left_index, unsigned char right_index)
+static int getequalizer(caddr_t arg,
+			unsigned char left_index, unsigned char right_index)
 {
-	int vol, ret;
+	int buf;
+	unsigned int vol;
 
 	/* left channel */
-	vol = *(int *)arg & 0xff;
-	if (vol > 100)
-		vol = 100;
-	vol = SCALE(100, 0x20, vol);
-	if (aci_write_cmd(left_index, 0x20 - vol))
-		return -EIO;
-	ret = SCALE(0x20, 100, vol);
+	if ((buf=aci_indexed_cmd(0xf0, left_index))<0)
+		return buf;
+	vol = eq_aci2oss(buf);
+	
+	/* right channel */
+	if ((buf=aci_indexed_cmd(0xf0, right_index))<0)
+		return buf;
+	vol |= eq_aci2oss(buf) << 8;
 
+	__put_user(vol, (int *)arg);
 
-	/* right channel */
-	vol = (*(int *)arg >> 8) & 0xff;
-	if (vol > 100)
-		vol = 100;
-	vol = SCALE(100, 0x20, vol);
-	if (aci_write_cmd(right_index, 0x20 - vol))
-		return -EIO;
-	ret |= SCALE(0x20, 100, vol) << 8;
- 
-	return (*(int *) arg = ret);
+	return 0;
 }
 
-
-static int
-aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+static int aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
 {
-	int status, vol;
-	unsigned char buf;
+	int vol, buf;
 
-	/* handle solo mode control */
-	if (cmd == SOUND_MIXER_PRIVATE1) {
-		if (*(int *) arg >= 0) {
-			aci_solo = !!*(int *) arg;
-			if (aci_write_cmd(0xd2, aci_solo))
-				return -EIO;
-		} else if (aci_version >= 0xb0) {
-			if ((status = read_general_status()) < 0)
-				return -EIO;
-			return (*(int *) arg = (status & 0x20) == 0);
+	switch (cmd) {
+	case SOUND_MIXER_WRITE_VOLUME:
+		return setvolume(arg, 0x01, 0x00);
+	case SOUND_MIXER_WRITE_CD:
+		return setvolume(arg, 0x3c, 0x34);
+	case SOUND_MIXER_WRITE_MIC:
+		return setvolume(arg, 0x38, 0x30);
+	case SOUND_MIXER_WRITE_LINE:
+		return setvolume(arg, 0x39, 0x31);
+	case SOUND_MIXER_WRITE_SYNTH:
+		return setvolume(arg, 0x3b, 0x33);
+	case SOUND_MIXER_WRITE_PCM:
+		return setvolume(arg, 0x3a, 0x32);
+	case MIXER_WRITE(SOUND_MIXER_RADIO): /* fall through */
+	case SOUND_MIXER_WRITE_LINE1:  /* AUX1 or radio */
+		return setvolume(arg, 0x3d, 0x35);
+	case SOUND_MIXER_WRITE_LINE2:  /* AUX2 */
+		return setvolume(arg, 0x3e, 0x36);
+	case SOUND_MIXER_WRITE_BASS:   /* set band one and two */
+		if (aci_idcode[1]=='C') {
+			if ((buf=setequalizer(arg, 0x48, 0x40)) || 
+			    (buf=setequalizer(arg, 0x49, 0x41)));
+			return buf;
 		}
-		
-		return (*(int *) arg = aci_solo);
-	}
-	
-	if (((cmd >> 8) & 0xff) == 'M') {
-		if (cmd & SIOC_IN)
-			/* read and write */
-			switch (cmd & 0xff) {
-				case SOUND_MIXER_VOLUME:
-					return setvolume(arg, 0x01, 0x00);
-				case SOUND_MIXER_CD:
-					return setvolume(arg, 0x3c, 0x34);
-				case SOUND_MIXER_MIC:
-					return setvolume(arg, 0x38, 0x30);
-				case SOUND_MIXER_LINE:
-					return setvolume(arg, 0x39, 0x31);
-				case SOUND_MIXER_SYNTH:
-					return setvolume(arg, 0x3b, 0x33);
-				case SOUND_MIXER_PCM:
-					return setvolume(arg, 0x3a, 0x32);
-				case SOUND_MIXER_LINE1:  /* AUX1 */
-					return setvolume(arg, 0x3d, 0x35);
-				case SOUND_MIXER_LINE2:  /* AUX2 */
-					return setvolume(arg, 0x3e, 0x36);
-				case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
-					vol = *(int *) arg & 0xff;
-					if (vol > 100)
-						vol = 100;
-					vol = SCALE(100, 3, vol);
-					if (aci_write_cmd(0x03, vol))
-						return -EIO;
-					vol = SCALE(3, 100, vol);
-					return (*(int *) arg = vol | (vol << 8));
-				case SOUND_MIXER_RECSRC:
-					return (*(int *) arg = 0);
-					break;
-				default:
-					return -EINVAL;
+		break;
+	case SOUND_MIXER_WRITE_TREBLE: /* set band six and seven */
+		if (aci_idcode[1]=='C') {
+			if ((buf=setequalizer(arg, 0x4d, 0x45)) || 
+			    (buf=setequalizer(arg, 0x4e, 0x46)));
+			return buf;
+		}
+		break;
+	case SOUND_MIXER_WRITE_IGAIN:  /* MIC pre-amp */
+		if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
+			__get_user(vol, (int *)arg);
+			vol = vol & 0xff;
+			if (vol > 100)
+				vol = 100;
+			vol = SCALE(100, 3, vol);
+			if ((buf=aci_write_cmd(0x03, vol))<0)
+				return buf;
+			aci_micpreamp = vol;
+			vol = SCALE(3, 100, vol);
+			vol |= (vol << 8);
+			__put_user(vol, (int *)arg);
+			return 0;
+		}
+		break;
+	case SOUND_MIXER_WRITE_OGAIN:  /* Power-amp/line-out level */
+		if (aci_idcode[1]=='A' || aci_idcode[1]=='B') {
+			__get_user(buf, (int *)arg);
+			buf = buf & 0xff;
+			if (buf > 50)
+				vol = 1;
+			else
+				vol = 0;
+			if ((buf=aci_write_cmd(0x0f, vol))<0)
+				return buf;
+			aci_amp = vol;
+			if (aci_amp)
+				buf = (100 || 100<<8);
+			else
+				buf = 0;
+			__put_user(buf, (int *)arg);
+			return 0;
+		}
+		break;
+	case SOUND_MIXER_WRITE_RECSRC:
+		/* handle solo mode control */
+		__get_user(buf, (int *)arg);
+		/* unset solo when RECSRC for PCM is requested */
+		if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
+			vol = !(buf & SOUND_MASK_PCM);
+			if ((buf=aci_write_cmd(0xd2, vol))<0)
+				return buf;
+			aci_solo = vol;
+		}
+		buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
+		       SOUND_MASK_SYNTH| SOUND_MASK_LINE2);
+		if (aci_idcode[1] == 'C') /* PCM20 radio */
+			buf |= SOUND_MASK_RADIO;
+		else
+			buf |= SOUND_MASK_LINE1;
+		if (!aci_solo)
+			buf |= SOUND_MASK_PCM;
+		__put_user(buf, (int *)arg);
+		return 0;
+	case SOUND_MIXER_READ_DEVMASK:
+		buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD    |
+		       SOUND_MASK_MIC    | SOUND_MASK_LINE  |
+		       SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
+		       SOUND_MASK_LINE2);
+		switch (aci_idcode[1]) {
+		case 'C': /* PCM20 radio */
+			buf |= (SOUND_MASK_RADIO | SOUND_MASK_IGAIN |
+				SOUND_MASK_BASS  | SOUND_MASK_TREBLE);
+			break;
+		case 'B': /* PCM12 */
+			buf |= (SOUND_MASK_LINE1 | SOUND_MASK_IGAIN |
+				SOUND_MASK_OGAIN);
+			break;
+		case 'A': /* PCM1-pro */
+			buf |= (SOUND_MASK_LINE1 | SOUND_MASK_OGAIN);
+			break;
+		default:
+			buf |= SOUND_MASK_LINE1;
+		}
+		__put_user(buf, (int *)arg);
+		return 0;
+	case SOUND_MIXER_READ_STEREODEVS:
+		buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD    |
+		       SOUND_MASK_MIC    | SOUND_MASK_LINE  |
+		       SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
+		       SOUND_MASK_LINE2);
+		switch (aci_idcode[1]) {
+		case 'C': /* PCM20 radio */
+			buf |= (SOUND_MASK_RADIO |
+				SOUND_MASK_BASS  | SOUND_MASK_TREBLE);
+			break;
+		default:
+			buf |= SOUND_MASK_LINE1;
+		}
+		__put_user(buf, (int *)arg);
+		return 0;
+	case SOUND_MIXER_READ_RECMASK:
+		buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
+		       SOUND_MASK_SYNTH| SOUND_MASK_LINE2| SOUND_MASK_PCM);
+		if (aci_idcode[1] == 'C') /* PCM20 radio */
+			buf |= SOUND_MASK_RADIO;
+		else
+			buf |= SOUND_MASK_LINE1;
+
+		__put_user(buf, (int *)arg);
+		return 0;
+	case SOUND_MIXER_READ_RECSRC:
+		buf = (SOUND_MASK_CD    | SOUND_MASK_MIC   | SOUND_MASK_LINE  |
+		       SOUND_MASK_SYNTH | SOUND_MASK_LINE2);
+		/* do we need aci_solo or can I get it from the ACI? */
+		switch (aci_idcode[1]) {
+		case 'B': /* PCM12 */
+		case 'C': /* PCM20 radio */
+			if (aci_version >= 0xb0) {
+				if ((vol=aci_rw_cmd(0xf0, 0x00, -1))<0)
+					return vol;
+				if (vol & 0x20)
+					buf |= SOUND_MASK_PCM;
 			}
+			else
+				if (!aci_solo)
+					buf |= SOUND_MASK_PCM;
+			break;
+		default:
+			buf |= SOUND_MASK_PCM;
+		}
+		if (aci_idcode[1] == 'C') /* PCM20 radio */
+			buf |= SOUND_MASK_RADIO;
 		else
-			/* only read */
-			switch (cmd & 0xff) {
-				case SOUND_MIXER_DEVMASK:
-					return (*(int *) arg =
-				 SOUND_MASK_VOLUME | SOUND_MASK_CD    |
-				 SOUND_MASK_MIC    | SOUND_MASK_LINE  |
-				 SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
-#if 0
-				 SOUND_MASK_IGAIN  |
-#endif
-				 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
-				 	break;
-				case SOUND_MIXER_STEREODEVS:
-					return (*(int *) arg =
-				 SOUND_MASK_VOLUME | SOUND_MASK_CD   |
-				 SOUND_MASK_MIC    | SOUND_MASK_LINE |
-				 SOUND_MASK_SYNTH  | SOUND_MASK_PCM  |
-				 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
-				 	break;
-				case SOUND_MIXER_RECMASK:
-					return (*(int *) arg = 0);
-					break;
-				case SOUND_MIXER_RECSRC:
-					return (*(int *) arg = 0);
-					break;
-				case SOUND_MIXER_CAPS:
-					return (*(int *) arg = 0);
-					break;
-				case SOUND_MIXER_VOLUME:
-					return getvolume(arg, 0x04, 0x03);
-				case SOUND_MIXER_CD:
-					return getvolume(arg, 0x0a, 0x09);
-				case SOUND_MIXER_MIC:
-					return getvolume(arg, 0x06, 0x05);
-				case SOUND_MIXER_LINE:
-					return getvolume(arg, 0x08, 0x07);
-				case SOUND_MIXER_SYNTH:
-					return getvolume(arg, 0x0c, 0x0b);
-				case SOUND_MIXER_PCM:
-					return getvolume(arg, 0x0e, 0x0d);
-				case SOUND_MIXER_LINE1:  /* AUX1 */
-					return getvolume(arg, 0x11, 0x10);
-				case SOUND_MIXER_LINE2:  /* AUX2 */
-					return getvolume(arg, 0x13, 0x12);
-				case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
-					if (aci_indexed_cmd(0xf0, 0x21, &buf))
-						return -EIO;
-					vol = SCALE(3, 100, buf <= 3 ? buf : 3);
-					vol |= vol << 8;
-					return (*(int *) arg = vol);
-				default:
-					return -EINVAL;
+			buf |= SOUND_MASK_LINE1;
+
+		__put_user(buf, (int *)arg);
+		return 0;
+	case SOUND_MIXER_READ_CAPS:
+		__put_user(0, (int *)arg);
+		return 0;
+	case SOUND_MIXER_READ_VOLUME:
+		return getvolume(arg, 0x04, 0x03);
+	case SOUND_MIXER_READ_CD:
+		return getvolume(arg, 0x0a, 0x09);
+	case SOUND_MIXER_READ_MIC:
+		return getvolume(arg, 0x06, 0x05);
+	case SOUND_MIXER_READ_LINE:
+		return getvolume(arg, 0x08, 0x07);
+	case SOUND_MIXER_READ_SYNTH:
+		return getvolume(arg, 0x0c, 0x0b);
+	case SOUND_MIXER_READ_PCM:
+		return getvolume(arg, 0x0e, 0x0d);
+	case MIXER_READ(SOUND_MIXER_RADIO): /* fall through */
+	case SOUND_MIXER_READ_LINE1:  /* AUX1 */
+		return getvolume(arg, 0x11, 0x10);
+	case SOUND_MIXER_READ_LINE2:  /* AUX2 */
+		return getvolume(arg, 0x13, 0x12);
+	case SOUND_MIXER_READ_BASS:   /* get band one */
+		if (aci_idcode[1]=='C') {
+			return getequalizer(arg, 0x23, 0x22);
+		}
+		break;
+	case SOUND_MIXER_READ_TREBLE: /* get band seven */
+		if (aci_idcode[1]=='C') {
+			return getequalizer(arg, 0x2f, 0x2e);
+		}
+		break;
+	case SOUND_MIXER_READ_IGAIN:  /* MIC pre-amp */
+		if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
+			/* aci_micpreamp or ACI? */
+			if (aci_version >= 0xb0) {
+				if ((buf=aci_indexed_cmd(0xf0, 0x21))<0)
+					return buf;
 			}
+			else
+				buf=aci_micpreamp;
+			vol = SCALE(3, 100, buf <= 3 ? buf : 3);
+			vol |= vol << 8;
+			__put_user(vol, (int *)arg);
+			return 0;
+		}
+		break;
+	case SOUND_MIXER_READ_OGAIN:
+		if (aci_amp)
+			buf = (100 || 100<<8);
+		else
+			buf = 0;
+		__put_user(buf, (int *)arg);
+		return 0;
 	}
-	
 	return -EINVAL;
 }
 
-
 static struct mixer_operations aci_mixer_operations =
 {
-	owner:	THIS_MODULE,
-	id:	"ACI",
-	name:	"ACI mixer",
-	ioctl:	aci_mixer_ioctl
+	owner: THIS_MODULE,
+	id:    "ACI",
+	ioctl: aci_mixer_ioctl
 };
 
-static unsigned char
-mad_read (int port)
-{
-	outb (0xE3, 0xf8f); /* Write MAD16 password */
-	return inb (port);  /* Read from port */
-}
-
-
 /*
- * Check, whether there actually is any ACI port operational and if
- * one was found, then initialize the ACI interface, reserve the I/O
- * addresses and attach the new mixer to the relevant VoxWare data
- * structures.
- *
- * Returns:  1   ACI mixer detected
- *           0   nothing there
- *
  * There is also an internal mixer in the codec (CS4231A or AD1845),
  * that deserves no purpose in an ACI based system which uses an
  * external ACI controlled stereo mixer. Make sure that this codec
@@ -570,153 +595,108 @@
 
 static int __init attach_aci(void)
 {
-	char *boardname = "unknown";
-	int volume;
+	char *boardname;
+	int i;
 
-#define MC4_PORT	0xf90
+	init_MUTEX(&aci_sem);
 
-	aci_port =
-		(mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
+	outb(0xE3, 0xf8f); /* Write MAD16 password */
+	aci_port = (inb(0xf90) & 0x10) ?
+		0x344: 0x354; /* Get aci_port from MC4_PORT */
 
 	if (check_region(aci_port, 3)) {
-#ifdef DEBUG
-		printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
-			aci_port, aci_port+2);
-#endif
-		return 0;
+		printk(KERN_NOTICE "aci: I/O area 0x%03x-0x%03x already used.\n",
+		       aci_port, aci_port+2);
+		return -EBUSY;
 	}
-	
-	if (aci_read_cmd(0xf2, 2, aci_idcode)) {
-#ifdef DEBUG
-		printk("ACI: Failed to read idcode.\n");
-#endif
-		return 0;
+
+	/* force ACI into a known state */
+	for (i=0; i<3; i++)
+		if (aci_rw_cmd(0xdf, -1, -1)<0)
+			return -EFAULT;
+
+	/* official this is one aci read call: */
+	if ((aci_idcode[0]=aci_rw_cmd(0xf2, -1, -1))<0 ||
+	    (aci_idcode[1]=aci_rw_cmd(0xf2, -1, -1))<0) {
+		printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port);
+		return -EFAULT;
 	}
-	
-	if (aci_read_cmd(0xf1, 1, &aci_version)) {
-#ifdef DEBUG
-		printk("ACI: Failed to read version.\n");
-#endif
-		return 0;
+
+	if ((aci_version=aci_rw_cmd(0xf1, -1, -1))<0) {
+		printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port);
+		return -EFAULT;
 	}
 
-	if (aci_idcode[0] == 0x6d) {
+	if (aci_idcode[0] == 'm') {
 		/* It looks like a miro sound card. */
 		switch (aci_idcode[1]) {
-			case 0x41:
-				boardname = "PCM1 pro / early PCM12";
-				break;
-			case 0x42:
-				boardname = "PCM12";
-				break;
-			case 0x43:
-				boardname = "PCM20";
-				break;
-			default:
-				boardname = "unknown miro";
+		case 'A':
+			boardname = "PCM1 pro / early PCM12";
+			break;
+		case 'B':
+			boardname = "PCM12";
+			break;
+		case 'C':
+			boardname = "PCM20 radio";
+			break;
+		default:
+			boardname = "unknown miro";
 		}
-	} else
-#ifndef DEBUG
-	return 0;
-#endif
-  
-  	printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
-		aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
-
-	if (aci_reset) {
-		/* initialize ACI mixer */
-		aci_implied_cmd(0xff);
-		aci_solo = 0;
-	}
-
-	/* attach the mixer */
-	request_region(aci_port, 3, "sound mixer (ACI)");
-	if (num_mixers < MAX_MIXER_DEV) {
-		if (num_mixers > 0 &&
-		  !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {
-			/*
-			 * The previously registered mixer device is the CS4231A which
-			 * has no function on an ACI card. Make the ACI mixer the first
-			 * of the two mixer devices.
-			 */
-			mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
-			mixer_devs[num_mixers-1] = &aci_mixer_operations;
-			/*
-			 * Initialize the CS4231A mixer with reasonable values. It is
-			 * unlikely that the user ever will want to change these as all
-			 * channels can be mixed via ACI.
-			 */
-			volume = 0x6464;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
-			volume = 0x6464;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_IGAIN,   (caddr_t) &volume);
-			volume = 0;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
-			volume = 0;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
-			volume = 0;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume);
-			volume = 0;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
-			volume = 0;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
-			volume = 0;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume);
-			volume = SOUND_MASK_LINE1;
-			mixer_devs[num_mixers]->ioctl(num_mixers,
-				SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume);
-			num_mixers++;
-		} else
-			mixer_devs[num_mixers++] = &aci_mixer_operations;
-	}
-
-	/* Just do something; otherwise the first write command fails, at
-	 * least with my PCM20.
-	 */
-	aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);
-	
-	if (aci_reset) {
-		/* Initialize ACI mixer with reasonable power-up values */
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH,  (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM,    (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE,   (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC,    (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD,     (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1,  (caddr_t) &volume);
-		volume = 0x3232;
-		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2,  (caddr_t) &volume);
+	} else {
+		printk(KERN_WARNING "aci: Warning: unsupported card! - "
+		       "no hardware, no specs...\n");
+		boardname = "unknown Cardinal Technologies";
+	}
+
+	printk(KERN_INFO "<ACI 0x%02x, id %02x/%02x \"%c/%c\", (%s)> at 0x%03x\n",
+	       aci_version,
+	       aci_idcode[0], aci_idcode[1],
+	       aci_idcode[0], aci_idcode[1],
+	       boardname, aci_port);
+
+	if (reset) {
+		/* first write()s after reset fail with my PCM20 */
+		if (aci_rw_cmd(0xff, -1, -1)<0 ||
+		    aci_rw_cmd(0xdf, 0xdf, 0xdf)<0 ||
+		    aci_rw_cmd(0xdf, 0xdf, 0xdf)<0)
+			return -EBUSY;
+	}
+
+	/* the PCM20 is muted after reset (and reboot) */
+	if (aci_rw_cmd(0x0d, 0x00, -1)<0)
+		return -EBUSY;
+
+	if (ide>=0)
+		if (aci_rw_cmd(0xd0, !ide, -1)<0)
+			return -EBUSY;
+	
+	if (wss>=0 && aci_idcode[1]=='A')
+		if (aci_rw_cmd(0xd1, !!wss, -1)<0)
+			return -EBUSY;
+
+	if (!request_region(aci_port, 3, "sound mixer (ACI)"))
+		return -ENOMEM;
+
+	if ((mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION,
+						boardname,
+						&aci_mixer_operations,
+						sizeof(aci_mixer_operations),
+						NULL)) >= 0) {
+		/* Maybe initialize the CS4231A mixer here... */
+	} else {
+		printk(KERN_ERR "aci: Failed to install mixer.\n");
+		release_region(aci_port, 3);
+		return mixer_device;
 	}
 
-	aci_present = 1;
-
-	return 1;
+	return 0;
 }
 
 static void __exit unload_aci(void)
 {
-	if (aci_present)
-		release_region(aci_port, 3);
+	sound_unload_mixerdev(mixer_device);
+	release_region(aci_port, 3);
 }
-
-EXPORT_SYMBOL(aci_write_cmd);
-EXPORT_SYMBOL(aci_indexed_cmd);
-EXPORT_SYMBOL(aci_write_cmd_d);
 
 module_init(attach_aci);
 module_exit(unload_aci);
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/aci.h linux/drivers/sound/aci.h
--- v2.4.3/linux/drivers/sound/aci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/aci.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,55 @@
+#ifndef _ACI_H_
+#define _ACI_H_
+
+extern int aci_port;
+extern int aci_idcode[2];	/* manufacturer and product ID */
+extern int aci_version;		/* ACI firmware version	*/
+extern int aci_rw_cmd(int write1, int write2, int write3);
+
+extern char * aci_radio_name;
+extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
+
+#define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1)
+#define aci_write_cmd(a, b)   aci_rw_cmd(a, b, -1)
+#define aci_read_cmd(a)       aci_rw_cmd(a,-1, -1)
+
+#define COMMAND_REGISTER    (aci_port)      /* write register */
+#define STATUS_REGISTER     (aci_port + 1)  /* read register */
+#define BUSY_REGISTER       (aci_port + 2)  /* also used for rds */
+
+#define RDS_REGISTER        BUSY_REGISTER
+
+#define RDS_STATUS      0x01
+#define RDS_STATIONNAME 0x02
+#define RDS_TEXT        0x03
+#define RDS_ALTFREQ     0x04
+#define RDS_TIMEDATE    0x05
+#define RDS_PI_CODE     0x06
+#define RDS_PTYTATP     0x07
+#define RDS_RESET       0x08
+#define RDS_RXVALUE     0x09
+
+/*
+ * The following macro SCALE can be used to scale one integer volume
+ * value into another one using only integer arithmetic. If the input
+ * value x is in the range 0 <= x <= xmax, then the result will be in
+ * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
+ *
+ * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
+ * following nice properties:
+ *
+ * - SCALE(xmax,ymax,xmax) = ymax
+ * - SCALE(xmax,ymax,0) = 0
+ * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
+ *
+ * In addition, the rounding error is minimal and nicely distributed.
+ * The proofs are left as an exercise to the reader.
+ */
+
+#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+
+extern void __exit unload_aci_rds(void);
+extern int __init attach_aci_rds(void);
+
+
+#endif  /* _ACI_H_ */
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c
--- v2.4.3/linux/drivers/sound/aedsp16.c	Wed Sep 27 13:53:57 2000
+++ linux/drivers/sound/aedsp16.c	Fri Apr 13 20:26:07 2001
@@ -257,9 +257,9 @@
 
 #define VERSION "1.3"		/* Version of Audio Excel DSP 16 driver */
 
-#undef	AEDSP16_DEBUG 1		/* Define this to enable debug code     */
-#undef	AEDSP16_DEBUG_MORE 1	/* Define this to enable more debug     */
-#undef	AEDSP16_INFO  1		/* Define this to enable info code      */
+#undef	AEDSP16_DEBUG 		/* Define this to 1 to enable debug code     */
+#undef	AEDSP16_DEBUG_MORE 	/* Define this to 1 to enable more debug     */
+#undef	AEDSP16_INFO 		/* Define this to 1 to enable info code      */
 
 #if defined(AEDSP16_DEBUG)
 # define DBG(x)  printk x
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs4281/cs4281_wrapper-24.c linux/drivers/sound/cs4281/cs4281_wrapper-24.c
--- v2.4.3/linux/drivers/sound/cs4281/cs4281_wrapper-24.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/cs4281/cs4281_wrapper-24.c	Wed Apr 18 11:49:11 2001
@@ -40,12 +40,3 @@
 				    (state)->tmpbuff, (state)->dmaaddr_tmpbuff);
 #define cs4x_pgoff(vma) ((vma)->vm_pgoff)
 
-#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
-	 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
-	 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
-#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-#define PCI_GET_DRIVER_DATA pci_get_drvdata
-#define PCI_SET_DRIVER_DATA pci_set_drvdata
-#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask
-
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- v2.4.3/linux/drivers/sound/cs4281/cs4281m.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/cs4281/cs4281m.c	Wed Apr 18 11:49:11 2001
@@ -4289,23 +4289,29 @@
 	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
 		  printk(KERN_INFO "cs4281: probe()+\n"));
 
-	if (!RSRCISMEMORYREGION(pcidev, 0) ||
-	    !RSRCISMEMORYREGION(pcidev, 1)) {
+	if (pci_enable_device(pcidev)) {
+		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+			 "cs4281: pci_enable_device() failed\n"));
+		return -1;
+	}
+	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) ||
+	    !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) {
 		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
 			 "cs4281: probe()- Memory region not assigned\n"));
-		return -1;
+		return -ENODEV;
 	}
 	if (pcidev->irq == 0) {
 		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
 			 "cs4281: probe() IRQ not assigned\n"));
-		return -1;
+		return -ENODEV;
 	}
-	if (!pci_dma_supported(pcidev, 0xffffffff)) {
+	dma_mask = 0xffffffff;	/* this enables playback and recording */
+	i = pci_set_dma_mask(pcidev, dma_mask);
+	if (i) {
 		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
 		      "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n"));
-		return -1;
+		return i;
 	}
-	dma_mask = 0xffffffff;	/* this enables playback and recording */
 	if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
 		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
 		      "cs4281: probe() no memory for state struct.\n"));
@@ -4323,8 +4329,8 @@
 	init_MUTEX(&s->open_sem_adc);
 	init_MUTEX(&s->open_sem_dac);
 	spin_lock_init(&s->lock);
-	s->pBA0phys = RSRCADDRESS(pcidev, 0);
-	s->pBA1phys = RSRCADDRESS(pcidev, 1);
+	s->pBA0phys = pci_resource_start(pcidev, 0);
+	s->pBA1phys = pci_resource_start(pcidev, 1);
 
 	/* Convert phys to linear. */
 	s->pBA0 = ioremap_nocache(s->pBA0phys, 4096);
@@ -4366,11 +4372,6 @@
 	s->magic = CS4281_MAGIC;
 	s->pcidev = pcidev;
 	s->irq = pcidev->irq;
-	if (pci_enable_device(pcidev)) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: pci_enable_device() failed\n"));
-		goto err_irq;
-	}
 	if (request_irq
 	    (s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)) {
 		CS_DBGOUT(CS_INIT | CS_ERROR, 1,
@@ -4427,8 +4428,7 @@
 	mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val);
 	set_fs(fs);
 
-	PCI_SET_DRIVER_DATA(pcidev, s);
-	PCI_SET_DMA_MASK(pcidev, dma_mask);
+	pci_set_drvdata(pcidev, s);
 	list_add(&s->list, &cs4281_devs);
 	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
 		"cs4281: probe()- device allocated successfully\n"));
@@ -4457,7 +4457,7 @@
 
 static void __devinit cs4281_remove(struct pci_dev *pci_dev)
 {
-	struct cs4281_state *s = PCI_GET_DRIVER_DATA(pci_dev);
+	struct cs4281_state *s = pci_get_drvdata(pci_dev);
 	// stop DMA controller 
 	synchronize_irq();
 	free_irq(s->irq, s);
@@ -4467,7 +4467,7 @@
 	iounmap(s->pBA1);
 	iounmap(s->pBA0);
 	kfree(s);
-	PCI_SET_DRIVER_DATA(pci_dev,NULL);
+	pci_set_drvdata(pci_dev,NULL);
 	list_del(&s->list);
 	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
 		 "cs4281: cs4281_remove()-: remove successful\n"));
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs461x.h linux/drivers/sound/cs461x.h
--- v2.4.3/linux/drivers/sound/cs461x.h	Tue Aug 22 11:31:05 2000
+++ linux/drivers/sound/cs461x.h	Wed Apr 11 19:02:37 2001
@@ -2,6 +2,7 @@
 #define __CS461X_H
 
 /*
+ *  Copyright (c) by Cirrus Logic Corporation <pcaudio@crystal.cirrus.com>
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *  Definitions for Cirrus Logic CS461x chips
  *
@@ -1614,4 +1615,77 @@
 #define CS461X_MODE_OUTPUT	(1<<0)	 /* MIDI UART - output */ 
 #define CS461X_MODE_INPUT	(1<<1)	 /* MIDI UART - input */
 
+//****************************************************************************
+//
+// The following define the offsets of the AC97 shadow registers, which appear
+// as a virtual extension to the base address register zero memory range.
+//
+//****************************************************************************
+#define AC97_REG_OFFSET_MASK                    0x0000007EL
+#define AC97_CODEC_NUMBER_MASK                  0x00003000L
+
+#define BA0_AC97_RESET                          0x00001000L
+#define BA0_AC97_MASTER_VOLUME                  0x00001002L
+#define BA0_AC97_HEADPHONE_VOLUME               0x00001004L
+#define BA0_AC97_MASTER_VOLUME_MONO             0x00001006L
+#define BA0_AC97_MASTER_TONE                    0x00001008L
+#define BA0_AC97_PC_BEEP_VOLUME                 0x0000100AL
+#define BA0_AC97_PHONE_VOLUME                   0x0000100CL
+#define BA0_AC97_MIC_VOLUME                     0x0000100EL
+#define BA0_AC97_LINE_IN_VOLUME                 0x00001010L
+#define BA0_AC97_CD_VOLUME                      0x00001012L
+#define BA0_AC97_VIDEO_VOLUME                   0x00001014L
+#define BA0_AC97_AUX_VOLUME                     0x00001016L
+#define BA0_AC97_PCM_OUT_VOLUME                 0x00001018L
+#define BA0_AC97_RECORD_SELECT                  0x0000101AL
+#define BA0_AC97_RECORD_GAIN                    0x0000101CL
+#define BA0_AC97_RECORD_GAIN_MIC                0x0000101EL
+#define BA0_AC97_GENERAL_PURPOSE                0x00001020L
+#define BA0_AC97_3D_CONTROL                     0x00001022L
+#define BA0_AC97_MODEM_RATE                     0x00001024L
+#define BA0_AC97_POWERDOWN                      0x00001026L
+#define BA0_AC97_EXT_AUDIO_ID                   0x00001028L
+#define BA0_AC97_EXT_AUDIO_POWER                0x0000102AL
+#define BA0_AC97_PCM_FRONT_DAC_RATE             0x0000102CL
+#define BA0_AC97_PCM_SURR_DAC_RATE              0x0000102EL
+#define BA0_AC97_PCM_LFE_DAC_RATE               0x00001030L
+#define BA0_AC97_PCM_LR_ADC_RATE                0x00001032L
+#define BA0_AC97_MIC_ADC_RATE                   0x00001034L
+#define BA0_AC97_6CH_VOL_C_LFE                  0x00001036L
+#define BA0_AC97_6CH_VOL_SURROUND               0x00001038L
+#define BA0_AC97_RESERVED_3A                    0x0000103AL
+#define BA0_AC97_EXT_MODEM_ID                   0x0000103CL
+#define BA0_AC97_EXT_MODEM_POWER                0x0000103EL
+#define BA0_AC97_LINE1_CODEC_RATE               0x00001040L
+#define BA0_AC97_LINE2_CODEC_RATE               0x00001042L
+#define BA0_AC97_HANDSET_CODEC_RATE             0x00001044L
+#define BA0_AC97_LINE1_CODEC_LEVEL              0x00001046L
+#define BA0_AC97_LINE2_CODEC_LEVEL              0x00001048L
+#define BA0_AC97_HANDSET_CODEC_LEVEL            0x0000104AL
+#define BA0_AC97_GPIO_PIN_CONFIG                0x0000104CL
+#define BA0_AC97_GPIO_PIN_TYPE                  0x0000104EL
+#define BA0_AC97_GPIO_PIN_STICKY                0x00001050L
+#define BA0_AC97_GPIO_PIN_WAKEUP                0x00001052L
+#define BA0_AC97_GPIO_PIN_STATUS                0x00001054L
+#define BA0_AC97_MISC_MODEM_AFE_STAT            0x00001056L
+#define BA0_AC97_RESERVED_58                    0x00001058L
+#define BA0_AC97_CRYSTAL_REV_N_FAB_ID           0x0000105AL
+#define BA0_AC97_TEST_AND_MISC_CTRL             0x0000105CL
+#define BA0_AC97_AC_MODE                        0x0000105EL
+#define BA0_AC97_MISC_CRYSTAL_CONTROL           0x00001060L
+#define BA0_AC97_LINE1_HYPRID_CTRL              0x00001062L
+#define BA0_AC97_VENDOR_RESERVED_64             0x00001064L
+#define BA0_AC97_VENDOR_RESERVED_66             0x00001066L
+#define BA0_AC97_SPDIF_CONTROL                  0x00001068L
+#define BA0_AC97_VENDOR_RESERVED_6A             0x0000106AL
+#define BA0_AC97_VENDOR_RESERVED_6C             0x0000106CL
+#define BA0_AC97_VENDOR_RESERVED_6E             0x0000106EL
+#define BA0_AC97_VENDOR_RESERVED_70             0x00001070L
+#define BA0_AC97_VENDOR_RESERVED_72             0x00001072L
+#define BA0_AC97_VENDOR_RESERVED_74             0x00001074L
+#define BA0_AC97_CAL_ADDRESS                    0x00001076L
+#define BA0_AC97_CAL_DATA                       0x00001078L
+#define BA0_AC97_VENDOR_RESERVED_7A             0x0000107AL
+#define BA0_AC97_VENDOR_ID1                     0x0000107CL
+#define BA0_AC97_VENDOR_ID2                     0x0000107EL
 #endif				/* __CS461X_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs461x_image.h linux/drivers/sound/cs461x_image.h
--- v2.4.3/linux/drivers/sound/cs461x_image.h	Wed Dec  6 16:13:33 2000
+++ linux/drivers/sound/cs461x_image.h	Wed Apr 11 19:02:37 2001
@@ -1,9 +1,12 @@
 /****************************************************************************
  * "CWCIMAGE.H"-- For CS46XX. Ver 1.04
- *      Copyright 1998-2000 (c) Cirrus Logic Corp.
+ *      Copyright 1998-2001 (c) Cirrus Logic Corp.
  *      Version 1.04
  ****************************************************************************
  */
+#ifndef __CS_IMAGE_H
+#define __CS_IMAGE_H
+
 #define CLEAR__COUNT     3
 #define FILL__COUNT      4
 #define BA1__DWORD_SIZE  13*1024+512
@@ -314,3 +317,6 @@
                             {0x000137f0, sizeof(FillArray3), FillArray3},
                             {0x00020000, sizeof(FillArray4), FillArray4}
                           };
+
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- v2.4.3/linux/drivers/sound/cs46xx.c	Tue Mar 20 12:04:58 2001
+++ linux/drivers/sound/cs46xx.c	Thu Apr 12 12:16:36 2001
@@ -1,7 +1,8 @@
 /*
  *	Crystal SoundFusion CS46xx driver
  *
- *	Copyright 1998-2000 Cirrus Logic Corporation <audio@crystal.cirrus.com>
+ *	Copyright 1998-2001 Cirrus Logic Corporation <pcaudio@crystal.cirrus.com>
+ *						<twoller@crystal.cirrus.com>
  *	Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz>
  *	Copyright 2000 Alan Cox <alan@redhat.com>
  *
@@ -22,7 +23,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.
- *
  *	Current maintainers:
  *		Cirrus Logic Corporation, Thomas Woller (tw)
  *			<twoller@crystal.cirrus.com>
@@ -43,17 +43,33 @@
  *			underruns.
  *	20001201-tw	add resyncing of swptr on underruns.
  *	20001205-tw-nf	fixed GETOSPACE ioctl() after open()
- *
+ *	20010113-tw	patch from Hans Grobler general cleanup.
+ *	20010117-tw	2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0
+ *	20010118-tw	basic PM support for 2.2.16+ and 2.4.0/2.4.2.
+ *	20010228-dh	patch from David Huggins - cs_update_ptr recursion.
  *
  *	Status:
  *	Playback/Capture supported from 8k-48k.
  *	16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
+ *
+ *	APM/PM - 2.2.x APM is enabled and functioning fine. APM can also
+ *	be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
+ *	definition.
+ *
+ *      Hercules Game Pro XP - the EGPIO2 pin controls the external Amp,
+ *	but the static image can not modify the EGPIO pins, so we can not
+ *	turn on the external amp.
+ *
+ *	VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
+ *	the external amplifier for the "back" speakers, since we do not
+ *	support the secondary codec then this external amp is also not
+ *	turned on.
  */
  
-#include <linux/module.h>
+#include <linux/list.h>
 #include <linux/version.h>
+#include <linux/module.h>
 #include <linux/string.h>
-#include <linux/ctype.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
@@ -61,22 +77,21 @@
 #include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
-#ifdef CS46XX_PM
-#include <linux/pm.h>
-#endif
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
+#include <linux/smp_lock.h>
 #include <linux/wrapper.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include <linux/ac97_codec.h>
+#include "cs46xxpm-24.h"
+#include "cs46xx_wrapper-24.h"
 
 #include "cs461x.h"
 
-
 /* MIDI buffer sizes */
 #define CS_MIDIINBUF  500
 #define CS_MIDIOUTBUF 500
@@ -90,6 +105,11 @@
 
 #define CS_TYPE_ADC	1
 #define CS_TYPE_DAC	2
+
+#define CS_TRUE 	1
+#define CS_FALSE 	0
+
+#define CS_DBGBREAKPOINT {__asm__("INT $3");}
 /*
  *	CS461x definitions
  */
@@ -135,14 +155,22 @@
 #define CS_RELEASE	0x00000800		/* all release functions in the driver */
 #define CS_PARMS	0x00001000		/* functional and operational parameters */
 #define CS_IOCTL	0x00002000		/* ioctl (non-mixer) */
+#define CS_PM		0x00004000		/* PM */
 #define CS_TMP		0x10000000		/* tmp debug mask bit */
 
+#define CS_IOCTL_CMD_SUSPEND	0x1	// suspend
+#define CS_IOCTL_CMD_RESUME	0x2	// resume
+
 #if CSDEBUG
 static unsigned long cs_debuglevel=1;			/* levels range from 1-9 */
 MODULE_PARM(cs_debuglevel, "i");
 static unsigned long cs_debugmask=CS_INIT | CS_ERROR;	/* use CS_DBGOUT with various mask values */
 MODULE_PARM(cs_debugmask, "i");
 #endif
+static unsigned long initdelay=700;  /* PM delay in millisecs */
+MODULE_PARM(initdelay, "i");
+static unsigned long powerdown=1;  /* turn on/off powerdown processing in driver */
+MODULE_PARM(powerdown, "i");
 #define DMABUF_DEFAULTORDER 3
 static unsigned long defaultorder=DMABUF_DEFAULTORDER;
 MODULE_PARM(defaultorder, "i");
@@ -153,7 +181,6 @@
 MODULE_PARM(thinkpad, "i");
 
 /* An instance of the 4610 channel */
-
 struct cs_channel 
 {
 	int used;
@@ -161,7 +188,16 @@
 	void *state;
 };
 
-#define DRIVER_VERSION "1.10"
+#define CS46XX_MAJOR_VERSION "1"
+#define CS46XX_MINOR_VERSION "22"
+
+#ifdef __ia64__
+#define CS46XX_ARCH	     	"64"	//architecture key
+#else
+#define CS46XX_ARCH	     	"32"	//architecture key
+#endif
+
+struct list_head cs46xx_devs = { &cs46xx_devs, &cs46xx_devs };
 
 /* magic numbers to protect our data structures */
 #define CS_CARD_MAGIC		0x43525553 /* "CRUS" */
@@ -208,7 +244,8 @@
 		unsigned divisor;
 		unsigned type;
 		void *tmpbuff;			/* tmp buffer for sample conversions */
-		dma_addr_t dma_handle_tmpbuff;
+		dma_addr_t dmaaddr;
+		dma_addr_t dmaaddr_tmpbuff;
 		unsigned buforder_tmpbuff;	/* Log base 2 of size in bytes.. */
 
 		/* our buffer acts like a circular ring */
@@ -239,7 +276,6 @@
 	} dmabuf;
 };
 
-
 struct cs_card {
 	struct cs_channel channel[2];
 	unsigned int magic;
@@ -253,6 +289,7 @@
 
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
+	struct list_head list;
 
 	unsigned int pctl, cctl;	/* Hardware DMA flag sets */
 
@@ -268,6 +305,7 @@
 	
 	int amplifier;			/* Amplifier control */
 	void (*amplifier_ctrl)(struct cs_card *, int);
+	void (*amp_init)(struct cs_card *);
 	
 	int active;			/* Active clocking */
 	void (*active_ctrl)(struct cs_card *, int);
@@ -309,15 +347,17 @@
 		mode_t open_mode;
 		struct semaphore open_sem;
 	} midi;
+	struct cs46xx_pm pm;
 };
 
-static struct cs_card *devs;
-
 static int cs_open_mixdev(struct inode *inode, struct file *file);
 static int cs_release_mixdev(struct inode *inode, struct file *file);
 static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
 				unsigned long arg);
 static loff_t cs_llseek(struct file *file, loff_t offset, int origin);
+static int cs_hardware_init(struct cs_card *card);
+static int cs46xx_powerup(struct cs_card *card, unsigned int type);
+static int cs461x_powerdown(struct cs_card *card, unsigned int type);
 
 static inline unsigned ld2(unsigned int x)
 {
@@ -352,13 +392,9 @@
 #define SOUND_MIXER_CS_SETDBGLEVEL 	_SIOWR('M',121, int)
 #define SOUND_MIXER_CS_GETDBGMASK 	_SIOWR('M',122, int)
 #define SOUND_MIXER_CS_SETDBGMASK 	_SIOWR('M',123, int)
+#define SOUND_MIXER_CS_APM	 	_SIOWR('M',124, int)
 
-#define SNDCTL_DSP_CS_GETDBGLEVEL 	_SIOWR('P', 50, int)
-#define SNDCTL_DSP_CS_SETDBGLEVEL 	_SIOWR('P', 51, int)
-#define SNDCTL_DSP_CS_GETDBGMASK 	_SIOWR('P', 52, int)
-#define SNDCTL_DSP_CS_SETDBGMASK 	_SIOWR('P', 53, int)
-
-static void printioctl(unsigned int x)
+void printioctl(unsigned int x)
 {
     unsigned int i;
     unsigned char vidx;
@@ -477,18 +513,6 @@
         case SOUND_PCM_READ_FILTER:
 		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") );
 		break;
-        case SNDCTL_DSP_CS_GETDBGMASK:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_GETDBGMASK: ") );
-		break;
-        case SNDCTL_DSP_CS_GETDBGLEVEL:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_GETDBGLEVEL: ") );
-		break;
-        case SNDCTL_DSP_CS_SETDBGMASK:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_SETDBGMASK: ") );
-		break;
-        case SNDCTL_DSP_CS_SETDBGLEVEL:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_SETDBGLEVEL: ") );
-		break;
 
         case SOUND_MIXER_PRIVATE1:
 		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") );
@@ -650,6 +674,8 @@
 	unsigned int tmp1, tmp2;
 	unsigned int phiIncr;
 	unsigned int correctionPerGOF, correctionPerSec;
+	unsigned long flags;
+
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) );
 
 	/*
@@ -685,11 +711,11 @@
 	 *  Fill in the SampleRateConverter control block.
 	 */
 	 
-	spin_lock_irq(&state->card->lock);
+	spin_lock_irqsave(&state->card->lock, flags);
 	cs461x_poke(state->card, BA1_PSRC,
 	  ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
 	cs461x_poke(state->card, BA1_PPI, phiIncr);
-	spin_unlock_irq(&state->card->lock);
+	spin_unlock_irqrestore(&state->card->lock, flags);
 	dmabuf->rate = rate;
 	
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) );
@@ -704,6 +730,7 @@
 	unsigned int phiIncr, coeffIncr, tmp1, tmp2;
 	unsigned int correctionPerGOF, correctionPerSec, initialDelay;
 	unsigned int frameGroupLength, cnt;
+	unsigned long flags;
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) );
 
 	/*
@@ -766,14 +793,14 @@
 	/*
 	 *  Fill in the VariDecimate control block.
 	 */
-	spin_lock_irq(&card->lock);
+	spin_lock_irqsave(&card->lock, flags);
 	cs461x_poke(card, BA1_CSRC,
 		((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
 	cs461x_poke(card, BA1_CCI, coeffIncr);
 	cs461x_poke(card, BA1_CD,
 		(((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
 	cs461x_poke(card, BA1_CPI, phiIncr);
-	spin_unlock_irq(&card->lock);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	/*
 	 *  Figure out the frame group length for the write back task.  Basically,
@@ -796,13 +823,13 @@
 	/*
 	 * Fill in the WriteBack control block.
 	 */
-	spin_lock_irq(&card->lock);
+	spin_lock_irqsave(&card->lock, flags);
 	cs461x_poke(card, BA1_CFG1, frameGroupLength);
 	cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength));
 	cs461x_poke(card, BA1_CCST, 0x0000FFFF);
 	cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000));
 	cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF);
-	spin_unlock_irq(&card->lock);
+	spin_unlock_irqrestore(&card->lock, flags);
 	dmabuf->rate = rate;
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) );
 	return rate;
@@ -904,7 +931,7 @@
 /* get current playback/recording dma buffer pointer (byte offset from LBA),
    called with spinlock held! */
    
-static inline unsigned cs_get_dma_addr(struct cs_state *state)
+extern __inline__ unsigned cs_get_dma_addr(struct cs_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	u32 offset;
@@ -938,18 +965,20 @@
 
 static void resync_dma_ptrs(struct cs_state *state)
 {
-	struct dmabuf *dmabuf = &state->dmabuf;
-	int offset;
+	struct dmabuf *dmabuf;
 	
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") );
-	offset = 0;
-	dmabuf->hwptr=dmabuf->swptr = 0;
-	dmabuf->pringbuf = 0;
+	if(state)
+	{
+		dmabuf = &state->dmabuf;
+		dmabuf->hwptr=dmabuf->swptr = 0;
+		dmabuf->pringbuf = 0;
+	}
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") );
 }
 	
 /* Stop recording (lock held) */
-static inline void __stop_adc(struct cs_state *state)
+extern __inline__ void __stop_adc(struct cs_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	struct cs_card *card = state->card;
@@ -983,7 +1012,9 @@
 	spin_lock_irqsave(&card->lock, flags);
 	if (!(dmabuf->enable & ADC_RUNNING) && 
 	     ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) 
-	       && dmabuf->ready)) 
+	       && dmabuf->ready) && 
+	       ((card->pm.flags & CS46XX_PM_IDLE) || 
+	        (card->pm.flags & CS46XX_PM_RESUMED)) )
 	{
 		dmabuf->enable |= ADC_RUNNING;
 		cs_set_divisor(dmabuf);
@@ -1032,7 +1063,10 @@
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") );
 	spin_lock_irqsave(&card->lock, flags);
 	if (!(dmabuf->enable & DAC_RUNNING) && 
-	    ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready)) {
+	    ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) &&
+	       ((card->pm.flags & CS46XX_PM_IDLE) || 
+	        (card->pm.flags & CS46XX_PM_RESUMED)) )
+	{
 		dmabuf->enable |= DAC_RUNNING;
 		tmp = cs461x_peek(card, BA1_PCTL);
 		tmp &= 0xFFFF;
@@ -1054,54 +1088,82 @@
  */
 static int alloc_dmabuf(struct cs_state *state)
 {
+
+	struct cs_card *card=state->card;
 	struct dmabuf *dmabuf = &state->dmabuf;
 	void *rawbuf = NULL;
 	void *tmpbuff = NULL;
 	int order;
-	struct page *page, *pend;
-
-	/* alloc as big a chunk as we can */
-	for (order = defaultorder; order >= DMABUF_MINORDER; order--)
-		if((rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)))
-			break;
+	struct page *map, *mapend;
+	unsigned long df;
+	
+	dmabuf->ready  = dmabuf->mapped = 0;
+	dmabuf->SGok = 0;
+/*
+* check for order within limits, but do not overwrite value.
+*/
+	if((defaultorder > 1) && (defaultorder < 12))
+		df = defaultorder;
+	else
+		df = 2;	
 
-	if (!rawbuf)
+	for (order = df; order >= DMABUF_MINORDER; order--)
+		if ( (rawbuf = (void *) pci_alloc_consistent(
+			card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr)))
+			    break;
+	if (!rawbuf) {
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+			"cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n"));
 		return -ENOMEM;
-
+	}
 	dmabuf->buforder = order;
 	dmabuf->rawbuf = rawbuf;
+	// Now mark the pages as reserved; otherwise the 
+	// remap_page_range() in cs46xx_mmap doesn't work.
+	// 1. get index to last page in mem_map array for rawbuf.
+	mapend = virt_to_page(dmabuf->rawbuf + 
+		(PAGE_SIZE << dmabuf->buforder) - 1);
+
+	// 2. mark each physical page in range as 'reserved'.
+	for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
+		cs4x_mem_map_reserve(map);
 
-	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
-	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
-	for (page = virt_to_page(rawbuf); page <= pend; page++)
-		mem_map_reserve(page);
-
-	CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n",
+	CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n",
 	       PAGE_SIZE << order, order, rawbuf) );
+
+/*
+*  only allocate the conversion buffer for the ADC
+*/
+	if(dmabuf->type == CS_TYPE_DAC)
+	{
+		dmabuf->tmpbuff = NULL;
+		dmabuf->buforder_tmpbuff = 0;
+		return 0;
+	}
 /*
  * now the temp buffer for 16/8 conversions
  */
-	for (order = defaultorder; order >= DMABUF_MINORDER; order--)
-		if((tmpbuff = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)))
-			break;
+
+	tmpbuff = (void *) pci_alloc_consistent(
+		card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff);
+
 	if (!tmpbuff)
 		return -ENOMEM;
-	CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n",
+	CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n",
 	       PAGE_SIZE << order, order, tmpbuff) );
 
 	dmabuf->tmpbuff = tmpbuff;
 	dmabuf->buforder_tmpbuff = order;
 	
-	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
-	pend = virt_to_page(tmpbuff + (PAGE_SIZE << order) - 1);
-	for (page = virt_to_page(tmpbuff); page <= pend; page++)
-		mem_map_reserve(page);
-
-	CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n",
-	       PAGE_SIZE << order, order, tmpbuff) );
-
-	dmabuf->ready  = dmabuf->mapped = 0;
-	dmabuf->SGok = 0;
+	// Now mark the pages as reserved; otherwise the 
+	// remap_page_range() in cs46xx_mmap doesn't work.
+	// 1. get index to last page in mem_map array for rawbuf.
+	mapend = virt_to_page(dmabuf->tmpbuff + 
+		(PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
+
+	// 2. mark each physical page in range as 'reserved'.
+	for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
+		cs4x_mem_map_reserve(map);
 	return 0;
 }
 
@@ -1109,24 +1171,24 @@
 static void dealloc_dmabuf(struct cs_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct page *page, *pend;
+	struct page *map, *mapend;
 
 	if (dmabuf->rawbuf) {
-		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
-		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
-			mem_map_unreserve(page);
-		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
-				    dmabuf->rawbuf, dmabuf->dma_handle);
+		// Undo prog_dmabuf()'s marking the pages as reserved 
+		mapend = virt_to_page(dmabuf->rawbuf + 
+				(PAGE_SIZE << dmabuf->buforder) - 1);
+		for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
+			cs4x_mem_map_unreserve(map);
+		free_dmabuf(state->card, dmabuf);
 	}
-	dmabuf->rawbuf = NULL;
 
 	if (dmabuf->tmpbuff) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(dmabuf->tmpbuff + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
-		for (page = virt_to_page(dmabuf->tmpbuff); page <= pend; page++)
-			mem_map_unreserve(page);
-		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder_tmpbuff,
-				    dmabuf->tmpbuff, dmabuf->dma_handle_tmpbuff);
+		// Undo prog_dmabuf()'s marking the pages as reserved 
+		mapend = virt_to_page(dmabuf->tmpbuff +
+				(PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
+		for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
+			cs4x_mem_map_unreserve(map);
+		free_dmabuf2(state->card, dmabuf);
 	}
 
 	dmabuf->rawbuf = NULL;
@@ -1197,7 +1259,7 @@
 		dmabuf->ready = 1;
 
 		CS_DBGOUT(CS_PARMS, 4, printk(
-			"cs461x: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d "
+			"cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d "
 			"fragsize=%d dmasize=%d\n",
 			    dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
 			    dmabuf->fragsize, dmabuf->dmasize) );
@@ -1300,7 +1362,7 @@
 		dmabuf->ready = 1;
 
 		CS_DBGOUT(CS_PARMS, 4, printk(
-			"cs461x: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d "
+			"cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d "
 			"fragsize=%d dmasize=%d\n",
 			    dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
 			    dmabuf->fragsize, dmabuf->dmasize) );
@@ -1358,7 +1420,7 @@
 		tmo += (2048*HZ)/dmabuf->rate;
 		
 		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
-			printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count);
+			printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count);
 			break;
 		}
 	}
@@ -1372,9 +1434,8 @@
 
 
 /* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void cs_update_ptr(void)
+static void cs_update_ptr(struct cs_card *card, int wake)
 {
-	struct cs_card *card=devs;
 	struct cs_state *state;
 	struct dmabuf *dmabuf;
 	unsigned hwptr;
@@ -1401,11 +1462,11 @@
 
 			if(dmabuf->mapped)
 			{
-				if (dmabuf->count >= (signed)dmabuf->fragsize)
+				if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
 					wake_up(&dmabuf->wait);
 			} else 
 			{
-				if (dmabuf->count > 0)
+				if (wake && dmabuf->count > 0)
 					wake_up(&dmabuf->wait);
 			}
 		}
@@ -1431,7 +1492,7 @@
 			dmabuf->total_bytes += diff;
 			if (dmabuf->mapped) {
 				dmabuf->count += diff;
-				if (dmabuf->count >= (signed)dmabuf->fragsize)
+				if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
 					wake_up(&dmabuf->wait);
 				/*
 				 * other drivers use fragsize, but don't see any sense
@@ -1475,7 +1536,7 @@
 					dmabuf->count = 0;
 					dmabuf->error++;
 				}
-				if (dmabuf->count < (signed)dmabuf->dmasize/2)
+				if (wake && dmabuf->count < (signed)dmabuf->dmasize/2)
 					wake_up(&dmabuf->wait);
 			}
 		}
@@ -1544,7 +1605,7 @@
 	{
 		CS_DBGOUT(CS_INTERRUPT, 8, printk(
 			"cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status));
-		cs_update_ptr();
+		cs_update_ptr(card, CS_TRUE);
 	}
 
         if( status & HISR_MIDI )
@@ -1681,12 +1742,26 @@
 static int cs_midi_open(struct inode *inode, struct file *file)
 {
         int minor = MINOR(inode->i_rdev);
-        struct cs_card *card = devs;
+        struct cs_card *card=NULL;
         unsigned long flags;
-        while (card && card->dev_midi != minor)
-                card = card->next;
-        if (!card)
-                return -ENODEV;
+	struct list_head *entry;
+
+	list_for_each(entry, &cs46xx_devs)
+	{
+		card = list_entry(entry, struct cs_card, list);
+		if (card->dev_midi == minor)
+			break;
+	}
+
+	if (entry == &cs46xx_devs)
+		return -ENODEV;
+	if (!card)
+	{
+		CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+			"cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n"));
+		return -ENODEV;
+	}
+
         file->private_data = card;
         /* wait for device to become free */
         down(&card->midi.open_sem);
@@ -1765,13 +1840,13 @@
  *   Midi file operations struct.
  */
 static /*const*/ struct file_operations cs_midi_fops = {
-	owner:		THIS_MODULE,
-        llseek:		cs_llseek,
-        read:		cs_midi_read,
-        write:		cs_midi_write,
-        poll:		cs_midi_poll,
-        open:		cs_midi_open,
-        release:	cs_midi_release,
+	CS_OWNER	CS_THIS_MODULE
+	llseek:		cs_llseek,
+	read:		cs_midi_read,
+	write:		cs_midi_write,
+	poll:		cs_midi_poll,
+	open:		cs_midi_open,
+	release:	cs_midi_release,
 };
 
 static loff_t cs_llseek(struct file *file, loff_t offset, int origin)
@@ -1806,7 +1881,7 @@
     s16 *psDst=(s16 *)dst;
     u8 *pucDst=(u8 *)dst;
 
-    CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: CopySamples()+ ") );
+    CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") );
     CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
 	" dst=0x%x src=0x%x count=%d fmt=0x%x\n",
 	(unsigned)dst,(unsigned)src,(unsigned)count,(unsigned)fmt) );
@@ -1912,14 +1987,14 @@
         if (copy_to_user(dest, src, cnt))
 	{
 		CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR 
-			"cs4281: cs_copy_to_user()- fault dest=0x%x src=0x%x cnt=%d\n",
+			"cs46xx: cs_copy_to_user()- fault dest=0x%x src=0x%x cnt=%d\n",
 				(unsigned)dest,(unsigned)src,cnt) );
 		*copied = 0;
 		return -EFAULT;
 	}
 	*copied = cnt;
 	CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO 
-		"cs4281: cs_copy_to_user()- copied bytes is %d \n",cnt) );
+		"cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt) );
 	return 0;
 }
 
@@ -1927,7 +2002,7 @@
    the user's buffer.  it is filled by the dma machine and drained by this loop. */
 static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
-	struct cs_card *card=devs;
+	struct cs_card *card = (struct cs_card *) file->private_data;
 	struct cs_state *state;
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf;
@@ -1937,7 +2012,8 @@
 	int cnt;
 	unsigned copied=0;
 
-	CS_DBGOUT(CS_WAVE_READ, 4, printk("cs461x: cs_read()+ %d\n",count) );
+	CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, 
+		printk("cs46xx: cs_read()+ %d\n",count) );
 	state = (struct cs_state *)card->states[0];
 	if(!state)
 		return -ENODEV;
@@ -1951,9 +2027,18 @@
 		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	ret = 0;
 
 	add_wait_queue(&state->dmabuf.wait, &wait);
 	while (count > 0) {
+		while(!(card->pm.flags & CS46XX_PM_IDLE))
+		{
+			schedule();
+			if (signal_pending(current)) {
+				ret = ret ? ret : -ERESTARTSYS;
+				break;
+			}
+		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		swptr = dmabuf->swptr;
 		cnt = dmabuf->dmasize - swptr;
@@ -1978,7 +2063,7 @@
 				ret = ret ? ret : -ERESTARTSYS;
 				break;
 			}
-			continue;
+ 			continue;
 		}
 
 		CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO 
@@ -2005,7 +2090,8 @@
 	}
 	remove_wait_queue(&state->dmabuf.wait, &wait);
 	set_current_state(TASK_RUNNING);
-	CS_DBGOUT(CS_WAVE_READ, 4, printk("cs461x: cs_read()- %d\n",ret) );
+	CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, 
+		printk("cs46xx: cs_read()- %d\n",ret) );
 	return ret;
 }
 
@@ -2013,17 +2099,17 @@
    the soundcard.  it is drained by the dma machine and filled by this loop. */
 static ssize_t cs_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
-	struct cs_card *card=devs;
+	struct cs_card *card = (struct cs_card *) file->private_data;
 	struct cs_state *state;
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf;
-	ssize_t ret = 0;
+	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
 	int cnt;
 
 	CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
-		printk("cs461x: cs_write called, count = %d\n", count) );
+		printk("cs46xx: cs_write called, count = %d\n", count) );
 	state = (struct cs_state *)card->states[1];
 	if(!state)
 		return -ENODEV;
@@ -2038,7 +2124,20 @@
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
 	add_wait_queue(&state->dmabuf.wait, &wait);
+	ret = 0;
+/*
+* Start the loop to read from the user's buffer and write to the dma buffer.
+* check for PM events and underrun/overrun in the loop.
+*/
 	while (count > 0) {
+		while(!(card->pm.flags & CS46XX_PM_IDLE))
+		{
+			schedule();
+			if (signal_pending(current)) {
+				ret = ret ? ret : -ERESTARTSYS;
+				break;
+			}
+		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->count < 0) {
 			/* buffer underrun, we are recovering from sleep_on_timeout,
@@ -2052,6 +2151,7 @@
 			dmabuf->hwptr = cs_get_dma_addr(state);
 			dmabuf->swptr = dmabuf->hwptr;
 		}
+
 		swptr = dmabuf->swptr;
 		cnt = dmabuf->dmasize - swptr;
 		if (dmabuf->count + cnt > dmabuf->dmasize)
@@ -2081,10 +2181,8 @@
 			if (!ret) ret = -EFAULT;
 			return ret;
 		}
-
-		swptr = (swptr + cnt) % dmabuf->dmasize;
-
 		spin_lock_irqsave(&state->card->lock, flags);
+		swptr = (swptr + cnt) % dmabuf->dmasize;
 		dmabuf->swptr = swptr;
 		dmabuf->count += cnt;
 		if(dmabuf->count > dmabuf->dmasize)
@@ -2143,7 +2241,7 @@
 	}
 
 	spin_lock_irqsave(&card->lock, flags);
-	cs_update_ptr();
+	cs_update_ptr(card, CS_FALSE);
 	if (file->f_mode & FMODE_READ) {
 		state = card->states[0];
 		if(state)
@@ -2170,7 +2268,8 @@
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- \n"));
+	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n",
+		mask));
 	return mask;
 }
 
@@ -2184,7 +2283,7 @@
  
 static int cs_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct cs_card *card=devs;
+	struct cs_card *card = (struct cs_card *)file->private_data;
 	struct cs_state *state;
 	struct dmabuf *dmabuf;
 	int ret;
@@ -2199,7 +2298,7 @@
 		if(state)
 		{
 			CS_DBGOUT(CS_OPEN, 2, printk(
-			  "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
+			  "cs46xx: cs_mmap() VM_WRITE - state CS_TRUE prog_dmabuf DAC\n") );
 			if ((ret = prog_dmabuf(state)) != 0)
 				return ret;
 		}
@@ -2208,7 +2307,7 @@
 		if(state)
 		{
 			CS_DBGOUT(CS_OPEN, 2, printk(
-			  "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
+			  "cs46xx: cs_mmap() VM_READ - state CS_TRUE prog_dmabuf ADC\n") );
 			if ((ret = prog_dmabuf(state)) != 0)
 				return ret;
 		}
@@ -2231,7 +2330,7 @@
 		return -EINVAL;
 
 	dmabuf = &state->dmabuf;
-	if (vma->vm_pgoff != 0)
+	if (cs4x_pgoff(vma) != 0)
 		return -EINVAL;
 	size = vma->vm_end - vma->vm_start;
 
@@ -2617,7 +2716,7 @@
 		{
 			dmabuf = &state->dmabuf;
 			spin_lock_irqsave(&state->card->lock, flags);
-			cs_update_ptr();
+			cs_update_ptr(card, CS_TRUE);
 			abinfo.fragsize = dmabuf->fragsize;
 			abinfo.fragstotal = dmabuf->numfrag;
 		/*
@@ -2640,7 +2739,7 @@
 		{
 			dmabuf = &state->dmabuf;
 			spin_lock_irqsave(&state->card->lock, flags);
-			cs_update_ptr();
+			cs_update_ptr(card, CS_TRUE);
 			abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor;
 			abinfo.bytes = dmabuf->count/dmabuf->divisor;
 			abinfo.fragstotal = dmabuf->numfrag;
@@ -2721,7 +2820,7 @@
 		{
 			dmabuf = &state->dmabuf;
 			spin_lock_irqsave(&state->card->lock, flags);
-			cs_update_ptr();
+			cs_update_ptr(card, CS_TRUE);
 			cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor;
 			cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift;
 			cinfo.ptr = dmabuf->hwptr/dmabuf->divisor;
@@ -2736,7 +2835,7 @@
 		{
 			dmabuf = &state->dmabuf;
 			spin_lock_irqsave(&state->card->lock, flags);
-			cs_update_ptr();
+			cs_update_ptr(card, CS_TRUE);
 			cinfo.bytes = dmabuf->total_bytes;
 			if (dmabuf->mapped)
 			{
@@ -2772,7 +2871,7 @@
 		{
 			dmabuf = &state->dmabuf;
 			spin_lock_irqsave(&state->card->lock, flags);
-			cs_update_ptr();
+			cs_update_ptr(card, CS_TRUE);
 			val = dmabuf->count;
 			spin_unlock_irqrestore(&state->card->lock, flags);
 		}
@@ -2856,10 +2955,12 @@
 	}
 }
 
-
-
 /*
- *	Untested
+ *	For the VTB Santa Cruz card, the Secondary Codec must have the 
+ *	GPIO pins 7 and 8 manipulated, not the Primary codec.
+ *	Currently, only the primary codec is supported, so the following
+ *	code will not function.  Additionally, slot 12 must be setup
+ *	to allow proper output for 7 and 8 to occur (trw).
  */
  
 static void amp_voyetra_4294(struct cs_card *card, int change)
@@ -2897,9 +2998,9 @@
 	u16 control;
 	u8 pp;
 	unsigned long port;
-	int old=card->amplifier;
+	int old=card->active;
 	
-	card->amplifier+=change;
+	card->active+=change;
 	
 	acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
 	if(acpi_dev == NULL)
@@ -2913,24 +3014,55 @@
 	control=inw(port+0x10);
 
 	/* Flip CLKRUN off while running */
-	if(!card->amplifier && old)
+	if(!card->active && old)
+	{
+		CS_DBGOUT(CS_PARMS , 9, printk(
+			"cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
+				change,card->active));
 		outw(control|0x2000, port+0x10);
-	else if(card->amplifier && !old)
+	}
+	else 
+	{
+	/*
+	* sometimes on a resume the bit is set, so always reset the bit.
+	*/
+		CS_DBGOUT(CS_PARMS , 9, printk(
+			"cs46xx: clkrun() disable clkrun - change=%d active=%d\n",
+				change,card->active));
 		outw(control&~0x2000, port+0x10);
+	}
 }
 
 	
 static int cs_open(struct inode *inode, struct file *file)
 {
-	struct cs_card *card = devs;
+	struct cs_card *card = (struct cs_card *)file->private_data;
 	struct cs_state *state = NULL;
 	struct dmabuf *dmabuf = NULL;
+	struct list_head *entry;
+        int minor = MINOR(inode->i_rdev);
 	int ret=0;
+	unsigned int tmp;
 
 	CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=0x%x %s %s\n",
 		(unsigned)file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
 		file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
 
+	list_for_each(entry, &cs46xx_devs)
+	{
+		card = list_entry(entry, struct cs_card, list);
+
+		if (!((card->dev_audio ^ minor) & ~0xf))
+			break;
+	}
+	if (entry == &cs46xx_devs)
+		return -ENODEV;
+	if (!card) {
+		CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+			"cs46xx: cs_open(): Error - unable to find audio card struct\n"));
+		return -ENODEV;
+	}
+
 	/*
 	 * hardcode state[0] for capture, [1] for playback
 	 */
@@ -2971,6 +3103,13 @@
 		state->card->active_ctrl(state->card,1);
 		state->card->amplifier_ctrl(state->card,1);
 		
+		if( (tmp = cs46xx_powerup(card, CS_POWER_ADC)) )
+		{
+			CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+				"cs46xx: cs46xx_powerup of ADC failed (0x%x)\n",tmp) );
+			return -EIO;
+		}
+
 		dmabuf->channel->state = state;
 		/* initialize the virtual channel */
 		state->virt = 0;
@@ -3034,6 +3173,13 @@
 		state->card = card;
 		state->card->active_ctrl(state->card,1);
 		state->card->amplifier_ctrl(state->card,1);
+
+		if( (tmp = cs46xx_powerup(card, CS_POWER_DAC)) )
+		{
+			CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+				"cs46xx: cs46xx_powerup of DAC failed (0x%x)\n",tmp) );
+			return -EIO;
+		}
 		
 		dmabuf->channel->state = state;
 		/* initialize the virtual channel */
@@ -3074,6 +3220,7 @@
 	struct cs_card *card = (struct cs_card *)file->private_data;
 	struct dmabuf *dmabuf;
 	struct cs_state *state;
+	unsigned int tmp;
 	CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=0x%x %s %s\n",
 		(unsigned)file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
 		file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
@@ -3103,6 +3250,13 @@
 			state->card->states[state->virt] = NULL;
 			state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
+			if( (tmp = cs461x_powerdown(card, CS_POWER_DAC )) )
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
+					"cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
+				return -EIO;
+			}
+
 			/* Now turn off external AMP if needed */
 			state->card->amplifier_ctrl(state->card, -1);
 			state->card->active_ctrl(state->card, -1);
@@ -3130,6 +3284,13 @@
 			state->card->states[state->virt] = NULL;
 			state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
+			if( (tmp = cs461x_powerdown(card, CS_POWER_ADC )) )
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
+					"cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
+				return -EIO;
+			}
+
 			/* Now turn off external AMP if needed */
 			state->card->amplifier_ctrl(state->card, -1);
 			state->card->active_ctrl(state->card, -1);
@@ -3143,127 +3304,494 @@
 	return 0;
 }
 
-static /*const*/ struct file_operations cs461x_fops = {
-	owner:		THIS_MODULE,
-	llseek:		cs_llseek,
-	read:		cs_read,
-	write:		cs_write,
-	poll:		cs_poll,
-	ioctl:		cs_ioctl,
-	mmap:		cs_mmap,
-	open:		cs_open,
-	release:	cs_release,
-};
-
-/* Write AC97 codec registers */
+void printpm(struct cs_card *s)
+{
+	CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
+	CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
+		(unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
+	CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
+		s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
+	CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
+		s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
+	CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
+		s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
+	CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
+		s->pm.u32SSCR,s->pm.u32SRCSA));
+	CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
+		s->pm.u32DacASR,s->pm.u32AdcASR));
+	CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
+		s->pm.u32DacSR,s->pm.u32AdcSR));
+	CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
+		s->pm.u32MIDCR_Save));
+	CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n",
+		s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose));
+	CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n",
+		s->pm.u32AC97_master_volume));
+	CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n",
+		s->pm.u32AC97_headphone_volume));
+	CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n",
+		s->pm.u32AC97_master_volume_mono));
+	CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n",
+		s->pm.u32AC97_pcm_out_volume));
+	CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n",
+		s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play));
+	CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n",
+		s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture));
 
+}
 
-static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
+/****************************************************************************
+*
+*  Suspend - save the ac97 regs, mute the outputs and power down the part.  
+*
+****************************************************************************/
+void cs46xx_ac97_suspend(struct cs_card *card)
 {
-	struct cs_card *card = dev->private_data;
-	int count;
-	
-	/*
-	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-	 *  2. Write ACCDA = Command Data Register = 470h    for data to write to AC97 
-	 *  3. Write ACCTL = Control Register = 460h for initiating the write
-	 *  4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
-	 *  5. if DCV not cleared, break and return error
-	 *  6. Read ACSTS = Status Register = 464h, check VSTS bit
-	 */
-
+	int Count,i;
+	unsigned int tmp;
+	struct ac97_codec *dev=card->ac97_codec[0];
 
-	cs461x_peekBA0(card, BA0_ACSDA);
+	CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
 
-	/*
-	 *  Setup the AC97 control registers on the CS461x to send the
-	 *  appropriate command to the AC97 to perform the read.
-	 *  ACCAD = Command Address Register = 46Ch
-	 *  ACCDA = Command Data Register = 470h
-	 *  ACCTL = Control Register = 460h
-	 *  set DCV - will clear when process completed
-	 *  set CRW - Read command
-	 *  set VFRM - valid frame enabled
-	 *  set ESYN - ASYNC generation enabled
-	 *  set RSTN - ARST# inactive, AC97 codec not reset
-	 */
+	if(card->states[1])
+	{
+		stop_dac(card->states[1]);
+		resync_dma_ptrs(card->states[1]);
+	}
+	if(card->states[0])
+	{
+		stop_adc(card->states[0]);
+		resync_dma_ptrs(card->states[0]);
+	}
 
-	cs461x_pokeBA0(card, BA0_ACCAD, reg);
-	cs461x_pokeBA0(card, BA0_ACCDA, 0);
-	cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
-					     ACCTL_VFRM | ACCTL_ESYN |
-					     ACCTL_RSTN);
+	for(Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
+			&& (i < CS46XX_AC97_NUMBER_RESTORE_REGS); 
+		Count += 2, i++)
+	{
+		card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count);
+	}
+/*
+* Save the ac97 volume registers as well as the current powerdown state.
+* Now, mute the all the outputs (master, headphone, and mono), as well
+* as the PCM volume, in preparation for powering down the entire part.
+*/ 
+	card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, 
+			(u8)BA0_AC97_MASTER_VOLUME); 
+	card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, 
+			(u8)BA0_AC97_HEADPHONE_VOLUME); 
+	card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev, 
+			(u8)BA0_AC97_MASTER_VOLUME_MONO); 
+	card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, 
+			(u8)BA0_AC97_PCM_OUT_VOLUME);
+		
+	cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
+	cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
+	cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
+	cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
 
+	card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL); 
+	card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE); 
 
-	/*
-	 *  Wait for the read to occur.
-	 */
-	for (count = 0; count < 500; count++) {
-		/*
-		 *  First, we want to wait for a short time.
-	 	 */
-		udelay(10);
-		/*
-		 *  Now, check to see if the read has completed.
-		 *  ACCTL = 460h, DCV should be reset by now and 460h = 17h
-		 */
-		if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
-			break;
+/*
+* And power down everything on the AC97 codec.
+* well, for now, only power down the DAC/ADC and MIXER VREFON components. 
+* trouble with removing VREF.
+*/
+	if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+			CS_POWER_MIXVON )) )
+	{
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+			"cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) );
 	}
 
-	/*
-	 *  Make sure the read completed.
-	 */
-	if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
-		printk(KERN_WARNING "cs461x: AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
-		return 0xffff;
-	}
+	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_suspend()-\n"));
+}
 
-	/*
-	 *  Wait for the valid status bit to go active.
-	 */
-	for (count = 0; count < 100; count++) {
-		/*
-		 *  Read the AC97 status register.
-		 *  ACSTS = Status Register = 464h
-		 *  VSTS - Valid Status
-		 */
-		if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
-			break;
-		udelay(10);
-	}
-	
-	/*
-	 *  Make sure we got valid status.
-	 */
-	if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)) {
-		printk(KERN_WARNING "cs461x: AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg);
-		return 0xffff;
+/****************************************************************************
+*
+*  Resume - power up the part and restore its registers..  
+*
+****************************************************************************/
+void cs46xx_ac97_resume(struct cs_card *card)
+{
+	int Count,i;
+	struct ac97_codec *dev=card->ac97_codec[0];
+
+	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()+\n"));
+
+/*
+* First, we restore the state of the general purpose register.  This
+* contains the mic select (mic1 or mic2) and if we restore this after
+* we restore the mic volume/boost state and mic2 was selected at
+* suspend time, we will end up with a brief period of time where mic1
+* is selected with the volume/boost settings for mic2, causing
+* acoustic feedback.  So we restore the general purpose register
+* first, thereby getting the correct mic selected before we restore
+* the mic volume/boost.
+*/
+	cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE, 
+		(u16)card->pm.u32AC97_general_purpose);
+
+	cs_ac97_set(dev, (u8)AC97_POWER_CONTROL, 
+		(u16)card->pm.u32AC97_powerdown);
+	mdelay(10);
+
+/*
+* Now, while the outputs are still muted, restore the state of power
+* on the AC97 part.
+*/
+	cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
+	mdelay(5);
+/*
+* Restore just the first set of registers, from register number
+* 0x02 to the register number that ulHighestRegToRestore specifies.
+*/
+	for(	Count = 0x2, i=0; 
+		(Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
+			&& (i < CS46XX_AC97_NUMBER_RESTORE_REGS); 
+		Count += 2, i++)
+	{
+		cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]);
 	}
 
-	/*
-	 *  Read the data returned from the AC97 register.
-	 *  ACSDA = Status Data Register = 474h
-	 */
-#if 0
-	printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
-			cs461x_peekBA0(card, BA0_ACSDA),
-			cs461x_peekBA0(card, BA0_ACCAD));
-#endif
-	return cs461x_peekBA0(card, BA0_ACSDA);
+	/* Check if we have to init the amplifier */
+	if(card->amp_init)
+		card->amp_init(card);
+        
+	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()-\n"));
 }
 
-static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
+
+static int cs46xx_restart_part(struct cs_card *card)
 {
-	struct cs_card *card = dev->private_data;
-	int count;
-	int val2 = 0;
-	
-	if(reg == AC97_CD_VOL)
-	{
-		val2 = cs_ac97_get(dev, AC97_CD_VOL);
-	}
-	
+	struct dmabuf *dmabuf;
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
+		printk( "cs46xx: cs46xx_restart_part()+\n"));
+	if(card->states[1])
+	{
+		dmabuf = &card->states[1]->dmabuf;
+		dmabuf->ready = 0;
+		resync_dma_ptrs(card->states[1]);
+		cs_set_divisor(dmabuf);
+		if(prog_dmabuf(card->states[1]))
+		{
+			CS_DBGOUT(CS_PM | CS_ERROR, 1, 
+				printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
+			return -1;
+		}
+		cs_set_dac_rate(card->states[1], dmabuf->rate);
+	}
+	if(card->states[0])
+	{
+		dmabuf = &card->states[0]->dmabuf;
+		dmabuf->ready = 0;
+		resync_dma_ptrs(card->states[0]);
+		cs_set_divisor(dmabuf);
+		if(prog_dmabuf(card->states[0]))
+		{
+			CS_DBGOUT(CS_PM | CS_ERROR, 1, 
+				printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
+			return -1;
+		}
+		cs_set_adc_rate(card->states[0], dmabuf->rate);
+	}
+	card->pm.flags |= CS46XX_PM_RESUMED;
+	if(card->states[0])
+		start_adc(card->states[0]);
+	if(card->states[1])
+		start_dac(card->states[1]);
+
+	card->pm.flags |= CS46XX_PM_IDLE;
+	card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED 
+			| CS46XX_PM_RESUMING | CS46XX_PM_RESUMED);
+	if(card->states[0])
+		wake_up(&card->states[0]->dmabuf.wait);
+	if(card->states[1])
+		wake_up(&card->states[1]->dmabuf.wait);
+
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
+		printk( "cs46xx: cs46xx_restart_part()-\n"));
+	return 0;
+}
+
+
+static void cs461x_reset(struct cs_card *card);
+static void cs461x_proc_stop(struct cs_card *card);
+int cs46xx_suspend(struct cs_card *card)
+{
+	unsigned int tmp;
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
+		printk("cs46xx: cs46xx_suspend()+ flags=%d s=0x%x\n",
+			(unsigned)card->pm.flags,(unsigned)card));
+/*
+* check the current state, only suspend if IDLE
+*/
+	if(!(card->pm.flags & CS46XX_PM_IDLE))
+	{
+		CS_DBGOUT(CS_PM | CS_ERROR, 2, 
+			printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n"));
+		return 1;
+	}
+	card->pm.flags &= ~CS46XX_PM_IDLE;
+	card->pm.flags |= CS46XX_PM_SUSPENDING;
+
+	card->active_ctrl(card,1);
+	
+	tmp = cs461x_peek(card, BA1_PFIE);
+	tmp &= ~0x0000f03f;
+	tmp |=  0x00000010;
+	cs461x_poke(card, BA1_PFIE, tmp);	/* playback interrupt disable */
+
+	tmp = cs461x_peek(card, BA1_CIE);
+	tmp &= ~0x0000003f;
+	tmp |=  0x00000011;
+	cs461x_poke(card, BA1_CIE, tmp);	/* capture interrupt disable */
+
+	/*
+         *  Stop playback DMA.
+	 */
+	tmp = cs461x_peek(card, BA1_PCTL);
+	cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
+
+	/*
+         *  Stop capture DMA.
+	 */
+	tmp = cs461x_peek(card, BA1_CCTL);
+	cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
+
+	if(card->states[1])
+	{
+		card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr;
+		card->pm.dmabuf_count_play = card->states[1]->dmabuf.count;
+	}
+	if(card->states[0])
+	{
+		card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr;
+		card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count;
+	}
+
+	cs46xx_ac97_suspend(card);
+
+	/*
+         *  Reset the processor.
+         */
+	cs461x_reset(card);
+
+	cs461x_proc_stop(card);
+
+	/*
+	 *  Power down the DAC and ADC.  For now leave the other areas on.
+	 */
+	cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300);
+
+	/*
+	 *  Power down the PLL.
+	 */
+	cs461x_pokeBA0(card, BA0_CLKCR1, 0);
+
+	/*
+	 *  Turn off the Processor by turning off the software clock enable flag in 
+	 *  the clock control register.
+	 */
+	tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
+	cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
+
+	card->active_ctrl(card,-1);
+
+	card->pm.flags &= ~CS46XX_PM_SUSPENDING;
+	card->pm.flags |= CS46XX_PM_SUSPENDED;
+
+	printpm(card);
+
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
+		printk("cs46xx: cs46xx_suspend()- flags=%d\n",
+			(unsigned)card->pm.flags));
+	return 0;
+}
+
+int cs46xx_resume(struct cs_card *card)
+{
+	int i;
+
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
+		printk( "cs46xx: cs46xx_resume()+ flags=%d\n",
+			(unsigned)card->pm.flags));
+	if(!(card->pm.flags & CS46XX_PM_SUSPENDED))
+	{
+		CS_DBGOUT(CS_PM | CS_ERROR, 2, 
+			printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n"));
+		return 1;
+	}
+	card->pm.flags |= CS46XX_PM_RESUMING;
+	card->pm.flags &= ~CS46XX_PM_SUSPENDED;
+	printpm(card);
+	card->active_ctrl(card, 1);
+
+	for(i=0;i<5;i++)
+	{
+		if (cs_hardware_init(card) != 0)
+		{
+			CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
+				"cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
+			mdelay(10);
+			cs461x_reset(card);
+			continue;
+		}
+		break;
+	}
+	if(i>=4)
+	{
+		CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
+			"cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i));
+		return 0;
+	}
+
+	if(cs46xx_restart_part(card))
+	{
+		CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
+			"cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n"));
+	}
+
+	card->active_ctrl(card, -1);
+
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=%d\n",
+		(unsigned)card->pm.flags));
+	return 0;
+}
+
+static /*const*/ struct file_operations cs461x_fops = {
+	CS_OWNER	CS_THIS_MODULE
+	llseek:		cs_llseek,
+	read:		cs_read,
+	write:		cs_write,
+	poll:		cs_poll,
+	ioctl:		cs_ioctl,
+	mmap:		cs_mmap,
+	open:		cs_open,
+	release:	cs_release,
+};
+
+/* Write AC97 codec registers */
+
+
+static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct cs_card *card = dev->private_data;
+	int count,loopcnt;
+	unsigned int tmp;
+	
+	/*
+	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
+	 *  2. Write ACCDA = Command Data Register = 470h    for data to write to AC97 
+	 *  3. Write ACCTL = Control Register = 460h for initiating the write
+	 *  4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
+	 *  5. if DCV not cleared, break and return error
+	 *  6. Read ACSTS = Status Register = 464h, check VSTS bit
+	 */
+
+
+	cs461x_peekBA0(card, BA0_ACSDA);
+
+	/*
+	 *  Setup the AC97 control registers on the CS461x to send the
+	 *  appropriate command to the AC97 to perform the read.
+	 *  ACCAD = Command Address Register = 46Ch
+	 *  ACCDA = Command Data Register = 470h
+	 *  ACCTL = Control Register = 460h
+	 *  set DCV - will clear when process completed
+	 *  set CRW - Read command
+	 *  set VFRM - valid frame enabled
+	 *  set ESYN - ASYNC generation enabled
+	 *  set RSTN - ARST# inactive, AC97 codec not reset
+	 */
+
+	cs461x_pokeBA0(card, BA0_ACCAD, reg);
+	cs461x_pokeBA0(card, BA0_ACCDA, 0);
+	cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
+					     ACCTL_VFRM | ACCTL_ESYN |
+					     ACCTL_RSTN);
+
+
+	/*
+	 *  Wait for the read to occur.
+	 */
+	if(!(card->pm.flags & CS46XX_PM_IDLE))
+		loopcnt = 2000;
+	else
+		loopcnt = 500;
+	for (count = 0; count < loopcnt; count++) {
+		/*
+		 *  First, we want to wait for a short time.
+	 	 */
+		udelay(10);
+		/*
+		 *  Now, check to see if the read has completed.
+		 *  ACCTL = 460h, DCV should be reset by now and 460h = 17h
+		 */
+		if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
+			break;
+	}
+
+	/*
+	 *  Make sure the read completed.
+	 */
+	if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+			"cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg));
+		return 0xffff;
+	}
+
+	/*
+	 *  Wait for the valid status bit to go active.
+	 */
+
+	if(!(card->pm.flags & CS46XX_PM_IDLE))
+		loopcnt = 2000;
+	else
+		loopcnt = 100;
+	for (count = 0; count < loopcnt; count++) {
+		/*
+		 *  Read the AC97 status register.
+		 *  ACSTS = Status Register = 464h
+		 *  VSTS - Valid Status
+		 */
+		if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
+			break;
+		udelay(10);
+	}
+	
+	/*
+	 *  Make sure we got valid status.
+	 */
+	if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+			"cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x \n", reg, tmp));
+		CS_DBGOUT(CS_ERROR, 9, printk(KERN_WARNING "returning 0xffff\n"));
+		return 0xffff;
+	}
+
+	/*
+	 *  Read the data returned from the AC97 register.
+	 *  ACSDA = Status Data Register = 474h
+	 */
+	CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO
+		"cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", 
+			reg, cs461x_peekBA0(card, BA0_ACSDA),
+			cs461x_peekBA0(card, BA0_ACCAD)));
+	return (cs461x_peekBA0(card, BA0_ACSDA));
+}
+
+static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
+{
+	struct cs_card *card = dev->private_data;
+	int count;
+	int val2 = 0;
+	
+	if(reg == AC97_CD_VOL)
+	{
+		val2 = cs_ac97_get(dev, AC97_CD_VOL);
+	}
+	
 	/*
 	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
 	 *  2. Write ACCDA = Command Data Register = 470h    for data to write to AC97
@@ -3286,6 +3814,8 @@
          */
 	cs461x_pokeBA0(card, BA0_ACCAD, reg);
 	cs461x_pokeBA0(card, BA0_ACCDA, val);
+	cs461x_peekBA0(card, BA0_ACCTL);
+	cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
 	cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
 				             ACCTL_ESYN | ACCTL_RSTN);
 	for (count = 0; count < 1000; count++) {
@@ -3304,7 +3834,10 @@
 	 *  Make sure the write completed.
 	 */
 	if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)
-		printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
+	{
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+			"cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val));
+	}
 
 	/*
 	 *	Adjust power if the mixer is selected/deselected according
@@ -3343,7 +3876,11 @@
 			if(val&0x8000 || val == 0x1f1f)
 				card->amplifier_ctrl(card, -1);
 			else /* Mute off power on */
+			{
+				if(card->amp_init)
+					card->amp_init(card);
 				card->amplifier_ctrl(card, 1);
+			}
 		}
 	}
 }
@@ -3355,49 +3892,87 @@
 {
 	int i=0;
 	int minor = MINOR(inode->i_rdev);
-	struct cs_card *card = devs;
+	struct cs_card *card=NULL;
+	struct list_head *entry;
+	unsigned int tmp;
+
+	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
+		  printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n"));
 
-	for (card = devs; card != NULL; card = card->next)
+	list_for_each(entry, &cs46xx_devs)
+	{
+		card = list_entry(entry, struct cs_card, list);
 		for (i = 0; i < NR_AC97; i++)
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor)
 				goto match;
-
+	}
 	if (!card)
+	{
+		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
+			printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
 		return -ENODEV;
-
+	}
  match:
+	if(!card->ac97_codec[i])
+		return -ENODEV;
 	file->private_data = card->ac97_codec[i];
 
 	card->active_ctrl(card,1);
+	if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) )
+	{
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+			"cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) );
+		return -EIO;
+	}
 	MOD_INC_USE_COUNT;
+	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
+		  printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n"));
 	return 0;
 }
 
 static int cs_release_mixdev(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct cs_card *card = devs;
+	struct cs_card *card=NULL;
+	struct list_head *entry;
 	int i;
+	unsigned int tmp;
+	
 	
-	for (card = devs; card != NULL; card = card->next)
+	list_for_each(entry, &cs46xx_devs)
+	{
+		card = list_entry(entry, struct cs_card, list);
 		for (i = 0; i < NR_AC97; i++)
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor)
 				goto match;
-
+	}
 	if (!card)
+	{
+		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
+			printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
 		return -ENODEV;
+	}
 match:
+	if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) )
+	{
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+			"cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) );
+		return -EIO;
+	}
 	card->active_ctrl(card, -1);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+void __exit cs46xx_cleanup_module(void);
 static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
 				unsigned long arg)
 {
 	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+	struct cs_card *card=NULL;
+	struct list_head *entry;
 
 #if CSDEBUG_INTERFACE
         int val;
@@ -3405,7 +3980,8 @@
 	if( 	(cmd == SOUND_MIXER_CS_GETDBGMASK) || 
 		(cmd == SOUND_MIXER_CS_SETDBGMASK) ||
 		(cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
-		(cmd == SOUND_MIXER_CS_SETDBGLEVEL) )
+		(cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
+		(cmd == SOUND_MIXER_CS_APM))
 	{
 	    switch(cmd)
 	    {
@@ -3427,9 +4003,38 @@
 				return -EFAULT;
 			cs_debuglevel = val;
 			return 0;
+
+		case SOUND_MIXER_CS_APM:
+			if (get_user(val, (unsigned long *) arg))
+				return -EFAULT;
+			if(val == CS_IOCTL_CMD_SUSPEND) 
+			{
+				list_for_each(entry, &cs46xx_devs)
+				{
+					card = list_entry(entry, struct cs_card, list);
+					cs46xx_suspend(card);
+				}
+
+			}
+			else if(val == CS_IOCTL_CMD_RESUME)
+			{
+				list_for_each(entry, &cs46xx_devs)
+				{
+					card = list_entry(entry, struct cs_card, list);
+					cs46xx_resume(card);
+				}
+			}
+			else
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+				    "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n",
+					val));
+			}
+			return 0;
+
 		default:
 			CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
-				"cs4281: mixer_ioctl(): ERROR unknown debug cmd\n") );
+				"cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n") );
 			return 0;
 	    }
 	}
@@ -3438,7 +4043,7 @@
 }
 
 static /*const*/ struct file_operations cs_mixer_fops = {
-	owner:		THIS_MODULE,
+	CS_OWNER	CS_THIS_MODULE
 	llseek:		cs_llseek,
 	ioctl:		cs_ioctl_mixdev,
 	open:		cs_open_mixdev,
@@ -3453,6 +4058,9 @@
 	struct ac97_codec *codec;
 	u16 eid;
 
+	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+		"cs46xx: cs_ac97_init()+\n") );
+
 	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
 		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
 			return -ENOMEM;
@@ -3467,13 +4075,21 @@
 		codec->codec_write = cs_ac97_set;
 	
 		if (ac97_probe_codec(codec) == 0)
+		{
+			CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+				"cs46xx: cs_ac97_init()- codec number %d not found\n",
+					num_ac97) );
+			card->ac97_codec[num_ac97] = 0;
 			break;
+		}
+		CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+			"cs46xx: cs_ac97_init() found codec %d\n",num_ac97) );
 
 		eid = cs_ac97_get(codec, AC97_EXTENDED_ID);
 		
 		if(eid==0xFFFFFF)
 		{
-			printk(KERN_WARNING "cs461x: no codec attached ?\n");
+			printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97);
 			kfree(codec);
 			break;
 		}
@@ -3481,17 +4097,25 @@
 		card->ac97_features = eid;
 			
 		if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) {
-			printk(KERN_ERR "cs461x: couldn't register mixer!\n");
+			printk(KERN_ERR "cs46xx: couldn't register mixer!\n");
 			kfree(codec);
 			break;
 		}
-
 		card->ac97_codec[num_ac97] = codec;
 
+		CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+			"cs46xx: cs_ac97_init() ac97_codec[%d] set to 0x%x\n",
+				(unsigned int)num_ac97,
+				(unsigned int)codec));
 		/* if there is no secondary codec at all, don't probe any more */
 		if (!ready_2nd)
-			return num_ac97+1;
+		{
+			num_ac97 += 1;
+			break;
+		}
 	}
+	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+		"cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97));
 	return num_ac97;
 }
 
@@ -3599,96 +4223,426 @@
 		 */
 		cs461x_pokeBA0(card, BA0_SERBAD, idx);
 		/*
-		 *  Tell the serial port to load the new value into the FIFO location.
+		 *  Tell the serial port to load the new value into the FIFO location.
+		 */
+		cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC);
+	}
+	/*
+	 *  Now, if we powered up the devices, then power them back down again.
+	 *  This is kinda ugly, but should never happen.
+	 */
+	if (powerdown)
+		cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
+}
+
+
+static int cs461x_powerdown(struct cs_card *card, unsigned int type)
+{
+	int count;
+	unsigned int tmp=0;
+
+	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
+		"cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
+	if(!powerdown)
+	{
+		CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
+			"cs46xx: cs461x_powerdown() DISABLED exiting\n"));
+		return 0;
+	}
+	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+	CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
+		"cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp));
+/*
+* if powering down only the VREF, and not powering down the DAC/ADC,
+* then do not power down the VREF, UNLESS both the DAC and ADC are not
+* currently powered down.  If powering down DAC and ADC, then
+* it is possible to power down the VREF (ON).
+*/
+	if (    ((type & CS_POWER_MIXVON) && 
+		 (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))) )
+	      && 
+		((tmp & CS_AC97_POWER_CONTROL_ADC_ON) ||
+		 (tmp & CS_AC97_POWER_CONTROL_DAC_ON) ) )
+	{
+		CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
+			"cs46xx: cs461x_powerdown()- 0  unable to powerdown. tmp=0x%x\n",tmp));
+		return 0;
+	}
+	/*
+	 *  Power down indicated areas.
+	 */
+	if(type & CS_POWER_MIXVOFF)
+	{
+
+		CS_DBGOUT(CS_FUNCTION, 4, 
+			printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n"));
+		/*
+		 *  Power down the MIXER (VREF ON) on the AC97 card.  
+		 */
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)
+		{
+			tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
+
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_MIXVOFF_ON))
+					break;
+			}
+			
+			/*
+			 *  Check the status..
+			 */
+			if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_MIXVOFF_ON)
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerdown MIXVOFF failed\n"));
+				return 1;
+			}
+		}
+	}
+	if(type & CS_POWER_MIXVON)
+	{
+
+		CS_DBGOUT(CS_FUNCTION, 4, 
+			printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n"));
+		/*
+		 *  Power down the MIXER (VREF ON) on the AC97 card.  
+		 */
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)
+		{
+			tmp |= CS_AC97_POWER_CONTROL_MIXVON;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
+
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_MIXVON_ON))
+					break;
+			}
+			
+			/*
+			 *  Check the status..
+			 */
+			if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_MIXVON_ON)
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerdown MIXVON failed\n"));
+				return 1;
+			}
+		}
+	}
+	if(type & CS_POWER_ADC)
+	{
+		/*
+		 *  Power down the ADC on the AC97 card.  
+		 */
+		CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n"));
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (tmp & CS_AC97_POWER_CONTROL_ADC_ON)
+		{
+			tmp |= CS_AC97_POWER_CONTROL_ADC;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
+
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_ADC_ON))
+					break;
+			}
+
+			/*
+			 *  Check the status..
+			 */
+			if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_ADC_ON)
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerdown ADC failed\n"));
+				return 1;
+			}
+		}
+	}
+	if(type & CS_POWER_DAC)
+	{
+		/*
+		 *  Power down the DAC on the AC97 card.  
 		 */
-		cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC);
+
+		CS_DBGOUT(CS_FUNCTION, 4, 
+			printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n"));
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (tmp & CS_AC97_POWER_CONTROL_DAC_ON)
+		{
+			tmp |= CS_AC97_POWER_CONTROL_DAC;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
+
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_DAC_ON))
+					break;
+			}
+			
+			/*
+			 *  Check the status..
+			 */
+			if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_DAC_ON)
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerdown DAC failed\n"));
+				return 1;
+			}
+		}
 	}
-	/*
-	 *  Now, if we powered up the devices, then power them back down again.
-	 *  This is kinda ugly, but should never happen.
-	 */
-	if (powerdown)
-		cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
+	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
+		"cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
+	return 0;
 }
 
-static void cs461x_powerup_dac(struct cs_card *card)
+static int cs46xx_powerup(struct cs_card *card, unsigned int type)
 {
 	int count;
-	unsigned int tmp;
+	unsigned int tmp=0;
 
+	CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
+		"cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
 	/*
-	 *  Power on the DACs on the AC97 card.  We turn off the DAC
-	 *  powerdown bit and write the new value of the power control
-	 *  register.
-	 */
-	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
-	if (tmp & 2)	/* already */
-		return;
-	cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfdff);
-
+	* check for VREF and powerup if need to.
+	*/
+	if(type & CS_POWER_MIXVON)
+		type |= CS_POWER_MIXVOFF;
+	if(type & (CS_POWER_DAC | CS_POWER_ADC))
+		type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
 	/*
-	 *  Now, we wait until we sample a DAC ready state.
+	 *  Power up indicated areas.
 	 */
-	for (count = 0; count < 32; count++) {
+	if(type & CS_POWER_MIXVOFF)
+	{
+
+		CS_DBGOUT(CS_FUNCTION, 4, 
+			printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n"));
 		/*
-		 *  First, lets wait a short while to let things settle out a
-		 *  bit, and to prevent retrying the read too quickly.
+		 *  Power up the MIXER (VREF ON) on the AC97 card.  
 		 */
-		udelay(50);
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON))
+		{
+			tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
+
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_MIXVOFF_ON)
+					break;
+			}
+			
+			/*
+			 *  Check the status..
+			 */
+			if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_MIXVOFF_ON))
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerup MIXVOFF failed\n"));
+				return 1;
+			}
+		}
+	}
+	if(type & CS_POWER_MIXVON)
+	{
 
+		CS_DBGOUT(CS_FUNCTION, 4, 
+			printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n"));
 		/*
-		 *  Read the current state of the power control register.
+		 *  Power up the MIXER (VREF ON) on the AC97 card.  
 		 */
-		if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2)
-			break;
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON))
+		{
+			tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
+
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_MIXVON_ON)
+					break;
+			}
+			
+			/*
+			 *  Check the status..
+			 */
+			if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_MIXVON_ON))
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerup MIXVON failed\n"));
+				return 1;
+			}
+		}
 	}
-	
-	/*
-	 *  Check the status..
-	 */
-	if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2))
-		printk(KERN_WARNING "cs461x: powerup DAC failed\n");
-}
+	if(type & CS_POWER_ADC)
+	{
+		/*
+		 *  Power up the ADC on the AC97 card.  
+		 */
+		CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n"));
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON))
+		{
+			tmp &= ~CS_AC97_POWER_CONTROL_ADC;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 
-static void cs461x_powerup_adc(struct cs_card *card)
-{
-	int count;
-	unsigned int tmp;
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
 
-	/*
-	 *  Power on the ADCs on the AC97 card.  We turn off the DAC
-	 *  powerdown bit and write the new value of the power control
-	 *  register.
-	 */
-	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
-	if (tmp & 1)	/* already */
-		return;
-	cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfeff);
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_ADC_ON)
+					break;
+			}
 
-	/*
-	 *  Now, we wait until we sample a ADC ready state.
-	 */
-	for (count = 0; count < 32; count++) {
+			/*
+			 *  Check the status..
+			 */
+			if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_ADC_ON))
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerup ADC failed\n"));
+				return 1;
+			}
+		}
+	}
+	if(type & CS_POWER_DAC)
+	{
 		/*
-		 *  First, lets wait a short while to let things settle out a
-		 *  bit, and to prevent retrying the read too quickly.
+		 *  Power up the DAC on the AC97 card.  
 		 */
-		udelay(50);
 
-		/*
-		 *  Read the current state of the power control register.
-		 */
-		if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1)
-			break;
-	}
+		CS_DBGOUT(CS_FUNCTION, 4, 
+			printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n"));
+		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+		if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON))
+		{
+			tmp &= ~CS_AC97_POWER_CONTROL_DAC;
+			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
+			/*
+			 *  Now, we wait until we sample a ready state.
+			 */
+			for (count = 0; count < 32; count++) {
+				/*
+				 *  First, lets wait a short while to let things settle out a
+				 *  bit, and to prevent retrying the read too quickly.
+				 */
+				udelay(500);
 
-	/*
-	 *  Check the status..
-	 */
-	if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1))
-		printk(KERN_WARNING "cs461x: powerup ADC failed\n");
+				/*
+				 *  Read the current state of the power control register.
+				 */
+				if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+					CS_AC97_POWER_CONTROL_DAC_ON)
+					break;
+			}
+			
+			/*
+			 *  Check the status..
+			 */
+			if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 
+				CS_AC97_POWER_CONTROL_DAC_ON))
+			{
+				CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
+					"cs46xx: powerup DAC failed\n"));
+				return 1;
+			}
+		}
+	}
+	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
+	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
+		"cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
+	return 0;
 }
 
+
 static void cs461x_proc_start(struct cs_card *card)
 {
 	int cnt;
@@ -3713,7 +4667,7 @@
 	}
 
 	if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)
-		printk(KERN_WARNING "cs461x: SPCR_RUNFR never reset\n");
+		printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n");
 }
 
 static void cs461x_proc_stop(struct cs_card *card)
@@ -3725,13 +4679,13 @@
 	cs461x_poke(card, BA1_SPCR, 0);
 }
 
-
-
 static int cs_hardware_init(struct cs_card *card)
 {
 	unsigned long end_time;
-	unsigned int tmp;
+	unsigned int tmp,count;
 	
+	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+		"cs46xx: cs_hardware_init()+\n") );
 	/* 
 	 *  First, blast the clock control register to zero so that the PLL starts
          *  out in a known state, and blast the master serial port control register
@@ -3753,6 +4707,8 @@
          *  there might be logic external to the CS461x that uses the ARST# line
          *  for a reset.
          */
+        cs461x_pokeBA0(card, BA0_ACCTL, 1);
+        udelay(50);
         cs461x_pokeBA0(card, BA0_ACCTL, 0);
         udelay(50);
         cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
@@ -3778,6 +4734,15 @@
 	cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97);
 
 	/*
+	* The part seems to not be ready for a while after a resume.
+	* so, if we are resuming, then wait for 700 mils.  Note that 600 mils
+	* is not enough for some platforms! tested on an IBM Thinkpads and 
+	* reference cards.
+	*/
+	if(!(card->pm.flags & CS46XX_PM_IDLE))
+		mdelay(initdelay);
+
+	/*
 	 *  Write the selected clock control setup to the hardware.  Do not turn on
 	 *  SWCE yet (if requested), so that the devices clocked by the output of
 	 *  PLL are not clocked until the PLL is stable.
@@ -3823,27 +4788,48 @@
 
 	mdelay(5);		/* Shouldnt be needed ?? */
 	
+/*
+* If we are resuming under 2.2.x then we can not schedule a timeout.
+* so, just spin the CPU.
+*/
+	if(card->pm.flags & CS46XX_PM_IDLE)
+	{
 	/*
 	 * Wait for the card ready signal from the AC97 card.
 	 */
-	end_time = jiffies + 3 * (HZ >> 2);
-	do {
+		end_time = jiffies + 3 * (HZ >> 2);
+		do {
 		/*
 		 *  Read the AC97 status register to see if we've seen a CODEC READY
 		 *  signal from the AC97 card.
 		 */
-		if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
-			break;
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(1);
-	} while (time_before(jiffies, end_time));
+			if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
+				break;
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(1);
+		} while (time_before(jiffies, end_time));
+	}
+	else
+	{
+		for (count = 0; count < 100; count++) {
+		// First, we want to wait for a short time.
+			udelay(25);
+
+			if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
+				break;
+		}
+	}
 
 	/*
 	 *  Make sure CODEC is READY.
 	 */
 	if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) {
-		printk(KERN_WARNING "cs461x: create - never read card ready from AC'97\n");
-		printk(KERN_WARNING "cs461x: it is probably not a bug, try using the CS4232 driver\n");
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING  
+			"cs46xx: create - never read card ready from AC'97\n"));
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING  
+			"cs46xx: probably not a bug, try using the CS4232 driver,\n"));
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING  
+			"cs46xx: or turn off any automatic Power Management support in the BIOS.\n"));
 		return -EIO;
 	}
 
@@ -3853,28 +4839,40 @@
 	 */
 	cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
 
+	if(card->pm.flags & CS46XX_PM_IDLE)
+	{
 	/*
 	 *  Wait until we've sampled input slots 3 and 4 as valid, meaning that
 	 *  the card is pumping ADC data across the AC-link.
 	 */
-	end_time = jiffies + 3 * (HZ >> 2);
-	do {
-		/*
-		 *  Read the input slot valid register and see if input slots 3 and
-		 *  4 are valid yet.
-		 */
-		if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
-			break;
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(1);
-	} while (time_before(jiffies, end_time));
+		end_time = jiffies + 3 * (HZ >> 2);
+		do {
+			/*
+			 *  Read the input slot valid register and see if input slots 3 and
+			 *  4 are valid yet.
+			 */
+			if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
+				break;
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(1);
+		} while (time_before(jiffies, end_time));
+	}
+	else
+	{
+		for (count = 0; count < 100; count++) {
+		// First, we want to wait for a short time.
+			udelay(25);
 
+			if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
+				break;
+		}
+	}
 	/*
 	 *  Make sure input slots 3 and 4 are valid.  If not, then return
 	 *  an error.
 	 */
 	if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) {
-		printk(KERN_WARNING "cs461x: create - never read ISV3 & ISV4 from AC'97\n");
+		printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n");
 		return -EIO;
 	}
 
@@ -3885,12 +4883,6 @@
 	cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
 
 	/*
-	 *  Power down the DAC and ADC.  We will power them up (if) when we need
-	 *  them.
-	 */
-	/* cs461x_pokeBA0(card, BA0_AC97_POWERDOWN, 0x300); */
-
-	/*
 	 *  Turn off the Processor by turning off the software clock enable flag in 
 	 *  the clock control register.
 	 */
@@ -3923,14 +4915,20 @@
 	cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
 
 	/* initialize AC97 codec and register /dev/mixer */
-	if (cs_ac97_init(card) <= 0)
-		return -EIO;
-		
-	mdelay(5);		/* Do we need this ?? */
+	if(card->pm.flags & CS46XX_PM_IDLE)
+	{
+		if (cs_ac97_init(card) <= 0)
+		{
+			CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+				"cs46xx: cs_ac97_init() failure\n") );
+			return -EIO;
+		}
+	}
+	else
+	{
+		cs46xx_ac97_resume(card);
+	}
 	
-	cs461x_powerup_adc(card);
-	cs461x_powerup_dac(card);
-
 	cs461x_proc_start(card);
 
 	/*
@@ -3946,11 +4944,29 @@
 	tmp &= ~0x0000003f;
 	tmp |=  0x00000001;
 	cs461x_poke(card, BA1_CIE, tmp);	/* capture interrupt enable */	
+
+	/*
+	 *  If IDLE then Power down the part.  We will power components up 
+	 *  when we need them.  
+	 */
+	if(card->pm.flags & CS46XX_PM_IDLE)
+	{
+		if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+				CS_POWER_MIXVON )) )
+		{
+			CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+				"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
+			return -EIO;
+		}
+	}
+	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO 
+		"cs46xx: cs_hardware_init()- 0\n"));
 	return 0;
 }
 
+
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
    
    
 /*
@@ -3963,65 +4979,77 @@
 	u16 id;
 	char *name;
 	void (*amp)(struct cs_card *, int);
+	void (*amp_init)(struct cs_card *);
 	void (*active)(struct cs_card *, int);
 };
 
-static struct cs_card_type __initdata cards[]={
-	{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL},
-	{0x5053, 0x3357, "Voyetra", amp_voyetra, NULL},
-	{0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL},
+static struct cs_card_type cards[]={
+	{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL},
+	{0x5053, 0x3357, "Voyetra", amp_voyetra, NULL, NULL},
+	{0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL},
+	{0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL},
+	{0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL},
 	/* Not sure if the 570 needs the clkrun hack */
-	{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 },
+	{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, NULL, clkrun_hack},
+	{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack},
+	{PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL, NULL},
+	{0, 0, "Card without SSID set", NULL, NULL, NULL },
 	{0, 0, NULL, NULL, NULL}
 };
 
-#ifdef CS46XX_PM
-static int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-struct cs_state *state = (struct cs_state *) dev->data;
-
-	if (state) {
-		switch(rqst) {
-			case PM_RESUME:
-				printk( KERN_DEBUG "cs46xx: PM resume request\n");
-				cs_hardware_init(state->card);
-				break;
-			case PM_SUSPEND:
-				printk( KERN_DEBUG "cs46xx: PM suspend request\n");
-				stop_dac(state);
-				resync_dma_ptrs(state);
-				break;
-		}
-	}
+MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>");
+MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
 
-return 0;
-}
-#endif
+static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n";
+static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n";
 
-static int __init cs_install(struct pci_dev *pci_dev)
+static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
+				  const struct pci_device_id *pciid)
 {
-	struct cs_card *card;
-	struct cs_card_type *cp = &cards[0];
-#ifdef CS46XX_PM
 	struct pm_dev *pmdev;
-#endif
+	int i,j;
 	u16 ss_card, ss_vendor;
-	
-	
+	struct cs_card *card;
+	dma_addr_t dma_mask;
+	struct cs_card_type *cp = &cards[0];
+
+	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
+		  printk(KERN_INFO "cs46xx: probe()+\n"));
+
+	if (!RSRCISMEMORYREGION(pci_dev, 0) ||
+	    !RSRCISMEMORYREGION(pci_dev, 1)) {
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+			 "cs46xx: probe()- Memory region not assigned\n"));
+		return -1;
+	}
+	if (pci_dev->irq == 0) {
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+			 "cs46xx: probe() IRQ not assigned\n"));
+		return -1;
+	}
+	if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+		      "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
+		return -1;
+	}
+	dma_mask = 0xffffffff;	/* this enables playback and recording */
+
 	pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
 	pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
 
 	if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
-		printk(KERN_ERR "cs461x: out of memory\n");
+		printk(KERN_ERR "cs46xx: out of memory\n");
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(*card));
 
-	card->ba0_addr = pci_resource_start(pci_dev, 0);
-	card->ba1_addr = pci_resource_start(pci_dev, 1);
+	if (pci_enable_device(pci_dev)) {
+		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
+			 "cs46xx: pci_enable_device() failed\n"));
+		goto fail2;
+	}
+	card->ba0_addr = RSRCADDRESS(pci_dev, 0);
+	card->ba1_addr = RSRCADDRESS(pci_dev, 1);
 	card->pci_dev = pci_dev;
 	card->irq = pci_dev->irq;
 	card->magic = CS_CARD_MAGIC;
@@ -4029,7 +5057,8 @@
 
 	pci_set_master(pci_dev);
 
-	printk(KERN_INFO "cs461x: Card found at 0x%08lx and 0x%08lx, IRQ %d\n",
+	printk(cs46xx_banner);
+	printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n",
 	       card->ba0_addr, card->ba1_addr, card->irq);
 
 	card->alloc_pcm_channel = cs_alloc_pcm_channel;
@@ -4037,7 +5066,7 @@
 	card->free_pcm_channel = cs_free_pcm_channel;
 	card->amplifier_ctrl = amp_none;
 	card->active_ctrl = amp_none;
-	
+
 	while (cp->name)
 	{
 		if(cp->vendor == ss_vendor && cp->id == ss_card)
@@ -4045,19 +5074,21 @@
 			card->amplifier_ctrl = cp->amp;
 			if(cp->active)
 				card->active_ctrl = cp->active;
+			if(cp->amp_init)
+				card->amp_init = cp->amp_init;
 			break;
 		}
 		cp++;
 	}
 	if (cp->name==NULL)
 	{
-		printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
+		printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
 			ss_vendor, ss_card, card->ba0_addr, card->ba1_addr,  card->irq);
 	}
 	else
 	{
-		printk(KERN_INFO "cs461x: %s at 0x%08lx/0x%08lx, IRQ %d\n",
-			cp->name, card->ba0_addr, card->ba1_addr, card->irq);
+		printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
+			cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
 	}
 	
 	if (card->amplifier_ctrl==NULL)
@@ -4068,74 +5099,121 @@
 		       
 	if (external_amp == 1)
 	{
-		printk(KERN_INFO "cs461x: Crystal EAPD support forced on.\n");
+		printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
 		card->amplifier_ctrl = amp_voyetra;
 	}
 
 	if (thinkpad == 1)
 	{
+		printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
 		card->active_ctrl = clkrun_hack;
-		printk(KERN_INFO "cs461x: Activating CLKRUN hack for Thinkpad.\n");
 	}
 	
 	card->active_ctrl(card, 1);
-	
+
 	/* claim our iospace and irq */
 	
-	card->ba0 = ioremap(card->ba0_addr, CS461X_BA0_SIZE);
-	card->ba1.name.data0 = ioremap(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
-	card->ba1.name.data1 = ioremap(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
-	card->ba1.name.pmem = ioremap(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
-	card->ba1.name.reg = ioremap(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-	
-	CS_DBGOUT(CS_INIT, 4, printk("card->ba0=0x%.08x\n",(unsigned)card->ba0) );
-	CS_DBGOUT(CS_INIT, 4, printk("card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n",
-		(unsigned)card->ba1.name.data0,
-		(unsigned)card->ba1.name.data1,
-		(unsigned)card->ba1.name.pmem,
-		(unsigned)card->ba1.name.reg) );
+	card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE);
+	card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
+	card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
+	card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
+	card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
+	
+	CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO 
+		"cs46xx: card->ba0=0x%.08x\n",(unsigned)card->ba0) );
+	CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO 
+		"cs46xx: card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n",
+			(unsigned)card->ba1.name.data0,
+			(unsigned)card->ba1.name.data1,
+			(unsigned)card->ba1.name.pmem,
+			(unsigned)card->ba1.name.reg) );
 
 	if(card->ba0 == 0 || card->ba1.name.data0 == 0 ||
 		card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 ||
 		card->ba1.name.reg == 0)
 		goto fail2;
 		
-	if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs461x", card)) {
-		printk(KERN_ERR "cs461x: unable to allocate irq %d\n", card->irq);
+	if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs46xx", card)) {
+		printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq);
 		goto fail2;
 	}
 	/* register /dev/dsp */
 	if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) {
-		printk(KERN_ERR "cs461x: unable to register dsp\n");
+		printk(KERN_ERR "cs46xx: unable to register dsp\n");
 		goto fail;
 	}
 
         /* register /dev/midi */
         if((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
-                printk(KERN_ERR "cs461x: unable to register midi\n");
+                printk(KERN_ERR "cs46xx: unable to register midi\n");
                 
-        if (cs_hardware_init(card)<0)
-        {
+	card->pm.flags |= CS46XX_PM_IDLE;
+	for(i=0;i<5;i++)
+	{
+		if (cs_hardware_init(card) != 0)
+		{
+			CS_DBGOUT(CS_ERROR, 4, printk(
+				"cs46xx: ERROR in cs_hardware_init()... retrying\n"));
+			for (j = 0; j < NR_AC97; j++)
+				if (card->ac97_codec[j] != NULL) {
+					unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
+					kfree (card->ac97_codec[j]);
+				}
+			mdelay(10);
+			continue;
+		}
+		break;
+	}
+	if(i>=4)
+	{
+		CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
+			"cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i));
                 unregister_sound_dsp(card->dev_audio);
                 if(card->dev_midi)
                         unregister_sound_midi(card->dev_midi);
                 goto fail;
-        }
+	}
+
         init_waitqueue_head(&card->midi.open_wait);
         init_MUTEX(&card->midi.open_sem);
         init_waitqueue_head(&card->midi.iwait);
         init_waitqueue_head(&card->midi.owait);
-        card->next = devs;
-        devs = card;
         cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST);   
         cs461x_pokeBA0(card, BA0_MIDCR, 0);   
-        
+
+	/* 
+	* Check if we have to init the amplifier, but probably already done
+	* since the CD logic in the ac97 init code will turn on the ext amp.
+	*/
+	if(cp->amp_init)
+		cp->amp_init(card);
         card->active_ctrl(card, -1);
-#ifdef CS46XX_PM
-        pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), cs46xx_pm_callback);
-        if (pmdev)
-        	pmdev->data = card;
-#endif
+
+	PCI_SET_DRIVER_DATA(pci_dev, card);
+	PCI_SET_DMA_MASK(pci_dev, dma_mask);
+	list_add(&card->list, &cs46xx_devs);
+
+	pmdev = cs_pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), cs46xx_pm_callback);
+	if (pmdev)
+	{
+		CS_DBGOUT(CS_INIT | CS_PM, 4, printk(KERN_INFO
+			 "cs46xx: probe() pm_register() succeeded (0x%x).\n",
+				(unsigned)pmdev));
+		pmdev->data = card;
+	}
+	else
+	{
+		CS_DBGOUT(CS_INIT | CS_PM | CS_ERROR, 2, printk(KERN_INFO
+			 "cs46xx: probe() pm_register() failed (0x%x).\n",
+				(unsigned)pmdev));
+		card->pm.flags |= CS46XX_PM_NOT_REGISTERED;
+	}
+
+	CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=0x%x\n",
+		(unsigned)card->pm.flags,(unsigned)card));
+
+	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+		"cs46xx: probe()- device allocated successfully\n"));
         return 0;
 
 fail:
@@ -4152,15 +5230,22 @@
 	if(card->ba1.name.reg)
 		iounmap(card->ba1.name.reg);
 	kfree(card);
+	CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
+		"cs46xx: probe()- no device allocated\n"));
 	return -ENODEV;
+} // probe_cs46xx
 
-}
+// --------------------------------------------------------------------- 
 
-static void cs_remove(struct cs_card *card)
+static void __devinit cs46xx_remove(struct pci_dev *pci_dev)
 {
+	struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev);
 	int i;
 	unsigned int tmp;
 	
+	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+		 "cs46xx: cs46xx_remove()+\n"));
+
 	card->active_ctrl(card,1);
 	
 	tmp = cs461x_peek(card, BA1_PFIE);
@@ -4196,7 +5281,12 @@
 	 *  Power down the DAC and ADC.  We will power them up (if) when we need
 	 *  them.
 	 */
-	cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x300);
+	if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
+			CS_POWER_MIXVON )) )
+	{
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
+			"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
+	}
 
 	/*
 	 *  Power down the PLL.
@@ -4230,54 +5320,123 @@
         if(card->dev_midi)
                 unregister_sound_midi(card->dev_midi);
 	kfree(card);
-}
+	PCI_SET_DRIVER_DATA(pci_dev,NULL);
+	list_del(&card->list);
 
-MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <audio@crystal.cirrus.com>");
-MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
+	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+		 "cs46xx: cs46xx_remove()-: remove successful\n"));
+}
 
-static char banner[] __initdata = KERN_INFO "Crystal 4280/461x + AC97 Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n";
-static char fndmsg[] __initdata = KERN_INFO "cs461x: Found %d audio device(s).\n";
+enum {
+	CS46XX_4610 = 0,
+	CS46XX_4612,  	/* same as 4624 */
+	CS46XX_4615,  	/* same as 4630 */
+};
 
-static int __init cs_init_driver(void)
-{
-	struct pci_dev *pcidev = NULL;
-	int foundone=0;
+static struct pci_device_id cs46xx_pci_tbl[] __devinitdata = {
+	
+	{PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4610},
+	{PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4612},
+	{PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4615},
+	{0,}
+};
 
-	if (!pci_present())   /* No PCI bus in this machine! */
-		return -ENODEV;
+MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl);
 
-	printk(banner);
+struct pci_driver cs46xx_pci_driver = {
+	name:"cs46xx",
+	id_table:cs46xx_pci_tbl,
+	probe:cs46xx_probe,
+	remove:cs46xx_remove,
+	suspend:CS46XX_SUSPEND_TBL,
+	resume:CS46XX_RESUME_TBL,
+};
 
-	while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) {
-		if (cs_install(pcidev)==0)
-			foundone++;
-	}
-	while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) {
-		if (cs_install(pcidev)==0)
-			foundone++;
+int __init cs46xx_init_module(void)
+{
+	int rtn = 0;
+	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO 
+		"cs46xx: cs46xx_init_module()+ \n"));
+	if (!pci_present()) {	/* No PCI bus in this machine! */
+		CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
+			"cs46xx: cs46xx_init_module()- no pci bus found\n"));
+		return -ENODEV;
 	}
-	while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) {
-		if (cs_install(pcidev)==0)
-			foundone++;
+	rtn = pci_module_init(&cs46xx_pci_driver);
+
+	if(rtn == -ENODEV)
+	{
+		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk( 
+			"cs46xx: Unable to detect valid cs46xx device\n"));
 	}
 
-	printk(fndmsg, foundone);
-	return foundone ? 0 : -ENODEV;
+	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+		  printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn));
+	return rtn;
 }
 
-static void __exit cs_exit_driver(void)
+void __exit cs46xx_cleanup_module(void)
 {
-	struct cs_card *next;
-#ifdef CS46XX_PM
-	pm_unregister_all(cs46xx_pm_callback);
-#endif
-	while(devs)
-	{
-		next=devs->next;
-		cs_remove(devs);
-		devs=next;
+	pci_unregister_driver(&cs46xx_pci_driver);
+	cs_pm_unregister_all(cs46xx_pm_callback);
+	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+		  printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n"));
+}
+
+module_init(cs46xx_init_module);
+module_exit(cs46xx_cleanup_module);
+
+int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	struct cs_card *card;
+
+	CS_DBGOUT(CS_PM, 2, printk(KERN_INFO 
+		"cs46xx: cs46xx_pm_callback dev=0x%x rqst=0x%x card=%d\n",
+			(unsigned)dev,(unsigned)rqst,(unsigned)data));
+	card = (struct cs_card *) dev->data;
+	if (card) {
+		switch(rqst) {
+			case PM_SUSPEND:
+				CS_DBGOUT(CS_PM, 2, printk(KERN_INFO
+					"cs46xx: PM suspend request\n"));
+				if(cs46xx_suspend(card))
+				{
+				    CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
+					"cs46xx: PM suspend request refused\n"));
+					return 1; 
+				}
+				break;
+			case PM_RESUME:
+				CS_DBGOUT(CS_PM, 2, printk(KERN_INFO
+					"cs46xx: PM resume request\n"));
+				if(cs46xx_resume(card))
+				{
+				    CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
+					"cs46xx: PM resume request refused\n"));
+					return 1;
+				}
+				break;
+		}
 	}
+
+	return 0;
+}
+
+static void cs46xx_suspend_tbl(struct pci_dev *pcidev)
+{
+	struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
+		printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
+	cs46xx_suspend(s);
+	return;
+}
+
+static void cs46xx_resume_tbl(struct pci_dev *pcidev)
+{
+	struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
+	CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
+		printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
+	cs46xx_resume(s);
+	return;
 }
 
-module_init(cs_init_driver);
-module_exit(cs_exit_driver);
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xx_wrapper-24.h linux/drivers/sound/cs46xx_wrapper-24.h
--- v2.4.3/linux/drivers/sound/cs46xx_wrapper-24.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/cs46xx_wrapper-24.h	Wed Apr 11 19:02:38 2001
@@ -0,0 +1,56 @@
+/*******************************************************************************
+*
+*      "cs46xx_wrapper.c" --  Cirrus Logic-Crystal CS46XX linux audio driver.
+*
+*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
+*            -- tom woller (twoller@crystal.cirrus.com) or
+*               (pcaudio@crystal.cirrus.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.
+*
+* 01/11/2001 trw - new file from cs4281 wrapper code. 
+*
+*******************************************************************************/
+#ifndef __CS46XX_WRAPPER24_H
+#define __CS46XX_WRAPPER24_H
+
+#include <linux/spinlock.h>
+
+#define CS_OWNER owner:
+#define CS_THIS_MODULE THIS_MODULE,
+void cs46xx_null(struct pci_dev *pcidev) { return; }
+#define cs4x_mem_map_reserve(page) mem_map_reserve(page)
+#define cs4x_mem_map_unreserve(page) mem_map_unreserve(page)
+
+#define free_dmabuf(card, dmabuf) \
+	pci_free_consistent((card)->pci_dev, \
+			    PAGE_SIZE << (dmabuf)->buforder, \
+			    (dmabuf)->rawbuf, (dmabuf)->dmaaddr);
+#define free_dmabuf2(card, dmabuf) \
+	pci_free_consistent((card)->pci_dev, \
+				    PAGE_SIZE << (dmabuf)->buforder_tmpbuff, \
+				    (dmabuf)->tmpbuff, (dmabuf)->dmaaddr_tmpbuff);
+#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
+
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+	 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+	 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+#define PCI_GET_DRIVER_DATA pci_get_drvdata
+#define PCI_SET_DRIVER_DATA pci_set_drvdata
+#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xxpm-24.h linux/drivers/sound/cs46xxpm-24.h
--- v2.4.3/linux/drivers/sound/cs46xxpm-24.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/cs46xxpm-24.h	Wed Apr 11 19:02:38 2001
@@ -0,0 +1,53 @@
+/*******************************************************************************
+*
+*      "cs46xxpm-24.h" --  Cirrus Logic-Crystal CS46XX linux audio driver.
+*
+*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
+*            -- tom woller (twoller@crystal.cirrus.com) or
+*               (pcaudio@crystal.cirrus.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.
+*
+* 12/22/00 trw - new file. 
+*
+*******************************************************************************/
+#ifndef __CS46XXPM24_H
+#define __CS46XXPM24_H
+
+#include <linux/pm.h>
+#include "cs46xxpm.h"
+
+
+#define CS46XX_ACPI_SUPPORT 1
+#ifdef CS46XX_ACPI_SUPPORT
+/* 
+* for now (12/22/00) only enable the pm_register PM support.
+* allow these table entries to be null.
+*/
+static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
+static void cs46xx_resume_tbl(struct pci_dev *pcidev);
+#define cs_pm_register(a, b, c)  0
+#define cs_pm_unregister_all(a) 
+#define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl
+#define CS46XX_RESUME_TBL cs46xx_resume_tbl
+#else
+#define cs_pm_register(a, b, c) pm_register((a), (b), (c));
+#define cs_pm_unregister_all(a) pm_unregister_all((a));
+#define CS46XX_SUSPEND_TBL cs46xx_null
+#define CS46XX_RESUME_TBL cs46xx_null
+#endif
+int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xxpm.h linux/drivers/sound/cs46xxpm.h
--- v2.4.3/linux/drivers/sound/cs46xxpm.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/cs46xxpm.h	Wed Apr 11 19:02:38 2001
@@ -0,0 +1,70 @@
+/*******************************************************************************
+*
+*      "cs46xxpm.h" --  Cirrus Logic-Crystal CS46XX linux audio driver.
+*
+*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
+*            -- tom woller (twoller@crystal.cirrus.com) or
+*               (pcaudio@crystal.cirrus.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.
+*
+* 12/22/00 trw - new file. 
+*
+*******************************************************************************/
+#ifndef __CS46XXPM_H
+#define __CS46XXPM_H
+
+#define CS46XX_AC97_HIGHESTREGTORESTORE 0x26
+#define CS46XX_AC97_NUMBER_RESTORE_REGS (CS46XX_AC97_HIGHESTREGTORESTORE/2-1)
+
+/* PM state defintions */
+#define CS46XX_PM_NOT_REGISTERED	0x1000
+#define CS46XX_PM_IDLE			0x0001
+#define CS46XX_PM_SUSPENDING		0x0002
+#define CS46XX_PM_SUSPENDED		0x0004
+#define CS46XX_PM_RESUMING		0x0008
+#define CS46XX_PM_RESUMED		0x0010
+
+#define CS_POWER_DAC			0x0001
+#define CS_POWER_ADC			0x0002
+#define CS_POWER_MIXVON			0x0004
+#define CS_POWER_MIXVOFF		0x0008
+#define CS_AC97_POWER_CONTROL_ON	0xf000  /* always on bits (inverted) */
+#define CS_AC97_POWER_CONTROL_ADC	0x0100
+#define CS_AC97_POWER_CONTROL_DAC	0x0200
+#define CS_AC97_POWER_CONTROL_MIXVON	0x0400
+#define CS_AC97_POWER_CONTROL_MIXVOFF	0x0800
+#define CS_AC97_POWER_CONTROL_ADC_ON	0x0001
+#define CS_AC97_POWER_CONTROL_DAC_ON	0x0002
+#define CS_AC97_POWER_CONTROL_MIXVON_ON	0x0004
+#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008
+
+struct cs46xx_pm {
+	unsigned long flags;
+	u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
+	u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
+	u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
+	u32 u32SSPM_BITS;
+	u32 ac97[CS46XX_AC97_NUMBER_RESTORE_REGS];
+	u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
+	u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
+	u32 u32hwptr_playback,u32hwptr_capture;
+	unsigned dmabuf_swptr_play;
+	int dmabuf_count_play;
+	unsigned dmabuf_swptr_capture;
+	int dmabuf_count_capture;
+};
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c
--- v2.4.3/linux/drivers/sound/emu10k1/audio.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/sound/emu10k1/audio.c	Wed Apr 18 11:49:11 2001
@@ -272,7 +272,7 @@
 
 					/* Undo marking the pages as reserved */
 					for (i = 0; i < woinst->buffer.pages; i++)
-						mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
+						mem_map_unreserve(virt_to_page(woinst->buffer.addr[i]));
 				}
 
 				emu10k1_waveout_close(wave_dev);
@@ -322,7 +322,7 @@
 
 					/* Undo marking the pages as reserved */
 					for (i = 0; i < woinst->buffer.pages; i++)
-						mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
+						mem_map_unreserve(virt_to_page(woinst->buffer.addr[i]));
 				}
 
 				emu10k1_waveout_close(wave_dev);
@@ -1011,7 +1011,7 @@
 static int emu10k1_audio_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct emu10k1_card *card;
+	struct emu10k1_card *card=NULL;
 	struct list_head *entry;
 	struct emu10k1_wavedevice *wave_dev;
 
@@ -1204,7 +1204,7 @@
 
 				/* Undo marking the pages as reserved */
 				for (i = 0; i < woinst->buffer.pages; i++)
-					mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
+					mem_map_unreserve(virt_to_page(woinst->buffer.addr[i]));
 			}
 
 			emu10k1_waveout_close(wave_dev);
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/emu10k1/cardmi.h linux/drivers/sound/emu10k1/cardmi.h
--- v2.4.3/linux/drivers/sound/emu10k1/cardmi.h	Mon Dec 11 13:02:20 2000
+++ linux/drivers/sound/emu10k1/cardmi.h	Fri Apr 13 20:26:07 2001
@@ -34,6 +34,7 @@
 #define _CARDMI_H
 
 #include "icardmid.h"
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 
 typedef enum
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/emu10k1/timer.h linux/drivers/sound/emu10k1/timer.h
--- v2.4.3/linux/drivers/sound/emu10k1/timer.h	Mon Dec 11 13:02:19 2000
+++ linux/drivers/sound/emu10k1/timer.h	Fri Apr 13 20:26:07 2001
@@ -27,6 +27,7 @@
 #ifndef _TIMER_H
 #define _TIMER_H
 
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include "hwaccess.h"
 
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.4.3/linux/drivers/sound/es1370.c	Tue Mar 20 12:04:58 2001
+++ linux/drivers/sound/es1370.c	Thu Apr 12 12:16:36 2001
@@ -3,7 +3,7 @@
 /*
  *      es1370.c  --  Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
  *
- *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      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
@@ -117,6 +117,11 @@
  *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
  *    07.02.2000   0.33  Use pci_alloc_consistent and pci_register_driver
  *    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>
+ *    07.01.2001   0.36  Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de>
+ *    31.01.2001   0.37  Register/Unregister gameport
+ *                       Fix SETTRIGGER non OSS API conformity
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -159,6 +164,23 @@
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
+#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE)
+#include <linux/gameport.h>
+#else
+struct gameport {
+	int io;
+	int size;
+};
+
+extern inline void gameport_register_port(struct gameport *gameport)
+{
+}
+
+extern inline void gameport_unregister_port(struct gameport *gameport)
+{
+}
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -170,6 +192,7 @@
 #ifndef PCI_VENDOR_ID_ENSONIQ
 #define PCI_VENDOR_ID_ENSONIQ        0x1274    
 #endif
+
 #ifndef PCI_DEVICE_ID_ENSONIQ_ES1370
 #define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
 #endif
@@ -361,6 +384,7 @@
 		unsigned mapped:1;
 		unsigned ready:1;
 		unsigned endcleared:1;
+		unsigned enabled:1;
 		unsigned ossfragshift;
 		int ossmaxfrags;
 		unsigned subdivision;
@@ -375,6 +399,8 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
+
+	struct gameport gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -419,15 +445,16 @@
 
 static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data)
 {
-	unsigned long tmo = jiffies + HZ/10;
+	unsigned long tmo = jiffies + HZ/10, j;
 	
 	do {
+		j = jiffies;
 		if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) {
 			outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC);
 			return;
 		}
 		schedule();
-	} while ((signed)(tmo-jiffies) > 0);
+	} while ((signed)(tmo-j) > 0);
 	printk(KERN_ERR "es1370: write to codec register timeout\n");
 }
 
@@ -600,6 +627,7 @@
 	outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
 	outl(db->dmaaddr, s->io+(reg & 0xff));
 	outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
+	db->enabled = 1;
 	db->ready = 1;
 	return 0;
 }
@@ -1168,7 +1196,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_adc(s);
+			if (s->dma_adc.enabled)
+				start_adc(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1195,7 +1224,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_adc(s);
+		if (s->dma_adc.enabled)
+			start_adc(s);
 	}
         remove_wait_queue(&s->dma_adc.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1238,7 +1268,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_dac2(s);
+			if (s->dma_dac2.enabled)
+				start_dac2(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1266,7 +1297,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac2(s);
+		if (s->dma_dac2.enabled)
+			start_dac2(s);
 	}
         remove_wait_queue(&s->dma_dac2.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1520,25 +1552,31 @@
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
 					return ret;
+				s->dma_adc.enabled = 1;
 				start_adc(s);
-			} else
+			} else {
+				s->dma_adc.enabled = 0;
 				stop_adc(s);
+			}
 		}
 		if (file->f_mode & FMODE_WRITE) {
 			if (val & PCM_ENABLE_OUTPUT) {
 				if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
 					return ret;
+				s->dma_dac2.enabled = 1;
 				start_dac2(s);
-			} else
+			} else {
+				s->dma_dac2.enabled = 0;
 				stop_dac2(s);
+			}
 		}
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-			return ret;
+		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;
@@ -1554,8 +1592,8 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-			return ret;
+		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;
@@ -1575,8 +1613,8 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-			return ret;
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
                 count = s->dma_dac2.count;
@@ -1588,8 +1626,8 @@
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-			return ret;
+		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;
@@ -1606,8 +1644,8 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-			return ret;
+		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;
@@ -1729,6 +1767,7 @@
 		s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV);
 	if (file->f_mode & FMODE_READ) {
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+		s->dma_adc.enabled = 1;
 		s->sctrl &= ~SCTRL_R1FMT;
 		if ((minor & 0xf) == SND_DEV_DSP16)
 			s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT;
@@ -1737,6 +1776,7 @@
 	}
 	if (file->f_mode & FMODE_WRITE) {
 		s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
+		s->dma_dac2.enabled = 1;
 		s->sctrl &= ~SCTRL_P2FMT;
 		if ((minor & 0xf) == SND_DEV_DSP16)
 			s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT;
@@ -1772,8 +1812,8 @@
 	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 	wake_up(&s->open_wait);
 	up(&s->open_sem);
-	return 0;
 	unlock_kernel();
+	return 0;
 }
 
 static /*const*/ struct file_operations es1370_audio_fops = {
@@ -1825,7 +1865,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_dac1(s);
+			if (s->dma_dac1.enabled)
+				start_dac1(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1853,7 +1894,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac1(s);
+		if (s->dma_dac1.enabled)
+			start_dac1(s);
 	}
         remove_wait_queue(&s->dma_dac1.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -2021,13 +2063,16 @@
 		if (val & PCM_ENABLE_OUTPUT) {
 			if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
 				return ret;
+			s->dma_dac1.enabled = 1;
 			start_dac1(s);
-		} else
+		} else {
+			s->dma_dac1.enabled = 0;
 			stop_dac1(s);
+		}
 		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);
@@ -2046,6 +2091,8 @@
                 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);
                 count = s->dma_dac1.count;
@@ -2055,8 +2102,8 @@
 		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;
@@ -2158,6 +2205,7 @@
 		down(&s->open_sem);
 	}
 	s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
+	s->dma_dac1.enabled = 1;
 	spin_lock_irqsave(&s->lock, flags);
 	s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL);
       	s->sctrl &= ~SCTRL_P1FMT;
@@ -2439,6 +2487,7 @@
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
 				set_current_state(TASK_RUNNING);
+				unlock_kernel();
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2560,11 +2609,16 @@
 	/* note: setting CTRL_SERR_DIS is reported to break
 	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
 	s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
+	s->gameport.io = 0;
+	s->gameport.size = 0;
 	if (joystick[devindex]) {
-		if (check_region(0x200, JOY_EXTENT))
-			printk(KERN_ERR "es1370: io port 0x200 in use\n");
-		else
+		if (!request_region(0x200, JOY_EXTENT, "es1370"))
+			printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
+		else {
 			s->ctrl |= CTRL_JYSTK_EN;
+			s->gameport.io = 0x200;
+			s->gameport.size = JOY_EXTENT;
+		}
 	}
 	if (lineout[devindex])
 		s->ctrl |= CTRL_XCTL0;
@@ -2607,6 +2661,9 @@
 		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
 	}
 	set_fs(fs);
+	/* register gameport */
+	gameport_register_port(&s->gameport);
+
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2625,6 +2682,8 @@
  err_dev1:
 	printk(KERN_ERR "es1370: cannot register misc device\n");
 	free_irq(s->irq, s);
+	if (s->gameport.io)
+		release_region(s->gameport.io, s->gameport.size);
  err_irq:
 	release_region(s->io, ES1370_EXTENT);
  err_region:
@@ -2634,22 +2693,26 @@
 
 static void __devinit es1370_remove(struct pci_dev *dev)
 {
-       struct es1370_state *s = pci_get_drvdata(dev);
+	struct es1370_state *s = pci_get_drvdata(dev);
 
-       if (!s)
-               return;
-       list_del(&s->devs);
-       outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */
-       outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
-       synchronize_irq();
-       free_irq(s->irq, s);
-       release_region(s->io, ES1370_EXTENT);
-       unregister_sound_dsp(s->dev_audio);
-       unregister_sound_mixer(s->dev_mixer);
-       unregister_sound_dsp(s->dev_dac);
-       unregister_sound_midi(s->dev_midi);
-       kfree(s);
-       pci_set_drvdata(dev, NULL);
+	if (!s)
+		return;
+	list_del(&s->devs);
+	outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */
+	outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
+	synchronize_irq();
+	free_irq(s->irq, s);
+	if (s->gameport.io) {
+		gameport_unregister_port(&s->gameport);
+		release_region(s->gameport.io, s->gameport.size);
+	}
+	release_region(s->io, ES1370_EXTENT);
+	unregister_sound_dsp(s->dev_audio);
+	unregister_sound_mixer(s->dev_mixer);
+	unregister_sound_dsp(s->dev_dac);
+	unregister_sound_midi(s->dev_midi);
+	kfree(s);
+	pci_set_drvdata(dev, NULL);
 }
 
 static struct pci_device_id id_table[] __devinitdata = {
@@ -2670,7 +2733,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.34 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.37 time " __TIME__ " " __DATE__ "\n");
 	return pci_module_init(&es1370_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.4.3/linux/drivers/sound/es1371.c	Tue Mar 20 12:04:58 2001
+++ linux/drivers/sound/es1371.c	Thu Apr 12 12:16:36 2001
@@ -3,7 +3,7 @@
 /*
  *      es1371.c  --  Creative Ensoniq ES1371.
  *
- *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      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
@@ -102,6 +102,13 @@
  *    01.03.2000   0.26  SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com>
  *                       Use pci_module_init
  *    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>
+ *    05.01.2001   0.29  Hopefully updates will not be required anymore when Creative bumps
+ *                       the CT5880 revision.
+ *                       suggested by Stephan Müller <smueller@chronox.de>
+ *    31.01.2001   0.30  Register/Unregister gameport
+ *                       Fix SETTRIGGER non OSS API conformity
  */
 
 /*****************************************************************************/
@@ -129,6 +136,23 @@
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
+#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE)
+#include <linux/gameport.h>
+#else
+struct gameport {
+	int io;
+	int size;
+};
+
+extern inline void gameport_register_port(struct gameport *gameport)
+{
+}
+
+extern inline void gameport_unregister_port(struct gameport *gameport)
+{
+}
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -168,6 +192,7 @@
 #define ES1371REV_ES1373_B  0x06
 #define ES1371REV_CT5880_A  0x07
 #define CT5880REV_CT5880_C  0x02
+#define CT5880REV_CT5880_D  0x03
 #define ES1371REV_ES1371_B  0x09
 #define EV1938REV_EV1938_A  0x00
 #define ES1371REV_ES1373_8  0x08
@@ -432,6 +457,7 @@
 		unsigned mapped:1;
 		unsigned ready:1;
 		unsigned endcleared:1;
+		unsigned enabled:1;
 		unsigned ossfragshift;
 		int ossmaxfrags;
 		unsigned subdivision;
@@ -446,6 +472,8 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
+
+	struct gameport gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -932,6 +960,7 @@
 	outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE);
 	outl(db->dmaaddr, s->io+(reg & 0xff));
 	outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
+	db->enabled = 1;
 	db->ready = 1;
 	return 0;
 }
@@ -1351,7 +1380,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_adc(s);
+			if (s->dma_adc.enabled)
+				start_adc(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1378,7 +1408,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_adc(s);
+		if (s->dma_adc.enabled)
+			start_adc(s);
 	}
 	remove_wait_queue(&s->dma_adc.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1421,7 +1452,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_dac2(s);
+			if (s->dma_dac2.enabled)
+				start_dac2(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1449,7 +1481,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac2(s);
+		if (s->dma_dac2.enabled)
+			start_dac2(s);
 	}
 	remove_wait_queue(&s->dma_dac2.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1700,25 +1733,31 @@
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
 					return ret;
+				s->dma_adc.enabled = 1;
 				start_adc(s);
-			} else
+			} else {
+				s->dma_adc.enabled = 0;
 				stop_adc(s);
+			}
 		}
 		if (file->f_mode & FMODE_WRITE) {
 			if (val & PCM_ENABLE_OUTPUT) {
 				if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
 					return ret;
+				s->dma_dac2.enabled = 1;
 				start_dac2(s);
-			} else
+			} else {
+				s->dma_dac2.enabled = 0;
 				stop_dac2(s);
+			}
 		}
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-			return ret;
+		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;
@@ -1734,8 +1773,8 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-			return ret;
+		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;
@@ -1755,8 +1794,8 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-			return ret;
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
                 count = s->dma_dac2.count;
@@ -1768,8 +1807,8 @@
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-			return ret;
+		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;
@@ -1786,8 +1825,8 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-			return ret;
+		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;
@@ -1904,10 +1943,12 @@
 	}
 	if (file->f_mode & FMODE_READ) {
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+		s->dma_adc.enabled = 1;
 		set_adc_rate(s, 8000);
 	}
 	if (file->f_mode & FMODE_WRITE) {
 		s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
+		s->dma_dac2.enabled = 1;
 		set_dac2_rate(s, 8000);
 	}
 	spin_lock_irqsave(&s->lock, flags);
@@ -2005,7 +2046,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_dac1(s);
+			if (s->dma_dac1.enabled)
+				start_dac1(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -2033,7 +2075,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac1(s);
+		if (s->dma_dac1.enabled)
+			start_dac1(s);
 	}
 	remove_wait_queue(&s->dma_dac1.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -2192,13 +2235,16 @@
 		if (val & PCM_ENABLE_OUTPUT) {
 			if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
 				return ret;
+			s->dma_dac1.enabled = 1;
 			start_dac1(s);
-		} else
+		} else {
+			s->dma_dac1.enabled = 0;
 			stop_dac1(s);
+		}
 		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);
@@ -2217,6 +2263,8 @@
                 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);
                 count = s->dma_dac1.count;
@@ -2226,8 +2274,8 @@
 		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;
@@ -2329,6 +2377,7 @@
 		down(&s->open_sem);
 	}
 	s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
+	s->dma_dac1.enabled = 1;
 	set_dac1_rate(s, 8000);
 	spin_lock_irqsave(&s->lock, flags);
 	s->sctrl &= ~SCTRL_P1FMT;
@@ -2608,6 +2657,7 @@
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
 				set_current_state(TASK_RUNNING);
+				unlock_kernel();
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2800,12 +2850,26 @@
 		s->ctrl |= CTRL_GPIO_OUT0;
 		printk(KERN_INFO PFX "Running On Gateway 2000 Solo 2510 - Amp On \n");
 	}	
+	s->gameport.io = s->gameport.size = 0;
 	if ((joystick[devindex] & ~0x18) == 0x200) {
-		if (check_region(joystick[devindex], JOY_EXTENT))
+		if (!request_region(joystick[devindex], JOY_EXTENT, "es1371"))
 			printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]);
 		else {
 			s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+			s->gameport.io = joystick[devindex];
+			s->gameport.size = JOY_EXTENT;
 		}
+	} else if (joystick[devindex] == 1) {
+		for (i = 0x218; i >= 0x200; i -= 0x08) {
+			if (request_region(i, JOY_EXTENT, "es1371")) {
+				s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+				s->gameport.io = i;
+				s->gameport.size = JOY_EXTENT;
+				break;
+			}
+		}
+		if (!s->gameport.io)
+			printk(KERN_ERR PFX "no free joystick address found\n");
 	}
 	s->sctrl = 0;
 	cssr = 0;
@@ -2830,7 +2894,7 @@
 	pci_set_master(pcidev);  /* enable bus mastering */
 	/* if we are a 5880 turn on the AC97 */
 	if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
-	    ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev == CT5880REV_CT5880_C) || 
+	    ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev >= CT5880REV_CT5880_C) || 
 	     (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) || 
 	     (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) { 
 		cssr |= CSTAT_5880_AC97_RST;
@@ -2853,7 +2917,7 @@
 	src_init(s);
 	/* codec init */
 	if (!ac97_probe_codec(&s->codec))
-		goto err_dev4;
+		goto err_gp;
 	/* set default values */
 
 	fs = get_fs();
@@ -2873,6 +2937,8 @@
 	set_fs(fs);
 	/* turn on S/PDIF output driver if requested */
 	outl(cssr, s->io+ES1371_REG_STATUS);
+	/* register gameport */
+	gameport_register_port(&s->gameport);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2882,6 +2948,9 @@
 		devindex++;
        	return 0;
 
+ err_gp:
+	if (s->gameport.io)
+		release_region(s->gameport.io, s->gameport.size);
  err_dev4:
 	unregister_sound_dsp(s->dev_dac);
  err_dev3:
@@ -2913,6 +2982,10 @@
 	outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq();
 	free_irq(s->irq, s);
+	if (s->gameport.io) {
+		gameport_unregister_port(&s->gameport);
+		release_region(s->gameport.io, s->gameport.size);
+	}
 	release_region(s->io, ES1371_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
 	unregister_sound_mixer(s->codec.dev_mixer);
@@ -2942,7 +3015,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO PFX "version v0.27 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO PFX "version v0.30 time " __TIME__ " " __DATE__ "\n");
 	return pci_module_init(&es1371_driver);
 }
 
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.4.3/linux/drivers/sound/esssolo1.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/sound/esssolo1.c	Thu Apr 12 12:16:36 2001
@@ -3,7 +3,7 @@
 /*
  *      esssolo1.c  --  ESS Technology Solo1 (ES1946) audio driver.
  *
- *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -70,6 +70,13 @@
  *    19.02.2000   0.14  Use pci_dma_supported to determine if recording should be disabled
  *    13.03.2000   0.15  Reintroduce initialization of a couple of PCI config space registers
  *    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>
+ *    31.01.2001   0.18  Register/Unregister gameport, original patch from
+ *                       Nathaniel Daw <daw@cs.cmu.edu>
+ *                       Fix SETTRIGGER non OSS API conformity
+ *    10.03.2001         provide abs function, prevent picking up a bogus kernel macro
+ *                       for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
  */
 
 /*****************************************************************************/
@@ -98,12 +105,40 @@
 
 #include "dm.h"
 
+#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE)
+#include <linux/gameport.h>
+#else
+struct gameport {
+	int io;
+	int size;
+};
+
+extern inline void gameport_register_port(struct gameport *gameport)
+{
+}
+
+extern inline void gameport_unregister_port(struct gameport *gameport)
+{
+}
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
 
 /* --------------------------------------------------------------------- */
 
+/* prevent picking up a bogus abs macro */
+#undef abs
+extern inline int abs(int x)
+{
+	if (x < 0)
+		return -x;
+	return x;
+}
+
+/* --------------------------------------------------------------------- */
+
 #ifndef PCI_VENDOR_ID_ESS
 #define PCI_VENDOR_ID_ESS         0x125d
 #endif
@@ -154,7 +189,7 @@
 	int dev_dmfm;
 
 	/* hardware resources */
-	unsigned long iobase, sbbase, vcbase, ddmabase, mpubase, gpbase; /* long for SPARC */
+	unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */
 	unsigned int irq;
 
 	/* mixer registers */
@@ -196,6 +231,7 @@
 		unsigned mapped:1;
 		unsigned ready:1;
 		unsigned endcleared:1;
+		unsigned enabled:1;
 		unsigned ossfragshift;
 		int ossmaxfrags;
 		unsigned subdivision;
@@ -211,6 +247,8 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
+
+	struct gameport gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -465,6 +503,7 @@
 		db->numfrag = db->ossmaxfrags;
 	db->fragsamples = db->fragsize >> sample_shift;
 	db->dmasize = db->numfrag << db->fragshift;
+	db->enabled = 1;
 	return 0;
 }
 
@@ -1024,7 +1063,8 @@
 		       read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);
 #endif
 		if (cnt <= 0) {
-			start_adc(s);
+			if (s->dma_adc.enabled)
+				start_adc(s);
 #ifdef DEBUGREC
 			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"
 			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"
@@ -1071,7 +1111,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_adc(s);
+		if (s->dma_adc.enabled)
+			start_adc(s);
 #ifdef DEBUGREC
 		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x\n", 
 		       read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
@@ -1126,7 +1167,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_dac(s);
+			if (s->dma_dac.enabled)
+				start_dac(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1154,7 +1196,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac(s);
+		if (s->dma_dac.enabled)
+			start_dac(s);
 	}
 	remove_wait_queue(&s->dma_dac.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1370,27 +1413,33 @@
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
 					return ret;
+				s->dma_dac.enabled = 1;
 				start_adc(s);
 				if (inb(s->ddmabase+15) & 1)
 					printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
-			} else
+			} else {
+				s->dma_dac.enabled = 0;
 				stop_adc(s);
+			}
 		}
 		if (file->f_mode & FMODE_WRITE) {
 			if (val & PCM_ENABLE_OUTPUT) {
 				if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
 					return ret;
+				s->dma_dac.enabled = 1;
 				start_dac(s);
-			} else
+			} else {
+				s->dma_dac.enabled = 0;
 				stop_dac(s);
+			}
 		}
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
-			return ret;
+		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
 		abinfo.fragsize = s->dma_dac.fragsize;
@@ -1406,8 +1455,8 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-			return ret;
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
 		abinfo.fragsize = s->dma_adc.fragsize;
@@ -1424,8 +1473,8 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
-			return ret;
+		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;
@@ -1437,8 +1486,8 @@
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-			return ret;
+		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;
@@ -1452,8 +1501,8 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
-			return ret;
+		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;
@@ -1606,7 +1655,9 @@
 	s->clkdiv = 96 | 0x80;
 	s->ena = 0;
 	s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+	s->dma_adc.enabled = 1;
 	s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+	s->dma_dac.enabled = 1;
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&s->open_sem);
 	prog_codec(s);
@@ -1933,6 +1984,7 @@
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
 				set_current_state(TASK_RUNNING);
+				unlock_kernel();
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2281,7 +2333,8 @@
 	s->vcbase = pci_resource_start(pcidev, 2);
 	s->ddmabase = s->vcbase + DDMABASE_OFFSET;
 	s->mpubase = pci_resource_start(pcidev, 3);
-	s->gpbase = pci_resource_start(pcidev, 4);
+	s->gameport.io = pci_resource_start(pcidev, 4);
+	s->gameport.size = pci_resource_len(pcidev,4);
 	s->irq = pcidev->irq;
 	if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
 		printk(KERN_ERR "solo1: io ports in use\n");
@@ -2299,13 +2352,19 @@
 		printk(KERN_ERR "solo1: io ports in use\n");
 		goto err_region4;
 	}
+	if (!s->gameport.size)
+		s->gameport.io = 0;
+	if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) {
+		printk(KERN_ERR "solo1: gameport io ports in use\n");
+		s->gameport.io = s->gameport.size = 0;
+	}
 	if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
 		printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
 		goto err_irq;
 	}
  	if (pci_enable_device(pcidev))
 		goto err_irq;
-	printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
+	printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1);
 	/* register devices */
 	if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0)
 		goto err_dev1;
@@ -2317,6 +2376,8 @@
 		goto err_dev4;
 	if (setup_solo1(s))
 		goto err;
+	/* register gameport */
+	gameport_register_port(&s->gameport);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2340,6 +2401,8 @@
 	printk(KERN_ERR "solo1: initialisation error\n");
 	free_irq(s->irq, s);
  err_irq:
+	if (s->gameport.io)
+		release_region(s->gameport.io, s->gameport.size);
 	release_region(s->iobase, IOBASE_EXTENT);
  err_region4:
 	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
@@ -2366,6 +2429,10 @@
 	synchronize_irq();
 	pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
 	free_irq(s->irq, s);
+	if (s->gameport.io) {
+		gameport_unregister_port(&s->gameport);
+		release_region(s->gameport.io, s->gameport.size);
+	}
 	release_region(s->iobase, IOBASE_EXTENT);
 	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 	release_region(s->ddmabase, DDMABASE_EXTENT);
@@ -2397,7 +2464,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.16 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.18 time " __TIME__ " " __DATE__ "\n");
 	if (!pci_register_driver(&solo1_driver)) {
 		pci_unregister_driver(&solo1_driver);
                 return -ENODEV;
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.4.3/linux/drivers/sound/i810_audio.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/sound/i810_audio.c	Wed Apr 18 11:49:12 2001
@@ -101,8 +101,11 @@
 #endif
 
 static int ftsodell=0;
+static int strict_clocking=0;
 static unsigned int clocking=48000;
 
+//#define DEBUG
+//#define DEBUG2
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -169,6 +172,7 @@
 #define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */
 #define DMA_INT_LVI		(1<<2)  /* last valid done */
 #define DMA_INT_CELV		(1<<1)  /* last valid is current */
+#define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */
 #define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
 
 /* interrupts for the whole chip */
@@ -183,7 +187,7 @@
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
 
-#define DRIVER_VERSION "0.01"
+#define DRIVER_VERSION "0.02"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -247,7 +251,7 @@
 	struct dmabuf {
 		/* wave sample stuff */
 		unsigned int rate;
-		unsigned char fmt, enable;
+		unsigned char fmt, enable, trigger;
 
 		/* hardware channel */
 		struct i810_channel *read_channel;
@@ -277,10 +281,9 @@
 		/* OSS stuff */
 		unsigned mapped:1;
 		unsigned ready:1;
-		unsigned endcleared:1;
 		unsigned update_flag;
-		unsigned ossfragshift;
-		int ossmaxfrags;
+		unsigned ossfragsize;
+		unsigned ossmaxfrags;
 		unsigned subdivision;
 	} dmabuf;
 };
@@ -408,8 +411,11 @@
 	/*
 	 *	Adjust for misclocked crap
 	 */
-	 
 	rate = ( rate * clocking)/48000;
+	if(strict_clocking && rate < 8000) {
+		rate = 8000;
+		dmabuf->rate = (rate * 48000)/clocking;
+	}
 	
 	if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE))
 	{
@@ -456,6 +462,10 @@
 	 */
 	 
 	rate = ( rate * clocking)/48000;
+	if(strict_clocking && rate < 8000) {
+		rate = 8000;
+		dmabuf->rate = (rate * 48000)/clocking;
+	}
 	
 	if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE))
 	{
@@ -478,34 +488,10 @@
 	return dmabuf->rate;
 }
 
-/* prepare channel attributes for playback */ 
-static void i810_play_setup(struct i810_state *state)
-{
-//	struct dmabuf *dmabuf = &state->dmabuf;
-//	struct i810_channel *channel = dmabuf->channel;
-	/* Fixed format. .. */
-	//if (dmabuf->fmt & I810_FMT_16BIT)
-	//if (dmabuf->fmt & I810_FMT_STEREO)
-}
-
-/* prepare channel attributes for recording */
-static void i810_rec_setup(struct i810_state *state)
-{
-//	u16 w;
-//	struct i810_card *card = state->card;
-//	struct dmabuf *dmabuf = &state->dmabuf;
-//	struct i810_channel *channel = dmabuf->channel;
-
-	/* Enable AC-97 ADC (capture) */
-//	if (dmabuf->fmt & I810_FMT_16BIT) {
-//	if (dmabuf->fmt & I810_FMT_STEREO)
-}
-
-
 /* get current playback/recording dma buffer pointer (byte offset from LBA),
    called with spinlock held! */
    
-extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state)
+extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state, int rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned int civ, offset;
@@ -513,17 +499,13 @@
 	
 	if (!dmabuf->enable)
 		return 0;
-	if (dmabuf->enable & DAC_RUNNING)
-		c = dmabuf->write_channel;
-	else if (dmabuf->enable & ADC_RUNNING)
+	if (rec)
 		c = dmabuf->read_channel;
-	else {
-		printk("i810_audio: invalid dmabuf->enable state in get_dma_addr\n");
-		return 0;
-	}
+	else
+		c = dmabuf->write_channel;
 	do {
 		civ = inb(state->card->iobase+c->port+OFF_CIV);
-		offset = (civ + 1) * (dmabuf->dmasize/SG_LEN) -
+		offset = (civ + 1) * dmabuf->fragsize -
 			      2 * inw(state->card->iobase+c->port+OFF_PICB);
 		/* CIV changed before we read PICB (very seldom) ?
 		 * then PICB was rubbish, so try again */
@@ -532,22 +514,26 @@
 	return offset;
 }
 
-static void resync_dma_ptrs(struct i810_state *state, int rec)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	struct i810_channel *c;
-	int offset;
-
-	if(rec) {
-		c = dmabuf->read_channel;
-	} else {
-		c = dmabuf->write_channel;
-	}
-	offset = inb(state->card->iobase+c->port+OFF_CIV);
-	offset *= (dmabuf->dmasize/SG_LEN);
-	
-	dmabuf->hwptr=dmabuf->swptr = offset;
-}
+//static void resync_dma_ptrs(struct i810_state *state, int rec)
+//{
+//	struct dmabuf *dmabuf = &state->dmabuf;
+//	struct i810_channel *c;
+//	int offset;
+//
+//	if(rec) {
+//		c = dmabuf->read_channel;
+//	} else {
+//		c = dmabuf->write_channel;
+//	}
+//	if(c==NULL)
+//		return;
+//	offset = inb(state->card->iobase+c->port+OFF_CIV);
+//	if(offset == inb(state->card->iobase+c->port+OFF_LVI))
+//		offset++;
+//	offset *= dmabuf->fragsize;
+//	
+//	dmabuf->hwptr=dmabuf->swptr = offset;
+//}
 	
 /* Stop recording (lock held) */
 extern __inline__ void __stop_adc(struct i810_state *state)
@@ -575,12 +561,13 @@
 	struct i810_card *card = state->card;
 	unsigned long flags;
 
-	spin_lock_irqsave(&card->lock, flags);
-	if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) {
+	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
+	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+		spin_lock_irqsave(&card->lock, flags);
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | 1<<2 | 1, card->iobase + PI_CR);
+		outb((1<<4) | (1<<2) | 1, card->iobase + PI_CR);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
-	spin_unlock_irqrestore(&card->lock, flags);
 }
 
 /* stop playback (lock held) */
@@ -609,12 +596,13 @@
 	struct i810_card *card = state->card;
 	unsigned long flags;
 
-	spin_lock_irqsave(&card->lock, flags);
-	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
+	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+		spin_lock_irqsave(&card->lock, flags);
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR);
+		outb((1<<4) | (1<<2) | 1, card->iobase + PO_CR);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
-	spin_unlock_irqrestore(&card->lock, flags);
 }
 
 #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
@@ -625,18 +613,29 @@
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	void *rawbuf= NULL;
-	int order;
+	int order, size;
 	struct page *page, *pend;
 
-	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
-	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+	/* If we don't have any oss frag params, then use our default ones */
+	if(dmabuf->ossmaxfrags == 0)
+		dmabuf->ossmaxfrags = 4;
+	if(dmabuf->ossfragsize == 0)
+		dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
+	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+
+	/* alloc enough to satisfy the oss params */
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+		if ( (PAGE_SIZE<<order) > size )
+			continue;
 		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
 						   PAGE_SIZE << order,
 						   &dmabuf->dma_handle)))
 			break;
+	}
 	if (!rawbuf)
 		return -ENOMEM;
 
+
 #ifdef DEBUG
 	printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",
 	       PAGE_SIZE << order, order, rawbuf);
@@ -677,52 +676,53 @@
 	struct dmabuf *dmabuf = &state->dmabuf;
 	struct i810_channel *c;
 	struct sg_item *sg;
-	unsigned bytepersec;
-	unsigned bufsize;
 	unsigned long flags;
 	int ret;
-	unsigned fragsize;
+	unsigned fragint;
 	int i;
 
 	spin_lock_irqsave(&state->card->lock, flags);
-	resync_dma_ptrs(state, rec);
+	if(dmabuf->enable & DAC_RUNNING)
+		__stop_dac(state);
+	if(dmabuf->enable & ADC_RUNNING)
+		__stop_adc(state);
 	dmabuf->total_bytes = 0;
 	dmabuf->count = dmabuf->error = 0;
+	dmabuf->swptr = dmabuf->hwptr = 0;
 	spin_unlock_irqrestore(&state->card->lock, flags);
 
 	/* allocate DMA buffer if not allocated yet */
-	if (!dmabuf->rawbuf)
-		if ((ret = alloc_dmabuf(state)))
-			return ret;
+	if (dmabuf->rawbuf)
+		dealloc_dmabuf(state);
+	if ((ret = alloc_dmabuf(state)))
+		return ret;
 
 	/* FIXME: figure out all this OSS fragment stuff */
-	/* sample_shift is for 16 byte samples, add an extra shift for bytes */
-	bytepersec = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1);
-	bufsize = PAGE_SIZE << dmabuf->buforder;
-	if (dmabuf->ossfragshift) {
-		if ((1000 << dmabuf->ossfragshift) < bytepersec)
-			dmabuf->fragshift = ld2(bytepersec/1000);
-		else
-			dmabuf->fragshift = dmabuf->ossfragshift;
+	/* I did, it now does what it should according to the OSS API.  DL */
+	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
+	dmabuf->numfrag = SG_LEN;
+	dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
+	dmabuf->fragsamples = dmabuf->fragsize >> 1;
+
+	memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
+
+	if(dmabuf->ossmaxfrags == 4) {
+		fragint = 8;
+		dmabuf->ossfragsize = dmabuf->dmasize>>2;
+		dmabuf->fragshift = 2;
+	} else if (dmabuf->ossmaxfrags == 8) {
+		fragint = 4;
+		dmabuf->ossfragsize = dmabuf->dmasize>>3;
+		dmabuf->fragshift = 3;
+	} else if (dmabuf->ossmaxfrags == 16) {
+		fragint = 2;
+		dmabuf->ossfragsize = dmabuf->dmasize>>4;
+		dmabuf->fragshift = 4;
 	} else {
-		/* lets hand out reasonable big ass buffers by default */
-		dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+		fragint = 1;
+		dmabuf->ossfragsize = dmabuf->dmasize>>5;
+		dmabuf->fragshift = 5;
 	}
-	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
-	while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
-		dmabuf->fragshift--;
-		dmabuf->numfrag = bufsize >> dmabuf->fragshift;
-	}
-	dmabuf->fragsize = 1 << dmabuf->fragshift;
-	if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)
-		dmabuf->numfrag = dmabuf->ossmaxfrags;
-	dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
-	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
-
-	memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80,
-	       dmabuf->dmasize);
-
-	fragsize = bufsize / SG_LEN;
 	/*
 	 *	Now set up the ring 
 	 */
@@ -737,24 +737,26 @@
 		 *	way (we might want more interrupts later..) 
 		 */
 	  
-		for(i=0;i<32;i++)
+		for(i=0;i<dmabuf->numfrag;i++)
 		{
-			sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i);
-			sg->control=(fragsize>>sample_shift[dmabuf->fmt]);
-			sg->control|=CON_IOC;
+			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
+			// the card will always be doing 16bit stereo
+			sg->control=dmabuf->fragsamples;
+			sg->control|=CON_BUFPAD;
+			// set us up to get IOC interrupts as often as needed to
+			// satisfy numfrag requirements, no more
+			if( ((i+1) % fragint) == 0) {
+				sg->control|=CON_IOC;
+			}
 			sg++;
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
 		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-		outb(31, state->card->iobase+c->port+OFF_LVI);
 		outb(0, state->card->iobase+c->port+OFF_CIV);
+		outb(0, state->card->iobase+c->port+OFF_LVI);
+		dmabuf->count = 0;
 
-		if (c == dmabuf->read_channel) {
-			i810_rec_setup(state);
-		} else {
-			i810_play_setup(state);
-		}
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		if(c != dmabuf->write_channel)
@@ -775,36 +777,115 @@
 
 	return 0;
 }
-/*
- * Clear the rest of the last i810 dma buffer, normally there is no rest
- * because the OSS fragment size is the same as the size of this buffer.
- */
-static void i810_clear_tail(struct i810_state *state)
+
+static void __i810_update_lvi(struct i810_state *state, int rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned swptr;
-	unsigned char silence = (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80;
-	unsigned int len;
-	unsigned long flags;
+	int x, port;
+	
+	port = state->card->iobase;
+	if(rec)
+		port += dmabuf->read_channel->port;
+	else
+		port += dmabuf->write_channel->port;
 
-	spin_lock_irqsave(&state->card->lock, flags);
-	swptr = dmabuf->swptr;
-	spin_unlock_irqrestore(&state->card->lock, flags);
+	if(dmabuf->mapped) {
+		if(rec)
+			dmabuf->swptr = (dmabuf->hwptr + dmabuf->dmasize
+				       	- dmabuf->count) % dmabuf->dmasize;
+		else
+			dmabuf->swptr = (dmabuf->hwptr + dmabuf->count)
+			       		% dmabuf->dmasize;
+	}
+	/*
+	 * two special cases, count == 0 on write
+	 * means no data, and count == dmasize
+	 * means no data on read, handle appropriately
+	 */
+	if(!rec && dmabuf->count == 0) {
+		outb(inb(port+OFF_CIV),port+OFF_LVI);
+		return;
+	}
+	if(rec && dmabuf->count == dmabuf->dmasize) {
+		outb(inb(port+OFF_CIV),port+OFF_LVI);
+		return;
+	}
+	/* swptr - 1 is the tail of our transfer */
+	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
+	x /= dmabuf->fragsize;
+	outb(x&31, port+OFF_LVI);
+}
 
-	if(dmabuf->dmasize)
-		len = swptr % (dmabuf->dmasize/SG_LEN);
-	else
-		len = 0;
-	
-	memset(dmabuf->rawbuf + swptr, silence, len);
+static void i810_update_lvi(struct i810_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
 
+	if(!dmabuf->ready)
+		return;
 	spin_lock_irqsave(&state->card->lock, flags);
-	dmabuf->swptr += len;
-	dmabuf->count += len;
+	__i810_update_lvi(state, rec);
 	spin_unlock_irqrestore(&state->card->lock, flags);
+}
 
-	/* restart the dma machine in case it is halted */
-	start_dac(state);
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
+static void i810_update_ptr(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned hwptr;
+	int diff;
+
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == ADC_RUNNING) {
+		/* update hardware pointer */
+		hwptr = i810_get_dma_addr(state, 1);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+//		printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+		if (dmabuf->count > dmabuf->dmasize) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a read */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if(inb(state->card->iobase + PI_CIV) !=
+			   inb(state->card->iobase + PI_LVI)) {
+				printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count > dmabuf->ossfragsize)
+			wake_up(&dmabuf->wait);
+	}
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == DAC_RUNNING) {
+		/* update hardware pointer */
+		hwptr = i810_get_dma_addr(state, 0);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+//		printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if(inb(state->card->iobase + PO_CIV) !=
+			   inb(state->card->iobase + PO_LVI)) {
+				printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
+				printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
+					"count %d\n",
+					inb(state->card->iobase + PO_CIV),
+					inb(state->card->iobase + PO_LVI),
+					dmabuf->hwptr, dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize-dmabuf->ossfragsize))
+			wake_up(&dmabuf->wait);
+	}
 }
 
 static int drain_dac(struct i810_state *state, int nonblock)
@@ -815,7 +896,7 @@
 	unsigned long tmo;
 	int count;
 
-	if (dmabuf->mapped || !dmabuf->ready)
+	if (!dmabuf->ready)
 		return 0;
 
 	add_wait_queue(&dmabuf->wait, &wait);
@@ -825,6 +906,7 @@
 		current->state = TASK_INTERRUPTIBLE;
 
 		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
 		count = dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -834,6 +916,10 @@
 		if (signal_pending(current))
 			break;
 
+		i810_update_lvi(state,0);
+		if (dmabuf->enable != DAC_RUNNING)
+			start_dac(state);
+
 		if (nonblock) {
 			remove_wait_queue(&dmabuf->wait, &wait);
 			current->state = TASK_RUNNING;
@@ -841,7 +927,7 @@
 		}
 
 		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
-		tmo >>= sample_shift[dmabuf->fmt];
+		tmo >>= 1;
 		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
 			printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
 			break;
@@ -855,88 +941,18 @@
 	return 0;
 }
 
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void i810_update_ptr(struct i810_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned hwptr, swptr;
-	int clear_cnt = 0;
-	int diff;
-	unsigned char silence;
-//	unsigned half_dmasize;
-
-	/* update hardware pointer */
-	hwptr = i810_get_dma_addr(state);
-	diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-//	printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-	dmabuf->hwptr = hwptr;
-	dmabuf->total_bytes += diff;
-
-	/* error handling and process wake up for DAC */
-	if (dmabuf->enable == ADC_RUNNING) {
-		if (dmabuf->mapped) {
-			dmabuf->count -= diff;
-			if (dmabuf->count >= (signed)dmabuf->fragsize)
-				wake_up(&dmabuf->wait);
-		} else {
-			dmabuf->count += diff;
-
-			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
-				/* buffer underrun or buffer overrun, we have no way to recover
-				   it here, just stop the machine and let the process force hwptr
-				   and swptr to sync */
-				__stop_adc(state);
-				dmabuf->error++;
-			}
-			else if (!dmabuf->endcleared) {
-				swptr = dmabuf->swptr;
-				silence = (dmabuf->fmt & I810_FMT_16BIT ? 0 : 0x80);
-				if (dmabuf->count < (signed) dmabuf->fragsize) 
-				{
-					clear_cnt = dmabuf->fragsize;
-					if ((swptr + clear_cnt) > dmabuf->dmasize)
-						clear_cnt = dmabuf->dmasize - swptr;
-					memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
-					dmabuf->endcleared = 1;
-				}
-			}			
-			if (dmabuf->count < (signed)dmabuf->dmasize/2) {
-				wake_up(&dmabuf->wait);
-			}
-		}
-	}
-	/* error handling and process wake up for DAC */
-	if (dmabuf->enable == DAC_RUNNING) {
-		if (dmabuf->mapped) {
-			dmabuf->count += diff;
-			if (dmabuf->count >= (signed)dmabuf->fragsize)
-				wake_up(&dmabuf->wait);
-		} else {
-			dmabuf->count -= diff;
-
-			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
-				/* buffer underrun or buffer overrun, we have no way to recover
-				   it here, just stop the machine and let the process force hwptr
-				   and swptr to sync */
-				__stop_dac(state);
-				printk(KERN_WARNING "i810_audio: DMA overrun on send\n");
-				dmabuf->error++;
-			}
-			if (dmabuf->count < (signed)dmabuf->dmasize/2) {
-				wake_up(&dmabuf->wait);
-			}
-		}
-	}
-}
-
 static void i810_channel_interrupt(struct i810_card *card)
 {
-	int i;
-
+	int i, count;
+	
+#ifdef DEBUG_INTERRUPTS
+	printk("CHANNEL ");
+#endif
 	for(i=0;i<NR_HW_CH;i++)
 	{
 		struct i810_state *state = card->states[i];
 		struct i810_channel *c;
+		struct dmabuf *dmabuf;
 		unsigned long port = card->iobase;
 		u16 status;
 		
@@ -944,35 +960,56 @@
 			continue;
 		if(!state->dmabuf.ready)
 			continue;
-		if(state->dmabuf.enable & DAC_RUNNING)
-			c=state->dmabuf.write_channel;
+		dmabuf = &state->dmabuf;
+		if(dmabuf->enable & DAC_RUNNING)
+			c=dmabuf->write_channel;
 		else
-			c=state->dmabuf.read_channel;
+			c=dmabuf->read_channel;
 		
 		port+=c->port;
 		
 		status = inw(port + OFF_SR);
-		
+#ifdef DEBUG_INTERRUPTS
+		printk("NUM %d PORT %lX IRQ ( ST%d ", c->num, c->port, status);
+#endif
 		if(status & DMA_INT_COMPLETE)
 		{
-			int x;
-			/* Keep the card chasing its tail */
-			outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI);
 			i810_update_ptr(state);
+#ifdef DEBUG_INTERRUPTS
+			printk("COMP%d ",x);
+#endif
 		}
 		if(status & DMA_INT_LVI)
 		{
-			/* Back to the start */
 			i810_update_ptr(state);
-			outb(0, port + OFF_CR);
+			wake_up(&dmabuf->wait);
+#ifdef DEBUG_INTERRUPTS
+			printk("LVI ");
+#endif
+		}
+		if(status & DMA_INT_DCH)
+		{
+			i810_update_ptr(state);
+			if(dmabuf->enable & DAC_RUNNING)
+				count = dmabuf->count;
+			else
+				count = dmabuf->dmasize - dmabuf->count;
+			if(count > 0) {
+				outb(inb(port+OFF_CR) | 1, port+OFF_CR);
+			} else {
+				wake_up(&dmabuf->wait);
+#ifdef DEBUG_INTERRUPTS
+				printk("DCH - STOP ");
+#endif
+			}
 		}
 		outw(status & DMA_INT_MASK, port + OFF_SR);
 	}
+#ifdef DEBUG_INTERRUPTS
+	printk(")\n");
+#endif
 }
 
-static u32 jiff = 0;
-static u32 jiff_count = 0;
-
 static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct i810_card *card = (struct i810_card *)dev_id;
@@ -1009,10 +1046,10 @@
 	struct dmabuf *dmabuf = &state->dmabuf;
 	ssize_t ret;
 	unsigned long flags;
-	unsigned swptr;
+	unsigned int swptr;
 	int cnt;
 
-#ifdef DEBUG
+#ifdef DEBUG2
 	printk("i810_audio: i810_read called, count = %d\n", count);
 #endif
 
@@ -1026,43 +1063,45 @@
 		dmabuf->ready = 0;
 		dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
 		if (!dmabuf->read_channel) {
-			return -ENODEV;
+			return -EBUSY;
 		}
 	}
 	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	dmabuf->trigger &= ~PCM_ENABLE_OUTPUT;
 	ret = 0;
 
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
-		if (dmabuf->count > (signed) dmabuf->dmasize) {
-			/* buffer overrun, we are recovering from sleep_on_timeout,
-			   resync hwptr and swptr, make process flush the buffer */
-			dmabuf->count = dmabuf->dmasize;
-			dmabuf->swptr = dmabuf->hwptr;
-		}
 		swptr = dmabuf->swptr;
-		cnt = dmabuf->dmasize - swptr;
-		if (dmabuf->count < cnt)
-			cnt = dmabuf->count;
+		if (dmabuf->count > dmabuf->dmasize) {
+			dmabuf->count = 0;
+		}
+		cnt = dmabuf->count;
+		if(cnt > (dmabuf->dmasize - swptr))
+			cnt = dmabuf->dmasize - swptr;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
 			unsigned long tmo;
-			/* buffer is empty, start the dma machine and wait for data to be
-			   recorded */
-			start_adc(state);
+			// are we already running?  only start us if we aren't running
+			// currently
+			i810_update_lvi(state,1);
+			if(!dmabuf->enable) {
+				dmabuf->trigger |= PCM_ENABLE_INPUT;
+				start_adc(state);
+			}
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				return ret;
 			}
 			/* This isnt strictly right for the 810  but it'll do */
 			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
-			tmo >>= sample_shift[dmabuf->fmt];
+			tmo >>= 1;
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1102,8 +1141,9 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_adc(state);
 	}
+	i810_update_lvi(state,1);
+	start_adc(state);
 	return ret;
 }
 
@@ -1115,10 +1155,10 @@
 	struct dmabuf *dmabuf = &state->dmabuf;
 	ssize_t ret;
 	unsigned long flags;
-	unsigned swptr;
-	int cnt;
+	unsigned int swptr = 0;
+	int cnt, x;
 
-#ifdef DEBUG
+#ifdef DEBUG2
 	printk("i810_audio: i810_write called, count = %d\n", count);
 #endif
 
@@ -1132,25 +1172,23 @@
 		dmabuf->ready = 0;
 		dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
 		if(!dmabuf->write_channel)
-			return -ENODEV;
+			return -EBUSY;
 	}
 	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	dmabuf->trigger &= ~PCM_ENABLE_INPUT;
 	ret = 0;
 
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
+		swptr = dmabuf->swptr;
 		if (dmabuf->count < 0) {
-			/* buffer underrun, we are recovering from sleep_on_timeout,
-			   resync hwptr and swptr */
 			dmabuf->count = 0;
-			dmabuf->swptr = dmabuf->hwptr;
 		}
-		swptr = dmabuf->swptr;
 		cnt = dmabuf->dmasize - swptr;
-		if (dmabuf->count + cnt > dmabuf->dmasize)
+		if(cnt > (dmabuf->dmasize - dmabuf->count))
 			cnt = dmabuf->dmasize - dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -1158,16 +1196,20 @@
 			cnt = count;
 		if (cnt <= 0) {
 			unsigned long tmo;
-			/* buffer is full, start the dma machine and wait for data to be
-			   played */
-			start_dac(state);
+			// There is data waiting to be played
+			i810_update_lvi(state,0);
+			if(!dmabuf->enable && dmabuf->count) {
+				/* force the starting incase SETTRIGGER has been used */
+				/* to stop it, otherwise this is a deadlock situation */
+				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
+				start_dac(state);
+			}
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				return ret;
 			}
 			/* Not strictly correct but works */
-			tmo = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1);
-			tmo = dmabuf->dmasize * HZ / tmo;
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 4);
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1184,6 +1226,7 @@
 #endif
 				/* a buffer underrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have data to play */
+				//return ret;
 			}
 			if (signal_pending(current)) {
 				if (!ret) ret = -ERESTARTSYS;
@@ -1191,7 +1234,7 @@
 			}
 			continue;
 		}
-		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+		if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) {
 			if (!ret) ret = -EFAULT;
 			return ret;
 		}
@@ -1201,14 +1244,21 @@
 		spin_lock_irqsave(&state->card->lock, flags);
 		dmabuf->swptr = swptr;
 		dmabuf->count += cnt;
-		dmabuf->endcleared = 0;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac(state);
 	}
+	if (swptr % dmabuf->fragsize) {
+		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
+		if((x + dmabuf->count) < dmabuf->dmasize)
+			memset(dmabuf->rawbuf + swptr, '\0', x);
+	}
+	i810_update_lvi(state,0);
+	if (!dmabuf->enable && dmabuf->count >= dmabuf->ossfragsize)
+		start_dac(state);
+
 	return ret;
 }
 
@@ -1220,21 +1270,9 @@
 	unsigned long flags;
 	unsigned int mask = 0;
 
-	if (file->f_mode & FMODE_WRITE) {
-		if (!dmabuf->write_channel)
-			return 0;
-		if (!dmabuf->ready && prog_dmabuf(state, 0))
-			return 0;
-		poll_wait(file, &dmabuf->wait, wait);
-	} else { 
-	// don't do both read and write paths or we won't get woke up properly
-	// when we have a file with both permissions
-		if (!dmabuf->read_channel)
-			return 0;
-		if (!dmabuf->ready && prog_dmabuf(state, 1))
-			return 0;
-		poll_wait(file, &dmabuf->wait, wait);
-	}
+	if(!dmabuf->ready)
+		return 0;
+	poll_wait(file, &dmabuf->wait, wait);
 	spin_lock_irqsave(&state->card->lock, flags);
 	i810_update_ptr(state);
 	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
@@ -1262,22 +1300,24 @@
 	int ret = -EINVAL;
 	unsigned long size;
 
-	/* 
-	 *	Until we figure out a few problems
-	 */
-	 
 	lock_kernel();
 	if (vma->vm_flags & VM_WRITE) {
-		if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL)
-			goto out;
-		if ((ret = prog_dmabuf(state, 0)) != 0)
+		if (!dmabuf->write_channel &&
+		    (dmabuf->write_channel =
+		     state->card->alloc_pcm_channel(state->card)) == NULL) {
+			ret = -EBUSY;
 			goto out;
-	} else if (vma->vm_flags & VM_READ) {
-		if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL)
-			goto out;
-		if ((ret = prog_dmabuf(state, 1)) != 0)
+		}
+	}
+	if (vma->vm_flags & VM_READ) {
+		if (!dmabuf->read_channel &&
+		    (dmabuf->read_channel = 
+		     state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
+			ret = -EBUSY;
 			goto out;
-	} else 
+		}
+	}
+	if ((ret = prog_dmabuf(state, 0)) != 0)
 		goto out;
 
 	ret = -EINVAL;
@@ -1291,9 +1331,13 @@
 			     size, vma->vm_page_prot))
 		goto out;
 	dmabuf->mapped = 1;
+	if(vma->vm_flags & VM_WRITE)
+		dmabuf->count = dmabuf->dmasize;
+	else
+		dmabuf->count = 0;
 	ret = 0;
 #ifdef DEBUG
-	printk("i810_audio: mmap'ed %d bytes of data space\n", size);
+	printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
 #endif
 out:
 	unlock_kernel();
@@ -1312,41 +1356,52 @@
 	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
 		((file->f_mode & FMODE_READ) && dmabuf->mapped);
 #ifdef DEBUG
-	printk("i810_audio: i810_ioctl, command = %2d, arg = 0x%08x\n",
-	       _IOC_NR(cmd), arg ? *(int *)arg : 0);
+	printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0);
 #endif
 
 	switch (cmd) 
 	{
 	case OSS_GETVERSION:
+#ifdef DEBUG
+		printk("OSS_GETVERSION\n");
+#endif
 		return put_user(SOUND_VERSION, (int *)arg);
 
 	case SNDCTL_DSP_RESET:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_RESET\n");
+#endif
 		/* FIXME: spin_lock ? */
-		if (file->f_mode & FMODE_WRITE) {
+		if (dmabuf->enable == DAC_RUNNING) {
 			stop_dac(state);
-			synchronize_irq();
-			dmabuf->ready = 0;
-			resync_dma_ptrs(state, 0);
-			dmabuf->swptr = dmabuf->hwptr = 0;
-			dmabuf->count = dmabuf->total_bytes = 0;
 		}
-		if (file->f_mode & FMODE_READ) {
+		if (dmabuf->enable == ADC_RUNNING) {
 			stop_adc(state);
-			synchronize_irq();
-			resync_dma_ptrs(state, 1);
-			dmabuf->ready = 0;
-			dmabuf->swptr = dmabuf->hwptr = 0;
-			dmabuf->count = dmabuf->total_bytes = 0;
 		}
+		synchronize_irq();
+		dmabuf->ready = 0;
+		dmabuf->swptr = dmabuf->hwptr = 0;
+		dmabuf->count = dmabuf->total_bytes = 0;
 		return 0;
 
 	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(state, file->f_flags & O_NONBLOCK);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SYNC\n");
+#endif
+		if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
+			return 0;
+		drain_dac(state, 0);
+		stop_dac(state);
+		synchronize_irq();
+		dmabuf->ready = 0;
+		dmabuf->swptr = dmabuf->hwptr = 0;
+		dmabuf->count = dmabuf->total_bytes = 0;
 		return 0;
 
 	case SNDCTL_DSP_SPEED: /* set smaple rate */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SPEED\n");
+#endif
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		if (val >= 0) {
@@ -1368,71 +1423,68 @@
 		return put_user(dmabuf->rate, (int *)arg);
 
 	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_STEREO\n");
+#endif
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-		if(val==0)
-			return -EINVAL;
-		if (file->f_mode & FMODE_WRITE) {
+		if(val==0) {
+			ret = -EINVAL;
+		} else {
+			ret = 1;
+		}
+		if (dmabuf->enable & DAC_RUNNING) {
 			stop_dac(state);
-			dmabuf->ready = 0;
-			dmabuf->fmt |= I810_FMT_STEREO;
 		}
-		if (file->f_mode & FMODE_READ) {
+		if (dmabuf->enable & ADC_RUNNING) {
 			stop_adc(state);
-			dmabuf->ready = 0;
-			dmabuf->fmt |= I810_FMT_STEREO;
 		}
-		return 0;
+		return ret;
 
 	case SNDCTL_DSP_GETBLKSIZE:
 		if (file->f_mode & FMODE_WRITE) {
 			if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
 				return val;
-			return put_user(dmabuf->fragsize, (int *)arg);
 		}
 		if (file->f_mode & FMODE_READ) {
 			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
 				return val;
-			return put_user(dmabuf->fragsize, (int *)arg);
 		}
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->ossfragsize);
+#endif
+		return put_user(dmabuf->ossfragsize, (int *)arg);
 
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETFMTS\n");
+#endif
 		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Select sample format */
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(state);
-				dmabuf->ready = 0;
-				dmabuf->fmt |= I810_FMT_16BIT;
-			}
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(state);
-				dmabuf->ready = 0;
-				dmabuf->fmt |= I810_FMT_16BIT;
-			}
-		}
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETFMT\n");
+#endif
 		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (val != 0) {
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(state);
-				dmabuf->ready = 0;
-			}
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(state);
-				dmabuf->ready = 0;
-			}
-		}
+#ifdef DEBUG
+		printk("SNDCTL_DSP_CHANNELS\n");
+#endif
 		return put_user(2, (int *)arg);
 
-	case SNDCTL_DSP_POST:
-		/* FIXME: the same as RESET ?? */
+	case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
+		/* we update the swptr to the end of the last sg segment then return */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_POST\n");
+#endif
+		if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
+			return 0;
+		if((dmabuf->swptr % dmabuf->fragsize) != 0) {
+			val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
+			dmabuf->swptr += val;
+			dmabuf->count += val;
+		}
 		return 0;
 
 	case SNDCTL_DSP_SUBDIVIDE:
@@ -1442,6 +1494,9 @@
 			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
+#endif
 		dmabuf->subdivision = val;
 		dmabuf->ready = 0;
 		return 0;
@@ -1450,15 +1505,27 @@
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
 
-		dmabuf->ossfragshift = val & 0xffff;
+		dmabuf->ossfragsize = 1<<(val & 0xffff);
 		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-		if (dmabuf->ossfragshift < 4)
-			dmabuf->ossfragshift = 4;
-		if (dmabuf->ossfragshift > 15)
-			dmabuf->ossfragshift = 15;
-		if (dmabuf->ossmaxfrags < 4)
+		if (dmabuf->ossmaxfrags <= 4)
 			dmabuf->ossmaxfrags = 4;
+		else if (dmabuf->ossmaxfrags <= 8)
+			dmabuf->ossmaxfrags = 8;
+		else if (dmabuf->ossmaxfrags <= 16)
+			dmabuf->ossmaxfrags = 16;
+		else
+			dmabuf->ossmaxfrags = 32;
+		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+		if (val < 16384)
+			val = 16384;
+		if (val > 65536)
+			val = 65536;
+		dmabuf->ossfragsize = val/dmabuf->ossmaxfrags;
 		dmabuf->ready = 0;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
+			dmabuf->ossfragsize, dmabuf->ossmaxfrags);
+#endif
 
 		return 0;
 
@@ -1469,13 +1536,42 @@
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
-		abinfo.fragsize = dmabuf->fragsize;
-		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
-		abinfo.fragstotal = dmabuf->numfrag;
-		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+		abinfo.fragsize = dmabuf->ossfragsize;
+		abinfo.fragstotal = dmabuf->ossmaxfrags;
+		if(dmabuf->mapped)
+			abinfo.bytes = dmabuf->count;
+		else
+			abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.fragments = abinfo.bytes / dmabuf->ossfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
+			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
+#endif
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
+	case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.ptr = dmabuf->hwptr;
+		cinfo.blocks = (dmabuf->dmasize - dmabuf->count)/dmabuf->ossfragsize;
+		if (dmabuf->mapped) {
+			dmabuf->count = (dmabuf->dmasize - 
+					 (dmabuf->count & (dmabuf->ossfragsize-1)));
+			__i810_update_lvi(state, 0);
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
+			cinfo.blocks, cinfo.ptr, dmabuf->count);
+#endif
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
@@ -1483,87 +1579,111 @@
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
-		abinfo.fragsize = dmabuf->fragsize;
-		abinfo.bytes = dmabuf->count;
-		abinfo.fragstotal = dmabuf->numfrag;
-		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+		abinfo.fragsize = dmabuf->ossfragsize;
+		abinfo.fragstotal = dmabuf->ossmaxfrags;
+		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.fragments = abinfo.bytes / dmabuf->ossfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
+			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
+#endif
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		i810_update_ptr(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count/dmabuf->ossfragsize;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped) {
+			dmabuf->count &= dmabuf->ossfragsize-1;
+			__i810_update_lvi(state, 1);
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
+			cinfo.blocks, cinfo.ptr, dmabuf->count);
+#endif
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
 	case SNDCTL_DSP_NONBLOCK:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_NONBLOCK\n");
+#endif
 		file->f_flags |= O_NONBLOCK;
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETCAPS\n");
+#endif
 	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
 			    (int *)arg);
 
 	case SNDCTL_DSP_GETTRIGGER:
 		val = 0;
-		if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING)
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, (int *)arg);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
+#endif
+		return put_user(dmabuf->trigger, (int *)arg);
 
 	case SNDCTL_DSP_SETTRIGGER:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-		if (file->f_mode & FMODE_READ && val & PCM_ENABLE_INPUT) {
-			if (dmabuf->enable & DAC_RUNNING)
-				return -ENODEV;
-			if (!dmabuf->read_channel) {
-				dmabuf->ready = 0;
-				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
-				if (!dmabuf->read_channel)
-					return -ENODEV;
-			}
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-				return ret;
-			start_adc(state);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
+#endif
+		if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+			stop_adc(state);
 		}
-		if (file->f_mode & FMODE_WRITE && val & PCM_ENABLE_OUTPUT) {
-			if (dmabuf->enable & ADC_RUNNING)
-				return -ENODEV;
+		if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+			stop_dac(state);
+		}
+		dmabuf->trigger = val;
+		if(val & PCM_ENABLE_OUTPUT) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
 				if (!dmabuf->write_channel)
-					return -ENODEV;
+					return -EBUSY;
 			}
 			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 				return ret;
-			start_dac(state);
+			if (dmabuf->mapped) {
+				dmabuf->count = dmabuf->dmasize;
+				i810_update_lvi(state,0);
+			}
+			if (!dmabuf->enable && dmabuf->count > dmabuf->fragsize)
+				start_dac(state);
+		}
+		if(val & PCM_ENABLE_INPUT) {
+			if (!dmabuf->read_channel) {
+				dmabuf->ready = 0;
+				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
+				if (!dmabuf->read_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+				return ret;
+			if (dmabuf->mapped) {
+				dmabuf->count = 0;
+				i810_update_lvi(state,1);
+			}
+			if (!dmabuf->enable && dmabuf->count <
+			    (dmabuf->dmasize - dmabuf->fragsize))
+				start_adc(state);
 		}
 		return 0;
 
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
-		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
-		cinfo.ptr = dmabuf->hwptr;
-		if (dmabuf->mapped)
-			dmabuf->count &= dmabuf->fragsize-1;
-		spin_unlock_irqrestore(&state->card->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(&state->card->lock, flags);
-		i810_update_ptr(state);
-		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
-		cinfo.ptr = dmabuf->hwptr;
-		if (dmabuf->mapped)
-			dmabuf->count &= dmabuf->fragsize-1;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-
 	case SNDCTL_DSP_SETDUPLEX:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETDUPLEX\n");
+#endif
 		return -EINVAL;
 
 	case SNDCTL_DSP_GETODELAY:
@@ -1573,16 +1693,27 @@
 		i810_update_ptr(state);
 		val = dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
+#endif
 		return put_user(val, (int *)arg);
 
 	case SOUND_PCM_READ_RATE:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
+#endif
 		return put_user(dmabuf->rate, (int *)arg);
 
 	case SOUND_PCM_READ_CHANNELS:
-		return put_user((dmabuf->fmt & I810_FMT_STEREO) ? 2 : 1,
-				(int *)arg);
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_CHANNELS\n");
+#endif
+		return put_user(2, (int *)arg);
 
 	case SOUND_PCM_READ_BITS:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_BITS\n");
+#endif
 		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_MAPINBUF:
@@ -1590,6 +1721,9 @@
 	case SNDCTL_DSP_SETSYNCRO:
 	case SOUND_PCM_WRITE_FILTER:
 	case SOUND_PCM_READ_FILTER:
+#ifdef DEBUG
+		printk("SNDCTL_* -EINVAL\n");
+#endif
 		return -EINVAL;
 	}
 	return -EINVAL;
@@ -1621,7 +1755,7 @@
 	if (!state)
 		return -ENODEV;
 
- found_virt:
+found_virt:
 	/* initialize the virtual channel */
 	state->virt = i;
 	state->card = card;
@@ -1629,33 +1763,36 @@
 	init_waitqueue_head(&dmabuf->wait);
 	init_MUTEX(&state->open_sem);
 	file->private_data = state;
+	dmabuf->trigger = 0;
 
 	/* allocate hardware channels */
 	if(file->f_mode & FMODE_READ) {
 		if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
 			kfree (card->states[i]);
 			card->states[i] = NULL;;
-			return -ENODEV;
+			return -EBUSY;
 		}
-		i810_set_adc_rate(state, 48000);
+		i810_set_adc_rate(state, 8000);
+		dmabuf->trigger |= PCM_ENABLE_INPUT;
 	}
 	if(file->f_mode & FMODE_WRITE) {
 		if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
 			kfree (card->states[i]);
 			card->states[i] = NULL;;
-			return -ENODEV;
+			return -EBUSY;
 		}
-		i810_set_dac_rate(state, 48000);
+		i810_set_dac_rate(state, 8000);
+		dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 	}
 		
 	down(&state->open_sem);
 
 	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
 	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
-	   /dev/dspW will accept 16-bits sample */
-	dmabuf->fmt &= ~I810_FMT_MASK;
-	dmabuf->fmt |= I810_FMT_16BIT;
-	dmabuf->ossfragshift = 0;
+	   /dev/dspW will accept 16-bits sample, but we don't support those so we
+	   set it immediately to stereo and 16bit, which is all we do support */
+	dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO;
+	dmabuf->ossfragsize = 0;
 	dmabuf->ossmaxfrags  = 0;
 	dmabuf->subdivision  = 0;
 
@@ -1671,22 +1808,19 @@
 	struct dmabuf *dmabuf = &state->dmabuf;
 
 	lock_kernel();
-	if (file->f_mode & FMODE_WRITE) {
-	}
 
-	/* stop DMA state machine and free DMA buffers/channels */
 	down(&state->open_sem);
 
-	if (dmabuf->enable & DAC_RUNNING) {
-		i810_clear_tail(state);
-		drain_dac(state, file->f_flags & O_NONBLOCK);
+	/* stop DMA state machine and free DMA buffers/channels */
+	if(dmabuf->enable == DAC_RUNNING ||
+	   (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
+		drain_dac(state,0);
 		stop_dac(state);
-		dealloc_dmabuf(state);
 	}
 	if(dmabuf->enable & ADC_RUNNING) {
 		stop_adc(state);
-		dealloc_dmabuf(state);
 	}
+	dealloc_dmabuf(state);
 	if (file->f_mode & FMODE_WRITE) {
 		state->card->free_pcm_channel(state->card, dmabuf->write_channel->num);
 	}
@@ -1827,6 +1961,19 @@
 		if (ac97_probe_codec(codec) == 0)
 			break;
 
+		/* power up everything, modify this when implementing power saving */
+		i810_ac97_set(codec, AC97_POWER_CONTROL,
+			i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+		/* wait for analog ready */
+	        for (i=10;
+		     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);
+		     i--)
+		{
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ/20);
+		}
+
+		/* Don't attempt to get eid until powerup is complete */
 		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
 		
 		if(eid==0xFFFFFF)
@@ -1845,18 +1992,6 @@
 			printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
 		else
 		{
-			/* power up everything, modify this when implementing power saving */
-			i810_ac97_set(codec, AC97_POWER_CONTROL,
-				i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
-			/* wait for analog ready */
-		        for (i=10;
-			     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);
-			     i--)
-			{
-				current->state = TASK_UNINTERRUPTIBLE;
-				schedule_timeout(HZ/20);
-			}
-
 			/* Enable variable rate mode */
 			i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
 			i810_ac97_set(codec,AC97_EXTENDED_STATUS,
@@ -1996,6 +2131,7 @@
 MODULE_DESCRIPTION("Intel 810 audio support");
 MODULE_PARM(ftsodell, "i");
 MODULE_PARM(clocking, "i");
+MODULE_PARM(strict_clocking, "i");
 
 #define I810_MODULE_NAME "intel810_audio"
 
@@ -2036,6 +2172,7 @@
 		init_waitqueue_head(&dmabuf->wait);
 		init_MUTEX(&state->open_sem);
 		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
+		dmabuf->trigger = PCM_ENABLE_OUTPUT;
 		i810_set_dac_rate(state, 48000);
 		if(prog_dmabuf(state, 0) != 0) {
 			goto config_out_nodmabuf;
@@ -2044,25 +2181,30 @@
 			goto config_out;
 		}
 		dmabuf->count = dmabuf->dmasize;
+		outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI);
 		save_flags(flags);
 		cli();
 		start_dac(state);
-		offset = i810_get_dma_addr(state);
+		offset = i810_get_dma_addr(state, 0);
 		mdelay(50);
-		new_offset = i810_get_dma_addr(state);
+		new_offset = i810_get_dma_addr(state, 0);
 		stop_dac(state);
 		outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR);
 		restore_flags(flags);
 		i = new_offset - offset;
+#ifdef DEBUG
 		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
+#endif
+		if(i == 0)
+			goto config_out;
 		i = i / 4 * 20;
 		if (i > 48500 || i < 47500) {
 			clocking = clocking * clocking / i;
-			printk("i810_audio: setting clocking to %d to compensate\n", clocking);
+			printk("i810_audio: setting clocking to %d\n", clocking);
 		}
-config_out_nodmabuf:
-		dealloc_dmabuf(state);
 config_out:
+		dealloc_dmabuf(state);
+config_out_nodmabuf:
 		state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num);
 		kfree(state);
 		card->states[0] = NULL;
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.4.3/linux/drivers/sound/mad16.c	Sat Dec 30 11:23:14 2000
+++ linux/drivers/sound/mad16.c	Fri Apr  6 10:51:19 2001
@@ -423,72 +423,80 @@
 
 	DDB(printk("Detect using password = 0xE5\n"));
 	
-	if (!detect_mad16())	/* No luck. Try different model */
-	{
-		board_type = C928;
+	if (detect_mad16()) {
+		return 1;
+	}
+	
+	board_type = C928;
 
-		DDB(printk("Detect using password = 0xE2\n"));
+	DDB(printk("Detect using password = 0xE2\n"));
 
-		if (!detect_mad16())
-		{
-			board_type = C929;
-
-			DDB(printk("Detect using password = 0xE3\n"));
-
-			if (!detect_mad16())
-			{
-				if (inb(PASSWD_REG) != 0xff)
-					return 0;
-
-				/*
-				 * First relocate MC# registers to 0xe0e/0xe0f, disable password 
-				 */
-
-				outb((0xE4), PASSWD_REG);
-				outb((0x80), PASSWD_REG);
-
-				board_type = C930;
-
-				DDB(printk("Detect using password = 0xE4\n"));
-
-				for (i = 0xf8d; i <= 0xf93; i++)
-					DDB(printk("port %03x = %02x\n", i, mad_read(i)));
-                                if(!detect_mad16()) {
-
-				  /* The C931 has the password reg at F8D */
-				  outb((0xE4), 0xF8D);
-				  outb((0x80), 0xF8D);
-				  DDB(printk("Detect using password = 0xE4 for C931\n"));
-
-				  if (!detect_mad16()) {
-				    board_type = C924;
-				    c924pnp++;
-				    DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
-				    if (!detect_mad16()) {
-				      c924pnp=0;
-				      return 0;
-				    }
-				  
-				    DDB(printk("mad16.c: 82C924 PnP detected\n"));
-				  }
-				}
-				else
-				  DDB(printk("mad16.c: 82C930 detected\n"));
-			} else
-				DDB(printk("mad16.c: 82C929 detected\n"));
-		} else {
-			unsigned char model;
+	if (detect_mad16())
+	{
+		unsigned char model;
 
-			if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
-				DDB(printk("mad16.c: Mozart detected\n"));
-				board_type = MOZART;
-			} else {
-				DDB(printk("mad16.c: 82C928 detected???\n"));
-				board_type = C928;
-			}
+		if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
+			DDB(printk("mad16.c: Mozart detected\n"));
+			board_type = MOZART;
+		} else {
+			DDB(printk("mad16.c: 82C928 detected???\n"));
+			board_type = C928;
 		}
+		return 1;
+	}
+
+	board_type = C929;
+
+	DDB(printk("Detect using password = 0xE3\n"));
+
+	if (detect_mad16())
+	{
+		DDB(printk("mad16.c: 82C929 detected\n"));
+		return 1;
+	}
+
+	if (inb(PASSWD_REG) != 0xff)
+		return 0;
+
+	/*
+	 * First relocate MC# registers to 0xe0e/0xe0f, disable password 
+	 */
+
+	outb((0xE4), PASSWD_REG);
+	outb((0x80), PASSWD_REG);
+
+	board_type = C930;
+
+	DDB(printk("Detect using password = 0xE4\n"));
+
+	for (i = 0xf8d; i <= 0xf93; i++)
+		DDB(printk("port %03x = %02x\n", i, mad_read(i)));
+
+        if(detect_mad16()) {
+		DDB(printk("mad16.c: 82C930 detected\n"));
+		return 1;
 	}
-	return 1;
+
+	/* The C931 has the password reg at F8D */
+	outb((0xE4), 0xF8D);
+	outb((0x80), 0xF8D);
+	DDB(printk("Detect using password = 0xE4 for C931\n"));
+
+	if (detect_mad16()) {
+		return 1;
+	}
+
+	board_type = C924;
+	c924pnp++;
+	DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
+	if (detect_mad16()) {
+		DDB(printk("mad16.c: 82C924 PnP detected\n"));
+		return 1;
+	}
+	
+	c924pnp=0;
+
+	return 0;
 }
 
 static int __init probe_mad16(struct address_info *hw_config)
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- v2.4.3/linux/drivers/sound/maestro3.c	Fri Mar  2 18:38:39 2001
+++ linux/drivers/sound/maestro3.c	Sat Apr 21 10:36:30 2001
@@ -81,7 +81,7 @@
  *  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
+ *  instance' code portions.  There is generally 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 
@@ -2307,6 +2307,8 @@
     codec->private_data = card;
     codec->codec_read = m3_ac97_read;
     codec->codec_write = m3_ac97_write;
+    /* someday we should support secondary codecs.. */
+    codec->id = 0;
 
     if (ac97_probe_codec(codec) == 0) {
         printk(KERN_ERR PFX "codec probe failed\n");
@@ -2595,18 +2597,16 @@
 
     DPRINTK(DPMOD, "in maestro_install\n");
 
-    if (!pci_dma_supported(pci_dev, M3_PCI_DMA_MASK)) {
+    if (pci_enable_device(pci_dev))
+        return -EIO;
+
+    if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) {
         printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n");
         return -ENODEV;
     }
         
-    if (pci_enable_device(pci_dev))
-        return -EIO;
-
     pci_set_master(pci_dev);
 
-    pci_dev->dma_mask = M3_PCI_DMA_MASK;
-
     if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) {
         printk(KERN_WARNING PFX "out of memory\n");
         return -ENOMEM;
@@ -2936,6 +2936,7 @@
 
     if (!pci_register_driver(&m3_pci_driver)) {
         pci_unregister_driver(&m3_pci_driver);
+        unregister_reboot_notifier(&m3_reboot_nb);
         return -ENODEV;
     }
     return 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/miroaci.h linux/drivers/sound/miroaci.h
--- v2.4.3/linux/drivers/sound/miroaci.h	Sun Mar 12 19:13:06 2000
+++ linux/drivers/sound/miroaci.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-extern int aci_implied_cmd(unsigned char opcode);
-extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
-extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
-extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
-extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.4.3/linux/drivers/sound/sb_common.c	Fri Feb 16 16:02:37 2001
+++ linux/drivers/sound/sb_common.c	Wed Apr 18 11:49:12 2001
@@ -1227,7 +1227,7 @@
 		if (!ess_midi_init(devc, hw_config))
 			return 0;
 		hw_config->name = "ESS1xxx MPU";
-		devc->midi_irq_cookie = -1;
+		devc->midi_irq_cookie = NULL;
 		if (!probe_mpu401(hw_config))
 			return 0;
 		attach_mpu401(hw_config, owner);
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.4.3/linux/drivers/sound/sonicvibes.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/sound/sonicvibes.c	Thu Apr 12 12:16:36 2001
@@ -3,7 +3,7 @@
 /*
  *      sonicvibes.c  --  S3 Sonic Vibes audio driver.
  *
- *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      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
@@ -88,6 +88,10 @@
  *                       use Martin Mares' pci_assign_resource
  *    07.02.2000   0.26  Use pci_alloc_consistent and pci_register_driver
  *    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>
+ *    31.01.2001   0.29  Register/Unregister gameport
+ *                       Fix SETTRIGGER non OSS API conformity
  *
  */
 
@@ -115,6 +119,23 @@
 
 #include "dm.h"
 
+#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE)
+#include <linux/gameport.h>
+#else
+struct gameport {
+	int io;
+	int size;
+};
+
+extern inline void gameport_register_port(struct gameport *gameport)
+{
+}
+
+extern inline void gameport_unregister_port(struct gameport *gameport)
+{
+}
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -301,7 +322,7 @@
 	int dev_dmfm;
 
 	/* hardware resources */
-	unsigned long iosb, ioenh, iosynth, iomidi, iogame;  /* long for SPARC */
+	unsigned long iosb, ioenh, iosynth, iomidi;  /* long for SPARC */
 	unsigned int iodmaa, iodmac, irq;
 
         /* mixer stuff */
@@ -340,6 +361,7 @@
 		unsigned mapped:1;
 		unsigned ready:1;
 		unsigned endcleared:1;
+		unsigned enabled:1;
 		unsigned ossfragshift;
 		int ossmaxfrags;
 		unsigned subdivision;
@@ -355,6 +377,8 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
+
+	struct gameport gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -786,6 +810,7 @@
 		wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1);
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
+	db->enabled = 1;
 	db->ready = 1;
 	return 0;
 }
@@ -1343,7 +1368,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_adc(s);
+			if (s->dma_adc.enabled)
+				start_adc(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1382,7 +1408,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_adc(s);
+		if (s->dma_adc.enabled)
+			start_adc(s);
 	}
         remove_wait_queue(&s->dma_adc.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1430,7 +1457,8 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			start_dac(s);
+			if (s->dma_dac.enabled)
+				start_dac(s);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret)
 					ret = -EAGAIN;
@@ -1470,7 +1498,8 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_dac(s);
+		if (s->dma_dac.enabled)
+			start_dac(s);
 	}
         remove_wait_queue(&s->dma_dac.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1706,25 +1735,31 @@
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
 					return ret;
+				s->dma_adc.enabled = 1;
 				start_adc(s);
-			} else
+			} else {
+				s->dma_adc.enabled = 0;
 				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;
+				s->dma_dac.enabled = 1;
 				start_dac(s);
-			} else
+			} else {
+				s->dma_dac.enabled = 0;
 				stop_dac(s);
+			}
 		}
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
+		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;
@@ -1740,8 +1775,8 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-			return ret;
+		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;
@@ -1761,8 +1796,8 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
+		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		sv_update_ptr(s);
                 count = s->dma_dac.count;
@@ -1774,8 +1809,8 @@
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-			return ret;
+		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;
@@ -1792,8 +1827,8 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
+		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;
@@ -1915,6 +1950,7 @@
 		if ((minor & 0xf) == SND_DEV_DSP16)
 			fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+		s->dma_adc.enabled = 1;
 		set_adc_rate(s, 8000);
 	}
 	if (file->f_mode & FMODE_WRITE) {
@@ -1922,6 +1958,7 @@
 		if ((minor & 0xf) == SND_DEV_DSP16)
 			fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
 		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+		s->dma_dac.enabled = 1;
 		set_dac_rate(s, 8000);
 	}
 	set_fmt(s, fmtm, fmts);
@@ -2212,6 +2249,7 @@
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
 				set_current_state(TASK_RUNNING);
+				unlock_kernel();
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2517,13 +2555,14 @@
 	s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH);
 	s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH);
 	s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
-	s->iogame = pci_resource_start(pcidev, RESOURCE_GAME);
 	s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
 	s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
+	s->gameport.io = pci_resource_start(pcidev, RESOURCE_GAME);
+	s->gameport.size = pci_resource_len(pcidev,RESOURCE_GAME);
 	pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9);  /* enable and use extended mode */
 	pci_write_config_dword(pcidev, 0x48, s->iodmac | 9);  /* enable */
-	printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n",
-	       s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac);
+	printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
+	       s->iosb, s->ioenh, s->iosynth, s->iomidi, s->gameport.io, s->iodmaa, s->iodmac);
 	s->irq = pcidev->irq;
 	
 	/* hack */
@@ -2549,6 +2588,12 @@
 		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
 		goto err_region1;
 	}
+	if (!s->gameport.size)
+		s->gameport.io = 0;
+	if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) {
+		printk(KERN_ERR "sv: gameport io ports in use\n");
+		s->gameport.io = s->gameport.size = 0;
+	}
 	if (pci_enable_device(pcidev))
 		goto err_irq;
 	/* initialize codec registers */
@@ -2600,7 +2645,9 @@
 		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
 	}
 	set_fs(fs);
-       /* store it in the driver field */
+	/* register gameport */
+	gameport_register_port(&s->gameport);
+	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
 	list_add_tail(&s->devs, &devs);
@@ -2619,6 +2666,8 @@
 	printk(KERN_ERR "sv: cannot register misc device\n");
 	free_irq(s->irq, s);
  err_irq:
+	if (s->gameport.io)
+		release_region(s->gameport.io, s->gameport.size);
 	release_region(s->iosynth, SV_EXTENT_SYNTH);
  err_region1:
 	release_region(s->iomidi, SV_EXTENT_MIDI);
@@ -2635,29 +2684,33 @@
 
 static void __devinit sv_remove(struct pci_dev *dev)
 {
-       struct sv_state *s = pci_get_drvdata(dev);
+	struct sv_state *s = pci_get_drvdata(dev);
 
-       if (!s)
-               return;
-       list_del(&s->devs);
-       outb(~0, s->ioenh + SV_CODEC_INTMASK);  /* disable ints */
-       synchronize_irq();
-       inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
-       wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-       /*outb(0, s->iodmaa + SV_DMA_RESET);*/
-       /*outb(0, s->iodmac + SV_DMA_RESET);*/
-       free_irq(s->irq, s);
-       release_region(s->iodmac, SV_EXTENT_DMA);
-       release_region(s->iodmaa, SV_EXTENT_DMA);
-       release_region(s->ioenh, SV_EXTENT_ENH);
-       release_region(s->iomidi, SV_EXTENT_MIDI);
-       release_region(s->iosynth, SV_EXTENT_SYNTH);
-       unregister_sound_dsp(s->dev_audio);
-       unregister_sound_mixer(s->dev_mixer);
-       unregister_sound_midi(s->dev_midi);
-       unregister_sound_special(s->dev_dmfm);
-       kfree(s);
-       pci_set_drvdata(dev, NULL);
+	if (!s)
+		return;
+	list_del(&s->devs);
+	outb(~0, s->ioenh + SV_CODEC_INTMASK);  /* disable ints */
+	synchronize_irq();
+	inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
+	wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
+	/*outb(0, s->iodmaa + SV_DMA_RESET);*/
+	/*outb(0, s->iodmac + SV_DMA_RESET);*/
+	free_irq(s->irq, s);
+	if (s->gameport.io) {
+		gameport_unregister_port(&s->gameport);
+		release_region(s->gameport.io, s->gameport.size);
+	}
+	release_region(s->iodmac, SV_EXTENT_DMA);
+	release_region(s->iodmaa, SV_EXTENT_DMA);
+	release_region(s->ioenh, SV_EXTENT_ENH);
+	release_region(s->iomidi, SV_EXTENT_MIDI);
+	release_region(s->iosynth, SV_EXTENT_SYNTH);
+	unregister_sound_dsp(s->dev_audio);
+	unregister_sound_mixer(s->dev_mixer);
+	unregister_sound_midi(s->dev_midi);
+	unregister_sound_special(s->dev_dmfm);
+	kfree(s);
+	pci_set_drvdata(dev, NULL);
 }
 
 static struct pci_device_id id_table[] __devinitdata = {
@@ -2678,7 +2731,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.27 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.29 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 --recursive --new-file v2.4.3/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.4.3/linux/drivers/sound/sound_core.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/sound/sound_core.c	Fri Apr  6 10:51:19 2001
@@ -168,7 +168,11 @@
 	spin_unlock(&sound_loader_lock);
 	
 	if(r<0)
+	{
 		kfree(s);
+		return r;
+	}
+	
 	if (r == low)
 		sprintf (name_buf, "%s", name);
 	else
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.4.3/linux/drivers/sound/trident.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/sound/trident.c	Fri Apr  6 10:51:19 2001
@@ -2890,7 +2890,7 @@
 	{	
 		if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A) || (i*4 == T4D_START_A))
 			continue;
-		ali_registers.global_regs[i] = inl(TRID_REG(card, i*4));
+		outl(ali_registers.global_regs[i], TRID_REG(card, i*4));
 	}
 	
 	//start HW channel
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c
--- v2.4.3/linux/drivers/sound/vidc.c	Wed Sep 27 13:39:23 2000
+++ linux/drivers/sound/vidc.c	Fri Apr 13 20:26:07 2001
@@ -17,6 +17,7 @@
  * We currently support a mixer device, but it is currently non-functional.
  */
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -82,6 +83,7 @@
 static void	(*old_mksound)(unsigned int hz, unsigned int ticks);
 extern void	(*kd_mksound)(unsigned int hz, unsigned int ticks);
 extern void	vidc_update_filler(int bits, int channels);
+extern int	softoss_dev;
 
 static void
 vidc_mksound(unsigned int hz, unsigned int ticks)
@@ -214,8 +216,8 @@
 			rate = VIDC_SOUND_CLOCK / hwrate;
 		}
 
-		outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE);
-		outl(0xb1000000 | hwctrl, IO_VIDC_BASE);
+		vidc_writel(0xb0000000 | (hwrate - 2));
+		vidc_writel(0xb1000000 | hwctrl);
 
 		newsize = (10000 / hwrate) & ~3;
 		if (newsize < 208)
@@ -354,7 +356,7 @@
 
 			dma_interrupt = vidc_audio_dma_interrupt;
 			vidc_sound_dma_irq(0, NULL, NULL);
-			outb(DMA_CR_E | 0x10, IOMD_SD0CR);
+			iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR);
 
 			local_irq_restore(flags);
 		}
@@ -473,6 +475,9 @@
 	vidc_adev = adev;
 	vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
 
+#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
+	softoss_dev = adev;
+#endif
 	return;
 
 irq_failed:
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c
--- v2.4.3/linux/drivers/sound/waveartist.c	Sat Nov 11 18:33:14 2000
+++ linux/drivers/sound/waveartist.c	Fri Apr 13 20:26:07 2001
@@ -1824,7 +1824,7 @@
 	io	= ints[1];
 	irq	= ints[2];
 	dma	= ints[3];
-	dma16	= ints[4];
+	dma2	= ints[4];
 
 	return 1;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- v2.4.3/linux/drivers/sound/ymfpci.c	Tue Mar 20 11:29:01 2001
+++ linux/drivers/sound/ymfpci.c	Mon Apr 23 23:21:08 2001
@@ -1853,6 +1853,7 @@
 		return -ENXIO;
 	}
 
+	unit = NULL;	/* gcc warns */
 	for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {
 		unit = list_entry(list, ymfpci_t, ymf_devs);
 		if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
@@ -2147,8 +2148,8 @@
 	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
 
 	/* setup DSP instruction code */
-	for (i = 0; i < YDSXG_DSPLENGTH; i++)
-		ymfpci_writel(codec, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2]);
+	for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
+		ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
 
 	switch (codec->pci->device) {
 	case PCI_DEVICE_ID_YAMAHA_724F:
@@ -2163,11 +2164,11 @@
 
 	if (ver_1e) {
 		/* setup control instruction code */
-		for (i = 0; i < YDSXG_CTRLLENGTH; i++)
-			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst1E[i >> 2]);
+		for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
+			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]);
 	} else {
-		for (i = 0; i < YDSXG_CTRLLENGTH; i++)
-			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst[i >> 2]);
+		for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
+			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]);
 	}
 
 	ymfpci_enable_dsp(codec);
@@ -2252,7 +2253,7 @@
 
 	/* move this volume setup to mixer */
 	ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
-	ymfpci_writel(codec, YDSXGR_BUF441OUTVOL, 0x3fff3fff);
+	ymfpci_writel(codec, YDSXGR_BUF441OUTVOL, 0);
 	ymfpci_writel(codec, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
 	ymfpci_writel(codec, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ymfpci_image.h linux/drivers/sound/ymfpci_image.h
--- v2.4.3/linux/drivers/sound/ymfpci_image.h	Sun Dec  3 23:58:10 2000
+++ linux/drivers/sound/ymfpci_image.h	Fri Apr  6 10:51:19 2001
@@ -1,7 +1,7 @@
 #ifndef _HWMCODE_
 #define _HWMCODE_
 
-static unsigned long int	DspInst[] = {
+static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
 	0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
 	0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
 	0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
@@ -12,7 +12,7 @@
 	0x00000000, 0x00000000, 0x00000000, 0x00000000
 };
 
-static unsigned long int	CntrlInst[] = {
+static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
 	0x000007, 0x240007, 0x0C0007, 0x1C0007,
 	0x060007, 0x700002, 0x000020, 0x030040,
 	0x007104, 0x004286, 0x030040, 0x000F0D,
@@ -791,7 +791,7 @@
 // 04/09  creat
 // 04/12  stop nise fix
 // 06/21  WorkingOff timming
-static unsigned long int	CntrlInst1E[] = {
+static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
 	0x000007, 0x240007, 0x0C0007, 0x1C0007,
 	0x060007, 0x700002, 0x000020, 0x030040,
 	0x007104, 0x004286, 0x030040, 0x000F0D,
diff -u --recursive --new-file v2.4.3/linux/drivers/tc/Makefile linux/drivers/tc/Makefile
--- v2.4.3/linux/drivers/tc/Makefile	Fri Jun 25 17:38:40 1999
+++ linux/drivers/tc/Makefile	Fri Apr 13 20:26:07 2001
@@ -7,27 +7,36 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-SUB_DIRS     :=
-MOD_SUB_DIRS := 
-ALL_SUB_DIRS := 
-
-L_TARGET := tc.a
-L_OBJS   := tc.o
-
-# Nasty trick as nobody references tcsyms.o, but we still want it linked.
-# Stolen from pci Makefile
-ifeq ($(CONFIG_MODULES),y)
-O_TARGET = tc_syms.o
-OX_OBJS  = tcsyms.o
-O_OBJS   = tc.o
-L_OBJS   := tc_syms.o
-else
-L_OBJS   := tc.o
-endif
-
-ifdef CONFIG_ZS
-L_OBJS   += zs.o
-endif
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs	:= tc.o
+
+# Object file lists.
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_ZS) += zs.o
+obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+
+# Translate to Rules.make lists.
+
+L_TARGET	:= tc.a
+
+L_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-y)))
+LX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-y)))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
 
 include $(TOPDIR)/Rules.make
 
+lk201-map.c: lk201-map.map
+	loadkeys --mktable lk201-map.map > lk201-map.c
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- v2.4.3/linux/drivers/usb/dc2xx.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/dc2xx.c	Wed Apr 18 11:49:12 2001
@@ -48,7 +48,7 @@
  * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter
  *
  * Thanks to:  the folk who've provided USB product IDs, sent in
- * patches, and shared their sucesses!
+ * patches, and shared their successes!
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.4.3/linux/drivers/usb/devio.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/devio.c	Fri Apr  6 15:51:50 2001
@@ -175,6 +175,7 @@
                 return NULL;
         memset(as, 0, assize);
         as->urb.number_of_packets = numisoframes;
+        spin_lock_init(&as->urb.lock);
         return as;
 }
 
@@ -250,10 +251,6 @@
         struct dev_state *ps = as->ps;
 	struct siginfo sinfo;
 
-#if 1
-	printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", 
-	       urb->status, urb->error_count, urb->actual_length, urb->pipe);
-#endif
         spin_lock(&ps->lock);
         list_del(&as->asynclist);
         list_add_tail(&as->asynclist, &ps->async_completed);
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/hid.h linux/drivers/usb/hid.h
--- v2.4.3/linux/drivers/usb/hid.h	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/hid.h	Wed Apr 18 11:49:12 2001
@@ -205,7 +205,7 @@
 };
 
 /*
- * This is the local enviroment. It is resistent up the the next main-item.
+ * This is the local enviroment. It is resistent up the next main-item.
  */
 
 #define HID_MAX_DESCRIPTOR_SIZE		4096
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.4.3/linux/drivers/usb/hub.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/hub.c	Wed Apr 25 14:10:47 2001
@@ -98,15 +98,12 @@
 	hub->nerrors = 0;
 
 	/* Something happened, let khubd figure it out */
-	if (waitqueue_active(&khubd_wait)) {
-		/* Add the hub to the event queue */
-		spin_lock_irqsave(&hub_event_lock, flags);
-		if (list_empty(&hub->event_list)) {
-			list_add(&hub->event_list, &hub_event_list);
-			wake_up(&khubd_wait);
-		}
-		spin_unlock_irqrestore(&hub_event_lock, flags);
+	spin_lock_irqsave(&hub_event_lock, flags);
+	if (list_empty(&hub->event_list)) {
+		list_add(&hub->event_list, &hub_event_list);
+		wake_up(&khubd_wait);
 	}
+	spin_unlock_irqrestore(&hub_event_lock, flags);
 }
 
 static void usb_hub_power_on(struct usb_hub *hub)
@@ -239,7 +236,6 @@
 
 static void *hub_probe(struct usb_device *dev, unsigned int i,
 		       const struct usb_device_id *id)
-
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
@@ -293,7 +289,7 @@
 
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->dev = dev;
-	init_MUTEX(&hub->khubd_sem);
+	atomic_set(&hub->refcnt, 1);
 
 	/* Record the new hub's existence */
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -322,11 +318,34 @@
 	return NULL;
 }
 
+static void hub_get(struct usb_hub *hub)
+{
+	atomic_inc(&hub->refcnt);
+}
+
+static void hub_put(struct usb_hub *hub)
+{
+	if (atomic_dec_and_test(&hub->refcnt)) {
+		if (hub->descriptor) {
+			kfree(hub->descriptor);
+			hub->descriptor = NULL;
+		}
+
+		kfree(hub);
+	}
+}
+
 static void hub_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_hub *hub = (struct usb_hub *)ptr;
 	unsigned long flags;
 
+	if (hub->urb) {
+		usb_unlink_urb(hub->urb);
+		usb_free_urb(hub->urb);
+		hub->urb = NULL;
+	}
+
 	spin_lock_irqsave(&hub_event_lock, flags);
 
 	/* Delete it and then reset it */
@@ -337,22 +356,7 @@
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
-	down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
-	up(&hub->khubd_sem);
-
-	if (hub->urb) {
-		usb_unlink_urb(hub->urb);
-		usb_free_urb(hub->urb);
-		hub->urb = NULL;
-	}
-
-	if (hub->descriptor) {
-		kfree(hub->descriptor);
-		hub->descriptor = NULL;
-	}
-
-	/* Free the memory */
-	kfree(hub);
+	hub_put(hub);
 }
 
 static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
@@ -406,6 +410,7 @@
 	if (usb_reset_device(dev))
 		return -1;
 
+	hub->urb->dev = dev;                                                    
 	if (usb_submit_urb(hub->urb))
 		return -1;
 
@@ -663,7 +668,7 @@
 		list_del(tmp);
 		INIT_LIST_HEAD(tmp);
 
-		down(&hub->khubd_sem); /* never blocks, we were on list */
+		hub_get(hub);
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
@@ -672,7 +677,7 @@
 			if (usb_hub_reset(hub)) {
 				err("error resetting hub %d - disconnecting", dev->devnum);
 				usb_hub_disconnect(dev);
-				up(&hub->khubd_sem);
+				hub_put(hub);
 				continue;
 			}
 
@@ -748,7 +753,7 @@
                         	usb_hub_power_on(hub);
 			}
 		}
-		up(&hub->khubd_sem);
+		hub_put(hub);
         } /* end while (1) */
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/hub.h linux/drivers/usb/hub.h
--- v2.4.3/linux/drivers/usb/hub.h	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/hub.h	Tue Apr 17 17:23:06 2001
@@ -109,7 +109,7 @@
 
 	struct usb_hub_descriptor *descriptor;
 
-	struct semaphore khubd_sem;
+	atomic_t refcnt;
 };
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c
--- v2.4.3/linux/drivers/usb/plusb.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/plusb.c	Wed Apr 18 11:49:12 2001
@@ -255,7 +255,7 @@
 /*
  * dequeue_next_skb - submit the first thing on the tx_skb_list to the
  * USB stack.  This function should be called each time we get a new
- * message to send to the other host, or each time a message is sucessfully
+ * message to send to the other host, or each time a message is successfully
  * sent.
  */
 static void dequeue_next_skb(char * func, plusb_t * s)
@@ -393,7 +393,7 @@
 
 /*
  * plusb_write_bulk_complete () - callback after the data has been
- *   sent to the USB device, or a timeout occured.
+ *   sent to the USB device, or a timeout occurred.
  */
 static void plusb_write_bulk_complete(urb_t *purb)
 {
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.4.3/linux/drivers/usb/scanner.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/scanner.c	Wed Apr 18 11:49:12 2001
@@ -174,7 +174,7 @@
  *      <flynn@isr.uni-stuttgart.de>.
  *    - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
  *    - Added access time update for the device file courtesy of Paul
- *      Mackerras <paulus@linuxcare.com>.  This allows a user space daemon
+ *      Mackerras <paulus@samba.org>.  This allows a user space daemon
  *      to turn the lamp off for a Umax 1220U scanner after a prescribed
  *      time.
  *    - Fixed HP S20 ID's.  Thanks to Ruud Linders <rlinders@xs4all.nl>.
@@ -420,7 +420,7 @@
 		dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
 
 		if (result == -ETIMEDOUT) {	/* NAK -- shouldn't happen */
-			warn("write_scanner: NAK recieved.");
+			warn("write_scanner: NAK received.");
 			ret = result;
 			break;
 		} else if (result < 0) { /* We should not get any I/O errors */
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- v2.4.3/linux/drivers/usb/serial/Config.in	Mon Mar 19 17:21:54 2001
+++ linux/drivers/usb/serial/Config.in	Fri Apr  6 15:51:50 2001
@@ -6,7 +6,9 @@
 
 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
+  if [ "$CONFIG_USB_SERIAL" = "y" ]; then
+     bool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
+  fi
   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
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- v2.4.3/linux/drivers/usb/serial/belkin_sa.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Fri Apr  6 15:51:50 2001
@@ -68,13 +68,13 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
- 	#define DEBUG
+ 	static int debug = 1;
 #else
- 	#undef DEBUG
+ 	static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
 #include "belkin_sa.h"
@@ -607,3 +607,7 @@
 module_exit (belkin_sa_exit);
 
 MODULE_DESCRIPTION("USB Belkin Serial converter driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/belkin_sa.h linux/drivers/usb/serial/belkin_sa.h
--- v2.4.3/linux/drivers/usb/serial/belkin_sa.h	Tue Mar 20 14:02:46 2001
+++ linux/drivers/usb/serial/belkin_sa.h	Fri Apr  6 15:51:52 2001
@@ -43,7 +43,7 @@
 #define PERACOM_PID	0x0001	/* Peracom's single port serial converter's id */
 
 #define GOHUBS_VID	0x0921	/* GoHubs vendor id */
-#define GOHUBS_PID	0x0100	/* GoHubs single port serial converter's id (identical to the Peracom device) */
+#define GOHUBS_PID	0x1000	/* GoHubs single port serial converter's id (identical to the Peracom device) */
 
 /* Vendor Request Interface */
 #define BELKIN_SA_SET_BAUDRATE_REQUEST	0  /* Set baud rate */
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- v2.4.3/linux/drivers/usb/serial/digi_acceleport.c	Tue Mar 20 14:02:46 2001
+++ linux/drivers/usb/serial/digi_acceleport.c	Fri Apr  6 15:51:50 2001
@@ -241,14 +241,14 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
 
-#include <linux/usb.h>
 #include "usb-serial.h"
 
 
@@ -2085,4 +2085,7 @@
 
 MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>");
 MODULE_DESCRIPTION("Digi AccelePort USB-2/USB-4 Serial Converter driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- v2.4.3/linux/drivers/usb/serial/empeg.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/serial/empeg.c	Fri Apr  6 15:51:51 2001
@@ -55,12 +55,13 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
+
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
 
@@ -705,3 +706,7 @@
 
 MODULE_AUTHOR("Gary Brubaker <xavyer@ix.netcom.com>");
 MODULE_DESCRIPTION("USB Empeg Mark I/II Driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.4.3/linux/drivers/usb/serial/ftdi_sio.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Wed Apr 18 11:49:12 2001
@@ -78,16 +78,15 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
-
 #include "ftdi_sio.h"
 
 
@@ -423,7 +422,7 @@
 		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 a wait_queue */
+		   hitting interruptible_sleep_on  - so wrapping in a wait_queue */
 
 		add_wait_queue(&port->write_wait, &wait);
 		set_current_state (TASK_INTERRUPTIBLE);
@@ -881,3 +880,7 @@
 
 MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>");
 MODULE_DESCRIPTION("USB FTDI RS232 converters driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- v2.4.3/linux/drivers/usb/serial/io_edgeport.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Thu Apr 12 12:16:36 2001
@@ -223,6 +223,7 @@
  * 
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -239,15 +240,14 @@
 #include <linux/serial.h>
 #include <linux/ioctl.h>
 #include <linux/proc_fs.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
 
-#include <linux/usb.h>
-
 #include "usb-serial.h"
 
 #include "io_edgeport.h"
@@ -279,6 +279,9 @@
 MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli");
 MODULE_DESCRIPTION("Edgeport USB Serial Driver");
 
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
 #define MAX_NAME_LEN		64
 
 
@@ -474,47 +477,6 @@
 
 
 
-
-#ifdef DEBUG
-
-/* Dump a buffer in HEX and Ascii */
-void DbgDisplayBuffer( void *pBuffer, __u32 Len )
-{
-	char    DisplayBuf[80];
-	char *  pStr = DisplayBuf;
-	__u8 *pBuf = pBuffer; 
-	__u32   i;
-	__u8   d;
-
-	while (Len) {
-		// Init for new line
-		memset( DisplayBuf, ' ', sizeof( DisplayBuf ));
-		DisplayBuf[79]=0;
-		pStr = DisplayBuf;
-		pStr[54] = '[';
-		pStr[71] = ']';
-
-		for ( i = 0; i < MIN(16, Len) ; i++ ) {
-			d = (__u8)(*pBuf >> 4);
-			pStr[(i*3)+0] = (char)((d < 10) ? d+'0' : d -10 + 'A');
-			d = (__u8)(*pBuf & 0xf);
-			pStr[(i*3)+1] = (char)((d < 10) ? d+'0' : d -10 + 'A');
-
-			if (*pBuf > 31 && *pBuf < 127)
-				pStr[i+55]=*pBuf;
-			else
-				pStr[i+55]='.';
-
-			pBuf++;
-		}
-		Len -= i;
-		dbg("%s", DisplayBuf );
-	}
-}
-#endif
-
-
-
 // ************************************************************************
 // ************************************************************************
 // ************************************************************************
@@ -745,7 +707,6 @@
 			break;
 	}
 
-#ifdef DEBUG
 	// Dump Product Info structure
 	dbg("**Product Information:");
 	dbg("  ProductId             %x", product_info->ProductId );
@@ -770,7 +731,6 @@
 	    product_info->ManufactureDescDate[2]+1900);
 	dbg("  iDownloadFile         0x%x",     product_info->iDownloadFile);
 
-#endif
 }
 
 
@@ -812,14 +772,7 @@
 
 	// process this interrupt-read even if there are no ports open
 	if (length) {
-#ifdef DEBUG
-		int i;
-		printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, data = ", length);
-		for (i = 0; i < length; ++i) {
-			printk ("%.2x ", data[i]);
-		}
-		printk ("\n");
-#endif
+		usb_serial_debug_data (__FILE__, __FUNCTION__, length, data);
 
 		if (length > 1) {
 			bytes_avail = data[0] | (data[1] << 8);
@@ -894,13 +847,7 @@
 	if (urb->actual_length) {
 		raw_data_length = urb->actual_length;
 
-#ifdef DEBUG
-		{
-//			int i;
-			dbg (__FUNCTION__" - length = %d, data = ", raw_data_length);
-//			DbgDisplayBuffer((void *)data, raw_data_length);
-		}
-#endif
+		usb_serial_debug_data (__FILE__, __FUNCTION__, raw_data_length, data);
 
 		/* decrement our rxBytes available by the number that we just got */
 		edge_serial->rxBytesAvail -= raw_data_length;
@@ -976,10 +923,8 @@
 
 	dbg(__FUNCTION__);
 
-#ifdef DEBUG	
 	CmdUrbs--;
 	dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs);
-#endif
 
 
 	/* if this urb had a transfer buffer already (old transfer) free it */
@@ -1412,12 +1357,9 @@
 		// No need to check for wrap since we can not get to end of fifo in this part
 	}
 
-#ifdef DEBUG
 	if (copySize) {
-		dbg (__FUNCTION__" - length = %d, data = ", copySize);
-		DbgDisplayBuffer((void *)data, copySize);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, copySize, data);
 	}
-#endif
 
 	send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port);
 
@@ -1519,12 +1461,9 @@
 		fifo->count -= secondhalf;
 	}
 
-#ifdef DEBUG
 	if (count) {
-		dbg (__FUNCTION__" - length = %d, data = ", count);
-		DbgDisplayBuffer((void *)&buffer[2], count);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, count, &buffer[2]);
 	}
-#endif
 
 	/* fill up the urb with all of our data and submit it */
 	FILL_BULK_URB (urb, edge_serial->serial->dev, 
@@ -2498,16 +2437,7 @@
 	urb_t *urb;
 	int timeout;
 
-#ifdef DEBUG
-	if (length) {
-		int i;
-		printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, buffer = ", length);
-		for (i = 0; i < length; ++i) {
-			printk ("%.2x ", buffer[i]);
-		}
-		printk ("\n");
-	}
-#endif
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
 
 	/* Allocate our next urb */
 	urb = usb_alloc_urb (0);
@@ -2857,7 +2787,6 @@
 	if (response < 1) {
 		err("error in getting manufacturer descriptor");
 	} else {
-#ifdef DEBUG
 		char string[30];
 		dbg("**Manufacturer Descriptor");
 		dbg("  RomSize:        %dK", edge_serial->manuf_descriptor.RomSize);
@@ -2875,7 +2804,6 @@
 		dbg("  UartType:       %d", edge_serial->manuf_descriptor.UartType);
 		dbg("  IonPid:         %d", edge_serial->manuf_descriptor.IonPid);
 		dbg("  IonConfig:      %d", edge_serial->manuf_descriptor.IonConfig);
-#endif
 	}
 }
 
@@ -3138,6 +3066,4 @@
 
 module_init(edgeport_init);
 module_exit(edgeport_exit);
-
-
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.4.3/linux/drivers/usb/serial/keyspan.c	Fri Mar  2 17:50:22 2001
+++ linux/drivers/usb/serial/keyspan.c	Thu Apr 12 12:16:36 2001
@@ -49,6 +49,7 @@
 */
 
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -62,13 +63,14 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-
-#define DEBUG
-/*  #ifdef CONFIG_USB_SERIAL_DEBUG */
-	#define DEBUG
-/*  #endif */
 #include <linux/usb.h>
 
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
 #include "usb-serial.h"
 #include "keyspan.h"
 
@@ -1671,3 +1673,7 @@
 		kfree(port->private);
 	}
 }
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c
--- v2.4.3/linux/drivers/usb/serial/keyspan_pda.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/serial/keyspan_pda.c	Fri Apr  6 15:51:51 2001
@@ -67,13 +67,14 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
-#include <linux/usb.h>
+
 
 struct ezusb_hex_record {
 	__u16 address;
@@ -82,7 +83,6 @@
 };
 
 #include "keyspan_pda_fw.h"
-
 #include "usb-serial.h"
 
 struct keyspan_pda_private {
@@ -823,3 +823,7 @@
 
 MODULE_AUTHOR("Brian Warner <warner@lothar.com>");
 MODULE_DESCRIPTION("USB Keyspan PDA Converter driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- v2.4.3/linux/drivers/usb/serial/mct_u232.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/serial/mct_u232.c	Fri Apr  6 15:51:52 2001
@@ -53,13 +53,13 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
- 	#define DEBUG
+ 	static int debug = 1;
 #else
- 	#undef DEBUG
+ 	static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
 #include "mct_u232.h"
@@ -848,3 +848,7 @@
 MODULE_PARM_DESC(write_blocking, 
 		 "The write function will block to write out all data");
 #endif
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- v2.4.3/linux/drivers/usb/serial/omninet.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/serial/omninet.c	Fri Apr  6 15:51:52 2001
@@ -43,17 +43,14 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) )
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
 
-#include <linux/usb.h>
-
 #include "usb-serial.h"
 
 
@@ -252,8 +249,7 @@
 		return;
 	}
 
-#ifdef DEBUG
-	if(header->oh_xxx != 0x30) {
+	if ((debug) && (header->oh_xxx != 0x30)) {
 		if (urb->actual_length) {
 			printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
 			for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
@@ -262,7 +258,6 @@
 			printk ("\n");
 		}
 	}
-#endif
 
 	if (urb->actual_length && header->oh_len) {
 		for (i = 0; i < header->oh_len; i++) {
@@ -413,4 +408,7 @@
 
 module_init(omninet_init);
 module_exit(omninet_exit);
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h
--- v2.4.3/linux/drivers/usb/serial/usb-serial.h	Mon Dec 11 13:17:29 2000
+++ linux/drivers/usb/serial/usb-serial.h	Fri Apr  6 15:51:52 2001
@@ -219,15 +219,24 @@
 
 static inline void usb_serial_debug_data (const char *file, const char *function, int size, const unsigned char *data)
 {
-#ifdef CONFIG_USB_SERIAL_DEBUG
 	int i;
+
+	if (!debug)
+		return;
+	
 	printk (KERN_DEBUG "%s: %s - length = %d, data = ", file, function, size);
 	for (i = 0; i < size; ++i) {
 		printk ("%.2x ", data[i]);
 	}
 	printk ("\n");
-#endif
 }
+
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
+
+
 
 #endif	/* ifdef __LINUX_USB_SERIAL_H */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.4.3/linux/drivers/usb/serial/usbserial.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/serial/usbserial.c	Fri Apr  6 15:51:52 2001
@@ -272,19 +272,24 @@
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
-#include <linux/usb.h>
+
+#include "usb-serial.h"
+
 
 /* Module information */
 MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
 MODULE_DESCRIPTION("USB Serial Driver");
 
-#include "usb-serial.h"
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
 
 #define MAX(a,b)	(((a)>(b))?(a):(b))
 
@@ -364,6 +369,7 @@
 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];	/* initially all NULL */
+
 
 LIST_HEAD(usb_serial_driver_list);
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.4.3/linux/drivers/usb/serial/visor.c	Mon Mar 19 17:21:54 2001
+++ linux/drivers/usb/serial/visor.c	Fri Apr  6 15:51:52 2001
@@ -92,16 +92,15 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
-
 #include "visor.h"
 
 #define MIN(a,b)                (((a)<(b))?(a):(b))
@@ -689,3 +688,7 @@
 
 MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
 MODULE_DESCRIPTION("USB HandSpring Visor driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/visor.h linux/drivers/usb/serial/visor.h
--- v2.4.3/linux/drivers/usb/serial/visor.h	Fri May  5 13:41:30 2000
+++ linux/drivers/usb/serial/visor.h	Wed Apr 18 11:49:12 2001
@@ -29,7 +29,7 @@
 
 /****************************************************************************
  * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
- * are available to be transfered to the host for the specified endpoint.
+ * are available to be transferred to the host for the specified endpoint.
  * Currently this is not used, and always returns 0x0001
  ****************************************************************************/
 #define VISOR_REQUEST_BYTES_AVAILABLE		0x01
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- v2.4.3/linux/drivers/usb/serial/whiteheat.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/serial/whiteheat.c	Fri Apr  6 15:51:52 2001
@@ -67,18 +67,16 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-	#define DEBUG
+	static int debug = 1;
 #else
-	#undef DEBUG
+	static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
-
 #include "whiteheat_fw.h"		/* firmware for the ConnectTech WhiteHEAT device */
-
 #include "whiteheat.h"			/* WhiteHEAT specific commands */
 
 #define CONNECT_TECH_VENDOR_ID		0x0710
@@ -634,3 +632,7 @@
 
 MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
 MODULE_DESCRIPTION("USB ConnectTech WhiteHEAT driver");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/storage/sddr09.c linux/drivers/usb/storage/sddr09.c
--- v2.4.3/linux/drivers/usb/storage/sddr09.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/storage/sddr09.c	Wed Apr 18 11:49:12 2001
@@ -182,7 +182,7 @@
 		return US_BULK_TRANSFER_SHORT;
 	}
 
-	US_DEBUGP("Transfered %d of %d bytes\n", act_len, len);
+	US_DEBUGP("Transferred %d of %d bytes\n", act_len, len);
 
 	return US_BULK_TRANSFER_GOOD;
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c
--- v2.4.3/linux/drivers/usb/storage/transport.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/storage/transport.c	Wed Apr 18 11:49:12 2001
@@ -635,7 +635,7 @@
 /* Invoke the transport and basic error-handling/recovery methods
  *
  * This is used by the protocol layers to actually send the message to
- * the device and recieve the response.
+ * the device and receive the response.
  */
 void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
@@ -821,7 +821,7 @@
 {
 	struct us_data *us = (struct us_data *)urb->context;
 
-	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+	US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no);
 	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
 	US_DEBUGP("-- IRQ state is %d\n", urb->status);
 	US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
@@ -1117,7 +1117,7 @@
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	/* if the command transfered well, then we go to the data stage */
+	/* if the command transferred well, then we go to the data stage */
 	if (result == 0) {
 		/* send/receive data payload, if there is any */
 		if (bcb.DataTransferLength) {
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/storage/transport.h linux/drivers/usb/storage/transport.h
--- v2.4.3/linux/drivers/usb/storage/transport.h	Mon Mar 26 15:49:54 2001
+++ linux/drivers/usb/storage/transport.h	Wed Apr 25 16:25:44 2001
@@ -107,7 +107,7 @@
  * us_bulk_transfer() return codes
  */
 #define US_BULK_TRANSFER_GOOD		0  /* good transfer                 */
-#define US_BULK_TRANSFER_SHORT		1  /* transfered less than expected */
+#define US_BULK_TRANSFER_SHORT		1  /* transferred less than expected */
 #define US_BULK_TRANSFER_FAILED		2  /* transfer died in the middle   */
 #define US_BULK_TRANSFER_ABORTED	3  /* transfer canceled             */
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h
--- v2.4.3/linux/drivers/usb/uhci-debug.h	Mon Mar 26 15:50:14 2001
+++ linux/drivers/usb/uhci-debug.h	Wed Apr 25 16:23:09 2001
@@ -6,20 +6,65 @@
  * visible pointers are surrounded in ()'s
  *
  * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999-2001 Johannes Erdfelt
  */
 
 #include <linux/kernel.h>
+#include <linux/proc_fs.h>
 #include <asm/io.h>
 
 #include "uhci.h"
 
-void uhci_show_td(struct uhci_td *td)
+/* Handle REALLY large printk's so we don't overflow buffers */
+static void inline lprintk(char *buf)
 {
+	char *p;
+
+	/* Just write one line at a time */
+	while (buf) {
+		p = strchr(buf, '\n');
+		if (p)
+			*p = 0;
+		printk("%s\n", buf);
+		buf = p;
+		if (buf)
+			buf++;
+	}
+}
+
+static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (td == uhci->skeltd[i])
+			return 1;
+
+	return 0;
+}
+
+static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (qh == uhci->skelqh[i])
+			return 1;
+
+	return 0;
+}
+
+static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
+{
+	char *out = buf;
 	char *spid;
 
-	printk("%08x ", td->link);
-	printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+	/* Try to make sure there's enough memory */
+	if (len < 160)
+		return 0;
+
+	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
+	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
 		((td->status >> 27) & 3),
 		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
 		(td->status & TD_CTRL_LS) ?       "LS " : "",
@@ -48,19 +93,27 @@
 			break;
 	}
 
-	printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+	out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
 		td->info >> 21,
 		((td->info >> 19) & 1),
 		(td->info >> 15) & 15,
 		(td->info >> 8) & 127,
 		(td->info & 0xff),
 		spid);
-	printk("(buf=%08x)\n", td->buffer);
+	out += sprintf(out, "(buf=%08x)\n", td->buffer);
+
+	return out - buf;
 }
 
-static void uhci_show_sc(int port, unsigned short status)
+static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 {
-	printk("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+	char *out = buf;
+
+	/* Try to make sure there's enough memory */
+	if (len < 80)
+		return 0;
+
+	out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
 		port,
 		status,
 		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
@@ -71,16 +124,23 @@
 		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
 		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
 		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
+
+	return out - buf;
 }
 
-void uhci_show_status(struct uhci *uhci)
+static int uhci_show_status(struct uhci *uhci, char *buf, int len)
 {
+	char *out = buf;
 	unsigned int io_addr = uhci->io_addr;
 	unsigned short usbcmd, usbstat, usbint, usbfrnum;
 	unsigned int flbaseadd;
 	unsigned char sof;
 	unsigned short portsc1, portsc2;
 
+	/* Try to make sure there's enough memory */
+	if (len < 80 * 6)
+		return 0;
+
 	usbcmd    = inw(io_addr + 0);
 	usbstat   = inw(io_addr + 2);
 	usbint    = inw(io_addr + 4);
@@ -90,7 +150,7 @@
 	portsc1   = inw(io_addr + 16);
 	portsc2   = inw(io_addr + 18);
 
-	printk("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+	out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
 		usbcmd,
 		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
 		(usbcmd & USBCMD_CF) ?      "CF " : "",
@@ -101,7 +161,7 @@
 		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
 		(usbcmd & USBCMD_RS) ?      "RS " : "");
 
-	printk("  usbstat   =     %04x   %s%s%s%s%s%s\n",
+	out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
 		usbstat,
 		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
 		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
@@ -110,53 +170,69 @@
 		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
 		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
 
-	printk("  usbint    =     %04x\n", usbint);
-	printk("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+	out += sprintf(out, "  usbint    =     %04x\n", usbint);
+	out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
 		0xfff & (4*(unsigned int)usbfrnum));
-	printk("  flbaseadd = %08x\n", flbaseadd);
-	printk("  sof       =       %02x\n", sof);
-	uhci_show_sc(1, portsc1);
-	uhci_show_sc(2, portsc2);
-}
-
-#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
-
-struct uhci_td *uhci_link_to_td(unsigned int link)
-{
-	if (link & UHCI_PTR_TERM)
-		return NULL;
+	out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
+	out += sprintf(out, "  sof       =       %02x\n", sof);
+	out += uhci_show_sc(1, portsc1, out, len - (out - buf));
+	out += uhci_show_sc(2, portsc2, out, len - (out - buf));
 
-	return bus_to_virt(link & ~UHCI_PTR_BITS);
+	return out - buf;
 }
 
-void uhci_show_urb_queue(struct urb *urb)
+static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
 {
-	struct urb_priv *urbp = urb->hcpriv;
+	char *out = buf;
+	struct urb_priv *urbp;
 	struct list_head *head, *tmp;
-	int i, checked = 0, prevactive = 0;
+	struct uhci_td *td;
+	int i = 0, checked = 0, prevactive = 0;
+
+	/* Try to make sure there's enough memory */
+	if (len < 80 * 6)
+		return 0;
+
+	out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
+			qh, qh->link, qh->element);
+
+	if (qh->element & UHCI_PTR_QH)
+		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
+
+	if (qh->element & UHCI_PTR_DEPTH)
+		out += sprintf(out, "%*s  Depth traverse\n", space, "");
 
-	printk("  URB [%p] urbp [%p]\n", urb, urbp);
+	if (qh->element & 8)
+		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
 
-	if (urbp->qh)
-		printk("    QH [%p]\n", urbp->qh);
-	else
-		printk("    QH [%p] element (%08x) link (%08x)\n", urbp->qh,
-			urbp->qh->element, urbp->qh->link);
+	if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
+		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
+
+	if (!qh->urbp) {
+		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
+		goto out;
+	}
 
-	i = 0;
+	urbp = qh->urbp;
 
-	head = &urbp->list;
+	head = &urbp->td_list;
 	tmp = head->next;
+
+	td = list_entry(tmp, struct uhci_td, list);
+
+	if (td->dma_handle != (qh->element & ~UHCI_PTR_BITS))
+		out += sprintf(out, "%*s Element != First TD\n", space, "");
+
 	while (tmp != head) {
 		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
 		tmp = tmp->next;
 
-		printk("      td %d: [%p]\n", i++, td);
-		printk("      ");
-		uhci_show_td(td);
+		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
+		out += uhci_show_td(td, out, len - (out - buf), 0);
 
-		if (i > 10 && !checked && prevactive && tmp != head) {
+		if (i > 10 && !checked && prevactive && tmp != head &&
+		    debug <= 2) {
 			struct list_head *ntmp = tmp;
 			struct uhci_td *ntd = td;
 			int active = 1, ni = i;
@@ -174,7 +250,7 @@
 			}
 
 			if (active && ni > i) {
-				printk("      [skipped %d active TD's]\n", ni - i);
+				out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
 				tmp = ntmp;
 				td = ntd;
 				i = ni;
@@ -183,134 +259,312 @@
 
 		prevactive = td->status & TD_CTRL_ACTIVE;
 	}
-}
 
-void uhci_show_queue(struct uhci_qh *qh)
-{
-	struct uhci_td *td, *first;
-	int i = 0, count = 1000;
+	if (list_empty(&urbp->queue_list) || urbp->queued)
+		goto out;
 
-	if (qh->element & UHCI_PTR_QH)
-		printk("      Element points to QH (bug?)\n");
+	out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
 
-	if (qh->element & UHCI_PTR_DEPTH)
-		printk("      Depth traverse\n");
+	head = &urbp->queue_list;
+	tmp = head->next;
 
-	if (qh->element & UHCI_PTR_TERM)
-		printk("      Terminate\n");
+	while (tmp != head) {
+		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
+						queue_list);
+		tmp = tmp->next;
 
-	if (!(qh->element & ~UHCI_PTR_BITS)) {
-		printk("      td 0: [NULL]\n");
-		return;
+		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
 	}
 
-	first = uhci_link_to_td(qh->element);
+out:
+	return out - buf;
+}
 
-	/* Make sure it doesn't runaway */
-	for (td = first; td && count > 0; 
-	     td = uhci_link_to_td(td->link), --count) {
-		printk("      td %d: [%p]\n", i++, td);
-		printk("      ");
-		uhci_show_td(td);
+static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
+				 "skel_int4_td", "skel_int8_td",
+				 "skel_int16_td", "skel_int32_td",
+				 "skel_int64_td", "skel_int128_td",
+				 "skel_int256_td", "skel_term_td" };
+static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
+				  "skel_bulk_qh", "skel_term_qh" };
+
+#define show_frame_num()	\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- Frame %d\n", i); \
+	}
 
-		if (td == uhci_link_to_td(td->link)) {
-			printk(KERN_ERR "td links to itself!\n");
-			break;
-		}
+#define show_td_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", td_names[i]); \
 	}
-}
 
-static int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
-{
-	int j;
+#define show_qh_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", qh_names[i]); \
+	}
 
-	for (j = 0; j < UHCI_NUM_SKELTD; j++)
-		if (td == uhci->skeltd + j)
-			return 1;
+static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
+{
+	char *out = buf;
+	int i;
+	struct uhci_qh *qh;
+	struct uhci_td *td;
+	struct list_head *tmp, *head;
 
-	return 0;
-}
+	out += sprintf(out, "HC status\n");
+	out += uhci_show_status(uhci, out, len - (out - buf));
 
-static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	int j;
+	out += sprintf(out, "Frame List\n");
+	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+		int shown = 0;
+		td = uhci->fl->frame_cpu[i];
+		if (!td)
+			continue;
+
+		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
+			show_frame_num();
+			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+		}
+		if (uhci_is_skeleton_td(uhci, td))
+			continue;
+		show_frame_num();
+
+		head = &td->fl_list;
+		tmp = head;
+		do {
+			td = list_entry(tmp, struct uhci_td, fl_list);
+			tmp = tmp->next;
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		} while (tmp != head);
+	}
 
-	for (j = 0; j < UHCI_NUM_SKELQH; j++)
-		if (qh == uhci->skelqh + j)
-			return 1;
+	out += sprintf(out, "Skeleton TD's\n");
+	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
+		int shown = 0;
 
-	return 0;
-}
+		td = uhci->skeltd[i];
 
-static const char *td_names[] = {"interrupt1", "interrupt2", "interrupt4",
-				 "interrupt8", "interrupt16", "interrupt32",
-				 "interrupt64", "interrupt128", "interrupt256" };
-static const char *qh_names[] = { "control", "bulk" };
+		if (debug > 1) {
+			show_td_name();
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		}
 
-void uhci_show_queues(struct uhci *uhci)
-{
-	int i, isqh = 0;
-	struct uhci_qh *qh;
-	struct uhci_td *td;
+		if (list_empty(&td->fl_list)) {
+			/* TD 0 is the int1 TD and links to control_ls_qh */
+			if (!i) {
+				if (td->link !=
+				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
+					show_td_name();
+					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
+				}
+			} else if (i < 9) {
+				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
+					show_td_name();
+					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
+				}
+			} else {
+				show_td_name();
 
-	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		int shown = 0;
+				if (td->link != td->dma_handle)
+					out += sprintf(out, "    skel_term_td does not link to self\n");
 
-		td = uhci_link_to_td(uhci->fl->frame[i]);
-		if (td)
-			isqh = uhci->fl->frame[i] & UHCI_PTR_QH;
-		while (td && !isqh) {
-			if (uhci_is_skeleton_td(uhci, td))
-				break;
-
-			if (!shown) {
-				printk("   Frame %d\n", i);
-				shown = 1;
+				out += uhci_show_td(td, out, len - (out - buf), 4);
 			}
 
-			printk("[%p] ", td);
+			continue;
+		}
+
+		show_td_name();
+
+		head = &td->fl_list;
+		tmp = head->next;
+
+		while (tmp != head) {
+			td = list_entry(tmp, struct uhci_td, fl_list);
+
+			tmp = tmp->next;
+
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		}
 
-			uhci_show_td(td);
-			td = uhci_link_to_td(td->link);
-			if (td)
-				isqh = td->link & UHCI_PTR_QH;
-		}
-	}
-	for (i = 0; i < UHCI_NUM_SKELTD; ++i) {
-		printk("  %s: [%p] (%08x)\n", td_names[i],
-			&uhci->skeltd[i],
-			uhci->skeltd[i].link);
-
-		td = uhci_link_to_td(uhci->skeltd[i].link);
-		if (td)
-			isqh = uhci->skeltd[i].link & UHCI_PTR_QH;
-		while (td && !isqh) {
-			if (uhci_is_skeleton_td(uhci, td))
-				break;
-
-			printk("[%p] ", td);
-
-			uhci_show_td(td);
-			td = uhci_link_to_td(td->link);
-			if (td)
-				isqh = td->link & UHCI_PTR_QH;
+		if (!i) {
+			if (td->link !=
+			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
+				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
+		} else if (i < 9) {
+			if (td->link != uhci->skeltd[i - 1]->dma_handle)
+				out += sprintf(out, "    last TD not linked to next skeleton!\n");
 		}
 	}
+
+	out += sprintf(out, "Skeleton QH's\n");
+
 	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-		printk("  %s: [%p] (%08x) (%08x)\n", qh_names[i],
-			&uhci->skelqh[i],
-			uhci->skelqh[i].link, uhci->skelqh[i].element);
-
-		qh = uhci_link_to_qh(uhci->skelqh[i].link);
-		for (; qh; qh = uhci_link_to_qh(qh->link)) {
-			if (uhci_is_skeleton_qh(uhci, qh))
-				break;
+		int shown = 0;
+
+		qh = uhci->skelqh[i];
+
+		if (debug > 1) {
+			show_qh_name();
+			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+		}
+
+		/* QH 3 is the Terminating QH, it's different */
+		if (i == 3) {
+			if (qh->link != UHCI_PTR_TERM) {
+				show_qh_name();
+				out += sprintf(out, "    bandwidth reclamation on!\n");
+			}
 
-			printk("    [%p] (%08x) (%08x)\n",
-				qh, qh->link, qh->element);
+			if (qh->element != uhci->skel_term_td->dma_handle) {
+				show_qh_name();
+				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
+			}
+		}
+
+		if (list_empty(&qh->list)) {
+			if (i < 3) {
+				if (qh->link !=
+				    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH)) {
+					show_qh_name();
+					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
+				}
+			}
 
-			uhci_show_queue(qh);
+			continue;
 		}
+
+		show_qh_name();
+
+		head = &qh->list;
+		tmp = head->next;
+
+		while (tmp != head) {
+			qh = list_entry(tmp, struct uhci_qh, list);
+
+			tmp = tmp->next;
+
+			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+		}
+
+		if (i < 3) {
+			if (qh->link !=
+			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
+				out += sprintf(out, "    last QH not linked to next skeleton!\n");
+		}
+	}
+
+	return out - buf;
+}
+
+#ifdef CONFIG_PROC_FS
+#define MAX_OUTPUT	(PAGE_SIZE * 8)
+
+static struct proc_dir_entry *uhci_proc_root = NULL;
+
+struct uhci_proc {
+	int size;
+	char *data;
+	struct uhci *uhci;
+};
+
+static int uhci_proc_open(struct inode *inode, struct file *file)
+{
+	const struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct uhci *uhci = dp->data;
+	struct uhci_proc *up;
+	unsigned long flags;
+	int ret = -ENOMEM;
+
+	lock_kernel();
+	up = kmalloc(sizeof(*up), GFP_KERNEL);
+	if (!up)
+		goto out;
+
+	up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
+	if (!up->data) {
+		kfree(up);
+		goto out;
+	}
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+
+	file->private_data = up;
+
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
+{
+	struct uhci_proc *up = file->private_data;
+	loff_t new;
+
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+	default:
+		return -EINVAL;
 	}
+	if (new < 0 || new > up->size)
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
+			loff_t *ppos)
+{
+	struct uhci_proc *up = file->private_data;
+	unsigned int pos;
+	unsigned int size;
+
+	pos = *ppos;
+	size = up->size;
+	if (pos >= size)
+		return 0;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
+
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EINVAL;
+
+	copy_to_user(buf, up->data + pos, nbytes);
+
+	*ppos += nbytes;
+
+	return nbytes;
+}
+
+static int uhci_proc_release(struct inode *inode, struct file *file)
+{
+	struct uhci_proc *up = file->private_data;
+
+	kfree(up->data);
+	kfree(up);
+
+	return 0;
 }
+
+static struct file_operations uhci_proc_operations = {
+	open:		uhci_proc_open,
+	llseek:		uhci_proc_lseek,
+	read:		uhci_proc_read,
+//	write:		uhci_proc_write,
+	release:	uhci_proc_release,
+};
+#endif
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.3/linux/drivers/usb/uhci.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/uhci.c	Wed Apr 25 14:10:49 2001
@@ -1,8 +1,10 @@
 /*
  * Universal Host Controller Interface driver for USB.
  *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
  * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2000 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999-2001 Johannes Erdfelt, johannes@erdfelt.com
  * (C) Copyright 1999 Randy Dunlap
  * (C) Copyright 1999 Georg Acher, acher@in.tum.de
  * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
@@ -12,7 +14,6 @@
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
  *
- *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
  * people who decided that they want to do the same thing in a
@@ -39,7 +40,12 @@
 #include <linux/unistd.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_USB_DEBUG
 #define DEBUG
+#else
+#undef DEBUG
+#endif
 #include <linux/usb.h>
 
 #include <asm/uaccess.h>
@@ -48,23 +54,36 @@
 #include <asm/system.h>
 
 #include "uhci.h"
-#include "uhci-debug.h"
 
 #include <linux/pm.h>
 
+/*
+ * debug = 0, no debugging messages
+ * debug = 1, dump failed URB's except for stalls
+ * debug = 2, dump all failed URB's (including stalls)
+ *            show all queues in /proc/uhci/hc*
+ * debug = 3, show all TD's in URB's when dumping
+ */
+#ifdef DEBUG
 static int debug = 1;
+#else
+static int debug = 0;
+#endif
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug level");
+static char *errbuf;
+#define ERRBUF_LEN    (PAGE_SIZE * 8)
+
+#include "uhci-debug.h"
 
-static kmem_cache_t *uhci_td_cachep;
-static kmem_cache_t *uhci_qh_cachep;
 static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
 
 static int rh_submit_urb(struct urb *urb);
 static int rh_unlink_urb(struct urb *urb);
 static int uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_generic(struct urb *urb);
 static int uhci_unlink_urb(struct urb *urb);
+static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb);
+static void uhci_call_completion(struct urb *urb);
 
 static int  ports_active(struct uhci *uhci);
 static void suspend_hc(struct uhci *uhci);
@@ -75,6 +94,8 @@
 /* If a transfer is still active after this much time, turn off FSBR */
 #define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
 
+#define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
+
 /*
  * Only the USB core should call uhci_alloc_dev and uhci_free_dev
  */
@@ -86,80 +107,94 @@
 static int uhci_free_dev(struct usb_device *dev)
 {
 	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	struct list_head *tmp, *head = &uhci->urb_list;
+	struct list_head list, *tmp, *head;
 	unsigned long flags;
 
 	/* Walk through the entire URB list and forcefully remove any */
 	/*  URBs that are still active for that device */
-	nested_lock(&uhci->urblist_lock, flags);
+
+	/* Two stage unlink so we don't deadlock on urb_list_lock */
+	INIT_LIST_HEAD(&list);
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
 
 		tmp = tmp->next;
 
-		if (u->dev == dev)
-			uhci_unlink_urb(u);
+		if (urb->dev == dev) {
+			list_del(&urb->urb_list);
+			list_add(&urb->urb_list, &list);
+		}
 	}
-	nested_unlock(&uhci->urblist_lock, flags);
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
-	return 0;
-}
+	head = &list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+		tmp = tmp->next;
 
-static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
+		/* Make sure we block waiting on these to die */
+		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+
+		/* uhci_unlink_urb will unlink from the temp list */
+		uhci_unlink_urb(urb);
+	}
 
-	nested_lock(&uhci->urblist_lock, flags);
-	list_add(&urb->urb_list, &uhci->urb_list);
-	nested_unlock(&uhci->urblist_lock, flags);
+	return 0;
 }
 
-static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
+static inline void uhci_set_next_interrupt(struct uhci *uhci)
 {
 	unsigned long flags;
 
-	nested_lock(&uhci->urblist_lock, flags);
-	if (!list_empty(&urb->urb_list)) {
-		list_del(&urb->urb_list);
-		INIT_LIST_HEAD(&urb->urb_list);
-	}
-	nested_unlock(&uhci->urblist_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	uhci->skel_term_td->status |= TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-void uhci_set_next_interrupt(struct uhci *uhci)
+static inline void uhci_clear_next_interrupt(struct uhci *uhci)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
-	uhci->skel_term_td.status |= TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-void uhci_clear_next_interrupt(struct uhci *uhci)
+static inline void uhci_add_complete(struct urb *urb)
 {
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
-	uhci->skel_term_td.status &= ~TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	list_add(&urbp->complete_list, &uhci->complete_list);
+	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
 }
 
-static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
+static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
 {
+	dma_addr_t dma_handle;
 	struct uhci_td *td;
 
-	td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
 	if (!td)
 		return NULL;
 
+	td->dma_handle = dma_handle;
+
 	td->link = UHCI_PTR_TERM;
 	td->buffer = 0;
 
-	td->frameptr = NULL;
-	td->nexttd = td->prevtd = NULL;
+	td->frame = -1;
 	td->dev = dev;
+
 	INIT_LIST_HEAD(&td->list);
+	INIT_LIST_HEAD(&td->fl_list);
 
 	usb_inc_dev_use(dev);
 
@@ -177,20 +212,19 @@
 static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
 {
 	unsigned long flags;
+	struct uhci_td *ltd;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list);
 
-	/* Fix the linked list pointers */
-	td->nexttd = skeltd->nexttd;
-	td->prevtd = skeltd;
-	if (skeltd->nexttd)
-		skeltd->nexttd->prevtd = td;
-	skeltd->nexttd = td;
+	td->link = ltd->link;
+	mb();
+	ltd->link = td->dma_handle;
 
-	td->link = skeltd->link;
-	skeltd->link = virt_to_bus(td);
+	list_add_tail(&td->fl_list, &skeltd->fl_list);
 
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 /*
@@ -200,27 +234,36 @@
  * frame list pointer -> iso td's (if any) ->
  * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
  */
-
 static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
 {
 	unsigned long flags;
-	struct uhci_td *nexttd;
 
 	framenum %= UHCI_NUMFRAMES;
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	td->frame = framenum;
+
+	/* Is there a TD already mapped there? */
+	if (uhci->fl->frame_cpu[framenum]) {
+		struct uhci_td *ftd, *ltd;
+
+		ftd = uhci->fl->frame_cpu[framenum];
+		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
+
+		list_add_tail(&td->fl_list, &ftd->fl_list);
 
-	td->frameptr = &uhci->fl->frame[framenum];
-	td->link = uhci->fl->frame[framenum];
-	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
-		nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
-		td->nexttd = nexttd;
-		nexttd->prevtd = td;
-		nexttd->frameptr = NULL;
+		td->link = ltd->link;
+		mb();
+		ltd->link = td->dma_handle;
+	} else {
+		td->link = uhci->fl->frame[framenum];
+		mb();
+		uhci->fl->frame[framenum] = td->dma_handle;
+		uhci->fl->frame_cpu[framenum] = td;
 	}
-	uhci->fl->frame[framenum] = virt_to_bus(td);
 
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
@@ -228,29 +271,36 @@
 	unsigned long flags;
 
 	/* If it's not inserted, don't remove it */
-	if (!td->frameptr && !td->prevtd && !td->nexttd)
+	if (td->frame == -1 && list_empty(&td->fl_list))
 		return;
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
-	if (td->frameptr) {
-		*(td->frameptr) = td->link;
-		if (td->nexttd) {
-			td->nexttd->frameptr = td->frameptr;
-			td->nexttd->prevtd = NULL;
-			td->nexttd = NULL;
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+		if (list_empty(&td->fl_list)) {
+			uhci->fl->frame[td->frame] = td->link;
+			uhci->fl->frame_cpu[td->frame] = NULL;
+		} else {
+			struct uhci_td *ntd;
+
+			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
+			uhci->fl->frame[td->frame] = ntd->dma_handle;
+			uhci->fl->frame_cpu[td->frame] = ntd;
 		}
-		td->frameptr = NULL;
 	} else {
-		if (td->prevtd) {
-			td->prevtd->nexttd = td->nexttd;
-			td->prevtd->link = td->link;
-		}
-		if (td->nexttd)
-			td->nexttd->prevtd = td->prevtd;
-		td->prevtd = td->nexttd = NULL;
+		struct uhci_td *ptd;
+
+		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
+		ptd->link = td->link;
 	}
+
+	mb();
 	td->link = UHCI_PTR_TERM;
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+
+	list_del(&td->fl_list);
+	INIT_LIST_HEAD(&td->fl_list);
+	td->frame = -1;
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 /*
@@ -260,22 +310,22 @@
 {
 	struct list_head *tmp, *head;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td, *prevtd;
+	struct uhci_td *td, *ptd;
 
-	if (!urbp)
+	if (list_empty(&urbp->td_list))
 		return;
 
-	head = &urbp->list;
+	head = &urbp->td_list;
 	tmp = head->next;
-	if (head == tmp)
-		return;
 
+	/* Ordering isn't important here yet since the QH hasn't been */
+	/*  inserted into the schedule yet */
 	td = list_entry(tmp, struct uhci_td, list);
 
 	/* Add the first TD to the QH element pointer */
-	qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
+	qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
 
-	prevtd = td;
+	ptd = td;
 
 	/* Then link the rest of the TD's */
 	tmp = tmp->next;
@@ -284,39 +334,42 @@
 
 		tmp = tmp->next;
 
-		prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
+		ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
 
-		prevtd = td;
+		ptd = td;
 	}
 
-	prevtd->link = UHCI_PTR_TERM;
+	ptd->link = UHCI_PTR_TERM;
 }
 
-static void uhci_free_td(struct uhci_td *td)
+static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
 {
-	if (!list_empty(&td->list))
+	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
 		dbg("td is still in URB list!");
 
 	if (td->dev)
 		usb_dec_dev_use(td->dev);
 
-	kmem_cache_free(uhci_td_cachep, td);
+	pci_pool_free(uhci->td_pool, td, td->dma_handle);
 }
 
-static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev)
+static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
 {
+	dma_addr_t dma_handle;
 	struct uhci_qh *qh;
 
-	qh = kmem_cache_alloc(uhci_qh_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
 	if (!qh)
 		return NULL;
 
+	qh->dma_handle = dma_handle;
+
 	qh->element = UHCI_PTR_TERM;
 	qh->link = UHCI_PTR_TERM;
 
 	qh->dev = dev;
-	qh->prevqh = qh->nextqh = NULL;
 
+	INIT_LIST_HEAD(&qh->list);
 	INIT_LIST_HEAD(&qh->remove_list);
 
 	usb_inc_dev_use(dev);
@@ -324,181 +377,290 @@
 	return qh;
 }
 
-static void uhci_free_qh(struct uhci_qh *qh)
+static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
+	if (!list_empty(&qh->list))
+		dbg("qh list not empty!");
+	if (!list_empty(&qh->remove_list))
+		dbg("qh still in remove_list!");
+
 	if (qh->dev)
 		usb_dec_dev_use(qh->dev);
 
-	kmem_cache_free(uhci_qh_cachep, qh);
+	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
 static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
 {
+	struct uhci_qh *lqh;
 	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	/* Grab the last QH */
+	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
 
-	/* Fix the linked list pointers */
-	qh->nextqh = skelqh->nextqh;
-	qh->prevqh = skelqh;
-	if (skelqh->nextqh)
-		skelqh->nextqh->prevqh = qh;
-	skelqh->nextqh = qh;
+	qh->link = lqh->link;
+	mb();				/* Ordering is important */
+	lqh->link = qh->dma_handle | UHCI_PTR_QH;
 
-	qh->link = skelqh->link;
-	skelqh->link = virt_to_bus(qh) | UHCI_PTR_QH;
+	list_add_tail(&qh->list, &skelqh->list);
 
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
 	unsigned long flags;
-	int delayed;
+	struct uhci_qh *prevqh;
 
-	/* If the QH isn't queued, then we don't need to delay unlink it */
-	delayed = (qh->prevqh || qh->nextqh);
+	/* Only go through the hoops if it's actually linked in */
+	if (list_empty(&qh->list)) {
+		uhci_free_qh(uhci, qh);
+		return;
+	}
+
+	qh->urbp = NULL;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	prevqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
-	if (qh->prevqh) {
-		qh->prevqh->nextqh = qh->nextqh;
-		qh->prevqh->link = qh->link;
-	}
-	if (qh->nextqh)
-		qh->nextqh->prevqh = qh->prevqh;
-	qh->prevqh = qh->nextqh = NULL;
+	prevqh->link = qh->link;
+	mb();
 	qh->element = qh->link = UHCI_PTR_TERM;
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 
-	if (delayed) {
-		spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+	list_del(&qh->list);
+	INIT_LIST_HEAD(&qh->list);
 
-		/* Check to see if the remove list is empty */
-		/* Set the IOC bit to force an interrupt so we can remove the QH */
-		if (list_empty(&uhci->qh_remove_list))
-			uhci_set_next_interrupt(uhci);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 
-		/* Add it */
-		list_add(&qh->remove_list, &uhci->qh_remove_list);
+	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 
-		spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
-	} else
-		uhci_free_qh(qh);
+	/* Check to see if the remove list is empty. Set the IOC bit */
+	/* to force an interrupt so we can remove the QH */
+	if (list_empty(&uhci->qh_remove_list))
+		uhci_set_next_interrupt(uhci);
+
+	list_add(&qh->remove_list, &uhci->qh_remove_list);
+
+	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
 }
 
-static spinlock_t uhci_append_urb_lock = SPIN_LOCK_UNLOCKED;
+static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		td->info &= ~(1 << TD_TOKEN_TOGGLE);
+		if (toggle)
+			td->info |= (1 << TD_TOKEN_TOGGLE);
+
+		toggle ^= 1;
+	}
+
+	return toggle;
+}
 
 /* This function will append one URB's QH to another URB's QH. This is for */
-/*  USB_QUEUE_BULK support */
+/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
+/*  control transfers */
 static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
 {
 	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
 	struct list_head *tmp;
-	struct uhci_td *td, *ltd;
+	struct uhci_td *ftd, *lltd;
 	unsigned long flags;
 
 	eurbp = eurb->hcpriv;
 	urbp = urb->hcpriv;
 
-	spin_lock_irqsave(&uhci_append_urb_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-	/* Find the beginning URB in the queue */
+	/* Find the first URB in the queue */
 	if (eurbp->queued) {
-		struct list_head *head = &eurbp->urb_queue_list;
+		struct list_head *head = &eurbp->queue_list;
 
 		tmp = head->next;
 		while (tmp != head) {
 			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, urb_queue_list);
-
-			tmp = tmp->next;
+				list_entry(tmp, struct urb_priv, queue_list);
 
 			if (!turbp->queued)
 				break;
+
+			tmp = tmp->next;
 		}
 	} else
-		tmp = &eurbp->urb_queue_list;
+		tmp = &eurbp->queue_list;
 
-	furbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+	furbp = list_entry(tmp, struct urb_priv, queue_list);
+	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
 
-	tmp = furbp->urb_queue_list.prev;
-	lurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+	ftd = list_entry(urbp->td_list.next, struct uhci_td, list);
 
-	/* Add this one to the end */
-	list_add_tail(&urbp->urb_queue_list, &furbp->urb_queue_list);
+	uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
 
-	/* Grab the last TD from the last URB */
-	ltd = list_entry(lurbp->list.prev, struct uhci_td, list);
+	mb();			/* Make sure we flush everything */
+	/* Only support bulk right now, so no depth */
+	lltd->link = ftd->dma_handle;
 
-	/* Grab the first TD from the first URB */
-	td = list_entry(urbp->list.next, struct uhci_td, list);
+	list_add_tail(&urbp->queue_list, &furbp->queue_list);
 
-	/* No breadth since this will only be called for bulk transfers */
-	ltd->link = virt_to_bus(td);
+	urbp->queued = 1;
 
-	spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
 {
 	struct urb_priv *urbp, *nurbp;
+	struct list_head *head, *tmp;
+	struct urb_priv *purbp;
+	struct uhci_td *pltd;
+	unsigned int toggle;
 	unsigned long flags;
 
 	urbp = urb->hcpriv;
 
-	spin_lock_irqsave(&uhci_append_urb_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-	nurbp = list_entry(urbp->urb_queue_list.next, struct urb_priv,
-			urb_queue_list);
+	if (list_empty(&urbp->queue_list))
+		goto out;
+
+	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+
+	/* Fix up the toggle for the next URB's */
+	if (!urbp->queued)
+		toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+	else {
+		/* If we're in the middle of the queue, grab the toggle */
+		/*  from the TD previous to us */
+		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+				queue_list);
+
+		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+
+		toggle = uhci_toggle(pltd->info) ^ 1;
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp;
+
+		turbp = list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		if (!turbp->queued)
+			break;
+
+		toggle = uhci_fixup_toggle(turbp->urb, toggle);
+	}
+
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+		usb_pipeout(urb->pipe), toggle);
 
 	if (!urbp->queued) {
-		/* We're the head, so just insert the QH for the next URB */
-		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+		int status;
+
+		/*  The HC may continue using the current QH if it finished */
+		/* all of the TD's in this URB and may have started on the */
+		/* next URB's TD's already, so we'll take over ownership */
+		/* of this QH and use it instead. Don't forget to delete */
+		/* the old QH first */
+		uhci_free_qh(uhci, nurbp->qh);
+
+		nurbp->qh = urbp->qh;
+		nurbp->qh->urbp = nurbp;
+		urbp->qh = NULL;
+
+		/* If the last TD from the first (this) urb didn't */
+		/*  complete, reset qh->element to the first TD in the */
+		/*  next urb */
+		pltd = list_entry(urbp->td_list.prev, struct uhci_td, list);
+		status = uhci_status_bits(pltd->status);
+		if ((status & TD_CTRL_ACTIVE) || uhci_actual_length(pltd->status) < uhci_expected_length(pltd->info)) {
+			struct uhci_td *ftd = list_entry(nurbp->td_list.next, struct uhci_td, list);
+			nurbp->qh->element = ftd->dma_handle;
+		}
+
 		nurbp->queued = 0;
 	} else {
-		struct urb_priv *purbp;
-		struct uhci_td *ptd;
-
 		/* We're somewhere in the middle (or end). A bit trickier */
 		/*  than the head scenario */
-		purbp = list_entry(urbp->urb_queue_list.prev, struct urb_priv,
-				urb_queue_list);
+		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+				queue_list);
+
+		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+		if (nurbp->queued) {
+			struct uhci_td *nftd;
 
-		ptd = list_entry(purbp->list.prev, struct uhci_td, list);
-		if (nurbp->queued)
 			/* Close the gap between the two */
-			ptd->link = virt_to_bus(list_entry(nurbp->list.next,
-					struct uhci_td, list));
-		else
+			nftd = list_entry(nurbp->td_list.next, struct uhci_td,
+					list);
+			pltd->link = nftd->dma_handle;
+		} else
 			/* The next URB happens to be the beggining, so */
 			/*  we're the last, end the chain */
-			ptd->link = UHCI_PTR_TERM;
-		
+			pltd->link = UHCI_PTR_TERM;
 	}
 
-	list_del(&urbp->urb_queue_list);
+	list_del(&urbp->queue_list);
+	INIT_LIST_HEAD(&urbp->queue_list);
 
-	spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
+out:
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
+static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
 {
 	struct urb_priv *urbp;
 
 	urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
-	if (!urbp)
+	if (!urbp) {
+		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
 		return NULL;
+	}
 
 	memset((void *)urbp, 0, sizeof(*urbp));
 
 	urbp->inserttime = jiffies;
 	urbp->urb = urb;
+	urbp->dev = urb->dev;
 	
-	INIT_LIST_HEAD(&urbp->list);
-	INIT_LIST_HEAD(&urbp->urb_queue_list);
+	INIT_LIST_HEAD(&urbp->td_list);
+	INIT_LIST_HEAD(&urbp->queue_list);
+	INIT_LIST_HEAD(&urbp->complete_list);
 
 	urb->hcpriv = urbp;
 
+	if (urb->transfer_buffer_length) {
+		urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
+			urb->transfer_buffer, urb->transfer_buffer_length,
+			usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
+			PCI_DMA_TODEVICE);
+		if (!urbp->transfer_buffer_dma_handle)
+			return NULL;
+	}
+
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
+		urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
+			urb->setup_packet, sizeof(devrequest),
+			PCI_DMA_TODEVICE);
+		if (!urbp->setup_packet_dma_handle)
+			return NULL;
+	}
+
 	return urbp;
 }
 
@@ -508,13 +670,11 @@
 
 	td->urb = urb;
 
-	list_add_tail(&td->list, &urbp->list);
+	list_add_tail(&td->list, &urbp->td_list);
 }
 
-static void uhci_remove_td_from_urb(struct urb *urb, struct uhci_td *td)
+static void uhci_remove_td_from_urb(struct uhci_td *td)
 {
-	urb = NULL;	/* No warnings */
-
 	if (list_empty(&td->list))
 		return;
 
@@ -526,41 +686,55 @@
 
 static void uhci_destroy_urb_priv(struct urb *urb)
 {
-	struct list_head *tmp, *head;
+	struct list_head *head, *tmp;
 	struct urb_priv *urbp;
 	struct uhci *uhci;
-	struct uhci_td *td;
 	unsigned long flags;
 
 	spin_lock_irqsave(&urb->lock, flags);
 
 	urbp = (struct urb_priv *)urb->hcpriv;
 	if (!urbp)
-		goto unlock;
+		goto out;
 
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
-		goto unlock;
+	if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) {
+		warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb);
+		goto out;
+	}
+
+	if (!list_empty(&urb->urb_list))
+		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
 
-	uhci = urb->dev->bus->hcpriv;
+	if (!list_empty(&urbp->complete_list))
+		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
 
-	head = &urbp->list;
+	uhci = urbp->dev->bus->hcpriv;
+
+	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
 		tmp = tmp->next;
 
-		uhci_remove_td_from_urb(urb, td);
-
+		uhci_remove_td_from_urb(td);
 		uhci_remove_td(uhci, td);
-
-		uhci_free_td(td);
+		uhci_free_td(uhci, td);
 	}
 
+	if (urb->setup_packet)
+		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
+			sizeof(devrequest), PCI_DMA_TODEVICE);
+
+	if (urb->transfer_buffer_length)
+		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
+			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
+			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+
 	urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 
-unlock:
+out:
 	spin_unlock_irqrestore(&urb->lock, flags);
 }
 
@@ -569,18 +743,15 @@
 	unsigned long flags;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	if (!urbp)
-		return;
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && (!urbp->fsbr)) {
+	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
 		urbp->fsbr = 1;
 		if (!uhci->fsbr++)
-			uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
 	}
 
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
@@ -588,18 +759,15 @@
 	unsigned long flags;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	if (!urbp)
-		return;
-
-	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
 	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
 		urbp->fsbr = 0;
 		if (!--uhci->fsbr)
-			uhci->skel_term_qh.link = UHCI_PTR_TERM;
+			uhci->skel_term_qh->link = UHCI_PTR_TERM;
 	}
 
-	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 /*
@@ -646,7 +814,7 @@
 	unsigned long destination, status;
 	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	int len = urb->transfer_buffer_length;
-	unsigned char *data = urb->transfer_buffer;
+	dma_addr_t data = urbp->transfer_buffer_dma_handle;
 
 	/* The "pipe" thing contains the destination in bits 8--18 */
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -657,13 +825,13 @@
 	/*
 	 * Build the TD for the control request
 	 */
-	td = uhci_alloc_td(urb->dev);
+	td = uhci_alloc_td(uhci, urb->dev);
 	if (!td)
 		return -ENOMEM;
 
 	uhci_add_td_to_urb(urb, td);
 	uhci_fill_td(td, status, destination | (7 << 21),
-		virt_to_bus(urb->setup_packet));
+		urbp->setup_packet_dma_handle);
 
 	/*
 	 * If direction is "send", change the frame from SETUP (0x2D)
@@ -683,7 +851,7 @@
 		if (pktsze > maxsze)
 			pktsze = maxsze;
 
-		td = uhci_alloc_td(urb->dev);
+		td = uhci_alloc_td(uhci, urb->dev);
 		if (!td)
 			return -ENOMEM;
 
@@ -692,7 +860,7 @@
 	
 		uhci_add_td_to_urb(urb, td);
 		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
-			virt_to_bus(data));
+			data);
 
 		data += pktsze;
 		len -= pktsze;
@@ -701,7 +869,7 @@
 	/*
 	 * Build the final TD for control status 
 	 */
-	td = uhci_alloc_td(urb->dev);
+	td = uhci_alloc_td(uhci, urb->dev);
 	if (!td)
 		return -ENOMEM;
 
@@ -723,23 +891,22 @@
 	uhci_fill_td(td, status | TD_CTRL_IOC,
 		destination | (UHCI_NULL_DATA_SIZE << 21), 0);
 
-	qh = uhci_alloc_qh(urb->dev);
+	qh = uhci_alloc_qh(uhci, urb->dev);
 	if (!qh)
 		return -ENOMEM;
 
 	/* Low speed or small transfers gets a different queue and treatment */
 	if (urb->pipe & TD_CTRL_LS) {
 		uhci_insert_tds_in_qh(qh, urb, 0);
-		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, qh);
 	} else {
 		uhci_insert_tds_in_qh(qh, urb, 1);
-		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, qh);
 		uhci_inc_fsbr(uhci, urb);
 	}
 
 	urbp->qh = qh;
-
-	uhci_add_urb_list(uhci, urb);
+	qh->urbp = urbp;
 
 	return -EINPROGRESS;
 }
@@ -754,12 +921,10 @@
 	unsigned int status;
 	int ret = 0;
 
-	if (!urbp)
+	if (list_empty(&urbp->td_list))
 		return -EINVAL;
 
-	head = &urbp->list;
-	if (head->next == head)
-		return -EINVAL;
+	head = &urbp->td_list;
 
 	if (urbp->short_control_packet) {
 		tmp = head->prev;
@@ -849,12 +1014,16 @@
 	    			uhci_packetout(td->info));
 
 err:
-	if (debug && ret != -EPIPE) {
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
 		/* Some debugging code */
 		dbg("uhci_result_control() failed with status %x", status);
 
-		/* Print the chain for debugging purposes */
-		uhci_show_urb_queue(urb);
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
 	}
 
 	return ret;
@@ -872,34 +1041,34 @@
 	uhci_remove_qh(uhci, urbp->qh);
 
 	/* Delete all of the TD's except for the status TD at the end */
-	head = &urbp->list;
+	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head && tmp->next != head) {
 		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
 		tmp = tmp->next;
 
-		uhci_remove_td_from_urb(urb, td);
-
+		uhci_remove_td_from_urb(td);
 		uhci_remove_td(uhci, td);
-
-		uhci_free_td(td);
+		uhci_free_td(uhci, td);
 	}
 
-	urbp->qh = uhci_alloc_qh(urb->dev);
+	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
 	if (!urbp->qh) {
 		err("unable to allocate new QH for control retrigger");
 		return -ENOMEM;
 	}
 
+	urbp->qh->urbp = urbp;
+
 	/* One TD, who cares about Breadth first? */
 	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
 
 	/* Low speed or small transfers gets a different queue and treatment */
 	if (urb->pipe & TD_CTRL_LS)
-		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urbp->qh);
 	else
-		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urbp->qh);
 
 	return -EINPROGRESS;
 }
@@ -912,6 +1081,7 @@
 	struct uhci_td *td;
 	unsigned long destination, status;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
 		return -EINVAL;
@@ -921,7 +1091,7 @@
 
 	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
 
-	td = uhci_alloc_td(urb->dev);
+	td = uhci_alloc_td(uhci, urb->dev);
 	if (!td)
 		return -ENOMEM;
 
@@ -931,12 +1101,9 @@
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 
 	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination,
-		virt_to_bus(urb->transfer_buffer));
-
-	uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td);
+	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
 
-	uhci_add_urb_list(uhci, urb);
+	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
 
 	return -EINPROGRESS;
 }
@@ -949,12 +1116,9 @@
 	unsigned int status;
 	int ret = 0;
 
-	if (!urbp)
-		return -EINVAL;
-
 	urb->actual_length = 0;
 
-	head = &urbp->list;
+	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head) {
 		td = list_entry(tmp, struct uhci_td, list);
@@ -1000,16 +1164,20 @@
 	    			uhci_packetout(td->info));
 
 err:
-	if (debug && ret != -EPIPE) {
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
 		/* Some debugging code */
 		dbg("uhci_result_interrupt/bulk() failed with status %x",
 			status);
 
-		/* Print the chain for debugging purposes */
-		if (urbp->qh)
-			uhci_show_urb_queue(urb);
-		else
-			uhci_show_td(td);
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			if (urbp->qh)
+				uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+			else
+				uhci_show_td(td, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
 	}
 
 	return ret;
@@ -1017,24 +1185,28 @@
 
 static void uhci_reset_interrupt(struct urb *urb)
 {
-	struct list_head *tmp;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci_td *td;
+	unsigned long flags;
 
-	if (!urbp)
-		return;
+	spin_lock_irqsave(&urb->lock, flags);
 
-	tmp = urbp->list.next;
-	td = list_entry(tmp, struct uhci_td, list);
-	if (!td)
-		return;
+	/* Root hub is special */
+	if (urb->dev == uhci->rh.dev)
+		goto out;
+
+	td = list_entry(urbp->td_list.next, struct uhci_td, list);
 
 	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
 	td->info &= ~(1 << TD_TOKEN_TOGGLE);
 	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
 	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 
+out:
 	urb->status = -EINPROGRESS;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
 }
 
 /*
@@ -1048,8 +1220,8 @@
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	int len = urb->transfer_buffer_length;
-	unsigned char *data = urb->transfer_buffer;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	dma_addr_t data = urbp->transfer_buffer_dma_handle;
 
 	if (len < 0)
 		return -EINVAL;
@@ -1076,7 +1248,7 @@
 		if (pktsze > maxsze)
 			pktsze = maxsze;
 
-		td = uhci_alloc_td(urb->dev);
+		td = uhci_alloc_td(uhci, urb->dev);
 		if (!td)
 			return -ENOMEM;
 
@@ -1084,7 +1256,7 @@
 		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
 			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
-			virt_to_bus(data));
+			data);
 
 		data += pktsze;
 		len -= maxsze;
@@ -1096,22 +1268,20 @@
 			usb_pipeout(urb->pipe));
 	} while (len > 0);
 
-	qh = uhci_alloc_qh(urb->dev);
+	qh = uhci_alloc_qh(uhci, urb->dev);
 	if (!qh)
 		return -ENOMEM;
 
 	urbp->qh = qh;
+	qh->urbp = urbp;
 
-	/* Always assume depth first */
+	/* Always assume breadth first */
 	uhci_insert_tds_in_qh(qh, urb, 1);
 
-	if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
-		urbp->queued = 1;
+	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
 		uhci_append_queued_urb(uhci, eurb, urb);
-	} else
-		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
-
-	uhci_add_urb_list(uhci, urb);
+	else
+		uhci_insert_qh(uhci, uhci->skel_bulk_qh, qh);
 
 	uhci_inc_fsbr(uhci, urb);
 
@@ -1128,11 +1298,12 @@
 {
 	struct urb *last_urb = NULL;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head *tmp, *head = &uhci->urb_list;
+	struct list_head *tmp, *head;
 	int ret = 0;
 	unsigned long flags;
 
-	nested_lock(&uhci->urblist_lock, flags);
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
 		struct urb *u = list_entry(tmp, struct urb, urb_list);
@@ -1154,7 +1325,7 @@
 	} else
 		ret = -1;	/* no previous urb found */
 
-	nested_unlock(&uhci->urblist_lock, flags);
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
 	return ret;
 }
@@ -1185,12 +1356,16 @@
 	return 0;
 }
 
+/*
+ * Isochronous transfers
+ */
 static int uhci_submit_isochronous(struct urb *urb)
 {
 	struct uhci_td *td;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	int i, ret, framenum;
 	int status, destination;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
@@ -1204,13 +1379,13 @@
 		if (!urb->iso_frame_desc[i].length)
 			continue;
 
-		td = uhci_alloc_td(urb->dev);
+		td = uhci_alloc_td(uhci, urb->dev);
 		if (!td)
 			return -ENOMEM;
 
 		uhci_add_td_to_urb(urb, td);
 		uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
-			virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset));
+			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
 
 		if (i + 1 >= urb->number_of_packets)
 			td->status |= TD_CTRL_IOC;
@@ -1218,8 +1393,6 @@
 		uhci_insert_td_frame_list(uhci, td, framenum);
 	}
 
-	uhci_add_urb_list(uhci, urb);
-
 	return -EINPROGRESS;
 }
 
@@ -1230,13 +1403,10 @@
 	int status;
 	int i, ret = 0;
 
-	if (!urbp)
-		return -EINVAL;
-
 	urb->actual_length = 0;
 
 	i = 0;
-	head = &urbp->list;
+	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head) {
 		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
@@ -1253,7 +1423,7 @@
 
 		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
 		urb->iso_frame_desc[i].status = status;
-		if (status != 0) {
+		if (status) {
 			urb->error_count++;
 			ret = status;
 		}
@@ -1266,28 +1436,30 @@
 
 static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
 {
-	struct list_head *tmp, *head = &uhci->urb_list;
+	struct list_head *tmp, *head;
 	unsigned long flags;
 	struct urb *u = NULL;
 
+	/* We don't match Isoc transfers since they are special */
 	if (usb_pipeisoc(urb->pipe))
 		return NULL;
 
-	nested_lock(&uhci->urblist_lock, flags);
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
 		u = list_entry(tmp, struct urb, urb_list);
 
 		tmp = tmp->next;
 
-		if (u->dev == urb->dev &&
-		    u->pipe == urb->pipe)
-			goto found;
+		if (u->dev == urb->dev && u->pipe == urb->pipe &&
+		    u->status == -EINPROGRESS)
+			goto out;
 	}
 	u = NULL;
 
-found:
-	nested_unlock(&uhci->urblist_lock, flags);
+out:
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
 	return u;
 }
@@ -1297,33 +1469,52 @@
 	int ret = -EINVAL;
 	struct uhci *uhci;
 	unsigned long flags;
-	struct urb *u;
+	struct urb *eurb;
 	int bustime;
 
 	if (!urb)
 		return -EINVAL;
 
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
 		return -ENODEV;
+	}
 
 	uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
-	/* Short circuit the virtual root hub */
-	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
-		return rh_submit_urb(urb);
-
-	u = uhci_find_urb_ep(uhci, urb);
-	if (u && !(urb->transfer_flags & USB_QUEUE_BULK))
-		return -ENXIO;
-
+	INIT_LIST_HEAD(&urb->urb_list);
 	usb_inc_dev_use(urb->dev);
+
 	spin_lock_irqsave(&urb->lock, flags);
 
-	if (!uhci_alloc_urb_priv(urb)) {
+	if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
+	    urb->status == -ECONNABORTED) {
+		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
+		/* Since we can have problems on the out path */
 		spin_unlock_irqrestore(&urb->lock, flags);
 		usb_dec_dev_use(urb->dev);
 
-		return -ENOMEM;
+		return ret;
+	}
+
+	if (!uhci_alloc_urb_priv(uhci, urb)) {
+		ret = -ENOMEM;
+
+		goto out;
+	}
+
+	eurb = uhci_find_urb_ep(uhci, urb);
+	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
+		ret = -ENXIO;
+
+		goto out;
+	}
+
+	/* Short circuit the virtual root hub */
+	if (urb->dev == uhci->rh.dev) {
+		ret = rh_submit_urb(urb);
+
+		goto out;
 	}
 
 	switch (usb_pipetype(urb->pipe)) {
@@ -1344,7 +1535,7 @@
 			ret = uhci_submit_interrupt(urb);
 		break;
 	case PIPE_BULK:
-		ret = uhci_submit_bulk(urb, u);
+		ret = uhci_submit_bulk(urb, eurb);
 		break;
 	case PIPE_ISOCHRONOUS:
 		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
@@ -1366,35 +1557,53 @@
 		break;
 	}
 
+out:
 	urb->status = ret;
 
 	spin_unlock_irqrestore(&urb->lock, flags);
 
-	if (ret == -EINPROGRESS)
-		ret = 0;
-	else {
-		uhci_unlink_generic(urb);
-		usb_dec_dev_use(urb->dev);
+	if (ret == -EINPROGRESS) {
+		spin_lock_irqsave(&uhci->urb_list_lock, flags);
+		/* We use _tail to make find_urb_ep more efficient */
+		list_add_tail(&urb->urb_list, &uhci->urb_list);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		return 0;
 	}
 
+	uhci_unlink_generic(uhci, urb);
+	uhci_destroy_urb_priv(urb);
+
+	usb_dec_dev_use(urb->dev);
+
 	return ret;
 }
 
 /*
  * Return the result of a transfer
  *
- * Must be called with urblist_lock acquired
+ * Must be called with urb_list_lock acquired
  */
-static void uhci_transfer_result(struct urb *urb)
+static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
 {
-	struct usb_device *dev = urb->dev;
-	struct urb *turb;
-	int proceed = 0, is_ring = 0;
 	int ret = -EINVAL;
 	unsigned long flags;
+	struct urb_priv *urbp;
+
+	/* The root hub is special */
+	if (urb->dev == uhci->rh.dev)
+		return;
 
 	spin_lock_irqsave(&urb->lock, flags);
 
+	urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->status != -EINPROGRESS) {
+		info("uhci_transfer_result: called for URB %p not in flight?", urb);
+		spin_unlock_irqrestore(&urb->lock, flags);
+		return;
+	}
+
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
 		ret = uhci_result_control(urb);
@@ -1410,7 +1619,7 @@
 		break;
 	}
 
-	urb->status = ret;
+	urbp->status = ret;
 
 	spin_unlock_irqrestore(&urb->lock, flags);
 
@@ -1425,106 +1634,65 @@
 		/* Spinlock needed ? */
 		if (urb->bandwidth)
 			usb_release_bandwidth(urb->dev, urb, 1);
-		uhci_unlink_generic(urb);
+		uhci_unlink_generic(uhci, urb);
 		break;
 	case PIPE_INTERRUPT:
 		/* Interrupts are an exception */
 		if (urb->interval) {
-			urb->complete(urb);
-			uhci_reset_interrupt(urb);
-			return;
+			uhci_add_complete(urb);
+			return;		/* <-- note return */
 		}
 
 		/* Release bandwidth for Interrupt or Isoc. transfers */
 		/* Spinlock needed ? */
 		if (urb->bandwidth)
 			usb_release_bandwidth(urb->dev, urb, 0);
-		uhci_unlink_generic(urb);
+		uhci_unlink_generic(uhci, urb);
 		break;
+	default:
+		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
+			usb_pipetype(urb->pipe), urb);
 	}
 
-	if (urb->next) {
-		turb = urb->next;
-		do {
-			if (turb->status != -EINPROGRESS) {
-				proceed = 1;
-				break;
-			}
-
-			turb = turb->next;
-		} while (turb && turb != urb && turb != urb->next);
-
-		if (turb == urb || turb == urb->next)
-			is_ring = 1;
-	}
-
-	if (urb->complete && !proceed) {
-		urb->complete(urb);
-		if (!proceed && is_ring)
-			uhci_submit_urb(urb);
-	}
-
-	if (proceed && urb->next) {
-		turb = urb->next;
-		do {
-			if (turb->status != -EINPROGRESS &&
-			    uhci_submit_urb(turb) != 0)
+	list_del(&urb->urb_list);
+	INIT_LIST_HEAD(&urb->urb_list);
 
-			turb = turb->next;
-		} while (turb && turb != urb->next);
-
-		if (urb->complete)
-			urb->complete(urb);
-	}
-
-	/* We decrement the usage count after we're done with everything */
-	usb_dec_dev_use(dev);
+	uhci_add_complete(urb);
 }
 
-static int uhci_unlink_generic(struct urb *urb)
+static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
 {
 	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
+	/* We can get called when urbp allocation fails, so check */
 	if (!urbp)
-		return -EINVAL;
+		return;
 
 	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
 
-	uhci_remove_urb_list(uhci, urb);
+	uhci_delete_queued_urb(uhci, urb);
 
 	if (urbp->qh)
 		/* The interrupt loop will reclaim the QH's */
 		uhci_remove_qh(uhci, urbp->qh);
-
-	if (!list_empty(&urbp->urb_queue_list))
-		uhci_delete_queued_urb(uhci, urb);
-
-	uhci_destroy_urb_priv(urb);
-
-	urb->dev = NULL;
-
-	return 0;
 }
 
+/* FIXME: If we forcefully unlink an urb, we should reset the toggle for */
+/*  that pipe to match what actually completed */
 static int uhci_unlink_urb(struct urb *urb)
 {
 	struct uhci *uhci;
-	int ret = 0;
 	unsigned long flags;
+	struct urb_priv *urbp = urb->hcpriv;
 
 	if (!urb)
 		return -EINVAL;
 
-	if (!urb->dev || !urb->dev->bus)
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
 		return -ENODEV;
 
 	uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
-	/* Short circuit the virtual root hub */
-	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
-		return rh_unlink_urb(urb);
-
 	/* Release bandwidth for Interrupt or Isoc. transfers */
 	/* Spinlock needed ? */
 	if (urb->bandwidth) {
@@ -1540,13 +1708,28 @@
 		}
 	}
 
-	if (urb->status == -EINPROGRESS) {
-		uhci_unlink_generic(urb);
+	if (urb->status != -EINPROGRESS)
+		return 0;
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	list_del(&urb->urb_list);
+	INIT_LIST_HEAD(&urb->urb_list);
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+	uhci_unlink_generic(uhci, urb);
 
+	/* Short circuit the virtual root hub */
+	if (urb->dev == uhci->rh.dev) {
+		rh_unlink_urb(urb);
+		uhci_call_completion(urb);
+	} else {
 		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-			urb->status = -ECONNABORTED;
+			/* urb_list is available now since we called */
+			/*  uhci_unlink_generic already */
 
-			spin_lock_irqsave(&uhci->urb_remove_lock, flags);
+			urbp->status = urb->status = -ECONNABORTED;
+
+			spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
 
 			/* Check to see if the remove list is empty */
 			if (list_empty(&uhci->urb_remove_list))
@@ -1554,7 +1737,7 @@
 			
 			list_add(&urb->urb_list, &uhci->urb_remove_list);
 
-			spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
+			spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
 		} else {
 			urb->status = -ENOENT;
 
@@ -1567,12 +1750,11 @@
 			} else
 				schedule_timeout(1+1*HZ/1000); 
 
-			if (urb->complete)
-				urb->complete(urb);
+			uhci_call_completion(urb);
 		}
 	}
 
-	return ret;
+	return 0;
 }
 
 static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
@@ -1588,7 +1770,7 @@
 	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */
 	urbp->fsbr_timeout = 1;
 
-	head = &urbp->list;
+	head = &urbp->td_list;
 	tmp = head->next;
 	while (tmp != head) {
 		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
@@ -1624,9 +1806,7 @@
 	uhci_unlink_urb
 };
 
-/* -------------------------------------------------------------------
-   Virtual Root Hub
-   ------------------------------------------------------------------- */
+/* Virtual Root Hub */
 
 static __u8 root_hub_dev_des[] =
 {
@@ -1700,7 +1880,6 @@
 	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
 };
 
-/*-------------------------------------------------------------------------*/
 /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
 static int rh_send_irq(struct urb *urb)
 {
@@ -1708,6 +1887,7 @@
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	unsigned int io_addr = uhci->io_addr;
 	__u16 data = 0;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 	for (i = 0; i < uhci->rh.numports; i++) {
 		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
@@ -1716,18 +1896,17 @@
 
 	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
 	urb->actual_length = len;
-	urb->status = USB_ST_NOERROR;
+	urbp->status = 0;
 
 	if ((data > 0) && (uhci->rh.send != 0)) {
 		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
 			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
-		urb->complete(urb);
+		uhci_call_completion(urb);
 	}
 
-	return USB_ST_NOERROR;
+	return 0;
 }
 
-/*-------------------------------------------------------------------------*/
 /* Virtual Root Hub INTs are polled by this timer every "interval" ms */
 static int rh_init_int_timer(struct urb *urb);
 
@@ -1735,41 +1914,46 @@
 {
 	struct urb *urb = (struct urb *)ptr;
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head *tmp, *head = &uhci->urb_list;
-	struct urb_priv *urbp;
-	int len;
+	struct list_head list, *tmp, *head;
 	unsigned long flags;
 
-	if (uhci->rh.send) {
-		len = rh_send_irq(urb);
-		if (len > 0) {
-			urb->actual_length = len;
-			if (urb->complete)
-				urb->complete(urb);
+	if (uhci->rh.send)
+		rh_send_irq(urb);
+
+	INIT_LIST_HEAD(&list);
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	head = &uhci->urb_list;
+
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+		struct urb_priv *urbp = (struct urb_priv *)u->hcpriv;
+
+		tmp = tmp->next;
+
+		/* Check if the FSBR timed out */
+		if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+			uhci_fsbr_timeout(uhci, u);
+
+		/* Check if the URB timed out */
+		if (u->timeout && time_after_eq(jiffies, u->timeout)) {
+			list_del(&u->urb_list);
+			list_add_tail(&u->urb_list, &list);
 		}
 	}
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
-	nested_lock(&uhci->urblist_lock, flags);
+	head = &list;
 	tmp = head->next;
 	while (tmp != head) {
-		struct urb *u = list_entry(tmp, urb_t, urb_list);
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
 
 		tmp = tmp->next;
 
-		urbp = (struct urb_priv *)u->hcpriv;
-		if (urbp) {
-			/* Check if the FSBR timed out */
-			if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
-				uhci_fsbr_timeout(uhci, u);
-
-			/* Check if the URB timed out */
-			if (u->timeout && time_after_eq(jiffies, u->timeout)) {
-				u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
-				uhci_unlink_urb(u);
-			}
-		}
+		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+		uhci_unlink_urb(u);
 	}
-	nested_unlock(&uhci->urblist_lock, flags);
 
 	/* enter global suspend if nothing connected */
 	if (!uhci->is_suspended && !ports_active(uhci))
@@ -1778,7 +1962,6 @@
 	rh_init_int_timer(urb);
 }
 
-/*-------------------------------------------------------------------------*/
 /* Root Hub INTs are polled by this timer */
 static int rh_init_int_timer(struct urb *urb)
 {
@@ -1794,7 +1977,6 @@
 	return 0;
 }
 
-/*-------------------------------------------------------------------------*/
 #define OK(x)			len = (x); break
 
 #define CLR_RH_PORTSTAT(x) \
@@ -1808,11 +1990,7 @@
 	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
 
 
-/*-------------------------------------------------------------------------*/
-/*************************
- ** Root Hub Control Pipe
- *************************/
-
+/* Root Hub Control Pipe */
 static int rh_submit_urb(struct urb *urb)
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1822,7 +2000,7 @@
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
 	int status = 0;
-	int stat = USB_ST_NOERROR;
+	int stat = 0;
 	int i;
 	unsigned int io_addr = uhci->io_addr;
 	__u16 cstatus;
@@ -1837,7 +2015,7 @@
 		uhci->rh.interval = urb->interval;
 		rh_init_int_timer(urb);
 
-		return USB_ST_NOERROR;
+		return -EINPROGRESS;
 	}
 
 	bmRType_bReq = cmd->requesttype | cmd->request << 8;
@@ -1987,33 +2165,29 @@
 	}
 
 	urb->actual_length = len;
-	urb->status = stat;
-	if (urb->complete)
-		urb->complete(urb);
 
-	return USB_ST_NOERROR;
+	return stat;
 }
-/*-------------------------------------------------------------------------*/
 
 static int rh_unlink_urb(struct urb *urb)
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
 	if (uhci->rh.urb == urb) {
+		urb->status = -ENOENT;
 		uhci->rh.send = 0;
+		uhci->rh.urb = NULL;
 		del_timer(&uhci->rh.rh_int_timer);
 	}
 	return 0;
 }
-/*-------------------------------------------------------------------*/
 
-void uhci_free_pending_qhs(struct uhci *uhci)
+static void uhci_free_pending_qhs(struct uhci *uhci)
 {
 	struct list_head *tmp, *head;
 	unsigned long flags;
 
-	/* Free any pending QH's */
-	spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 	head = &uhci->qh_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -2022,10 +2196,128 @@
 		tmp = tmp->next;
 
 		list_del(&qh->remove_list);
+		INIT_LIST_HEAD(&qh->remove_list);
 
-		uhci_free_qh(qh);
+		uhci_free_qh(uhci, qh);
 	}
-	spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
+}
+
+static void uhci_call_completion(struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct usb_device *dev = urb->dev;
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
+	int is_ring = 0, killed, resubmit_interrupt, status;
+	struct urb *nurb;
+
+	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
+			urb->status == -ECONNRESET);
+	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
+			urb->interval && !killed);
+
+	nurb = urb->next;
+	if (nurb && !killed) {
+		int count = 0;
+
+		while (nurb && nurb != urb && count < MAX_URB_LOOP) {
+			if (nurb->status == -ENOENT ||
+			    nurb->status == -ECONNABORTED ||
+			    nurb->status == -ECONNRESET) {
+				killed = 1;
+				break;
+			}
+
+			nurb = nurb->next;
+			count++;
+		}
+
+		if (count == MAX_URB_LOOP)
+			err("uhci_call_completion: too many linked URB's, loop? (first loop)");
+
+		/* Check to see if chain is a ring */
+		is_ring = (nurb == urb);
+	}
+
+	status = urbp->status;
+	if (!resubmit_interrupt)
+		/* We don't need urb_priv anymore */
+		uhci_destroy_urb_priv(urb);
+
+	if (!killed)
+		urb->status = status;
+
+	if (urb->transfer_buffer_length)
+		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
+			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
+			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet)
+		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
+			sizeof(devrequest), PCI_DMA_TODEVICE);
+
+	urb->dev = NULL;
+	if (urb->complete)
+		urb->complete(urb);
+
+	if (resubmit_interrupt) {
+		urb->dev = dev;
+		uhci_reset_interrupt(urb);
+	} else {
+		if (is_ring && !killed) {
+			urb->dev = dev;
+			uhci_submit_urb(urb);
+		} else {
+			/* We decrement the usage count after we're done */
+			/*  with everything */
+			usb_dec_dev_use(dev);
+		}
+	}
+}
+
+static void uhci_finish_completion(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	head = &uhci->complete_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+		struct urb *urb = urbp->urb;
+
+		tmp = tmp->next;
+
+		list_del(&urbp->complete_list);
+		INIT_LIST_HEAD(&urbp->complete_list);
+
+		uhci_call_completion(urb);
+	}
+	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+}
+
+static void uhci_remove_pending_qhs(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
+	head = &uhci->urb_remove_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+		tmp = tmp->next;
+
+		list_del(&urb->urb_list);
+		INIT_LIST_HEAD(&urb->urb_list);
+
+		urbp->status = urb->status = -ECONNRESET;
+		uhci_call_completion(urb);
+	}
+	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
 }
 
 static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
@@ -2033,7 +2325,6 @@
 	struct uhci *uhci = __uhci;
 	unsigned int io_addr = uhci->io_addr;
 	unsigned short status;
-	unsigned long flags;
 	struct list_head *tmp, *head;
 
 	/*
@@ -2043,7 +2334,7 @@
 	status = inw(io_addr + USBSTS);
 	if (!status)	/* shared interrupt, not mine */
 		return;
-	outw(status, io_addr + USBSTS);
+	outw(status, io_addr + USBSTS);		/* Clear it */
 
 	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
 		if (status & USBSTS_HSE)
@@ -2056,31 +2347,17 @@
 		}
 	}
 
-	if (status & USBSTS_RD) {
+	if (status & USBSTS_RD)
 		wakeup_hc(uhci);
-	}
 
 	uhci_free_pending_qhs(uhci);
 
-	spin_lock(&uhci->urb_remove_lock);
-	head = &uhci->urb_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		list_del(&urb->urb_list);
-
-		if (urb->complete)
-			urb->complete(urb);
-	}
-	spin_unlock(&uhci->urb_remove_lock);
+	uhci_remove_pending_qhs(uhci);
 
 	uhci_clear_next_interrupt(uhci);
 
-	/* Walk the list of pending TD's to see which ones completed */
-	nested_lock(&uhci->urblist_lock, flags);
+	/* Walk the list of pending URB's to see which ones completed */
+	spin_lock(&uhci->urb_list_lock);
 	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -2089,9 +2366,11 @@
 		tmp = tmp->next;
 
 		/* Checks the status and does all of the magic necessary */
-		uhci_transfer_result(urb);
+		uhci_transfer_result(uhci, urb);
 	}
-	nested_unlock(&uhci->urblist_lock, flags);
+	spin_unlock(&uhci->urb_list_lock);
+
+	uhci_finish_completion(uhci);
 }
 
 static void reset_hc(struct uhci *uhci)
@@ -2173,12 +2452,43 @@
 
 	/* Start at frame 0 */
 	outw(0, io_addr + USBFRNUM);
-	outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
+	outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
 
 	/* Run and mark it configured with a 64-byte max packet */
 	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
 }
 
+static int uhci_alloc_root_hub(struct uhci *uhci)
+{
+	struct usb_device *dev;
+
+	dev = usb_alloc_dev(NULL, uhci->bus);
+	if (!dev)
+		return -1;
+
+	uhci->bus->root_hub = dev;
+	uhci->rh.dev = dev;
+
+	return 0;
+}
+
+static int uhci_start_root_hub(struct uhci *uhci)
+{
+	usb_connect(uhci->rh.dev);
+
+	if (usb_new_device(uhci->rh.dev) != 0) {
+		usb_free_dev(uhci->rh.dev);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+static int uhci_num = 0;
+#endif
+
 /*
  * Allocate a frame list, and then setup the skeleton
  *
@@ -2193,11 +2503,12 @@
  *  - The second queue is the "control queue", split into low and high speed
  *  - The third queue is "bulk data".
  */
-static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
+static struct uhci *alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
 {
 	int i, port;
 	struct uhci *uhci;
 	struct usb_bus *bus;
+	dma_addr_t dma_handle;
 
 	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
 	if (!uhci)
@@ -2205,30 +2516,54 @@
 
 	memset(uhci, 0, sizeof(*uhci));
 
+	uhci->dev = dev;
 	uhci->irq = -1;
 	uhci->io_addr = io_addr;
 	uhci->io_size = io_size;
 
-	spin_lock_init(&uhci->qh_remove_lock);
+	spin_lock_init(&uhci->qh_remove_list_lock);
 	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
-	spin_lock_init(&uhci->urb_remove_lock);
+	spin_lock_init(&uhci->urb_remove_list_lock);
 	INIT_LIST_HEAD(&uhci->urb_remove_list);
 
-	nested_init(&uhci->urblist_lock);
+	spin_lock_init(&uhci->urb_list_lock);
 	INIT_LIST_HEAD(&uhci->urb_list);
 
-	spin_lock_init(&uhci->framelist_lock);
+	spin_lock_init(&uhci->complete_list_lock);
+	INIT_LIST_HEAD(&uhci->complete_list);
+
+	spin_lock_init(&uhci->frame_list_lock);
 
 	/* We need exactly one page (per UHCI specs), how convenient */
 	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
-	uhci->fl = (void *)__get_free_page(GFP_KERNEL);
-	if (!uhci->fl)
-		goto au_free_uhci;
+	uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
+	if (!uhci->fl) {
+		printk(KERN_ERR "Unable to allocate consistent memory for frame list\n");
+		goto free_uhci;
+	}
+
+	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
+
+	uhci->fl->dma_handle = dma_handle;
+
+	uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
+		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
+	if (!uhci->td_pool) {
+		printk(KERN_ERR "Unable to create td pci_pool\n");
+		goto free_fl;
+	}
+
+	uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
+		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
+	if (!uhci->qh_pool) {
+		printk(KERN_ERR "Unable to create qh pci_pool\n");
+		goto free_td_pool;
+	}
 
 	bus = usb_alloc_bus(&uhci_device_operations);
 	if (!bus)
-		goto au_free_fl;
+		goto free_qh_pool;
 
 	uhci->bus = bus;
 	bus->hcpriv = uhci;
@@ -2258,36 +2593,66 @@
 
 	uhci->rh.numports = port;
 
+	if (uhci_alloc_root_hub(uhci)) {
+		err("unable to allocate root hub");
+		goto free_fl;
+	}
+
+	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
+	if (!uhci->skeltd[0]) {
+		err("unable to allocate TD 0");
+		goto free_fl;
+	}
+
 	/*
 	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
 	 * then link int1 to control and control to bulk
 	 */
 	for (i = 1; i < 9; i++) {
-		struct uhci_td *td = &uhci->skeltd[i];
+		struct uhci_td *td;
+
+		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
+		if (!td) {
+			err("unable to allocate TD %d", i);
+			goto free_tds;
+		}
 
 		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-		td->link = virt_to_bus(&uhci->skeltd[i - 1]);
+		td->link = uhci->skeltd[i - 1]->dma_handle;
 	}
 
+	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
+	if (!uhci->skel_term_td) {
+		err("unable to allocate TD 0");
+		goto free_fl;
+	}
 
-	uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_ls_control_qh) | UHCI_PTR_QH;
+	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
+		if (!uhci->skelqh[i]) {
+			err("unable to allocate QH %d", i);
+			goto free_qhs;
+		}
+	}
+
+	uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH;
 
-	uhci->skel_ls_control_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
-	uhci->skel_ls_control_qh.element = UHCI_PTR_TERM;
+	uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_ls_control_qh->element = UHCI_PTR_TERM;
 
-	uhci->skel_hs_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH;
-	uhci->skel_hs_control_qh.element = UHCI_PTR_TERM;
+	uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_hs_control_qh->element = UHCI_PTR_TERM;
 
-	uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH;
-	uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
+	uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_bulk_qh->element = UHCI_PTR_TERM;
 
 	/* This dummy TD is to work around a bug in Intel PIIX controllers */
-	uhci_fill_td(&uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_term_td.link = UHCI_PTR_TERM;
+	uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_term_td->link = uhci->skel_term_td->dma_handle;
 
-	uhci->skel_term_qh.link = UHCI_PTR_TERM;
-	uhci->skel_term_qh.element = virt_to_bus(&uhci->skel_term_td);
+	uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle;
 
 	/*
 	 * Fill the frame list: make all entries point to
@@ -2297,8 +2662,8 @@
 	 * scatter the interrupt queues in a way that gives
 	 * us a reasonable dynamic range for irq latencies.
 	 */
-	for (i = 0; i < 1024; i++) {
-		struct uhci_td *irq = &uhci->skel_int1_td;
+	for (i = 0; i < UHCI_NUMFRAMES; i++) {
+		int irq = 0;
 
 		if (i & 1) {
 			irq++;
@@ -2322,7 +2687,7 @@
 		}
 
 		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] =  virt_to_bus(irq);
+		uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
 	}
 
 	return uhci;
@@ -2330,9 +2695,30 @@
 /*
  * error exits:
  */
-au_free_fl:
-	free_page((unsigned long)uhci->fl);
-au_free_uhci:
+free_qhs:
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+free_tds:
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (uhci->skeltd[i]) {
+			uhci_free_td(uhci, uhci->skeltd[i]);
+			uhci->skeltd[i] = NULL;
+		}
+
+free_qh_pool:
+	pci_pool_destroy(uhci->qh_pool);
+
+free_td_pool:
+	pci_pool_destroy(uhci->td_pool);
+
+free_fl:
+	pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+
+free_uhci:
 	kfree(uhci);
 
 	return NULL;
@@ -2343,49 +2729,66 @@
  */
 static void release_uhci(struct uhci *uhci)
 {
+	int i;
+#ifdef CONFIG_PROC_FS
+	char buf[8];
+#endif
+
 	if (uhci->irq >= 0) {
 		free_irq(uhci->irq, uhci);
 		uhci->irq = -1;
 	}
 
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (uhci->skeltd[i]) {
+			uhci_free_td(uhci, uhci->skeltd[i]);
+			uhci->skeltd[i] = NULL;
+		}
+
+	if (uhci->qh_pool) {
+		pci_pool_destroy(uhci->qh_pool);
+		uhci->qh_pool = NULL;
+	}
+
+	if (uhci->td_pool) {
+		pci_pool_destroy(uhci->td_pool);
+		uhci->td_pool = NULL;
+	}
+
 	if (uhci->fl) {
-		free_page((unsigned long)uhci->fl);
+		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
 		uhci->fl = NULL;
 	}
 
 	usb_free_bus(uhci->bus);
-	kfree(uhci);
-}
-
-int uhci_start_root_hub(struct uhci *uhci)
-{
-	struct usb_device *dev;
-
-	dev = usb_alloc_dev(NULL, uhci->bus);
-	if (!dev)
-		return -1;
-
-	uhci->bus->root_hub = dev;
-	usb_connect(dev);
 
-	if (usb_new_device(dev) != 0) {
-		usb_free_dev(dev);
+#ifdef CONFIG_PROC_FS
+	sprintf(buf, "hc%d", uhci->num);
 
-		return -1;
-	}
+	remove_proc_entry(buf, uhci_proc_root);
+	uhci->proc_entry = NULL;
+#endif
 
-	return 0;
+	kfree(uhci);
 }
 
 /*
- * If we've successfully found a UHCI, now is the time to increment the
- * module usage count, and return success..
+ * If we've successfully found a UHCI, now is the time to return success..
  */
 static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
 {
 	int retval;
 	struct uhci *uhci;
 	char buf[8], *bufp = buf;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+#endif
 
 #ifndef __sparc__
 	sprintf(buf, "%d", irq);
@@ -2395,11 +2798,27 @@
 	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
 		io_addr, bufp);
 
-	uhci = alloc_uhci(io_addr, io_size);
+	uhci = alloc_uhci(dev, io_addr, io_size);
 	if (!uhci)
 		return -ENOMEM;
+
 	dev->driver_data = uhci;
 
+#ifdef CONFIG_PROC_FS
+	uhci->num = uhci_num++;
+
+	sprintf(buf, "hc%d", uhci->num);
+
+	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
+	if (!ent)
+		return -ENOMEM;
+
+	ent->data = uhci;
+	ent->proc_fops = &uhci_proc_operations;
+	ent->size = 0;
+	uhci->proc_entry = ent;
+#endif
+
 	request_region(uhci->io_addr, io_size, "usb-uhci");
 
 	reset_hc(uhci);
@@ -2430,6 +2849,12 @@
 {
 	int i;
 
+	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
+		err("PCI subsystem doesn't support 32 bit addressing?");
+		return -ENODEV;
+	}
+	dev->dma_mask = 0xFFFFFFFF;
+
 	/* disable legacy emulation */
 	pci_write_config_word(dev, USBLEGSUP, 0);
 
@@ -2470,6 +2895,13 @@
 
 	usb_deregister_bus(uhci->bus);
 
+	/*
+	 * At this point, we're guaranteed that no new connects can be made
+	 * to this bus since there are no more parents
+	 */
+	uhci_free_pending_qhs(uhci);
+	uhci_remove_pending_qhs(uhci);
+
 	reset_hc(uhci);
 	release_region(uhci->io_addr, uhci->io_size);
 
@@ -2489,9 +2921,7 @@
 	start_hc((struct uhci *) dev->driver_data);
 }
 
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
+static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
 
 	/* handle any USB UHCI controller */
 	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
@@ -2524,34 +2954,26 @@
  
 static int __init uhci_hcd_init(void)
 {
-	int retval;
-
-	retval = -ENOMEM;
+	int retval = -ENOMEM;
 
-	/* We throw all of the TD's and QH's into a kmem cache */
-	/* TD's and QH's need to be 16 byte aligned and SLAB_HWCACHE_ALIGN */
-	/*  does this for us */
-	uhci_td_cachep = kmem_cache_create("uhci_td",
-		sizeof(struct uhci_td), 0,
-		SLAB_HWCACHE_ALIGN, NULL, NULL);
-
-	if (!uhci_td_cachep)
-		goto td_failed;
-
-	uhci_qh_cachep = kmem_cache_create("uhci_qh",
-		sizeof(struct uhci_qh), 0,
-		SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (debug) {
+		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+		if (!errbuf)
+			goto errbuf_failed;
+	}
 
-	if (!uhci_qh_cachep)
-		goto qh_failed;
+#ifdef CONFIG_PROC_FS
+	uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
+	if (!uhci_proc_root)
+		goto proc_failed;
+#endif
 
 	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
 		sizeof(struct urb_priv), 0, 0, NULL, NULL);
-
 	if (!uhci_up_cachep)
 		goto up_failed;
 
-	retval = pci_module_init (&uhci_pci_driver);
+	retval = pci_module_init(&uhci_pci_driver);
 	if (retval)
 		goto init_failed;
 
@@ -2562,29 +2984,33 @@
 		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
 
 up_failed:
-	if (kmem_cache_destroy(uhci_qh_cachep))
-		printk(KERN_INFO "uhci: not all QH's were freed\n");
 
-qh_failed:
-	if (kmem_cache_destroy(uhci_td_cachep))
-		printk(KERN_INFO "uhci: not all TD's were freed\n");
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("uhci", 0);
+
+proc_failed:
+#endif
+	if (errbuf)
+		kfree(errbuf);
+
+errbuf_failed:
 
-td_failed:
 	return retval;
 }
 
 static void __exit uhci_hcd_cleanup (void) 
 {
-	pci_unregister_driver (&uhci_pci_driver);
+	pci_unregister_driver(&uhci_pci_driver);
 	
 	if (kmem_cache_destroy(uhci_up_cachep))
 		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
 
-	if (kmem_cache_destroy(uhci_qh_cachep))
-		printk(KERN_INFO "uhci: not all QH's were freed\n");
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("uhci", 0);
+#endif
 
-	if (kmem_cache_destroy(uhci_td_cachep))
-		printk(KERN_INFO "uhci: not all TD's were freed\n");
+	if (errbuf)
+		kfree(errbuf);
 }
 
 module_init(uhci_hcd_init);
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.4.3/linux/drivers/usb/uhci.h	Mon Mar 26 15:50:12 2001
+++ linux/drivers/usb/uhci.h	Wed Apr 25 16:23:08 2001
@@ -5,36 +5,6 @@
 #include <linux/usb.h>
 
 /*
- * This nested spinlock code is courtesy of Davide Libenzi <dlibenzi@maticad.it>
- */
-struct s_nested_lock {
-	spinlock_t lock;
-	void *uniq;
-	short int count;
-};
-
-#define nested_init(snl) \
-	spin_lock_init(&(snl)->lock); \
-	(snl)->uniq = NULL; \
-	(snl)->count = 0;
-
-#define nested_lock(snl, flags) \
-	if ((snl)->uniq == current) { \
-		(snl)->count++; \
-		flags = 0; /* No warnings */ \
-	} else { \
-		spin_lock_irqsave(&(snl)->lock, flags); \
-		(snl)->count++; \
-		(snl)->uniq = current; \
-	}
-
-#define nested_unlock(snl, flags) \
-	if (!--(snl)->count) { \
-		(snl)->uniq = NULL; \
-		spin_unlock_irqrestore(&(snl)->lock, flags); \
-	}
-
-/*
  * Universal Host Controller Interface data structures and defines
  */
 
@@ -97,24 +67,29 @@
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
 
-struct uhci_framelist {
+struct uhci_frame_list {
 	__u32 frame[UHCI_NUMFRAMES];
-} __attribute__((aligned(4096)));
 
-struct uhci_td;
+	void *frame_cpu[UHCI_NUMFRAMES];
+
+	dma_addr_t dma_handle;
+};
+
+struct urb_priv;
 
 struct uhci_qh {
 	/* Hardware fields */
-	__u32 link;				/* Next queue */
-	__u32 element;				/* Queue element pointer */
+	__u32 link;			/* Next queue */
+	__u32 element;			/* Queue element pointer */
 
 	/* Software fields */
-	/* Can't use list_head since we want a specific order */
-	struct usb_device *dev;			/* The owning device */
+	dma_addr_t dma_handle;
 
-	struct uhci_qh *prevqh, *nextqh;
+	struct usb_device *dev;
+	struct urb_priv *urbp;
 
-	struct list_head remove_list;
+	struct list_head list;		/* P: uhci->frame_list_lock */
+	struct list_head remove_list;	/* P: uhci->remove_list_lock */
 } __attribute__((aligned(16)));
 
 /*
@@ -141,8 +116,6 @@
 #define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
 #define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
 
-#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
-
 /*
  * for TD <info>: (a.k.a. Token)
  */
@@ -170,7 +143,8 @@
  * On 64-bit machines we probably want to take advantage of the fact that
  * hw doesn't really care about the size of the sw-only area.
  *
- * Alas, not anymore, we have more than 4 words for software, woops
+ * Alas, not anymore, we have more than 4 words for software, woops.
+ * Everything still works tho, surprise! -jerdfelt
  */
 struct uhci_td {
 	/* Hardware fields */
@@ -180,13 +154,15 @@
 	__u32 buffer;
 
 	/* Software fields */
-	unsigned int *frameptr;		/* Frame list pointer */
-	struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */
+	dma_addr_t dma_handle;
 
 	struct usb_device *dev;
-	struct urb *urb;		/* URB this TD belongs to */
+	struct urb *urb;
 
-	struct list_head list;
+	struct list_head list;		/* P: urb->lock */
+
+	int frame;
+	struct list_head fl_list;	/* P: frame_list_lock */
 } __attribute__((aligned(16)));
 
 /*
@@ -289,8 +265,9 @@
 }
 
 struct virt_root_hub {
+	struct usb_device *dev;
 	int devnum;		/* Address of Root Hub endpoint */
-	void *urb;
+	struct urb *urb;
 	void *int_addr;
 	int send;
 	int interval;
@@ -306,6 +283,12 @@
  * a subset of what the full implementation needs.
  */
 struct uhci {
+	struct pci_dev *dev;
+
+	/* procfs */
+	int num;
+	struct proc_dir_entry *proc_entry;
+
 	/* Grabbed from PCI */
 	int irq;
 	unsigned int io_addr;
@@ -313,32 +296,43 @@
 
 	struct list_head uhci_list;
 
+	struct pci_pool *qh_pool;
+	struct pci_pool *td_pool;
+
 	struct usb_bus *bus;
 
-	struct uhci_td skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
-	struct uhci_qh skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
+	struct uhci_td *skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
+	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
-	spinlock_t framelist_lock;
-	struct uhci_framelist *fl;		/* Frame list */
+	spinlock_t frame_list_lock;
+	struct uhci_frame_list *fl;		/* Frame list */
 	int fsbr;				/* Full speed bandwidth reclamation */
 	int is_suspended;
 
-	spinlock_t qh_remove_lock;
+	spinlock_t qh_remove_list_lock;
 	struct list_head qh_remove_list;
 
-	spinlock_t urb_remove_lock;
+	spinlock_t urb_remove_list_lock;
 	struct list_head urb_remove_list;
 
-	struct s_nested_lock urblist_lock;
+	spinlock_t urb_list_lock;
 	struct list_head urb_list;
 
+	spinlock_t complete_list_lock;
+	struct list_head complete_list;
+
 	struct virt_root_hub rh;	/* private data of the virtual root hub */
 };
 
 struct urb_priv {
 	struct urb *urb;
+	struct usb_device *dev;
+
+	dma_addr_t setup_packet_dma_handle;
+	dma_addr_t transfer_buffer_dma_handle;
 
 	struct uhci_qh *qh;		/* QH for this URB */
+	struct list_head td_list;
 
 	int fsbr : 1;			/* URB turned on FSBR */
 	int fsbr_timeout : 1;		/* URB timed out on FSBR */
@@ -347,11 +341,12 @@
 					/*  a control transfer, retrigger */
 					/*  the status phase */
 
-	unsigned long inserttime;	/* In jiffies */
+	int status;			/* Final status */
 
-	struct list_head list;
+	unsigned long inserttime;	/* In jiffies */
 
-	struct list_head urb_queue_list;	/* URB's linked together */
+	struct list_head queue_list;
+	struct list_head complete_list;
 };
 
 /* -------------------------------------------------------------------------
@@ -408,16 +403,6 @@
 #define RH_ACK			0x01
 #define RH_REQ_ERR		-1
 #define RH_NACK			0x00
-
-/* needed for the debugging code */
-struct uhci_td *uhci_link_to_td(unsigned int element);
-
-/* Debugging code */
-void uhci_show_td(struct uhci_td *td);
-void uhci_show_status(struct uhci *uhci);
-void uhci_show_urb_queue(struct urb *urb);
-void uhci_show_queue(struct uhci_qh *qh);
-void uhci_show_queues(struct uhci *uhci);
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.4.3/linux/drivers/usb/usb-ohci.c	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/usb-ohci.c	Wed Apr 25 14:10:49 2001
@@ -12,11 +12,15 @@
  * 
  * History:
  * 
+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
+ 	pci_map_single (db)
+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
  * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
+ *
  * 2000/09/26 fixed races in removing the private portion of the urb
  * 2000/09/07 disable bulk and control lists when unlinking the last
  *	endpoint descriptor in order to avoid unrecoverable errors on
- *	the Lucent chips.
+ *	the Lucent chips. (rwc@sgi)
  * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
  *	urb unlink probs, indentation fixes
  * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
@@ -65,8 +69,6 @@
 
 #define OHCI_USE_NPS		// force NoPowerSwitching mode
 // #define OHCI_VERBOSE_DEBUG	/* not always helpful */
-// #define OHCI_MEM_SLAB
-// #define OHCI_MEM_FLAGS	SLAB_POISON	/* no redzones; see mm/slab.c */
 
 #include "usb-ohci.h"
 
@@ -92,6 +94,30 @@
 static LIST_HEAD (ohci_hcd_list);
 static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
 
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define read_roothub(hc, register, mask) ({ \
+	u32 temp = readl (&hc->regs->roothub.register); \
+	if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = readl (&hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
 /*-------------------------------------------------------------------------*
  * URB support functions 
  *-------------------------------------------------------------------------*/ 
@@ -100,10 +126,29 @@
 
 static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
 {
-	int i;
-
-	for (i = 0; i < urb_priv->length; i++) {
-		if (urb_priv->td [i]) {
+	int		i;
+	int		last = urb_priv->length - 1;
+	struct td	*td;
+
+	for (i = 0; i <= last; i++) {
+		td = urb_priv->td [i];
+		if (td) {
+			int		len;
+			int		dir;
+
+			if ((td->hwINFO & cpu_to_le32 (TD_DP)) == TD_DP_SETUP) {
+				len = 8;
+				dir = PCI_DMA_TODEVICE;
+			} else if (i == last) {
+				len = td->urb->transfer_buffer_length,
+				dir = usb_pipeout (td->urb->pipe)
+					? PCI_DMA_TODEVICE
+					: PCI_DMA_FROMDEVICE;
+			} else
+				len = dir = 0;
+			if (len && td->data_dma)
+				pci_unmap_single (hc->ohci_dev,
+					td->data_dma, len, dir);
 			td_free (hc, urb_priv->td [i]);
 		}
 	}
@@ -118,6 +163,13 @@
 	if (urb_priv) {
 		urb->hcpriv = NULL;
 
+#ifdef	DO_TIMEOUTS
+		if (urb->timeout) {
+			list_del (&urb->urb_list);
+			urb->timeout -= jiffies;
+		}
+#endif
+
 		/* Release int/iso bandwidth */
 		if (urb->bandwidth) {
 			switch (usb_pipetype(urb->pipe)) {
@@ -132,7 +184,7 @@
 			}
 		}
 
-		urb_free_priv ((struct ohci *)urb->dev->bus, urb_priv);
+		urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
 		usb_dec_dev_use (urb->dev);
 		urb->dev = NULL;
 	}
@@ -214,7 +266,7 @@
 		    continue;
 		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
 		while (*ed_p != 0 && j--) {
-			ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
+			ed_t *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
 			printk (" ed: %4x;", ed->hwINFO);
 			ed_p = &ed->hwNextED;
 		}
@@ -307,10 +359,9 @@
 
 static void ohci_dump_roothub (ohci_t *controller, int verbose)
 {
-	struct ohci_regs	*regs = controller->regs;
 	__u32			temp, ndp, i;
 
-	temp = readl (&regs->roothub.a);
+	temp = roothub_a (controller);
 	ndp = (temp & RH_A_NDP);
 
 	if (verbose) {
@@ -323,13 +374,13 @@
 			(temp & RH_A_PSM) ? " PSM" : "",
 			ndp
 			);
-		temp = readl (&regs->roothub.b);
+		temp = roothub_b (controller);
 		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
 			temp,
 			(temp & RH_B_PPCM) >> 16,
 			(temp & RH_B_DR)
 			);
-		temp = readl (&regs->roothub.status);
+		temp = roothub_status (controller);
 		dbg ("roothub.status: %08x%s%s%s%s%s%s",
 			temp,
 			(temp & RH_HS_CRWE) ? " CRWE" : "",
@@ -342,7 +393,7 @@
 	}
 	
 	for (i = 0; i < ndp; i++) {
-		temp = readl (&regs->roothub.portstatus [i]);
+		temp = roothub_portstatus (controller, i);
 		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
 			i,
 			temp,
@@ -385,7 +436,7 @@
 
 /* return a request to the completion handler */
  
-static int sohci_return_urb (urb_t * urb)
+static int sohci_return_urb (struct ohci *hc, urb_t * urb)
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
 	urb_t * urbt;
@@ -407,7 +458,15 @@
 
 	switch (usb_pipetype (urb->pipe)) {
   		case PIPE_INTERRUPT:
-			urb->complete (urb); /* call complete and requeue URB */	
+			pci_unmap_single (hc->ohci_dev,
+				urb_priv->td [0]->data_dma,
+				urb->transfer_buffer_length,
+				usb_pipeout (urb->pipe)
+					? PCI_DMA_TODEVICE
+					: PCI_DMA_FROMDEVICE);
+			urb->complete (urb);
+
+			/* implicitly requeued */
   			urb->actual_length = 0;
   			urb->status = USB_ST_URB_PENDING;
   			if (urb_priv->state != URB_DEL)
@@ -417,8 +476,13 @@
 		case PIPE_ISOCHRONOUS:
 			for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
 			if (urbt) { /* send the reply and requeue URB */	
+				pci_unmap_single (hc->ohci_dev,
+					urb_priv->td [0]->data_dma,
+					urb->transfer_buffer_length,
+					usb_pipeout (urb->pipe)
+						? PCI_DMA_TODEVICE
+						: PCI_DMA_FROMDEVICE);
 				urb->complete (urb);
-				
 				spin_lock_irqsave (&usb_ed_lock, flags);
 				urb->actual_length = 0;
   				urb->status = USB_ST_URB_PENDING;
@@ -460,6 +524,7 @@
 	int i, size = 0;
 	unsigned long flags;
 	int bustime = 0;
+	int mem_flags = ALLOC_FLAGS;
 	
 	if (!urb->dev || !urb->dev->bus)
 		return -ENODEV;
@@ -489,7 +554,7 @@
 	}
 
 	/* every endpoint has a ed, locate and fill it */
-	if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
+	if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
 		usb_dec_dev_use (urb->dev);	
 		return -ENOMEM;
 	}
@@ -534,8 +599,9 @@
 
 	/* allocate the TDs */
 	for (i = 0; i < size; i++) { 
-		urb_priv->td[i] = td_alloc (ohci);
+		urb_priv->td[i] = td_alloc (ohci, mem_flags);
 		if (!urb_priv->td[i]) {
+			urb_priv->length = i;
 			urb_free_priv (ohci, urb_priv);
 			usb_dec_dev_use (urb->dev);	
 			return -ENOMEM;
@@ -569,6 +635,9 @@
 				return bustime;
 			}
 			usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
+#ifdef	DO_TIMEOUTS
+			urb->timeout = 0;
+#endif
 	}
 
 	spin_lock_irqsave (&usb_ed_lock, flags);
@@ -582,6 +651,31 @@
 
 	/* fill the TDs and link it to the ed */
 	td_submit_urb (urb);
+
+#ifdef	DO_TIMEOUTS
+	/* maybe add to ordered list of timeouts */
+	if (urb->timeout) {
+		struct list_head	*entry;
+
+		// FIXME:  usb-uhci uses relative timeouts (like this),
+		// while uhci uses absolute ones (probably better).
+		// Pick one solution and change the affected drivers.
+		urb->timeout += jiffies;
+
+		list_for_each (entry, &ohci->timeout_list) {
+			struct urb	*next_urb;
+
+			next_urb = list_entry (entry, struct urb, urb_list);
+			if (time_after_eq (urb->timeout, next_urb->timeout))
+				break;
+		}
+		list_add (&urb->urb_list, entry);
+
+		/* drive timeouts by SF (messy, but works) */
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);	
+	}
+#endif
+
 	spin_unlock_irqrestore (&usb_ed_lock, flags);
 
 	return 0;	
@@ -687,18 +781,11 @@
 {
 	struct ohci_device * dev;
 
-	/* FIXME:  ED allocation with pci_consistent memory
-	 * must know the controller ... either pass it in here,
-	 * or decouple ED allocation from dev allocation.
-	 */
-	dev = dev_alloc (NULL);
+	dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS);
 	if (!dev)
 		return -ENOMEM;
-		
-	memset (dev, 0, sizeof (*dev));
 
 	usb_dev->hcpriv = dev;
-
 	return 0;
 }
 
@@ -783,7 +870,7 @@
 	}
 
 	/* free device, and associated EDs */
-	dev_free (dev);
+	dev_free (ohci, dev);
 
 	return 0;
 }
@@ -877,9 +964,9 @@
 	case PIPE_CONTROL:
 		ed->hwNextED = 0;
 		if (ohci->ed_controltail == NULL) {
-			writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
+			writel (ed->dma, &ohci->regs->ed_controlhead);
 		} else {
-			ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+			ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
 		}
 		ed->ed_prev = ohci->ed_controltail;
 		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
@@ -893,9 +980,9 @@
 	case PIPE_BULK:
 		ed->hwNextED = 0;
 		if (ohci->ed_bulktail == NULL) {
-			writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
+			writel (ed->dma, &ohci->regs->ed_bulkhead);
 		} else {
-			ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+			ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
 		}
 		ed->ed_prev = ohci->ed_bulktail;
 		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
@@ -916,11 +1003,11 @@
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
 			inter = 1;
 			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]); 
-				(*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval); 
-				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
-					inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+				(*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval); 
+				ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
+					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
 			ed->hwNextED = *ed_p; 
-			*ed_p = cpu_to_le32 (virt_to_bus (ed));
+			*ed_p = cpu_to_le32 (ed->dma);
 		}
 #ifdef DEBUG
 		ep_print_int_eds (ohci, "LINK_INT");
@@ -931,16 +1018,16 @@
 		ed->hwNextED = 0;
 		ed->int_interval = 1;
 		if (ohci->ed_isotail != NULL) {
-			ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+			ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
 			ed->ed_prev = ohci->ed_isotail;
 		} else {
 			for ( i = 0; i < 32; i += inter) {
 				inter = 1;
 				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
 					*ed_p != 0; 
-					ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
-						inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-				*ed_p = cpu_to_le32 (virt_to_bus (ed));	
+					ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
+						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+				*ed_p = cpu_to_le32 (ed->dma);	
 			}	
 			ed->ed_prev = NULL;
 		}	
@@ -984,7 +1071,7 @@
 		if (ohci->ed_controltail == ed) {
 			ohci->ed_controltail = ed->ed_prev;
 		} else {
-			((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
 		}
 		break;
       
@@ -1001,7 +1088,7 @@
 		if (ohci->ed_bulktail == ed) {
 			ohci->ed_bulktail = ed->ed_prev;
 		} else {
-			((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
 		}
 		break;
       
@@ -1012,9 +1099,9 @@
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
 			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]), inter = 1; 
 				(*ed_p != 0) && (*ed_p != ed->hwNextED); 
-				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED), 
-				inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) {				
-					if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+				ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED), 
+				inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {				
+					if((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
 			  			*ed_p = ed->hwNextED;		
 			  			break;
 			  		}
@@ -1031,7 +1118,7 @@
 		if (ohci->ed_isotail == ed)
 			ohci->ed_isotail = ed->ed_prev;
 		if (ed->hwNextED != 0) 
-		    ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		    (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
 				    
 		if (ed->ed_prev != NULL) {
 			ed->ed_prev->hwNextED = ed->hwNextED;
@@ -1039,9 +1126,9 @@
 			for (i = 0; i < 32; i++) {
 				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
 						*ed_p != 0; 
-						ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
-					// inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-					if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+						ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
+					// inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+					if((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
 						*ed_p = ed->hwNextED;		
 						break;
 					}
@@ -1066,7 +1153,13 @@
  * in all other cases the state is left unchanged
  * the ed info fields are setted anyway even though most of them should not change */
  
-static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load)
+static ed_t * ep_add_ed (
+	struct usb_device * usb_dev,
+	unsigned int pipe,
+	int interval,
+	int load,
+	int mem_flags
+)
 {
    	ohci_t * ohci = usb_dev->bus->hcpriv;
 	td_t * td;
@@ -1089,13 +1182,16 @@
 	if (ed->state == ED_NEW) {
 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
   		/* dummy td; end of td list for ed */
-		td = td_alloc (ohci);
-  		if (!td) {
+		td = td_alloc (ohci, mem_flags);
+		/* hash the ed for later reverse mapping */
+ 		if (!td || !hash_add_ed (ohci, (ed_t *)ed)) {
 			/* out of memory */
+		        if (td)
+		            td_free(ohci, td);
 			spin_unlock_irqrestore (&usb_ed_lock, flags);
 			return NULL;
 		}
-		ed->hwTailP = cpu_to_le32 (virt_to_bus (td));
+		ed->hwTailP = cpu_to_le32 (td->td_dma);
 		ed->hwHeadP = ed->hwTailP;	
 		ed->state = ED_UNLINK;
 		ed->type = usb_pipetype (pipe);
@@ -1164,43 +1260,52 @@
  * TD handling functions
  *-------------------------------------------------------------------------*/
 
-/* prepare a TD */
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
 
-static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int index)
+static void
+td_fill (ohci_t * ohci, unsigned int info,
+	dma_addr_t data, int len,
+	urb_t * urb, int index)
 {
 	volatile td_t  * td, * td_pt;
 	urb_priv_t * urb_priv = urb->hcpriv;
-
+	
 	if (index >= urb_priv->length) {
 		err("internal OHCI error: TD index > length");
 		return;
 	}
 	
+	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+
 	/* fill the old dummy TD */
-	td = urb_priv->td [index] = (td_t *)
-		bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0);
+	td = urb_priv->td [index] = dma_to_td (ohci,
+			le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
+
 	td->ed = urb_priv->ed;
 	td->next_dl_td = NULL;
 	td->index = index;
 	td->urb = urb; 
+	td->data_dma = data;
+	if (!len)
+		data = 0;
+
 	td->hwINFO = cpu_to_le32 (info);
 	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
-		td->hwCBP = cpu_to_le32 (((!data || !len)
-			? 0
-			: virt_to_bus (data)) & 0xFFFFF000);
+		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
 		td->ed->last_iso = info & 0xffff;
 	} else {
-		td->hwCBP = cpu_to_le32 (((!data || !len)
-			? 0
-			: virt_to_bus (data))); 
+		td->hwCBP = cpu_to_le32 (data); 
 	}			
-	td->hwBE = cpu_to_le32 ((!data || !len )
-		? 0
-		: virt_to_bus (data + len - 1));
-	td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
-	td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
-	td_pt->hwNextTD = 0;
+	if (data)
+		td->hwBE = cpu_to_le32 (data + len - 1);
+	else
+		td->hwBE = 0;
+	td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
+	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
+
+	/* append to queue */
 	td->ed->hwTailP = td->hwNextTD;
 }
 
@@ -1212,8 +1317,7 @@
 { 
 	urb_priv_t * urb_priv = urb->hcpriv;
 	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
-	void * ctrl = urb->setup_packet;
-	void * data = urb->transfer_buffer;
+	dma_addr_t data;
 	int data_len = urb->transfer_buffer_length;
 	int cnt = 0; 
 	__u32 info = 0;
@@ -1228,18 +1332,28 @@
 	}
 	
 	urb_priv->td_cnt = 0;
+
+	if (data_len) {
+		data = pci_map_single (ohci->ohci_dev,
+			urb->transfer_buffer, data_len,
+			usb_pipeout (urb->pipe)
+				? PCI_DMA_TODEVICE
+				: PCI_DMA_FROMDEVICE
+			);
+	} else
+		data = 0;
 	
 	switch (usb_pipetype (urb->pipe)) {
 		case PIPE_BULK:
 			info = usb_pipeout (urb->pipe)? 
 				TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
 			while(data_len > 4096) {		
-				td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
+				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
 				data += 4096; data_len -= 4096; cnt++;
 			}
 			info = usb_pipeout (urb->pipe)?
 				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
-			td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
+			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
 			cnt++;
 			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
 			break;
@@ -1247,27 +1361,32 @@
 		case PIPE_INTERRUPT:
 			info = usb_pipeout (urb->pipe)? 
 				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
-			td_fill (info, data, data_len, urb, cnt++);
+			td_fill (ohci, info, data, data_len, urb, cnt++);
 			break;
 
 		case PIPE_CONTROL:
 			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-			td_fill (info, ctrl, 8, urb, cnt++); 
+			td_fill (ohci, info,
+				pci_map_single (ohci->ohci_dev,
+					urb->setup_packet, 8,
+					PCI_DMA_TODEVICE),
+				8, urb, cnt++); 
 			if (data_len > 0) {  
 				info = usb_pipeout (urb->pipe)? 
 					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
-				td_fill (info, data, data_len, urb, cnt++);  
+				/* NOTE:  mishandles transfers >8K, some >4K */
+				td_fill (ohci, info, data, data_len, urb, cnt++);  
 			} 
 			info = usb_pipeout (urb->pipe)? 
  				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
-			td_fill (info, NULL, 0, urb, cnt++);
+			td_fill (ohci, info, data, 0, urb, cnt++);
 			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
 			break;
 
 		case PIPE_ISOCHRONOUS:
 			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-				td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
- 					(__u8 *) data + urb->iso_frame_desc[cnt].offset, 
+				td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
+					data + urb->iso_frame_desc[cnt].offset, 
 					urb->iso_frame_desc[cnt].length, urb, cnt); 
 			}
 			break;
@@ -1318,9 +1437,9 @@
 				((td->index == 0) || (td->index == urb_priv->length - 1)))) {
  			if (tdBE != 0) {
  				if (td->hwCBP == 0)
-					urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;
+					urb->actual_length += tdBE - td->data_dma + 1;
   				else
-					urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;
+					urb->actual_length += tdCBP - td->data_dma;
 			}
   		}
   	}
@@ -1366,7 +1485,7 @@
 	ohci->hcca->done_head = 0;
 	
 	while (td_list_hc) {		
-		td_list = (td_t *) bus_to_virt (td_list_hc);
+		td_list = dma_to_td (ohci, td_list_hc);
 
 		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
 			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
@@ -1411,8 +1530,8 @@
 
 	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
 
-   	 	tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-		tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
 		edINFO = le32_to_cpup (&ed->hwINFO);
 		td_p = &ed->hwHeadP;
 
@@ -1420,7 +1539,7 @@
 			urb_t * urb = td->urb;
 			urb_priv_t * urb_priv = td->urb->hcpriv;
 			
-			td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
 			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
 				tdINFO = le32_to_cpup (&td->hwINFO);
 				if (TD_CC_GET (tdINFO) < 0xE)
@@ -1439,7 +1558,8 @@
 			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
 			td_free (ohci, tdTailP); /* free dummy td */
    	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
-   	 		ed->state = ED_NEW; 
+			ed->state = ED_NEW;
+			hash_free_ed(ohci, ed);
    	 		/* if all eds are removed wake up sohci_free_dev */
    	 		if (!--dev->ed_cnt) {
 				wait_queue_head_t *wait_head = dev->wait;
@@ -1450,7 +1570,7 @@
 			}
    	 	} else {
    	 		ed->state &= ~ED_URB_DEL;
-			tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+			tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
 
 			if (tdHeadP == tdTailP) {
 				if (ed->state == ED_OPER)
@@ -1458,6 +1578,7 @@
 				td_free (ohci, tdTailP);
 				ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
 				ed->state = ED_NEW;
+				hash_free_ed(ohci, ed);
 				--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
 			} else
    	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
@@ -1535,7 +1656,7 @@
 			if ((ed->state & (ED_OPER | ED_UNLINK))
 					&& (urb_priv->state != URB_DEL)) {
   				urb->status = cc_to_error[cc];
-  				sohci_return_urb (urb);
+  				sohci_return_urb (ohci, urb);
   			} else {
 				spin_lock_irqsave (&usb_ed_lock, flags);
   				dl_del_urb (urb);
@@ -1640,7 +1761,7 @@
 
 	__u8 data[8];
 
-	num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP; 
+	num_ports = roothub_a (ohci) & RH_A_NDP; 
 	if (num_ports > MAX_ROOT_PORTS) {
 		err ("bogus NDP=%d for OHCI usb-%s", num_ports,
 			ohci->ohci_dev->slot_name);
@@ -1649,13 +1770,13 @@
 		/* retry later; "should not happen" */
 		return 0;
 	}
-	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
+	*(__u8 *) data = (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
 		? 1: 0;
 	ret = *(__u8 *) data;
 
 	for ( i = 0; i < num_ports; i++) {
 		*(__u8 *) (data + (i + 1) / 8) |= 
-			((readl (&ohci->regs->roothub.portstatus[i]) &
+			((roothub_portstatus (ohci, i) &
 				(RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
 			    ? 1: 0) << ((i + 1) % 8);
 		ret += *(__u8 *) (data + (i + 1) / 8);
@@ -1726,8 +1847,8 @@
 #define OK(x) 			len = (x); break
 #define WR_RH_STAT(x) 		writel((x), &ohci->regs->roothub.status)
 #define WR_RH_PORTSTAT(x) 	writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT		readl(&ohci->regs->roothub.status)
-#define RD_RH_PORTSTAT		readl(&ohci->regs->roothub.portstatus[wIndex-1])
+#define RD_RH_STAT		roothub_status(ohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(ohci,wIndex-1)
 
 /* request to virtual root hub */
 
@@ -1765,9 +1886,6 @@
 	wIndex        = le16_to_cpu (cmd->index);
 	wLength       = le16_to_cpu (cmd->length);
 
-	dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
-		bmRType_bReq, wLength);
-
 	switch (bmRType_bReq) {
 	/* Request Destination:
 	   without flags: Device, 
@@ -1869,7 +1987,7 @@
 		
 		case RH_GET_DESCRIPTOR | RH_CLASS:
 		    {
-			    __u32 temp = readl (&ohci->regs->roothub.a);
+			    __u32 temp = roothub_a (ohci);
 
 			    data_buf [0] = 9;		// min length;
 			    data_buf [1] = 0x29;
@@ -1884,7 +2002,7 @@
 
 			    datab [1] = 0;
 			    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
-			    temp = readl (&ohci->regs->roothub.b);
+			    temp = roothub_b (ohci);
 			    data_buf [7] = temp & RH_B_DR;
 			    if (data_buf [2] < 7) {
 				data_buf [8] = 0xff;
@@ -2038,13 +2156,14 @@
 	writel (mask, &ohci->regs->intrstatus);
 
 #ifdef	OHCI_USE_NPS
-	writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
+	/* required for AMD-756 and some Mac platforms */
+	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
 		&ohci->regs->roothub.a);
 	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
 #endif	/* OHCI_USE_NPS */
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
-	mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
+	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
  
 	/* connect the virtual root hub */
 	ohci->rh.devnum = 0;
@@ -2068,6 +2187,37 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* called only from interrupt handler */
+
+static void check_timeouts (struct ohci *ohci)
+{
+	spin_lock (&usb_ed_lock);
+	while (!list_empty (&ohci->timeout_list)) {
+		struct urb	*urb;
+
+		urb = list_entry (ohci->timeout_list.next, struct urb, urb_list);
+		if (time_after (jiffies, urb->timeout))
+			break;
+
+		list_del_init (&urb->urb_list);
+		if (urb->status != -EINPROGRESS)
+			continue;
+
+		urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+		spin_unlock (&usb_ed_lock);
+
+		// outside the interrupt handler (in a timer...)
+		// this reference would race interrupts
+		sohci_unlink_urb (urb);
+
+		spin_lock (&usb_ed_lock);
+	}
+	spin_unlock (&usb_ed_lock);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
 /* an interrupt happens */
 
 static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
@@ -2120,10 +2270,18 @@
 		if (ohci->ed_rm_list[frame] != NULL)
 			writel (OHCI_INTR_SF, &regs->intrenable);	
 	}
+
+	if (!list_empty (&ohci->timeout_list)) {
+		check_timeouts (ohci);
+// FIXME:  enable SF as needed in a timer;
+// don't make lots of 1ms interrupts
+// On unloaded USB, think 4k ~= 4-5msec
+		if (!list_empty (&ohci->timeout_list))
+			writel (OHCI_INTR_SF, &regs->intrenable);	
+	}
+
 	writel (ints, &regs->intrstatus);
 	writel (OHCI_INTR_MIE, &regs->intrenable);	
-
-	/* FIXME:  check URB timeouts */
 }
 
 /*-------------------------------------------------------------------------*/
@@ -2159,6 +2317,8 @@
 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
 	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
 
+	INIT_LIST_HEAD (&ohci->timeout_list);
+
 	bus = usb_alloc_bus (&sohci_device_operations);
 	if (!bus) {
 		kfree (ohci);
@@ -2198,6 +2358,8 @@
 
 	list_del (&ohci->ohci_hcd_list);
 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+
+	ohci_mem_cleanup (ohci);
     
 	/* unmap the IO address space */
 	iounmap (ohci->regs);
@@ -2215,11 +2377,13 @@
 static struct pci_driver ohci_pci_driver;
  
 static int __devinit
-hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
+hc_found_ohci (struct pci_dev *dev, int irq,
+	void *mem_base, const struct pci_device_id *id)
 {
 	ohci_t * ohci;
 	u8 latency, limit;
 	char buf[8], *bufp = buf;
+	int ret;
 
 #ifndef __sparc__
 	sprintf(buf, "%d", irq);
@@ -2234,6 +2398,13 @@
 	if (!ohci) {
 		return -ENOMEM;
 	}
+	if ((ret = ohci_mem_init (ohci)) < 0) {
+		hc_release_ohci (ohci);
+		return ret;
+	}
+	ohci->flags = id->driver_data;
+	if (ohci->flags & OHCI_QUIRK_AMD756)
+		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
 
 	/* bad pci latencies can contribute to overruns */ 
 	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
@@ -2331,13 +2502,6 @@
 	unsigned long mem_resource, mem_len;
 	void *mem_base;
 
-	/* blacklisted hardware? */
-	if (id->driver_data) {
-		info ("%s (%s): %s", dev->slot_name,
-			dev->name, (char *) id->driver_data);
-		return -ENODEV;
-	}
-
 	if (pci_enable_device(dev) < 0)
 		return -ENODEV;
 	
@@ -2358,7 +2522,7 @@
 	/* controller writes into our memory */
 	pci_set_master (dev);
 
-	return hc_found_ohci (dev, dev->irq, mem_base);
+	return hc_found_ohci (dev, dev->irq, mem_base, id);
 } 
 
 /*-------------------------------------------------------------------------*/
@@ -2505,15 +2669,14 @@
 
 	/*
 	 * AMD-756 [Viper] USB has a serious erratum when used with
-	 * lowspeed devices like mice; oopses have been seen.  The
-	 * vendor workaround needs an NDA ... for now, blacklist it.
+	 * lowspeed devices like mice.
 	 */
 	vendor:		0x1022,
 	device:		0x740c,
 	subvendor:	PCI_ANY_ID,
 	subdevice:	PCI_ANY_ID,
 
-	driver_data:	(unsigned long) "blacklisted, erratum #4",
+	driver_data:	OHCI_QUIRK_AMD756,
 
 } , {
 
@@ -2586,11 +2749,7 @@
 {
 	int ret;
 
-	if ((ret = ohci_mem_init ()) < 0)
-		return ret;
-
 	if ((ret = pci_module_init (&ohci_pci_driver)) < 0) {
-		ohci_mem_cleanup ();
 		return ret;
 	}
 
@@ -2608,7 +2767,6 @@
 	pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
 #endif  
 	pci_unregister_driver (&ohci_pci_driver);
-	ohci_mem_cleanup ();
 }
 
 module_init (ohci_hcd_init);
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h
--- v2.4.3/linux/drivers/usb/usb-ohci.h	Mon Mar 19 17:21:54 2001
+++ linux/drivers/usb/usb-ohci.h	Wed Apr 25 14:10:49 2001
@@ -39,7 +39,7 @@
 #define ED_URB_DEL  	0x08
 
 /* usb_ohci_ed */
-typedef struct ed {
+struct ed {
 	__u32 hwINFO;       
 	__u32 hwTailP;
 	__u32 hwHeadP;
@@ -53,9 +53,12 @@
 	__u8 state;
 	__u8 type; 
 	__u16 last_iso;
-    struct ed * ed_rm_list;
-   
-} ed_t;
+	struct ed * ed_rm_list;
+
+	dma_addr_t dma;
+	__u32 unused[3];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
 
  
 /* TD info field */
@@ -75,7 +78,7 @@
 #define TD_DP_IN    0x00100000
 #define TD_DP_OUT   0x00080000
 
-#define TD_ISO		0x00010000
+#define TD_ISO	    0x00010000
 #define TD_DEL      0x00020000
 
 /* CC Codes */
@@ -96,20 +99,24 @@
 
 #define MAXPSW 1
 
-typedef struct td { 
+struct td {
 	__u32 hwINFO;
   	__u32 hwCBP;		/* Current Buffer Pointer */
   	__u32 hwNextTD;		/* Next TD Pointer */
   	__u32 hwBE;		/* Memory Buffer End Pointer */
-  	__u16 hwPSW[MAXPSW];
 
+  	__u16 hwPSW[MAXPSW];
   	__u8 unused;
   	__u8 index;
   	struct ed * ed;
   	struct td * next_dl_td;
   	urb_t * urb;
-} td_t;
 
+	dma_addr_t td_dma;
+	dma_addr_t data_dma;
+	__u32 unused2[2];
+} __attribute((aligned(16)));
+typedef struct td td_t;
 
 #define OHCI_ED_SKIP	(1 << 14)
 
@@ -121,7 +128,7 @@
  
 #define NUM_INTS 32	/* part of the OHCI standard */
 struct ohci_hcca {
-    __u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
 	__u16	frame_no;		/* current frame number */
 	__u16	pad1;			/* set to 0 on each frame_no change */
 	__u32	done_head;		/* info returned for an interrupt */
@@ -337,6 +344,27 @@
 } urb_priv_t;
 #define URB_DEL 1
 
+
+/* Hash struct used for TD/ED hashing */
+struct hash_t {
+	void		*virt;
+	dma_addr_t	dma;
+	struct hash_t	*next; // chaining for collision cases
+};
+
+/* List of TD/ED hash entries */
+struct hash_list_t {
+	struct hash_t	*head;
+	struct hash_t	*tail;
+};
+
+#define TD_HASH_SIZE    64    /* power'o'two */
+#define ED_HASH_SIZE    64    /* power'o'two */
+
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
+#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
+
+
 /*
  * This is the full ohci controller description
  *
@@ -352,11 +380,14 @@
 	int irq;
 	int disabled;			/* e.g. got a UE, we're hung */
 	atomic_t resume_count;		/* defending against multiple resumes */
+	unsigned long flags;		/* for HC bugs */
+#define	OHCI_QUIRK_AMD756	0x01		/* erratum #4 */
 
 	struct ohci_regs * regs;	/* OHCI controller's memory */
 	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
 
-	struct ohci * next; 		// chain of uhci device contexts
+	struct ohci * next; 		// chain of ohci device contexts
+	struct list_head timeout_list;
 	// struct list_head urb_list; 	// list of all pending urbs
 	// spinlock_t urb_list_lock; 	// lock to keep consistency 
   
@@ -371,17 +402,21 @@
 	struct usb_device * dev[128];
 	struct virt_root_hub rh;
 
-	/* PCI device handle and settings */
+	/* PCI device handle, settings, ... */
 	struct pci_dev	*ohci_dev;
 	u8		pci_latency;
-} ohci_t;
+	struct pci_pool	*td_cache;
+	struct pci_pool	*dev_cache;
+	struct hash_list_t	td_hash[TD_HASH_SIZE];
+	struct hash_list_t	ed_hash[ED_HASH_SIZE];
 
+} ohci_t;
 
-#define NUM_TDS	0		/* num of preallocated transfer descriptors */
 #define NUM_EDS 32		/* num of preallocated endpoint descriptors */
 
 struct ohci_device {
 	ed_t 	ed[NUM_EDS];
+	dma_addr_t dma;
 	int ed_cnt;
 	wait_queue_head_t * wait;
 };
@@ -393,10 +428,10 @@
 /* endpoint */
 static int ep_link(ohci_t * ohci, ed_t * ed);
 static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
 static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
 /* td */
-static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int index);
+static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, urb_t * urb, int index);
 static void td_submit_urb(urb_t * urb);
 /* root hub */
 static int rh_submit_urb(urb_t * urb);
@@ -406,97 +441,204 @@
 /*-------------------------------------------------------------------------*/
 
 #define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
- 
-#ifdef OHCI_MEM_SLAB
-#define	__alloc(t,c) kmem_cache_alloc(c,ALLOC_FLAGS)
-#define	__free(c,x) kmem_cache_free(c,x)
-static kmem_cache_t *td_cache, *ed_cache;
 
-/*
- * WARNING:  do NOT use this with "forced slab debug"; it won't respect
- * our hardware alignment requirement.
- */
-#ifndef OHCI_MEM_FLAGS
-#define	OHCI_MEM_FLAGS 0
+#ifdef DEBUG
+#	define OHCI_MEM_FLAGS	SLAB_POISON
+#else
+#	define OHCI_MEM_FLAGS	0
+#endif
+ 
+#ifndef CONFIG_PCI
+#	error "usb-ohci currently requires PCI-based controllers"
+	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
 #endif
 
-static int ohci_mem_init (void)
+
+/* Recover a TD/ED using its collision chain */
+static inline void *
+dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
 {
-	/* redzoning (or forced debug!) breaks alignment */
-	int	flags = (OHCI_MEM_FLAGS) & ~SLAB_RED_ZONE;
+	struct hash_t * scan = entry->head;
+	while (scan && scan->dma != dma)
+		scan = scan->next;
+	if (!scan)
+		BUG();
+	return scan->virt;
+}
 
-	/* TDs accessed by controllers and host */
-	td_cache = kmem_cache_create ("ohci_td", sizeof (struct td), 0,
-		flags | SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!td_cache) {
-		dbg ("no TD cache?");
-		return -ENOMEM;
-	}
+static inline struct ed *
+dma_to_ed (struct ohci * hc, dma_addr_t ed_dma)
+{
+	return (struct ed *) dma_to_ed_td(&(hc->ed_hash[ED_HASH_FUNC(ed_dma)]),
+				      ed_dma);
+}
 
-	/* EDs are accessed by controllers and host;  dev part is host-only */
-	ed_cache = kmem_cache_create ("ohci_ed", sizeof (struct ohci_device), 0,
-		flags | SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!ed_cache) {
-		dbg ("no ED cache?");
-		kmem_cache_destroy (td_cache);
-		td_cache = 0;
-		return -ENOMEM;
+static inline struct td *
+dma_to_td (struct ohci * hc, dma_addr_t td_dma)
+{
+	return (struct td *) dma_to_ed_td(&(hc->td_hash[TD_HASH_FUNC(td_dma)]),
+				      td_dma);
+}
+
+/* Add a hash entry for a TD/ED; return true on success */
+static inline int
+hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
+{
+	struct hash_t * scan;
+	
+	scan = (struct hash_t *)kmalloc(sizeof(struct hash_t), ALLOC_FLAGS);
+	if (!scan)
+		return 0;
+	
+	if (!entry->tail) {
+		entry->head = entry->tail = scan;
+	} else {
+		entry->tail->next = scan;
+		entry->tail = scan;
 	}
-	dbg ("slab flags 0x%x", flags);
-	return 0;
+	
+	scan->virt = virt;
+	scan->dma = dma;
+	scan->next = NULL;
+	return 1;
 }
 
-static void ohci_mem_cleanup (void)
+static inline int
+hash_add_ed (struct ohci * hc, struct ed * ed)
 {
-	if (ed_cache && kmem_cache_destroy (ed_cache))
-		err ("ed_cache remained");
-	ed_cache = 0;
-
-	if (td_cache && kmem_cache_destroy (td_cache))
-		err ("td_cache remained");
-	td_cache = 0;
+	return hash_add_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]),
+			ed, ed->dma);
 }
 
-#else
-#define	__alloc(t,c) kmalloc(sizeof(t),ALLOC_FLAGS)
-#define	__free(dev,x) kfree(x)
-#define td_cache 0
-#define ed_cache 0
+static inline int
+hash_add_td (struct ohci * hc, struct td * td)
+{
+	return hash_add_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]),
+			td, td->td_dma);
+}
 
-static inline int ohci_mem_init (void) { return 0; }
-static inline void ohci_mem_cleanup (void) { return; }
 
-/* FIXME: pci_consistent version */
+static inline void
+hash_free_ed_td (struct hash_list_t * entry, void * virt)
+{
+	struct hash_t *scan, *prev;
+	scan = prev = entry->head;
 
-#endif
+	// Find and unlink hash entry
+	while (scan && scan->virt != virt) {
+		prev = scan;
+		scan = scan->next;
+	}
+	if (scan) {
+		if (scan == entry->head) {
+			if (entry->head == entry->tail)
+				entry->head = entry->tail = NULL;
+			else
+				entry->head = scan->next;
+		} else if (scan == entry->tail) {
+			entry->tail = prev;
+			prev->next = NULL;
+		} else
+			prev->next = scan->next;
+		kfree(scan);
+	}
+}
+
+static inline void
+hash_free_ed (struct ohci * hc, struct ed * ed)
+{
+	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
+}
+
+static inline void
+hash_free_td (struct ohci * hc, struct td * td)
+{
+	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
+}
+
+
+static int ohci_mem_init (struct ohci *ohci)
+{
+	ohci->td_cache = pci_pool_create ("ohci_td", ohci->ohci_dev,
+		sizeof (struct td),
+		16 /* byte alignment */,
+		0 /* no page-crossing issues */,
+		GFP_KERNEL | OHCI_MEM_FLAGS);
+	if (!ohci->td_cache)
+		return -ENOMEM;
+	ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev,
+		sizeof (struct ohci_device),
+		16 /* byte alignment */,
+		0 /* no page-crossing issues */,
+		GFP_KERNEL | OHCI_MEM_FLAGS);
+	if (!ohci->dev_cache)
+		return -ENOMEM;
+	return 0;
+}
 
+static void ohci_mem_cleanup (struct ohci *ohci)
+{
+	if (ohci->td_cache) {
+		pci_pool_destroy (ohci->td_cache);
+		ohci->td_cache = 0;
+	}
+	if (ohci->dev_cache) {
+		pci_pool_destroy (ohci->dev_cache);
+		ohci->dev_cache = 0;
+	}
+}
 
 /* TDs ... */
 static inline struct td *
-td_alloc (struct ohci *hc)
+td_alloc (struct ohci *hc, int mem_flags)
 {
-	struct td *td = (struct td *) __alloc (struct td, td_cache);
+	dma_addr_t	dma;
+	struct td	*td;
+
+	td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
+	if (td) {
+		td->td_dma = dma;
+
+		/* hash it for later reverse mapping */
+		if (!hash_add_td (hc, td)) {
+			pci_pool_free (hc->td_cache, td, dma);
+			return NULL;
+		}
+	}
 	return td;
 }
 
 static inline void
 td_free (struct ohci *hc, struct td *td)
 {
-	__free (td_cache, td);
+	hash_free_td (hc, td);
+	pci_pool_free (hc->td_cache, td, td->td_dma);
 }
 
 
 /* DEV + EDs ... only the EDs need to be consistent */
 static inline struct ohci_device *
-dev_alloc (struct ohci *hc)
+dev_alloc (struct ohci *hc, int mem_flags)
 {
-	struct ohci_device *dev = (struct ohci_device *)
-		__alloc (struct ohci_device, ed_cache);
+	dma_addr_t		dma;
+	struct ohci_device	*dev;
+	int			i, offset;
+
+	dev = pci_pool_alloc (hc->dev_cache, mem_flags, &dma);
+	if (dev) {
+		memset (dev, 0, sizeof (*dev));
+		dev->dma = dma;
+		offset = ((char *)&dev->ed) - ((char *)dev);
+		for (i = 0; i < NUM_EDS; i++, offset += sizeof dev->ed [0])
+			dev->ed [i].dma = dma + offset;
+		/* add to hashtable if used */
+	}
 	return dev;
 }
 
 static inline void
-dev_free (struct ohci_device *dev)
+dev_free (struct ohci *hc, struct ohci_device *dev)
 {
-	__free (ed_cache, dev);
+	pci_pool_free (hc->dev_cache, dev, dev->dma);
 }
+
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.4.3/linux/drivers/usb/usb-uhci.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/usb/usb-uhci.c	Wed Apr 18 11:49:12 2001
@@ -1411,7 +1411,7 @@
 /*-------------------------------------------------------------------*/
 // submits USB interrupt (ie. polling ;-) 
 // ASAP-flag set implicitely
-// if period==0, the the transfer is only done once
+// if period==0, the transfer is only done once
 
 _static int uhci_submit_int_urb (urb_t *urb)
 {
@@ -2390,7 +2390,7 @@
 			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
 		}
 
-		// if any error occured: ignore this td, and continue
+		// if any error occurred: ignore this td, and continue
 		if (status != 0) {
 			//uhci_show_td (desc);
 			urb->error_count++;
diff -u --recursive --new-file v2.4.3/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.3/linux/drivers/usb/usb.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/usb/usb.c	Wed Apr 25 14:10:47 2001
@@ -2,7 +2,7 @@
  * drivers/usb/usb.c
  *
  * (C) Copyright Linus Torvalds 1999
- * (C) Copyright Johannes Erdfelt 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
  * (C) Copyright Andreas Gal 1999
  * (C) Copyright Gregory P. Smith 1999
  * (C) Copyright Deti Fliegl 1999 (new USB architecture)
@@ -18,8 +18,6 @@
  * Think of this as a "USB library" rather than anything else.
  * It should be considered a slave, with no callbacks. Callbacks
  * are evil.
- *
- * $Id: usb.c,v 1.53 2000/01/14 16:19:09 acher Exp $
  */
 
 #include <linux/config.h>
@@ -340,6 +338,17 @@
 	urb->bandwidth = 0;
 }
 
+static void usb_bus_get(struct usb_bus *bus)
+{
+	atomic_inc(&bus->refcnt);
+}
+
+static void usb_bus_put(struct usb_bus *bus)
+{
+	if (atomic_dec_and_test(&bus->refcnt))
+		kfree(bus);
+}
+
 /**
  *	usb_alloc_bus - creates a new USB host controller structure
  *	@op: pointer to a struct usb_operations that this bus structure should use
@@ -377,6 +386,8 @@
 	INIT_LIST_HEAD(&bus->bus_list);
 	INIT_LIST_HEAD(&bus->inodes);
 
+	atomic_set(&bus->refcnt, 1);
+
 	return bus;
 }
 
@@ -391,7 +402,7 @@
 	if (!bus)
 		return;
 
-	kfree(bus);
+	usb_bus_put(bus);
 }
 
 /**
@@ -411,6 +422,8 @@
 	} else
 		warn("too many buses");
 
+	usb_bus_get(bus);
+
 	/* Add it to the list of buses */
 	list_add(&bus->bus_list, &usb_bus_list);
 
@@ -439,6 +452,8 @@
         usbdevfs_remove_bus(bus);
 
 	clear_bit(bus->busnum, busmap.busmap);
+
+	usb_bus_put(bus);
 }
 
 /*
@@ -902,6 +917,8 @@
 
 	memset(dev, 0, sizeof(*dev));
 
+	usb_bus_get(bus);
+
 	dev->bus = bus;
 	dev->parent = parent;
 	atomic_set(&dev->refcnt, 1);
@@ -918,6 +935,9 @@
 	if (atomic_dec_and_test(&dev->refcnt)) {
 		dev->bus->op->deallocate(dev);
 		usb_destroy_configuration(dev);
+
+		usb_bus_put(dev->bus);
+
 		kfree(dev);
 	}
 }
diff -u --recursive --new-file v2.4.3/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.4.3/linux/drivers/video/Config.in	Thu Jan  4 13:00:55 2001
+++ linux/drivers/video/Config.in	Fri Apr 13 20:31:32 2001
@@ -98,6 +98,14 @@
          bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
       fi
    fi
+   bool '  Epson 1355 framebuffer support' CONFIG_FB_E1355
+   if [ "$CONFIG_FB_E1355" = "y" ]; then
+      hex '    Register Base Address' CONFIG_E1355_REG_BASE a8000000
+      hex '    Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
+   fi
+   if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+      tristate '  Dreamcast Frame Buffer support' CONFIG_FB_DC
+   fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
diff -u --recursive --new-file v2.4.3/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.4.3/linux/drivers/video/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/drivers/video/Makefile	Fri Apr 13 20:31:32 2001
@@ -100,6 +100,8 @@
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
 obj-$(CONFIG_FB_HIT)              += hitfb.o fbgen.o
+obj-$(CONFIG_FB_E1355)            += epson1355fb.o fbgen.o
+obj-$(CONFIG_FB_DC)               += dcfb.o fbgen.o
 
 # Generic Low Level Drivers
 
diff -u --recursive --new-file v2.4.3/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.4.3/linux/drivers/video/acornfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/acornfb.c	Wed Apr 18 11:49:12 2001
@@ -263,28 +263,28 @@
 	vidc.v_border_end	= vidc.v_display_end;
 
 #ifdef CONFIG_ARCH_A5K
-	outb(vid_ctl, IOEB_VID_CTL);
+	__raw_writeb(vid_ctl, IOEB_VID_CTL);
 #endif
 	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
 		current_vidc = vidc;
 
-		outl(0xe0000000 | vidc_ctl,			IO_VIDC_BASE);
-		outl(0x80000000 | (vidc.h_cycle << 14),		IO_VIDC_BASE);
-		outl(0x84000000 | (vidc.h_sync_width << 14),	IO_VIDC_BASE);
-		outl(0x88000000 | (vidc.h_border_start << 14),	IO_VIDC_BASE);
-		outl(0x8c000000 | (vidc.h_display_start << 14),	IO_VIDC_BASE);
-		outl(0x90000000 | (vidc.h_display_end << 14),	IO_VIDC_BASE);
-		outl(0x94000000 | (vidc.h_border_end << 14),	IO_VIDC_BASE);
-		outl(0x98000000,				IO_VIDC_BASE);
-		outl(0x9c000000 | (vidc.h_interlace << 14),	IO_VIDC_BASE);
-		outl(0xa0000000 | (vidc.v_cycle << 14),		IO_VIDC_BASE);
-		outl(0xa4000000 | (vidc.v_sync_width << 14),	IO_VIDC_BASE);
-		outl(0xa8000000 | (vidc.v_border_start << 14),	IO_VIDC_BASE);
-		outl(0xac000000 | (vidc.v_display_start << 14),	IO_VIDC_BASE);
-		outl(0xb0000000 | (vidc.v_display_end << 14),	IO_VIDC_BASE);
-		outl(0xb4000000 | (vidc.v_border_end << 14),	IO_VIDC_BASE);
-		outl(0xb8000000,				IO_VIDC_BASE);
-		outl(0xbc000000,				IO_VIDC_BASE);
+		vidc_writel(0xe0000000 | vidc_ctl);
+		vidc_writel(0x80000000 | (vidc.h_cycle << 14));
+		vidc_writel(0x84000000 | (vidc.h_sync_width << 14));
+		vidc_writel(0x88000000 | (vidc.h_border_start << 14));
+		vidc_writel(0x8c000000 | (vidc.h_display_start << 14));
+		vidc_writel(0x90000000 | (vidc.h_display_end << 14));
+		vidc_writel(0x94000000 | (vidc.h_border_end << 14));
+		vidc_writel(0x98000000);
+		vidc_writel(0x9c000000 | (vidc.h_interlace << 14));
+		vidc_writel(0xa0000000 | (vidc.v_cycle << 14));
+		vidc_writel(0xa4000000 | (vidc.v_sync_width << 14));
+		vidc_writel(0xa8000000 | (vidc.v_border_start << 14));
+		vidc_writel(0xac000000 | (vidc.v_display_start << 14));
+		vidc_writel(0xb0000000 | (vidc.v_display_end << 14));
+		vidc_writel(0xb4000000 | (vidc.v_border_end << 14));
+		vidc_writel(0xb8000000);
+		vidc_writel(0xbc000000);
 	}
 #ifdef DEBUG_MODE_SELECTION
 	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
@@ -310,7 +310,7 @@
 static inline void
 acornfb_palette_write(u_int regno, union palette pal)
 {
-	outl(pal.p, IO_VIDC_BASE);
+	vidc_writel(pal.p);
 }
 
 static inline union palette
@@ -402,27 +402,27 @@
 	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
 		current_vidc = vidc;
 
-		outl(VIDC20_CTRL| vidc.control,		IO_VIDC_BASE);
-		outl(0xd0000000 | vidc.pll_ctl,		IO_VIDC_BASE);
-		outl(0x80000000 | vidc.h_cycle,		IO_VIDC_BASE);
-		outl(0x81000000 | vidc.h_sync_width,	IO_VIDC_BASE);
-		outl(0x82000000 | vidc.h_border_start,	IO_VIDC_BASE);
-		outl(0x83000000 | vidc.h_display_start,	IO_VIDC_BASE);
-		outl(0x84000000 | vidc.h_display_end,	IO_VIDC_BASE);
-		outl(0x85000000 | vidc.h_border_end,	IO_VIDC_BASE);
-		outl(0x86000000,			IO_VIDC_BASE);
-		outl(0x87000000 | vidc.h_interlace,	IO_VIDC_BASE);
-		outl(0x90000000 | vidc.v_cycle,		IO_VIDC_BASE);
-		outl(0x91000000 | vidc.v_sync_width,	IO_VIDC_BASE);
-		outl(0x92000000 | vidc.v_border_start,	IO_VIDC_BASE);
-		outl(0x93000000 | vidc.v_display_start,	IO_VIDC_BASE);
-		outl(0x94000000 | vidc.v_display_end,	IO_VIDC_BASE);
-		outl(0x95000000 | vidc.v_border_end,	IO_VIDC_BASE);
-		outl(0x96000000,			IO_VIDC_BASE);
-		outl(0x97000000,			IO_VIDC_BASE);
+		vidc_writel(VIDC20_CTRL| vidc.control);
+		vidc_writel(0xd0000000 | vidc.pll_ctl);
+		vidc_writel(0x80000000 | vidc.h_cycle);
+		vidc_writel(0x81000000 | vidc.h_sync_width);
+		vidc_writel(0x82000000 | vidc.h_border_start);
+		vidc_writel(0x83000000 | vidc.h_display_start);
+		vidc_writel(0x84000000 | vidc.h_display_end);
+		vidc_writel(0x85000000 | vidc.h_border_end);
+		vidc_writel(0x86000000);
+		vidc_writel(0x87000000 | vidc.h_interlace);
+		vidc_writel(0x90000000 | vidc.v_cycle);
+		vidc_writel(0x91000000 | vidc.v_sync_width);
+		vidc_writel(0x92000000 | vidc.v_border_start);
+		vidc_writel(0x93000000 | vidc.v_display_start);
+		vidc_writel(0x94000000 | vidc.v_display_end);
+		vidc_writel(0x95000000 | vidc.v_border_end);
+		vidc_writel(0x96000000);
+		vidc_writel(0x97000000);
 	}
 
-	outl(fsize, IOMD_FSIZE);
+	iomd_writel(fsize, IOMD_FSIZE);
 
 	ext_ctl = acornfb_default_econtrol();
 
@@ -440,7 +440,7 @@
 			ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
 	}
 
-	outl(VIDC20_ECTL | ext_ctl, IO_VIDC_BASE);
+	vidc_writel(VIDC20_ECTL | ext_ctl);
 
 	words_per_line = var->xres * var->bits_per_pixel / 32;
 
@@ -461,7 +461,7 @@
 	} else 
 		dat_ctl |= VIDC20_DCTL_BUS_D31_0;
 
-	outl(VIDC20_DCTL | dat_ctl, IO_VIDC_BASE);
+	vidc_writel(VIDC20_DCTL | dat_ctl);
 
 #ifdef DEBUG_MODE_SELECTION
 	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
@@ -490,8 +490,8 @@
 static inline void
 acornfb_palette_write(u_int regno, union palette pal)
 {
-	outl(0x10000000 | regno, IO_VIDC_BASE);
-	outl(pal.p, IO_VIDC_BASE);
+	vidc_writel(0x10000000 | regno);
+	vidc_writel(pal.p);
 }
 
 static inline union palette
@@ -672,7 +672,7 @@
 #if defined(HAS_MEMC)
 	memc_write(VDMA_INIT, off >> 2);
 #elif defined(HAS_IOMD)
-	outl(current_par.screen_base_p + off, IOMD_VIDINIT);
+	iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT);
 #endif
 }
 
@@ -744,12 +744,12 @@
 		int i;
 
 		pal.p = 0;
-		outl(0x10000000, IO_VIDC_BASE);
+		vidc_writel(0x10000000);
 		for (i = 0; i < 256; i += 1) {
 			pal.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;
 			pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
 			pal.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
-			outl(pal.p, IO_VIDC_BASE);
+			vidc_writel(pal.p);
 			/* Palette register pointer auto-increments */
 		}
 	} else
@@ -1074,9 +1074,9 @@
 			control = DMA_CR_E | DMA_CR_D | 16;
 		}
 
-		outl(start,   IOMD_VIDSTART);
-		outl(size,    IOMD_VIDEND);
-		outl(control, IOMD_VIDCR);
+		iomd_writel(start,   IOMD_VIDSTART);
+		iomd_writel(size,    IOMD_VIDEND);
+		iomd_writel(control, IOMD_VIDCR);
 #endif
 		acornfb_update_dma(var);
 		acornfb_set_timing(var);
@@ -1119,6 +1119,45 @@
 	return 0;
 }
 
+/*
+ * Note that we are entered with the kernel locked.
+ */
+static int
+acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long off, start;
+	u32 len;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	start = current_par.screen_base_p;
+	len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size;
+	start &= PAGE_MASK;
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
+
+#ifdef CONFIG_CPU_32
+	pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE;
+#endif
+
+	/*
+	 * Don't alter the page protection flags; we want to keep the area
+	 * cached for better performance.  This does mean that we may miss
+	 * some updates to the screen occasionally, but process switches
+	 * should cause the caches and buffers to be flushed often enough.
+	 */
+	if (io_remap_page_range(vma->vm_start, off,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+		return -EAGAIN;
+	return 0;
+}
+
 static struct fb_ops acornfb_ops = {
 	owner:		THIS_MODULE,
 	fb_get_fix:	acornfb_get_fix,
@@ -1127,6 +1166,7 @@
 	fb_get_cmap:	acornfb_get_cmap,
 	fb_set_cmap:	acornfb_set_cmap,
 	fb_pan_display:	acornfb_pan_display,
+	fb_mmap:	acornfb_mmap,
 };
 
 static int
diff -u --recursive --new-file v2.4.3/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.4.3/linux/drivers/video/amifb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/amifb.c	Wed Apr 18 11:49:12 2001
@@ -256,7 +256,7 @@
       - for horizontal panning decrease diwstrt_h
       - the length of a fetchline must be aligned to fetchsize (table 3)
       - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
-        moved to optimize use of dma (usefull for OCS/ECS overscan displays)
+        moved to optimize use of dma (useful for OCS/ECS overscan displays)
       - ddfstop is ddfstrt+ddfsize-fetchsize
       - If C= didn't change anything for AGA, then at following positions the
         dma bus is allready used:
@@ -2106,7 +2106,7 @@
 			return -EINVAL;
 		}
 		if (par->diwstop_v > par->vtotal) {
-			DPRINTK("invaild diwstop_v\n");
+			DPRINTK("invalid diwstop_v\n");
 			return -EINVAL;
 		}
 
diff -u --recursive --new-file v2.4.3/linux/drivers/video/atafb.c linux/drivers/video/atafb.c
--- v2.4.3/linux/drivers/video/atafb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/atafb.c	Wed Apr 18 11:49:12 2001
@@ -208,7 +208,7 @@
 
 /*
 The MV300 mixes the color registers. So we need an array of munged
-indices in order to acces the correct reg.
+indices in order to access the correct reg.
 */
 static int MV300_reg_1bit[2]={0,1};
 static int MV300_reg_4bit[16]={
diff -u --recursive --new-file v2.4.3/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.4.3/linux/drivers/video/atyfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/atyfb.c	Thu Apr 12 12:10:25 2001
@@ -3144,51 +3144,6 @@
 
 	vma->vm_pgoff = off >> PAGE_SHIFT;	/* propagate off changes */
 
-#ifdef __sparc_v9__
-	/* Align it as much as desirable */
-	{
-		unsigned long j, align;
-		int max = -1;
-
-		map_offset = off + size;
-		for (i = 0; fb->mmap_map[i].size; i++) {
-			if (fb->mmap_map[i].voff < off)
-				continue;
-			if (fb->mmap_map[i].voff >= map_offset)
-				break;
-			if (max < 0 ||
-			    fb->mmap_map[i].size > fb->mmap_map[max].size)
-				max = i;
-		}
-		if (max >= 0) {
-			j = fb->mmap_map[max].size;
-			if (fb->mmap_map[max].voff + j > map_offset)
-				j = map_offset - fb->mmap_map[max].voff;
-			for (align = 0x400000; align > PAGE_SIZE; align >>= 3)
-				if (j >= align &&
-				    !(fb->mmap_map[max].poff & (align - 1)))
-					break;
-			if (align > PAGE_SIZE) {
-				j = align;
-				align = j - ((vma->vm_start
-					      + fb->mmap_map[max].voff
-					      - off) & (j - 1));
-				if (align != j) {
-					struct vm_area_struct *vmm;
-
-					vmm = find_vma(current->mm,
-						       vma->vm_start);
-					if (!vmm || vmm->vm_start
-						    >= vma->vm_end + align) {
-						vma->vm_start += align;
-						vma->vm_end += align;
-					}
-				}
-			}
-		}
-	}
-#endif
-
 	/* Each page, see which map applies */
 	for (page = 0; page < size; ) {
 		map_size = 0;
diff -u --recursive --new-file v2.4.3/linux/drivers/video/dcfb.c linux/drivers/video/dcfb.c
--- v2.4.3/linux/drivers/video/dcfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/dcfb.c	Fri Apr 13 20:31:32 2001
@@ -0,0 +1,504 @@
+/*
+ *	$Id: dcfb.c,v 1.1 2001/04/01 15:02:51 yaegashi Exp $
+ *	SEGA Dreamcast framebuffer
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/nubus.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <linux/fb.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#define BORDERRGB	0xa05f8040
+#define DISPLAYMODE	0xa05f8044
+#define ALPHAMODE	0xa05f8048
+#define DISPLAYALIGN	0xa05f804c
+#define BASEOFFSET1	0xa05f8050
+#define BASEOFFSET2	0xa05f8054
+#define DISPLAYSIZE	0xa05f805c
+#define SYNCMODE	0xa05f80d0
+#define VERTICALRANGE	0xa05f80dc
+#define HORIZPOSITION	0xa05f80ec
+#define VERTPOSITION	0xa05f80f0
+#define PALETTEMODE	0xa05f8108
+#define VIDEOOUTPUT	0xa0702c00
+
+static unsigned long dc_parm_vga_16bpp[] = {
+    DISPLAYMODE,	0x00800005,
+    BASEOFFSET1,	0,
+    BASEOFFSET2,	640*2,
+    DISPLAYSIZE,	(1<<20)+((480-1)<<10)+(640*2/4-1),
+    SYNCMODE,		0x100,
+    VERTPOSITION,	0x00230023,
+    VERTICALRANGE,	0x00280208,
+    HORIZPOSITION,	0x00000090,
+    VIDEOOUTPUT,	0,
+    0, 0,
+};
+    
+static unsigned long dc_parm_vga_32bpp[] = {
+    DISPLAYMODE,	0x0080000d,
+    BASEOFFSET1,	0,
+    BASEOFFSET2,	640*4,
+    DISPLAYSIZE,	(1<<20)+((480-1)<<10)+(640*4/4-1),
+    SYNCMODE,		0x100,
+    VERTPOSITION,	0x00230023,
+    VERTICALRANGE,	0x00280208,
+    HORIZPOSITION,	0x00000090,
+    VIDEOOUTPUT,	0,
+    0, 0,
+};
+
+static unsigned long *dc_parm_vga[] = {
+    dc_parm_vga_16bpp,
+    dc_parm_vga_32bpp,
+};
+
+static unsigned long dc_parm_composite_16bpp[] = {
+    DISPLAYMODE,	0x00000005,
+    BASEOFFSET1,	0,
+    BASEOFFSET2,	640*2,
+    DISPLAYSIZE,	((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
+    SYNCMODE,		0x150,
+    VERTPOSITION,	0x00120012,
+    VERTICALRANGE,	0x00240204,
+    HORIZPOSITION,	0x000000a4,
+    VIDEOOUTPUT,	0x300,
+    0, 0,
+};
+    
+static unsigned long dc_parm_composite_32bpp[] = {
+    DISPLAYMODE,	0x0000000d,
+    BASEOFFSET1,	0,
+    BASEOFFSET2,	640*4,
+    DISPLAYSIZE,	((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
+    SYNCMODE,		0x150,
+    VERTPOSITION,	0x00120012,
+    VERTICALRANGE,	0x00240204,
+    HORIZPOSITION,	0x000000a4,
+    VIDEOOUTPUT,	0x300,
+    0, 0,
+};
+
+static unsigned long *dc_parm_composite[] = {
+    dc_parm_composite_16bpp,
+    dc_parm_composite_32bpp,
+};
+
+static unsigned long dc_parm_interlace_16bpp[] = {
+    DISPLAYMODE,	0x00000005,
+    BASEOFFSET1,	0,
+    BASEOFFSET2,	640*2,
+    DISPLAYSIZE,	((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
+    SYNCMODE,		0x150,
+    VERTPOSITION,	0x00120012,
+    VERTICALRANGE,	0x00240204,
+    HORIZPOSITION,	0x000000a4,
+    VIDEOOUTPUT,	0,
+    0, 0,
+};
+    
+static unsigned long dc_parm_interlace_32bpp[] = {
+    DISPLAYMODE,	0x0000000d,
+    BASEOFFSET1,	0,
+    BASEOFFSET2,	640*4,
+    DISPLAYSIZE,	((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
+    SYNCMODE,		0x150,
+    VERTPOSITION,	0x00120012,
+    VERTICALRANGE,	0x00240204,
+    HORIZPOSITION,	0x000000a4,
+    VIDEOOUTPUT,	0,
+    0, 0,
+};
+
+static unsigned long *dc_parm_interlace[] = {
+    dc_parm_interlace_16bpp,
+    dc_parm_interlace_32bpp,
+};
+
+struct dcfb_info {
+    struct fb_info_gen gen;
+};
+
+struct dcfb_par
+{
+    int x, y;
+    int bpp;
+};
+
+static struct dcfb_info fb_info;
+static struct dcfb_par current_par;
+static int current_par_valid = 0;
+static struct display disp;
+
+static union {
+#ifdef FBCON_HAS_CFB16
+    u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+    u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+static unsigned long **dc_parms;
+static unsigned long dc_videobase, dc_videosize;
+static struct fb_var_screeninfo default_var;
+
+int dcfb_init(void);
+
+static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info);
+static void dcfb_encode_var(struct fb_var_screeninfo *var, 
+			      struct dcfb_par *par,
+			      const struct fb_info *info);
+
+
+/*
+ *	Check cable type.
+ *	0: VGA, 2: RGB, 3: Composite
+ */
+
+#define	PCTRA	0xff80002c
+#define PDTRA	0xff800030
+
+static int dcfb_cable_check(void)
+{
+    unsigned long temp = ctrl_inl(PCTRA);
+    temp &= 0xfff0ffff;
+    temp |= 0x000a0000;
+    ctrl_outl(temp, PCTRA);
+    return (ctrl_inw(PDTRA)>>8)&3;
+}
+
+static void dcfb_detect(void)
+{
+    struct dcfb_par par;
+    int cable = dcfb_cable_check();
+    unsigned long **parm_list[4] = {
+	dc_parm_vga, dc_parm_vga, dc_parm_interlace, dc_parm_composite,
+    };
+    char *cable_name[] = { "VGA", "VGA", "Interlace", "Composite", };
+
+    dc_videobase = 0xa5000000;
+    dc_videosize = 0x00200000;
+
+    par.x = 640;
+    par.y = 480;
+    par.bpp = 32;
+    dc_parms = parm_list[cable];
+    printk(KERN_INFO "Dreamcast video cable detected: %s.\n", cable_name[cable]);
+
+    dcfb_set_par(&par, NULL);
+    dcfb_encode_var(&default_var, &par, NULL);
+}
+
+static int dcfb_encode_fix(struct fb_fix_screeninfo *fix,
+			    struct dcfb_par *par,
+			    const struct fb_info *info)
+{
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+    strcpy(fix->id, "SEGA Dreamcast");
+    fix->smem_start = dc_videobase;
+    fix->smem_len = dc_videosize;
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
+    fix->visual = FB_VISUAL_TRUECOLOR;
+    fix->xpanstep = 0;
+    fix->ypanstep = 0;
+    fix->ywrapstep = 0;
+
+    switch(par->bpp) {
+    default:
+    case 16:
+	fix->line_length = par->x*2;
+	break;
+    case 32:
+	fix->line_length = par->x*4;
+	break;
+    }
+
+    return 0;
+}
+
+
+static int dcfb_decode_var(struct fb_var_screeninfo *var,
+			    struct dcfb_par *par,
+			    const struct fb_info *info)
+{
+    par->x = var->xres;
+    par->y = var->yres;
+    par->bpp = var->bits_per_pixel;
+    return 0;
+}
+
+
+static void dcfb_encode_var(struct fb_var_screeninfo *var, 
+			     struct dcfb_par *par,
+			     const struct fb_info *info)
+{
+    memset(var, 0, sizeof(*var));
+
+    var->xres = par->x;
+    var->yres = par->y;
+    var->xres_virtual = var->xres;
+    var->yres_virtual = var->yres;
+    var->xoffset = 0;
+    var->yoffset = 0;
+    var->bits_per_pixel = par->bpp;
+    var->grayscale = 0;
+    var->transp.offset = 0;
+    var->transp.length = 0;
+    var->transp.msb_right = 0;
+    var->nonstd = 0;
+    var->activate = 0;
+    var->height = -1;
+    var->width = -1;
+    var->vmode = FB_VMODE_NONINTERLACED;
+    var->pixclock = 0;
+    var->sync = 0;
+    var->left_margin = 0;
+    var->right_margin = 0;
+    var->upper_margin = 0;
+    var->lower_margin = 0;
+    var->hsync_len = 0;
+    var->vsync_len = 0;
+
+    switch (var->bits_per_pixel) {
+
+	case 16:	/* RGB 565 */
+	    var->red.offset = 11;
+	    var->red.length = 5;
+	    var->green.offset = 5;
+	    var->green.length = 6;
+	    var->blue.offset = 0;
+	    var->blue.length = 5;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+
+	case 32:
+	    var->red.offset = 16;
+	    var->red.length = 8;
+	    var->green.offset = 8;
+	    var->green.length = 8;
+	    var->blue.offset = 0;
+	    var->blue.length = 8;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+
+    }
+
+    var->red.msb_right = 0;
+    var->green.msb_right = 0;
+    var->blue.msb_right = 0;
+    var->transp.msb_right = 0;
+}
+
+
+static void dcfb_get_par(struct dcfb_par *par, const struct fb_info *info)
+{
+    *par = current_par;
+}
+
+
+static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info)
+{
+    unsigned long a, d, *p;
+
+    current_par = *par;
+    current_par_valid = 1;
+
+    switch(par->bpp) {
+    default:
+    case 16:
+	p = dc_parms[0];
+	break;
+    case 32:
+	p = dc_parms[1];
+	break;
+    }
+
+    ctrl_outl(0, 0xa05f8008);	/* reset? */
+    ctrl_outl(0, BORDERRGB);
+
+    while(1) {
+	a = *p++; d = *p++;
+	if (!a) break;
+	ctrl_outl(d, a);
+    }
+
+}
+
+static struct {
+  u_int red, green, blue;
+} palette[256];
+
+static int dcfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp, struct fb_info *info)
+{
+    if (regno > 255)
+	return 1;	
+
+    *red = palette[regno].red;
+    *green = palette[regno].green;
+    *blue = palette[regno].blue;
+    *transp = 0;
+    
+    return 0;
+}
+
+
+static int dcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *info)
+{
+    if (regno > 255)
+	return 1;
+
+    palette[regno].red = red;
+    palette[regno].green = green;
+    palette[regno].blue = blue;
+    
+    if(regno<16) {
+	switch(current_par.bpp) {
+#ifdef FBCON_HAS_CFB16
+	case 16:
+	    fbcon_cmap.cfb16[regno] =
+		((red   & 0xf800)      ) |
+		((green & 0xfc00) >>  5) |
+		((blue  & 0xf800) >> 11);
+	    break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+	    fbcon_cmap.cfb32[regno] =
+		((red   & 0xff00) <<  8) |
+		((green & 0xff00)      ) |
+		((blue  & 0xff00) >>  8);
+	    break;
+#endif
+	}
+    }
+
+    return 0;
+}
+
+static int dcfb_blank(int blank_mode, const struct fb_info *info)
+{
+    return 0;
+}
+
+
+static void dcfb_set_disp(const void *par, struct display *disp,
+			   struct fb_info_gen *info)
+{
+    disp->screen_base = (void *)dc_videobase;
+    disp->scrollmode = SCROLL_YREDRAW;
+
+    switch(((struct dcfb_par *)par)->bpp) {
+#ifdef FBCON_HAS_CFB16
+    case 16:
+	disp->dispsw = &fbcon_cfb16;
+	disp->dispsw_data = fbcon_cmap.cfb16;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+	disp->dispsw = &fbcon_cfb32;
+	disp->dispsw_data = fbcon_cmap.cfb32;
+	break;
+#endif
+    default:
+	disp->dispsw = &fbcon_dummy;
+    }
+}
+
+
+struct fbgen_hwswitch dcfb_switch = {
+    dcfb_detect,
+    dcfb_encode_fix,
+    dcfb_decode_var,
+    dcfb_encode_var,
+    dcfb_get_par,
+    dcfb_set_par,
+    dcfb_getcolreg,
+    dcfb_setcolreg,
+    NULL,
+    dcfb_blank,
+    dcfb_set_disp
+};
+
+static struct fb_ops dcfb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+};
+
+
+int __init dcfb_init(void)
+{
+    strcpy(fb_info.gen.info.modename, "SEGA Dreamcast");
+    fb_info.gen.info.node = -1;
+    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+    fb_info.gen.info.fbops = &dcfb_ops;
+    fb_info.gen.info.disp = &disp;
+    fb_info.gen.info.changevar = NULL;
+    fb_info.gen.info.switch_con = &fbgen_switch;
+    fb_info.gen.info.updatevar = &fbgen_update_var;
+    fb_info.gen.info.blank = &fbgen_blank;
+    fb_info.gen.parsize = sizeof(struct dcfb_par);
+    fb_info.gen.fbhw = &dcfb_switch;
+    fb_info.gen.fbhw->detect();
+    
+    fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+    disp.var.activate = FB_ACTIVATE_NOW;
+    fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+    fbgen_set_disp(-1, &fb_info.gen);
+    fbgen_install_cmap(0, &fb_info.gen);
+    
+    if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL;
+    
+    printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	   GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
+    
+    return 0;
+}
+
+
+void dcfb_cleanup(struct fb_info *info)
+{
+    unregister_framebuffer(info);
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+    return dcfb_init();
+}
+
+void cleanup_module(void)
+{
+    dcfb_cleanup(void);
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/drivers/video/epson1355fb.c linux/drivers/video/epson1355fb.c
--- v2.4.3/linux/drivers/video/epson1355fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/epson1355fb.c	Fri Apr 13 20:31:32 2001
@@ -0,0 +1,539 @@
+/*
+ * linux/drivers/video/epson1355fb.c
+ *	-- Support for the Epson SED1355 LCD/CRT controller
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ * based on linux/drivers/video/skeletonfb.c, which was
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+/* TODO (roughly in order of priority):
+ * 16 bpp support
+ * crt support
+ * hw cursor support
+ * SwivelView
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon.h>
+
+/* Register defines.  The docs don't seem to provide nice mnemonic names
+ * so I made them up myself ... */
+
+#define E1355_PANEL	0x02
+#define E1355_DISPLAY	0x0D
+#define E1355_MISC	0x1B
+#define E1355_GPIO	0x20
+#define E1355_LUT_INDEX 0x24
+#define E1355_LUT_DATA	0x26
+
+#ifdef CONFIG_SUPERH
+#define E1355_REG_BASE	CONFIG_E1355_REG_BASE
+#define E1355_FB_BASE	CONFIG_E1355_FB_BASE
+
+static inline u8 e1355_read_reg(int index)
+{
+	return ctrl_inb(E1355_REG_BASE + index);
+}
+
+static inline void e1355_write_reg(u8 data, int index)
+{
+	ctrl_outb(data, E1355_REG_BASE + index);
+}
+
+static inline u16 e1355_read_reg16(int index)
+{
+	return e1355_read_reg(index) + (e1355_read_reg(index+1) << 8);
+}
+
+static inline void e1355_write_reg16(u16 data, int index)
+{
+	e1355_write_reg((data&0xff), index);
+	e1355_write_reg(((data>>8)&0xff), index + 1);
+}
+#else
+#error unknown architecture
+#endif
+
+struct e1355fb_info {
+	struct fb_info_gen gen;
+};
+
+static int current_par_valid = 0;
+static struct display disp;
+
+static struct fb_var_screeninfo default_var;
+
+int e1355fb_init(void);
+int e1355fb_setup(char*);
+static int e1355_encode_var(struct fb_var_screeninfo *var, const void *par,
+			    struct fb_info_gen *info);
+/* ------------------- chipset specific functions -------------------------- */
+
+
+static void disable_hw_cursor(void)
+{
+	u8 curs;
+
+	curs = e1355_read_reg(0x27);
+	curs &= ~0xc0;
+	e1355_write_reg(curs, 0x27);
+}
+
+static void e1355_detect(void)
+{
+	u8 rev;
+
+	e1355_write_reg(0x00, E1355_MISC);
+
+	rev = e1355_read_reg(0x00);
+
+	if ((rev & 0xfc) != 0x0c) {
+		printk(KERN_WARNING "Epson 1355 not detected\n");
+	}
+
+	/* XXX */
+	disable_hw_cursor();
+
+	e1355_encode_var(&default_var, NULL, NULL);
+}
+
+struct e1355_par {
+	u32 xres;
+	u32 yres;
+
+	int bpp;
+	int mem_bpp;
+
+	u32 panel_xres;
+	u32 panel_yres;
+	
+	int panel_width;
+	int panel_ymul;
+};
+
+static int e1355_encode_fix(struct fb_fix_screeninfo *fix,
+			    const void *raw_par,
+			    struct fb_info_gen *info)
+{
+	const struct e1355_par *par = raw_par;
+	
+	memset(fix, 0, sizeof *fix);
+	
+	fix->type= FB_TYPE_PACKED_PIXELS;
+
+	if (!par)
+		BUG();
+
+	if (par->bpp == 1) {
+		fix->visual = FB_VISUAL_MONO10;
+	} else if (par->bpp <= 8) {
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	} else {
+		fix->visual = FB_VISUAL_TRUECOLOR;
+	}
+
+	return 0;
+}
+
+static int e1355_set_bpp(struct e1355_par *par, int bpp)
+{
+	int code;
+	u8 disp;
+	u16 bytes_per_line;
+
+	switch(bpp) {
+	case 1:
+		code = 0; break;
+	case 2:
+		code = 1; break;
+	case 4:
+		code = 2; break;
+	case 8:
+		code = 3; break;
+	case 16:
+		code = 5; break;
+	default:
+		return -EINVAL; break;
+	}
+
+	disp = e1355_read_reg(E1355_DISPLAY);
+	disp &= ~0x1c;
+	disp |= code << 2;
+	e1355_write_reg(disp, E1355_DISPLAY);
+	
+	bytes_per_line = (par->xres * bpp) >> 3;
+	
+	e1355_write_reg16(bytes_per_line, 0x16);
+
+	par->bpp = bpp;
+
+	return 0;
+}
+		
+static int e1355_decode_var(const struct fb_var_screeninfo *var,
+			    void *raw_par,
+			    struct fb_info_gen *info)
+{
+	struct e1355_par *par = raw_par;
+	int ret;
+
+	if (!par)
+		BUG();
+
+	/*
+	 * Don't allow setting any of these yet: xres and yres don't
+	 * make sense for LCD panels; xres_virtual and yres_virtual
+	 * should be supported fine by our hardware though.
+	 */
+	if (var->xres != par->xres ||
+	    var->yres != par->yres ||
+	    var->xres != var->xres_virtual ||
+	    var->yres != var->yres_virtual ||
+	    var->xoffset != 0 ||
+	    var->yoffset != 0)
+		return -EINVAL;
+
+	if(var->bits_per_pixel != par->bpp) {
+		ret = e1355_set_bpp(par, var->bits_per_pixel);
+
+		if (ret)
+			goto out_err;
+	}
+		
+	return 0;
+
+ out_err:
+	return ret;
+}
+
+static void dump_panel_data(void)
+{
+	u8 panel = e1355_read_reg(E1355_PANEL);
+	int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+
+	printk("%s %s %s panel, width %d bits\n",
+	       panel & 2 ? "dual" : "single",
+	       panel & 4 ? "color" : "mono",
+	       panel & 1 ? "TFT" : "passive",
+	       width[panel&1][(panel>>4)&3]);
+
+	printk("resolution %d x %d\n",
+	       (e1355_read_reg(0x04) + 1) * 8,
+	       ((e1355_read_reg16(0x08) + 1) * (1 + ((panel & 3) == 2))));
+}
+
+static int e1355_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
+{
+	switch(bpp) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		var->bits_per_pixel = bpp;
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = bpp;
+		break;
+	case 16:
+		var->bits_per_pixel = 16;
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		break;
+	}
+
+	return 0;
+}
+
+static int e1355_encode_var(struct fb_var_screeninfo *var, const void *raw_par,
+			    struct fb_info_gen *info)
+{
+	u8 panel, display;
+	u32 xres, xres_virtual, yres;
+	static int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+	static int bpp_tab[8] = { 1, 2, 4, 8, 15, 16 };
+	int bpp, hw_bpp;
+	int is_color, is_dual, is_tft;
+	int lcd_enabled, crt_enabled;
+
+	panel = e1355_read_reg(E1355_PANEL);
+	display = e1355_read_reg(E1355_DISPLAY);
+
+	is_color = (panel & 0x04) != 0;
+	is_dual  = (panel & 0x02) != 0;
+	is_tft   = (panel & 0x01) != 0;
+
+	bpp = bpp_tab[(display>>2)&7]; 
+	e1355_bpp_to_var(bpp, var);
+
+	crt_enabled = (display & 0x02) != 0;
+	lcd_enabled = (display & 0x02) != 0;
+
+	hw_bpp = width[is_tft][(panel>>4)&3];
+
+	xres = e1355_read_reg(0x04) + 1;
+	yres = e1355_read_reg16(0x08) + 1;
+	
+	xres *= 8;
+	/* talk about weird hardware .. */
+	yres *= (is_dual && !crt_enabled) ? 2 : 1;
+
+	xres_virtual = e1355_read_reg16(0x16);
+	/* it's in 2-byte words initially */
+	xres_virtual *= 16;
+	xres_virtual /= var->bits_per_pixel;
+
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = xres_virtual;
+	var->yres_virtual = yres;
+
+	var->xoffset = var->yoffset = 0;
+
+	var->grayscale = !is_color;
+	
+	return 0;
+}
+
+#define is_dual(panel) (((panel)&3)==2)
+
+static void get_panel_data(struct e1355_par *par)
+{
+	u8 panel;
+	int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+
+	panel = e1355_read_reg(E1355_PANEL);
+
+	par->panel_width = width[panel&1][(panel>>4)&3];
+	par->panel_xres = (e1355_read_reg(0x04) + 1) * 8;
+	par->panel_ymul = is_dual(panel) ? 2 : 1;
+	par->panel_yres = ((e1355_read_reg16(0x08) + 1)
+			   * par->panel_ymul);
+}
+
+static void e1355_get_par(void *raw_par, struct fb_info_gen *info)
+{
+	struct e1355_par *par = raw_par;
+
+	get_panel_data(par);
+}
+
+static void e1355_set_par(const void *par, struct fb_info_gen *info)
+{
+}
+
+static int e1355_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info)
+{
+	u8 r, g, b;
+
+	e1355_write_reg(regno, E1355_LUT_INDEX);
+	r = e1355_read_reg(E1355_LUT_DATA);
+	g = e1355_read_reg(E1355_LUT_DATA);
+	b = e1355_read_reg(E1355_LUT_DATA);
+
+	*red = r << 8;
+	*green = g << 8;
+	*blue = b << 8;
+
+	return 0;
+}
+
+static int e1355_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	u8 r = (red >> 8) & 0xf0;
+	u8 g = (green>>8) & 0xf0;
+	u8 b = (blue>> 8) & 0xf0;
+
+	e1355_write_reg(regno, E1355_LUT_INDEX);
+	e1355_write_reg(r, E1355_LUT_DATA);
+	e1355_write_reg(g, E1355_LUT_DATA);
+	e1355_write_reg(b, E1355_LUT_DATA);
+	
+	return 0;
+}
+
+static int e1355_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info)
+{
+	BUG();
+	
+	return -EINVAL;
+}
+
+/*
+ * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000.
+ * I'm not sure they aren't dangerous to the hardware, so be warned.
+ */
+#undef AERO_HACKS
+
+static int e1355_blank(int blank_mode, struct fb_info_gen *info)
+{
+	u8 disp;
+
+	switch (blank_mode) {
+	case VESA_NO_BLANKING:
+		disp = e1355_read_reg(E1355_DISPLAY);
+		disp |= 1;
+		e1355_write_reg(disp, E1355_DISPLAY);
+ 		
+#ifdef AERO_HACKS
+		e1355_write_reg(0x6, 0x20);
+#endif
+		break;
+
+	case VESA_VSYNC_SUSPEND:
+	case VESA_HSYNC_SUSPEND:
+	case VESA_POWERDOWN:
+		disp = e1355_read_reg(E1355_DISPLAY);
+		disp &= ~1;
+		e1355_write_reg(disp, E1355_DISPLAY);
+
+#ifdef AERO_HACKS
+		e1355_write_reg(0x0, 0x20);
+#endif
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct display_switch e1355_dispsw;
+
+static void e1355_set_disp(const void *unused, struct display *disp,
+			   struct fb_info_gen *info)
+{
+	struct display_switch *d;
+
+	disp->screen_base = (void *)E1355_FB_BASE;
+	disp->dispsw = &e1355_dispsw;
+	
+	switch(disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+	case 1:
+		d = &fbcon_mfb; break;
+#endif	       
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		d = &fbcon_cfb8; break;
+#endif
+	default:
+		BUG(); break;
+	}
+
+	memcpy(&e1355_dispsw, d, sizeof *d);
+
+	/* reading is terribly slow for us */
+#if 0 /* XXX: need to work out why this doesn't work */
+	e1355_dispsw.bmove = fbcon_redraw_bmove;
+#endif
+}
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+
+struct fbgen_hwswitch e1355_switch = {
+	detect:		e1355_detect,
+	encode_fix:	e1355_encode_fix,
+	decode_var:	e1355_decode_var,
+	encode_var:	e1355_encode_var,
+	get_par:	e1355_get_par,
+	set_par:	e1355_set_par,
+	getcolreg:	e1355_getcolreg,
+	setcolreg:	e1355_setcolreg,
+	pan_display:	e1355_pan_display,
+	blank:		e1355_blank,
+	set_disp:	e1355_set_disp,
+};
+
+
+/* ------------ Hardware Independent Functions ------------ */
+
+
+static struct fb_ops e1355fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+	fb_pan_display:	fbgen_pan_display,
+};
+
+static struct e1355fb_info fb_info;
+
+int __init e1355fb_setup(char *str)
+{
+	return 0;
+}
+
+int __init e1355fb_init(void)
+{
+	fb_info.gen.fbhw = &e1355_switch;
+	fb_info.gen.fbhw->detect();
+	strcpy(fb_info.gen.info.modename, "SED1355");
+	fb_info.gen.info.changevar = NULL;
+	fb_info.gen.info.node = -1;
+	fb_info.gen.info.fbops = &e1355fb_ops;
+	fb_info.gen.info.disp = &disp;
+	fb_info.gen.parsize = sizeof(struct e1355_par);
+	fb_info.gen.info.switch_con = &fbgen_switch;
+	fb_info.gen.info.updatevar = &fbgen_update_var;
+	fb_info.gen.info.blank = &fbgen_blank;
+	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+	/* This should give a reasonable default video mode */
+	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+	fbgen_set_disp(-1, &fb_info.gen);
+	if (disp.var.bits_per_pixel > 1) 
+		fbgen_install_cmap(0, &fb_info.gen);
+	if (register_framebuffer(&fb_info.gen.info) < 0)
+		return -EINVAL;
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
+	       fb_info.gen.info.modename);
+
+	return 0;
+}
+
+
+    /*
+     *  Cleanup
+     */
+
+void e1355fb_cleanup(struct fb_info *info)
+{
+	/*
+	 *  If your driver supports multiple boards, you should unregister and
+	 *  clean up all instances.
+	 */
+	
+	unregister_framebuffer(info);
+	/* ... */
+}
+
diff -u --recursive --new-file v2.4.3/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.4.3/linux/drivers/video/fbmem.c	Fri Mar  2 18:38:39 2001
+++ linux/drivers/video/fbmem.c	Wed Apr 25 16:31:16 2001
@@ -120,7 +120,10 @@
 extern int stifb_setup(char*);
 extern int radeonfb_init(void);
 extern int radeonfb_setup(char*);
-
+extern int e1355fb_init(void);
+extern int e1355fb_setup(char*);
+extern int dcfb_init(void);
+  
 static struct {
 	const char *name;
 	int (*init)(void);
@@ -264,6 +267,12 @@
 #ifdef CONFIG_FB_HIT
 	{ "hitfb", hitfb_init, NULL },
 #endif
+#ifdef CONFIG_FB_E1355
+	{ "e1355fb", e1355fb_init, e1355fb_setup },
+#endif
+#ifdef CONFIG_FB_DC
+	{ "dcfb", dcfb_init, NULL },
+#endif
 
 	/*
 	 * Generic drivers that don't use resource management (yet)
@@ -562,22 +571,6 @@
 	vma->vm_pgoff = off >> PAGE_SHIFT;
 #if defined(__sparc_v9__)
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
-	{
-		unsigned long align, j;
-		for (align = 0x400000; align > PAGE_SIZE; align >>= 3)
-			if (len >= align && !((start & ~PAGE_MASK) & (align - 1)))
-				break;
-		if (align > PAGE_SIZE && vma->vm_start & (align - 1)) {
-			/* align as much as possible */
-			struct vm_area_struct *vmm;
-			j = (-vma->vm_start) & (align - 1);
-			vmm = find_vma(current->mm, vma->vm_start);
-			if (!vmm || vmm->vm_start >= vma->vm_end + j) {
-				vma->vm_start += j;
-				vma->vm_end += j;
-			}
-		}
-	}
 	if (io_remap_page_range(vma->vm_start, off,
 				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
 		return -EAGAIN;
@@ -687,6 +680,9 @@
 	mmap:		fb_mmap,
 	open:		fb_open,
 	release:	fb_release,
+#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
+	get_unmapped_area: get_fb_unmapped_area,
+#endif
 };
 
 static devfs_handle_t devfs_handle;
diff -u --recursive --new-file v2.4.3/linux/drivers/video/hitfb.c linux/drivers/video/hitfb.c
--- v2.4.3/linux/drivers/video/hitfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/hitfb.c	Wed Apr 11 21:24:52 2001
@@ -22,9 +22,11 @@
 #include <linux/nubus.h>
 #include <linux/init.h>
 
+#include <asm/machvec.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
+#include <asm/hd64461.h>
 
 #include <linux/fb.h>
 
@@ -32,20 +34,6 @@
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
 
-#include <asm/hd64461.h>
-
-#define CONFIG_SH_LCD_VIDEOBASE		CONFIG_HD64461_IOBASE+0x2000000
-
-/* These are for HP Jornada 680/690.
-   It is desired that they are configurable...  */
-#define CONFIG_SH_LCD_VIDEOSIZE		1024*1024
-#define CONFIG_SH_LCD_HORZ		640
-#define CONFIG_SH_LCD_VERT		240
-#define CONFIG_SH_LCD_DEFAULTBPP	16
-
-struct hitfb_info {
-    struct fb_info_gen gen;
-};
 
 struct hitfb_par
 {
@@ -53,55 +41,79 @@
     int bpp;
 };
 
-static struct hitfb_info fb_info;
-static struct hitfb_par current_par;
-static int current_par_valid = 0;
-static struct display disp;
 
-static union {
+struct hitfb_info {
+    struct fb_info_gen gen;
+    struct display disp;
+    struct hitfb_par current_par;
+    struct fb_var_screeninfo default_var;
+    int current_par_valid;
+    unsigned long hit_videobase, hit_videosize;
+    union {
 #ifdef FBCON_HAS_CFB16
-    u16 cfb16[16];
+	u16 cfb16[16];
 #endif
-} fbcon_cmap;
-
-unsigned long hit_videobase, hit_videosize;
-static struct fb_var_screeninfo default_var;
+    } fbcon_cmap;
+} fb_info = {
+    {},
+    {},
+    {},
+    {},
+    0, 0, 0,
+    {},
+};
 
-int hitfb_init(void);
 
-static void hitfb_set_par(struct hitfb_par *par, const struct fb_info *info);
-static void hitfb_encode_var(struct fb_var_screeninfo *var, 
-			     struct hitfb_par *par,
-			     const struct fb_info *info);
+static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info);
+static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
+			    struct fb_info_gen *info);
 
 
 static void hitfb_detect(void)
 {
     struct hitfb_par par;
+    unsigned short lcdclor, ldr3, ldvntr;
+
+    fb_info.hit_videobase = CONFIG_HD64461_IOBASE + 0x02000000;
+    fb_info.hit_videosize = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024;
 
-    hit_videobase = CONFIG_SH_LCD_VIDEOBASE;
-    hit_videosize = CONFIG_SH_LCD_VIDEOSIZE;
+    lcdclor = inw(HD64461_LCDCLOR);
+    ldvntr = inw(HD64461_LDVNTR);
+    ldr3 = inw(HD64461_LDR3);
+
+    switch(ldr3&15) {
+    default:
+    case 4:
+        par.bpp = 8;
+	par.x = lcdclor;
+	break;
+    case 8:
+        par.bpp = 16;
+	par.x = lcdclor/2;
+	break;
+    }
 
-    par.x = CONFIG_SH_LCD_HORZ;
-    par.y = CONFIG_SH_LCD_VERT;
-    par.bpp = CONFIG_SH_LCD_DEFAULTBPP;
+    par.y = ldvntr+1;
 
     hitfb_set_par(&par, NULL);
-    hitfb_encode_var(&default_var, &par, NULL);
+    hitfb_encode_var(&fb_info.default_var, &par, NULL);
 }
 
-static int hitfb_encode_fix(struct fb_fix_screeninfo *fix,
-			    struct hitfb_par *par,
-			    const struct fb_info *info)
+
+static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
+			     struct fb_info_gen *info)
 {
+    const struct hitfb_par *par = fb_par;
+
     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
     strcpy(fix->id, "Hitachi HD64461");
-    fix->smem_start = hit_videobase;
-    fix->smem_len = hit_videosize;
+    fix->smem_start = fb_info.hit_videobase;
+    fix->smem_len = fb_info.hit_videosize;
     fix->type = FB_TYPE_PACKED_PIXELS;
     fix->type_aux = 0;
-    fix->visual = FB_VISUAL_TRUECOLOR;
+    fix->visual = (par->bpp == 8) ?
+	FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
     fix->xpanstep = 0;
     fix->ypanstep = 0;
     fix->ywrapstep = 0;
@@ -120,10 +132,11 @@
 }
 
 
-static int hitfb_decode_var(struct fb_var_screeninfo *var,
-			    struct hitfb_par *par,
-			    const struct fb_info *info)
+static int hitfb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
+			     struct fb_info_gen *info)
 {
+    struct hitfb_par *par = fb_par;
+
     par->x = var->xres;
     par->y = var->yres;
     par->bpp = var->bits_per_pixel;
@@ -131,10 +144,11 @@
 }
 
 
-static void hitfb_encode_var(struct fb_var_screeninfo *var, 
-			     struct hitfb_par *par,
-			     const struct fb_info *info)
+static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
+			     struct fb_info_gen *info)
 {
+    const struct hitfb_par *par = fb_par;
+
     memset(var, 0, sizeof(*var));
 
     var->xres = par->x;
@@ -191,25 +205,28 @@
     var->green.msb_right = 0;
     var->blue.msb_right = 0;
     var->transp.msb_right = 0;
+
+    return 0;
 }
 
 
-static void hitfb_get_par(struct hitfb_par *par, const struct fb_info *info)
+static void hitfb_get_par(void *par, struct fb_info_gen *info)
 {
-    *par = current_par;
+    *(struct hitfb_par *)par = fb_info.current_par;
 }
 
 
-static void hitfb_set_par(struct hitfb_par *par, const struct fb_info *info)
+static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info)
 {
-    /* Set the hardware according to 'par'. */
-    current_par = *par;
-    current_par_valid = 1;
+    const struct hitfb_par *par = fb_par;
+    fb_info.current_par = *par;
+    fb_info.current_par_valid = 1;
 }
 
 
-static int hitfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
+static int hitfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info)
 {
     if (regno > 255)
 	return 1;	
@@ -224,8 +241,9 @@
 }
 
 
-static int hitfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
+static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
 {
     if (regno > 255)
 	return 1;
@@ -236,10 +254,10 @@
     outw(blue>>10, HD64461_CPTWDR);
     
     if(regno<16) {
-	switch(current_par.bpp) {
+	switch(fb_info.current_par.bpp) {
 #ifdef FBCON_HAS_CFB16
 	case 16:
-	    fbcon_cmap.cfb16[regno] =
+	    fb_info.fbcon_cmap.cfb16[regno] =
 		((red   & 0xf800)      ) |
 		((green & 0xfc00) >>  5) |
 		((blue  & 0xf800) >> 11);
@@ -251,16 +269,34 @@
     return 0;
 }
 
-static int hitfb_blank(int blank_mode, const struct fb_info *info)
+
+static int hitfb_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info)
 {
+    if (!fb_info.current_par_valid)
+	return -EINVAL;
+
     return 0;
 }
 
 
-static void hitfb_set_disp(const void *par, struct display *disp,
-			   struct fb_info_gen *info)
+static int hitfb_blank(int blank_mode, struct fb_info_gen *info)
 {
-    disp->screen_base = (void *)hit_videobase;
+    if (!fb_info.current_par_valid)
+	return 1;
+
+    return 0;
+}
+
+
+static void hitfb_set_disp(const void *fb_par, struct display *disp,
+			    struct fb_info_gen *info)
+{
+    const struct hitfb_par *par = fb_par;
+
+    disp->screen_base = (void *)fb_info.hit_videobase;
+    disp->scrollmode = SCROLL_YREDRAW;
+
     switch(((struct hitfb_par *)par)->bpp) {
 #ifdef FBCON_HAS_CFB8
     case 8:
@@ -270,7 +306,7 @@
 #ifdef FBCON_HAS_CFB16
     case 16:
 	disp->dispsw = &fbcon_cfb16;
-	disp->dispsw_data = fbcon_cmap.cfb16;
+	disp->dispsw_data = fb_info.fbcon_cmap.cfb16;
 	break;
 #endif
     default:
@@ -288,18 +324,20 @@
     hitfb_set_par,
     hitfb_getcolreg,
     hitfb_setcolreg,
-    NULL,
+    hitfb_pan_display,
     hitfb_blank,
     hitfb_set_disp
 };
 
+
 static struct fb_ops hitfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	fbgen_set_cmap,
+    owner:		THIS_MODULE,
+    fb_get_fix:		fbgen_get_fix,
+    fb_get_var:		fbgen_get_var,
+    fb_set_var:		fbgen_set_var,
+    fb_get_cmap:	fbgen_get_cmap,
+    fb_set_cmap:	fbgen_set_cmap,
+    fb_pan_display:	fbgen_pan_display,
 };
 
 
@@ -309,7 +347,7 @@
     fb_info.gen.info.node = -1;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &hitfb_ops;
-    fb_info.gen.info.disp = &disp;
+    fb_info.gen.info.disp = &fb_info.disp;
     fb_info.gen.info.changevar = NULL;
     fb_info.gen.info.switch_con = &fbgen_switch;
     fb_info.gen.info.updatevar = &fbgen_update_var;
@@ -318,9 +356,9 @@
     fb_info.gen.fbhw = &hitfb_switch;
     fb_info.gen.fbhw->detect();
     
-    fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
-    disp.var.activate = FB_ACTIVATE_NOW;
-    fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+    fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
+    fb_info.disp.var.activate = FB_ACTIVATE_NOW;
+    fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
     fbgen_set_disp(-1, &fb_info.gen);
     fbgen_install_cmap(0, &fb_info.gen);
     
@@ -347,6 +385,13 @@
 
 void cleanup_module(void)
 {
-    hitfb_cleanup(void);
+  hitfb_cleanup(void);
 }
 #endif
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * End:
+ */
diff -u --recursive --new-file v2.4.3/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.4.3/linux/drivers/video/imsttfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/imsttfb.c	Wed Apr 18 11:49:12 2001
@@ -178,10 +178,10 @@
 
 /* TI TVP 3030 RAMDAC Direct Registers */
 enum {
-	TVPADDRW = 0x00,	/* 0  Palette/Cursor RAM Write Adress/Index */
+	TVPADDRW = 0x00,	/* 0  Palette/Cursor RAM Write Address/Index */
 	TVPPDATA = 0x04,	/* 1  Palette Data RAM Data */
 	TVPPMASK = 0x08,	/* 2  Pixel Read-Mask */
-	TVPPADRR = 0x0c,	/* 3  Palette/Cursor RAM Read Adress */
+	TVPPADRR = 0x0c,	/* 3  Palette/Cursor RAM Read Address */
 	TVPCADRW = 0x10,	/* 4  Cursor/Overscan Color Write Address */
 	TVPCDATA = 0x14,	/* 5  Cursor/Overscan Color Data */
 				/* 6  reserved */
diff -u --recursive --new-file v2.4.3/linux/drivers/video/matrox/matroxfb_DAC1064.c linux/drivers/video/matrox/matroxfb_DAC1064.c
--- v2.4.3/linux/drivers/video/matrox/matroxfb_DAC1064.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/video/matrox/matroxfb_DAC1064.c	Wed Apr 11 19:21:35 2001
@@ -416,7 +416,12 @@
 	outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
 	outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
 	outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
-	if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
+	/*
+	 * We must ALWAYS reprogram hardware due to broken XF4 matrox drivers...
+	 *
+	 * if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) 
+	 */
+	{
 		unsigned int i;
 
 		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
diff -u --recursive --new-file v2.4.3/linux/drivers/video/maxinefb.c linux/drivers/video/maxinefb.c
--- v2.4.3/linux/drivers/video/maxinefb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/maxinefb.c	Wed Apr 18 11:49:12 2001
@@ -0,0 +1,425 @@
+/*
+ *      linux/drivers/video/maxinefb.c
+ *
+ *	DECstation 5000/xx onboard framebuffer support ... derived from:
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998", the original code can be
+ *      found in the file hpfb.c in the same directory.
+ *
+ *      DECstation related code Copyright (C) 1999,2000,2001 by
+ *      Michael Engel <engel@unix-ag.org> and
+ *      Karsten Merker <merker@linuxtag.org>.
+ *      This file is subject to the terms and conditions of the GNU General
+ *      Public License.  See the file COPYING in the main directory of this
+ *      archive for more details.
+ *
+ */
+
+/*
+ * Changes:
+ * 2001/01/27 removed debugging and testing code, fixed fb_ops
+ *            initialization which had caused a crash before,
+ *            general cleanup, first official release (KM)
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <video/fbcon.h>
+#include "maxinefb.h"
+
+/* bootinfo.h defines the machine type values, needed when checking */
+/* whether are really running on a maxine, KM                       */
+#include <asm/bootinfo.h>
+
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+
+#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+
+static struct display disp;
+static struct fb_info fb_info;
+
+unsigned long fb_start, fb_size = 1024 * 768, fb_line_length = 1024;
+unsigned long fb_regs;
+unsigned char fb_bitmask;
+
+static struct fb_var_screeninfo maxinefb_defined = {
+	0, 0, 0, 0,		/* W,H, W, H (virtual) load xres,xres_virtual */
+	0, 0,			/* virtual -> visible no offset */
+	0,			/* depth -> load bits_per_pixel */
+	0,			/* greyscale ? */
+	{0, 0, 0},		/* R */
+	{0, 0, 0},		/* G */
+	{0, 0, 0},		/* B */
+	{0, 0, 0},		/* transparency */
+	0,			/* standard pixel format */
+	FB_ACTIVATE_NOW,
+	274, 195,		/* 14" monitor */
+	FB_ACCEL_NONE,
+	0L, 0L, 0L, 0L, 0L,
+	0L, 0L, 0,		/* No sync info */
+	FB_VMODE_NONINTERLACED,
+	{0, 0, 0, 0, 0, 0}
+};
+
+struct maxinefb_par {
+};
+
+static int currcon = 0;
+struct maxinefb_par current_par;
+
+/* Reference to machine type set in arch/mips/dec/prom/identify.c, KM */
+extern unsigned long mips_machtype;
+
+
+/* Handle the funny Inmos RamDAC/video controller ... */
+
+void maxinefb_ims332_write_register(int regno, register unsigned int val)
+{
+	register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS;
+	unsigned char *wptr;
+
+	wptr = regs + 0xa0000 + (regno << 4);
+	*((volatile unsigned int *) (regs)) = (val >> 8) & 0xff00;
+	*((volatile unsigned short *) (wptr)) = val;
+}
+
+unsigned int maxinefb_ims332_read_register(int regno)
+{
+	register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS;
+	unsigned char *rptr;
+	register unsigned int j, k;
+
+	rptr = regs + 0x80000 + (regno << 4);
+	j = *((volatile unsigned short *) rptr);
+	k = *((volatile unsigned short *) regs);
+
+	return (j & 0xffff) | ((k & 0xff00) << 8);
+}
+
+
+static void maxinefb_encode_var(struct fb_var_screeninfo *var,
+				struct maxinefb_par *par)
+{
+	int i = 0;
+	var->xres = 1024;
+	var->yres = 768;
+	var->xres_virtual = 1024;
+	var->yres_virtual = 768;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->bits_per_pixel = 8;
+	var->grayscale = 0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	var->nonstd = 0;
+	var->activate = 1;
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->pixclock = 0;
+	var->sync = 0;
+	var->left_margin = 0;
+	var->right_margin = 0;
+	var->upper_margin = 0;
+	var->lower_margin = 0;
+	var->hsync_len = 0;
+	var->vsync_len = 0;
+	for (i = 0; i < arraysize(var->reserved); i++)
+		var->reserved[i] = 0;
+}
+
+static void maxinefb_get_par(struct maxinefb_par *par)
+{
+	*par = current_par;
+}
+
+static int maxinefb_fb_update_var(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static int maxinefb_do_fb_set_var(struct fb_var_screeninfo *var,
+				  int isactive)
+{
+	struct maxinefb_par par;
+
+	maxinefb_get_par(&par);
+	maxinefb_encode_var(var, &par);
+	return 0;
+}
+
+
+/* Get the palette */
+
+static int maxinefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	unsigned int i;
+	unsigned long hw_colorvalue = 0;	/* raw color value from the register */
+	unsigned int length;
+
+	if (((cmap->start) + (cmap->len)) >= 256) {
+		length = 256 - (cmap->start);
+	} else {
+		length = cmap->len;
+	}
+	for (i = 0; i < length; i++) {
+		hw_colorvalue =
+		    maxinefb_ims332_read_register(IMS332_REG_COLOR_PALETTE
+						  + cmap->start + i);
+		(cmap->red[i]) = ((hw_colorvalue & 0x0000ff));
+		(cmap->green[i]) = ((hw_colorvalue & 0x00ff00) >> 8);
+		(cmap->blue[i]) = ((hw_colorvalue & 0xff0000) >> 16);
+
+	}
+	return 0;
+}
+
+
+/* Set the palette */
+
+static int maxinefb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	unsigned int i;
+	unsigned long hw_colorvalue;	/* value to be written into the palette reg. */
+	unsigned short cmap_red;
+	unsigned short cmap_green;
+	unsigned short cmap_blue;
+	unsigned int length;
+
+	hw_colorvalue = 0;
+	if (((cmap->start) + (cmap->len)) >= 256) {
+		length = 256 - (cmap->start);
+	} else {
+		length = cmap->len;
+	}
+
+	for (i = 0; i < length; i++) {
+		cmap_red = ((cmap->red[i]) >> 8);	/* The cmap fields are 16 bits    */
+		cmap_green = ((cmap->green[i]) >> 8);	/* wide, but the harware colormap */
+		cmap_blue = ((cmap->blue[i]) >> 8);	/* registers are only 8 bits wide */
+
+		hw_colorvalue =
+		    (cmap_blue << 16) + (cmap_green << 8) + (cmap_red);
+		maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE +
+					       cmap->start + i,
+					       hw_colorvalue);
+	}
+	return 0;
+}
+
+static int maxinefb_get_var(struct fb_var_screeninfo *var, int con,
+			    struct fb_info *info)
+{
+	struct maxinefb_par par;
+	if (con == -1) {
+		maxinefb_get_par(&par);
+		maxinefb_encode_var(var, &par);
+	} else
+		*var = fb_display[con].var;
+	return 0;
+}
+
+
+static int maxinefb_set_var(struct fb_var_screeninfo *var, int con,
+			    struct fb_info *info)
+{
+	int err;
+
+	if ((err = maxinefb_do_fb_set_var(var, 1)))
+		return err;
+	return 0;
+}
+static void maxinefb_encode_fix(struct fb_fix_screeninfo *fix,
+				struct maxinefb_par *par)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "maxinefb");
+	/* fix->id is a char[16], so a maximum of 15 characters, KM */
+
+	fix->smem_start = (char *) fb_start;	/* display memory base address, KM */
+	fix->smem_len = fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = fb_line_length;
+}
+
+static int maxinefb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			    struct fb_info *info)
+{
+	struct maxinefb_par par;
+	maxinefb_get_par(&par);
+	maxinefb_encode_fix(fix, &par);
+	return 0;
+}
+
+
+static int maxinefb_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg, int con,
+			  struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+static int maxinefb_switch(int con, struct fb_info *info)
+{
+	maxinefb_do_fb_set_var(&fb_display[con].var, 1);
+	currcon = con;
+	return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void maxinefb_blank(int blank, struct fb_info *info)
+{
+	/* Not supported */
+}
+
+static int maxinefb_open(struct fb_info *info, int user)
+{
+	/*
+	 * Nothing, only a usage count for the moment
+	 */
+	MOD_INC_USE_COUNT;
+	return (0);
+}
+
+static void maxinefb_set_disp(int con)
+{
+	struct fb_fix_screeninfo fix;
+	struct display *display;
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &disp;	/* used during initialization */
+
+	maxinefb_get_fix(&fix, con, 0);
+
+	display->screen_base = fix.smem_start;
+	display->visual = fix.visual;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->line_length = fix.line_length;
+	display->next_line = fix.line_length;
+	display->can_soft_blank = 0;
+	display->inverse = 0;
+
+	display->dispsw = &fbcon_cfb8;
+}
+
+static int maxinefb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static struct fb_ops maxinefb_ops = {
+	owner:THIS_MODULE,
+	fb_open:maxinefb_open,
+	fb_release:maxinefb_release,
+	fb_get_fix:maxinefb_get_fix,
+	fb_get_var:maxinefb_get_var,
+	fb_set_var:maxinefb_set_var,
+	fb_get_cmap:maxinefb_get_cmap,
+	fb_set_cmap:maxinefb_set_cmap,
+	fb_ioctl:maxinefb_ioctl,
+	fb_mmap:0,
+	fb_rasterimg:0
+};
+
+int __init maxinefb_init_one()
+{
+	volatile unsigned char *fboff;
+	int i;
+
+	/* Framebuffer display memory base address */
+	fb_start = DS5000_xx_ONBOARD_FBMEM_START;
+
+	/* Clear screen */
+	for (fboff = fb_start; fboff < fb_start + 0x1ffff; fboff++)
+		*fboff = 0x0;
+
+	/* erase hardware cursor */
+	for (i = 0; i < 512; i++) {
+		maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i,
+					       0);
+		/*
+		   if (i&0x8 == 0)
+		   maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0x0f);
+		   else
+		   maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0xf0);
+		 */
+	}
+
+	/* Fill in the available video resolution */
+	maxinefb_defined.xres = 1024;
+	maxinefb_defined.yres = 768;
+	maxinefb_defined.xres_virtual = 1024;
+	maxinefb_defined.yres_virtual = 768;
+	maxinefb_defined.bits_per_pixel = 8;
+
+	/* Let there be consoles... */
+
+	strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8");
+	/* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */
+	fb_info.changevar = NULL;
+	fb_info.node = -1;
+	fb_info.fbops = &maxinefb_ops;
+	fb_info.disp = &disp;
+	fb_info.switch_con = &maxinefb_switch;
+	fb_info.updatevar = &maxinefb_fb_update_var;
+	fb_info.blank = &maxinefb_blank;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	maxinefb_do_fb_set_var(&maxinefb_defined, 1);
+
+	maxinefb_get_var(&disp.var, -1, &fb_info);
+	maxinefb_set_disp(-1);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return 1;
+
+	return 0;
+}
+
+
+/* Initialise the framebuffer */
+
+void __init maxinefb_init()
+{
+	unsigned int sid;
+
+	if (mips_machtype == MACH_DS5000_XX) {
+		printk("Maxinefb: Personal DECstation detected\n");
+		printk("Maxinefb: initializing onboard framebuffer\n");
+
+		maxinefb_init_one();
+
+	}
+
+}
+
+void __init maxinefb_setup(char *options, int *ints)
+{
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/video/maxinefb.h linux/drivers/video/maxinefb.h
--- v2.4.3/linux/drivers/video/maxinefb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/maxinefb.h	Wed Apr 18 11:49:12 2001
@@ -0,0 +1,37 @@
+/*
+ *      linux/drivers/video/maxinefb.h
+ *
+ *      DECstation 5000/xx onboard framebuffer support, Copyright (C) 1999 by
+ *      Michael Engel <engel@unix-ag.org> and Karsten Merker <merker@guug.de>
+ *      This file is subject to the terms and conditions of the GNU General
+ *      Public License.  See the file COPYING in the main directory of this
+ *      archive for more details.
+ */
+
+
+/*
+ * IMS332 video controller register base address
+ */
+#define MAXINEFB_IMS332_ADDRESS                  0xbc140000
+
+/*
+ * Begin of DECstation 5000/xx onboard framebuffer memory, default resolution
+ * is 1024x768x8
+ */
+#define DS5000_xx_ONBOARD_FBMEM_START	0xaa000000
+
+/*
+ *      The IMS 332 video controller used in the DECstation 5000/xx series
+ *      uses 32 bits wide registers; the following defines declare the
+ *      register numbers, to get the real offset, these have to be multiplied
+ *      by four.
+ */
+
+#define IMS332_REG_CURSOR_RAM           0x200	/* hardware cursor bitmap */
+
+/*
+ * The color palette entries have the form 0x00BBGGRR
+ */
+#define IMS332_REG_COLOR_PALETTE        0x100	/* color palette, 256 entries */
+#define IMS332_REG_CURSOR_COLOR_PALETTE	0x0a1	/* cursor color palette, */
+						/* 3 entries             */
diff -u --recursive --new-file v2.4.3/linux/drivers/video/pmag-ba-fb.c linux/drivers/video/pmag-ba-fb.c
--- v2.4.3/linux/drivers/video/pmag-ba-fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/pmag-ba-fb.c	Wed Apr 18 11:49:12 2001
@@ -0,0 +1,431 @@
+/*
+ *      linux/drivers/video/pmag-ba-fb.c
+ *
+ *	PMAG-BA TurboChannel framebuffer card support ... derived from:
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998", the original code can be
+ *      found in the file hpfb.c in the same directory.
+ *
+ *	Based on digital document:
+ * 	"PMAG-BA TURBOchannel Color Frame Buffer
+ *	 Functional Specification", Revision 1.2, August 27, 1990
+ *
+ *      DECstation related code Copyright (C) 1999, 2000, 2001 by
+ *      Michael Engel <engel@unix-ag.org>, 
+ *      Karsten Merker <merker@linuxtag.org> and
+ *	Harald Koerfgen <harald@unix-ag.org>.
+ *      This file is subject to the terms and conditions of the GNU General
+ *      Public License.  See the file COPYING in the main directory of this
+ *      archive for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include "pmag-ba-fb.h"
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+
+#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+
+struct pmag_ba_ramdac_regs {
+	unsigned char addr_low;
+	unsigned char pad0[3];
+	unsigned char addr_hi;
+	unsigned char pad1[3];
+	unsigned char data;
+	unsigned char pad2[3];
+	unsigned char cmap;
+};
+
+struct pmag_ba_my_fb_info {
+	struct fb_info info;
+	struct pmag_ba_ramdac_regs *bt459_regs;
+	unsigned long pmagba_fb_start;
+	unsigned long pmagba_fb_size;
+	unsigned long pmagba_fb_line_length;
+};
+
+static struct display disp;
+/*
+ * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
+ */
+static struct pmag_ba_my_fb_info pmagba_fb_info[3];
+
+static struct fb_var_screeninfo pmagbafb_defined = {
+	0, 0, 0, 0,		/* W,H, W, H (virtual) load xres,xres_virtual */
+	0, 0,			/* virtual -> visible no offset */
+	0,			/* depth -> load bits_per_pixel */
+	0,			/* greyscale ? */
+	{0, 0, 0},		/* R */
+	{0, 0, 0},		/* G */
+	{0, 0, 0},		/* B */
+	{0, 0, 0},		/* transparency */
+	0,			/* standard pixel format */
+	FB_ACTIVATE_NOW,
+	274, 195,		/* 14" monitor */
+	FB_ACCEL_NONE,
+	0L, 0L, 0L, 0L, 0L,
+	0L, 0L, 0,		/* No sync info */
+	FB_VMODE_NONINTERLACED,
+	{0, 0, 0, 0, 0, 0}
+};
+
+struct pmagbafb_par {
+};
+
+static int currcon = 0;
+struct pmagbafb_par current_par;
+
+static void pmagbafb_encode_var(struct fb_var_screeninfo *var,
+				struct pmagbafb_par *par)
+{
+	int i = 0;
+	var->xres = 1024;
+	var->yres = 864;
+	var->xres_virtual = 1024;
+	var->yres_virtual = 864;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->bits_per_pixel = 8;
+	var->grayscale = 0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	var->nonstd = 0;
+	var->activate = 1;
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->pixclock = 0;
+	var->sync = 0;
+	var->left_margin = 0;
+	var->right_margin = 0;
+	var->upper_margin = 0;
+	var->lower_margin = 0;
+	var->hsync_len = 0;
+	var->vsync_len = 0;
+	for (i = 0; i < arraysize(var->reserved); i++)
+		var->reserved[i] = 0;
+}
+
+static void pmagbafb_get_par(struct pmagbafb_par *par)
+{
+	*par = current_par;
+}
+
+static int pmagba_fb_update_var(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static int pmagba_do_fb_set_var(struct fb_var_screeninfo *var,
+				int isactive)
+{
+	struct pmagbafb_par par;
+
+	pmagbafb_get_par(&par);
+	pmagbafb_encode_var(var, &par);
+	return 0;
+}
+
+/*
+ * Turn hardware cursor off
+ */
+void pmagbafb_erase_cursor(struct pmag_ba_my_fb_info *info)
+{
+	info->bt459_regs->addr_low = 0;
+	info->bt459_regs->addr_hi = 3;
+	info->bt459_regs->data = 0;
+}
+
+/*
+ * Write to a Bt459 color map register
+ */
+void pmag_ba_bt459_write_colormap(struct pmag_ba_my_fb_info *info,
+				  int reg, __u8 red, __u8 green, __u8 blue)
+{
+	info->bt459_regs->addr_low = (__u8) reg;
+	info->bt459_regs->addr_hi = 0;
+	info->bt459_regs->cmap = red;
+	info->bt459_regs->cmap = green;
+	info->bt459_regs->cmap = blue;
+}
+
+/*
+ * Get the palette
+ */
+
+static int pmagbafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	unsigned int i;
+	unsigned int length;
+
+	if (((cmap->start) + (cmap->len)) >= 256) {
+		length = 256 - (cmap->start);
+	} else {
+		length = cmap->len;
+	}
+	for (i = 0; i < length; i++) {
+		/*
+		 * TODO
+		 */
+	}
+	return 0;
+}
+
+/*
+ * Set the palette. 
+ */
+static int pmagbafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	unsigned int i;
+	__u8 cmap_red, cmap_green, cmap_blue;
+	unsigned int length;
+
+	if (((cmap->start) + (cmap->len)) >= 256)
+		length = 256 - (cmap->start);
+	else
+		length = cmap->len;
+
+	for (i = 0; i < length; i++) {
+		cmap_red = ((cmap->red[i]) >> 8);	/* The cmap fields are 16 bits    */
+		cmap_green = ((cmap->green[i]) >> 8);	/* wide, but the harware colormap */
+		cmap_blue = ((cmap->blue[i]) >> 8);	/* registers are only 8 bits wide */
+
+		pmag_ba_bt459_write_colormap((struct pmag_ba_my_fb_info *)
+					     info, cmap->start + i,
+					     cmap_red, cmap_green,
+					     cmap_blue);
+	}
+	return 0;
+}
+
+static int pmagbafb_get_var(struct fb_var_screeninfo *var, int con,
+			    struct fb_info *info)
+{
+	struct pmagbafb_par par;
+	if (con == -1) {
+		pmagbafb_get_par(&par);
+		pmagbafb_encode_var(var, &par);
+	} else
+		*var = fb_display[con].var;
+	return 0;
+}
+
+
+static int pmagbafb_set_var(struct fb_var_screeninfo *var, int con,
+			    struct fb_info *info)
+{
+	int err;
+
+	if ((err = pmagba_do_fb_set_var(var, 1)))
+		return err;
+	return 0;
+}
+
+static void pmagbafb_encode_fix(struct fb_fix_screeninfo *fix,
+				struct pmagbafb_par *par,
+				struct pmag_ba_my_fb_info *info)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "PMAG-BA");
+
+	fix->smem_start = info->pmagba_fb_start;
+	fix->smem_len = info->pmagba_fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = info->pmagba_fb_line_length;
+}
+
+static int pmagbafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			    struct fb_info *info)
+{
+	struct pmagbafb_par par;
+
+	pmagbafb_get_par(&par);
+	pmagbafb_encode_fix(fix, &par, (struct pmag_ba_my_fb_info *) info);
+
+	return 0;
+}
+
+
+static int pmagbafb_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg, int con,
+			  struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+static int pmagbafb_switch(int con, struct fb_info *info)
+{
+	pmagba_do_fb_set_var(&fb_display[con].var, 1);
+	currcon = con;
+
+	return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void pmagbafb_blank(int blank, struct fb_info *info)
+{
+	/* Not supported */
+}
+
+static int pmagbafb_open(struct fb_info *info, int user)
+{
+	/*
+	 * Nothing, only a usage count for the moment
+	 */
+	MOD_INC_USE_COUNT;
+	return (0);
+}
+
+static void pmagbafb_set_disp(int con, struct pmag_ba_my_fb_info *info)
+{
+	struct fb_fix_screeninfo fix;
+	struct display *display;
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &disp;	/* used during initialization */
+
+	pmagbafb_get_fix(&fix, con, (struct fb_info *) info);
+
+	display->screen_base = (char *) fix.smem_start;
+	display->visual = fix.visual;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->line_length = fix.line_length;
+	display->next_line = fix.line_length;
+	display->can_soft_blank = 0;
+	display->inverse = 0;
+
+	display->dispsw = &fbcon_cfb8;
+}
+
+static int pmagbafb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static struct fb_ops pmagbafb_ops = {
+	owner:THIS_MODULE,
+	fb_open:pmagbafb_open,
+	fb_release:pmagbafb_release,
+	fb_get_fix:pmagbafb_get_fix,
+	fb_get_var:pmagbafb_get_var,
+	fb_set_var:pmagbafb_set_var,
+	fb_get_cmap:pmagbafb_get_cmap,
+	fb_set_cmap:pmagbafb_set_cmap,
+	fb_ioctl:pmagbafb_ioctl,
+	fb_mmap:0,
+	fb_rasterimg:0
+};
+
+int __init pmagbafb_init_one(int slot)
+{
+	unsigned long base_addr = get_tc_base_addr(slot);
+	struct pmag_ba_my_fb_info *ip =
+	    (struct pmag_ba_my_fb_info *) &pmagba_fb_info[slot];
+
+	printk("PMAG-BA framebuffer in slot %d\n", slot);
+
+	/*
+	 * Framebuffer display memory base address and friends
+	 */
+	ip->bt459_regs =
+	    (struct pmag_ba_ramdac_regs *) (base_addr +
+					    PMAG_BA_BT459_OFFSET);
+	ip->pmagba_fb_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
+	ip->pmagba_fb_size = 1024 * 864;
+	ip->pmagba_fb_line_length = 1024;
+
+	/*
+	 * Configure the Bt459 RAM DAC
+	 */
+	pmagbafb_erase_cursor(ip);
+
+	/*
+	 *      Fill in the available video resolution
+	 */
+
+	pmagbafb_defined.xres = 1024;
+	pmagbafb_defined.yres = 864;
+	pmagbafb_defined.xres_virtual = 1024;
+	pmagbafb_defined.yres_virtual = 864;
+	pmagbafb_defined.bits_per_pixel = 8;
+
+	/*
+	 *      Let there be consoles..
+	 */
+	strcpy(ip->info.modename, "PMAG-BA");
+	ip->info.changevar = NULL;
+	ip->info.node = -1;
+	ip->info.fbops = &pmagbafb_ops;
+	ip->info.disp = &disp;
+	ip->info.switch_con = &pmagbafb_switch;
+	ip->info.updatevar = &pmagba_fb_update_var;
+	ip->info.blank = &pmagbafb_blank;
+	ip->info.flags = FBINFO_FLAG_DEFAULT;
+
+	pmagba_do_fb_set_var(&pmagbafb_defined, 1);
+	pmagbafb_get_var(&disp.var, -1, (struct fb_info *) ip);
+	pmagbafb_set_disp(-1, ip);
+
+	if (register_framebuffer((struct fb_info *) ip) < 0)
+		return 1;
+
+	return 0;
+}
+
+/* 
+ * Initialise the framebuffer
+ */
+
+int __init pmagbafb_init(void)
+{
+	int sid;
+	int found = 0;
+
+	if (TURBOCHANNEL) {
+		while ((sid = search_tc_card("PMAG-BA")) >= 0) {
+			found = 1;
+			claim_tc_card(sid);
+			pmagbafb_init_one(sid);
+		}
+		return found ? 0 : -ENODEV;
+	} else {
+		return -ENODEV;
+	}
+}
+
+int __init pmagbafb_setup(char *options)
+{
+	return 0;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/video/pmag-ba-fb.h linux/drivers/video/pmag-ba-fb.h
--- v2.4.3/linux/drivers/video/pmag-ba-fb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/pmag-ba-fb.h	Wed Apr 18 11:49:12 2001
@@ -0,0 +1,24 @@
+/*
+ *      linux/drivers/video/pmag-ba-fb.h
+ *
+ *      TurboChannel PMAG-BA framebuffer card support,
+ *      Copyright (C) 1999,2000,2001 by
+ *      Michael Engel <engel@unix-ag.org>,
+ *      Karsten Merker <merker@linuxtag.org>
+ *      This file is subject to the terms and conditions of the GNU General
+ *      Public License.  See the file COPYING in the main directory of this
+ *      archive for more details.
+ */
+
+/*
+ * Bt459 RAM DAC register base offset (rel. to TC slot base address)
+ */
+
+#define PMAG_BA_BT459_OFFSET                    0x00200000
+
+/*
+ * Begin of PMAG-BA framebuffer memory relative to TC slot address,
+ * resolution is 1024x864x8
+ */
+
+#define PMAG_BA_ONBOARD_FBMEM_OFFSET    0x00000000
diff -u --recursive --new-file v2.4.3/linux/drivers/video/pmagb-b-fb.c linux/drivers/video/pmagb-b-fb.c
--- v2.4.3/linux/drivers/video/pmagb-b-fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/pmagb-b-fb.c	Wed Apr 18 11:49:12 2001
@@ -0,0 +1,434 @@
+/*
+ *      linux/drivers/video/pmagb-b-fb.c
+ *
+ *	PMAGB-B TurboChannel framebuffer card support ... derived from:
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998", the original code can be
+ *      found in the file hpfb.c in the same directory.
+ *
+ *      DECstation related code Copyright (C) 1999, 2000, 2001 by
+ *      Michael Engel <engel@unix-ag.org>,
+ *      Karsten Merker <merker@linuxtag.org> and 
+ *	Harald Koerfgen <harald@unix-ag.org>.
+ *      This file is subject to the terms and conditions of the GNU General
+ *      Public License.  See the file COPYING in the main directory of this
+ *      archive for more details.
+ *
+ */
+
+/*
+ *      We currently only support the PMAGB-B in high resolution mode
+ *      as I know of no way to detect low resolution mode set via jumper.
+ *      KM, 2001/01/07
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include "pmagb-b-fb.h"
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+
+#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+
+struct pmagb_b_ramdac_regs {
+	unsigned char addr_low;
+	unsigned char pad0[3];
+	unsigned char addr_hi;
+	unsigned char pad1[3];
+	unsigned char data;
+	unsigned char pad2[3];
+	unsigned char cmap;
+};
+
+struct pmagb_b_my_fb_info {
+	struct fb_info info;
+	struct pmagb_b_ramdac_regs *bt459_regs;
+	unsigned long pmagbb_fb_start;
+	unsigned long pmagbb_fb_size;
+	unsigned long pmagbb_fb_line_length;
+};
+
+static struct display disp;
+/*
+ * Max 3 TURBOchannel slots -> max 3 PMAGB-B :)
+ */
+static struct pmagb_b_my_fb_info pmagbb_fb_info[3];
+
+static struct fb_var_screeninfo pmagbbfb_defined = {
+	0, 0, 0, 0,		/* W,H, W, H (virtual) load xres,xres_virtual */
+	0, 0,			/* virtual -> visible no offset */
+	0,			/* depth -> load bits_per_pixel */
+	0,			/* greyscale ? */
+	{0, 0, 0},		/* R */
+	{0, 0, 0},		/* G */
+	{0, 0, 0},		/* B */
+	{0, 0, 0},		/* transparency */
+	0,			/* standard pixel format */
+	FB_ACTIVATE_NOW,
+	274, 195,		/* 14" monitor */
+	FB_ACCEL_NONE,
+	0L, 0L, 0L, 0L, 0L,
+	0L, 0L, 0,		/* No sync info */
+	FB_VMODE_NONINTERLACED,
+	{0, 0, 0, 0, 0, 0}
+};
+
+struct pmagbbfb_par {
+};
+
+static int currcon = 0;
+struct pmagbbfb_par current_par;
+
+static void pmagbbfb_encode_var(struct fb_var_screeninfo *var,
+				struct pmagbbfb_par *par)
+{
+	int i = 0;
+	var->xres = 1280;
+	var->yres = 1024;
+	var->xres_virtual = 1280;
+	var->yres_virtual = 1024;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->bits_per_pixel = 8;
+	var->grayscale = 0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	var->nonstd = 0;
+	var->activate = 1;
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->pixclock = 0;
+	var->sync = 0;
+	var->left_margin = 0;
+	var->right_margin = 0;
+	var->upper_margin = 0;
+	var->lower_margin = 0;
+	var->hsync_len = 0;
+	var->vsync_len = 0;
+	for (i = 0; i < arraysize(var->reserved); i++)
+		var->reserved[i] = 0;
+}
+
+static void pmagbbfb_get_par(struct pmagbbfb_par *par)
+{
+	*par = current_par;
+}
+
+static int pmagbb_fb_update_var(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static int pmagbb_do_fb_set_var(struct fb_var_screeninfo *var,
+				int isactive)
+{
+	struct pmagbbfb_par par;
+
+	pmagbbfb_get_par(&par);
+	pmagbbfb_encode_var(var, &par);
+	return 0;
+}
+
+/*
+ * Turn hardware cursor off
+ */
+void pmagbbfb_erase_cursor(struct pmagb_b_my_fb_info *info)
+{
+	info->bt459_regs->addr_low = 0;
+	info->bt459_regs->addr_hi = 3;
+	info->bt459_regs->data = 0;
+}
+
+/*
+ * Write to a Bt459 color map register
+ */
+void pmagb_b_bt459_write_colormap(struct pmagb_b_my_fb_info *info,
+				  int reg, __u8 red, __u8 green, __u8 blue)
+{
+	info->bt459_regs->addr_low = (__u8) reg;
+	info->bt459_regs->addr_hi = 0;
+	info->bt459_regs->cmap = red;
+	info->bt459_regs->cmap = green;
+	info->bt459_regs->cmap = blue;
+}
+
+/*
+ * Get the palette
+ */
+
+static int pmagbbfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	unsigned int i;
+	unsigned int length;
+
+	if (((cmap->start) + (cmap->len)) >= 256) {
+		length = 256 - (cmap->start);
+	} else {
+		length = cmap->len;
+	}
+	for (i = 0; i < length; i++) {
+		/*
+		 * TODO
+		 */
+	}
+	return 0;
+}
+
+/*
+ * Set the palette. 
+ */
+static int pmagbbfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			     struct fb_info *info)
+{
+	unsigned int i;
+	__u8 cmap_red, cmap_green, cmap_blue;
+	unsigned int length;
+
+	if (((cmap->start) + (cmap->len)) >= 256)
+		length = 256 - (cmap->start);
+	else
+		length = cmap->len;
+
+	for (i = 0; i < length; i++) {
+		cmap_red = ((cmap->red[i]) >> 8);	/* The cmap fields are 16 bits    */
+		cmap_green = ((cmap->green[i]) >> 8);	/* wide, but the harware colormap */
+		cmap_blue = ((cmap->blue[i]) >> 8);	/* registers are only 8 bits wide */
+
+		pmagb_b_bt459_write_colormap((struct pmagb_b_my_fb_info *)
+					     info, cmap->start + i,
+					     cmap_red, cmap_green,
+					     cmap_blue);
+	}
+	return 0;
+}
+
+static int pmagbbfb_get_var(struct fb_var_screeninfo *var, int con,
+			    struct fb_info *info)
+{
+	struct pmagbbfb_par par;
+	if (con == -1) {
+		pmagbbfb_get_par(&par);
+		pmagbbfb_encode_var(var, &par);
+	} else
+		*var = fb_display[con].var;
+	return 0;
+}
+
+
+static int pmagbbfb_set_var(struct fb_var_screeninfo *var, int con,
+			    struct fb_info *info)
+{
+	int err;
+
+	if ((err = pmagbb_do_fb_set_var(var, 1)))
+		return err;
+	return 0;
+}
+
+static void pmagbbfb_encode_fix(struct fb_fix_screeninfo *fix,
+				struct pmagbbfb_par *par,
+				struct pmagb_b_my_fb_info *info)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "PMAGB-BA");
+
+	fix->smem_start = info->pmagbb_fb_start;
+	fix->smem_len = info->pmagbb_fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = info->pmagbb_fb_line_length;
+}
+
+static int pmagbbfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			    struct fb_info *info)
+{
+	struct pmagbbfb_par par;
+
+	pmagbbfb_get_par(&par);
+	pmagbbfb_encode_fix(fix, &par, (struct pmagb_b_my_fb_info *) info);
+
+	return 0;
+}
+
+
+static int pmagbbfb_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg, int con,
+			  struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+static int pmagbbfb_switch(int con, struct fb_info *info)
+{
+	pmagbb_do_fb_set_var(&fb_display[con].var, 1);
+	currcon = con;
+
+	return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void pmagbbfb_blank(int blank, struct fb_info *info)
+{
+	/* Not supported */
+}
+
+static int pmagbbfb_open(struct fb_info *info, int user)
+{
+	/*
+	 * Nothing, only a usage count for the moment
+	 */
+	MOD_INC_USE_COUNT;
+	return (0);
+}
+
+static void pmagbbfb_set_disp(int con, struct pmagb_b_my_fb_info *info)
+{
+	struct fb_fix_screeninfo fix;
+	struct display *display;
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &disp;	/* used during initialization */
+
+	pmagbbfb_get_fix(&fix, con, (struct fb_info *) info);
+
+	display->screen_base = (char *) fix.smem_start;
+	display->visual = fix.visual;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->line_length = fix.line_length;
+	display->next_line = fix.line_length;
+	display->can_soft_blank = 0;
+	display->inverse = 0;
+
+	display->dispsw = &fbcon_cfb8;
+}
+
+static int pmagbbfb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static struct fb_ops pmagbbfb_ops = {
+	owner:THIS_MODULE,
+	fb_open:pmagbbfb_open,
+	fb_release:pmagbbfb_release,
+	fb_get_fix:pmagbbfb_get_fix,
+	fb_get_var:pmagbbfb_get_var,
+	fb_set_var:pmagbbfb_set_var,
+	fb_get_cmap:pmagbbfb_get_cmap,
+	fb_set_cmap:pmagbbfb_set_cmap,
+	fb_ioctl:pmagbbfb_ioctl,
+	fb_mmap:0,
+	fb_rasterimg:0
+};
+
+int __init pmagbbfb_init_one(int slot)
+{
+	unsigned long base_addr = get_tc_base_addr(slot);
+	struct pmagb_b_my_fb_info *ip =
+	    (struct pmagb_b_my_fb_info *) &pmagbb_fb_info[slot];
+
+	printk("PMAGB-BA framebuffer in slot %d\n", slot);
+
+	/*
+	 * Framebuffer display memory base address and friends
+	 */
+	ip->bt459_regs =
+	    (struct pmagb_b_ramdac_regs *) (base_addr +
+					    PMAGB_B_BT459_OFFSET);
+	ip->pmagbb_fb_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET;
+	ip->pmagbb_fb_size = 1280 * 1024;
+	ip->pmagbb_fb_line_length = 1280;
+
+	/*
+	 * Configure the Bt459 RAM DAC
+	 */
+	pmagbbfb_erase_cursor(ip);
+
+	/*
+	 *      Fill in the available video resolution
+	 */
+
+	pmagbbfb_defined.xres = 1280;
+	pmagbbfb_defined.yres = 1024;
+	pmagbbfb_defined.xres_virtual = 1280;
+	pmagbbfb_defined.yres_virtual = 1024;
+	pmagbbfb_defined.bits_per_pixel = 8;
+
+	/*
+	 *      Let there be consoles..
+	 */
+	strcpy(ip->info.modename, "PMAGB-BA");
+	ip->info.changevar = NULL;
+	ip->info.node = -1;
+	ip->info.fbops = &pmagbbfb_ops;
+	ip->info.disp = &disp;
+	ip->info.switch_con = &pmagbbfb_switch;
+	ip->info.updatevar = &pmagbb_fb_update_var;
+	ip->info.blank = &pmagbbfb_blank;
+	ip->info.flags = FBINFO_FLAG_DEFAULT;
+
+	pmagbb_do_fb_set_var(&pmagbbfb_defined, 1);
+	pmagbbfb_get_var(&disp.var, -1, (struct fb_info *) ip);
+	pmagbbfb_set_disp(-1, ip);
+
+	if (register_framebuffer((struct fb_info *) ip) < 0)
+		return 1;
+
+	return 0;
+}
+
+/* 
+ * Initialise the framebuffer
+ */
+
+int __init pmagbbfb_init(void)
+{
+	int sid;
+	int found = 0;
+
+	if (TURBOCHANNEL) {
+		while ((sid = search_tc_card("PMAGB-BA")) >= 0) {
+			found = 1;
+			claim_tc_card(sid);
+			pmagbbfb_init_one(sid);
+		}
+		return found ? 0 : -ENODEV;
+	} else {
+		return -ENODEV;
+	}
+}
+
+int __init pmagbbfb_setup(char *options)
+{
+	return 0;
+}
diff -u --recursive --new-file v2.4.3/linux/drivers/video/pmagb-b-fb.h linux/drivers/video/pmagb-b-fb.h
--- v2.4.3/linux/drivers/video/pmagb-b-fb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/pmagb-b-fb.h	Wed Apr 18 11:49:12 2001
@@ -0,0 +1,32 @@
+/*
+ *      linux/drivers/video/pmagb-b-fb.h
+ *
+ *      TurboChannel PMAGB-B framebuffer card support,
+ *      Copyright (C) 1999, 2000, 2001 by
+ *      Michael Engel <engel@unix-ag.org> and 
+ *      Karsten Merker <merker@linxutag.org>
+ *      This file is subject to the terms and conditions of the GNU General
+ *      Public License.  See the file COPYING in the main directory of this
+ *      archive for more details.
+ */
+
+
+/*
+ * Bt459 RAM DAC register base offset (rel. to TC slot base address)
+ */
+#define PMAGB_B_BT459_OFFSET			0x001C0000
+
+/*
+ * Begin of PMAGB-B framebuffer memory, resolution is configurable:
+ * 1024x864x8 or 1280x1024x8, settable by jumper on the card
+ */
+#define PMAGB_B_ONBOARD_FBMEM_OFFSET	0x00201000
+
+/*
+ * Bt459 register offsets, byte-wide registers
+ */
+
+#define BT459_ADR_LOW			BT459_OFFSET + 0x00	/* addr. low */
+#define BT459_ADR_HIGH			BT459_OFFSET + 0x04	/* addr. high */
+#define BT459_DATA			BT459_OFFSET + 0x08	/* r/w data */
+#define BT459_CMAP			BT459_OFFSET + 0x0C	/* color map */
diff -u --recursive --new-file v2.4.3/linux/drivers/video/riva/rivafb.h linux/drivers/video/riva/rivafb.h
--- v2.4.3/linux/drivers/video/riva/rivafb.h	Sat Feb  3 12:48:00 2001
+++ linux/drivers/video/riva/rivafb.h	Wed Apr 18 11:49:12 2001
@@ -82,4 +82,4 @@
 #endif
 };
 
-#endif /* __RIVAFB_H */
\ No newline at end of file
+#endif /* __RIVAFB_H */
diff -u --recursive --new-file v2.4.3/linux/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c
--- v2.4.3/linux/drivers/video/sa1100fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/sa1100fb.c	Wed Apr 18 11:49:12 2001
@@ -688,6 +688,16 @@
 		init_var.grayscale	= 0;
 		init_var.sync		= 0;
 		init_var.pixclock	= 171521;
+	} else if (machine_is_pangolin()) {
+		current_par.max_xres	= 1024;
+		current_par.max_yres	= 768;
+		current_par.max_bpp	= 16;
+		init_var.red.length	= 5;
+		init_var.green.length	= 6;
+		init_var.blue.length	= 5;
+		init_var.grayscale	= 0;
+		init_var.sync		= 0;	
+		init_var.pixclock	= 15400;
 	} else if (machine_is_bitsy()) {
 		current_par.max_xres	= 320;
 		current_par.max_yres	= 240;
@@ -717,15 +727,7 @@
 		init_var.grayscale	= 1;
 		init_var.pixclock	= 150000;	
 		init_var.sync		= 0;
-	} else if (machine_is_penny()) {
-		current_par.max_xres	= 640;
-		current_par.max_yres	= 480;
-		current_par.max_bpp	= 8;
-		init_var.red.length	= 4;				
-		init_var.green		= init_var.red;
-		init_var.blue		= init_var.red;
-		init_var.sync		= 0;
-	} else if (machine_is_thinclient() || machine_is_graphicsclient()) {
+	} else if (machine_is_graphicsclient()) {
 		current_par.max_xres	= 640;
 		current_par.max_yres	= 480;
 		current_par.max_bpp	= 8;
@@ -733,24 +735,6 @@
 		init_var.green		= init_var.red;
 		init_var.blue		= init_var.red;
 		init_var.sync		= 0;
-	} else if (machine_is_tifon()) {
-		current_par.max_xres	= 640;
-		current_par.max_yres	= 200;
-		current_par.max_bpp	= 4;
-		current_par.inv_4bpp	= 1;
-		init_var.red.length	= 4;				
-		init_var.green		= init_var.red;
-		init_var.blue		= init_var.red;
-		init_var.grayscale	= 1;
-	        init_var.pixclock	= 150000;	
-	        init_var.left_margin	= 20;
-	        init_var.right_margin	= 255;
-	        init_var.upper_margin	= 20;
-	        init_var.lower_margin	= 0;
-	        init_var.hsync_len	= 2;
-	        init_var.vsync_len	= 1;
-		init_var.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
-		init_var.vmode		= 0;
 	} else if (machine_is_xp860()) {
 		current_par.max_xres	= 1024;
 		current_par.max_yres	= 768;
@@ -870,14 +854,7 @@
 {
 	unsigned int pcd = 0;
 
-	if (machine_is_tifon()) {
-		pcd = frequency[PPCR &0xf] / 1000;
-		pcd *= pixclock/1000;
-		pcd = pcd / 10000000 * 12;
-		/* the last multiplication by 1.2 is to handle */
-		/* sync problems */
-	}
-	if (machine_is_assabet()) {
+	if (machine_is_assabet() | machine_is_pangolin()) {
 		pcd = frequency[PPCR & 0xf] / 1000;
 		pcd *= pixclock / 1000;
 		pcd = pcd / 1000000;
@@ -933,6 +910,26 @@
 
 		/* Set board control register to handle new color depth */
 		sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16);
+	} else if (machine_is_pangolin()) {
+		DPRINTK("Configuring Pangolin LCD\n");
+		lcd_shadow.lccr0 = 
+			LCCR0_LEN + LCCR0_Color + LCCR0_LDM +
+			LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
+			LCCR0_LtlEnd + LCCR0_DMADel(0);
+		lcd_shadow.lccr1 = 
+			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(63) + 
+			LCCR1_BegLnDel(127) + LCCR1_EndLnDel(127);
+		lcd_shadow.lccr2 = 
+			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) + 
+			LCCR2_BegFrmDel(18) + LCCR2_EndFrmDel(18);
+		lcd_shadow.lccr3 = 
+			LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH +
+			LCCR3_VrtSnchH + LCCR3_OutEnH;
+		DPRINTK("pcd = %d\n", pcd);
+		DPRINTK("LCCR1_DisWdth(var->xres) = 0x%x\n",
+			LCCR1_DisWdth(var->xres));
+		DPRINTK("LCCR2_DisHght(var->yres) = 0x%x\n",
+			LCCR2_DisHght(var->yres));
 	} else if (machine_is_bitsy()) {
 		DPRINTK("Configuring  Bitsy LCD\n");
 		lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
@@ -998,24 +995,8 @@
 		lcd_shadow.lccr3 = 
 			LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
 			LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
-	} else if (machine_is_penny()) {
-		DPRINTK("Configuring  Penny LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + 
-			LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
-			LCCR0_DMADel(0); 
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(65) +
-			LCCR1_EndLnDel(43) + LCCR1_BegLnDel(43);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(35) + 
-			LCCR2_EndFrmDel(0) + LCCR2_BegFrmDel(0);
-		lcd_shadow.lccr3 = 
-			LCCR3_PixClkDiv(16) + LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff +
-			((var->sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) +
-			((var->sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
-	} else if (machine_is_thinclient() || machine_is_graphicsclient()) {
-		DPRINTK("Configuring ThinClient LCD\n");
+	} else if (machine_is_graphicsclient()) {
+		DPRINTK("Configuring GraphicsClient LCD\n");
 		lcd_shadow.lccr0 = 
 			LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
 		lcd_shadow.lccr1 = 
@@ -1027,29 +1008,6 @@
 		lcd_shadow.lccr3 = 
 			LCCR3_PixClkDiv(6) + LCCR3_ACBsDiv(2) + 
 			LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
-	} else if (machine_is_tifon()) {
-		DPRINTK("Configuring TIFON LCD\n");
-		lcd_shadow.lccr0 = 
-			LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
-			LCCR0_BigEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
-			LCCR0_8PixMono + LCCR0_DMADel(0);
-		lcd_shadow.lccr1 = 
-			LCCR1_DisWdth(var->xres) + 
-			LCCR1_HorSnchWdth(var->hsync_len) +
-			LCCR1_BegLnDel(var->left_margin) +
-			LCCR1_EndLnDel(var->right_margin);
-		lcd_shadow.lccr2 = 
-			LCCR2_DisHght(var->yres) + 
-			LCCR2_VrtSnchWdth(var->vsync_len) +
-			LCCR2_BegFrmDel(var->upper_margin) +
-			LCCR2_EndFrmDel(var->lower_margin);
-		lcd_shadow.lccr3 = 
-			LCCR3_PixClkDiv(pcd) + LCCR3_ACBsDiv(512) +
-			LCCR3_ACBsCnt(0) + LCCR3_HorSnchH + LCCR3_VrtSnchH;
-		/*
-			((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) +
-			((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
-		*/
 	} else if (machine_is_xp860()) {
 		DPRINTK("Configuring XP860 LCD\n");
 		lcd_shadow.lccr0 = 
@@ -1116,13 +1074,6 @@
 		                if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE)
 		                        clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
 #endif
-			} else if (machine_is_penny()) {
-#ifdef CONFIG_SA1100_PENNY
-				FpgaLcdCS1 = 0x000;	/* LCD Backlight to 0%    */
-				FpgaPortI &= ~LCD_ON;	/* Turn off LCD Backlight */
-#endif
-			} else if (machine_is_tifon()) {
-				GPCR = GPIO_GPIO(24);	/* turn off display */
 			}
 		}
 	}
@@ -1174,7 +1125,7 @@
 
 		/* Make sure the mode bits are present in the first palette entry */
 		current_par.v_palette_base[0] &= 0x0FFF; 	           
-		current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel); 	 
+		current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
 
 		/* Enable GPIO<9:2> for LCD usage if dual-scan */
 		if (lcd_shadow.lccr0 & LCCR0_SDS) {
@@ -1204,15 +1155,6 @@
 			DPRINTK("LCCR2=%x\n", LCCR2);
 			DPRINTK("LCCR3=%x\n", LCCR3);
 #endif
-		} else if (machine_is_penny()) {
-#ifdef CONFIG_SA1100_PENNY
-			FpgaLcdCS1 = 0x0FF;	/* LCD Backlight to 100% */
-			FpgaPortI  |= LCD_ON;	/* Turn on LCD Backlight */
-#endif
-		} else if (machine_is_tifon()) {
-			GPCR = GPIO_GPIO(24);	/* cycle on/off-switch */
-			udelay(150);
-			GPSR = GPIO_GPIO(24);	/* turn on display */
 		}
 
 		current_par.controller_state = LCD_MODE_ENABLED;
@@ -1307,19 +1249,15 @@
 		GAFR |= 0x3fc;
 		sa1100fb_assabet_set_truecolor(current_par.visual ==
 					       FB_VISUAL_TRUECOLOR);
+	} else if (machine_is_pangolin()) {
+		GPDR |= 0x3fc;
+		GAFR |= 0x3fc;
 	} else if (machine_is_bitsy()) {
 		GPDR = (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
 		GAFR |= (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
 	} else if (machine_is_cerf()) {
 		GPDR |= 0x3fc;
 		GAFR |= 0x3fc;
-	} else if (machine_is_penny()) {
-#ifdef CONFIG_SA1100_PENNY
-		GPDR |= GPIO_GPDR_GFX;	/* GPIO Data Direction register for LCD data bits 8-11 */
-		GAFR |= GPIO_GAFR_GFX;	/* GPIO Alternate Function register for LCD data bits 8-11 */
-#endif
-	} else if (machine_is_tifon()) {
-		GPDR |= GPIO_GPIO(24);	/* set GPIO24 to output */
 	} else if (machine_is_xp860()) {
 		GPDR |= 0x3fc;
 		GAFR |= 0x3fc;
diff -u --recursive --new-file v2.4.3/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.4.3/linux/drivers/video/sbusfb.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/video/sbusfb.c	Thu Apr 12 12:10:25 2001
@@ -193,44 +193,6 @@
 	/* To stop the swapper from even considering these pages */
 	vma->vm_flags |= (VM_SHM| VM_LOCKED);
 	
-#ifdef __sparc_v9__
-	/* Align it as much as desirable */
-	{
-		unsigned long j, alignment, s = 0;
-		int max = -1;
-		
-		map_offset = (vma->vm_pgoff << PAGE_SHIFT) + size;
-		for (i = 0; fb->mmap_map[i].size; i++) {
-			if (fb->mmap_map[i].voff < off)
-				continue;
-			if (fb->mmap_map[i].voff >= map_offset)
-				break;
-			if (max < 0 || sbusfb_mmapsize(fb,fb->mmap_map[i].size) > s) {
-				max = i;
-				s = sbusfb_mmapsize(fb,fb->mmap_map[max].size);
-			}
-		}
-		if (max >= 0) {
-			j = s;
-			if (fb->mmap_map[max].voff + j > map_offset)
-				j = map_offset - fb->mmap_map[max].voff;
-			for (alignment = 0x400000; alignment > PAGE_SIZE; alignment >>= 3)
-				if (j >= alignment && !(fb->mmap_map[max].poff & (alignment - 1)))
-					break;
-			if (alignment > PAGE_SIZE) {
-				j = alignment;
-				alignment = j - ((vma->vm_start + fb->mmap_map[max].voff - off) & (j - 1));
-				if (alignment != j) {
-					struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
-					if (!vmm || vmm->vm_start >= vma->vm_end + alignment) {
-						vma->vm_start += alignment;
-						vma->vm_end += alignment;
-					}
-				}
-			}
-		}
-	}
-#endif	
 
 	/* Each page, see which map applies */
 	for (page = 0; page < size; ){
diff -u --recursive --new-file v2.4.3/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.4.3/linux/drivers/video/tdfxfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/tdfxfb.c	Wed Apr 18 11:49:12 2001
@@ -88,6 +88,10 @@
 
 #include <linux/spinlock.h>
 
+#ifndef PCI_DEVICE_ID_3DFX_VOODOO5
+#define PCI_DEVICE_ID_3DFX_VOODOO5	0x0009
+#endif
+
 /* membase0 register offsets */
 #define STATUS		0x00
 #define PCIINIT0	0x04
@@ -248,6 +252,7 @@
 
 #define BANSHEE_MAX_PIXCLOCK 270000.0
 #define VOODOO3_MAX_PIXCLOCK 300000.0
+#define VOODOO5_MAX_PIXCLOCK 350000.0
 
 struct banshee_reg {
   /* VGA rubbish */
@@ -279,6 +284,7 @@
   unsigned long clip1max;
   unsigned long srcbase;
   unsigned long dstbase;
+  unsigned long miscinit0;
 };
 
 struct tdfxfb_par {
@@ -646,12 +652,14 @@
 static void do_flashcursor(unsigned long ptr)
 {
    struct fb_info_tdfx* i=(struct fb_info_tdfx *)ptr;
-   spin_lock(&i->DAClock);
+   unsigned long flags;
+
+   spin_lock_irqsave(&i->DAClock, flags);
    banshee_make_room(1);
    tdfx_outl( VIDPROCCFG, tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE );
    i->cursor.timer.expires=jiffies+HZ/2;
    add_timer(&i->cursor.timer);
-   spin_unlock(&i->DAClock);
+   spin_unlock_irqrestore(&i->DAClock, flags);
 }
 
 /*
@@ -921,6 +929,7 @@
   tdfx_outl(VIDDESKSTART,  reg->startaddr);
   tdfx_outl(VIDPROCCFG,    reg->vidcfg);
   tdfx_outl(VGAINIT1,      reg->vgainit1);  
+  tdfx_outl(MISCINIT0,	   reg->miscinit0);
 
   banshee_make_room(8);
   tdfx_outl(SRCBASE,         reg->srcbase);
@@ -942,19 +951,27 @@
   u32 lfbsize   = 0;
   int sgram_p     = 0;
 
-  if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
-       (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)))
-    return 0;
-
   draminit0 = tdfx_inl(DRAMINIT0);  
   draminit1 = tdfx_inl(DRAMINIT1);
-   
-  sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
+
+  if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+      (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) {
+    sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
   
-  lfbsize = sgram_p ?
-    (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
-     ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
-    16 * 1024 * 1024;
+    lfbsize = sgram_p ?
+      (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
+       ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
+      16 * 1024 * 1024;
+  } else {
+    /* Voodoo4/5 */
+    u32 chips, psize, banks;
+
+    chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
+    psize = 1 << ((draminit0 & 0x38000000) >> 28);
+    banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
+    lfbsize = chips * psize * banks;
+    lfbsize <<= 20;
+  }
 
   /* disable block writes for SDRAM (why?) */
   miscinit1 = tdfx_inl(MISCINIT1);
@@ -1412,6 +1429,26 @@
   reg.screensize = par->width | (par->height << 12);
   reg.vidcfg &= ~VIDCFG_HALF_MODE;
 
+  reg.miscinit0 = tdfx_inl(MISCINIT0);
+
+#if defined(__BIG_ENDIAN)
+  switch (par->bpp) {
+    case 8:
+      reg.miscinit0 &= ~(1 << 30);
+      reg.miscinit0 &= ~(1 << 31);
+      break;
+    case 16:
+      reg.miscinit0 |= (1 << 30);
+      reg.miscinit0 |= (1 << 31);
+      break;
+    case 24:
+    case 32:
+      reg.miscinit0 |= (1 << 30);
+      reg.miscinit0 &= ~(1 << 31);
+      break;
+  }
+#endif
+
   do_write_regs(&reg);
 
   i->current_par = *par;
@@ -1462,6 +1499,7 @@
   switch(i->dev) {
   case PCI_DEVICE_ID_3DFX_BANSHEE:
   case PCI_DEVICE_ID_3DFX_VOODOO3:
+  case PCI_DEVICE_ID_3DFX_VOODOO5:
     par->width       = (var->xres + 15) & ~15; /* could sometimes be 8 */
     par->width_virt  = par->width;
     par->height      = var->yres;
@@ -1584,32 +1622,34 @@
 
   switch(info->dev) {
   case PCI_DEVICE_ID_3DFX_BANSHEE:
+    strcpy(fix->id, "3Dfx Banshee");
+    break;
   case PCI_DEVICE_ID_3DFX_VOODOO3:
-    strcpy(fix->id, 
-	   info->dev == PCI_DEVICE_ID_3DFX_BANSHEE 
-	   ? "3Dfx Banshee"
-	   : "3Dfx Voodoo3");
-    fix->smem_start  = info->bufbase_phys;
-    fix->smem_len    = info->bufbase_size;
-    fix->mmio_start  = info->regbase_phys;
-    fix->mmio_len    = info->regbase_size;
-    fix->accel       = FB_ACCEL_3DFX_BANSHEE;
-    fix->type        = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux    = 0;
-    fix->line_length = par->lpitch;
-    fix->visual      = (par->bpp == 8) 
-                       ? FB_VISUAL_PSEUDOCOLOR
-                       : FB_VISUAL_DIRECTCOLOR;
-
-    fix->xpanstep    = 0; 
-    fix->ypanstep    = nopan ? 0 : 1;
-    fix->ywrapstep   = nowrap ? 0 : 1;
-
+    strcpy(fix->id, "3Dfx Voodoo3");
+    break;
+  case PCI_DEVICE_ID_3DFX_VOODOO5:
+    strcpy(fix->id, "3Dfx Voodoo5");
     break;
   default:
     return -EINVAL;
   }
 
+  fix->smem_start  = info->bufbase_phys;
+  fix->smem_len    = info->bufbase_size;
+  fix->mmio_start  = info->regbase_phys;
+  fix->mmio_len    = info->regbase_size;
+  fix->accel       = FB_ACCEL_3DFX_BANSHEE;
+  fix->type        = FB_TYPE_PACKED_PIXELS;
+  fix->type_aux    = 0;
+  fix->line_length = par->lpitch;
+  fix->visual      = (par->bpp == 8) 
+                     ? FB_VISUAL_PSEUDOCOLOR
+                     : FB_VISUAL_DIRECTCOLOR;
+
+  fix->xpanstep    = 0; 
+  fix->ypanstep    = nopan ? 0 : 1;
+  fix->ywrapstep   = nowrap ? 0 : 1;
+
   return 0;
 }
 
@@ -1850,17 +1890,25 @@
   while ((pdev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_ANY_ID, pdev))) {
     if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
        ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
-	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
-      char* name = pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
-	? "Banshee"
-	: "Voodoo3";
+	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3) ||
+	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO5))) {
+      char *name;
 
       fb_info.dev   = pdev->device;
-      fb_info.max_pixclock = 
-	pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE 
-	? BANSHEE_MAX_PIXCLOCK
-	: VOODOO3_MAX_PIXCLOCK;
-
+      switch (pdev->device) {
+      case PCI_DEVICE_ID_3DFX_BANSHEE:
+	fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK;
+	name = "Banshee";
+	break;
+      case PCI_DEVICE_ID_3DFX_VOODOO3:
+	fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK;
+	name = "Voodoo3";
+	break;
+      case PCI_DEVICE_ID_3DFX_VOODOO5:
+	fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK;
+	name = "Voodoo5";
+	break;
+      }
       fb_info.regbase_phys = pci_resource_start(pdev, 0);
       fb_info.regbase_size = 1 << 24;
       fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24);
diff -u --recursive --new-file v2.4.3/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.4.3/linux/drivers/video/vesafb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/vesafb.c	Wed Apr 18 11:49:12 2001
@@ -2,7 +2,7 @@
  * framebuffer driver for VBE 2.0 compliant graphic boards
  *
  * switching to graphics mode happens at boot time (while
- * running in real mode, see arch/i386/video.S).
+ * running in real mode, see arch/i386/boot/video.S).
  *
  * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
  *
diff -u --recursive --new-file v2.4.3/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.4.3/linux/drivers/video/vga16fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/vga16fb.c	Wed Apr 18 11:49:12 2001
@@ -897,6 +897,10 @@
 	/* XXX share VGA_FB_PHYS region with vgacon */
 
         vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
+	if (!vga16fb.video_vbase) {
+		printk(KERN_ERR "vga16fb: unable to map device\n");
+		return -ENOMEM;
+	}
 	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
 
 	vga16fb.isVGA = ORIG_VIDEO_ISVGA;
@@ -931,8 +935,10 @@
 	vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
 	vga16fb_set_disp(-1, &vga16fb);
 
-	if (register_framebuffer(&vga16fb.fb_info)<0)
+	if (register_framebuffer(&vga16fb.fb_info)<0) {
+		iounmap(vga16fb.video_vbase);
 		return -EINVAL;
+	}
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 	       GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
diff -u --recursive --new-file v2.4.3/linux/fs/Config.in linux/fs/Config.in
--- v2.4.3/linux/fs/Config.in	Mon Jan 15 12:42:32 2001
+++ linux/fs/Config.in	Thu Apr 12 12:25:53 2001
@@ -31,6 +31,7 @@
 	int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0
 fi
 tristate 'Compressed ROM file system support' CONFIG_CRAMFS
+bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
 tristate 'Simple RAM-based file system support' CONFIG_RAMFS
 
 tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
diff -u --recursive --new-file v2.4.3/linux/fs/adfs/super.c linux/fs/adfs/super.c
--- v2.4.3/linux/fs/adfs/super.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/adfs/super.c	Tue Apr 17 23:16:38 2001
@@ -386,12 +386,6 @@
 	sb->u.adfs_sb.s_version  = dr->format_version;
 	sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize;
 	
-	/*
-	 * Max file size is 2Gb
-	 */
-	 
-	sb->s_maxbytes = MAX_NON_LFS;
-
 	sb->u.adfs_sb.s_map = adfs_read_map(sb, dr);
 	if (!sb->u.adfs_sb.s_map)
 		goto error_free_bh;
diff -u --recursive --new-file v2.4.3/linux/fs/affs/Changes linux/fs/affs/Changes
--- v2.4.3/linux/fs/affs/Changes	Thu Apr 13 13:57:09 2000
+++ linux/fs/affs/Changes	Thu Apr 19 22:57:06 2001
@@ -26,7 +26,30 @@
   last allocated block is not cleared. Well,
   this fs never claimed to be Posix conformant.
 
-Please direct bug reports to: hjw@zvw.de
+Please direct bug reports to: zippel@linux-m68k.org
+
+Version 3.14
+------------
+
+- correctly cut off long file names for compares
+- correctly initialize s_last_bmap
+
+Version 3.13
+------------
+
+Major cleanup for 2.4 [Roman Zippel]
+- new extended block handling
+- new bitmap allocation functions
+- locking should be safe for the future
+- cleanup of some interfaces
+
+Version 3.12
+------------
+
+more 2.4 fixes: [Roman Zippel]
+- s_lock changes
+- increased getblock mess
+- clear meta blocks 
 
 Version 3.11
 ------------
diff -u --recursive --new-file v2.4.3/linux/fs/affs/Makefile linux/fs/affs/Makefile
--- v2.4.3/linux/fs/affs/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/affs/Makefile	Thu Apr 19 22:57:06 2001
@@ -7,6 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile.
 
+#EXTRA_CFLAGS=-DDEBUG=1
+
 O_TARGET := affs.o
 
 obj-y   := super.o namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
diff -u --recursive --new-file v2.4.3/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v2.4.3/linux/fs/affs/amigaffs.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/affs/amigaffs.c	Thu Apr 19 22:57:06 2001
@@ -8,7 +8,6 @@
  *  Please send bug reports to: hjw@zvw.de
  */
 
-#define DEBUG 0
 #include <stdarg.h>
 #include <linux/stat.h>
 #include <linux/sched.h>
@@ -26,170 +25,236 @@
  * Functions for accessing Amiga-FFS structures.
  */
 
-/* Set *NAME to point to the file name in a file header block in memory
-   pointed to by FH_DATA.  The length of the name is returned. */
 
-int
-affs_get_file_name(int bsize, void *fh_data, unsigned char **name)
-{
-	struct file_end *file_end;
-
-	file_end = GET_END_PTR(struct file_end, fh_data, bsize);
-	if (file_end->file_name[0] == 0
-	    || file_end->file_name[0] > 30) {
-		printk(KERN_WARNING "AFFS: bad filename (length=%d chars)\n",
-			file_end->file_name[0]);
-		*name = "***BAD_FILE***";
-		return 14;
-        }
-	*name = (unsigned char *)&file_end->file_name[1];
-        return file_end->file_name[0];
-}
-
-/* Insert a header block (file) into the directory (next).
- * This routine assumes that the caller has the superblock locked.
+/* Insert a header block bh into the directory dir
+ * caller must hold AFFS_DIR->i_hash_lock!
  */
 
 int
-affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *inode)
+affs_insert_hash(struct inode *dir, struct buffer_head *bh)
 {
-	struct buffer_head	*bh;
-	s32			 ino;
-	int			 offset;
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *dir_bh;
+	u32 ino, hash_ino;
+	int offset;
 
-	offset = affs_hash_name(FILE_END(file->b_data,inode)->file_name+1,
-				FILE_END(file->b_data,inode)->file_name[0],
-				AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
-	ino    = be32_to_cpu(((struct dir_front *)file->b_data)->own_key);
+	ino = bh->b_blocknr;
+	offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
 
-	pr_debug("AFFS: insert_hash(dir_ino=%lu,ino=%d)\n",next,ino);
+	pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino);
 
-	FILE_END(file->b_data,inode)->parent = cpu_to_be32(next);
+	dir_bh = affs_bread(sb, dir->i_ino);
+	if (!dir_bh)
+		return -EIO;
 
-	while (1) {
-		if (!(bh = affs_bread(inode->i_dev,next,AFFS_I2BSIZE(inode))))
+	hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
+	while (hash_ino) {
+		affs_brelse(dir_bh);
+		dir_bh = affs_bread(sb, hash_ino);
+		if (!dir_bh)
 			return -EIO;
-		next = be32_to_cpu(((s32 *)bh->b_data)[offset]);
-		if (!next || next > ino)
-			break;
-		offset = AFFS_I2BSIZE(inode) / 4 - 4;
-		affs_brelse(bh);
+		hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
 	}
+	AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
+	AFFS_TAIL(sb, bh)->hash_chain = 0;
 
-	DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next);
-	((s32 *)bh->b_data)[offset]             = cpu_to_be32(ino);
-	affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-	mark_buffer_dirty(bh);
-	affs_brelse(bh);
+	if (dir->i_ino == dir_bh->b_blocknr)
+		AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
+	else
+		AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
+
+	affs_adjust_checksum(dir_bh, ino);
+	mark_buffer_dirty(dir_bh);
+	affs_brelse(dir_bh);
+
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	dir->i_version = ++event;
+	mark_inode_dirty(dir);
 
 	return 0;
 }
-/* Remove a header block from its hash table (directory).
- * 'inode' may be any inode on the partition, it's only
- * used for calculating the block size and superblock
- * reference.
+
+/* Remove a header block from its directory.
+ * caller must hold AFFS_DIR->i_hash_lock!
  */
 
 int
-affs_remove_hash(struct buffer_head *dbh, struct inode *inode)
+affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
 {
-	s32			 ownkey;
-	s32			 key;
-	s32			 ptype;
-	s32			 stype;
-	int			 offset;
-	int			 retval;
-	struct buffer_head	*bh;
-
-	ownkey = be32_to_cpu(((struct dir_front *)dbh->b_data)->own_key);
-	key    = be32_to_cpu(FILE_END(dbh->b_data,inode)->parent);
-	offset = affs_hash_name(FILE_END(dbh->b_data,inode)->file_name+1,
-				FILE_END(dbh->b_data,inode)->file_name[0],
-				AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
-	pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n",key,ownkey,offset-6);
-	retval = -ENOENT;
+	struct super_block *sb;
+	struct buffer_head *bh;
+	u32 rem_ino, hash_ino, ino;
+	int offset, retval;
+
+	sb = dir->i_sb;
+	rem_ino = rem_bh->b_blocknr;
+	offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
+	pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset);
 
-	lock_super(inode->i_sb);
-	while (key) {
-		if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
-			retval = -EIO;
-			break;
-		}
-		if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)
-		    || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
-					    stype != ST_LINKFILE && stype != ST_LINKDIR &&
-					    stype != ST_ROOT && stype != ST_SOFTLINK)) {
-			affs_error(inode->i_sb,"affs_remove_hash",
-				"Bad block in hash chain (key=%d, ptype=%d, stype=%d, ownkey=%d)",
-				key,ptype,stype,ownkey);
-			affs_brelse(bh);
-			retval = -EINVAL;
-			break;
-		}
-		key = be32_to_cpu(((s32 *)bh->b_data)[offset]);
-		if (ownkey == key) {
-			((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain;
-			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+	bh = affs_bread(sb, dir->i_ino);
+	if (!bh)
+		return -EIO;
+
+	retval = -ENOENT;
+	hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
+	while (hash_ino) {
+		if (hash_ino == rem_ino) {
+			ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
+			if (dir->i_ino == bh->b_blocknr)
+				AFFS_HEAD(bh)->table[offset] = ino;
+			else
+				AFFS_TAIL(sb, bh)->hash_chain = ino;
+			affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
 			mark_buffer_dirty(bh);
-			affs_brelse(bh);
 			retval = 0;
 			break;
 		}
 		affs_brelse(bh);
-		offset = AFFS_I2BSIZE(inode) / 4 - 4;
+		bh = affs_bread(sb, hash_ino);
+		if (!bh)
+			return -EIO;
+		hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
 	}
-	unlock_super(inode->i_sb);
+
+	affs_brelse(bh);
+
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	dir->i_version = ++event;
+	mark_inode_dirty(dir);
 
 	return retval;
 }
 
+static void
+affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
+{
+	struct inode *inode = dentry->d_inode;
+	void *data = dentry->d_fsdata;
+	struct list_head *head, *next;
+
+	spin_lock(&dcache_lock);
+	head = &inode->i_dentry;
+	next = head->next;
+	while (next != head) {
+		dentry = list_entry(next, struct dentry, d_alias);
+		if (entry_ino == (u32)dentry->d_fsdata) {
+			dentry->d_fsdata = data;
+			break;
+		}
+		next = next->next;
+	}
+	spin_unlock(&dcache_lock);
+}
+
+
 /* Remove header from link chain */
 
-int
-affs_remove_link(struct buffer_head *dbh, struct inode *inode)
+static int
+affs_remove_link(struct dentry *dentry)
 {
-	int			 retval;
-	s32			 key;
-	s32			 ownkey;
-	s32			 ptype;
-	s32			 stype;
-	struct buffer_head	*bh;
-
-	ownkey = be32_to_cpu((DIR_FRONT(dbh)->own_key));
-	key    = be32_to_cpu(FILE_END(dbh->b_data,inode)->original);
-	retval = -ENOENT;
+	struct inode *dir, *inode = dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh = NULL, *link_bh = NULL;
+	u32 link_ino, ino;
+	int retval;
+
+	pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
+	down(&AFFS_INODE->i_link_lock);
+	retval = -EIO;
+	bh = affs_bread(sb, inode->i_ino);
+	if (!bh)
+		goto done;
+
+	link_ino = (u32)dentry->d_fsdata;
+	if (inode->i_ino == link_ino) {
+		/* we can't remove the head of the link, as its blocknr is still used as ino,
+		 * so we remove the block of the first link instead.
+		 */ 
+		link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
+		link_bh = affs_bread(sb, link_ino);
+		if (!link_bh)
+			goto done;
+
+		dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
+		if (!dir)
+			goto done;
+
+		down(&AFFS_DIR->i_hash_lock);
+		affs_fix_dcache(dentry, link_ino);
+		retval = affs_remove_hash(dir, link_bh);
+		if (retval)
+			goto done;
+
+		memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
+		retval = affs_insert_hash(dir, bh);
+		if (retval)
+			goto done;
 
-	pr_debug("AFFS: remove_link(link=%d, original=%d)\n",ownkey,key);
+		up(&AFFS_DIR->i_hash_lock);
+		iput(dir);
+	} else {
+		link_bh = affs_bread(sb, link_ino);
+		if (!link_bh)
+			goto done;
+	}
 
-	lock_super(inode->i_sb);
-	while (key) {
-		if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
-			retval = -EIO;
-			break;
-		}
-		if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)) {
-			affs_error(inode->i_sb,"affs_remove_link","Checksum error (block %d)",key);
-			affs_brelse(bh);
-			retval = -EINVAL;
-			break;
-		}
-		key = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
-		if (ownkey == key) {
-			FILE_END(bh->b_data,inode)->link_chain =
-						FILE_END(dbh->b_data,inode)->link_chain;
-			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+	while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain))) {
+		if (ino == link_ino) {
+			ino = AFFS_TAIL(sb, link_bh)->link_chain;
+			AFFS_TAIL(sb, bh)->link_chain = ino;
+			affs_adjust_checksum(bh, be32_to_cpu(ino) - link_ino);
 			mark_buffer_dirty(bh);
-			affs_brelse(bh);
 			retval = 0;
-			break;
+			/* Fix the link count, if bh is a normal header block without links */
+			switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
+			case ST_LINKDIR:
+			case ST_LINKFILE:
+				break;
+			default:
+				if (!AFFS_TAIL(sb, bh)->link_chain)
+					inode->i_nlink = 1;
+			}
+			affs_free_block(sb, link_ino);
+			goto done;
 		}
 		affs_brelse(bh);
+		bh = affs_bread(sb, ino);
+		if (!bh)
+			goto done;
 	}
-	unlock_super(inode->i_sb);
+	retval = -ENOENT;
+done:
+	affs_brelse(link_bh);
+	affs_brelse(bh);
+	up(&AFFS_INODE->i_link_lock);
+	return retval;
+}
+
 
+static int
+affs_empty_dir(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh;
+	int retval, size;
+
+	retval = -EIO;
+	bh = affs_bread(sb, inode->i_ino);
+	if (!bh)
+		goto done;
+
+	retval = -ENOTEMPTY;
+	for (size = AFFS_SB->s_hashsize - 1; size >= 0; size--)
+		if (AFFS_HEAD(bh)->table[size])
+			goto not_empty;
+	retval = 0;
+not_empty:
+	affs_brelse(bh);
+done:
 	return retval;
 }
 
+
 /* Remove a filesystem object. If the object to be removed has
  * links to it, one of the links must be changed to inherit
  * the file or directory. As above, any inode will do.
@@ -200,86 +265,55 @@
  */
 
 int
-affs_remove_header(struct buffer_head *bh, struct inode *inode)
+affs_remove_header(struct dentry *dentry)
 {
-	struct buffer_head	*link_bh;
-	struct inode		*dir;
-	unsigned long		 link_ino;
-	unsigned long		 orig_ino;
-	unsigned int		 dir_ino;
-	int			 error;
-
-	pr_debug("AFFS: remove_header(key=%ld)\n",be32_to_cpu(DIR_FRONT(bh)->own_key));
-
-	/* Mark directory as changed.  We do this before anything else,
-	 * as it must be done anyway and doesn't hurt even if an
-	 * error occurs later.
-	 */
-	dir = iget(inode->i_sb,be32_to_cpu(FILE_END(bh->b_data,inode)->parent));
-	if (!dir)
-		return -EIO;
-	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_version++;
-	mark_inode_dirty(dir);
-	iput(dir);
+	struct super_block *sb;
+	struct inode *inode, *dir;
+	struct buffer_head *bh = NULL;
+	int retval;
 
-	orig_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->original);
-	if (orig_ino) {		/* This is just a link. Nothing much to do. */
-		pr_debug("AFFS: Removing link.\n");
-		if ((error = affs_remove_link(bh,inode)))
-			return error;
-		if ((error = affs_remove_hash(bh,inode)))
-			return error;
-		affs_free_block(inode->i_sb,be32_to_cpu(DIR_FRONT(bh)->own_key));
-		return 1;
-	}
-	
-	link_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
-	if (link_ino) {		/* This is the complicated case. Yuck. */
-		pr_debug("AFFS: Removing original with links to it.\n");
-		/* Unlink the object and its first link from their directories. */
-		if ((error = affs_remove_hash(bh,inode)))
-			return error;
-		if (!(link_bh = affs_bread(inode->i_dev,link_ino,AFFS_I2BSIZE(inode))))
-			return -EIO;
-		if ((error = affs_remove_hash(link_bh,inode))) {
-			affs_brelse(link_bh);
-			return error;
-		}
-		/* Fix link chain. */
-		if ((error = affs_remove_link(link_bh,inode))) {
-			affs_brelse(link_bh);
-			return error;
-		}
-		/* Rename link to object. */
-		memcpy(FILE_END(bh->b_data,inode)->file_name,
-			FILE_END(link_bh->b_data,inode)->file_name,32);
-		/* Insert object into dir the link was in. */
-		dir_ino = be32_to_cpu(FILE_END(link_bh->b_data,inode)->parent);
-		if ((error = affs_insert_hash(dir_ino,bh,inode))) {
-			affs_brelse(link_bh);
-			return error;
-		}
-		affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-		mark_buffer_dirty(bh);
-		affs_brelse(link_bh);
-		affs_free_block(inode->i_sb,link_ino);
-		/* Mark the link's parent dir as changed, too. */
-		if (!(dir = iget(inode->i_sb,dir_ino)))
-			return -EIO;
-		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-		dir->i_version++;
-		mark_inode_dirty(dir);
-		iput(dir);
-		return 1;
+	dir = dentry->d_parent->d_inode;
+	sb = dir->i_sb;
+
+	retval = -ENOENT;
+	inode = dentry->d_inode;
+	if (!inode)
+		goto done;
+
+	pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino);
+	down(&AFFS_DIR->i_hash_lock);
+	if (S_ISDIR(inode->i_mode)) {
+		retval = affs_empty_dir(inode);
+		if (retval)
+			goto done_unlock;
 	}
-	/* Plain file/dir. This is the simplest case. */
-	pr_debug("AFFS: Removing plain file/dir.\n");
-	if ((error = affs_remove_hash(bh,inode)))
-		return error;
-	return 0;
-}
 
+	retval = -EIO;
+	bh = affs_bread(sb, inode->i_ino);
+	if (!bh)
+		goto done;
+
+	retval = affs_remove_hash(dir, bh);
+	if (retval)
+		goto done_unlock;
+
+	up(&AFFS_DIR->i_hash_lock);
+
+	if (inode->i_nlink > 1)
+		retval = affs_remove_link(dentry);
+	else
+		inode->i_nlink = 0;
+	inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+
+done:
+	affs_brelse(bh);
+	return retval;
+
+done_unlock:
+	up(&AFFS_DIR->i_hash_lock);
+	goto done;
+}
 
 /* Checksum a block, do various consistency checks and optionally return
    the blocks type number.  DATA points to the block.  If their pointers
@@ -289,21 +323,15 @@
    Returns non-zero if the block is not consistent. */
 
 u32
-affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
+affs_checksum_block(struct super_block *sb, struct buffer_head *bh)
 {
-	u32	 sum;
-	u32	*p;
-
-	bsize /= 4;
-	if (ptype)
-		*ptype = be32_to_cpu(((s32 *)data)[0]);
-	if (stype)
-		*stype = be32_to_cpu(((s32 *)data)[bsize - 1]);
-
-	sum    = 0;
-	p      = data;
-	while (bsize--)
-		sum += be32_to_cpu(*p++);
+	u32 *ptr = (u32 *)bh->b_data;
+	u32 sum;
+	int bsize;
+
+	sum = 0;
+	for (bsize = sb->s_blocksize / sizeof(u32); bsize > 0; bsize--)
+		sum += be32_to_cpu(*ptr++);
 	return sum;
 }
 
@@ -313,19 +341,21 @@
  */
 
 void
-affs_fix_checksum(int bsize, void *data, int cspos)
+affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
 {
-	u32	 ocs;
-	u32	 cs;
-
-	cs   = affs_checksum_block(bsize,data,NULL,NULL);
-	ocs  = be32_to_cpu(((u32 *)data)[cspos]);
-	ocs -= cs;
-	((u32 *)data)[cspos] = be32_to_cpu(ocs);
+	int cnt = sb->s_blocksize / sizeof(u32);
+	u32 *ptr = (u32 *)bh->b_data;
+	u32 checksum, *checksumptr;
+
+	checksumptr = ptr + 5;
+	*checksumptr = 0;
+	for (checksum = 0; cnt > 0; ptr++, cnt--)
+		checksum += be32_to_cpu(*ptr);
+	*checksumptr = cpu_to_be32(-checksum);
 }
 
 void
-secs_to_datestamp(time_t secs, struct DateStamp *ds)
+secs_to_datestamp(time_t secs, struct affs_date *ds)
 {
 	u32	 days;
 	u32	 minute;
@@ -338,59 +368,64 @@
 	minute  = secs / 60;
 	secs   -= minute * 60;
 
-	ds->ds_Days   = be32_to_cpu(days);
-	ds->ds_Minute = be32_to_cpu(minute);
-	ds->ds_Tick   = be32_to_cpu(secs * 50);
+	ds->days = be32_to_cpu(days);
+	ds->mins = be32_to_cpu(minute);
+	ds->ticks = be32_to_cpu(secs * 50);
 }
 
-int
+mode_t
 prot_to_mode(u32 prot)
 {
-	int	 mode = 0;
+	int mode = 0;
 
-	if (AFFS_UMAYWRITE(prot))
+	if (!(prot & FIBF_NOWRITE))
 		mode |= S_IWUSR;
-	if (AFFS_UMAYREAD(prot))
+	if (!(prot & FIBF_NOREAD))
 		mode |= S_IRUSR;
-	if (AFFS_UMAYEXECUTE(prot))
+	if (!(prot & FIBF_NOEXECUTE))
 		mode |= S_IXUSR;
-	if (AFFS_GMAYWRITE(prot))
+	if (prot & FIBF_GRP_WRITE)
 		mode |= S_IWGRP;
-	if (AFFS_GMAYREAD(prot))
+	if (prot & FIBF_GRP_READ)
 		mode |= S_IRGRP;
-	if (AFFS_GMAYEXECUTE(prot))
+	if (prot & FIBF_GRP_EXECUTE)
 		mode |= S_IXGRP;
-	if (AFFS_OMAYWRITE(prot))
+	if (prot & FIBF_OTR_WRITE)
 		mode |= S_IWOTH;
-	if (AFFS_OMAYREAD(prot))
+	if (prot & FIBF_OTR_READ)
 		mode |= S_IROTH;
-	if (AFFS_OMAYEXECUTE(prot))
+	if (prot & FIBF_OTR_EXECUTE)
 		mode |= S_IXOTH;
-	
+
 	return mode;
 }
 
-u32
-mode_to_prot(int mode)
+void
+mode_to_prot(struct inode *inode)
 {
-	u32	 prot = 0;
+	u32 prot = AFFS_INODE->i_protect;
+	mode_t mode = inode->i_mode;
 
-	if (mode & S_IXUSR)
-		prot |= FIBF_SCRIPT;
-	if (mode & S_IRUSR)
-		prot |= FIBF_READ;
-	if (mode & S_IWUSR)
-		prot |= FIBF_WRITE | FIBF_DELETE;
+	if (!(mode & S_IXUSR))
+		prot |= FIBF_NOEXECUTE;
+	if (!(mode & S_IRUSR))
+		prot |= FIBF_NOREAD;
+	if (!(mode & S_IWUSR))
+		prot |= FIBF_NOWRITE;
+	if (mode & S_IXGRP)
+		prot |= FIBF_GRP_EXECUTE;
 	if (mode & S_IRGRP)
 		prot |= FIBF_GRP_READ;
 	if (mode & S_IWGRP)
 		prot |= FIBF_GRP_WRITE;
+	if (mode & S_IXOTH)
+		prot |= FIBF_OTR_EXECUTE;
 	if (mode & S_IROTH)
 		prot |= FIBF_OTR_READ;
 	if (mode & S_IWOTH)
 		prot |= FIBF_OTR_WRITE;
-	
-	return prot;
+
+	AFFS_INODE->i_protect = prot;
 }
 
 void
@@ -402,12 +437,12 @@
 	vsprintf(ErrorBuffer,fmt,args);
 	va_end(args);
 
-	printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+	printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", bdevname(sb->s_dev),
 		function,ErrorBuffer);
 	if (!(sb->s_flags & MS_RDONLY))
 		printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
 	sb->s_flags |= MS_RDONLY;
-	sb->u.affs_sb.s_flags |= SF_READONLY;	/* Don't allow to remount rw */
+	AFFS_SB->s_flags |= SF_READONLY;	/* Don't allow to remount rw */
 }
 
 void
@@ -419,7 +454,7 @@
 	vsprintf(ErrorBuffer,fmt,args);
 	va_end(args);
 
-	printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n",kdevname(sb->s_dev),
+	printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", bdevname(sb->s_dev),
 		function,ErrorBuffer);
 }
 
@@ -454,15 +489,11 @@
  */
 
 int
-affs_copy_name(unsigned char *bstr, const unsigned char *name)
+affs_copy_name(unsigned char *bstr, struct dentry *dentry)
 {
-	int	 len;
+	int len = MIN(dentry->d_name.len, 30);
 
-	for (len = 0; len < 30; len++) {
-		bstr[len + 1] = name[len];
-		if (name[len] == '\0')
-			break;
-	}
-	bstr[0] = len;
+	*bstr++ = len;
+	memcpy(bstr, dentry->d_name.name, len);
 	return len;
 }
diff -u --recursive --new-file v2.4.3/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- v2.4.3/linux/fs/affs/bitmap.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/affs/bitmap.c	Wed Apr 25 14:57:09 2001
@@ -7,100 +7,129 @@
  *  block allocation, deallocation, calculation of free space.
  */
 
-#define DEBUG 0
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
 #include <linux/stat.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/bitops.h>
 #include <linux/amigaffs.h>
 
-#include <asm/bitops.h>
-
 /* This is, of course, shamelessly stolen from fs/minix */
 
 static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
 
-int
-affs_count_free_bits(int blocksize, const char *data)
+u32
+affs_count_free_bits(u32 blocksize, const void *data)
 {
-  int	 free;
-  int	 i;
+	const u32 *map;
+	u32 free;
+	u32 tmp;
 
-  free = 0;
-  for (i = 0; i < blocksize; i++) {
-    free  += nibblemap[data[i] & 0xF] + nibblemap[(data[i]>>4) & 0xF];
-  }
+	map = data;
+	free = 0;
+	for (blocksize /= 4; blocksize > 0; blocksize--) {
+		tmp = *map++;
+		while (tmp) {
+			free += nibblemap[tmp & 0xf];
+			tmp >>= 4;
+		}
+	}
 
-  return free;
+	return free;
 }
 
-int
-affs_count_free_blocks(struct super_block *s)
+u32
+affs_count_free_blocks(struct super_block *sb)
 {
-	int	 free;
-	int	 i;
+	struct affs_bm_info *bm;
+	u32 free;
+	int i;
 
 	pr_debug("AFFS: count_free_blocks()\n");
 
+	if (sb->s_flags & MS_RDONLY)
+		return 0;
+
+	down(&AFFS_SB->s_bmlock);
+
+	bm = AFFS_SB->s_bitmap;
 	free = 0;
-	if (s->u.affs_sb.s_flags & SF_BM_VALID) {
-		for (i = 0; i < s->u.affs_sb.s_num_az; i++) {
-			free += s->u.affs_sb.s_alloc[i].az_free;
-		}
-	}
+	for (i = AFFS_SB->s_bmap_count; i > 0; bm++, i--)
+		free += bm->bm_free;
+
+	up(&AFFS_SB->s_bmlock);
+
 	return free;
 }
 
 void
-affs_free_block(struct super_block *sb, s32 block)
+affs_free_block(struct super_block *sb, u32 block)
 {
-	int			 bmap;
-	int			 bit;
-	int			 blk;
-	int			 zone_no;
-	struct affs_bm_info	*bm;
-
-	pr_debug("AFFS: free_block(%d)\n",block);
-
-	blk     = block - sb->u.affs_sb.s_reserved;
-	bmap    = blk / (sb->s_blocksize * 8 - 32);
-	bit     = blk % (sb->s_blocksize * 8 - 32);
-	zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024;
-	bm      = &sb->u.affs_sb.s_bitmap[bmap];
-	if (bmap >= sb->u.affs_sb.s_bm_count) {
-		affs_error(sb,"affs_free_block","Block %d outside partition",block);
-		return;
-	}
-	blk = 0;
-	set_bit(bit & 31,&blk);
+	struct affs_bm_info *bm;
+	struct buffer_head *bh;
+	u32 blk, bmap, bit, mask, tmp;
+	u32 *data;
+
+	pr_debug("AFFS: free_block(%u)\n", block);
+
+	if (block > AFFS_SB->s_partition_size)
+		goto err_range;
+
+	blk     = block - AFFS_SB->s_reserved;
+	bmap    = blk / AFFS_SB->s_bmap_bits;
+	bit     = blk % AFFS_SB->s_bmap_bits;
+	bm      = &AFFS_SB->s_bitmap[bmap];
+
+	down(&AFFS_SB->s_bmlock);
+
+	bh = AFFS_SB->s_bmap_bh;
+	if (AFFS_SB->s_last_bmap != bmap) {
+		affs_brelse(bh);
+		bh = affs_bread(sb, bm->bm_key);
+		if (!bh)
+			goto err_bh_read;
+		AFFS_SB->s_bmap_bh = bh;
+		AFFS_SB->s_last_bmap = bmap;
+	}
+
+	mask = 1 << (bit & 31);
+	data = (u32 *)bh->b_data + bit / 32 + 1;
+
+	/* mark block free */
+	tmp = be32_to_cpu(*data);
+	if (tmp & mask)
+		goto err_free;
+	*data = cpu_to_be32(tmp | mask);
+
+	/* fix checksum */
+	tmp = be32_to_cpu(*(u32 *)bh->b_data);
+	*(u32 *)bh->b_data = cpu_to_be32(tmp - mask);
 
-	lock_super(sb);
-	bm->bm_count++;
-	if (!bm->bm_bh) {
-		bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize);
-		if (!bm->bm_bh) {
-			bm->bm_count--;
-			unlock_super(sb);
-			affs_error(sb,"affs_free_block","Cannot read bitmap block %d",bm->bm_key);
-			return;
-		}
-	}
-	if (test_and_set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
-		affs_warning(sb,"affs_free_block","Trying to free block %d which is already free",
-				block);
-	else {
-		sb->u.affs_sb.s_alloc[zone_no].az_free++;
-		((u32 *)bm->bm_bh->b_data)[0] = cpu_to_be32(be32_to_cpu(((u32 *)bm->bm_bh->b_data)[0]) - blk);
-		mark_buffer_dirty(bm->bm_bh);
-		sb->s_dirt = 1;
-	}
-	if (--bm->bm_count == 0) {
-		affs_brelse(bm->bm_bh);
-		bm->bm_bh = NULL;
-	}
-	unlock_super(sb);
+	mark_buffer_dirty(bh);
+	sb->s_dirt = 1;
+	bm->bm_free++;
+
+	up(&AFFS_SB->s_bmlock);
+	return;
+
+err_free:
+	affs_warning(sb,"affs_free_block","Trying to free block %u which is already free", block);
+	up(&AFFS_SB->s_bmlock);
+	return;
+
+err_bh_read:
+	affs_error(sb,"affs_free_block","Cannot read bitmap block %u", bm->bm_key);
+	AFFS_SB->s_bmap_bh = NULL;
+	AFFS_SB->s_last_bmap = ~0;
+	up(&AFFS_SB->s_bmlock);
+	return;
+
+err_range:
+	affs_error(sb, "affs_free_block","Block %u outside partition", block);
+	return;
 }
 
 /*
@@ -112,266 +141,240 @@
  * header zone, though.
  */
 
-static s32
-affs_balloc(struct inode *inode, int zone_no)
+u32
+affs_alloc_block(struct inode *inode, u32 goal)
 {
-	u32			 w;
-	u32			*bm;
-	int			 fb;
-	int			 i;
-	int			 fwb;
-	s32			 block;
-	struct affs_zone	*zone;
-	struct affs_alloc_zone	*az;
-	struct super_block	*sb;
-
-	sb   = inode->i_sb;
-	zone = &sb->u.affs_sb.s_zones[zone_no];
-
-	if (!zone->z_bm || !zone->z_bm->bm_bh)
-		return 0;	
-
-	pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
-
-	az = &sb->u.affs_sb.s_alloc[zone->z_az_no];
-	bm = (u32 *)zone->z_bm->bm_bh->b_data;
-repeat:
-	for (i = zone->z_start; i < zone->z_end; i++) {
-		if (bm[i])
-			goto found;
-	}
-	return 0;	
+	struct super_block *sb;
+	struct affs_bm_info *bm;
+	struct buffer_head *bh;
+	u32 *data, *enddata;
+	u32 blk, bmap, bit, mask, mask2, tmp;
+	int i;
 
-found:
-	fwb = zone->z_bm->bm_firstblk + (i - 1) * 32;
-	lock_super(sb);
-	zone->z_start = i;
-	w   = ~be32_to_cpu(bm[i]);
-	fb  = find_first_zero_bit(&w,32);
-	if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
-		unlock_super(sb);
-		affs_warning(sb,"balloc","Empty block disappeared somehow");
-		goto repeat;
-	}
-	block = fwb + fb;
-	az->az_free--;
+	sb = inode->i_sb;
 
-	/* prealloc as much as possible within this word, but not in header zone */
+	pr_debug("AFFS: balloc(inode=%lu,goal=%u): ", inode->i_ino, goal);
 
-	if (zone_no) {
-		while (inode->u.affs_i.i_pa_cnt < AFFS_MAX_PREALLOC && ++fb < 32) {
-			fb = find_next_zero_bit(&w,32,fb);
-			if (fb > 31)
-				break;
-			if (!test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
-				affs_warning(sb,"balloc","Empty block disappeared somehow");
-				break;
-			}
-			inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
-			inode->u.affs_i.i_pa_last &= AFFS_MAX_PREALLOC - 1;
-			inode->u.affs_i.i_pa_cnt++;
-			az->az_free--;
-		}
+	if (inode->u.affs_i.i_pa_cnt) {
+		pr_debug("%d\n", inode->u.affs_i.i_lastalloc+1);
+		inode->u.affs_i.i_pa_cnt--;
+		return ++inode->u.affs_i.i_lastalloc;
 	}
-	w     = ~w - be32_to_cpu(bm[i]);
-	bm[0] = cpu_to_be32(be32_to_cpu(bm[0]) + w);
-	unlock_super(sb);
-	mark_buffer_dirty(zone->z_bm->bm_bh);
-	sb->s_dirt = 1;
-	zone->z_lru_time = jiffies;
-
-	return block;
-}
-
-/* Find a new allocation zone, starting at zone_no. */
 
-static int
-affs_find_new_zone(struct super_block *sb, int zone_no)
-{
-	struct affs_bm_info	*bm;
-	struct affs_zone	*zone;
-	struct affs_alloc_zone	*az;
-	int			 bestfree;
-	int			 bestno;
-	int			 bestused;
-	int			 lusers;
-	int			 i;
-	int			 min;
-
-	pr_debug("AFFS: find_new_zone(zone_no=%d)\n",zone_no);
-
-	bestfree = 0;
-	bestused = -1;
-	bestno   = -1;
-	lusers   = MAX_ZONES;
-	min      = zone_no ? AFFS_DATA_MIN_FREE : AFFS_HDR_MIN_FREE;
-	lock_super(sb);
-	zone = &sb->u.affs_sb.s_zones[zone_no];
-	i    = zone->z_az_no;
-	az   = &sb->u.affs_sb.s_alloc[i];
-	if (zone->z_bm && zone->z_bm->bm_count) {
-		if (--zone->z_bm->bm_count == 0) {
-			affs_brelse(zone->z_bm->bm_bh);
-			zone->z_bm->bm_bh = NULL;
-		}
-		if (az->az_count)
-			az->az_count--;
-		else
-			affs_error(sb,"find_new_zone","az_count=0, but bm used");
-
-	}
-	while (1) {
-		az = &sb->u.affs_sb.s_alloc[i];
-		if (!az->az_count) {
-			if (az->az_free > min) {
-				break;
-			}
-			if (az->az_free > bestfree) {
-				bestfree = az->az_free;
-				bestno   = i;
-			}
-		} else if (az->az_free && az->az_count < lusers) {
-			lusers   = az->az_count;
-			bestused = i;
-		}
-		if (++i >= sb->u.affs_sb.s_num_az)
-			i = 0;
-		if (i == zone->z_az_no) {		/* Seen all */
-			if (bestno >= 0) {
-				i = bestno;
-			} else {
-				i = bestused;
-			}
+	if (!goal || goal > AFFS_SB->s_partition_size) {
+		if (goal)
+			affs_warning(sb, "affs_balloc", "invalid goal %d", goal);
+		//if (!inode->u.affs_i.i_last_block)
+		//	affs_warning(sb, "affs_balloc", "no last alloc block");
+		goal = AFFS_SB->s_reserved;
+	}
+
+	blk = goal - AFFS_SB->s_reserved;
+	bmap = blk / AFFS_SB->s_bmap_bits;
+	bm = &AFFS_SB->s_bitmap[bmap];
+
+	down(&AFFS_SB->s_bmlock);
+
+	if (bm->bm_free)
+		goto find_bmap_bit;
+
+find_bmap:
+	/* search for the next bmap buffer with free bits */
+	i = AFFS_SB->s_bmap_count;
+	do {
+		bmap++;
+		bm++;
+		if (bmap < AFFS_SB->s_bmap_count)
+			continue;
+		/* restart search at zero */
+		bmap = 0;
+		bm = AFFS_SB->s_bitmap;
+		if (--i <= 0)
+			goto err_full;
+	} while (!bm->bm_free);
+	blk = bmap * AFFS_SB->s_bmap_bits;
+
+find_bmap_bit:
+
+	bh = AFFS_SB->s_bmap_bh;
+	if (AFFS_SB->s_last_bmap != bmap) {
+		affs_brelse(bh);
+		bh = affs_bread(sb, bm->bm_key);
+		if (!bh)
+			goto err_bh_read;
+		AFFS_SB->s_bmap_bh = bh;
+		AFFS_SB->s_last_bmap = bmap;
+	}
+
+	/* find an unused block in this bitmap block */
+	bit = blk % AFFS_SB->s_bmap_bits;
+	data = (u32 *)bh->b_data + bit / 32 + 1;
+	enddata = (u32 *)((u8 *)bh->b_data + sb->s_blocksize);
+	mask = ~0UL << (bit & 31);
+	blk &= ~31UL;
+
+	tmp = be32_to_cpu(*data) & mask;
+	if (tmp)
+		goto find_bit;
+
+	/* scan the rest of the buffer */
+	do {
+		blk += 32;
+		if (++data >= enddata)
+			/* didn't find something, can only happen
+			 * if scan didn't start at 0, try next bmap
+			 */
+			goto find_bmap;
+	} while (!(tmp = *data));
+	tmp = be32_to_cpu(tmp);
+
+find_bit:
+	/* finally look for a free bit in the word */
+	bit = ffs(tmp) - 1;
+	blk += bit + AFFS_SB->s_reserved;
+	mask2 = mask = 1 << (bit & 31);
+	inode->u.affs_i.i_lastalloc = blk;
+
+	/* prealloc as much as possible within this word */
+	while ((mask2 <<= 1)) {
+		if (!(tmp & mask2))
 			break;
-		}
+		inode->u.affs_i.i_pa_cnt++;
+		mask |= mask2;
 	}
-	if (i < 0) {
-		/* Didn't find a single free block anywhere. */
-		unlock_super(sb);
-		return 0;
-	}
-	az = &sb->u.affs_sb.s_alloc[i];
-	az->az_count++;
-	bm = &sb->u.affs_sb.s_bitmap[i >> (sb->s_blocksize_bits - 7)];
-	bm->bm_count++;
-	if (!bm->bm_bh)
-		bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize);
-	if (!bm->bm_bh) {
-		bm->bm_count--;
-		az->az_count--;
-		unlock_super(sb);
-		affs_error(sb,"find_new_zone","Cannot read bitmap");
-		return 0;
-	}
-	zone->z_bm    = bm;
-	zone->z_start = (i & ((sb->s_blocksize / 128) - 1)) * 32 + 1;
-	zone->z_end   = zone->z_start + az->az_size;
-	zone->z_az_no = i;
-	zone->z_lru_time = jiffies;
-	pr_debug("AFFS: found zone (%d) in bm %d at lw offset %d with %d free blocks\n",
-		 i,(i >> (sb->s_blocksize_bits - 7)),zone->z_start,az->az_free);
-	unlock_super(sb);
-	return az->az_free;
-}
+	bm->bm_free -= inode->u.affs_i.i_pa_cnt + 1;
 
-/* Allocate a new header block. */
-
-s32
-affs_new_header(struct inode *inode)
-{
-	s32			 block;
+	*data = cpu_to_be32(tmp & ~mask);
 
-	pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino);
+	/* fix checksum */
+	tmp = be32_to_cpu(*(u32 *)bh->b_data);
+	*(u32 *)bh->b_data = cpu_to_be32(tmp + mask);
 
-	if (!(block = affs_balloc(inode,0))) {
-		while (affs_find_new_zone(inode->i_sb,0)) {
-			if ((block = affs_balloc(inode,0)))
-				return block;
-			schedule();
-		}
-		return 0;
-	}
-	return block;
-}
+	mark_buffer_dirty(bh);
+	sb->s_dirt = 1;
 
-/* Allocate a new data block. */
+	up(&AFFS_SB->s_bmlock);
 
-s32
-affs_new_data(struct inode *inode)
-{
-	int			 empty, old;
-	unsigned long		 oldest;
-	struct affs_zone	*zone;
-	struct super_block	*sb;
-	int			 i = 0;
-	s32			 block;
+	pr_debug("%d\n", blk);
+	return blk;
 
-	pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
+err_bh_read:
+	affs_error(sb,"affs_read_block","Cannot read bitmap block %u", bm->bm_key);
+	AFFS_SB->s_bmap_bh = NULL;
+	AFFS_SB->s_last_bmap = ~0;
+err_full:
+	pr_debug("failed\n");
+	up(&AFFS_SB->s_bmlock);
+	return 0;
+}
 
-	sb = inode->i_sb;
-	lock_super(sb);
-	if (inode->u.affs_i.i_pa_cnt) {
-		inode->u.affs_i.i_pa_cnt--;
-		unlock_super(sb);
-		block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
-		inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
-		return block;
-	}
-	unlock_super(sb);
-	oldest = jiffies;
-	old    = 0;
-	empty  = 0;
-	zone   = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
-	if (zone->z_ino == inode->i_ino) {
-		i = inode->u.affs_i.i_zone;
-		goto found;
-	}
-	for (i = 1; i < MAX_ZONES; i++) {
-		zone = &sb->u.affs_sb.s_zones[i];
-		if (!empty && zone->z_bm && !zone->z_ino)
-			empty = i;
-		if (zone->z_bm && zone->z_lru_time < oldest) {
-			old    = i;
-			oldest = zone->z_lru_time;
-		}
-	}
-	if (empty)
-		i = empty;
-	else if (old)
-		i = old;
-	else {
-		inode->u.affs_i.i_zone = 0;
-		return affs_new_header(inode);
-	}
+int
+affs_init_bitmap(struct super_block *sb)
+{
+	struct affs_bm_info *bm;
+	struct buffer_head *bmap_bh = NULL, *bh = NULL;
+	u32 *bmap_blk;
+	u32 size, blk, end, offset, mask;
+	int i, res = 0;
 
-	inode->u.affs_i.i_zone = i;
-	zone->z_ino            = inode->i_ino;
+	if (sb->s_flags & MS_RDONLY)
+		return 0;
 
-found:
-	zone = &sb->u.affs_sb.s_zones[i];
-	if (!(block = affs_balloc(inode,i))) {		/* No data zones left */
-		while (affs_find_new_zone(sb,i)) {
-			if ((block = affs_balloc(inode,i)))
-				return block;
-			schedule();
-		}
-		inode->u.affs_i.i_zone = 0;
-		zone->z_ino            = -1;
+	if (!AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag) {
+		printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
+			kdevname(sb->s_dev));
+		sb->s_flags |= MS_RDONLY;
 		return 0;
 	}
-	return block;
-}
-
-void
-affs_make_zones(struct super_block *sb)
-{
-	int	 i, mid;
 
-	pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_az);
+	AFFS_SB->s_last_bmap = ~0;
+	AFFS_SB->s_bmap_bh = NULL;
+	AFFS_SB->s_bmap_bits = sb->s_blocksize * 8 - 32;
+	AFFS_SB->s_bmap_count = (AFFS_SB->s_partition_size - AFFS_SB->s_reserved +
+				 AFFS_SB->s_bmap_bits - 1) / AFFS_SB->s_bmap_bits;
+	size = AFFS_SB->s_bmap_count * sizeof(struct affs_bm_info);
+	bm = AFFS_SB->s_bitmap = kmalloc(size, GFP_KERNEL);
+	if (!AFFS_SB->s_bitmap) {
+		printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
+		return 1;
+	}
+	memset(AFFS_SB->s_bitmap, 0, size);
+
+	bmap_blk = (u32 *)AFFS_SB->s_root_bh->b_data;
+	blk = sb->s_blocksize / 4 - 49;
+	end = blk + 25;
+
+	for (i = AFFS_SB->s_bmap_count; i > 0; bm++, i--) {
+		affs_brelse(bh);
+
+		bm->bm_key = be32_to_cpu(bmap_blk[blk]);
+		bh = affs_bread(sb, bm->bm_key);
+		if (!bh) {
+			printk(KERN_ERR "AFFS: Cannot read bitmap\n");
+			res = 1;
+			goto out;
+		}
+		if (affs_checksum_block(sb, bh)) {
+			printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n",
+			       bm->bm_key, kdevname(sb->s_dev));
+			sb->s_flags |= MS_RDONLY;
+			goto out;
+		}
+		pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
+		bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
 
-	mid = (sb->u.affs_sb.s_num_az + 1) / 2;
-	for (i = 0; i < MAX_ZONES; i++) {
-		sb->u.affs_sb.s_zones[i].z_az_no = mid;
-		affs_find_new_zone(sb,i);
-	}
+		/* Don't try read the extension if this is the last block,
+		 * but we also need the right bm pointer below
+		 */
+		if (++blk < end || i == 1)
+			continue;
+		if (bmap_bh)
+			affs_brelse(bmap_bh);
+		bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk]));
+		if (!bmap_bh) {
+			printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
+			res = 1;
+			goto out;
+		}
+		bmap_blk = (u32 *)bmap_bh->b_data;
+		blk = 0;
+		end = sb->s_blocksize / 4 - 1;
+	}
+
+	offset = (AFFS_SB->s_partition_size - AFFS_SB->s_reserved) % AFFS_SB->s_bmap_bits;
+	mask = ~(0xFFFFFFFFU << (offset & 31));
+	pr_debug("last word: %d %d %d\n", offset, offset / 32 + 1, mask);
+	offset = offset / 32 + 1;
+
+	if (mask) {
+		u32 old, new;
+
+		/* Mark unused bits in the last word as allocated */
+		old = be32_to_cpu(((u32 *)bh->b_data)[offset]);
+		new = old & mask;
+		//if (old != new) {
+			((u32 *)bh->b_data)[offset] = cpu_to_be32(new);
+			/* fix checksum */
+			//new -= old;
+			//old = be32_to_cpu(*(u32 *)bh->b_data);
+			//*(u32 *)bh->b_data = cpu_to_be32(old - new);
+			//mark_buffer_dirty(bh);
+		//}
+		/* correct offset for the bitmap count below */
+		//offset++;
+	}
+	while (++offset < sb->s_blocksize / 4)
+		((u32 *)bh->b_data)[offset] = 0;
+	((u32 *)bh->b_data)[0] = 0;
+	((u32 *)bh->b_data)[0] = cpu_to_be32(-affs_checksum_block(sb, bh));
+	mark_buffer_dirty(bh);
+
+	/* recalculate bitmap count for last block */
+	bm--;
+	bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+
+out:
+	affs_brelse(bh);
+	affs_brelse(bmap_bh);
+	return res;
 }
diff -u --recursive --new-file v2.4.3/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- v2.4.3/linux/fs/affs/dir.c	Fri Aug 11 14:29:02 2000
+++ linux/fs/affs/dir.c	Thu Apr 19 22:57:06 2001
@@ -13,7 +13,6 @@
  *
  */
 
-#define DEBUG 0
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -50,109 +49,115 @@
 static int
 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-	int			 j, namelen;
-	s32			 i;
+	struct inode		*inode = filp->f_dentry->d_inode;
+	struct super_block	*sb = inode->i_sb;
+	struct buffer_head	*dir_bh;
+	struct buffer_head	*fh_bh;
+	unsigned char		*name;
+	int			 namelen;
+	u32			 i;
 	int			 hash_pos;
 	int			 chain_pos;
-	unsigned long		 ino;
+	u32			 f_pos;
+	u32			 ino;
 	int			 stored;
-	unsigned char		*name;
-	struct buffer_head	*dir_bh;
-	struct buffer_head	*fh_bh;
-	struct inode		*dir;
-	struct inode		*inode = filp->f_dentry->d_inode;
+	int			 res;
 
-	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
+	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
 	stored = 0;
+	res    = -EIO;
 	dir_bh = NULL;
 	fh_bh  = NULL;
-	dir    = NULL;
-	ino    = inode->i_ino;
+	f_pos  = filp->f_pos;
 
-	if (filp->f_pos == 0) {
+	if (f_pos == 0) {
 		filp->private_data = (void *)0;
-		if (filldir(dirent,".",1,filp->f_pos,inode->i_ino,DT_DIR) < 0) {
+		if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
 			return 0;
-		}
-		++filp->f_pos;
+		filp->f_pos = f_pos = 1;
 		stored++;
 	}
-	if (filp->f_pos == 1) {
-		if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode),DT_DIR) < 0) {
+	if (f_pos == 1) {
+		if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
 			return stored;
-		}
-		filp->f_pos = 2;
+		filp->f_pos = f_pos = 2;
 		stored++;
 	}
-	chain_pos = (filp->f_pos - 2) & 0xffff;
-	hash_pos  = (filp->f_pos - 2) >> 16;
+
+	down(&AFFS_INODE->i_hash_lock);
+	chain_pos = (f_pos - 2) & 0xffff;
+	hash_pos  = (f_pos - 2) >> 16;
 	if (chain_pos == 0xffff) {
-		affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
+		affs_warning(sb, "readdir", "More than 65535 entries in chain");
 		chain_pos = 0;
 		hash_pos++;
 		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 	}
-	if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
-				  AFFS_I2BSIZE(inode))))
-		goto readdir_done;
-
-	while (1) {
-		while (hash_pos < AFFS_I2HSIZE(inode) &&
-		     !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
-			hash_pos++;
-		if (hash_pos >= AFFS_I2HSIZE(inode))
-			break;
-		
-		i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
-		j = chain_pos;
-
-		/* If the directory hasn't changed since the last call to readdir(),
-		 * we can jump directly to where we left off.
-		 */
-		if (filp->private_data && filp->f_version == inode->i_version) {
-			i = (s32)(unsigned long)filp->private_data;
-			j = 0;
-			pr_debug("AFFS: readdir() left off=%d\n",i);
+	dir_bh = affs_bread(sb, inode->i_ino);
+	if (!dir_bh)
+		goto readdir_out;
+
+	/* If the directory hasn't changed since the last call to readdir(),
+	 * we can jump directly to where we left off.
+	 */
+	ino = (u32)filp->private_data;
+	if (ino && filp->f_version == inode->i_version) {
+		pr_debug("AFFS: readdir() left off=%d\n", ino);
+		goto inside;
+	}
+
+	ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
+	for (i = 0; ino && i < chain_pos; i++) {
+		fh_bh = affs_bread(sb, ino);
+		if (!fh_bh) {
+			affs_error(sb, "readdir","Cannot read block %d", i);
+			goto readdir_out;
 		}
-		filp->f_version = inode->i_version;
-		pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
-		while (i) {
-			if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
-				affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
+		ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
+		affs_brelse(fh_bh);
+		fh_bh = NULL;
+	}
+	if (ino)
+		goto inside;
+	hash_pos++;
+
+	for (; hash_pos < AFFS_SB->s_hashsize; hash_pos++) {
+		ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
+		if (!ino)
+			continue;
+		f_pos = (hash_pos << 16) + 2;
+inside:
+		do {
+			fh_bh = affs_bread(sb, ino);
+			if (!fh_bh) {
+				affs_error(sb, "readdir","Cannot read block %d", ino);
 				goto readdir_done;
 			}
-			ino = i;
-			i   = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
-			if (j == 0)
-				break;
-			affs_brelse(fh_bh);
-			fh_bh = NULL;
-			j--;
-		}
-		if (fh_bh) {
-			namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
-			pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
-				 namelen,name,ino,i);
-			filp->private_data = (void *)ino;
-			if (filldir(dirent,name,namelen,filp->f_pos,ino,DT_UNKNOWN) < 0)
+
+			namelen = MIN(AFFS_TAIL(sb, fh_bh)->name[0], 30);
+			name = AFFS_TAIL(sb, fh_bh)->name + 1;
+			pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
+				 namelen, name, ino, hash_pos, f_pos);
+			if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
 				goto readdir_done;
-			filp->private_data = (void *)(unsigned long)i;
+			stored++;
+			f_pos++;
+			ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
 			affs_brelse(fh_bh);
 			fh_bh = NULL;
-			stored++;
-		}
-		if (i == 0) {
-			hash_pos++;
-			chain_pos = 0;
-		} else
-			chain_pos++;
-		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+		} while (ino);
 	}
-
 readdir_done:
+	filp->f_pos = f_pos;
+	filp->f_version = inode->i_version;
+	filp->private_data = (void *)ino;
+	res = stored;
+
+readdir_out:
 	affs_brelse(dir_bh);
 	affs_brelse(fh_bh);
-	pr_debug("AFFS: readdir()=%d\n",stored);
-	return stored;
+	up(&AFFS_INODE->i_hash_lock);
+	pr_debug("AFFS: readdir()=%d\n", stored);
+	return res;
 }
diff -u --recursive --new-file v2.4.3/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.4.3/linux/fs/affs/file.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/affs/file.c	Thu Apr 19 22:57:06 2001
@@ -12,7 +12,6 @@
  *  affs regular file handling primitives
  */
 
-#define DEBUG 0
 #include <asm/div64.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -31,23 +30,26 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
 #if PAGE_SIZE < 4096
 #error PAGE_SIZE must be at least 4096
 #endif
 
-static struct buffer_head *affs_getblock(struct inode *inode, s32 block);
-static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos);
+static int affs_grow_extcache(struct inode *inode, u32 lc_idx);
+static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);
+static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);
+static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
+static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create);
+
 static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
-static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos);
-static int alloc_ext_cache(struct inode *inode);
+static int affs_file_open(struct inode *inode, struct file *filp);
+static int affs_file_release(struct inode *inode, struct file *filp);
 
 struct file_operations affs_file_operations = {
 	read:		generic_file_read,
 	write:		affs_file_write,
 	mmap:		generic_file_mmap,
+	open:		affs_file_open,
+	release:	affs_file_release,
 	fsync:		file_fsync,
 };
 
@@ -56,299 +58,368 @@
 	setattr:	affs_notify_change,
 };
 
-struct file_operations affs_file_operations_ofs = {
-	read:		affs_file_read_ofs,
-	write:		affs_file_write_ofs,
-	fsync:		file_fsync,
-};
-
-#define AFFS_ISINDEX(x)	((x < 129) ||				\
-			 (x < 512 && (x & 1) == 0) ||		\
-			 (x < 1024 && (x & 3) == 0) ||		\
-			 (x < 2048 && (x & 15) == 0) ||		\
-			 (x < 4096 && (x & 63) == 0) ||		\
-			 (x < 20480 && (x & 255) == 0) ||	\
-			 (x < 36864 && (x & 511) == 0))
-
-/* The keys of the extension blocks are stored in a 512-entry
- * deep cache. In order to save memory, not every key of later
- * extension blocks is stored - the larger the file gets, the
- * bigger the holes in between.
- */
-
 static int
-seqnum_to_index(int seqnum)
+affs_file_open(struct inode *inode, struct file *filp)
 {
-	/* All of the first 127 keys are stored */
-	if (seqnum < 128)
-		return seqnum;
-	seqnum -= 128;
-
-	/* Of the next 384 keys, every 2nd is kept */
-	if (seqnum < (192 * 2))
-		return 128 + (seqnum >> 1);
-	seqnum -= 192 * 2;
-	
-	/* Every 4th of the next 512 */
-	if (seqnum < (128 * 4))
-		return 128 + 192 + (seqnum >> 2);
-	seqnum -= 128 * 4;
-
-	/* Every 16th of the next 1024 */
-	if (seqnum < (64 * 16))
-		return 128 + 192 + 128 + (seqnum >> 4);
-	seqnum -= 64 * 16;
-
-	/* Every 64th of the next 2048 */
-	if (seqnum < (32 * 64))
-		return 128 + 192 + 128 + 64 + (seqnum >> 6);
-	seqnum -= 32 * 64;
-
-	/* Every 256th of the next 16384 */
-	if (seqnum < (64 * 256))
-		return 128 + 192 + 128 + 64 + 32 + (seqnum >> 8);
-	seqnum -= 64 * 256;
-
-	/* Every 512th upto 36479 (1.3 GB with 512 byte blocks).
-	 * Seeking to positions behind this will get slower
-	 * than dead snails nailed to the ground. But if
-	 * someone uses files that large with 512-byte blocks,
-	 * he or she deserves no better.
-	 */
-	
-	if (seqnum > (31 * 512))
-		seqnum = 31 * 512;
-	return 128 + 192 + 128 + 64 + 32 + 64 + (seqnum >> 9);
-}
-
-/* Now the other way round: Calculate the sequence
- * number of an extension block of a key at the
- * given index in the cache.
- */
+	if (atomic_read(&filp->f_count) != 1)
+		return 0;
+	pr_debug("AFFS: open(%d)\n", AFFS_INODE->i_opencnt);
+	AFFS_INODE->i_opencnt++;
+	return 0;
+}
 
 static int
-index_to_seqnum(int index)
+affs_file_release(struct inode *inode, struct file *filp)
 {
-	if (index < 128)
-		return index;
-	index -= 128;
-	if (index < 192)
-		return 128 + (index << 1);
-	index -= 192;
-	if (index < 128)
-		return 128 + 192 * 2 + (index << 2);
-	index -= 128;
-	if (index < 64)
-		return 128 + 192 * 2 + 128 * 4 + (index << 4);
-	index -= 64;
-	if (index < 32)
-		return 128 + 192 * 2 + 128 * 4 + 64 * 16 + (index << 6);
-	index -= 32;
-	if (index < 64)
-		return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + (index << 8);
-	index -= 64;
-	return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9);
-}
-
-static s32 __inline__
-calc_key(struct inode *inode, int *ext)
-{
-	int		  index;
-	struct key_cache *kc;
-
-	for (index = 0; index < 4; index++) {
-		kc = &inode->u.affs_i.i_ec->kc[index];
-		if (kc->kc_last == -1)
-			continue;	/* don't look in cache if invalid. */
-		if (*ext == kc->kc_this_seq) {
-			return kc->kc_this_key;
-		} else if (*ext == kc->kc_this_seq + 1) {
-			if (kc->kc_next_key)
-				return kc->kc_next_key;
-			else {
-				(*ext)--;
-				return kc->kc_this_key;
-			}
-		}
-	}
-	index = seqnum_to_index(*ext);
-	if (index > inode->u.affs_i.i_ec->max_ext)
-		index = inode->u.affs_i.i_ec->max_ext;
-	*ext = index_to_seqnum(index);
-	return inode->u.affs_i.i_ec->ec[index];
+	if (atomic_read(&filp->f_count) != 0)
+		return 0;
+	pr_debug("AFFS: release(%d)\n", AFFS_INODE->i_opencnt);
+	AFFS_INODE->i_opencnt--;
+	if (!AFFS_INODE->i_opencnt)
+		affs_free_prealloc(inode);
+
+	return 0;
 }
 
-int
-affs_bmap(struct inode *inode, int block)
+static int
+affs_grow_extcache(struct inode *inode, u32 lc_idx)
 {
+	struct super_block	*sb = inode->i_sb;
 	struct buffer_head	*bh;
-	s32			 key, nkey;
-	s32			 ptype, stype;
-	int			 ext;
-	int			 index;
-	int			 keycount;
-	struct key_cache	*kc;
-	struct key_cache	*tkc;
-	struct timeval		 tv;
-	s32			*keyp;
-	int			 i;
-
-	pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
-
-	lock_kernel();
-	if (block < 0) {
-		affs_error(inode->i_sb,"bmap","Block < 0");
-		goto out_fail;
-	}
-	if (!inode->u.affs_i.i_ec) {
-		if (alloc_ext_cache(inode)) {
-			goto out_fail;
-		}
-	}
+	u32 lc_max;
+	int i, j, key;
 
-	/* Try to find the requested key in the cache.
-	 * In order to speed this up as much as possible,
-	 * the cache line lookup is done in a separate
-	 * step.
-	 */
-
-	for (i = 0; i < 4; i++) {
-		tkc = &inode->u.affs_i.i_ec->kc[i];
-		/* Look in any cache if the key is there */
-		if (block <= tkc->kc_last && block >= tkc->kc_first) {
-			unlock_kernel();
-			return tkc->kc_keys[block - tkc->kc_first];
-		}
-	}
-	kc = NULL;
-	tv = xtime;
-	for (i = 0; i < 4; i++) {
-		tkc = &inode->u.affs_i.i_ec->kc[i];
-		if (tkc->kc_lru_time.tv_sec > tv.tv_sec)
+	if (!AFFS_INODE->i_lc) {
+		char *ptr = (char *)get_zeroed_page(GFP_BUFFER);
+		if (!ptr)
+			return -ENOMEM;
+		AFFS_INODE->i_lc = (u32 *)ptr;
+		AFFS_INODE->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
+	}
+
+	lc_max = AFFS_LC_SIZE << AFFS_INODE->i_lc_shift;
+
+	if (AFFS_INODE->i_extcnt > lc_max) {
+		u32 lc_shift, lc_mask, tmp, off;
+
+		/* need to recalculate linear cache, start from old size */
+		lc_shift = AFFS_INODE->i_lc_shift;
+		tmp = (AFFS_INODE->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
+		for (; tmp; tmp >>= 1)
+			lc_shift++;
+		lc_mask = (1 << lc_shift) - 1;
+
+		/* fix idx and old size to new shift */
+		lc_idx >>= (lc_shift - AFFS_INODE->i_lc_shift);
+		AFFS_INODE->i_lc_size >>= (lc_shift - AFFS_INODE->i_lc_shift);
+
+		/* first shrink old cache to make more space */
+		off = 1 << (lc_shift - AFFS_INODE->i_lc_shift);
+		for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
+			AFFS_INODE->i_ac[i] = AFFS_INODE->i_ac[j];
+
+		AFFS_INODE->i_lc_shift = lc_shift;
+		AFFS_INODE->i_lc_mask = lc_mask;
+	}
+
+	/* fill cache to the needed index */
+	i = AFFS_INODE->i_lc_size;
+	AFFS_INODE->i_lc_size = lc_idx + 1;
+	for (; i <= lc_idx; i++) {
+		if (!i) {
+			AFFS_INODE->i_lc[0] = inode->i_ino;
 			continue;
-		if (tkc->kc_lru_time.tv_sec < tv.tv_sec ||
-		    tkc->kc_lru_time.tv_usec < tv.tv_usec) {
-			kc = tkc;
-			tv = tkc->kc_lru_time;
 		}
+		key = AFFS_INODE->i_lc[i - 1];
+		j = AFFS_INODE->i_lc_mask + 1;
+		// unlock cache
+		for (; j > 0; j--) {
+			bh = affs_bread(sb, key);
+			if (!bh)
+				goto err;
+			key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+			affs_brelse(bh);
+		}
+		// lock cache
+		AFFS_INODE->i_lc[i] = key;
 	}
-	if (!kc)	/* Really shouldn't happen */
-		kc = tkc;
-	kc->kc_lru_time = xtime;
-	keyp            = kc->kc_keys;
-	kc->kc_first    = block;
-	kc->kc_last     = -1;
-	keycount        = AFFS_KCSIZE;
-
-	/* Calculate sequence number of the extension block where the
-	 * number of the requested block is stored. 0 means it's in
-	 * the file header.
-	 */
-
-	ext    = block / AFFS_I2HSIZE(inode);
-	key    = calc_key(inode,&ext);
-	block -= ext * AFFS_I2HSIZE(inode);
 
-	for (;;) {
-		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-		if (!bh)
-			goto out_fail;
+	return 0;
 
-		index = seqnum_to_index(ext);
-		if (index > inode->u.affs_i.i_ec->max_ext &&
-		    (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
-		     (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) {
-			affs_brelse(bh);
-			goto out_fail;
-		}
-		nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
-		if (block < AFFS_I2HSIZE(inode)) {
-			/* Fill cache as much as possible */
-			if (keycount) {
-				kc->kc_first = ext * AFFS_I2HSIZE(inode) + block;
-				keycount     = keycount < AFFS_I2HSIZE(inode) - block ? keycount :
-						AFFS_I2HSIZE(inode) - block;
-				for (i = 0; i < keycount; i++)
-					kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i));
-				kc->kc_last = kc->kc_first + i - 1;
-			}
-			break;
-		}
-		block -= AFFS_I2HSIZE(inode);
-		affs_brelse(bh);
-		ext++;
-		if (index > inode->u.affs_i.i_ec->max_ext && AFFS_ISINDEX(ext)) {
-			inode->u.affs_i.i_ec->ec[index] = nkey;
-			inode->u.affs_i.i_ec->max_ext   = index;
-		}
-		key = nkey;
+err:
+	// lock cache
+	return -EIO;
+}
+
+static struct buffer_head *
+affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
+{
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *new_bh;
+	u32 blocknr, tmp;
+
+	blocknr = affs_alloc_block(inode, bh->b_blocknr);
+	if (!blocknr)
+		return ERR_PTR(-ENOSPC);
+
+	new_bh = affs_getzeroblk(sb, blocknr);
+	if (!new_bh) {
+		affs_free_block(sb, blocknr);
+		return ERR_PTR(-EIO);
 	}
-	kc->kc_this_key = key;
-	kc->kc_this_seq = ext;
-	kc->kc_next_key = nkey;
-	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
-	affs_brelse(bh);
-out:
-	unlock_kernel();
-	return key;
 
-out_fail:
-	key=0;
-	goto out;
+	AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);
+	AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);
+	AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);
+	AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);
+	affs_fix_checksum(sb, new_bh);
+
+	mark_buffer_dirty(new_bh);
+
+	tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+	if (tmp)
+		affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);
+	AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);
+	affs_adjust_checksum(bh, blocknr - tmp);
+	mark_buffer_dirty(bh);
+
+	AFFS_INODE->i_extcnt++;
+	mark_inode_dirty(inode);
+
+	return new_bh;
 }
 
+static inline struct buffer_head *
+affs_get_extblock(struct inode *inode, u32 ext)
+{
+	/* inline the simplest case: same extended block as last time */
+	struct buffer_head *bh = AFFS_INODE->i_ext_bh;
+	if (ext == AFFS_INODE->i_ext_last)
+		atomic_inc(&bh->b_count);
+	else
+		/* we have to do more (not inlined) */
+		bh = affs_get_extblock_slow(inode, ext);
 
-static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+	return bh;
+}
+
+static struct buffer_head *
+affs_get_extblock_slow(struct inode *inode, u32 ext)
 {
-	int err, phys=0, new=0;
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh;
+	u32 ext_key;
+	u32 lc_idx, lc_off, ac_idx;
+	u32 tmp, idx;
+
+	if (ext == AFFS_INODE->i_ext_last + 1) {
+		/* read the next extended block from the current one */
+		bh = AFFS_INODE->i_ext_bh;
+		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+		if (ext < AFFS_INODE->i_extcnt)
+			goto read_ext;
+		if (ext > AFFS_INODE->i_extcnt)
+			BUG();
+		bh = affs_alloc_extblock(inode, bh, ext);
+		if (IS_ERR(bh))
+			return bh;
+		goto store_ext;
+	}
+
+	if (ext == 0) {
+		/* we seek back to the file header block */
+		ext_key = inode->i_ino;
+		goto read_ext;
+	}
+
+	if (ext >= AFFS_INODE->i_extcnt) {
+		struct buffer_head *prev_bh;
+
+		/* allocate a new extended block */
+		if (ext > AFFS_INODE->i_extcnt)
+			BUG();
+
+		/* get previous extended block */
+		prev_bh = affs_get_extblock(inode, ext - 1);
+		if (IS_ERR(prev_bh))
+			return prev_bh;
+		bh = affs_alloc_extblock(inode, prev_bh, ext);
+		affs_brelse(prev_bh);
+		if (IS_ERR(bh))
+			return bh;
+		goto store_ext;
+	}
+
+again:
+	/* check if there is an extended cache and whether it's large enough */
+	lc_idx = ext >> AFFS_INODE->i_lc_shift;
+	lc_off = ext & AFFS_INODE->i_lc_mask;
+
+	if (lc_idx >= AFFS_INODE->i_lc_size) {
+		int err;
+
+		err = affs_grow_extcache(inode, lc_idx);
+		if (err)
+			return ERR_PTR(err);
+		goto again;
+	}
+
+	/* every n'th key we find in the linear cache */
+	if (!lc_off) {
+		ext_key = AFFS_INODE->i_lc[lc_idx];
+		goto read_ext;
+	}
+
+	/* maybe it's still in the associative cache */
+	ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
+	if (AFFS_INODE->i_ac[ac_idx].ext == ext) {
+		ext_key = AFFS_INODE->i_ac[ac_idx].key;
+		goto read_ext;
+	}
+
+	/* try to find one of the previous extended blocks */
+	tmp = ext;
+	idx = ac_idx;
+	while (--tmp, --lc_off > 0) {
+		idx = (idx - 1) & AFFS_AC_MASK;
+		if (AFFS_INODE->i_ac[idx].ext == tmp) {
+			ext_key = AFFS_INODE->i_ac[idx].key;
+			goto find_ext;
+		}
+	}
+
+	/* fall back to the linear cache */
+	ext_key = AFFS_INODE->i_lc[lc_idx];
+find_ext:
+	/* read all extended blocks until we find the one we need */
+	//unlock cache
+	do {
+		bh = affs_bread(sb, ext_key);
+		if (!bh)
+			goto err_bread;
+		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+		affs_brelse(bh);
+		tmp++;
+	} while (tmp < ext);
+	//lock cache
+
+	/* store it in the associative cache */
+	// recalculate ac_idx?
+	AFFS_INODE->i_ac[ac_idx].ext = ext;
+	AFFS_INODE->i_ac[ac_idx].key = ext_key;
+
+read_ext:
+	/* finally read the right extended block */
+	//unlock cache
+	bh = affs_bread(sb, ext_key);
+	if (!bh)
+		goto err_bread;
+	//lock cache
+
+store_ext:
+	/* release old cached extended block and store the new one */
+	affs_brelse(AFFS_INODE->i_ext_bh);
+	AFFS_INODE->i_ext_last = ext;
+	AFFS_INODE->i_ext_bh = bh;
+	atomic_inc(&bh->b_count);
 
-	if (!create) {
-		phys = affs_bmap(inode, block);
-		if (phys) {
-			bh_result->b_dev = inode->i_dev;
-			bh_result->b_blocknr = phys;
-			bh_result->b_state |= (1UL << BH_Mapped);
-		}
-		return 0;
-	}
+	return bh;
 
-	err = -EIO;
-	lock_kernel();
-	if (block < 0)
-		goto abort_negative;
+err_bread:
+	affs_brelse(bh);
+	return ERR_PTR(-EIO);
+}
 
-	if (affs_getblock(inode, block)==NULL) {
-		err = -EIO;
-		goto abort;
-	}
+static int
+affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+{
+	struct super_block	*sb = inode->i_sb;
+	struct buffer_head	*ext_bh;
+	u32			 ext;
+
+	pr_debug("AFFS: get_block(%u, %ld)\n", (u32)inode->i_ino, block);
 
+	if (block < 0)
+		goto err_small;
+
+	if (block >= AFFS_INODE->i_blkcnt) {
+		if (block > AFFS_INODE->i_blkcnt || !create)
+			goto err_big;
+	} else
+		create = 0;
+
+	//lock cache
+	down(&AFFS_INODE->i_ext_lock);
+
+	ext = block / AFFS_SB->s_hashsize;
+	block -= ext * AFFS_SB->s_hashsize;
+	ext_bh = affs_get_extblock(inode, ext);
+	if (IS_ERR(ext_bh))
+		goto err_ext;
+	bh_result->b_blocknr = be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block));
 	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr = phys;
 	bh_result->b_state |= (1UL << BH_Mapped);
-	if (new)
+
+	if (create) {
+		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
+		if (!blocknr)
+			goto err_alloc;
 		bh_result->b_state |= (1UL << BH_New);
-	
-abort:
-	unlock_kernel();
-	return err;
+		AFFS_INODE->mmu_private += AFFS_SB->s_data_blksize;
+		AFFS_INODE->i_blkcnt++;
 
-abort_negative:
-	affs_error(inode->i_sb,"affs_get_block","Block < 0");
-	goto abort;
+		/* store new block */
+		if (bh_result->b_blocknr)
+			affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr);
+		AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);
+		AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);
+		affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);
+		bh_result->b_blocknr = blocknr;
+
+		if (!block) {
+			/* insert first block into header block */
+			u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);
+			if (tmp)
+				affs_warning(sb, "get_block", "first block already set (%d)", tmp);
+			AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);
+			affs_adjust_checksum(ext_bh, blocknr - tmp);
+		}
+	}
 
+	affs_brelse(ext_bh);
+	//unlock cache
+	up(&AFFS_INODE->i_ext_lock);
+	return 0;
+
+err_small:
+	affs_error(inode->i_sb,"get_block","Block < 0");
+	return -EIO;
+err_big:
+	affs_error(inode->i_sb,"get_block","strange block request %d", block);
+	return -EIO;
+err_ext:
+	// unlock cache
+	up(&AFFS_INODE->i_ext_lock);
+	return PTR_ERR(ext_bh);
+err_alloc:
+	brelse(ext_bh);
+	bh_result->b_state &= ~(1UL << BH_Mapped);
+	// unlock cache
+	up(&AFFS_INODE->i_ext_lock);
+	return -ENOSPC;
 }
-		
+
 static int affs_writepage(struct page *page)
 {
-	return block_write_full_page(page,affs_get_block);
+	return block_write_full_page(page, affs_get_block);
 }
 static int affs_readpage(struct file *file, struct page *page)
 {
-	return block_read_full_page(page,affs_get_block);
+	return block_read_full_page(page, affs_get_block);
 }
 static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	return cont_prepare_write(page,from,to,affs_get_block,
+	return cont_prepare_write(page, from, to, affs_get_block,
 		&page->mapping->host->u.affs_i.mmu_private);
 }
 static int _affs_bmap(struct address_space *mapping, long block)
@@ -364,227 +435,61 @@
 	bmap: _affs_bmap
 };
 
-/* With the affs, getting a random block from a file is not
- * a simple business. Since this fs does not allow holes,
- * it may be necessary to allocate all the missing blocks
- * in between, as well as some new extension blocks. The OFS
- * is even worse: All data blocks contain pointers to the
- * next ones, so you have to fix [n-1] after allocating [n].
- * What a mess.
- */
-
-static struct buffer_head * affs_getblock(struct inode *inode, s32 block)
+static inline struct buffer_head *
+affs_bread_ino(struct inode *inode, int block, int create)
 {
-	struct super_block	*sb = inode->i_sb;
-	int			 ofs = sb->u.affs_sb.s_flags & SF_OFS;
-	int			 ext = block / AFFS_I2HSIZE(inode);
-	struct buffer_head	*bh, *ebh, *pbh = NULL;
-	struct key_cache	*kc;
-	s32			 key, nkey;
-	int			 cf, j, pt;
-	int			 index;
-	int			 err;
-
-	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
-
-	key    = calc_key(inode,&ext);
-	block -= ext * AFFS_I2HSIZE(inode);
-	pt     = ext ? T_LIST : T_SHORT;
-
-	/* Key refers now to the last known extension block,
-	 * ext is its sequence number (if 0, key refers to the
-	 * header block), and block is the block number relative
-	 * to the first block stored in that extension block.
-	 */
-	for (;;) {	/* Loop over header block and extension blocks */
-		struct file_front *fdp;
+	struct buffer_head *bh, tmp_bh;
+	int err;
 
-		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-		if (!bh)
-			goto out_fail;
-		fdp = (struct file_front *) bh->b_data;
-		err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j);
-		if (err || cf != pt || j != ST_FILE) {
-		    	affs_error(sb, "getblock",
-				"Block %d is not a valid %s", key,
-				pt == T_SHORT ? "file header" : "ext block");
-			goto out_free_bh;
-		}
-		j  = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);
-		for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {
-			if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
-				if (j > 0) {
-					s32 k = AFFS_BLOCK(bh->b_data, inode, j - 1);
-					pbh = affs_bread(inode->i_dev,
-							be32_to_cpu(k),
-							AFFS_I2BSIZE(inode));
-				} else
-					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
-				if (!pbh) {
-					affs_error(sb,"getblock", "Cannot get last block in file");
-					break;
-				}
-			}
-			nkey = affs_new_data(inode);
-			if (!nkey)
-				break;
-			inode->u.affs_i.i_lastblock++;
-			if (AFFS_BLOCK(bh->b_data,inode,j)) {
-				affs_warning(sb,"getblock","Block already allocated");
-				affs_free_block(sb,nkey);
-				continue;
-			}
-			AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);
-			if (ofs) {
-				ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
-				if (!ebh) {
-					affs_error(sb,"getblock", "Cannot get block %d",nkey);
-					affs_free_block(sb,nkey);
-					AFFS_BLOCK(bh->b_data,inode,j) = 0;
-					break;
-				}
-				DATA_FRONT(ebh)->primary_type    = cpu_to_be32(T_DATA);
-				DATA_FRONT(ebh)->header_key      = cpu_to_be32(inode->i_ino);
-				DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
-				affs_fix_checksum(AFFS_I2BSIZE(inode), ebh->b_data, 5);
-				mark_buffer_dirty(ebh);
-				if (pbh) {
-					DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
-					DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);
-					affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
-					mark_buffer_dirty(pbh);
-					affs_brelse(pbh);
-				}
-				pbh = ebh;
-			}
-			cf = 1;
-		}
-		/* N.B. May need to release pbh after here */
-
-		if (cf) {
-			if (pt == T_SHORT)
-				fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);
-			fdp->block_count = cpu_to_be32(j);
-			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-			mark_buffer_dirty(bh);
+	tmp_bh.b_state = 0;
+	err = affs_get_block(inode, block, &tmp_bh, create);
+	if (!err) {
+		bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);
+		if (bh) {
+			bh->b_state |= tmp_bh.b_state;
+			return bh;
 		}
+		err = -EIO;
+	}
+	return ERR_PTR(err);
+}
 
-		if (block < j) {
-			if (pbh)
-				affs_brelse(pbh);
-			break;
-		}
-		if (j < AFFS_I2HSIZE(inode)) {
-			/* N.B. What about pbh here? */
-			goto out_free_bh;
-		}
+static inline struct buffer_head *
+affs_getzeroblk_ino(struct inode *inode, int block)
+{
+	struct buffer_head *bh, tmp_bh;
+	int err;
 
-		block -= AFFS_I2HSIZE(inode);
-		key    = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
-		if (!key) {
-			key = affs_new_header(inode);
-			if (!key)
-				goto out_free_bh;
-			ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-			if (!ebh) {
-				/* N.B. must free bh here */
-				goto out_free_block;
-			}
-			((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST);
-			((struct file_front *)ebh->b_data)->own_key      = cpu_to_be32(key);
-			FILE_END(ebh->b_data,inode)->secondary_type      = cpu_to_be32(ST_FILE);
-			FILE_END(ebh->b_data,inode)->parent              = cpu_to_be32(inode->i_ino);
-			affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
-			mark_buffer_dirty(ebh);
-			FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key);
-			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-			mark_buffer_dirty(bh);
-			affs_brelse(bh);
-			bh = ebh;
-		}
-		pt = T_LIST;
-		ext++;
-		index = seqnum_to_index(ext);
-		if (index > inode->u.affs_i.i_ec->max_ext &&
-		    AFFS_ISINDEX(ext)) {
-			inode->u.affs_i.i_ec->ec[index] = key;
-			inode->u.affs_i.i_ec->max_ext   = index;
+	tmp_bh.b_state = 0;
+	err = affs_get_block(inode, block, &tmp_bh, 1);
+	if (!err) {
+		bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);
+		if (bh) {
+			bh->b_state |= tmp_bh.b_state;
+			return bh;
 		}
-		affs_brelse(bh);
-	}
-
-	/* Invalidate key cache */
-	for (j = 0; j < 4; j++) {
-		kc = &inode->u.affs_i.i_ec->kc[j];
-		kc->kc_last = -1;
+		err = -EIO;
 	}
-	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
-	affs_brelse(bh);
-	if (!key)
-		goto out_fail;
-
-	bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode));
-	return bh;
-
-out_free_block:
-	affs_free_block(sb, key);
-out_free_bh:
-	affs_brelse(bh);
-out_fail:
-	return NULL;
+	return ERR_PTR(err);
 }
 
-static ssize_t
-affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos)
+static inline struct buffer_head *
+affs_getemptyblk_ino(struct inode *inode, int block)
 {
-	struct inode		*inode = filp->f_dentry->d_inode;
-	char			*start;
-	ssize_t			 left, offset, size, sector;
-	ssize_t			 blocksize;
-	struct buffer_head	*bh;
-	void			*data;
-	loff_t		tmp;
-
-	pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,
-		 (unsigned long)*ppos,count);
-
-	if (!inode) {
-		affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
-		return -EINVAL;
-	}
-	blocksize = AFFS_I2BSIZE(inode) - 24;
-	if (!(S_ISREG(inode->i_mode))) {
-		pr_debug("AFFS: file_read: mode = %07o",inode->i_mode);
-		return -EINVAL;
-	}
-	if (*ppos >= inode->i_size || count <= 0)
-		return 0;
+	struct buffer_head *bh, tmp_bh;
+	int err;
 
-	start = buf;
-	for (;;) {
-		left = MIN (inode->i_size - *ppos,count - (buf - start));
-		if (!left)
-			break;
-		tmp = *ppos;
-		do_div(tmp, blocksize);
-		sector = affs_bmap(inode, tmp);
-		if (!sector)
-			break;
-		tmp = *ppos;
-		offset = do_div(tmp, blocksize);
-		bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
-		if (!bh)
-			break;
-		data = bh->b_data + 24;
-		size = MIN(blocksize - offset,left);
-		*ppos += size;
-		copy_to_user(buf,data + offset,size);
-		buf += size;
-		affs_brelse(bh);
+	tmp_bh.b_state = 0;
+	err = affs_get_block(inode, block, &tmp_bh, 1);
+	if (!err) {
+		bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr);
+		if (bh) {
+			bh->b_state |= tmp_bh.b_state;
+			return bh;
+		}
+		err = -EIO;
 	}
-	if (start == buf)
-		return -EIO;
-	return buf - start;
+	return ERR_PTR(err);
 }
 
 static ssize_t
@@ -601,232 +506,388 @@
 	return retval;
 }
 
-static ssize_t
-affs_file_write_ofs(struct file *file, const char *buf, size_t count, loff_t *ppos)
+static int
+affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	ssize_t retval;
-
-	retval = generic_file_write (file, buf, count, ppos);
-	if (retval >0) {
-		struct inode *inode = file->f_dentry->d_inode;
-		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-		mark_inode_dirty(inode);
+	struct inode *inode = file->f_dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh;
+	char *data;
+	u32 bidx, boff, bsize;
+	u32 tmp;
+
+	pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+	data = page_address(page);
+	bsize = AFFS_SB->s_data_blksize;
+	tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+	bidx = tmp / bsize;
+	boff = tmp % bsize;
+
+	while (from < to) {
+		bh = affs_bread_ino(inode, bidx, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+		tmp = MIN(bsize - boff, from - to);
+		memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
+		affs_brelse(bh);
+		bidx++;
+		from += tmp;
+		boff = 0;
 	}
-	return retval;
+	return 0;
 }
 
-/* Free any preallocated blocks. */
-
-void
-affs_free_prealloc(struct inode *inode)
+static int
+affs_extent_file_ofs(struct file *file, u32 newsize)
 {
-	struct super_block	*sb = inode->i_sb;
-	struct affs_zone	*zone;
-	int block;
-
-	pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
-
-	while (inode->u.affs_i.i_pa_cnt) {	
-		block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
-		inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
-		inode->u.affs_i.i_pa_cnt--;
-		affs_free_block(sb, block);
-	}
-	if (inode->u.affs_i.i_zone) {
-		zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
-		if (zone->z_ino == inode->i_ino)
-			zone->z_ino = 0;
+	struct inode *inode = file->f_dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh, *prev_bh;
+	u32 bidx, boff;
+	u32 size, bsize;
+	u32 tmp;
+
+	pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
+	bsize = AFFS_SB->s_data_blksize;
+	bh = NULL;
+	size = inode->i_size;
+	bidx = size / bsize;
+	boff = size % bsize;
+	if (boff) {
+		bh = affs_bread_ino(inode, bidx, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+		tmp = MIN(bsize - boff, newsize - size);
+		memset(AFFS_DATA(bh) + boff, 0, tmp);
+		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+		affs_fix_checksum(sb, bh);
+		mark_buffer_dirty(bh);
+		size += tmp;
+		bidx++;
+	} else if (bidx) {
+		bh = affs_bread_ino(inode, bidx - 1, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+	}
+
+	while (size < newsize) {
+		prev_bh = bh;
+		bh = affs_getzeroblk_ino(inode, bidx);
+		if (IS_ERR(bh))
+			goto out;
+		tmp = MIN(bsize, newsize - size);
+		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
+		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
+		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
+		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
+		affs_fix_checksum(sb, bh);
+		mark_buffer_dirty(bh);
+		if (prev_bh) {
+			u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+			if (tmp)
+				affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+			AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
+			affs_adjust_checksum(prev_bh, bidx - tmp);
+			mark_buffer_dirty(prev_bh);
+			affs_brelse(prev_bh);
+		}
+		size += bsize;
+		bidx++;
 	}
+	affs_brelse(bh);
+	inode->i_size = AFFS_INODE->mmu_private = size;
+	return 0;
+
+out:
+	inode->i_size = AFFS_INODE->mmu_private = size;
+	return PTR_ERR(bh);
 }
 
-/* Truncate (or enlarge) a file to the requested size. */
+static int
+affs_readpage_ofs(struct file *file, struct page *page)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	u32 to;
+	int err;
+
+	pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index);
+	to = PAGE_CACHE_SIZE;
+	if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) {
+		to = inode->i_size & ~PAGE_CACHE_MASK;
+		memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
+	}
+
+	err = affs_do_readpage_ofs(file, page, 0, to);
+	if (!err)
+		SetPageUptodate(page);
+	UnlockPage(page);
+	return err;
+}
 
-void
-affs_truncate(struct inode *inode)
+static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct buffer_head	*bh = NULL;
-	int	 first;			/* First block to be thrown away	*/
-	int	 block;
-	s32	 key;
-	s32	*keyp;
-	s32	 ekey;
-	s32	 ptype, stype;
-	int	 freethis;
-	int	 net_blocksize;
-	int	 blocksize = AFFS_I2BSIZE(inode);
-	int	 rem;
-	int	 ext;
-	loff_t tmp;
-
-	pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
-
-	net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
-	first = inode->i_size + net_blocksize -1;
-	do_div (first, net_blocksize);
-	if (inode->u.affs_i.i_lastblock < first - 1) {
-		/* There has to be at least one new block to be allocated */
-		if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) {
-			/* XXX Fine! No way to indicate an error. */
-			return /* -ENOSPC */;
-		}
-		bh = affs_getblock(inode,first - 1);
-		if (!bh) {
-			affs_warning(inode->i_sb,"truncate","Cannot extend file");
-			inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
-		} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
-			tmp = inode->i_size;
-			rem = do_div(tmp, net_blocksize);
-			DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
-			affs_fix_checksum(blocksize,bh->b_data,5);
-			mark_buffer_dirty(bh);
+	struct inode *inode = file->f_dentry->d_inode;
+	u32 size, offset;
+	u32 tmp;
+	int err = 0;
+
+	pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+	if (Page_Uptodate(page))
+		return 0;
+
+	size = inode->i_size;
+	offset = page->index << PAGE_CACHE_SHIFT;
+	if (offset + from > size) {
+		err = affs_extent_file_ofs(file, offset + from);
+		if (err)
+			return err;
+	}
+
+	if (from) {
+		err = affs_do_readpage_ofs(file, page, 0, from);
+		if (err)
+			return err;
+	}
+	if (to < PAGE_CACHE_SIZE) {
+		memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
+		if (size > offset + to) {
+			if (size < offset + PAGE_CACHE_SIZE)
+				tmp = size & PAGE_CACHE_MASK;
+			else
+				tmp = PAGE_CACHE_SIZE;
+			err = affs_do_readpage_ofs(file, page, to, tmp);
 		}
-		goto out_truncate;
 	}
-	ekey = inode->i_ino;
-	ext  = 0;
+	return err;
+}
 
-	/* Free all blocks starting at 'first' and all then-empty
-	 * extension blocks. Do not free the header block, though.
-	 */
-	while (ekey) {
-		if (!(bh = affs_bread(inode->i_dev,ekey,blocksize))) {
-			affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
-			goto out_truncate;
-		}
-		if (affs_checksum_block(blocksize,bh->b_data,&ptype,&stype)) {
-			affs_error(inode->i_sb,"truncate","Checksum error in header/ext block %d",
-				   ekey);
-			goto out_truncate;
-		}
-		if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
-			affs_error(inode->i_sb,"truncate",
-				   "Bad block (key=%d, ptype=%d, stype=%d)",ekey,ptype,stype);
-			goto out_truncate;
-		}
-		/* Do we have to free this extension block after
-		 * freeing the data blocks pointed to?
-		 */
-		freethis = first == 0 && ekey != inode->i_ino;
-
-		/* Free the data blocks. 'first' is relative to this
-		 * extension block and may well lie behind this block.
-		 */
-		for (block = first; block < AFFS_I2HSIZE(inode); block++) {
-			keyp = &AFFS_BLOCK(bh->b_data,inode,block);
-			key  = be32_to_cpu(*keyp);
-			if (key) {
-				*keyp = 0;
-				affs_free_block(inode->i_sb,key);
-			} else
-				break;
+static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh, *prev_bh;
+	char *data;
+	u32 bidx, boff, bsize;
+	u32 tmp;
+	int written;
+
+	pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+	bsize = AFFS_SB->s_data_blksize;
+	data = page_address(page);
+
+	bh = NULL;
+	written = 0;
+	tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+	bidx = tmp / bsize;
+	boff = tmp % bsize;
+	if (boff) {
+		bh = affs_bread_ino(inode, bidx, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+		tmp = MIN(bsize - boff, to - from);
+		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
+		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+		affs_fix_checksum(sb, bh);
+		mark_buffer_dirty(bh);
+		written += tmp;
+		from += tmp;
+		bidx++;
+	} else if (bidx) {
+		bh = affs_bread_ino(inode, bidx - 1, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+	}
+	while (from + bsize <= to) {
+		prev_bh = bh;
+		bh = affs_getemptyblk_ino(inode, bidx);
+		if (IS_ERR(bh))
+			goto out;
+		memcpy(AFFS_DATA(bh), data + from, bsize);
+		if (bh->b_state & (1UL << BH_New)) {
+			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
+			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
+			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
+			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
+			AFFS_DATA_HEAD(bh)->next = 0;
+			if (prev_bh) {
+				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+				if (tmp)
+					affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
+				affs_adjust_checksum(prev_bh, bidx - tmp);
+				mark_buffer_dirty(prev_bh);
+			}
 		}
-		keyp = &GET_END_PTR(struct file_end,bh->b_data,blocksize)->extension;
-		key  = be32_to_cpu(*keyp);
-
-		/* If 'first' is in this block or is the first
-		 * in the next one, this will be the last in
-		 * the list, thus we have to adjust the count
-		 * and zero the pointer to the next ext block.
-		 */
-		if (first <= AFFS_I2HSIZE(inode)) {
-			((struct file_front *)bh->b_data)->block_count = cpu_to_be32(first);
-			first = 0;
-			*keyp = 0;
-			affs_fix_checksum(blocksize,bh->b_data,5);
-			mark_buffer_dirty(bh);
-		} else
-			first -= AFFS_I2HSIZE(inode);
-		affs_brelse(bh);
-		bh = NULL;
-		if (freethis)			/* Don't bother fixing checksum */
-			affs_free_block(inode->i_sb,ekey);
-		ekey = key;
-	}
-	block = inode->i_size + net_blocksize - 1;
-	do_div (block, net_blocksize);
-	block--;
-	inode->u.affs_i.i_lastblock = block;
-
-	/* If the file is not truncated to a block boundary,
-	 * the partial block after the EOF must be zeroed
-	 * so it cannot become accessible again.
-	 */
-
-	tmp = inode->i_size;
-	rem = do_div(tmp, net_blocksize);
-	if (rem) {
-		if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
-			rem += 24;
-		pr_debug("AFFS: Zeroing from offset %d in block %d\n",rem,block);
-		bh = affs_getblock(inode,block);
-		if (bh) {
-			memset(bh->b_data + rem,0,blocksize - rem);
-			if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) {
-				((struct data_front *)bh->b_data)->data_size = cpu_to_be32(rem);
-				((struct data_front *)bh->b_data)->next_data = 0;
-				affs_fix_checksum(blocksize,bh->b_data,5);
+		affs_brelse(prev_bh);
+		affs_fix_checksum(sb, bh);
+		mark_buffer_dirty(bh);
+		written += bsize;
+		from += bsize;
+		bidx++;
+	}
+	if (from < to) {
+		prev_bh = bh;
+		bh = affs_bread_ino(inode, bidx, 1);
+		if (IS_ERR(bh))
+			goto out;
+		tmp = MIN(bsize, to - from);
+		memcpy(AFFS_DATA(bh), data + from, tmp);
+		if (bh->b_state & (1UL << BH_New)) {
+			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
+			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
+			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
+			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
+			AFFS_DATA_HEAD(bh)->next = 0;
+			if (prev_bh) {
+				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+				if (tmp)
+					affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
+				affs_adjust_checksum(prev_bh, bidx - tmp);
+				mark_buffer_dirty(prev_bh);
 			}
-			mark_buffer_dirty(bh);
-		} else 
-			affs_error(inode->i_sb,"truncate","Cannot read block %d",block);
+		} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
+			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
+		affs_brelse(prev_bh);
+		affs_fix_checksum(sb, bh);
+		mark_buffer_dirty(bh);
+		written += tmp;
+		from += tmp;
+		bidx++;
 	}
+	SetPageUptodate(page);
 
-out_truncate:
+done:
 	affs_brelse(bh);
-	/* Invalidate cache */
-	if (inode->u.affs_i.i_ec) {
-		inode->u.affs_i.i_ec->max_ext = 0;
-		for (key = 0; key < 4; key++) {
-			inode->u.affs_i.i_ec->kc[key].kc_next_key = 0;
-			inode->u.affs_i.i_ec->kc[key].kc_last     = -1;
-		}
-	}
-	mark_inode_dirty(inode);
+	tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+	if (tmp > inode->i_size)
+		inode->i_size = AFFS_INODE->mmu_private = tmp;
+
+	return written;
+
+out:
+	bh = prev_bh;
+	if (!written)
+		written = PTR_ERR(bh);
+	goto done;
 }
 
-/*
- * Called only when we need to allocate the extension cache.
- */
+struct address_space_operations affs_aops_ofs = {
+	readpage: affs_readpage_ofs,
+	//writepage: affs_writepage_ofs,
+	//sync_page: affs_sync_page_ofs,
+	prepare_write: affs_prepare_write_ofs,
+	commit_write: affs_commit_write_ofs
+};
 
-static int
-alloc_ext_cache(struct inode *inode)
+/* Free any preallocated blocks. */
+
+void
+affs_free_prealloc(struct inode *inode)
 {
-	s32	 key;
-	int	 i;
-	unsigned long cache_page;
-	int      error = 0;
-
-	pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino);
-
-	cache_page = get_free_page(GFP_KERNEL);
-	/*
-	 * Check whether somebody else allocated it for us ...
-	 */
-	if (inode->u.affs_i.i_ec)
-		goto out_free;
-	if (!cache_page)
-		goto out_error;
-
-	inode->u.affs_i.i_ec = (struct ext_cache *) cache_page;
-	/* We only have to initialize non-zero values.
-	 * get_free_page() zeroed the page already.
-	 */
-	key = inode->i_ino;
-	inode->u.affs_i.i_ec->ec[0] = key;
-	for (i = 0; i < 4; i++) {
-		inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
-		inode->u.affs_i.i_ec->kc[i].kc_last     = -1;
+	struct super_block *sb = inode->i_sb;
+
+	pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
+
+	while (inode->u.affs_i.i_pa_cnt) {
+		inode->u.affs_i.i_pa_cnt--;
+		affs_free_block(sb, ++inode->u.affs_i.i_lastalloc);
 	}
-out:
-	return error;
+}
+
+/* Truncate (or enlarge) a file to the requested size. */
 
-out_free:
-	if (cache_page)
-		free_page(cache_page);
-	goto out;
-
-out_error:
-	affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
-	error = -ENOMEM;
-	goto out;
+void
+affs_truncate(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	u32 ext, ext_key;
+	u32 last_blk, blkcnt, blk;
+	u32 size;
+	struct buffer_head *ext_bh;
+	int i;
+
+	pr_debug("AFFS: truncate(inode=%d, size=%u)\n", (u32)inode->i_ino, (u32)inode->i_size);
+
+	last_blk = 0;
+	ext = 0;
+	if (inode->i_size) {
+		last_blk = ((u32)inode->i_size - 1) / AFFS_SB->s_data_blksize;
+		ext = last_blk / AFFS_SB->s_hashsize;
+	}
+
+	if (inode->i_size > AFFS_INODE->mmu_private) {
+		struct address_space *mapping = inode->i_mapping;
+		struct page *page;
+		u32 size = inode->i_size - 1;
+		int res;
+
+		page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
+		if (!page)
+			return;
+		size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
+		res = mapping->a_ops->prepare_write(NULL, page, size, size);
+		if (!res)
+			res = mapping->a_ops->commit_write(NULL, page, size, size);
+		UnlockPage(page);
+		page_cache_release(page);
+		mark_inode_dirty(inode);
+		return;
+	} else if (inode->i_size == AFFS_INODE->mmu_private)
+		return;
+
+	// lock cache
+	ext_bh = affs_get_extblock(inode, ext);
+	if (AFFS_INODE->i_lc) {
+		/* clear linear cache */
+		for (i = (ext + 1) >> AFFS_INODE->i_lc_shift; i < AFFS_LC_SIZE; i++)
+			AFFS_INODE->i_lc[i] = 0;
+		/* clear associative cache */
+		for (i = 0; i < AFFS_AC_SIZE; i++)
+			if (AFFS_INODE->i_ac[i].ext >= ext)
+				AFFS_INODE->i_ac[i].ext = 0;
+	}
+	ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
+
+	blkcnt = AFFS_INODE->i_blkcnt;
+	i = 0;
+	blk = last_blk;
+	if (inode->i_size) {
+		i = last_blk % AFFS_SB->s_hashsize + 1;
+		blk++;
+	} else
+		AFFS_HEAD(ext_bh)->first_data = 0;
+	size = AFFS_SB->s_hashsize;
+	if (size > blkcnt - blk + i)
+		size = blkcnt - blk + i;
+	for (; i < size; i++, blk++) {
+		affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
+		AFFS_BLOCK(sb, ext_bh, i) = 0;
+	}
+	AFFS_TAIL(sb, ext_bh)->extension = 0;
+	affs_fix_checksum(sb, ext_bh);
+	mark_buffer_dirty(ext_bh);
+	affs_brelse(ext_bh);
+
+	if (inode->i_size) {
+		AFFS_INODE->i_blkcnt = last_blk + 1;
+		AFFS_INODE->i_extcnt = ext + 1;
+	} else {
+		AFFS_INODE->i_blkcnt = 0;
+		AFFS_INODE->i_extcnt = 1;
+	}
+	AFFS_INODE->mmu_private = inode->i_size;
+	// unlock cache
+
+	while (ext_key) {
+		ext_bh = affs_bread(sb, ext_key);
+		size = AFFS_SB->s_hashsize;
+		if (size > blkcnt - blk)
+			size = blkcnt - blk;
+		for (i = 0; i < size; i++, blk++)
+			affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
+		affs_free_block(sb, ext_key);
+		ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
+		affs_brelse(ext_bh);
+	}
 }
diff -u --recursive --new-file v2.4.3/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.4.3/linux/fs/affs/inode.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/affs/inode.c	Wed Apr 25 14:35:25 2001
@@ -10,7 +10,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#define DEBUG 0
 #include <asm/div64.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -31,209 +30,185 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-extern int *blk_size[];
-extern struct timezone sys_tz;
 extern struct inode_operations affs_symlink_inode_operations;
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
-unsigned long
-affs_parent_ino(struct inode *dir)
-{
-	int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
-
-	if (!S_ISDIR(dir->i_mode)) {
-		affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory");
-		return root_ino;
-	}
-	if (dir->i_ino == root_ino)
-		return root_ino;
-	return dir->u.affs_i.i_parent;
-}
+extern struct timezone sys_tz;
 
 void
 affs_read_inode(struct inode *inode)
 {
+	struct super_block	*sb = inode->i_sb;
 	struct buffer_head	*bh;
-	struct file_front	*file_front;
-	struct file_end		*file_end;
-	s32			 block;
-	unsigned long		 prot;
-	s32			 ptype, stype;
-	unsigned short		 id;
-	loff_t		tmp;
+	struct affs_head	*head;
+	struct affs_tail	*tail;
+	u32			 block;
+	u32			 size;
+	u32			 prot;
+	u16			 id;
 
 	pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
 
 	block = inode->i_ino;
-	if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
-		affs_error(inode->i_sb,"read_inode","Cannot read block %d",block);
-		return;
-	}
-	if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
-		affs_error(inode->i_sb,"read_inode",
-			   "Checksum or type (ptype=%d) error on inode %d",ptype,block);
-		affs_brelse(bh);
-		return;
+	bh = affs_bread(sb, block);
+	if (!bh) {
+		affs_warning(sb, "read_inode", "Cannot read block %d", block);
+		goto bad_inode;
+	}
+	if (affs_checksum_block(sb, bh) || be32_to_cpu(AFFS_HEAD(bh)->ptype) != T_SHORT) {
+		affs_warning(sb,"read_inode",
+			   "Checksum or type (ptype=%d) error on inode %d",
+			   AFFS_HEAD(bh)->ptype, block);
+		goto bad_inode;
 	}
 
-	file_front = (struct file_front *)bh->b_data;
-	file_end   = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
-	prot       = (be32_to_cpu(file_end->protect) & ~0x10) ^ FIBF_OWNER;
-
-	inode->u.affs_i.i_protect      = prot;
-	inode->u.affs_i.i_parent       = be32_to_cpu(file_end->parent);
-	inode->u.affs_i.i_original     = 0;
-	inode->u.affs_i.i_zone         = 0;
-	inode->u.affs_i.i_hlink        = 0;
-	inode->u.affs_i.i_pa_cnt       = 0;
-	inode->u.affs_i.i_pa_next      = 0;
-	inode->u.affs_i.i_pa_last      = 0;
-	inode->u.affs_i.i_ec           = NULL;
-	inode->u.affs_i.i_lastblock    = -1;
-	inode->i_nlink                 = 1;
-	inode->i_mode                  = 0;
+	head = AFFS_HEAD(bh);
+	tail = AFFS_TAIL(sb, bh);
+	prot = be32_to_cpu(tail->protect);
 
-	if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE)
-		inode->i_mode = inode->i_sb->u.affs_sb.s_mode;
+	inode->i_size = 0;
+	inode->i_nlink = 1;
+	inode->i_mode = 0;
+	memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
+	init_MUTEX(&AFFS_INODE->i_link_lock);
+	init_MUTEX(&AFFS_INODE->i_ext_lock);
+	AFFS_INODE->i_extcnt = 1;
+	AFFS_INODE->i_ext_last = ~1;
+	AFFS_INODE->i_protect = prot;
+
+	if (AFFS_SB->s_flags & SF_SETMODE)
+		inode->i_mode = AFFS_SB->s_mode;
 	else
 		inode->i_mode = prot_to_mode(prot);
 
-	if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
-		inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
-	id = be16_to_cpu(file_end->owner_uid);
-	if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
-		inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
-	else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
+	id = be16_to_cpu(tail->uid);
+	if (id == 0 || AFFS_SB->s_flags & SF_SETUID)
+		inode->i_uid = AFFS_SB->s_uid;
+	else if (id == 0xFFFF && AFFS_SB->s_flags & SF_MUFS)
 		inode->i_uid = 0;
-	else 
+	else
 		inode->i_uid = id;
 
-	id = be16_to_cpu(file_end->owner_gid);
-	if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
-		inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
-	else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
+	id = be16_to_cpu(tail->gid);
+	if (id == 0 || AFFS_SB->s_flags & SF_SETGID)
+		inode->i_gid = AFFS_SB->s_gid;
+	else if (id == 0xFFFF && AFFS_SB->s_flags & SF_MUFS)
 		inode->i_gid = 0;
 	else
 		inode->i_gid = id;
 
-	switch (be32_to_cpu(file_end->secondary_type)) {
-		case ST_ROOT:
-			inode->i_uid   = inode->i_sb->u.affs_sb.s_uid;
-			inode->i_gid   = inode->i_sb->u.affs_sb.s_gid;
-		case ST_USERDIR:
-			if (be32_to_cpu(file_end->secondary_type) == ST_USERDIR ||
-			    inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) {
-				if (inode->i_mode & S_IRUSR)
-					inode->i_mode |= S_IXUSR;
-				if (inode->i_mode & S_IRGRP)
-					inode->i_mode |= S_IXGRP;
-				if (inode->i_mode & S_IROTH)
-					inode->i_mode |= S_IXOTH;
-				inode->i_mode |= S_IFDIR;
-			} else
-				inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
-			inode->i_size  = 0;
-			break;
-		case ST_LINKDIR:
-			affs_error(inode->i_sb,"read_inode","inode is LINKDIR");
-			affs_brelse(bh);
-			return;
-		case ST_LINKFILE:
-			affs_error(inode->i_sb,"read_inode","inode is LINKFILE");
-			affs_brelse(bh);
-			return;
-		case ST_FILE:
-			inode->i_mode |= S_IFREG;
-			inode->i_size  = be32_to_cpu(file_end->byte_size);
-			if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
-				block = AFFS_I2BSIZE(inode) - 24;
-			else
-				block = AFFS_I2BSIZE(inode);
-			tmp = inode->i_size + block -1;
-			do_div (tmp, block);
-			tmp--;
-			inode->u.affs_i.i_lastblock = tmp;
-			break;
-		case ST_SOFTLINK:
-			inode->i_mode |= S_IFLNK;
-			inode->i_size  = 0;
-			break;
+	switch (be32_to_cpu(tail->stype)) {
+	case ST_ROOT:
+		inode->i_uid = AFFS_SB->s_uid;
+		inode->i_gid = AFFS_SB->s_gid;
+		/* fall through */
+	case ST_USERDIR:
+		if (be32_to_cpu(tail->stype) == ST_USERDIR ||
+		    AFFS_SB->s_flags & SF_SETMODE) {
+			if (inode->i_mode & S_IRUSR)
+				inode->i_mode |= S_IXUSR;
+			if (inode->i_mode & S_IRGRP)
+				inode->i_mode |= S_IXGRP;
+			if (inode->i_mode & S_IROTH)
+				inode->i_mode |= S_IXOTH;
+			inode->i_mode |= S_IFDIR;
+		} else
+			inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
+		if (tail->link_chain)
+			inode->i_nlink = 2;
+		/* Maybe it should be controlled by mount parameter? */
+		//inode->i_mode |= S_ISVTX;
+		inode->i_op = &affs_dir_inode_operations;
+		inode->i_fop = &affs_dir_operations;
+		break;
+	case ST_LINKDIR:
+		affs_warning(sb, "read_inode", "inode is LINKDIR");
+		goto bad_inode;
+	case ST_LINKFILE:
+		affs_warning(sb, "read_inode", "inode is LINKFILE");
+		goto bad_inode;
+	case ST_FILE:
+		size = be32_to_cpu(tail->size);
+		inode->i_mode |= S_IFREG;
+		AFFS_INODE->mmu_private = inode->i_size = size;
+		if (inode->i_size) {
+			AFFS_INODE->i_blkcnt = (size - 1) /
+					       AFFS_SB->s_data_blksize + 1;
+			AFFS_INODE->i_extcnt = (AFFS_INODE->i_blkcnt - 1) /
+					       AFFS_SB->s_hashsize + 1;
+		}
+		if (tail->link_chain)
+			inode->i_nlink = 2;
+		inode->i_mapping->a_ops = (AFFS_SB->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
+		inode->i_op = &affs_file_inode_operations;
+		inode->i_fop = &affs_file_operations;
+		break;
+	case ST_SOFTLINK:
+		inode->i_mode |= S_IFLNK;
+		inode->i_op = &affs_symlink_inode_operations;
+		inode->i_data.a_ops = &affs_symlink_aops;
+		break;
 	}
 
 	inode->i_mtime = inode->i_atime = inode->i_ctime
-		       = (be32_to_cpu(file_end->created.ds_Days) * (24 * 60 * 60) +
-		         be32_to_cpu(file_end->created.ds_Minute) * 60 +
-			 be32_to_cpu(file_end->created.ds_Tick) / 50 +
+		       = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
+		         be32_to_cpu(tail->change.mins) * 60 +
+			 be32_to_cpu(tail->change.ticks) / 50 +
 			 ((8 * 365 + 2) * 24 * 60 * 60)) +
 			 sys_tz.tz_minuteswest * 60;
 	affs_brelse(bh);
+	return;
 
-	if (S_ISREG(inode->i_mode)) {
-		if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
-			inode->i_op = &affs_file_inode_operations;
-			inode->i_fop = &affs_file_operations_ofs;
-			return;
-		}
-		inode->i_op = &affs_file_inode_operations;
-		inode->i_fop = &affs_file_operations;
-		inode->i_mapping->a_ops = &affs_aops;
-		inode->u.affs_i.mmu_private = inode->i_size;
-	} else if (S_ISDIR(inode->i_mode)) {
-		/* Maybe it should be controlled by mount parameter? */
-		inode->i_mode |= S_ISVTX;
-		inode->i_op = &affs_dir_inode_operations;
-		inode->i_fop = &affs_dir_operations;
-	}
-	else if (S_ISLNK(inode->i_mode)) {
-		inode->i_op = &affs_symlink_inode_operations;
-		inode->i_data.a_ops = &affs_symlink_aops;
-	}
+bad_inode:
+	make_bad_inode(inode);
+	affs_brelse(bh);
+	return;
 }
 
 void
 affs_write_inode(struct inode *inode, int unused)
 {
+	struct super_block	*sb = inode->i_sb;
 	struct buffer_head	*bh;
-	struct file_end		*file_end;
+	struct affs_tail	*tail;
 	uid_t			 uid;
 	gid_t			 gid;
 
 	pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
 
 	if (!inode->i_nlink)
+		// possibly free block
 		return;
 	lock_kernel();
-	if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
-		affs_error(inode->i_sb,"write_inode","Cannot read block %lu",inode->i_ino);
+	bh = affs_bread(sb, inode->i_ino);
+	if (!bh) {
+		affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
 		unlock_kernel();
 		return;
 	}
-	file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
-	if (file_end->secondary_type == be32_to_cpu(ST_ROOT)) {
-		secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered);
+	tail = AFFS_TAIL(sb, bh);
+	if (tail->stype == be32_to_cpu(ST_ROOT)) {
+		secs_to_datestamp(inode->i_mtime,&AFFS_ROOT_TAIL(sb, bh)->root_change);
 	} else {
-		file_end->protect   = cpu_to_be32(inode->u.affs_i.i_protect ^ FIBF_OWNER);
-		file_end->byte_size = cpu_to_be32(inode->i_size);
-		secs_to_datestamp(inode->i_mtime,&file_end->created);
-		if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) {
+		tail->protect = cpu_to_be32(AFFS_INODE->i_protect);
+		tail->size = cpu_to_be32(inode->i_size);
+		secs_to_datestamp(inode->i_mtime,&tail->change);
+		if (!(inode->i_ino == AFFS_SB->s_root_block)) {
 			uid = inode->i_uid;
 			gid = inode->i_gid;
-			if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+			if (sb->u.affs_sb.s_flags & SF_MUFS) {
 				if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
 					uid = inode->i_uid ^ ~0;
 				if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
 					gid = inode->i_gid ^ ~0;
 			}
-			if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID))
-				file_end->owner_uid = cpu_to_be16(uid);
-			if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID))
-				file_end->owner_gid = cpu_to_be16(gid);
+			if (!(sb->u.affs_sb.s_flags & SF_SETUID))
+				tail->uid = cpu_to_be16(uid);
+			if (!(sb->u.affs_sb.s_flags & SF_SETGID))
+				tail->gid = cpu_to_be16(gid);
 		}
 	}
-	affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+	affs_fix_checksum(sb, bh);
 	mark_buffer_dirty(bh);
-	brelse(bh);
+	affs_brelse(bh);
 	unlock_kernel();
 }
 
@@ -258,11 +233,9 @@
 		goto out;
 	}
 
-	if (attr->ia_valid & ATTR_MODE)
-		inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
-
-	error = 0;
 	inode_setattr(inode, attr);
+	if (!error && (attr->ia_valid & ATTR_MODE))
+		mode_to_prot(inode);
 out:
 	return error;
 }
@@ -270,18 +243,14 @@
 void
 affs_put_inode(struct inode *inode)
 {
-	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",
-		inode->i_ino,inode->i_nlink);
-
+	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
 	lock_kernel();
 	affs_free_prealloc(inode);
 	if (atomic_read(&inode->i_count) == 1) {
-		unsigned long cache_page = (unsigned long) inode->u.affs_i.i_ec;
-		if (cache_page) {
-			pr_debug("AFFS: freeing ext cache\n");
-			inode->u.affs_i.i_ec = NULL;
-			free_page(cache_page);
-		}
+		if (inode->i_size != AFFS_INODE->mmu_private)
+			affs_truncate(inode);
+		//if (inode->i_nlink)
+		//	affs_clear_inode(inode);
 	}
 	unlock_kernel();
 }
@@ -289,55 +258,76 @@
 void
 affs_delete_inode(struct inode *inode)
 {
-	pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
+	pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
 	lock_kernel();
 	inode->i_size = 0;
-	if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink)
+	if (S_ISREG(inode->i_mode))
 		affs_truncate(inode);
-	affs_free_block(inode->i_sb,inode->i_ino);
-	unlock_kernel();
 	clear_inode(inode);
+	affs_free_block(inode->i_sb, inode->i_ino);
+	unlock_kernel();
+}
+
+void
+affs_clear_inode(struct inode *inode)
+{
+	unsigned long cache_page = (unsigned long) inode->u.affs_i.i_lc;
+
+	pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
+	if (cache_page) {
+		pr_debug("AFFS: freeing ext cache\n");
+		inode->u.affs_i.i_lc = NULL;
+		inode->u.affs_i.i_ac = NULL;
+		free_page(cache_page);
+	}
+	affs_brelse(AFFS_INODE->i_ext_bh);
+	AFFS_INODE->i_ext_last = ~1;
+	AFFS_INODE->i_ext_bh = NULL;
 }
 
 struct inode *
-affs_new_inode(const struct inode *dir)
+affs_new_inode(struct inode *dir)
 {
+	struct super_block	*sb = dir->i_sb;
 	struct inode		*inode;
-	struct super_block	*sb;
-	s32			 block;
+	u32			 block;
+	struct buffer_head	*bh;
 
-	if (!dir)
-		return NULL;
+	if (!dir || !(inode = get_empty_inode()))
+		goto err_inode;
 
-	sb = dir->i_sb;
-	inode = new_inode(sb);
-	if (!inode)
-		return NULL;
-
-	if (!(block = affs_new_header((struct inode *)dir))) {
-		iput(inode);
-		return NULL;
-	}
+	if (!(block = affs_alloc_block(dir, dir->i_ino)))
+		goto err_block;
+
+	bh = affs_getzeroblk(sb, block);
+	if (!bh)
+		goto err_bh;
+	mark_buffer_dirty(bh);
+	affs_brelse(bh);
 
+	inode->i_sb      = sb;
+	inode->i_dev     = sb->s_dev;
 	inode->i_uid     = current->fsuid;
 	inode->i_gid     = current->fsgid;
 	inode->i_ino     = block;
+	inode->i_nlink   = 1;
 	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-
-	inode->u.affs_i.i_original  = 0;
-	inode->u.affs_i.i_parent    = dir->i_ino;
-	inode->u.affs_i.i_zone      = 0;
-	inode->u.affs_i.i_hlink     = 0;
-	inode->u.affs_i.i_pa_cnt    = 0;
-	inode->u.affs_i.i_pa_next   = 0;
-	inode->u.affs_i.i_pa_last   = 0;
-	inode->u.affs_i.i_ec        = NULL;
-	inode->u.affs_i.i_lastblock = -1;
+	memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
+	AFFS_INODE->i_extcnt = 1;
+	AFFS_INODE->i_ext_last = ~1;
+	init_MUTEX(&AFFS_INODE->i_link_lock);
+	init_MUTEX(&AFFS_INODE->i_ext_lock);
 
 	insert_inode_hash(inode);
-	mark_inode_dirty(inode);
 
 	return inode;
+
+err_bh:
+	affs_free_block(sb, block);
+err_block:
+	iput(inode);
+err_inode:
+	return NULL;
 }
 
 /*
@@ -346,70 +336,73 @@
  */
 
 int
-affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
-	       struct dentry *dentry, int type)
+affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
 {
-	struct buffer_head	*dir_bh;
-	struct buffer_head	*inode_bh;
-	struct buffer_head	*link_bh;
-	int			 retval;
-	const unsigned char	*name = dentry->d_name.name;
-	int			 len  = dentry->d_name.len;
-
-	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino,
-		 len,name,type);
-
-	if ((retval = affs_check_name(name,len)))
-		return retval;
-	if (len > 30)
-		len = 30;
-
-	dir_bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
-	inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
-	link_bh  = NULL;
-	retval   = -EIO;
-	if (!dir_bh || !inode_bh)
-		goto addentry_done;
-	if (link) {
-		link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
-		if (!link_bh)
-			goto addentry_done;
-	}
-	((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT);
-	((struct dir_front *)inode_bh->b_data)->own_key      = cpu_to_be32(inode->i_ino);
-	DIR_END(inode_bh->b_data,inode)->dir_name[0]         = len;
-	strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
-	DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type);
-	DIR_END(inode_bh->b_data,inode)->parent         = cpu_to_be32(dir->i_ino);
-
-	lock_super(inode->i_sb);
-	retval = affs_insert_hash(dir->i_ino,inode_bh,dir);
-
-	if (link_bh) {
-		LINK_END(inode_bh->b_data,inode)->original   = cpu_to_be32(link->i_ino);
-		LINK_END(inode_bh->b_data,inode)->link_chain =
-						FILE_END(link_bh->b_data,link)->link_chain;
-		FILE_END(link_bh->b_data,link)->link_chain   = cpu_to_be32(inode->i_ino);
-		affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
-		link->i_version = ++event;
-		mark_inode_dirty(link);
-		mark_buffer_dirty(link_bh);
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *inode_bh = NULL;
+	struct buffer_head *bh = NULL;
+	u32 block = 0;
+	int retval;
+
+	pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)\n", (u32)dir->i_ino,
+	         (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);
+
+	retval = -EIO;
+	bh = affs_bread(sb, inode->i_ino);
+	if (!bh)
+		goto done;
+
+	switch (type) {
+	case ST_LINKFILE:
+	case ST_LINKDIR:
+		inode_bh = bh;
+		retval = -ENOSPC;
+		block = affs_alloc_block(dir, dir->i_ino);
+		if (!block)
+			goto err;
+		retval = -EIO;
+		bh = affs_getzeroblk(sb, block);
+		if (!bh)
+			goto err;
+		break;
+	default:
+		break;
+	}
+
+	AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
+	AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
+	affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
+	AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
+	AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
+
+	if (inode_bh) {
+		u32 chain;
+		down(&AFFS_INODE->i_link_lock);
+	       	chain = AFFS_TAIL(sb, inode_bh)->link_chain;
+		AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
+		AFFS_TAIL(sb, bh)->link_chain = chain;
+		AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
+		affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
+		mark_buffer_dirty(inode_bh);
+		inode->i_nlink = 2;
+		atomic_inc(&inode->i_count);
+		up(&AFFS_INODE->i_link_lock);
 	}
-	affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
-	affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
-	dir->i_version = ++event;
-	dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
-	unlock_super(inode->i_sb);
-
-	mark_inode_dirty(dir);
-	mark_inode_dirty(inode);
-	mark_buffer_dirty(dir_bh);
-	mark_buffer_dirty(inode_bh);
+	affs_fix_checksum(sb, bh);
+	mark_buffer_dirty(bh);
 
-addentry_done:
-	affs_brelse(dir_bh);
+	down(&AFFS_DIR->i_hash_lock);
+	retval = affs_insert_hash(dir, bh);
+	up(&AFFS_DIR->i_hash_lock);
+
+	dentry->d_fsdata = (void *)bh->b_blocknr;
+	d_instantiate(dentry, inode);
+done:
 	affs_brelse(inode_bh);
-	affs_brelse(link_bh);
-
+	affs_brelse(bh);
 	return retval;
+err:
+	if (block)
+		affs_free_block(sb, block);
+	goto done;
 }
diff -u --recursive --new-file v2.4.3/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.4.3/linux/fs/affs/namei.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/affs/namei.c	Wed Apr 25 14:57:29 2001
@@ -8,7 +8,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#define DEBUG 0
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
 #include <linux/kernel.h>
@@ -21,283 +20,268 @@
 
 #include <linux/errno.h>
 
+typedef int (*toupper_t)(int);
+
 extern struct inode_operations affs_symlink_inode_operations;
 
+static int	 affs_toupper(int ch);
+static int	 affs_hash_dentry(struct dentry *, struct qstr *);
+static int       affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+static int	 affs_intl_toupper(int ch);
+static int	 affs_intl_hash_dentry(struct dentry *, struct qstr *);
+static int       affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+
+struct dentry_operations affs_dentry_operations = {
+	d_hash:		affs_hash_dentry,
+	d_compare:	affs_compare_dentry,
+};
+
+struct dentry_operations affs_intl_dentry_operations = {
+	d_hash:		affs_intl_hash_dentry,
+	d_compare:	affs_intl_compare_dentry,
+};
+
+
 /* Simple toupper() for DOS\1 */
 
-static unsigned int
-affs_toupper(unsigned int ch)
+static int
+affs_toupper(int ch)
 {
 	return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
 }
 
 /* International toupper() for DOS\3 ("international") */
 
-static unsigned int
-affs_intl_toupper(unsigned int ch)
+static int
+affs_intl_toupper(int ch)
 {
 	return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
 		&& ch <= 0xFE && ch != 0xF7) ?
 		ch - ('a' - 'A') : ch;
 }
 
-static int	 affs_hash_dentry(struct dentry *, struct qstr *);
-static int       affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-struct dentry_operations affs_dentry_operations = {
-	d_hash:		affs_hash_dentry,
-	d_compare:	affs_compare_dentry,
-};
+static inline toupper_t
+affs_get_toupper(struct super_block *sb)
+{
+	return AFFS_SB->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper;
+}
 
 /*
  * Note: the dentry argument is the parent dentry.
  */
-static int
-affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+static inline int
+__affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
 {
-	unsigned int (*toupper)(unsigned int) = affs_toupper;
-	unsigned long	 hash;
-	int		 i;
+	const char *name = qstr->name;
+	unsigned long hash;
+	int i;
 
-	if ((i = affs_check_name(qstr->name,qstr->len)))
+	i = affs_check_name(qstr->name,qstr->len);
+	if (i)
 		return i;
 
-	/* Check whether to use the international 'toupper' routine */
-	if (AFFS_I2FSTYPE(dentry->d_inode))
-		toupper = affs_intl_toupper;
 	hash = init_name_hash();
-	for (i = 0; i < qstr->len && i < 30; i++)
-		hash = partial_name_hash(toupper(qstr->name[i]), hash);
+	i = MIN(qstr->len, 30);
+	for (; i > 0; name++, i--)
+		hash = partial_name_hash(toupper(*name), hash);
 	qstr->hash = end_name_hash(hash);
 
 	return 0;
 }
 
 static int
-affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+	return __affs_hash_dentry(dentry, qstr, affs_toupper);
+}
+static int
+affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+	return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
+}
+
+static inline int
+__affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper)
 {
-	unsigned int (*toupper)(unsigned int) = affs_toupper;
-	int	 alen = a->len;
-	int      blen = b->len;
-	int	 i;
+	const u8 *aname = a->name;
+	const u8 *bname = b->name;
+	int len;
 
 	/* 'a' is the qstr of an already existing dentry, so the name
 	 * must be valid. 'b' must be validated first.
 	 */
-	
+
 	if (affs_check_name(b->name,b->len))
 		return 1;
 
 	/* If the names are longer than the allowed 30 chars,
 	 * the excess is ignored, so their length may differ.
 	 */
-	if (alen > 30)
-		alen = 30;
-	if (blen > 30)
-		blen = 30;
-	if (alen != blen)
+	len = a->len;
+	if (len >= 30) {
+		if (b->len < 30)
+			return 1;
+		len = 30;
+	} else if (len != b->len)
 		return 1;
 
-	/* Check whether to use the international 'toupper' routine */
-	if (AFFS_I2FSTYPE(dentry->d_inode))
-		toupper = affs_intl_toupper;
-
-	for (i = 0; i < alen; i++)
-		if (toupper(a->name[i]) != toupper(b->name[i]))
+	for (; len > 0; len--)
+		if (toupper(*aname++) != toupper(*bname++))
 			return 1;
-	
+
 	return 0;
 }
 
+static int
+affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+	return __affs_compare_dentry(dentry, a, b, affs_toupper);
+}
+static int
+affs_intl_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+	return __affs_compare_dentry(dentry, a, b, affs_intl_toupper);
+}
+
 /*
  * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
  */
 
-static int
-affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
+static inline int
+affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
 {
-	unsigned int	(*toupper)(unsigned int) = intl ? affs_intl_toupper : affs_toupper;
-	int		  i;
-
-	if (!compare)
-		return 0;
+	const u8 *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
 
-	if (len > 30)
+	if (len >= 30) {
+		if (*name2 < 30)
+			return 0;
 		len = 30;
-	if (dlen > 30)
-		dlen = 30;
-
-	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-	if (!len && dlen == 1 && compare[0] == '.')
-		return 1;
-	if (dlen != len)
+	} else if (len != *name2)
 		return 0;
-	for (i = 0; i < len; i++)
-		if (toupper(name[i]) != toupper(compare[i]))
+
+	for (name2++; len > 0; len--)
+		if (toupper(*name++) != toupper(*name2++))
 			return 0;
 	return 1;
 }
 
 int
-affs_hash_name(const unsigned char *name, int len, int intl, int hashsize)
+affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
 {
-	unsigned int i, x;
-
-	if (len > 30)
-		len = 30;
+	toupper_t toupper = affs_get_toupper(sb);
+	int hash;
 
-	x = len;
-	for (i = 0; i < len; i++)
-		if (intl)
-			x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
-		else
-			x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
+	hash = len = MIN(len, 30);
+	for (; len > 0; len--)
+		hash = (hash * 13 + toupper(*name++)) & 0x7ff;
 
-	return x % hashsize;
+	return hash % AFFS_SB->s_hashsize;
 }
 
 static struct buffer_head *
-affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
+affs_find_entry(struct inode *dir, struct dentry *dentry)
 {
-	struct buffer_head	*bh;
-	int			 intl = AFFS_I2FSTYPE(dir);
-	s32			 key;
-	const char		*name = dentry->d_name.name;
-	int			 namelen = dentry->d_name.len;
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *bh;
+	toupper_t toupper = affs_get_toupper(sb);
+	u32 key;
 
-	pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
+	pr_debug("AFFS: find_entry(\"%.*s\")\n", (int)dentry->d_name.len, dentry->d_name.name);
 
-	bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+	bh = affs_bread(sb, dir->i_ino);
 	if (!bh)
-		return NULL;
+		return ERR_PTR(-EIO);
 
-	if (namelen == 1 && name[0] == '.') {
-		*ino = dir->i_ino;
-		return bh;
-	}
-	if (namelen == 2 && name[0] == '.' && name[1] == '.') {
-		*ino = affs_parent_ino(dir);
-		return bh;
-	}
-
-	key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
+	key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
 
 	for (;;) {
-		unsigned char *cname;
-		int cnamelen;
-
 		affs_brelse(bh);
-		bh = NULL;
 		if (key == 0)
-			break;
-		bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
+			return NULL;
+		bh = affs_bread(sb, key);
 		if (!bh)
-			break;
-		cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
-		if (affs_match(name,namelen,cname,cnamelen,intl))
-			break;
-		key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain);
+			return ERR_PTR(-EIO);
+		if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
+			return bh;
+		key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
 	}
-	*ino = key;
-	return bh;
 }
 
 struct dentry *
 affs_lookup(struct inode *dir, struct dentry *dentry)
 {
-	unsigned long		 ino;
-	struct buffer_head	*bh;
-	struct inode		*inode;
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *bh;
+	struct inode *inode = NULL;
 
 	pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
 
-	inode = NULL;
-	bh = affs_find_entry(dir,dentry,&ino);
+	down(&AFFS_DIR->i_hash_lock);
+	bh = affs_find_entry(dir, dentry);
+	up(&AFFS_DIR->i_hash_lock);
+	if (IS_ERR(bh))
+		return ERR_PTR(PTR_ERR(bh));
 	if (bh) {
-		if (FILE_END(bh->b_data,dir)->original)
-			ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original);
+		u32 ino = bh->b_blocknr;
+
+		/* store the real header ino in d_fsdata for faster lookups */
+		dentry->d_fsdata = (void *)(long)ino;
+		switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
+		case ST_LINKDIR:
+		case ST_LINKFILE:
+			ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
+		}
 		affs_brelse(bh);
-		inode = iget(dir->i_sb,ino);
+		inode = iget(sb, ino);
 		if (!inode)
 			return ERR_PTR(-EACCES);
 	}
-	dentry->d_op = &affs_dentry_operations;
-	d_add(dentry,inode);
+	dentry->d_op = AFFS_SB->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
+	d_add(dentry, inode);
 	return NULL;
 }
 
 int
 affs_unlink(struct inode *dir, struct dentry *dentry)
 {
-	int			 retval;
-	struct buffer_head	*bh;
-	unsigned long		 ino;
-	struct inode		*inode;
-
-	pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
-		 (int)dentry->d_name.len,dentry->d_name.name);
+	pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
+		 (int)dentry->d_name.len, dentry->d_name.name);
 
-	retval  = -ENOENT;
-	if (!(bh = affs_find_entry(dir,dentry,&ino)))
-		goto unlink_done;
-
-	inode  = dentry->d_inode;
-
-	if ((retval = affs_remove_header(bh,inode)) < 0)
-		goto unlink_done;
-	
-	inode->i_nlink = retval;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_version = ++event;
-	mark_inode_dirty(inode);
-	mark_inode_dirty(dir);
-	retval = 0;
+	if (!dentry->d_inode)
+		return -ENOENT;
 
-unlink_done:
-	affs_brelse(bh);
-	return retval;
+	return affs_remove_header(dentry);
 }
 
 int
 affs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
+	struct super_block *sb = dir->i_sb;
 	struct inode	*inode;
 	int		 error;
-	
+
 	pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
 		 dentry->d_name.name,mode);
 
-	error = -ENOSPC;
 	inode = affs_new_inode(dir);
 	if (!inode)
-		goto out;
+		return -ENOSPC;
 
-	pr_debug("AFFS: ino=%lu\n",inode->i_ino);
-	if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) {
-		inode->i_op = &affs_file_inode_operations;
-		inode->i_fop = &affs_file_operations_ofs;
-	} else {
-		inode->i_op = &affs_file_inode_operations;
-		inode->i_fop = &affs_file_operations;
-		inode->i_mapping->a_ops = &affs_aops;
-		inode->u.affs_i.mmu_private = inode->i_size;
-	}
-	error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
-	if (error)
-		goto out_iput;
 	inode->i_mode = mode;
-	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-	d_instantiate(dentry,inode);
+	mode_to_prot(inode);
 	mark_inode_dirty(inode);
-	dir->i_version = ++event;
-	mark_inode_dirty(dir);
-out:
-	return error;
 
-out_iput:
-	inode->i_nlink = 0;
-	mark_inode_dirty(inode);
-	iput(inode);
-	goto out;
+	inode->i_op = &affs_file_inode_operations;
+	inode->i_fop = &affs_file_operations;
+	inode->i_mapping->a_ops = (AFFS_SB->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
+	error = affs_add_entry(dir, inode, dentry, ST_FILE);
+	if (error) {
+		inode->i_nlink = 0;
+		iput(inode);
+		return error;
+	}
+	return 0;
 }
 
 int
@@ -305,121 +289,78 @@
 {
 	struct inode		*inode;
 	int			 error;
-	
+
 	pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
 		 (int)dentry->d_name.len,dentry->d_name.name,mode);
 
-	error = -ENOSPC;
 	inode = affs_new_inode(dir);
 	if (!inode)
-		goto out;
+		return -ENOSPC;
+
+	inode->i_mode = S_IFDIR | mode;
+	mode_to_prot(inode);
 
 	inode->i_op = &affs_dir_inode_operations;
 	inode->i_fop = &affs_dir_operations;
-	error       = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
-	if (error)
-		goto out_iput;
-	inode->i_mode = S_IFDIR | S_ISVTX | mode;
-	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-	d_instantiate(dentry,inode);
-	mark_inode_dirty(inode);
-	dir->i_version = ++event;
-	mark_inode_dirty(dir);
-out:
-	return error;
 
-out_iput:
-	inode->i_nlink = 0;
-	mark_inode_dirty(inode);
-	iput(inode);
-	goto out;
-}
-
-static int
-empty_dir(struct buffer_head *bh, int hashsize)
-{
-	while (--hashsize >= 0) {
-		if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
-			return 0;
+	error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
+	if (error) {
+		inode->i_nlink = 0;
+		mark_inode_dirty(inode);
+		iput(inode);
+		return error;
 	}
-	return 1;
+	return 0;
 }
 
 int
 affs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	struct inode		*inode = dentry->d_inode;
-	int			 retval;
-	unsigned long		 ino;
-	struct buffer_head	*bh;
-
-	pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
-		 (int)dentry->d_name.len,dentry->d_name.name);
-
-	retval = -ENOENT;
-	if (!(bh = affs_find_entry(dir,dentry,&ino)))
-		goto rmdir_done;
+	pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
+		 (int)dentry->d_name.len, dentry->d_name.name);
 
-	/*
-	 * Make sure the directory is empty and the dentry isn't busy.
-	 */
-	retval = -ENOTEMPTY;
-	if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
-		goto rmdir_done;
-	retval = -EBUSY;
-	if (!d_unhashed(dentry))
-		goto rmdir_done;
-
-	if ((retval = affs_remove_header(bh,inode)) < 0)
-		goto rmdir_done;
-	
-	inode->i_nlink = retval;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	retval         = 0;
-	dir->i_version = ++event;
-	mark_inode_dirty(dir);
-	mark_inode_dirty(inode);
+	if (!dentry->d_inode)
+		return -ENOENT;
 
-rmdir_done:
-	affs_brelse(bh);
-	return retval;
+	return affs_remove_header(dentry);
 }
 
 int
 affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
+	struct super_block	*sb = dir->i_sb;
 	struct buffer_head	*bh;
 	struct inode		*inode;
 	char			*p;
-	unsigned long		 tmp;
 	int			 i, maxlen, error;
 	char			 c, lc;
 
 	pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
 		 (int)dentry->d_name.len,dentry->d_name.name,symname);
-	
-	maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
+
+	maxlen = AFFS_SB->s_hashsize * sizeof(u32) - 1;
 	error = -ENOSPC;
 	inode  = affs_new_inode(dir);
 	if (!inode)
-		goto out;
+		return -ENOSPC;
 
 	inode->i_op = &affs_symlink_inode_operations;
 	inode->i_data.a_ops = &affs_symlink_aops;
 	inode->i_mode = S_IFLNK | 0777;
-	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+	mode_to_prot(inode);
+
 	error = -EIO;
-	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+	bh = affs_bread(sb, inode->i_ino);
 	if (!bh)
-		goto out_iput;
+		goto err;
 	i  = 0;
-	p  = ((struct slink_front *)bh->b_data)->symname;
+	p  = (char *)AFFS_HEAD(bh)->table;
 	lc = '/';
 	if (*symname == '/') {
 		while (*symname == '/')
 			symname++;
-		while (inode->i_sb->u.affs_sb.s_volume[i])	/* Cannot overflow */
-			*p++ = inode->i_sb->u.affs_sb.s_volume[i++];
+		while (AFFS_SB->s_volume[i])	/* Cannot overflow */
+			*p++ = AFFS_SB->s_volume[i++];
 	}
 	while (i < maxlen && (c = *symname++)) {
 		if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
@@ -444,159 +385,90 @@
 	affs_brelse(bh);
 	mark_inode_dirty(inode);
 
-	/* N.B. This test shouldn't be necessary ... dentry must be negative */
-	error = -EEXIST;
-	bh = affs_find_entry(dir,dentry,&tmp);
-	if (bh)
-		goto out_release;
-	/* N.B. Shouldn't we add the entry before dirtying the buffer? */
-	error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
+	error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
 	if (error)
-		goto out_release;
-	d_instantiate(dentry,inode);
-	dir->i_version = ++event;
-	mark_inode_dirty(dir);
+		goto err;
 
-out:
-	return error;
+	return 0;
 
-out_release:
-	affs_brelse(bh);
-out_iput:
+err:
 	inode->i_nlink = 0;
 	mark_inode_dirty(inode);
 	iput(inode);
-	goto out;
+	return error;
 }
 
 int
 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
-	struct inode		*oldinode = old_dentry->d_inode;
-	struct inode		*inode;
-	struct buffer_head	*bh;
-	unsigned long		 i;
-	int			 error;
-	
-	pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
-		 (int)dentry->d_name.len,dentry->d_name.name);
+	struct inode *inode = old_dentry->d_inode;
+	int error;
 
-	/* N.B. Do we need this test? The dentry must be negative ... */
-	bh = affs_find_entry(dir,dentry,&i);
-	if (bh) {
-		affs_brelse(bh);
-		return -EEXIST;
-	}
-	if (oldinode->u.affs_i.i_hlink)	{	/* Cannot happen */
-		affs_warning(dir->i_sb,"link","Impossible link to link");
-		return -EINVAL;
-	}
-	error = -ENOSPC;
-	if (!(inode = affs_new_inode(dir)))
-		goto out;
+	pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino,
+		 (int)dentry->d_name.len,dentry->d_name.name);
 
-	inode->i_op                = oldinode->i_op;
-	inode->i_fop               = oldinode->i_fop;
-	inode->u.affs_i.i_protect  = mode_to_prot(oldinode->i_mode);
-	inode->u.affs_i.i_original = oldinode->i_ino;
-	inode->u.affs_i.i_hlink    = 1;
-	inode->i_mtime             = oldinode->i_mtime;
-
-	if (S_ISDIR(oldinode->i_mode))
-		error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR);
-	else
-		error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE);
-	if (error)
+	error = affs_add_entry(dir, inode, dentry, S_ISDIR(inode->i_mode) ? ST_LINKDIR : ST_LINKFILE);
+	if (error) {
 		inode->i_nlink = 0;
-	else {
-		dir->i_version = ++event;
-		mark_inode_dirty(dir);
-		mark_inode_dirty(oldinode);
-		atomic_inc(&oldinode->i_count);
-		d_instantiate(dentry,oldinode);
+		mark_inode_dirty(inode);
+		iput(inode);
+		return error;
 	}
-	mark_inode_dirty(inode);
-	iput(inode);
-
-out:
-	return error;
+	return 0;
 }
 
 int
 affs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	    struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct inode		*old_inode = old_dentry->d_inode;
-	struct inode		*new_inode = new_dentry->d_inode;
-	struct buffer_head	*old_bh;
-	struct buffer_head	*new_bh;
-	unsigned long		 old_ino;
-	unsigned long		 new_ino;
-	int			 retval;
-
-	pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n",
-		 old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode,
-		 new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
-	
-	if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
-		goto out;
+	struct super_block *sb = old_dir->i_sb;
+	struct inode *dir;
+	struct buffer_head *bh = NULL;
+	int retval;
+
+	pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
+		 (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
+		 (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
 
-	new_bh = NULL;
-	retval = -ENOENT;
-	old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
-	if (!old_bh)
-		goto end_rename;
-
-	new_bh = affs_find_entry(new_dir,new_dentry,&new_ino);
-	if (new_bh && !new_inode) {
-		affs_error(old_inode->i_sb,"affs_rename",
-			   "No inode for entry found (key=%lu)\n",new_ino);
-		goto end_rename;
-	}
-	if (S_ISDIR(old_inode->i_mode)) {
-		if (new_inode) {
-			retval = -EBUSY;
-			if (!d_unhashed(new_dentry))
-				goto end_rename;
-			retval = -ENOTEMPTY;
-			if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
-				goto end_rename;
-		}
+	if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
+		goto done;
 
-		retval = -ENOENT;
-		if (affs_parent_ino(old_inode) != old_dir->i_ino)
-			goto end_rename;
-	}
 	/* Unlink destination if it already exists */
-	if (new_inode) {
-		if ((retval = affs_remove_header(new_bh,new_dir)) < 0)
-			goto end_rename;
-		new_inode->i_nlink = retval;
-		mark_inode_dirty(new_inode);
-		if (new_inode->i_ino == new_ino)
-			new_inode->i_nlink = 0;
+	if (new_dentry->d_inode) {
+		retval = affs_remove_header(new_dentry);
+		if (retval)
+			return retval;
 	}
+
+	retval = -EIO;
+	bh = affs_bread(sb, old_dentry->d_inode->i_ino);
+	if (!bh)
+		goto done;
+
 	/* Remove header from its parent directory. */
-	if ((retval = affs_remove_hash(old_bh,old_dir)))
-		goto end_rename;
+	dir = old_dir;
+	down(&AFFS_DIR->i_hash_lock);
+	retval = affs_remove_hash(dir, bh);
+	if (retval)
+		goto done_unlock;
+
+	up(&AFFS_DIR->i_hash_lock);
+
 	/* And insert it into the new directory with the new name. */
-	affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
-	if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
-		goto end_rename;
-	affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);
-
-	new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
-			   = old_dir->i_mtime = CURRENT_TIME;
-	new_dir->i_version = ++event;
-	old_dir->i_version = ++event;
-	retval             = 0;
-	mark_inode_dirty(new_dir);
-	mark_inode_dirty(old_dir);
-	mark_buffer_dirty(old_bh);
-	
-end_rename:
-	affs_brelse(old_bh);
-	affs_brelse(new_bh);
-out:
+	dir = new_dir;
+	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
+	affs_fix_checksum(sb, bh);
+	down(&AFFS_DIR->i_hash_lock);
+	retval = affs_insert_hash(new_dir, bh);
+	if (retval)
+		goto done_unlock;
+	up(&AFFS_DIR->i_hash_lock);
+
+done:
+	affs_brelse(bh);
 	return retval;
+
+done_unlock:
+	up(&AFFS_DIR->i_hash_lock);
+	goto done;
 }
diff -u --recursive --new-file v2.4.3/linux/fs/affs/super.c linux/fs/affs/super.c
--- v2.4.3/linux/fs/affs/super.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/affs/super.c	Thu Apr 19 22:57:06 2001
@@ -10,7 +10,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#define DEBUG 0
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -33,37 +32,27 @@
 extern int *blk_size[];
 extern struct timezone sys_tz;
 
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
 static int affs_statfs(struct super_block *sb, struct statfs *buf);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
 static void
 affs_put_super(struct super_block *sb)
 {
-	int	 i;
-
 	pr_debug("AFFS: put_super()\n");
 
-	for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
-		affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
 	if (!(sb->s_flags & MS_RDONLY)) {
-		ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = be32_to_cpu(1);
+		AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag = be32_to_cpu(1);
 		secs_to_datestamp(CURRENT_TIME,
-				  &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
-		affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
-		mark_buffer_dirty(sb->u.affs_sb.s_root_bh);
+				  &AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->disk_change);
+		affs_fix_checksum(sb, AFFS_SB->s_root_bh);
+		mark_buffer_dirty(AFFS_SB->s_root_bh);
 	}
 
-	if (sb->u.affs_sb.s_prefix)
-		kfree(sb->u.affs_sb.s_prefix);
-	kfree(sb->u.affs_sb.s_bitmap);
-	affs_brelse(sb->u.affs_sb.s_root_bh);
-
-	/*
-	 * Restore the previous value of this device's blksize_size[][]
-	 */
-	set_blocksize(sb->s_dev, sb->u.affs_sb.s_blksize);
+	affs_brelse(AFFS_SB->s_bmap_bh);
+	if (AFFS_SB->s_prefix)
+		kfree(AFFS_SB->s_prefix);
+	kfree(AFFS_SB->s_bitmap);
+	affs_brelse(AFFS_SB->s_root_bh);
 
 	return;
 }
@@ -71,24 +60,17 @@
 static void
 affs_write_super(struct super_block *sb)
 {
-	int	 i, clean = 2;
+	int clean = 2;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
-		lock_super(sb);
-		for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) {
-			if (sb->u.affs_sb.s_bitmap[i].bm_bh) {
-				if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
-					clean = 0;
-					break;
-				}
-			}
-		}
-		unlock_super(sb);
-		ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = be32_to_cpu(clean);
+		//	if (AFFS_SB->s_bitmap[i].bm_bh) {
+		//		if (buffer_dirty(AFFS_SB->s_bitmap[i].bm_bh)) {
+		//			clean = 0;
+		AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag = be32_to_cpu(clean);
 		secs_to_datestamp(CURRENT_TIME,
-				  &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
-		affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
-		mark_buffer_dirty(sb->u.affs_sb.s_root_bh);
+				  &AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->disk_change);
+		affs_fix_checksum(sb, AFFS_SB->s_root_bh);
+		mark_buffer_dirty(AFFS_SB->s_root_bh);
 		sb->s_dirt = !clean;	/* redo until bitmap synced */
 	} else
 		sb->s_dirt = 0;
@@ -101,6 +83,7 @@
 	write_inode:	affs_write_inode,
 	put_inode:	affs_put_inode,
 	delete_inode:	affs_delete_inode,
+	clear_inode:	affs_clear_inode,
 	put_super:	affs_put_super,
 	write_super:	affs_write_super,
 	statfs:		affs_statfs,
@@ -236,65 +219,59 @@
  */
 
 static struct super_block *
-affs_read_super(struct super_block *s, void *data, int silent)
+affs_read_super(struct super_block *sb, void *data, int silent)
 {
-	struct buffer_head	*bh = NULL;
-	struct buffer_head	*bb;
-	struct inode		*root_inode;
-	kdev_t			 dev = s->s_dev;
+	struct buffer_head	*root_bh = NULL;
+	struct buffer_head	*boot_bh;
+	struct inode		*root_inode = NULL;
+	kdev_t			 dev = sb->s_dev;
 	s32			 root_block;
 	int			 blocks, size, blocksize;
 	u32			 chksum;
-	u32			*bm;
-	s32			 ptype, stype;
-	int			 mapidx;
 	int			 num_bm;
 	int			 i, j;
 	s32			 key;
 	uid_t			 uid;
 	gid_t			 gid;
 	int			 reserved;
-	int			 az_no;
-	int			 bmalt = 0;
 	unsigned long		 mount_flags;
-	unsigned long		 offset;
 
 	pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
-	s->s_magic             = AFFS_SUPER_MAGIC;
-	s->s_op                = &affs_sops;
-	s->u.affs_sb.s_bitmap  = NULL;
-	s->u.affs_sb.s_root_bh = NULL;
-	s->u.affs_sb.s_prefix  = NULL;
-	s->u.affs_sb.s_hashsize= 0;
+	sb->s_magic             = AFFS_SUPER_MAGIC;
+	sb->s_op                = &affs_sops;
+	memset(AFFS_SB, 0, sizeof(struct affs_sb_info));
+	init_MUTEX(&AFFS_SB->s_bmlock);
 
 	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
-				&blocksize,&s->u.affs_sb.s_prefix,
-				s->u.affs_sb.s_volume, &mount_flags))
-		goto out_bad_opts;
+				&blocksize,&AFFS_SB->s_prefix,
+				AFFS_SB->s_volume, &mount_flags)) {
+		printk(KERN_ERR "AFFS: Error parsing options\n");
+		return NULL;
+	}
 	/* N.B. after this point s_prefix must be released */
 
-	s->u.affs_sb.s_flags   = mount_flags;
-	s->u.affs_sb.s_mode    = i;
-	s->u.affs_sb.s_uid     = uid;
-	s->u.affs_sb.s_gid     = gid;
-	s->u.affs_sb.s_reserved= reserved;
+	AFFS_SB->s_flags   = mount_flags;
+	AFFS_SB->s_mode    = i;
+	AFFS_SB->s_uid     = uid;
+	AFFS_SB->s_gid     = gid;
+	AFFS_SB->s_reserved= reserved;
 
 	/* Get the size of the device in 512-byte blocks.
 	 * If we later see that the partition uses bigger
 	 * blocks, we will have to change it.
 	 */
 
-	blocks = blk_size[MAJOR(dev)][MINOR(dev)];
-	if (blocks == 0)
-		goto out_bad_size;
-	s->u.affs_sb.s_blksize = blksize_size[MAJOR(dev)][MINOR(dev)];
-	if (!s->u.affs_sb.s_blksize)
-		s->u.affs_sb.s_blksize = BLOCK_SIZE;
-	size = (s->u.affs_sb.s_blksize / 512) * blocks;
-	pr_debug("AFFS: initial blksize=%d, blocks=%d\n",
-		s->u.affs_sb.s_blksize, blocks);
+	blocks = blk_size[MAJOR(dev)] ? blk_size[MAJOR(dev)][MINOR(dev)] : 0;
+	if (!blocks) {
+		printk(KERN_ERR "AFFS: Could not determine device size\n");
+		goto out_error;
+	}
+	size = (BLOCK_SIZE / 512) * blocks;
+	pr_debug("AFFS: initial blksize=%d, blocks=%d\n", 512, blocks);
 
+#warning
+	affs_set_blocksize(sb, PAGE_SIZE);
 	/* Try to find root block. Its location depends on the block size. */
 
 	i = 512;
@@ -304,11 +281,12 @@
 		size = size / (blocksize / 512);
 	}
 	for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
-		s->u.affs_sb.s_root_block = root_block;
+		AFFS_SB->s_root_block = root_block;
 		if (root_block < 0)
-			s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
+			AFFS_SB->s_root_block = (reserved + size - 1) / 2;
 		pr_debug("AFFS: setting blocksize to %d\n", blocksize);
-		set_blocksize(dev, blocksize);
+		affs_set_blocksize(sb, blocksize);
+		AFFS_SB->s_partition_size = size;
 
 		/* The root block location that was calculated above is not
 		 * correct if the partition size is an odd number of 512-
@@ -324,299 +302,137 @@
 			pr_debug("AFFS: Dev %s, trying root=%u, bs=%d, "
 				"size=%d, reserved=%d\n",
 				kdevname(dev),
-				s->u.affs_sb.s_root_block + num_bm,
+				AFFS_SB->s_root_block + num_bm,
 				blocksize, size, reserved);
-			bh = affs_bread(dev, s->u.affs_sb.s_root_block + num_bm,
-					blocksize);
-			if (!bh)
+			root_bh = affs_bread(sb, AFFS_SB->s_root_block + num_bm);
+			if (!root_bh)
 				continue;
-			if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
-			    ptype == T_SHORT && stype == ST_ROOT) {
-				s->s_blocksize             = blocksize;
-				s->u.affs_sb.s_hashsize    = blocksize / 4 - 56;
-				s->u.affs_sb.s_root_block += num_bm;
+			if (!affs_checksum_block(sb, root_bh) &&
+			    be32_to_cpu(AFFS_ROOT_HEAD(root_bh)->ptype) == T_SHORT &&
+			    be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
+				AFFS_SB->s_hashsize    = blocksize / 4 - 56;
+				AFFS_SB->s_root_block += num_bm;
 				key                        = 1;
 				goto got_root;
 			}
-			affs_brelse(bh);
-			bh = NULL;
+			affs_brelse(root_bh);
+			root_bh = NULL;
 		}
 	}
-	goto out_no_valid_block;
+	if (!silent)
+		printk(KERN_ERR "AFFS: No valid root block on device %s\n",
+			kdevname(dev));
+	goto out_error;
 
 	/* N.B. after this point bh must be released */
 got_root:
-	root_block = s->u.affs_sb.s_root_block;
+	root_block = AFFS_SB->s_root_block;
 
-	s->u.affs_sb.s_partition_size   = size;
-	s->s_blocksize_bits             = blocksize == 512 ? 9 :
-					  blocksize == 1024 ? 10 :
-					  blocksize == 2048 ? 11 : 12;
+	sb->s_blocksize_bits = blocksize == 512 ? 9 :
+			       blocksize == 1024 ? 10 :
+			       blocksize == 2048 ? 11 : 12;
 
 	/* Find out which kind of FS we have */
-	bb = affs_bread(dev,0,s->s_blocksize);
-	if (!bb)
-		goto out_no_root_block;
-	chksum = be32_to_cpu(*(u32 *)bb->b_data);
-	affs_brelse(bb);
+	boot_bh = bread(sb->s_dev, 0, sb->s_blocksize);
+	if (!boot_bh) {
+		printk(KERN_ERR "AFFS: Cannot read boot block\n");
+		goto out_error;
+	}
+	chksum = be32_to_cpu(*(u32 *)boot_bh->b_data);
+	brelse(boot_bh);
 
 	/* Dircache filesystems are compatible with non-dircache ones
 	 * when reading. As long as they aren't supported, writing is
 	 * not recommended.
 	 */
 	if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
-	     || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
+	     || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) {
 		printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
 			kdevname(dev));
-		s->s_flags |= MS_RDONLY;
-		s->u.affs_sb.s_flags |= SF_READONLY;
+		sb->s_flags |= MS_RDONLY;
+		AFFS_SB->s_flags |= SF_READONLY;
 	}
 	switch (chksum) {
 		case MUFS_FS:
 		case MUFS_INTLFFS:
-			s->u.affs_sb.s_flags |= SF_MUFS;
+			AFFS_SB->s_flags |= SF_MUFS;
 			/* fall thru */
 		case FS_INTLFFS:
-			s->u.affs_sb.s_flags |= SF_INTL;
+			AFFS_SB->s_flags |= SF_INTL;
 			break;
 		case MUFS_DCFFS:
 		case MUFS_FFS:
-			s->u.affs_sb.s_flags |= SF_MUFS;
+			AFFS_SB->s_flags |= SF_MUFS;
 			break;
 		case FS_DCFFS:
 		case FS_FFS:
 			break;
 		case MUFS_OFS:
-			s->u.affs_sb.s_flags |= SF_MUFS;
+			AFFS_SB->s_flags |= SF_MUFS;
 			/* fall thru */
 		case FS_OFS:
-			s->u.affs_sb.s_flags |= SF_OFS;
-			s->s_flags |= MS_NOEXEC;
+			AFFS_SB->s_flags |= SF_OFS;
+			sb->s_flags |= MS_NOEXEC;
 			break;
 		case MUFS_DCOFS:
 		case MUFS_INTLOFS:
-			s->u.affs_sb.s_flags |= SF_MUFS;
+			AFFS_SB->s_flags |= SF_MUFS;
 		case FS_DCOFS:
 		case FS_INTLOFS:
-			s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
-			s->s_flags |= MS_NOEXEC;
+			AFFS_SB->s_flags |= SF_INTL | SF_OFS;
+			sb->s_flags |= MS_NOEXEC;
 			break;
 		default:
-			goto out_unknown_fs;
+			printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
+				kdevname(dev), chksum);
+			goto out_error;
 	}
 
 	if (mount_flags & SF_VERBOSE) {
 		chksum = cpu_to_be32(chksum);
 		printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
-			GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
-			&GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
+			AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
+			AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
 			(char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
 	}
 
-	s->s_flags |= MS_NODEV | MS_NOSUID;
+	sb->s_flags |= MS_NODEV | MS_NOSUID;
 
-	/*
-	 * Max file size is 2Gb
-	 */
-	 
-	s->s_maxbytes = MAX_NON_LFS;
+	AFFS_SB->s_data_blksize = sb->s_blocksize;
+	if (AFFS_SB->s_flags & SF_OFS)
+		AFFS_SB->s_data_blksize -= 24;
 
 	/* Keep super block in cache */
-	bb = affs_bread(dev,root_block,s->s_blocksize);
-	if (!bb)
-		goto out_no_root_block;
-	s->u.affs_sb.s_root_bh = bb;
+	AFFS_SB->s_root_bh = root_bh;
 	/* N.B. after this point s_root_bh must be released */
 
-	/* Allocate space for bitmaps, zones and others */
-
-	size   = s->u.affs_sb.s_partition_size - reserved;
-	num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
-	az_no  = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32);
-	ptype  = num_bm * sizeof(struct affs_bm_info) +
-		 az_no * sizeof(struct affs_alloc_zone) +
-		 MAX_ZONES * sizeof(struct affs_zone);
-	pr_debug("AFFS: num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
-	if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype, GFP_KERNEL)))
-		goto out_no_bitmap;
-	memset(s->u.affs_sb.s_bitmap,0,ptype);
-	/* N.B. after the point s_bitmap must be released */
-
-	s->u.affs_sb.s_zones   = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
-	s->u.affs_sb.s_alloc   = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES];
-	s->u.affs_sb.s_num_az  = az_no;
-
-	mapidx = 0;
-
-	if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) {
-		if (!(s->s_flags & MS_RDONLY)) {
-			printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
-				kdevname(dev));
-			s->s_flags |= MS_RDONLY;
-		}
-		affs_brelse(bh);
-		bh = NULL;
-		goto nobitmap;
-	}
-
-	/* The following section is ugly, I know. Especially because of the
-	 * reuse of some variables that are not named properly.
-	 */
-
-	key    = root_block;
-	ptype  = s->s_blocksize / 4 - 49;
-	stype  = ptype + 25;
-	offset = s->u.affs_sb.s_reserved;
-	az_no  = 0;
-	while (bh) {
-		bm = (u32 *)bh->b_data;
-		for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
-			if (mapidx >= num_bm) {
-				printk(KERN_ERR "AFFS: Extraneous bitmap pointer - "
-					       "mounting %s read only.\n",kdevname(dev));
-				s->s_flags |= MS_RDONLY;
-				s->u.affs_sb.s_flags |= SF_READONLY;
-				continue;
-			}
-			bb = affs_bread(dev,be32_to_cpu(bm[i]),s->s_blocksize);
-			if (!bb)
-				goto out_no_read_bm;
-			if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
-			    !(s->s_flags & MS_RDONLY)) {
-				printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - "
-				       "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]),
-					kdevname(dev));
-				s->s_flags |= MS_RDONLY;
-				s->u.affs_sb.s_flags |= SF_READONLY;
-			}
-			/* Mark unused bits in the last word as allocated */
-			if (size <= s->s_blocksize * 8 - 32) {	/* last bitmap */
-				ptype = size / 32 + 1;		/* word number */
-				key   = size & 0x1F;		/* used bits */
-				if (key && !(s->s_flags & MS_RDONLY)) {
-					chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key));
-					((u32 *)bb->b_data)[ptype] &= chksum;
-					affs_fix_checksum(s->s_blocksize,bb->b_data,0);
-					mark_buffer_dirty(bb);
-					bmalt = 1;
-				}
-				ptype = (size + 31) & ~0x1F;
-				size  = 0;
-				s->u.affs_sb.s_flags |= SF_BM_VALID;
-			} else {
-				ptype = s->s_blocksize * 8 - 32;
-				size -= ptype;
-			}
-			s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
-			s->u.affs_sb.s_bitmap[mapidx].bm_bh       = NULL;
-			s->u.affs_sb.s_bitmap[mapidx].bm_key      = be32_to_cpu(bm[i]);
-			s->u.affs_sb.s_bitmap[mapidx].bm_count    = 0;
-			offset += ptype;
-
-			for (j = 0; ptype > 0; j++, az_no++, ptype -= key) {
-				key = MIN(ptype,AFFS_ZONE_SIZE);	/* size in bits */
-				s->u.affs_sb.s_alloc[az_no].az_size = key / 32;
-				s->u.affs_sb.s_alloc[az_no].az_free =
-					affs_count_free_bits(key / 8,bb->b_data +
-					     j * (AFFS_ZONE_SIZE / 8) + 4);
-			}
-			affs_brelse(bb);
-		}
-		key   = be32_to_cpu(bm[stype]);		/* Next block of bitmap pointers	*/
-		ptype = 0;
-		stype = s->s_blocksize / 4 - 1;
-		affs_brelse(bh);
-		bh = NULL;
-		if (key) {
-			bh = affs_bread(dev,key,s->s_blocksize);
-			if (!bh)
-				goto out_no_bm_ext;
-		}
-	}
-	if (mapidx < num_bm)
-		goto out_bad_num;
-
-nobitmap:
-	s->u.affs_sb.s_bm_count = num_bm;
+	if (affs_init_bitmap(sb))
+		goto out_error;
 
 	/* set up enough so that it can read an inode */
 
-	s->s_dirt  = 1;
-	root_inode = iget(s,root_block);
-	if (!root_inode)
-		goto out_no_root;
-	s->s_root  = d_alloc_root(root_inode);
-	if (!s->s_root)
-		goto out_no_root;
-	s->s_root->d_op = &affs_dentry_operations;
-
-	/* Record date of last change if the bitmap was truncated and
-	 * create data zones if the volume is writable.
-	 */
-
-	if (!(s->s_flags & MS_RDONLY)) {
-		if (bmalt) {
-			secs_to_datestamp(CURRENT_TIME,&ROOT_END(
-				s->u.affs_sb.s_root_bh->b_data,root_inode)->disk_altered);
-			affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
-			mark_buffer_dirty(s->u.affs_sb.s_root_bh);
-		}
-		affs_make_zones(s);
+	root_inode = iget(sb, root_block);
+	sb->s_root = d_alloc_root(root_inode);
+	if (!sb->s_root) {
+		printk(KERN_ERR "AFFS: Get root inode failed\n");
+		goto out_error;
 	}
+	sb->s_root->d_op = &affs_dentry_operations;
 
-	pr_debug("AFFS: s_flags=%lX\n",s->s_flags);
-	return s;
-
-out_bad_opts:
-	printk(KERN_ERR "AFFS: Error parsing options\n");
-	goto out_fail;
-out_bad_size:
-	printk(KERN_ERR "AFFS: Could not determine device size\n");
-	goto out_free_prefix;
-out_no_valid_block:
-	if (!silent)
-		printk(KERN_ERR "AFFS: No valid root block on device %s\n",
-			kdevname(dev));
-	goto out_restore;
-out_unknown_fs:
-	printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
-		kdevname(dev), chksum);
-	goto out_free_bh;
-out_no_root_block:
-	printk(KERN_ERR "AFFS: Cannot read root block\n");
-	goto out_free_bh;
-out_no_bitmap:
-	printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
-	goto out_free_root_block;
-out_no_read_bm:
-	printk(KERN_ERR "AFFS: Cannot read bitmap\n");
-	goto out_free_bitmap;
-out_no_bm_ext:
-	printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
-	goto out_free_bitmap;
-out_bad_num:
-	printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",
-		mapidx, num_bm);
-	goto out_free_bitmap;
-out_no_root:
-	printk(KERN_ERR "AFFS: Get root inode failed\n");
+	pr_debug("AFFS: s_flags=%lX\n",sb->s_flags);
+	return sb;
 
 	/*
 	 * Begin the cascaded cleanup ...
 	 */
-	iput(root_inode);
-out_free_bitmap:
-	kfree(s->u.affs_sb.s_bitmap);
-out_free_root_block:
-	affs_brelse(s->u.affs_sb.s_root_bh);
-out_free_bh:
-	affs_brelse(bh);
-out_restore:
-	set_blocksize(dev, s->u.affs_sb.s_blksize);
-out_free_prefix:
-	if (s->u.affs_sb.s_prefix)
-		kfree(s->u.affs_sb.s_prefix);
-out_fail:
+out_error:
+	if (root_inode)
+		iput(root_inode);
+	if (AFFS_SB->s_bitmap)
+		kfree(AFFS_SB->s_bitmap);
+	affs_brelse(root_bh);
+	if (AFFS_SB->s_prefix)
+		kfree(AFFS_SB->s_prefix);
 	return NULL;
 }
 
@@ -630,17 +446,17 @@
 	int			 reserved;
 	int			 root_block;
 	unsigned long		 mount_flags;
-	unsigned long		 read_only = sb->u.affs_sb.s_flags & SF_READONLY;
+	unsigned long		 read_only = AFFS_SB->s_flags & SF_READONLY;
 
 	pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
 
 	if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
-	    &blocksize,&sb->u.affs_sb.s_prefix,sb->u.affs_sb.s_volume,&mount_flags))
+	    &blocksize,&AFFS_SB->s_prefix,AFFS_SB->s_volume,&mount_flags))
 		return -EINVAL;
-	sb->u.affs_sb.s_flags = mount_flags | read_only;
-	sb->u.affs_sb.s_mode  = mode;
-	sb->u.affs_sb.s_uid   = uid;
-	sb->u.affs_sb.s_gid   = gid;
+	AFFS_SB->s_flags = mount_flags | read_only;
+	AFFS_SB->s_mode  = mode;
+	AFFS_SB->s_uid   = uid;
+	AFFS_SB->s_gid   = gid;
 
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 		return 0;
@@ -649,9 +465,8 @@
 		while (sb->s_dirt)
 			affs_write_super(sb);
 		sb->s_flags |= MS_RDONLY;
-	} else if (!(sb->u.affs_sb.s_flags & SF_READONLY)) {
+	} else if (!(AFFS_SB->s_flags & SF_READONLY)) {
 		sb->s_flags &= ~MS_RDONLY;
-		affs_make_zones(sb);
 	} else {
 		affs_warning(sb,"remount","Cannot remount fs read/write because of errors");
 		return -EINVAL;
@@ -664,13 +479,13 @@
 {
 	int		 free;
 
-	pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
-	     sb->u.affs_sb.s_reserved);
+	pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB->s_partition_size,
+	     AFFS_SB->s_reserved);
 
 	free          = affs_count_free_blocks(sb);
 	buf->f_type    = AFFS_SUPER_MAGIC;
 	buf->f_bsize   = sb->s_blocksize;
-	buf->f_blocks  = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
+	buf->f_blocks  = AFFS_SB->s_partition_size - AFFS_SB->s_reserved;
 	buf->f_bfree   = free;
 	buf->f_bavail  = free;
 	return 0;
diff -u --recursive --new-file v2.4.3/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- v2.4.3/linux/fs/affs/symlink.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/affs/symlink.c	Thu Apr 19 22:57:06 2001
@@ -32,7 +32,7 @@
 
 	err = -EIO;
 	lock_kernel();
-	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+	bh = affs_bread(inode->i_sb, inode->i_ino);
 	unlock_kernel();
 	if (!bh)
 		goto fail;
diff -u --recursive --new-file v2.4.3/linux/fs/autofs4/expire.c linux/fs/autofs4/expire.c
--- v2.4.3/linux/fs/autofs4/expire.c	Mon Oct 23 21:57:38 2000
+++ linux/fs/autofs4/expire.c	Fri Apr 20 22:57:51 2001
@@ -98,8 +98,6 @@
 		 top, count));
 	this_parent = top;
 
-	count--;	/* top is passed in after being dgot */
-
 	if (is_autofs4_dentry(top)) {
 		count--;
 		DPRINTK(("is_tree_busy: autofs; count=%d\n", count));
@@ -168,8 +166,6 @@
 	unsigned long timeout;
 	struct dentry *root = sb->s_root;
 	struct list_head *tmp;
-	struct dentry *d;
-	struct vfsmount *p;
 
 	if (!sbi->exp_timeout || !root)
 		return NULL;
@@ -208,23 +204,17 @@
 			     attempts if expire fails the first time */
 			ino->last_used = now;
 		}
-		p = mntget(mnt);
-		d = dget_locked(dentry);
-
-		if (!is_tree_busy(p, d)) {
+		if (!is_tree_busy(mnt, dentry)) {
 			DPRINTK(("autofs_expire: returning %p %.*s\n",
 				 dentry, (int)dentry->d_name.len, dentry->d_name.name));
 			/* Start from here next time */
 			list_del(&root->d_subdirs);
 			list_add(&root->d_subdirs, &dentry->d_child);
+			dget(dentry);
 			spin_unlock(&dcache_lock);
 
-			dput(d);
-			mntput(p);
 			return dentry;
 		}
-		dput(d);
-		mntput(p);
 	}
 	spin_unlock(&dcache_lock);
 
@@ -251,6 +241,7 @@
 	pkt.len = dentry->d_name.len;
 	memcpy(pkt.name, dentry->d_name.name, pkt.len);
 	pkt.name[pkt.len] = '\0';
+	dput(dentry);
 
 	if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
 		return -EFAULT;
@@ -278,6 +269,7 @@
 		de_info->flags |= AUTOFS_INF_EXPIRING;
 		ret = autofs4_wait(sbi, &dentry->d_name, NFY_EXPIRE);
 		de_info->flags &= ~AUTOFS_INF_EXPIRING;
+		dput(dentry);
 	}
 		
 	return ret;
diff -u --recursive --new-file v2.4.3/linux/fs/bfs/inode.c linux/fs/bfs/inode.c
--- v2.4.3/linux/fs/bfs/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/bfs/inode.c	Tue Apr 17 23:16:38 2001
@@ -250,7 +250,6 @@
 	set_blocksize(dev, BFS_BSIZE);
 	s->s_blocksize = BFS_BSIZE;
 	s->s_blocksize_bits = BFS_BSIZE_BITS;
-	s->s_maxbytes = MAX_NON_LFS;
 
 	bh = bread(dev, 0, BFS_BSIZE);
 	if(!bh)
diff -u --recursive --new-file v2.4.3/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.4.3/linux/fs/binfmt_elf.c	Mon Mar 19 17:05:16 2001
+++ linux/fs/binfmt_elf.c	Thu Apr  5 17:13:23 2001
@@ -140,7 +140,7 @@
 	 */
 	sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL);
 	csp = sp;
-	csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0));
+	csp -= DLINFO_ITEMS*2 + (k_platform ? 2 : 0);
 	csp -= envc+1;
 	csp -= argc+1;
 	csp -= (!ibcs ? 3 : 1);	/* argc itself */
@@ -160,25 +160,20 @@
 		sp -= 2;
 		NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform);
 	}
-	sp -= 3*2;
-	NEW_AUX_ENT(0, AT_HWCAP, hwcap);
-	NEW_AUX_ENT(1, AT_PAGESZ, ELF_EXEC_PAGESIZE);
-	NEW_AUX_ENT(2, AT_CLKTCK, CLOCKS_PER_SEC);
-
-	if (exec) {
-		sp -= 10*2;
-
-		NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff);
-		NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr));
-		NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum);
-		NEW_AUX_ENT(3, AT_BASE, interp_load_addr);
-		NEW_AUX_ENT(4, AT_FLAGS, 0);
-		NEW_AUX_ENT(5, AT_ENTRY, load_bias + exec->e_entry);
-		NEW_AUX_ENT(6, AT_UID, (elf_addr_t) current->uid);
-		NEW_AUX_ENT(7, AT_EUID, (elf_addr_t) current->euid);
-		NEW_AUX_ENT(8, AT_GID, (elf_addr_t) current->gid);
-		NEW_AUX_ENT(9, AT_EGID, (elf_addr_t) current->egid);
-	}
+	sp -= DLINFO_ITEMS*2;
+	NEW_AUX_ENT( 0, AT_HWCAP, hwcap);
+	NEW_AUX_ENT( 1, AT_PAGESZ, ELF_EXEC_PAGESIZE);
+	NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC);
+	NEW_AUX_ENT( 3, AT_PHDR, load_addr + exec->e_phoff);
+	NEW_AUX_ENT( 4, AT_PHENT, sizeof (struct elf_phdr));
+	NEW_AUX_ENT( 5, AT_PHNUM, exec->e_phnum);
+	NEW_AUX_ENT( 6, AT_BASE, interp_load_addr);
+	NEW_AUX_ENT( 7, AT_FLAGS, 0);
+	NEW_AUX_ENT( 8, AT_ENTRY, load_bias + exec->e_entry);
+	NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid);
+	NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid);
+	NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid);
+	NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid);
 #undef NEW_AUX_ENT
 
 	sp -= envc+1;
@@ -694,7 +689,7 @@
 	  create_elf_tables((char *)bprm->p,
 			bprm->argc,
 			bprm->envc,
-			(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+			&elf_ex,
 			load_addr, load_bias,
 			interp_load_addr,
 			(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
diff -u --recursive --new-file v2.4.3/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.3/linux/fs/buffer.c	Sat Mar 24 19:31:58 2001
+++ linux/fs/buffer.c	Wed Apr 18 11:49:13 2001
@@ -555,25 +555,6 @@
 	return bh;
 }
 
-unsigned int get_hardblocksize(kdev_t dev)
-{
-	/*
-	 * Get the hard sector size for the given device.  If we don't know
-	 * what it is, return 0.
-	 */
-	if (hardsect_size[MAJOR(dev)] != NULL) {
-		int blksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
-		if (blksize != 0)
-			return blksize;
-	}
-
-	/*
-	 * We don't know what the hardware sector size for this device is.
-	 * Return 0 indicating that we don't know.
-	 */
-	return 0;
-}
-
 void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
 {
 	spin_lock(&lru_list_lock);
@@ -1367,11 +1348,12 @@
 {
 	if (buffer_mapped(bh)) {
 		mark_buffer_clean(bh);
-		wait_on_buffer(bh);
+		lock_buffer(bh);
 		clear_bit(BH_Uptodate, &bh->b_state);
 		clear_bit(BH_Mapped, &bh->b_state);
 		clear_bit(BH_Req, &bh->b_state);
 		clear_bit(BH_New, &bh->b_state);
+		unlock_buffer(bh);
 	}
 }
 
diff -u --recursive --new-file v2.4.3/linux/fs/coda/cache.c linux/fs/coda/cache.c
--- v2.4.3/linux/fs/coda/cache.c	Thu Sep 21 09:59:46 2000
+++ linux/fs/coda/cache.c	Wed Apr 25 16:18:54 2001
@@ -1,9 +1,10 @@
 /*
  * Cache operations for Coda.
  * For Linux 2.1: (C) 1997 Carnegie Mellon University
+ * For Linux 2.3: (C) 2000 Carnegie Mellon University
  *
  * Carnegie Mellon encourages users of this code to contribute improvements
- * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
+ * to the Coda project http://www.coda.cs.cmu.edu/ <coda@cs.cmu.edu>.
  */
 
 #include <linux/types.h>
@@ -59,8 +60,6 @@
         list_for_each(tmp, &sbi->sbi_cihead)
         {
 		cii = list_entry(tmp, struct coda_inode_info, c_cilist);
-                if ( cii->c_magic != CODA_CNODE_MAGIC ) BUG();
-
                 if (!cred || coda_cred_eq(cred, &cii->c_cached_cred))
                         cii->c_cached_perm = 0;
 	}
@@ -93,26 +92,6 @@
    - an inode method coda_revalidate (for attributes) if the 
      flag is C_VATTR
 */
-
-/* 
-   Some of this is pretty scary: what can disappear underneath us?
-   - shrink_dcache_parent calls on purge_one_dentry which is safe:
-     it only purges children.
-   - dput is evil since it  may recurse up the dentry tree
- */
-
-void coda_purge_dentries(struct inode *inode)
-{
-	if (!inode)
-		return ;
-
-	/* better safe than sorry: dput could kill us */
-	iget(inode->i_sb, inode->i_ino);
-	/* catch the dentries later if some are still busy */
-	coda_flag_inode(inode, C_PURGE);
-	d_prune_aliases(inode);
-	iput(inode);
-}
 
 /* this won't do any harm: just flag all children */
 static void coda_flag_children(struct dentry *parent, int flag)
diff -u --recursive --new-file v2.4.3/linux/fs/coda/cnode.c linux/fs/coda/cnode.c
--- v2.4.3/linux/fs/coda/cnode.c	Fri Feb  9 10:18:27 2001
+++ linux/fs/coda/cnode.c	Wed Apr 25 16:18:54 2001
@@ -14,8 +14,6 @@
 extern int coda_debug;
 extern int coda_print_entry;
 
-static ViceFid NullFID = { 0, 0, 0 };
-
 inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
 {
 	if (fid1->Vnode != fid2->Vnode)   return 0;
@@ -24,6 +22,12 @@
 	return 1;
 }
 
+inline int coda_isnullfid(ViceFid *fid)
+{
+	if (fid->Vnode || fid->Volume || fid->Unique) return 0;
+	return 1;
+}
+
 static int coda_inocmp(struct inode *inode, unsigned long ino, void *opaque)
 {
 	return (coda_fideq((ViceFid *)opaque, &(ITOC(inode)->c_fid)));
@@ -64,7 +68,7 @@
 {
 	struct inode *inode;
 	struct coda_inode_info *cii;
-	ino_t ino = attr->va_fileid;
+	ino_t ino = coda_f2i(fid);
 
 	inode = iget4(sb, ino, coda_inocmp, fid);
 
@@ -75,14 +79,12 @@
 
 	/* check if the inode is already initialized */
 	cii = ITOC(inode);
-	if (coda_fideq(&cii->c_fid, &NullFID)) {
+	if (coda_isnullfid(&cii->c_fid))
 		/* new, empty inode found... initializing */
-		cii->c_fid   = *fid;
-		cii->c_vnode = inode;
-	}
+		cii->c_fid = *fid;
 
 	/* we shouldnt see inode collisions anymore */
-	if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
+	if (!coda_fideq(fid, &cii->c_fid)) BUG();
 
 	/* always replace the attributes, type might have changed */
 	coda_fill_inode(inode, attr);
@@ -122,7 +124,7 @@
 
 	CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n",
 		(*inode)->i_ino, atomic_read(&(*inode)->i_count), 
-		coda_f2s(&(*inode)->u.coda_i.c_fid));
+		coda_f2s(&ITOC(*inode)->c_fid));
         EXIT;
 	return 0;
 }
@@ -135,18 +137,18 @@
 	
 	cii = ITOC(inode);
 
-	if ( ! coda_fideq(&cii->c_fid, oldfid) )
-		printk("What? oldfid != cii->c_fid. Call 911.\n");
+	if (!coda_fideq(&cii->c_fid, oldfid))
+		BUG();
 
+	/* replace fid and rehash inode */
+	/* XXX we probably need to hold some lock here! */
+	remove_inode_hash(inode);
 	cii->c_fid = *newfid;
+	inode->i_ino = coda_f2i(newfid);
+	insert_inode_hash(inode);
 }
 
-
- 
-
-/* convert a fid to an inode. Mostly we can compute
-   the inode number from the FID, but not for volume
-   mount points: those are in a list */
+/* convert a fid to an inode. */
 struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) 
 {
 	ino_t nr;
@@ -161,31 +163,6 @@
 
 	CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
 
-
-        /* weird fids cannot be hashed, have to look for them the hard way */
-	if ( coda_fid_is_weird(fid) ) {
-		struct coda_sb_info *sbi = coda_sbp(sb);
-		struct list_head *le;
-
-                list_for_each(le, &sbi->sbi_cihead)
-                {
-			cii = list_entry(le, struct coda_inode_info, c_cilist);
-			if ( cii->c_magic != CODA_CNODE_MAGIC ) BUG();
-
-			CDEBUG(D_DOWNCALL, "iterating, now doing %s, ino %ld\n",
-			       coda_f2s(&cii->c_fid), cii->c_vnode->i_ino);
-
-			if ( coda_fideq(&cii->c_fid, fid) ) {
-				inode = cii->c_vnode;
-				CDEBUG(D_INODE, "volume root, found %ld\n", inode->i_ino);
-				iget4(sb, inode->i_ino, coda_inocmp, fid);
-				return inode;
-			}
-		}
-		return NULL;
-	}
-
-	/* fid is not weird: ino should be computable */
 	nr = coda_f2i(fid);
 	inode = iget4(sb, nr, coda_inocmp, fid);
 	if ( !inode ) {
@@ -196,13 +173,14 @@
 
 	cii = ITOC(inode);
 
-	/* The inode might already be purged due to memory pressure */
-	if ( coda_fideq(&cii->c_fid, &NullFID) ) {
+	/* The inode could already be purged due to memory pressure */
+	if (coda_isnullfid(&cii->c_fid)) {
+		inode->i_nlink = 0;
 		iput(inode);
 		return NULL;
 	}
 
-	/* we shouldn't have inode collisions anymore */
+	/* we shouldn't see inode collisions anymore */
 	if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
 
         CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
diff -u --recursive --new-file v2.4.3/linux/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c
--- v2.4.3/linux/fs/coda/coda_linux.c	Tue Sep 19 15:08:59 2000
+++ linux/fs/coda/coda_linux.c	Wed Apr 25 16:18:54 2001
@@ -25,9 +25,10 @@
 #include <linux/coda_fs_i.h>
 
 /* initialize the debugging variables */
-int coda_debug = 0;
-int coda_print_entry = 0; 
+int coda_debug;
+int coda_print_entry; 
 int coda_access_cache = 1;
+int coda_fake_statfs;
 
 /* print a fid */
 char * coda_f2s(ViceFid *f)
@@ -54,50 +55,15 @@
 /* recognize special .CONTROL name */
 int coda_iscontrol(const char *name, size_t length)
 {
-	if ((CODA_CONTROLLEN == length) && 
-	    (strncmp(name, CODA_CONTROL, CODA_CONTROLLEN) == 0))
-		return 1;
-	return 0;
+	return ((CODA_CONTROLLEN == length) && 
+                (strncmp(name, CODA_CONTROL, CODA_CONTROLLEN) == 0));
 }
 
 /* recognize /coda inode */
 int coda_isroot(struct inode *i)
 {
-    if ( i->i_sb->s_root->d_inode == i ) {
-	    return 1;
-    } else {
-	    return 0;
-    }
+    return ( i->i_sb->s_root->d_inode == i );
 }
-
-int coda_fid_is_weird(struct ViceFid *fid)
-{
-        /* volume roots */
-        if ( (fid->Vnode == 1) && (fid->Unique == 1 ) )
-	        return 1;
-        /* tmpfid unique (simulate.cc) */
-	if ( fid->Unique == 0xffffffff )
-	        return 1;
-	/* LocalFakeVnode (local.h)  */
-	if ( fid->Vnode == 0xfffffffd )
-	        return 1;
-	/* LocalFileVnode (venus.private.h) */
-	if ( fid->Vnode == 0xfffffffe )
-	        return 1;
-	/* local fake vid (local.h) */
-	if ( fid->Volume == 0xffffffff )
-	        return 1;
-	/* local DirVnode (venus.private.h) */
-	if ( fid->Vnode == 0xffffffff )
-	        return 1;
-	/* FakeVnode (venus.private.h) */
-	if ( fid->Vnode == 0xfffffffc )
-	        return 1;
-
-	return 0;
-}
-
-
 
 /* put the current process credentials in the cred */
 void coda_load_creds(struct coda_cred *cred)
diff -u --recursive --new-file v2.4.3/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.4.3/linux/fs/coda/dir.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/coda/dir.c	Wed Apr 25 16:18:54 2001
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
@@ -49,11 +50,9 @@
 static int coda_dentry_delete(struct dentry *);
 
 /* support routines */
-static void coda_prepare_fakefile(struct inode *coda_inode,
-		                  struct file *coda_file, 
-				  struct inode *open_inode,
-				  struct file *open_file,
-				  struct dentry *open_dentry);
+static void coda_prepare_fakefile(struct file *coda_file, 
+				  struct dentry *open_dentry,
+				  struct file *open_file);
 static int coda_venus_readdir(struct file *filp, void *dirent, 
 			      filldir_t filldir);
 int coda_fsync(struct file *, struct dentry *dentry, int datasync);
@@ -86,13 +85,14 @@
 	read:		generic_read_dir,
 	readdir:	coda_readdir,
 	open:		coda_open,
+	flush:  	coda_flush,
 	release:	coda_release,
 	fsync:		coda_fsync,
 };
 
 
 /* inode operations for directories */
-/* acces routines: lookup, readlink, permission */
+/* access routines: lookup, readlink, permission */
 static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
 {
 	struct inode *res_inode = NULL;
@@ -138,11 +138,6 @@
 
 	    	error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
 		if (error) return ERR_PTR(error);
-
-		/* make sure we drop unexpected weird fid's */
-		if (coda_f2i(&resfid) != res_inode->i_ino &&
-		    !coda_fid_is_weird(&resfid))
-			dropme = 1;
 	} else if (error != -ENOENT) {
 	        CDEBUG(D_INODE, "error for %s(%*s)%d\n",
 		       coda_i2s(dir), (int)length, name, error);
@@ -513,179 +508,47 @@
 int coda_readdir(struct file *file, void *dirent,  filldir_t filldir)
 {
         int result = 0;
-        struct file open_file;
-	struct dentry open_dentry;
-	struct inode *inode=file->f_dentry->d_inode, *container;
+	struct dentry *cdentry;
+	struct inode *cinode, *inode = file->f_dentry->d_inode;
+	struct file *cfile, fakefile;
+	struct coda_inode_info *cii = ITOC(inode);
 
         ENTRY;
 	coda_vfs_stat.readdir++;
 
-        if ( inode->i_mapping == &inode->i_data ) {
-                CDEBUG(D_FILE, "no container inode.\n");
-                return -EIO;
-        }
+        cfile = cii->c_container;
+        if (!cfile) BUG();
 
-	container = inode->i_mapping->host;
+	cinode = cii->c_container->f_dentry->d_inode;
+	if ( S_ISREG(cinode->i_mode) ) {
+		/* Venus: we must read Venus dirents from the file */
+		cdentry = cii->c_container->f_dentry;
+		coda_prepare_fakefile(file, cdentry, &fakefile);
 
-	coda_prepare_fakefile(inode, file, container, &open_file, &open_dentry);
+		result = coda_venus_readdir(&fakefile, dirent, filldir);
 
-        if ( S_ISREG(container->i_mode) ) {
-                /* Venus: we must read Venus dirents from the file */
-                result = coda_venus_readdir(&open_file, dirent, filldir);
+		file->f_pos = fakefile.f_pos;
+		file->f_version = fakefile.f_version;
         } else {
 		/* potemkin case: we are handed a directory inode */
-                result = vfs_readdir(&open_file, filldir, dirent);
+		result = vfs_readdir(file, filldir, dirent);
         }
 
-	/* we only have to restore the file position (and f_version?) */
-	file->f_pos = open_file.f_pos;
-	file->f_version = open_file.f_version;
-
         EXIT;
 	return result;
 }
 
-/* grab the ext2 inode of the container file */
-static int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind)
-{
-        struct super_block *sbptr;
-
-        sbptr = get_super(dev);
-
-        if ( !sbptr ) {
-                printk("coda_inode_grab: coda_find_super returns NULL.\n");
-                return -ENXIO;
-        }
-                
-        *ind = NULL;
-        *ind = iget(sbptr, ino);
-
-        if ( *ind == NULL ) {
-		printk("coda_inode_grab: iget(dev: %d, ino: %ld) "
-		       "returns NULL.\n", dev, (long)ino);
-                return -ENOENT;
-        }
-	CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op);
-        return 0;
-}
-
-/* ask venus to cache the file and return the inode of the container file,
-   put this inode pointer in the cnode for future read/writes */
-int coda_open(struct inode *i, struct file *f)
-{
-        ino_t ino;
-	dev_t dev;
-        int error = 0;
-        struct inode *cont_inode = NULL, *old_container;
-        unsigned short flags = f->f_flags & (~O_EXCL);
-	unsigned short coda_flags = coda_flags_to_cflags(flags);
-	struct coda_cred *cred;
-        struct coda_inode_info *cii;
-
-	lock_kernel();
-        ENTRY;
-	coda_vfs_stat.open++;
-
-        CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
-	       f->f_dentry->d_inode->i_ino, atomic_read(&f->f_dentry->d_count), flags);
-
-	error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &ino, &dev); 
-	if (error) {
-	        CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n",
-		       dev, (long)ino, error);
-		unlock_kernel();
-		return error;
-	}
-
-        /* coda_upcall returns ino number of cached object, get inode */
-        CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, (long)ino);
-	error = coda_inode_grab(dev, ino, &cont_inode);
-	
-	if ( error || !cont_inode ){
-		printk("coda_open: coda_inode_grab error %d.", error);
-		if (cont_inode) 
-			iput(cont_inode);
-		unlock_kernel();
-		return error;
-	}
-
-	CODA_ALLOC(cred, struct coda_cred *, sizeof(*cred));
-	coda_load_creds(cred);
-	f->private_data = cred;
-
-	if ( i->i_mapping != &i->i_data ) {
-		old_container = i->i_mapping->host;
-		i->i_mapping = &i->i_data;
-		iput(old_container);
-	}
-	i->i_mapping = cont_inode->i_mapping;
-
-        cii = ITOC(i);
-        cii->c_contcount++;
-
-	CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n", 
-	       error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino);
-	CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", 
-	       cont_inode->i_ino, atomic_read(&cont_inode->i_count),
-               cont_inode->i_op);
-        EXIT;
-	unlock_kernel();
-        return 0;
-}
-
-int coda_release(struct inode *i, struct file *f)
-{
-	struct inode *container = NULL;
-	int error = 0;
-        unsigned short flags = (f->f_flags) & (~O_EXCL);
-	unsigned short cflags = coda_flags_to_cflags(flags);
-	struct coda_cred *cred;
-        struct coda_inode_info *cii;
-
-	lock_kernel();
-        ENTRY;
-	coda_vfs_stat.release++;
-
-	cred = (struct coda_cred *)f->private_data;
-
-	if (i->i_mapping != &i->i_data)
-		container = i->i_mapping->host;
-
-        cii = ITOC(i);
-        CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d, cc %d) cache (ino %ld, ct %d)\n",
-		i->i_ino, atomic_read(&i->i_count), cii->c_contcount,
-                (container ? container->i_ino : 0),
-		(container ? atomic_read(&container->i_count) : -99));
-
-        if (--cii->c_contcount == 0 && container) {
-                i->i_mapping = &i->i_data;
-                iput(container);
-        }
-
-	error = venus_release(i->i_sb, coda_i2f(i), cflags, cred);
-
-	f->private_data = NULL;
-	if (cred)
-		CODA_FREE(cred, sizeof(*cred));
-
-        CDEBUG(D_FILE, "coda_release: result: %d\n", error);
-	unlock_kernel();
-        return error;
-}
-
 /* support routines */
 
-/* instantiate a fake file and dentry to pass to coda_venus_readdir */
-static void coda_prepare_fakefile(struct inode *i, struct file *coda_file, 
-				  struct inode *cont_inode,
-				  struct file *cont_file,
-				  struct dentry *cont_dentry)
-{
-	cont_file->f_dentry = cont_dentry;
-	cont_file->f_dentry->d_inode = cont_inode;
-	cont_file->f_pos = coda_file->f_pos;
-	cont_file->f_version = coda_file->f_version;
-	cont_file->f_op = cont_inode->i_fop;
+/* instantiate a fake file to pass to coda_venus_readdir */
+static void coda_prepare_fakefile(struct file *coda_file, 
+				  struct dentry *cont_dentry,
+				  struct file *fake_file)
+{
+	fake_file->f_dentry = cont_dentry;
+	fake_file->f_pos = coda_file->f_pos;
+	fake_file->f_version = coda_file->f_version;
+	fake_file->f_op = cont_dentry->d_inode->i_fop;
 	return ;
 }
 
@@ -783,13 +646,13 @@
 		}
                 pos += (unsigned int) vdirent->d_reclen;
 		i++;
-        } 
+	} 
 
-       if ( i >= 1024 ) {
-               printk("Repeating too much in readdir %ld\n", 
-                      filp->f_dentry->d_inode->i_ino);
-               result = -EINVAL;
-       }
+	if ( i >= 1024 ) {
+		printk("Repeating too much in readdir %ld\n", 
+		       filp->f_dentry->d_inode->i_ino);
+		result = -EINVAL;
+	}
 
 exit:
         CODA_FREE(buff, DIR_BUFSIZE);
@@ -812,7 +675,7 @@
 		goto bad;
 
 	cii = ITOC(de->d_inode);
-	if (! (cii->c_flags & (C_PURGE | C_FLUSH)) )
+	if (cii->c_flags & (C_PURGE | C_FLUSH))
 		goto out;
 
 	shrink_dcache_parent(de);
@@ -874,7 +737,7 @@
 	int error = 0;
 	int old_mode;
 	ino_t old_ino;
-	struct inode *inode = dentry->d_inode, *container;
+	struct inode *inode = dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 
 	ENTRY;
@@ -883,7 +746,7 @@
 	       dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
 
 	lock_kernel();
-	if ( cii->c_flags == 0 )
+	if ( !cii->c_flags )
 		goto ok;
 
 	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
@@ -921,10 +784,10 @@
 	return 0;
 
 return_bad_inode:
-	if ( inode->i_mapping != &inode->i_data ) {
-		container = inode->i_mapping->host;
-		inode->i_mapping = &inode->i_data;
-		iput(container);
+        inode->i_mapping = &inode->i_data;
+	if (cii->c_container) {
+		fput(cii->c_container);
+		cii->c_container = NULL;
 	}
 	make_bad_inode(inode);
 	unlock_kernel();
diff -u --recursive --new-file v2.4.3/linux/fs/coda/file.c linux/fs/coda/file.c
--- v2.4.3/linux/fs/coda/file.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/coda/file.c	Wed Apr 25 16:18:54 2001
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
@@ -25,54 +26,213 @@
 #include <linux/coda_psdev.h>
 #include <linux/coda_proc.h>
 
+/* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
+ * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
+int use_coda_close;
+
 static ssize_t
 coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct inode *container = inode->i_mapping->host;
+	struct file *cfile;
+	struct inode *cinode, *inode = file->f_dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(inode);
 	ssize_t n;
 
-        down(&container->i_sem);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	if (!cfile->f_op || cfile->f_op->write != generic_file_write)
+		BUG();
+
+	cinode = cfile->f_dentry->d_inode;
+	down(&cinode->i_sem);
 
 	n = generic_file_write(file, buf, count, ppos);
-	inode->i_size = container->i_size;
+	inode->i_size = cinode->i_size;
 
-        up(&container->i_sem);
+	up(&cinode->i_sem);
 
 	return n;
 }
 
-/* exported from this file (used for dirs) */
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
+int coda_open(struct inode *i, struct file *f)
 {
-	struct inode *inode = coda_dentry->d_inode;
-	struct dentry cont_dentry;
-	int result = 0;
+	struct file *fh = NULL;
+	int error = 0;
+	unsigned short flags = f->f_flags & (~O_EXCL);
+	unsigned short coda_flags = coda_flags_to_cflags(flags);
+	struct coda_cred *cred;
+	struct coda_inode_info *cii;
+
+	lock_kernel();
+	ENTRY;
+	coda_vfs_stat.open++;
+
+	CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
+	       f->f_dentry->d_inode->i_ino, atomic_read(&f->f_dentry->d_count), flags);
+
+	error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh); 
+	if (error || !fh) {
+	        CDEBUG(D_FILE, "coda_open: venus_open result %d\n", error);
+		unlock_kernel();
+		return error;
+	}
+
+	/* coda_upcall returns filehandle of container file object */
+	cii = ITOC(i);
+	if (cii->c_container)
+		fput(cii->c_container);
+
+	cii->c_contcount++;
+	cii->c_container = fh;
+	i->i_mapping = &cii->c_container->f_dentry->d_inode->i_data;
+
+	cred = kmalloc(sizeof(struct coda_cred), GFP_KERNEL);
+
+	/* If the allocation failed, we'll just muddle on. This actually works
+	 * fine for normal cases. (i.e. when open credentials are the same as
+	 * close credentials) */
+	if (cred) {
+		coda_load_creds(cred);
+		f->private_data = cred;
+	}
+
+	CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n", 
+	       error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino);
+	CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", 
+	       fh->f_dentry->d_inode->i_ino,
+	       atomic_read(&fh->f_dentry->d_inode->i_count),
+               fh->f_dentry->d_inode->i_op);
+	EXIT;
+	unlock_kernel();
+	return 0;
+}
+
+
+int coda_flush(struct file *file)
+{
+	unsigned short flags = (file->f_flags) & (~O_EXCL);
+	unsigned short cflags;
+	struct coda_inode_info *cii;
+	struct file *cfile;
+	struct inode *cinode, *inode;
+	int err = 0, fcnt;
+
+	ENTRY;
+	coda_vfs_stat.flush++;
+
+	/* No need to make an upcall when we have not made any modifications
+	 * to the file */
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return 0;
+
+	if (use_coda_close)
+		return 0;
+
+	fcnt = file_count(file);
+	if (fcnt > 1) return 0;
+
+	cflags = coda_flags_to_cflags(flags);
+
+	inode = file->f_dentry->d_inode;
+	cii = ITOC(inode);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	cinode = cfile->f_dentry->d_inode;
+
+	CDEBUG(D_FILE, "FLUSH coda (file %p ct %d)\n", file, fcnt);
+
+	err = venus_store(inode->i_sb, coda_i2f(inode), cflags,
+                          (struct coda_cred *)file->private_data);
+	if (err == -EOPNOTSUPP) {
+		use_coda_close = 1;
+		err = 0;
+	}
+
+	CDEBUG(D_FILE, "coda_flush: result: %d\n", err);
+	return err;
+}
+
+int coda_release(struct inode *i, struct file *f)
+{
+	unsigned short flags = (f->f_flags) & (~O_EXCL);
+	unsigned short cflags = coda_flags_to_cflags(flags);
+	struct coda_inode_info *cii;
+	struct file *cfile;
+	int err = 0;
+
+	lock_kernel();
+	ENTRY;
+	coda_vfs_stat.release++;
+ 
+	if (!use_coda_close) {
+		err = venus_release(i->i_sb, coda_i2f(i), cflags);
+		if (err == -EOPNOTSUPP) {
+			use_coda_close = 1;
+			err = 0;
+		}
+	}
+
+	if (use_coda_close)
+		err = venus_close(i->i_sb, coda_i2f(i), cflags,
+                                  (struct coda_cred *)f->private_data);
+
+	cii = ITOC(i);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	if (--cii->c_contcount) {
+		unlock_kernel();
+		return err;
+	}
+
+	i->i_mapping = &i->i_data;
+	fput(cfile);
+	cii->c_container = NULL;
+
+	if (f->private_data) {
+		kfree(f->private_data);
+		f->private_data = NULL;
+	}
+
+	unlock_kernel();
+	return err;
+}
+
+int coda_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct file *cfile;
+	struct dentry *cdentry;
+	struct inode *cinode, *inode = dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(inode);
+	int err = 0;
 	ENTRY;
-	coda_vfs_stat.fsync++;
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	      S_ISLNK(inode->i_mode)))
 		return -EINVAL;
 
-	if ( inode->i_mapping == &inode->i_data ) {
-		printk("coda_fsync: no container inode!\n");
-                return -1; 
-        }
-
-	cont_dentry.d_inode = inode->i_mapping->host;
-  
-	down(&cont_dentry.d_inode->i_sem);
-	result = file_fsync(NULL, &cont_dentry, datasync);
-	up(&cont_dentry.d_inode->i_sem);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	coda_vfs_stat.fsync++;
+
+	if (cfile->f_op && cfile->f_op->fsync) {
+		cdentry = cfile->f_dentry;
+		cinode = cdentry->d_inode;
+		down(&cinode->i_sem);
+		err = cfile->f_op->fsync(cfile, cdentry, datasync);
+		up(&cinode->i_sem);
+	}
 
-	if ( result == 0 && datasync == 0 ) {
+	if ( !err && !datasync ) {
 		lock_kernel();
-		result = venus_fsync(inode->i_sb, coda_i2f(inode));
+		err = venus_fsync(inode->i_sb, coda_i2f(inode));
 		unlock_kernel();
 	}
 
-	return result;
+	return err;
 }
 
 struct file_operations coda_file_operations = {
@@ -80,6 +240,7 @@
 	write:		coda_file_write,
 	mmap:		generic_file_mmap,
 	open:		coda_open,
+	flush:  	coda_flush,
 	release:	coda_release,
 	fsync:		coda_fsync,
 };
diff -u --recursive --new-file v2.4.3/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.4.3/linux/fs/coda/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/coda/inode.c	Wed Apr 25 16:18:54 2001
@@ -141,7 +141,6 @@
         sb->s_magic = CODA_SUPER_MAGIC;
         sb->s_dev = dev;
         sb->s_op = &coda_super_operations;
-	sb->s_maxbytes = MAX_NON_LFS;
 
 	/* get root fid from Venus: this needs the root inode */
 	error = venus_rootfid(sb, &fid);
@@ -172,9 +171,9 @@
 		if(vc)
 			vc->vc_sb = NULL;		
 	}
-        if (root) {
+	if (root)
                 iput(root);
-        }
+
         return NULL;
 }
 
@@ -203,47 +202,51 @@
 
         if (!sbi) BUG();
 
+#if 0
+	/* check if the inode is already initialized */
+	if (inode->u.generic_ip) {
+            printk("coda_read_inode: initialized inode");
+            return;
+        }
+
+	inode->u.generic_ip = cii_alloc();
+	if (!inode->u.generic_ip) {
+		CDEBUG(D_CNODE, "coda_read_inode: failed to allocate inode info\n");
+		make_bad_inode(inode);
+		return;
+	}
+	memset(inode->u.generic_ip, 0, sizeof(struct coda_inode_info));
+#endif
+
 	cii = ITOC(inode);
-        if (cii->c_magic == CODA_CNODE_MAGIC) {
+	if (!coda_isnullfid(&cii->c_fid)) {
             printk("coda_read_inode: initialized inode");
             return;
         }
 
-	memset(cii, 0, sizeof(struct coda_inode_info));
 	list_add(&cii->c_cilist, &sbi->sbi_cihead);
-        cii->c_magic = CODA_CNODE_MAGIC;
 }
 
 static void coda_clear_inode(struct inode *inode)
 {
 	struct coda_inode_info *cii = ITOC(inode);
-        struct inode *open_inode;
 
         ENTRY;
         CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", 
 	       inode->i_ino, atomic_read(&inode->i_count));        
+	CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
 
-	if ( cii->c_magic != CODA_CNODE_MAGIC )
-                return;
-
+	if (cii->c_container) BUG();
+	
         list_del_init(&cii->c_cilist);
+	inode->i_mapping = &inode->i_data;
+	coda_cache_clear_inode(inode);
 
-	if ( inode->i_ino == CTL_INO )
-		goto out;
+#if 0
+	cii_free(inode->u.generic_ip);
+	inode->u.generic_ip = NULL;
+#endif
 
-	if ( inode->i_mapping != &inode->i_data ) {
-		open_inode = inode->i_mapping->host;
-                CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",  
-			open_inode->i_ino,  atomic_read(&open_inode->i_count));
-		inode->i_mapping = &inode->i_data;
-		iput(open_inode);
-        }
-	
-	CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
-	coda_cache_clear_inode(inode);
-out:
-	inode->u.coda_i.c_magic = 0;
-	memset(&inode->u.coda_i.c_fid, 0, sizeof(struct ViceFid));
 	EXIT;
 }
 
diff -u --recursive --new-file v2.4.3/linux/fs/coda/psdev.c linux/fs/coda/psdev.c
--- v2.4.3/linux/fs/coda/psdev.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/coda/psdev.c	Wed Apr 25 16:18:54 2001
@@ -32,6 +32,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -48,6 +49,8 @@
 #include <linux/coda_psdev.h>
 #include <linux/coda_proc.h>
 
+#define upc_free(r) kfree(r)
+
 /* 
  * Coda stuff
  */
@@ -59,6 +62,7 @@
 
 
 struct venus_comm coda_comms[MAX_CODADEVS];
+kmem_cache_t *cii_cache, *cred_cache, *upc_cache;
 
 /*
  * Device operations
@@ -158,29 +162,28 @@
 		}
 		count = nbytes;
 		goto out;
-        }
+	}
         
-        /* Look for the message on the processing queue. */
-        lock_kernel();
-	lh  = &vcp->vc_processing;
-        while ( (lh = lh->next) != &vcp->vc_processing ) {
+	/* Look for the message on the processing queue. */
+	lock_kernel();
+	list_for_each(lh, &vcp->vc_processing) {
 		tmp = list_entry(lh, struct upc_req , uc_chain);
-	        if (tmp->uc_unique == hdr.unique) {
+		if (tmp->uc_unique == hdr.unique) {
 			req = tmp;
 			list_del(&req->uc_chain);
-			CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", 
-			       hdr.unique);
 			break;
 		}
 	}
-        unlock_kernel();
+	unlock_kernel();
 
-        if (!req) {
-	        printk("psdev_write: msg (%ld, %ld) not found\n", 
-		       hdr.opcode, hdr.unique);
+	if (!req) {
+		printk("psdev_write: msg (%ld, %ld) not found\n", 
+			hdr.opcode, hdr.unique);
 		retval = -ESRCH;
 		goto out;
-        }
+	}
+
+	CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", hdr.unique);
 
         /* move data into response buffer. */
 	if (req->uc_outSize < nbytes) {
@@ -195,11 +198,18 @@
 		goto out;
 	}
 
-	/* adjust outsize. is this usefull ?? */
+	/* adjust outsize. is this useful ?? */
         req->uc_outSize = nbytes;	
         req->uc_flags |= REQ_WRITE;
 	count = nbytes;
 
+	/* Convert filedescriptor into a file handle */
+	if (req->uc_opcode == CODA_OPEN_BY_FD) {
+		struct coda_open_by_fd_out *outp =
+			(struct coda_open_by_fd_out *)req->uc_data;
+		outp->fh = fget(outp->fd);
+	}
+
 	CDEBUG(D_PSDEV, 
 	       "Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n", 
 	        (long)count, hdr.opcode, hdr.unique, &req);
@@ -258,13 +268,11 @@
 		count = nbytes;
         }
 
-	if (copy_to_user(buf, req->uc_data, count)) {
+	if (copy_to_user(buf, req->uc_data, count))
 	        retval = -EFAULT;
-		goto free_out;
-	}
         
 	/* If request was not a signal, enqueue and don't free */
-	if (req->uc_opcode != CODA_SIGNAL) {
+	if (!(req->uc_flags & REQ_ASYNC)) {
 		req->uc_flags |= REQ_READ;
 		list_add(&(req->uc_chain), vcp->vc_processing.prev);
 		goto out;
@@ -273,9 +281,8 @@
 	CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n", 
 			req->uc_opcode, req->uc_unique);
 
-free_out:
 	CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
-	CODA_FREE(req, sizeof(struct upc_req));
+	upc_free(req);
 out:
 	unlock_kernel();
 	return (count ? count : retval);
@@ -289,12 +296,16 @@
 
 	lock_kernel();
 	idx = MINOR(inode->i_rdev);
-	if(idx >= MAX_CODADEVS)
+	if(idx >= MAX_CODADEVS) {
+		unlock_kernel();
 		return -ENODEV;
+	}
 
 	vcp = &coda_comms[idx];
-	if(vcp->vc_inuse)
+	if(vcp->vc_inuse) {
+		unlock_kernel();
 		return -EBUSY;
+	}
 	
 	if (!vcp->vc_inuse++) {
 		INIT_LIST_HEAD(&vcp->vc_pending);
@@ -344,7 +355,7 @@
 		/* Async requests need to be freed here */
 		if (req->uc_flags & REQ_ASYNC) {
 			CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
-			CODA_FREE(req, (u_int)sizeof(struct upc_req));
+			upc_free(req);
 			continue;
 		}
 		req->uc_flags |= REQ_ABORT;
@@ -403,9 +414,8 @@
 static int __init init_coda(void)
 {
 	int status;
-	printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.9, coda@cs.cmu.edu\n");
+	printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.14, coda@cs.cmu.edu\n");
 
-	
 	status = init_coda_psdev();
 	if ( status ) {
 		printk("Problem (%d) in init_coda_psdev\n", status);
@@ -414,7 +424,10 @@
 	
 	status = register_filesystem(&coda_fs_type);
 	if (status) {
-		printk("coda: failed in init_coda_fs!\n");
+		printk("coda: failed to register filesystem!\n");
+		devfs_unregister(devfs_handle);
+		devfs_unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
+		coda_sysctl_clean();
 	}
 	return status;
 }
@@ -429,10 +442,11 @@
         if ( err != 0 ) {
                 printk("coda: failed to unregister filesystem\n");
         }
-	devfs_unregister (devfs_handle);
-        devfs_unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
+	devfs_unregister(devfs_handle);
+	devfs_unregister_chrdev(CODA_PSDEV_MAJOR, "coda_psdev");
 	coda_sysctl_clean();
 }
 
 module_init(init_coda);
 module_exit(exit_coda);
+
diff -u --recursive --new-file v2.4.3/linux/fs/coda/symlink.c linux/fs/coda/symlink.c
--- v2.4.3/linux/fs/coda/symlink.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/coda/symlink.c	Wed Apr 25 16:18:54 2001
@@ -26,15 +26,15 @@
 {
 	struct inode *inode = page->mapping->host;
 	int error;
-	struct coda_inode_info *cnp;
+	struct coda_inode_info *cii;
 	unsigned int len = PAGE_SIZE;
 	char *p = kmap(page);
 
 	lock_kernel();
-        cnp = ITOC(inode);
+	cii = ITOC(inode);
 	coda_vfs_stat.follow_link++;
 
-	error = venus_readlink(inode->i_sb, &(cnp->c_fid), p, &len);
+	error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
 	unlock_kernel();
 	if (error)
 		goto fail;
diff -u --recursive --new-file v2.4.3/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c
--- v2.4.3/linux/fs/coda/sysctl.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/coda/sysctl.c	Wed Apr 25 16:18:54 2001
@@ -47,6 +47,7 @@
 #define CODA_UPCALL 	 7       /* upcall statistics */
 #define CODA_PERMISSION	 8       /* permission statistics */
 #define CODA_CACHE_INV 	 9       /* cache invalidation statistics */
+#define CODA_FAKE_STATFS 10	 /* don't query venus for actual cache usage */
 
 static ctl_table coda_table[] = {
 	{CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &proc_dointvec},
@@ -58,6 +59,7 @@
  	{CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
  	{CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
  	{CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
+ 	{CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec},
 	{ 0 }
 };
 
@@ -109,7 +111,9 @@
 	"open_by_path",   /* 31 */
 	"resolve     ",   /* 32 */
 	"reintegrate ",   /* 33 */
-	"statfs      "    /* 34 */
+	"statfs      ",   /* 34 */
+	"store       ",   /* 35 */
+	"release     "    /* 36 */
 };
 
 
@@ -297,7 +301,8 @@
 			"===================\n\n"
 			"File Operations:\n"
 			"\topen\t\t%9d\n"
-			"\trelase\t\t%9d\n"
+			"\tflush\t\t%9d\n"
+			"\trelease\t\t%9d\n"
 			"\tfsync\t\t%9d\n\n"
 			"Dir Operations:\n"
 			"\treaddir\t\t%9d\n\n"
@@ -314,6 +319,7 @@
 
 			/* file operations */
 			ps->open,
+			ps->flush,
 			ps->release,
 			ps->fsync,
 
@@ -485,11 +491,13 @@
 
 #ifdef CONFIG_PROC_FS
 	proc_fs_coda = proc_mkdir("coda", proc_root_fs);
-	proc_fs_coda->owner = THIS_MODULE;
-	coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
-	coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
-	coda_proc_create("permission_stats", coda_permission_stats_get_info);
-	coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
+	if (proc_fs_coda) {
+		proc_fs_coda->owner = THIS_MODULE;
+		coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
+		coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
+		coda_proc_create("permission_stats", coda_permission_stats_get_info);
+		coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
+	}
 #endif
 
 #ifdef CONFIG_SYSCTL
diff -u --recursive --new-file v2.4.3/linux/fs/coda/upcall.c linux/fs/coda/upcall.c
--- v2.4.3/linux/fs/coda/upcall.c	Fri Feb  9 10:18:27 2001
+++ linux/fs/coda/upcall.c	Wed Apr 25 16:18:54 2001
@@ -39,6 +39,8 @@
 #include <linux/coda_cache.h>
 #include <linux/coda_proc.h> 
 
+#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
+#define upc_free(r) kfree(r)
 
 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, 
 		       union inputArgs *buffer);
@@ -127,8 +129,8 @@
         return error;
 }
 
-int  venus_setattr(struct super_block *sb, struct ViceFid *fid, 
-		      struct coda_vattr *vattr)
+int venus_setattr(struct super_block *sb, struct ViceFid *fid, 
+		  struct coda_vattr *vattr)
 {
         union inputArgs *inp;
         union outputArgs *outp;
@@ -176,15 +178,56 @@
 	return error;
 }
 
+int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
+                struct coda_cred *cred)
+{
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+	
+	insize = SIZE(store);
+	UPARG(CODA_STORE);
+	
+	if ( cred ) {
+		memcpy(&(inp->ih.cred), cred, sizeof(*cred));
+	} else 
+		printk("CODA: store without valid file creds.\n");
+	
+        inp->coda_store.VFid = *fid;
+        inp->coda_store.flags = flags;
 
-int venus_release(struct super_block *sb, struct ViceFid *fid, int flags,
-		  struct coda_cred *cred)
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+	CODA_FREE(inp, insize);
+        return error;
+}
+
+int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
 {
         union inputArgs *inp;
         union outputArgs *outp;
         int insize, outsize, error;
 	
-	insize = SIZE(close);
+	insize = SIZE(release);
+	UPARG(CODA_RELEASE);
+	
+	inp->coda_release.VFid = *fid;
+	inp->coda_release.flags = flags;
+
+	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+	CODA_FREE(inp, insize);
+	return error;
+}
+
+int venus_close(struct super_block *sb, struct ViceFid *fid, int flags,
+                struct coda_cred *cred)
+{
+	union inputArgs *inp;
+	union outputArgs *outp;
+	int insize, outsize, error;
+	
+	insize = SIZE(release);
 	UPARG(CODA_CLOSE);
 	
 	if ( cred ) {
@@ -202,22 +245,21 @@
 }
 
 int venus_open(struct super_block *sb, struct ViceFid *fid,
-		  int flags, ino_t *ino, dev_t *dev)
+		  int flags, struct file **fh)
 {
         union inputArgs *inp;
         union outputArgs *outp;
         int insize, outsize, error;
        
-	insize = SIZE(open);
-	UPARG(CODA_OPEN);
+	insize = SIZE(open_by_fd);
+	UPARG(CODA_OPEN_BY_FD);
 
         inp->coda_open.VFid = *fid;
         inp->coda_open.flags = flags;
 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-	*ino = outp->coda_open.inode;
-	*dev = outp->coda_open.dev;
+	*fh = outp->coda_open_by_fd.fh;
 
 	CODA_FREE(inp, insize);
 	return error;
@@ -519,7 +561,7 @@
 
         /* build packet for Venus */
         if (data->vi.in_size > VC_MAXDATASIZE) {
-	        error = -EINVAL;
+		error = -EINVAL;
 		goto exit;
         }
 
@@ -539,7 +581,7 @@
         /* get the data out of user space */
         if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
 			    data->vi.in, data->vi.in_size) ) {
-	        error = -EINVAL;
+		error = -EINVAL;
 	        goto exit;
 	}
 
@@ -557,7 +599,7 @@
                 CDEBUG(D_FILE, "return len %d <= request len %d\n",
                       outp->coda_ioctl.len, 
                       data->vi.out_size);
-                error = -EINVAL;
+		error = -EINVAL;
         } else {
 		error = verify_area(VERIFY_WRITE, data->vi.out, 
                                     data->vi.out_size);
@@ -566,7 +608,7 @@
 		if (copy_to_user(data->vi.out, 
 				 (char *)outp + (long)outp->coda_ioctl.data, 
 				 data->vi.out_size)) {
-		        error = -EINVAL;
+			error = -EINVAL;
 			goto exit;
 		}
         }
@@ -585,7 +627,7 @@
 	insize = max(INSIZE(statfs), OUTSIZE(statfs));
 	UPARG(CODA_STATFS);
 
-        error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 	
         if (!error) {
 		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
@@ -696,7 +738,11 @@
 	}
 
 	/* Format the request message. */
-	CODA_ALLOC(req,struct upc_req *,sizeof(struct upc_req));
+	req = upc_alloc();
+	if (!req) {
+		printk("Failed to allocate upc_req structure\n");
+		return -ENOMEM;
+	}
 	req->uc_data = (void *)buffer;
 	req->uc_flags = 0;
 	req->uc_inSize = inSize;
@@ -768,10 +814,17 @@
 			   req->uc_opcode, req->uc_unique, req->uc_flags);
 		    
 		    list_del(&(req->uc_chain));
-		    error = -EINTR;
-		    CODA_ALLOC(sig_req, struct upc_req *, sizeof (struct upc_req));
+		    error = -ENOMEM;
+		    sig_req = upc_alloc();
+		    if (!sig_req) goto exit;
+
 		    CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
+		    if (!sig_req->uc_data) {
+			upc_free(sig_req);
+			goto exit;
+		    }
 		    
+		    error = -EINTR;
 		    sig_inputArgs = (union inputArgs *)sig_req->uc_data;
 		    sig_inputArgs->ih.opcode = CODA_SIGNAL;
 		    sig_inputArgs->ih.unique = req->uc_unique;
@@ -799,7 +852,7 @@
 	}
 
  exit:
-	CODA_FREE(req, sizeof(struct upc_req));
+	upc_free(req);
 	if (error) 
 	        badclstats();
 	return error;
@@ -913,13 +966,17 @@
 		  clstats(CODA_PURGEFID);
 		  inode = coda_fid_to_inode(fid, sb);
 		  if ( inode ) { 
-			  CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
-				 inode->i_ino);
-			  coda_flag_inode_children(inode, C_PURGE);
-			  coda_purge_dentries(inode);
-			  iput(inode);
+			CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
+			       inode->i_ino);
+			coda_flag_inode_children(inode, C_PURGE);
+
+			/* catch the dentries later if some are still busy */
+			coda_flag_inode(inode, C_PURGE);
+			d_prune_aliases(inode);
+
+			iput(inode);
 		  } else 
-			  CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
+			CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
 		  return 0;
 	  }
 
diff -u --recursive --new-file v2.4.3/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- v2.4.3/linux/fs/cramfs/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/cramfs/inode.c	Tue Apr 17 23:16:38 2001
@@ -195,7 +195,6 @@
 	/* Set it all up.. */
 	sb->s_op	= &cramfs_ops;
 	sb->s_root 	= d_alloc_root(get_cramfs_inode(sb, &super.root));
-	sb->s_maxbytes = MAX_NON_LFS;
 	retval = sb;
 out:
 	return retval;
diff -u --recursive --new-file v2.4.3/linux/fs/dcache.c linux/fs/dcache.c
--- v2.4.3/linux/fs/dcache.c	Wed Mar  7 16:53:48 2001
+++ linux/fs/dcache.c	Thu Apr 12 12:14:45 2001
@@ -340,7 +340,7 @@
 		if (dentry->d_flags & DCACHE_REFERENCED) {
 			dentry->d_flags &= ~DCACHE_REFERENCED;
 			list_add(&dentry->d_lru, &dentry_unused);
-			goto next;
+			continue;
 		}
 		dentry_stat.nr_unused--;
 
@@ -349,7 +349,6 @@
 			BUG();
 
 		prune_one_dentry(dentry);
-	next:
 		if (!--count)
 			break;
 	}
diff -u --recursive --new-file v2.4.3/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.4.3/linux/fs/devfs/base.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/devfs/base.c	Tue Apr 17 15:04:10 2001
@@ -3339,7 +3339,7 @@
 }   /*  End Function devfsd_close  */
 
 
-int __init init_devfs_fs (void)
+static int __init init_devfs_fs (void)
 {
     int err;
 
@@ -3369,3 +3369,5 @@
     if (err == 0) printk ("Mounted devfs on /dev\n");
     else printk ("Warning: unable to mount devfs, err: %d\n", err);
 }   /*  End Function mount_devfs_fs  */
+
+module_init(init_devfs_fs)
diff -u --recursive --new-file v2.4.3/linux/fs/devpts/inode.c linux/fs/devpts/inode.c
--- v2.4.3/linux/fs/devpts/inode.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/devpts/inode.c	Tue Apr 17 15:04:36 2001
@@ -220,7 +220,7 @@
 	}
 }
 
-int __init init_devpts_fs(void)
+static int __init init_devpts_fs(void)
 {
 	int err = register_filesystem(&devpts_fs_type);
 	if (!err) {
@@ -228,28 +228,25 @@
 		err = PTR_ERR(devpts_mnt);
 		if (!IS_ERR(devpts_mnt))
 			err = 0;
-	}
-	return err;
-}
-
 #ifdef MODULE
-
-int init_module(void)
-{
-	int err = init_devpts_fs();
-	if ( !err ) {
-		devpts_upcall_new  = devpts_pty_new;
-		devpts_upcall_kill = devpts_pty_kill;
+		if ( !err ) {
+			devpts_upcall_new  = devpts_pty_new;
+			devpts_upcall_kill = devpts_pty_kill;
+		}
+#endif
 	}
 	return err;
 }
 
-void cleanup_module(void)
+static void __exit exit_devpts_fs(void)
 {
+#ifdef MODULE
 	devpts_upcall_new  = NULL;
 	devpts_upcall_kill = NULL;
+#endif
 	unregister_filesystem(&devpts_fs_type);
 	kern_umount(devpts_mnt);
 }
 
-#endif
+module_init(init_devpts_fs)
+module_exit(exit_devpts_fs)
diff -u --recursive --new-file v2.4.3/linux/fs/efs/super.c linux/fs/efs/super.c
--- v2.4.3/linux/fs/efs/super.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/efs/super.c	Tue Apr 17 23:16:38 2001
@@ -178,7 +178,6 @@
 	s->s_magic		= EFS_SUPER_MAGIC;
 	s->s_blocksize		= EFS_BLOCKSIZE;
 	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
-	s->s_maxbytes		= MAX_NON_LFS;
 
 	if (!(s->s_flags & MS_RDONLY)) {
 #ifdef DEBUG
diff -u --recursive --new-file v2.4.3/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.4.3/linux/fs/ext2/inode.c	Fri Mar 23 12:15:29 2001
+++ linux/fs/ext2/inode.c	Tue Apr 10 12:10:43 2001
@@ -568,7 +568,7 @@
 
 changed:
 	while (partial > chain) {
-		bforget(partial->bh);
+		brelse(partial->bh);
 		partial--;
 	}
 	goto reread;
@@ -799,8 +799,8 @@
 				/* Writer: ->i_blocks */
 				inode->i_blocks -= blocks * count;
 				/* Writer: end */
-				ext2_free_blocks (inode, block_to_free, count);
 				mark_inode_dirty(inode);
+				ext2_free_blocks (inode, block_to_free, count);
 			free_this:
 				block_to_free = nr;
 				count = 1;
@@ -811,8 +811,8 @@
 		/* Writer: ->i_blocks */
 		inode->i_blocks -= blocks * count;
 		/* Writer: end */
-		ext2_free_blocks (inode, block_to_free, count);
 		mark_inode_dirty(inode);
+		ext2_free_blocks (inode, block_to_free, count);
 	}
 }
 
diff -u --recursive --new-file v2.4.3/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.4.3/linux/fs/ext2/super.c	Fri Dec 29 14:36:44 2000
+++ linux/fs/ext2/super.c	Wed Apr 18 11:49:13 2001
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/locks.h>
+#include <linux/blkdev.h>
 #include <asm/uaccess.h>
 
 
@@ -380,6 +381,23 @@
 }
 
 #define log2(n) ffz(~(n))
+ 
+/*
+ * Maximal file size.  There is a direct, and {,double-,triple-}indirect
+ * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
+ * We need to be 1 filesystem block less than the 2^32 sector limit.
+ */
+static loff_t ext2_max_size(int bits)
+{
+	loff_t res = EXT2_NDIR_BLOCKS;
+	res += 1LL << (bits-2);
+	res += 1LL << (2*(bits-2));
+	res += 1LL << (3*(bits-2));
+	res <<= bits;
+	if (res > (512LL << 32) - (1 << bits))
+		res = (512LL << 32) - (1 << bits);
+	return res;
+}
 
 struct super_block * ext2_read_super (struct super_block * sb, void * data,
 				      int silent)
@@ -404,11 +422,9 @@
 	 * This is important for devices that have a hardware
 	 * sectorsize that is larger than the default.
 	 */
-	blocksize = get_hardblocksize(dev);
-	if( blocksize == 0 || blocksize < BLOCK_SIZE )
-	  {
+	blocksize = get_hardsect_size(dev);
+	if(blocksize < BLOCK_SIZE )
 	    blocksize = BLOCK_SIZE;
-	  }
 
 	sb->u.ext2_sb.s_mount_opt = 0;
 	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
@@ -475,6 +491,9 @@
 	sb->s_blocksize_bits =
 		le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10;
 	sb->s_blocksize = 1 << sb->s_blocksize_bits;
+
+	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
+
 	if (sb->s_blocksize != BLOCK_SIZE &&
 	    (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||
 	     sb->s_blocksize == 4096)) {
@@ -482,11 +501,9 @@
 		 * Make sure the blocksize for the filesystem is larger
 		 * than the hardware sectorsize for the machine.
 		 */
-		hblock = get_hardblocksize(dev);
-		if(    (hblock != 0)
-		    && (sb->s_blocksize < hblock) )
-		{
-			printk("EXT2-fs: blocksize too small for device.\n");
+		hblock = get_hardsect_size(dev);
+		if (sb->s_blocksize < hblock) {
+			printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n");
 			goto failed_mount;
 		}
 
diff -u --recursive --new-file v2.4.3/linux/fs/fat/Makefile linux/fs/fat/Makefile
--- v2.4.3/linux/fs/fat/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/fat/Makefile	Wed Apr 18 11:49:12 2001
@@ -11,7 +11,7 @@
 
 export-objs := fatfs_syms.o
 
-obj-y    := buffer.o cache.o dir.o file.o inode.o misc.o tables.o cvf.o fatfs_syms.o
+obj-y    := buffer.o cache.o dir.o file.o inode.o misc.o cvf.o fatfs_syms.o
 obj-m    := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.3/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.4.3/linux/fs/fat/dir.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/fat/dir.c	Wed Apr 18 11:49:12 2001
@@ -65,7 +65,7 @@
 
 	while (*ip) {
 		ec = *ip++;
-		if ( (charlen = nls->uni2char(ec, op, 3)) > 0) {
+		if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
 			op += charlen;
 		} else {
 			if (uni_xlate == 1) {
@@ -114,20 +114,44 @@
 }
 
 static inline int
-fat_short2lower_uni(struct nls_table *t, unsigned char c, wchar_t *uni)
+fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
 {
 	int charlen;
-	unsigned char nc = t->charset2lower[c];
-	
-	if (!nc)
-		nc = c;
 
-	if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) {
+	charlen = t->char2uni(c, clen, uni);
+	if (charlen < 0) {
 		*uni = 0x003f;	/* a question mark */
+		charlen = 1;
 	}
 	return charlen;
 }
 
+static inline int
+fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
+{
+	int charlen;
+	wchar_t wc;
+
+	charlen = t->char2uni(c, clen, &wc);
+	if (charlen < 0) {
+		*uni = 0x003f;	/* a question mark */
+		charlen = 1;
+	} else if (charlen <= 1) {
+		unsigned char nc = t->charset2lower[*c];
+		
+		if (!nc)
+			nc = *c;
+		
+		if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) {
+			*uni = 0x003f;	/* a question mark */
+			charlen = 1;
+		}
+	} else
+		*uni = wc;
+	
+	return charlen;
+}
+
 static int
 fat_strnicmp(struct nls_table *t, const unsigned char *s1,
 					const unsigned char *s2, int len)
@@ -153,10 +177,11 @@
 	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
 	wchar_t bufuname[14];
 	unsigned char xlate_len, long_slots, *unicode = NULL;
-	char c, bufname[260];	/* 256 + 4 */
+	char work[8], bufname[260];	/* 256 + 4 */
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
-	int ino, i, i2, last, res = 0;
+	int nocase = MSDOS_SB(sb)->options.nocase;
+	int ino, chl, i, j, last_u, res = 0;
 	loff_t cpos = 0;
 
 	while(1) {
@@ -237,27 +262,49 @@
 				long_slots = 0;
 		}
 
-		for (i = 0, last = 0; i < 8;) {
-			if (!(c = de->name[i])) break;
-			if (c == 0x05) c = 0xE5;
-			fat_short2lower_uni(nls_disk, c, &bufuname[i++]);
-			if (c != ' ')
-				last = i;
+		for (i = 0; i < 8; i++) {
+			/* see namei.c, msdos_format_name */
+			if (de->name[i] == 0x05)
+				work[i] = 0xE5;
+			else
+				work[i] = de->name[i];
 		}
-		i = last;
-		fat_short2lower_uni(nls_disk, '.', &bufuname[i++]);
-		for (i2 = 0; i2 < 3; i2++) {
-			if (!(c = de->ext[i2])) break;
-			fat_short2lower_uni(nls_disk, c, &bufuname[i++]);
-			if (c != ' ')
-				last = i;
+		for (i = 0, j = 0, last_u = 0; i < 8;) {
+			if (!work[i]) break;
+			if (nocase)
+				chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
+			else
+				chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
+			if (chl <= 1) {
+				if (work[i] != ' ')
+					last_u = j;
+			} else {
+				last_u = j;
+			}
+			i += chl;
 		}
-		if (!last)
+		j = last_u;
+		fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
+		for (i = 0; i < 3;) {
+			if (!de->ext[i]) break;
+			if (nocase)
+				chl = fat_short2uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
+			else
+				chl = fat_short2lower_uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
+			if (chl <= 1) {
+				if (de->ext[i] != ' ')
+					last_u = j;
+			} else {
+				last_u = j;
+			}
+			i += chl;
+		}
+		if (!last_u)
 			continue;
 
-		memset(&bufuname[last], 0, sizeof(wchar_t));
+		bufuname[last_u] = 0x0000;
 		xlate_len = utf8
-			?utf8_wcstombs(bufname, bufuname, 260)
+			?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
 			:uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
 		if (xlate_len == name_len)
 			if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -267,7 +314,7 @@
 
 		if (long_slots) {
 			xlate_len = utf8
-				?utf8_wcstombs(bufname, (wchar_t *) unicode, 260)
+				?utf8_wcstombs(bufname, (wchar_t *) unicode, sizeof(bufname))
 				:uni16_to_x8(bufname, (wchar_t *) unicode, uni_xlate, nls_io);
 			if (xlate_len != name_len)
 				continue;
@@ -298,15 +345,15 @@
 	struct msdos_dir_entry *de;
 	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
 	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
-	wchar_t bufuname[14], *ptuname = &bufuname[0];
+	wchar_t bufuname[14];
 	unsigned char long_slots, *unicode = NULL;
-	char c, bufname[56], *ptname = bufname;
+	char c, work[8], bufname[56], *ptname = bufname;
 	unsigned long lpos, dummy, *furrfu = &lpos;
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int isvfat = MSDOS_SB(sb)->options.isvfat;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
 	int nocase = MSDOS_SB(sb)->options.nocase;
-	int ino,inum,i,i2,last, dotoffset = 0;
+	int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
 	loff_t cpos;
 
 	cpos = filp->f_pos;
@@ -414,33 +461,67 @@
 	}
 
 	if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
-		fat_short2lower_uni(nls_disk, '.', ptuname);
 		*ptname++ = '.';
 		dotoffset = 1;
 	}
-	for (i = 0, last = 0; i < 8;) {
-		if (!(c = de->name[i])) break;
+
+	for (i = 0; i < 8; i++) {
 		/* see namei.c, msdos_format_name */
-		if (c == 0x05) c = 0xE5;
-		fat_short2lower_uni(nls_disk, c, &ptuname[i]);
-		ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
-		if (c != ' ')
-			last = i;
+		if (de->name[i] == 0x05)
+			work[i] = 0xE5;
+		else
+			work[i] = de->name[i];
+	}
+	for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
+		if (!(c = work[i])) break;
+		if (nocase)
+			chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
+		else
+			chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
+		if (chl <= 1) {
+			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
+			if (c != ' ') {
+				last = i;
+				last_u = j;
+			}
+		} else {
+			last_u = j;
+			for (chi = 0; chi < chl && i < 8; chi++) {
+				ptname[i] = work[i];
+				i++; last = i;
+			}
+		}
 	}
 	i = last;
-	fat_short2lower_uni(nls_disk, '.', &ptuname[i]);
+	j = last_u;
+	fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
 	ptname[i++] = '.';
-	for (i2 = 0; i2 < 3; i2++) {
+	for (i2 = 0; i2 < 3;) {
 		if (!(c = de->ext[i2])) break;
-		fat_short2lower_uni(nls_disk, c, &ptuname[i]);
-		ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
-		if (c != ' ')
-			last = i;
+		if (nocase)
+			chl = fat_short2uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
+		else
+			chl = fat_short2lower_uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
+		if (chl <= 1) {
+			i2++;
+			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
+			if (c != ' ') {
+				last = i;
+				last_u = j;
+			}
+		} else {
+			last_u = j;
+			for (chi = 0; chi < chl && i2 < 3; chi++) {
+				ptname[i++] = de->ext[i2++];
+				last = i;
+			}
+		}
 	}
 	if (!last)
 		goto RecEnd;
 
 	i = last + dotoffset;
+	j = last_u;
 
 	lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
 	if (!memcmp(de->name,MSDOS_DOT,11))
@@ -458,8 +539,8 @@
 	}
 
 	if (isvfat) {
-		memset(&bufuname[i], 0, sizeof(wchar_t));
-		i = utf8 ? utf8_wcstombs(bufname, bufuname, 56)
+		bufuname[j] = 0x0000;
+		i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
 			 : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
 	}
 
@@ -471,8 +552,8 @@
 			goto FillFailed;
 	} else {
 		char longname[275];
-		unsigned char long_len = utf8
-			? utf8_wcstombs(longname, (wchar_t *) unicode, 275)
+		int long_len = utf8
+			? utf8_wcstombs(longname, (wchar_t *) unicode, sizeof(longname))
 			: uni16_to_x8(longname, (wchar_t *) unicode, uni_xlate,
 				      nls_io);
 		if (both) {
diff -u --recursive --new-file v2.4.3/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.4.3/linux/fs/fat/fatfs_syms.c	Sat Jul  8 19:38:30 2000
+++ linux/fs/fat/fatfs_syms.c	Wed Apr 18 11:49:12 2001
@@ -14,7 +14,6 @@
 #include <linux/fat_cvf.h>
 
 #include "msbuffer.h"
-#include "tables.h"
 
 EXPORT_SYMBOL(fat_new_dir);
 EXPORT_SYMBOL(fat_get_block);
diff -u --recursive --new-file v2.4.3/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.4.3/linux/fs/fat/inode.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/fat/inode.c	Wed Apr 18 11:49:12 2001
@@ -434,7 +434,7 @@
 	char *p;
 	int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;
 	int debug,error,fat,cp;
-	int blksize = 512;
+	int blksize;
 	int fat32;
 	struct fat_mount_options opts;
 	char buf[50];
@@ -448,14 +448,14 @@
 	sbi->private_data = NULL;
 
 	sbi->dir_ops = fs_dir_inode_ops;
-	sb->s_op = &fat_sops;
-	if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
-		blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)];
-		if (blksize != 512){
-			printk ("MSDOS: Hardware sector size is %d\n",blksize);
-		}
 
-	}
+	sb->s_maxbytes = MAX_NON_LFS;
+	sb->s_op = &fat_sops;
+	blksize = get_hardsect_size(sb->s_dev);
+	if (!blksize)
+		blksize = 512;
+	if (blksize != 512)
+		printk ("MSDOS: Hardware sector size is %d\n",blksize);
 
 	opts.isvfat = sbi->options.isvfat;
 	if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, 
diff -u --recursive --new-file v2.4.3/linux/fs/file_table.c linux/fs/file_table.c
--- v2.4.3/linux/fs/file_table.c	Tue Dec  5 10:27:31 2000
+++ linux/fs/file_table.c	Wed Apr 18 11:49:12 2001
@@ -66,10 +66,10 @@
 			goto new_one;
 		}
 		/* Big problems... */
-		printk("VFS: filp allocation failed\n");
+		printk(KERN_WARNING "VFS: filp allocation failed\n");
 
 	} else if (files_stat.max_files > old_max) {
-		printk("VFS: file-max limit %d reached\n", files_stat.max_files);
+		printk(KERN_INFO "VFS: file-max limit %d reached\n", files_stat.max_files);
 		old_max = files_stat.max_files;
 	}
 	file_list_unlock();
diff -u --recursive --new-file v2.4.3/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.4.3/linux/fs/filesystems.c	Mon Sep 25 17:05:01 2000
+++ linux/fs/filesystems.c	Tue Apr 17 23:23:12 2001
@@ -7,36 +7,11 @@
  */
 
 #include <linux/config.h>
-#include <linux/fs.h>
-
-#include <linux/devfs_fs_kernel.h>
-#include <linux/nfs_fs.h>
-#include <linux/auto_fs.h>
-#include <linux/devpts_fs.h>
-#include <linux/major.h>
-#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/module.h>
 #include <linux/nfsd/interface.h>
-
-#ifdef CONFIG_DEVPTS_FS
-extern int init_devpts_fs(void);
-#endif
-
-void __init filesystem_setup(void)
-{
-	init_devfs_fs();  /*  Header file may make this empty  */
-
-#ifdef CONFIG_NFS_FS
-	init_nfs_fs();
-#endif
-
-#ifdef CONFIG_DEVPTS_FS
-	init_devpts_fs();
-#endif
-}
 
 #if defined(CONFIG_NFSD_MODULE)
 struct nfsd_linkage *nfsd_linkage = NULL;
diff -u --recursive --new-file v2.4.3/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.4.3/linux/fs/hfs/super.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/hfs/super.c	Tue Apr 17 23:16:39 2001
@@ -436,7 +436,6 @@
 		goto bail1;
 	}
 
-	s->s_maxbytes = MAX_NON_LFS;
 	s->s_magic = HFS_SUPER_MAGIC;
 	s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
 	s->s_blocksize = HFS_SECTOR_SIZE;
diff -u --recursive --new-file v2.4.3/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.4.3/linux/fs/hpfs/super.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/hpfs/super.c	Tue Apr 17 23:16:39 2001
@@ -427,7 +427,6 @@
 	s->s_blocksize = 512;
 	s->s_blocksize_bits = 9;
 	s->s_op = &hpfs_sops;
-	s->s_maxbytes = MAX_NON_LFS;
 
 	s->s_hpfs_root = superblock->root;
 	s->s_hpfs_fs_size = superblock->n_sectors;
diff -u --recursive --new-file v2.4.3/linux/fs/inode.c linux/fs/inode.c
--- v2.4.3/linux/fs/inode.c	Thu Mar 22 11:04:13 2001
+++ linux/fs/inode.c	Wed Apr 25 16:24:43 2001
@@ -13,6 +13,8 @@
 #include <linux/quotaops.h>
 #include <linux/slab.h>
 #include <linux/cache.h>
+#include <linux/swap.h>
+#include <linux/swapctl.h>
 
 /*
  * New inode.c implementation.
@@ -179,7 +181,7 @@
 
 static inline void write_inode(struct inode *inode, int sync)
 {
-	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
+	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode && !is_bad_inode(inode))
 		inode->i_sb->s_op->write_inode(inode, sync);
 }
 
@@ -197,6 +199,34 @@
 	inodes_stat.nr_unused--;
 }
 
+static inline void __sync_one(struct inode *inode, int sync)
+{
+	unsigned dirty;
+
+	list_del(&inode->i_list);
+	list_add(&inode->i_list, atomic_read(&inode->i_count)
+						? &inode_in_use
+						: &inode_unused);
+
+	/* Set I_LOCK, reset I_DIRTY */
+	dirty = inode->i_state & I_DIRTY;
+	inode->i_state |= I_LOCK;
+	inode->i_state &= ~I_DIRTY;
+	spin_unlock(&inode_lock);
+
+	filemap_fdatasync(inode->i_mapping);
+
+	/* Don't write the inode if only I_DIRTY_PAGES was set */
+	if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
+		write_inode(inode, sync);
+
+	filemap_fdatawait(inode->i_mapping);
+
+	spin_lock(&inode_lock);
+	inode->i_state &= ~I_LOCK;
+	wake_up(&inode->i_wait);
+}
+
 static inline void sync_one(struct inode *inode, int sync)
 {
 	if (inode->i_state & I_LOCK) {
@@ -206,29 +236,7 @@
 		iput(inode);
 		spin_lock(&inode_lock);
 	} else {
-		unsigned dirty;
-
-		list_del(&inode->i_list);
-		list_add(&inode->i_list, atomic_read(&inode->i_count)
-							? &inode_in_use
-							: &inode_unused);
-		/* Set I_LOCK, reset I_DIRTY */
-		dirty = inode->i_state & I_DIRTY;
-		inode->i_state |= I_LOCK;
-		inode->i_state &= ~I_DIRTY;
-		spin_unlock(&inode_lock);
-
-		filemap_fdatasync(inode->i_mapping);
-
-		/* Don't write the inode if only I_DIRTY_PAGES was set */
-		if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
-			write_inode(inode, sync);
-
-		filemap_fdatawait(inode->i_mapping);
-
-		spin_lock(&inode_lock);
-		inode->i_state &= ~I_LOCK;
-		wake_up(&inode->i_wait);
+		__sync_one(inode, sync);
 	}
 }
 
@@ -236,10 +244,42 @@
 {
 	struct list_head * tmp;
 
-	while ((tmp = head->prev) != head)
+	while ((tmp = head->prev) != head) 
 		sync_one(list_entry(tmp, struct inode, i_list), 0);
 }
 
+static inline int try_to_sync_unused_list(struct list_head *head)
+{
+	struct list_head *tmp = head;
+	struct inode *inode;
+
+	while ((tmp = tmp->prev) != head) {
+		inode = list_entry(tmp, struct inode, i_list);
+
+		if (!(inode->i_state & I_LOCK) 
+				&& !atomic_read(&inode->i_count)) {
+			/* 
+			 * We're under PF_MEMALLOC here, and syncing the 
+			 * inode may have to allocate memory. To avoid
+			 * running into a OOM deadlock, we write one 
+			 * inode synchronously and stop syncing in case 
+			 * we're under freepages.low
+			 */
+
+			int sync = nr_free_pages() < freepages.low;
+			__sync_one(inode, sync);
+			if (sync) 
+				return 0;
+			/* 
+			 * __sync_one moved the inode to another list,
+			 * so we have to start looking from the list head.
+			 */
+			tmp = head;
+		}
+	}
+	return 1;
+}
+
 /**
  *	sync_inodes
  *	@dev: device to sync the inodes from.
@@ -273,13 +313,14 @@
 /*
  * Called with the spinlock already held..
  */
-static void sync_all_inodes(void)
+static void try_to_sync_unused_inodes(void)
 {
 	struct super_block * sb = sb_entry(super_blocks.next);
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
 		if (!sb->s_dev)
 			continue;
-		sync_list(&sb->s_dirty);
+		if (!try_to_sync_unused_list(&sb->s_dirty))
+			break;
 	}
 }
 
@@ -503,13 +544,12 @@
 {
 	LIST_HEAD(list);
 	struct list_head *entry, *freeable = &list;
-	int count = 0;
+	int count = 0, synced = 0;
 	struct inode * inode;
 
 	spin_lock(&inode_lock);
-	/* go simple and safe syncing everything before starting */
-	sync_all_inodes();
 
+free_unused:
 	entry = inode_unused.prev;
 	while (entry != &inode_unused)
 	{
@@ -536,6 +576,20 @@
 	spin_unlock(&inode_lock);
 
 	dispose_list(freeable);
+
+	/* 
+	 * If we freed enough clean inodes, avoid writing 
+	 * dirty ones. Also giveup if we already tried to
+	 * sync dirty inodes.
+	 */
+	if (!goal || synced)
+		return;
+	
+	synced = 1;
+
+	spin_lock(&inode_lock);
+	try_to_sync_unused_inodes();
+	goto free_unused;
 }
 
 void shrink_icache_memory(int priority, int gfp_mask)
diff -u --recursive --new-file v2.4.3/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.4.3/linux/fs/isofs/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/isofs/inode.c	Wed Apr 18 11:49:13 2001
@@ -27,6 +27,7 @@
 #include <linux/nls.h>
 #include <linux/ctype.h>
 #include <linux/smp_lock.h>
+#include <linux/blkdev.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -493,21 +494,21 @@
 	printk("iocharset = %s\n", opt.iocharset);
 #endif
 
- 	/*
- 	 * First of all, get the hardware blocksize for this device.
- 	 * If we don't know what it is, or the hardware blocksize is
- 	 * larger than the blocksize the user specified, then use
- 	 * that value.
- 	 */
- 	blocksize = get_hardblocksize(dev);
- 	if(blocksize > opt.blocksize) {
- 	    /*
- 	     * Force the blocksize we are going to use to be the
- 	     * hardware blocksize.
- 	     */
- 	    opt.blocksize = blocksize;
+	/*
+	 * First of all, get the hardware blocksize for this device.
+	 * If we don't know what it is, or the hardware blocksize is
+	 * larger than the blocksize the user specified, then use
+	 * that value.
+	 */
+	blocksize = get_hardsect_size(dev);
+	if(blocksize > opt.blocksize) {
+	    /*
+	     * Force the blocksize we are going to use to be the
+	     * hardware blocksize.
+	     */
+	    opt.blocksize = blocksize;
 	}
- 
+
 	blocksize_bits = 0;
 	{
 	  int i = opt.blocksize;
@@ -666,8 +667,6 @@
 	/* Set this for reference. Its not currently used except on write
 	   which we don't have .. */
 	   
-	s->s_maxbytes = MAX_NON_LFS;
-
 	/* RDE: data zone now byte offset! */
 
 	first_data_zone = ((isonum_733 (rootp->extent) +
diff -u --recursive --new-file v2.4.3/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.4.3/linux/fs/minix/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/minix/inode.c	Wed Apr 18 11:49:13 2001
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/highuid.h>
+#include <linux/blkdev.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -179,7 +180,7 @@
 	const char * errmsg;
 	struct inode *root_inode;
 	unsigned int hblock;
-	
+
 	/* N.B. These should be compile-time tests.
 	   Unfortunately that is impossible. */
 	if (32 != sizeof (struct minix_inode))
@@ -187,8 +188,8 @@
 	if (64 != sizeof(struct minix2_inode))
 		panic("bad V2 i-node size");
 
-	hblock = get_hardblocksize(dev);
-	if (hblock && hblock > BLOCK_SIZE)
+	hblock = get_hardsect_size(dev);
+	if (hblock > BLOCK_SIZE)
 		goto out_bad_hblock;
 
 	set_blocksize(dev, BLOCK_SIZE);
@@ -259,8 +260,6 @@
 
 	minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
 	minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
-
-	s->s_maxbytes = MAX_NON_LFS;
 
 	/* set up enough so that it can read an inode */
 	s->s_op = &minix_sops;
diff -u --recursive --new-file v2.4.3/linux/fs/minix/itree_common.c linux/fs/minix/itree_common.c
--- v2.4.3/linux/fs/minix/itree_common.c	Wed Sep 27 19:23:40 2000
+++ linux/fs/minix/itree_common.c	Sun Apr  8 12:30:59 2001
@@ -201,7 +201,7 @@
 
 changed:
 	while (partial > chain) {
-		bforget(partial->bh);
+		brelse(partial->bh);
 		partial--;
 	}
 	goto reread;
diff -u --recursive --new-file v2.4.3/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.4.3/linux/fs/msdos/namei.c	Tue Sep  5 14:07:29 2000
+++ linux/fs/msdos/namei.c	Wed Apr 18 11:49:12 2001
@@ -389,7 +389,7 @@
 	return res;
 
 mkdir_error:
-	printk("msdos_mkdir: error=%d, attempting cleanup\n", res);
+	printk(KERN_WARNING "msdos_mkdir: error=%d, attempting cleanup\n", res);
 	inode->i_nlink = 0;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_nlink--;
diff -u --recursive --new-file v2.4.3/linux/fs/namei.c linux/fs/namei.c
--- v2.4.3/linux/fs/namei.c	Thu Mar 22 11:07:58 2001
+++ linux/fs/namei.c	Fri Apr 20 16:04:32 2001
@@ -113,7 +113,7 @@
 	if ((unsigned long) filename >= TASK_SIZE) {
 		if (!segment_eq(get_fs(), KERNEL_DS))
 			return -EFAULT;
-	} else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE)
+	} else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1)
 		len = TASK_SIZE - (unsigned long) filename;
 
 	retval = strncpy_from_user((char *)page, filename, len);
diff -u --recursive --new-file v2.4.3/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.4.3/linux/fs/ncpfs/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/ncpfs/inode.c	Tue Apr 17 23:16:39 2001
@@ -327,7 +327,6 @@
 	else
 		default_bufsize = 1024;
 
-	sb->s_maxbytes = MAX_NON_LFS;
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = NCP_SUPER_MAGIC;
diff -u --recursive --new-file v2.4.3/linux/fs/nfs/flushd.c linux/fs/nfs/flushd.c
--- v2.4.3/linux/fs/nfs/flushd.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfs/flushd.c	Tue Apr  3 13:45:37 2001
@@ -177,14 +177,14 @@
  out:
 }
 
+/* Protect me using the BKL */
 void inode_remove_flushd(struct inode *inode)
 {
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct inode		**q;
 
-	lock_kernel();
 	if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH))
-		goto out;
+		return;
 
 	q = &cache->inodes;
 	while (*q && *q != inode)
@@ -194,8 +194,6 @@
 		NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
 		iput(inode);
 	}
- out:
-	unlock_kernel();
 }
 
 void inode_schedule_scan(struct inode *inode, unsigned long time)
diff -u --recursive --new-file v2.4.3/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.4.3/linux/fs/nfs/inode.c	Fri Mar  2 11:12:11 2001
+++ linux/fs/nfs/inode.c	Wed Apr 25 14:58:17 2001
@@ -15,6 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -434,10 +435,7 @@
         if (server->namelen == 0 || server->namelen > maxlen)
                 server->namelen = maxlen;
 
-	if(version == 2)
-		sb->s_maxbytes = MAX_NON_LFS;
-	else
-		sb->s_maxbytes = ~0ULL;	/* Unlimited on NFSv3 */
+	sb->s_maxbytes = fsinfo.maxfilesize;
 
 	/* Fire up the writeback cache */
 	if (nfs_reqlist_alloc(server) < 0) {
@@ -1060,8 +1058,7 @@
 /*
  * Initialize NFS
  */
-int
-init_nfs_fs(void)
+static int __init init_nfs_fs(void)
 {
 	int err;
 
@@ -1079,23 +1076,7 @@
         return register_filesystem(&nfs_fs_type);
 }
 
-/*
- * Every kernel module contains stuff like this.
- */
-#ifdef MODULE
-
-EXPORT_NO_SYMBOLS;
-/* Not quite true; I just maintain it */
-MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-
-int
-init_module(void)
-{
-	return init_nfs_fs();
-}
-
-void
-cleanup_module(void)
+static void __exit exit_nfs_fs(void)
 {
 	nfs_destroy_readpagecache();
 	nfs_destroy_nfspagecache();
@@ -1104,4 +1085,10 @@
 #endif
 	unregister_filesystem(&nfs_fs_type);
 }
-#endif
+
+EXPORT_NO_SYMBOLS;
+/* Not quite true; I just maintain it */
+MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
+
+module_init(init_nfs_fs)
+module_exit(exit_nfs_fs)
diff -u --recursive --new-file v2.4.3/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.4.3/linux/fs/nfs/read.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfs/read.c	Tue Apr  3 13:45:37 2001
@@ -335,7 +335,9 @@
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
+	lock_kernel();
 	rpc_execute(task);
+	unlock_kernel();
 	rpc_clnt_sigunmask(clnt, &oldset);
 	return 0;
 out_bad:
diff -u --recursive --new-file v2.4.3/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.4.3/linux/fs/nfs/write.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfs/write.c	Tue Apr  3 13:45:37 2001
@@ -183,7 +183,6 @@
 	if (file)
 		cred = nfs_file_cred(file);
 
-	lock_kernel();
 	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%Ld)\n",
 		inode->i_dev, (long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
@@ -228,7 +227,6 @@
 io_error:
 	kunmap(page);
 
-	unlock_kernel();
 	return written? written : result;
 }
 
@@ -282,16 +280,17 @@
 	if (page->index >= end_index+1 || !offset)
 		goto out;
 do_it:
-	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
+	lock_kernel();
+	if (NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
 		err = nfs_writepage_async(NULL, inode, page, 0, offset);
 		if (err >= 0)
-			goto out_ok;
-	}
-	err = nfs_writepage_sync(NULL, inode, page, 0, offset); 
-	if ( err == offset) {
-out_ok:
-		err = 0;
+			err = 0;
+	} else {
+		err = nfs_writepage_sync(NULL, inode, page, 0, offset); 
+		if (err == offset)
+			err = 0;
 	}
+	unlock_kernel();
 out:
 	UnlockPage(page);
 	return err; 
@@ -1172,7 +1171,9 @@
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
+	lock_kernel();
 	rpc_execute(task);
+	unlock_kernel();
 	rpc_clnt_sigunmask(clnt, &oldset);
 	return 0;
  out_bad:
@@ -1394,7 +1395,9 @@
 	dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
+	lock_kernel();
 	rpc_execute(task);
+	unlock_kernel();
 	rpc_clnt_sigunmask(clnt, &oldset);
 	return 0;
  out_bad:
diff -u --recursive --new-file v2.4.3/linux/fs/nfsd/nfs3proc.c linux/fs/nfsd/nfs3proc.c
--- v2.4.3/linux/fs/nfsd/nfs3proc.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfsd/nfs3proc.c	Wed Apr 25 14:58:17 2001
@@ -542,6 +542,7 @@
 		if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) {
 			resp->f_properties = NFS3_FSF_BILLYBOY;
 		}
+		resp->f_maxfilesize = sb->s_maxbytes;
 	}
 
 	fh_put(&argp->fh);
diff -u --recursive --new-file v2.4.3/linux/fs/nls/Config.in linux/fs/nls/Config.in
--- v2.4.3/linux/fs/nls/Config.in	Fri Dec 29 14:35:47 2000
+++ linux/fs/nls/Config.in	Fri Apr  6 10:51:19 2001
@@ -37,23 +37,26 @@
   tristate 'Codepage 865 (Norwegian, Danish)'      CONFIG_NLS_CODEPAGE_865
   tristate 'Codepage 866 (Cyrillic/Russian)'       CONFIG_NLS_CODEPAGE_866
   tristate 'Codepage 869 (Greek)'                  CONFIG_NLS_CODEPAGE_869
-  tristate 'Codepage 874 (Thai)'                   CONFIG_NLS_CODEPAGE_874
-  tristate 'Codepage 932 (Shift-JIS, EUC-JP)'      CONFIG_NLS_CODEPAGE_932
-  tristate 'Codepage 936 (GBK)'                    CONFIG_NLS_CODEPAGE_936
-  tristate 'Codepage 949 (UnifiedHangul)'          CONFIG_NLS_CODEPAGE_949
-  tristate 'Codepage 950 (Big5)'                   CONFIG_NLS_CODEPAGE_950
+  tristate 'Simplified Chinese charset (CP936, GB2312)' CONFIG_NLS_CODEPAGE_936
+  tristate 'Traditional Chinese charset (Big5)'    CONFIG_NLS_CODEPAGE_950
+  tristate 'Japanese charsets (Shift-JIS, EUC-JP)' CONFIG_NLS_CODEPAGE_932
+  tristate 'Korean charset (CP949, EUC-KR)'        CONFIG_NLS_CODEPAGE_949
+  tristate 'Thai charset (CP874, TIS-620)'         CONFIG_NLS_CODEPAGE_874
+  tristate 'Hebrew charsets (ISO-8859-8, CP1255)'  CONFIG_NLS_ISO8859_8
+  tristate 'Windows CP1251 (Bulgarian, Belarussian)' CONFIG_NLS_CODEPAGE_1251
   tristate 'NLS ISO 8859-1  (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
   tristate 'NLS ISO 8859-2  (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2
   tristate 'NLS ISO 8859-3  (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3
-  tristate 'NLS ISO 8859-4  (Latin 4; Estonian, Latvian, Lithuanian)' CONFIG_NLS_ISO8859_4
+  tristate 'NLS ISO 8859-4  (Latin 4; old Baltic charset)' CONFIG_NLS_ISO8859_4
   tristate 'NLS ISO 8859-5  (Cyrillic)'             CONFIG_NLS_ISO8859_5
   tristate 'NLS ISO 8859-6  (Arabic)'               CONFIG_NLS_ISO8859_6
   tristate 'NLS ISO 8859-7  (Modern Greek)'         CONFIG_NLS_ISO8859_7
-  tristate 'NLS ISO 8859-8  (Hebrew)'               CONFIG_NLS_ISO8859_8
   tristate 'NLS ISO 8859-9  (Latin 5; Turkish)'     CONFIG_NLS_ISO8859_9
+  tristate 'NLS ISO 8859-13 (Latin 7; Baltic)'      CONFIG_NLS_ISO8859_13
   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-U (Ukrainian)'                 CONFIG_NLS_KOI8_U
   tristate 'NLS UTF8'                               CONFIG_NLS_UTF8
   endmenu
 fi
diff -u --recursive --new-file v2.4.3/linux/fs/nls/Makefile linux/fs/nls/Makefile
--- v2.4.3/linux/fs/nls/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/nls/Makefile	Fri Apr  6 10:51:19 2001
@@ -22,7 +22,7 @@
 obj-$(CONFIG_NLS_CODEPAGE_865)	+= nls_cp865.o
 obj-$(CONFIG_NLS_CODEPAGE_866)	+= nls_cp866.o
 obj-$(CONFIG_NLS_CODEPAGE_869)	+= nls_cp869.o
-obj-$(CONFIG_NLS_CODEPAGE_874)	+= nls_cp874.o
+obj-$(CONFIG_NLS_CODEPAGE_874)	+= nls_cp874.o nls_tis-620.o
 obj-$(CONFIG_NLS_CODEPAGE_932)	+= nls_cp932.o nls_sjis.o nls_euc-jp.o
 obj-$(CONFIG_NLS_CODEPAGE_936)	+= nls_cp936.o nls_gb2312.o
 obj-$(CONFIG_NLS_CODEPAGE_949)	+= nls_cp949.o nls_euc-kr.o
@@ -32,7 +32,6 @@
 obj-$(CONFIG_NLS_CODEPAGE_1252)	+= nls_cp1252.o
 obj-$(CONFIG_NLS_CODEPAGE_1253)	+= nls_cp1253.o
 obj-$(CONFIG_NLS_CODEPAGE_1254)	+= nls_cp1254.o
-obj-$(CONFIG_NLS_CODEPAGE_1255)	+= nls_cp1255.o
 obj-$(CONFIG_NLS_CODEPAGE_1256)	+= nls_cp1256.o
 obj-$(CONFIG_NLS_CODEPAGE_1257)	+= nls_cp1257.o
 obj-$(CONFIG_NLS_CODEPAGE_1258)	+= nls_cp1258.o
@@ -43,12 +42,14 @@
 obj-$(CONFIG_NLS_ISO8859_5)	+= nls_iso8859-5.o
 obj-$(CONFIG_NLS_ISO8859_6)	+= nls_iso8859-6.o
 obj-$(CONFIG_NLS_ISO8859_7)	+= nls_iso8859-7.o
-obj-$(CONFIG_NLS_ISO8859_8)	+= nls_iso8859-8.o
+obj-$(CONFIG_NLS_ISO8859_8)	+= nls_cp1255.o nls_iso8859-8.o
 obj-$(CONFIG_NLS_ISO8859_9)	+= nls_iso8859-9.o
 obj-$(CONFIG_NLS_ISO8859_10)	+= nls_iso8859-10.o
+obj-$(CONFIG_NLS_ISO8859_13)	+= nls_iso8859-13.o
 obj-$(CONFIG_NLS_ISO8859_14)	+= nls_iso8859-14.o
 obj-$(CONFIG_NLS_ISO8859_15)	+= nls_iso8859-15.o
 obj-$(CONFIG_NLS_KOI8_R)	+= nls_koi8-r.o
+obj-$(CONFIG_NLS_KOI8_U)	+= nls_koi8-u.o
 obj-$(CONFIG_NLS_ABC)		+= nls_abc.o
 obj-$(CONFIG_NLS_UTF8)		+= nls_utf8.o
 
diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_cp1251.c linux/fs/nls/nls_cp1251.c
--- v2.4.3/linux/fs/nls/nls_cp1251.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/nls_cp1251.c	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,317 @@
+/*
+ * linux/fs/nls_cp1251.c
+ *
+ * Charset cp1251 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/errno.h>
+
+static wchar_t charset2uni[256] = {
+	/* 0x00*/
+	0x0000, 0x0001, 0x0002, 0x0003, 
+	0x0004, 0x0005, 0x0006, 0x0007, 
+	0x0008, 0x0009, 0x000a, 0x000b, 
+	0x000c, 0x000d, 0x000e, 0x000f, 
+	/* 0x10*/
+	0x0010, 0x0011, 0x0012, 0x0013, 
+	0x0014, 0x0015, 0x0016, 0x0017, 
+	0x0018, 0x0019, 0x001a, 0x001b, 
+	0x001c, 0x001d, 0x001e, 0x001f, 
+	/* 0x20*/
+	0x0020, 0x0021, 0x0022, 0x0023, 
+	0x0024, 0x0025, 0x0026, 0x0027, 
+	0x0028, 0x0029, 0x002a, 0x002b, 
+	0x002c, 0x002d, 0x002e, 0x002f, 
+	/* 0x30*/
+	0x0030, 0x0031, 0x0032, 0x0033, 
+	0x0034, 0x0035, 0x0036, 0x0037, 
+	0x0038, 0x0039, 0x003a, 0x003b, 
+	0x003c, 0x003d, 0x003e, 0x003f, 
+	/* 0x40*/
+	0x0040, 0x0041, 0x0042, 0x0043, 
+	0x0044, 0x0045, 0x0046, 0x0047, 
+	0x0048, 0x0049, 0x004a, 0x004b, 
+	0x004c, 0x004d, 0x004e, 0x004f, 
+	/* 0x50*/
+	0x0050, 0x0051, 0x0052, 0x0053, 
+	0x0054, 0x0055, 0x0056, 0x0057, 
+	0x0058, 0x0059, 0x005a, 0x005b, 
+	0x005c, 0x005d, 0x005e, 0x005f, 
+	/* 0x60*/
+	0x0060, 0x0061, 0x0062, 0x0063, 
+	0x0064, 0x0065, 0x0066, 0x0067, 
+	0x0068, 0x0069, 0x006a, 0x006b, 
+	0x006c, 0x006d, 0x006e, 0x006f, 
+	/* 0x70*/
+	0x0070, 0x0071, 0x0072, 0x0073, 
+	0x0074, 0x0075, 0x0076, 0x0077, 
+	0x0078, 0x0079, 0x007a, 0x007b, 
+	0x007c, 0x007d, 0x007e, 0x007f, 
+	/* 0x80*/
+	0x0402, 0x0403, 0x201a, 0x0453, 
+	0x201e, 0x2026, 0x2020, 0x2021, 
+	0x20ac, 0x2030, 0x0409, 0x2039, 
+	0x040a, 0x040c, 0x040b, 0x040f, 
+	/* 0x90*/
+	0x0452, 0x2018, 0x2019, 0x201c, 
+	0x201d, 0x2022, 0x2013, 0x2014, 
+	0x0000, 0x2122, 0x0459, 0x203a, 
+	0x045a, 0x045c, 0x045b, 0x045f, 
+	/* 0xa0*/
+	0x00a0, 0x040e, 0x045e, 0x0408, 
+	0x00a4, 0x0490, 0x00a6, 0x00a7, 
+	0x0401, 0x00a9, 0x0404, 0x00ab, 
+	0x00ac, 0x00ad, 0x00ae, 0x0407, 
+	/* 0xb0*/
+	0x00b0, 0x00b1, 0x0406, 0x0456, 
+	0x0491, 0x00b5, 0x00b6, 0x00b7, 
+	0x0451, 0x2116, 0x0454, 0x00bb, 
+	0x0458, 0x0405, 0x0455, 0x0457, 
+	/* 0xc0*/
+	0x0410, 0x0411, 0x0412, 0x0413, 
+	0x0414, 0x0415, 0x0416, 0x0417, 
+	0x0418, 0x0419, 0x041a, 0x041b, 
+	0x041c, 0x041d, 0x041e, 0x041f, 
+	/* 0xd0*/
+	0x0420, 0x0421, 0x0422, 0x0423, 
+	0x0424, 0x0425, 0x0426, 0x0427, 
+	0x0428, 0x0429, 0x042a, 0x042b, 
+	0x042c, 0x042d, 0x042e, 0x042f, 
+	/* 0xe0*/
+	0x0430, 0x0431, 0x0432, 0x0433, 
+	0x0434, 0x0435, 0x0436, 0x0437, 
+	0x0438, 0x0439, 0x043a, 0x043b, 
+	0x043c, 0x043d, 0x043e, 0x043f, 
+	/* 0xf0*/
+	0x0440, 0x0441, 0x0442, 0x0443, 
+	0x0444, 0x0445, 0x0446, 0x0447, 
+	0x0448, 0x0449, 0x044a, 0x044b, 
+	0x044c, 0x044d, 0x044e, 0x044f, 
+};
+
+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 */
+	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0x00, 0x00, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0xa8, 0x80, 0x81, 0xaa, 0xbd, 0xb2, 0xaf, /* 0x00-0x07 */
+	0xa3, 0x8a, 0x8c, 0x8e, 0x8d, 0x00, 0xa1, 0x8f, /* 0x08-0x0f */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x10-0x17 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x18-0x1f */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x20-0x27 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x28-0x2f */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x30-0x37 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x38-0x3f */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x40-0x47 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0x48-0x4f */
+	0x00, 0xb8, 0x90, 0x83, 0xba, 0xbe, 0xb3, 0xbf, /* 0x50-0x57 */
+	0xbc, 0x9a, 0x9c, 0x9e, 0x9d, 0x00, 0xa2, 0x9f, /* 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, 0xa5, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */
+	0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+};
+
+static unsigned char page21[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, 0xb9, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+};
+
+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,   
+	page20, page21, NULL,	NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2lower[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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x90, 0x83, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa2, 0xa2, 0xbc, 0xa4, 0xb4, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xb8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 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 */
+};
+
+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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x81, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x80, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb2, 0xa5, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xa8, 0xb9, 0xaa, 0xbb, 0xa3, 0xbd, 0xbd, 0xaf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */
+};
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+	unsigned char *uni2charset;
+	unsigned char cl = uni & 0x00ff;
+	unsigned char ch = (uni & 0xff00) >> 8;
+
+	if (boundlen <= 0)
+		return -ENAMETOOLONG;
+
+	uni2charset = page_uni2charset[ch];
+	if (uni2charset && uni2charset[cl])
+		out[0] = uni2charset[cl];
+	else
+		return -EINVAL;
+	return 1;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+	*uni = charset2uni[*rawstring];
+	if (*uni == 0x0000)
+		return -EINVAL;
+	return 1;
+}
+
+static struct nls_table table = {
+	"cp1251",
+	uni2char,
+	char2uni,
+	charset2lower,
+	charset2upper,
+	THIS_MODULE,
+};
+
+static int __init init_nls_cp1251(void)
+{
+	return register_nls(&table);
+}
+
+static void __exit exit_nls_cp1251(void)
+{
+	unregister_nls(&table);
+}
+
+module_init(init_nls_cp1251)
+module_exit(exit_nls_cp1251)
+
+/*
+ * 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 --recursive --new-file v2.4.3/linux/fs/nls/nls_cp1255.c linux/fs/nls/nls_cp1255.c
--- v2.4.3/linux/fs/nls/nls_cp1255.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/nls_cp1255.c	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,398 @@
+/*
+ * linux/fs/nls_cp1255.c
+ *
+ * Charset cp1255 translation tables.
+ * 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/errno.h>
+
+static wchar_t charset2uni[256] = {
+	/* 0x00*/
+	0x0000, 0x0001, 0x0002, 0x0003,
+	0x0004, 0x0005, 0x0006, 0x0007,
+	0x0008, 0x0009, 0x000a, 0x000b,
+	0x000c, 0x000d, 0x000e, 0x000f,
+	/* 0x10*/
+	0x0010, 0x0011, 0x0012, 0x0013,
+	0x0014, 0x0015, 0x0016, 0x0017,
+	0x0018, 0x0019, 0x001a, 0x001b,
+	0x001c, 0x001d, 0x001e, 0x001f,
+	/* 0x20*/
+	0x0020, 0x0021, 0x0022, 0x0023,
+	0x0024, 0x0025, 0x0026, 0x0027,
+	0x0028, 0x0029, 0x002a, 0x002b,
+	0x002c, 0x002d, 0x002e, 0x002f,
+	/* 0x30*/
+	0x0030, 0x0031, 0x0032, 0x0033,
+	0x0034, 0x0035, 0x0036, 0x0037,
+	0x0038, 0x0039, 0x003a, 0x003b,
+	0x003c, 0x003d, 0x003e, 0x003f,
+	/* 0x40*/
+	0x0040, 0x0041, 0x0042, 0x0043,
+	0x0044, 0x0045, 0x0046, 0x0047,
+	0x0048, 0x0049, 0x004a, 0x004b,
+	0x004c, 0x004d, 0x004e, 0x004f,
+	/* 0x50*/
+	0x0050, 0x0051, 0x0052, 0x0053,
+	0x0054, 0x0055, 0x0056, 0x0057,
+	0x0058, 0x0059, 0x005a, 0x005b,
+	0x005c, 0x005d, 0x005e, 0x005f,
+	/* 0x60*/
+	0x0060, 0x0061, 0x0062, 0x0063,
+	0x0064, 0x0065, 0x0066, 0x0067,
+	0x0068, 0x0069, 0x006a, 0x006b,
+	0x006c, 0x006d, 0x006e, 0x006f,
+	/* 0x70*/
+	0x0070, 0x0071, 0x0072, 0x0073,
+	0x0074, 0x0075, 0x0076, 0x0077,
+	0x0078, 0x0079, 0x007a, 0x007b,
+	0x007c, 0x007d, 0x007e, 0x007f,
+	/* 0x80*/
+	0x20ac, 0x0000, 0x201a, 0x0192,
+	0x201e, 0x2026, 0x2020, 0x2021,
+	0x02c6, 0x2030, 0x0000, 0x2039,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	/* 0x90*/
+	0x0000, 0x2018, 0x2019, 0x201c,
+	0x201d, 0x2022, 0x2013, 0x2014,
+	0x02dc, 0x2122, 0x0000, 0x203a,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	/* 0xa0*/
+	0x00a0, 0x00a1, 0x00a2, 0x00a3,
+	0x20aa, 0x00a5, 0x00a6, 0x00a7,
+	0x00a8, 0x00a9, 0x00d7, 0x00ab,
+	0x00ac, 0x00ad, 0x00ae, 0x203e,
+	/* 0xb0*/
+	0x00b0, 0x00b1, 0x00b2, 0x00b3,
+	0x00b4, 0x00b5, 0x00b6, 0x00b7,
+	0x00b8, 0x00b9, 0x00f7, 0x00bb,
+	0x00bc, 0x00bd, 0x00be, 0x00bf,
+	/* 0xc0*/
+	0x05b0, 0x05b1, 0x05b2, 0x05b3,
+	0x05b4, 0x05b5, 0x05b6, 0x05b7,
+	0x05b8, 0x05b9, 0x0000, 0x05bb,
+	0x05bc, 0x05bd, 0x05be, 0x05bf,
+	/* 0xd0*/
+	0x05c0, 0x05c1, 0x05c2, 0x05c3,
+	0x05f0, 0x05f1, 0x05f2, 0x05f3,
+	0x05f4, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x2017,
+	/* 0xe0*/
+	0x05d0, 0x05d1, 0x05d2, 0x05d3,
+	0x05d4, 0x05d5, 0x05d6, 0x05d7,
+	0x05d8, 0x05d9, 0x05da, 0x05db,
+	0x05dc, 0x05dd, 0x05de, 0x05df,
+	/* 0xf0*/
+	0x05e0, 0x05e1, 0x05e2, 0x05e3,
+	0x05e4, 0x05e5, 0x05e6, 0x05e7,
+	0x05e8, 0x05e9, 0x05ea, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+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 */
+	0xa0, 0x00, 0xa2, 0xa3, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 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, 0xaa, /* 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, 0xba, /* 0xf0-0xf7 */
+};
+
+static unsigned char page01[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 */
+	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 */
+	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, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+
+static unsigned char page02[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 */
+	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 */
+	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, 0x88, 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, 0x98, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+};
+
+static unsigned char page05[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 */
+	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 */
+	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 */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xb0-0xb7 */
+	0xc8, 0xc9, 0x00, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xb8-0xbf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */
+	0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfe, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */
+	0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x8b, 0x9b, 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, 0xa4, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+};
+
+static unsigned char page21[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, 0xb9, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   NULL,   page05, 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,   
+	page20, page21, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2lower[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, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */
+	0x78, 0x79, 0x7a, 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 */
+	0xa0, 0x00, 0xa2, 0xa3, 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, 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, 0xdf, /* 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, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+	0x58, 0x59, 0x5a, 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 */
+	0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 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, 0xdf, /* 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, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+	unsigned char *uni2charset;
+	unsigned char cl = uni & 0x00ff;
+	unsigned char ch = (uni & 0xff00) >> 8;
+
+	if (boundlen <= 0)
+		return -ENAMETOOLONG;
+
+	uni2charset = page_uni2charset[ch];
+	if (uni2charset && uni2charset[cl])
+		out[0] = uni2charset[cl];
+	else
+		return -EINVAL;
+	return 1;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+	*uni = charset2uni[*rawstring];
+	if (*uni == 0x0000)
+		return -EINVAL;
+	return 1;
+}
+
+static struct nls_table table = {
+	"cp1255",
+	uni2char,
+	char2uni,
+	charset2lower,
+	charset2upper,
+	THIS_MODULE,
+};
+
+static int __init init_nls_cp1255(void)
+{
+	return register_nls(&table);
+}
+
+static void __exit exit_nls_cp1255(void)
+{
+	unregister_nls(&table);
+}
+
+module_init(init_nls_cp1255)
+module_exit(exit_nls_cp1255)
+
+/*
+ * 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 --recursive --new-file v2.4.3/linux/fs/nls/nls_cp932.c linux/fs/nls/nls_cp932.c
--- v2.4.3/linux/fs/nls/nls_cp932.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_cp932.c	Fri Apr  6 10:51:19 2001
@@ -7819,73 +7819,68 @@
 };
 
 static int uni2char(const wchar_t uni,
-			unsigned char *out, int boundlen)
+		    unsigned char *out, int boundlen)
 {
 	unsigned char *uni2charset;
 	unsigned char cl = uni&0xFF;
 	unsigned char ch = (uni>>8)&0xFF;
-	int n;
 
 	if (boundlen <= 0)
 		return -ENAMETOOLONG;
 
 	if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F) {
 		out[0] = cl + 0x40;
-		n = 1;
-		return n;
+		return 1;
 	}
 	uni2charset = page_uni2charset[ch];
 	if (uni2charset) {
-		if (boundlen <= 1)
+		if (boundlen < 2)
 			return -ENAMETOOLONG;
+
 		out[0] = uni2charset[cl*2];
 		out[1] = uni2charset[cl*2+1];
 		if (out[0] == 0x00 && out[1] == 0x00)
 			return -EINVAL;
-		n = 2;
-	} else if (ch==0 && cl) {
+		return 2;
+	} else if ((ch == 0) && (cl <= 0x7F)) {
 		out[0] = cl;
-		n = 1;
+		return 1;
 	}
 	else
 		return -EINVAL;
-
-	return n;
 }
 
 static int char2uni(const unsigned char *rawstring, int boundlen,
-			wchar_t *uni)
+		    wchar_t *uni)
 {
 	unsigned char ch, cl;
 	wchar_t *charset2uni;
-	int n;
 
 	if (boundlen <= 0)
 		return -ENAMETOOLONG;
 
-	if (boundlen == 1) {
+	if (rawstring[0] <= 0x7F) {
 		*uni = rawstring[0];
 		return 1;
 	}
+	if (0xA1 <= rawstring[0] && rawstring[0] <= 0xDF) {
+		*uni = 0xFF00 | (rawstring[0] - 0x40);
+		return 1;
+	}
 
+	if (boundlen < 2)
+		return -ENAMETOOLONG;
 	ch = rawstring[0];
 	cl = rawstring[1];
-	if (0xA1 <= ch && ch <= 0xDF) {
-		*uni = 0xFF00 | (ch - 0x40);
-		n = 1;
-		return n;
-	}
 	charset2uni = page_charset2uni[ch];
 	if (charset2uni && cl) {
 		*uni = charset2uni[cl];
 		if (*uni == 0x0000)
 			return -EINVAL;
-		n = 2;
-	} else{
-		*uni = ch;
-		n = 1;
+		return 2;
 	}
-	return n;
+	else
+		return -EINVAL;
 }
 
 static struct nls_table table = {
diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_euc-jp.c linux/fs/nls/nls_euc-jp.c
--- v2.4.3/linux/fs/nls/nls_euc-jp.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/nls/nls_euc-jp.c	Fri Apr  6 10:51:19 2001
@@ -1,5 +1,9 @@
 /*
  * linux/fs/nls_euc-jp.c
+ *
+ * Added `OSF/JVC Recommended Code Set Conversion Specification
+ * between Japanese EUC and Shift-JIS' support: <hirofumi@mail.parknet.co.jp>
+ * (http://www.opengroup.or.jp/jvc/cde/sjis-euc-e.html)
  */
 
 #include <linux/module.h>
@@ -10,49 +14,463 @@
 
 static struct nls_table *p_nls;
 
+#define IS_SJIS_LOW_BYTE(l)	((0x40 <= (l)) && ((l) <= 0xFC) && ((l) != 0x7F))
+/* JIS X 0208 (include NEC spesial characters) */
+#define IS_SJIS_JISX0208(h, l)	((((0x81 <= (h)) && ((h) <= 0x9F))	\
+				 || ((0xE0 <= (h)) && ((h) <= 0xEA)))	\
+				 && IS_SJIS_LOW_BYTE(l))
+#define IS_SJIS_JISX0201KANA(c)	((0xA1 <= (c)) && ((c) <= 0xDF))
+#define IS_SJIS_UDC_LOW(h, l)	(((0xF0 <= (h)) && ((h) <= 0xF4))	\
+				 && IS_SJIS_LOW_BYTE(l))
+#define IS_SJIS_UDC_HI(h, l)	(((0xF5 <= (h)) && ((h) <= 0xF9))	\
+				 && IS_SJIS_LOW_BYTE(l))
+#define IS_SJIS_IBM(h, l)	(((0xFA <= (h)) && ((h) <= 0xFC))	\
+				 && IS_SJIS_LOW_BYTE(l))
+#define IS_SJIS_NECIBM(h, l)	(((0xED <= (h)) && ((h) <= 0xEE))	\
+				 && IS_SJIS_LOW_BYTE(l))
+#define MAP_SJIS2EUC(sjis_hi, sjis_lo, sjis_p, euc_hi, euc_lo, euc_p) {		\
+	if ((sjis_lo) >= 0x9F) {						\
+		(euc_hi) = (sjis_hi) * 2 - (((sjis_p) * 2 - (euc_p)) - 1);	\
+		(euc_lo) = (sjis_lo) + 2;					\
+	} else {								\
+		(euc_hi) = (sjis_hi) * 2 - ((sjis_p) * 2 - (euc_p));		\
+		(euc_lo) = (sjis_lo) + ((sjis_lo) >= 0x7F ? 0x60 : 0x61);	\
+	}									\
+} while(0)
 
 #define SS2		(0x8E)		/* Single Shift 2 */
 #define SS3		(0x8F)		/* Single Shift 3 */
+#define IS_EUC_BYTE(c)		((0xA1 <= (c)) && ((c) <= 0xFE))
+#define IS_EUC_JISX0208(h, l)	(IS_EUC_BYTE(h) && IS_EUC_BYTE(l))
+#define IS_EUC_JISX0201KANA(h, l)	(((h) == SS2) && (0xA1 <= (l) && (l) <= 0xDF))
+#define IS_EUC_UDC_LOW(h, l)	(((0xF5 <= (h)) && ((h) <= 0xFE))	\
+				 && IS_EUC_BYTE(l))
+#define IS_EUC_UDC_HI(h, l)	IS_EUC_UDC_LOW(h, l) /* G3 block */
+#define MAP_EUC2SJIS(euc_hi, euc_lo, euc_p, sjis_hi, sjis_lo, sjis_p) {		\
+	if ((euc_hi) & 1) {							\
+		(sjis_hi) = (euc_hi) / 2 + ((sjis_p) - (euc_p) / 2);		\
+		(sjis_lo) = (euc_lo) - ((euc_lo) >= 0xE0 ? 0x60 : 0x61);	\
+	} else {								\
+		(sjis_hi) = (euc_hi) / 2 + (((sjis_p) - (euc_p) / 2) - 1);	\
+		(sjis_lo) = (euc_lo) - 2;					\
+	}									\
+} while(0)
+
+/* SJIS IBM extended characters to EUC map */
+static unsigned char sjisibm2euc_map[][2] = {
+	{0xF3, 0xF3}, {0xF3, 0xF4}, {0xF3, 0xF5}, {0xF3, 0xF6}, {0xF3, 0xF7},
+	{0xF3, 0xF8}, {0xF3, 0xF9}, {0xF3, 0xFA}, {0xF3, 0xFB}, {0xF3, 0xFC},
+	{0xF3, 0xFD}, {0xF3, 0xFE}, {0xF4, 0xA1}, {0xF4, 0xA2}, {0xF4, 0xA3},
+	{0xF4, 0xA4}, {0xF4, 0xA5}, {0xF4, 0xA6}, {0xF4, 0xA7}, {0xF4, 0xA8},
+	{0xA2, 0xCC}, {0xA2, 0xC3}, {0xF4, 0xA9}, {0xF4, 0xAA}, {0xF4, 0xAB},
+	{0xF4, 0xAC}, {0xF4, 0xAD}, {0xA2, 0xE8}, {0xD4, 0xE3}, {0xDC, 0xDF},
+	{0xE4, 0xE9}, {0xE3, 0xF8}, {0xD9, 0xA1}, {0xB1, 0xBB}, {0xF4, 0xAE},
+	{0xC2, 0xAD}, {0xC3, 0xFC}, {0xE4, 0xD0}, {0xC2, 0xBF}, {0xBC, 0xF4},
+	{0xB0, 0xA9}, {0xB0, 0xC8}, {0xF4, 0xAF}, {0xB0, 0xD2}, {0xB0, 0xD4},
+	{0xB0, 0xE3}, {0xB0, 0xEE}, {0xB1, 0xA7}, {0xB1, 0xA3}, {0xB1, 0xAC},
+	{0xB1, 0xA9}, {0xB1, 0xBE}, {0xB1, 0xDF}, {0xB1, 0xD8}, {0xB1, 0xC8},
+	{0xB1, 0xD7}, {0xB1, 0xE3}, {0xB1, 0xF4}, {0xB1, 0xE1}, {0xB2, 0xA3},
+	{0xF4, 0xB0}, {0xB2, 0xBB}, {0xB2, 0xE6}, {0x00, 0x00}, {0xB2, 0xED},
+	{0xB2, 0xF5}, {0xB2, 0xFC}, {0xF4, 0xB1}, {0xB3, 0xB5}, {0xB3, 0xD8},
+	{0xB3, 0xDB}, {0xB3, 0xE5}, {0xB3, 0xEE}, {0xB3, 0xFB}, {0xF4, 0xB2},
+	{0xF4, 0xB3}, {0xB4, 0xC0}, {0xB4, 0xC7}, {0xB4, 0xD0}, {0xB4, 0xDE},
+	{0xF4, 0xB4}, {0xB5, 0xAA}, {0xF4, 0xB5}, {0xB5, 0xAF}, {0xB5, 0xC4},
+	{0xB5, 0xE8}, {0xF4, 0xB6}, {0xB7, 0xC2}, {0xB7, 0xE4}, {0xB7, 0xE8},
+	{0xB7, 0xE7}, {0xF4, 0xB7}, {0xF4, 0xB8}, {0xF4, 0xB9}, {0xB8, 0xCE},
+	{0xB8, 0xE1}, {0xB8, 0xF5}, {0xB8, 0xF7}, {0xB8, 0xF8}, {0xB8, 0xFC},
+	{0xB9, 0xAF}, {0xB9, 0xB7}, {0xBA, 0xBE}, {0xBA, 0xDB}, {0xCD, 0xAA},
+	{0xBA, 0xE1}, {0xF4, 0xBA}, {0xBA, 0xEB}, {0xBB, 0xB3}, {0xBB, 0xB8},
+	{0xF4, 0xBB}, {0xBB, 0xCA}, {0xF4, 0xBC}, {0xF4, 0xBD}, {0xBB, 0xD0},
+	{0xBB, 0xDE}, {0xBB, 0xF4}, {0xBB, 0xF5}, {0xBB, 0xF9}, {0xBC, 0xE4},
+	{0xBC, 0xED}, {0xBC, 0xFE}, {0xF4, 0xBE}, {0xBD, 0xC2}, {0xBD, 0xE7},
+	{0xF4, 0xBF}, {0xBD, 0xF0}, {0xBE, 0xB0}, {0xBE, 0xAC}, {0xF4, 0xC0},
+	{0xBE, 0xB3}, {0xBE, 0xBD}, {0xBE, 0xCD}, {0xBE, 0xC9}, {0xBE, 0xE4},
+	{0xBF, 0xA8}, {0xBF, 0xC9}, {0xC0, 0xC4}, {0xC0, 0xE4}, {0xC0, 0xF4},
+	{0xC1, 0xA6}, {0xF4, 0xC1}, {0xC1, 0xF5}, {0xC1, 0xFC}, {0xF4, 0xC2},
+	{0xC1, 0xF8}, {0xC2, 0xAB}, {0xC2, 0xA1}, {0xC2, 0xA5}, {0xF4, 0xC3},
+	{0xC2, 0xB8}, {0xC2, 0xBA}, {0xF4, 0xC4}, {0xC2, 0xC4}, {0xC2, 0xD2},
+	{0xC2, 0xD7}, {0xC2, 0xDB}, {0xC2, 0xDE}, {0xC2, 0xED}, {0xC2, 0xF0},
+	{0xF4, 0xC5}, {0xC3, 0xA1}, {0xC3, 0xB5}, {0xC3, 0xC9}, {0xC3, 0xB9},
+	{0xF4, 0xC6}, {0xC3, 0xD8}, {0xC3, 0xFE}, {0xF4, 0xC7}, {0xC4, 0xCC},
+	{0xF4, 0xC8}, {0xC4, 0xD9}, {0xC4, 0xEA}, {0xC4, 0xFD}, {0xF4, 0xC9},
+	{0xC5, 0xA7}, {0xC5, 0xB5}, {0xC5, 0xB6}, {0xF4, 0xCA}, {0xC5, 0xD5},
+	{0xC6, 0xB8}, {0xC6, 0xD7}, {0xC6, 0xE0}, {0xC6, 0xEA}, {0xC6, 0xE3},
+	{0xC7, 0xA1}, {0xC7, 0xAB}, {0xC7, 0xC7}, {0xC7, 0xC3}, {0xC7, 0xCB},
+	{0xC7, 0xCF}, {0xC7, 0xD9}, {0xF4, 0xCB}, {0xF4, 0xCC}, {0xC7, 0xE6},
+	{0xC7, 0xEE}, {0xC7, 0xFC}, {0xC7, 0xEB}, {0xC7, 0xF0}, {0xC8, 0xB1},
+	{0xC8, 0xE5}, {0xC8, 0xF8}, {0xC9, 0xA6}, {0xC9, 0xAB}, {0xC9, 0xAD},
+	{0xF4, 0xCD}, {0xC9, 0xCA}, {0xC9, 0xD3}, {0xC9, 0xE9}, {0xC9, 0xE3},
+	{0xC9, 0xFC}, {0xC9, 0xF4}, {0xC9, 0xF5}, {0xF4, 0xCE}, {0xCA, 0xB3},
+	{0xCA, 0xBD}, {0xCA, 0xEF}, {0xCA, 0xF1}, {0xCB, 0xAE}, {0xF4, 0xCF},
+	{0xCB, 0xCA}, {0xCB, 0xE6}, {0xCB, 0xEA}, {0xCB, 0xF0}, {0xCB, 0xF4},
+	{0xCB, 0xEE}, {0xCC, 0xA5}, {0xCB, 0xF9}, {0xCC, 0xAB}, {0xCC, 0xAE},
+	{0xCC, 0xAD}, {0xCC, 0xB2}, {0xCC, 0xC2}, {0xCC, 0xD0}, {0xCC, 0xD9},
+	{0xF4, 0xD0}, {0xCD, 0xBB}, {0xF4, 0xD1}, {0xCE, 0xBB}, {0xF4, 0xD2},
+	{0xCE, 0xBA}, {0xCE, 0xC3}, {0xF4, 0xD3}, {0xCE, 0xF2}, {0xB3, 0xDD},
+	{0xCF, 0xD5}, {0xCF, 0xE2}, {0xCF, 0xE9}, {0xCF, 0xED}, {0xF4, 0xD4},
+	{0xF4, 0xD5}, {0xF4, 0xD6}, {0x00, 0x00}, {0xF4, 0xD7}, {0xD0, 0xE5},
+	{0xF4, 0xD8}, {0xD0, 0xE9}, {0xD1, 0xE8}, {0xF4, 0xD9}, {0xF4, 0xDA},
+	{0xD1, 0xEC}, {0xD2, 0xBB}, {0xF4, 0xDB}, {0xD3, 0xE1}, {0xD3, 0xE8},
+	{0xD4, 0xA7}, {0xF4, 0xDC}, {0xF4, 0xDD}, {0xD4, 0xD4}, {0xD4, 0xF2},
+	{0xD5, 0xAE}, {0xF4, 0xDE}, {0xD7, 0xDE}, {0xF4, 0xDF}, {0xD8, 0xA2},
+	{0xD8, 0xB7}, {0xD8, 0xC1}, {0xD8, 0xD1}, {0xD8, 0xF4}, {0xD9, 0xC6},
+	{0xD9, 0xC8}, {0xD9, 0xD1}, {0xF4, 0xE0}, {0xF4, 0xE1}, {0xF4, 0xE2},
+	{0xF4, 0xE3}, {0xF4, 0xE4}, {0xDC, 0xD3}, {0xDD, 0xC8}, {0xDD, 0xD4},
+	{0xDD, 0xEA}, {0xDD, 0xFA}, {0xDE, 0xA4}, {0xDE, 0xB0}, {0xF4, 0xE5},
+	{0xDE, 0xB5}, {0xDE, 0xCB}, {0xF4, 0xE6}, {0xDF, 0xB9}, {0xF4, 0xE7},
+	{0xDF, 0xC3}, {0xF4, 0xE8}, {0xF4, 0xE9}, {0xE0, 0xD9}, {0xF4, 0xEA},
+	{0xF4, 0xEB}, {0xE1, 0xE2}, {0xF4, 0xEC}, {0xF4, 0xED}, {0xF4, 0xEE},
+	{0xE2, 0xC7}, {0xE3, 0xA8}, {0xE3, 0xA6}, {0xE3, 0xA9}, {0xE3, 0xAF},
+	{0xE3, 0xB0}, {0xE3, 0xAA}, {0xE3, 0xAB}, {0xE3, 0xBC}, {0xE3, 0xC1},
+	{0xE3, 0xBF}, {0xE3, 0xD5}, {0xE3, 0xD8}, {0xE3, 0xD6}, {0xE3, 0xDF},
+	{0xE3, 0xE3}, {0xE3, 0xE1}, {0xE3, 0xD4}, {0xE3, 0xE9}, {0xE4, 0xA6},
+	{0xE3, 0xF1}, {0xE3, 0xF2}, {0xE4, 0xCB}, {0xE4, 0xC1}, {0xE4, 0xC3},
+	{0xE4, 0xBE}, {0xF4, 0xEF}, {0xE4, 0xC0}, {0xE4, 0xC7}, {0xE4, 0xBF},
+	{0xE4, 0xE0}, {0xE4, 0xDE}, {0xE4, 0xD1}, {0xF4, 0xF0}, {0xE4, 0xDC},
+	{0xE4, 0xD2}, {0xE4, 0xDB}, {0xE4, 0xD4}, {0xE4, 0xFA}, {0xE4, 0xEF},
+	{0xE5, 0xB3}, {0xE5, 0xBF}, {0xE5, 0xC9}, {0xE5, 0xD0}, {0xE5, 0xE2},
+	{0xE5, 0xEA}, {0xE5, 0xEB}, {0xF4, 0xF1}, {0xF4, 0xF2}, {0xF4, 0xF3},
+	{0xE6, 0xE8}, {0xE6, 0xEF}, {0xE7, 0xAC}, {0xF4, 0xF4}, {0xE7, 0xAE},
+	{0xF4, 0xF5}, {0xE7, 0xB1}, {0xF4, 0xF6}, {0xE7, 0xB2}, {0xE8, 0xB1},
+	{0xE8, 0xB6}, {0xF4, 0xF7}, {0xF4, 0xF8}, {0xE8, 0xDD}, {0xF4, 0xF9},
+	{0xF4, 0xFA}, {0xE9, 0xD1}, {0xF4, 0xFB}, {0xE9, 0xED}, {0xEA, 0xCD},
+	{0xF4, 0xFC}, {0xEA, 0xDB}, {0xEA, 0xE6}, {0xEA, 0xEA}, {0xEB, 0xA5},
+	{0xEB, 0xFB}, {0xEB, 0xFA}, {0xF4, 0xFD}, {0xEC, 0xD6}, {0xF4, 0xFE},
+};
+
+#define IS_EUC_IBM2JISX0208(h, l) \
+		(((h) == 0xA2 && (l) == 0xCC) || ((h) == 0xA2 && (l) == 0xE8))
+
+/* EUC to SJIS IBM extended characters map (G3 JIS X 0212 block) */
+static struct {
+	unsigned short euc;
+	unsigned char sjis[2];
+} euc2sjisibm_jisx0212_map[] = {
+	{0xA2C3, {0xFA, 0x55}}, {0xB0A9, {0xFA, 0x68}}, {0xB0C8, {0xFA, 0x69}},
+	{0xB0D2, {0xFA, 0x6B}}, {0xB0D4, {0xFA, 0x6C}}, {0xB0E3, {0xFA, 0x6D}},
+	{0xB0EE, {0xFA, 0x6E}}, {0xB1A3, {0xFA, 0x70}}, {0xB1A7, {0xFA, 0x6F}},
+	{0xB1A9, {0xFA, 0x72}}, {0xB1AC, {0xFA, 0x71}}, {0xB1BB, {0xFA, 0x61}},
+	{0xB1BE, {0xFA, 0x73}}, {0xB1C8, {0xFA, 0x76}}, {0xB1D7, {0xFA, 0x77}},
+	{0xB1D8, {0xFA, 0x75}}, {0xB1DF, {0xFA, 0x74}}, {0xB1E1, {0xFA, 0x7A}},
+	{0xB1E3, {0xFA, 0x78}}, {0xB1F4, {0xFA, 0x79}}, {0xB2A3, {0xFA, 0x7B}},
+	{0xB2BB, {0xFA, 0x7D}}, {0xB2E6, {0xFA, 0x7E}}, {0xB2ED, {0xFA, 0x80}},
+	{0xB2F5, {0xFA, 0x81}}, {0xB2FC, {0xFA, 0x82}}, {0xB3B5, {0xFA, 0x84}},
+	{0xB3D8, {0xFA, 0x85}}, {0xB3DB, {0xFA, 0x86}}, {0xB3DD, {0xFB, 0x77}},
+	{0xB3E5, {0xFA, 0x87}}, {0xB3EE, {0xFA, 0x88}}, {0xB3FB, {0xFA, 0x89}},
+	{0xB4C0, {0xFA, 0x8C}}, {0xB4C7, {0xFA, 0x8D}}, {0xB4D0, {0xFA, 0x8E}},
+	{0xB4DE, {0xFA, 0x8F}}, {0xB5AA, {0xFA, 0x91}}, {0xB5AF, {0xFA, 0x93}},
+	{0xB5C4, {0xFA, 0x94}}, {0xB5E8, {0xFA, 0x95}}, {0xB7C2, {0xFA, 0x97}},
+	{0xB7E4, {0xFA, 0x98}}, {0xB7E7, {0xFA, 0x9A}}, {0xB7E8, {0xFA, 0x99}},
+	{0xB8CE, {0xFA, 0x9E}}, {0xB8E1, {0xFA, 0x9F}}, {0xB8F5, {0xFA, 0xA0}},
+	{0xB8F7, {0xFA, 0xA1}}, {0xB8F8, {0xFA, 0xA2}}, {0xB8FC, {0xFA, 0xA3}},
+	{0xB9AF, {0xFA, 0xA4}}, {0xB9B7, {0xFA, 0xA5}}, {0xBABE, {0xFA, 0xA6}},
+	{0xBADB, {0xFA, 0xA7}}, {0xBAE1, {0xFA, 0xA9}}, {0xBAEB, {0xFA, 0xAB}},
+	{0xBBB3, {0xFA, 0xAC}}, {0xBBB8, {0xFA, 0xAD}}, {0xBBCA, {0xFA, 0xAF}},
+	{0xBBD0, {0xFA, 0xB2}}, {0xBBDE, {0xFA, 0xB3}}, {0xBBF4, {0xFA, 0xB4}},
+	{0xBBF5, {0xFA, 0xB5}}, {0xBBF9, {0xFA, 0xB6}}, {0xBCE4, {0xFA, 0xB7}},
+	{0xBCED, {0xFA, 0xB8}}, {0xBCF4, {0xFA, 0x67}}, {0xBCFE, {0xFA, 0xB9}},
+	{0xBDC2, {0xFA, 0xBB}}, {0xBDE7, {0xFA, 0xBC}}, {0xBDF0, {0xFA, 0xBE}},
+	{0xBEAC, {0xFA, 0xC0}}, {0xBEB0, {0xFA, 0xBF}}, {0xBEB3, {0xFA, 0xC2}},
+	{0xBEBD, {0xFA, 0xC3}}, {0xBEC9, {0xFA, 0xC5}}, {0xBECD, {0xFA, 0xC4}},
+	{0xBEE4, {0xFA, 0xC6}}, {0xBFA8, {0xFA, 0xC7}}, {0xBFC9, {0xFA, 0xC8}},
+	{0xC0C4, {0xFA, 0xC9}}, {0xC0E4, {0xFA, 0xCA}}, {0xC0F4, {0xFA, 0xCB}},
+	{0xC1A6, {0xFA, 0xCC}}, {0xC1F5, {0xFA, 0xCE}}, {0xC1F8, {0xFA, 0xD1}},
+	{0xC1FC, {0xFA, 0xCF}}, {0xC2A1, {0xFA, 0xD3}}, {0xC2A5, {0xFA, 0xD4}},
+	{0xC2AB, {0xFA, 0xD2}}, {0xC2AD, {0xFA, 0x63}}, {0xC2B8, {0xFA, 0xD6}},
+	{0xC2BA, {0xFA, 0xD7}}, {0xC2BF, {0xFA, 0x66}}, {0xC2C4, {0xFA, 0xD9}},
+	{0xC2D2, {0xFA, 0xDA}}, {0xC2D7, {0xFA, 0xDB}}, {0xC2DB, {0xFA, 0xDC}},
+	{0xC2DE, {0xFA, 0xDD}}, {0xC2ED, {0xFA, 0xDE}}, {0xC2F0, {0xFA, 0xDF}},
+	{0xC3A1, {0xFA, 0xE1}}, {0xC3B5, {0xFA, 0xE2}}, {0xC3B9, {0xFA, 0xE4}},
+	{0xC3C9, {0xFA, 0xE3}}, {0xC3D8, {0xFA, 0xE6}}, {0xC3FC, {0xFA, 0x64}},
+	{0xC3FE, {0xFA, 0xE7}}, {0xC4CC, {0xFA, 0xE9}}, {0xC4D9, {0xFA, 0xEB}},
+	{0xC4EA, {0xFA, 0xEC}}, {0xC4FD, {0xFA, 0xED}}, {0xC5A7, {0xFA, 0xEF}},
+	{0xC5B5, {0xFA, 0xF0}}, {0xC5B6, {0xFA, 0xF1}}, {0xC5D5, {0xFA, 0xF3}},
+	{0xC6B8, {0xFA, 0xF4}}, {0xC6D7, {0xFA, 0xF5}}, {0xC6E0, {0xFA, 0xF6}},
+	{0xC6E3, {0xFA, 0xF8}}, {0xC6EA, {0xFA, 0xF7}}, {0xC7A1, {0xFA, 0xF9}},
+	{0xC7AB, {0xFA, 0xFA}}, {0xC7C3, {0xFA, 0xFC}}, {0xC7C7, {0xFA, 0xFB}},
+	{0xC7CB, {0xFB, 0x40}}, {0xC7CF, {0xFB, 0x41}}, {0xC7D9, {0xFB, 0x42}},
+	{0xC7E6, {0xFB, 0x45}}, {0xC7EB, {0xFB, 0x48}}, {0xC7EE, {0xFB, 0x46}},
+	{0xC7F0, {0xFB, 0x49}}, {0xC7FC, {0xFB, 0x47}}, {0xC8B1, {0xFB, 0x4A}},
+	{0xC8E5, {0xFB, 0x4B}}, {0xC8F8, {0xFB, 0x4C}}, {0xC9A6, {0xFB, 0x4D}},
+	{0xC9AB, {0xFB, 0x4E}}, {0xC9AD, {0xFB, 0x4F}}, {0xC9CA, {0xFB, 0x51}},
+	{0xC9D3, {0xFB, 0x52}}, {0xC9E3, {0xFB, 0x54}}, {0xC9E9, {0xFB, 0x53}},
+	{0xC9F4, {0xFB, 0x56}}, {0xC9F5, {0xFB, 0x57}}, {0xC9FC, {0xFB, 0x55}},
+	{0xCAB3, {0xFB, 0x59}}, {0xCABD, {0xFB, 0x5A}}, {0xCAEF, {0xFB, 0x5B}},
+	{0xCAF1, {0xFB, 0x5C}}, {0xCBAE, {0xFB, 0x5D}}, {0xCBCA, {0xFB, 0x5F}},
+	{0xCBE6, {0xFB, 0x60}}, {0xCBEA, {0xFB, 0x61}}, {0xCBEE, {0xFB, 0x64}},
+	{0xCBF0, {0xFB, 0x62}}, {0xCBF4, {0xFB, 0x63}}, {0xCBF9, {0xFB, 0x66}},
+	{0xCCA5, {0xFB, 0x65}}, {0xCCAB, {0xFB, 0x67}}, {0xCCAD, {0xFB, 0x69}},
+	{0xCCAE, {0xFB, 0x68}}, {0xCCB2, {0xFB, 0x6A}}, {0xCCC2, {0xFB, 0x6B}},
+	{0xCCD0, {0xFB, 0x6C}}, {0xCCD9, {0xFB, 0x6D}}, {0xCDAA, {0xFA, 0xA8}},
+	{0xCDBB, {0xFB, 0x6F}}, {0xCEBA, {0xFB, 0x73}}, {0xCEBB, {0xFB, 0x71}},
+	{0xCEC3, {0xFB, 0x74}}, {0xCEF2, {0xFB, 0x76}}, {0xCFD5, {0xFB, 0x78}},
+	{0xCFE2, {0xFB, 0x79}}, {0xCFE9, {0xFB, 0x7A}}, {0xCFED, {0xFB, 0x7B}},
+	{0xD0E5, {0xFB, 0x81}}, {0xD0E9, {0xFB, 0x83}}, {0xD1E8, {0xFB, 0x84}},
+	{0xD1EC, {0xFB, 0x87}}, {0xD2BB, {0xFB, 0x88}}, {0xD3E1, {0xFB, 0x8A}},
+	{0xD3E8, {0xFB, 0x8B}}, {0xD4A7, {0xFB, 0x8C}}, {0xD4D4, {0xFB, 0x8F}},
+	{0xD4E3, {0xFA, 0x5C}}, {0xD4F2, {0xFB, 0x90}}, {0xD5AE, {0xFB, 0x91}},
+	{0xD7DE, {0xFB, 0x93}}, {0xD8A2, {0xFB, 0x95}}, {0xD8B7, {0xFB, 0x96}},
+	{0xD8C1, {0xFB, 0x97}}, {0xD8D1, {0xFB, 0x98}}, {0xD8F4, {0xFB, 0x99}},
+	{0xD9A1, {0xFA, 0x60}}, {0xD9C6, {0xFB, 0x9A}}, {0xD9C8, {0xFB, 0x9B}},
+	{0xD9D1, {0xFB, 0x9C}}, {0xDCD3, {0xFB, 0xA2}}, {0xDCDF, {0xFA, 0x5D}},
+	{0xDDC8, {0xFB, 0xA3}}, {0xDDD4, {0xFB, 0xA4}}, {0xDDEA, {0xFB, 0xA5}},
+	{0xDDFA, {0xFB, 0xA6}}, {0xDEA4, {0xFB, 0xA7}}, {0xDEB0, {0xFB, 0xA8}},
+	{0xDEB5, {0xFB, 0xAA}}, {0xDECB, {0xFB, 0xAB}}, {0xDFB9, {0xFB, 0xAD}},
+	{0xDFC3, {0xFB, 0xAF}}, {0xE0D9, {0xFB, 0xB2}}, {0xE1E2, {0xFB, 0xB5}},
+	{0xE2C7, {0xFB, 0xB9}}, {0xE3A6, {0xFB, 0xBB}}, {0xE3A8, {0xFB, 0xBA}},
+	{0xE3A9, {0xFB, 0xBC}}, {0xE3AA, {0xFB, 0xBF}}, {0xE3AB, {0xFB, 0xC0}},
+	{0xE3AF, {0xFB, 0xBD}}, {0xE3B0, {0xFB, 0xBE}}, {0xE3BC, {0xFB, 0xC1}},
+	{0xE3BF, {0xFB, 0xC3}}, {0xE3C1, {0xFB, 0xC2}}, {0xE3D4, {0xFB, 0xCA}},
+	{0xE3D5, {0xFB, 0xC4}}, {0xE3D6, {0xFB, 0xC6}}, {0xE3D8, {0xFB, 0xC5}},
+	{0xE3DF, {0xFB, 0xC7}}, {0xE3E1, {0xFB, 0xC9}}, {0xE3E3, {0xFB, 0xC8}},
+	{0xE3E9, {0xFB, 0xCB}}, {0xE3F1, {0xFB, 0xCD}}, {0xE3F2, {0xFB, 0xCE}},
+	{0xE3F8, {0xFA, 0x5F}}, {0xE4A6, {0xFB, 0xCC}}, {0xE4BE, {0xFB, 0xD2}},
+	{0xE4BF, {0xFB, 0xD6}}, {0xE4C0, {0xFB, 0xD4}}, {0xE4C1, {0xFB, 0xD0}},
+	{0xE4C3, {0xFB, 0xD1}}, {0xE4C7, {0xFB, 0xD5}}, {0xE4CB, {0xFB, 0xCF}},
+	{0xE4D0, {0xFA, 0x65}}, {0xE4D1, {0xFB, 0xD9}}, {0xE4D2, {0xFB, 0xDC}},
+	{0xE4D4, {0xFB, 0xDE}}, {0xE4DB, {0xFB, 0xDD}}, {0xE4DC, {0xFB, 0xDB}},
+	{0xE4DE, {0xFB, 0xD8}}, {0xE4E0, {0xFB, 0xD7}}, {0xE4E9, {0xFA, 0x5E}},
+	{0xE4EF, {0xFB, 0xE0}}, {0xE4FA, {0xFB, 0xDF}}, {0xE5B3, {0xFB, 0xE1}},
+	{0xE5BF, {0xFB, 0xE2}}, {0xE5C9, {0xFB, 0xE3}}, {0xE5D0, {0xFB, 0xE4}},
+	{0xE5E2, {0xFB, 0xE5}}, {0xE5EA, {0xFB, 0xE6}}, {0xE5EB, {0xFB, 0xE7}},
+	{0xE6E8, {0xFB, 0xEB}}, {0xE6EF, {0xFB, 0xEC}}, {0xE7AC, {0xFB, 0xED}},
+	{0xE7AE, {0xFB, 0xEF}}, {0xE7B1, {0xFB, 0xF1}}, {0xE7B2, {0xFB, 0xF3}},
+	{0xE8B1, {0xFB, 0xF4}}, {0xE8B6, {0xFB, 0xF5}}, {0xE8DD, {0xFB, 0xF8}},
+	{0xE9D1, {0xFB, 0xFB}}, {0xE9ED, {0xFC, 0x40}}, {0xEACD, {0xFC, 0x41}},
+	{0xEADB, {0xFC, 0x43}}, {0xEAE6, {0xFC, 0x44}}, {0xEAEA, {0xFC, 0x45}},
+	{0xEBA5, {0xFC, 0x46}}, {0xEBFA, {0xFC, 0x48}}, {0xEBFB, {0xFC, 0x47}},
+	{0xECD6, {0xFC, 0x4A}},
+};
+
+/* EUC to SJIS IBM extended characters map (G3 Upper block) */
+static unsigned char euc2sjisibm_g3upper_map[][2] = {
+	{0xFA, 0x40}, {0xFA, 0x41}, {0xFA, 0x42}, {0xFA, 0x43}, {0xFA, 0x44},
+	{0xFA, 0x45}, {0xFA, 0x46}, {0xFA, 0x47}, {0xFA, 0x48}, {0xFA, 0x49},
+	{0xFA, 0x4A}, {0xFA, 0x4B}, {0xFA, 0x4C}, {0xFA, 0x4D}, {0xFA, 0x4E},
+	{0xFA, 0x4F}, {0xFA, 0x50}, {0xFA, 0x51}, {0xFA, 0x52}, {0xFA, 0x53},
+	{0xFA, 0x56}, {0xFA, 0x57}, {0xFA, 0x58}, {0xFA, 0x59}, {0xFA, 0x5A},
+	{0xFA, 0x62}, {0xFA, 0x6A}, {0xFA, 0x7C}, {0xFA, 0x83}, {0xFA, 0x8A},
+	{0xFA, 0x8B}, {0xFA, 0x90}, {0xFA, 0x92}, {0xFA, 0x96}, {0xFA, 0x9B},
+	{0xFA, 0x9C}, {0xFA, 0x9D}, {0xFA, 0xAA}, {0xFA, 0xAE}, {0xFA, 0xB0},
+	{0xFA, 0xB1}, {0xFA, 0xBA}, {0xFA, 0xBD}, {0xFA, 0xC1}, {0xFA, 0xCD},
+	{0xFA, 0xD0}, {0xFA, 0xD5}, {0xFA, 0xD8}, {0xFA, 0xE0}, {0xFA, 0xE5},
+	{0xFA, 0xE8}, {0xFA, 0xEA}, {0xFA, 0xEE}, {0xFA, 0xF2}, {0xFB, 0x43},
+	{0xFB, 0x44}, {0xFB, 0x50}, {0xFB, 0x58}, {0xFB, 0x5E}, {0xFB, 0x6E},
+	{0xFB, 0x70}, {0xFB, 0x72}, {0xFB, 0x75}, {0xFB, 0x7C}, {0xFB, 0x7D},
+	{0xFB, 0x7E}, {0xFB, 0x80}, {0xFB, 0x82}, {0xFB, 0x85}, {0xFB, 0x86},
+	{0xFB, 0x89}, {0xFB, 0x8D}, {0xFB, 0x8E}, {0xFB, 0x92}, {0xFB, 0x94},
+	{0xFB, 0x9D}, {0xFB, 0x9E}, {0xFB, 0x9F}, {0xFB, 0xA0}, {0xFB, 0xA1},
+	{0xFB, 0xA9}, {0xFB, 0xAC}, {0xFB, 0xAE}, {0xFB, 0xB0}, {0xFB, 0xB1},
+	{0xFB, 0xB3}, {0xFB, 0xB4}, {0xFB, 0xB6}, {0xFB, 0xB7}, {0xFB, 0xB8},
+	{0xFB, 0xD3}, {0xFB, 0xDA}, {0xFB, 0xE8}, {0xFB, 0xE9}, {0xFB, 0xEA},
+	{0xFB, 0xEE}, {0xFB, 0xF0}, {0xFB, 0xF2}, {0xFB, 0xF6}, {0xFB, 0xF7},
+	{0xFB, 0xF9}, {0xFB, 0xFA}, {0xFB, 0xFC}, {0xFC, 0x42}, {0xFC, 0x49},
+	{0xFC, 0x4B},
+};
+
+#define MAP_ELEMENT_OF(map)	(sizeof(map) / sizeof(map[0]))
+
+static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi,
+			      const unsigned char sjis_lo);
+static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi,
+				       const unsigned char euc_lo);
+static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi,
+				      const unsigned char euc_lo);
+static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi,
+			      const unsigned char euc_lo);
+static inline int sjisnec2sjisibm(unsigned char *sjisibm,
+				  const unsigned char sjisnec_hi,
+				  const unsigned char sjisnec_lo);
+
+/* SJIS IBM extended characters to EUC */
+static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi,
+			      const unsigned char sjis_lo)
+{
+	int index;
+
+	index = ((sjis_hi - 0xFA) * (0xFD - 0x40)) + (sjis_lo - 0x40);
+	if (IS_EUC_IBM2JISX0208(sjisibm2euc_map[index][0],
+				sjisibm2euc_map[index][1])) {
+		euc[0] = sjisibm2euc_map[index][0];
+		euc[1] = sjisibm2euc_map[index][1];
+		return 2;
+	} else {
+		euc[0] = SS3;
+		euc[1] = sjisibm2euc_map[index][0];
+		euc[2] = sjisibm2euc_map[index][1];
+		return 3;
+	}
+}
+
+/* EUC to SJIS IBM extended characters (G3 JIS X 0212 block) */
+static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi,
+				       const unsigned char euc_lo)
+{
+	int index, min_index, max_index;
+	unsigned short euc;
+
+	min_index = 0;
+	max_index = MAP_ELEMENT_OF(euc2sjisibm_jisx0212_map) - 1;
+	euc = (euc_hi << 8) | euc_lo;
+
+	while (min_index <= max_index) {
+		index = (min_index + max_index) / 2;
+		if (euc < euc2sjisibm_jisx0212_map[index].euc)
+			max_index = index - 1;
+		else
+			min_index = index + 1;
+		if (euc == euc2sjisibm_jisx0212_map[index].euc) {
+			sjis[0] = euc2sjisibm_jisx0212_map[index].sjis[0];
+			sjis[1] = euc2sjisibm_jisx0212_map[index].sjis[1];
+			return 3;
+		}
+	}
+	return 0;
+}
+
+/* EUC to SJIS IBM extended characters (G3 Upper block) */
+static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi,
+				      const unsigned char euc_lo)
+{
+	int index;
+
+	if (euc_hi == 0xF3)
+		index = ((euc_hi << 8) | euc_lo) - 0xF3F3;
+	else
+		index = ((euc_hi << 8) | euc_lo) - 0xF4A1 + 12;
+
+	if ((index < 0) || (index >= MAP_ELEMENT_OF(euc2sjisibm_g3upper_map)))
+		return 0;
+
+	sjis[0] = euc2sjisibm_g3upper_map[index][0];
+	sjis[1] = euc2sjisibm_g3upper_map[index][1];
+
+	return 3;
+}
+
+/* EUC to SJIS IBM extended characters (G3 block) */
+static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi,
+			      const unsigned char euc_lo)
+{
+	int n;
+
+#if 0
+	if ((euc_hi == 0xA2) && (euc_lo == 0xCC)) {
+		sjis[0] = 0xFA;
+		sjis[1] = 0x54;
+		return 2;
+	} else if ((euc_hi == 0xA2) && (euc_lo == 0xE8)) {
+		sjis[0] = 0xFA;
+		sjis[1] = 0x5B;
+		return 2;
+	}
+#endif
+	if ((n = euc2sjisibm_g3upper(sjis, euc_hi, euc_lo))) {
+		return n;
+	} else if ((n = euc2sjisibm_jisx0212(sjis, euc_hi, euc_lo))) {
+		return n;
+	}
+
+	return 0;
+}
+
+/* NEC/IBM extended characters to IBM extended characters */
+static inline int sjisnec2sjisibm(unsigned char *sjisibm,
+				  const unsigned char sjisnec_hi,
+				  const unsigned char sjisnec_lo)
+{
+	int count;
+
+	if (! IS_SJIS_NECIBM(sjisnec_hi, sjisnec_lo))
+		return 0;
+
+	if ((sjisnec_hi == 0xEE) && (sjisnec_lo == 0xF9)) {
+		sjisibm[0] = 0x81;
+		sjisibm[1] = 0xCA;
+		return 2;
+	}
+
+	if ((sjisnec_hi == 0xEE) && (sjisnec_lo >= 0xEF)) {
+		count = (sjisnec_hi << 8 | sjisnec_lo)
+			- (sjisnec_lo <= 0xF9 ? 0xEEEF : (0xEEEF - 10));
+	} else {
+		count = (sjisnec_hi - 0xED) * (0xFC - 0x40)
+			+ (sjisnec_lo - 0x40) + (0x5C - 0x40);
+		if (sjisnec_lo >= 0x7F)
+			count--;
+	}
+
+	sjisibm[0] = 0xFA + (count / (0xFC - 0x40));
+	sjisibm[1] = 0x40 + (count % (0xFC - 0x40));
+	if (sjisibm[1] >= 0x7F)
+		sjisibm[1]++;
+
+	return 2;
+}
 
 static int uni2char(const wchar_t uni,
-			unsigned char *out, int boundlen)
+		    unsigned char *out, int boundlen)
 {
 	int n;
 
-	if ( !p_nls )
- 		return -EINVAL;
-	if ( (n = p_nls->uni2char(uni, out, boundlen)) < 0)
+	if (!p_nls)
+		return -EINVAL;
+	if ((n = p_nls->uni2char(uni, out, boundlen)) < 0)
 		return n;
-	
+
 	/* translate SJIS into EUC-JP */
 	if (n == 1) {
-		/* JIS X 201 KANA */
-		if (0xA1 <= out[0] && out[0] <= 0xDF) {
-			if (boundlen <= 1)
+		if (IS_SJIS_JISX0201KANA(out[0])) {
+			/* JIS X 0201 KANA */
+			if (boundlen < 2)
 				return -ENAMETOOLONG;
+
 			out[1] = out[0];
 			out[0] = SS2;
-			n = 2;    
+			return 2;
 		}
-	} else if (n == 2) { 
-		/* JIS X 208 */
+	} else if (n == 2) {
+		/* NEC/IBM extended characters to IBM extended characters */
+		sjisnec2sjisibm(out, out[0], out[1]);
+
+		if (IS_SJIS_UDC_LOW(out[0], out[1])) {
+			/* User defined characters half low */
+			MAP_SJIS2EUC(out[0], out[1], 0xF0, out[0], out[1], 0xF5);
+		} else if (IS_SJIS_UDC_HI(out[0], out[1])) {
+			/* User defined characters half high */
+			unsigned char ch, cl;
 
-		/* SJIS codes 0xF0xx to 0xFFxx are machine-dependent codes and user-defining characters */
-		if (out[0] >= 0xF0) {
-			out[0] = 0x81;  /* 'GETA' with SJIS coding */
-			out[1] = 0xAC;
-		}
+			if (boundlen < 3)
+				return -ENAMETOOLONG;
 
-		out[0] = (out[0]^0xA0)*2 + 0x5F;
-		if (out[1] > 0x9E)
-			out[0]++; 
-		
-		if (out[1] < 0x7F)
-			out[1] = out[1] + 0x61;
-		else if (out[1] < 0x9F)
-			out[1] = out[1] + 0x60;
-		else
-			out[1] = out[1] + 0x02;
+			n = 3; ch = out[0]; cl = out[1];
+			out[0] = SS3;
+			MAP_SJIS2EUC(ch, cl, 0xF5, out[1], out[2], 0xF5);
+		} else if (IS_SJIS_IBM(out[0], out[1])) {
+			/* IBM extended characters */
+			unsigned char euc[3], i;
+
+			n = sjisibm2euc(euc, out[0], out[1]);
+			if (boundlen < n)
+				return -ENAMETOOLONG;
+			for (i = 0; i < n; i++)
+				out[i] = euc[i];
+		} else if (IS_SJIS_JISX0208(out[0], out[1])) {
+			/* JIS X 0208 (include NEC special characters) */
+			out[0] = (out[0]^0xA0)*2 + 0x5F;
+			if (out[1] > 0x9E)
+				out[0]++;
+
+			if (out[1] < 0x7F)
+				out[1] = out[1] + 0x61;
+			else if (out[1] < 0x9F)
+				out[1] = out[1] + 0x60;
+			else
+				out[1] = out[1] + 0x02;
+		} else {
+			/* Invalid characters */
+			return -EINVAL;
+		}
 	}
 	else
 		return -EINVAL;
@@ -61,52 +479,73 @@
 }
 
 static int char2uni(const unsigned char *rawstring, int boundlen,
-				wchar_t *uni)
+		    wchar_t *uni)
 {
 	unsigned char sjis_temp[2];
 	int euc_offset, n;
-	
+
 	if ( !p_nls )
 		return -EINVAL;
 	if (boundlen <= 0)
 		return -ENAMETOOLONG;
 
-	if (boundlen == 1) {
-		*uni = rawstring[0];
-		return 1;
-	}
-
 	/* translate EUC-JP into SJIS */
 	if (rawstring[0] > 0x7F) {
-		if (rawstring[0] == SS2) {
-			/* JIS X 201 KANA */
-			sjis_temp[0] = rawstring[1];
-			sjis_temp[1] = 0x00;
-			euc_offset = 2;
-		} else if (rawstring[0] == SS3) {
-			/* JIS X 212 */
-			sjis_temp[0] = 0x81; /* 'GETA' with SJIS coding */
-			sjis_temp[1] = 0xAC;
+		if (rawstring[0] == SS3) {
+			if (boundlen < 3)
+				return -EINVAL;
 			euc_offset = 3;
-		} else { 
-			/* JIS X 208 */
-			sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0;
-			if (!(rawstring[0]&1))
-				sjis_temp[1] = rawstring[1] - 0x02;
-			else if (rawstring[1] < 0xE0)
-				sjis_temp[1] = rawstring[1] - 0x61;
-			else
-				sjis_temp[1] = rawstring[1] - 0x60;
+
+			if (IS_EUC_UDC_HI(rawstring[1], rawstring[2])) {
+				/* User defined characters half high */
+				MAP_EUC2SJIS(rawstring[1], rawstring[2], 0xF5,
+					     sjis_temp[0], sjis_temp[1], 0xF5);
+			} else if (euc2sjisibm(sjis_temp,rawstring[1],rawstring[2])) {
+				/* IBM extended characters */
+			} else {
+				/* JIS X 0212 and Invalid characters*/
+				return -EINVAL;
+
+				/* 'GETA' with SJIS coding */
+				/* sjis_temp[0] = 0x81; */
+				/* sjis_temp[1] = 0xAC; */
+			}
+		} else {
+			if (boundlen < 2)
+				return -EINVAL;
 			euc_offset = 2;
+
+			if (IS_EUC_JISX0201KANA(rawstring[0], rawstring[1])) {
+				/* JIS X 0201 KANA */
+				sjis_temp[0] = rawstring[1];
+				sjis_temp[1] = 0x00;
+			} else if (IS_EUC_UDC_LOW(rawstring[0], rawstring[1])) {
+				/* User defined characters half low */
+				MAP_EUC2SJIS(rawstring[0], rawstring[1], 0xF5,
+					     sjis_temp[0], sjis_temp[1], 0xF0);
+			} else if (IS_EUC_JISX0208(rawstring[0], rawstring[1])) {
+				/* JIS X 0208 (include NEC spesial characters) */
+				sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0;
+				if (!(rawstring[0] & 1))
+					sjis_temp[1] = rawstring[1] - 0x02;
+				else if (rawstring[1] < 0xE0)
+					sjis_temp[1] = rawstring[1] - 0x61;
+				else
+					sjis_temp[1] = rawstring[1] - 0x60;
+			} else {
+				/* Invalid characters */
+				return -EINVAL;
+			}
 		}
-	} else { 
-		/* JIS X 201 ROMAJI */
-		sjis_temp[0] = rawstring[0];
-		sjis_temp[1] = rawstring[1];
+	} else {
 		euc_offset = 1;
+
+		/* JIS X 0201 ROMAJI */
+		sjis_temp[0] = rawstring[0];
+		sjis_temp[1] = 0x00;
 	}
 
-	if ( (n = p_nls->char2uni(sjis_temp, boundlen, uni)) < 0)
+	if ( (n = p_nls->char2uni(sjis_temp, sizeof(sjis_temp), uni)) < 0)
 		return n;
 
 	return euc_offset;
diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_iso8859-13.c linux/fs/nls/nls_iso8859-13.c
--- v2.4.3/linux/fs/nls/nls_iso8859-13.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/nls_iso8859-13.c	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,330 @@
+/*
+ * linux/fs/nls_iso8859-13.c
+ *
+ * Charset iso8859-13 translation tables.
+ * 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/errno.h>
+
+static wchar_t charset2uni[256] = {
+	/* 0x00*/
+	0x0000, 0x0001, 0x0002, 0x0003,
+	0x0004, 0x0005, 0x0006, 0x0007,
+	0x0008, 0x0009, 0x000a, 0x000b,
+	0x000c, 0x000d, 0x000e, 0x000f,
+	/* 0x10*/
+	0x0010, 0x0011, 0x0012, 0x0013,
+	0x0014, 0x0015, 0x0016, 0x0017,
+	0x0018, 0x0019, 0x001a, 0x001b,
+	0x001c, 0x001d, 0x001e, 0x001f,
+	/* 0x20*/
+	0x0020, 0x0021, 0x0022, 0x0023,
+	0x0024, 0x0025, 0x0026, 0x0027,
+	0x0028, 0x0029, 0x002a, 0x002b,
+	0x002c, 0x002d, 0x002e, 0x002f,
+	/* 0x30*/
+	0x0030, 0x0031, 0x0032, 0x0033,
+	0x0034, 0x0035, 0x0036, 0x0037,
+	0x0038, 0x0039, 0x003a, 0x003b,
+	0x003c, 0x003d, 0x003e, 0x003f,
+	/* 0x40*/
+	0x0040, 0x0041, 0x0042, 0x0043,
+	0x0044, 0x0045, 0x0046, 0x0047,
+	0x0048, 0x0049, 0x004a, 0x004b,
+	0x004c, 0x004d, 0x004e, 0x004f,
+	/* 0x50*/
+	0x0050, 0x0051, 0x0052, 0x0053,
+	0x0054, 0x0055, 0x0056, 0x0057,
+	0x0058, 0x0059, 0x005a, 0x005b,
+	0x005c, 0x005d, 0x005e, 0x005f,
+	/* 0x60*/
+	0x0060, 0x0061, 0x0062, 0x0063,
+	0x0064, 0x0065, 0x0066, 0x0067,
+	0x0068, 0x0069, 0x006a, 0x006b,
+	0x006c, 0x006d, 0x006e, 0x006f,
+	/* 0x70*/
+	0x0070, 0x0071, 0x0072, 0x0073,
+	0x0074, 0x0075, 0x0076, 0x0077,
+	0x0078, 0x0079, 0x007a, 0x007b,
+	0x007c, 0x007d, 0x007e, 0x007f,
+	/* 0x80*/
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	/* 0x90*/
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	/* 0xa0*/
+	0x00a0, 0x201d, 0x00a2, 0x00a3,
+	0x00a4, 0x201e, 0x00a6, 0x00a7,
+	0x00d8, 0x00a9, 0x0156, 0x00ab,
+	0x00ac, 0x00ad, 0x00ae, 0x00c6,
+	/* 0xb0*/
+	0x00b0, 0x00b1, 0x00b2, 0x00b3,
+	0x201c, 0x00b5, 0x00b6, 0x00b7,
+	0x00f8, 0x00b9, 0x0157, 0x00bb,
+	0x00bc, 0x00bd, 0x00be, 0x00e6,
+	/* 0xc0*/
+	0x0104, 0x012e, 0x0100, 0x0106,
+	0x00c4, 0x00c5, 0x0118, 0x0112,
+	0x010c, 0x00c9, 0x0179, 0x0116,
+	0x0122, 0x0136, 0x012a, 0x013b,
+	/* 0xd0*/
+	0x0160, 0x0143, 0x0145, 0x00d3,
+	0x014c, 0x00d5, 0x00d6, 0x00d7,
+	0x0172, 0x0141, 0x015a, 0x016a,
+	0x00dc, 0x017b, 0x017d, 0x00df,
+	/* 0xe0*/
+	0x0105, 0x012f, 0x0101, 0x0107,
+	0x00e4, 0x00e5, 0x0119, 0x0113,
+	0x010d, 0x00e9, 0x017a, 0x0117,
+	0x0123, 0x0137, 0x012b, 0x013c,
+	/* 0xf0*/
+	0x0161, 0x0144, 0x0146, 0x00f3,
+	0x014d, 0x00f5, 0x00f6, 0x00f7,
+	0x0173, 0x0142, 0x015b, 0x016b,
+	0x00fc, 0x017c, 0x017e, 0x2019,
+};
+
+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 */
+	0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0x00, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0xaf, 0x00, /* 0xc0-0xc7 */
+	0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0xd3, 0x00, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xa8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0xe4, 0xe5, 0xbf, 0x00, /* 0xe0-0xe7 */
+	0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xf3, 0x00, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xb8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+	0xc2, 0xe2, 0x00, 0x00, 0xc0, 0xe0, 0xc3, 0xe3, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0xc7, 0xe7, 0x00, 0x00, 0xcb, 0xeb, /* 0x10-0x17 */
+	0xc6, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0xce, 0xee, 0x00, 0x00, 0xc1, 0xe1, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xed, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0xcf, 0xef, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0xd9, 0xf9, 0xd1, 0xf1, 0xd2, 0xf2, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0xd4, 0xf4, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xba, /* 0x50-0x57 */
+	0x00, 0x00, 0xda, 0xfa, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0xd8, 0xf8, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0xca, 0xea, 0xdd, 0xfd, 0xde, 0xfe, 0x00, /* 0x78-0x7f */
+};
+
+static unsigned char page02[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, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 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 */
+	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 */
+};
+
+static unsigned char page20[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, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, page01,   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,   NULL,   
+	page20,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+};
+
+static unsigned char charset2lower[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, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */
+	0x78, 0x79, 0x7a, 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 */
+	0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbf, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 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 */
+};
+
+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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+	0x58, 0x59, 0x5a, 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 */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xbd, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */
+};
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+	unsigned char *uni2charset;
+	unsigned char cl = uni & 0x00ff;
+	unsigned char ch = (uni & 0xff00) >> 8;
+
+	if (boundlen <= 0)
+		return -ENAMETOOLONG;
+
+	uni2charset = page_uni2charset[ch];
+	if (uni2charset && uni2charset[cl])
+		out[0] = uni2charset[cl];
+	else
+		return -EINVAL;
+	return 1;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+	*uni = charset2uni[*rawstring];
+	if (*uni == 0x0000)
+		return -EINVAL;
+	return 1;
+}
+
+static struct nls_table table = {
+	"iso8859-13",
+	uni2char,
+	char2uni,
+	charset2lower,
+	charset2upper,
+	THIS_MODULE,
+};
+
+static int __init init_nls_iso8859_13(void)
+{
+	return register_nls(&table);
+}
+
+static void __exit exit_nls_iso8859_13(void)
+{
+	unregister_nls(&table);
+}
+
+module_init(init_nls_iso8859_13)
+module_exit(exit_nls_iso8859_13)
+
+/*
+ * 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 --recursive --new-file v2.4.3/linux/fs/nls/nls_iso8859-8.c linux/fs/nls/nls_iso8859-8.c
--- v2.4.3/linux/fs/nls/nls_iso8859-8.c	Fri Jul 21 15:19:51 2000
+++ linux/fs/nls/nls_iso8859-8.c	Fri Apr  6 10:51:19 2001
@@ -1,10 +1,5 @@
 /*
  * linux/fs/nls_iso8859-8.c
- *
- * Charset iso8859-8 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>
@@ -13,291 +8,36 @@
 #include <linux/nls.h>
 #include <linux/errno.h>
 
-static wchar_t charset2uni[256] = {
-	/* 0x00*/
-	0x0000, 0x0001, 0x0002, 0x0003,
-	0x0004, 0x0005, 0x0006, 0x0007,
-	0x0008, 0x0009, 0x000a, 0x000b,
-	0x000c, 0x000d, 0x000e, 0x000f,
-	/* 0x10*/
-	0x0010, 0x0011, 0x0012, 0x0013,
-	0x0014, 0x0015, 0x0016, 0x0017,
-	0x0018, 0x0019, 0x001a, 0x001b,
-	0x001c, 0x001d, 0x001e, 0x001f,
-	/* 0x20*/
-	0x0020, 0x0021, 0x0022, 0x0023,
-	0x0024, 0x0025, 0x0026, 0x0027,
-	0x0028, 0x0029, 0x002a, 0x002b,
-	0x002c, 0x002d, 0x002e, 0x002f,
-	/* 0x30*/
-	0x0030, 0x0031, 0x0032, 0x0033,
-	0x0034, 0x0035, 0x0036, 0x0037,
-	0x0038, 0x0039, 0x003a, 0x003b,
-	0x003c, 0x003d, 0x003e, 0x003f,
-	/* 0x40*/
-	0x0040, 0x0041, 0x0042, 0x0043,
-	0x0044, 0x0045, 0x0046, 0x0047,
-	0x0048, 0x0049, 0x004a, 0x004b,
-	0x004c, 0x004d, 0x004e, 0x004f,
-	/* 0x50*/
-	0x0050, 0x0051, 0x0052, 0x0053,
-	0x0054, 0x0055, 0x0056, 0x0057,
-	0x0058, 0x0059, 0x005a, 0x005b,
-	0x005c, 0x005d, 0x005e, 0x005f,
-	/* 0x60*/
-	0x0060, 0x0061, 0x0062, 0x0063,
-	0x0064, 0x0065, 0x0066, 0x0067,
-	0x0068, 0x0069, 0x006a, 0x006b,
-	0x006c, 0x006d, 0x006e, 0x006f,
-	/* 0x70*/
-	0x0070, 0x0071, 0x0072, 0x0073,
-	0x0074, 0x0075, 0x0076, 0x0077,
-	0x0078, 0x0079, 0x007a, 0x007b,
-	0x007c, 0x007d, 0x007e, 0x007f,
-	/* 0x80*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	/* 0x90*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	/* 0xa0*/
-	0x00a0, 0x0000, 0x00a2, 0x00a3,
-	0x00a4, 0x00a5, 0x00a6, 0x00a7,
-	0x00a8, 0x00a9, 0x00d7, 0x00ab,
-	0x00ac, 0x00ad, 0x00ae, 0x203e,
-	/* 0xb0*/
-	0x00b0, 0x00b1, 0x00b2, 0x00b3,
-	0x00b4, 0x00b5, 0x00b6, 0x00b7,
-	0x00b8, 0x00b9, 0x00f7, 0x00bb,
-	0x00bc, 0x00bd, 0x00be, 0x0000,
-	/* 0xc0*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	/* 0xd0*/
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x2017,
-	/* 0xe0*/
-	0x05d0, 0x05d1, 0x05d2, 0x05d3,
-	0x05d4, 0x05d5, 0x05d6, 0x05d7,
-	0x05d8, 0x05d9, 0x05da, 0x05db,
-	0x05dc, 0x05dd, 0x05de, 0x05df,
-	/* 0xf0*/
-	0x05e0, 0x05e1, 0x05e2, 0x05e3,
-	0x05e4, 0x05e5, 0x05e6, 0x05e7,
-	0x05e8, 0x05e9, 0x05ea, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-};
-
-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 */
-	0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
-	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
-	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
-	0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 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, 0xaa, /* 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, 0xba, /* 0xf0-0xf7 */
-};
-
-static unsigned char page05[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 */
-	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 */
-	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 */
-	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */
-	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */
-	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */
-	0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
-};
-
-static unsigned char page20[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, 0xdf, /* 0x10-0x17 */
-	0x00, 0x00, 0x00, 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, 0xaf, 0x00, /* 0x38-0x3f */
-};
-
-static unsigned char *page_uni2charset[256] = {
-	page00, NULL,   NULL,   NULL,   NULL,   page05, 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,   
-	page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
-};
-
-static unsigned char charset2lower[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, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */
-	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */
-	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */
-	0x78, 0x79, 0x7a, 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 */
-	0xa0, 0x00, 0xa2, 0xa3, 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, 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, 0xdf, /* 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, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
-};
-
-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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
-	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
-	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
-	0x58, 0x59, 0x5a, 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 */
-	0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
-	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
-	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */
-	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 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, 0xdf, /* 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, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
-};
-
-static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
-{
-	unsigned char *uni2charset;
-	unsigned char cl = uni & 0x00ff;
-	unsigned char ch = (uni & 0xff00) >> 8;
-
-	if (boundlen <= 0)
-		return -ENAMETOOLONG;
-
-	uni2charset = page_uni2charset[ch];
-	if (uni2charset && uni2charset[cl])
-		out[0] = uni2charset[cl];
-	else
-		return -EINVAL;
-	return 1;
-}
-
-static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
-{
-	*uni = charset2uni[*rawstring];
-	if (*uni == 0x0000)
-		return -EINVAL;
-	return 1;
-}
+static struct nls_table *p_nls;
 
 static struct nls_table table = {
 	"iso8859-8",
-	uni2char,
-	char2uni,
-	charset2lower,
-	charset2upper,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
 	THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_8(void)
 {
-	return register_nls(&table);
+	p_nls = load_nls("cp1255");
+
+	if (p_nls) {
+		table.uni2char = p_nls->uni2char;
+		table.char2uni = p_nls->char2uni;
+		table.charset2upper = p_nls->charset2upper;
+		table.charset2lower = p_nls->charset2lower;
+		return register_nls(&table);
+	}
+
+	return -EINVAL;
 }
 
 static void __exit exit_nls_iso8859_8(void)
 {
 	unregister_nls(&table);
+	unload_nls(p_nls);
 }
 
 module_init(init_nls_iso8859_8)
@@ -308,7 +48,8 @@
  * 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
diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_koi8-u.c linux/fs/nls/nls_koi8-u.c
--- v2.4.3/linux/fs/nls/nls_koi8-u.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/nls_koi8-u.c	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,345 @@
+/*
+ * linux/fs/nls_koi8-u.c
+ *
+ * Charset koi8-u translation tables.
+ * 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/errno.h>
+
+static wchar_t charset2uni[256] = {
+	/* 0x00*/
+	0x0000, 0x0001, 0x0002, 0x0003,
+	0x0004, 0x0005, 0x0006, 0x0007,
+	0x0008, 0x0009, 0x000a, 0x000b,
+	0x000c, 0x000d, 0x000e, 0x000f,
+	/* 0x10*/
+	0x0010, 0x0011, 0x0012, 0x0013,
+	0x0014, 0x0015, 0x0016, 0x0017,
+	0x0018, 0x0019, 0x001a, 0x001b,
+	0x001c, 0x001d, 0x001e, 0x001f,
+	/* 0x20*/
+	0x0020, 0x0021, 0x0022, 0x0023,
+	0x0024, 0x0025, 0x0026, 0x0027,
+	0x0028, 0x0029, 0x002a, 0x002b,
+	0x002c, 0x002d, 0x002e, 0x002f,
+	/* 0x30*/
+	0x0030, 0x0031, 0x0032, 0x0033,
+	0x0034, 0x0035, 0x0036, 0x0037,
+	0x0038, 0x0039, 0x003a, 0x003b,
+	0x003c, 0x003d, 0x003e, 0x003f,
+	/* 0x40*/
+	0x0040, 0x0041, 0x0042, 0x0043,
+	0x0044, 0x0045, 0x0046, 0x0047,
+	0x0048, 0x0049, 0x004a, 0x004b,
+	0x004c, 0x004d, 0x004e, 0x004f,
+	/* 0x50*/
+	0x0050, 0x0051, 0x0052, 0x0053,
+	0x0054, 0x0055, 0x0056, 0x0057,
+	0x0058, 0x0059, 0x005a, 0x005b,
+	0x005c, 0x005d, 0x005e, 0x005f,
+	/* 0x60*/
+	0x0060, 0x0061, 0x0062, 0x0063,
+	0x0064, 0x0065, 0x0066, 0x0067,
+	0x0068, 0x0069, 0x006a, 0x006b,
+	0x006c, 0x006d, 0x006e, 0x006f,
+	/* 0x70*/
+	0x0070, 0x0071, 0x0072, 0x0073,
+	0x0074, 0x0075, 0x0076, 0x0077,
+	0x0078, 0x0079, 0x007a, 0x007b,
+	0x007c, 0x007d, 0x007e, 0x007f,
+	/* 0x80*/
+	0x2500, 0x2502, 0x250c, 0x2510,
+	0x2514, 0x2518, 0x251c, 0x2524,
+	0x252c, 0x2534, 0x253c, 0x2580,
+	0x2584, 0x2588, 0x258c, 0x2590,
+	/* 0x90*/
+	0x2591, 0x2592, 0x2593, 0x2320,
+	0x25a0, 0x2219, 0x221a, 0x2248,
+	0x2264, 0x2265, 0x00a0, 0x2321,
+	0x00b0, 0x00b2, 0x00b7, 0x00f7,
+	/* 0xa0*/
+	0x2550, 0x2551, 0x2552, 0x0451,
+	0x0454, 0x2554, 0x0456, 0x0457,
+	0x2557, 0x2558, 0x2559, 0x255a,
+	0x255b, 0x0491, 0x255d, 0x255e,
+	/* 0xb0*/
+	0x255f, 0x2560, 0x2561, 0x0401,
+	0x0404, 0x2563, 0x0406, 0x0407,
+	0x2566, 0x2567, 0x2568, 0x2569,
+	0x256a, 0x0490, 0x256c, 0x00a9,
+	/* 0xc0*/
+	0x044e, 0x0430, 0x0431, 0x0446,
+	0x0434, 0x0435, 0x0444, 0x0433,
+	0x0445, 0x0438, 0x0439, 0x043a,
+	0x043b, 0x043c, 0x043d, 0x043e,
+	/* 0xd0*/
+	0x043f, 0x044f, 0x0440, 0x0441,
+	0x0442, 0x0443, 0x0436, 0x0432,
+	0x044c, 0x044b, 0x0437, 0x0448,
+	0x044d, 0x0449, 0x0447, 0x044a,
+	/* 0xe0*/
+	0x042e, 0x0410, 0x0411, 0x0426,
+	0x0414, 0x0415, 0x0424, 0x0413,
+	0x0425, 0x0418, 0x0419, 0x041a,
+	0x041b, 0x041c, 0x041d, 0x041e,
+	/* 0xf0*/
+	0x041f, 0x042f, 0x0420, 0x0421,
+	0x0422, 0x0423, 0x0416, 0x0412,
+	0x042c, 0x042b, 0x0417, 0x0428,
+	0x042d, 0x0429, 0x0427, 0x042a,
+};
+
+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 */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0xb3, 0x00, 0x00, 0xb4, 0x00, 0xb6, 0xb7, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0x50-0x57 */
+	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 */
+
+	0xbd, 0xad, 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 */
+};
+
+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 */
+};
+
+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 */
+};
+
+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, 0x00, 0xa5, 0x00, 0x00, 0xa8, /* 0x50-0x57 */
+	0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */
+	0xb1, 0xb2, 0x00, 0xb5, 0x00, 0x00, 0xb8, 0xb9, /* 0x60-0x67 */
+	0xba, 0xbb, 0xbc, 0x00, 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 */
+};
+
+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,   
+};
+
+static unsigned char charset2lower[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, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */
+	0x78, 0x79, 0x7a, 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 */
+
+	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, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xa3, 0xa4, 0xb5, 0xa6, 0xa7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */
+};
+
+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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+	0x58, 0x59, 0x5a, 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, 0xb3, 0xb4, 0xa5, 0xb6, 0xb7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 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 */
+};
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+	unsigned char *uni2charset;
+	unsigned char cl = uni & 0x00ff;
+	unsigned char ch = (uni & 0xff00) >> 8;
+
+	if (boundlen <= 0)
+		return -ENAMETOOLONG;
+
+	uni2charset = page_uni2charset[ch];
+	if (uni2charset && uni2charset[cl])
+		out[0] = uni2charset[cl];
+	else
+		return -EINVAL;
+	return 1;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+	*uni = charset2uni[*rawstring];
+	if (*uni == 0x0000)
+		return -EINVAL;
+	return 1;
+}
+
+static struct nls_table table = {
+	"koi8-u",
+	uni2char,
+	char2uni,
+	charset2lower,
+	charset2upper,
+	THIS_MODULE,
+};
+
+static int __init init_nls_koi8_u(void)
+{
+	return register_nls(&table);
+}
+
+static void __exit exit_nls_koi8_u(void)
+{
+	unregister_nls(&table);
+}
+
+module_init(init_nls_koi8_u)
+module_exit(exit_nls_koi8_u)
+
+/*
+ * 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 --recursive --new-file v2.4.3/linux/fs/nls/nls_tis-620.c linux/fs/nls/nls_tis-620.c
--- v2.4.3/linux/fs/nls/nls_tis-620.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nls/nls_tis-620.c	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,62 @@
+/*
+ * linux/fs/nls_tis-620.c
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/errno.h>
+
+static struct nls_table *p_nls;
+
+static struct nls_table table = {
+	"tis-620",
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	THIS_MODULE,
+};
+
+static int __init init_nls_tis_620(void)
+{
+	p_nls = load_nls("cp874");
+
+	if (p_nls) {
+		table.uni2char = p_nls->uni2char;
+		table.char2uni = p_nls->char2uni;
+		table.charset2upper = p_nls->charset2upper;
+		table.charset2lower = p_nls->charset2lower;
+		return register_nls(&table);
+	}
+
+	return -EINVAL;
+}
+
+static void __exit exit_nls_tis_620(void)
+{
+	unregister_nls(&table);
+	unload_nls(p_nls);
+}
+
+module_init(init_nls_tis_620)
+module_exit(exit_nls_tis_620)
+
+/*
+ * 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 --recursive --new-file v2.4.3/linux/fs/ntfs/Makefile linux/fs/ntfs/Makefile
--- v2.4.3/linux/fs/ntfs/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/ntfs/Makefile	Wed Apr 18 11:49:13 2001
@@ -4,7 +4,8 @@
 
 obj-y   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
 obj-m   := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000607\"
+# Version format: YYMMDD
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"010116\"
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/attr.c linux/fs/ntfs/attr.c
--- v2.4.3/linux/fs/ntfs/attr.c	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/attr.c	Wed Apr 18 11:49:13 2001
@@ -1,10 +1,10 @@
-/*
- *  attr.c
+/*  attr.c
  *
  *  Copyright (C) 1996-1999 Martin von Löwis
  *  Copyright (C) 1996-1997 Régis Duchesne
  *  Copyright (C) 1998 Joseph Malicki
  *  Copyright (C) 1999 Steve Dodd
+ *  Copyright (C) 2001 Anton Altaparmakov (AIA)
  */
 
 #include "ntfstypes.h"
@@ -12,401 +12,389 @@
 #include "attr.h"
 
 #include <linux/errno.h>
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
 #include "macros.h"
 #include "support.h"
 #include "util.h"
 #include "super.h"
 #include "inode.h"
 
-/* Look if an attribute already exists in the inode, and if not, create it */
-int 
-ntfs_new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos,
-			int *found, int do_search )
+/* Look if an attribute already exists in the inode, and if not, create it. */
+int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, int *pos,
+		  int *found, int do_search)
 {
-	int do_insert=0;
+	int do_insert = 0;
 	int i;
 
-	for(i=0;i<ino->attr_count;i++)
+	for (i = 0; i < ino->attr_count; i++)
 	{
-		int n=min(namelen,ino->attrs[i].namelen);
-		int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n);
-		if( do_search ) {
-			/*
-			 * We assume that each attribute can be uniquely 
-			 * identified by inode
-			 * number, attribute type and attribute name.
-			 */
-			if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
-				*found=1;
-				*pos=i;
+		int n = min(namelen, ino->attrs[i].namelen);
+		int s = ntfs_uni_strncmp(ino->attrs[i].name, name, n);
+		if (do_search) {
+			/* We assume that each attribute can be uniquely 
+			 * identified by inode number, attribute type and
+			 * attribute name. */
+			if (ino->attrs[i].type == type && 
+			    ino->attrs[i].namelen == namelen && !s) {
+				*found = 1;
+				*pos = i;
 				return 0;
 			}
 		}
-		/* attributes are ordered by type, then by name */
-		if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){
-			do_insert=1;
+		/* Attributes are ordered by type, then by name. */
+		if (ino->attrs[i].type > type || 
+		    (ino->attrs[i].type == type && s == 1)) {
+			do_insert = 1;
 			break;
 		}
 	}
 
-	/* re-allocate space */
-	if(ino->attr_count % 8 ==0)
+	/* Re-allocate space. */
+	if (ino->attr_count % 8 == 0)
 	{
 		ntfs_attribute* new;
-		new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
-			     sizeof(ntfs_attribute));
-		if( !new )
-			return ENOMEM;
-		if( ino->attrs ) {
-			ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) );
-			ntfs_free( ino->attrs );
+		new = (ntfs_attribute*)ntfs_malloc((ino->attr_count + 8) *
+							sizeof(ntfs_attribute));
+		if (!new)
+			return -ENOMEM;
+		if (ino->attrs) {
+			ntfs_memcpy(new, ino->attrs, ino->attr_count *
+							sizeof(ntfs_attribute));
+			ntfs_free(ino->attrs);
 		}
 		ino->attrs = new;
 	}
-	if(do_insert)
-		ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)*
-			    sizeof(ntfs_attribute));
-
+	if (do_insert)
+		ntfs_memmove(ino->attrs + i + 1, ino->attrs + i,
+			     (ino->attr_count - i) * sizeof(ntfs_attribute));
 	ino->attr_count++;
-	ino->attrs[i].type=type;
-	ino->attrs[i].namelen=namelen;
-	ino->attrs[i].name=name;
-	*pos=i;
-	*found=0;
+	ino->attrs[i].type = type;
+	ino->attrs[i].namelen = namelen;
+	ino->attrs[i].name = name;
+	*pos = i;
+	*found = 0;
 	return 0;
 }
 
-int 
-ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr)
+int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr)
 {
-	int size=attr->size;
-	if(size>0){
+	int size = attr->size;
+	if (size > 0) {
 		/* FIXME: read data, free clusters */
-		return EOPNOTSUPP;
+		return -EOPNOTSUPP;
 	}
-	attr->resident=1;
+	attr->resident = 1;
 	return 0;
 }
 
-/* Store in the inode readable information about a run */
-void
-ntfs_insert_run(ntfs_attribute *attr,int cnum,ntfs_cluster_t cluster,int len)
+/* Store in the inode readable information about a run. */
+void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
+		     int len)
 {
-	/* (re-)allocate space if necessary */
-	if(attr->d.r.len % 8 == 0) {
+	/* (re-)allocate space if necessary. */
+	if (attr->d.r.len % 8 == 0) {
 		ntfs_runlist* new;
-		new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
-		if( !new )
+		new = ntfs_malloc((attr->d.r.len + 8) * sizeof(ntfs_runlist));
+		if (!new)
 			return;
-		if( attr->d.r.runlist ) {
+		if (attr->d.r.runlist) {
 			ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
-				    *sizeof(ntfs_runlist));
-			ntfs_free( attr->d.r.runlist );
+							* sizeof(ntfs_runlist));
+			ntfs_free(attr->d.r.runlist);
 		}
 		attr->d.r.runlist = new;
 	}
-	if(attr->d.r.len>cnum)
-		ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum,
-			    (attr->d.r.len-cnum)*sizeof(ntfs_runlist));
-	attr->d.r.runlist[cnum].cluster=cluster;
-	attr->d.r.runlist[cnum].len=len;
+	if (attr->d.r.len > cnum)
+		ntfs_memmove(attr->d.r.runlist + cnum + 1,
+			     attr->d.r.runlist + cnum,
+			     (attr->d.r.len - cnum) * sizeof(ntfs_runlist));
+	attr->d.r.runlist[cnum].cluster = cluster;
+	attr->d.r.runlist[cnum].len = len;
 	attr->d.r.len++;
 }
 
-/* Extends an attribute. Another run will be added if necessary,
- * but we try to extend the last run in the runlist first.
+/* Extends an attribute. Another run will be added if necessary, but we try to
+ * extend the last run in the runlist first.
  * FIXME: what if there isn't enough contiguous space, we don't create
  * multiple runs?
  *
  * *len: the desired new length of the attr (_not_ the amount to extend by)
  */
-int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
-		int flags)
+int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, int flags)
 {
-	int error=0;
+	int error = 0;
 	ntfs_runlist *rl;
 	int rlen;
 	ntfs_cluster_t cluster;
 	int clen;
 
-	if(attr->compressed)return EOPNOTSUPP;
-	if(ino->record_count>1)return EOPNOTSUPP;
-
-	if(attr->resident) {
-		error = ntfs_make_attr_nonresident(ino,attr);
-		if(error)
+	if (attr->compressed || ino->record_count > 1)
+		return -EOPNOTSUPP;
+	if (attr->resident) {
+		error = ntfs_make_attr_nonresident(ino, attr);
+		if (error)
 			return error;
 	}
-
-	if( *len <= attr->allocated )
-		return 0;	/* truely stupid things do sometimes happen */
-
-	rl=attr->d.r.runlist;
-	rlen=attr->d.r.len-1;
-
-	if(rlen>=0)
-		cluster=rl[rlen].cluster+rl[rlen].len;
+	if (*len <= attr->allocated)
+		return 0;	/* Truely stupid things do sometimes happen. */
+	rl = attr->d.r.runlist;
+	rlen = attr->d.r.len - 1;
+	if (rlen >= 0)
+		cluster = rl[rlen].cluster + rl[rlen].len;
 	else
-		/* no preference for allocation space */
-		cluster=0;
-
-	/* calculate the extra space we need, and round up to multiple of cluster
-	 * size to get number of new clusters needed */
-
-	clen=( (*len - attr->allocated ) + ino->vol->clustersize - 1 ) /
+		/* No preference for allocation space. */
+		cluster = 0;
+	/* Calculate the extra space we need, and round up to multiple of
+	 * cluster size to get number of new clusters needed */
+	clen = ((*len - attr->allocated) + ino->vol->clustersize - 1) /
 		ino->vol->clustersize;
-	if(clen==0)
+	if (clen == 0)
 		return 0;
-
 	/* FIXME: try to allocate smaller pieces */
-	error=ntfs_allocate_clusters(ino->vol,&cluster,&clen,
-				     flags|ALLOC_REQUIRE_SIZE);
-	if(error)return error;
-	attr->allocated += clen*ino->vol->clustersize;
+	error = ntfs_allocate_clusters(ino->vol, &cluster, &clen,
+				       flags | ALLOC_REQUIRE_SIZE);
+	if (error)
+		return error;
+	attr->allocated += clen * ino->vol->clustersize;
 	*len = attr->allocated;
-
-	/* contiguous chunk */
-	if(rlen>=0 && cluster==rl[rlen].cluster+rl[rlen].len){
+	/* Contiguous chunk. */
+	if (rlen >= 0 && cluster == rl[rlen].cluster + rl[rlen].len) {
 		rl[rlen].len += clen;
 		return 0;
 	}
-	ntfs_insert_run(attr,rlen+1,cluster,clen);
+	ntfs_insert_run(attr, rlen + 1, cluster, clen);
 	return 0;
 }
 
-int
-ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
+int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
 {
-	void *data=attr->d.data;
-	int len=attr->size;
-	int error,alen;
+	void *data = attr->d.data;
+	int len = attr->size;
+	int error, alen;
 	ntfs_io io;
-	attr->d.r.len=0;
-	attr->d.r.runlist=0;
-	attr->resident=0;
-	attr->allocated=attr->initialized=0;
-	alen=len;
-	error=ntfs_extend_attr(ino,attr,&alen,ALLOC_REQUIRE_SIZE);
-	if(error)return error;/* FIXME: On error, restore old values */
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.param=data;
-	io.size=len;
-	io.do_read=0;
-	return ntfs_readwrite_attr(ino,attr,0,&io);
+	attr->d.r.len = 0;
+	attr->d.r.runlist = 0;
+	attr->resident = 0;
+	attr->allocated=attr->initialized = 0;
+	alen = len;
+	error = ntfs_extend_attr(ino, attr, &alen, ALLOC_REQUIRE_SIZE);
+	if (error)
+		return error; /* FIXME: On error, restore old values. */
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.param = data;
+	io.size = len;
+	io.do_read = 0;
+	return ntfs_readwrite_attr(ino, attr, 0, &io);
 }
 
-int
-ntfs_attr_allnonresident(ntfs_inode *ino)
+int ntfs_attr_allnonresident(ntfs_inode *ino)
 {
-	int i, error=0;
+	int i, error = 0;
         ntfs_volume *vol = ino->vol;
 
-	for (i=0; !error && i<ino->attr_count; i++)
+	for (i = 0; !error && i < ino->attr_count; i++)
 	{
-		if (ino->attrs[i].type != vol->at_security_descriptor
-		    && ino->attrs[i].type != vol->at_data)
+		if (ino->attrs[i].type != vol->at_security_descriptor &&
+		    ino->attrs[i].type != vol->at_data)
 			continue;
-		error = ntfs_make_attr_nonresident (ino, ino->attrs+i);
+		error = ntfs_make_attr_nonresident(ino, ino->attrs + i);
 	}
 	return error;
 }
 
-/* Resize the attribute to a newsize */
+/* Resize the attribute to a newsize. */
 int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
 {
-	int error=0;
-	int oldsize=attr->size;
-	int clustersize=ino->vol->clustersize;
-	int i,count,newlen,newcount;
+	int error = 0;
+	int oldsize = attr->size;
+	int clustersize = ino->vol->clustersize;
+	int i, count, newlen, newcount;
 	ntfs_runlist *rl;
 
-	if(newsize==oldsize)
+	if (newsize == oldsize)
 		return 0;
-	/* modifying compressed attributes not supported yet */
-	if(attr->compressed)
-		/* extending is easy: just insert sparse runs */
-		return EOPNOTSUPP;
-	if(attr->resident){
+	/* FIXME: Modifying compressed attributes not supported yet. */
+	if (attr->compressed)
+		/* FIXME: Extending is easy: just insert sparse runs. */
+		return -EOPNOTSUPP;
+	if (attr->resident) {
 		void *v;
-		if(newsize>ino->vol->mft_recordsize){
-			error=ntfs_make_attr_nonresident(ino,attr);
-			if(error)return error;
-			return ntfs_resize_attr(ino,attr,newsize);
+		if (newsize > ino->vol->mft_recordsize) {
+			error = ntfs_make_attr_nonresident(ino, attr);
+			if (error)
+				return error;
+			return ntfs_resize_attr(ino, attr, newsize);
 		}
-		v=attr->d.data;
-		if(newsize){
-			attr->d.data=ntfs_malloc(newsize);
-			if(!attr->d.data) {
+		v = attr->d.data;
+		if (newsize) {
+			attr->d.data = ntfs_malloc(newsize);
+			if (!attr->d.data) {
 				ntfs_free(v);
-				return ENOMEM;
+				return -ENOMEM;
 			}
-			if(newsize>oldsize)
-				ntfs_bzero((char*)attr->d.data+oldsize,
-					   newsize-oldsize);
-			ntfs_memcpy((char*)attr->d.data,v,min(newsize,oldsize));
-		}else
-			attr->d.data=0;
+			if (newsize > oldsize)
+				ntfs_bzero((char*)attr->d.data + oldsize,
+					   newsize - oldsize);
+			ntfs_memcpy((char*)attr->d.data, v,
+				    min(newsize, oldsize));
+		} else
+			attr->d.data = 0;
 		ntfs_free(v);
-		attr->size=newsize;
+		attr->size = newsize;
 		return 0;
 	}
-	/* non-resident attribute */
-	rl=attr->d.r.runlist;
-	if(newsize<oldsize){
-		for(i=0,count=0;i<attr->d.r.len;i++){
-			if((count+rl[i].len)*clustersize>newsize)
+	/* Non-resident attribute. */
+	rl = attr->d.r.runlist;
+	if (newsize < oldsize) {
+		for (i = 0, count = 0; i < attr->d.r.len; i++) {
+			if ((count + rl[i].len) * clustersize > newsize)
 				break;
-			count+=(int)rl[i].len;
+			count += (int)rl[i].len;
 		}
-		newlen=i+1;
-		/* free unused clusters in current run, unless sparse */
-		newcount=count;
-		if(rl[i].cluster!=MAX_CLUSTER_T){
-			int rounded=newsize-count*clustersize;
-			rounded=(rounded+clustersize-1)/clustersize;
-			error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster+rounded,
-						       (int)rl[i].len-rounded);
-			if(error)
-				return error; /* FIXME: incomplete operation */
-			rl[i].len=rounded;
-			newcount=count+rounded;
+		newlen = i + 1;
+		/* Free unused clusters in current run, unless sparse. */
+		newcount = count;
+		if (rl[i].cluster != MAX_CLUSTER_T) {
+			int rounded = newsize - count * clustersize;
+			rounded = (rounded + clustersize - 1) / clustersize;
+			error = ntfs_deallocate_clusters(ino->vol, 
+						rl[i].cluster + rounded,
+						(int)rl[i].len - rounded);
+			if (error)
+				return error; /* FIXME: Incomplete operation. */
+			rl[i].len = rounded;
+			newcount = count + rounded;
 		}
-		/* free all other runs */
-		for(i++;i<attr->d.r.len;i++)
-			if(rl[i].cluster!=MAX_CLUSTER_T){
-				error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,(int)rl[i].len);
-				if(error)
-					return error; /* FIXME: incomplete operation */
+		/* Free all other runs. */
+		for (i++; i < attr->d.r.len; i++)
+			if (rl[i].cluster != MAX_CLUSTER_T) {
+				error = ntfs_deallocate_clusters(ino->vol,
+								rl[i].cluster,
+								(int)rl[i].len);
+				if (error)
+					return error; /* FIXME: Incomplete 
+						       * operation */
 			}
-		/* FIXME? free space for extra runs in memory */
-		attr->d.r.len=newlen;
-	}else{
-		newlen=newsize;
-		error=ntfs_extend_attr(ino,attr,&newlen,ALLOC_REQUIRE_SIZE);
-		if(error)return error; /* FIXME: incomplete */
-		newcount=newlen/clustersize;
+		/* FIXME: Free space for extra runs in memory? */
+		attr->d.r.len = newlen;
+	} else {
+		newlen = newsize;
+		error = ntfs_extend_attr(ino, attr, &newlen,
+					 ALLOC_REQUIRE_SIZE);
+		if (error)
+			return error; /* FIXME: Incomplete operation. */
+		newcount = newlen / clustersize;
 	}
-	/* fill in new sizes */
-	attr->allocated = newcount*clustersize;
+	/* Fill in new sizes. */
+	attr->allocated = newcount * clustersize;
 	attr->size = newsize;
 	/* attr->initialized does not change. */
-	if(!newsize)
-		error=ntfs_make_attr_resident(ino,attr);
+	if (!newsize)
+		error = ntfs_make_attr_resident(ino, attr);
 	return error;
 }
 
 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
-	int dsize, ntfs_attribute **rattr)
+		     int dsize, ntfs_attribute **rattr)
 {
 	void *name;
 	int namelen;
-	int found,i;
+	int found, i;
 	int error;
 	ntfs_attribute *attr;
-	if(dsize>ino->vol->mft_recordsize)
-		/* FIXME: non-resident attributes */
-		return EOPNOTSUPP;
-	if(aname){
-		namelen=strlen(aname);
-		name=ntfs_malloc(2*namelen);
-		if( !name )
-			return ENOMEM;
-		ntfs_ascii2uni(name,aname,namelen);
-	}else{
-		name=0;
-		namelen=0;
-	}
-
-	error = ntfs_new_attr(ino,anum,name,namelen,&i,&found,1);
-	if( error ) {
-		ntfs_free( name );
+	
+	if (dsize > ino->vol->mft_recordsize)
+		/* FIXME: Non-resident attributes. */
+		return -EOPNOTSUPP;
+	if (aname) {
+		namelen = strlen(aname);
+		name = ntfs_malloc(2 * namelen);
+		if (!name)
+			return -ENOMEM;
+		ntfs_ascii2uni(name, aname, namelen);
+	} else {
+		name = 0;
+		namelen = 0;
+	}
+	error = ntfs_new_attr(ino, anum, name, namelen, &i, &found, 1);
+	if (error) {
+		ntfs_free(name);
 		return error;
 	}
-
-	if(found){
+	if (found) {
 		ntfs_free(name);
-		return EEXIST;
+		return -EEXIST;
 	}
-	*rattr=attr=ino->attrs+i;
-	/* allocate a new number.
-	   FIXME: Should this happen on inode writeback?
-	   FIXME: extensions records not supported */
-	error=ntfs_allocate_attr_number(ino,&i);
-	if(error)
+	*rattr = attr = ino->attrs + i;
+	/* Allocate a new number.
+	 * FIXME: Should this happen on inode writeback?
+	 * FIXME: Extension records not supported. */
+	error = ntfs_allocate_attr_number(ino, &i);
+	if (error)
 		return error;
-	attr->attrno=i;
-
-	attr->resident=1;
-	attr->compressed=attr->cengine=0;
-	attr->size=attr->allocated=attr->initialized=dsize;
+	attr->attrno = i;
+	attr->resident = 1;
+	attr->compressed = attr->cengine = 0;
+	attr->size = attr->allocated = attr->initialized = dsize;
 
 	/* FIXME: INDEXED information should come from $AttrDef
-	   Currently, only file names are indexed */
-	if(anum==ino->vol->at_file_name){
-		attr->indexed=1;
-	}else
-		attr->indexed=0;
-	attr->d.data=ntfs_malloc(dsize);
-
-	if( !attr->d.data )
-		return ENOMEM;
-
-	ntfs_memcpy(attr->d.data,data,dsize);
+	 * Currently, only file names are indexed. As of NTFS v3.0 (Win2k),
+	 * this is no longer true. Different attributes can be indexed now. */
+	if (anum == ino->vol->at_file_name) {
+		attr->indexed = 1;
+	} else
+		attr->indexed = 0;
+	attr->d.data = ntfs_malloc(dsize);
+	if (!attr->d.data)
+		return -ENOMEM;
+	ntfs_memcpy(attr->d.data, data, dsize);
 	return 0;
 }
 
 /* Non-resident attributes are stored in runs (intervals of clusters).
  *
  * This function stores in the inode readable information about a non-resident
- * attribute.
- */
-static int 
-ntfs_process_runs(ntfs_inode *ino,ntfs_attribute* attr,unsigned char *data)
+ * attribute. */
+static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr,
+			     unsigned char *data)
 {
-	int startvcn,endvcn;
-	int vcn,cnum;
+	int startvcn, endvcn;
+	int vcn, cnum;
 	ntfs_cluster_t cluster;
-	int len,ctype;
-	startvcn = NTFS_GETU64(data+0x10);
-	endvcn = NTFS_GETU64(data+0x18);
-
-	/* check whether this chunk really belongs to the end */
-	for(cnum=0,vcn=0;cnum<attr->d.r.len;cnum++)
-		vcn+=attr->d.r.runlist[cnum].len;
-	if(vcn!=startvcn)
-	{
+	int len, ctype;
+	startvcn = NTFS_GETU64(data + 0x10);
+	endvcn = NTFS_GETU64(data + 0x18);
+
+	/* Check whether this chunk really belongs to the end. */
+	for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++)
+		vcn += attr->d.r.runlist[cnum].len;
+	if (vcn != startvcn) {
 		ntfs_error("Problem with runlist in extended record\n");
 		return -1;
 	}
-	if(!endvcn)
-	{
-		endvcn = NTFS_GETU64(data+0x28)-1; /* allocated length */
+	if (!endvcn) {
+		endvcn = NTFS_GETU64(data + 0x28) - 1; /* Allocated length. */
 		endvcn /= ino->vol->clustersize;
 	}
-	data=data+NTFS_GETU16(data+0x20);
-	cnum=attr->d.r.len;
-	cluster=0;
-	for(vcn=startvcn; vcn<=endvcn; vcn+=len)
-	{
-		if(ntfs_decompress_run(&data,&len,&cluster,&ctype))
+	data = data + NTFS_GETU16(data + 0x20);
+	cnum = attr->d.r.len;
+	cluster = 0;
+	for (vcn = startvcn; vcn <= endvcn; vcn += len)	{
+		if (ntfs_decompress_run(&data, &len, &cluster, &ctype))
 			return -1;
-		if(ctype)
-			ntfs_insert_run(attr,cnum,-1,len);
+		if (ctype)
+			ntfs_insert_run(attr, cnum, -1, len);
 		else
-			ntfs_insert_run(attr,cnum,cluster,len);
+			ntfs_insert_run(attr, cnum, cluster, len);
 		cnum++;
 	}
 	return 0;
 }
   
-/* Insert the attribute starting at attr in the inode ino */
+/* Insert the attribute starting at attr in the inode ino. */
 int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
 {
-	int i,found;
+	int i, found;
 	int type;
 	short int *name;
 	int namelen;
@@ -415,208 +403,207 @@
 	int error;
 
 	type = NTFS_GETU32(attrdata);
-	namelen = NTFS_GETU8(attrdata+9);
-	/* read the attribute's name if it has one */
-	if(!namelen)
-		name=0;
-	else
-	{
-		/* 1 Unicode character fits in 2 bytes */
-		name=ntfs_malloc(2*namelen);
-		if( !name )
-			return ENOMEM;
-
-		ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen);
-	}
-
-	error = ntfs_new_attr(ino,type,name,namelen,&i,&found,1);
-	if( error ) {
-		if( name ) ntfs_free( name );
+	namelen = NTFS_GETU8(attrdata + 9);
+	/* Read the attribute's name if it has one. */
+	if (!namelen)
+		name = 0;
+	else {
+		/* 1 Unicode character fits in 2 bytes. */
+		name = ntfs_malloc(2 * namelen);
+		if (!name)
+			return -ENOMEM;
+		ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10),
+			    2 * namelen);
+	}
+	error = ntfs_new_attr(ino, type, name, namelen, &i, &found, 1);
+	if (error) {
+		if (name)
+			ntfs_free(name);
 		return error;
 	}
-
-	/* We can have in one inode two attributes with type 0x00000030 (File Name) 
-	   and without name */
-	if(found && /*FIXME*/type!=ino->vol->at_file_name)
+	/* We can have in one inode two attributes with type 0x00000030 (File
+	 * Name) and without name. FIXME: We can have a lot more than two!
+	 * That is how hard links are implemented. (AIA) */
+	if (found && /*FIXME*/ type != ino->vol->at_file_name)
 	{
-		ntfs_process_runs(ino,ino->attrs+i,attrdata);
+		ntfs_process_runs(ino, ino->attrs + i, attrdata);
 		return 0;
- 	} else if( found ) {
- 		/*	Don't understand the above, but I know it leaks memory below
- 			as it overwrites a found entry without freeing it. So here we
- 			call ntfs_new_attr again but this time ask it to always allocate a
- 			new	entry */
- 		ntfs_new_attr(ino,type,name,namelen,&i,&found,0);
-	}
-	attr=ino->attrs+i;
-	attr->resident=NTFS_GETU8(attrdata+8)==0;
-	attr->compressed=NTFS_GETU16(attrdata+0xC);
-	attr->attrno=NTFS_GETU16(attrdata+0xE);
+ 	} else if (found) {
+ 		/* Don't understand the above, but I know it leaks memory below
+		 * as it overwrites a found entry without freeing it. So here
+		 * we call ntfs_new_attr again but this time ask it to always
+		 * allocate a new entry. */
+ 		ntfs_new_attr(ino, type, name, namelen, &i, &found, 0);
+	}
+	attr = ino->attrs + i;
+	attr->resident = NTFS_GETU8(attrdata + 8) == 0;
+	attr->compressed = NTFS_GETU16(attrdata + 0xC);
+	attr->attrno = NTFS_GETU16(attrdata + 0xE);
   
-	if(attr->resident) {
-		attr->size=NTFS_GETU16(attrdata+0x10);
-		data=attrdata+NTFS_GETU16(attrdata+0x14);
+	if (attr->resident) {
+		attr->size = NTFS_GETU16(attrdata + 0x10);
+		data = attrdata + NTFS_GETU16(attrdata + 0x14);
 		attr->d.data = (void*)ntfs_malloc(attr->size);
-		if( !attr->d.data )
-			return ENOMEM;
-		ntfs_memcpy(attr->d.data,data,attr->size);
-		attr->indexed=NTFS_GETU16(attrdata+0x16);
-	}else{
-		attr->allocated=NTFS_GETU32(attrdata+0x28);
-		attr->size=NTFS_GETU32(attrdata+0x30);
-		attr->initialized=NTFS_GETU32(attrdata+0x38);
-		attr->cengine=NTFS_GETU16(attrdata+0x22);
-		if(attr->compressed)
-			attr->compsize=NTFS_GETU32(attrdata+0x40);
-		ino->attrs[i].d.r.runlist=0;
-		ino->attrs[i].d.r.len=0;
-		ntfs_process_runs(ino,attr,attrdata);
+		if (!attr->d.data)
+			return -ENOMEM;
+		ntfs_memcpy(attr->d.data, data, attr->size);
+		attr->indexed = NTFS_GETU16(attrdata + 0x16);
+	} else {
+		attr->allocated = NTFS_GETU32(attrdata + 0x28);
+		attr->size = NTFS_GETU32(attrdata + 0x30);
+		attr->initialized = NTFS_GETU32(attrdata + 0x38);
+		attr->cengine = NTFS_GETU16(attrdata + 0x22);
+		if (attr->compressed)
+			attr->compsize = NTFS_GETU32(attrdata + 0x40);
+		ino->attrs[i].d.r.runlist = 0;
+		ino->attrs[i].d.r.len = 0;
+		ntfs_process_runs(ino, attr, attrdata);
 	}
 	return 0;
 }
 
-int
-ntfs_read_zero(ntfs_io *dest,int size)
+int ntfs_read_zero(ntfs_io *dest, int size)
 {
-	char *sparse=ntfs_calloc(512);
-	if(!sparse)
-		return ENOMEM;
-	while(size){
-		int i=min(size,512);
-		dest->fn_put(dest,sparse,i);
-		size-=i;
+	char *sparse = ntfs_calloc(512);
+	if (!sparse)
+		return -ENOMEM;
+	while (size) {
+		int i = min(size, 512);
+		dest->fn_put(dest, sparse, i);
+		size -= i;
 	}
 	ntfs_free(sparse);
 	return 0;
 }
 
-/* process compressed attributes */
+/* Process compressed attributes. */
 int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
-	ntfs_io *dest)
+			 ntfs_io *dest)
 {
-	int error=0;
-	int clustersize,l;
-	int s_vcn,rnum,vcn,len,chunk,got,l1,offs1,copied;
-	ntfs_cluster_t cluster,cl1;
-	char *comp=0,*comp1;
-	char *decomp=0;
+	int error = 0;
+	int clustersize, l;
+	int s_vcn, rnum, vcn, len, chunk, got, l1, offs1, copied;
+	ntfs_cluster_t cluster, cl1;
+	char *comp = 0, *comp1;
+	char *decomp = 0;
 	ntfs_io io;
 	ntfs_runlist *rl;
 
-	l=dest->size;
-	clustersize=ino->vol->clustersize;
-	/* starting cluster of potential chunk
-	   there are three situations:
-	   a) in a large uncompressible or sparse chunk, 
-	   s_vcn is in the middle of a run
-	   b) s_vcn is right on a run border
-	   c) when several runs make a chunk, s_vcn is before the chunks
-	*/
-	s_vcn=offset/clustersize;
-	/* round down to multiple of 16 */
+	l = dest->size;
+	clustersize = ino->vol->clustersize;
+	/* Starting cluster of potential chunk. There are three situations:
+	   a) In a large uncompressible or sparse chunk, s_vcn is in the middle
+	      of a run.
+	   b) s_vcn is right on a run border.
+	   c) When several runs make a chunk, s_vcn is before the chunks. */
+	s_vcn = offset / clustersize;
+	/* Round down to multiple of 16. */
 	s_vcn &= ~15;
-	rl=attr->d.r.runlist;
-	for(rnum=vcn=0;rnum<attr->d.r.len && vcn+rl->len<=s_vcn;rnum++,rl++)
-		vcn+=rl->len;
-	if(rnum==attr->d.r.len){
-		/* beyond end of file */
-		/* FIXME: check allocated/initialized */
-		dest->size=0;
+	rl = attr->d.r.runlist;
+	for (rnum = vcn = 0; rnum < attr->d.r.len && vcn + rl->len <= s_vcn;
+								rnum++, rl++)
+		vcn += rl->len;
+	if (rnum == attr->d.r.len) {
+		/* Beyond end of file. */
+		/* FIXME: Check allocated / initialized. */
+		dest->size = 0;
 		return 0;
 	}
-	io.do_read=1;
-	io.fn_put=ntfs_put;
-	io.fn_get=0;
-	cluster=rl->cluster;
-	len=rl->len;
-	copied=0;
-	while(l){
-		chunk=0;
-		if(cluster==MAX_CLUSTER_T){
-			/* sparse cluster */
+	io.do_read = 1;
+	io.fn_put = ntfs_put;
+	io.fn_get = 0;
+	cluster = rl->cluster;
+	len = rl->len;
+	copied = 0;
+	while (l) {
+		chunk = 0;
+		if (cluster == MAX_CLUSTER_T) {
+			/* Sparse cluster. */
 			int l1;
-			if((len-(s_vcn-vcn)) & 15)
-				ntfs_error("unexpected sparse chunk size");
-			l1=chunk = min((vcn+len)*clustersize-offset,l);
-			error = ntfs_read_zero(dest,l1);
-			if(error)
+			if ((len - (s_vcn - vcn)) & 15)
+				ntfs_error("Unexpected sparse chunk size.");
+			l1 = chunk = min((vcn + len) * clustersize - offset, l);
+			error = ntfs_read_zero(dest, l1);
+			if (error)
 				goto out;
-		}else if(dest->do_read){
-			if(!comp){
-				comp=ntfs_malloc(16*clustersize);
-				if(!comp){
-					error=ENOMEM;
+		} else if (dest->do_read) {
+			if (!comp) {
+				comp = ntfs_malloc(16 * clustersize);
+				if (!comp) {
+					error = -ENOMEM;
 					goto out;
 				}
 			}
-			got=0;
-			/* we might need to start in the middle of a run */
-			cl1=cluster+s_vcn-vcn;
-			comp1=comp;
-			do{
-				io.param=comp1;
-				l1=min(len-max(s_vcn-vcn,0),16-got);
-				io.size=l1*clustersize;
-				error=ntfs_getput_clusters(ino->vol,cl1,0,&io);
-				if(error)goto out;
-				if(l1+max(s_vcn-vcn,0)==len){
-					rnum++;rl++;
-					vcn+=len;
-					cluster=cl1=rl->cluster;
-					len=rl->len;
+			got = 0;
+			/* We might need to start in the middle of a run. */
+			cl1 = cluster + s_vcn - vcn;
+			comp1 = comp;
+			do {
+				io.param = comp1;
+				l1 = min(len - max(s_vcn - vcn, 0), 16 - got);
+				io.size = l1 * clustersize;
+				error = ntfs_getput_clusters(ino->vol, cl1, 0,
+					       		     &io);
+				if (error)
+					goto out;
+				if (l1 + max(s_vcn - vcn, 0) == len) {
+					rnum++;
+					rl++;
+					vcn += len;
+					cluster = cl1 = rl->cluster;
+					len = rl->len;
 				}
-				got+=l1;
-				comp1+=l1*clustersize;
-			}while(cluster!=MAX_CLUSTER_T && got<16); /* until empty run */
-			chunk=16*clustersize;
-			if(cluster!=MAX_CLUSTER_T || got==16)
-				/* uncompressible */
-				comp1=comp;
-			else{
-				if(!decomp){
-					decomp=ntfs_malloc(16*clustersize);
-					if(!decomp){
-						error=ENOMEM;
+				got += l1;
+				comp1 += l1 * clustersize;
+			} while (cluster != MAX_CLUSTER_T && got < 16);
+							/* Until empty run. */
+			chunk = 16 * clustersize;
+			if (cluster != MAX_CLUSTER_T || got == 16)
+				/* Uncompressible */
+				comp1 = comp;
+			else {
+				if (!decomp) {
+					decomp = ntfs_malloc(16 * clustersize);
+					if (!decomp) {
+						error = -ENOMEM;
 						goto out;
 					}
 				}
-				/* make sure there are null bytes
-				   after the last block */
-				*(ntfs_u32*)comp1=0;
-				ntfs_decompress(decomp,comp,chunk);
-				comp1=decomp;
+				/* Make sure there are null bytes after the
+				 * last block. */
+				*(ntfs_u32*)comp1 = 0;
+				ntfs_decompress(decomp, comp, chunk);
+				comp1 = decomp;
 			}
-			offs1=offset-s_vcn*clustersize;
-			chunk=min(16*clustersize-offs1,chunk);
-			chunk=min(l,chunk);
-			dest->fn_put(dest,comp1+offs1,chunk);
+			offs1 = offset - s_vcn * clustersize;
+			chunk = min(16 * clustersize - offs1, chunk);
+			chunk = min(l, chunk);
+			dest->fn_put(dest, comp1 + offs1, chunk);
 		}
-		l-=chunk;
-		copied+=chunk;
-		offset+=chunk;
-		s_vcn=offset/clustersize & ~15;
-		if(l && offset>=((vcn+len)*clustersize)){
-			rnum++;rl++;
-			vcn+=len;
-			cluster=rl->cluster;
-			len=rl->len;
+		l -= chunk;
+		copied += chunk;
+		offset += chunk;
+		s_vcn = offset / clustersize & ~15;
+		if (l && offset >= ((vcn + len) * clustersize)) {
+			rnum++;
+			rl++;
+			vcn += len;
+			cluster = rl->cluster;
+			len = rl->len;
 		}
 	}
  out:
-	if(comp)ntfs_free(comp);
-	if(decomp)ntfs_free(decomp);
-	dest->size=copied;
+	if (comp)
+		ntfs_free(comp);
+	if (decomp)
+		ntfs_free(decomp);
+	dest->size = copied;
 	return error;
 }
 
 int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
-	ntfs_io *dest)
+			  ntfs_io *dest)
 {
-	return EOPNOTSUPP;
+	return -EOPNOTSUPP;
 }
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/attr.h linux/fs/ntfs/attr.h
--- v2.4.3/linux/fs/ntfs/attr.h	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/attr.h	Wed Apr 18 11:49:13 2001
@@ -1,24 +1,33 @@
-/*
- *  attr.h
- *  Header file for attr.c
+/*  attr.h -  Header file for attr.c
  *
  *  Copyright (C) 1997 Régis Duchesne
  */
 
 int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
-  int flags);
+		     int flags);
+
 int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize);
+
 int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata);
+
 int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
-  ntfs_io *dest);
+			 ntfs_io *dest);
+
 int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
-  ntfs_io *dest);
+			  ntfs_io *dest);
+
 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
-  int dsize, ntfs_attribute **rattr);
-int ntfs_read_zero(ntfs_io *dest,int size);
+		     int dsize, ntfs_attribute **rattr);
+
+int ntfs_read_zero(ntfs_io *dest, int size);
+
 int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr);
+
 int ntfs_attr_allnonresident(ntfs_inode *ino);
-int ntfs_new_attr( ntfs_inode *ino, int type, void *name, int namelen,
- int *pos, int *found, int do_search );
-void ntfs_insert_run( ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
- int len );
+
+int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen,
+		  int *pos, int *found, int do_search );
+
+void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
+		     int len );
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/dir.c linux/fs/ntfs/dir.c
--- v2.4.3/linux/fs/ntfs/dir.c	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/dir.c	Wed Apr 18 11:49:13 2001
@@ -1,9 +1,9 @@
-/*
- *  dir.c
+/*  dir.c
  *
  *  Copyright (C) 1995-1997, 1999 Martin von Löwis
  *  Copyright (C) 1999 Steve Dodd
  *  Copyright (C) 1999 Joseph Malicki
+ *  Copyright (C) 2001 Anton Altaparmakov (AIA)
  */
 
 #include "ntfstypes.h"
@@ -20,39 +20,44 @@
 
 static char I30[]="$I30";
 
-/* An index record should start with INDX, and the last word in each
-   block should contain the check value. If it passes, the original
-   values need to be restored */
+/* An index record should start with INDX, and the last word in each block
+ * should contain the check value. If it passes, the original values need to
+ * be restored. */
 int ntfs_check_index_record(ntfs_inode *ino, char *record)
 {
-	return ntfs_fixup_record(ino->vol, record, "INDX", 
+	return ntfs_fixup_record(ino->vol, record, "INDX",
 				 ino->u.index.recordsize);
 }
 
 static inline int ntfs_is_top(ntfs_u64 stack)
 {
-	return stack==14;
+	return stack == 14;
 }
 
 static int ntfs_pop(ntfs_u64 *stack)
 {
-	static int width[16]={1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
-	int res=-1;
-	switch(width[*stack & 15])
-	{
-	case 1:res=(int)((*stack&15)>>1);
-		*stack>>=4;
+	static int width[16] = {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
+	int res = -1;
+	
+	switch (width[*stack & 15]) {
+	case 1:
+		res = (int)((*stack & 15) >> 1);
+		*stack >>= 4;
 		break;
-	case 2:res=(int)(((*stack&63)>>2)+7);
-		*stack>>=6;
+	case 2:
+		res = (int)(((*stack & 63) >> 2) + 7);
+		*stack >>= 6;
 		break;
-	case 3:res=(int)(((*stack & 255)>>3)+23);
-		*stack>>=8;
+	case 3:
+		res = (int)(((*stack & 255) >> 3) + 23);
+		*stack >>= 8;
 		break;
-	case 4:res=(int)(((*stack & 1023)>>4)+55);
-		*stack>>=10;
+	case 4:
+		res = (int)(((*stack & 1023) >> 4) + 55);
+		*stack >>= 10;
 		break;
-	default:ntfs_error("Unknown encoding\n");
+	default:
+		ntfs_error("Unknown encoding\n");
 	}
 	return res;
 }
@@ -62,12 +67,16 @@
 	return 14;
 }
 
-static ntfs_u64 ntfs_push(ntfs_u64 stack,int i)
+static ntfs_u64 ntfs_push(ntfs_u64 stack, int i)
 {
-	if(i<7)return (stack<<4)|(i<<1);
-	if(i<23)return (stack<<6)|((i-7)<<2)|1;
-	if(i<55)return (stack<<8)|((i-23)<<3)|3;
-	if(i<120)return (stack<<10)|((i-55)<<4)|7;
+	if (i < 7)
+		return (stack << 4) | (i << 1);
+	if (i < 23)
+		return (stack << 6) | ((i - 7) << 2) | 1;
+	if (i < 55)
+		return (stack << 8) | ((i - 23) << 3) | 3;
+	if (i < 120)
+		return (stack << 10) | ((i - 55) << 4) | 7;
 	ntfs_error("Too many entries\n");
 	return ~((ntfs_u64)0);
 }
@@ -77,133 +86,136 @@
 {
 	while(!ntfs_is_top(stack))
 	{
-		printf("%d ",ntfs_pop(&stack));
+		printf("%d ", ntfs_pop(&stack));
 	}
 	printf("\n");
 }
 #endif
 
-/* True if the entry points to another block of entries */
+/* True if the entry points to another block of entries. */
 static inline int ntfs_entry_has_subnodes(char* entry)
 {
-	return (int)NTFS_GETU8(entry+12)&1;
+	return (int)NTFS_GETU8(entry + 12) & 1;
 }
 
-/* True if it is not the 'end of dir' entry */
+/* True if it is not the 'end of dir' entry. */
 static inline int ntfs_entry_is_used(char* entry)
 {
-	return (int)(NTFS_GETU8(entry+12)&2)==0;
+	return (int)(NTFS_GETU8(entry + 12) & 2) == 0;
 }
 
 static int ntfs_allocate_index_block(ntfs_iterate_s *walk)
 {
-	ntfs_attribute *allocation=0,*bitmap=0;
-	int error,size,i,bit;
+	ntfs_attribute *allocation = 0, *bitmap = 0;
+	int error, size, i, bit;
 	ntfs_u8 *bmap;
 	ntfs_io io;
-	ntfs_volume *vol=walk->dir->vol;
+	ntfs_volume *vol = walk->dir->vol;
 
-	/* check for allocation attribute */
-	allocation=ntfs_find_attr(walk->dir,vol->at_index_allocation,I30);
-	if(!allocation){
+	/* Check for allocation attribute. */
+	allocation = ntfs_find_attr(walk->dir, vol->at_index_allocation, I30);
+	if (!allocation) {
 		ntfs_u8 bmp[8];
-		/* create index allocation attribute */
-		error=ntfs_create_attr(walk->dir,vol->at_index_allocation,I30,
-				       0,0,&allocation);
-		if(error)return error;
-		ntfs_bzero(bmp,sizeof(bmp));
-		error=ntfs_create_attr(walk->dir,vol->at_bitmap,I30,
-				       bmp,sizeof(bmp),&bitmap);
-		if(error)return error;
-	}else
-		bitmap=ntfs_find_attr(walk->dir,vol->at_bitmap,I30);
-	if(!bitmap){
+		/* Create index allocation attribute. */
+		error = ntfs_create_attr(walk->dir, vol->at_index_allocation,
+					 I30, 0, 0, &allocation);
+		if (error)
+			return error;
+		ntfs_bzero(bmp, sizeof(bmp));
+		error = ntfs_create_attr(walk->dir, vol->at_bitmap, I30, bmp,
+					 sizeof(bmp), &bitmap);
+		if (error)
+			return error;
+	} else
+		bitmap = ntfs_find_attr(walk->dir, vol->at_bitmap, I30);
+	if (!bitmap) {
 		ntfs_error("Directory w/o bitmap\n");
-		return EINVAL;
+		return -EINVAL;
 	}
-	size=bitmap->size;
-	bmap=ntfs_malloc(size);
-	if(!bmap)return ENOMEM;
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.param=bmap;
-	io.size=size;
-	error=ntfs_read_attr(walk->dir,vol->at_bitmap,I30,0,&io);
-	if(error){
+	size = bitmap->size;
+	bmap = ntfs_malloc(size);
+	if (!bmap)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.param = bmap;
+	io.size = size;
+	error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, 0, &io);
+	if (error) {
 		ntfs_free(bmap);
 		return error;
 	}
-	if(io.size!=size){
+	if (io.size != size) {
 		ntfs_free(bmap);
-		return EIO;
+		return -EIO;
 	}
-	
-	/* allocate a bit */
-	for(i=bit=0;i<size;i++){
-		if(bmap[i]==0xFF)continue;
-		for(bit=0;bit<8;bit++)
-			if(((bmap[i]>>bit) & 1) == 0)
+	/* Allocate a bit. */
+	for (i = bit = 0; i < size; i++) {
+		if (bmap[i] == 0xFF)
+			continue;
+		for (bit = 0; bit < 8; bit++)
+			if (((bmap[i] >> bit) & 1) == 0)
 				break;
-		if(bit!=8)break;
+		if (bit != 8)
+			break;
 	}
-	if(i==size)
-		/* FIXME: extend bitmap */
-		return EOPNOTSUPP;
-	walk->newblock=(i*8+bit)*walk->dir->u.index.clusters_per_record;
-	bmap[i]|= 1<<bit;
-	io.param=bmap;
-	io.size=size;
-	error=ntfs_write_attr(walk->dir,vol->at_bitmap,I30,0,&io);
-	if(error || io.size!=size){
+	if (i == size)
+		/* FIXME: Extend bitmap. */
+		return -EOPNOTSUPP;
+	walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record;
+	bmap[i] |= 1 << bit;
+	io.param = bmap;
+	io.size = size;
+	error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, 0, &io);
+	if (error || io.size != size) {
 		ntfs_free(bmap);
-		return error?error:EIO;
+		return error ? error : -EIO;
 	}
 	ntfs_free(bmap);
-
-	/* check whether record is out of allocated range */
-	size=allocation->size;
-	if(walk->newblock * vol->clustersize >= size){
-		/* build index record */
-		int s1=walk->dir->u.index.recordsize;
-		int nr_fix = s1/vol->blocksize+1;
+	/* Check whether record is out of allocated range. */
+	size = allocation->size;
+	if (walk->newblock * vol->clustersize >= size) {
+		/* Build index record. */
+		int s1 = walk->dir->u.index.recordsize;
+		int nr_fix = s1/vol->blocksize + 1;
 		int hsize;
-		char *record=ntfs_malloc(s1);
-		if( !record )
-			return ENOMEM;
-		ntfs_bzero(record,s1);
-		/* magic */
-		ntfs_memcpy(record,"INDX",4);
-		/* offset to fixups */
-		NTFS_PUTU16(record+4,0x28);
-		/* number of fixups */
-		NTFS_PUTU16(record+6,nr_fix);
-		/* FIXME: log file number */
+		char *record = ntfs_malloc(s1);
+		if (!record)
+			return -ENOMEM;
+		ntfs_bzero(record, s1);
+		/* Magic */
+		ntfs_memcpy(record, "INDX", 4);
+		/* Offset to fixups */
+		NTFS_PUTU16(record + 4, 0x28);
+		/* Number of fixups. */
+		NTFS_PUTU16(record + 6, nr_fix);
+		/* Log file sequence number - We don't do journalling so we
+		 * just set it to zero which should be the Right Thing. (AIA) */
+		NTFS_PUTU64(record + 8, 0);
 		/* VCN of buffer */
-		NTFS_PUTU64(record+0x10,walk->newblock);
-		/* header size. */
-		hsize = 0x10+2*nr_fix;
-		hsize = (hsize+7) & ~7; /* Align. */
-		NTFS_PUTU16(record+0x18, hsize);
-		/* total size of record */
-		NTFS_PUTU32(record+0x20,s1-0x18);
+		NTFS_PUTU64(record + 0x10, walk->newblock);
+		/* Header size. */
+		hsize = 0x10 + 2 * nr_fix;
+		hsize = (hsize + 7) & ~7; /* Align. */
+		NTFS_PUTU16(record + 0x18, hsize);
+		/* Total size of record. */
+		NTFS_PUTU32(record + 0x20, s1 - 0x18);
 		/* Writing the data will extend the attribute. */
-		io.param=record;
-		io.size=s1;
-		io.do_read=0;
-		error=ntfs_readwrite_attr(walk->dir, allocation, size, &io);
-		if(error || io.size!=s1){
+		io.param = record;
+		io.size = s1;
+		io.do_read = 0;
+		error = ntfs_readwrite_attr(walk->dir, allocation, size, &io);
+		if (error || io.size != s1) {
 			ntfs_free(record);
-			return error?error:EIO;
+			return error ? error : -EIO;
 		}
 		ntfs_free(record);
 	}
-
 	return 0;
 }
 
 /* Write an index block (root or allocation) back to storage.
-   used is the total number of bytes in buf, including all headers. */
-
+ * Used is the total number of bytes in buf, including all headers. */
 static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block,
 				int used)
 {
@@ -212,231 +224,235 @@
 	ntfs_attribute *a;
 	ntfs_volume *vol = walk->dir->vol;
 	
-	io.fn_put=0;
-	io.fn_get=ntfs_get;
-	io.param=buf;
-	if(block==-1){
-		NTFS_PUTU16(buf+0x14,used-0x10);
-		/* 0x18 is a copy thereof */
-		NTFS_PUTU16(buf+0x18,used-0x10);
-		io.size=used;
-		error=ntfs_write_attr(walk->dir,vol->at_index_root,
-				      I30,0,&io);
-		if(error)return error;
-		if(io.size!=used)return EIO;
-		/* shrink if necessary */
+	io.fn_put = 0;
+	io.fn_get = ntfs_get;
+	io.param = buf;
+	if (block == -1) {
+		NTFS_PUTU16(buf + 0x14, used - 0x10);
+		/* 0x18 is a copy thereof. */
+		NTFS_PUTU16(buf + 0x18, used - 0x10);
+		io.size = used;
+		error = ntfs_write_attr(walk->dir, vol->at_index_root, I30, 0,
+					&io);
+		if (error)
+			return error;
+		if (io.size != used)
+			return -EIO;
+		/* Shrink if necessary. */
 		a = ntfs_find_attr(walk->dir, vol->at_index_root, I30);
 		ntfs_resize_attr(walk->dir, a, used);
-	}else{
-		NTFS_PUTU16(buf+0x1C,used-0x18);
-		ntfs_insert_fixups(buf,vol->blocksize);
-		io.size=walk->dir->u.index.recordsize;
-		error=ntfs_write_attr(walk->dir,vol->at_index_allocation,I30,
-				      block*vol->clustersize,
-				      &io);
-		if(error)return error;
-		if(io.size!=walk->dir->u.index.recordsize)
-			return EIO;
+	} else {
+		NTFS_PUTU16(buf + 0x1C, used - 0x18);
+		ntfs_insert_fixups(buf, vol->blocksize);
+		io.size = walk->dir->u.index.recordsize;
+		error = ntfs_write_attr(walk->dir, vol->at_index_allocation,
+					I30, block*vol->clustersize, &io);
+		if (error)
+			return error;
+		if (io.size != walk->dir->u.index.recordsize)
+			return -EIO;
 	}
 	return 0;
 }
 
 static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize,
-	int usize)
+			     int usize)
 {
-	char *entry,*prev;
-	ntfs_u8 *newbuf=0,*middle=0;
-	int error,othersize,mlen;
+	char *entry, *prev;
+	ntfs_u8 *newbuf = 0, *middle = 0;
+	int error, othersize, mlen;
 	ntfs_io io;
-	ntfs_volume *vol=walk->dir->vol;
+	ntfs_volume *vol = walk->dir->vol;
 	int oldblock;
 
-	error=ntfs_allocate_index_block(walk);
-	if(error)
+	error = ntfs_allocate_index_block(walk);
+	if (error)
 		return error;
-	/* This should not happen */
-	if(walk->block == -1){
+	/* This should not happen. */
+	if (walk->block == -1) {
 		ntfs_error("Trying to split root");
-		return EOPNOTSUPP;
+		return -EOPNOTSUPP;
 	}
-	entry = start+NTFS_GETU16(start+0x18)+0x18; 
-	for(prev=entry; entry-start<usize/2; entry += NTFS_GETU16(entry+8))
-		prev=entry;
-
-	newbuf=ntfs_malloc(vol->index_recordsize);
-	if(!newbuf)
-		return ENOMEM;
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.param=newbuf;
-	io.size=vol->index_recordsize;
-	/* read in old header. FIXME: reading everything is overkill */
-	error=ntfs_read_attr(walk->dir,vol->at_index_allocation,I30,
-			     walk->newblock*vol->clustersize,&io);
-	if(error)goto out;
-	if(io.size!=vol->index_recordsize){
-		error=EIO;
-		goto out;
-	}
-	/* FIXME: adjust header */
-	/* copy everything from entry to new block */
-	othersize=usize-(entry-start);
-	ntfs_memcpy(newbuf+NTFS_GETU16(newbuf+0x18)+0x18,entry,othersize);
+	entry = start + NTFS_GETU16(start + 0x18) + 0x18; 
+	for (prev = entry; entry - start < usize / 2; 
+					       entry += NTFS_GETU16(entry + 8))
+		prev = entry;
+	newbuf = ntfs_malloc(vol->index_recordsize);
+	if (!newbuf)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.param = newbuf;
+	io.size = vol->index_recordsize;
+	/* Read in old header. FIXME: Reading everything is overkill. */
+	error = ntfs_read_attr(walk->dir, vol->at_index_allocation, I30,
+			       walk->newblock * vol->clustersize, &io);
+	if (error)
+		goto out;
+	if (io.size != vol->index_recordsize) {
+		error = -EIO;
+		goto out;
+	}
+	/* FIXME: Adjust header. */
+	/* Copy everything from entry to new block. */
+	othersize = usize - (entry - start);
+	ntfs_memcpy(newbuf + NTFS_GETU16(newbuf + 0x18) + 0x18, entry,
+								    othersize);
 	/* Copy flags. */
-	NTFS_PUTU32(newbuf+0x24, NTFS_GETU32(start+0x24));
-	error=ntfs_index_writeback(walk,newbuf,walk->newblock,
-				   othersize+NTFS_GETU16(newbuf+0x18)+0x18);
-	if(error)goto out;
-
-	/* move prev to walk */
-	mlen=NTFS_GETU16(prev+0x8);
+	NTFS_PUTU32(newbuf + 0x24, NTFS_GETU32(start + 0x24));
+	error = ntfs_index_writeback(walk, newbuf, walk->newblock,
+				othersize + NTFS_GETU16(newbuf + 0x18) + 0x18);
+	if (error)
+		goto out;
+	/* Move prev to walk. */
+	mlen = NTFS_GETU16(prev + 0x8);
 	/* Remember old child node. */
-	if(ntfs_entry_has_subnodes(prev))
-		oldblock = NTFS_GETU32(prev+mlen-8);
+	if (ntfs_entry_has_subnodes(prev))
+		oldblock = NTFS_GETU32(prev + mlen - 8);
 	else
 		oldblock = -1;
-	/* allow for pointer to subnode */
-	middle=ntfs_malloc(ntfs_entry_has_subnodes(prev)?mlen:mlen+8);
-	if(!middle){
-		error=ENOMEM;
+	/* Allow for pointer to subnode. */
+	middle = ntfs_malloc(ntfs_entry_has_subnodes(prev) ? mlen : mlen + 8);
+	if (!middle){
+		error = -ENOMEM;
 		goto out;
 	}
-	ntfs_memcpy(middle,prev,mlen);
-	/* set has_subnodes flag */
-	NTFS_PUTU8(middle+0xC, NTFS_GETU8(middle+0xC) | 1);
-	/* middle entry points to block, parent entry will point to newblock */
-	NTFS_PUTU64(middle+mlen-8,walk->block);
-	if(walk->new_entry)
-		ntfs_error("entry not reset");
-	walk->new_entry=middle;
-	walk->u.flags|=ITERATE_SPLIT_DONE;
+	ntfs_memcpy(middle, prev, mlen);
+	/* Set has_subnodes flag. */
+	NTFS_PUTU8(middle + 0xC, NTFS_GETU8(middle + 0xC) | 1);
+	/* Middle entry points to block, parent entry will point to newblock. */
+	NTFS_PUTU64(middle + mlen - 8, walk->block);
+	if (walk->new_entry)
+		ntfs_error("Entry not reset");
+	walk->new_entry = middle;
+	walk->u.flags |= ITERATE_SPLIT_DONE;
 	/* Terminate old block. */
-	othersize = usize-(prev-start);
+	othersize = usize - (prev-start);
 	NTFS_PUTU64(prev, 0);
-	if(oldblock==-1){
-		NTFS_PUTU32(prev+8, 0x10);
-		NTFS_PUTU32(prev+0xC, 2);
+	if (oldblock == -1) {
+		NTFS_PUTU32(prev + 8, 0x10);
+		NTFS_PUTU32(prev + 0xC, 2);
 		othersize += 0x10;
-	}else{
-		NTFS_PUTU32(prev+8, 0x18);
-		NTFS_PUTU32(prev+0xC, 3);
-		NTFS_PUTU64(prev+0x10, oldblock);
+	} else {
+		NTFS_PUTU32(prev + 8, 0x18);
+		NTFS_PUTU32(prev + 0xC, 3);
+		NTFS_PUTU64(prev + 0x10, oldblock);
 		othersize += 0x18;
 	}
-	/* write back original block */
-	error=ntfs_index_writeback(walk,start,walk->block,othersize);
+	/* Write back original block. */
+	error = ntfs_index_writeback(walk, start, walk->block, othersize);
  out:
-	if(newbuf)ntfs_free(newbuf);
-	if(middle)ntfs_free(middle);
+	if (newbuf)
+		ntfs_free(newbuf);
+	if (middle)
+		ntfs_free(middle);
 	return error;
 }
 
 static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
 {
-	int blocksize,usedsize,error,offset;
-	int do_split=0;
-	offset=entry-start;
-	if(walk->block==-1){ /*index root */
-		blocksize=walk->dir->vol->mft_recordsize;
-		usedsize=NTFS_GETU16(start+0x14)+0x10;
-	}else{
-		blocksize=walk->dir->u.index.recordsize;
-		usedsize=NTFS_GETU16(start+0x1C)+0x18;
-	}
-	if(usedsize+walk->new_entry_size > blocksize){
-		char* s1=ntfs_malloc(blocksize+walk->new_entry_size);
-		if(!s1)return ENOMEM;
-		ntfs_memcpy(s1,start,usedsize);
-		do_split=1;
-		/* adjust entry to s1 */
-		entry=s1+(entry-start);
-		start=s1;
-	}
-	ntfs_memmove(entry+walk->new_entry_size,entry,usedsize-offset);
-	ntfs_memcpy(entry,walk->new_entry,walk->new_entry_size);
-	usedsize+=walk->new_entry_size;
+	int blocksize, usedsize, error, offset;
+	int do_split = 0;
+	offset = entry - start;
+	if (walk->block == -1) { /* index root */
+		blocksize = walk->dir->vol->mft_recordsize;
+		usedsize = NTFS_GETU16(start + 0x14) + 0x10;
+	} else {
+		blocksize = walk->dir->u.index.recordsize;
+		usedsize = NTFS_GETU16(start + 0x1C) + 0x18;
+	}
+	if (usedsize + walk->new_entry_size > blocksize) {
+		char* s1 = ntfs_malloc(blocksize + walk->new_entry_size);
+		if (!s1)
+			return -ENOMEM;
+		ntfs_memcpy(s1, start, usedsize);
+		do_split = 1;
+		/* Adjust entry to s1. */
+		entry = s1 + (entry - start);
+		start = s1;
+	}
+	ntfs_memmove(entry + walk->new_entry_size, entry, usedsize - offset);
+	ntfs_memcpy(entry, walk->new_entry, walk->new_entry_size);
+	usedsize += walk->new_entry_size;
 	ntfs_free(walk->new_entry);
-	walk->new_entry=0;
-	if(do_split){
-		error=ntfs_split_record(walk,start,blocksize,usedsize);
+	walk->new_entry = 0;
+	if (do_split) {
+		error = ntfs_split_record(walk, start, blocksize, usedsize);
 		ntfs_free(start);
-	}else{
-		error=ntfs_index_writeback(walk,start,walk->block,usedsize);
-		if(error)return error;
+	} else {
+		error = ntfs_index_writeback(walk, start, walk->block,usedsize);
+		if (error)
+			return error;
 	}
 	return 0;
 }
 
-/* Try to split INDEX_ROOT attributes. Return E2BIG if nothing changed. */
-
-int
-ntfs_split_indexroot(ntfs_inode *ino)
+/* Try to split INDEX_ROOT attributes. Return -E2BIG if nothing changed. */
+int ntfs_split_indexroot(ntfs_inode *ino)
 {
 	ntfs_attribute *ra;
-	ntfs_u8 *root=0, *index=0;
+	ntfs_u8 *root = 0, *index = 0;
 	ntfs_io io;
 	int error, off, i, bsize, isize;
 	ntfs_iterate_s walk;
 
 	ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30);
-	if(!ra)
-		return E2BIG;
+	if (!ra)
+		return -E2BIG;
 	bsize = ino->vol->mft_recordsize;
 	root = ntfs_malloc(bsize);
-	if(!root)
-		return E2BIG;
+	if (!root)
+		return -E2BIG;
 	io.fn_put = ntfs_put;
 	io.param = root;
 	io.size = bsize;
 	error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io);
-	if(error)
+	if (error)
 		goto out;
 	off = 0x20;
 	/* Count number of entries. */
-	for(i = 0; ntfs_entry_is_used(root+off); i++)
-		off += NTFS_GETU16(root+off+8);
-	if(i<=2){
+	for (i = 0; ntfs_entry_is_used(root + off); i++)
+		off += NTFS_GETU16(root + off + 8);
+	if (i <= 2) {
 		/* We don't split small index roots. */
-		error = E2BIG;
+		error = -E2BIG;
 		goto out;
 	}
 	index = ntfs_malloc(ino->vol->index_recordsize);
-	if(!index) {
-		error = ENOMEM; goto out;
+	if (!index) {
+		error = -ENOMEM;
+		goto out;
 	}
 	walk.dir = ino;
 	walk.block = -1;
 	walk.result = walk.new_entry = 0;
 	walk.name = 0;
 	error = ntfs_allocate_index_block(&walk);
-	if(error)
+	if (error)
 		goto out;
-
 	/* Write old root to new index block. */
 	io.param = index;
 	io.size = ino->vol->index_recordsize;
 	error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30,
-			       walk.newblock*ino->vol->clustersize, &io);
-	if(error)
+			       walk.newblock * ino->vol->clustersize, &io);
+	if (error)
 		goto out;
-	isize = NTFS_GETU16(root+0x18) - 0x10;
-	ntfs_memcpy(index+NTFS_GETU16(index+0x18)+0x18, root+0x20, isize);
+	isize = NTFS_GETU16(root + 0x18) - 0x10;
+	ntfs_memcpy(index + NTFS_GETU16(index + 0x18) + 0x18, root+0x20, isize);
 	/* Copy flags. */
-	NTFS_PUTU32(index+0x24, NTFS_GETU32(root+0x1C));
-
+	NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C));
 	error = ntfs_index_writeback(&walk, index, walk.newblock, 
-				     isize+NTFS_GETU16(index+0x18)+0x18);
+				     isize + NTFS_GETU16(index + 0x18) + 0x18);
 	if(error)
 		goto out;
-
 	/* Mark root as split. */
-	NTFS_PUTU32(root+0x1C, 1);
+	NTFS_PUTU32(root + 0x1C, 1);
 	/* Truncate index root. */
-	NTFS_PUTU64(root+0x20, 0);
-	NTFS_PUTU32(root+0x28, 0x18);
-	NTFS_PUTU32(root+0x2C, 3);
-	NTFS_PUTU64(root+0x30, walk.newblock);
-	error = ntfs_index_writeback(&walk,root,-1,0x38);
+	NTFS_PUTU64(root + 0x20, 0);
+	NTFS_PUTU32(root + 0x28, 0x18);
+	NTFS_PUTU32(root + 0x2C, 3);
+	NTFS_PUTU64(root + 0x30, walk.newblock);
+	error = ntfs_index_writeback(&walk, root, -1, 0x38);
  out:
 	ntfs_free(root);
 	ntfs_free(index);
@@ -451,422 +467,428 @@
 	return 1;
 }
 
-/* use $UpCase some day */
+/* Use $UpCase some day. */
 static inline unsigned short ntfs_my_toupper(ntfs_volume *vol, ntfs_u16 x)
 {
-	/* we should read any pending rest of $UpCase here */
-	if(x >= vol->upcase_length)
+	/* We should read any pending rest of $UpCase here. */
+	if (x >= vol->upcase_length)
 		return x;
 	return vol->upcase[x];
 }
 
-/* everything passed in walk and entry */
+/* Everything passed in walk and entry. */
 static int ntfs_my_strcmp(ntfs_iterate_s *walk, const unsigned char *entry)
 {
-	int lu=*(entry+0x50);
+	int lu = *(entry + 0x50);
 	int i;
 
-	ntfs_u16* name=(ntfs_u16*)(entry+0x52);
-	ntfs_volume *vol=walk->dir->vol;
-	for(i=0;i<lu && i<walk->namelen;i++)
-		if(ntfs_my_toupper(vol,NTFS_GETU16(name+i))!=ntfs_my_toupper(vol,NTFS_GETU16(walk->name+i)))
+	ntfs_u16* name = (ntfs_u16*)(entry + 0x52);
+	ntfs_volume *vol = walk->dir->vol;
+	for (i = 0; i < lu && i < walk->namelen; i++)
+		if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) != 
+			     ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i)))
 			break;
-	if(i==lu && i==walk->namelen)return 0;
-	if(i==lu)return 1;
-	if(i==walk->namelen)return -1;
-	if(ntfs_my_toupper(vol,NTFS_GETU16(name+i))<ntfs_my_toupper(vol,NTFS_GETU16(walk->name+i)))return 1;
+	if (i == lu && i == walk->namelen)
+		return 0;
+	if (i == lu)
+		return 1;
+	if (i == walk->namelen)
+		return -1;
+	if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) < 
+			    ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i)))
+		return 1;
 	return -1;
 }
 
-/* Necessary forward declaration */
+/* Necessary forward declaration. */
 static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry);
 
-/* Parse a block of entries. Load the block, fix it up, and iterate
-   over the entries. The block is given as virtual cluster number */
+/* Parse a block of entries. Load the block, fix it up, and iterate over the
+ * entries. The block is given as virtual cluster number. */
 static int ntfs_getdir_record(ntfs_iterate_s *walk, int block)
 {
-	int length=walk->dir->u.index.recordsize;
-	char *record=(char*)ntfs_malloc(length);
+	int length = walk->dir->u.index.recordsize;
+	char *record = (char*)ntfs_malloc(length);
 	char *offset;
 	int retval,error;
 	int oldblock;
 	ntfs_io io;
 
-	if( !record )
-		return ENOMEM;
-
-	io.fn_put=ntfs_put;
-	io.param=record;
-	io.size=length;
-	/* Read the block from the index allocation attribute */
-	error=ntfs_read_attr(walk->dir,walk->dir->vol->at_index_allocation,I30,
-			     block*walk->dir->vol->clustersize,&io);
-	if(error || io.size!=length){
+	if (!record)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.param = record;
+	io.size = length;
+	/* Read the block from the index allocation attribute. */
+	error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_allocation,
+			       I30, block * walk->dir->vol->clustersize, &io);
+	if (error || io.size != length) {
 		ntfs_error("read failed\n");
 		ntfs_free(record);
 		return 0;
 	}
-	if(!ntfs_check_index_record(walk->dir,record)){
-		ntfs_error("%x is not an index record\n",block);
+	if (!ntfs_check_index_record(walk->dir, record)) {
+		ntfs_error("%x is not an index record\n", block);
 		ntfs_free(record);
 		return 0;
 	}
-	offset=record+NTFS_GETU16(record+0x18)+0x18;
-	oldblock=walk->block;
-	walk->block=block;
-	retval=ntfs_getdir_iterate(walk,record,offset);
-	walk->block=oldblock;
+	offset = record + NTFS_GETU16(record + 0x18) + 0x18;
+	oldblock = walk->block;
+	walk->block = block;
+	retval = ntfs_getdir_iterate(walk, record, offset);
+	walk->block = oldblock;
 	ntfs_free(record);
 	return retval;
 }
 
-/* go down to the next block of entries. These collate before
-   the current entry */
+/* Go down to the next block of entries. These collate before the current
+ * entry. */
 static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry)
 {
-	int length=NTFS_GETU16(entry+8);
+	int length = NTFS_GETU16(entry + 8);
 	int nextblock=NTFS_GETU32(entry+length-8);
 	int error;
 
-	if(!ntfs_entry_has_subnodes(entry)) {
+	if (!ntfs_entry_has_subnodes(entry)) {
 		ntfs_error("illegal ntfs_descend call\n");
 		return 0;
 	}
-	error=ntfs_getdir_record(walk,nextblock);
-	if(!error && walk->type==DIR_INSERT && 
-	   (walk->u.flags & ITERATE_SPLIT_DONE)){
+	error = ntfs_getdir_record(walk, nextblock);
+	if (!error && walk->type == DIR_INSERT && 
+	    (walk->u.flags & ITERATE_SPLIT_DONE)) {
 		/* Split has occurred. Adjust entry, insert new_entry. */
-		NTFS_PUTU32(entry+length-8,walk->newblock);
+		NTFS_PUTU32(entry + length - 8, walk->newblock);
 		/* Reset flags, as the current block might be split again. */
 		walk->u.flags &= ~ITERATE_SPLIT_DONE;
-		error=ntfs_dir_insert(walk,start,entry);
+		error = ntfs_dir_insert(walk, start, entry);
 	}
 	return error;
 }
 
-static int 
-ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk,char* start,char *entry)
+static int ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk, char* start,
+					  char *entry)
 {
-	int retval=0;
-	int curpos=0,destpos=0;
+	int retval = 0;
+	int curpos = 0, destpos = 0;
 	int length;
-	if(walk->u.pos!=0){
-		if(ntfs_is_top(walk->u.pos))return 0;
-		destpos=ntfs_pop(&walk->u.pos);
-	}
-	while(1){
-		if(walk->u.pos==0)
-		{
-			if(ntfs_entry_has_subnodes(entry))
-				ntfs_descend(walk,start,entry);
+	if (walk->u.pos != 0) {
+		if (ntfs_is_top(walk->u.pos))
+			return 0;
+		destpos = ntfs_pop(&walk->u.pos);
+	}
+	while (1) {
+		if (walk->u.pos == 0) {
+			if (ntfs_entry_has_subnodes(entry))
+				ntfs_descend(walk, start, entry);
 			else
-				walk->u.pos=ntfs_top();
-			if(ntfs_is_top(walk->u.pos) && !ntfs_entry_is_used(entry))
-			{
+				walk->u.pos = ntfs_top();
+			if (ntfs_is_top(walk->u.pos) && 
+			    !ntfs_entry_is_used(entry))
 				return 1;
-			}
-			walk->u.pos=ntfs_push(walk->u.pos,curpos);
+			walk->u.pos = ntfs_push(walk->u.pos, curpos);
 			return 1;
 		}
-		if(curpos==destpos)
-		{
-			if(!ntfs_is_top(walk->u.pos) && ntfs_entry_has_subnodes(entry))
-			{
-				retval=ntfs_descend(walk,start,entry);
-				if(retval){
-					walk->u.pos=ntfs_push(walk->u.pos,curpos);
+		if (curpos == destpos) {
+			if (!ntfs_is_top(walk->u.pos) && 
+			    ntfs_entry_has_subnodes(entry)) {
+				retval = ntfs_descend(walk, start, entry);
+				if (retval) {
+					walk->u.pos = ntfs_push(walk->u.pos,
+								curpos);
 					return retval;
-				}else{
-					if(!ntfs_entry_is_used(entry))
-						return 0;
-					walk->u.pos=0;
 				}
+				if (!ntfs_entry_is_used(entry))
+					return 0;
+				walk->u.pos = 0;
 			}
-			if(ntfs_entry_is_used(entry))
-			{
-				retval=ntfs_copyresult(walk->result,entry);
-				walk->u.pos=0;
-			}else{
-				walk->u.pos=ntfs_top();
+			if (ntfs_entry_is_used(entry)) {
+				retval = ntfs_copyresult(walk->result, entry);
+				walk->u.pos = 0;
+			} else {
+				walk->u.pos = ntfs_top();
 				return 0;
 			}
 		}
 		curpos++;
-		if(!ntfs_entry_is_used(entry))break;
-		length=NTFS_GETU16(entry+8);
-		if(!length){
+		if (!ntfs_entry_is_used(entry))
+			break;
+		length = NTFS_GETU16(entry + 8);
+		if (!length) {
 			ntfs_error("infinite loop\n");
 			break;
 		}
-		entry+=length;
+		entry += length;
 	}
 	return -1;
 }
 	
-/* Iterate over a list of entries, either from an index block, or from
-   the index root. 
-   If searching BY_POSITION, pop the top index from the position. If the
-   position stack is empty then, return the item at the index and set the
-   position to the next entry. If the position stack is not empty, 
-   recursively proceed for subnodes. If the entry at the position is the
-   'end of dir' entry, return 'not found' and the empty stack.
-   If searching BY_NAME, walk through the items until found or until
-   one item is collated after the requested item. In the former case, return
-   the result. In the latter case, recursively proceed to the subnodes.
-   If 'end of dir' is reached, the name is not in the directory */
+/* Iterate over a list of entries, either from an index block, or from the
+ * index root.
+ * If searching BY_POSITION, pop the top index from the position. If the
+ * position stack is empty then, return the item at the index and set the
+ * position to the next entry. If the position stack is not empty, 
+ * recursively proceed for subnodes. If the entry at the position is the
+ * 'end of dir' entry, return 'not found' and the empty stack.
+ * If searching BY_NAME, walk through the items until found or until
+ * one item is collated after the requested item. In the former case, return
+ * the result. In the latter case, recursively proceed to the subnodes.
+ * If 'end of dir' is reached, the name is not in the directory */
 static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry)
 {
 	int length;
 	int cmp;
 
-	if(walk->type==BY_POSITION)
-		return ntfs_getdir_iterate_byposition(walk,start,entry);
-	do{
-		/* if the current entry is a real one, compare with the
-		   requested item. If the current entry is the last item,
-		   it is always larger than the requested item */
-		cmp = ntfs_entry_is_used(entry) ? ntfs_my_strcmp(walk,entry) : -1;
-		switch(walk->type){
+	if (walk->type == BY_POSITION)
+		return ntfs_getdir_iterate_byposition(walk, start, entry);
+	do {
+		/* If the current entry is a real one, compare with the
+		 * requested item. If the current entry is the last item, it
+		 * is always larger than the requested item. */
+		cmp = ntfs_entry_is_used(entry) ? 
+						ntfs_my_strcmp(walk,entry) : -1;
+		switch (walk->type) {
 		case BY_NAME:
-			switch(cmp)
-			{
-			case -1:return ntfs_entry_has_subnodes(entry)?
-				       ntfs_descend(walk,start,entry):0;
-			case  0:return ntfs_copyresult(walk->result,entry);
-			case  1:break;
+			switch (cmp) {
+				case -1:
+					return ntfs_entry_has_subnodes(entry) ?
+					       ntfs_descend(walk,start,entry) :
+					       0;
+				case  0:
+					return ntfs_copyresult(walk->result,
+							       entry);
+				case  1:
+					break;
 			}
 			break;
 		case DIR_INSERT:
-			switch(cmp){
-			case -1:return ntfs_entry_has_subnodes(entry)?
-				       ntfs_descend(walk,start,entry):
-					       ntfs_dir_insert(walk,start,entry);
-			case  0:return EEXIST;
-			case  1:break;
+			switch (cmp) {
+			case -1:
+				return ntfs_entry_has_subnodes(entry) ?
+					   ntfs_descend(walk, start, entry) :
+					   ntfs_dir_insert(walk, start, entry);
+			case  0:
+				return -EEXIST;
+			case  1:
+				break;
 			}
 			break;
 		default:
-			ntfs_error("TODO\n");
+			ntfs_error("TODO\n"); /* FIXME: ? */
 		}
-		if(!ntfs_entry_is_used(entry))break;
-		length=NTFS_GETU16(entry+8);
-		if(!length){
+		if (!ntfs_entry_is_used(entry))
+			break;
+		length = NTFS_GETU16(entry + 8);
+		if (!length) {
 			ntfs_error("infinite loop\n");
 			break;
 		}
-		entry+=length;
-	}while(1);
+		entry += length;
+	} while (1);
 	return 0;
 }
 
-/*	Tree walking is done using position numbers. The following numbers have
-    a special meaning:
-        0    start (.)
-        -1   no more entries
-        -2   ..
-    All other numbers encode sequences of indices. The sequence a,b,c is 
-    encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The
-    first few integers are encoded as follows:
-        0:    0000    1:    0010    2:    0100    3:    0110
-        4:    1000    5:    1010    6:    1100 stop:    1110
-        7:  000001    8:  000101	9:  001001   10:  001101
-    The least significant bits give the width of this encoding, the
-    other bits encode the value, starting from the first value of the 
-    interval.
-     tag     width  first value  last value
-     0       3      0            6
-     01      4      7            22
-     011     5      23           54
-     0111    6      55           119
-     More values are hopefully not needed, as the file position has currently
-     64 bits in total.
-*/
+/*  Tree walking is done using position numbers. The following numbers have a
+ *  special meaning:
+ *       0   start (.)
+ *      -1   no more entries
+ *      -2   ..
+ *  All other numbers encode sequences of indices. The sequence a, b, c is 
+ *  encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The
+ *  first few integers are encoded as follows:
+ *      0:    0000    1:    0010    2:    0100    3:    0110
+ *      4:    1000    5:    1010    6:    1100 stop:    1110
+ *      7:  000001    8:  000101    9:  001001   10:  001101
+ *  The least significant bits give the width of this encoding, the other bits
+ *  encode the value, starting from the first value of the interval.
+ *   tag     width  first value  last value
+ *   0       3      0            6
+ *   01      4      7            22
+ *   011     5      23           54
+ *   0111    6      55           119
+ *   More values are hopefully not needed, as the file position has currently
+ *   64 bits in total. */
 
-/* Find an entry in the directory. Return 0 if not found, otherwise copy
-   the entry to the result buffer. */
+/* Find an entry in the directory. Return 0 if not found, otherwise copy the
+ * entry to the result buffer. */
 int ntfs_getdir(ntfs_iterate_s* walk)
 {
-	int length=walk->dir->vol->mft_recordsize;
-	int retval,error;
-	/* start at the index root.*/
-	char *root=ntfs_malloc(length);
+	int length = walk->dir->vol->mft_recordsize;
+	int retval, error;
+	/* Start at the index root. */
+	char *root = ntfs_malloc(length);
 	ntfs_io io;
 
-	if( !root )
-		return ENOMEM;
-
-	io.fn_put=ntfs_put;
-	io.param=root;
-	io.size=length;
-	error=ntfs_read_attr(walk->dir,walk->dir->vol->at_index_root,
-			     I30,0,&io);
-	if(error)
-	{
+	if (!root)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.param = root;
+	io.size = length;
+	error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_root, I30,
+			       0, &io);
+	if (error) {
 		ntfs_error("Not a directory\n");
 		return 0;
 	}
-	walk->block=-1;
-	/* FIXME: move these to walk */
-	walk->dir->u.index.recordsize = NTFS_GETU32(root+0x8);
-	walk->dir->u.index.clusters_per_record = NTFS_GETU32(root+0xC);
-	/* FIXME: consistency check */
-	/* skip header */
-	retval = ntfs_getdir_iterate(walk,root,root+0x20);
+	walk->block = -1;
+	/* FIXME: Move these to walk. */
+	walk->dir->u.index.recordsize = NTFS_GETU32(root + 0x8);
+	walk->dir->u.index.clusters_per_record = NTFS_GETU32(root + 0xC);
+	/* FIXME: Consistency check. */
+	/* Skip header. */
+	retval = ntfs_getdir_iterate(walk, root, root + 0x20);
 	ntfs_free(root);
 	return retval;
 }
 
 /* Find an entry in the directory by its position stack. Iteration starts
-   if the stack is 0, in which case the position is set to the first item
-   in the directory. If the position is nonzero, return the item at the
-   position and change the position to the next item. The position is -1
-   if there are no more items */
+ * if the stack is 0, in which case the position is set to the first item
+ * in the directory. If the position is nonzero, return the item at the
+ * position and change the position to the next item. The position is -1
+ * if there are no more items. */
 int ntfs_getdir_byposition(ntfs_iterate_s *walk)
 {
-	walk->type=BY_POSITION;
+	walk->type = BY_POSITION;
 	return ntfs_getdir(walk);
 }
 
-/* Find an entry in the directory by its name. Return 0 if not found */
+/* Find an entry in the directory by its name. Return 0 if not found. */
 int ntfs_getdir_byname(ntfs_iterate_s *walk)
 {
-	walk->type=BY_NAME;
+	walk->type = BY_NAME;
 	return ntfs_getdir(walk);
 }
 
-int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
-			 int(*cb)(ntfs_u8*,void*),void *param)
+int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low,
+			 int (*cb)(ntfs_u8*, void*), void *param)
 {
-	char *buf=0,*entry=0;
+	char *buf = 0, *entry = 0;
 	ntfs_io io;
 	int length;
 	int block;
 	int start;
 	ntfs_attribute *attr;
-	ntfs_volume *vol=ino->vol;
-	int byte,bit;
-	int error=0;
+	ntfs_volume *vol = ino->vol;
+	int byte, bit;
+	int error = 0;
 
-	if(!ino){
+	if (!ino) {
 		ntfs_error("No inode passed to getdir_unsorted\n");
-		return EINVAL;
+		return -EINVAL;
 	}
-	if(!vol){
-		ntfs_error("Inode %d has no volume\n",ino->i_number);
-		return EINVAL;
-	}
-	ntfs_debug(DEBUG_DIR3,"unsorted 1\n");
-	/* are we still in the index root */
-	if(*p_high==0){
-		buf=ntfs_malloc(length=vol->mft_recordsize);
-		if( !buf )
-			return ENOMEM;
-		io.fn_put=ntfs_put;
-		io.param=buf;
-		io.size=length;
-		error=ntfs_read_attr(ino,vol->at_index_root,I30,0,&io);
-		if(error){
+	if (!vol) {
+		ntfs_error("Inode %d has no volume\n", ino->i_number);
+		return -EINVAL;
+	}
+	ntfs_debug(DEBUG_DIR3, "unsorted 1\n");
+	/* Are we still in the index root? */
+	if (*p_high == 0) {
+		buf = ntfs_malloc(length = vol->mft_recordsize);
+		if (!buf)
+			return -ENOMEM;
+		io.fn_put = ntfs_put;
+		io.param = buf;
+		io.size = length;
+		error = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
+		if (error) {
 			ntfs_free(buf);
 			return error;
 		}
-		ino->u.index.recordsize = NTFS_GETU32(buf+0x8);
-		ino->u.index.clusters_per_record = NTFS_GETU32(buf+0xC);
-		entry=buf+0x20;
-		ntfs_debug(DEBUG_DIR3,"unsorted 2\n");
-	}else{ /* we are in an index record */
-		length=ino->u.index.recordsize;
-		buf=ntfs_malloc(length);
-		if( !buf )
-			return ENOMEM;
-		io.fn_put=ntfs_put;
-		io.param=buf;
-		io.size=length;
-		/* 0 is index root, index allocation starts with 4 */
+		ino->u.index.recordsize = NTFS_GETU32(buf + 0x8);
+		ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC);
+		entry = buf + 0x20;
+		ntfs_debug(DEBUG_DIR3, "unsorted 2\n");
+	} else { /* we are in an index record */
+		length = ino->u.index.recordsize;
+		buf = ntfs_malloc(length);
+		if (!buf)
+			return -ENOMEM;
+		io.fn_put = ntfs_put;
+		io.param = buf;
+		io.size = length;
+		/* 0 is index root, index allocation starts with 4. */
 		block = *p_high - ino->u.index.clusters_per_record;
-		error=ntfs_read_attr(ino,vol->at_index_allocation,I30,
-				     block*vol->clustersize,&io);
-		if(!error && io.size!=length)error=EIO;
-		if(error){
+		error = ntfs_read_attr(ino, vol->at_index_allocation, I30,
+				       block*vol->clustersize, &io);
+		if (!error && io.size != length)
+			error = -EIO;
+		if (error) {
 			ntfs_error("read failed\n");
 			ntfs_free(buf);
 			return error;
 		}
-		if(!ntfs_check_index_record(ino,buf)){
-			ntfs_error("%x is not an index record\n",block);
+		if (!ntfs_check_index_record(ino, buf)) {
+			ntfs_error("%x is not an index record\n", block);
 			ntfs_free(buf);
-			return ENOTDIR;
+			return -ENOTDIR;
 		}
-		entry=buf+NTFS_GETU16(buf+0x18)+0x18;
-		ntfs_debug(DEBUG_DIR3,"unsorted 3\n");
+		entry = buf + NTFS_GETU16(buf + 0x18) + 0x18;
+		ntfs_debug(DEBUG_DIR3, "unsorted 3\n");
 	}
-
-	/* process the entries */
-	start=*p_low;
-	while(ntfs_entry_is_used(entry)){
-		ntfs_debug(DEBUG_DIR3,"unsorted 4\n");
-		if(start)
-			start--; /* skip entries that were already processed */
-		else{
-			ntfs_debug(DEBUG_DIR3,"unsorted 5\n");
-			if((error=cb(entry,param)))
-				/* the entry could not be processed */
+	/* Process the entries. */
+	start = *p_low;
+	while (ntfs_entry_is_used(entry)) {
+		ntfs_debug(DEBUG_DIR3, "unsorted 4\n");
+		if (start)
+			start--; /* Skip entries that were already processed. */
+		else {
+			ntfs_debug(DEBUG_DIR3, "unsorted 5\n");
+			if ((error = cb(entry, param)))
+				/* The entry could not be processed. */
 				break;
 			(*p_low)++;
 		}
-		entry+=NTFS_GETU16(entry+8);
+		entry += NTFS_GETU16(entry + 8);
 	}
-
-	ntfs_debug(DEBUG_DIR3,"unsorted 6\n");
-	/* caller did not process all entries */
-	if(error){
+	ntfs_debug(DEBUG_DIR3, "unsorted 6\n");
+	/* Caller did not process all entries. */
+	if (error) {
 		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3,"unsorted 7\n");
+		ntfs_debug(DEBUG_DIR3, "unsorted 7\n");
 		return error;
 	}
-
-	/* we have to locate the next record */
+	/* We have to locate the next record. */
 	ntfs_free(buf);
-	buf=0;
-	*p_low=0;
-	attr=ntfs_find_attr(ino,vol->at_bitmap,I30);
-	if(!attr){
-		/* directory does not have index allocation */
-		*p_high=0xFFFFFFFF;
-		*p_low=0;
-		ntfs_debug(DEBUG_DIR3,"unsorted 8\n");
+	buf = 0;
+	*p_low = 0;
+	attr = ntfs_find_attr(ino, vol->at_bitmap, I30);
+	if (!attr) {
+		/* Directory does not have index allocation. */
+		*p_high = 0xFFFFFFFF;
+		*p_low = 0;
+		ntfs_debug(DEBUG_DIR3, "unsorted 8\n");
 		return 0;
 	}
-	buf=ntfs_malloc(length=attr->size);
-	if( !buf )
-		return ENOMEM;
-
-	io.param=buf;
-	io.size=length;
-	error=ntfs_read_attr(ino,vol->at_bitmap,I30,0,&io);
-	if(!error && io.size!=length)error=EIO;
-	if(error){
+	buf = ntfs_malloc(length = attr->size);
+	if (!buf)
+		return -ENOMEM;
+	io.param = buf;
+	io.size = length;
+	error = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
+	if (!error && io.size != length)
+		error = -EIO;
+	if (error) {
 		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3,"unsorted 9\n");
-		return EIO;
+		ntfs_debug(DEBUG_DIR3, "unsorted 9\n");
+		return -EIO;
 	}
-	attr=ntfs_find_attr(ino,vol->at_index_allocation,I30);
-	while(1){
-		if(*p_high*vol->clustersize > attr->size){
-			/* no more index records */
-			*p_high=0xFFFFFFFF;
+	attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
+	while (1) {
+		if (*p_high * vol->clustersize > attr->size) {
+			/* No more index records. */
+			*p_high = 0xFFFFFFFF;
 			ntfs_free(buf);
-			ntfs_debug(DEBUG_DIR3,"unsorted 10\n");
+			ntfs_debug(DEBUG_DIR3, "unsorted 10\n");
 			return 0;
 		}
-		*p_high+=ino->u.index.clusters_per_record;
-		byte=*p_high/ino->u.index.clusters_per_record-1;
+		*p_high += ino->u.index.clusters_per_record;
+		byte = *p_high / ino->u.index.clusters_per_record - 1;
 		bit  = 1 << (byte & 7);
 		byte = byte >> 3;
-		/* this record is allocated */
-		if(buf[byte] & bit)
+		/* This record is allocated. */
+		if (buf[byte] & bit)
 			break;
 	}
-	ntfs_debug(DEBUG_DIR3,"unsorted 11\n");
+	ntfs_debug(DEBUG_DIR3, "unsorted 11\n");
 	ntfs_free(buf);
 	return 0;
 }
@@ -874,116 +896,120 @@
 int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name)
 {
 	ntfs_iterate_s walk;
-	int nsize,esize;
-	ntfs_u8* entry,*ndata;
+	int nsize, esize;
+	ntfs_u8* entry, *ndata;
 	int error;
 
-	walk.type=DIR_INSERT;
-	walk.dir=dir;
-	walk.u.flags=0;
+	walk.type = DIR_INSERT;
+	walk.dir = dir;
+	walk.u.flags = 0;
 	nsize = name->size;
 	ndata = name->d.data;
-	walk.name=(ntfs_u16*)(ndata+0x42);
-	walk.namelen=NTFS_GETU8(ndata+0x40);
-	walk.new_entry_size = esize = ((nsize+0x18)/8)*8;
-	walk.new_entry=entry=ntfs_malloc(esize);
-	if(!entry)return ENOMEM;
-	ntfs_bzero(entry,esize);
-	NTFS_PUTINUM(entry,new);
-	NTFS_PUTU16(entry+0x8,esize); /* size of entry */
-	NTFS_PUTU16(entry+0xA,nsize); /* size of original name attribute */
-	NTFS_PUTU32(entry+0xC,0);     /* FIXME: D-F? */
-	ntfs_memcpy(entry+0x10,ndata,nsize);
-	error=ntfs_getdir(&walk);
-	if(walk.new_entry)
+	walk.name = (ntfs_u16*)(ndata + 0x42);
+	walk.namelen = NTFS_GETU8(ndata + 0x40);
+	walk.new_entry_size = esize = ((nsize + 0x18) / 8) * 8;
+	walk.new_entry = entry = ntfs_malloc(esize);
+	if (!entry)
+		return -ENOMEM;
+	ntfs_bzero(entry, esize);
+	NTFS_PUTINUM(entry, new);
+	NTFS_PUTU16(entry + 0x8, esize); /* Size of entry. */
+	NTFS_PUTU16(entry + 0xA, nsize); /* Size of original name attribute. */
+	NTFS_PUTU32(entry + 0xC, 0);     /* FIXME: D-F? */
+	ntfs_memcpy(entry + 0x10, ndata, nsize);
+	error = ntfs_getdir(&walk);
+	if (walk.new_entry)
 		ntfs_free(walk.new_entry);
 	return error;
 }
 
 #if 0
-int ntfs_dir_add1(ntfs_inode *dir,const char* name,int namelen,ntfs_inode *ino)
+int ntfs_dir_add1(ntfs_inode *dir, const char* name, int namelen,
+		  ntfs_inode *ino)
 {
 	ntfs_iterate_s walk;
 	int error;
 	int nsize;
 	char *entry;
 	ntfs_attribute *name_attr;
-	error=ntfs_decodeuni(dir->vol,name,namelen,&walk.name,&walk.namelen);
-	if(error)
+	error = ntfs_decodeuni(dir->vol, name, namelen, &walk.name,
+			       &walk.namelen);
+	if (error)
 		return error;
-	/* FIXME: set flags */
-	walk.type=DIR_INSERT;
-	walk.dir=dir;
-	/*walk.new=ino;*/
-	/* prepare new entry */
-	/* round up to a multiple of 8 */
-	walk.new_entry_size = nsize = ((0x52+2*walk.namelen+7)/8)*8;
-	walk.new_entry=entry=ntfs_malloc(nsize);
-	if(!entry)
-		return ENOMEM;
-	ntfs_bzero(entry,nsize);
-	NTFS_PUTINUM(entry,ino);
-	NTFS_PUTU16(entry+8,nsize);
-	NTFS_PUTU16(entry+0xA,0x42+2*namelen); /*FIXME: size of name attr*/
-	NTFS_PUTU32(entry+0xC,0); /*FIXME: D-F? */
-	name_attr=ntfs_find_attr(ino,vol->at_file_name,0); /* FIXME:multiple names */
-	if(!name_attr || !name_attr->resident)
-		return EIDRM;
-	/* directory, file stamps, sizes, filename */
-	ntfs_memcpy(entry+0x10,name_attr->d.data,0x42+2*namelen);
-	error=ntfs_getdir(&walk);
+	/* FIXME: Set flags. */
+	walk.type = DIR_INSERT;
+	walk.dir = dir;
+	/* walk.new = ino; */
+	/* Prepare new entry. */
+	/* Round up to a multiple of 8. */
+	walk.new_entry_size = nsize = ((0x52 + 2 * walk.namelen + 7) / 8) * 8;
+	walk.new_entry = entry = ntfs_malloc(nsize);
+	if (!entry)
+		return -ENOMEM;
+	ntfs_bzero(entry, nsize);
+	NTFS_PUTINUM(entry, ino);
+	NTFS_PUTU16(entry + 8, nsize);
+	NTFS_PUTU16(entry + 0xA, 0x42 + 2 * namelen); /* FIXME: Size of name 
+						       * attribute. */
+	NTFS_PUTU32(entry + 0xC, 0); /* FIXME: D-F? */
+	name_attr = ntfs_find_attr(ino, vol->at_file_name, 0);
+						    /* FIXME: multiple names */
+	if (!name_attr || !name_attr->resident)
+		return -EIDRM;
+	/* Directory, file stamps, sizes, filename. */
+	ntfs_memcpy(entry + 0x10, name_attr->d.data, 0x42 + 2 * namelen);
+	error = ntfs_getdir(&walk);
 	ntfs_free(walk.name);
 	return error;
 }
 #endif
 
 /* Fills out and creates an INDEX_ROOT attribute. */
-
-int
-ntfs_add_index_root (ntfs_inode *ino, int type)
+int ntfs_add_index_root(ntfs_inode *ino, int type)
 {
 	ntfs_attribute *da;
-	ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry */
+	ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry. */
 	char name[10];
 
 	NTFS_PUTU32(data, type);
-	/* ??? */
-	NTFS_PUTU32(data+4, 1);
-	NTFS_PUTU32(data+8, ino->vol->index_recordsize);
-	NTFS_PUTU32(data+0xC, ino->vol->index_clusters_per_record);
-	/* ??? */
-	NTFS_PUTU32(data+0x10, 0x10);
+	/* FIXME: ??? */
+	NTFS_PUTU32(data + 4, 1);
+	NTFS_PUTU32(data + 8, ino->vol->index_recordsize);
+	NTFS_PUTU32(data + 0xC, ino->vol->index_clusters_per_record);
+	/* FXIME: ??? */
+	NTFS_PUTU32(data + 0x10, 0x10);
 	/* Size of entries, including header. */
-	NTFS_PUTU32(data+0x14, 0x20);
-	NTFS_PUTU32(data+0x18, 0x20);
+	NTFS_PUTU32(data + 0x14, 0x20);
+	NTFS_PUTU32(data + 0x18, 0x20);
 	/* No index allocation, yet. */
-	NTFS_PUTU32(data+0x1C, 0);
-	/* add last entry. */
-	/* indexed MFT record. */
-	NTFS_PUTU64(data+0x20, 0);
-	/* size of entry */
-	NTFS_PUTU32(data+0x28, 0x10);
-	/* flags: last entry, no child nodes. */
-	NTFS_PUTU32(data+0x2C, 2);
-	/* compute name */
+	NTFS_PUTU32(data + 0x1C, 0);
+	/* Add last entry. */
+	/* Indexed MFT record. */
+	NTFS_PUTU64(data + 0x20, 0);
+	/* Size of entry. */
+	NTFS_PUTU32(data + 0x28, 0x10);
+	/* Flags: Last entry, no child nodes. */
+	NTFS_PUTU32(data + 0x2C, 2);
+	/* Compute name. */
 	ntfs_indexname(name, type);
 	return ntfs_create_attr(ino, ino->vol->at_index_root, name,
 				data, sizeof(data), &da);
 }
 
-int
-ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *result)
+int ntfs_mkdir(ntfs_inode* dir, const char* name, int namelen,
+	       ntfs_inode *result)
 {
 	int error;
+	
 	error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR);
-	if(error)
+	if (error)
 		goto out;
 	error = ntfs_add_index_root(result, 0x30);
 	if (error)
 		goto out;
-	/* Set directory bit */
+	/* Set directory bit. */
 	result->attr[0x16] |= 2;
-	error = ntfs_update_inode (dir);
+	error = ntfs_update_inode(dir);
 	if (error)
 		goto out;
 	error = ntfs_update_inode (result);
@@ -993,8 +1019,3 @@
 	return error;
 }
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/dir.h linux/fs/ntfs/dir.h
--- v2.4.3/linux/fs/ntfs/dir.h	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/dir.h	Wed Apr 18 11:49:13 2001
@@ -1,6 +1,4 @@
-/*
- *  dir.h
- *  Header file for dir.c
+/*  dir.h - Header file for dir.c
  *
  *  Copyright (C) 1997 Régis Duchesne
  */
@@ -32,11 +30,19 @@
 } ntfs_iterate_s;
 
 int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low,
-  int(*cb)(ntfs_u8*,void*), void *param);
+			 int (*cb)(ntfs_u8*, void*), void *param);
+
 int ntfs_getdir_byname(ntfs_iterate_s *walk);
+
 int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name);
+
 int ntfs_check_index_record(ntfs_inode *ino, char *record);
+
 int ntfs_getdir_byposition(ntfs_iterate_s *walk);
+
 int ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *ino);
+
 int ntfs_split_indexroot(ntfs_inode *ino);
-int ntfs_add_index_root( ntfs_inode *ino, int type );
+
+int ntfs_add_index_root(ntfs_inode *ino, int type);
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.4.3/linux/fs/ntfs/fs.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/ntfs/fs.c	Wed Apr 18 11:49:13 2001
@@ -1,19 +1,12 @@
-/*
- *  fs.c
- *  NTFS driver for Linux 2.3.x
+/*  fs.c - NTFS driver for Linux 2.4.x
  *
  *  Copyright (C) 1995-1997, 1999 Martin von Löwis
  *  Copyright (C) 1996 Richard Russon
  *  Copyright (C) 1996-1997 Régis Duchesne
- *  Copyright (C) 2000, Anton Altaparmakov
+ *  Copyright (C) 2000-2001, Anton Altaparmakov (AIA)
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#ifdef NTFS_IN_LINUX_KERNEL
 #include <linux/config.h>
-#endif
 
 #include "ntfstypes.h"
 #include "struct.h"
@@ -30,66 +23,67 @@
 #include <linux/locks.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <asm/page.h>
 
-/* Forward declarations */
+/* Forward declarations. */
 static struct inode_operations ntfs_dir_inode_operations;
 static struct file_operations ntfs_dir_operations;
 
 #define ITEM_SIZE 2040
 
-/* io functions to user space */
-static void ntfs_putuser(ntfs_io* dest,void *src,ntfs_size_t len)
+/* Io functions to user space. */
+static void ntfs_putuser(ntfs_io* dest, void *src, ntfs_size_t len)
 {
-	copy_to_user(dest->param,src,len);
-	dest->param+=len;
+	copy_to_user(dest->param, src, len);
+	dest->param += len;
 }
 
 #ifdef CONFIG_NTFS_RW
-struct ntfs_getuser_update_vm_s{
+struct ntfs_getuser_update_vm_s {
 	const char *user;
 	struct inode *ino;
 	loff_t off;
 };
 
-static void ntfs_getuser_update_vm (void *dest, ntfs_io *src, ntfs_size_t len)
+static void ntfs_getuser_update_vm(void *dest, ntfs_io *src, ntfs_size_t len)
 {
 	struct ntfs_getuser_update_vm_s *p = src->param;
-	copy_from_user (dest, p->user, len);
+	
+	copy_from_user(dest, p->user, len);
 	p->user += len;
 	p->off += len;
 }
 #endif
 
-static ssize_t
-ntfs_read(struct file * filp, char *buf, size_t count, loff_t *off)
+static ssize_t ntfs_read(struct file *filp, char *buf, size_t count,loff_t *off)
 {
 	int error;
 	ntfs_io io;
-	ntfs_inode *ino=NTFS_LINO2NINO(filp->f_dentry->d_inode);
+	ntfs_inode *ino = NTFS_LINO2NINO(filp->f_dentry->d_inode);
 
-	/* inode is not properly initialized */
-	if(!ino)return -EINVAL;
+	/* Inode is not properly initialized. */
+	if (!ino)
+		return -EINVAL;
 	ntfs_debug(DEBUG_OTHER, "ntfs_read %x,%x,%x ->",
-		   (unsigned)ino->i_number,(unsigned)*off,(unsigned)count);
-	/* inode has no unnamed data attribute */
-	if(!ntfs_find_attr(ino,ino->vol->at_data,NULL))
+		   (unsigned)ino->i_number, (unsigned)*off, (unsigned)count);
+	/* Inode has no unnamed data attribute. */
+	if(!ntfs_find_attr(ino, ino->vol->at_data, NULL))
 		return -EINVAL;
-	
-	/* read the data */
-	io.fn_put=ntfs_putuser;
-	io.fn_get=0;
-	io.param=buf;
-	io.size=count;
-	error=ntfs_read_attr(ino,ino->vol->at_data,NULL,*off,&io);
-	if(error && !io.size)return -error;
-	
-	*off+=io.size;
+	/* Read the data. */
+	io.fn_put = ntfs_putuser;
+	io.fn_get = 0;
+	io.param = buf;
+	io.size = count;
+	error = ntfs_read_attr(ino, ino->vol->at_data, NULL, *off, &io);
+	if (error && !io.size)
+		return error;
+	*off += io.size;
 	return io.size;
 }
 
 #ifdef CONFIG_NTFS_RW
-static ssize_t
-ntfs_write(struct file *filp,const char* buf,size_t count,loff_t *pos)
+static ssize_t ntfs_write(struct file *filp, const char* buf, size_t count,
+			  loff_t *pos)
 {
 	int ret;
 	ntfs_io io;
@@ -99,14 +93,13 @@
 
 	if (!ino)
 		return -EINVAL;
-	ntfs_debug (DEBUG_LINUX, "ntfs_write %x,%x,%x ->\n",
-	       (unsigned)ino->i_number, (unsigned)*pos, (unsigned)count);
-	/* Allows to lock fs ro at any time */
+	ntfs_debug(DEBUG_LINUX, "ntfs_write %x, %x, %x ->\n",
+		   (unsigned)ino->i_number, (unsigned)*pos, (unsigned)count);
+	/* Allows to lock fs ro at any time. */
 	if (inode->i_sb->s_flags & MS_RDONLY)
 		return -ENOSPC;
-	if (!ntfs_find_attr(ino,ino->vol->at_data,NULL))
+	if (!ntfs_find_attr(ino, ino->vol->at_data, NULL))
 		return -EINVAL;
-
 	/* Evaluating O_APPEND is the file system's job... */
 	if (filp->f_flags & O_APPEND)
 		*pos = inode->i_size;
@@ -117,15 +110,14 @@
 	io.fn_get = ntfs_getuser_update_vm;
 	io.param = &param;
 	io.size = count;
-	ret = ntfs_write_attr (ino, ino->vol->at_data, NULL, *pos, &io);
-	ntfs_debug (DEBUG_LINUX, "write -> %x\n", ret);
-	if(ret<0)
+	ret = ntfs_write_attr(ino, ino->vol->at_data, NULL, *pos, &io);
+	ntfs_debug(DEBUG_LINUX, "write -> %x\n", ret);
+	if (ret < 0)
 		return -EINVAL;
-
 	*pos += io.size;
 	if (*pos > inode->i_size)
 		inode->i_size = *pos;
-	mark_inode_dirty (filp->f_dentry->d_inode);
+	mark_inode_dirty(filp->f_dentry->d_inode);
 	return io.size;
 }
 #endif
@@ -140,269 +132,273 @@
 	int namelen;
 };
 	
-static int ntfs_printcb(ntfs_u8 *entry,void *param)
+static int ntfs_printcb(ntfs_u8 *entry, void *param)
 {
-	struct ntfs_filldir* nf=param;
-	int flags=NTFS_GETU8(entry+0x51);
-	int show_hidden=0;
-	int length=NTFS_GETU8(entry+0x50);
-	int inum=NTFS_GETU32(entry);
+	struct ntfs_filldir *nf = param;
+	int flags = NTFS_GETU8(entry + 0x51);
+	int show_hidden = 0;
+	int length = NTFS_GETU8(entry + 0x50);
+	int inum = NTFS_GETU32(entry);
 	int error;
 #ifdef NTFS_NGT_NT_DOES_LOWER
-	int i,to_lower=0;
+	int i, to_lower = 0;
 #endif
-	switch(nf->type){
+	switch (nf->type) {
 	case ngt_dos:
-		/* Don't display long names */
-		if((flags & 2)==0)
+		/* Don't display long names. */
+		if ((flags & 2) == 0)
 			return 0;
 		break;
 	case ngt_nt:
-		/* Don't display short-only names */
-		switch(flags&3){
-		case 2: return 0;
+		/* Don't display short-only names. */
+		switch (flags & 3) {
+		case 2: 
+			return 0;
 #ifdef NTFS_NGT_NT_DOES_LOWER
-		case 3: to_lower=1;
+		case 3: 
+			to_lower = 1;
 #endif
 		}
 		break;
 	case ngt_posix:
 		break;
 	case ngt_full:
-		show_hidden=1;
+		show_hidden = 1;
 		break;
 	}
-	if(!show_hidden && ((NTFS_GETU8(entry+0x48) & 2)==2)){
-		ntfs_debug(DEBUG_OTHER,"Skipping hidden file\n");
+	if (!show_hidden && ((NTFS_GETU8(entry + 0x48) & 2) == 2)) {
+		ntfs_debug(DEBUG_OTHER, "Skipping hidden file\n");
 		return 0;
 	}
-	nf->name=0;
-	if(ntfs_encodeuni(NTFS_INO2VOL(nf->dir),(ntfs_u16*)(entry+0x52),
-			  length,&nf->name,&nf->namelen)){
-		ntfs_debug(DEBUG_OTHER,"Skipping unrepresentable file\n");
-		if(nf->name)ntfs_free(nf->name);
+	nf->name = 0;
+	if (ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52),
+			   length, &nf->name, &nf->namelen)){
+		ntfs_debug(DEBUG_OTHER, "Skipping unrepresentable file\n");
+		if (nf->name)
+			ntfs_free(nf->name);
 		return 0;
 	}
-	/* Do not return ".", as this is faked */
-	if(length==1 && *nf->name=='.')
+	/* Do not return ".", as this is faked. */
+	if (length == 1 && *nf->name == '.')
 		return 0;
 #ifdef NTFS_NGT_NT_DOES_LOWER
-	if(to_lower)
-		for(i=0;i<nf->namelen;i++)
-			/* This supports ASCII only. Since only DOS-only
-			   names get converted, and since those are restricted
-			   to ASCII, this should be correct */
-			if(nf->name[i]>='A' && nf->name[i]<='Z')
-				nf->name[i]+='a'-'A';
-#endif
-	nf->name[nf->namelen]=0;
-	ntfs_debug(DEBUG_OTHER, "readdir got %s,len %d\n",nf->name,nf->namelen);
-	/* filldir expects an off_t rather than an loff_t.
-	   Hope we don't have more than 65535 index records */
-	error=nf->filldir(nf->dirent,nf->name,nf->namelen,
-			(nf->ph<<16)|nf->pl,inum,DT_UNKNOWN);
+	if (to_lower)
+		for(i = 0; i < nf->namelen; i++)
+			/* This supports ASCII only. Since only DOS-only names
+			 * get converted, and since those are restricted to
+			 * ASCII, this should be correct. */
+			if (nf->name[i] >= 'A' && nf->name[i] <= 'Z')
+				nf->name[i] += 'a' - 'A';
+#endif
+	nf->name[nf->namelen] = 0;
+	ntfs_debug(DEBUG_OTHER, "readdir got %s, len %d\n", nf->name,
+		       						nf->namelen);
+	/* filldir expects an off_t rather than an loff_t. Hope we don't have
+	 * more than 65535 index records. */
+	error = nf->filldir(nf->dirent, nf->name, nf->namelen,
+			    (nf->ph << 16) | nf->pl, inum, DT_UNKNOWN);
 	ntfs_free(nf->name);
-	/* Linux filldir errors are negative, other errors positive */
 	return error;
 }
 
-/* readdir returns '..', then '.', then the directory entries in sequence
-   As the root directory contains a entry for itself, '.' is not emulated
-   for the root directory */
+/* readdir returns '..', then '.', then the directory entries in sequence.
+ * As the root directory contains a entry for itself, '.' is not emulated for
+ * the root directory. */
 static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir)
 {
 	struct ntfs_filldir cb;
 	int error;
-	struct inode *dir=filp->f_dentry->d_inode;
+	struct inode *dir = filp->f_dentry->d_inode;
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n",
-	       (unsigned)dir->i_ino,(unsigned int)dir->i_mode);
+		   (unsigned)dir->i_ino, (unsigned int)dir->i_mode);
 
 	ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n",
-	       (unsigned)filp->f_pos,atomic_read(&dir->i_count));
-	cb.pl=filp->f_pos & 0xFFFF;
-	cb.ph=filp->f_pos >> 16;
-	/* end of directory */
-	if(cb.ph==0xFFFF){
-		/* FIXME: Maybe we can return those with the previous call */
-		switch(cb.pl){
-		case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino,DT_DIR);
-			filp->f_pos=0xFFFF0001;
+		   (unsigned)filp->f_pos, atomic_read(&dir->i_count));
+	cb.pl = filp->f_pos & 0xFFFF;
+	cb.ph = filp->f_pos >> 16;
+	/* End of directory. */
+	if (cb.ph == 0xFFFF) {
+		/* FIXME: Maybe we can return those with the previous call. */
+		switch (cb.pl) {
+		case 0: 
+			filldir(dirent, ".", 1, filp->f_pos, dir->i_ino,DT_DIR);
+			filp->f_pos = 0xFFFF0001;
 			return 0;
-			/* FIXME: parent directory */
-		case 1: filldir(dirent,"..",2,filp->f_pos,0,DT_DIR);
-			filp->f_pos=0xFFFF0002;
+			/* FIXME: Parent directory. */
+		case 1:
+			filldir(dirent, "..", 2, filp->f_pos, 0, DT_DIR);
+			filp->f_pos = 0xFFFF0002;
 			return 0;
 		}
 		ntfs_debug(DEBUG_OTHER, "readdir: EOD\n");
 		return 0;
 	}
-	cb.dir=dir;
-	cb.filldir=filldir;
-	cb.dirent=dirent;
-	cb.type=NTFS_INO2VOL(dir)->ngt;
-	do{
+	cb.dir = dir;
+	cb.filldir = filldir;
+	cb.dirent = dirent;
+	cb.type = NTFS_INO2VOL(dir)->ngt;
+	do {
 		ntfs_debug(DEBUG_OTHER,"looking for next file\n");
-		error=ntfs_getdir_unsorted(NTFS_LINO2NINO(dir),&cb.ph,&cb.pl,
-				   ntfs_printcb,&cb);
-	}while(!error && cb.ph!=0xFFFFFFFF);
-	filp->f_pos=(cb.ph<<16)|cb.pl;
-	ntfs_debug(DEBUG_OTHER, "new position %x\n",(unsigned)filp->f_pos);
-        /* -EINVAL is on user buffer full. This is not considered 
-	   as an error by sys_getdents */
-	if(error<0) 
-		error=0;
-	/* Otherwise (device error, inconsistent data), switch the sign */
-	return -error;
+		error = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph,
+					     &cb.pl, ntfs_printcb, &cb);
+	} while (!error && cb.ph != 0xFFFFFFFF);
+	filp->f_pos = (cb.ph << 16) | cb.pl;
+	ntfs_debug(DEBUG_OTHER, "new position %x\n", (unsigned)filp->f_pos);
+        /* -EINVAL is on user buffer full. This is not considered as an error
+	 * by sys_getdents. */
+	if (error == -EINVAL) 
+		error = 0;
+	/* Otherwise (device error, inconsistent data) return the error code. */
+	return error;
 }
 
-/* Copied from vfat driver */
+/* Copied from vfat driver. */
 static int simple_getbool(char *s, int *setval)
 {
 	if (s) {
-		if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) {
+		if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true"))
 			*setval = 1;
-		} else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) {
+		else if (!strcmp(s, "0") || !strcmp(s, "no") ||
+							!strcmp(s, "false"))
 			*setval = 0;
-		} else {
+		else
 			return 0;
-		}
-	} else {
+	} else
 		*setval = 1;
-	}
 	return 1;
 }
 
-/* Parse the (re)mount options */
-static int parse_options(ntfs_volume* vol,char *opt)
+/* Parse the (re)mount options. */
+static int parse_options(ntfs_volume* vol, char *opt)
 {
 	char *value;
 
-	vol->uid=vol->gid=0;
-	vol->umask=0077;
-	vol->ngt=ngt_nt;
-	vol->nls_map=0;
-	vol->nct=0;
-	if(!opt)goto done;
-
-	for(opt = strtok(opt,",");opt;opt=strtok(NULL,","))
+	vol->uid = vol->gid = 0;
+	vol->umask = 0077;
+	vol->ngt = ngt_nt;
+	vol->nls_map = 0;
+	vol->nct = 0;
+	if (!opt)
+		goto done;
+	for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ","))
 	{
 		if ((value = strchr(opt, '=')) != NULL)
-			*value++='\0';
-		if(strcmp(opt,"uid")==0)
-		{
-			if(!value || !*value)goto needs_arg;
-			vol->uid=simple_strtoul(value,&value,0);
-			if(*value){
+			*value ++= '\0';
+		if (strcmp(opt, "uid") == 0) {
+			if (!value || !*value)
+				goto needs_arg;
+			vol->uid = simple_strtoul(value, &value, 0);
+			if (*value) {
 				printk(KERN_ERR "NTFS: uid invalid argument\n");
 				return 0;
 			}
-		}else if(strcmp(opt, "gid") == 0)
-		{
-			if(!value || !*value)goto needs_arg;
-			vol->gid=simple_strtoul(value,&value,0);
-			if(*value){
-				printk(KERN_ERR "gid invalid argument\n");
+		} else if (strcmp(opt, "gid") == 0) {
+			if (!value || !*value)
+				goto needs_arg;
+			vol->gid = simple_strtoul(value, &value, 0);
+			if (*value) {
+				printk(KERN_ERR "NTFS: gid invalid argument\n");
 				return 0;
 			}
-		}else if(strcmp(opt, "umask") == 0)
-		{
-			if(!value || !*value)goto needs_arg;
-			vol->umask=simple_strtoul(value,&value,0);
-			if(*value){
-				printk(KERN_ERR "umask invalid argument\n");
+		} else if (strcmp(opt, "umask") == 0) {
+			if (!value || !*value)
+				goto needs_arg;
+			vol->umask = simple_strtoul(value, &value, 0);
+			if (*value) {
+				printk(KERN_ERR "NTFS: umask invalid "
+						"argument\n");
 				return 0;
 			}
-		}else if(strcmp(opt, "iocharset") == 0){
-			if(!value || !*value)goto needs_arg;
-			vol->nls_map=load_nls(value);
+		} else if (strcmp(opt, "iocharset") == 0) {
+			if (!value || !*value)
+				goto needs_arg;
+			vol->nls_map = load_nls(value);
 			vol->nct |= nct_map;
-			if(!vol->nls_map){
+			if (!vol->nls_map) {
 				printk(KERN_ERR "NTFS: charset not found");
 				return 0;
 			}
-		}else if(strcmp(opt, "posix") == 0){
+		} else if (strcmp(opt, "posix") == 0) {
 			int val;
-			if(!value || !*value)goto needs_arg;
-			if(!simple_getbool(value,&val))
+			if (!value || !*value)
+				goto needs_arg;
+			if (!simple_getbool(value, &val))
 				goto needs_bool;
-			vol->ngt=val?ngt_posix:ngt_nt;
-		}else if(strcmp(opt,"utf8") == 0){
-			int val=0;
-			if(!value || !*value)
-				val=1;
-			else if(!simple_getbool(value,&val))
+			vol->ngt = val ? ngt_posix : ngt_nt;
+		} else if (strcmp(opt, "utf8") == 0) {
+			int val = 0;
+			if (!value || !*value)
+				val = 1;
+			else if (!simple_getbool(value, &val))
 				goto needs_bool;
-			if(val)
-				vol->nct|=nct_utf8;
-		}else if(strcmp(opt,"uni_xlate") == 0){
-			int val=0;
-			/* no argument: uni_vfat.
-			   boolean argument: uni_vfat.
-			   "2": uni.
-			*/
-			if(!value || !*value)
-				val=1;
-			else if(strcmp(value,"2")==0)
+			if (val)
+				vol->nct |= nct_utf8;
+		} else if (strcmp(opt, "uni_xlate") == 0) {
+			int val = 0;
+			/* No argument: uni_vfat. boolean argument: uni_vfat.
+			 * "2": uni. */
+			if (!value || !*value)
+				val = 1;
+			else if (strcmp(value, "2") == 0)
 				vol->nct |= nct_uni_xlate;
-			else if(!simple_getbool(value,&val))
+			else if (!simple_getbool(value, &val))
 				goto needs_bool;
-			if(val)
+			if (val)
 				vol->nct |= nct_uni_xlate_vfat | nct_uni_xlate;
-		}else{
+		} else {
 			printk(KERN_ERR "NTFS: unkown option '%s'\n", opt);
 			return 0;
 		}
 	}
-	if(vol->nct & nct_utf8 & (nct_map | nct_uni_xlate)){
-		printk(KERN_ERR "utf8 cannot be combined with iocharset or uni_xlate\n");
+	if (vol->nct & nct_utf8 & (nct_map | nct_uni_xlate)) {
+		printk(KERN_ERR "utf8 cannot be combined with iocharset or "
+				"uni_xlate\n");
 		return 0;
 	}
  done:
-	if((vol->nct & (nct_uni_xlate | nct_map | nct_utf8))==0)
+	if ((vol->nct & (nct_uni_xlate | nct_map | nct_utf8)) == 0)
 		/* default to UTF-8 */
-		vol->nct=nct_utf8;
-	if(!vol->nls_map){
-		vol->nls_map=load_nls_default();
+		vol->nct = nct_utf8;
+	if (!vol->nls_map) {
+		vol->nls_map = load_nls_default();
 		if (vol->nls_map)
-			vol->nct=nct_map | (vol->nct&nct_uni_xlate);
+			vol->nct = nct_map | (vol->nct&nct_uni_xlate);
 	}
 	return 1;
-
  needs_arg:
-	printk(KERN_ERR "NTFS: %s needs an argument",opt);
+	printk(KERN_ERR "NTFS: %s needs an argument", opt);
 	return 0;
  needs_bool:
-	printk(KERN_ERR "NTFS: %s needs boolean argument",opt);
+	printk(KERN_ERR "NTFS: %s needs boolean argument", opt);
 	return 0;
 }
 			
 static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
 {
-	struct inode *res=0;
-	char *item=0;
+	struct inode *res = 0;
+	char *item = 0;
 	ntfs_iterate_s walk;
 	int error;
-	ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n",d->d_name.name,
+	
+	ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n", d->d_name.name,
 		   (unsigned)dir->i_ino);
-	/* convert to wide string */
-	error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name,
-			     d->d_name.len,&walk.name,&walk.namelen);
-	if(error)
-		return ERR_PTR(-error);
-	item=ntfs_malloc(ITEM_SIZE);
-	if( !item )
+	/* Convert to wide string. */
+	error = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name,
+			       d->d_name.len, &walk.name, &walk.namelen);
+	if (error)
+		return ERR_PTR(error);
+	item = ntfs_malloc(ITEM_SIZE);
+	if (!item)
 		return ERR_PTR(-ENOMEM);
-	/* ntfs_getdir will place the directory entry into item,
-	   and the first long long is the MFT record number */
-	walk.type=BY_NAME;
-	walk.dir=NTFS_LINO2NINO(dir);
-	walk.result=item;
-	if(ntfs_getdir_byname(&walk))
-	{
-		res=iget(dir->i_sb,NTFS_GETU32(item));
-	}
-	d_add(d,res);
+	/* ntfs_getdir will place the directory entry into item, and the first
+	 * long long is the MFT record number. */
+	walk.type = BY_NAME;
+	walk.dir = NTFS_LINO2NINO(dir);
+	walk.result = item;
+	if (ntfs_getdir_byname(&walk))
+		res = iget(dir->i_sb, NTFS_GETU32(item));
+	d_add(d, res);
 	ntfs_free(item);
 	ntfs_free(walk.name);
 	/* Always return success, the dcache will handle negative entries. */
@@ -419,74 +415,61 @@
 static struct inode_operations ntfs_inode_operations_nobmap;
 
 #ifdef CONFIG_NTFS_RW
-static int
-ntfs_create(struct inode* dir,struct dentry *d,int mode)
+static int ntfs_create(struct inode* dir, struct dentry *d, int mode)
 {
-	struct inode *r=0;
-	ntfs_inode *ino=0;
+	struct inode *r = 0;
+	ntfs_inode *ino = 0;
 	ntfs_volume *vol;
-	int error=0;
+	int error = 0;
 	ntfs_attribute *si;
 
-	r=new_inode(dir->i_sb);
-	if(!r){
-		error=ENOMEM;
+	r = new_inode(dir->i_sb);
+	if (!r) {
+		error = -ENOMEM;
 		goto fail;
 	}
-
-	ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n",d->d_name.name);
-	vol=NTFS_INO2VOL(dir);
-#ifdef NTFS_IN_LINUX_KERNEL
-	ino=NTFS_LINO2NINO(r);
-#else
-	ino=ntfs_malloc(sizeof(ntfs_inode));
-	if(!ino){
-		error=ENOMEM;
+	ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n", d->d_name.name);
+	vol = NTFS_INO2VOL(dir);
+	ino = NTFS_LINO2NINO(r);
+	error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name,
+				d->d_name.len);
+	if (error)
 		goto fail;
-	}
-	r->u.generic_ip=ino;
-#endif
-	error=ntfs_alloc_file(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name,
-			       d->d_name.len);
-	if(error)goto fail;
-	error=ntfs_update_inode(ino);
-	if(error)goto fail;
-	error=ntfs_update_inode(NTFS_LINO2NINO(dir));
-	if(error)goto fail;
-
-	r->i_uid=vol->uid;
-	r->i_gid=vol->gid;
+	error = ntfs_update_inode(ino);
+	if (error)
+		goto fail;
+	error = ntfs_update_inode(NTFS_LINO2NINO(dir));
+	if (error)
+		goto fail;
+	r->i_uid = vol->uid;
+	r->i_gid = vol->gid;
 	/* FIXME: dirty? dev? */
-	/* get the file modification times from the standard information */
-	si=ntfs_find_attr(ino,vol->at_standard_information,NULL);
-	if(si){
-		char *attr=si->d.data;
-		r->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18));
-		r->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr));
-		r->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8));
+	/* Get the file modification times from the standard information. */
+	si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
+	if (si) {
+		char *attr = si->d.data;
+		r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
+		r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
+		r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
 	}
 	/* It's not a directory */
-	r->i_op=&ntfs_inode_operations_nobmap;
-	r->i_fop=&ntfs_file_operations_nommap,
-	r->i_mode=S_IFREG|S_IRUGO;
+	r->i_op = &ntfs_inode_operations_nobmap;
+	r->i_fop = &ntfs_file_operations_nommap,
+	r->i_mode = S_IFREG | S_IRUGO;
 #ifdef CONFIG_NTFS_RW
-	r->i_mode|=S_IWUGO;
+	r->i_mode |= S_IWUGO;
 #endif
 	r->i_mode &= ~vol->umask;
-
 	insert_inode_hash(r);
-	d_instantiate(d,r);
+	d_instantiate(d, r);
 	return 0;
  fail:
-	#ifndef NTFS_IN_LINUX_KERNEL
-	if(ino)ntfs_free(ino);
-	#endif
-	if(r)iput(r);
-	return -error;
+	if (r)
+		iput(r);
+	return error;
 }
 
-static int
-_linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
+static int _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
 {
 	int error;
 	struct inode *r = 0;
@@ -494,45 +477,35 @@
 	ntfs_inode *ino;
 	ntfs_attribute *si;
 
-	ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n",d->d_name.name, dir->i_ino);
-	error = ENAMETOOLONG;
-	if (d->d_name.len > /* FIXME */255)
+	ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n", d->d_name.name, dir->i_ino);
+	error = -ENAMETOOLONG;
+	if (d->d_name.len > /* FIXME: */ 255)
 		goto out;
-
-	error = EIO;
+	error = -EIO;
 	r = new_inode(dir->i_sb);
 	if (!r)
 		goto out;
-	
 	vol = NTFS_INO2VOL(dir);
-#ifdef NTFS_IN_LINUX_KERNEL
 	ino = NTFS_LINO2NINO(r);
-#else
-	ino = ntfs_malloc(sizeof(ntfs_inode));
-	error = ENOMEM;
-	if(!ino)
-		goto out;
-	r->u.generic_ip = ino;
-#endif
-	error = ntfs_mkdir(NTFS_LINO2NINO(dir), 
-			   d->d_name.name, d->d_name.len, ino);
-	if(error)
+	error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len,
+			   ino);
+	if (error)
 		goto out;
 	r->i_uid = vol->uid;
 	r->i_gid = vol->gid;
-	si = ntfs_find_attr(ino,vol->at_standard_information,NULL);
-	if(si){
+	si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
+	if (si) {
 		char *attr = si->d.data;
-		r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18));
+		r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
 		r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
-		r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+8));
+		r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
 	}
-	/* It's a directory */
+	/* It's a directory. */
 	r->i_op = &ntfs_dir_inode_operations;
 	r->i_fop = &ntfs_dir_operations;
-	r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+	r->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
 #ifdef CONFIG_NTFS_RW
-	r->i_mode|=S_IWUGO;
+	r->i_mode |= S_IWUGO;
 #endif
 	r->i_mode &= ~vol->umask;	
 	
@@ -540,24 +513,23 @@
 	d_instantiate(d, r);
 	error = 0;
  out:
- 	ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error);
-	return -error;
+ 	ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", error);
+	return error;
 }
 #endif
 
 #if 0
-static int 
-ntfs_bmap(struct inode *ino,int block)
+static int ntfs_bmap(struct inode *ino, int block)
 {
-	int ret=ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino),block);
-	ntfs_debug(DEBUG_OTHER, "bmap of %lx,block %x is %x\n",
-	       ino->i_ino,block,ret);
-	return (ret==-1) ? 0:ret;
+	int ret = ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino), block);
+	ntfs_debug(DEBUG_OTHER, "bmap of %lx, block %x is %x\n", ino->i_ino,
+		   block, ret);
+	return (ret == -1) ? 0 : ret;
 }
 #endif
 
 /* It's fscking broken. */
-/* FIXME: [bm]map code is disabled until ntfs_get_block gets sorted! */
+/* FIXME: [bm]map code is disabled until ntfs_get_block() gets sorted! */
 /*
 static int ntfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
 {
@@ -594,19 +566,24 @@
 {
 	return block_write_full_page(page,ntfs_get_block);
 }
+
 static int ntfs_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,ntfs_get_block);
 }
-static int ntfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+
+static int ntfs_prepare_write(struct file *file, struct page *page,
+			      unsigned from, unsigned to)
 {
-	return cont_prepare_write(page,from,to,ntfs_get_block,
-		&page->mapping->host->u.ntfs_i.mmu_private);
+	return cont_prepare_write(page, from, to, ntfs_get_block,
+				  &page->mapping->host->u.ntfs_i.mmu_private);
 }
+
 static int _ntfs_bmap(struct address_space *mapping, long block)
 {
-	return generic_block_bmap(mapping,block,ntfs_get_block);
+	return generic_block_bmap(mapping, block, ntfs_get_block);
 }
+
 struct address_space_operations ntfs_aops = {
 	readpage: ntfs_readpage,
 	writepage: ntfs_writepage,
@@ -617,84 +594,69 @@
 };
 */
 
-/* ntfs_read_inode is called by the Virtual File System (the kernel layer that
- * deals with filesystems) when iget is called requesting an inode not already
- * present in the inode table. Typically filesystems have separate
- * inode_operations for directories, files and symlinks.
- */
+/* ntfs_read_inode() is called by the Virtual File System (the kernel layer 
+ * that deals with filesystems) when iget is called requesting an inode not
+ * already present in the inode table. Typically filesystems have separate
+ * inode_operations for directories, files and symlinks. */
 static void ntfs_read_inode(struct inode* inode)
 {
 	ntfs_volume *vol;
-	int can_mmap=0;
+	int can_mmap = 0;
 	ntfs_inode *ino;
 	ntfs_attribute *data;
 	ntfs_attribute *si;
 
-	vol=NTFS_INO2VOL(inode);
-	inode->i_mode=0;
-	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino);
-
-	switch(inode->i_ino)
-	{
-		/* those are loaded special files */
-	case FILE_MFT:
-		ntfs_error("Trying to open MFT\n");return;
+	vol = NTFS_INO2VOL(inode);
+	inode->i_mode = 0;
+	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n", (unsigned)inode->i_ino);
+	switch (inode->i_ino) {
+		/* Those are loaded special files. */
+	case FILE_$Mft:
+		ntfs_error("Trying to open MFT\n");
+		return;
 	default:
-		#ifdef NTFS_IN_LINUX_KERNEL
-		ino=&inode->u.ntfs_i;
-		#else
-		/* FIXME: check for ntfs_malloc failure */
-		ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
-		inode->u.generic_ip=ino;
-		#endif
-		if(!ino || ntfs_init_inode(ino,
-					   NTFS_INO2VOL(inode),inode->i_ino))
+		ino = &inode->u.ntfs_i;
+		if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),
+								inode->i_ino))
 		{
-			ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n",
-			       (unsigned int)inode->i_ino);
+			ntfs_debug(DEBUG_OTHER, "NTFS :Error loading inode "
+					"%x\n", (unsigned int)inode->i_ino);
 			return;
 		}
 	}
 	/* Set uid/gid from mount options */
-	inode->i_uid=vol->uid;
-	inode->i_gid=vol->gid;
-	inode->i_nlink=1;
+	inode->i_uid = vol->uid;
+	inode->i_gid = vol->gid;
+	inode->i_nlink = 1;
 	/* Use the size of the data attribute as file size */
-	data = ntfs_find_attr(ino,vol->at_data,NULL);
-	if(!data)
-	{
-		inode->i_size=0;
-		can_mmap=0;
-	}
-	else
-	{
-		inode->i_size=data->size;
+	data = ntfs_find_attr(ino, vol->at_data, NULL);
+	if (!data) {
+		inode->i_size = 0;
+		can_mmap = 0;
+	} else {
+		inode->i_size = data->size;
 		/* FIXME: once ntfs_get_block is implemented, uncomment the
-		 * next line and remove the can_mmap = 0; */
-		/* can_mmap=!data->resident && !data->compressed;*/
+		 * next line and remove the "can_mmap = 0;". (AIA) */
+		/* can_mmap = !data->resident && !data->compressed; */
 		can_mmap = 0;
 	}
-	/* get the file modification times from the standard information */
-	si=ntfs_find_attr(ino,vol->at_standard_information,NULL);
-	if(si){
-		char *attr=si->d.data;
-		inode->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18));
-		inode->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr));
-		inode->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8));
+	/* Get the file modification times from the standard information. */
+	si = ntfs_find_attr(ino,vol->at_standard_information, NULL);
+	if (si) {
+		char *attr = si->d.data;
+		inode->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
+		inode->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
+		inode->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
 	}
-	/* if it has an index root, it's a directory */
-	if(ntfs_find_attr(ino,vol->at_index_root,"$I30"))
-	{
+	/* If it has an index root, it's a directory. */
+	if (ntfs_find_attr(ino, vol->at_index_root, "$I30")) {
 		ntfs_attribute *at;
-		at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30");
+		at = ntfs_find_attr(ino, vol->at_index_allocation, "$I30");
 		inode->i_size = at ? at->size : 0;
-	  
-		inode->i_op=&ntfs_dir_inode_operations;
-		inode->i_fop=&ntfs_dir_operations;
-		inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO;
-	}
-	else
-	{
+		inode->i_op = &ntfs_dir_inode_operations;
+		inode->i_fop = &ntfs_dir_operations;
+		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	} else {
 		/* As long as ntfs_get_block() is just a call to BUG() do not
 	 	 * define any [bm]map ops or we get the BUG() whenever someone
 		 * runs mc or mpg123 on an ntfs partition!
@@ -706,25 +668,24 @@
 			inode->i_mapping->a_ops = &ntfs_aops;
 			inode->u.ntfs_i.mmu_private = inode->i_size;
 		} else */ {
-			inode->i_op=&ntfs_inode_operations_nobmap;
-			inode->i_fop=&ntfs_file_operations_nommap;
+			inode->i_op = &ntfs_inode_operations_nobmap;
+			inode->i_fop = &ntfs_file_operations_nommap;
 		}
-		inode->i_mode=S_IFREG|S_IRUGO;
+		inode->i_mode = S_IFREG | S_IRUGO;
 	}
 #ifdef CONFIG_NTFS_RW
-	if(!data || !data->compressed)
-		inode->i_mode|=S_IWUGO;
+	if (!data || !data->compressed)
+		inode->i_mode |= S_IWUGO;
 #endif
 	inode->i_mode &= ~vol->umask;
 }
 
 #ifdef CONFIG_NTFS_RW
-static void 
-ntfs_write_inode (struct inode *ino, int unused)
+static void ntfs_write_inode(struct inode *ino, int unused)
 {
 	lock_kernel();
-	ntfs_debug (DEBUG_LINUX, "ntfs:write inode %x\n", ino->i_ino);
-	ntfs_update_inode (NTFS_LINO2NINO (ino));
+	ntfs_debug(DEBUG_LINUX, "ntfs_write_inode %x\n", ino->i_ino);
+	ntfs_update_inode(NTFS_LINO2NINO(ino));
 	unlock_kernel();
 }
 #endif
@@ -732,41 +693,27 @@
 static void _ntfs_clear_inode(struct inode *ino)
 {
 	lock_kernel();
-	ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n",ino->i_ino);
-#ifdef NTFS_IN_LINUX_KERNEL
-	if(ino->i_ino!=FILE_MFT)
+	ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n", ino->i_ino);
+	if (ino->i_ino != FILE_$Mft)
 		ntfs_clear_inode(&ino->u.ntfs_i);
-#else
-	if(ino->i_ino!=FILE_MFT && ino->u.generic_ip)
-	{
-		ntfs_clear_inode(ino->u.generic_ip);
-		ntfs_free(ino->u.generic_ip);
-		ino->u.generic_ip=0;
-	}
-#endif
 	unlock_kernel();
 	return;
 }
 
-/* Called when umounting a filesystem by do_umount() in fs/super.c */
+/* Called when umounting a filesystem by do_umount() in fs/super.c. */
 static void ntfs_put_super(struct super_block *sb)
 {
 	ntfs_volume *vol;
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n");
-
-	vol=NTFS_SB2VOL(sb);
-
+	vol = NTFS_SB2VOL(sb);
 	ntfs_release_volume(vol);
-	if(vol->nls_map)
+	if (vol->nls_map)
 		unload_nls(vol->nls_map);
-#ifndef NTFS_IN_LINUX_KERNEL
-	ntfs_free(vol);
-#endif
 	ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n");
 }
 
-/* Called by the kernel when asking for stats */
+/* Called by the kernel when asking for stats. */
 static int ntfs_statfs(struct super_block *sb, struct statfs *sf)
 {
 	struct inode *mft;
@@ -775,34 +722,31 @@
 	int error;
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
-	vol=NTFS_SB2VOL(sb);
-	sf->f_type=NTFS_SUPER_MAGIC;
-	sf->f_bsize=vol->clustersize;
-
-	error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &size );
-	if( error )
-		return -error;
-	sf->f_blocks = size;	/* volumesize is in clusters */
-	sf->f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
-	sf->f_bavail=sf->f_bfree;
-
-	mft=iget(sb,FILE_MFT);
+	vol = NTFS_SB2VOL(sb);
+	sf->f_type = NTFS_SUPER_MAGIC;
+	sf->f_bsize = vol->clustersize;
+	error = ntfs_get_volumesize(NTFS_SB2VOL(sb), &size);
+	if (error)
+		return error;
+	sf->f_blocks = size;	/* Volumesize is in clusters. */
+	sf->f_bfree = ntfs_get_free_cluster_count(vol->bitmap);
+	sf->f_bavail = sf->f_bfree;
+	mft = iget(sb, FILE_$Mft);
 	if (!mft)
 		return -EIO;
-	/* So ... we lie... thus this following cast of loff_t value
-	   is ok here.. */
+	/* So ... we lie... thus this following cast of loff_t value is ok
+	 * here.. */
 	sf->f_files = (unsigned long)mft->i_size / vol->mft_recordsize;
 	iput(mft);
-
-	/* should be read from volume */
-	sf->f_namelen=255;
+	/* Should be read from volume. */
+	sf->f_namelen = 255;
 	return 0;
 }
 
-/* Called when remounting a filesystem by do_remount_sb() in fs/super.c */
+/* Called when remounting a filesystem by do_remount_sb() in fs/super.c. */
 static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options)
 {
-	if(!parse_options(NTFS_SB2VOL(sb), options))
+	if (!parse_options(NTFS_SB2VOL(sb), options))
 		return -EINVAL;
 	return 0;
 }
@@ -819,144 +763,133 @@
 	clear_inode:	_ntfs_clear_inode,
 };
 
-/* Called to mount a filesystem by read_super() in fs/super.c
- * Return a super block, the main structure of a filesystem
+/* Called to mount a filesystem by read_super() in fs/super.c.
+ * Return a super block, the main structure of a filesystem.
  *
  * NOTE : Don't store a pointer to an option, as the page containing the
  * options is freed after ntfs_read_super() returns.
  *
  * NOTE : A context switch can happen in kernel code only if the code blocks
- * (= calls schedule() in kernel/sched.c).
- */
-struct super_block * ntfs_read_super(struct super_block *sb, 
-				     void *options, int silent)
+ * (= calls schedule() in kernel/sched.c). */
+struct super_block * ntfs_read_super(struct super_block *sb, void *options,
+				     int silent)
 {
 	ntfs_volume *vol;
 	struct buffer_head *bh;
 	int i;
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");
-
-#ifdef NTFS_IN_LINUX_KERNEL
 	vol = NTFS_SB2VOL(sb);
-#else
-	if(!(vol = ntfs_malloc(sizeof(ntfs_volume))))
-		goto ntfs_read_super_dec;
-	NTFS_SB2VOL(sb)=vol;
-#endif
-	
-	if(!parse_options(vol,(char*)options))
+	if (!parse_options(vol, (char*)options))
 		goto ntfs_read_super_vol;
-
 #if 0
 	/* Set to read only, user option might reset it */
 	sb->s_flags |= MS_RDONLY;
 #endif
-
-	/* Assume a 512 bytes block device for now */
+	/* Assume a 512 bytes block device for now. */
 	set_blocksize(sb->s_dev, 512);
-	/* Read the super block (boot block) */
-	if(!(bh=bread(sb->s_dev,0,512))) {
+	/* Read the super block (boot block). */
+	if (!(bh = bread(sb->s_dev, 0, 512))) {
 		ntfs_error("Reading super block failed\n");
 		goto ntfs_read_super_unl;
 	}
 	ntfs_debug(DEBUG_OTHER, "Done reading boot block\n");
-
 	/* Check for 'NTFS' magic number */
-	if(!IS_NTFS_VOLUME(bh->b_data)){
+	if (!IS_NTFS_VOLUME(bh->b_data)) {
 		ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n");
 		brelse(bh);
 		goto ntfs_read_super_unl;
 	}
-
 	ntfs_debug(DEBUG_OTHER, "Going to init volume\n");
-	ntfs_init_volume(vol,bh->b_data);
-	ntfs_debug(DEBUG_OTHER, "MFT record at cluster 0x%X\n",vol->mft_cluster);
+	if (ntfs_init_volume(vol, bh->b_data) < 0) {
+		ntfs_debug(DEBUG_OTHER, "Init volume failed.\n");
+		brelse(bh);
+		goto ntfs_read_super_unl;
+	}
+	ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%Lx\n", vol->mft_cluster);
 	brelse(bh);
-	NTFS_SB(vol)=sb;
+	NTFS_SB(vol) = sb;
 	ntfs_debug(DEBUG_OTHER, "Done to init volume\n");
-
-	/* Inform the kernel that a device block is a NTFS cluster */
-	sb->s_blocksize=vol->clustersize;
-	for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i != 1;i>>=1)
+	/* Inform the kernel that a device block is a NTFS cluster. */
+	sb->s_blocksize = vol->clustersize;
+	if (sb->s_blocksize > PAGE_SIZE) {
+		ntfs_error("Partition cluster size is not supported yet (too "
+			   "large for kernel blocksize).\n");
+		goto ntfs_read_super_unl;
+	}
+	for (i = sb->s_blocksize, sb->s_blocksize_bits = 0; i != 1; i >>= 1)
 		sb->s_blocksize_bits++;
-	set_blocksize(sb->s_dev,sb->s_blocksize);
+	set_blocksize(sb->s_dev, sb->s_blocksize);
 	ntfs_debug(DEBUG_OTHER, "set_blocksize\n");
 
-	/* Allocate a MFT record (MFT record can be smaller than a cluster) */
-	if(!(vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize))))
+	/* Allocate a MFT record (MFT record can be smaller than a cluster). */
+	if (!(vol->mft = ntfs_malloc(max(vol->mft_recordsize,
+							   vol->clustersize))))
 		goto ntfs_read_super_unl;
 
-	/* Read at least the MFT record for $MFT */
-	for(i=0;i<max(vol->mft_clusters_per_record,1);i++){
-		if(!(bh=bread(sb->s_dev,vol->mft_cluster+i,vol->clustersize))) {
-			ntfs_error("Could not read MFT record 0\n");
+	/* Read at least the MFT record for $Mft. */
+	for (i = 0; i < max(vol->mft_clusters_per_record, 1); i++) {
+		if (!(bh = bread(sb->s_dev, vol->mft_cluster + i,
+							  vol->clustersize))) {
+			ntfs_error("Could not read $Mft record 0\n");
 			goto ntfs_read_super_mft;
 		}
-		ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize);
+		ntfs_memcpy(vol->mft + i * vol->clustersize, bh->b_data,
+							     vol->clustersize);
 		brelse(bh);
-		ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i);
+		ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",
+							 vol->mft_cluster + i);
 	}
-
 	/* Check and fixup this MFT record */
-	if(!ntfs_check_mft_record(vol,vol->mft)){
-		ntfs_error("Invalid MFT record 0\n");
+	if (!ntfs_check_mft_record(vol, vol->mft)){
+		ntfs_error("Invalid $Mft record 0\n");
 		goto ntfs_read_super_mft;
 	}
-
-	/* Inform the kernel about which super operations are available */
+	/* Inform the kernel about which super operations are available. */
 	sb->s_op = &ntfs_super_operations;
 	sb->s_magic = NTFS_SUPER_MAGIC;
-	
+	sb->s_maxbytes = ~0ULL;
 	ntfs_debug(DEBUG_OTHER, "Reading special files\n");
-	if(ntfs_load_special_files(vol)){
+	if (ntfs_load_special_files(vol)) {
 		ntfs_error("Error loading special files\n");
 		goto ntfs_read_super_mft;
 	}
-
 	ntfs_debug(DEBUG_OTHER, "Getting RootDir\n");
-	/* Get the root directory */
-	if(!(sb->s_root=d_alloc_root(iget(sb,FILE_ROOT)))){
+	/* Get the root directory. */
+	if (!(sb->s_root = d_alloc_root(iget(sb, FILE_$root)))) {
 		ntfs_error("Could not get root dir inode\n");
 		goto ntfs_read_super_mft;
 	}
 	ntfs_debug(DEBUG_OTHER, "read_super: done\n");
 	return sb;
-
 ntfs_read_super_mft:
 	ntfs_free(vol->mft);
 ntfs_read_super_unl:
 ntfs_read_super_vol:
-	#ifndef NTFS_IN_LINUX_KERNEL
-	ntfs_free(vol);
-ntfs_read_super_dec:
-	#endif
 	ntfs_debug(DEBUG_OTHER, "read_super: done\n");
 	return NULL;
 }
 
-/* Define the filesystem
- */
+/* Define the filesystem */
 static DECLARE_FSTYPE_DEV(ntfs_fs_type, "ntfs", ntfs_read_super);
 
 static int __init init_ntfs_fs(void)
 {
-	/* Comment this if you trust klogd. There are reasons not to trust it
-	 */
+	/* Comment this if you trust klogd. There are reasons not to trust it */
 #if defined(DEBUG) && !defined(MODULE)
 	console_verbose();
 #endif
 	printk(KERN_NOTICE "NTFS version " NTFS_VERSION "\n");
 	SYSCTL(1);
-	ntfs_debug(DEBUG_OTHER, "registering %s\n",ntfs_fs_type.name);
-	/* add this filesystem to the kernel table of filesystems */
+	ntfs_debug(DEBUG_OTHER, "registering %s\n", ntfs_fs_type.name);
+	/* Add this filesystem to the kernel table of filesystems. */
 	return register_filesystem(&ntfs_fs_type);
 }
 
 static void __exit exit_ntfs_fs(void)
 {
 	SYSCTL(0);
-	ntfs_debug(DEBUG_OTHER, "unregistering %s\n",ntfs_fs_type.name);
+	ntfs_debug(DEBUG_OTHER, "unregistering %s\n", ntfs_fs_type.name);
 	unregister_filesystem(&ntfs_fs_type);
 }
 
@@ -970,8 +903,4 @@
 
 module_init(init_ntfs_fs)
 module_exit(exit_ntfs_fs)
-/*
- * Local variables:
- *  c-file-style: "linux"
- * End:
- */
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/inode.c linux/fs/ntfs/inode.c
--- v2.4.3/linux/fs/ntfs/inode.c	Fri Nov 17 11:35:27 2000
+++ linux/fs/ntfs/inode.c	Wed Apr 18 11:49:13 2001
@@ -1,23 +1,18 @@
-/*
- *  inode.c
+/*  inode.c
  *
  *  Copyright (C) 1995-1999 Martin von Löwis
  *  Copyright (C) 1996 Albert D. Cahalan
  *  Copyright (C) 1996-1997 Régis Duchesne
  *  Copyright (C) 1998 Joseph Malicki
  *  Copyright (C) 1999 Steve Dodd
- *  Copyright (C) 2000 Anton Altaparmakov
+ *  Copyright (C) 2000-2001 Anton Altaparmakov (AIA)
  */
 
 #include "ntfstypes.h"
 #include "ntfsendian.h"
 #include "struct.h"
 #include "inode.h"
-
 #include <linux/errno.h>
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
 #include "macros.h"
 #include "attr.h"
 #include "super.h"
@@ -27,210 +22,229 @@
 
 typedef struct {
 	int recno;
-	unsigned char* record;
+	unsigned char *record;
 } ntfs_mft_record;
 
 typedef struct {
 	int size;
 	int count;
-	ntfs_mft_record* records;
+	ntfs_mft_record *records;
 } ntfs_disk_inode;
 
-void
-ntfs_fill_mft_header(ntfs_u8*mft,int record_size,int blocksize,
-		int sequence_number)
+void ntfs_fill_mft_header(ntfs_u8 *mft, int record_size, int blocksize,
+			  int sequence_number)
 {
 	int fixup_count = record_size / blocksize + 1;
 	int attr_offset = (0x2a + (2 * fixup_count) + 7) & ~7;
 	int fixup_offset = 0x2a;
 
 	NTFS_PUTU32(mft + 0x00, 0x454c4946);	     /* FILE */
-	NTFS_PUTU16(mft + 0x04, 0x2a);		     /* offset to fixup */
-	NTFS_PUTU16(mft + 0x06, fixup_count);	     /* Number of fixups */
-	NTFS_PUTU16(mft + 0x10, sequence_number);
-	NTFS_PUTU16(mft + 0x12, 1);                  /* hard link count */
-	NTFS_PUTU16(mft + 0x14, attr_offset);	     /* Offset to attributes */
-	NTFS_PUTU16(mft + 0x16, 1);                  /*FIXME: flags ?? */
-	NTFS_PUTU32(mft + 0x18, attr_offset + 0x08);	/* In use */
-	NTFS_PUTU32(mft + 0x1c, record_size);	     /* Total size */
-
-	NTFS_PUTU16(mft + fixup_offset, 1);		/* Fixup word */
-	NTFS_PUTU32(mft + attr_offset, 0xffffffff);	/* End marker */
-}
-
-/* Search in an inode an attribute by type and name */
-ntfs_attribute* 
-ntfs_find_attr(ntfs_inode *ino,int type,char *name)
+	NTFS_PUTU16(mft + 0x04, 0x2a);		     /* Offset to fixup. */
+	NTFS_PUTU16(mft + 0x06, fixup_count);	     /* Number of fixups. */
+	NTFS_PUTU16(mft + 0x10, sequence_number);    /* Sequence number. */
+	NTFS_PUTU16(mft + 0x12, 1);                  /* Hard link count. */
+	NTFS_PUTU16(mft + 0x14, attr_offset);	     /* Offset to attributes. */
+	NTFS_PUTU16(mft + 0x16, 1);                  /* Flags: 1 = In use,
+							       2 = Directory. */
+	NTFS_PUTU32(mft + 0x18, attr_offset + 0x08); /* Bytes in use. */
+	NTFS_PUTU32(mft + 0x1c, record_size);	     /* Total allocated size. */
+	NTFS_PUTU16(mft + fixup_offset, 1);	     /* Fixup word. */
+	NTFS_PUTU32(mft + attr_offset, 0xffffffff);  /* End marker. */
+}
+
+/* Search in an inode an attribute by type and name. 
+ * FIXME: Check that when attributes are inserted all attribute list
+ * attributes are expanded otherwise need to modify this function to deal
+ * with attribute lists. (AIA) */
+ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name)
 {
 	int i;
-	if(!ino){
+	
+	if (!ino) {
 		ntfs_error("ntfs_find_attr: NO INODE!\n");
 		return 0;
 	}
-	for(i=0;i<ino->attr_count;i++)
-	{
-		if(type==ino->attrs[i].type)
-		{
-			if(!name && !ino->attrs[i].name)
-				return ino->attrs+i;
-			if(name && !ino->attrs[i].name)
-				return 0;
-			if(!name && ino->attrs[i].name)
-				return 0;
-			if(ntfs_ua_strncmp(ino->attrs[i].name,name,strlen(name))==0)
-				return ino->attrs+i;
-		}
-		if(type<ino->attrs[i].type)
+	for (i = 0; i < ino->attr_count; i++) {
+		if (type < ino->attrs[i].type)
 			return 0;
+		if (type == ino->attrs[i].type) {
+			if (!name) {
+				if (!ino->attrs[i].name)
+					return ino->attrs + i;
+			} else if (ino->attrs[i].name &&
+				   !ntfs_ua_strncmp(ino->attrs[i].name, name,
+						    strlen(name)))
+				return ino->attrs + i;
+		}
 	}
 	return 0;
 }
 
-/* FIXME: need better strategy to extend the MFT */
-static int 
-ntfs_extend_mft(ntfs_volume *vol)
-{
-	/* Try to allocate at least 0.1% of the remaining disk space
-	   for inodes. If the disk is almost full, make sure at least one
-	   inode is requested.
-	 */
-	int size,rcount,error,block;
-	ntfs_attribute* mdata,*bmp;
+/* FIXME: Need better strategy to extend the MFT. */
+static int ntfs_extend_mft(ntfs_volume *vol)
+{
+	/* Try to allocate at least 0.1% of the remaining disk space for
+	 * inodes. If the disk is almost full, make sure at least one inode is
+	 * requested. */
+	int size, rcount, error, block;
+	ntfs_attribute *mdata, *bmp;
 	ntfs_u8 *buf;
 	ntfs_io io;
 
-	mdata=ntfs_find_attr(vol->mft_ino,vol->at_data,0);
-	/* first check whether there is uninitialized space */
-	if(mdata->allocated<mdata->size+vol->mft_recordsize){
-		size=ntfs_get_free_cluster_count(vol->bitmap)*vol->clustersize;
-		block=vol->mft_recordsize;
-		size=max(size/1000,mdata->size+vol->mft_recordsize);
-		size=((size+block-1)/block)*block;
-		/* require this to be a single chunk */
-		error=ntfs_extend_attr(vol->mft_ino,mdata,&size,
-				       ALLOC_REQUIRE_SIZE);
-		/* Try again, now we have the largest available fragment */
-		if(error==ENOSPC){
-			/* round down to multiple of mft record size */
-			size=(size/vol->mft_recordsize)*vol->mft_recordsize;
-			if(!size)return ENOSPC;
-			error=ntfs_extend_attr(vol->mft_ino,mdata,&size,
-					       ALLOC_REQUIRE_SIZE);
+	mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+	/* First check whether there is uninitialized space. */
+	if (mdata->allocated < mdata->size + vol->mft_recordsize) {
+		size = ntfs_get_free_cluster_count(vol->bitmap) *
+							      vol->clustersize;
+		block = vol->mft_recordsize;
+		size = max(size / 1000, mdata->size + vol->mft_recordsize);
+		size = ((size + block - 1) / block) * block;
+		/* Require this to be a single chunk. */
+		error = ntfs_extend_attr(vol->mft_ino, mdata, &size,
+							   ALLOC_REQUIRE_SIZE);
+		/* Try again, now we have the largest available fragment. */
+		if (error == -ENOSPC) {
+			/* Round down to multiple of mft record size. */
+			size = (size / vol->mft_recordsize) *
+							   vol->mft_recordsize;
+			if (!size)
+				return -ENOSPC;
+			error = ntfs_extend_attr(vol->mft_ino, mdata, &size,
+							   ALLOC_REQUIRE_SIZE);
 		}
-		if(error)
+		if (error)
 			return error;
 	}
-	/* even though we might have allocated more than needed,
-	   we initialize only one record */
-	mdata->size+=vol->mft_recordsize;
-	
-	/* now extend the bitmap if necessary*/
-	rcount=mdata->size/vol->mft_recordsize;
-	bmp=ntfs_find_attr(vol->mft_ino,vol->at_bitmap,0);
-	if(bmp->size*8<rcount){ /* less bits than MFT records */
+	/* Even though we might have allocated more than needed, we initialize
+	 * only one record. */
+	mdata->size += vol->mft_recordsize;
+	/* Now extend the bitmap if necessary. */
+	rcount = mdata->size / vol->mft_recordsize;
+	bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
+	if (bmp->size * 8 < rcount) { /* Less bits than MFT records. */
 		ntfs_u8 buf[1];
-		/* extend bitmap by one byte */
-		error=ntfs_resize_attr(vol->mft_ino,bmp,bmp->size+1);
-		if(error)return error;
-		/* write the single byte */
-		buf[0]=0;
-		io.fn_put=ntfs_put;
-		io.fn_get=ntfs_get;
-		io.param=buf;
-		io.size=1;
-		error=ntfs_write_attr(vol->mft_ino,vol->at_bitmap,0,
-				      bmp->size-1,&io);
-		if(error)return error;
-		if(io.size!=1)return EIO;
-	}
-
-	/* now fill in the MFT header for the new block */
-	buf=ntfs_calloc(vol->mft_recordsize);
-	if(!buf)return ENOMEM;
-	ntfs_fill_mft_header(buf,vol->mft_recordsize,vol->blocksize,0);
-	ntfs_insert_fixups(buf,vol->blocksize);
-	io.param=buf;
-	io.size=vol->mft_recordsize;
+		/* Extend bitmap by one byte. */
+		error = ntfs_resize_attr(vol->mft_ino, bmp, bmp->size + 1);
+		if (error)
+			return error;
+		/* Write the single byte. */
+		buf[0] = 0;
+		io.fn_put = ntfs_put;
+		io.fn_get = ntfs_get;
+		io.param = buf;
+		io.size = 1;
+		error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0,
+					bmp->size - 1, &io);
+		if (error)
+			return error;
+		if (io.size != 1)
+			return -EIO;
+	}
+	/* Now fill in the MFT header for the new block. */
+	buf = ntfs_calloc(vol->mft_recordsize);
+	if (!buf)
+		return -ENOMEM;
+	ntfs_fill_mft_header(buf, vol->mft_recordsize, vol->blocksize, 0);
+	ntfs_insert_fixups(buf, vol->blocksize);
+	io.param = buf;
+	io.size = vol->mft_recordsize;
 	io.fn_put = ntfs_put;
 	io.fn_get = ntfs_get;
-	error=ntfs_write_attr(vol->mft_ino,vol->at_data,0,
-			      (rcount-1)*vol->mft_recordsize,&io);
-	if(error)return error;
-	if(io.size!=vol->mft_recordsize)return EIO;
-	error=ntfs_update_inode(vol->mft_ino);
-	if(error)return error;
+	error = ntfs_write_attr(vol->mft_ino, vol->at_data, 0,
+				(rcount - 1) * vol->mft_recordsize, &io);
+	if (error)
+		return error;
+	if (io.size != vol->mft_recordsize)
+		return -EIO;
+	error = ntfs_update_inode(vol->mft_ino);
+	if (error)
+		return error;
 	return 0;
 }
 
-/* Insert all attributes from the record mftno of the MFT in the inode ino */
-void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno)
+/* Insert all attributes from the record mftno of the MFT in the inode ino.
+ * FIXME: We should be performing structural consistency checks. (AIA)
+ * Return 0 on success or -errno on error. */
+static int ntfs_insert_mft_attributes(ntfs_inode* ino, char *mft, int mftno)
 {
-	int i;
+	int i, error, type, len;
 	char *it;
-	int type,len;
-	/* check for duplicate */
-	for(i=0;i<ino->record_count;i++)
-		if(ino->records[i]==mftno)
-			return;
-	/* (re-)allocate space if necessary */
-	if(ino->record_count % 8==0)
-	{
+	
+	/* Check for duplicate. */
+	for(i = 0; i < ino->record_count; i++)
+		if (ino->records[i] == mftno)
+			return 0;
+	/* (re-)allocate space if necessary. */
+	if (ino->record_count % 8 == 0)	{
 		int *new;
-		new = ntfs_malloc((ino->record_count+8)*sizeof(int));
-		if( !new )
-			return;
-		if( ino->records ) {
-			for(i=0;i<ino->record_count;i++)
+
+		new = ntfs_malloc((ino->record_count + 8) * sizeof(int));
+		if (!new)
+			return -ENOMEM;
+		if (ino->records) {
+			for (i = 0; i < ino->record_count; i++)
 				new[i] = ino->records[i];
-			ntfs_free( ino->records );
+			ntfs_free(ino->records);
 		}
 		ino->records = new;
 	}
-	ino->records[ino->record_count]=mftno;
+	ino->records[ino->record_count] = mftno;
 	ino->record_count++;
 	it = mft + NTFS_GETU16(mft + 0x14);
-	do{
-		type=NTFS_GETU32(it);
-		len=NTFS_GETU32(it+4);
-		if(type!=-1) {
-			/* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */
-			ntfs_insert_attribute(ino,it);
-		}
-		it+=len;
-	}while(type!=-1); /* attribute list ends with type -1 */
+	do {
+		type = NTFS_GETU32(it);
+		len = NTFS_GETU32(it + 4);
+		if (type != -1) {
+			error = ntfs_insert_attribute(ino, it);
+			if (error)
+				return error;
+		}
+		it += len;
+	} while (type != -1); /* Attribute list ends with type -1. */
+	return 0;
 }
 
-/* Read and insert all the attributes of an 'attribute list' attribute
-   Return the number of remaining bytes in *plen
-*/
+/* Read and insert all the attributes of an 'attribute list' attribute.
+ * Return the number of remaining bytes in *plen. */
 static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen)
 {
 	char *mft;
-	int mftno,l,error;
-	int last_mft=-1;
-	int len=*plen;
-	mft=ntfs_malloc(ino->vol->mft_recordsize);
-	if( !mft )
-		return ENOMEM;
-	while(len>8)
-	{
-		l=NTFS_GETU16(alist+4);
-		if(l>len)break;
-	        /* process an attribute description */
-		mftno=NTFS_GETU32(alist+0x10); /* BUG: this is u64 */
-		if(mftno!=last_mft){
-			last_mft=mftno;
-			/* FIXME: avoid loading record if it's 
-			   already processed */
-			error=ntfs_read_mft_record(ino->vol,mftno,mft);
-			if(error)return error;
-			ntfs_insert_mft_attributes(ino,mft,mftno);
+	int mftno, l, error;
+	int last_mft = -1;
+	int len = *plen;
+	
+	mft = ntfs_malloc(ino->vol->mft_recordsize);
+	if (!mft)
+		return -ENOMEM;
+	while (len > 8)	{
+		l = NTFS_GETU16(alist + 4);
+		if (l > len)
+			break;
+	        /* Process an attribute description. */
+		mftno = NTFS_GETU32(alist + 0x10); 
+			/* FIXME: The mft reference (alist + 0x10) is __u64.
+			* - Not a problem unless we encounter a huge partition.
+			* - Should be consistency checking the sequence numbers
+			*   though! This should maybe happen in 
+			*   ntfs_read_mft_record() itself and a hotfix could
+			*   then occur there or the user notified to run
+			*   ntfsck. (AIA) */
+		if (mftno != last_mft){
+			last_mft = mftno;
+			/* FIXME: Avoid loading record if it's already
+			 * processed. */
+			error = ntfs_read_mft_record(ino->vol, mftno, mft);
+			if (error)
+				return error;
+			error = ntfs_insert_mft_attributes(ino, mft, mftno);
+			if (error)
+				return error;
 		}
-		len-=l;
-		alist+=l;
+		len -= l;
+		alist += l;
 	}
 	ntfs_free(mft);
-	*plen=len;
+	*plen = len;
 	return 0;
 }
 
@@ -238,167 +252,176 @@
 {
 	ntfs_attribute *alist;
 	int datasize;
-	int offset,len,delta;
+	int offset, len, delta;
 	char *buf;
-	ntfs_volume *vol=ino->vol;
-	ntfs_debug(DEBUG_FILE2, "load_attributes %x 1\n",ino->i_number);
-	ntfs_insert_mft_attributes(ino,ino->attr,ino->i_number);
-	ntfs_debug(DEBUG_FILE2, "load_attributes %x 2\n",ino->i_number);
-	alist=ntfs_find_attr(ino,vol->at_attribute_list,0);
-	ntfs_debug(DEBUG_FILE2, "load_attributes %x 3\n",ino->i_number);
-	if(!alist)
+	ntfs_volume *vol = ino->vol;
+	
+	ntfs_debug(DEBUG_FILE2, "load_attributes %x 1\n", ino->i_number);
+	if (ntfs_insert_mft_attributes(ino, ino->attr, ino->i_number))
 		return;
-	ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n",ino->i_number);
-	datasize=alist->size;
-	if(alist->resident)
-	{
-		parse_attributes(ino,alist->d.data,&datasize);
+	ntfs_debug(DEBUG_FILE2, "load_attributes %x 2\n", ino->i_number);
+	alist = ntfs_find_attr(ino, vol->at_attribute_list, 0);
+	ntfs_debug(DEBUG_FILE2, "load_attributes %x 3\n", ino->i_number);
+	if (!alist)
+		return;
+	ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n", ino->i_number);
+	datasize = alist->size;
+	if (alist->resident) {
+		parse_attributes(ino, alist->d.data, &datasize);
 		return;
 	}
-	buf=ntfs_malloc(1024);
-	if( !buf )
+	buf = ntfs_malloc(1024);
+	if (!buf)    /* FIXME: Should be passing error code to caller. (AIA) */
 		return;
-	delta=0;
-	for(offset=0;datasize;datasize-=len,offset+=len)
-	{
+	delta = 0;
+	for (offset = 0; datasize; datasize -= len, offset += len) {
 		ntfs_io io;
-		io.fn_put=ntfs_put;
-		io.fn_get=0;
-		io.param=buf+delta;
-		io.size=len=min(datasize,1024-delta);
-		if(ntfs_read_attr(ino,vol->at_attribute_list,0,offset,&io)){
+		
+		io.fn_put = ntfs_put;
+		io.fn_get = 0;
+		io.param = buf + delta;
+		io.size = len = min(datasize, 1024 - delta);
+		if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset,
+				   &io))
 			ntfs_error("error in load_attributes\n");
-		}
-		delta+=len;
-		parse_attributes(ino,buf,&delta);
-		if(delta)
-			/* move remaining bytes to buffer start */
-			ntfs_memmove(buf,buf+len-delta,delta);
+		delta += len;
+		parse_attributes(ino, buf, &delta);
+		if (delta)
+			/* Move remaining bytes to buffer start. */
+			ntfs_memmove(buf, buf + len - delta, delta);
 	}
-	ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n",ino->i_number);
+	ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n", ino->i_number);
 	ntfs_free(buf);
 }
 	
-int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum)
+int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum)
 {
 	char *buf;
 	int error;
 
-	ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n",inum);
-	if(!vol)
+	ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n", inum);
+	if (!vol)
 		ntfs_error("NO VOLUME!\n");
-	ino->i_number=inum;
-	ino->vol=vol;
-	ino->attr=buf=ntfs_malloc(vol->mft_recordsize);
-	if( !buf )
-		return ENOMEM;
-	error=ntfs_read_mft_record(vol,inum,ino->attr);
-	if(error){
-		ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum);
+	ino->i_number = inum;
+	ino->vol = vol;
+	ino->attr = buf = ntfs_malloc(vol->mft_recordsize);
+	if (!buf)
+		return -ENOMEM;
+	error = ntfs_read_mft_record(vol, inum, ino->attr);
+	if (error) {
+		ntfs_debug(DEBUG_OTHER, "Init inode: %x failed\n", inum);
 		return error;
 	}
-	ntfs_debug(DEBUG_FILE2, "Init: got mft %x\n",inum);
-	ino->sequence_number=NTFS_GETU16(buf+0x10);
-	ino->attr_count=0;
-	ino->record_count=0;
-	ino->records=0;
-	ino->attrs=0;
+	ntfs_debug(DEBUG_FILE2, "Init inode: got mft %x\n", inum);
+	ino->sequence_number = NTFS_GETU16(buf + 0x10);
+	ino->attr_count = 0;
+	ino->record_count = 0;
+	ino->records = 0;
+	ino->attrs = 0;
 	ntfs_load_attributes(ino);
-	ntfs_debug(DEBUG_FILE2, "Init: done %x\n",inum);
+	ntfs_debug(DEBUG_FILE2, "Init inode: done %x\n", inum);
 	return 0;
 }
 
 void ntfs_clear_inode(ntfs_inode *ino)
 {
 	int i;
-	if(!ino->attr){
+	if (!ino->attr) {
 		ntfs_error("ntfs_clear_inode: double free\n");
 		return;
 	}
 	ntfs_free(ino->attr);
-	ino->attr=0;
+	ino->attr = 0;
 	ntfs_free(ino->records);
-	ino->records=0;
-	for(i=0;i<ino->attr_count;i++)
-	{
-		if(ino->attrs[i].name)
+	ino->records = 0;
+	for (i = 0; i < ino->attr_count; i++) {
+		if (ino->attrs[i].name)
 			ntfs_free(ino->attrs[i].name);
-		if(ino->attrs[i].resident)
-		{
-			if(ino->attrs[i].d.data)
+		if (ino->attrs[i].resident) {
+			if (ino->attrs[i].d.data)
 				ntfs_free(ino->attrs[i].d.data);
-		}else{
-			if(ino->attrs[i].d.r.runlist)
+		} else {
+			if (ino->attrs[i].d.r.runlist)
 				ntfs_free(ino->attrs[i].d.r.runlist);
 		}
 	}
 	ntfs_free(ino->attrs);
-	ino->attrs=0;
+	ino->attrs = 0;
 }
 
-/* Check and fixup a MFT record */
-int ntfs_check_mft_record(ntfs_volume *vol,char *record)
+/* Check and fixup a MFT record. */
+int ntfs_check_mft_record(ntfs_volume *vol, char *record)
 {
 	return ntfs_fixup_record(vol, record, "FILE", vol->mft_recordsize);
 }
 
 /* Return (in result) the value indicating the next available attribute 
-   chunk number. Works for inodes w/o extension records only */
+ * chunk number. Works for inodes w/o extension records only. */
 int ntfs_allocate_attr_number(ntfs_inode *ino, int *result)
 {
-	if(ino->record_count!=1)
-		return EOPNOTSUPP;
-	*result=NTFS_GETU16(ino->attr+0x28);
-	NTFS_PUTU16(ino->attr+0x28, (*result)+1);
+	if (ino->record_count != 1)
+		return -EOPNOTSUPP;
+	*result = NTFS_GETU16(ino->attr + 0x28);
+	NTFS_PUTU16(ino->attr + 0x28, (*result) + 1);
 	return 0;
 }
 
-/* find the location of an attribute in the inode. A name of NULL indicates
-   unnamed attributes. Return pointer to attribute or NULL if not found */
-char *
-ntfs_get_attr(ntfs_inode *ino,int attr,char *name)
+/* Find the location of an attribute in the inode. A name of NULL indicates
+ * unnamed attributes. Return pointer to attribute or NULL if not found. */
+char *ntfs_get_attr(ntfs_inode *ino, int attr, char *name)
 {
-	/* location of first attribute */
-	char *it= ino->attr + NTFS_GETU16(ino->attr + 0x14);
+	/* Location of first attribute. */
+	char *it = ino->attr + NTFS_GETU16(ino->attr + 0x14);
 	int type;
 	int len;
-	/* Only check for magic DWORD here, fixup should have happened before */
-	if(!IS_MFT_RECORD(ino->attr))return 0;
-	do{
-		type=NTFS_GETU32(it);
-		len=NTFS_GETU16(it+4);
+	
+	/* Only check for magic DWORD here, fixup should have happened before.*/
+	if (!IS_MFT_RECORD(ino->attr))
+		return 0;
+	do {
+		type = NTFS_GETU32(it);
+		len = NTFS_GETU16(it + 4);
 		/* We found the attribute type. Is the name correct, too? */
-		if(type==attr)
-		{
-			int namelen=NTFS_GETU8(it+9);
-			char *name_it;
-			/* match given name and attribute name if present,
-			   make sure attribute name is Unicode */
-			for(name_it=it+NTFS_GETU16(it+10);namelen;
-			    name++,name_it+=2,namelen--)
-				if(*name_it!=*name || name_it[1])break;
-			if(!namelen)break;
-		}
-		it+=len;
-	}while(type!=-1); /* attribute list end with type -1 */
-	if(type==-1)return 0;
+		if (type == attr) {
+			int namelen = NTFS_GETU8(it + 9);
+			char *name_it, *n = name;
+			/* Match given name and attribute name if present.
+			   Make sure attribute name is Unicode. */
+			if (!name) {
+				goto check_namelen;
+			} else if (namelen) {
+				for (name_it = it + NTFS_GETU16(it + 10);
+				     namelen; n++, name_it += 2, namelen--)
+					if (*name_it != *n || name_it[1])
+						break;
+check_namelen:
+				if (!namelen)
+					break;
+			}
+		}
+		it += len;
+	} while (type != -1); /* List of attributes ends with type -1. */
+	if (type == -1)
+		return 0;
 	return it;
 }
 
-int 
-ntfs_get_attr_size(ntfs_inode*ino,int type,char*name)
+int ntfs_get_attr_size(ntfs_inode *ino, int type, char *name)
 {
-	ntfs_attribute *attr=ntfs_find_attr(ino,type,name);
-	if(!attr)return 0;
-	return attr->size;
+	ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
+	if (!attr)
+		return 0;
+	return
+		attr->size;
 }
 	
-int 
-ntfs_attr_is_resident(ntfs_inode*ino,int type,char*name)
+int ntfs_attr_is_resident(ntfs_inode *ino, int type, char *name)
 {
-	ntfs_attribute *attr=ntfs_find_attr(ino,type,name);
-	if(!attr)return 0;
-	return attr->resident;
+	ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
+	if (!attr)
+		return 0;
+	return
+		attr->resident;
 }
 	
 /*
@@ -413,489 +436,520 @@
  * This function decodes a run. Length is an output parameter, data and cluster
  * are in/out parameters.
  */
-int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster,
-	int *ctype)
+int ntfs_decompress_run(unsigned char **data, int *length, 
+			ntfs_cluster_t *cluster, int *ctype)
 {
-	unsigned char type=*(*data)++;
-	*ctype=0;
-	switch(type & 0xF)
-	{
-	case 1: *length=NTFS_GETU8(*data);break;
-	case 2: *length=NTFS_GETU16(*data);break;
-	case 3: *length=NTFS_GETU24(*data);break;
-        case 4: *length=NTFS_GETU32(*data);break;
-        	/* Note: cases 5-8 are probably pointless to code,
-        	   since how many runs > 4GB of length are there?
-        	   at the most, cases 5 and 6 are probably necessary,
-        	   and would also require making length 64-bit
-        	   throughout */
+	unsigned char type = *(*data)++;
+	*ctype = 0;
+	switch (type & 0xF) {
+	case 1: 
+		*length = NTFS_GETS8(*data);
+		break;
+	case 2: 
+		*length = NTFS_GETS16(*data);
+		break;
+	case 3: 
+		*length = NTFS_GETS24(*data);
+		break;
+        case 4: 
+		*length = NTFS_GETS32(*data);
+		break;
+        	/* Note: cases 5-8 are probably pointless to code, since how
+		 * many runs > 4GB of length are there? At the most, cases 5
+		 * and 6 are probably necessary, and would also require making
+		 * length 64-bit throughout. */
 	default:
-		ntfs_error("Can't decode run type field %x\n",type);
+		ntfs_error("Can't decode run type field %x\n", type);
 		return -1;
 	}
-	*data+=(type & 0xF);
-
-	switch(type & 0xF0)
+	if (*length < 0)
 	{
-	case 0:	   *ctype=2; break;
-	case 0x10: *cluster += NTFS_GETS8(*data);break;
-	case 0x20: *cluster += NTFS_GETS16(*data);break;
-	case 0x30: *cluster += NTFS_GETS24(*data);break;
-	case 0x40: *cluster += NTFS_GETS32(*data);break;
-#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit */
-	case 0x50: *cluster += NTFS_GETS40(*data);break;
-	case 0x60: *cluster += NTFS_GETS48(*data);break;
-	case 0x70: *cluster += NTFS_GETS56(*data);break;
-	case 0x80: *cluster += NTFS_GETS64(*data);break;	
+		ntfs_error("Negative run length decoded\n");
+		return -1;
+	}
+	*data += (type & 0xF);
+	switch (type & 0xF0) {
+	case 0:
+		*ctype = 2;
+		break;
+	case 0x10:
+		*cluster += NTFS_GETS8(*data);
+		break;
+	case 0x20:
+		*cluster += NTFS_GETS16(*data);
+		break;
+	case 0x30:
+		*cluster += NTFS_GETS24(*data);
+		break;
+	case 0x40:
+		*cluster += NTFS_GETS32(*data);
+		break;
+#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit. */
+	case 0x50: 
+		*cluster += NTFS_GETS40(*data);
+		break;
+	case 0x60: 
+		*cluster += NTFS_GETS48(*data);
+		break;
+	case 0x70: 
+		*cluster += NTFS_GETS56(*data);
+		break;
+	case 0x80: 
+		*cluster += NTFS_GETS64(*data);
+		break;
 #endif
 	default:
-		ntfs_error("Can't decode run type field %x\n",type);
+		ntfs_error("Can't decode run type field %x\n", type);
 		return -1;
 	}
-	*data+=(type >> 4);
+	*data += (type >> 4);
 	return 0;
 }
 
-/* Reads l bytes of the attribute (attr,name) of ino starting at offset
-   on vol into buf. Returns the number of bytes read in the ntfs_io struct.
-   Returns 0 on success, errno on failure */
+/*
+ * FIXME: ntfs_readwrite_attr() has the effect of writing @dest to @offset of
+ * the attribute value of the attribute @attr in the in memory inode @ino.
+ * If the attribute value of @attr is non-resident the value's contents at
+ * @offset are actually written to disk (from @dest). The on disk mft record
+ * describing the non-resident attribute value is not updated!
+ * If the attribute value is resident then the value is written only in
+ * memory. The on disk mft record containing the value is not written to disk.
+ * A possible fix would be to call ntfs_update_inode() before returning. (AIA)
+ */
+/* Reads l bytes of the attribute (attr, name) of ino starting at offset on
+ * vol into buf. Returns the number of bytes read in the ntfs_io struct.
+ * Returns 0 on success, errno on failure */
 int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
-	ntfs_io *dest)
+			ntfs_io *dest)
 {
 	int rnum;
-	ntfs_cluster_t cluster,s_cluster,vcn,len;
-	int l,chunk,copied;
+	ntfs_cluster_t cluster, s_cluster, vcn, len;
+	int l, chunk, copied;
 	int s_vcn;
 	int clustersize;
 	int error;
 
-	clustersize=ino->vol->clustersize;
-	l=dest->size;
-	if(l==0)
+	clustersize = ino->vol->clustersize;
+	l = dest->size;
+	if (l == 0)
 		return 0;
-	if(dest->do_read)
-	{
-		/* if read _starts_ beyond end of stream, return nothing */
-		if(offset>=attr->size){
-			dest->size=0;
+	if (dest->do_read) {
+		/* If read _starts_ beyond end of stream, return nothing. */
+		if (offset >= attr->size) {
+			dest->size = 0;
 			return 0;
 		}
-
-		/* if read _extends_ beyond end of stream, return as much
-			initialised data as we have */
-		if(offset+l>=attr->size) 
-			l=dest->size=attr->size-offset;
-
-	}else {
-		/* fixed by CSA: if writing beyond end, extend attribute */
-
-		/* if write extends beyond _allocated_ size, extend attrib */
-		if (offset+l>attr->allocated) {
-			error=ntfs_resize_attr(ino,attr,offset+l);
-			if(error)
+		/* If read _extends_ beyond end of stream, return as much
+		 * initialised data as we have. */
+		if (offset + l >= attr->size)
+			l = dest->size = attr->size - offset;
+	} else {
+		/* Fixed by CSA: If writing beyond end, extend attribute. */
+		/* If write extends beyond _allocated_ size, extend attrib. */
+		if (offset + l > attr->allocated) {
+			error = ntfs_resize_attr(ino, attr, offset + l);
+			if (error)
 				return error;
 		}
-
-		/* the amount of initialised data has increased; update */
-		/* FIXME: shouldn't we zero-out the section between the old
-			initialised length and the write start? */
-		if (offset+l > attr->initialized) {
-			attr->initialized = offset+l;
-			attr->size = offset+l;
+		/* The amount of initialised data has increased: update. */
+		/* FIXME: Shouldn't we zero-out the section between the old
+		 * 	  initialised length and the write start? */
+		if (offset + l > attr->initialized) {
+			attr->initialized = offset + l;
+			attr->size = offset + l;
 		}
 	}
-	if(attr->resident)
-	{
-		if(dest->do_read)
-			dest->fn_put(dest,(ntfs_u8*)attr->d.data+offset,l);
+	if (attr->resident) {
+		if (dest->do_read)
+			dest->fn_put(dest, (ntfs_u8*)attr->d.data + offset, l);
 		else
-			dest->fn_get((ntfs_u8*)attr->d.data+offset,dest,l);
-		dest->size=l;
+			dest->fn_get((ntfs_u8*)attr->d.data + offset, dest, l);
+		dest->size = l;
 		return 0;
 	}
-	/* read uninitialized data */
-	if(offset>=attr->initialized && dest->do_read)
-		return ntfs_read_zero(dest,l);
-	if(offset+l>attr->initialized && dest->do_read)
-	{
-		dest->size = chunk = offset+l - attr->initialized;
-		error = ntfs_readwrite_attr(ino,attr,offset,dest);
-		if(error)
+	/* Read uninitialized data. */
+	if (offset >= attr->initialized && dest->do_read)
+		return ntfs_read_zero(dest, l);
+	if (offset + l > attr->initialized && dest->do_read) {
+		dest->size = chunk = offset + l - attr->initialized;
+		error = ntfs_readwrite_attr(ino, attr, offset, dest);
+		if (error)
 			return error;		
-		return ntfs_read_zero(dest,l-chunk);
+		return ntfs_read_zero(dest, l - chunk);
 	}
-	if(attr->compressed){
-		if(dest->do_read)
-			return ntfs_read_compressed(ino,attr,offset,dest);
+	if (attr->compressed) {
+		if (dest->do_read)
+			return ntfs_read_compressed(ino, attr, offset, dest);
 		else
-			return ntfs_write_compressed(ino,attr,offset,dest);
+			return ntfs_write_compressed(ino, attr, offset, dest);
 	}
-	vcn=0;
-	s_vcn = offset/clustersize;
-	for(rnum=0;rnum<attr->d.r.len && 
-		    vcn+attr->d.r.runlist[rnum].len<=s_vcn;rnum++)
-		vcn+=attr->d.r.runlist[rnum].len;
-	if(rnum==attr->d.r.len)
-		/*FIXME: should extend runlist */
-		return EOPNOTSUPP;
-	
-	copied=0;
-	while(l)
-	{
-		s_vcn = offset/clustersize;
-		cluster=attr->d.r.runlist[rnum].cluster;
-		len=attr->d.r.runlist[rnum].len;
-
-		s_cluster = cluster+s_vcn-vcn;
-			
-		chunk=min((vcn+len)*clustersize-offset,l);
-		dest->size=chunk;
-		error=ntfs_getput_clusters(ino->vol,s_cluster,
-					   offset-s_vcn*clustersize,dest);
-		if(error)
-		{
-			ntfs_error("Read error\n");
-			dest->size=copied;
+	vcn = 0;
+	s_vcn = offset / clustersize;
+	for (rnum = 0; rnum < attr->d.r.len && 
+		       vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++)
+		vcn += attr->d.r.runlist[rnum].len;
+	if (rnum == attr->d.r.len)
+		/*FIXME: Should extend runlist. */
+		return -EOPNOTSUPP;
+	copied = 0;
+	while (l) {
+		s_vcn = offset / clustersize;
+		cluster = attr->d.r.runlist[rnum].cluster;
+		len = attr->d.r.runlist[rnum].len;
+		s_cluster = cluster + s_vcn - vcn;
+		chunk = min((vcn + len) * clustersize - offset, l);
+		dest->size = chunk;
+		error = ntfs_getput_clusters(ino->vol, s_cluster, 
+					   offset - s_vcn * clustersize, dest);
+		if (error) {
+			ntfs_error("Read/write error\n");
+			dest->size = copied;
 			return error;
 		}
-		l-=chunk;
-		copied+=chunk;
-		offset+=chunk;
-		if(l && offset>=((vcn+len)*clustersize))
-		{
+		l -= chunk;
+		copied += chunk;
+		offset += chunk;
+		if (l && offset >= ((vcn + len) * clustersize))	{
 			rnum++;
-			vcn+=len;
+			vcn += len;
 			cluster = attr->d.r.runlist[rnum].cluster;
 			len = attr->d.r.runlist[rnum].len;
 		}
 	}
-	dest->size=copied;
+	dest->size = copied;
 	return 0;
 }
 
 int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset,
-        ntfs_io *buf)
+		   ntfs_io *buf)
 {
 	ntfs_attribute *attr;
-	buf->do_read=1;
-	attr=ntfs_find_attr(ino,type,name);
-	if(!attr)
-		return EINVAL;
-	return ntfs_readwrite_attr(ino,attr,offset,buf);
+
+	buf->do_read = 1;
+	attr = ntfs_find_attr(ino, type, name);
+	if (!attr)
+		return -EINVAL;
+	return ntfs_readwrite_attr(ino, attr, offset, buf);
 }
 
 int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset,
-		ntfs_io *buf)
+		    ntfs_io *buf)
 {
 	ntfs_attribute *attr;
-	buf->do_read=0;
-	attr=ntfs_find_attr(ino,type,name);
-	if(!attr)
-		return EINVAL;
-	return ntfs_readwrite_attr(ino,attr,offset,buf);
+	
+	buf->do_read = 0;
+	attr = ntfs_find_attr(ino, type, name);
+	if (!attr)
+		return -EINVAL;
+	return ntfs_readwrite_attr(ino, attr, offset, buf);
 }
 
-int ntfs_vcn_to_lcn(ntfs_inode *ino,int vcn)
+int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn)
 {
 	int rnum;
 	ntfs_attribute *data;
-	data=ntfs_find_attr(ino,ino->vol->at_data,0);
-	/* It's hard to give an error code */
-	if(!data)return -1;
-	if(data->resident)return -1;
-	if(data->compressed)return -1;
-	if(data->size <= vcn*ino->vol->clustersize)return -1;
-
-
+	
+	data = ntfs_find_attr(ino, ino->vol->at_data, 0);
+	/* It's hard to give an error code. */
+	if (!data || data->resident || data->compressed)
+		return -1;
+	if (data->size <= vcn*ino->vol->clustersize)
+		return -1;
 	/* For Linux, block number 0 represents a hole.
-	   Hopefully, nobody will attempt to bmap $Boot. */
-	if(data->initialized <= vcn*ino->vol->clustersize)
+	 * Hopefully, nobody will attempt to bmap $Boot. */
+	if (data->initialized <= vcn * ino->vol->clustersize)
 		return 0;
-
-	for(rnum=0;rnum<data->d.r.len && 
-		    vcn>=data->d.r.runlist[rnum].len;rnum++)
-		vcn-=data->d.r.runlist[rnum].len;
-	
-	return data->d.r.runlist[rnum].cluster+vcn;
+	for (rnum = 0; rnum < data->d.r.len &&
+		       vcn >= data->d.r.runlist[rnum].len; rnum++)
+		vcn -= data->d.r.runlist[rnum].len;
+	return data->d.r.runlist[rnum].cluster + vcn;
 }
 
-static int 
-allocate_store(ntfs_volume *vol,ntfs_disk_inode *store,int count)
+static int allocate_store(ntfs_volume *vol, ntfs_disk_inode *store, int count)
 {
 	int i;
-	if(store->count>count)
+	
+	if (store->count > count)
 		return 0;
-	if(store->size<count){
-		ntfs_mft_record* n=ntfs_malloc((count+4)*sizeof(ntfs_mft_record));
-		if(!n)
-			return ENOMEM;
-		if(store->size){
-			for(i=0;i<store->size;i++)
-				n[i]=store->records[i];
+	if (store->size < count) {
+		ntfs_mft_record *n = ntfs_malloc((count + 4) * 
+						 sizeof(ntfs_mft_record));
+		if (!n)
+			return -ENOMEM;
+		if (store->size) {
+			for (i = 0; i < store->size; i++)
+				n[i] = store->records[i];
 			ntfs_free(store->records);
 		}
-		store->size=count+4;
-		store->records=n;
+		store->size = count + 4;
+		store->records = n;
 	}
-	for(i=store->count;i<count;i++){
-		store->records[i].record=ntfs_malloc(vol->mft_recordsize);
-		if(!store->records[i].record)
-			return ENOMEM;
+	for (i = store->count; i < count; i++) {
+		store->records[i].record = ntfs_malloc(vol->mft_recordsize);
+		if (!store->records[i].record)
+			return -ENOMEM;
 		store->count++;
 	}
 	return 0;
 }
 
-static void 
-deallocate_store(ntfs_disk_inode* store)
+static void deallocate_store(ntfs_disk_inode* store)
 {
 	int i;
-	for(i=0;i<store->count;i++)
+	
+	for (i = 0; i < store->count; i++)
 		ntfs_free(store->records[i].record);
 	ntfs_free(store->records);
-	store->count=store->size=0;
-	store->records=0;
+	store->count = store->size = 0;
+	store->records = 0;
 }
 
-int 
-layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size)
+/**
+ * layout_runs - compress runlist into mapping pairs array
+ * @attr:	attribute containing the runlist to compress
+ * @rec:	destination buffer to hold the mapping pairs array
+ * @offs:	current position in @rec (in/out variable)
+ * @size:	size of the buffer @rec
+ *
+ * layout_runs walks the runlist in @attr, compresses it and writes it out the
+ * resulting mapping pairs array into @rec (up to a maximum of @size bytes are
+ * written). On entry @offs is the offset in @rec at which to begin writting the
+ * mapping pairs array. On exit, it contains the offset in @rec of the first
+ * byte after the end of the mapping pairs array.
+ */
+static int layout_runs(ntfs_attribute *attr, char* rec, int* offs, int size)
 {
-	int i,len,offset,coffs;
-	ntfs_cluster_t cluster,rclus;
-	ntfs_runlist *rl=attr->d.r.runlist;
-	cluster=0;
-	offset=*offs;
-	for(i=0;i<attr->d.r.len;i++){
-		rclus=rl[i].cluster-cluster;
-		len=rl[i].len;
-		rec[offset]=0;
-		if(offset+8>size)
-			return E2BIG; /* it might still fit, but this simplifies testing */
-		if(len<0x100){
-			NTFS_PUTU8(rec+offset+1,len);
-			coffs=1;
-		}else if(len<0x10000){
-			NTFS_PUTU16(rec+offset+1,len);
-			coffs=2;
-		}else if(len<0x1000000){
-			NTFS_PUTU24(rec+offset+1,len);
-			coffs=3;
-		}else{
-			NTFS_PUTU32(rec+offset+1,len);
-			coffs=4;
-		}
-    
-		*(rec+offset)|=coffs++;
-
-		if(rl[i].cluster==MAX_CLUSTER_T) /*compressed run*/
-			/*nothing*/;
-		else if(rclus>-0x80 && rclus<0x7F){
-			*(rec+offset)|=0x10;
-			NTFS_PUTS8(rec+offset+coffs,rclus);
-			coffs+=1;
-		}else if(rclus>-0x8000 && rclus<0x7FFF){
-			*(rec+offset)|=0x20;
-			NTFS_PUTS16(rec+offset+coffs,rclus);
-			coffs+=2;
-		}else if(rclus>-0x800000 && rclus<0x7FFFFF){
-			*(rec+offset)|=0x30;
-			NTFS_PUTS24(rec+offset+coffs,rclus);
-			coffs+=3;
-		}else
-#if 0 /* In case ntfs_cluster_t ever becomes 64bit */
-	       	if (rclus>-0x80000000LL && rclus<0x7FFFFFFF)
+	int i, len, offset, coffs;
+	ntfs_cluster_t cluster, rclus;
+	ntfs_runlist *rl = attr->d.r.runlist;
+	cluster = 0;
+	offset = *offs;
+	for (i = 0; i < attr->d.r.len; i++) {
+		rclus = rl[i].cluster - cluster;
+		len = rl[i].len;
+		rec[offset] = 0;
+ 		if (offset + 9 > size)
+			return -E2BIG; /* It might still fit, but this
+					* simplifies testing. */
+		/* Run length is stored as signed number. */
+		if (len <= 0x7F) {
+			NTFS_PUTU8(rec + offset + 1, len);
+			coffs = 1;
+ 		} else if (len <= 0x7FFF) {
+			NTFS_PUTU16(rec + offset + 1, len);
+			coffs = 2;
+ 		} else if (len <= 0x7FFFFF) {
+			NTFS_PUTU24(rec + offset + 1, len);
+			coffs = 3;
+		} else {
+			NTFS_PUTU32(rec + offset + 1, len);
+			coffs = 4;
+		}
+    		*(rec + offset) |= coffs++;
+		if (rl[i].cluster == MAX_CLUSTER_T) /* Compressed run. */
+			/* Nothing */;
+		else if (rclus >= -0x80 && rclus <= 0x7F) {
+			*(rec + offset) |= 0x10;
+			NTFS_PUTS8(rec + offset + coffs, rclus);
+			coffs += 1;
+		} else if(rclus >= -0x8000 && rclus <= 0x7FFF) {
+			*(rec + offset) |= 0x20;
+			NTFS_PUTS16(rec + offset + coffs, rclus);
+			coffs += 2;
+		} else if(rclus >= -0x800000 && rclus <= 0x7FFFFF) {
+			*(rec + offset) |= 0x30;
+			NTFS_PUTS24(rec + offset + coffs, rclus);
+			coffs += 3;
+		} else
+#if 0 /* In case ntfs_cluster_t ever becomes 64bit. */
+	       	if (rclus >= -0x80000000LL && rclus <= 0x7FFFFFFF)
 #endif
 		{
-			*(rec+offset)|=0x40;
-			NTFS_PUTS32(rec+offset+coffs,rclus);
-			coffs+=4;
+			*(rec + offset) |= 0x40;
+			NTFS_PUTS32(rec + offset + coffs, rclus);
+			coffs += 4;
 		}
 #if 0 /* For 64-bit ntfs_cluster_t */
-		else if (rclus>-0x8000000000 && rclus<0x7FFFFFFFFF){
-			*(rec+offset)|=0x50;
-			NTFS_PUTS40(rec+offset+coffs,rclus);
-			coffs+=5;
-		}else if (rclus>-0x800000000000 && rclus<0x7FFFFFFFFFFF){
-			*(rec+offset)|=0x60;
-			NTFS_PUTS48(rec+offset+coffs,rclus);
-			coffs+=6;
-		}else if (rclus>-0x80000000000000 && rclus<0x7FFFFFFFFFFFFF){
-			*(rec+offset)|=0x70;
-			NTFS_PUTS56(rec+offset+coffs,rclus);
-			coffs+=7;
-		}else{
-			*(rec+offset)|=0x80;
-			NTFS_PUTS64(rec+offset+coffs,rclus);
-			coffs+=8;
+		else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) {
+			*(rec + offset) |= 0x50;
+			NTFS_PUTS40(rec + offset + coffs, rclus);
+			coffs += 5;
+		} else if (rclus >= -0x800000000000 && 
+						rclus <= 0x7FFFFFFFFFFF) {
+			*(rec + offset) |= 0x60;
+			NTFS_PUTS48(rec + offset + coffs, rclus);
+			coffs += 6;
+		} else if (rclus >= -0x80000000000000 && 
+						rclus <= 0x7FFFFFFFFFFFFF) {
+			*(rec + offset) |= 0x70;
+			NTFS_PUTS56(rec + offset + coffs, rclus);
+			coffs += 7;
+		} else {
+			*(rec + offset) |= 0x80;
+			NTFS_PUTS64(rec + offset + coffs, rclus);
+			coffs += 8;
 		}
 #endif
-		offset+=coffs;
-		if(rl[i].cluster)
-			cluster=rl[i].cluster;
-	}
-	if(offset>=size)
-		return E2BIG;
-	/* terminating null */
-	*(rec+offset++)=0;
-	*offs=offset;
+		offset += coffs;
+		if (rl[i].cluster)
+			cluster = rl[i].cluster;
+	}
+	if (offset >= size)
+		return -E2BIG;
+	/* Terminating null. */
+	*(rec + offset++) = 0;
+	*offs = offset;
 	return 0;
 }
 
-static void 
-count_runs(ntfs_attribute *attr,char *buf)
+static void count_runs(ntfs_attribute *attr, char *buf)
 {
-	ntfs_u32 first,count,last,i;
-	first=0;
-	for(i=0,count=0;i<attr->d.r.len;i++)
-		count+=attr->d.r.runlist[i].len;
-	last=first+count-1;
-
-	NTFS_PUTU64(buf+0x10,first);
-	NTFS_PUTU64(buf+0x18,last);
+	ntfs_u32 first, count, last, i;
+	
+	first = 0;
+	for (i = 0, count = 0; i < attr->d.r.len; i++)
+		count += attr->d.r.runlist[i].len;
+	last = first + count - 1;
+	NTFS_PUTU64(buf + 0x10, first);
+	NTFS_PUTU64(buf + 0x18, last);
 } 
 
-static int
-layout_attr(ntfs_attribute* attr,char*buf, int size,int *psize)
+/**
+ * layout_attr - convert in memory attribute to on disk attribute record
+ * @attr:	in memory attribute to convert
+ * @buf:	destination buffer for on disk attribute record
+ * @size:	size of the destination buffer
+ * @psize:	size of converted on disk attribute record (out variable)
+ *
+ * layout_attr takes the attribute @attr and converts it into the appropriate
+ * on disk structure, writing it into @buf (up to @size bytes are written).
+ * On return, @psize contains the actual size of the on disk attribute written
+ * into @buf.
+ */
+static int layout_attr(ntfs_attribute* attr, char *buf, int size, int *psize)
 {
-	int asize,error;
-	if(size<10)return E2BIG;
-	NTFS_PUTU32(buf,attr->type);
-	/* fill in length later */
-	NTFS_PUTU8(buf+8,attr->resident ? 0:1);
-	NTFS_PUTU8(buf+9,attr->namelen);
-	/* fill in offset to name later */
-	NTFS_PUTU16(buf+0xA,0);
-	NTFS_PUTU16(buf+0xC,attr->compressed);
-	/* FIXME: assign attribute ID??? */
-	NTFS_PUTU16(buf+0xE,attr->attrno);
-	if(attr->resident){
-		if(size<attr->size+0x18+attr->namelen)return E2BIG;
-		asize=0x18;
-		NTFS_PUTU32(buf+0x10,attr->size);
-		NTFS_PUTU16(buf+0x16,attr->indexed);
-		if(attr->name){
-			ntfs_memcpy(buf+asize,attr->name,2*attr->namelen);
-			NTFS_PUTU16(buf+0xA,asize);
-			asize+=2*attr->namelen;
-			asize=(asize+7) & ~7;
-		}
-		NTFS_PUTU16(buf+0x14,asize);
-		ntfs_memcpy(buf+asize,attr->d.data,attr->size);
-		asize+=attr->size;
-	}else{
+	int asize, error;
+	if (size < 10)
+		return -E2BIG;
+	NTFS_PUTU32(buf, attr->type);
+	/* Fill in length later. */
+	NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1);
+	NTFS_PUTU8(buf + 9, attr->namelen);
+	/* Fill in offset to name later. */
+	NTFS_PUTU16(buf + 0xA, 0);
+	NTFS_PUTU16(buf + 0xC, attr->compressed);
+	/* Assign attribute instance. */
+	NTFS_PUTU16(buf + 0xE, attr->attrno);
+	if (attr->resident) {
+		if (size < attr->size + 0x18 + attr->namelen)
+			return -E2BIG;
+		asize = 0x18;
+		NTFS_PUTU32(buf + 0x10, attr->size);
+		NTFS_PUTU16(buf + 0x16, attr->indexed);
+		if (attr->name) {
+			ntfs_memcpy(buf + asize, attr->name, 2 * attr->namelen);
+			NTFS_PUTU16(buf + 0xA, asize);
+			asize += 2 * attr->namelen;
+			asize = (asize + 7) & ~7;
+		}
+		NTFS_PUTU16(buf + 0x14, asize);
+		ntfs_memcpy(buf + asize, attr->d.data, attr->size);
+		asize += attr->size;
+	} else {
 		/* FIXME: fragments */
-		count_runs(attr,buf);
-		/* offset to data is added later */
-		NTFS_PUTU16(buf+0x22,attr->cengine);
-		NTFS_PUTU32(buf+0x24,0);
-		NTFS_PUTU64(buf+0x28,attr->allocated);
-		NTFS_PUTU64(buf+0x30,attr->size);
-		NTFS_PUTU64(buf+0x38,attr->initialized);
-		if(attr->compressed){
-			NTFS_PUTU64(buf+0x40,attr->compsize);
-			asize=0x48;
-		}else
-			asize=0x40;
-		if(attr->name){
-			NTFS_PUTU16(buf+0xA,asize);
-			ntfs_memcpy(buf+asize,attr->name,2*attr->namelen);
-			asize+=2*attr->namelen;
-			/* SRD: you whaaa?
-			asize=(asize+7) & ~7;*/
-		}
-		/* asize points at the beginning of the data */
-		NTFS_PUTU16(buf+0x20,asize);
-		error=layout_runs(attr,buf,&asize,size);
-		/* now asize pointes at the end of the data */
-		if(error)
+		count_runs(attr, buf);
+		/* Offset to data is added later. */
+		NTFS_PUTU16(buf + 0x22, attr->cengine);
+		NTFS_PUTU32(buf + 0x24, 0);
+		NTFS_PUTU64(buf + 0x28, attr->allocated);
+		NTFS_PUTU64(buf + 0x30, attr->size);
+		NTFS_PUTU64(buf + 0x38, attr->initialized);
+		if (attr->compressed) {
+			NTFS_PUTU64(buf + 0x40, attr->compsize);
+			asize = 0x48;
+		} else
+			asize = 0x40;
+		if (attr->name) {
+			NTFS_PUTU16(buf + 0xA, asize);
+			ntfs_memcpy(buf + asize, attr->name, 2 * attr->namelen);
+			asize += 2 * attr->namelen;
+			/* SRD: you whaaa? - AIA: Align to next 8 byte boundary
+			 * as required by NTFS design and implementation. */
+			asize = (asize + 7) & ~7;
+		}
+		/* asize points at the beginning of the data. */
+		NTFS_PUTU16(buf + 0x20, asize);
+		error = layout_runs(attr, buf, &asize, size);
+		/* Now asize points at the end of the data. */
+		if (error)
 			return error;
 	}
-	asize=(asize+7) & ~7;
-	NTFS_PUTU32(buf+4,asize);
-	*psize=asize;
+	asize = (asize + 7) & ~7;
+	NTFS_PUTU32(buf + 4, asize);
+	*psize = asize;
 	return 0;
 }
-		
-		
 
-/* Try to layout ino into store. Return 0 on success,
-   E2BIG if it does not fit, 
-   ENOMEM if memory allocation problem,
-   EOPNOTSUP if beyond our capabilities 
-*/
-int 
-layout_inode(ntfs_inode *ino,ntfs_disk_inode *store)
+/**
+ * layout_inode - convert an in memory inode into on disk mft record(s)
+ * @ino:	in memory inode to convert
+ * @store:	on disk inode, contain buffers for the on disk mft record(s)
+ *
+ * layout_inode takes the in memory inode @ino, converts it into a (sequence of)
+ * mft record(s) and writes them to the appropriate buffers in the @store.
+ *
+ * Return 0 on success,
+ * the required mft record count (>0) if the inode does not fit,
+ * -ENOMEM if memory allocation problem or
+ * -EOPNOTSUP if beyond our capabilities.
+ */
+int layout_inode(ntfs_inode *ino, ntfs_disk_inode *store)
 {
-	int offset,i;
+	int offset, i;
 	ntfs_attribute *attr;
 	unsigned char *rec;
-	int size,psize;
+	int size, psize;
 	int error;
 
-	if(ino->record_count>1)
-	{
+	if (ino->record_count > 1) {
 		ntfs_error("layout_inode: attribute lists not supported\n");
-		return EOPNOTSUPP;
+		return -EOPNOTSUPP;
 	}
-	error=allocate_store(ino->vol,store,1);
-	if(error)
+	error = allocate_store(ino->vol, store, 1);
+	if (error)
 		return error;
-	rec=store->records[0].record;
-	size=ino->vol->mft_recordsize;
-	store->records[0].recno=ino->records[0];
-	/* copy header */
-	offset=NTFS_GETU16(ino->attr+0x14);
-	ntfs_memcpy(rec,ino->attr,offset);
-	for(i=0;i<ino->attr_count;i++){
-		attr=ino->attrs+i;
-		error=layout_attr(attr,rec+offset,size-offset,&psize);
-		if(error)return error;
-		offset+=psize;
-#if 0
-		/* copy attribute header */
-		ntfs_memcpy(rec+offset,attr->header,
-			    min(sizeof(attr->header),size-offset)); /* consider overrun */
-		if(attr->namelen)
-			/* named attributes are added later */
-			return EOPNOTSUPP;
-		/* FIXME: assign attribute ID??? */
-		if(attr->resident){
-			asize=attr->size;
-			aoffset=NTFS_GETU16(rec+offset+0x14);
-			if(offset+aoffset+asize>size)
-				return E2BIG;
-			ntfs_memcpy(rec+offset+aoffset,attr->d.data,asize);
-			next=offset+aoffset+asize;
-		}else{
-			count_runs(attr,rec+offset);
-			aoffset=NTFS_GETU16(rec+offset+0x20);
-			next=offset+aoffset;
-			error=layout_runs(attr,rec,&next,size);
-			if(error)
-				return error;
-		}
-		/* SRD: umm..
-		next=(next+7) & ~7; */
-		/* is this setting the length? if so maybe we could get
-		   away with rounding up so long as we set the length first..
-		   ..except, is the length the only way to get to the next attr?
-		 */
-		NTFS_PUTU16(rec+offset+4,next-offset);
-		offset=next;
-#endif
+	rec = store->records[0].record;
+	size = ino->vol->mft_recordsize;
+	store->records[0].recno = ino->records[0];
+	/* Copy header. */
+	offset = NTFS_GETU16(ino->attr + 0x14);
+	ntfs_memcpy(rec, ino->attr, offset);
+	for (i = 0; i < ino->attr_count; i++) {
+		attr = ino->attrs + i;
+		error = layout_attr(attr, rec + offset, size - offset, &psize);
+		if (error)
+			return error;
+		offset += psize;
 	}
-	/* terminating attribute */
-	if(offset+8<size){
-		NTFS_PUTU32(rec+offset,0xFFFFFFFF);
-		offset+=4;
-		NTFS_PUTU32(rec+offset,0);
-		offset+=4;
-	}else
-		return E2BIG;
-	NTFS_PUTU32(rec+0x18,offset);
+	/* Terminating attribute. */
+	if (offset + 8 < size) {
+		NTFS_PUTU32(rec + offset, 0xFFFFFFFF);
+		offset += 4;
+		NTFS_PUTU32(rec + offset, 0);
+		offset += 4;
+	} else
+		return -E2BIG;
+	NTFS_PUTU32(rec + 0x18, offset);
 	return 0;
 }
-  
+
+/*
+ * FIXME: ntfs_update_inode() calls layout_inode() to create the mft record on
+ * disk structure corresponding to the inode @ino. After that, ntfs_write_attr()
+ * is called to write out the created mft record to disk.
+ * We shouldn't need to re-layout every single time we are updating an mft
+ * record. No wonder the ntfs driver is slow like hell. (AIA)
+ */
 int ntfs_update_inode(ntfs_inode *ino)
 {
 	int error;
@@ -903,218 +957,217 @@
 	ntfs_io io;
 	int i;
 
-	store.count=store.size=0;
-	store.records=0;
-	error=layout_inode(ino,&store);
-	if(error==E2BIG){
+	store.count = store.size = 0;
+	store.records = 0;
+	error = layout_inode(ino, &store);
+	if (error == -E2BIG) {
 		error = ntfs_split_indexroot(ino);
-		if(!error)
-			error = layout_inode(ino,&store);
+		if (!error)
+			error = layout_inode(ino, &store);
 	}
-	if(error == E2BIG){
+	if (error == -E2BIG) {
 		error = ntfs_attr_allnonresident(ino);
-		if(!error)
-			error = layout_inode(ino,&store);
+		if (!error)
+			error = layout_inode(ino, &store);
 	}
-	if(error == E2BIG){
-		/* should try:
-		   introduce extension records
-		   */
-		ntfs_error("cannot handle saving inode %x\n",ino->i_number);
+	if (error == -E2BIG) {
+		/* FIXME: should try: introduce extension records */
+		ntfs_error("cannot handle saving inode %x\n", ino->i_number);
 		deallocate_store(&store);
-		return EOPNOTSUPP;
+		return -EOPNOTSUPP;
 	}
-	if(error){
+	if (error) {
 		deallocate_store(&store);
 		return error;
 	}
-	io.fn_get=ntfs_get;
-	io.fn_put=0;
-	for(i=0;i<store.count;i++){
-		ntfs_insert_fixups(store.records[i].record,ino->vol->blocksize);
-		io.param=store.records[i].record;
-		io.size=ino->vol->mft_recordsize;
-		/* FIXME: is this the right way? */
-		error=ntfs_write_attr(
-			ino->vol->mft_ino,ino->vol->at_data,0,
-			store.records[i].recno*ino->vol->mft_recordsize,&io);
-		if(error || io.size!=ino->vol->mft_recordsize){
-			/* big trouble, partially written file */
-			ntfs_error("Please unmount: write error in inode %x\n",ino->i_number);
+	io.fn_get = ntfs_get;
+	io.fn_put = 0;
+	for (i = 0; i < store.count; i++) {
+		ntfs_insert_fixups(store.records[i].record,
+							  ino->vol->blocksize);
+		io.param = store.records[i].record;
+		io.size = ino->vol->mft_recordsize;
+		/* FIXME: Is this the right way? */
+		error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data,
+					0, store.records[i].recno * 
+					ino->vol->mft_recordsize, &io);
+		if (error || io.size != ino->vol->mft_recordsize) {
+			/* Big trouble, partially written file. */
+			ntfs_error("Please unmount: Write error in inode %x\n",
+				   ino->i_number);
 			deallocate_store(&store);
-			return error?error:EIO;
+			return error ? error : -EIO;
 		}
 	}
 	return 0;
 }	
 
-
 void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l)
 {
-	int head,comp;
-	int copied=0;
+	int head, comp;
+	int copied = 0;
 	unsigned char *stop;
 	int bits;
-	int tag=0;
+	int tag = 0;
 	int clear_pos;
-	while(1)
-	{
+	
+	while (1) {
 		head = NTFS_GETU16(src) & 0xFFF;
-		/* high bit indicates that compression was performed */
+		/* High bit indicates that compression was performed. */
 		comp = NTFS_GETU16(src) & 0x8000;
 		src += 2;
-		stop = src+head;
+		stop = src + head;
 		bits = 0;
-		clear_pos=0;
-		if(head==0)
-			/* block is not used */
+		clear_pos = 0;
+		if (head == 0)
+			/* Block is not used. */
 			return;/* FIXME: copied */
-		if(!comp) /* uncompressible */
-		{
-			ntfs_memcpy(dest,src,0x1000);
-			dest+=0x1000;
-			copied+=0x1000;
-			src+=0x1000;
-			if(l==copied)
+		if (!comp) { /* uncompressible */
+			ntfs_memcpy(dest, src, 0x1000);
+			dest += 0x1000;
+			copied += 0x1000;
+			src += 0x1000;
+			if (l == copied)
 				return;
 			continue;
 		}
-		while(src<=stop)
-		{
-			if(clear_pos>4096)
-			{
+		while (src <= stop) {
+			if (clear_pos > 4096) {
 				ntfs_error("Error 1 in decompress\n");
 				return;
 			}
-			if(!bits){
-				tag=NTFS_GETU8(src);
-				bits=8;
+			if (!bits) {
+				tag = NTFS_GETU8(src);
+				bits = 8;
 				src++;
-				if(src>stop)
+				if (src > stop)
 					break;
 			}
-			if(tag & 1){
-				int i,len,delta,code,lmask,dshift;
+			if (tag & 1) {
+				int i, len, delta, code, lmask, dshift;
 				code = NTFS_GETU16(src);
-				src+=2;
-				if(!clear_pos)
-				{
+				src += 2;
+				if (!clear_pos) {
 					ntfs_error("Error 2 in decompress\n");
 					return;
 				}
-				for(i=clear_pos-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1)
-				{
+				for (i = clear_pos - 1, lmask = 0xFFF,
+				     dshift = 12; i >= 0x10; i >>= 1) {
 					lmask >>= 1;
 					dshift--;
 				}
 				delta = code >> dshift;
 				len = (code & lmask) + 3;
-				for(i=0; i<len; i++)
-				{
-					dest[clear_pos]=dest[clear_pos-delta-1];
+				for (i = 0; i < len; i++) {
+					dest[clear_pos] = dest[clear_pos - 
+								    delta - 1];
 					clear_pos++;
 					copied++;
-					if(copied==l)
+					if (copied==l)
 						return;
 				}
-			}else{
-				dest[clear_pos++]=NTFS_GETU8(src);
+			} else {
+				dest[clear_pos++] = NTFS_GETU8(src);
 				src++;
 				copied++;
-				if(copied==l)
+				if (copied==l)
 					return;
 			}
-			tag>>=1;
+			tag >>= 1;
 			bits--;
 		}
-		dest+=clear_pos;
+		dest += clear_pos;
 	}
 }
 
-/* Caveat: No range checking in either ntfs_set_bit or ntfs_clear_bit */
-void 
-ntfs_set_bit (unsigned char *byte, int bit)
+/* Caveat: No range checking in either ntfs_set_bit or ntfs_clear_bit. */
+void ntfs_set_bit(unsigned char *byte, int bit)
 {
 	byte += (bit >> 3);
 	bit &= 7;
 	*byte |= (1 << bit);
 }
 
-void 
-ntfs_clear_bit (unsigned char *byte, int bit)
+void ntfs_clear_bit(unsigned char *byte, int bit)
 {
 	byte += (bit >> 3);
 	bit &= 7;
 	*byte &= ~(1 << bit);
 }
 
-/* We have to skip the 16 metafiles and the 8 reserved entries */
-static int 
-ntfs_new_inode (ntfs_volume* vol,int* result)
+/**
+ * ntfs_new_inode - allocate an mft record
+ * @vol:	volume to allocate an mft record on
+ * @result:	the mft record number allocated
+ *
+ * Allocate a new mft record on disk by finding the first free mft record
+ * and allocating it in the mft bitmap.
+ * Return 0 on success or -ERRNO on error.
+ *
+ * TODO(AIA): Implement mft bitmap caching. Replace function by race safe one.
+ */
+static int ntfs_new_inode(ntfs_volume* vol, int* result)
 {
-	int byte,error;
+	int byte, error;
 	int bit;
-	int size,length;
+	int size, length;
 	unsigned char value;
 	ntfs_u8 *buffer;
 	ntfs_io io;
 	ntfs_attribute *data;
 
-	buffer=ntfs_malloc(2048);
-	if(!buffer)return ENOMEM;
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.param=buffer;
-	/* FIXME: bitmaps larger than 2048 bytes */
-	io.size=2048;
-	error=ntfs_read_attr(vol->mft_ino,vol->at_bitmap,0,0,&io);
-	if(error){
+	buffer = ntfs_malloc(2048);
+	if (!buffer)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.param = buffer;
+	/* FIXME: Bitmaps larger than 2048 bytes. */
+	io.size = 2048;
+	error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, 0, &io);
+	if (error) {
 		ntfs_free(buffer);
 		return error;
 	}
-	size=io.size;
-	data=ntfs_find_attr(vol->mft_ino,vol->at_data,0);
-	length=data->size/vol->mft_recordsize;
-
-	/* SRD: start at byte 0: bits for system files _are_ already set in bitmap */
-	for (byte = 0; 8*byte < length; byte++)
-	{
+	size = io.size;
+	data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+	length = data->size / vol->mft_recordsize;
+	/* SRD: Start at byte 0: bits for system files _are_ already set in 
+	 * bitmap. AIA: This includes the reserved entries as well. */
+	for (byte = 0; 8 * byte < length; byte++) {
 		value = buffer[byte];
-		if(value==0xFF)
+		if (value == 0xFF)
 			continue;
-		for (bit = 0; (bit < 8) && (8*byte+bit<length); 
-		     bit++, value >>= 1)
-		{
-			if (!(value & 1)){
-				*result=byte*8+bit;
+		for (bit = 0; (bit < 8) && (8 * byte + bit < length); 
+							 bit++, value >>= 1) {
+			if (!(value & 1)) {
+				*result = byte * 8 + bit;
 				return 0;
 			}
 		}
 	}
-	/* There is no free space.  We must first extend the MFT. */
-	return ENOSPC;
+	/* There is no free space. We must first extend the MFT. */
+	return -ENOSPC;
 }
 
-static int 
-add_mft_header (ntfs_inode *ino)
+static int add_mft_header(ntfs_inode *ino)
 {
-	unsigned char* mft;
-	ntfs_volume *vol=ino->vol;
-	mft=ino->attr;
+	unsigned char *mft;
+	ntfs_volume *vol = ino->vol;
 
+	mft = ino->attr;
 	ntfs_bzero(mft, vol->mft_recordsize);
-	ntfs_fill_mft_header(mft,vol->mft_recordsize,vol->blocksize,
-			ino->sequence_number);
+	ntfs_fill_mft_header(mft, vol->mft_recordsize, vol->blocksize,
+			     ino->sequence_number);
 	return 0;
 }
 
-/* We need 0x48 bytes in total */
-static int 
-add_standard_information (ntfs_inode *ino)
+/* We need 0x48 bytes in total. */
+static int add_standard_information(ntfs_inode *ino)
 {
 	ntfs_time64_t now;
 	char data[0x30];
-	char *position=data;
+	char *position = data;
 	int error;
 	ntfs_attribute *si;
 
@@ -1123,66 +1176,63 @@
 	NTFS_PUTU64(position + 0x08, now);		/* Last modification */
 	NTFS_PUTU64(position + 0x10, now);		/* Last mod for MFT */
 	NTFS_PUTU64(position + 0x18, now);		/* Last access */
-
-	NTFS_PUTU64(position + 0x20, 0x00);		/* MSDOS file perms */
-	NTFS_PUTU64(position + 0x28, 0);               /* unknown */
-	error=ntfs_create_attr(ino,ino->vol->at_standard_information,0,
-			       data,sizeof(data),&si);
-
+	NTFS_PUTU64(position + 0x20, 0);		/* MSDOS file perms */
+	NTFS_PUTU64(position + 0x28, 0);		/* unknown */
+	error = ntfs_create_attr(ino, ino->vol->at_standard_information, 0,
+				 data, sizeof(data), &si);
 	return error;
 }
 
-static int 
-add_filename (ntfs_inode* ino, ntfs_inode* dir, 
-	      const unsigned char *filename, int length, ntfs_u32 flags)
-{
-	unsigned char   *position;
-	unsigned int    size;
-	ntfs_time64_t   now;
-	int		count;
-	int error;
+/* FIXME: Need to pass in the size of the file (Data size) as well as the
+ * allocated size for file data on disk (Allocated size). (AIA) */
+static int add_filename(ntfs_inode* ino, ntfs_inode* dir, 
+			const unsigned char *filename, int length, 
+			ntfs_u32 flags)
+{
+	unsigned char *position;
+	unsigned int size;
+	ntfs_time64_t now;
+	int count, error;
 	unsigned char* data;
 	ntfs_attribute *fn;
 
-	/* work out the size */
+	/* Work out the size. */
 	size = 0x42 + 2 * length;
 	data = ntfs_malloc(size);
-	if( !data )
-		return ENOMEM;
-	ntfs_bzero(data,size);
-
-	/* search for a position */
+	if (!data)
+		return -ENOMEM;
+	ntfs_bzero(data, size);
+	/* Search for a position. */
 	position = data;
-
-	NTFS_PUTINUM(position, dir);	/* Inode num of dir */
-
+	NTFS_PUTINUM(position, dir);			/* Inode num of dir */
 	now = ntfs_now();
 	NTFS_PUTU64(position + 0x08, now);		/* File creation */
 	NTFS_PUTU64(position + 0x10, now);		/* Last modification */
 	NTFS_PUTU64(position + 0x18, now);		/* Last mod for MFT */
 	NTFS_PUTU64(position + 0x20, now);		/* Last access */
-
-	/* Don't know */
-	NTFS_PUTU32(position+0x38, flags);
-
-	NTFS_PUTU8(position + 0x40, length);	      /* Filename length */
-	NTFS_PUTU8(position + 0x41, 0x0);	      /* only long name */
-
+	/*NTFS_PUTU64(position + 0x28, 0);*/		/* Allocated size */
+	/*NTFS_PUTU64(position + 0x30, 0);*/		/* Data size */
+	NTFS_PUTU32(position + 0x38, flags);		/* File flags */
+	/*NTFS_PUTU32(position + 0x3c, 0);*/		/* We don't use these
+							 * features yet. */
+	NTFS_PUTU8(position + 0x40, length);		/* Filename length */
+	NTFS_PUTU8(position + 0x41, 0);			/* Only long name */
+		/* FIXME: This is madness. We are defining the POSIX namespace
+		 * for the filename here which can mean that the file will be
+		 * invisible when in Windows NT/2k! )-: (AIA) */
 	position += 0x42;
-	for (count = 0; count < length; count++)
-	{
+	for (count = 0; count < length; count++) {
 		NTFS_PUTU16(position + 2 * count, filename[count]);
 	}
-
-	error=ntfs_create_attr(ino,ino->vol->at_file_name,0,data,size,&fn);
-	if(!error)
-		error=ntfs_dir_add(dir,ino,fn);
+	error = ntfs_create_attr(ino, ino->vol->at_file_name, 0, data, size,
+				 &fn);
+	if (!error)
+		error = ntfs_dir_add(dir, ino, fn);
 	ntfs_free(data);
 	return error;
 }
 
-int 
-add_security (ntfs_inode* ino, ntfs_inode* dir)
+int add_security(ntfs_inode* ino, ntfs_inode* dir)
 {
 	int error;
 	char *buf;
@@ -1191,133 +1241,138 @@
 	ntfs_io io;
 	ntfs_attribute *se;
 
-	attr=ntfs_find_attr(dir,ino->vol->at_security_descriptor,0);
-	if(!attr)
-		return EOPNOTSUPP; /* need security in directory */
+	attr = ntfs_find_attr(dir, ino->vol->at_security_descriptor, 0);
+	if (!attr)
+		return -EOPNOTSUPP; /* Need security in directory. */
 	size = attr->size;
-	if(size>512)
-		return EOPNOTSUPP;
-	buf=ntfs_malloc(size);
-	if(!buf)
-		return ENOMEM;
-	io.fn_get=ntfs_get;
-	io.fn_put=ntfs_put;
-	io.param=buf;
-	io.size=size;
-	error=ntfs_read_attr(dir,ino->vol->at_security_descriptor,0,0,&io);
-	if(!error && io.size!=size)ntfs_error("wrong size in add_security");
-	if(error){
+	if (size > 512)
+		return -EOPNOTSUPP;
+	buf = ntfs_malloc(size);
+	if (!buf)
+		return -ENOMEM;
+	io.fn_get = ntfs_get;
+	io.fn_put = ntfs_put;
+	io.param = buf;
+	io.size = size;
+	error = ntfs_read_attr(dir, ino->vol->at_security_descriptor, 0, 0,&io);
+	if (!error && io.size != size)
+		ntfs_error("wrong size in add_security");
+	if (error) {
 		ntfs_free(buf);
 		return error;
 	}
-	/* FIXME: consider ACL inheritance */
-	error=ntfs_create_attr(ino,ino->vol->at_security_descriptor,
-			       0,buf,size,&se);
+	/* FIXME: Consider ACL inheritance. */
+	error = ntfs_create_attr(ino, ino->vol->at_security_descriptor,
+				 0, buf, size, &se);
 	ntfs_free(buf);
 	return error;
 }
 
-static int 
-add_data (ntfs_inode* ino, unsigned char *data, int length)
+static int add_data(ntfs_inode* ino, unsigned char *data, int length)
 {
 	int error;
 	ntfs_attribute *da;
-	error=ntfs_create_attr(ino,ino->vol->at_data,0,data,length,&da);
+	
+	error = ntfs_create_attr(ino, ino->vol->at_data, 0, data, length, &da);
 	return error;
 }
 
-/* We _could_ use 'dir' to help optimise inode allocation */
-int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, 
-		      const char *filename, int namelen, ntfs_u32 flags)
+/* We _could_ use 'dir' to help optimise inode allocation. */
+int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename,
+		     int namelen, ntfs_u32 flags)
 {
 	ntfs_io io;
 	int error;
 	ntfs_u8 buffer[2];
-	ntfs_volume* vol=dir->vol;
-	int byte,bit;
+	ntfs_volume *vol = dir->vol;
+	int byte, bit;
 
-	error=ntfs_new_inode (vol,&(result->i_number));
-	if(error==ENOSPC){
-		error=ntfs_extend_mft(vol);
-		if(error)return error;
-		error=ntfs_new_inode(vol,&(result->i_number));
+	error = ntfs_new_inode(vol, &(result->i_number));
+	if (error == -ENOSPC) {
+		error = ntfs_extend_mft(vol);
+		if (error)
+			return error;
+		error = ntfs_new_inode(vol, &(result->i_number));
 	}
-	if(error){
-		ntfs_error ("ntfs_get_empty_inode: no free inodes\n");
+	if (error) {
+		ntfs_error("ntfs_get_empty_inode: no free inodes\n");
 		return error;
 	}
-	byte=result->i_number/8;
-	bit=result->i_number & 7;
-
+	byte = result->i_number / 8;
+	bit = result->i_number & 7;
 	io.fn_put = ntfs_put;
 	io.fn_get = ntfs_get;
 	io.param = buffer;
-	io.size=1;
-	/* set a single bit */
-	error=ntfs_read_attr(vol->mft_ino,vol->at_bitmap,0,byte,&io);
-	if(error)return error;
-	if(io.size!=1)
-		return EIO;
-	ntfs_set_bit (buffer, bit);
+	io.size = 1;
+	/* Set a single bit. */
+	error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io);
+	if (error)
+		return error;
+	if (io.size != 1)
+		return -EIO;
+	ntfs_set_bit(buffer, bit);
 	io.param = buffer;
 	io.size = 1;
- 	error = ntfs_write_attr (vol->mft_ino, vol->at_bitmap, 0, byte, &io);
-	if(error)return error;
+ 	error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io);
+	if (error)
+		return error;
 	if (io.size != 1)
-		return EIO;
-	/*FIXME: Should change MFT on disk
-	  error=ntfs_update_inode(vol->mft_ino);
-	  if(error)return error;
-	  */
-	/* get the sequence number */
+		return -EIO;
+	/* FIXME: Should change $Mft on disk.
+	 * error = ntfs_update_inode(vol->mft_ino);
+	 * if (error)
+	 * 	return error; 
+	 * FIXME: And don't forget $MftMirr, though this probably belongs
+	 * in ntfs_update_inode() (or even deeper). (AIA) */
+	/* Get the sequence number. */
 	io.param = buffer;
 	io.size = 2;
 	error = ntfs_read_attr(vol->mft_ino, vol->at_data, 0, 
-			       result->i_number*vol->mft_recordsize+0x10,&io);
-	if(error)
+			       result->i_number * vol->mft_recordsize + 0x10,
+			       &io);
+	if (error)
 		return error;
-	result->sequence_number=NTFS_GETU16(buffer)+1;
-	result->vol=vol;
-	result->attr=ntfs_malloc(vol->mft_recordsize);
-	if( !result->attr )
-		return ENOMEM;
-	result->attr_count=0;
-	result->attrs=0;
-	result->record_count=1;
-	result->records=ntfs_malloc(8*sizeof(int));
-	if( !result->records ) {
-		ntfs_free( result->attr );
+	/* Increment the sequence number skipping zero. */
+	if (NTFS_GETU16(buffer) == 0xffff)
+		result->sequence_number = 1;
+	else
+		result->sequence_number = NTFS_GETU16(buffer) + 1;
+	result->vol = vol;
+	result->attr = ntfs_malloc(vol->mft_recordsize);
+	if (!result->attr)
+		return -ENOMEM;
+	result->attr_count = 0;
+	result->attrs = 0;
+	result->record_count = 1;
+	result->records = ntfs_malloc(8 * sizeof(int));
+	if (!result->records) {
+		ntfs_free(result->attr);
 		result->attr = 0;
-		return ENOMEM;
+		return -ENOMEM;
 	}
-	result->records[0]=result->i_number;
-	error=add_mft_header(result);
-	if(error)
+	result->records[0] = result->i_number;
+	error = add_mft_header(result);
+	if (error)
+		return error;
+	error = add_standard_information(result);
+	if (error)
 		return error;
-	error=add_standard_information(result);
-	if(error)
+	error = add_filename(result, dir, filename, namelen, flags);
+	if (error)
 		return error;
-	error=add_filename(result,dir,filename,namelen,flags);
-	if(error)
+	error = add_security(result, dir);
+	if (error)
 		return error;
-	error=add_security(result,dir);
-	/*FIXME: check error */
 	return 0;
 }
 
-int
-ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
-		int namelen)
+int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
+		    int namelen)
 {
-	int error = ntfs_alloc_inode(dir,result,filename,namelen,0);
-	if(error)
+	int error = ntfs_alloc_inode(dir, result, filename, namelen, 0);
+	if (error)
 		return error;
-	error = add_data(result,0,0);
+	error = add_data(result, 0, 0);
 	return error;
 }
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/inode.h linux/fs/ntfs/inode.h
--- v2.4.3/linux/fs/ntfs/inode.h	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/inode.h	Wed Apr 18 11:49:13 2001
@@ -1,30 +1,43 @@
-/*
- *  inode.h
- *  Header file for inode.c
+/*  inode.h -  Header file for inode.c
  *
  *  Copyright (C) 1997 Régis Duchesne
  *  Copyright (C) 1998 Martin von Löwis
  */
 
 ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name);
+
 int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset,
 		   ntfs_io *buf);
+
 int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset,
 		    ntfs_io *buf);
-int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum);
+
+int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum);
+
 void ntfs_clear_inode(ntfs_inode *ino);
-int ntfs_check_mft_record(ntfs_volume *vol,char *record);
-int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, 
-		      const char *filename, int namelen,ntfs_u32);
-int ntfs_alloc_file (ntfs_inode *dir, ntfs_inode *result, 
-		     char *filename, int namelen);
+
+int ntfs_check_mft_record(ntfs_volume *vol, char *record);
+
+int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename,
+		     int namelen, ntfs_u32);
+
+int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
+		    int namelen);
+
 int ntfs_update_inode(ntfs_inode *ino);
+
 int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn);
+
 int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
 			ntfs_io *dest);
+
 int ntfs_allocate_attr_number(ntfs_inode *ino, int *result);
-int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster,
-			int *ctype);
+
+int ntfs_decompress_run(unsigned char **data, int *length,
+			ntfs_cluster_t *cluster, int *ctype);
+
 void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l);
-void ntfs_fill_mft_header( ntfs_u8 *mft, int recordsize, int blocksize,
-			int sequence_number );
+
+void ntfs_fill_mft_header(ntfs_u8 *mft, int recordsize, int blocksize,
+			  int sequence_number);
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/macros.h linux/fs/ntfs/macros.h
--- v2.4.3/linux/fs/ntfs/macros.h	Sat Jan  2 10:24:46 1999
+++ linux/fs/ntfs/macros.h	Wed Apr 18 11:49:13 2001
@@ -1,5 +1,4 @@
-/*
- *  macros.h
+/*  macros.h
  *
  *  Copyright (C) 1995 Martin von Löwis
  *  Copyright (C) 1996 Régis Duchesne
@@ -7,23 +6,10 @@
 
 #define NTFS_FD(vol)		((vol)->u.fd)
 
-/* Linux */
-#ifdef NTFS_IN_LINUX_KERNEL
 #define NTFS_SB(vol)		((struct super_block*)(vol)->sb)
 #define NTFS_SB2VOL(sb)         (&(sb)->u.ntfs_sb)
 #define NTFS_INO2VOL(ino)	(&((ino)->i_sb->u.ntfs_sb))
 #define NTFS_LINO2NINO(ino)     (&((ino)->u.ntfs_i))
-#else
-#define NTFS_SB(vol)		((struct super_block*)(vol)->u.sb)
-#define NTFS_SB2VOL(sb)		((ntfs_volume*)(sb)->u.generic_sbp)
-#define NTFS_INO2VOL(ino)	((ntfs_volume*)((ino)->i_sb->u.generic_sbp))
-#define NTFS_LINO2NINO(ino)     ((ntfs_inode*)((ino)->u.generic_ip))
-#endif
-
-/* BSD */
-#define NTFS_MNT(vol)		((struct mount*)(vol)->u.sb)
-#define NTFS_MNT2VOL(sb)	((ntfs_volume*)(sb)->mnt_data)
-#define NTFS_V2INO(ino)		((ntfs_inode*)((ino)->v_data))
 
 /* Classical min and max macros still missing in standard headers... */
 #ifndef min
@@ -31,9 +17,9 @@
 #define max(a,b)	((a) >= (b) ? (a) : (b))
 #endif
 
-#define IS_MAGIC(a,b)		(*(int*)(a)==*(int*)(b))
+#define IS_MAGIC(a,b)		(*(int*)(a) == *(int*)(b))
 #define IS_MFT_RECORD(a)	IS_MAGIC((a),"FILE")
-#define IS_NTFS_VOLUME(a)	IS_MAGIC((a)+3,"NTFS")
+#define IS_NTFS_VOLUME(a)	IS_MAGIC((a) + 3,"NTFS")
 #define IS_INDEX_RECORD(a)	IS_MAGIC((a),"INDX")
 
 /* 'NTFS' in little endian */
@@ -46,8 +32,3 @@
 #define NTFS_AFLAG_COMPRESSED   0x800
 #define NTFS_AFLAG_DIR          0x10000000
 
-/*
- * Local variables:
- *  c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/ntfsendian.h linux/fs/ntfs/ntfsendian.h
--- v2.4.3/linux/fs/ntfs/ntfsendian.h	Mon Dec 11 13:26:39 2000
+++ linux/fs/ntfs/ntfsendian.h	Wed Apr 18 11:49:13 2001
@@ -1,17 +1,13 @@
-/*
- *  ntfsendian.h
+/*  ntfsendian.h
  *
  *  Copyright (C) 1998, 1999 Martin von Löwis
  *  Copyright (C) 1998 Joseph Malicki
  *  Copyright (C) 1999 Werner Seiler
+ *  Copyright (C) 2001 Anton Altaparmakov (AIA)
  */
 
-#ifdef __linux__
-/* This defines __cpu_to_le16 on Linux 2.1 and higher. */
 #include <asm/byteorder.h>
-#endif
 
-#ifdef __cpu_to_le16
 #define CPU_TO_LE16(a) __cpu_to_le16(a)
 #define CPU_TO_LE32(a) __cpu_to_le32(a)
 #define CPU_TO_LE64(a) __cpu_to_le64(a)
@@ -20,68 +16,44 @@
 #define LE32_TO_CPU(a) __cpu_to_le32(a)
 #define LE64_TO_CPU(a) __cpu_to_le64(a)
 
-#else
-
-#ifdef __LITTLE_ENDIAN
-
-#define CPU_TO_LE16(a) (a)
-#define CPU_TO_LE32(a) (a)
-#define CPU_TO_LE64(a) (a)
-#define LE16_TO_CPU(a) (a)
-#define LE32_TO_CPU(a) (a)
-#define LE64_TO_CPU(a) (a)
-
-#else
-
-/* Routines for big-endian machines */
-#ifdef __BIG_ENDIAN
-
-/* We hope its big-endian, not PDP-endian :) */
-#define CPU_TO_LE16(a) ((((a)&0xFF) << 8)|((a) >> 8))
-#define CPU_TO_LE32(a) ((((a) & 0xFF) << 24) | (((a) & 0xFF00) << 8) | \
-			(((a) & 0xFF0000) >> 8) | ((a) >> 24))
-#define CPU_TO_LE64(a) ((CPU_TO_LE32(a)<<32)|CPU_TO_LE32((a)>>32)
-
-#define LE16_TO_CPU(a) CPU_TO_LE16(a)
-#define LE32_TO_CPU(a) CPU_TO_LE32(a)
-#define LE64_TO_CPU(a) CPU_TO_LE64(a)
-
-#else
-
-#error Please define Endianness - __BIG_ENDIAN or __LITTLE_ENDIAN or add OS-specific macros
-
-#endif /* __BIG_ENDIAN */
-#endif /* __LITTLE_ENDIAN */
-#endif /* __cpu_to_le16 */
-
 #define NTFS_GETU8(p)      (*(ntfs_u8*)(p))
 #define NTFS_GETU16(p)     ((ntfs_u16)LE16_TO_CPU(*(ntfs_u16*)(p)))
-#define NTFS_GETU24(p)     ((ntfs_u32)NTFS_GETU16(p) | ((ntfs_u32)NTFS_GETU8(((char*)(p))+2)<<16))
+#define NTFS_GETU24(p)     ((ntfs_u32)NTFS_GETU16(p) | \
+			   ((ntfs_u32)NTFS_GETU8(((char*)(p)) + 2) << 16))
 #define NTFS_GETU32(p)     ((ntfs_u32)LE32_TO_CPU(*(ntfs_u32*)(p)))
-#define NTFS_GETU40(p)     ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU8(((char*)(p))+4))<<32))
-#define NTFS_GETU48(p)     ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU16(((char*)(p))+4))<<32))
-#define NTFS_GETU56(p)     ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU24(((char*)(p))+4))<<32))
+#define NTFS_GETU40(p)     ((ntfs_u64)NTFS_GETU32(p) | \
+			   (((ntfs_u64)NTFS_GETU8(((char*)(p)) + 4)) << 32))
+#define NTFS_GETU48(p)     ((ntfs_u64)NTFS_GETU32(p) | \
+			   (((ntfs_u64)NTFS_GETU16(((char*)(p)) + 4)) << 32))
+#define NTFS_GETU56(p)     ((ntfs_u64)NTFS_GETU32(p) | \
+			   (((ntfs_u64)NTFS_GETU24(((char*)(p)) + 4)) << 32))
 #define NTFS_GETU64(p)     ((ntfs_u64)LE64_TO_CPU(*(ntfs_u64*)(p)))
  
  /* Macros writing unsigned integers */
-#define NTFS_PUTU8(p,v)      ((*(ntfs_u8*)(p))=(v))
-#define NTFS_PUTU16(p,v)     ((*(ntfs_u16*)(p))=CPU_TO_LE16(v))
-#define NTFS_PUTU24(p,v)     NTFS_PUTU16(p,(v) & 0xFFFF);\
-                             NTFS_PUTU8(((char*)(p))+2,(v)>>16)
-#define NTFS_PUTU32(p,v)     ((*(ntfs_u32*)(p))=CPU_TO_LE32(v))
-#define NTFS_PUTU64(p,v)     ((*(ntfs_u64*)(p))=CPU_TO_LE64(v))
+#define NTFS_PUTU8(p,v)      ((*(ntfs_u8*)(p)) = (v))
+#define NTFS_PUTU16(p,v)     ((*(ntfs_u16*)(p)) = CPU_TO_LE16(v))
+#define NTFS_PUTU24(p,v)     NTFS_PUTU16(p, (v) & 0xFFFF);\
+                             NTFS_PUTU8(((char*)(p)) + 2, (v) >> 16)
+#define NTFS_PUTU32(p,v)     ((*(ntfs_u32*)(p)) = CPU_TO_LE32(v))
+#define NTFS_PUTU64(p,v)     ((*(ntfs_u64*)(p)) = CPU_TO_LE64(v))
  
  /* Macros reading signed integers */
 #define NTFS_GETS8(p)        ((*(ntfs_s8*)(p)))
 #define NTFS_GETS16(p)       ((ntfs_s16)LE16_TO_CPU(*(short*)(p)))
-#define NTFS_GETS24(p)       (NTFS_GETU24(p) < 0x800000 ? (int)NTFS_GETU24(p) : (int)(NTFS_GETU24(p) - 0x1000000))
+#define NTFS_GETS24(p)       (NTFS_GETU24(p) < 0x800000 ? \
+					(int)NTFS_GETU24(p) : \
+					(int)(NTFS_GETU24(p) - 0x1000000))
 #define NTFS_GETS32(p)       ((ntfs_s32)LE32_TO_CPU(*(int*)(p)))
-#define NTFS_GETS40(p)       (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS8(((char*)(p))+4)) << 32))
-#define NTFS_GETS48(p)       (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS16(((char*)(p))+4)) << 32))
-#define NTFS_GETS56(p)       (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS24(((char*)(p))+4)) << 32))
+#define NTFS_GETS40(p)       (((ntfs_s64)NTFS_GETU32(p)) | \
+			     (((ntfs_s64)NTFS_GETS8(((char*)(p)) + 4)) << 32))
+#define NTFS_GETS48(p)       (((ntfs_s64)NTFS_GETU32(p)) | \
+			     (((ntfs_s64)NTFS_GETS16(((char*)(p)) + 4)) << 32))
+#define NTFS_GETS56(p)       (((ntfs_s64)NTFS_GETU32(p)) | \
+			     (((ntfs_s64)NTFS_GETS24(((char*)(p)) + 4)) << 32))
 #define NTFS_GETS64(p)	     ((ntfs_s64)NTFS_GETU64(p))
  
 #define NTFS_PUTS8(p,v)      NTFS_PUTU8(p,v)
 #define NTFS_PUTS16(p,v)     NTFS_PUTU16(p,v)
 #define NTFS_PUTS24(p,v)     NTFS_PUTU24(p,v)
 #define NTFS_PUTS32(p,v)     NTFS_PUTU32(p,v)
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/ntfstypes.h linux/fs/ntfs/ntfstypes.h
--- v2.4.3/linux/fs/ntfs/ntfstypes.h	Mon Dec 11 13:26:39 2000
+++ linux/fs/ntfs/ntfstypes.h	Wed Apr 18 11:49:13 2001
@@ -1,26 +1,21 @@
-/*
- *  ntfstypes.h
- *  This file defines four things:
- *   - generic platform independent fixed-size types (e.g. ntfs_u32)
- *   - specific fixed-size types (e.g. ntfs_offset_t)
- *   - macros that read and write those types from and to byte arrays
- *   - types derived from OS specific ones
+/*  ntfstypes.h - This file defines four things:
+ *   - Generic platform independent fixed-size types (e.g. ntfs_u32).
+ *   - Specific fixed-size types (e.g. ntfs_offset_t).
+ *   - Macros that read and write those types from and to byte arrays.
+ *   - Types derived from OS specific ones.
  *
- *  Copyright (C) 1996,1998, 1999 Martin von Löwis
+ *  Copyright (C) 1996, 1998, 1999 Martin von Löwis
+ *  Copyright (C) 2001 Anton Altaparmakov (AIA)
  */
 
-#ifdef NTFS_IN_LINUX_KERNEL
-/* get installed types if we compile the kernel*/
 #include <linux/fs.h>
-#endif
 
 /* We don't need to define __LITTLE_ENDIAN, as we use
    <asm/byteorder>. */
-
 #include "ntfsendian.h"
 #include <asm/types.h>
 
-/* integral types */
+/* Integral types */
 #ifndef NTFS_INTEGRAL_TYPES
 #define NTFS_INTEGRAL_TYPES
 typedef u8  ntfs_u8;
@@ -33,12 +28,12 @@
 typedef s64 ntfs_s64;
 #endif
 
-/* unicode character type */
+/* Unicode character type */
 #ifndef NTFS_WCHAR_T
 #define NTFS_WCHAR_T
 typedef u16 ntfs_wchar_t;
 #endif
-/* file offset */
+/* File offset */
 #ifndef NTFS_OFFSET_T
 #define NTFS_OFFSET_T
 typedef u64 ntfs_offset_t;
@@ -48,7 +43,7 @@
 #define NTFS_TIME64_T
 typedef u64 ntfs_time64_t;
 #endif
-/* This is really unsigned long long. So we support only volumes up to 2 TB */
+/* This is really unsigned long long. So we support only volumes up to 2Tb. */
 #ifndef NTFS_CLUSTER_T
 #define NTFS_CLUSTER_T
 typedef u32 ntfs_cluster_t;
@@ -58,13 +53,13 @@
 #define MAX_CLUSTER_T (~((ntfs_cluster_t)0))
 #endif
 
-/* architecture independent macros */
+/* Architecture independent macros. */
 
-/* PUTU32 would not clear all bytes */
-#define NTFS_PUTINUM(p,i)    NTFS_PUTU64(p,i->i_number);\
-                             NTFS_PUTU16(((char*)p)+6,i->sequence_number)
+/* PUTU32 would not clear all bytes. */
+#define NTFS_PUTINUM(p,i)    NTFS_PUTU64(p, i->i_number); \
+                             NTFS_PUTU16(((char*)p) + 6, i->sequence_number)
 
-/* system dependent types */
+/* System dependent types. */
 #include <asm/posix_types.h>
 #ifndef NTMODE_T
 #define NTMODE_T
@@ -87,8 +82,3 @@
 typedef __kernel_time_t ntfs_time_t;
 #endif
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/struct.h linux/fs/ntfs/struct.h
--- v2.4.3/linux/fs/ntfs/struct.h	Tue May  2 13:46:53 2000
+++ linux/fs/ntfs/struct.h	Wed Apr 18 11:49:13 2001
@@ -1,143 +1,50 @@
-/*
- * struct.h
- * Structure definitions
+/*  struct.h - Structure definitions
  *
  *  Copyright (C) 1997 Régis Duchesne
- *  Copyright (C) 2000 Anton Altaparmakov
+ *  Copyright (C) 2000-2001 Anton Altaparmakov (AIA)
  */
 
-/* Necessary forward definition */
+/* Necessary forward definition. */
 struct ntfs_inode;
 
-#ifdef __FreeBSD__
-#include <sys/queue.h>
-/* Define the struct ntfs_head type */
-LIST_HEAD(ntfs_head,ntfs_inode);
-#endif
+/* Which files should be returned from a director listing. */
+#define ngt_dos   1	/* only short names, no hidden files */
+#define ngt_nt    2	/* only long names, all-uppercase becomes 
+			 * all-lowercase, no hidden files */
+#define ngt_posix 3	/* all names except hidden files */
+#define ngt_full  4	/* all entries */
 
-/* which files should be returned from a director listing */
-/* only short names, no hidden files */
-#define ngt_dos   1
-/* only long names, all-uppercase becomes all-lowercase, no hidden files */
-#define ngt_nt    2
-/* all names except hidden files */
-#define ngt_posix 3
-/* all entries */
-#define ngt_full  4
 
-#ifdef NTFS_IN_LINUX_KERNEL
 typedef struct ntfs_sb_info ntfs_volume;
-#else
-typedef struct _ntfs_volume{
-	/* NTFS_SB_INFO_START */
-	/* Configuration provided by user at mount time */
-	ntfs_uid_t uid;
-	ntfs_gid_t gid;
-	ntmode_t umask;
-        unsigned int nct;
-	void *nls_map;
-	unsigned int ngt;
-	/* Configuration provided by user with ntfstools */
-	ntfs_size_t partition_bias;	/* for access to underlying device */
-	/* Attribute definitions */
-	ntfs_u32 at_standard_information;
-	ntfs_u32 at_attribute_list;
-	ntfs_u32 at_file_name;
-	ntfs_u32 at_volume_version;
-	ntfs_u32 at_security_descriptor;
-	ntfs_u32 at_volume_name;
-	ntfs_u32 at_volume_information;
-	ntfs_u32 at_data;
-	ntfs_u32 at_index_root;
-	ntfs_u32 at_index_allocation;
-	ntfs_u32 at_bitmap;
-	ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */
-	/* Data read from the boot file */
-	int blocksize;
-	int clusterfactor;
-	int clustersize;
-	int mft_recordsize;
-	int mft_clusters_per_record;
-	int index_recordsize;
-	int index_clusters_per_record;
-	int mft_cluster;
-	/* data read from special files */
-	unsigned char *mft;
-	unsigned short *upcase;
-	unsigned int upcase_length;
-	/* inodes we always hold onto */
-	struct ntfs_inode *mft_ino;
-	struct ntfs_inode *mftmirr;
-	struct ntfs_inode *bitmap;
-	/* NTFS_SB_INFO_END */
-	union{
-		int fd;		/* file descriptor for the tools */
-		void *sb;	/* pointer to super block for the kernel */
-	}u;
-#ifdef __FreeBSD__
-	dev_t rdev;
-	struct vnode *devvp;
-	struct ntfs_head *inode_hash;   /* not really a hash */
-#endif
-}ntfs_volume;
-#endif
 
 typedef struct {
 	ntfs_cluster_t cluster;
 	ntfs_cluster_t len;
-}ntfs_runlist;
+} ntfs_runlist;
 
 typedef struct ntfs_attribute{
 	int type;
 	ntfs_u16 *name;
 	int namelen;
 	int attrno;
-	int size,allocated,initialized,compsize;
-	int compressed,resident,indexed;
+	int size, allocated, initialized, compsize;
+	int compressed, resident, indexed;
 	int cengine;
-	union{
+	union {
 		void *data;             /* if resident */
 		struct {
 			ntfs_runlist *runlist;
 			int len;
-		}r;
-	}d;
-}ntfs_attribute;
-
-/* Structure to define IO to user buffer. do_read means that
-   the destination has to be written using fn_put, do_write means
-   that the destination has to read using fn_get. So, do_read is
-   from a user's point of view, while put and get are from the driver's
-   point of view. The first argument is always the destination of the IO
-*/
-#ifdef NTFS_IN_LINUX_KERNEL
+		} r;
+	} d;
+} ntfs_attribute;
+
+/* Structure to define IO to user buffer. do_read means that the destination
+ * has to be written using fn_put, do_write means that the destination has to
+ * read using fn_get. So, do_read is from a user's point of view, while put and
+ * get are from the driver's point of view. The first argument is always the
+ * destination of the IO. */
 typedef struct ntfs_inode_info ntfs_inode;
-#else
-typedef struct ntfs_inode{
-	ntfs_volume *vol;
-	/* NTFS_INODE_INFO_START */
-	int i_number;                /* should be really 48 bits */
-	unsigned sequence_number;
-	unsigned char* attr;         /* array of the attributes */
-	int attr_count;              /* size of attrs[] */
-	struct ntfs_attribute *attrs;
-	int record_count;            /* size of records[] */
-	/* array of the record numbers of the MFT 
-	   whose attributes have been inserted in the inode */
-	int *records;
-	union{
-		struct{
-			int recordsize;
-			int clusters_per_record;
-		}index;
-	} u;	
-	/* NTFS_INODE_INFO_END */
-#ifdef __FreeBSD__
-	struct vnode *vp;
-	LIST_ENTRY(ntfs_inode) h_next;
-#endif
-}ntfs_inode;
-#endif
 
 typedef struct ntfs_io{
 	int do_read;
@@ -145,7 +52,7 @@
 	void (*fn_get)(void *buf, struct ntfs_io *src, ntfs_size_t len);
 	void *param;
 	int size;
-}ntfs_io;
+} ntfs_io;
 
 #if 0
 typedef struct {
@@ -157,3 +64,4 @@
 	int start_vcn;
 } ntfs_attrlist_item;
 #endif
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/super.c linux/fs/ntfs/super.c
--- v2.4.3/linux/fs/ntfs/super.c	Tue Nov  7 11:22:35 2000
+++ linux/fs/ntfs/super.c	Wed Apr 18 11:49:13 2001
@@ -1,10 +1,9 @@
-/*
- *  super.c
+/*  super.c
  *
  *  Copyright (C) 1995-1997, 1999 Martin von Löwis
  *  Copyright (C) 1996-1997 Régis Duchesne
  *  Copyright (C) 1999 Steve Dodd
- *  Copyright (C) 2000 Anton Altparmakov
+ *  Copyright (C) 2000-2001 Anton Altparmakov (AIA)
  */
 
 #include "ntfstypes.h"
@@ -12,13 +11,13 @@
 #include "super.h"
 
 #include <linux/errno.h>
+#include <linux/bitops.h>
 #include "macros.h"
 #include "inode.h"
 #include "support.h"
 #include "util.h"
 
-/*
- * All important structures in NTFS use 2 consistency checks :
+/* All important structures in NTFS use 2 consistency checks:
  * . a magic structure identifier (FILE, INDX, RSTR, RCRD...)
  * . a fixup technique : the last word of each sector (called a fixup) of a
  *   structure's record should end with the word at offset <n> of the first
@@ -36,188 +35,204 @@
 	int start, count, offset;
 	ntfs_u16 fixup;
 
-	if(!IS_MAGIC(record,magic))
+	if (!IS_MAGIC(record, magic))
 		return 0;
-	start=NTFS_GETU16(record+4);
-	count=NTFS_GETU16(record+6);
+	start = NTFS_GETU16(record + 4);
+	count = NTFS_GETU16(record + 6);
 	count--;
-	if(size && vol->blocksize*count != size)
+	if(size && vol->blocksize * count != size)
 		return 0;
-	fixup = NTFS_GETU16(record+start);
-	start+=2;
-	offset=vol->blocksize-2;
-	while(count--){
-		if(NTFS_GETU16(record+offset)!=fixup)
+	fixup = NTFS_GETU16(record + start);
+	start += 2;
+	offset = vol->blocksize - 2;
+	while (count--){
+		if (NTFS_GETU16(record + offset) != fixup)
 			return 0;
-		NTFS_PUTU16(record+offset, NTFS_GETU16(record+start));
-		start+=2;
-		offset+=vol->blocksize;
+		NTFS_PUTU16(record + offset, NTFS_GETU16(record + start));
+		start += 2;
+		offset += vol->blocksize;
 	}
 	return 1;
 }
 
-/* Get vital informations about the ntfs partition from the boot sector */
-int ntfs_init_volume(ntfs_volume *vol,char *boot)
+/*
+ * Get vital informations about the ntfs partition from the boot sector.
+ * Return 0 on success or -1 on error.
+ */
+int ntfs_init_volume(ntfs_volume *vol, char *boot)
 {
-	/* Historical default values, in case we don't load $AttrDef */
-	vol->at_standard_information=0x10;
-	vol->at_attribute_list=0x20;
-	vol->at_file_name=0x30;
-	vol->at_volume_version=0x40;
-	vol->at_security_descriptor=0x50;
-	vol->at_volume_name=0x60;
-	vol->at_volume_information=0x70;
-	vol->at_data=0x80;
-	vol->at_index_root=0x90;
-	vol->at_index_allocation=0xA0;
-	vol->at_bitmap=0xB0;
-	vol->at_symlink=0xC0;
-
+	/* Historical default values, in case we don't load $AttrDef. */
+	vol->at_standard_information = 0x10;
+	vol->at_attribute_list = 0x20;
+	vol->at_file_name = 0x30;
+	vol->at_volume_version = 0x40;
+	vol->at_security_descriptor = 0x50;
+	vol->at_volume_name = 0x60;
+	vol->at_volume_information = 0x70;
+	vol->at_data = 0x80;
+	vol->at_index_root = 0x90;
+	vol->at_index_allocation = 0xA0;
+	vol->at_bitmap = 0xB0;
+	vol->at_symlink = 0xC0;
 	/* Sector size */
-	vol->blocksize=NTFS_GETU16(boot+0xB);
-	vol->clusterfactor=NTFS_GETU8(boot+0xD);
-	vol->mft_clusters_per_record=NTFS_GETS8(boot+0x40);
-	vol->index_clusters_per_record=NTFS_GETS8(boot+0x44);
-	
-	/* Just some consistency checks */
-	if(NTFS_GETU32(boot+0x40)>256)
+	vol->blocksize = NTFS_GETU16(boot + 0xB);
+	vol->clusterfactorbits = ffs(NTFS_GETU8(boot + 0xD)) - 1;
+	vol->mft_clusters_per_record = NTFS_GETS8(boot + 0x40);
+	vol->index_clusters_per_record = NTFS_GETS8(boot + 0x44);
+	/* Just some consistency checks. */
+	if (NTFS_GETU32(boot + 0x40) > 256)
 		ntfs_error("Unexpected data #1 in boot block\n");
-	if(NTFS_GETU32(boot+0x44)>256)
+	if (NTFS_GETU32(boot+ 0x44) > 256)
 		ntfs_error("Unexpected data #2 in boot block\n");
-	if(vol->index_clusters_per_record<0){
-		ntfs_error("Unexpected data #3 in boot block\n");
-		/* If this really means a fraction, setting it to 1
-		   should be safe. */
-		vol->index_clusters_per_record=1;
-	}
-	/* in some cases, 0xF6 meant 1024 bytes. Other strange values have not
-	   been observed */
-	if(vol->mft_clusters_per_record<0 && vol->mft_clusters_per_record!=-10)
-		ntfs_error("Unexpected data #4 in boot block\n");
-
-	vol->clustersize=vol->blocksize*vol->clusterfactor;
-	if(vol->mft_clusters_per_record>0)
-		vol->mft_recordsize=
-			vol->clustersize*vol->mft_clusters_per_record;
-	else
-		vol->mft_recordsize=1<<(-vol->mft_clusters_per_record);
-	vol->index_recordsize=vol->clustersize*vol->index_clusters_per_record;
+	vol->clustersize = vol->blocksize << vol->clusterfactorbits;
+	if (vol->mft_clusters_per_record > 0)
+		vol->mft_recordsize =
+			       vol->clustersize * vol->mft_clusters_per_record;
+	else {
+		/* If mft_recordsize < clustersize then mft_clusters_per_record
+		   = -log2(mft_recordsize) bytes. Mft_recordsize normaly equals
+		   1024 bytes, which is encoded as 0xF6. */
+		if (vol->mft_clusters_per_record < -31 ||
+					-9 < vol->mft_clusters_per_record) {
+			ntfs_error("Unexpected mft clusters per record value "
+				   "in boot block.\n");
+			return -1;
+		}
+		vol->mft_recordsize = 1 << (-vol->mft_clusters_per_record);
+	}
+	if (vol->index_clusters_per_record > 0)
+		vol->index_recordsize =
+			vol->clustersize * vol->index_clusters_per_record;
+	else {
+		/* If index_recordsize < clustersize then
+		   index_clusters_per_record = -log2(index_recordsize) bytes.
+		   Index_recordsize normaly equals 1024 bytes, which is
+		   encoded as 0xF6. */
+		if (vol->index_clusters_per_record < -31 ||
+					-9 < vol->index_clusters_per_record) {
+			ntfs_error("Unexpected index clusters per record "
+				   "value in boot block.\n");
+			return -1;
+		}
+		vol->index_recordsize = 1 << (-vol->index_clusters_per_record);
+	}
+	if (NTFS_GETU64(boot + 0x30) >= (1ULL << 32)) {
+		ntfs_error("Would require 64-bit inodes to mount partition.");
+		return -1;
+	}
 	/* FIXME: long long value */
-	vol->mft_cluster=NTFS_GETU64(boot+0x30);
-
-	/* This will be initialized later */
-	vol->upcase=0;
-	vol->upcase_length=0;
-	vol->mft_ino=0;
+	vol->mft_cluster = NTFS_GETU64(boot + 0x30);
+	/* This will be initialized later. */
+	vol->upcase = 0;
+	vol->upcase_length = 0;
+	vol->mft_ino = 0;
 	return 0;
 }
 
-static void 
-ntfs_init_upcase(ntfs_inode *upcase)
+static void ntfs_init_upcase(ntfs_inode *upcase)
 {
 	ntfs_io io;
 #define UPCASE_LENGTH  256
-	upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH);
-	if( !upcase->vol->upcase )
+	upcase->vol->upcase = ntfs_malloc(UPCASE_LENGTH << 1);
+	if (!upcase->vol->upcase)
 		return;
-	io.fn_put=ntfs_put;
-	io.fn_get=0;
-	io.param=(char*)upcase->vol->upcase;
-	io.size=2*UPCASE_LENGTH;
-	ntfs_read_attr(upcase,upcase->vol->at_data,0,0,&io);
-	upcase->vol->upcase_length = io.size / 2;
+	io.fn_put = ntfs_put;
+	io.fn_get = 0;
+	io.param = (char*)upcase->vol->upcase;
+	io.size = UPCASE_LENGTH << 1;
+	ntfs_read_attr(upcase, upcase->vol->at_data, 0, 0, &io);
+	upcase->vol->upcase_length = io.size >> 1;
 }
 
-static int
-process_attrdef(ntfs_inode* attrdef,ntfs_u8* def)
+static int process_attrdef(ntfs_inode* attrdef, ntfs_u8* def)
 {
 	int type = NTFS_GETU32(def+0x80);
 	int check_type = 0;
-	ntfs_volume *vol=attrdef->vol;
+	ntfs_volume *vol = attrdef->vol;
 	ntfs_u16* name = (ntfs_u16*)def;
 
-	if(ntfs_ua_strncmp(name,"$STANDARD_INFORMATION",64)==0){
-		vol->at_standard_information=type;
-		check_type=0x10;
-	}else if(ntfs_ua_strncmp(name,"$ATTRIBUTE_LIST",64)==0){
-		vol->at_attribute_list=type;
-		check_type=0x20;
-	}else if(ntfs_ua_strncmp(name,"$FILE_NAME",64)==0){
-		vol->at_file_name=type;
-		check_type=0x30;
-	}else if(ntfs_ua_strncmp(name,"$VOLUME_VERSION",64)==0){
-		vol->at_volume_version=type;
-		check_type=0x40;
-	}else if(ntfs_ua_strncmp(name,"$SECURITY_DESCRIPTOR",64)==0){
-		vol->at_security_descriptor=type;
-		check_type=0x50;
-	}else if(ntfs_ua_strncmp(name,"$VOLUME_NAME",64)==0){
-		vol->at_volume_name=type;
-		check_type=0x60;
-	}else if(ntfs_ua_strncmp(name,"$VOLUME_INFORMATION",64)==0){
-		vol->at_volume_information=type;
-		check_type=0x70;
-	}else if(ntfs_ua_strncmp(name,"$DATA",64)==0){
-		vol->at_data=type;
-		check_type=0x80;
-	}else if(ntfs_ua_strncmp(name,"$INDEX_ROOT",64)==0){
-		vol->at_index_root=type;
-		check_type=0x90;
-	}else if(ntfs_ua_strncmp(name,"$INDEX_ALLOCATION",64)==0){
-		vol->at_index_allocation=type;
-		check_type=0xA0;
-	}else if(ntfs_ua_strncmp(name,"$BITMAP",64)==0){
-		vol->at_bitmap=type;
-		check_type=0xB0;
-	}else if(ntfs_ua_strncmp(name,"$SYMBOLIC_LINK",64)==0 ||
-		 ntfs_ua_strncmp(name,"$REPARSE_POINT",64)==0){
-		vol->at_symlink=type;
-		check_type=0xC0;
-	}
-	if(check_type && check_type!=type){
-		ntfs_error("Unexpected type %x for %x\n",type,check_type);
-		return EINVAL;
+	if (ntfs_ua_strncmp(name, "$STANDARD_INFORMATION", 64) == 0) {
+		vol->at_standard_information = type;
+		check_type = 0x10;
+	} else if (ntfs_ua_strncmp(name, "$ATTRIBUTE_LIST", 64) == 0) {
+		vol->at_attribute_list = type;
+		check_type = 0x20;
+	} else if (ntfs_ua_strncmp(name, "$FILE_NAME", 64) == 0) {
+		vol->at_file_name = type;
+		check_type = 0x30;
+	} else if (ntfs_ua_strncmp(name, "$VOLUME_VERSION", 64) == 0) {
+		vol->at_volume_version = type;
+		check_type = 0x40;
+	} else if (ntfs_ua_strncmp(name, "$SECURITY_DESCRIPTOR", 64) == 0) {
+		vol->at_security_descriptor = type;
+		check_type = 0x50;
+	} else if (ntfs_ua_strncmp(name, "$VOLUME_NAME", 64) == 0) {
+		vol->at_volume_name = type;
+		check_type = 0x60;
+	} else if (ntfs_ua_strncmp(name, "$VOLUME_INFORMATION", 64) == 0) {
+		vol->at_volume_information = type;
+		check_type = 0x70;
+	} else if (ntfs_ua_strncmp(name, "$DATA", 64) == 0) {
+		vol->at_data = type;
+		check_type = 0x80;
+	} else if (ntfs_ua_strncmp(name, "$INDEX_ROOT", 64) == 0) {
+		vol->at_index_root = type;
+		check_type = 0x90;
+	} else if (ntfs_ua_strncmp(name, "$INDEX_ALLOCATION", 64) == 0) {
+		vol->at_index_allocation = type;
+		check_type = 0xA0;
+	} else if (ntfs_ua_strncmp(name, "$BITMAP", 64) == 0) {
+		vol->at_bitmap = type;
+		check_type = 0xB0;
+	} else if (ntfs_ua_strncmp(name, "$SYMBOLIC_LINK", 64) == 0 ||
+		 ntfs_ua_strncmp(name, "$REPARSE_POINT", 64) == 0) {
+		vol->at_symlink = type;
+		check_type = 0xC0;
+	}
+	if (check_type && check_type != type) {
+		ntfs_error("Unexpected type %x for %x\n", type, check_type);
+		return -EINVAL;
 	}
 	return 0;
 }
 
-int
-ntfs_init_attrdef(ntfs_inode* attrdef)
+int ntfs_init_attrdef(ntfs_inode* attrdef)
 {
 	ntfs_u8 *buf;
 	ntfs_io io;
-	int offset,error,i;
+	int offset, error,i;
 	ntfs_attribute *data;
-	buf=ntfs_malloc(4050); /* 90*45 */
-	if(!buf)return ENOMEM;
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.do_read=1;
-	offset=0;
-	data=ntfs_find_attr(attrdef,attrdef->vol->at_data,0);
-	if(!data){
+
+	buf = ntfs_malloc(4050); /* 90*45 */
+	if (!buf)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.do_read = 1;
+	offset = 0;
+	data = ntfs_find_attr(attrdef, attrdef->vol->at_data, 0);
+	if (!data) {
 		ntfs_free(buf);
-		return EINVAL;
+		return -EINVAL;
 	}
-	do{
-		io.param=buf;
-		io.size=4050;
-		error=ntfs_readwrite_attr(attrdef,data,offset,&io);
-		for(i=0;!error && i<io.size-0xA0;i+=0xA0)
-			error=process_attrdef(attrdef,buf+i);
-		offset+=4096;
-	}while(!error && io.size);
+	do {
+		io.param = buf;
+		io.size = 4050;
+		error = ntfs_readwrite_attr(attrdef, data, offset, &io);
+		for (i = 0; !error && i < io.size - 0xA0; i += 0xA0)
+			error = process_attrdef(attrdef, buf + i);
+		offset += 4096;
+	} while (!error && io.size);
 	ntfs_free(buf);
 	return error;
 }
 
-/* ntfs_get_version will determine the NTFS version of the 
-   volume and will return the version in a BCD format, with
-   the MSB being the major version number and the LSB the
-   minor one. Otherwise return <0 on error. 
-   Example: version 3.1 will be returned as 0x0301.
-   This has the obvious limitation of not coping with version
-   numbers above 0x80 but that shouldn't be a problem... */
+/* ntfs_get_version will determine the NTFS version of the volume and will
+ * return the version in a BCD format, with the MSB being the major version
+ * number and the LSB the minor one. Otherwise return <0 on error.
+ * Example: version 3.1 will be returned as 0x0301. This has the obvious
+ * limitation of not coping with version numbers above 0x80 but that shouldn't
+ * be a problem... */
 int ntfs_get_version(ntfs_inode* volume)
 {
 	ntfs_attribute *volinfo;
@@ -229,7 +244,8 @@
 		ntfs_error("Volume information attribute is not resident!\n");
 		return -EINVAL;
 	}
-	return ((ntfs_u8*)volinfo->d.data)[8] << 8 | ((ntfs_u8*)volinfo->d.data)[9];
+	return ((ntfs_u8*)volinfo->d.data)[8] << 8 | 
+	       ((ntfs_u8*)volinfo->d.data)[9];
 }
 
 int ntfs_load_special_files(ntfs_volume *vol)
@@ -237,119 +253,120 @@
 	int error;
 	ntfs_inode upcase, attrdef, volume;
 
-	vol->mft_ino=(ntfs_inode*)ntfs_calloc(3*sizeof(ntfs_inode));
-	error=ENOMEM;
-	ntfs_debug(DEBUG_BSD,"Going to load MFT\n");
-	if(!vol->mft_ino || (error=ntfs_init_inode(vol->mft_ino,vol,FILE_MFT)))
+	vol->mft_ino = (ntfs_inode*)ntfs_calloc(3 * sizeof(ntfs_inode));
+	error = -ENOMEM;
+	ntfs_debug(DEBUG_BSD, "Going to load MFT\n");
+	if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol,
+						      FILE_$Mft)))
 	{
 		ntfs_error("Problem loading MFT\n");
 		return error;
 	}
-	ntfs_debug(DEBUG_BSD,"Going to load MIRR\n");
-	vol->mftmirr=vol->mft_ino+1;
-	if((error=ntfs_init_inode(vol->mftmirr,vol,FILE_MFTMIRR))){
-		ntfs_error("Problem %d loading MFTMirr\n",error);
+	ntfs_debug(DEBUG_BSD, "Going to load MIRR\n");
+	vol->mftmirr = vol->mft_ino + 1;
+	if ((error = ntfs_init_inode(vol->mftmirr, vol, FILE_$MftMirr))) {
+		ntfs_error("Problem %d loading MFTMirr\n", error);
 		return error;
 	}
-	ntfs_debug(DEBUG_BSD,"Going to load BITMAP\n");
-	vol->bitmap=vol->mft_ino+2;
-	if((error=ntfs_init_inode(vol->bitmap,vol,FILE_BITMAP))){
+	ntfs_debug(DEBUG_BSD, "Going to load BITMAP\n");
+	vol->bitmap = vol->mft_ino + 2;
+	if ((error = ntfs_init_inode(vol->bitmap, vol, FILE_$BitMap))) {
 		ntfs_error("Problem loading Bitmap\n");
 		return error;
 	}
-	ntfs_debug(DEBUG_BSD,"Going to load UPCASE\n");
-	error=ntfs_init_inode(&upcase,vol,FILE_UPCASE);
-	if(error)return error;
+	ntfs_debug(DEBUG_BSD, "Going to load UPCASE\n");
+	error = ntfs_init_inode(&upcase, vol, FILE_$UpCase);
+	if (error)
+		return error;
 	ntfs_init_upcase(&upcase);
 	ntfs_clear_inode(&upcase);
-	ntfs_debug(DEBUG_BSD,"Going to load ATTRDEF\n");
-	error=ntfs_init_inode(&attrdef,vol,FILE_ATTRDEF);
-	if(error)return error;
-	error=ntfs_init_attrdef(&attrdef);
+	ntfs_debug(DEBUG_BSD, "Going to load ATTRDEF\n");
+	error = ntfs_init_inode(&attrdef, vol, FILE_$AttrDef);
+	if (error)
+		return error;
+	error = ntfs_init_attrdef(&attrdef);
 	ntfs_clear_inode(&attrdef);
-	if(error)return error;
+	if (error)
+		return error;
 
-	/* Check for NTFS version and if Win2k version (ie. 3.0+)
-	   do not allow write access since the driver write support
-	   is broken, especially for Win2k. */
-	ntfs_debug(DEBUG_BSD,"Going to load VOLUME\n");
-	error = ntfs_init_inode(&volume,vol,FILE_VOLUME);
-	if (error) return error;
-	if ((error = ntfs_get_version(&volume)) >= 0x0300) {
+	/* Check for NTFS version and if Win2k version (ie. 3.0+) do not allow
+	 * write access since the driver write support is broken. */
+	ntfs_debug(DEBUG_BSD, "Going to load VOLUME\n");
+	error = ntfs_init_inode(&volume, vol, FILE_$Volume);
+	if (error)
+		return error;
+	if ((error = ntfs_get_version(&volume)) >= 0x0300 &&
+	    !(NTFS_SB(vol)->s_flags & MS_RDONLY)) {
 		NTFS_SB(vol)->s_flags |= MS_RDONLY;
-		ntfs_error("Warning! NTFS volume version is Win2k+: Mounting read-only\n");
+		ntfs_error("Warning! NTFS volume version is Win2k+: Mounting "
+			   "read-only\n");
 	}
 	ntfs_clear_inode(&volume);
-	if (error < 0) return error;
-	ntfs_debug(DEBUG_BSD, "NTFS volume is version %d.%d\n", error >> 8, error & 0xff);
-
+	if (error < 0)
+		return error;
+	ntfs_debug(DEBUG_BSD, "NTFS volume is version %d.%d\n", error >> 8,
+								error & 0xff);
 	return 0;
 }
 
 int ntfs_release_volume(ntfs_volume *vol)
 {
-	if(vol->mft_ino){
+	if (vol->mft_ino) {
 		ntfs_clear_inode(vol->mft_ino);
 		ntfs_clear_inode(vol->mftmirr);
 		ntfs_clear_inode(vol->bitmap);
 		ntfs_free(vol->mft_ino);
-		vol->mft_ino=0;
+		vol->mft_ino = 0;
 	}
 	ntfs_free(vol->mft);
 	ntfs_free(vol->upcase);
 	return 0;
 }
 
-/*
- * Writes the volume size into vol_size. Returns 0 if successful
- * or error.
- */
-int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size )
+/* Writes the volume size into vol_size. Returns 0 if successful or error. */
+int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size)
 {
 	ntfs_io io;
 	char *cluster0;
 
-	if( !vol_size )
-		return EFAULT;
-
-	cluster0=ntfs_malloc(vol->clustersize);
-	if( !cluster0 )
-		return ENOMEM;
-
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.param=cluster0;
-	io.do_read=1;
-	io.size=vol->clustersize;
-	ntfs_getput_clusters(vol,0,0,&io);
-	*vol_size = NTFS_GETU64(cluster0+0x28);
+	if (!vol_size)
+		return -EFAULT;
+	cluster0 = ntfs_malloc(vol->clustersize);
+	if (!cluster0)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.param = cluster0;
+	io.do_read = 1;
+	io.size = vol->clustersize;
+	ntfs_getput_clusters(vol, 0, 0, &io);
+	*vol_size = NTFS_GETU64(cluster0 + 0x28) >> vol->clusterfactorbits;
 	ntfs_free(cluster0);
 	return 0;
 }
 
 static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};
 
-int 
-ntfs_get_free_cluster_count(ntfs_inode *bitmap)
+int ntfs_get_free_cluster_count(ntfs_inode *bitmap)
 {
 	unsigned char bits[2048];
-	int offset,error;
-	int clusters=0;
+	int offset, error;
+	int clusters = 0;
 	ntfs_io io;
 
-	offset=0;
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	while(1)
-	{
+	offset = 0;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	while (1) {
 		register int i;
-		io.param=bits;
-		io.size=2048;
-		error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,
-				     offset,&io);
-		if(error || io.size==0)break;
+		io.param = bits;
+		io.size = 2048;
+		error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, offset,
+									&io);
+		if (error || io.size == 0)
+			break;
 		/* I never thought I would do loop unrolling some day */
-		for(i=0;i<io.size-8;){
+		for (i = 0; i < io.size - 8; ) {
 			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
 			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
 			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
@@ -359,261 +376,263 @@
 			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
 			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
 		}
-		for(;i<io.size;){
-			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
+		while (i < io.size) {
+			clusters += nc[bits[i] >> 4];
+			clusters += nc[bits[i++] & 0xF];
 		}
-		offset+=io.size;
+		offset += io.size;
 	}
 	return clusters;
 }
 
-/* Insert the fixups for the record. The number and location of the fixes 
-   is obtained from the record header */
+/* Insert the fixups for the record. The number and location of the fixes
+ * is obtained from the record header */
 void ntfs_insert_fixups(unsigned char *rec, int secsize)
 {
-	int first=NTFS_GETU16(rec+4);
-	int count=NTFS_GETU16(rec+6);
-	int offset=-2;
-	ntfs_u16 fix=NTFS_GETU16(rec+first);
-	fix=fix+1;
-	NTFS_PUTU16(rec+first,fix);
+	int first = NTFS_GETU16(rec + 4);
+	int count = NTFS_GETU16(rec + 6);
+	int offset = -2;
+	ntfs_u16 fix = NTFS_GETU16(rec + first);
+	
+	fix++;
+	if (fix == 0xffff || !fix)
+		fix = 1;
+	NTFS_PUTU16(rec + first, fix);
 	count--;
-	while(count--){
-		first+=2;
-		offset+=secsize;
-		NTFS_PUTU16(rec+first,NTFS_GETU16(rec+offset));
-		NTFS_PUTU16(rec+offset,fix);
+	while (count--) {
+		first += 2;
+		offset += secsize;
+		NTFS_PUTU16(rec + first, NTFS_GETU16(rec + offset));
+		NTFS_PUTU16(rec + offset, fix);
 	};
 }
 
-/* search the bitmap bits of l bytes for *cnt zero bits. Return the bit
-   number in *loc, which is initially set to the number of the first bit.
-   Return the largest block found in *cnt. Return 0 on success, ENOSPC if
-   all bits are used */
-static int 
-search_bits(unsigned char* bits,ntfs_cluster_t *loc,int *cnt,int l)
-{
-	unsigned char c=0;
-	int bc=0;
-	int bstart=0,bstop=0,found=0;
-	int start,stop=0,in=0;
+/* Search the bitmap bits of l bytes for *cnt zero bits. Return the bit number
+ * in *loc, which is initially set to the number of the first bit. Return the
+ * largest block found in *cnt. Return 0 on success, -ENOSPC if all bits are
+ * used. */
+static int search_bits(unsigned char* bits, ntfs_cluster_t *loc, int *cnt,int l)
+{
+	unsigned char c = 0;
+	int bc = 0;
+	int bstart = 0, bstop = 0, found = 0;
+	int start, stop = 0, in = 0;
 	/* special case searching for a single block */
-	if(*cnt==1){
-		while(l && *bits==0xFF){
+	if (*cnt == 1) {
+		while (l && *bits == 0xFF) {
 			bits++;
-			*loc+=8;
+			*loc += 8;
 			l--;
 		}
-		if(!l)return ENOSPC;
-		for(c=*bits;c & 1;c>>=1)
+		if (!l)
+			return -ENOSPC;
+		for (c = *bits; c & 1; c >>= 1)
 			(*loc)++;
 		return 0;
 	}
-	start=*loc;
-	while(l || bc){
-		if(bc==0){
-			c=*bits;
-			if(l){
-				l--;bits++;
+	start = *loc;
+	while (l || bc) {
+		if (bc == 0) {
+			c = *bits;
+			if (l) {
+				l--;
+				bits++;
 			}
-			bc=8;
+			bc = 8;
 		}
-		if(in){
-			if((c&1)==0)
+		if (in) {
+			if ((c & 1) == 0)
 				stop++;
-			else{ /* end of sequence of zeroes */
-				in=0;
-				if(!found || bstop-bstart<stop-start){
-					bstop=stop;bstart=start;found=1;
-					if(bstop-bstart>*cnt)
+			else { /* end of sequence of zeroes */
+				in = 0;
+				if (!found || bstop-bstart < stop-start) {
+					bstop = stop; bstart = start;
+					found = 1;
+					if (bstop - bstart > *cnt)
 						break;
 				}
-				start=stop+1;
+				start = stop + 1;
 			}
-		}else{
-			if(c&1)
+		} else {
+			if (c & 1)
 				start++;
-			else{ /*start of sequence*/
-				in=1;
-				stop=start+1;
+			else { /*start of sequence*/
+				in = 1;
+				stop = start + 1;
 			}
 		}
 		bc--;
-		c>>=1;
+		c >>= 1;
 	}
-	if(in && (!found || bstop-bstart<stop-start)){
-		bstop=stop;bstart=start;found=1;
+	if (in && (!found || bstop - bstart < stop - start)) {
+		bstop = stop; bstart = start; found = 1;
 	}
-	if(!found)return ENOSPC;
-	*loc=bstart;
-	if(*cnt>bstop-bstart)
-		*cnt=bstop-bstart;
+	if (!found)
+		return -ENOSPC;
+	*loc = bstart;
+	if (*cnt > bstop - bstart)
+		*cnt = bstop - bstart;
 	return 0;
 }
 
-int 
-ntfs_set_bitrange(ntfs_inode* bitmap,ntfs_cluster_t loc,int cnt,int bit)
+int ntfs_set_bitrange(ntfs_inode* bitmap, ntfs_cluster_t loc, int cnt, int bit)
 {
-	int bsize,locit,error;
-	unsigned char *bits,*it;
+	int bsize, locit, error;
+	unsigned char *bits, *it;
 	ntfs_io io;
 
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	bsize=(cnt+(loc & 7)+7) >> 3; /* round up to multiple of 8*/
-	bits=ntfs_malloc(bsize);
-	io.param=bits;
-	io.size=bsize;
-	if(!bits)
-		return ENOMEM;
-	error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,loc>>3,&io);
-	if(error || io.size!=bsize){
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	bsize = (cnt + (loc & 7) + 7) >> 3; /* round up to multiple of 8*/
+	bits = ntfs_malloc(bsize);
+	if (!bits)
+		return -ENOMEM;
+	io.param = bits;
+	io.size = bsize;
+	error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, loc >> 3, &io);
+	if (error || io.size != bsize){
 		ntfs_free(bits);
-		return error?error:EIO;
+		return error ? error : -EIO;
 	}
-	/* now set the bits */
-	it=bits;
-	locit=loc;
-	while(locit%8 && cnt){ /* process first byte */
-		if(bit)
-			*it |= 1<<(locit%8);
+	/* Now set the bits. */
+	it = bits;
+	locit = loc;
+	while (locit % 8 && cnt) { /* process first byte */
+		if (bit)
+			*it |= 1 << (locit % 8);
 		else
-			*it &= ~(1<<(locit%8));
-		cnt--;locit++;
-		if(locit%8==0)
+			*it &= ~(1 << (locit % 8));
+		cnt--;
+		locit++;
+		if (locit % 8 == 0)
 			it++;
 	}
-	while(cnt>8){ /*process full bytes */
-		*it= bit ? 0xFF : 0;
-		cnt-=8;
-		locit+=8;
+	while (cnt > 8) { /*process full bytes */
+		*it = bit ? 0xFF : 0;
+		cnt -= 8;
+		locit += 8;
 		it++;
 	}
-	while(cnt){ /*process last byte */
-		if(bit)
-			*it |= 1<<(locit%8);
+	while (cnt) { /*process last byte */
+		if (bit)
+			*it |= 1 << (locit % 8);
 		else
-			*it &= ~(1<<(locit%8));
-		cnt--;locit++;
+			*it &= ~(1 << (locit % 8));
+		cnt--;
+		locit++;
 	}
 	/* reset to start */
-	io.param=bits;
-	io.size=bsize;
-	error=ntfs_write_attr(bitmap,bitmap->vol->at_data,0,loc>>3,&io);
+	io.param = bits;
+	io.size = bsize;
+	error = ntfs_write_attr(bitmap, bitmap->vol->at_data, 0, loc >> 3, &io);
 	ntfs_free(bits);
-	if(error)return error;
-	if(io.size!=bsize)
-		return EIO;
+	if (error)
+		return error;
+	if (io.size != bsize)
+		return -EIO;
 	return 0;
 }
-  
-  
 	
-/* allocate count clusters around location. If location is -1,
-   it does not matter where the clusters are. Result is 0 if
-   success, in which case location and count says what they really got */
-int 
-ntfs_search_bits(ntfs_inode* bitmap, ntfs_cluster_t *location, int *count, int flags)
+/* Allocate count clusters around location. If location is -1, it does not
+ * matter where the clusters are. Result is 0 if success, in which case
+ * location and count says what they really got. */
+int ntfs_search_bits(ntfs_inode* bitmap, ntfs_cluster_t *location, int *count,
+		     int flags)
 {
 	unsigned char *bits;
 	ntfs_io io;
-	int error=0,found=0;
-	int cnt,bloc=-1,bcnt=0;
+	int error = 0, found = 0;
+	int cnt, bloc = -1, bcnt = 0;
 	int start;
 	ntfs_cluster_t loc;
 
-	bits=ntfs_malloc(2048);
-	if( !bits )
-		return ENOMEM;
-	io.fn_put=ntfs_put;
-	io.fn_get=ntfs_get;
-	io.param=bits;
+	bits = ntfs_malloc(2048);
+	if (!bits)
+		return -ENOMEM;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
+	io.param = bits;
 
 	/* first search within +/- 8192 clusters */
-	start=*location>>3;
-	start= start>1024 ? start-1024 : 0;
-	io.size=2048;
-	error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,start,&io);
-	if(error)goto fail;
-	loc=start*8;
-	cnt=*count;
-	error=search_bits(bits,&loc,&cnt,io.size);
-	if(error)
+	start = *location >> 3;
+	start = start > 1024 ? start - 1024 : 0;
+	io.size = 2048;
+	error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, start, &io);
+	if (error)
 		goto fail;
-	if(*count==cnt){
-		bloc=loc;
-		bcnt=cnt;
+	loc = start * 8;
+	cnt = *count;
+	error = search_bits(bits, &loc, &cnt, io.size);
+	if (error)
+		goto fail;
+	if (*count == cnt){
+		bloc = loc;
+		bcnt = cnt;
 		goto success;
 	}
-
-	/* now search from the beginning */
-	for(start=0;1;start+=2048)
-	{
-		io.param=bits;
-		io.size=2048;
-		error=ntfs_read_attr(bitmap,bitmap->vol->at_data,
-				     0,start,&io);
-		if(error)goto fail;
-		if(io.size==0){
+	/* Now search from the beginning. */
+	for (start = 0; 1; start += 2048) {
+		io.param = bits;
+		io.size = 2048;
+		error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, start,
+									&io);
+		if (error)
+			goto fail;
+		if (io.size == 0) {
 			if(found)
 				goto success;
-			else{
-				error=ENOSPC;
+			else {
+				error = -ENOSPC;
 				goto fail;
 			}
 		}
-		loc=start*8;
-		cnt=*count;
-		error=search_bits(bits,&loc,&cnt,io.size);
-		if(error)
+		loc = start * 8;
+		cnt = *count;
+		error = search_bits(bits, &loc, &cnt, io.size);
+		if (error)
 			goto fail;
-		if(*count==cnt)
+		if (*count == cnt)
 			goto success;
-		if(bcnt<cnt){
-			bcnt=cnt;
-			bloc=loc;
-			found=1;
+		if (bcnt < cnt) {
+			bcnt = cnt;
+			bloc = loc;
+			found = 1;
 		}
 	}
  success:
 	ntfs_free(bits);
 	/* check flags */
-	if((flags & ALLOC_REQUIRE_LOCATION) && *location!=bloc)
-		error=ENOSPC;
-	else if((flags & ALLOC_REQUIRE_SIZE) && *count!=bcnt)
-		error=ENOSPC;
-	else ntfs_set_bitrange(bitmap,bloc,bcnt,1);
-	/* If allocation failed due to the flags, tell the caller what he
-	   could have gotten */
-	*location=bloc;
-	*count=bcnt;
+	if ((flags & ALLOC_REQUIRE_LOCATION) && *location != bloc)
+		error = -ENOSPC;
+	else if ((flags & ALLOC_REQUIRE_SIZE) && *count != bcnt)
+		error = -ENOSPC;
+	else
+		ntfs_set_bitrange(bitmap, bloc, bcnt, 1);
+	/* If allocation failed due to the flags, tell the caller what he could
+	 * have gotten */
+	*location = bloc;
+	*count = bcnt;
 	return 0;
  fail:
-	*location=-1;
-	*count=0;
+	*location = -1;
+	*count = 0;
 	ntfs_free(bits);
 	return error;
 }
 
-int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, int *count,
-	int flags)
+int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location,
+			   int *count, int flags)
 {
 	int error;
-	error=ntfs_search_bits(vol->bitmap,location,count,flags);
+	error = ntfs_search_bits(vol->bitmap, location, count, flags);
 	return error;
 }
 
-int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, int count)
+int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location,
+			     int count)
 {
 	int error;
-	error=ntfs_set_bitrange(vol->bitmap,location,count,0);
+	error = ntfs_set_bitrange(vol->bitmap, location, count, 0);
 	return error;
 }
-
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
-
 
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/super.h linux/fs/ntfs/super.h
--- v2.4.3/linux/fs/ntfs/super.h	Thu Dec  9 13:14:30 1999
+++ linux/fs/ntfs/super.h	Wed Apr 18 11:49:13 2001
@@ -1,6 +1,4 @@
-/*
- *  super.h
- *  Header file for super.c
+/*  super.h - Header file for super.c
  *
  *  Copyright (C) 1995-1997 Martin von Löwis
  *  Copyright (C) 1996-1997 Régis Duchesne
@@ -10,12 +8,22 @@
 #define ALLOC_REQUIRE_SIZE     2
 
 int ntfs_get_free_cluster_count(ntfs_inode *bitmap);
+
 int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size );
-int ntfs_init_volume(ntfs_volume *vol,char *boot);
+
+int ntfs_init_volume(ntfs_volume *vol, char *boot);
+
 int ntfs_load_special_files(ntfs_volume *vol);
+
 int ntfs_release_volume(ntfs_volume *vol);
+
 void ntfs_insert_fixups(unsigned char *rec, int secsize);
+
 int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size);
-int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, int *count,
-  int flags);
-int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, int count);
+
+int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location,
+			   int *count, int flags);
+
+int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location,
+			     int count);
+
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/support.c linux/fs/ntfs/support.c
--- v2.4.3/linux/fs/ntfs/support.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/ntfs/support.c	Wed Apr 18 11:49:13 2001
@@ -1,15 +1,10 @@
-/*
- *  support.c
- *  Specific support functions
+/*  support.c -  Specific support functions
  *
  *  Copyright (C) 1997 Martin von Löwis
  *  Copyright (C) 1997 Régis Duchesne
- *
+ *  Copyright (C) 2001 Anton Altaparmakov (AIA)
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
 #include "ntfstypes.h"
 #include "struct.h"
 #include "support.h"
@@ -64,7 +59,7 @@
 	kfree(block);
 }
 #endif
-#else
+#else /* End of DEBUG functions. Normal ones below... */
 void ntfs_debug(int mask, const char *fmt, ...)
 {
 }
@@ -102,7 +97,7 @@
 	memmove(dest, src, n);
 }
 
-/* Warn that an error occured. */
+/* Warn that an error occurred. */
 void ntfs_error(const char *fmt,...)
 {
         va_list ap;
@@ -120,68 +115,72 @@
 	ntfs_io io;
 
 	ntfs_debug(DEBUG_OTHER, "read_mft_record %x\n",mftno);
-	if(mftno==FILE_MFT)
+	if(mftno == FILE_$Mft)
 	{
-		ntfs_memcpy(buf,vol->mft,vol->mft_recordsize);
+		ntfs_memcpy(buf, vol->mft, vol->mft_recordsize);
 		return 0;
 	}
 	if(!vol->mft_ino)
 	{
-		printk("ntfs:something is terribly wrong here\n");
-		return ENODATA;
+		printk(KERN_ERR "NTFS: mft_ino is NULL. Something is terribly "
+				"wrong here!\n");
+		return -ENODATA;
 	}
- 	io.fn_put=ntfs_put;
-	io.fn_get=0;
-	io.param=buf;
-	io.size=vol->mft_recordsize;
-	error=ntfs_read_attr(vol->mft_ino,vol->at_data,NULL,
-			     mftno*vol->mft_recordsize,&io);
-	if(error || (io.size!=vol->mft_recordsize))
+ 	io.fn_put = ntfs_put;
+	io.fn_get = 0;
+	io.param = buf;
+	io.size = vol->mft_recordsize;
+	error = ntfs_read_attr(vol->mft_ino, vol->at_data, NULL,
+					mftno * vol->mft_recordsize, &io);
+	if (error || (io.size != vol->mft_recordsize))
 	{
-		ntfs_debug(DEBUG_OTHER, "read_mft_record: read %x failed (%d,%d,%d)\n",
-			   mftno,error,io.size,vol->mft_recordsize);
-		return error?error:ENODATA;
+		ntfs_debug(DEBUG_OTHER, "read_mft_record: read %x failed "
+				   	"(%d,%d,%d)\n", mftno, error, io.size,
+				   	vol->mft_recordsize);
+		return error ? error : -ENODATA;
 	}
-	ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read %x\n",mftno);
-	if(!ntfs_check_mft_record(vol,buf))
+	ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read %x\n", mftno);
+	if(!ntfs_check_mft_record(vol, buf))
 	{
-		printk("Invalid MFT record for %x\n",mftno);
-		return EINVAL;
+		/* FIXME: This is incomplete behaviour. We might be able to
+		 * recover at this stage. ntfs_check_mft_record() is too
+		 * conservative at aborting it's operations. It is OK for
+		 * now as we just can't handle some on disk structures
+		 * this way. (AIA) */
+		printk(KERN_WARNING "NTFS: Invalid MFT record for %x\n", mftno);
+		return -EINVAL;
 	}
-	ntfs_debug(DEBUG_OTHER, "read_mft_record: Done %x\n",mftno);
+	ntfs_debug(DEBUG_OTHER, "read_mft_record: Done %x\n", mftno);
 	return 0;
 }
 
 int ntfs_getput_clusters(ntfs_volume *vol, int cluster,	ntfs_size_t start_offs,
-	 ntfs_io *buf)
+			 ntfs_io *buf)
 {
-	struct super_block *sb=NTFS_SB(vol);
+	struct super_block *sb = NTFS_SB(vol);
 	struct buffer_head *bh;
 	ntfs_size_t to_copy;
-	int length=buf->size;
-	if(buf->do_read)
-		ntfs_debug(DEBUG_OTHER, "get_clusters %d %d %d\n",cluster,start_offs,length);
-	else
-		ntfs_debug(DEBUG_OTHER, "put_clusters %d %d %d\n",cluster,start_offs,length);
-	while(length)
-	{
-		if(!(bh=bread(sb->s_dev,cluster,vol->clustersize)))
-		{
-			ntfs_debug(DEBUG_OTHER, "%s failed\n", buf->do_read?"Reading":"Writing");
-			return EIO;
+	int length = buf->size;
+
+	ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n", 
+		   buf->do_read ? "get" : "put", cluster, start_offs, length);
+	while (length) {
+		if (!(bh = bread(sb->s_dev, cluster, vol->clustersize))) {
+			ntfs_debug(DEBUG_OTHER, "%s failed\n",
+				   buf->do_read ? "Reading" : "Writing");
+			return -EIO;
 		}
-		to_copy=min(vol->clustersize-start_offs,length);
+		to_copy = min(vol->clustersize - start_offs, length);
 		lock_buffer(bh);
-		if(buf->do_read)
-			buf->fn_put(buf,bh->b_data+start_offs,to_copy);
-		else
-		{
-			buf->fn_get(bh->b_data+start_offs,buf,to_copy);
+		if (buf->do_read)
+			buf->fn_put(buf, bh->b_data + start_offs, to_copy);
+		else {
+			buf->fn_get(bh->b_data + start_offs, buf, to_copy);
 			mark_buffer_dirty(bh);
 		}
 		unlock_buffer(bh);
-		length-=to_copy;
-		start_offs=0;
+		length -= to_copy;
+		start_offs = 0;
 		cluster++;
 		brelse(bh);
 	}
@@ -193,152 +192,147 @@
 	return ntfs_unixutc2ntutc(CURRENT_TIME);
 }
 
-/* when printing unicode characters base64, use this table.
-   It is not strictly base64, but the Linux vfat encoding.
-   base64 has the disadvantage of using the slash.
-*/
-static char uni2esc[64]=
-  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-";
-
-static unsigned char
-esc2uni(char c)
-{
-	if(c<'0')return 255;
-	if(c<='9')return c-'0';
-	if(c<'A')return 255;
-	if(c<='Z')return c-'A'+10;
-	if(c<'a')return 255;
-	if(c<='z')return c-'a'+36;
-	if(c=='+')return 62;
-	if(c=='-')return 63;
+/* When printing unicode characters base64, use this table. It is not strictly
+ * base64, but the Linux vfat encoding. base64 has the disadvantage of using
+ * the slash. */
+static char uni2esc[64] = 
+	    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-";
+
+static unsigned char esc2uni(char c)
+{
+	if (c <  '0') return 255;
+	if (c <= '9') return c - '0';
+	if (c <  'A') return 255;
+	if (c <= 'Z') return c - 'A' + 10;
+	if (c <  'a') return 255;
+	if (c <= 'z') return c - 'a' + 36;
+	if (c == '+') return 62;
+	if (c == '-') return 63;
 	return 255;
 }
 
 int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
-  int *out_len)
+		    int *out_len)
 {
-	int i,o,val,chl, chi;
-	char *result,*buf,charbuf[NLS_MAX_CHARSET_SIZE];
-	struct nls_table* nls=vol->nls_map;
-
-	result=ntfs_malloc(in_len+1);
-	if(!result)return ENOMEM;
-	*out_len=in_len;
-	result[in_len]='\0';
-	for(i=o=0;i<in_len;i++){
-		int cl,ch;
+	int i, o, val, chl, chi;
+	char *result, *buf, charbuf[NLS_MAX_CHARSET_SIZE];
+	struct nls_table* nls = vol->nls_map;
+
+	result = ntfs_malloc(in_len + 1);
+	if (!result)
+		return -ENOMEM;
+	*out_len = in_len;
+	result[in_len] = '\0';
+	for (i = o = 0; i < in_len; i++) {
+		int cl, ch;
 		/* FIXME: byte order? */
-		cl=in[i] & 0xFF;
-		ch=(in[i] >> 8) & 0xFF;
-		if(!nls){
-			if(!ch){
-				result[o++]=cl;
+		cl = in[i] & 0xFF;
+		ch = (in[i] >> 8) & 0xFF;
+		if (!nls) {
+			if (!ch) {
+				result[o++] = cl;
 				continue;
 			}
-		}else{
+		} else {
 			/* FIXME: byte order? */
 			wchar_t uni = in[i];
-			if ( (chl = nls->uni2char(uni, charbuf, NLS_MAX_CHARSET_SIZE)) > 0){
+			if ((chl = nls->uni2char(uni, charbuf,
+						NLS_MAX_CHARSET_SIZE)) > 0) {
 				/* adjust result buffer */
-				if (chl > 1){
-					buf=ntfs_malloc(*out_len + chl - 1);
+				if (chl > 1) {
+					buf = ntfs_malloc(*out_len + chl - 1);
 					memcpy(buf, result, o);
 					ntfs_free(result);
-					result=buf;
-					*out_len+=(chl-1);
+					result = buf;
+					*out_len += (chl - 1);
 				}
-				for (chi=0;chi<chl;chi++)
+				for (chi = 0; chi < chl; chi++)
 					result[o++] = charbuf[chi];
 			} else
 				result[o++] = '?';
 			continue;
-
 		}
-		if(!(vol->nct & nct_uni_xlate))goto inval;
+		if (!(vol->nct & nct_uni_xlate))
+			goto inval;
 		/* realloc */
-		buf=ntfs_malloc(*out_len+3);
-		if( !buf ) {
-			ntfs_free( result );
-			return ENOMEM;
+		buf = ntfs_malloc(*out_len + 3);
+		if (!buf) {
+			ntfs_free(result);
+			return -ENOMEM;
 		}
-		memcpy(buf,result,o);
+		memcpy(buf, result, o);
 		ntfs_free(result);
-		result=buf;
-		*out_len+=3;
-		result[o++]=':';
-		if(vol->nct & nct_uni_xlate_vfat){
-			val=(cl<<8)+ch;
-			result[o+2]=uni2esc[val & 0x3f];
-			val>>=6;
-			result[o+1]=uni2esc[val & 0x3f];
-			val>>=6;
-			result[o]=uni2esc[val & 0x3f];
-			o+=3;
-		}else{
-			val=(ch<<8)+cl;
-			result[o++]=uni2esc[val & 0x3f];
-			val>>=6;
-			result[o++]=uni2esc[val & 0x3f];
-			val>>=6;
-			result[o++]=uni2esc[val & 0x3f];
+		result = buf;
+		*out_len += 3;
+		result[o++] = ':';
+		if (vol->nct & nct_uni_xlate_vfat) {
+			val = (cl << 8) + ch;
+			result[o+2] = uni2esc[val & 0x3f];
+			val >>= 6;
+			result[o+1] = uni2esc[val & 0x3f];
+			val >>= 6;
+			result[o] = uni2esc[val & 0x3f];
+			o += 3;
+		} else {
+			val = (ch << 8) + cl;
+			result[o++] = uni2esc[val & 0x3f];
+			val >>= 6;
+			result[o++] = uni2esc[val & 0x3f];
+			val >>= 6;
+			result[o++] = uni2esc[val & 0x3f];
 		}
 	}
-	*out=result;
+	*out = result;
 	return 0;
  inval:
 	ntfs_free(result);
-	*out=0;
-	return EILSEQ;
+	*out = 0;
+	return -EILSEQ;
 }
 
 int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
-  int *out_len)
+		    int *out_len)
 {
-	int i,o;
+	int i, o;
 	ntfs_u16* result;
-	struct nls_table* nls=vol->nls_map;
+	struct nls_table* nls = vol->nls_map;
 
-	*out=result=ntfs_malloc(2*in_len);
-	if(!result)return ENOMEM;
-	*out_len=in_len;
-	for(i=o=0;i<in_len;i++,o++){
+	*out=result = ntfs_malloc(2 * in_len);
+	if (!result)
+		return -ENOMEM;
+	*out_len = in_len;
+	for (i = o = 0; i < in_len; i++, o++){
 		wchar_t uni;
-		if(in[i]!=':' || (vol->nct & nct_uni_xlate)==0){
+		if (in[i] != ':' || (vol->nct & nct_uni_xlate) == 0){
 			int charlen;
-			/* FIXME: is this error handling ok? */
 			charlen = nls->char2uni(&in[i], in_len-i, &uni);
 			if (charlen < 0)
 				return charlen;
-			*out_len -= (charlen-1);
-			i += (charlen-1);
-		}else{
-			unsigned char c1,c2,c3;
-			*out_len-=3;
-			c1=esc2uni(in[++i]);
-			c2=esc2uni(in[++i]);
-			c3=esc2uni(in[++i]);
-			if(c1==255 || c2==255 || c3==255)
+			*out_len -= (charlen - 1);
+			i += (charlen - 1);
+		} else {
+			unsigned char c1, c2, c3;
+			*out_len -= 3;
+			c1 = esc2uni(in[++i]);
+			c2 = esc2uni(in[++i]);
+			c3 = esc2uni(in[++i]);
+			if (c1 == 255 || c2 == 255 || c3 == 255)
 				uni = 0;
-			else if(vol->nct & nct_uni_xlate_vfat){
+			else if (vol->nct & nct_uni_xlate_vfat) {
 				uni = (((c2 & 0x3) << 6) + c3) << 8 |
-					((c1 << 4) + (c2 >> 2));
-			}else{
+				      ((c1 << 4) + (c2 >> 2));
+			} else {
 				uni = ((c3 << 4) + (c2 >> 2)) << 8 |
-					(((c2 & 0x3) << 6) + c1);
+				      (((c2 & 0x3) << 6) + c1);
 			}
 		}
 		/* FIXME: byte order? */
 		result[o] = uni;
-		if(!result[o]){
+		if (!result[o]) {
 			ntfs_free(result);
-			return EILSEQ;
+			return -EILSEQ;
 		}
 	}
 	return 0;
 }
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/support.h linux/fs/ntfs/support.h
--- v2.4.3/linux/fs/ntfs/support.h	Mon Dec 11 13:26:39 2000
+++ linux/fs/ntfs/support.h	Wed Apr 18 11:49:13 2001
@@ -1,6 +1,4 @@
-/*
- *  support.h
- *  Header file for specific support.c
+/*  support.h - Header file for specific support.c
  *
  *  Copyright (C) 1997 Régis Duchesne
  */
@@ -20,29 +18,31 @@
 #define DEBUG_NAME2  2048
 
 void ntfs_debug(int mask, const char *fmt, ...);
-#ifdef NTFS_IN_LINUX_KERNEL
+
 #include <linux/slab.h>
-#define ntfs_malloc(size)  kmalloc(size,GFP_KERNEL)
+
+#define ntfs_malloc(size)  kmalloc(size, GFP_KERNEL)
+
 #define ntfs_free(ptr)     kfree(ptr)
-#else
-void *ntfs_malloc(int size);
-void ntfs_free(void *block);
-#endif
+
 void ntfs_bzero(void *s, int n);
+
 void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n);
+
 void ntfs_memmove(void *dest, const void *src, ntfs_size_t n);
+
 void ntfs_error(const char *fmt,...);
+
 int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf);
+
 int ntfs_getput_clusters(ntfs_volume *pvol, int cluster, ntfs_size_t offs,
-        ntfs_io *buf);
+			 ntfs_io *buf);
+
 ntfs_time64_t ntfs_now(void);
+
 int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
-        int *out_len);
+		    int *out_len);
+
 int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
-        int *out_len);
+		    int *out_len);
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/sysctl.h linux/fs/ntfs/sysctl.h
--- v2.4.3/linux/fs/ntfs/sysctl.h	Sat Jan  2 10:24:46 1999
+++ linux/fs/ntfs/sysctl.h	Wed Apr 18 11:49:13 2001
@@ -1,28 +1,17 @@
-/*
- *  sysctl.h
- *  Header file for sysctl.c
+/*  sysctl.h - Header file for sysctl.c
  *
  *  Copyright (C) 1997 Martin von Löwis
  *  Copyright (C) 1997 Régis Duchesne
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #ifdef DEBUG
-extern int ntdebug;
+	extern int ntdebug;
 
-void ntfs_sysctl(int add);
+	void ntfs_sysctl(int add);
 
-#define SYSCTL(x)	ntfs_sysctl(x)
+	#define SYSCTL(x)	ntfs_sysctl(x)
 #else
-#define SYSCTL(x)
+	#define SYSCTL(x)
 #endif /* DEBUG */
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/util.c linux/fs/ntfs/util.c
--- v2.4.3/linux/fs/ntfs/util.c	Tue May  2 13:46:53 2000
+++ linux/fs/ntfs/util.c	Wed Apr 18 11:49:13 2001
@@ -1,9 +1,8 @@
-/*
- *  util.c
- *  Miscellaneous support
+/*  util.c -  Miscellaneous support
  *
  *  Copyright (C) 1997,1999 Martin von Löwis
  *  Copyright (C) 1997 Régis Duchesne
+ *  Copyright (C) 2001 Anton Altaparmakov (AIA)
  *
  *  The utf8 routines are copied from Python wstrop module.
  */
@@ -14,75 +13,66 @@
 
 #include <linux/string.h>
 #include <linux/errno.h>
-/* FreeBSD doesn't seem to have EILSEQ in errno.h */
-#ifndef EILSEQ
-# define EILSEQ	EINVAL
-#endif
 #include "support.h"
 
 /* Converts a single wide character to a sequence of utf8 bytes.
  * The character is represented in host byte order.
- * Returns the number of bytes, or 0 on error.
- */
-static int
-to_utf8(ntfs_u16 c,unsigned char* buf)
+ * Returns the number of bytes, or 0 on error. */
+static int to_utf8(ntfs_u16 c, unsigned char* buf)
 {
-	if(c==0)
-		return 0; /* No support for embedded 0 runes */
-	if(c<0x80){
-		if(buf)buf[0]=(unsigned char)c;
+	if (c == 0)
+		return 0; /* No support for embedded 0 runes. */
+	if (c < 0x80) {
+		if (buf)
+			buf[0] = (unsigned char)c;
 		return 1;
 	}
-	if(c<0x800){
-		if(buf){
-			buf[0] = 0xc0 | (c>>6);
+	if (c < 0x800) {
+		if (buf) {
+			buf[0] = 0xc0 | (c >> 6);
 			buf[1] = 0x80 | (c & 0x3f);
 		}
 		return 2;
 	}
-	if(c<0x10000){
-		if(buf){
-			buf[0] = 0xe0 | (c>>12);
-			buf[1] = 0x80 | ((c>>6) & 0x3f);
+	if (c < 0x10000) {
+		if (buf) {
+			buf[0] = 0xe0 | (c >> 12);
+			buf[1] = 0x80 | ((c >> 6) & 0x3f);
 			buf[2] = 0x80 | (c & 0x3f);
 		}
 		return 3;
 	}
-	/* We don't support characters above 0xFFFF in NTFS */
+	/* We don't support characters above 0xFFFF in NTFS. */
 	return 0;
 }
 
 /* Decodes a sequence of utf8 bytes into a single wide character.
  * The character is returned in host byte order.
- * Returns the number of bytes consumed, or 0 on error.
- */
-static int
-from_utf8(const unsigned char* str,ntfs_u16 *c)
+ * Returns the number of bytes consumed, or 0 on error. */
+static int from_utf8(const unsigned char* str, ntfs_u16 *c)
 {
-	int l=0,i;
+	int l = 0, i;
 
-	if(*str<0x80){
+	if (*str < 0x80) {
 		*c = *str;
 		return 1;
 	}
-	if(*str<0xc0) /* lead byte must not be 10xxxxxx */
-		return 0;   /* is c0 a possible lead byte? */
-	if(*str<0xe0){         /* 110xxxxx */
+	if (*str < 0xc0)	/* Lead byte must not be 10xxxxxx. */
+		return 0;	/* Is c0 a possible lead byte? */
+	if (*str < 0xe0) {		/* 110xxxxx */
 		*c = *str & 0x1f;
-		l=2;
-	}else if(*str<0xf0){   /* 1110xxxx */
+		l = 2;
+	} else if (*str < 0xf0) {	/* 1110xxxx */
 		*c = *str & 0xf;
-		l=3;
-	}else if(*str<0xf8){   /* 11110xxx */
+		l = 3;
+	} else if (*str < 0xf8) {   	/* 11110xxx */
 		*c = *str & 7;
-		l=4;
-	}else /* We don't support characters above 0xFFFF in NTFS */
+		l = 4;
+	} else /* We don't support characters above 0xFFFF in NTFS. */
 		return 0;
-	 
-
-	for(i=1;i<l;i++){
-		/* all other bytes must be 10xxxxxx */
-		if((str[i] & 0xc0) != 0x80)
+	for (i = 1; i < l; i++) {
+		/* All other bytes must be 10xxxxxx. */
+		if ((str[i] & 0xc0) != 0x80)
 			return 0;
 		*c <<= 6;
 		*c |= str[i] & 0x3f;
@@ -93,196 +83,195 @@
 /* Converts wide string to UTF-8. Expects two in- and two out-parameters.
  * Returns 0 on success, or error code. 
  * The caller has to free the result string.
- * There is no support for UTF-16, yet
- */
-static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len,char **out,int *out_len)
+ * There is no support for UTF-16, yet. */
+static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len, char **out, int *out_len)
 {
-	int i,tmp;
+	int i, tmp;
 	int len8;
 	unsigned char *result;
 
-	ntfs_debug(DEBUG_NAME1,"converting l=%d\n",in_len);
-	/* count the length of the resulting UTF-8 */
-	for(i=len8=0;i<in_len;i++){
-		tmp=to_utf8(NTFS_GETU16(in+i),0);
-		if(!tmp)
+	ntfs_debug(DEBUG_NAME1, "converting l = %d\n", in_len);
+	/* Count the length of the resulting UTF-8. */
+	for (i = len8 = 0; i < in_len; i++){
+		tmp = to_utf8(NTFS_GETU16(in + i), 0);
+		if (!tmp)
 			/* invalid character */
-			return EILSEQ;
-		len8+=tmp;
+			return -EILSEQ;
+		len8 += tmp;
 	}
-	*out=result=ntfs_malloc(len8+1); /* allow for zero-termination */
+	*out = result = ntfs_malloc(len8 + 1); /* allow for zero-termination */
 
-	if(!result)
-		return ENOMEM;
-	result[len8]='\0';
-	*out_len=len8;
-	for(i=len8=0;i<in_len;i++)
-		len8+=to_utf8(NTFS_GETU16(in+i),result+len8);
-	ntfs_debug(DEBUG_NAME1,"result %p:%s\n",result,result);
+	if (!result)
+		return -ENOMEM;
+	result[len8] = '\0';
+	*out_len = len8;
+	for (i = len8 = 0; i < in_len; i++)
+		len8 += to_utf8(NTFS_GETU16(in + i), result + len8);
+	ntfs_debug(DEBUG_NAME1, "result %p:%s\n", result, result);
 	return 0;
 }
 
 /* Converts an UTF-8 sequence to a wide string. Same conventions as the
- * previous function
- */
-static int ntfs_duputf82uni(unsigned char* in, int in_len,ntfs_u16** out,int *out_len)
+ * previous function. */
+static int ntfs_duputf82uni(unsigned char* in, int in_len, ntfs_u16** out,
+			    int *out_len)
 {
-	int i,tmp;
+	int i, tmp;
 	int len16;
-
 	ntfs_u16* result;
 	ntfs_u16 wtmp;
-	for(i=len16=0;i<in_len;i+=tmp,len16++){
-		tmp=from_utf8(in+i,&wtmp);
-		if(!tmp)
-			return EILSEQ;
-	}
-	*out=result=ntfs_malloc(2*(len16+1));
-	if(!result)
-		return ENOMEM;
-	result[len16]=0;
-	*out_len=len16;
-	for(i=len16=0;i<in_len;i+=tmp,len16++)
+
+	for (i = len16 = 0; i < in_len; i += tmp, len16++) {
+		tmp = from_utf8(in + i, &wtmp);
+		if (!tmp)
+			return -EILSEQ;
+	}
+	*out = result = ntfs_malloc(2 * (len16 + 1));
+	if (!result)
+		return -ENOMEM;
+	result[len16] = 0;
+	*out_len = len16;
+	for (i = len16 = 0; i < in_len; i += tmp, len16++)
 	{
-		tmp=from_utf8(in+i, &wtmp);
-		NTFS_PUTU16(result+len16, wtmp);
+		tmp = from_utf8(in + i, &wtmp);
+		NTFS_PUTU16(result + len16, wtmp);
 	}
 	return 0;
 }
 
-/* See above. Produces ISO-8859-1 from wide strings */
-static int ntfs_dupuni288591(ntfs_u16* in,int in_len,char** out,int *out_len)
+/* See above. Produces ISO-8859-1 from wide strings. */
+static int ntfs_dupuni288591(ntfs_u16* in, int in_len, char** out, int *out_len)
 {
 	int i;
 	char *result;
 
-	/* check for characters out of range */
-	for(i=0;i<in_len;i++)
-		if(NTFS_GETU16(in+i)>=256)
-			return EILSEQ;
-	*out=result=ntfs_malloc(in_len+1);
-	if(!result)
-		return ENOMEM;
-	result[in_len]='\0';
-	*out_len=in_len;
-	for(i=0;i<in_len;i++)
-		result[i]=(unsigned char)NTFS_GETU16(in+i);
+	/* Check for characters out of range. */
+	for (i = 0; i < in_len; i++)
+		if (NTFS_GETU16(in + i) >= 256)
+			return -EILSEQ;
+	*out = result = ntfs_malloc(in_len + 1);
+	if (!result)
+		return -ENOMEM;
+	result[in_len] = '\0';
+	*out_len = in_len;
+	for (i = 0; i < in_len; i++)
+		result[i] = (unsigned char)NTFS_GETU16(in + i);
 	return 0;
 }
 
-/* See above */
-static int ntfs_dup885912uni(unsigned char* in,int in_len,ntfs_u16 **out,int *out_len)
+/* See above. */
+static int ntfs_dup885912uni(unsigned char* in, int in_len, ntfs_u16 **out,
+			     int *out_len)
 {
 	int i;
 
 	ntfs_u16* result;
-	*out=result=ntfs_malloc(2*in_len);
-	if(!result)
-		return ENOMEM;
-	*out_len=in_len;
-	for(i=0;i<in_len;i++)
-		NTFS_PUTU16(result+i,in[i]);
+	*out = result = ntfs_malloc(2 * in_len);
+	if (!result)
+		return -ENOMEM;
+	*out_len = in_len;
+	for (i = 0; i < in_len; i++)
+		NTFS_PUTU16(result + i, in[i]);
 	return 0;
 }
 
 /* Encodings dispatcher */
-int ntfs_encodeuni(ntfs_volume *vol,ntfs_u16 *in, int in_len,
-		   char **out, int *out_len)
+int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
+		   int *out_len)
 {
-	if(vol->nct & nct_utf8)
-		return ntfs_dupuni2utf8(in,in_len,out,out_len);
-	else if(vol->nct & nct_iso8859_1)
-		return ntfs_dupuni288591(in,in_len,out,out_len);
-	else if(vol->nct & (nct_map|nct_uni_xlate))
-		/* uni_xlate is handled inside map */
-		return ntfs_dupuni2map(vol,in,in_len,out,out_len);
+	if (vol->nct & nct_utf8)
+		return ntfs_dupuni2utf8(in, in_len, out, out_len);
+	else if (vol->nct & nct_iso8859_1)
+		return ntfs_dupuni288591(in, in_len, out, out_len);
+	else if(vol->nct & (nct_map | nct_uni_xlate))
+		/* uni_xlate is handled inside map. */
+		return ntfs_dupuni2map(vol, in, in_len, out, out_len);
 	else
-		return EINVAL; /* unknown encoding */
+		return -EINVAL; /* unknown encoding */
 }
 
-int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len,
-		   ntfs_u16 **out, int *out_len)
+int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
+		   int *out_len)
 {
-	if(vol->nct & nct_utf8)
-		return ntfs_duputf82uni(in,in_len,out,out_len);
-	else if(vol->nct & nct_iso8859_1)
-		return ntfs_dup885912uni(in,in_len,out,out_len);
-	else if(vol->nct & (nct_map | nct_uni_xlate))
-		return ntfs_dupmap2uni(vol,in,in_len,out,out_len);
+	if (vol->nct & nct_utf8)
+		return ntfs_duputf82uni(in, in_len, out, out_len);
+	else if (vol->nct & nct_iso8859_1)
+		return ntfs_dup885912uni(in, in_len, out, out_len);
+	else if (vol->nct & (nct_map | nct_uni_xlate))
+		return ntfs_dupmap2uni(vol, in, in_len, out, out_len);
 	else
-		return EINVAL;
+		return -EINVAL;
 }
 
-/* Same address space copies */
-void ntfs_put(ntfs_io *dest,void *src,ntfs_size_t n)
+/* Same address space copies. */
+void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n)
 {
-	ntfs_memcpy(dest->param,src,n);
-	((char*)dest->param)+=n;
+	ntfs_memcpy(dest->param, src, n);
+	((char*)dest->param) += n;
 }
 
-void ntfs_get(void* dest,ntfs_io *src,ntfs_size_t n)
+void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n)
 {
-	ntfs_memcpy(dest,src->param,n);
-	((char*)src->param)+=n;
+	ntfs_memcpy(dest, src->param, n);
+	((char*)src->param) += n;
 }
 
 void *ntfs_calloc(int size)
 {
-	void *result=ntfs_malloc(size);
-	if(result)
-		ntfs_bzero(result,size);
+	void *result = ntfs_malloc(size);
+	if (result)
+		ntfs_bzero(result, size);
 	return result;
 }
 
 #if 0
-/* copy len unicode characters from from to to :) */
-void ntfs_uni2ascii(char *to,char *from,int len)
+/* Copy len unicode characters from from to to. :) */
+void ntfs_uni2ascii(char *to, short int *from, int len)
 {
 	int i;
 
-	for(i=0;i<len;i++)
-		to[i]=from[2*i];
-	to[i]='\0';
+	for (i = 0; i < len; i++)
+		to[i] = NTFS_GETU16(from + i);
+	to[i] = '\0';
 }
 #endif
 
-/* copy len asci characters from from to to :) */
-void ntfs_ascii2uni(short int *to,char *from,int len)
+/* Copy len ascii characters from from to to. :) */
+void ntfs_ascii2uni(short int *to, char *from, int len)
 {
 	int i;
 
-	for(i=0;i<len;i++)
-		to[i]=from[i];
-	to[i]=0;
+	for (i = 0; i < len; i++)
+		NTFS_PUTU16(to + i, from[i]);
+	to[i] = 0;
 }
 
-/* strncmp for Unicode strings */
-int ntfs_uni_strncmp(short int* a,short int *b,int n)
+/* strncmp for Unicode strings. */
+int ntfs_uni_strncmp(short int* a, short int *b, int n)
 {
 	int i;
 
-	for(i=0;i<n;i++)
+	for(i = 0; i < n; i++)
 	{
-		if(a[i]<b[i])
+		if (NTFS_GETU16(a + i) < NTFS_GETU16(b + i))
 			return -1;
-		if(b[i]<a[i])
+		if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i))
 			return 1;
-		if (a[i] == 0)
+		if (NTFS_GETU16(a + i) == 0)
 			return 0;
 	}
 	return 0;
 }
 
-/* strncmp between Unicode and ASCII strings */
-int ntfs_ua_strncmp(short int* a,char* b,int n)
+/* strncmp between Unicode and ASCII strings. */
+int ntfs_ua_strncmp(short int* a, char* b, int n)
 {
 	int i;
 
-	for(i=0;i<n;i++)
-	{
-		if(NTFS_GETU16(a+i)<b[i])
+	for (i = 0; i < n; i++)	{
+		if(NTFS_GETU16(a + i) < b[i])
 			return -1;
-		if(b[i]<NTFS_GETU16(a+i))
+		if(b[i] < NTFS_GETU16(a + i))
 			return 1;
 		if (b[i] == 0)
 			return 0;
@@ -291,16 +280,13 @@
 }
 
 /* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
- * into Unix UTC (based 1.1.1970, in seconds)
- */
+ * into Unix UTC (based 1.1.1970, in seconds). */
 ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
 {
-/*
- * This is very gross because
- * 1: We must do 64-bit division on a 32-bit machine
- * 2: We can't use libgcc for long long operations in the kernel
- * 3: Floating point math in the kernel would corrupt user data
- */
+/* This is very gross because:
+ * 1: We must do 64-bit division on a 32-bit machine.
+ * 2: We can't use libgcc for long long operations in the kernel.
+ * 3: Floating point math in the kernel would corrupt user data. */
 	const unsigned int D = 10000000;
 	unsigned int H = (unsigned int)(ntutc >> 32);
 	unsigned int L = (unsigned int)ntutc;
@@ -310,63 +296,55 @@
 
 	/* It is best to subtract 0x019db1ded53e8000 first. */
 	/* Then the 1601-based date becomes a 1970-based date. */
-	if(L < (unsigned)0xd53e8000) H--;
+	if (L < (unsigned)0xd53e8000)
+		H--;
 	L -= (unsigned)0xd53e8000;
 	H -= (unsigned)0x019db1de;
 
-	/*
-	 * Now divide 64-bit numbers on a 32-bit machine :-)
+	/* Now divide 64-bit numbers on a 32-bit machine. :-)
 	 * With the subtraction already done, the result fits in 32 bits.
 	 * The numerator fits in 56 bits and the denominator fits
-	 * in 24 bits, so we can shift by 8 bits to make this work.
-	 */
+	 * in 24 bits, so we can shift by 8 bits to make this work. */
 
-	numerator2  = (H<<8) | (L>>24);
+	numerator2  = (H << 8) | (L >> 24);
 	result      = (numerator2 / D);   /* shifted 24 right!! */
 	lowseconds  = result << 24;
 
-	numerator2  = ((numerator2-result*D)<<8) | ((L>>16)&0xff);
+	numerator2  = ((numerator2 - result * D) << 8) | ((L >> 16) & 0xff);
 	result      = (numerator2 / D);   /* shifted 16 right!! */
 	lowseconds |= result << 16;
 
-	numerator2  = ((numerator2-result*D)<<8) | ((L>>8)&0xff);
+	numerator2  = ((numerator2 - result * D) << 8) | ((L >> 8) & 0xff);
 	result      = (numerator2 / D);   /* shifted 8 right!! */
 	lowseconds |= result << 8;
 
-	numerator2  = ((numerator2-result*D)<<8) | (L&0xff);
+	numerator2  = ((numerator2 - result * D) << 8) | (L & 0xff);
 	result      = (numerator2 / D);   /* not shifted */
 	lowseconds |= result;
 
 	return lowseconds;
 }
 
-/* Convert the Unix UTC into NT UTC */
+/* Convert the Unix UTC into NT UTC. */
 ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
 {
-	return ((t + (ntfs_time64_t)(369*365+89)*24*3600) * 10000000);
+	return ((t + (ntfs_time64_t)(369 * 365 + 89) * 24 * 3600) * 10000000);
 }
 
 /* Fill index name. */
-
-void
-ntfs_indexname(char *buf, int type)
+void ntfs_indexname(char *buf, int type)
 {
-	char hex[]="0123456789ABCDEF";
+	char hex[] = "0123456789ABCDEF";
 	int index;
-	*buf++='$';
-	*buf++='I';
-	for (index=24; index>0; index-=4)
-		if((0xF << index) & type)
+	*buf++ = '$';
+	*buf++ = 'I';
+	for (index = 24; index > 0; index -= 4)
+		if ((0xF << index) & type)
 			break;
-	while(index>=0) {
+	while (index >= 0) {
 		*buf++ = hex[(type >> index) & 0xF];
-		index-=4;
+		index -= 4;
 	}
-	*buf='\0';
+	*buf = '\0';
 }
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/ntfs/util.h linux/fs/ntfs/util.h
--- v2.4.3/linux/fs/ntfs/util.h	Sat Jan  2 10:24:46 1999
+++ linux/fs/ntfs/util.h	Wed Apr 18 11:49:13 2001
@@ -1,55 +1,64 @@
-/*
- *  util.h
- *  Header file for util.c
+/*  util.h - Header file for util.c
  *
  *  Copyright (C) 1997 Régis Duchesne
+ *  Copyright (C) 2001 Anton Altaparmakov
  */
 
-/* Which character set is used for file names */
-/*  Translate everything to UTF-8 */
+/* Which character set is used for file names. */
+/*  Translate everything to UTF-8. */
 #define nct_utf8             1
-/*  Translate to 8859-1 */
+/*  Translate to 8859-1. */
 #define nct_iso8859_1        2
-/*  Quote unprintables with : */
+/*  Quote unprintables with ":". */
 #define nct_uni_xlate        4
-/*  Do that in the vfat way instead of the documented way */
+/*  Do that in the vfat way instead of the documented way. */
 #define nct_uni_xlate_vfat   8
-/*  Use a mapping table to determine printables */
+/*  Use a mapping table to determine printables. */
 #define nct_map              16
 
-/* The first 11 inodes correspond to special files */
-#define FILE_MFT      0
-#define FILE_MFTMIRR  1
-#define FILE_LOGFILE  2
-#define FILE_VOLUME   3
-#define FILE_ATTRDEF  4
-#define FILE_ROOT     5
-#define FILE_BITMAP   6
-#define FILE_BOOT     7
-#define FILE_BADCLUS  8
-#define FILE_QUOTA    9
-#define FILE_UPCASE  10
-
+/* The first 16 inodes correspond to NTFS special files */
+typedef enum {
+	FILE_$Mft	= 0,
+	FILE_$MftMirr	= 1,
+	FILE_$LogFile	= 2,
+	FILE_$Volume	= 3,
+	FILE_$AttrDef	= 4,
+	FILE_$root	= 5,
+	FILE_$BitMap	= 6,
+	FILE_$Boot	= 7,
+	FILE_$BadClus	= 8,
+	FILE_$Secure	= 9,
+	FILE_$UpCase	= 10,
+	FILE_$Extend	= 11,
+	FILE_Reserved12	= 12,
+	FILE_Reserved13	= 13,
+	FILE_Reserved14	= 14,
+	FILE_Reserved15	= 15,
+} NTFS_SYSTEM_FILES;
+ 
 /* Memory management */
 void *ntfs_calloc(int size);
 
 /* String operations */
 /*  Copy Unicode <-> ASCII */
 #if 0
-void ntfs_uni2ascii(char *to,char *from,int len);
+void ntfs_uni2ascii(char *to, char *from, int len);
 #endif
-void ntfs_ascii2uni(short int *to,char *from,int len);
+void ntfs_ascii2uni(short int *to, char *from, int len);
+
 /*  Comparison */
-int ntfs_uni_strncmp(short int* a,short int *b,int n);
-int ntfs_ua_strncmp(short int* a,char* b,int n);
+int ntfs_uni_strncmp(short int* a, short int *b, int n);
+int ntfs_ua_strncmp(short int* a, char* b, int n);
 
 /* Same address space copies */
 void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n);
 void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n);
 
 /* Charset conversion */
-int ntfs_encodeuni(ntfs_volume *vol,ntfs_u16 *in, int in_len,char **out, int *out_len);
-int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len, ntfs_u16 **out, int *out_len);
+int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
+		   int *out_len);
+int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
+		   int *out_len);
 
 /* Time conversion */
 /*  NT <-> Unix */
@@ -59,8 +68,3 @@
 /* Attribute names */
 void ntfs_indexname(char *buf, int type);
 
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -u --recursive --new-file v2.4.3/linux/fs/partitions/Makefile linux/fs/partitions/Makefile
--- v2.4.3/linux/fs/partitions/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/partitions/Makefile	Fri Apr 13 20:26:07 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := partitions.o
 
-export-objs := check.o
+export-objs := check.o ibm.o
 
 obj-y := check.o
 
diff -u --recursive --new-file v2.4.3/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- v2.4.3/linux/fs/partitions/ibm.c	Fri Feb 16 16:02:37 2001
+++ linux/fs/partitions/ibm.c	Fri Apr 13 20:26:07 2001
@@ -1,14 +1,17 @@
 /*
  * File...........: linux/fs/partitions/ibm.c      
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *                  Volker Sameske <sameske@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/10/00 Fixed detection of CMS formatted disks               
-
+ * 07/10/00 Fixed detection of CMS formatted disks     
+ * 02/13/00 VTOC partition support added
  */
 
+#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
@@ -25,145 +28,177 @@
 
 #include "ibm.h"
 #include "check.h"
+#include <asm/vtoc.h>
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 /* We hook in when DASD is a module... */
 int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL;
+EXPORT_SYMBOL(genhd_dasd_fillgeo);
+EXPORT_SYMBOL(genhd_dasd_name);
 #endif /* LINUX_IS_24 */
 
 typedef enum {
-  ibm_partition_none = 0,
-  ibm_partition_lnx1 = 1,
-  ibm_partition_vol1 = 3,
-  ibm_partition_cms1 = 4
+  ibm_partition_lnx1 = 0,
+  ibm_partition_vol1 = 1,
+  ibm_partition_cms1 = 2,
+  ibm_partition_none = 3
 } ibm_partition_t;
 
+static char* part_names[] = {   [ibm_partition_lnx1] = "LNX1",
+			     [ibm_partition_vol1] = "VOL1",
+			     [ibm_partition_cms1] = "CMS1",
+			     [ibm_partition_none] = "(nonl)"
+};
+
 static ibm_partition_t
 get_partition_type ( char * type )
 {
-        static char lnx[5]="LNX1";
-        static char vol[5]="VOL1";
-        static char cms[5]="CMS1";
-        if ( ! strncmp ( lnx, "LNX1",4 ) ) {
-                ASCEBC(lnx,4);
-                ASCEBC(vol,4);
-                ASCEBC(cms,4);
-        }
-        if ( ! strncmp (type,lnx,4) ||
-             ! strncmp (type,"LNX1",4) )
-                return ibm_partition_lnx1;
-        if ( ! strncmp (type,vol,4) )
-                return ibm_partition_vol1;
-        if ( ! strncmp (type,cms,4) )
-                return ibm_partition_cms1;
-        return ibm_partition_none;
+	int i;
+	for ( i = 0; i < 3; i ++) {
+		if ( ! strncmp (type,part_names[i],4) ) 
+			break;
+	}
+        return i;
+}
+
+/*
+ * add the two default partitions
+ * - whole dasd
+ * - whole dasd without "offset"
+ */
+static inline void
+two_partitions(struct gendisk *hd,
+	       int minor,
+	       int blocksize,
+	       int offset,
+	       int size) {
+
+        add_gd_partition( hd, minor, 0,size);
+	add_gd_partition( hd, minor + 1, 
+			   offset * (blocksize >> 9),
+			   size-offset*(blocksize>>9));
+}
+
+
+/*
+ * compute the block number from a 
+ * cyl-cyl-head-head structure
+ */
+static inline int
+cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
+        return ptr->cc * geo->heads * geo->sectors +
+	       ptr->hh * geo->sectors;
+}
+
+
+/*
+ * compute the block number from a 
+ * cyl-cyl-head-head-block structure
+ */
+static inline int
+cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
+        return ptr->cc * geo->heads * geo->sectors +
+		ptr->hh * geo->sectors +
+		ptr->b;
 }
 
 int 
 ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
 first_part_minor)
 {
-	struct buffer_head *bh;
+	struct buffer_head *bh, *buf;
 	ibm_partition_t partition_type;
 	char type[5] = {0,};
 	char name[7] = {0,};
 	struct hd_geometry geo;
-	mm_segment_t old_fs;
 	int blocksize;
-	struct file *filp = NULL;
-	struct inode *inode = NULL;
-	int offset, size;
+	int offset=0, size=0, psize=0, counter=0;
+	unsigned int blk;
+	format1_label_t f1;
+	volume_label_t vlabel;
 
+	if ( first_sector != 0 ) {
+		BUG();
+	}
+	if ( !genhd_dasd_fillgeo ) {
+		return 0;
+	}
+	genhd_dasd_fillgeo(dev,&geo);
 	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
 	if ( blocksize <= 0 ) {
 		return 0;
 	}
-	set_blocksize(dev, blocksize);  /* OUCH !! */
-
-	/* find out offset of volume label (partn table) */
-	inode = get_empty_inode();
-	inode -> i_rdev = dev;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	inode -> i_bdev = bdget(kdev_t_to_nr(dev));
-#endif /* KERNEL_VERSION */
-	filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
-	if (!filp)
-		return 0;
-	memset(filp,0,sizeof(struct file));
-	filp ->f_mode = 1; /* read only */
-	blkdev_open(inode,filp);
-	old_fs=get_fs();
-	set_fs(KERNEL_DS);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
-#else
-	filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
-#endif /* KERNEL_VERSION */
-	set_fs(old_fs);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
-        blkdev_put(inode->i_bdev,BDEV_FILE);
-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	blkdev_close(inode,filp);
-#else
-	blkdev_release(inode);
-#endif /* LINUX_VERSION_CODE */
 
-	size = hd -> sizes[MINOR(dev)]<<1;
+	set_blocksize(dev, blocksize);  /* OUCH !! */
 	if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
-		strncpy ( type,bh -> b_data, 4);
+		strncpy ( type,bh -> b_data + 0, 4);
 		strncpy ( name,bh -> b_data + 4, 6);
+		memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
         } else {
 		return 0;
 	}
-	if ( (*(char *)bh -> b_data) & 0x80 ) {
-		EBCASC(name,6);
-	}
-	switch ( partition_type = get_partition_type(type) ) {
-	case ibm_partition_lnx1: 
-		offset = (geo.start + 1);
-		printk ( "(LNX1)/%6s:",name);
-		break;
-	case ibm_partition_vol1:
-		offset = 0;
-		size = 0;
-		printk ( "(VOL1)/%6s:",name);
-		break;
+	EBCASC(type,4);
+	EBCASC(name,6);
+
+	partition_type = get_partition_type(type);
+	printk ( "%6s/%6s:",part_names[partition_type],name);
+	switch ( partition_type ) {
 	case ibm_partition_cms1:
-		printk ( "(CMS1)/%6s:",name);
-		if (* (((long *)bh->b_data) + 13) == 0) {
-			/* disk holds a CMS filesystem */
-			offset = (geo.start + 1);
-			printk ("(CMS)");
-		} else {
+		if (* (((long *)bh->b_data) + 13) != 0) {
 			/* disk is reserved minidisk */
-			// mdisk_setup_data.size[i] =
-			// (label[7] - 1 - label[13]) *
-			// (label[3] >> 9) >> 1;
 			long *label=(long*)bh->b_data;
 			blocksize = label[3];
 			offset = label[13];
 			size = (label[7]-1)*(blocksize>>9); 
 			printk ("(MDSK)");
+		} else {
+			offset = (geo.start + 1);
+			size = hd -> sizes[MINOR(dev)]<<1;
 		}
+		two_partitions( hd, MINOR(dev), blocksize, 
+				offset, size);
 		break;
+	case ibm_partition_lnx1: 
 	case ibm_partition_none:
-		printk ( "(nonl)/      :");
-		offset = (geo.start+1);
+		offset = (geo.start + 1);
+		size = hd -> sizes[MINOR(dev)]<<1;
+		two_partitions( hd, MINOR(dev), blocksize, 
+				offset, size);
+		break;
+	case ibm_partition_vol1:
+		add_gd_partition(hd, MINOR(dev), 0, size);
+
+		/* get block number and read then first format1 label */
+		blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+		if ((buf = bread( dev, blk, blocksize)) != NULL) {
+		        memcpy (&f1, buf->b_data, sizeof(format1_label_t));
+			bforget(buf);
+		}
+
+		while (f1.DS1FMTID == _ascebc['1']) {
+		        offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
+			psize  = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - 
+				offset + 1;
+			
+			counter++;
+			add_gd_partition(hd, MINOR(dev) + counter, 
+					  offset * (blocksize >> 9),
+					  psize * (blocksize >> 9));
+			
+			blk++;
+			if ((buf = bread( dev, blk, blocksize)) != NULL) {
+			        memcpy (&f1, buf->b_data, 
+					sizeof(format1_label_t));
+				bforget(buf);
+			}
+		}
 		break;
 	default:
-		offset = 0;
-		size = 0;
-		
+		add_gd_partition( hd, MINOR(dev), 0, 0);
+		add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
 	}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	add_gd_partition( hd, MINOR(dev), 0,size);
-	add_gd_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
-			  size-offset*(blocksize>>9));
-#else
-	add_partition( hd, MINOR(dev), 0,size,0);
-	add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
-			  size-offset*(blocksize>>9) ,0 );
-#endif /* LINUX_VERSION */
+
 	printk ( "\n" );
 	bforget(bh);
 	return 1;
diff -u --recursive --new-file v2.4.3/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.4.3/linux/fs/proc/array.c	Mon Mar 19 12:34:55 2001
+++ linux/fs/proc/array.c	Fri Apr  6 10:51:19 2001
@@ -273,9 +273,6 @@
 {
 	char * orig = buffer;
 	struct mm_struct *mm;
-#if defined(CONFIG_ARCH_S390)
-	int line,len;
-#endif
 
 	buffer = task_name(task, buffer);
 	buffer = task_state(task, buffer);
@@ -291,8 +288,7 @@
 	buffer = task_sig(task, buffer);
 	buffer = task_cap(task, buffer);
 #if defined(CONFIG_ARCH_S390)
-	for(line=0;(len=sprintf_regs(line,buffer,task,NULL,NULL))!=0;line++)
-		buffer+=len;
+	buffer = task_show_regs(task, buffer);
 #endif
 	return buffer - orig;
 }
diff -u --recursive --new-file v2.4.3/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.4.3/linux/fs/proc/inode.c	Fri Mar  2 11:12:12 2001
+++ linux/fs/proc/inode.c	Tue Apr 17 23:16:39 2001
@@ -188,7 +188,6 @@
 	s->s_blocksize_bits = 10;
 	s->s_magic = PROC_SUPER_MAGIC;
 	s->s_op = &proc_sops;
-	s->s_maxbytes = MAX_NON_LFS;
 	
 	root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
 	if (!root_inode)
diff -u --recursive --new-file v2.4.3/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.4.3/linux/fs/proc/proc_misc.c	Fri Mar 23 11:45:28 2001
+++ linux/fs/proc/proc_misc.c	Fri Apr 13 20:26:07 2001
@@ -274,8 +274,10 @@
 		user += kstat.per_cpu_user[cpu];
 		nice += kstat.per_cpu_nice[cpu];
 		system += kstat.per_cpu_system[cpu];
+#if !defined(CONFIG_ARCH_S390)
 		for (j = 0 ; j < NR_IRQS ; j++)
 			sum += kstat.irqs[cpu][j];
+#endif
 	}
 
 	len = sprintf(page, "cpu  %u %u %u %lu\n", user, nice, system,
@@ -299,8 +301,10 @@
 			kstat.pswpout,
 			sum
 	);
+#if !defined(CONFIG_ARCH_S390)
 	for (i = 0 ; i < NR_IRQS ; i++)
 		len += sprintf(page + len, " %u", kstat_irqs(i));
+#endif
 
 	len += sprintf(page + len, "\ndisk_io: ");
 
diff -u --recursive --new-file v2.4.3/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.4.3/linux/fs/qnx4/inode.c	Fri Mar  2 11:12:12 2001
+++ linux/fs/qnx4/inode.c	Tue Apr 17 23:16:39 2001
@@ -369,7 +369,6 @@
 	}
 	s->s_op = &qnx4_sops;
 	s->s_magic = QNX4_SUPER_MAGIC;
-	s->s_maxbytes = MAX_NON_LFS;
 #ifndef CONFIG_QNX4FS_RW
 	s->s_flags |= MS_RDONLY;	/* Yup, read-only yet */
 #endif
diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- v2.4.3/linux/fs/reiserfs/fix_node.c	Fri Mar  2 18:38:39 2001
+++ linux/fs/reiserfs/fix_node.c	Fri Apr 13 20:26:07 2001
@@ -479,7 +479,7 @@
     // do not count last 'end_bytes' units of 'end_item'-th item
     end_bytes = (to_bytes != -1) ? to_bytes : 0;
 
-    /* go through all item begining from the start_item-th item and ending by
+    /* go through all item beginning from the start_item-th item and ending by
        the end_item-th item. Do not count first 'start_bytes' units of
        'start_item'-th item and last 'end_bytes' of 'end_item'-th item */
     
diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- v2.4.3/linux/fs/reiserfs/journal.c	Mon Jan 15 15:31:19 2001
+++ linux/fs/reiserfs/journal.c	Thu Apr 19 22:57:06 2001
@@ -1814,16 +1814,14 @@
 ** then run the per filesystem commit task queue when we wakeup.
 */
 static int reiserfs_journal_commit_thread(void *nullp) {
-  exit_files(current);
-  exit_mm(current);
+
+  daemonize() ;
 
   spin_lock_irq(&current->sigmask_lock);
   sigfillset(&current->blocked);
   recalc_sigpending(current);
   spin_unlock_irq(&current->sigmask_lock);
 
-  current->session = 1;
-  current->pgrp = 1;
   sprintf(current->comm, "kreiserfsd") ;
   lock_kernel() ;
   while(1) {
@@ -2052,7 +2050,7 @@
 	sleep_on(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ;
       }
     }
-    lock_journal(p_s_sb) ; /* relock to continue */
+    goto relock ;
   }
 
   if (SB_JOURNAL(p_s_sb)->j_trans_start_time == 0) { /* we are the first writer, set trans_id */
diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/prints.c linux/fs/reiserfs/prints.c
--- v2.4.3/linux/fs/reiserfs/prints.c	Mon Jan 15 15:31:19 2001
+++ linux/fs/reiserfs/prints.c	Fri Apr 13 20:26:07 2001
@@ -259,14 +259,14 @@
 {
   do_reiserfs_warning;
   /* console_print (error_buf); */
-  printk ("%s", error_buf);
+  printk (KERN_WARNING "%s", error_buf);
 }
 
 void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...)
 {
 #ifdef CONFIG_REISERFS_CHECK
   do_reiserfs_warning;
-  printk ("%s", error_buf);
+  printk (KERN_DEBUG "%s", error_buf);
 #else
   ; 
 #endif
diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- v2.4.3/linux/fs/reiserfs/stree.c	Fri Mar  2 18:38:39 2001
+++ linux/fs/reiserfs/stree.c	Fri Apr 13 20:26:07 2001
@@ -380,7 +380,7 @@
     /* Parent at the path is not in the tree now. */
     if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
       return &MIN_KEY;
-    /* Check whether position in the parrent is correct. */
+    /* Check whether position in the parent is correct. */
     if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
       return &MIN_KEY;
     /* Check whether parent at the path really points to the child. */
diff -u --recursive --new-file v2.4.3/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.4.3/linux/fs/romfs/inode.c	Fri Mar  2 11:12:12 2001
+++ linux/fs/romfs/inode.c	Fri Apr 13 20:26:07 2001
@@ -403,9 +403,11 @@
 	void *buf;
 	int result = -EIO;
 
+	page_cache_get(page);
 	lock_kernel();
-	get_page(page);
-	buf = page_address(page);
+	buf = kmap(page);
+	if (!buf)
+		goto err_out;
 
 	/* 32 bit warning -- but not for us :) */
 	offset = page->index << PAGE_CACHE_SHIFT;
@@ -428,7 +430,9 @@
 
 	UnlockPage(page);
 
-	__free_page(page);
+	kunmap(page);
+err_out:
+	page_cache_release(page);
 	unlock_kernel();
 
 	return result;
diff -u --recursive --new-file v2.4.3/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.4.3/linux/fs/smbfs/inode.c	Tue Mar  6 19:14:59 2001
+++ linux/fs/smbfs/inode.c	Tue Apr 17 23:16:39 2001
@@ -392,7 +392,6 @@
 	sb->s_magic = SMB_SUPER_MAGIC;
 	sb->s_flags = 0;
 	sb->s_op = &smb_sops;
-	sb->s_maxbytes = MAX_NON_LFS;	/* client support missing */
 
 	sb->u.smbfs_sb.mnt = NULL;
 	sb->u.smbfs_sb.sock_file = NULL;
diff -u --recursive --new-file v2.4.3/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- v2.4.3/linux/fs/smbfs/ioctl.c	Tue Jul 18 22:30:34 2000
+++ linux/fs/smbfs/ioctl.c	Fri Apr 13 20:26:07 2001
@@ -45,7 +45,7 @@
 		if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
 			result = smb_newconn(server, &opt);
 		break;
-	default:
+	default:;
 	}
 
 	return result;
diff -u --recursive --new-file v2.4.3/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.4.3/linux/fs/smbfs/proc.c	Tue Mar  6 19:14:59 2001
+++ linux/fs/smbfs/proc.c	Fri Apr 13 20:26:07 2001
@@ -697,7 +697,7 @@
 #else
 	/*
 	 * We don't want to be interrupted. For example, what if 'current'
-	 * already has recieved a signal? sleep_on would terminate immediately
+	 * already has received a signal? sleep_on would terminate immediately
 	 * and smbmount would not be able to re-establish connection.
 	 *
 	 * smbmount should be able to reconnect later, but it can't because
@@ -712,7 +712,7 @@
 	if (server->state == CONN_VALID) {
 		/* This should be changed to VERBOSE, except many smbfs
 		   problems is with the userspace daemon not reconnecting. */
-		PARANOIA("sucessful, new pid=%d, generation=%d\n",
+		PARANOIA("successful, new pid=%d, generation=%d\n",
 			 server->conn_pid, server->generation);
 		result = 1;
 	}
diff -u --recursive --new-file v2.4.3/linux/fs/stat.c linux/fs/stat.c
--- v2.4.3/linux/fs/stat.c	Tue Dec  5 12:29:39 2000
+++ linux/fs/stat.c	Wed Apr 18 11:49:12 2001
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/file.h>
@@ -25,7 +26,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -38,7 +39,7 @@
 
 	if (warncount > 0) {
 		warncount--;
-		printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
+		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
 			current->comm);
 	} else if (warncount < 0) {
 		/* it's laughable, but... */
@@ -53,7 +54,7 @@
 	SET_OLDSTAT_GID(tmp, inode->i_gid);
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 #if BITS_PER_LONG == 32
-	if (inode->i_size > 0x7fffffff)
+	if (inode->i_size > MAX_NON_LFS)
 		return -EOVERFLOW;
 #endif	
 	tmp.st_size = inode->i_size;
@@ -79,7 +80,7 @@
 	SET_STAT_GID(tmp, inode->i_gid);
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 #if BITS_PER_LONG == 32
-	if (inode->i_size > 0x7fffffff)
+	if (inode->i_size > MAX_NON_LFS)
 		return -EOVERFLOW;
 #endif	
 	tmp.st_size = inode->i_size;
@@ -126,7 +127,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -162,7 +163,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -200,7 +201,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -267,7 +268,7 @@
 
 
 /* ---------- LFS-64 ----------- */
-#if !defined(__alpha__) && !defined (__ia64__) && !defined(__mips64)
+#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(CONFIG_ARCH_S390X)
 
 static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
 {
diff -u --recursive --new-file v2.4.3/linux/fs/super.c linux/fs/super.c
--- v2.4.3/linux/fs/super.c	Sun Mar 25 18:17:00 2001
+++ linux/fs/super.c	Tue Apr 17 14:39:50 2001
@@ -691,7 +691,7 @@
  *	the request.
  */
  
-struct super_block *get_empty_super(void)
+static struct super_block *get_empty_super(void)
 {
 	struct super_block *s;
 
@@ -738,6 +738,7 @@
 	sema_init(&s->s_dquot.dqio_sem, 1);
 	sema_init(&s->s_dquot.dqoff_sem, 1);
 	s->s_dquot.flags = 0;
+	s->s_maxbytes = MAX_NON_LFS;
 	lock_super(s);
 	if (!type->read_super(s, data, silent))
 		goto out_fail;
@@ -898,9 +899,9 @@
 	/* Need to clean after the sucker */
 	if (fs->fs_flags & FS_LITTER)
 		d_genocide(root);
-	if (fs->fs_flags & (FS_SINGLE|FS_LITTER))
-		shrink_dcache_parent(root);
+	shrink_dcache_parent(root);
 	dput(root);
+	fsync_dev(sb->s_dev);
 	lock_super(sb);
 	if (sop) {
 		if (sop->write_super && sb->s_dirt)
@@ -1073,20 +1074,6 @@
 
 	if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
 		sb->s_op->umount_begin(sb);
-
-	/*
-	 * Shrink dcache, then fsync. This guarantees that if the
-	 * filesystem is quiescent at this point, then (a) only the
-	 * root entry should be in use and (b) that root entry is
-	 * clean.
-	 */
-	shrink_dcache_sb(sb);
-	fsync_dev(sb->s_dev);
-
-	if (sb->s_root->d_inode->i_state) {
-		mntput(mnt);
-		return -EBUSY;
-	}
 
 	/* Something might grab it again - redo checks */
 
diff -u --recursive --new-file v2.4.3/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.4.3/linux/fs/sysv/inode.c	Fri Mar  2 11:12:12 2001
+++ linux/fs/sysv/inode.c	Tue Apr 17 23:16:39 2001
@@ -365,7 +365,6 @@
 		panic("sysv fs: bad i-node size");
 	set_blocksize(dev,BLOCK_SIZE);
 	sb->sv_block_base = 0;
-	sb->s_maxbytes = MAX_NON_LFS;
 
 	/* Try to read Xenix superblock */
 	if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) {
diff -u --recursive --new-file v2.4.3/linux/fs/udf/partition.c linux/fs/udf/partition.c
--- v2.4.3/linux/fs/udf/partition.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/udf/partition.c	Fri Apr 13 20:26:07 2001
@@ -162,6 +162,10 @@
 					mapsize = (rtl * sizeof(Uint32)) +
 						((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num);
 					sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL);
+					if (!sdata->s_spar_map) {
+						printk("couldnt allocate UDF s_spar_map!\n");
+						return;
+					}
 					sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl];
 					memset(sdata->s_spar_map, 0xFF, mapsize);
 				}
diff -u --recursive --new-file v2.4.3/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.4.3/linux/fs/udf/super.c	Fri Mar  2 11:12:12 2001
+++ linux/fs/udf/super.c	Mon Apr 23 10:00:21 2001
@@ -201,7 +201,7 @@
 	char *opt, *val;
 
 	uopt->novrs = 0;
-	uopt->blocksize = 512;
+	uopt->blocksize = 2048;
 	uopt->partition = 0xFFFF;
 	uopt->session = 0xFFFFFFFF;
 	uopt->lastblock = 0xFFFFFFFF;
@@ -344,8 +344,7 @@
 udf_set_blocksize(struct super_block *sb, int bsize)
 {
 	/* Use specified block size if specified */
-	if (!(sb->s_blocksize = get_hardblocksize(sb->s_dev)))
-		sb->s_blocksize = 2048;
+	sb->s_blocksize = get_hardsect_size(sb->s_dev);
 	if (bsize > sb->s_blocksize)
 		sb->s_blocksize = bsize;
 
diff -u --recursive --new-file v2.4.3/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.4.3/linux/fs/ufs/super.c	Fri Mar  2 11:12:12 2001
+++ linux/fs/ufs/super.c	Tue Apr 17 23:16:39 2001
@@ -489,12 +489,10 @@
 	if (!uspi)
 		goto failed;
 
-	/* Set a 2Gig file limit. Some UFS variants need to override 
+	/* Keep 2Gig file limit. Some UFS variants need to override 
 	   this but as I don't know which I'll let those in the know loosen
 	   the rules */
 	   
-	sb->s_maxbytes = MAX_NON_LFS;
-
 	switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) {
 	case UFS_MOUNT_UFSTYPE_44BSD:
 		UFSD(("ufstype=44bsd\n"))
diff -u --recursive --new-file v2.4.3/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.4.3/linux/fs/umsdos/ioctl.c	Tue Sep  5 14:05:46 2000
+++ linux/fs/umsdos/ioctl.c	Wed Apr 18 11:49:13 2001
@@ -95,7 +95,7 @@
 	    && cmd != UMSDOS_DOS_SETUP)
 		return fat_dir_ioctl (dir, filp, cmd, data_ptr);
 
-	/* #Specification: ioctl / acces
+	/* #Specification: ioctl / access
 	 * Only root (effective id) is allowed to do IOCTL on directory
 	 * in UMSDOS. EPERM is returned for other user.
 	 */
diff -u --recursive --new-file v2.4.3/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.4.3/linux/fs/vfat/namei.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/vfat/namei.c	Fri Apr  6 10:51:19 2001
@@ -10,6 +10,9 @@
  *    the problem, send a script that demonstrates it.
  *
  *  Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
+ *
+ *  Support Multibyte character and cleanup by
+ *  				OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
  */
 
 #define __NO_VERSION__
@@ -154,7 +157,7 @@
 	}
 	return 1;
 }
-
+#if 0 /* not used functions */
 static inline unsigned char
 vfat_getlower(struct nls_table *t, unsigned char c)
 {
@@ -162,62 +165,185 @@
 }
 
 static inline unsigned char
-vfat_tolower(struct nls_table *t, unsigned char c)
-{
-	unsigned char nc = t->charset2lower[c];
-
-	return nc ? nc : c;
-}
-
-static inline unsigned char
 vfat_getupper(struct nls_table *t, unsigned char c)
 {
 	return t->charset2upper[c];
 }
 
-static inline unsigned char
-vfat_toupper(struct nls_table *t, unsigned char c)
+static inline int
+vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound)
 {
-	unsigned char nc = t->charset2upper[c];
+	int charlen;
 
-	return nc ? nc : c;
+	if ( (charlen = t->uni2char(uc, op, bound)) < 0)
+		charlen = 0;
+
+	return charlen;
 }
 
-static int
-vfat_strnicmp(struct nls_table *t, const unsigned char *s1,
-					const unsigned char *s2, int len)
+static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len)
 {
-	while(len--)
-		if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++))
-			return 1;
+	wchar_t *walk;
+	unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE];
+	int chl, chi;
+	int space;
+
+	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
+		return -EINVAL;
+
+	if (IS_FREE(charbuf))
+		return -EINVAL;
+
+	chl = 0;
+	c = 0;
+	space = 1; /* disallow names starting with a dot */
+	for (walk = name; len && walk-name < 8;) {
+		len--;
+		chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE);
+		if (chl < 0)
+			return -EINVAL;
+
+		for (chi = 0; chi < chl; chi++) {
+			c = vfat_getupper(nls, charbuf[chi]);
+			if (!c) return -EINVAL;
+			if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
+			if (strchr(replace_chars,c)) return -EINVAL;
+			if (c < ' '|| c==':') return -EINVAL;
+			if (c == '.') goto dot;
+			space = c == ' ';
+		}
+	}
+dot:;
+	if (space) return -EINVAL;
+	if (len && c != '.') {
+		len--;
+		if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) {
+			if (charbuf[0] != '.') return -EINVAL;
+		} else
+			return -EINVAL;
+		c = '.';
+	}
+	if (c == '.') {
+		if (len >= 4) return -EINVAL;
+		while (len > 0) {
+			len--;
+			chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE);
+			if (chl < 0)
+				return -EINVAL;
+			for (chi = 0; chi < chl; chi++) {
+				c = vfat_getupper(nls, charbuf[chi]);
+				if (!c) return -EINVAL;
+				if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
+				if (strchr(replace_chars,c))
+					return -EINVAL;
+				if (c < ' ' || c == '.'|| c==':')
+					return -EINVAL;
+				space = c == ' ';
+			}
+		}
+		if (space) return -EINVAL;
+	}
 
 	return 0;
 }
 
-static inline int
-vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound)
+static int vfat_format_name(struct nls_table *nls, wchar_t *name,
+				int len, char *res)
 {
-	int charlen;
+	char *walk;
+	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
+	int chi, chl;
+	int space;
 
-	if ( (charlen = t->uni2char(uc, op, bound)) < 0)
-		charlen = 0;
+	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
+		return -EINVAL;
 
-	return charlen;
+	if (IS_FREE(charbuf))
+		return -EINVAL;
+
+	space = 1; /* disallow names starting with a dot */
+	for (walk = res; len--; ) {
+		chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
+		if (chl == 0)
+			return -EINVAL;
+		for (chi = 0; chi < chl; chi++){
+			if (charbuf[chi] == '.') goto dot;
+			if (!charbuf[chi]) return -EINVAL;
+			if (walk-res == 8) return -EINVAL;
+			if (strchr(replace_chars,charbuf[chi])) return -EINVAL;
+			if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL;
+			space = charbuf[chi] == ' ';
+			*walk = charbuf[chi];
+			walk++;
+		}
+	}
+dot:;
+	if (space) return -EINVAL;
+	if (len >= 0) {
+		while (walk-res < 8) *walk++ = ' ';
+		while (len > 0 && walk-res < MSDOS_NAME) {
+			chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
+			if (len < chl)
+				chl = len;
+			len -= chl;
+			for (chi = 0; chi < chl; chi++){
+				if (!charbuf[chi]) return -EINVAL;
+				if (strchr(replace_chars,charbuf[chi]))
+					return -EINVAL;
+				if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':')
+					return -EINVAL;
+				space = charbuf[chi] == ' ';
+				*walk++ = charbuf[chi];
+			}
+		}
+		if (space) return -EINVAL;
+		if (len) return -EINVAL;
+	}
+	while (walk-res < MSDOS_NAME) *walk++ = ' ';
+
+	return 0;
 }
 
 static inline int
 vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound)
 {
-	int chi, chl;
+	int chl;
 
 	if ( (chl = t->uni2char(uc, op, bound)) < 0)
 		chl = 0;
 
-	for (chi = 0; chi < chl; chi++)
-		op[chi] = vfat_toupper(t, op[chi]);
+	if (chl == 1)
+		op[0] = vfat_toupper(t, op[0]);
 
 	return chl;
 }
+#endif
+static inline unsigned char
+vfat_tolower(struct nls_table *t, unsigned char c)
+{
+	unsigned char nc = t->charset2lower[c];
+
+	return nc ? nc : c;
+}
+
+static inline unsigned char
+vfat_toupper(struct nls_table *t, unsigned char c)
+{
+	unsigned char nc = t->charset2upper[c];
+
+	return nc ? nc : c;
+}
+
+static int
+vfat_strnicmp(struct nls_table *t, const unsigned char *s1,
+					const unsigned char *s2, int len)
+{
+	while(len--)
+		if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++))
+			return 1;
+
+	return 0;
+}
 
 /*
  * Compute the hash for the vfat name corresponding to the dentry.
@@ -383,8 +509,35 @@
 
 /* Characters that are undesirable in an MS-DOS file name */
 
-static char bad_chars[] = "*?<>|\":/\\";
-static char replace_chars[] = "[];,+=";
+static wchar_t bad_chars[] = {
+	/*  `*'     `?'     `<'    `>'      `|'     `"'     `:'     `/'     `\' */
+	0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F, 0x005C, 0,
+};
+#define IS_BADCHAR(uni)	(vfat_unistrchr(bad_chars, (uni)) != NULL)
+
+static wchar_t replace_chars[] = {
+	/*  `['     `]'    `;'     `,'     `+'      `=' */
+	0x005B, 0x005D, 0x003B, 0x002C, 0x002B, 0x003D, 0,
+};
+#define IS_REPLACECHAR(uni)	(vfat_unistrchr(replace_chars, (uni)) != NULL)
+
+static inline wchar_t *vfat_unistrchr(const wchar_t *s, const wchar_t c)
+{
+	for(; *s != c; ++s)
+		if (*s == 0)
+			return NULL;
+	return (wchar_t *) s;
+}
+
+static inline int vfat_is_used_badchars(const wchar_t *s, int len)
+{
+	int i;
+	
+	for (i = 0; i < len; i++)
+		if (s[i] < 0x0020 || IS_BADCHAR(s[i]))
+			return -EINVAL;
+	return 0;
+}
 
 /* Checks the validity of a long MS-DOS filename */
 /* Returns negative number on error, 0 for a normal
@@ -393,18 +546,10 @@
 static int vfat_valid_longname(const char *name, int len, int xlate)
 {
 	const char **reserved, *walk;
-	unsigned char c;
-	int i, baselen;
+	int baselen;
 
 	if (len && name[len-1] == ' ') return -EINVAL;
 	if (len >= 256) return -EINVAL;
-	for (i = 0; i < len; i++) {
-		c = name[i];
-		if (xlate && c == ':') continue;
-		if (strchr(bad_chars,c)) {
-			return -EINVAL;
-		}
-	}
  	if (len < 3) return 0;
 
 	for (walk = name; *walk != 0 && *walk != '.'; walk++);
@@ -424,72 +569,6 @@
 	return 0;
 }
 
-static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len)
-{
-	wchar_t *walk;
-	unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE];
-	int chl, chi;
-	int space;
-
-	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
-		return -EINVAL;
-
-	if (IS_FREE(charbuf))
-		return -EINVAL;
-
-	chl = 0;
-	c = 0;
-	space = 1; /* disallow names starting with a dot */
-	for (walk = name; len && walk-name < 8;) {
-		len--;
-		chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE);
-		if (chl < 0)
-			return -EINVAL;
-
-		for (chi = 0; chi < chl; chi++) {
-			c = vfat_getupper(nls, charbuf[chi]);
-			if (!c) return -EINVAL;
-			if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
-			if (strchr(replace_chars,c)) return -EINVAL;
-			if (c < ' '|| c==':') return -EINVAL;
-			if (c == '.') goto dot;
-			space = c == ' ';
-		}
-	}
-dot:;
-	if (space) return -EINVAL;
-	if (len && c != '.') {
-		len--;
-		if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) {
-			if (charbuf[0] != '.') return -EINVAL;
-		} else
-			return -EINVAL;
-		c = '.';
-	}
-	if (c == '.') {
-		if (len >= 4) return -EINVAL;
-		while (len > 0) {
-			len--;
-			chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE);
-			if (chl < 0)
-				return -EINVAL;
-			for (chi = 0; chi < chl; chi++) {
-				c = vfat_getupper(nls, charbuf[chi]);
-				if (!c) return -EINVAL;
-				if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
-				if (strchr(replace_chars,c))
-					return -EINVAL;
-				if (c < ' ' || c == '.'|| c==':')
-					return -EINVAL;
-				space = c == ' ';
-			}
-		}
-		if (space) return -EINVAL;
-	}
-
-	return 0;
-}
-
 static int vfat_find_form(struct inode *dir,char *name)
 {
 	struct msdos_dir_entry *de;
@@ -503,127 +582,62 @@
 	return 0;
 }
 
-static int vfat_format_name(struct nls_table *nls, wchar_t *name,
-				int len, char *res)
-{
-	char *walk;
-	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
-	int chi, chl;
-	int space;
-
-	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
-		return -EINVAL;
-
-	if (IS_FREE(charbuf))
-		return -EINVAL;
-
-	space = 1; /* disallow names starting with a dot */
-	for (walk = res; len--; ) {
-		chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
-		if (chl == 0)
-			return -EINVAL;
-		for (chi = 0; chi < chl; chi++){
-			if (charbuf[chi] == '.') goto dot;
-			if (!charbuf[chi]) return -EINVAL;
-			if (walk-res == 8) return -EINVAL;
-			if (strchr(replace_chars,charbuf[chi])) return -EINVAL;
-			if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL;
-			space = charbuf[chi] == ' ';
-			*walk = charbuf[chi];
-			walk++;
-		}
-	}
-dot:;
-	if (space) return -EINVAL;
-	if (len >= 0) {
-		while (walk-res < 8) *walk++ = ' ';
-		while (len > 0 && walk-res < MSDOS_NAME) {
-			chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
-			if (len < chl)
-				chl = len;
-			len -= chl;
-			for (chi = 0; chi < chl; chi++){
-				if (!charbuf[chi]) return -EINVAL;
-				if (strchr(replace_chars,charbuf[chi]))
-					return -EINVAL;
-				if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':')
-					return -EINVAL;
-				space = charbuf[chi] == ' ';
-				*walk++ = charbuf[chi];
-			}
-		}
-		if (space) return -EINVAL;
-		if (len) return -EINVAL;
-	}
-	while (walk-res < MSDOS_NAME) *walk++ = ' ';
-
-	return 0;
-}
-
-static char skip_chars[] = ".:\"?<>| ";
+static wchar_t skip_chars[] = {
+	/*  `.'     ` ' */
+	0x002E, 0x0020, 0,
+};
+#define IS_SKIPCHAR(uni) \
+	((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1])
 
 /* Given a valid longname, create a unique shortname.  Make sure the
  * shortname does not exist
+ * Returns negative number on error, 0 for a normal
+ * return, and 1 for valid shortname
  */
 static int vfat_create_shortname(struct inode *dir, struct nls_table *nls,
-					wchar_t *name, int len,
-					char *name_res)
+				 wchar_t *uname, int ulen,
+				 char *name_res)
 {
-	wchar_t *ip, *op, *ext_start, *end, *name_start;
-	wchar_t msdos_name[13];
-	char base[9], ext[4], buf[8], *p;
+	wchar_t *ip, *ext_start, *end, *name_start;
+	unsigned char base[9], ext[4], buf[8], *p;
 	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
 	int chl, chi;
-	int sz, extlen, baselen, i;
-
-	PRINTK2(("Entering vfat_create_shortname\n"));
-	chl = 0;
-	sz = 0;			/* Make compiler happy */
-	if (len <= 12) {
-		/* Do a case insensitive search if the name would be a valid
-		 * shortname if is were all capitalized.  However, do not
-		 * allow spaces in short names because Win95 scandisk does
-		 * not like that */
-		for (i = 0, op = &msdos_name[0], ip = name; ; i++, ip++, op++) {
-			if (i == len) {
-				if (vfat_format_name(nls, &msdos_name[0], len,
-							name_res) < 0)
-					break;
-				PRINTK3(("vfat_create_shortname 1\n"));
-				if (vfat_find_form(dir, name_res) < 0)
-					return 0;
-				return -EEXIST;
-			}
-			chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE);
-			for (chi = 0; chi < chl; chi++){
-				if (charbuf[chi] == ' ')
-					break;
-			}
-			if (chi < chl)
-				break;
+	int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
+	int is_uppercase, is_shortname;
 
-			*op = *ip;
-		}
-	}
+	/* 
+	 * 1) Valid characters for the 8.3 format alias are any
+	 * combination of letters, uppercase alphabets, digits, any of
+	 * the following special characters:
+	 *     $ % ' ` - @ { } ~ ! # ( ) & _ ^
+	 * In this case Longfilename is not stored in disk.
+	 *     
+	 * 2) File name is 8.3 format, but it contain the lowercase
+	 * alphabet etc. In this case numtail is not added, but
+	 * Longfilename is stored.
+	 * 
+	 * 3) When the one except for the above, or the following special
+	 * character are contained:
+	 *        .   [ ] ; , + =
+	 * numtail is added, and Longfilename must be stored in disk .
+	 */
+	is_uppercase = 1;
+	is_shortname = 1;
 
-	PRINTK3(("vfat_create_shortname 3\n"));
 	/* Now, we need to create a shortname from the long name */
-	ext_start = end = &name[len];
-	while (--ext_start >= name) {
-		chl = vfat_uni2upper_short(nls, *ext_start, charbuf, NLS_MAX_CHARSET_SIZE);
-		for (chi = 0; chi < chl; chi++) {
-			if (charbuf[chi] == '.') {
-				if (ext_start == end - 1) {
-					sz = len;
-					ext_start = NULL;
-				}
-				goto stop0;
+	ext_start = end = &uname[ulen];
+	while (--ext_start >= uname) {
+		if (*ext_start == 0x002E) { /* is `.' */
+			if (ext_start == end - 1) {
+				sz = ulen;
+				ext_start = NULL;
 			}
+			break;
 		}
 	}
-stop0:;	
-	if (ext_start == name - 1) {
-		sz = len;
+
+	if (ext_start == uname - 1) {
+		sz = ulen;
 		ext_start = NULL;
 	} else if (ext_start) {
 		/*
@@ -631,45 +645,63 @@
 		 * an extension eg. "...test".  In this case Win95
 		 * uses the extension as the name and sets no extension.
 		 */
-		name_start = &name[0];
-		while (name_start < ext_start)
-		{
-			chl = vfat_uni2upper_short(nls, *name_start, charbuf, NLS_MAX_CHARSET_SIZE);
-			if (chl == 0)
+		name_start = &uname[0];
+		while (name_start < ext_start) {
+			if (!IS_SKIPCHAR(*name_start))
 				break;
-			for (chi = 0; chi < chl; chi++)
-				if (!strchr(skip_chars, charbuf[chi])) {
-					goto stop1;
-				}
 			name_start++;
 		}
-stop1:;		
 		if (name_start != ext_start) {
-			sz = ext_start - name;
+			sz = ext_start - uname;
 			ext_start++;
 		} else {
-			sz = len;
+			sz = ulen;
 			ext_start=NULL;
 		}
 	}
 
-	for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++, ip++)
+	numtail_baselen = 6;
+	numtail2_baselen = 2;
+	for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++)
 	{
-		chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE);
-		if (chl == 0){
-			*p++ = '_';
-			baselen++;
+		if (IS_SKIPCHAR(*ip)) {
+			is_shortname = 0;
 			continue;
 		}
+		if (IS_REPLACECHAR(*ip)) {
+			is_shortname = 0;
+			charbuf[0] = '_';
+			chl = 1;
+		} else {
+			chl = nls->uni2char(*ip, charbuf, sizeof(charbuf));
+			if (chl <= 0) {
+				is_shortname = 0;
+				charbuf[0]  = '_';
+				chl = 1;
+			} else if (chl == 1) {
+				unsigned char c = charbuf[0];
+				charbuf[0] = vfat_toupper(nls, charbuf[0]);
+				if (c >= 0x7F || charbuf[0] != c)
+					is_uppercase = 0;
+			} else {
+				is_uppercase = 0;
+			}
+		}
 
+		if (baselen < 2 && (baselen + chl) > 2)
+			numtail2_baselen = baselen;
+		if (baselen < 6 && (baselen + chl) > 6)
+			numtail_baselen = baselen;
 		for (chi = 0; chi < chl; chi++){
-			if (!strchr(skip_chars, charbuf[chi])){
-				if (strchr(replace_chars, charbuf[chi]))
-					*p = '_';
-				else
-					*p = charbuf[chi];
-				p++; baselen++;
-			}
+			*p++ = charbuf[chi];
+			baselen++;
+			if (baselen >= 8)
+				break;
+		}
+		if (baselen >= 8) {
+			if ((chi < chl - 1) || (ip + 1) - uname < sz)
+				is_shortname = 0;
+			break;
 		}
 	}
 	if (baselen == 0) {
@@ -679,30 +711,51 @@
 	extlen = 0;
 	if (ext_start) {
 		for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
-			chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE);
-			if (chl == 0) {
-				*p++ = '_';
-				extlen++;
+			if (IS_SKIPCHAR(*ip)) {
+				is_shortname = 0;
 				continue;
 			}
-
-			for (chi = 0; chi < chl; chi++) {
-				if (!strchr(skip_chars, charbuf[chi])) {
-					if (strchr(replace_chars, charbuf[chi]))
-						*p = '_';
-					else
-						*p = charbuf[chi];
-					p++; extlen++;
+			if (IS_REPLACECHAR(*ip)) {
+				is_shortname = 0;
+				charbuf[0] = '_';
+				chl = 1;
+			} else {
+				chl = nls->uni2char(*ip, charbuf, sizeof(charbuf));
+				if (chl <= 0) {
+					is_shortname = 0;
+					charbuf[0] = '_';
+					chl = 1;
+				} else if (chl == 1) {
+					unsigned char c = charbuf[0];
+					charbuf[0] = vfat_toupper(nls, charbuf[0]);
+					if (c >= 0x7F || charbuf[0] != c)
+						is_uppercase = 0;
+				} else {
+					is_uppercase = 0;
 				}
 			}
+				
+			if ((extlen + chl) > 3) {
+				is_shortname = 0;
+				break;
+			}
+			for (chi = 0; chi < chl; chi++) {
+				*p++ = charbuf[chi];
+				extlen++;
+			}
+			if (extlen >= 3) {
+				if (ip + 1 != end)
+					is_shortname = 0;
+				break;
+			}
 		}
 	}
 	ext[extlen] = '\0';
 	base[baselen] = '\0';
 
 	/* Yes, it can happen. ".\xe5" would do it. */
-	if (IS_FREE(base))
-		base[0]='_';
+	if (base[0] == DELETED_FLAG)
+		base[0] = 0x05;
 
 	/* OK, at this point we know that base is not longer than 8 symbols,
 	 * ext is not longer than 3, base is nonempty, both don't contain
@@ -712,6 +765,14 @@
 	memset(name_res, ' ', MSDOS_NAME);
 	memcpy(name_res,base,baselen);
 	memcpy(name_res+8,ext,extlen);
+
+	if (is_shortname) {
+		if (vfat_find_form(dir, name_res) < 0)
+			return is_uppercase;
+		else
+			return -EEXIST;
+	}
+	
 	if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
 		if (vfat_find_form(dir, name_res) < 0)
 			return 0;
@@ -724,8 +785,10 @@
 	 * values for part of the base.
 	 */
 
-	if (baselen>6)
-		baselen = 6;
+	if (baselen>6) {
+		baselen = numtail_baselen;
+		name_res[7] = ' ';
+	}
 	name_res[baselen] = '~';
 	for (i = 1; i < 10; i++) {
 		name_res[baselen+1] = i + '0';
@@ -735,8 +798,10 @@
 
 	i = jiffies & 0xffff;
 	sz = (jiffies >> 16) & 0x7;
-	if (baselen>2)
-		baselen = 2;
+	if (baselen>2) {
+		baselen = numtail2_baselen;
+		name_res[7] = ' ';
+	}
 	name_res[baselen+4] = '~';
 	name_res[baselen+5] = '1' + sz;
 	while (1) {
@@ -868,15 +933,18 @@
 		goto out_free;
 
 	uname = (wchar_t *) page;
-	if (vfat_valid_shortname(nls_disk, uname, ulen) >= 0) {
-		res = vfat_format_name(nls_disk, uname, ulen, de->name);
-		if (!res)
-			goto out_free;
-	}
+	res = vfat_is_used_badchars(uname, ulen);
+	if (res < 0)
+		goto out_free;
 
 	res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name);
-	if (res)
+	if (res < 0)
+		goto out_free;
+	else if (res == 1) {
+		strncpy(de->name, msdos_name, MSDOS_NAME);
+		res = 0;
 		goto out_free;
+	}
 
 	*slots = unilen / 13;
 	for (cksum = i = 0; i < 11; i++) {
@@ -956,7 +1024,8 @@
 		goto cleanup;
 
 	res = vfat_build_slots(dir, qname->name, len, ds, &slots);
-	if (res < 0) goto cleanup;
+	if (res < 0)
+		goto cleanup;
 
 	offset = fat_add_entries(dir, slots, &bh1, &de1, &ino);
 	if (offset < 0) {
diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/compiler.h linux/include/asm-alpha/compiler.h
--- v2.4.3/linux/include/asm-alpha/compiler.h	Sun Nov 12 19:27:11 2000
+++ linux/include/asm-alpha/compiler.h	Sun Apr 22 19:10:53 2001
@@ -72,13 +72,4 @@
   __asm__("stw %1,%0" : "=m"(mem) : "r"(val))
 #endif
 
-/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented
-   a mechanism by which the user can annotate likely branch directions and
-   expect the blocks to be reordered appropriately.  Define __builtin_expect
-   to nothing for earlier compilers.  */
-
-#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
-#define __builtin_expect(x, expected_value) (x)
-#endif
-
 #endif /* __ALPHA_COMPILER_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.4.3/linux/include/asm-alpha/io.h	Fri Mar  2 11:12:07 2001
+++ linux/include/asm-alpha/io.h	Fri Apr 13 20:26:07 2001
@@ -1,10 +1,6 @@
 #ifndef __ALPHA_IO_H
 #define __ALPHA_IO_H
 
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <asm/system.h>
-
 /* We don't use IO slowdowns on the Alpha, but.. */
 #define __SLOW_DOWN_IO	do { } while (0)
 #define SLOW_DOWN_IO	do { } while (0)
@@ -19,6 +15,9 @@
 #endif
 
 #ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
 #include <asm/machvec.h>
 
 /*
diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/ioctls.h linux/include/asm-alpha/ioctls.h
--- v2.4.3/linux/include/asm-alpha/ioctls.h	Thu Jan 27 16:40:09 2000
+++ linux/include/asm-alpha/ioctls.h	Fri Apr 13 20:26:07 2001
@@ -106,5 +106,7 @@
 
 #define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TIOCGHAYESESP	0x545E  /* Get Hayes ESP configuration */
+#define TIOCSHAYESESP	0x545F  /* Set Hayes ESP configuration */
 
 #endif /* _ASM_ALPHA_IOCTLS_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h
--- v2.4.3/linux/include/asm-alpha/pgalloc.h	Fri Dec 29 14:07:23 2000
+++ linux/include/asm-alpha/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -241,6 +241,9 @@
 #define pte_quicklist (quicklists.pte_cache)
 #define pgtable_cache_size (quicklists.pgtable_cache_sz)
 
+#define pmd_populate(mm, pmd, pte)	pmd_set(pmd, pte)
+#define pgd_populate(mm, pgd, pmd)	pgd_set(pgd, pmd)
+
 extern pgd_t *get_pgd_slow(void);
 
 static inline pgd_t *get_pgd_fast(void)
@@ -268,9 +271,15 @@
 	free_page((unsigned long)pgd);
 }
 
-extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
+	if (ret)
+		clear_page(ret);
+	return ret;
+}
 
-static inline pmd_t *get_pmd_fast(void)
+static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
 	unsigned long *ret;
 
@@ -282,21 +291,27 @@
 	return (pmd_t *)ret;
 }
 
-static inline void free_pmd_fast(pmd_t *pmd)
+static inline void pmd_free_fast(pmd_t *pmd)
 {
 	*(unsigned long *)pmd = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pmd;
 	pgtable_cache_size++;
 }
 
-static inline void free_pmd_slow(pmd_t *pmd)
+static inline void pmd_free_slow(pmd_t *pmd)
 {
 	free_page((unsigned long)pmd);
 }
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL);
+	if (pte)
+		clear_page(pte);
+	return pte;
+}
 
-static inline pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
 	unsigned long *ret;
 
@@ -308,66 +323,22 @@
 	return (pte_t *)ret;
 }
 
-static inline void free_pte_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
 {
 	*(unsigned long *)pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
 
-static inline void free_pte_slow(pte_t *pte)
+static inline void pte_free_slow(pte_t *pte)
 {
 	free_page((unsigned long)pte);
 }
 
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pmd(pgd_t *pgd);
-
-#define pte_free_kernel(pte)	free_pte_fast(pte)
-#define pte_free(pte)		free_pte_fast(pte)
-#define pmd_free_kernel(pmd)	free_pmd_fast(pmd)
-#define pmd_free(pmd)		free_pmd_fast(pmd)
+#define pte_free(pte)		pte_free_fast(pte)
+#define pmd_free(pmd)		pmd_free_fast(pmd)
 #define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
-
-static inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = get_pte_fast();
-		
-		if (!page)
-			return get_pte_slow(pmd, address);
-		pmd_set(pmd, page);
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-static inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *page = get_pmd_fast();
-		
-		if (!page)
-			return get_pmd_slow(pgd, address);
-		pgd_set(pgd, page);
-		return page + address;
-	}
-	if (pgd_bad(*pgd)) {
-		__bad_pmd(pgd);
-		return NULL;
-	}
-	return (pmd_t *) pgd_page(*pgd) + address;
-}
-
-#define pte_alloc_kernel	pte_alloc
-#define pmd_alloc_kernel	pmd_alloc
+#define pgd_alloc(mm)		get_pgd_fast()
 
 extern int do_check_pgt_cache(int, int);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.4.3/linux/include/asm-alpha/pgtable.h	Sun Dec  3 17:45:20 2000
+++ linux/include/asm-alpha/pgtable.h	Fri Apr 13 20:26:07 2001
@@ -59,11 +59,6 @@
 #define _PAGE_FOW	0x0004	/* used for page protection (fault on write) */
 #define _PAGE_FOE	0x0008	/* used for page protection (fault on exec) */
 #define _PAGE_ASM	0x0010
-#if defined(CONFIG_ALPHA_EV6) && !defined(CONFIG_SMP)
-#define _PAGE_MBE	0x0080	/* MB disable bit for EV6.  */
-#else
-#define _PAGE_MBE	0x0000
-#endif
 #define _PAGE_KRE	0x0100	/* xxx - see below on the "accessed" bit */
 #define _PAGE_URE	0x0200	/* xxx */
 #define _PAGE_KWE	0x1000	/* used to do the dirty bit in software */
@@ -90,20 +85,19 @@
 #define _PFN_MASK	0xFFFFFFFF00000000
 
 #define _PAGE_TABLE	(_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
-#define _PAGE_CHG_MASK	(_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_MBE)
+#define _PAGE_CHG_MASK	(_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
 
 /*
- * All the normal masks have the "page accessed" bits on, as any time they
- * are used, the page is accessed.  They are cleared only by the page-out
- * routines. 
+ * All the normal masks have the "page accessed" bits on, as any time they are used,
+ * the page is accessed. They are cleared only by the page-out routines
  */
 #define PAGE_NONE	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
 #define PAGE_SHARED	__pgprot(_PAGE_VALID | __ACCESS_BITS)
 #define PAGE_COPY	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
 #define PAGE_READONLY	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
-#define PAGE_KERNEL	__pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE | _PAGE_MBE)
+#define PAGE_KERNEL	__pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE)
 
-#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_MBE | (x))
+#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x))
 
 #define _PAGE_P(x) _PAGE_NORMAL((x) | (((x) & _PAGE_FOW)?0:_PAGE_FOW))
 #define _PAGE_S(x) _PAGE_NORMAL(x)
@@ -195,7 +189,6 @@
  * Conversion functions:  convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-
 #define mk_pte(page, pgprot)						\
 ({									\
 	pte_t pte;							\
@@ -206,7 +199,7 @@
 })
 
 extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | (pgprot_val(pgprot) & ~_PAGE_MBE); return pte; }
+{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.4.3/linux/include/asm-alpha/semaphore.h	Fri Mar  2 11:12:07 2001
+++ linux/include/asm-alpha/semaphore.h	Sun Apr 22 19:10:53 2001
@@ -11,8 +11,9 @@
 #include <asm/current.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/compiler.h>	/* __builtin_expect */
+#include <linux/compiler.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 #define DEBUG_SEMAPHORE 0
 #define DEBUG_RW_SEMAPHORE 0
@@ -220,153 +221,6 @@
 extern inline void up(struct semaphore *sem)
 {
 	__up(sem);
-}
-#endif
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subtracting
- * BIAS once per CPU will result in the int remaining
- * negative.
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *	      -ben
- *
- * Once we start supporting machines with more than 128 CPUs,
- * we should go for using a 64bit atomic type instead of 32bit
- * as counter. We shall probably go for bias 0x80000000 then,
- * so that single sethi can set it.
- *
- *	      -jj
- */
-
-#define RW_LOCK_BIAS		0x01000000
-
-struct rw_semaphore {
-	atomic_t		count;
-	/* bit 0 means read bias granted;
-	   bit 1 means write bias granted.  */
-	unsigned		granted;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count)					\
-	{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	  __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait)		\
-	  __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) \
-	__DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) \
-	__DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) \
-	__DECLARE_RWSEM_GENERIC(name, 0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set (&sem->count, RW_LOCK_BIAS);
-	sem->granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern void down_read(struct rw_semaphore *);
-extern void down_write(struct rw_semaphore *);
-extern void up_read(struct rw_semaphore *);
-extern void up_write(struct rw_semaphore *);
-extern void __down_read_failed(struct rw_semaphore *, int);
-extern void __down_write_failed(struct rw_semaphore *, int);
-extern void __rwsem_wake(struct rw_semaphore *, int);
-
-static inline void __down_read(struct rw_semaphore *sem)
-{
-	long count = atomic_dec_return(&sem->count);
-	if (__builtin_expect(count < 0, 0))
-		__down_read_failed(sem, count);
-}
-
-static inline void __down_write(struct rw_semaphore *sem)
-{
-	long count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-	if (__builtin_expect(count != 0, 0))
-		__down_write_failed(sem, count);
-}
-
-/* When a reader does a release, the only significant case is when there
-   was a writer waiting, and we've bumped the count to 0, then we must
-   wake the writer up.  */
-
-static inline void __up_read(struct rw_semaphore *sem)
-{
-	long count;
-	mb();
-	count = atomic_inc_return(&sem->count);
-	if (__builtin_expect(count == 0, 0))
-		__rwsem_wake(sem, 0);
-}
-
-/* Releasing the writer is easy -- just release it and wake up
-   any sleepers.  */
-
-static inline void __up_write(struct rw_semaphore *sem)
-{
-	long count, wake;
-	mb();
-	count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-
-	/* Only do the wake if we were, but are no longer, negative.  */
-	wake = ((int)(count - RW_LOCK_BIAS) < 0) && count >= 0;
-	if (__builtin_expect(wake, 0))
-		__rwsem_wake(sem, count);
-}
-
-#if !WAITQUEUE_DEBUG && !DEBUG_RW_SEMAPHORE
-extern inline void down_read(struct rw_semaphore *sem)
-{
-	__down_read(sem);
-}
-extern inline void down_write(struct rw_semaphore *sem)
-{
-	__down_write(sem);
-}
-extern inline void up_read(struct rw_semaphore *sem)
-{
-	__up_read(sem);
-}
-extern inline void up_write(struct rw_semaphore *sem)
-{
-	__up_write(sem);
 }
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h
--- v2.4.3/linux/include/asm-arm/arch-arc/hardware.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-arc/hardware.h	Thu Apr 12 12:20:31 2001
@@ -46,21 +46,28 @@
 #define SCREEN_BASE		0x02000000
 
 
+#define EXPMASK_BASE		0x03360000
+#define IOEB_BASE		0x03350000
+#define VIDC_BASE		0x03400000
+#define LATCHA_BASE		0x03250040
+#define LATCHB_BASE		0x03250018
+#define IOC_BASE		0x03200000
+#define FLOPPYDMA_BASE		0x0302a000
+#define PCIO_BASE		0x03010000
+
+#define vidc_writel(val)	__raw_writel(val, VIDC_BASE)
+
 #ifndef __ASSEMBLY__
 
 /*
  * for use with inb/outb
  */
-#define IO_VIDC_BASE		0x80100000
 #ifdef CONFIG_ARCH_A5K
-#define IOEB_VID_CTL		0x800d4012
-#define IOEB_PRESENT		0x800d4014
-#define IOEB_PSCLR		0x800d4016
-#define IOEB_MONTYPE		0x800d401c
+#define IOEB_VID_CTL		(IOEB_BASE + 0x48)
+#define IOEB_PRESENT		(IOEB_BASE + 0x50)
+#define IOEB_PSCLR		(IOEB_BASE + 0x58)
+#define IOEB_MONTYPE		(IOEB_BASE + 0x70)
 #endif
-#define LATCHAADDR		0x80094010
-#define LATCHBADDR		0x80094006
-#define IOC_BASE		0x80080000
 
 #define IO_EC_IOC4_BASE		0x8009c000
 #define IO_EC_IOC_BASE		0x80090000
@@ -74,36 +81,9 @@
 #define SCSI_BASE		0x03100000
 #endif
 
-/*
- * IO definitions
- */
-#define EXPMASK_BASE		((volatile unsigned char *)0x03360000)
-#define IOEB_BASE		((volatile unsigned char *)0x03350050)
-#define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0x0302a000)
-#define PCIO_BASE		0x03010000
-
-/*
- * RAM definitions
- */
-#define GET_MEMORY_END(p)	(PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_OFFSET		0x7c000
-
-#else
-
-#define IOEB_BASE		0x03350050
-#define IOC_BASE		0x03200000
-#define PCIO_FLOPPYDMABASE	0x0302a000
-#define PCIO_BASE		0x03010000
-
-#endif
-
-#ifndef __ASSEMBLY__
-#define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
-#else
-#define __EXPMASK(offset)	offset
 #endif
 
-#define	EXPMASK_STATUS	__EXPMASK(0x00)
-#define EXPMASK_ENABLE	__EXPMASK(0x04)
+#define	EXPMASK_STATUS		(EXPMASK_BASE + 0x00)
+#define EXPMASK_ENABLE		(EXPMASK_BASE + 0x04)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h
--- v2.4.3/linux/include/asm-arm/arch-arc/irq.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-arc/irq.h	Thu Apr 12 12:20:31 2001
@@ -16,6 +16,7 @@
  */
 #include <linux/config.h>
 #include <asm/hardware/ioc.h>
+#include <asm/io.h>
 
 #ifdef CONFIG_ARCH_ARC
 #define a_clf()	clf()
@@ -29,105 +30,81 @@
 
 static void arc_mask_irq_ack_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
+	mask = 1 << irq;
 	a_clf();
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]\n"
-"	strb	%1, [%3]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)),
-	  "r" (ioaddr(IOC_IRQCLRA)));
+	val = ioc_readb(IOC_IRQMASKA);
+	ioc_writeb(val & ~mask, IOC_IRQMASKA);
+	ioc_writeb(mask, IOC_IRQCLRA);
 	a_stf();
 }
 
 static void arc_mask_irq_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
+	mask = 1 << irq;
 	a_clf();
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)));
+	val = ioc_readb(IOC_IRQMASKA);
+	ioc_writeb(val & ~mask, IOC_IRQMASKA);
 	a_stf();
 }
 
 static void arc_unmask_irq_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
+	mask = 1 << irq;
 	a_clf();
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)));
+	val = ioc_readb(IOC_IRQMASKA);
+	ioc_writeb(val | mask, IOC_IRQMASKA);
 	a_stf();
 }
 
 static void arc_mask_irq_b(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB)));
+	mask = 1 << (irq & 7);
+	val = ioc_readb(IOC_IRQMASKB);
+	ioc_writeb(val & ~mask, IOC_IRQMASKB);
 }
 
 static void arc_unmask_irq_b(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB)));
+	mask = 1 << (irq & 7);
+	val = ioc_readb(IOC_IRQMASKB);
+	ioc_writeb(val | mask, IOC_IRQMASKB);
 }
 
 static void arc_mask_irq_fiq(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK)));
+	mask = 1 << (irq & 7);
+	val = ioc_readb(IOC_FIQMASK);
+	ioc_writeb(val & ~mask, IOC_FIQMASK);
 }
 
 static void arc_unmask_irq_fiq(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK)));
+	mask = 1 << (irq & 7);
+	val = ioc_readb(IOC_FIQMASK);
+	ioc_writeb(val | mask, IOC_FIQMASK);
 }
 
 static __inline__ void irq_init_irq(void)
 {
-	extern void ecard_disableirq(unsigned int irq);
-	extern void ecard_enableirq(unsigned int irq);
 	int irq;
 
-	outb(0, IOC_IRQMASKA);
-	outb(0, IOC_IRQMASKB);
-	outb(0, IOC_FIQMASK);
+	ioc_writeb(0, IOC_IRQMASKA);
+	ioc_writeb(0, IOC_IRQMASKB);
+	ioc_writeb(0, IOC_FIQMASK);
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
 		switch (irq) {
@@ -154,13 +131,6 @@
 			irq_desc[irq].mask_ack = arc_mask_irq_b;
 			irq_desc[irq].mask     = arc_mask_irq_b;
 			irq_desc[irq].unmask   = arc_unmask_irq_b;
-			break;
-
-		case 32 ... 40:
-			irq_desc[irq].valid    = 1;
-			irq_desc[irq].mask_ack = ecard_disableirq;
-			irq_desc[irq].mask     = ecard_disableirq;
-			irq_desc[irq].unmask   = ecard_enableirq;
 			break;
 
 		case 64 ... 72:
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- v2.4.3/linux/include/asm-arm/arch-arc/system.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-arc/system.h	Thu Apr 12 12:20:31 2001
@@ -15,13 +15,6 @@
 
 extern __inline__ void arch_reset(char mode)
 {
-	extern void ecard_reset(int card);
-
-	/*
-	 * Reset all expansion cards.
-	 */
-	ecard_reset(-1);
-
 	/*
 	 * copy branch instruction to reset location and call it
 	 */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/hardware.h linux/include/asm-arm/arch-cl7500/hardware.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/hardware.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-cl7500/hardware.h	Thu Apr 12 12:20:31 2001
@@ -49,47 +49,18 @@
 
 #define FLUSH_BASE		0xdf000000
 
-
-#ifndef __ASSEMBLY__
-
-/*
- * for use with inb/outb
- */
-#define IO_VIDC_AUDIO_BASE	0x80140000
-#define IO_VIDC_BASE		0x80100000
-#define IO_IOMD_BASE		0x80080000
-#define IOC_BASE		0x80080000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE		((volatile unsigned char *)0xe0360000)
-#define IOEB_BASE		((volatile unsigned char *)0xe0350050)
-#define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0xe002a000)
+#define VIDC_BASE		0xe0400000
+#define IOMD_BASE		0xe0200000
+#define IOC_BASE		0xe0200000
+#define FLOPPYDMA_BASE		0xe002a000
 #define PCIO_BASE		0xe0010000
-/* in/out bias for the ISA slot region */
-#define ISASLOT_IO		0x80400000
-
-/*
- * RAM definitions
- */
-#define GET_MEMORY_END(p)	(PAGE_OFFSET + p->u1.s.page_size * \
-						(p->u1.s.pages_in_bank[0] + \
-						 p->u1.s.pages_in_bank[1] + \
-						 p->u1.s.pages_in_bank[2] + \
-						 p->u1.s.pages_in_bank[3]))
 
 #define FLUSH_BASE_PHYS		0x00000000	/* ROM */
 
-#else
+#define vidc_writel(val)	__raw_writel(val, VIDC_BASE)
 
-#define VIDC_SND_BASE		0xe0500000
-#define VIDC_BASE		0xe0400000
-#define IOMD_BASE		0xe0200000
-#define IOC_BASE		0xe0200000
-#define PCIO_FLOPPYDMABASE	0xe002a000
-#define PCIO_BASE		0xe0010000
+/* in/out bias for the ISA slot region */
+#define ISASLOT_IO		0x80400000
 
-#endif
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/irq.h linux/include/asm-arm/arch-cl7500/irq.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/irq.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-cl7500/irq.h	Thu Apr 12 12:20:31 2001
@@ -2,14 +2,16 @@
  * include/asm-arm/arch-cl7500/irq.h
  *
  * Copyright (C) 1996 Russell King
- * Copyright (C) 1999 Nexus Electronics Ltd.
+ * Copyright (C) 1999, 2001 Nexus Electronics Ltd.
  *
  * Changelog:
  *   10-10-1996	RMK	Brought up to date with arch-sa110eval
  *   22-08-1998	RMK	Restructured IRQ routines
  *   11-08-1999	PJB	Created ARM7500 version, derived from RiscPC code
  */
+
 #include <asm/hardware/iomd.h>
+#include <asm/io.h>
 
 static inline int fixup_irq(unsigned int irq)
 {
@@ -19,7 +21,7 @@
 			printk("Spurious ISA IRQ!\n");
 			return irq;
 		}
-		irq = 40;
+		irq = IRQ_ISA_BASE;
 		while (!(isabits & 1)) {
 			irq++;
 			isabits >>= 1;
@@ -31,161 +33,121 @@
 
 static void cl7500_mask_irq_ack_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]\n"
-"	strb	%1, [%3]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)),
-	  "r" (ioaddr(IOMD_IRQCLRA)));
+	mask = 1 << irq;
+	val = iomd_readb(IOMD_IRQMASKA);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
+	iomd_writeb(mask, IOMD_IRQCLRA);
 }
 
 static void cl7500_mask_irq_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)));
+	mask = 1 << irq;
+	val = iomd_readb(IOMD_IRQMASKA);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
 }
 
 static void cl7500_unmask_irq_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)));
+	mask = 1 << irq;
+	val = iomd_readb(IOMD_IRQMASKA);
+	iomd_writeb(val | mask, IOMD_IRQMASKA);
 }
 
 static void cl7500_mask_irq_b(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKB);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKB);
 }
 
 static void cl7500_unmask_irq_b(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKB);
+	iomd_writeb(val | mask, IOMD_IRQMASKB);
 }
 
 static void cl7500_mask_irq_c(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKC)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKC);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKC);
 }
 
 static void cl7500_unmask_irq_c(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKC)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKC);
+	iomd_writeb(val | mask, IOMD_IRQMASKC);
 }
 
 
 static void cl7500_mask_irq_d(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKD)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKD);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKD);
 }
 
 static void cl7500_unmask_irq_d(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKD)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKD);
+	iomd_writeb(val | mask, IOMD_IRQMASKD);
 }
 
 static void cl7500_mask_irq_dma(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_DMAMASK);
+	iomd_writeb(val & ~mask, IOMD_DMAMASK);
 }
 
 static void cl7500_unmask_irq_dma(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_DMAMASK);
+	iomd_writeb(val | mask, IOMD_DMAMASK);
 }
 
 static void cl7500_mask_irq_fiq(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_FIQMASK);
+	iomd_writeb(val & ~mask, IOMD_FIQMASK);
 }
 
 static void cl7500_unmask_irq_fiq(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_FIQMASK);
+	iomd_writeb(val | mask, IOMD_FIQMASK);
 }
 
 static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
@@ -196,14 +158,12 @@
 
 static __inline__ void irq_init_irq(void)
 {
-	extern void ecard_disableirq(unsigned int irq);
-	extern void ecard_enableirq(unsigned int irq);
 	int irq;
 
-	outb(0, IOMD_IRQMASKA);
-	outb(0, IOMD_IRQMASKB);
-	outb(0, IOMD_FIQMASK);
-	outb(0, IOMD_DMAMASK);
+	iomd_writeb(0, IOMD_IRQMASKA);
+	iomd_writeb(0, IOMD_IRQMASKB);
+	iomd_writeb(0, IOMD_FIQMASK);
+	iomd_writeb(0, IOMD_DMAMASK);
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
 		switch (irq) {
@@ -239,14 +199,14 @@
 			irq_desc[irq].unmask   = cl7500_unmask_irq_c;
 			break;
 
-		case 32 ... 39:
+		case 40 ... 47:
 			irq_desc[irq].valid    = 1;
 			irq_desc[irq].mask_ack = cl7500_mask_irq_d;
 			irq_desc[irq].mask     = cl7500_mask_irq_d;
 			irq_desc[irq].unmask   = cl7500_unmask_irq_d;
 			break;
 
-		case 40 ... 47:
+		case 48 ... 55:
 			irq_desc[irq].valid      = 1;
 			irq_desc[irq].probe_ok   = 1;
 			irq_desc[irq].mask_ack   = no_action;
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/irqs.h linux/include/asm-arm/arch-cl7500/irqs.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/irqs.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-cl7500/irqs.h	Thu Apr 12 12:20:31 2001
@@ -35,20 +35,22 @@
 #define IRQ_IOP5		29
 #define IRQ_IOP6		30
 #define IRQ_IOP7		31
-#define IRQ_MOUSERX		32
-#define IRQ_MOUSETX		33
-#define IRQ_ADC			34
-#define IRQ_EVENT1		35
-#define IRQ_EVENT2		36
 
-#define IRQ_ISA_3		40
-#define IRQ_ISA_4		41
-#define IRQ_ISA_5		42
-#define IRQ_ISA_7		43
-#define IRQ_ISA_9		44
-#define IRQ_ISA_10		45
-#define IRQ_ISA_11		46
-#define IRQ_ISA_14		47	
+#define IRQ_MOUSERX		40
+#define IRQ_MOUSETX		41
+#define IRQ_ADC			42
+#define IRQ_EVENT1		43
+#define IRQ_EVENT2		44
+
+#define IRQ_ISA_BASE		48
+#define IRQ_ISA_3		48
+#define IRQ_ISA_4		49
+#define IRQ_ISA_5		50
+#define IRQ_ISA_7		51
+#define IRQ_ISA_9		52
+#define IRQ_ISA_10		53
+#define IRQ_ISA_11		54
+#define IRQ_ISA_14		55	
 
 #define FIQ_INT9		0
 #define FIQ_INT5		1
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/shmparam.h linux/include/asm-arm/arch-cl7500/shmparam.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/shmparam.h	Tue Nov 23 22:23:11 1999
+++ linux/include/asm-arm/arch-cl7500/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-/*
- * linux/include/asm-arm/arch-cl7500/shmparam.h
- *
- * Copyright (c) 1999 Nexus Electronics Ltd
- */
-
-/* The processor-centric definitions are OK.  */
-
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/system.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-cl7500/system.h	Thu Apr 12 12:20:31 2001
@@ -11,12 +11,12 @@
 static void arch_idle(void)
 {
 	while (!current->need_resched && !hlt_counter)
-		outb(0, IOMD_SUSMODE);
+		iomd_writeb(0, IOMD_SUSMODE);
 }
 
 #define arch_reset(mode)			\
 	do {					\
-		outb (0, IOMD_ROMCR0);		\
+		iomd_writeb(0, IOMD_ROMCR0);	\
 		cpu_reset(0);			\
 	} while (0);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/time.h linux/include/asm-arm/arch-cl7500/time.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/time.h	Sun Aug 13 09:54:15 2000
+++ linux/include/asm-arm/arch-cl7500/time.h	Thu Apr 12 12:20:31 2001
@@ -13,18 +13,17 @@
 {
 	do_timer(regs);
 	do_set_rtc();
+	do_profile(regs);
 
 	{
 		/* Twinkle the lights. */
-		static int count, state = 0xff;
+		static int count, state = 0xff00;
 		if (count-- == 0) {
-			state ^= 1;
+			state ^= 0x100;
 			count = 25;
-			*((volatile unsigned int *)(0xe002ba00)) = state;
+			*((volatile unsigned int *)LED_ADDRESS) = state;
 		}
 	}
-
-	do_profile(regs);
 }
 
 /*
@@ -32,6 +31,9 @@
  */
 extern __inline__ void setup_timer(void)
 {
+	extern void ioctime_init(void);
+	ioctime_init();
+
 	timer_irq.handler = timer_interrupt;
 
 	setup_arm_irq(IRQ_TIMER, &timer_irq);
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/uncompress.h linux/include/asm-arm/arch-cl7500/uncompress.h
--- v2.4.3/linux/include/asm-arm/arch-cl7500/uncompress.h	Sun Aug 13 09:54:15 2000
+++ linux/include/asm-arm/arch-cl7500/uncompress.h	Thu Apr 12 12:20:31 2001
@@ -1,11 +1,11 @@
 /*
  * linux/include/asm-arm/arch-cl7500/uncompress.h
  *
- * Copyright (C) 1999 Nexus Electronics Ltd.
+ * Copyright (C) 1999, 2000 Nexus Electronics Ltd.
  */
 
 #define BASE 0x03010000
-#define SERBASE (BASE + (0x3f8 << 2))
+#define SERBASE (BASE + (0x2f8 << 2))
 
 static __inline__ void putc(char c)
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa110/hardware.h	Mon Sep 18 15:15:22 2000
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Thu Apr 12 12:20:31 2001
@@ -12,41 +12,55 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#ifndef __ASSEMBLY__
-
 /*
- * IO definitions
+ * The EBSA110 has a weird "ISA IO" region:
+ *
+ * Region 0 (addr = 0xf0000000 + io << 2)
+ * --------------------------------------------------------
+ * Physical region	IO region
+ * f0000fe0 - f0000ffc	3f8 - 3ff  ttyS0
+ * f0000e60 - f0000e64	398 - 399
+ * f0000de0 - f0000dfc	378 - 37f  lp0
+ * f0000be0 - f0000bfc	2f8 - 2ff  ttyS1
+ *
+ * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
+ * --------------------------------------------------------
+ * Physical region	IO region
+ * f00014f1             a79        pnp write data
+ * f00007c0 - f00007c1	3e0 - 3e1  pcmcia
+ * f00004f1		279        pnp address
+ * f0000440 - f000046c  220 - 236  eth0
+ * f0000405		203        pnp read data
  */
-#define PIT_CTRL		((volatile unsigned char *)0xf200000d)
-#define PIT_T2			((volatile unsigned char *)0xf2000009)
-#define PIT_T1			((volatile unsigned char *)0xf2000005)
-#define PIT_T0			((volatile unsigned char *)0xf2000001)
 
-/*
- * Mapping areas
- */
-#define IO_BASE			0xe0000000
+#define ISAMEM_PHYS		0xe0000000
+#define ISAMEM_SIZE		0x10000000
 
-/*
- * RAM definitions
- */
-#define FLUSH_BASE_PHYS		0x40000000
+#define ISAIO_PHYS		0xf0000000
+#define ISAIO_SIZE		PGDIR_SIZE
 
-#else	/* __ASSEMBLY__ */
+#define TRICK0_PHYS		0xf2000000
+#define TRICK1_PHYS		0xf2400000
+#define TRICK2_PHYS		0xf2800000
+#define TRICK3_PHYS		0xf2c00000
+#define TRICK4_PHYS		0xf3000000
+#define TRICK5_PHYS		0xf3400000
+#define TRICK6_PHYS		0xf3800000
+#define TRICK7_PHYS		0xf3c00000
 
-#define IO_BASE			0
+#define ISAMEM_BASE		0xe0000000
+#define ISAIO_BASE		0xf0000000
 
-#endif	/* __ASSEMBLY__ */
-
-#define IO_SIZE			0x20000000
-#define IO_START		0xe0000000
+#define PIT_BASE		0xfc000000
+#define SOFT_BASE		0xfd000000
 
+/*
+ * RAM definitions
+ */
+#define FLUSH_BASE_PHYS		0x40000000
 #define FLUSH_BASE		0xdf000000
-#define PCIO_BASE		0xf0000000
-
-#define UNCACHEABLE_ADDR	0xf3000000
 
-#define PARAMS_OFFSET		0x400
+#define UNCACHEABLE_ADDR	0xff000000	/* IRQ_STAT */
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/io.h linux/include/asm-arm/arch-ebsa110/io.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa110/io.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-ebsa110/io.h	Thu Apr 12 12:20:31 2001
@@ -13,7 +13,7 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffff
 
 /*
  * Generic virtual read/write
@@ -21,6 +21,39 @@
 #define __arch_getw(a)		(*(volatile unsigned short *)(a))
 #define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
 
-#define __io(p)		(ISAIO_BASE + ((p) << 2))
+u8  __inb(int port);
+u16 __inw(int port);
+u32 __inl(int port);
+
+#define inb(p)			__inb(p)
+#define inw(p)			__inw(p)
+#define inl(p)			__inl(p)
+
+void __outb(u8  val, int port);
+void __outw(u16 val, int port);
+void __outl(u32 val, int port);
+
+#define outb(v,p)		__outb(v,p)
+#define outw(v,p)		__outw(v,p)
+#define outl(v,p)		__outl(v,p)
+
+u8  __readb(void *addr);
+u16 __readw(void *addr);
+u32 __readl(void *addr);
+
+#define readb(b)		__readb(b)
+#define readw(b)		__readw(b)
+#define readl(b)		__readl(b)
+
+void __writeb(u8  val, void *addr);
+void __writew(u16 val, void *addr);
+void __writel(u32 val, void *addr);
+
+#define writeb(v,b)		__writeb(v,b)
+#define writew(v,b)		__writew(v,b)
+#define writel(v,b)		__writel(v,b)
+
+#define __arch_ioremap(off,sz,c)	((void *)(off))
+#define __arch_iounmap(virt)		do { } while (0)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/irq.h linux/include/asm-arm/arch-ebsa110/irq.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa110/irq.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa110/irq.h	Thu Apr 12 12:20:31 2001
@@ -10,47 +10,4 @@
  *  Changelog:
  *   22-08-1998	RMK	Restructured IRQ routines
  */
-
-#define IRQ_MCLR	((volatile unsigned char *)0xf3000000)
-#define IRQ_MSET	((volatile unsigned char *)0xf2c00000)
-#define IRQ_MASK	((volatile unsigned char *)0xf2c00000)
-
-#define fixup_irq(x) (x)
-
-static void ebsa110_mask_and_ack_irq(unsigned int irq)
-{
-	*IRQ_MCLR = 1 << irq;
-}
-
-static void ebsa110_mask_irq(unsigned int irq)
-{
-	*IRQ_MCLR = 1 << irq;
-}
-
-static void ebsa110_unmask_irq(unsigned int irq)
-{
-	*IRQ_MSET = 1 << irq;
-}
- 
-static __inline__ void irq_init_irq(void)
-{
-	unsigned long flags;
-	int irq;
-
-	save_flags_cli (flags);
-	*IRQ_MCLR = 0xff;
-	*IRQ_MSET = 0x55;
-	*IRQ_MSET = 0x00;
-	if (*IRQ_MASK != 0x55)
-		while (1);
-	*IRQ_MCLR = 0xff;		/* clear all interrupt enables */
-	restore_flags (flags);
-
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= ebsa110_mask_and_ack_irq;
-		irq_desc[irq].mask	= ebsa110_mask_irq;
-		irq_desc[irq].unmask	= ebsa110_unmask_irq;
-	}
-}
+#define fixup_irq(i)	(i)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/memory.h linux/include/asm-arm/arch-ebsa110/memory.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa110/memory.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-ebsa110/memory.h	Thu Apr 12 12:20:31 2001
@@ -35,13 +35,17 @@
 #define PHYS_OFFSET	(0x00000000UL)
 
 #define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __virt_to_phys(vpage)	((vpage) - PAGE_OFFSET)
 #define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+#define __phys_to_virt(ppage)	((ppage) + PAGE_OFFSET)
 
+/*
+ * We keep this 1:1 so that we don't interfere
+ * with the PCMCIA memory regions
+ */
 #define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __virt_to_bus(x)	(x)
 #define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	__phys_to_virt(x)
+#define __bus_to_virt(x)	(x)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa110/time.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa110/time.h	Thu Apr 12 12:20:31 2001
@@ -18,39 +18,16 @@
 
 #include <asm/leds.h>
 
-#define MCLK_47_8
-
-#if defined(MCLK_42_3)
-#define PIT1_COUNT 0xecbe
-#elif defined(MCLK_47_8)
-/*
- * This should be 0x10B43, but that doesn't exactly fit.
- * We run the timer interrupt at 5ms, and then divide it by
- * two in software...  This is so that the user processes
- * see exactly the same model whichever ARM processor they're
- * running on.
- */
-#define PIT1_COUNT 0x85A1
-#define DIVISOR 2
-#endif
+extern int  ebsa110_reset_timer(void);
+extern void ebsa110_setup_timer(void);
 
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	*PIT_T1 = (PIT1_COUNT) & 0xff;
-	*PIT_T1 = (PIT1_COUNT) >> 8;
-
-#ifdef DIVISOR
-	{
-		static unsigned int divisor;
-
-		if (divisor--)
-			return;
-		divisor = DIVISOR - 1;
+	if (ebsa110_reset_timer()) {
+		do_leds();
+		do_timer(regs);
+		do_profile(regs);
 	}
-#endif
-	do_leds();
-	do_timer(regs);
-	do_profile(regs);
 }
 
 /*
@@ -58,17 +35,7 @@
  */
 extern __inline__ void setup_timer(void)
 {
-	/*
-	 * Timer 1, mode 0, 16-bit, autoreload
-	 */
-	*PIT_CTRL = 0x70;
-
-	/*
-	 * Refresh counter clocked at 47.8MHz/7 = 146.4ns
-	 * We want centi-second interrupts
-	 */
-	*PIT_T1 = (PIT1_COUNT) & 0xff;
-	*PIT_T1 = (PIT1_COUNT) >> 8;
+	ebsa110_setup_timer();
 
 	timer_irq.handler = timer_interrupt;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/uncompress.h linux/include/asm-arm/arch-ebsa110/uncompress.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa110/uncompress.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa110/uncompress.h	Thu Apr 12 12:20:31 2001
@@ -28,7 +28,11 @@
 	ldrb	%0, [%2], #1
 	teq	%0, #0
 	bne	1b
-3:	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+3:	ldrb	%1, [%3, #0x14]
+	and	%1, %1, #0x60
+	teq	%1, #0x60
+	bne	3b
+	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.4.3/linux/include/asm-arm/arch-ebsa285/irq.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Thu Apr 12 12:20:31 2001
@@ -19,34 +19,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-/*
- * Footbridge IRQ translation table
- *  Converts from our IRQ numbers into FootBridge masks
- */
-static const int dc21285_irq_mask[] = {
-	IRQ_MASK_UART_RX,	/*  0 */
-	IRQ_MASK_UART_TX,	/*  1 */
-	IRQ_MASK_TIMER1,	/*  2 */
-	IRQ_MASK_TIMER2,	/*  3 */
-	IRQ_MASK_TIMER3,	/*  4 */
-	IRQ_MASK_IN0,		/*  5 */
-	IRQ_MASK_IN1,		/*  6 */
-	IRQ_MASK_IN2,		/*  7 */
-	IRQ_MASK_IN3,		/*  8 */
-	IRQ_MASK_DOORBELLHOST,	/*  9 */
-	IRQ_MASK_DMA1,		/* 10 */
-	IRQ_MASK_DMA2,		/* 11 */
-	IRQ_MASK_PCI,		/* 12 */
-	IRQ_MASK_SDRAMPARITY,	/* 13 */
-	IRQ_MASK_I2OINPOST,	/* 14 */
-	IRQ_MASK_PCI_ABORT,	/* 15 */
-	IRQ_MASK_PCI_SERR,	/* 16 */
-	IRQ_MASK_DISCARD_TIMER,	/* 17 */
-	IRQ_MASK_PCI_DPERR,	/* 18 */
-	IRQ_MASK_PCI_PERR,	/* 19 */
-};
-
-static int isa_irq = -1;
+int isa_irq = -1;
 
 static inline int fixup_irq(unsigned int irq)
 {
@@ -58,166 +31,3 @@
 	return irq;
 }
 
-static void dc21285_mask_irq(unsigned int irq)
-{
-	*CSR_IRQ_DISABLE = dc21285_irq_mask[_DC21285_INR(irq)];
-}
-
-static void dc21285_unmask_irq(unsigned int irq)
-{
-	*CSR_IRQ_ENABLE = dc21285_irq_mask[_DC21285_INR(irq)];
-}
-
-static void isa_mask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-}
-
-static void isa_mask_ack_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-	outb(0x20, PIC_LO);
-}
-
-static void isa_unmask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
-}
-
-static void isa_mask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-}
-
-static void isa_mask_ack_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-	outb(0x62, PIC_LO);
-	outb(0x20, PIC_HI);
-}
-
-static void isa_unmask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
-}
-
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-}
-
-static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
-static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
-static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
-
-static __inline__ void irq_init_irq(void)
-{
-	int irq;
-
-	/*
-	 * setup DC21285 IRQs
-	 */
-	*CSR_IRQ_DISABLE = -1;
-	*CSR_FIQ_DISABLE = -1;
-
-	for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= dc21285_mask_irq;
-		irq_desc[irq].mask	= dc21285_mask_irq;
-		irq_desc[irq].unmask	= dc21285_unmask_irq;
-	}
-
-	/*
-	 * Determine the ISA settings for
-	 * the machine we're running on.
-	 */
-	isa_irq = -1;
-
-	if (footbridge_cfn_mode()) {
-		if (machine_is_ebsa285())
-			/* The following is dependent on which slot
-			 * you plug the Southbridge card into.  We
-			 * currently assume that you plug it into
-			 * the right-hand most slot.
-			 */
-			isa_irq = IRQ_PCI;
-
-		if (machine_is_cats())
-			isa_irq = IRQ_IN2;
-
-		if (machine_is_netwinder())
-			isa_irq = IRQ_IN3;
-	}
-
-	if (isa_irq != -1) {
-		/*
-		 * Setup, and then probe for an ISA PIC
-		 * If the PIC is not there, then we
-		 * ignore the PIC.
-		 */
-		outb(0x11, PIC_LO);
-		outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
-		outb(0x04, PIC_MASK_LO);	/* Slave on Ch2		*/
-		outb(0x01, PIC_MASK_LO);	/* x86			*/
-		outb(0xf5, PIC_MASK_LO);	/* pattern: 11110101	*/
-
-		outb(0x11, PIC_HI);
-		outb(_ISA_IRQ(8), PIC_MASK_HI);	/* IRQ number		*/
-		outb(0x02, PIC_MASK_HI);	/* Slave on Ch1		*/
-		outb(0x01, PIC_MASK_HI);	/* x86			*/
-		outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
-
-		outb(0x0b, PIC_LO);
-		outb(0x0b, PIC_HI);
-
-		if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
-			outb(0xff, PIC_MASK_LO);/* mask all IRQs	*/
-			outb(0xff, PIC_MASK_HI);/* mask all IRQs	*/
-		} else
-			isa_irq = -1;
-	}
-
-	if (isa_irq != -1) {
-		for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
-			irq_desc[irq].valid	= 1;
-			irq_desc[irq].probe_ok	= 1;
-			irq_desc[irq].mask_ack	= isa_mask_ack_pic_lo_irq;
-			irq_desc[irq].mask	= isa_mask_pic_lo_irq;
-			irq_desc[irq].unmask	= isa_unmask_pic_lo_irq;
-		}
-
-		for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
-			irq_desc[irq].valid	= 1;
-			irq_desc[irq].probe_ok	= 1;
-			irq_desc[irq].mask_ack	= isa_mask_ack_pic_hi_irq;
-			irq_desc[irq].mask	= isa_mask_pic_hi_irq;
-			irq_desc[irq].unmask	= isa_unmask_pic_hi_irq;
-		}
-
-		request_resource(&ioport_resource, &pic1_resource);
-		request_resource(&ioport_resource, &pic2_resource);
-		setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
-		setup_arm_irq(isa_irq, &irq_cascade);
-
-		/*
-		 * On the NetWinder, don't automatically
-		 * enable ISA IRQ11 when it is requested.
-		 * There appears to be a missing pull-up
-		 * resistor on this line.
-		 */
-		if (machine_is_netwinder())
-			irq_desc[_ISA_IRQ(11)].noautoenable = 1;
-	}
-}
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/aux_reg.h linux/include/asm-arm/arch-l7200/aux_reg.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/aux_reg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/aux_reg.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,28 @@
+/*
+ * linux/include/asm-arm/arch-l7200/aux_reg.h
+ *
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *   08-02-2000	SJH	Created file
+ */
+#ifndef _ASM_ARCH_AUXREG_H
+#define _ASM_ARCH_AUXREG_H
+
+#include <asm/arch/hardware.h>
+
+#define l7200aux_reg	*((volatile unsigned int *) (AUX_BASE))
+
+/*
+ * Auxillary register values
+ */
+#define AUX_CLEAR		0x00000000
+#define AUX_DIAG_LED_ON		0x00000002
+#define AUX_RTS_UART1		0x00000004
+#define AUX_DTR_UART1		0x00000008
+#define AUX_KBD_COLUMN_12_HIGH	0x00000010
+#define AUX_KBD_COLUMN_12_OFF	0x00000020
+#define AUX_KBD_COLUMN_13_HIGH	0x00000040
+#define AUX_KBD_COLUMN_13_OFF	0x00000080
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/dma.h linux/include/asm-arm/arch-l7200/dma.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/dma.h	Tue Jul 18 22:43:25 2000
+++ linux/include/asm-arm/arch-l7200/dma.h	Thu Apr 12 12:20:31 2001
@@ -1,26 +1,24 @@
 /*
  * linux/include/asm-arm/arch-l7200/dma.h
+ *
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *  08-29-2000	SJH	Created
  */
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
+/* DMA is not yet implemented! It should be the same as acorn, copy over.. */
+
 /*
  * This is the maximum DMA address that can be DMAd to.
  * There should not be more than (0xd0000000 - 0xc0000000)
  * bytes of RAM.
  */
-#define MAX_DMA_ADDRESS		0xd0000000
-#define MAX_DMA_CHANNELS	8
-
-#define DMA_0			0
-#define DMA_1			1
-#define DMA_2			2
-#define DMA_3			3
-#define DMA_S0			4
-#define DMA_S1			5
-#define DMA_VIRTUAL_FLOPPY	6
-#define DMA_VIRTUAL_SOUND	7
+#define MAX_DMA_ADDRESS         0xd0000000
+#define MAX_DMA_CHANNELS        0
 
-#define DMA_FLOPPY		DMA_VIRTUAL_FLOPPY
+#define DMA_S0                  0
 
-#endif
+#endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/gp_timers.h linux/include/asm-arm/arch-l7200/gp_timers.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/gp_timers.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/gp_timers.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,42 @@
+/*
+ * linux/include/asm-arm/arch-l7200/gp_timers.h
+ *
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *   07-28-2000	SJH	Created file
+ *   08-02-2000	SJH	Used structure for registers
+ */
+#ifndef _ASM_ARCH_GPTIMERS_H
+#define _ASM_ARCH_GPTIMERS_H
+
+#include <asm/arch/hardware.h>
+
+/*
+ * Layout of L7200 general purpose timer registers
+ */
+struct GPT_Regs {
+	unsigned int TIMERLOAD;
+	unsigned int TIMERVALUE;
+	unsigned int TIMERCONTROL;
+	unsigned int TIMERCLEAR;
+};
+
+#define GPT_BASE		(IO_BASE_2 + 0x3000)
+#define l7200_timer1_regs	((volatile struct GPT_Regs *) (GPT_BASE))
+#define l7200_timer2_regs	((volatile struct GPT_Regs *) (GPT_BASE + 0x20))
+
+/*
+ * General register values
+ */
+#define	GPT_PRESCALE_1		0x00000000
+#define	GPT_PRESCALE_16		0x00000004
+#define	GPT_PRESCALE_256	0x00000008
+#define GPT_MODE_FREERUN	0x00000000
+#define GPT_MODE_PERIODIC	0x00000040
+#define GPT_ENABLE		0x00000080
+#define GPT_BZTOG		0x00000100
+#define GPT_BZMOD		0x00000200
+#define GPT_LOAD_MASK 		0x0000ffff
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/gpio.h linux/include/asm-arm/arch-l7200/gpio.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/gpio.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/gpio.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,105 @@
+/****************************************************************************/
+/*
+ *      linux/include/asm-arm/arch-l7200/gpio.h
+ *
+ *      Registers and  helper functions for the L7200 Link-Up Systems
+ *      GPIO.
+ *
+ *      (C) Copyright 2000, S A McConnell  (samcconn@cotw.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+/****************************************************************************/
+
+#define GPIO_OFF   0x00005000  /* Offset from IO_START to the GPIO reg's. */
+
+/* IO_START and IO_BASE are defined in hardware.h */
+
+#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */
+#define GPIO_BASE  (IO_BASE_2  + GPIO_OFF) /* Virtual addr of the GPIO reg. */
+
+/* Offsets from the start of the GPIO for all the registers. */
+#define PADR_OFF     0x000
+#define PADDR_OFF    0x004
+#define PASBSR_OFF   0x008
+#define PAEENR_OFF   0x00c
+#define PAESNR_OFF   0x010
+#define PAESTR_OFF   0x014
+#define PAIMR_OFF    0x018
+#define PAINT_OFF    0x01c
+
+#define PBDR_OFF     0x020
+#define PBDDR_OFF    0x024
+#define PBSBSR_OFF   0x028
+#define PBIMR_OFF    0x038
+#define PBINT_OFF    0x03c
+
+#define PCDR_OFF     0x040
+#define PCDDR_OFF    0x044
+#define PCSBSR_OFF   0x048
+#define PCIMR_OFF    0x058
+#define PCINT_OFF    0x05c
+
+#define PDDR_OFF     0x060
+#define PDDDR_OFF    0x064
+#define PDSBSR_OFF   0x068
+#define PDEENR_OFF   0x06c
+#define PDESNR_OFF   0x070
+#define PDESTR_OFF   0x074
+#define PDIMR_OFF    0x078
+#define PDINT_OFF    0x07c
+
+#define PEDR_OFF     0x080
+#define PEDDR_OFF    0x084
+#define PESBSR_OFF   0x088
+#define PEEENR_OFF   0x08c
+#define PEESNR_OFF   0x090
+#define PEESTR_OFF   0x094
+#define PEIMR_OFF    0x098
+#define PEINT_OFF    0x09c
+
+/* Define the GPIO registers for use by device drivers and the kernel. */
+#define PADR   (*(volatile unsigned long *)(GPIO_BASE+PADR_OFF))
+#define PADDR  (*(volatile unsigned long *)(GPIO_BASE+PADDR_OFF))
+#define PASBSR (*(volatile unsigned long *)(GPIO_BASE+PASBSR_OFF))
+#define PAEENR (*(volatile unsigned long *)(GPIO_BASE+PAEENR_OFF))
+#define PAESNR (*(volatile unsigned long *)(GPIO_BASE+PAESNR_OFF))
+#define PAESTR (*(volatile unsigned long *)(GPIO_BASE+PAESTR_OFF))
+#define PAIMR  (*(volatile unsigned long *)(GPIO_BASE+PAIMR_OFF))
+#define PAINT  (*(volatile unsigned long *)(GPIO_BASE+PAINT_OFF))
+
+#define PBDR   (*(volatile unsigned long *)(GPIO_BASE+PBDR_OFF))
+#define PBDDR  (*(volatile unsigned long *)(GPIO_BASE+PBDDR_OFF))
+#define PBSBSR (*(volatile unsigned long *)(GPIO_BASE+PBSBSR_OFF))
+#define PBIMR  (*(volatile unsigned long *)(GPIO_BASE+PBIMR_OFF))
+#define PBINT  (*(volatile unsigned long *)(GPIO_BASE+PBINT_OFF))
+
+#define PCDR   (*(volatile unsigned long *)(GPIO_BASE+PCDR_OFF))
+#define PCDDR  (*(volatile unsigned long *)(GPIO_BASE+PCDDR_OFF))
+#define PCSBSR (*(volatile unsigned long *)(GPIO_BASE+PCSBSR_OFF))
+#define PCIMR  (*(volatile unsigned long *)(GPIO_BASE+PCIMR_OFF))
+#define PCINT  (*(volatile unsigned long *)(GPIO_BASE+PCINT_OFF))
+
+#define PDDR   (*(volatile unsigned long *)(GPIO_BASE+PDDR_OFF))
+#define PDDDR  (*(volatile unsigned long *)(GPIO_BASE+PDDDR_OFF))
+#define PDSBSR (*(volatile unsigned long *)(GPIO_BASE+PDSBSR_OFF))
+#define PDEENR (*(volatile unsigned long *)(GPIO_BASE+PDEENR_OFF))
+#define PDESNR (*(volatile unsigned long *)(GPIO_BASE+PDESNR_OFF))
+#define PDESTR (*(volatile unsigned long *)(GPIO_BASE+PDESTR_OFF))
+#define PDIMR  (*(volatile unsigned long *)(GPIO_BASE+PDIMR_OFF))
+#define PDINT  (*(volatile unsigned long *)(GPIO_BASE+PDINT_OFF))
+
+#define PEDR   (*(volatile unsigned long *)(GPIO_BASE+PEDR_OFF))
+#define PEDDR  (*(volatile unsigned long *)(GPIO_BASE+PEDDR_OFF))
+#define PESBSR (*(volatile unsigned long *)(GPIO_BASE+PESBSR_OFF))
+#define PEEENR (*(volatile unsigned long *)(GPIO_BASE+PEEENR_OFF))
+#define PEESNR (*(volatile unsigned long *)(GPIO_BASE+PEESNR_OFF))
+#define PEESTR (*(volatile unsigned long *)(GPIO_BASE+PEESTR_OFF))
+#define PEIMR  (*(volatile unsigned long *)(GPIO_BASE+PEIMR_OFF))
+#define PEINT  (*(volatile unsigned long *)(GPIO_BASE+PEINT_OFF))
+
+#define VEE_EN         0x02
+#define BACKLIGHT_EN   0x04
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/hardware.h linux/include/asm-arm/arch-l7200/hardware.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/hardware.h	Mon Nov 27 17:07:59 2000
+++ linux/include/asm-arm/arch-l7200/hardware.h	Thu Apr 12 12:20:31 2001
@@ -13,6 +13,8 @@
  *   04-21-2000	 RS 	Changed mapping of I/O in virtual space
  *   04-25-2000	SJH	Removed unused symbols and such
  *   05-05-2000	SJH	Complete rewrite
+ *   07-31-2000	SJH	Added undocumented debug auxillary port to
+ *			get at last two columns for keyboard driver
  */
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
@@ -33,6 +35,18 @@
 #define IO_START_2		0x90000000      /* I/O */
 #define IO_SIZE_2		0x01000000
 #define IO_BASE_2		0xd1000000
+
+#define AUX_START		0x1a000000      /* AUX PORT */
+#define AUX_SIZE 		0x01000000
+#define AUX_BASE		0xd2000000
+
+#define FLASH1_START		0x00000000      /* FLASH BANK 1 */
+#define FLASH1_SIZE 		0x01000000
+#define FLASH1_BASE		0xd3000000
+
+#define FLASH2_START		0x10000000      /* FLASH BANK 2 */
+#define FLASH2_SIZE 		0x01000000
+#define FLASH2_BASE		0xd4000000
 
 #define ISA_START		0x20000000	/* ISA */
 #define ISA_SIZE		0x20000000
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/io.h linux/include/asm-arm/arch-l7200/io.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/io.h	Sun Aug 13 09:54:15 2000
+++ linux/include/asm-arm/arch-l7200/io.h	Thu Apr 12 12:20:31 2001
@@ -3,8 +3,9 @@
  *
  * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
  *
- * Modifications:
+ * Changelog:
  *  03-21-2000	SJH	Created from linux/include/asm-arm/arch-nexuspci/io.h
+ *  08-31-2000	SJH	Added in IO functions necessary for new drivers
  */
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
@@ -14,16 +15,49 @@
 #define IO_SPACE_LIMIT 0xffffffff
 
 /*
+ * There are not real ISA nor PCI buses, so we fake it.
+ */
+#define __io_pci(a)             (PCIO_BASE + (a))
+#define __mem_pci(a)            ((unsigned long)(a))
+#define __mem_isa(a)            ((unsigned long)(a))
+
+#define __ioaddr(p)             __io_pci(p)
+
+/*
+ * Generic virtual read/write
+ */
+#define __arch_getb(a)          (*(volatile unsigned char *)(a))
+#define __arch_getl(a)          (*(volatile unsigned int  *)(a))
+
+extern __inline__ unsigned int __arch_getw(unsigned long a)
+{
+	unsigned int value;
+	__asm__ __volatile__("ldr%?h    %0, [%1, #0]    @ getw"
+		: "=&r" (value)
+		: "r" (a));
+	return value;
+}
+
+#define __arch_putb(v,a)        (*(volatile unsigned char *)(a) = (v))
+#define __arch_putl(v,a)        (*(volatile unsigned int  *)(a) = (v))
+
+extern __inline__ void __arch_putw(unsigned int value, unsigned long a)
+{
+        __asm__ __volatile__("str%?h    %0, [%1, #0]    @ putw"
+                : : "r" (value), "r" (a));
+}
+
+/*
  * Translated address IO functions
  *
  * IO address has already been translated to a virtual address
  */
-#define outb_t(v,p)	(*(volatile unsigned char *)(p) = (v))
-#define inb_t(p)	(*(volatile unsigned char *)(p))
-#define outw_t(v,p)	(*(volatile unsigned int *)(p) = (v))
-#define inw_t(p)	(*(volatile unsigned int *)(p))
-#define outl_t(v,p)	(*(volatile unsigned long *)(p) = (v))
-#define inl_t(p)	(*(volatile unsigned long *)(p))
+#define outb_t(v,p)		(*(volatile unsigned char *)(p) = (v))
+#define inb_t(p)		(*(volatile unsigned char *)(p))
+#define outw_t(v,p)		(*(volatile unsigned int *)(p) = (v))
+#define inw_t(p)		(*(volatile unsigned int *)(p))
+#define outl_t(v,p)		(*(volatile unsigned long *)(p) = (v))
+#define inl_t(p)		(*(volatile unsigned long *)(p))
 
 /*
  * FIXME - These are to allow for linking. On all the other
@@ -32,11 +66,13 @@
  *         macros will eventually become more involved. Use
  *         with caution and don't be surprised by kernel oopses!!!
  */
-#define inb(p)	 	inb_t(p)
-#define inw(p)	 	inw_t(p)
-#define inl(p)	 	inl_t(p)
-#define outb(v,p)	outb_t(v,p)
-#define outw(v,p)	outw_t(v,p)
-#define outl(v,p)	outl_t(v,p)
+#define inb(p)		 	inb_t(p)
+#define inw(p)	 		inw_t(p)
+#define inl(p)	 		inl_t(p)
+#define outb(v,p)		outb_t(v,p)
+#define outw(v,p)		outw_t(v,p)
+#define outl(v,p)		outl_t(v,p)
+
+#define __arch_ioremap		__ioremap
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/irq.h linux/include/asm-arm/arch-l7200/irq.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/irq.h	Mon May 15 12:00:33 2000
+++ linux/include/asm-arm/arch-l7200/irq.h	Thu Apr 12 12:20:31 2001
@@ -10,6 +10,8 @@
  *   05-05-2000 SJH     Complete rewrite
  */
 
+#include <asm/arch/hardware.h>
+
 /*
  * IRQ base register
  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/irqs.h linux/include/asm-arm/arch-l7200/irqs.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/irqs.h	Mon May 15 12:00:33 2000
+++ linux/include/asm-arm/arch-l7200/irqs.h	Thu Apr 12 12:20:31 2001
@@ -7,6 +7,12 @@
  * Changelog:
  *   01-02-2000 RS	Create l7200 version
  *   03-28-2000 SJH	Removed unused interrupt
+ *   07-28-2000 SJH	Added pseudo-keyboard interrupt
+ */
+
+/*
+ * NOTE: The second timer (Timer 2) is used as the keyboard
+ *       interrupt when the keyboard driver is enabled.
  */
 
 #define NR_IRQS          32
@@ -16,7 +22,7 @@
 #define IRQ_DEBUG_RX      2   /* Comm Rx debug */
 #define IRQ_DEBUG_TX      3   /* Comm Tx debug */
 #define IRQ_GCTC1         4   /* Timer 1 */
-#define IRQ_GCTC2         5   /* Timer 2 */
+#define IRQ_GCTC2         5   /* Timer 2 / Keyboard */
 #define IRQ_DMA           6   /* DMA controller */
 #define IRQ_CLCD          7   /* Color LCD controller */
 #define IRQ_SM_RX         8   /* Smart card */
@@ -40,6 +46,11 @@
 #define IRQ_INT0         26   /* External active low interrupt */
 #define IRQ_INT1         27   /* External active low interrupt */
 #define IRQ_INT2         28   /* External active low interrupt */
-#define IRQ_INT3         29   /* External active low interrupt */
+#define IRQ_UCB1200      29   /* Interrupt generated by UCB1200*/
 #define IRQ_BAT_LO       30   /* Low batery or external power */
 #define IRQ_MEDIA_CHG    31   /* Media change interrupt */
+
+/*
+ * This is the offset of the FIQ "IRQ" numbers
+ */
+#define FIQ_START	64
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/keyboard.h linux/include/asm-arm/arch-l7200/keyboard.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/keyboard.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,49 @@
+/*
+ *  linux/include/asm-arm/arch-l7200/keyboard.h
+ *
+ *  Keyboard driver definitions for LinkUp Systems L7200 architecture
+ *
+ *  Copyright (C) 2000 Scott A McConnell (samcconn@cotw.com)
+ *                     Steve Hill (sjhill@cotw.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * Changelog:
+ *   07-18-2000	SAM	Created file
+ *   07-28-2000	SJH	Complete rewrite
+ */
+
+#include <asm/irq.h>
+
+/*
+ * Layout of L7200 keyboard registers
+ */
+struct KBD_Port {       
+	unsigned int KBDR;
+	unsigned int KBDMR;
+	unsigned int KBSBSR;
+	unsigned int Reserved;
+	unsigned int KBKSR;
+};
+
+#define KBD_BASE        IO_BASE_2 + 0x4000
+#define l7200kbd_hwregs ((volatile struct KBD_Port *) (KBD_BASE))
+
+extern void l7200kbd_init_hw(void);
+extern int l7200kbd_translate(unsigned char scancode, unsigned char *keycode,
+			      char raw_mode);
+
+#define kbd_setkeycode(sc,kc)		(-EINVAL)
+#define kbd_getkeycode(sc)		(-EINVAL)
+
+#define kbd_translate(sc, kcp, rm)      ({ *(kcp) = (sc); 1; })
+#define kbd_unexpected_up(kc)           (0200)
+#define kbd_leds(leds)                  do {} while (0)
+#define kbd_init_hw()                   l7200kbd_init_hw()
+#define kbd_sysrq_xlate                 do {} while (0)
+#define kbd_disable_irq()               disable_irq(IRQ_GCTC2)
+#define kbd_enable_irq()                enable_irq(IRQ_GCTC2)
+
+#define SYSRQ_KEY	13
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/pmpcon.h linux/include/asm-arm/arch-l7200/pmpcon.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/pmpcon.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/pmpcon.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,46 @@
+/****************************************************************************/
+/*
+ *  linux/include/asm-arm/arch-l7200/pmpcon.h
+ *
+ *   Registers and  helper functions for the L7200 Link-Up Systems
+ *   DC/DC converter register.
+ *
+ *   (C) Copyright 2000, S A McConnell  (samcconn@cotw.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+/****************************************************************************/
+
+#define PMPCON_OFF 0x00006000  /* Offset from IO_START_2. */
+
+/* IO_START_2 and IO_BASE_2 are defined in hardware.h */
+
+#define PMPCON_START (IO_START_2 + PMPCON_OFF)  /* Physical address of reg. */
+#define PMPCON_BASE  (IO_BASE_2  + PMPCON_OFF)  /* Virtual address of reg. */
+
+
+#define PMPCON (*(volatile unsigned int *)(PMPCON_BASE))
+
+#define PWM2_50CYCLE 0x800
+#define CONTRAST     0x9
+
+#define PWM1H (CONTRAST)
+#define PWM1L (CONTRAST << 4)
+
+#define PMPCON_VALUE  (PWM2_50CYCLE | PWM1L | PWM1H) 
+	
+/* PMPCON = 0x811;   // too light and fuzzy
+ * PMPCON = 0x844;   
+ * PMPCON = 0x866;   // better color poor depth
+ * PMPCON = 0x888;   // Darker but better depth 
+ * PMPCON = 0x899;   // Darker even better depth
+ * PMPCON = 0x8aa;   // too dark even better depth
+ * PMPCON = 0X8cc;   // Way too dark
+ */
+
+/* As CONTRAST value increases the greater the depth perception and
+ * the darker the colors.
+ */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/pmu.h linux/include/asm-arm/arch-l7200/pmu.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/pmu.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/pmu.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,125 @@
+/****************************************************************************/
+/*
+ *  linux/include/asm-arm/arch-l7200/pmu.h
+ *
+ *   Registers and  helper functions for the L7200 Link-Up Systems
+ *   Power Management Unit (PMU).
+ *
+ *   (C) Copyright 2000, S A McConnell  (samcconn@cotw.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+/****************************************************************************/
+
+#define PMU_OFF   0x00050000  /* Offset from IO_START to the PMU registers. */
+
+/* IO_START and IO_BASE are defined in hardware.h */
+
+#define PMU_START (IO_START + PMU_OFF)  /* Physical addr. of the PMU reg. */
+#define PMU_BASE  (IO_BASE  + PMU_OFF)  /* Virtual addr. of the PMU reg. */
+
+
+/* Define the PMU registers for use by device drivers and the kernel. */
+
+typedef struct {
+     unsigned int CURRENT;  /* Current configuration register */
+     unsigned int NEXT;     /* Next configuration register */
+     unsigned int reserved;
+     unsigned int RUN;      /* Run configuration register */
+     unsigned int COMM;     /* Configuration command register */
+     unsigned int SDRAM;    /* SDRAM configuration bypass register */
+} pmu_interface;
+
+#define PMU ((volatile pmu_interface *)(PMU_BASE))
+
+
+/* Macro's for reading the common register fields. */
+
+#define GET_TRANSOP(reg)  ((reg >> 25) & 0x03) /* Bits 26-25 */
+#define GET_OSCEN(reg)    ((reg >> 16) & 0x01)
+#define GET_OSCMUX(reg)   ((reg >> 15) & 0x01)
+#define GET_PLLMUL(reg)   ((reg >>  9) & 0x3f) /* Bits 14-9 */
+#define GET_PLLEN(reg)    ((reg >>  8) & 0x01)
+#define GET_PLLMUX(reg)   ((reg >>  7) & 0x01)
+#define GET_BCLK_DIV(reg) ((reg >>  3) & 0x03) /* Bits 4-3 */
+#define GET_SDRB_SEL(reg) ((reg >>  2) & 0x01)
+#define GET_SDRF_SEL(reg) ((reg >>  1) & 0x01)
+#define GET_FASTBUS(reg)  (reg & 0x1)
+
+/* CFG_NEXT register */
+
+#define CFG_NEXT_CLOCKRECOVERY ((PMU->NEXT >> 18) & 0x7f)   /* Bits 24-18 */
+#define CFG_NEXT_INTRET        ((PMU->NEXT >> 17) & 0x01)
+#define CFG_NEXT_SDR_STOP      ((PMU->NEXT >>  6) & 0x01)
+#define CFG_NEXT_SYSCLKEN      ((PMU->NEXT >>  5) & 0x01)
+
+/* Useful field values that can be used to construct the
+ * CFG_NEXT and CFG_RUN registers.
+ */
+
+#define TRANSOP_NOP      0<<25  /* NOCHANGE_NOSTALL */
+#define NOCHANGE_STALL   1<<25
+#define CHANGE_NOSTALL   2<<25
+#define CHANGE_STALL     3<<25
+
+#define INTRET           1<<17
+#define OSCEN            1<<16
+#define OSCMUX           1<<15
+
+/* PLL frequencies */
+
+#define PLLMUL_0         0<<9         /*  3.6864 MHz */
+#define PLLMUL_1         1<<9         /*  ?????? MHz */
+#define PLLMUL_5         5<<9         /*  18.432 MHz */
+#define PLLMUL_10       10<<9         /*  36.864 MHz */
+#define PLLMUL_18       18<<9         /*  ?????? MHz */
+#define PLLMUL_20       20<<9         /*  73.728 MHz */
+#define PLLMUL_32       32<<9         /*  ?????? MHz */
+#define PLLMUL_35       35<<9         /* 129.024 MHz */
+#define PLLMUL_36       36<<9         /*  ?????? MHz */
+#define PLLMUL_39       39<<9         /*  ?????? MHz */
+#define PLLMUL_40       40<<9         /* 147.456 MHz */
+
+/* Clock recovery times */
+
+#define CRCLOCK_1        1<<18
+#define CRCLOCK_2        2<<18
+#define CRCLOCK_4        4<<18
+#define CRCLOCK_8        8<<18
+#define CRCLOCK_16      16<<18
+#define CRCLOCK_32      32<<18
+#define CRCLOCK_63      63<<18
+#define CRCLOCK_127    127<<18
+
+#define PLLEN            1<<8
+#define PLLMUX           1<<7
+#define SDR_STOP         1<<6
+#define SYSCLKEN         1<<5
+
+#define BCLK_DIV_4       2<<3
+#define BCLK_DIV_2       1<<3
+#define BCLK_DIV_1       0<<3
+
+#define SDRB_SEL         1<<2
+#define SDRF_SEL         1<<1
+#define FASTBUS          1<<0
+
+
+/* CFG_SDRAM */
+
+#define SDRREFFQ         1<<0  /* Only if SDRSTOPRQ is not set. */
+#define SDRREFACK        1<<1  /* Read-only */
+#define SDRSTOPRQ        1<<2  /* Only if SDRREFFQ is not set. */
+#define SDRSTOPACK       1<<3  /* Read-only */
+#define PICEN            1<<4  /* Enable Co-procesor */
+#define PICTEST          1<<5
+
+#define GET_SDRREFFQ    ((PMU->SDRAM >> 0) & 0x01)
+#define GET_SDRREFACK   ((PMU->SDRAM >> 1) & 0x01) /* Read-only */
+#define GET_SDRSTOPRQ   ((PMU->SDRAM >> 2) & 0x01)
+#define GET_SDRSTOPACK  ((PMU->SDRAM >> 3) & 0x01) /* Read-only */
+#define GET_PICEN       ((PMU->SDRAM >> 4) & 0x01)
+#define GET_PICTEST     ((PMU->SDRAM >> 5) & 0x01)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/serial.h linux/include/asm-arm/arch-l7200/serial.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/serial.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/serial.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,39 @@
+/*
+ * linux/include/asm-arm/arch-l7200/serial.h
+ *
+ * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *  03-20-2000  SJH     Created
+ *  03-26-2000  SJH     Added flags for serial ports
+ *  03-27-2000  SJH     Corrected BASE_BAUD value
+ *  04-14-2000  RS      Made register addr dependent on IO_BASE
+ *  05-03-2000  SJH     Complete rewrite
+ *  05-09-2000	SJH	Stripped out architecture specific serial stuff
+ *                      and placed it in a separate file
+ *  07-28-2000	SJH	Moved base baud rate variable
+ */
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+/*
+ * This assumes you have a 3.6864 MHz clock for your UART.
+ */
+#define BASE_BAUD	3686400
+
+/*
+ * Standard COM flags
+ */
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+#define RS_TABLE_SIZE 2
+
+#define STD_SERIAL_PORT_DEFNS		\
+	/* MAGIC UART CLK   PORT       IRQ     FLAGS */			\
+	{ 0, BASE_BAUD, UART1_BASE, IRQ_UART_1, STD_COM_FLAGS },  /* ttyLU0 */ \
+	{ 0, BASE_BAUD, UART2_BASE, IRQ_UART_2, STD_COM_FLAGS },  /* ttyLU1 */ \
+
+#define EXTRA_SERIAL_PORT_DEFNS
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/sib.h linux/include/asm-arm/arch-l7200/sib.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/sib.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/sib.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,119 @@
+/****************************************************************************/
+/*
+ *  linux/include/asm-arm/arch-l7200/sib.h
+ *
+ *  Registers and helper functions for the Serial Interface Bus.
+ *
+ *  (C) Copyright 2000, S A McConnell  (samcconn@cotw.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+/****************************************************************************/
+
+#define SIB_OFF   0x00040000  /* Offset from IO_START to the SIB reg's. */
+
+/* IO_START and IO_BASE are defined in hardware.h */
+
+#define SIB_START (IO_START + SIB_OFF) /* Physical addr of the SIB reg. */
+#define SIB_BASE  (IO_BASE  + SIB_OFF) /* Virtual addr of the SIB reg.  */
+
+/* Offsets from the start of the SIB for all the registers. */
+
+/* Define the SIB registers for use by device drivers and the kernel. */
+
+typedef struct
+{
+     unsigned int MCCR;    /* SIB Control Register           Offset: 0x00 */
+     unsigned int RES1;    /* Reserved                       Offset: 0x04 */
+     unsigned int MCDR0;   /* SIB Data Register 0            Offset: 0x08 */
+     unsigned int MCDR1;   /* SIB Data Register 1            Offset: 0x0c */
+     unsigned int MCDR2;   /* SIB Data Register 2 (UCB1x00)  Offset: 0x10 */
+     unsigned int RES2;    /* Reserved                       Offset: 0x14 */
+     unsigned int MCSR;    /* SIB Status Register            Offset: 0x18 */
+} SIB_Interface;
+
+#define SIB ((volatile SIB_Interface *) (SIB_BASE))
+
+/* MCCR */
+
+#define INTERNAL_FREQ   9216000  /* Hertz */
+#define AUDIO_FREQ         5000  /* Hertz */
+#define TELECOM_FREQ       5000  /* Hertz */
+
+#define AUDIO_DIVIDE    (INTERNAL_FREQ / (32 * AUDIO_FREQ))
+#define TELECOM_DIVIDE  (INTERNAL_FREQ / (32 * TELECOM_FREQ))
+
+#define MCCR_ASD57      AUDIO_DIVIDE
+#define MCCR_TSD57      (TELECOM_DIVIDE << 8)
+#define MCCR_MCE        (1 << 16)             /* SIB enable */
+#define MCCR_ECS        (1 << 17)             /* External Clock Select */
+#define MCCR_ADM        (1 << 18)             /* A/D Data Sampling */
+#define MCCR_PMC        (1 << 26)             /* PIN Multiplexer Control */
+
+
+#define GET_ASD ((SIB->MCCR >>  0) & 0x3f) /* Audio Sample Rate Div. */
+#define GET_TSD ((SIB->MCCR >>  8) & 0x3f) /* Telcom Sample Rate Div. */
+#define GET_MCE ((SIB->MCCR >> 16) & 0x01) /* SIB Enable */
+#define GET_ECS ((SIB->MCCR >> 17) & 0x01) /* External Clock Select */
+#define GET_ADM ((SIB->MCCR >> 18) & 0x01) /* A/D Data Sampling Mode */
+#define GET_TTM ((SIB->MCCR >> 19) & 0x01) /* Telco Trans. FIFO I mask */ 
+#define GET_TRM ((SIB->MCCR >> 20) & 0x01) /* Telco Recv. FIFO I mask */
+#define GET_ATM ((SIB->MCCR >> 21) & 0x01) /* Audio Trans. FIFO I mask */ 
+#define GET_ARM ((SIB->MCCR >> 22) & 0x01) /* Audio Recv. FIFO I mask */
+#define GET_LBM ((SIB->MCCR >> 23) & 0x01) /* Loop Back Mode */
+#define GET_ECP ((SIB->MCCR >> 24) & 0x03) /* Extern. Clck Prescale sel */
+#define GET_PMC ((SIB->MCCR >> 26) & 0x01) /* PIN Multiplexer Control */
+#define GET_ERI ((SIB->MCCR >> 27) & 0x01) /* External Read Interrupt */
+#define GET_EWI ((SIB->MCCR >> 28) & 0x01) /* External Write Interrupt */
+
+/* MCDR0 */
+
+#define AUDIO_RECV     ((SIB->MCDR0 >> 4) & 0xfff)
+#define AUDIO_WRITE(v) ((SIB->MCDR0 = (v & 0xfff) << 4))
+
+/* MCDR1 */
+
+#define TELECOM_RECV     ((SIB->MCDR1 >> 2) & 032fff)
+#define TELECOM_WRITE(v) ((SIB->MCDR1 = (v & 0x3fff) << 2))
+
+
+/* MCSR */
+
+#define MCSR_ATU (1 << 4)  /* Audio Transmit FIFO Underrun */
+#define MCSR_ARO (1 << 5)  /* Audio Receive  FIFO Underrun */
+#define MCSR_TTU (1 << 6)  /* TELECOM Transmit FIFO Underrun */
+#define MCSR_TRO (1 << 7)  /* TELECOM Receive  FIFO Underrun */
+
+#define MCSR_CLEAR_UNDERUN_BITS (MCSR_ATU | MCSR_ARO | MCSR_TTU | MCSR_TRO)
+
+
+#define GET_ATS ((SIB->MCSR >>  0) & 0x01) /* Audio Transmit FIFO Service Req*/
+#define GET_ARS ((SIB->MCSR >>  1) & 0x01) /* Audio Recv FIFO Service Request*/
+#define GET_TTS ((SIB->MCSR >>  2) & 0x01) /* TELECOM Transmit FIFO  Flag */
+#define GET_TRS ((SIB->MCSR >>  3) & 0x01) /* TELECOM Recv FIFO Service Req. */
+#define GET_ATU ((SIB->MCSR >>  4) & 0x01) /* Audio Transmit FIFO Underrun */
+#define GET_ARO ((SIB->MCSR >>  5) & 0x01) /* Audio Receive  FIFO Underrun */
+#define GET_TTU ((SIB->MCSR >>  6) & 0x01) /* TELECOM Transmit FIFO Underrun */
+#define GET_TRO ((SIB->MCSR >>  7) & 0x01) /* TELECOM Receive  FIFO Underrun */
+#define GET_ANF ((SIB->MCSR >>  8) & 0x01) /* Audio Transmit FIFO not full */
+#define GET_ANE ((SIB->MCSR >>  9) & 0x01) /* Audio Receive FIFO not empty */
+#define GET_TNF ((SIB->MCSR >> 10) & 0x01) /* Telecom Transmit FIFO not full */
+#define GET_TNE ((SIB->MCSR >> 11) & 0x01) /* Telecom Receive FIFO not empty */
+#define GET_CWC ((SIB->MCSR >> 12) & 0x01) /* Codec Write Complete */
+#define GET_CRC ((SIB->MCSR >> 13) & 0x01) /* Codec Read Complete */
+#define GET_ACE ((SIB->MCSR >> 14) & 0x01) /* Audio Codec Enabled */
+#define GET_TCE ((SIB->MCSR >> 15) & 0x01) /* Telecom Codec Enabled */
+
+/* MCDR2 */
+
+#define MCDR2_rW               (1 << 16)
+
+#define WRITE_MCDR2(reg, data) (SIB->MCDR2 =((reg<<17)|MCDR2_rW|(data&0xffff)))
+#define MCDR2_WRITE_COMPLETE   GET_CWC
+
+#define INITIATE_MCDR2_READ(reg) (SIB->MCDR2 = (reg << 17))
+#define MCDR2_READ_COMPLETE      GET_CRC
+#define MCDR2_READ               (SIB->MCDR2 & 0xffff)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/sys-clock.h linux/include/asm-arm/arch-l7200/sys-clock.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/sys-clock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-l7200/sys-clock.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,67 @@
+/****************************************************************************/
+/*
+ *  linux/include/asm-arm/arch-l7200/sys-clock.h
+ *
+ *   Registers and  helper functions for the L7200 Link-Up Systems
+ *   System clocks.
+ *
+ *   (C) Copyright 2000, S A McConnell  (samcconn@cotw.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+/****************************************************************************/
+
+#define SYS_CLOCK_OFF   0x00050030  /* Offset from IO_START. */
+
+/* IO_START and IO_BASE are defined in hardware.h */
+
+#define SYS_CLOCK_START (IO_START + SYS_CLCOK_OFF)  /* Physical address */
+#define SYS_CLOCK_BASE  (IO_BASE  + SYS_CLOCK_OFF)  /* Virtual address  */
+
+/* Define the interface to the SYS_CLOCK */
+
+typedef struct
+{
+     unsigned int ENABLE;
+     unsigned int ESYNC;
+     unsigned int SELECT;
+} sys_clock_interface;
+
+#define SYS_CLOCK   ((volatile sys_clock_interface *)(SYS_CLOCK_BASE))
+
+//#define CLOCK_EN    (*(volatile unsigned long *)(PMU_BASE+CLOCK_EN_OFF))
+//#define CLOCK_ESYNC (*(volatile unsigned long *)(PMU_BASE+CLOCK_ESYNC_OFF))
+//#define CLOCK_SEL   (*(volatile unsigned long *)(PMU_BASE+CLOCK_SEL_OFF))
+
+/* SYS_CLOCK -> ENABLE */
+
+#define SYN_EN          1<<0
+#define B18M_EN         1<<1
+#define CLK3M6_EN       1<<2
+#define BUART_EN        1<<3
+#define CLK18MU_EN      1<<4
+#define FIR_EN          1<<5
+#define MIRN_EN         1<<6
+#define UARTM_EN        1<<7
+#define SIBADC_EN       1<<8
+#define ALTD_EN         1<<9
+#define CLCLK_EN        1<<10
+
+/* SYS_CLOCK -> SELECT */
+
+#define CLK18M_DIV      1<<0
+#define MIR_SEL         1<<1
+#define SSP_SEL         1<<4
+#define MM_DIV          1<<5
+#define MM_SEL          1<<6
+#define ADC_SEL_2       0<<7
+#define ADC_SEL_4       1<<7
+#define ADC_SEL_8       3<<7
+#define ADC_SEL_16      7<<7
+#define ADC_SEL_32      0x0f<<7
+#define ADC_SEL_64      0x1f<<7
+#define ADC_SEL_128     0x3f<<7
+#define ALTD_SEL        1<<13
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/system.h linux/include/asm-arm/arch-l7200/system.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/system.h	Sun Aug 13 09:54:15 2000
+++ linux/include/asm-arm/arch-l7200/system.h	Thu Apr 12 12:20:31 2001
@@ -14,9 +14,8 @@
 
 static void arch_idle(void)
 {
-        while (!current->need_resched && !hlt_counter) {
-		cpu_do_idle(IDLE_WAIT_SLOW);
-	}
+	/* fixme: this needs to be cleaned up (converted from ASM code) --rmk */
+	*(unsigned long *)(IO_BASE + 0x50004) = 1;	/* idle mode */
 }
 
 extern inline void arch_reset(char mode)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/time.h linux/include/asm-arm/arch-l7200/time.h
--- v2.4.3/linux/include/asm-arm/arch-l7200/time.h	Sun Aug 13 09:54:15 2000
+++ linux/include/asm-arm/arch-l7200/time.h	Thu Apr 12 12:20:31 2001
@@ -40,7 +40,7 @@
 #define RTC_EN_STWDOG	0x08      /* Enable watchdog */
 
 /*
- * Handler for timer interrupt
+ * Handler for RTC timer interrupt
  */
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -50,7 +50,7 @@
 }
 
 /*
- * Set up timer interrupt, and return the current time in seconds.
+ * Set up RTC timer interrupt, and return the current time in seconds.
  */
 extern __inline__ void setup_timer(void)
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.4.3/linux/include/asm-arm/arch-rpc/hardware.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-rpc/hardware.h	Thu Apr 12 12:20:31 2001
@@ -43,66 +43,27 @@
 #define FLUSH_BASE		0xdf000000
 #define UNCACHEABLE_ADDR	0xdf010000
 
-
-#ifndef __ASSEMBLY__
-
-/*
- * for use with inb/outb
- */
-#define IO_VIDC_AUDIO_BASE	0x80140000
-#define IO_VIDC_BASE		0x80100000
-#define IO_IOMD_BASE		0x80080000
-#define IOC_BASE		0x80080000
-
-#define IO_EC_EASI_BASE		0x81400000
-#define IO_EC_IOC4_BASE		0x8009c000
-#define IO_EC_IOC_BASE		0x80090000
-#define IO_EC_MEMC8_BASE	0x8000ac00
-#define IO_EC_MEMC_BASE		0x80000000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE		((volatile unsigned char *)0xe0360000)
-#define IOEB_BASE		((volatile unsigned char *)0xe0350050)
-#define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0xe002a000)
-#define PCIO_BASE		0xe0010000
-
 /*
- * Offsets from RAM base
+ * IO Addresses
  */
-#define PARAMS_OFFSET		0x0100
-
-/*
- * RAM definitions
- */
-#define GET_MEMORY_END(p)	(PAGE_OFFSET + p->u1.s.page_size * \
-						(p->u1.s.pages_in_bank[0] + \
-						 p->u1.s.pages_in_bank[1] + \
-						 p->u1.s.pages_in_bank[2] + \
-						 p->u1.s.pages_in_bank[3]))
-
-#define Z_PARAMS_BASE		(RAM_START + PARAMS_OFFSET)
-#define FLUSH_BASE_PHYS		0x00000000	/* ROM */
-
-#else
-
-#define VIDC_SND_BASE		0xe0500000
 #define VIDC_BASE		0xe0400000
+#define EXPMASK_BASE		0xe0360000
 #define IOMD_BASE		0xe0200000
 #define IOC_BASE		0xe0200000
-#define PCIO_FLOPPYDMABASE	0xe002a000
 #define PCIO_BASE		0xe0010000
+#define FLOPPYDMA_BASE		0xe002a000
 
-#endif
+#define FLUSH_BASE_PHYS		0x00000000	/* ROM */
+
+#define vidc_writel(val)	__raw_writel(val, VIDC_BASE)
 
-#ifndef __ASSEMBLY__
-#define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
-#else
-#define __EXPMASK(offset)	offset
-#endif
+#define IO_EC_EASI_BASE		0x81400000
+#define IO_EC_IOC4_BASE		0x8009c000
+#define IO_EC_IOC_BASE		0x80090000
+#define IO_EC_MEMC8_BASE	0x8000ac00
+#define IO_EC_MEMC_BASE		0x80000000
 
-#define	EXPMASK_STATUS	__EXPMASK(0x00)
-#define EXPMASK_ENABLE	__EXPMASK(0x04)
+#define	EXPMASK_STATUS		(EXPMASK_BASE + 0x00)
+#define EXPMASK_ENABLE		(EXPMASK_BASE + 0x04)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h
--- v2.4.3/linux/include/asm-arm/arch-rpc/irq.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-rpc/irq.h	Thu Apr 12 12:20:31 2001
@@ -12,129 +12,100 @@
  *   22-08-1998	RMK	Restructured IRQ routines
  */
 #include <asm/hardware/iomd.h>
+#include <asm/io.h>
 
 #define fixup_irq(x) (x)
 
 static void rpc_mask_irq_ack_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]\n"
-"	strb	%1, [%3]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)),
-	  "r" (ioaddr(IOMD_IRQCLRA)));
+	mask = 1 << irq;
+	val = iomd_readb(IOMD_IRQMASKA);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
+	iomd_writeb(mask, IOMD_IRQCLRA);
 }
 
 static void rpc_mask_irq_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)));
+	mask = 1 << irq;
+	val = iomd_readb(IOMD_IRQMASKA);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
 }
 
 static void rpc_unmask_irq_a(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)));
+	mask = 1 << irq;
+	val = iomd_readb(IOMD_IRQMASKA);
+	iomd_writeb(val | mask, IOMD_IRQMASKA);
 }
 
 static void rpc_mask_irq_b(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKB);
+	iomd_writeb(val & ~mask, IOMD_IRQMASKB);
 }
 
 static void rpc_unmask_irq_b(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_IRQMASKB);
+	iomd_writeb(val | mask, IOMD_IRQMASKB);
 }
 
 static void rpc_mask_irq_dma(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_DMAMASK);
+	iomd_writeb(val & ~mask, IOMD_DMAMASK);
 }
 
 static void rpc_unmask_irq_dma(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_DMAMASK);
+	iomd_writeb(val | mask, IOMD_DMAMASK);
 }
 
 static void rpc_mask_irq_fiq(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_FIQMASK);
+	iomd_writeb(val & ~mask, IOMD_FIQMASK);
 }
 
 static void rpc_unmask_irq_fiq(unsigned int irq)
 {
-	unsigned int temp;
+	unsigned int val, mask;
 
-	__asm__ __volatile__(
-	"ldrb	%0, [%2]\n"
-"	orr	%0, %0, %1\n"
-"	strb	%0, [%2]"
-	: "=&r" (temp)
-	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK)));
+	mask = 1 << (irq & 7);
+	val = iomd_readb(IOMD_FIQMASK);
+	iomd_writeb(val | mask, IOMD_FIQMASK);
 }
 
 static __inline__ void irq_init_irq(void)
 {
-	extern void ecard_disableirq(unsigned int irq);
-	extern void ecard_enableirq(unsigned int irq);
 	int irq;
 
-	outb(0, IOMD_IRQMASKA);
-	outb(0, IOMD_IRQMASKB);
-	outb(0, IOMD_FIQMASK);
-	outb(0, IOMD_DMAMASK);
+	iomd_writeb(0, IOMD_IRQMASKA);
+	iomd_writeb(0, IOMD_IRQMASKB);
+	iomd_writeb(0, IOMD_FIQMASK);
+	iomd_writeb(0, IOMD_DMAMASK);
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
 		switch (irq) {
@@ -156,19 +127,14 @@
 			irq_desc[irq].unmask   = rpc_unmask_irq_b;
 			break;
 
-		case 16 ... 21:
-			irq_desc[irq].valid    = 1;
+		case 16 ... 19:
+		case 21:
 			irq_desc[irq].noautoenable = 1;
+		case 20:
+			irq_desc[irq].valid    = 1;
 			irq_desc[irq].mask_ack = rpc_mask_irq_dma;
 			irq_desc[irq].mask     = rpc_mask_irq_dma;
 			irq_desc[irq].unmask   = rpc_unmask_irq_dma;
-			break;
-
-		case 32 ... 39:
-			irq_desc[irq].valid    = 1;
-			irq_desc[irq].mask_ack = ecard_disableirq;
-			irq_desc[irq].mask     = ecard_disableirq;
-			irq_desc[irq].unmask   = ecard_enableirq;
 			break;
 
 		case 64 ... 71:
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.4.3/linux/include/asm-arm/arch-rpc/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-rpc/system.h	Thu Apr 12 12:20:31 2001
@@ -35,11 +35,7 @@
 
 extern __inline__ void arch_reset(char mode)
 {
-	extern void ecard_reset(int card);
-
-	ecard_reset(-1);
-
-	outb(0, IOMD_ROMCR0);
+	iomd_writeb(0, IOMD_ROMCR0);
 
 	/*
 	 * Jump into the ROM
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/SA-1100.h linux/include/asm-arm/arch-sa1100/SA-1100.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/SA-1100.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-sa1100/SA-1100.h	Thu Apr 12 12:20:31 2001
@@ -271,6 +271,7 @@
 
 #define UDCCR_UDD	0x00000001	/* UDC Disable                     */
 #define UDCCR_UDA	0x00000002	/* UDC Active (read)               */
+#define UDCCR_RESIM	0x00000004	/* Resume Interrupt Mask, per errata */
 #define UDCCR_EIM	0x00000008	/* End-point 0 Interrupt Mask      */
                 	        	/* (disable)                       */
 #define UDCCR_RIM	0x00000010	/* Receive Interrupt Mask          */
@@ -279,6 +280,7 @@
                 	        	/* (disable)                       */
 #define UDCCR_SRM	0x00000040	/* Suspend/Resume interrupt Mask   */
                 	        	/* (disable)                       */
+#define UDCCR_SUSIM	UDCCR_SRM	/* Per errata, SRM just masks suspend */
 #define UDCCR_REM	0x00000080	/* REset interrupt Mask (disable)  */
 
 #define UDCAR_ADD	Fld (7, 0)	/* function ADDress                */
@@ -502,6 +504,32 @@
 #define Ser3UTSR1	        	/* Ser. port 3 UART Status Reg. 1  */ \
                 	(*((volatile Word *) io_p2v (_Ser3UTSR1)))
 
+#elif LANGUAGE == Assembly
+#define Ser1UTCR0	( io_p2v (_Ser1UTCR0))
+#define Ser1UTCR1	( io_p2v (_Ser1UTCR1))
+#define Ser1UTCR2	( io_p2v (_Ser1UTCR2))
+#define Ser1UTCR3	( io_p2v (_Ser1UTCR3))
+#define Ser1UTDR	( io_p2v (_Ser1UTDR))
+#define Ser1UTSR0	( io_p2v (_Ser1UTSR0))
+#define Ser1UTSR1	( io_p2v (_Ser1UTSR1))
+
+#define Ser2UTCR0	( io_p2v (_Ser2UTCR0))
+#define Ser2UTCR1	( io_p2v (_Ser2UTCR1))
+#define Ser2UTCR2	( io_p2v (_Ser2UTCR2))
+#define Ser2UTCR3	( io_p2v (_Ser2UTCR3))
+#define Ser2UTCR4	( io_p2v (_Ser2UTCR4))
+#define Ser2UTDR	( io_p2v (_Ser2UTDR))
+#define Ser2UTSR0	( io_p2v (_Ser2UTSR0))
+#define Ser2UTSR1	( io_p2v (_Ser2UTSR1))
+
+#define Ser3UTCR0	( io_p2v (_Ser3UTCR0))
+#define Ser3UTCR1	( io_p2v (_Ser3UTCR1))
+#define Ser3UTCR2	( io_p2v (_Ser3UTCR2))
+#define Ser3UTCR3	( io_p2v (_Ser3UTCR3))
+#define Ser3UTDR	( io_p2v (_Ser3UTDR))
+#define Ser3UTSR0	( io_p2v (_Ser3UTSR0))
+#define Ser3UTSR1	( io_p2v (_Ser3UTSR1))
+
 #endif /* LANGUAGE == C */
 
 #define UTCR0_PE	0x00000001	/* Parity Enable                   */
@@ -1229,6 +1257,17 @@
                 	(*((volatile Word *) io_p2v (_PGSR)))
 #define POSR    	        	/* PM Oscillator Status Reg.       */ \
                 	(*((volatile Word *) io_p2v (_POSR)))
+
+#elif LANGUAGE == Assembly
+#define PMCR          	(io_p2v (_PMCR))
+#define PSSR          	(io_p2v (_PSSR))
+#define PSPR          	(io_p2v (_PSPR))
+#define PWER          	(io_p2v (_PWER))
+#define PCFR          	(io_p2v (_PCFR))
+#define PPCR          	(io_p2v (_PPCR))
+#define PGSR          	(io_p2v (_PGSR))
+#define POSR          	(io_p2v (_POSR))
+
 #endif /* LANGUAGE == C */
 
 #define PMCR_SF 	0x00000001	/* Sleep Force (set only)          */
@@ -1481,6 +1520,17 @@
                 	(*((volatile Word *) io_p2v (_GEDR)))
 #define GAFR    	        	/* GPIO Alternate Function Reg.    */ \
                 	(*((volatile Word *) io_p2v (_GAFR)))
+#elif LANGUAGE == Assembly
+
+#define GPLR  (io_p2v (_GPLR))
+#define GPDR  (io_p2v (_GPDR))
+#define GPSR  (io_p2v (_GPSR))
+#define GPCR  (io_p2v (_GPCR))
+#define GRER  (io_p2v (_GRER))
+#define GFER  (io_p2v (_GFER))
+#define GEDR  (io_p2v (_GEDR))
+#define GAFR  (io_p2v (_GAFR))
+
 #endif /* LANGUAGE == C */
 
 #define GPIO_MIN	(0)
@@ -1784,6 +1834,11 @@
 #define MDCAS0  	(MDCAS [0])	/*  DRAM CAS shift reg. 0          */
 #define MDCAS1  	(MDCAS [1])	/*  DRAM CAS shift reg. 1          */
 #define MDCAS2  	(MDCAS [2])	/*  DRAM CAS shift reg. 2          */
+
+#elif LANGUAGE == Assembly
+
+#define MDCNFG		(io_p2v(_MDCNFG))
+
 #endif /* LANGUAGE == C */
 
 /* SA1100 MDCNFG values */
@@ -1870,6 +1925,13 @@
                 	((volatile Word *) io_p2v (_MSC (0)))
 #define MSC0    	(MSC [0])	/*  Static memory Control reg. 0   */
 #define MSC1    	(MSC [1])	/*  Static memory Control reg. 1   */
+
+#elif LANGUAGE == Assembly
+
+#define MSC0		io_p2v(0xa0000010)
+#define MSC1		io_p2v(0xa0000014)
+#define MSC2		io_p2v(0xa000002c)
+
 #endif /* LANGUAGE == C */
 
 #define MSC_Bnk(Nb)	        	/* static memory Bank [0..3]       */ \
@@ -1895,32 +1957,32 @@
                 	        	/* First access - 1(.5) [Tmem]     */
 #define MSC_1stRdAcc(Tcpu)      	/*  1st Read Access time (burst    */ \
                 	        	/*  static memory) [3..65 Tcpu]    */ \
-                	(((Tcpu) - 3)/2 << FShft (MSC_RDF))
+                	((((Tcpu) - 3)/2) << FShft (MSC_RDF))
 #define MSC_Ceil1stRdAcc(Tcpu)  	/*  Ceil. of 1stRdAcc [3..65 Tcpu] */ \
-                	(((Tcpu) - 2)/2 << FShft (MSC_RDF))
+                	((((Tcpu) - 2)/2) << FShft (MSC_RDF))
 #define MSC_RdAcc(Tcpu)	        	/*  Read Access time (non-burst    */ \
                 	        	/*  static memory) [2..64 Tcpu]    */ \
-                	(((Tcpu) - 2)/2 << FShft (MSC_RDF))
+                	((((Tcpu) - 2)/2) << FShft (MSC_RDF))
 #define MSC_CeilRdAcc(Tcpu)     	/*  Ceil. of RdAcc [2..64 Tcpu]    */ \
-                	(((Tcpu) - 1)/2 << FShft (MSC_RDF))
+                	((((Tcpu) - 1)/2) << FShft (MSC_RDF))
 #define MSC_RDN 	Fld (5, 8)	/* ROM/static memory read Delay    */
                 	        	/* Next access - 1 [Tmem]          */
 #define MSC_NxtRdAcc(Tcpu)      	/*  Next Read Access time (burst   */ \
                 	        	/*  static memory) [2..64 Tcpu]    */ \
-                	(((Tcpu) - 2)/2 << FShft (MSC_RDN))
+                	((((Tcpu) - 2)/2) << FShft (MSC_RDN))
 #define MSC_CeilNxtRdAcc(Tcpu)  	/*  Ceil. of NxtRdAcc [2..64 Tcpu] */ \
-                	(((Tcpu) - 1)/2 << FShft (MSC_RDN))
+                	((((Tcpu) - 1)/2) << FShft (MSC_RDN))
 #define MSC_WrAcc(Tcpu)	        	/*  Write Access time (non-burst   */ \
                 	        	/*  static memory) [2..64 Tcpu]    */ \
-                	(((Tcpu) - 2)/2 << FShft (MSC_RDN))
+                	((((Tcpu) - 2)/2) << FShft (MSC_RDN))
 #define MSC_CeilWrAcc(Tcpu)     	/*  Ceil. of WrAcc [2..64 Tcpu]    */ \
-                	(((Tcpu) - 1)/2 << FShft (MSC_RDN))
+                	((((Tcpu) - 1)/2) << FShft (MSC_RDN))
 #define MSC_RRR 	Fld (3, 13)	/* ROM/static memory RecoveRy      */
                 	        	/* time/2 [Tmem]                   */
 #define MSC_Rec(Tcpu)	        	/*  Recovery time [0..28 Tcpu]     */ \
-                	((Tcpu)/4 << FShft (MSC_RRR))
+                	(((Tcpu)/4) << FShft (MSC_RRR))
 #define MSC_CeilRec(Tcpu)       	/*  Ceil. of Rec [0..28 Tcpu]      */ \
-                	(((Tcpu) + 3)/4 << FShft (MSC_RRR))
+                	((((Tcpu) + 3)/4) << FShft (MSC_RRR))
 
 
 /*
@@ -1955,20 +2017,20 @@
 
 #define MECR_BSIO	Fld (5, 0)	/* BCLK Select I/O - 1 [Tmem]      */
 #define MECR_IOClk(Tcpu)        	/*  I/O Clock [2..64 Tcpu]         */ \
-                	(((Tcpu) - 2)/2 << FShft (MECR_BSIO))
+                	((((Tcpu) - 2)/2) << FShft (MECR_BSIO))
 #define MECR_CeilIOClk(Tcpu)    	/*  Ceil. of IOClk [2..64 Tcpu]    */ \
-                	(((Tcpu) - 1)/2 << FShft (MECR_BSIO))
+                	((((Tcpu) - 1)/2) << FShft (MECR_BSIO))
 #define MECR_BSA	Fld (5, 5)	/* BCLK Select Attribute - 1       */
                 	        	/* [Tmem]                          */
 #define MECR_AttrClk(Tcpu)      	/*  Attribute Clock [2..64 Tcpu]   */ \
-                	(((Tcpu) - 2)/2 << FShft (MECR_BSA))
+                	((((Tcpu) - 2)/2) << FShft (MECR_BSA))
 #define MECR_CeilAttrClk(Tcpu)  	/*  Ceil. of AttrClk [2..64 Tcpu]  */ \
-                	(((Tcpu) - 1)/2 << FShft (MECR_BSA))
+                	((((Tcpu) - 1)/2) << FShft (MECR_BSA))
 #define MECR_BSM	Fld (5, 10)	/* BCLK Select Memory - 1 [Tmem]   */
 #define MECR_MemClk(Tcpu)       	/*  Memory Clock [2..64 Tcpu]      */ \
-                	(((Tcpu) - 2)/2 << FShft (MECR_BSM))
+                	((((Tcpu) - 2)/2) << FShft (MECR_BSM))
 #define MECR_CeilMemClk(Tcpu)   	/*  Ceil. of MemClk [2..64 Tcpu]   */ \
-                	(((Tcpu) - 1)/2 << FShft (MECR_BSM))
+                	((((Tcpu) - 1)/2) << FShft (MECR_BSM))
 
 /*
  * On SA1110 only
@@ -1981,6 +2043,10 @@
 #define MDREFR \
                 	(*((volatile Word *) io_p2v (_MDREFR)))
 
+#elif LANGUAGE == Assembly
+
+#define MDREFR		(io_p2v(_MDREFR))
+
 #endif /* LANGUAGE == C */
 
 #define MDREFR_TRASR		Fld (4, 0)
@@ -2456,18 +2522,18 @@
                 	(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
                 	 DDAR_Ser3UARTRc + DDAR_DevAdd (_Ser3UTDR))
 #define DDAR_Ser4MCP0Wr	        	/* Ser. port 4 MCP 0 Write (audio) */ \
-                	(DDAR_DevWr + DDAR_Brst8 + DDAR_16BitDev + \
+                	(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
                 	 DDAR_Ser4MCP0Tr + DDAR_DevAdd (_Ser4MCDR0))
 #define DDAR_Ser4MCP0Rd	        	/* Ser. port 4 MCP 0 Read (audio)  */ \
-                	(DDAR_DevRd + DDAR_Brst8 + DDAR_16BitDev + \
+                	(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
                 	 DDAR_Ser4MCP0Rc + DDAR_DevAdd (_Ser4MCDR0))
 #define DDAR_Ser4MCP1Wr	        	/* Ser. port 4 MCP 1 Write         */ \
                 	        	/* (telecom)                       */ \
-                	(DDAR_DevWr + DDAR_Brst8 + DDAR_16BitDev + \
+                	(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
                 	 DDAR_Ser4MCP1Tr + DDAR_DevAdd (_Ser4MCDR1))
 #define DDAR_Ser4MCP1Rd	        	/* Ser. port 4 MCP 1 Read          */ \
                 	        	/* (telecom)                       */ \
-                	(DDAR_DevRd + DDAR_Brst8 + DDAR_16BitDev + \
+                	(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
                 	 DDAR_Ser4MCP1Rc + DDAR_DevAdd (_Ser4MCDR1))
 #define DDAR_Ser4SSPWr	        	/* Ser. port 4 SSP Write (16 bits) */ \
                 	(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/assabet.h linux/include/asm-arm/arch-sa1100/assabet.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/assabet.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-sa1100/assabet.h	Thu Apr 12 12:20:31 2001
@@ -32,7 +32,7 @@
 #define BCR (*(volatile unsigned int *)(BCR_BASE))
 
 #define BCR_DB1110	(0x00A07410)
-#define BCR_DB1111	(0x00A07462)
+#define BCR_DB1111	(0x00A074E2)
 
 #define BCR_CF_PWR	(1<<0)	/* Compact Flash Power (1 = 3.3v, 0 = off) */
 #define BCR_CF_RST	(1<<1)	/* Compact Flash Reset (1 = power up reset) */
@@ -89,6 +89,7 @@
 
 #define IRQ_GPIO_CF_IRQ		IRQ_GPIO21
 #define IRQ_GPIO_CF_CD		IRQ_GPIO22
+#define IRQ_GPIO_MBREQ		IRQ_GPIO22
 #define IRQ_GPIO_UCB1300_IRQ	IRQ_GPIO23
 #define IRQ_GPIO_CF_BVD2	IRQ_GPIO24
 #define IRQ_GPIO_CF_BVD1	IRQ_GPIO25
@@ -139,6 +140,9 @@
 #define IRR_ETHERNET		(1<<0)
 #define IRR_USAR		(1<<1)
 #define IRR_SA1111		(1<<2)
+
+#define AUD_SEL_1341            (1<<0)
+#define AUD_MUTE_1341           (1<<1)
 
 #define NCR_GP01_OFF		(1<<0)
 #define NCR_TP_PWR_EN		(1<<1)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/bitsy.h linux/include/asm-arm/arch-sa1100/bitsy.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/bitsy.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-sa1100/bitsy.h	Thu Apr 12 12:20:31 2001
@@ -1,6 +1,9 @@
 #ifndef _INCLUDE_BITSY_H_
 #define _INCLUDE_BITSY_H_
 
+#define GPIO_BITSY_NPOWER_BUTTON    GPIO_GPIO (0)
+#define GPIO_BITSY_ACTION_BUTTON    GPIO_GPIO (18)
+
 #define GPIO_BITSY_PCMCIA_CD0  GPIO_GPIO (17)
 #define GPIO_BITSY_PCMCIA_CD1  GPIO_GPIO (10)
 #define GPIO_BITSY_PCMCIA_IRQ0 GPIO_GPIO (21)
@@ -15,6 +18,9 @@
 #define GPIO_BITSY_L3_MODE     GPIO_GPIO (15)
 
 
+
+#define IRQ_GPIO_BITSY_NPOWER_BUTTON    IRQ_GPIO0
+#define IRQ_GPIO_BITSY_ACTION_BUTTON    IRQ_GPIO18
 #define IRQ_GPIO_BITSY_PCMCIA_CD0	IRQ_GPIO17
 #define IRQ_GPIO_BITSY_PCMCIA_CD1	IRQ_GPIO10
 #define IRQ_GPIO_BITSY_PCMCIA_IRQ0	IRQ_GPIO21
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/dma.h linux/include/asm-arm/arch-sa1100/dma.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/dma.h	Tue Jul 18 22:43:25 2000
+++ linux/include/asm-arm/arch-sa1100/dma.h	Thu Apr 12 12:20:31 2001
@@ -1,12 +1,107 @@
 /*
  * linux/include/asm-arm/arch-sa1100/dma.h
+ *
+ * Generic SA1100 DMA support
+ *
+ * Copyright (C) 2000 Nicolas Pitre
+ *
  */
+
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
+#include <linux/config.h>
+#include "hardware.h"
+
+
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ */
 #define MAX_DMA_ADDRESS		0xffffffff
 
-/* No DMA (strictly, a lie :-) ) */
+
+/*
+ * The regular generic DMA interface is inappropriate for the
+ * SA1100 DMA model.  None of the SA1100 specific drivers using
+ * DMA are portable anyway so it's pointless to try to twist the
+ * regular DMA API to accommodate them.
+ */
 #define MAX_DMA_CHANNELS	0
+
+
+/*
+ * The SA1100 has six internal DMA channels.
+ */
+#define SA1100_DMA_CHANNELS     6
+
+
+/*
+ * The SA-1111 SAC has two DMA channels.
+ */
+#define SA1111_SAC_DMA_CHANNELS 2
+#define SA1111_SAC_XMT_CHANNEL  0
+#define SA1111_SAC_RCV_CHANNEL  1
+
+
+/*
+ * The SA-1111 SAC channels will reside in the same index space as
+ * the built-in SA-1100 channels, and will take on the next available
+ * identifiers after the 1100.
+ */
+#define SA1111_SAC_DMA_BASE     SA1100_DMA_CHANNELS
+
+#ifdef CONFIG_SA1111
+# define MAX_SA1100_DMA_CHANNELS (SA1100_DMA_CHANNELS + SA1111_SAC_DMA_CHANNELS)
+#else
+# define MAX_SA1100_DMA_CHANNELS SA1100_DMA_CHANNELS
+#endif
+
+
+/*
+ * All possible SA1100 devices a DMA channel can be attached to.
+ */
+typedef enum {
+	DMA_Ser0UDCWr  = DDAR_Ser0UDCWr,   /* Ser. port 0 UDC Write */
+	DMA_Ser0UDCRd  = DDAR_Ser0UDCRd,   /* Ser. port 0 UDC Read */
+	DMA_Ser1UARTWr = DDAR_Ser1UARTWr,  /* Ser. port 1 UART Write */
+	DMA_Ser1UARTRd = DDAR_Ser1UARTRd,  /* Ser. port 1 UART Read */
+	DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr,  /* Ser. port 1 SDLC Write */
+	DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd,  /* Ser. port 1 SDLC Read */
+	DMA_Ser2UARTWr = DDAR_Ser2UARTWr,  /* Ser. port 2 UART Write */
+	DMA_Ser2UARTRd = DDAR_Ser2UARTRd,  /* Ser. port 2 UART Read */
+	DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr,  /* Ser. port 2 HSSP Write */
+	DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd,  /* Ser. port 2 HSSP Read */
+	DMA_Ser3UARTWr = DDAR_Ser3UARTWr,  /* Ser. port 3 UART Write */
+	DMA_Ser3UARTRd = DDAR_Ser3UARTRd,  /* Ser. port 3 UART Read */
+	DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr,  /* Ser. port 4 MCP 0 Write (audio) */
+	DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd,  /* Ser. port 4 MCP 0 Read (audio) */
+	DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr,  /* Ser. port 4 MCP 1 Write */
+	DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd,  /* Ser. port 4 MCP 1 Read */
+	DMA_Ser4SSPWr  = DDAR_Ser4SSPWr,   /* Ser. port 4 SSP Write (16 bits) */
+	DMA_Ser4SSPRd  = DDAR_Ser4SSPRd    /* Ser. port 4 SSP Read (16 bits) */
+} dma_device_t;
+
+
+typedef void (*dma_callback_t)( void *buf_id, int size );
+
+
+/* SA1100 DMA API */
+extern int sa1100_request_dma( dmach_t *channel, const char *device_id );
+extern int sa1100_dma_set_callback( dmach_t channel, dma_callback_t cb );
+extern int sa1100_dma_set_device( dmach_t channel, dma_device_t device );
+extern int sa1100_dma_set_spin( dmach_t channel, dma_addr_t addr, int size );
+extern int sa1100_dma_queue_buffer( dmach_t channel, void *buf_id,
+				    dma_addr_t data, int size );
+extern int sa1100_dma_get_current( dmach_t channel, void **buf_id, dma_addr_t *addr );
+extern int sa1100_dma_stop( dmach_t channel );
+extern int sa1100_dma_resume( dmach_t channel );
+extern int sa1100_dma_flush_all( dmach_t channel );
+extern void sa1100_free_dma( dmach_t channel );
+
+/* Sa1111 DMA interface (all but registration uses the above) */
+extern int sa1111_sac_request_dma( dmach_t *channel, const char *device_id,
+				   unsigned int direction );
+extern int sa1111_check_dma_bug( dma_addr_t addr );
+
 
 #endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/keyboard.h linux/include/asm-arm/arch-sa1100/keyboard.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/keyboard.h	Tue Jul 18 22:43:25 2000
+++ linux/include/asm-arm/arch-sa1100/keyboard.h	Thu Apr 12 12:20:31 2001
@@ -10,7 +10,9 @@
 #include <linux/config.h>
 
 
-#ifdef CONFIG_SA1100_BRUTUS
+// #ifdef CONFIG_SA1100_BRUTUS
+/* need fixing... */
+#if 0
 
 extern int Brutus_kbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
@@ -32,6 +34,113 @@
 
 #define SYSRQ_KEY 0x54
 
+#elif CONFIG_SA1100_GRAPHICSCLIENT
+extern int gc_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode);
+extern void gc_kbd_leds(unsigned char leds);
+extern void gc_kbd_init_hw(void);
+extern void gc_kbd_enable_irq(void);
+extern void gc_kbd_disable_irq(void);
+extern unsigned char gc_kbd_sysrq_xlate[128];
+
+#define kbd_setkeycode(x...)    (-ENOSYS)
+#define kbd_getkeycode(x...)    (-ENOSYS)
+#define kbd_translate           gc_kbd_translate
+#define kbd_unexpected_up(x...) (1)
+#define kbd_leds                gc_kbd_leds
+#define kbd_init_hw             gc_kbd_init_hw
+#define kbd_enable_irq          gc_kbd_enable_irq
+#define kbd_disable_irq         gc_kbd_disable_irq
+#define kbd_sysrq_xlate         gc_kbd_sysrq_xlate
+
+#elif defined(CONFIG_SA1111)   /*@@@@@*/
+
+#define KEYBOARD_IRQ           TPRXINT
+#define DISABLE_KBD_DURING_INTERRUPTS  0
+
+/* redefine some macros */
+#ifdef KBD_DATA_REG
+#undef KBD_DATA_REG
+#endif
+#ifdef KBD_STATUS_REG
+#undef KBD_STATUS_REG
+#endif
+#ifdef KBD_CNTL_REG
+#undef KBD_CNTL_REG
+#endif
+#define KBD_DATA_REG           KBDDATA
+#define KBD_STATUS_REG         KBDSTAT
+#define KBD_CNTL_REG           KBDCR
+
+extern int sa1111_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int sa1111_getkeycode(unsigned int scancode);
+extern int sa1111_translate(unsigned char scancode, unsigned char *keycode,
+				char raw_mode);
+extern char sa1111_unexpected_up(unsigned char keycode);
+extern void sa1111_leds(unsigned char leds);
+extern void sa1111_init_hw(void);
+extern unsigned char sa1111_sysrq_xlate[128];
+
+#define kbd_setkeycode		sa1111_setkeycode
+#define kbd_getkeycode		sa1111_getkeycode
+#define kbd_translate		sa1111_translate
+#define kbd_unexpected_up	sa1111_unexpected_up
+#define kbd_leds		sa1111_leds
+#define kbd_init_hw		sa1111_init_hw
+#define kbd_sysrq_xlate		sa1111_sysrq_xlate
+#define kbd_disable_irq(x...)	do{;}while(0)
+#define kbd_enable_irq(x...)	do{;}while(0)
+
+#define SYSRQ_KEY 0x54
+
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+					"keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input()	(*KBDDATA & 0x00ff)
+#define kbd_read_status()	(*KBDSTAT & 0x01ff)
+#define kbd_write_output(val)	(*KBDDATA = (val))
+#define kbd_write_command(val)	(*KBDCR = (val))
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do {;} while(0)
+
+/* bit definitions for some registers */
+#define KBD_CR_ENA	(1<<3)
+
+#define KBD_STAT_RXB	(1<<4)
+#define KBD_STAT_RXF	(1<<5)
+#define KBD_STAT_TXB	(1<<6)
+#define KBD_STAT_TXE	(1<<7)
+#define KBD_STAT_STP	(1<<8)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ		MSRXINT
+
+#define aux_request_irq(hand, dev_id)  \
+		request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
+
+/* How to access the mouse macros on this platform.  */
+#define mse_read_input()	(*MSEDATA & 0x00ff)
+#define mse_read_status()	(*MSESTAT & 0x01ff)
+#define mse_write_output(val)	(*MSEDATA = (val))
+#define mse_write_command(val)	(*MSECR = (val))
+
+/* bit definitions for some registers */
+#define MSE_CR_ENA	(1<<3)
+
+#define MSE_STAT_RXB	(1<<4)
+#define MSE_STAT_RXF	(1<<5)
+#define MSE_STAT_TXB	(1<<6)
+#define MSE_STAT_TXE	(1<<7)
+#define MSE_STAT_STP	(1<<8)
+
+
 #else
 
 /* dummy i.e. no real keyboard */
@@ -39,11 +148,18 @@
 #define kbd_getkeycode(x...)	(-ENOSYS)
 #define kbd_translate(x...)	(0)
 #define kbd_unexpected_up(x...)	(1)
-#define kbd_leds(x...)		do { } while (0)
-#define kbd_init_hw(x...)	do { } while (0)
-#define kbd_enable_irq(x...)	do { } while (0)
-#define kbd_disable_irq(x...)	do { } while (0)
+#define kbd_leds(x...)		do {;} while (0)
+#define kbd_init_hw(x...)	do {;} while (0)
+#define kbd_enable_irq(x...)	do {;} while (0)
+#define kbd_disable_irq(x...)	do {;} while (0)
+
+#endif
+
 
+/* needed if MAGIC_SYSRQ is enabled for serial console */
+#ifndef SYSRQ_KEY
+#define SYSRQ_KEY		-1
+#define kbd_sysrq_xlate         ((unsigned char *)NULL)
 #endif
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/mmzone.h linux/include/asm-arm/arch-sa1100/mmzone.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/mmzone.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-sa1100/mmzone.h	Thu Apr 12 12:20:31 2001
@@ -21,21 +21,7 @@
  * 	node 3:  0xd8000000 - 0xdfffffff
  */
 
-
-/*
- * Currently defined in arch/arm/mm/mm-sa1100.c
- */
-extern pg_data_t sa1100_node_data[];
-
-/*
- * Return a pointer to the node data for node n.
- */
-#define NODE_DATA(nid)	(&sa1100_node_data[nid])
-
-/*
- * NODE_MEM_MAP gives the kaddr for the mem_map of the node.
- */
-#define NODE_MEM_MAP(nid)	(NODE_DATA(nid)->node_mem_map)
+#define NR_NODES	4
 
 /*
  * Given a kernel address, find the home node of the underlying memory.
@@ -71,7 +57,7 @@
  */
 #define VALID_PAGE(page) \
 ({ unsigned int node = KVADDR_TO_NID(page); \
-   ( (node < 4) && \
+   ( (node < NR_NODES) && \
      ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size) ); \
 })
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/pcmcia.h linux/include/asm-arm/arch-sa1100/pcmcia.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/pcmcia.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/pcmcia.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,70 @@
+/*
+ * linux/include/asm/arch/pcmcia.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
+ *
+ * This file contains definitions for the low-level SA-1100 kernel PCMCIA
+ * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
+ */
+
+#ifndef _ASM_ARCH_PCMCIA
+#define _ASM_ARCH_PCMCIA
+
+
+/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
+ * has support for two. This shows up in lots of hardwired ways, such
+ * as the fact that MECR only has enough bits to configure two sockets.
+ * Since it's so entrenched in the hardware, limiting the software
+ * in this way doesn't seem too terrible.
+ */
+#define SA1100_PCMCIA_MAX_SOCK   (2)
+
+
+#ifndef __ASSEMBLY__
+
+struct pcmcia_init {
+  void (*handler)(int irq, void *dev, struct pt_regs *regs);
+};
+
+struct pcmcia_state {
+  unsigned detect: 1,
+            ready: 1,
+             bvd1: 1,
+             bvd2: 1,
+           wrprot: 1,
+            vs_3v: 1,
+            vs_Xv: 1;
+};
+
+struct pcmcia_state_array {
+  unsigned int size;
+  struct pcmcia_state *state;
+};
+
+struct pcmcia_configure {
+  unsigned sock: 8,
+            vcc: 8,
+            vpp: 8,
+         output: 1,
+        speaker: 1,
+          reset: 1;
+};
+
+struct pcmcia_irq_info {
+  unsigned int sock;
+  unsigned int irq;
+};
+
+struct pcmcia_low_level {
+  int (*init)(struct pcmcia_init *);
+  int (*shutdown)(void);
+  int (*socket_state)(struct pcmcia_state_array *);
+  int (*get_irq_info)(struct pcmcia_irq_info *);
+  int (*configure_socket)(const struct pcmcia_configure *);
+};
+
+extern struct pcmcia_low_level *pcmcia_low_level;
+
+#endif  /* __ASSEMBLY__ */
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/serial.h linux/include/asm-arm/arch-sa1100/serial.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/serial.h	Thu Jan 13 13:30:31 2000
+++ linux/include/asm-arm/arch-sa1100/serial.h	Thu Apr 12 12:20:31 2001
@@ -22,11 +22,18 @@
 
 #define RS_TABLE_SIZE 4
 
-#define STD_SERIAL_PORT_DEFNS			\
-	/* UART CLK   PORT IRQ     FLAGS        */			\
-	{ 0, BASE_BAUD, 0x3F8, IRQ_GPIO3, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, IRQ_GPIO3, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0x3E8, IRQ_GPIO3, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0x2E8, IRQ_GPIO3, STD_COM4_FLAGS }	/* ttyS3 */
 
+/*
+ * Rather empty table...
+ * Hardwired serial ports should be defined here.
+ * PCMCIA will fill it dynamically.
+ */
+#define STD_SERIAL_PORT_DEFNS	\
+       /* UART	CLK     	PORT		IRQ	FLAGS		*/ \
+	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS },   \
+	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS },   \
+	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS },   \
+	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS }
+
+#define EXTRA_SERIAL_PORT_DEFNS
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- v2.4.3/linux/include/asm-arm/arch-sa1100/system.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-sa1100/system.h	Thu Apr 12 12:20:31 2001
@@ -7,7 +7,7 @@
 
 static inline void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	if (!hlt_counter)
 		cpu_do_idle(0);
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/dma.h linux/include/asm-arm/arch-shark/dma.h
--- v2.4.3/linux/include/asm-arm/arch-shark/dma.h	Mon Mar 27 10:46:29 2000
+++ linux/include/asm-arm/arch-shark/dma.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/dma.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  */
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/hardware.h linux/include/asm-arm/arch-shark/hardware.h
--- v2.4.3/linux/include/asm-arm/arch-shark/hardware.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-shark/hardware.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/hardware.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * derived from:
  * linux/include/asm-arm/arch-ebsa110/hardware.h
@@ -40,14 +40,16 @@
 /* defines for the Framebuffer */
 #define FB_START                0x06000000
 
-/* Registers for Framebuffer */
-/*#define FBREG_START             0x06800000*/
-
 #define UNCACHEABLE_ADDR        0xdf010000
 
 #define SEQUOIA_LED_GREEN       (1<<6)
 #define SEQUOIA_LED_AMBER       (1<<5)
 #define SEQUOIA_LED_BACK        (1<<7)
+
+#define pcibios_assign_all_busses()     1
+
+#define PCIBIOS_MIN_IO          0x6000
+#define PCIBIOS_MIN_MEM         0x50000000
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/ide.h linux/include/asm-arm/arch-shark/ide.h
--- v2.4.3/linux/include/asm-arm/arch-shark/ide.h	Mon Jun 26 12:04:42 2000
+++ linux/include/asm-arm/arch-shark/ide.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/ide.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * derived from:
  * linux/include/asm-arm/arch-ebsa285/ide.h
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/io.h linux/include/asm-arm/arch-shark/io.h
--- v2.4.3/linux/include/asm-arm/arch-shark/io.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-shark/io.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/io.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * derived from:
  * linux/include/asm-arm/arch-ebsa110/io.h
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/irq.h linux/include/asm-arm/arch-shark/irq.h
--- v2.4.3/linux/include/asm-arm/arch-shark/irq.h	Mon Mar 27 10:46:29 2000
+++ linux/include/asm-arm/arch-shark/irq.h	Thu Apr 12 12:20:31 2001
@@ -1,13 +1,14 @@
 /*
  * linux/include/asm-arm/arch-shark/irq.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * derived from linux/arch/ppc/kernel/i8259.c and:
  * include/asm-arm/arch-ebsa110/irq.h
  * Copyright (C) 1996-1998 Russell King
  */
 
+#include <asm/io.h>
 #define fixup_irq(x) (x)
 
 /*
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/irqs.h linux/include/asm-arm/arch-shark/irqs.h
--- v2.4.3/linux/include/asm-arm/arch-shark/irqs.h	Mon Mar 27 10:46:29 2000
+++ linux/include/asm-arm/arch-shark/irqs.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/irqs.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  */
 
 #define NR_IRQS			16
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/keyboard.h linux/include/asm-arm/arch-shark/keyboard.h
--- v2.4.3/linux/include/asm-arm/arch-shark/keyboard.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-shark/keyboard.h	Thu Apr 12 12:20:31 2001
@@ -1,6 +1,6 @@
 /*
  * linux/include/asm-arm/arch-shark/keyboard.h
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  * 
  * Derived from linux/include/asm-arm/arch-ebsa285/keyboard.h
  * (C) 1998 Russell King
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/memory.h linux/include/asm-arm/arch-shark/memory.h
--- v2.4.3/linux/include/asm-arm/arch-shark/memory.h	Mon Nov 27 17:07:59 2000
+++ linux/include/asm-arm/arch-shark/memory.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/memory.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * derived from:
  * linux/include/asm-arm/arch-ebsa110/memory.h
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/param.h linux/include/asm-arm/arch-shark/param.h
--- v2.4.3/linux/include/asm-arm/arch-shark/param.h	Mon Mar 27 10:46:29 2000
+++ linux/include/asm-arm/arch-shark/param.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/param.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  */
 
 /* This must be a power of 2 because the RTC
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/system.h linux/include/asm-arm/arch-shark/system.h
--- v2.4.3/linux/include/asm-arm/arch-shark/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-shark/system.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/system.h
  *
- * Copyright (c) 1996-1998 Russell King.
+ * by Alexander Schulz <aschulz@netwinder.org>
  */
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/time.h linux/include/asm-arm/arch-shark/time.h
--- v2.4.3/linux/include/asm-arm/arch-shark/time.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-shark/time.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-shark/time.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
  * Uses the real time clock because you can't run
  * the timer with level triggered interrupts and
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/timex.h linux/include/asm-arm/arch-shark/timex.h
--- v2.4.3/linux/include/asm-arm/arch-shark/timex.h	Mon Mar 27 10:46:29 2000
+++ linux/include/asm-arm/arch-shark/timex.h	Thu Apr 12 12:20:31 2001
@@ -1,5 +1,5 @@
 /*
  * linux/include/asm-arm/arch-shark/timex.h
  *
- * by Alexander.Schulz@stud.uni-karlsruhe.de
+ * by Alexander Schulz <aschulz@netwinder.org>
  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/uncompress.h linux/include/asm-arm/arch-shark/uncompress.h
--- v2.4.3/linux/include/asm-arm/arch-shark/uncompress.h	Mon Mar 27 10:46:29 2000
+++ linux/include/asm-arm/arch-shark/uncompress.h	Thu Apr 12 12:20:31 2001
@@ -1,31 +1,57 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ * linux/include/asm-arm/arch-shark/uncompress.h
+ * by Alexander Schulz <aschulz@netwinder.org>
  *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa285/uncompress.h
  * Copyright (C) 1996,1997,1998 Russell King
  */
 
+#define SERIAL_BASE ((volatile unsigned char *)0x400003f8)
+
+static __inline__ void putc(char c)
+{
+	int t;
+
+	SERIAL_BASE[0] = c;
+	t=0x10000;
+	while (t--);
+}
+
 /*
  * This does not append a newline
  */
 static void puts(const char *s)
 {
-	__asm__ __volatile__("
-	ldrb	%0, [%2], #1
-	teq	%0, #0
-	beq	3f
-1:	strb	%0, [%3]
-2:	ldrb	%1, [%3, #0x14]
-	and	%1, %1, #0x60
-	teq	%1, #0x60
-	bne	2b
-	teq	%0, #'\n'
-	moveq	%0, #'\r'
-	beq	1b
-	ldrb	%0, [%2], #1
-	teq	%0, #0
-	bne	1b
-3:	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+	while (*s) {
+		putc(*s);
+		if (*s == '\n')
+			putc('\r');
+		s++;
+	}
+}
+
+#ifdef DEBUG
+static void putn(unsigned long z)
+{
+	int i;
+	char x;
+
+	putc('0');
+	putc('x');
+	for (i=0;i<8;i++) {
+		x='0'+((z>>((7-i)*4))&0xf);
+		if (x>'9') x=x-'0'+'A'-10;
+		putc(x);
+	}
+}
+
+static void putr()
+{
+	putc('\n');
+	putc('\r');
 }
+#endif
 
 /*
  * nothing to do
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-tbox/time.h linux/include/asm-arm/arch-tbox/time.h
--- v2.4.3/linux/include/asm-arm/arch-tbox/time.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-tbox/time.h	Thu Apr 12 12:20:31 2001
@@ -8,6 +8,13 @@
  * our soft copy.
  */
 
+/*
+ * 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.
+ */
+
 #include <asm/io.h>
 #include <asm/hardware.h>
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/byteorder.h linux/include/asm-arm/byteorder.h
--- v2.4.3/linux/include/asm-arm/byteorder.h	Fri Oct 27 10:55:01 2000
+++ linux/include/asm-arm/byteorder.h	Thu Apr 12 12:20:31 2001
@@ -1,6 +1,21 @@
+/*
+ *  linux/include/asm-arm/byteorder.h
+ *
+ * ARM Endian-ness.  In little endian mode, the data bus is connected such
+ * that byte accesses appear as:
+ *  0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31
+ * and word accesses (data or instruction) appear as:
+ *  d0...d31
+ *
+ * When in big endian mode, byte accesses appear as:
+ *  0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7
+ * and word accesses (data or instruction) appear as:
+ *  d0...d31
+ */
 #ifndef __ASM_ARM_BYTEORDER_H
 #define __ASM_ARM_BYTEORDER_H
 
+
 #include <asm/types.h>
 
 #if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
@@ -8,7 +23,11 @@
 #  define __SWAB_64_THRU_32__
 #endif
 
+#ifdef __ARMEB__
+#include <linux/byteorder/big_endian.h>
+#else
 #include <linux/byteorder/little_endian.h>
+#endif
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/elf.h linux/include/asm-arm/elf.h
--- v2.4.3/linux/include/asm-arm/elf.h	Wed Oct 20 16:29:08 1999
+++ linux/include/asm-arm/elf.h	Thu Apr 12 12:20:31 2001
@@ -30,7 +30,7 @@
  */
 #define ELF_CLASS	ELFCLASS32
 #ifdef __ARMEB__
-#define ELF_DATA	ELFDATA2LSB;
+#define ELF_DATA	ELFDATA2MSB;
 #else
 #define ELF_DATA	ELFDATA2LSB;
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/clps7111.h linux/include/asm-arm/hardware/clps7111.h
--- v2.4.3/linux/include/asm-arm/hardware/clps7111.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/hardware/clps7111.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,181 @@
+/*
+ *  linux/include/asm-arm/hardware/clps7111.h
+ *
+ *  This file contains the hardware definitions of the CLPS7111 internal
+ *  registers.
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_HARDWARE_CLPS7111_H
+#define __ASM_HARDWARE_CLPS7111_H
+
+#define CLPS7111_PHYS_BASE	(0x80000000)
+
+#ifndef __ASSEMBLY__
+#define clps_readb(off)		__raw_readb(CLPS7111_BASE + (off))
+#define clps_readl(off)		__raw_readl(CLPS7111_BASE + (off))
+#define clps_writeb(val,off)	__raw_writeb(val, CLPS7111_BASE + (off))
+#define clps_writel(val,off)	__raw_writel(val, CLPS7111_BASE + (off))
+#endif
+
+#define PADR		(0x0000)
+#define PBDR		(0x0001)
+#define PDDR		(0x0003)
+#define PADDR		(0x0040)
+#define PBDDR		(0x0041)
+#define PDDDR		(0x0043)
+#define PEDR		(0x0080)
+#define PEDDR		(0x00c0)
+#define SYSCON1		(0x0100)
+#define SYSFLG1		(0x0140)
+#define MEMCFG1		(0x0180)
+#define MEMCFG2		(0x01c0)
+#define DRFPR		(0x0200)
+#define INTSR1		(0x0240)
+#define INTMR1		(0x0280)
+#define LCDCON		(0x02c0)
+#define TC2D		(0x0340)
+#define RTCDR		(0x0380)
+#define RTCMR		(0x03c0)
+#define PMPCON		(0x0400)
+#define CODR		(0x0440)
+#define UARTDR1		(0x0480)
+#define UBRLCR1		(0x04c0)
+#define SYNCIO		(0x0500)
+#define PALLSW		(0x0540)
+#define PALMSW		(0x0580)
+#define STFCLR		(0x05c0)
+#define BLEOI		(0x0600)
+#define MCEOI		(0x0640)
+#define TEOI		(0x0680)
+#define TC1EOI		(0x06c0)
+#define TC2EOI		(0x0700)
+#define RTCEOI		(0x0740)
+#define UMSEOI		(0x0780)
+#define COEOI		(0x07c0)
+#define HALT		(0x0800)
+#define STDBY		(0x0840)
+
+#define FBADDR		(0x1000)
+#define SYSCON2		(0x1100)
+#define SYSFLG2		(0x1140)
+#define INTSR2		(0x1240)
+#define INTMR2		(0x1280)
+#define UARTDR2		(0x1480)
+#define UBRLCR2		(0x14c0)
+#define SS2DR		(0x1500)
+#define SRXEOF		(0x1600)
+#define SS2POP		(0x16c0)
+#define KBDEOI		(0x1700)
+
+/* common bits: SYSCON1 / SYSCON2 */
+#define SYSCON_UARTEN		(1 << 8)
+
+#define SYSCON1_KBDSCAN(x)	((x) & 15)
+#define SYSCON1_KBDSCANMASK	(15)
+#define SYSCON1_TC1M		(1 << 4)
+#define SYSCON1_TC1S		(1 << 5)
+#define SYSCON1_TC2M		(1 << 6)
+#define SYSCON1_TC2S		(1 << 7)
+#define SYSCON1_UART1EN		SYSCON_UARTEN
+#define SYSCON1_BZTOG		(1 << 9)
+#define SYSCON1_BZMOD		(1 << 10)
+#define SYSCON1_DBGEN		(1 << 11)
+#define SYSCON1_LCDEN		(1 << 12)
+#define SYSCON1_CDENTX		(1 << 13)
+#define SYSCON1_CDENRX		(1 << 14)
+#define SYSCON1_SIREN		(1 << 15)
+#define SYSCON1_ADCKSEL(x)	(((x) & 3) << 16)
+#define SYSCON1_ADCKSEL_MASK	(3 << 16)
+#define SYSCON1_EXCKEN		(1 << 18)
+#define SYSCON1_WAKEDIS		(1 << 19)
+#define SYSCON1_IRTXM		(1 << 20)
+
+/* common bits: SYSFLG1 / SYSFLG2 */
+#define SYSFLG_UBUSY		(1 << 11)
+#define SYSFLG_URXFE		(1 << 22)
+#define SYSFLG_UTXFF		(1 << 23)
+
+#define SYSFLG1_MCDR		(1 << 0)
+#define SYSFLG1_DCDET		(1 << 1)
+#define SYSFLG1_WUDR		(1 << 2)
+#define SYSFLG1_WUON		(1 << 3)
+#define SYSFLG1_CTS		(1 << 8)
+#define SYSFLG1_DSR		(1 << 9)
+#define SYSFLG1_DCD		(1 << 10)
+#define SYSFLG1_UBUSY		SYSFLG_UBUSY
+#define SYSFLG1_NBFLG		(1 << 12)
+#define SYSFLG1_RSTFLG		(1 << 13)
+#define SYSFLG1_PFFLG		(1 << 14)
+#define SYSFLG1_CLDFLG		(1 << 15)
+#define SYSFLG1_URXFE		SYSFLG_URXFE
+#define SYSFLG1_UTXFF		SYSFLG_UTXFF
+#define SYSFLG1_CRXFE		(1 << 24)
+#define SYSFLG1_CTXFF		(1 << 25)
+#define SYSFLG1_SSIBUSY		(1 << 26)
+#define SYSFLG1_ID		(1 << 29)
+
+#define SYSFLG2_SSRXOF		(1 << 0)
+#define SYSFLG2_RESVAL		(1 << 1)
+#define SYSFLG2_RESFRM		(1 << 2)
+#define SYSFLG2_SS2RXFE		(1 << 3)
+#define SYSFLG2_SS2TXFF		(1 << 4)
+#define SYSFLG2_SS2TXUF		(1 << 5)
+#define SYSFLG2_CKMODE		(1 << 6)
+#define SYSFLG2_UBUSY		SYSFLG_UBUSY
+#define SYSFLG2_URXFE		SYSFLG_URXFE
+#define SYSFLG2_UTXFF		SYSFLG_UTXFF
+
+#define LCDCON_GSEN		(1 << 30)
+#define LCDCON_GSMD		(1 << 31)
+
+#define SYSCON2_SERSEL		(1 << 0)
+#define SYSCON2_KBD6		(1 << 1)
+#define SYSCON2_DRAMZ		(1 << 2)
+#define SYSCON2_KBWEN		(1 << 3)
+#define SYSCON2_SS2TXEN		(1 << 4)
+#define SYSCON2_PCCARD1		(1 << 5)
+#define SYSCON2_PCCARD2		(1 << 6)
+#define SYSCON2_SS2RXEN		(1 << 7)
+#define SYSCON2_UART2EN		SYSCON_UARTEN
+#define SYSCON2_SS2MAEN		(1 << 9)
+#define SYSCON2_OSTB		(1 << 12)
+#define SYSCON2_CLKENSL		(1 << 13)
+#define SYSCON2_BUZFREQ		(1 << 14)
+
+/* common bits: UARTDR1 / UARTDR2 */
+#define UARTDR_FRMERR		(1 << 8)
+#define UARTDR_PARERR		(1 << 9)
+#define UARTDR_OVERR		(1 << 10)
+
+/* common bits: UBRLCR1 / UBRLCR2 */
+#define UBRLCR_BAUD_MASK	((1 << 12) - 1)
+#define UBRLCR_BREAK		(1 << 12)
+#define UBRLCR_PRTEN		(1 << 13)
+#define UBRLCR_EVENPRT		(1 << 14)
+#define UBRLCR_XSTOP		(1 << 15)
+#define UBRLCR_FIFOEN		(1 << 16)
+#define UBRLCR_WRDLEN5		(0 << 17)
+#define UBRLCR_WRDLEN6		(1 << 17)
+#define UBRLCR_WRDLEN7		(2 << 17)
+#define UBRLCR_WRDLEN8		(3 << 17)
+#define UBRLCR_WRDLEN_MASK	(3 << 17)
+
+#define SYNCIO_SMCKEN		(1 << 13)
+#define SYNCIO_TXFRMEN		(1 << 14)
+
+#endif /* __ASM_HARDWARE_CLPS7111_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/ep7212.h linux/include/asm-arm/hardware/ep7212.h
--- v2.4.3/linux/include/asm-arm/hardware/ep7212.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/hardware/ep7212.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,84 @@
+/*
+ *  linux/include/asm-arm/hardware/ep7212.h
+ *
+ *  This file contains the hardware definitions of the EP7212 internal
+ *  registers.
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_HARDWARE_EP7212_H
+#define __ASM_HARDWARE_EP7212_H
+
+/*
+ * define EP7212_BASE to be the base address of the region
+ * you want to access.
+ */
+
+#define EP7212_PHYS_BASE	(0x80000000)
+
+#ifndef __ASSEMBLY__
+#define ep_readl(off)		__raw_readl(EP7212_BASE + (off))
+#define ep_writel(val,off)	__raw_writel(val, EP7212_BASE + (off))
+#endif
+
+/*
+ * These registers are specific to the EP7212 only
+ */
+#define DAIR			0x2000
+#define DAIR0			0x2040
+#define DAIDR1			0x2080
+#define DAIDR2			0x20c0
+#define DAISR			0x2100
+#define SYSCON3			0x2200
+#define INTSR3			0x2240
+#define INTMR3			0x2280
+#define LEDFLSH			0x22c0
+
+#define DAIR_DAIEN		(1 << 16)
+#define DAIR_ECS		(1 << 17)
+#define DAIR_LCTM		(1 << 19)
+#define DAIR_LCRM		(1 << 20)
+#define DAIR_RCTM		(1 << 21)
+#define DAIR_RCRM		(1 << 22)
+#define DAIR_LBM		(1 << 23)
+
+#define DAIDR2_FIFOEN		(1 << 15)
+#define DAIDR2_FIFOLEFT		(0x0d << 16)
+#define DAIDR2_FIFORIGHT	(0x11 << 16)
+
+#define DAISR_RCTS		(1 << 0)
+#define DAISR_RCRS		(1 << 1)
+#define DAISR_LCTS		(1 << 2)
+#define DAISR_LCRS		(1 << 3)
+#define DAISR_RCTU		(1 << 4)
+#define DAISR_RCRO		(1 << 5)
+#define DAISR_LCTU		(1 << 6)
+#define DAISR_LCRO		(1 << 7)
+#define DAISR_RCNF		(1 << 8)
+#define DAISR_RCNE		(1 << 9)
+#define DAISR_LCNF		(1 << 10)
+#define DAISR_LCNE		(1 << 11)
+#define DAISR_FIFO		(1 << 12)
+
+#define SYSCON3_ADCCON		(1 << 0)
+#define SYSCON3_DAISEL		(1 << 3)
+#define SYSCON3_ADCCKNSEN	(1 << 4)
+#define SYSCON3_FASTWAKE	(1 << 8)
+#define SYSCON3_DAIEN		(1 << 9)
+
+
+#endif /* __ASM_HARDWARE_EP7212_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/ioc.h linux/include/asm-arm/hardware/ioc.h
--- v2.4.3/linux/include/asm-arm/hardware/ioc.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/hardware/ioc.h	Thu Apr 12 12:20:31 2001
@@ -10,58 +10,63 @@
  *  Use these macros to read/write the IOC.  All it does is perform the actual
  *  read/write.
  */
-
-#ifndef IOC_CONTROL
+#ifndef __ASMARM_HARDWARE_IOC_H
+#define __ASMARM_HARDWARE_IOC_H
 
 #ifndef __ASSEMBLY__
-#define __IOC(offset)	(IOC_BASE + (offset >> 2))
-#else
-#define __IOC(offset)	offset
+
+/*
+ * We use __raw_base variants here so that we give the compiler the
+ * chance to keep IOC_BASE in a register.
+ */
+#define ioc_readb(off)		__raw_base_readb(IOC_BASE, (off))
+#define ioc_writeb(val,off)	__raw_base_writeb(val, IOC_BASE, (off))
+
 #endif
 
-#define IOC_CONTROL	__IOC(0x00)
-#define IOC_KARTTX	__IOC(0x04)
-#define IOC_KARTRX	__IOC(0x04)
-
-#define IOC_IRQSTATA	__IOC(0x10)
-#define IOC_IRQREQA	__IOC(0x14)
-#define IOC_IRQCLRA	__IOC(0x14)
-#define IOC_IRQMASKA	__IOC(0x18)
-
-#define IOC_IRQSTATB	__IOC(0x20)
-#define IOC_IRQREQB	__IOC(0x24)
-#define IOC_IRQMASKB	__IOC(0x28)
-
-#define IOC_FIQSTAT	__IOC(0x30)
-#define IOC_FIQREQ	__IOC(0x34)
-#define IOC_FIQMASK	__IOC(0x38)
-
-#define IOC_T0CNTL	__IOC(0x40)
-#define IOC_T0LTCHL	__IOC(0x40)
-#define IOC_T0CNTH	__IOC(0x44)
-#define IOC_T0LTCHH	__IOC(0x44)
-#define IOC_T0GO	__IOC(0x48)
-#define IOC_T0LATCH	__IOC(0x4c)
-
-#define IOC_T1CNTL	__IOC(0x50)
-#define IOC_T1LTCHL	__IOC(0x50)
-#define IOC_T1CNTH	__IOC(0x54)
-#define IOC_T1LTCHH	__IOC(0x54)
-#define IOC_T1GO	__IOC(0x58)
-#define IOC_T1LATCH	__IOC(0x5c)
-
-#define IOC_T2CNTL	__IOC(0x60)
-#define IOC_T2LTCHL	__IOC(0x60)
-#define IOC_T2CNTH	__IOC(0x64)
-#define IOC_T2LTCHH	__IOC(0x64)
-#define IOC_T2GO	__IOC(0x68)
-#define IOC_T2LATCH	__IOC(0x6c)
-
-#define IOC_T3CNTL	__IOC(0x70)
-#define IOC_T3LTCHL	__IOC(0x70)
-#define IOC_T3CNTH	__IOC(0x74)
-#define IOC_T3LTCHH	__IOC(0x74)
-#define IOC_T3GO	__IOC(0x78)
-#define IOC_T3LATCH	__IOC(0x7c)
+#define IOC_CONTROL	(0x00)
+#define IOC_KARTTX	(0x04)
+#define IOC_KARTRX	(0x04)
+
+#define IOC_IRQSTATA	(0x10)
+#define IOC_IRQREQA	(0x14)
+#define IOC_IRQCLRA	(0x14)
+#define IOC_IRQMASKA	(0x18)
+
+#define IOC_IRQSTATB	(0x20)
+#define IOC_IRQREQB	(0x24)
+#define IOC_IRQMASKB	(0x28)
+
+#define IOC_FIQSTAT	(0x30)
+#define IOC_FIQREQ	(0x34)
+#define IOC_FIQMASK	(0x38)
+
+#define IOC_T0CNTL	(0x40)
+#define IOC_T0LTCHL	(0x40)
+#define IOC_T0CNTH	(0x44)
+#define IOC_T0LTCHH	(0x44)
+#define IOC_T0GO	(0x48)
+#define IOC_T0LATCH	(0x4c)
+
+#define IOC_T1CNTL	(0x50)
+#define IOC_T1LTCHL	(0x50)
+#define IOC_T1CNTH	(0x54)
+#define IOC_T1LTCHH	(0x54)
+#define IOC_T1GO	(0x58)
+#define IOC_T1LATCH	(0x5c)
+
+#define IOC_T2CNTL	(0x60)
+#define IOC_T2LTCHL	(0x60)
+#define IOC_T2CNTH	(0x64)
+#define IOC_T2LTCHH	(0x64)
+#define IOC_T2GO	(0x68)
+#define IOC_T2LATCH	(0x6c)
+
+#define IOC_T3CNTL	(0x70)
+#define IOC_T3LTCHL	(0x70)
+#define IOC_T3CNTH	(0x74)
+#define IOC_T3LTCHH	(0x74)
+#define IOC_T3GO	(0x78)
+#define IOC_T3LATCH	(0x7c)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/iomd.h linux/include/asm-arm/hardware/iomd.h
--- v2.4.3/linux/include/asm-arm/hardware/iomd.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/hardware/iomd.h	Thu Apr 12 12:20:31 2001
@@ -1,5 +1,5 @@
 /*
- *  linux/include/asm-arm/iomd.h
+ *  linux/include/asm-arm/hardware/iomd.h
  *
  *  Copyright (C) 1999 Russell King
  *
@@ -10,111 +10,121 @@
  *  This file contains information out the IOMD ASIC used in the
  *  Acorn RiscPC and subsequently integrated into the CLPS7500 chips.
  */
+#ifndef __ASMARM_HARDWARE_IOMD_H
+#define __ASMARM_HARDWARE_IOMD_H
+
 #include <linux/config.h>
 
 #ifndef __ASSEMBLY__
-#define __IOMD(offset)	(IO_IOMD_BASE + (offset >> 2))
-#else
-#define __IOMD(offset)	offset
+
+/*
+ * We use __raw_base variants here so that we give the compiler the
+ * chance to keep IOC_BASE in a register.
+ */
+#define iomd_readb(off)		__raw_base_readb(IOMD_BASE, (off))
+#define iomd_readl(off)		__raw_base_readl(IOMD_BASE, (off))
+#define iomd_writeb(val,off)	__raw_base_writeb(val, IOMD_BASE, (off))
+#define iomd_writel(val,off)	__raw_base_writel(val, IOMD_BASE, (off))
+
 #endif
 
-#define IOMD_CONTROL	__IOMD(0x000)
-#define IOMD_KARTTX	__IOMD(0x004)
-#define IOMD_KARTRX	__IOMD(0x004)
-#define IOMD_KCTRL	__IOMD(0x008)
+#define IOMD_CONTROL	(0x000)
+#define IOMD_KARTTX	(0x004)
+#define IOMD_KARTRX	(0x004)
+#define IOMD_KCTRL	(0x008)
 
 #ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_IOLINES	__IOMD(0x00C)
+#define IOMD_IOLINES	(0x00C)
 #endif
 
-#define IOMD_IRQSTATA	__IOMD(0x010)
-#define IOMD_IRQREQA	__IOMD(0x014)
-#define IOMD_IRQCLRA	__IOMD(0x014)
-#define IOMD_IRQMASKA	__IOMD(0x018)
+#define IOMD_IRQSTATA	(0x010)
+#define IOMD_IRQREQA	(0x014)
+#define IOMD_IRQCLRA	(0x014)
+#define IOMD_IRQMASKA	(0x018)
 
 #ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_SUSMODE	__IOMD(0x01C)
+#define IOMD_SUSMODE	(0x01C)
 #endif
 
-#define IOMD_IRQSTATB	__IOMD(0x020)
-#define IOMD_IRQREQB	__IOMD(0x024)
-#define IOMD_IRQMASKB	__IOMD(0x028)
+#define IOMD_IRQSTATB	(0x020)
+#define IOMD_IRQREQB	(0x024)
+#define IOMD_IRQMASKB	(0x028)
 
-#define IOMD_FIQSTAT	__IOMD(0x030)
-#define IOMD_FIQREQ	__IOMD(0x034)
-#define IOMD_FIQMASK	__IOMD(0x038)
+#define IOMD_FIQSTAT	(0x030)
+#define IOMD_FIQREQ	(0x034)
+#define IOMD_FIQMASK	(0x038)
 
 #ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_CLKCTL	__IOMD(0x03C)
+#define IOMD_CLKCTL	(0x03C)
 #endif
 
-#define IOMD_T0CNTL	__IOMD(0x040)
-#define IOMD_T0LTCHL	__IOMD(0x040)
-#define IOMD_T0CNTH	__IOMD(0x044)
-#define IOMD_T0LTCHH	__IOMD(0x044)
-#define IOMD_T0GO	__IOMD(0x048)
-#define IOMD_T0LATCH	__IOMD(0x04c)
+#define IOMD_T0CNTL	(0x040)
+#define IOMD_T0LTCHL	(0x040)
+#define IOMD_T0CNTH	(0x044)
+#define IOMD_T0LTCHH	(0x044)
+#define IOMD_T0GO	(0x048)
+#define IOMD_T0LATCH	(0x04c)
 
-#define IOMD_T1CNTL	__IOMD(0x050)
-#define IOMD_T1LTCHL	__IOMD(0x050)
-#define IOMD_T1CNTH	__IOMD(0x054)
-#define IOMD_T1LTCHH	__IOMD(0x054)
-#define IOMD_T1GO	__IOMD(0x058)
-#define IOMD_T1LATCH	__IOMD(0x05c)
+#define IOMD_T1CNTL	(0x050)
+#define IOMD_T1LTCHL	(0x050)
+#define IOMD_T1CNTH	(0x054)
+#define IOMD_T1LTCHH	(0x054)
+#define IOMD_T1GO	(0x058)
+#define IOMD_T1LATCH	(0x05c)
 
 #ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_IRQSTATC	__IOMD(0x060)
-#define IOMD_IRQREQC	__IOMD(0x064)
-#define IOMD_IRQMASKC	__IOMD(0x068)
+#define IOMD_IRQSTATC	(0x060)
+#define IOMD_IRQREQC	(0x064)
+#define IOMD_IRQMASKC	(0x068)
 
-#define IOMD_VIDMUX	__IOMD(0x06c)
+#define IOMD_VIDMUX	(0x06c)
 
-#define IOMD_IRQSTATD	__IOMD(0x070)
-#define IOMD_IRQREQD	__IOMD(0x074)
-#define IOMD_IRQMASKD	__IOMD(0x078)
+#define IOMD_IRQSTATD	(0x070)
+#define IOMD_IRQREQD	(0x074)
+#define IOMD_IRQMASKD	(0x078)
 #endif
 
-#define IOMD_ROMCR0	__IOMD(0x080)
-#define IOMD_ROMCR1	__IOMD(0x084)
+#define IOMD_ROMCR0	(0x080)
+#define IOMD_ROMCR1	(0x084)
 #ifdef CONFIG_ARCH_RPC
-#define IOMD_DRAMCR	__IOMD(0x088)
+#define IOMD_DRAMCR	(0x088)
 #endif
-#define IOMD_REFCR	__IOMD(0x08C)
+#define IOMD_REFCR	(0x08C)
 
-#define IOMD_FSIZE	__IOMD(0x090)
-#define IOMD_ID0	__IOMD(0x094)
-#define IOMD_ID1	__IOMD(0x098)
-#define IOMD_VERSION	__IOMD(0x09C)
+#define IOMD_FSIZE	(0x090)
+#define IOMD_ID0	(0x094)
+#define IOMD_ID1	(0x098)
+#define IOMD_VERSION	(0x09C)
 
 #ifdef CONFIG_ARCH_RPC
-#define IOMD_MOUSEX	__IOMD(0x0A0)
-#define IOMD_MOUSEY	__IOMD(0x0A4)
+#define IOMD_MOUSEX	(0x0A0)
+#define IOMD_MOUSEY	(0x0A4)
 #endif
 
 #ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_MSEDAT	__IOMD(0x0A8)
-#define IOMD_MSECTL	__IOMD(0x0Ac)
+#define IOMD_MSEDAT	(0x0A8)
+#define IOMD_MSECTL	(0x0Ac)
 #endif
 
 #ifdef CONFIG_ARCH_RPC
-#define IOMD_DMATCR	__IOMD(0x0C0)
+#define IOMD_DMATCR	(0x0C0)
 #endif
-#define IOMD_IOTCR	__IOMD(0x0C4)
-#define IOMD_ECTCR	__IOMD(0x0C8)
+#define IOMD_IOTCR	(0x0C4)
+#define IOMD_ECTCR	(0x0C8)
 #ifdef CONFIG_ARCH_RPC
-#define IOMD_DMAEXT	__IOMD(0x0CC)
+#define IOMD_DMAEXT	(0x0CC)
 #endif
 #ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_ASTCR	__IOMD(0x0CC)
-#define IOMD_DRAMCR	__IOMD(0x0D0)
-#define IOMD_SELFREF	__IOMD(0x0D4)
-#define IOMD_ATODICR	__IOMD(0x0E0)
-#define IOMD_ATODSR	__IOMD(0x0E4)
-#define IOMD_ATODCC	__IOMD(0x0E8)
-#define IOMD_ATODCNT1	__IOMD(0x0EC)
-#define IOMD_ATODCNT2	__IOMD(0x0F0)
-#define IOMD_ATODCNT3	__IOMD(0x0F4)
-#define IOMD_ATODCNT4	__IOMD(0x0F8)
+#define IOMD_ASTCR	(0x0CC)
+#define IOMD_DRAMCR	(0x0D0)
+#define IOMD_SELFREF	(0x0D4)
+#define IOMD_ATODICR	(0x0E0)
+#define IOMD_ATODSR	(0x0E4)
+#define IOMD_ATODCC	(0x0E8)
+#define IOMD_ATODCNT1	(0x0EC)
+#define IOMD_ATODCNT2	(0x0F0)
+#define IOMD_ATODCNT3	(0x0F4)
+#define IOMD_ATODCNT4	(0x0F8)
 #endif
 
 #ifdef CONFIG_ARCH_RPC
@@ -123,63 +133,63 @@
 #define DMA_EXT_IO2	4
 #define DMA_EXT_IO3	8
 
-#define IOMD_IO0CURA	__IOMD(0x100)
-#define IOMD_IO0ENDA	__IOMD(0x104)
-#define IOMD_IO0CURB	__IOMD(0x108)
-#define IOMD_IO0ENDB	__IOMD(0x10C)
-#define IOMD_IO0CR	__IOMD(0x110)
-#define IOMD_IO0ST	__IOMD(0x114)
-
-#define IOMD_IO1CURA	__IOMD(0x120)
-#define IOMD_IO1ENDA	__IOMD(0x124)
-#define IOMD_IO1CURB	__IOMD(0x128)
-#define IOMD_IO1ENDB	__IOMD(0x12C)
-#define IOMD_IO1CR	__IOMD(0x130)
-#define IOMD_IO1ST	__IOMD(0x134)
-
-#define IOMD_IO2CURA	__IOMD(0x140)
-#define IOMD_IO2ENDA	__IOMD(0x144)
-#define IOMD_IO2CURB	__IOMD(0x148)
-#define IOMD_IO2ENDB	__IOMD(0x14C)
-#define IOMD_IO2CR	__IOMD(0x150)
-#define IOMD_IO2ST	__IOMD(0x154)
-
-#define IOMD_IO3CURA	__IOMD(0x160)
-#define IOMD_IO3ENDA	__IOMD(0x164)
-#define IOMD_IO3CURB	__IOMD(0x168)
-#define IOMD_IO3ENDB	__IOMD(0x16C)
-#define IOMD_IO3CR	__IOMD(0x170)
-#define IOMD_IO3ST	__IOMD(0x174)
-#endif
-
-#define IOMD_SD0CURA	__IOMD(0x180)
-#define IOMD_SD0ENDA	__IOMD(0x184)
-#define IOMD_SD0CURB	__IOMD(0x188)
-#define IOMD_SD0ENDB	__IOMD(0x18C)
-#define IOMD_SD0CR	__IOMD(0x190)
-#define IOMD_SD0ST	__IOMD(0x194)
-
-#ifdef CONFIG_ARCH_RPC
-#define IOMD_SD1CURA	__IOMD(0x1A0)
-#define IOMD_SD1ENDA	__IOMD(0x1A4)
-#define IOMD_SD1CURB	__IOMD(0x1A8)
-#define IOMD_SD1ENDB	__IOMD(0x1AC)
-#define IOMD_SD1CR	__IOMD(0x1B0)
-#define IOMD_SD1ST	__IOMD(0x1B4)
-#endif
-
-#define IOMD_CURSCUR	__IOMD(0x1C0)
-#define IOMD_CURSINIT	__IOMD(0x1C4)
-
-#define IOMD_VIDCUR	__IOMD(0x1D0)
-#define IOMD_VIDEND	__IOMD(0x1D4)
-#define IOMD_VIDSTART	__IOMD(0x1D8)
-#define IOMD_VIDINIT	__IOMD(0x1DC)
-#define IOMD_VIDCR	__IOMD(0x1E0)
-
-#define IOMD_DMASTAT	__IOMD(0x1F0)
-#define IOMD_DMAREQ	__IOMD(0x1F4)
-#define IOMD_DMAMASK	__IOMD(0x1F8)
+#define IOMD_IO0CURA	(0x100)
+#define IOMD_IO0ENDA	(0x104)
+#define IOMD_IO0CURB	(0x108)
+#define IOMD_IO0ENDB	(0x10C)
+#define IOMD_IO0CR	(0x110)
+#define IOMD_IO0ST	(0x114)
+
+#define IOMD_IO1CURA	(0x120)
+#define IOMD_IO1ENDA	(0x124)
+#define IOMD_IO1CURB	(0x128)
+#define IOMD_IO1ENDB	(0x12C)
+#define IOMD_IO1CR	(0x130)
+#define IOMD_IO1ST	(0x134)
+
+#define IOMD_IO2CURA	(0x140)
+#define IOMD_IO2ENDA	(0x144)
+#define IOMD_IO2CURB	(0x148)
+#define IOMD_IO2ENDB	(0x14C)
+#define IOMD_IO2CR	(0x150)
+#define IOMD_IO2ST	(0x154)
+
+#define IOMD_IO3CURA	(0x160)
+#define IOMD_IO3ENDA	(0x164)
+#define IOMD_IO3CURB	(0x168)
+#define IOMD_IO3ENDB	(0x16C)
+#define IOMD_IO3CR	(0x170)
+#define IOMD_IO3ST	(0x174)
+#endif
+
+#define IOMD_SD0CURA	(0x180)
+#define IOMD_SD0ENDA	(0x184)
+#define IOMD_SD0CURB	(0x188)
+#define IOMD_SD0ENDB	(0x18C)
+#define IOMD_SD0CR	(0x190)
+#define IOMD_SD0ST	(0x194)
+
+#ifdef CONFIG_ARCH_RPC
+#define IOMD_SD1CURA	(0x1A0)
+#define IOMD_SD1ENDA	(0x1A4)
+#define IOMD_SD1CURB	(0x1A8)
+#define IOMD_SD1ENDB	(0x1AC)
+#define IOMD_SD1CR	(0x1B0)
+#define IOMD_SD1ST	(0x1B4)
+#endif
+
+#define IOMD_CURSCUR	(0x1C0)
+#define IOMD_CURSINIT	(0x1C4)
+
+#define IOMD_VIDCUR	(0x1D0)
+#define IOMD_VIDEND	(0x1D4)
+#define IOMD_VIDSTART	(0x1D8)
+#define IOMD_VIDINIT	(0x1DC)
+#define IOMD_VIDCR	(0x1E0)
+
+#define IOMD_DMASTAT	(0x1F0)
+#define IOMD_DMAREQ	(0x1F4)
+#define IOMD_DMAMASK	(0x1F8)
 
 #define DMA_END_S	(1 << 31)
 #define DMA_END_L	(1 << 30)
@@ -192,39 +202,6 @@
 #define DMA_ST_INT	2
 #define DMA_ST_AB	1
 
-#ifndef IOC_CONTROL
-/*
- * IOC compatability
- */
-#define IOC_CONTROL	IOMD_CONTROL
-#define IOC_IRQSTATA	IOMD_IRQSTATA
-#define IOC_IRQREQA	IOMD_IRQREQA
-#define IOC_IRQCLRA	IOMD_IRQCLRA
-#define IOC_IRQMASKA	IOMD_IRQMASKA
-
-#define IOC_IRQSTATB	IOMD_IRQSTATB
-#define IOC_IRQREQB	IOMD_IRQREQB
-#define IOC_IRQMASKB	IOMD_IRQMASKB
-
-#define IOC_FIQSTAT	IOMD_FIQSTAT
-#define IOC_FIQREQ	IOMD_FIQREQ
-#define IOC_FIQMASK	IOMD_FIQMASK
-
-#define IOC_T0CNTL	IOMD_T0CNTL
-#define IOC_T0LTCHL	IOMD_T0LTCHL
-#define IOC_T0CNTH	IOMD_T0CNTH
-#define IOC_T0LTCHH	IOMD_T0LTCHH
-#define IOC_T0GO	IOMD_T0GO
-#define IOC_T0LATCH	IOMD_T0LATCH
-
-#define IOC_T1CNTL	IOMD_T1CNTL
-#define IOC_T1LTCHL	IOMD_T1LTCHL
-#define IOC_T1CNTH	IOMD_T1CNTH
-#define IOC_T1LTCHH	IOMD_T1LTCHH
-#define IOC_T1GO	IOMD_T1GO
-#define IOC_T1LATCH	IOMD_T1LATCH
-#endif
-
 /*
  * DMA (MEMC) compatability
  */
@@ -247,3 +224,4 @@
 } while (0)
 #endif
 
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.4.3/linux/include/asm-arm/io.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/io.h	Thu Apr 12 12:20:31 2001
@@ -104,11 +104,13 @@
 		_ret = __ioremap(iomem_to_phys(_off),_size,0);	\
 	_ret;							\
  })
+
+#define __arch_iounmap __iounmap
 #endif
 
 #define ioremap(off,sz)			__arch_ioremap((off),(sz),0)
 #define ioremap_nocache(off,sz)		__arch_ioremap((off),(sz),1)
-#define iounmap(_addr)			__iounmap(_addr)
+#define iounmap(_addr)			__arch_iounmap(_addr)
 
 /*
  * DMA-consistent mapping functions.  These allocate/free a region of
@@ -188,7 +190,7 @@
 	return retval;
 }
 
-#else	/* __mem_pci */
+#elif !defined(readb)
 
 #define readb(addr)			(__readwrite_bug("readb"),0)
 #define readw(addr)			(__readwrite_bug("readw"),0)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/mmzone.h linux/include/asm-arm/mmzone.h
--- v2.4.3/linux/include/asm-arm/mmzone.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/mmzone.h	Thu Apr 12 12:20:31 2001
@@ -10,6 +10,21 @@
 #ifndef __ASM_MMZONE_H
 #define __ASM_MMZONE_H
 
+/*
+ * Currently defined in arch/arm/mm/discontig.c
+ */
+extern pg_data_t discontig_node_data[];
+
+/*
+ * Return a pointer to the node data for node n.
+ */
+#define NODE_DATA(nid)		(&discontig_node_data[nid])
+
+/*
+ * NODE_MEM_MAP gives the kaddr for the mem_map of the node.
+ */
+#define NODE_MEM_MAP(nid)	(NODE_DATA(nid)->node_mem_map)
+
 #include <asm/arch/mmzone.h>
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/pgalloc.h linux/include/asm-arm/pgalloc.h
--- v2.4.3/linux/include/asm-arm/pgalloc.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/pgalloc.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/pgalloc.h
  *
- *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2000-2001 Russell King
  *
  * 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
@@ -25,6 +25,11 @@
 #define flush_tlb_pgtables(mm,start,end)	do { } while (0)
 
 /*
+ * Processor specific parts...
+ */
+#include <asm/proc/pgalloc.h>
+
+/*
  * Page table cache stuff
  */
 #ifndef CONFIG_NO_PGT_CACHE
@@ -68,20 +73,13 @@
 	pgtable_cache_size++;
 }
 
-/* We don't use pmd cache, so this is a dummy routine */
-#define get_pmd_fast()		((pmd_t *)0)
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
-}
-
-extern __inline__ pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
 	unsigned long *ret;
 
 	if((ret = pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)__pte_next(ret);
-		ret[0] = ret[1];
+		ret[0] = 0;
 		clean_dcache_entry(ret);
 		pgtable_cache_size--;
 	}
@@ -97,119 +95,47 @@
 
 #else	/* CONFIG_NO_PGT_CACHE */
 
-#define pgd_quicklist		((unsigned long *)0)
-#define pmd_quicklist		((unsigned long *)0)
-#define pte_quicklist		((unsigned long *)0)
+#define pgd_quicklist			((unsigned long *)0)
+#define pmd_quicklist			((unsigned long *)0)
+#define pte_quicklist			((unsigned long *)0)
 
-#define get_pgd_fast()		((pgd_t *)0)
-#define get_pmd_fast()		((pmd_t *)0)
-#define get_pte_fast()		((pte_t *)0)
-
-#define free_pgd_fast(pgd)	free_pgd_slow(pgd)
-#define free_pmd_fast(pmd)	free_pmd_slow(pmd)
-#define free_pte_fast(pte)	free_pte_slow(pte)
+#define get_pgd_fast()			((pgd_t *)0)
+#define pte_alloc_one_fast(mm,addr)	((pte_t *)0)
 
-#endif	/* CONFIG_NO_PGT_CACHE */
+#define free_pgd_fast(pgd)		free_pgd_slow(pgd)
+#define free_pte_fast(pte)		pte_free_slow(pte)
 
-extern pgd_t *get_pgd_slow(void);
-extern void free_pgd_slow(pgd_t *pgd);
+#endif	/* CONFIG_NO_PGT_CACHE */
 
-#define free_pmd_slow(pmd)	do { } while (0)
+#define pte_free(pte)			free_pte_fast(pte)
 
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long addr_preadjusted);
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long addr_preadjusted);
-extern void free_pte_slow(pte_t *pte);
 
 /*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
+ * Since we have only two-level page tables, these are trivial
  */
-#define pte_free_kernel(pte)	free_pte_fast(pte)
-#define pte_free(pte)		free_pte_fast(pte)
+#define pmd_alloc_one_fast(mm,addr)	({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm,addr)		({ BUG(); ((pmd_t *)2); })
+#define pmd_free_slow(pmd)		do { } while (0)
+#define pmd_free_fast(pmd)		do { } while (0)
+#define pmd_free(pmd)			do { } while (0)
+#define pgd_populate(mm,pmd,pte)	BUG()
 
-#ifndef pte_alloc_kernel
-extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_pte_fast();
-
-		if (!page)
-			return get_pte_kernel_slow(pmd, address);
-		set_pmd(pmd, mk_kernel_pmd(page));
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-#endif
-
-extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_pte_fast();
-
-		if (!page)
-			return get_pte_slow(pmd, address);
-		set_pmd(pmd, mk_user_pmd(page));
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-#define pmd_free_kernel		pmd_free
-#define pmd_free(pmd)		do { } while (0)
-
-#define pmd_alloc_kernel	pmd_alloc
-extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	return (pmd_t *) pgd;
-}
-
-#define pgd_free(pgd)		free_pgd_fast(pgd)
+extern pgd_t *get_pgd_slow(struct mm_struct *mm);
+extern void free_pgd_slow(pgd_t *pgd);
 
-extern __inline__ pgd_t *pgd_alloc(void)
+extern __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *pgd;
 
 	pgd = get_pgd_fast();
 	if (!pgd)
-		pgd = get_pgd_slow();
+		pgd = get_pgd_slow(mm);
 
 	return pgd;
 }
 
-extern int do_check_pgt_cache(int, int);
+#define pgd_free(pgd)			free_pgd_fast(pgd)
 
-extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
-{
-	struct task_struct * p;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-
-#ifndef CONFIG_NO_PGT_CACHE
-	{
-		pgd_t *pgd;
-		for (pgd = (pgd_t *)pgd_quicklist; pgd;
-		     pgd = (pgd_t *)__pgd_next(pgd))
-			pgd[address >> PGDIR_SHIFT] = entry;
-	}
-#endif
-}
+extern int do_check_pgt_cache(int, int);
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.4.3/linux/include/asm-arm/pgtable.h	Tue Mar  6 19:44:35 2001
+++ linux/include/asm-arm/pgtable.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/pgtable.h
  *
- *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2000-2001 Russell King
  *
  * 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
@@ -75,12 +75,6 @@
 extern struct page *empty_zero_page;
 #define ZERO_PAGE(vaddr)	(empty_zero_page)
 
-/*
- * Handling allocation failures during page table setup.
- */
-extern void __handle_bad_pmd(pmd_t *pmd);
-extern void __handle_bad_pmd_kernel(pmd_t *pmd);
-
 #define pte_none(pte)		(!pte_val(pte))
 #define pte_clear(ptep)		set_pte((ptep), __pte(0))
 
@@ -98,6 +92,7 @@
 #endif
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
+#define pmd_present(pmd)	(pmd_val(pmd))
 #define pmd_clear(pmdp)		set_pmd(pmdp, __pmd(0))
 
 /*
@@ -163,8 +158,6 @@
 }
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-#define update_mmu_cache(vma,address,pte) do { } while (0)
 
 /* Encode and decode a swap entry.
  *
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h
--- v2.4.3/linux/include/asm-arm/proc-armo/cache.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/proc-armo/cache.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/proc-armo/cache.h
  *
- *  Copyright (C) 1999-2000 Russell King
+ *  Copyright (C) 1999-2001 Russell King
  *
  * 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
@@ -37,8 +37,9 @@
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  */
 #define flush_tlb_all()				memc_update_all()
-#define flush_tlb_mm(mm)			do { } while (0)
-#define flush_tlb_range(mm, start, end)		do { (void)(start); (void)(end); } while (0)
+#define flush_tlb_mm(mm)			memc_update_mm(mm)
+#define flush_tlb_range(mm,start,end)		\
+		do { memc_update_mm(mm); (void)(start); (void)(end); } while (0)
 #define flush_tlb_page(vma, vmaddr)		do { } while (0)
 
 /*
@@ -57,7 +58,7 @@
 	processor._set_pgd(current->active_mm->pgd);
 }
 
-extern __inline__ void memc_update_mm(struct mm_struct *mm)
+static inline void memc_update_mm(struct mm_struct *mm)
 {
 	cpu_memc_update_all(mm->pgd);
 
@@ -66,19 +67,26 @@
 }
 
 extern __inline__ void
-memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr)
+memc_clear(struct mm_struct *mm, struct page *page)
 {
-	cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr);
+	cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0);
 
 	if (mm == current->active_mm)
 		processor._set_pgd(mm->pgd);
 }
 
-extern __inline__ void
-memc_clear(struct mm_struct *mm, struct page *page)
+static inline void
+memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr)
 {
-	cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0);
+	cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr);
 
 	if (mm == current->active_mm)
 		processor._set_pgd(mm->pgd);
+}
+
+static inline void
+update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	memc_update_addr(mm, pte, addr);
 }
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/pgalloc.h linux/include/asm-arm/proc-armo/pgalloc.h
--- v2.4.3/linux/include/asm-arm/proc-armo/pgalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armo/pgalloc.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,47 @@
+/*
+ *  linux/include/asm-arm/proc-armo/pgalloc.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * Page table allocation/freeing primitives for 26-bit ARM processors.
+ */
+
+/* unfortunately, this includes linux/mm.h and the rest of the universe. */
+#include <linux/slab.h>
+
+extern kmem_cache_t *pte_cache;
+
+/*
+ * Allocate one PTE table.
+ *
+ * Note that we keep the processor copy of the PTE entries separate
+ * from the Linux copy.  The processor copies are offset by -PTRS_PER_PTE
+ * words from the Linux copy.
+ */
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	return kmem_cache_alloc(pte_cache, GFP_KERNEL);
+}
+
+/*
+ * Free one PTE table.
+ */
+static inline void pte_free_slow(pte_t *pte)
+{
+	if (pte)
+		kmem_cache_free(pte_cache, pte);
+}
+
+/*
+ * Populate the pmdp entry with a pointer to the pte.  This pmd is part
+ * of the mm address space.
+ *
+ * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we
+ * need to set stuff up correctly for it.
+ */
+#define pmd_populate(mm,pmdp,pte)				\
+	do {							\
+		set_pmd(pmdp, __mk_pmd(pte, _PAGE_TABLE));	\
+	} while (0)
+
+
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.4.3/linux/include/asm-arm/proc-armo/pgtable.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/proc-armo/pgtable.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/proc-armo/pgtable.h
  *
- *  Copyright (C) 1995-1999 Russell King
+ *  Copyright (C) 1995-2001 Russell King
  *
  * 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
@@ -33,7 +33,7 @@
 #define pmd_bad(pmd)		((pmd_val(pmd) & 0xfc000002))
 #define set_pmd(pmdp,pmd)	((*(pmdp)) = (pmd))
 
-extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
+static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
 {
 	unsigned long pte_ptr = (unsigned long)ptep;
 	pmd_t pmd;
@@ -43,11 +43,7 @@
 	return pmd;
 }
 
-/* these are aliases for the above function */
-#define mk_user_pmd(ptep)	__mk_pmd(ptep, _PAGE_TABLE)
-#define mk_kernel_pmd(ptep)	__mk_pmd(ptep, _PAGE_TABLE)
-
-extern __inline__ unsigned long pmd_page(pmd_t pmd)
+static inline unsigned long pmd_page(pmd_t pmd)
 {
 	return __phys_to_virt(pmd_val(pmd) & ~_PAGE_TABLE);
 }
@@ -81,7 +77,6 @@
 #define pte_dirty(pte)			(!(pte_val(pte) & _PAGE_CLEAN))
 #define pte_young(pte)			(!(pte_val(pte) & _PAGE_OLD))
 
-extern inline pte_t pte_nocache(pte_t pte)	{ return pte; }
 extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) |= _PAGE_READONLY;  return pte; }
 extern inline pte_t pte_rdprotect(pte_t pte)    { pte_val(pte) |= _PAGE_NOT_USER;  return pte; }
 extern inline pte_t pte_exprotect(pte_t pte)    { pte_val(pte) |= _PAGE_NOT_USER;  return pte; }
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h
--- v2.4.3/linux/include/asm-arm/proc-armo/ptrace.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/proc-armo/ptrace.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/proc-armo/ptrace.h
  *
- *  Copyright (C) 1996-1999 Russell King
+ *  Copyright (C) 1996-2001 Russell King
  *
  * 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
@@ -14,6 +14,10 @@
 #define FIQ26_MODE	0x01
 #define IRQ26_MODE	0x02
 #define SVC26_MODE	0x03
+#define USR_MODE	USR26_MODE
+#define FIQ_MODE	FIQ26_MODE
+#define IRQ_MODE	IRQ26_MODE
+#define SVC_MODE	SVC26_MODE
 #define MODE_MASK	0x03
 #define F_BIT		(1 << 26)
 #define I_BIT		(1 << 27)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h
--- v2.4.3/linux/include/asm-arm/proc-armv/cache.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/proc-armv/cache.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/proc-armv/cache.h
  *
- *  Copyright (C) 1999-2000 Russell King
+ *  Copyright (C) 1999-2001 Russell King
  *
  * 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
@@ -154,3 +154,9 @@
 			cpu_tlb_invalidate_page((_page),		\
 				 ((_vma)->vm_flags & VM_EXEC));		\
 	} while (0)
+
+/*
+ * 32-bit ARM Processors don't have any MMU cache
+ */
+#define update_mmu_cache(vma,address,pte) do { } while (0)
+
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/pgalloc.h linux/include/asm-arm/proc-armv/pgalloc.h
--- v2.4.3/linux/include/asm-arm/proc-armv/pgalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armv/pgalloc.h	Thu Apr 12 12:20:31 2001
@@ -0,0 +1,58 @@
+/*
+ *  linux/include/asm-arm/proc-armv/pgalloc.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * Page table allocation/freeing primitives for 32-bit ARM processors.
+ */
+
+/* unfortunately, this includes linux/mm.h and the rest of the universe. */
+#include <linux/slab.h>
+
+extern kmem_cache_t *pte_cache;
+
+/*
+ * Allocate one PTE table.
+ *
+ * Note that we keep the processor copy of the PTE entries separate
+ * from the Linux copy.  The processor copies are offset by -PTRS_PER_PTE
+ * words from the Linux copy.
+ */
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte;
+
+	pte = kmem_cache_alloc(pte_cache, GFP_KERNEL);
+	if (pte)
+		pte += PTRS_PER_PTE;
+	return pte;
+}
+
+/*
+ * Free one PTE table.
+ */
+static inline void pte_free_slow(pte_t *pte)
+{
+	if (pte) {
+		pte -= PTRS_PER_PTE;
+		kmem_cache_free(pte_cache, pte);
+	}
+}
+
+/*
+ * Populate the pmdp entry with a pointer to the pte.  This pmd is part
+ * of the mm address space.
+ *
+ * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we
+ * need to set stuff up correctly for it.
+ */
+#define pmd_populate(mm,pmdp,pte)			\
+	do {						\
+		unsigned long __prot;			\
+		if (mm == &init_mm)			\
+			__prot = _PAGE_KERNEL_TABLE;	\
+		else					\
+			__prot = _PAGE_USER_TABLE;	\
+		set_pmd(pmdp, __mk_pmd(pte, __prot));	\
+	} while (0)
+
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.4.3/linux/include/asm-arm/proc-armv/pgtable.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/proc-armv/pgtable.h	Thu Apr 12 12:20:31 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/include/asm-arm/proc-armv/pgtable.h
  *
- *  Copyright (C) 1995-1999 Russell King
+ *  Copyright (C) 1995-2001 Russell King
  *
  * 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
@@ -48,7 +48,7 @@
 #define pmd_bad(pmd)		(pmd_val(pmd) & 2)
 #define set_pmd(pmdp,pmd)	cpu_set_pmd(pmdp,pmd)
 
-extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
+static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
 {
 	unsigned long pte_ptr = (unsigned long)ptep;
 	pmd_t pmd;
@@ -64,11 +64,7 @@
 	return pmd;
 }
 
-/* these are aliases for the above function */
-#define mk_user_pmd(ptep)	__mk_pmd(ptep, _PAGE_USER_TABLE)
-#define mk_kernel_pmd(ptep)	__mk_pmd(ptep, _PAGE_KERNEL_TABLE)
-
-extern __inline__ unsigned long pmd_page(pmd_t pmd)
+static inline unsigned long pmd_page(pmd_t pmd)
 {
 	unsigned long ptr;
 
@@ -161,7 +157,6 @@
 PTE_BIT_FUNC(mkdirty,   |= L_PTE_DIRTY);
 PTE_BIT_FUNC(mkold,     &= ~L_PTE_YOUNG);
 PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
-PTE_BIT_FUNC(nocache,   &= ~L_PTE_CACHEABLE);
 
 /*
  * Mark the prot value as uncacheable and unbufferable.
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h
--- v2.4.3/linux/include/asm-arm/proc-armv/uaccess.h	Tue Mar  6 19:44:35 2001
+++ linux/include/asm-arm/proc-armv/uaccess.h	Thu Apr 12 12:20:31 2001
@@ -91,7 +91,7 @@
 	"	.align	3\n"					\
 	"	.long	1b, 3b\n"				\
 	"	.previous"					\
-	: "=r" (err), "=r" (x)					\
+	: "=r" (err), "=&r" (x)					\
 	: "r" (addr), "i" (-EFAULT), "0" (err))
 
 #define __get_user_asm_half(x,addr,err)				\
@@ -117,7 +117,7 @@
 	"	.align	3\n"					\
 	"	.long	1b, 3b\n"				\
 	"	.previous"					\
-	: "=r" (err), "=r" (x)					\
+	: "=r" (err), "=&r" (x)					\
 	: "r" (addr), "i" (-EFAULT), "0" (err))
 
 extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n);
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.4.3/linux/include/asm-arm/processor.h	Sat Dec 30 09:35:40 2000
+++ linux/include/asm-arm/processor.h	Thu Apr 12 12:20:31 2001
@@ -38,6 +38,7 @@
 
 #define EISA_bus 0
 #define MCA_bus 0
+#define MCA_bus__is_a_macro
 
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/procinfo.h linux/include/asm-arm/procinfo.h
--- v2.4.3/linux/include/asm-arm/procinfo.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/procinfo.h	Thu Apr 12 12:20:31 2001
@@ -46,10 +46,13 @@
 
 #endif	/* __ASSEMBLY__ */
 
-#define HWCAP_SWP	1
-#define HWCAP_HALF	2
-#define HWCAP_THUMB	4
-#define HWCAP_26BIT	8	/* Play it safe */
+#define HWCAP_SWP	 1
+#define HWCAP_HALF	 2
+#define HWCAP_THUMB	 4
+#define HWCAP_26BIT	 8	/* Play it safe */
+#define HWCAP_FAST_MULT	 16
+#define HWCAP_FPA        32
+#define HWCAP_VFP        64
+#define HWCAP_EDSP	 128
 
 #endif
-
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.4.3/linux/include/asm-arm/semaphore.h	Sun Feb 13 10:47:01 2000
+++ linux/include/asm-arm/semaphore.h	Tue Apr 17 17:19:30 2001
@@ -7,6 +7,7 @@
 #include <linux/linkage.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 #include <asm/atomic.h>
 #include <asm/proc/locks.h>
@@ -122,135 +123,6 @@
 #endif
 
 	__up_op(sem, __up_wakeup);
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *              -ben
- */
-struct rw_semaphore {
-	atomic_t                count;
-	volatile unsigned char  write_bias_granted;
-	volatile unsigned char  read_bias_granted;
-	volatile unsigned char  pad1;
-	volatile unsigned char  pad2;
-	wait_queue_head_t       wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern struct rw_semaphore *__down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *__down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-	__down_op_read(sem, __down_read_failed);
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-	__down_op_write(sem, __down_write_failed);
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_op_read(sem, __rwsem_wake);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_op_write(sem, __rwsem_wake);
 }
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/setup.h linux/include/asm-arm/setup.h
--- v2.4.3/linux/include/asm-arm/setup.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/setup.h	Thu Apr 12 12:20:31 2001
@@ -207,7 +207,7 @@
 /*
  * Memory map description
  */
-#define NR_BANKS 4
+#define NR_BANKS 8
 
 struct meminfo {
 	int nr_banks;
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.4.3/linux/include/asm-arm/unistd.h	Tue Mar  6 19:44:35 2001
+++ linux/include/asm-arm/unistd.h	Thu Apr 12 12:20:31 2001
@@ -224,6 +224,10 @@
 #define __NR_setfsuid32			(__NR_SYSCALL_BASE+215)
 #define __NR_setfsgid32			(__NR_SYSCALL_BASE+216)
 #define __NR_getdents64			(__NR_SYSCALL_BASE+217)
+#define __NR_pivot_root			(__NR_SYSCALL_BASE+218)
+#define __NR_mincore			(__NR_SYSCALL_BASE+219)
+#define __NR_madvise			(__NR_SYSCALL_BASE+220)
+#define __NR_fcntl64			(__NR_SYSCALL_BASE+221)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/xor.h linux/include/asm-arm/xor.h
--- v2.4.3/linux/include/asm-arm/xor.h	Tue Mar  6 19:44:35 2001
+++ linux/include/asm-arm/xor.h	Thu Apr 12 12:20:31 2001
@@ -8,7 +8,289 @@
  * published by the Free Software Foundation.
  */
 
+/*
+ *  linux/include/asm-arm/xor.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * 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.
+ */
+
+/*
+ *  linux/include/asm-arm/xor.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * 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.
+ */
+
 #include <asm-generic/xor.h>
+
+#define __XOR(a1, a2) a1 ^= a2
+
+#define GET_BLOCK_2(dst) \
+	__asm__("ldmia	%0, {%1, %2}" \
+		: "=r" (dst), "=r" (a1), "=r" (a2) \
+		: "0" (dst))
+
+#define GET_BLOCK_4(dst) \
+	__asm__("ldmia	%0, {%1, %2, %3, %4}" \
+		: "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
+		: "0" (dst))
+
+#define XOR_BLOCK_2(src) \
+	__asm__("ldmia	%0!, {%1, %2}" \
+		: "=r" (src), "=r" (b1), "=r" (b2) \
+		: "0" (src)); \
+	__XOR(a1, b1); __XOR(a2, b2);
+
+#define XOR_BLOCK_4(src) \
+	__asm__("ldmia	%0!, {%1, %2, %3, %4}" \
+		: "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
+		: "0" (src)); \
+	__XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
+
+#define PUT_BLOCK_2(dst) \
+	__asm__ __volatile__("stmia	%0!, {%2, %3}" \
+		: "=r" (dst) \
+		: "0" (dst), "r" (a1), "r" (a2))
+
+#define PUT_BLOCK_4(dst) \
+	__asm__ __volatile__("stmia	%0!, {%2, %3, %4, %5}" \
+		: "=r" (dst) \
+		: "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
+
+static void
+xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 4;
+	register unsigned int a1 __asm__("r4");
+	register unsigned int a2 __asm__("r5");
+	register unsigned int a3 __asm__("r6");
+	register unsigned int a4 __asm__("r7");
+	register unsigned int b1 __asm__("r8");
+	register unsigned int b2 __asm__("r9");
+	register unsigned int b3 __asm__("ip");
+	register unsigned int b4 __asm__("lr");
+
+	do {
+		GET_BLOCK_4(p1);
+		XOR_BLOCK_4(p2);
+		PUT_BLOCK_4(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 4;
+	register unsigned int a1 __asm__("r4");
+	register unsigned int a2 __asm__("r5");
+	register unsigned int a3 __asm__("r6");
+	register unsigned int a4 __asm__("r7");
+	register unsigned int b1 __asm__("r8");
+	register unsigned int b2 __asm__("r9");
+	register unsigned int b3 __asm__("ip");
+	register unsigned int b4 __asm__("lr");
+
+	do {
+		GET_BLOCK_4(p1);
+		XOR_BLOCK_4(p2);
+		XOR_BLOCK_4(p3);
+		PUT_BLOCK_4(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3, unsigned long *p4)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 2;
+	register unsigned int a1 __asm__("r8");
+	register unsigned int a2 __asm__("r9");
+	register unsigned int b1 __asm__("ip");
+	register unsigned int b2 __asm__("lr");
+
+	do {
+		GET_BLOCK_2(p1);
+		XOR_BLOCK_2(p2);
+		XOR_BLOCK_2(p3);
+		XOR_BLOCK_2(p4);
+		PUT_BLOCK_2(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 2;
+	register unsigned int a1 __asm__("r8");
+	register unsigned int a2 __asm__("r9");
+	register unsigned int b1 __asm__("ip");
+	register unsigned int b2 __asm__("lr");
+
+	do {
+		GET_BLOCK_2(p1);
+		XOR_BLOCK_2(p2);
+		XOR_BLOCK_2(p3);
+		XOR_BLOCK_2(p4);
+		XOR_BLOCK_2(p5);
+		PUT_BLOCK_2(p1);
+	} while (--lines);
+}
+
+static struct xor_block_template xor_block_arm4regs = {
+	name:	"arm4regs",
+	do_2:	xor_arm4regs_2,
+	do_3:	xor_arm4regs_3,
+	do_4:	xor_arm4regs_4,
+	do_5:	xor_arm4regs_5,
+};
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES			\
+	do {					\
+		xor_speed(&xor_block_arm4regs);	\
+		xor_speed(&xor_block_8regs);	\
+		xor_speed(&xor_block_32regs);	\
+	} while (0)
+
+#define __XOR(a1, a2) a1 ^= a2
+
+#define GET_BLOCK_2(dst) \
+	__asm__("ldmia	%0, {%1, %2}" \
+		: "=r" (dst), "=r" (a1), "=r" (a2) \
+		: "0" (dst))
+
+#define GET_BLOCK_4(dst) \
+	__asm__("ldmia	%0, {%1, %2, %3, %4}" \
+		: "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
+		: "0" (dst))
+
+#define XOR_BLOCK_2(src) \
+	__asm__("ldmia	%0!, {%1, %2}" \
+		: "=r" (src), "=r" (b1), "=r" (b2) \
+		: "0" (src)); \
+	__XOR(a1, b1); __XOR(a2, b2);
+
+#define XOR_BLOCK_4(src) \
+	__asm__("ldmia	%0!, {%1, %2, %3, %4}" \
+		: "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
+		: "0" (src)); \
+	__XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
+
+#define PUT_BLOCK_2(dst) \
+	__asm__ __volatile__("stmia	%0!, {%2, %3}" \
+		: "=r" (dst) \
+		: "0" (dst), "r" (a1), "r" (a2))
+
+#define PUT_BLOCK_4(dst) \
+	__asm__ __volatile__("stmia	%0!, {%2, %3, %4, %5}" \
+		: "=r" (dst) \
+		: "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
+
+static void
+xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 4;
+	register unsigned int a1 __asm__("r4");
+	register unsigned int a2 __asm__("r5");
+	register unsigned int a3 __asm__("r6");
+	register unsigned int a4 __asm__("r7");
+	register unsigned int b1 __asm__("r8");
+	register unsigned int b2 __asm__("r9");
+	register unsigned int b3 __asm__("ip");
+	register unsigned int b4 __asm__("lr");
+
+	do {
+		GET_BLOCK_4(p1);
+		XOR_BLOCK_4(p2);
+		PUT_BLOCK_4(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 4;
+	register unsigned int a1 __asm__("r4");
+	register unsigned int a2 __asm__("r5");
+	register unsigned int a3 __asm__("r6");
+	register unsigned int a4 __asm__("r7");
+	register unsigned int b1 __asm__("r8");
+	register unsigned int b2 __asm__("r9");
+	register unsigned int b3 __asm__("ip");
+	register unsigned int b4 __asm__("lr");
+
+	do {
+		GET_BLOCK_4(p1);
+		XOR_BLOCK_4(p2);
+		XOR_BLOCK_4(p3);
+		PUT_BLOCK_4(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3, unsigned long *p4)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 2;
+	register unsigned int a1 __asm__("r8");
+	register unsigned int a2 __asm__("r9");
+	register unsigned int b1 __asm__("ip");
+	register unsigned int b2 __asm__("lr");
+
+	do {
+		GET_BLOCK_2(p1);
+		XOR_BLOCK_2(p2);
+		XOR_BLOCK_2(p3);
+		XOR_BLOCK_2(p4);
+		PUT_BLOCK_2(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 2;
+	register unsigned int a1 __asm__("r8");
+	register unsigned int a2 __asm__("r9");
+	register unsigned int b1 __asm__("ip");
+	register unsigned int b2 __asm__("lr");
+
+	do {
+		GET_BLOCK_2(p1);
+		XOR_BLOCK_2(p2);
+		XOR_BLOCK_2(p3);
+		XOR_BLOCK_2(p4);
+		XOR_BLOCK_2(p5);
+		PUT_BLOCK_2(p1);
+	} while (--lines);
+}
+
+static struct xor_block_template xor_block_arm4regs = {
+	name:	"arm4regs",
+	do_2:	xor_arm4regs_2,
+	do_3:	xor_arm4regs_3,
+	do_4:	xor_arm4regs_4,
+	do_5:	xor_arm4regs_5,
+};
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES			\
+	do {					\
+		xor_speed(&xor_block_arm4regs);	\
+		xor_speed(&xor_block_8regs);	\
+		xor_speed(&xor_block_32regs);	\
+	} while (0)
 
 #define __XOR(a1, a2) a1 ^= a2
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/bitops.h linux/include/asm-cris/bitops.h
--- v2.4.3/linux/include/asm-cris/bitops.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/bitops.h	Fri Apr  6 10:51:19 2001
@@ -1,9 +1,12 @@
-/* $Id: bitops.h,v 1.3 2000/10/17 14:56:27 bjornw Exp $ */
+/* $Id: bitops.h,v 1.4 2001/02/28 04:26:11 hp Exp $ */
 /* all of these should probably be rewritten in assembler for speed. */
 
 #ifndef _CRIS_BITOPS_H
 #define _CRIS_BITOPS_H
 
+/* Currently this is unsuitable for consumption outside the kernel.  */
+#ifdef __KERNEL__ 
+
 #include <asm/system.h>
 
 /*
@@ -163,8 +166,6 @@
 
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
-
-#ifdef __KERNEL__ 
 
 #define ext2_set_bit                 test_and_set_bit
 #define ext2_clear_bit               test_and_clear_bit
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/delay.h linux/include/asm-cris/delay.h
--- v2.4.3/linux/include/asm-cris/delay.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/delay.h	Fri Apr  6 10:51:19 2001
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.2 2000/08/08 16:36:41 bjornw Exp $ */
+/* $Id: delay.h,v 1.3 2001/02/23 13:47:33 bjornw Exp $ */
 
 #ifndef _CRIS_DELAY_H
 #define _CRIS_DELAY_H
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/eshlibld.h linux/include/asm-cris/eshlibld.h
--- v2.4.3/linux/include/asm-cris/eshlibld.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/eshlibld.h	Fri Apr  6 10:51:19 2001
@@ -12,7 +12,7 @@
 *! (C) Copyright 1998, 1999 Axis Communications AB, LUND, SWEDEN
 *!
 *!**************************************************************************/
-/* $Id: eshlibld.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: eshlibld.h,v 1.2 2001/02/23 13:47:33 bjornw Exp $ */
 
 #ifndef _cris_relocate_h
 #define _cris_relocate_h
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h
--- v2.4.3/linux/include/asm-cris/etraxgpio.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-cris/etraxgpio.h	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,32 @@
+#ifndef _ASM_ETRAXGPIO_H
+#define _ASM_ETRAXGPIO_H
+
+/* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */
+
+#define ETRAXGPIO_IOCTYPE 43
+
+/* supported ioctl _IOC_NR's */
+
+#define IO_READBITS  0x1  /* read and return current port bits */
+#define IO_SETBITS   0x2  /* set the bits marked by 1 in the argument */
+#define IO_CLRBITS   0x3  /* clear the bits marked by 1 in the argument */
+
+/* the alarm is waited for by select() */
+
+#define IO_HIGHALARM 0x4  /* set alarm on high for bits marked by 1 */
+#define IO_LOWALARM  0x5  /* set alarm on low for bits marked by 1 */
+#define IO_CLRALARM  0x6  /* clear alarm for bits marked by 1 */
+
+/* LED ioctl */
+#define IO_LEDACTIVE_SET 0x7 /* set active led
+                              * 0=off, 1=green, 2=red, 3=yellow */
+
+/* GPIO direction ioctl's */
+#define IO_READDIR    0x8  /* Read direction 0=input 1=output */
+#define IO_SETINPUT   0x9  /* Set direction 0=unchanged 1=input, 
+                              returns current dir */
+#define IO_SETOUTPUT  0xA  /* Set direction 0=unchanged 1=output,
+                              returns current dir */
+
+#endif
+
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/etraxi2c.h linux/include/asm-cris/etraxi2c.h
--- v2.4.3/linux/include/asm-cris/etraxi2c.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-cris/etraxi2c.h	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,36 @@
+/* $Id: etraxi2c.h,v 1.1 2001/01/18 15:49:57 bjornw Exp $ */
+
+#ifndef _LINUX_ETRAXI2C_H
+#define _LINUX_ETRAXI2C_H
+
+/* etraxi2c _IOC_TYPE, bits 8 to 15 in ioctl cmd */
+
+#define ETRAXI2C_IOCTYPE 44
+
+/* supported ioctl _IOC_NR's */
+
+/* in write operations, the argument contains both i2c
+ * slave, register and value.
+ */
+
+#define I2C_WRITEARG(slave, reg, value) (((slave) << 16) | ((reg) << 8) | (value))
+#define I2C_READARG(slave, reg) (((slave) << 16) | ((reg) << 8))
+
+#define I2C_ARGSLAVE(arg) ((arg) >> 16)
+#define I2C_ARGREG(arg) (((arg) >> 8) & 0xff)
+#define I2C_ARGVALUE(arg) ((arg) & 0xff)
+
+#define I2C_WRITEREG 0x1   /* write to an i2c register */
+#define I2C_READREG  0x2   /* read from an i2c register */
+
+/*
+EXAMPLE usage:
+
+    i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val);
+    ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg);
+
+    i2c_arg = I2C_READARG(STA013_READ_ADDR, reg);
+    val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
+
+*/
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/io.h linux/include/asm-cris/io.h
--- v2.4.3/linux/include/asm-cris/io.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/io.h	Fri Apr  6 10:51:19 2001
@@ -9,9 +9,9 @@
    use will be evident. */
 #ifdef CONFIG_SVINTO_SIM
   /* Let's use the ucsim interface since it lets us do write(2, ...) */
-#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
+#define SIMCOUT(s,len) asm ("moveq 4,r9\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
 \n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \
-       : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory")
+       : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory")
 #define TRACE_ON() __extension__ \
  ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \
 			       (255)); _Foofoo; })
@@ -127,6 +127,13 @@
 static inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
+}
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+extern inline void * ioremap (unsigned long offset, unsigned long size)
+{
+	return __ioremap(offset, size, 0);
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h
--- v2.4.3/linux/include/asm-cris/irq.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/irq.h	Fri Apr  6 10:51:19 2001
@@ -19,7 +19,7 @@
 
 #include <asm/sv_addr_ag.h>
 
-#define NR_IRQS 26     /* TODO: what is this for Etrax100/LX ? */
+#define NR_IRQS 32
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/pgalloc.h linux/include/asm-cris/pgalloc.h
--- v2.4.3/linux/include/asm-cris/pgalloc.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -191,7 +191,7 @@
 /* pgd handling */
 
 #define pgd_free(pgd)      free_pgd_slow(pgd)
-#define pgd_alloc()        get_pgd_fast()
+#define pgd_alloc(mm)      get_pgd_fast()
 
 /* other stuff */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/processor.h linux/include/asm-cris/processor.h
--- v2.4.3/linux/include/asm-cris/processor.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/processor.h	Fri Apr  6 10:51:19 2001
@@ -1,7 +1,7 @@
 /*
  * include/asm-cris/processor.h
  *
- * Copyright (C) 2000 Axis Communications AB
+ * Copyright (C) 2000, 2001 Axis Communications AB
  *
  * Authors:         Bjorn Wesen        Initial version
  *
@@ -57,9 +57,6 @@
 /* saved stack-frame upon syscall entry, points to registers */
 
 #define current_regs() (current->thread.esp0)
-
-/* this lives in process.c */
-asmlinkage void set_esp0(unsigned long ssp);
 
 /* INIT_MMAP is the kernels map of memory, between KSEG_C and KSEG_D */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h
--- v2.4.3/linux/include/asm-cris/ptrace.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/ptrace.h	Fri Apr  6 10:51:19 2001
@@ -23,9 +23,8 @@
 #define PT_DCCR      17
 #define PT_SRP       18
 #define PT_IRP       19
-#define PT_MAX       19
-
-#define PT_USP       42    /* special case - USP is not in the pt_regs */
+#define PT_USP       20    /* special case - USP is not in the pt_regs */
+#define PT_MAX       20
 
 /* Frame types */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/semaphore.h linux/include/asm-cris/semaphore.h
--- v2.4.3/linux/include/asm-cris/semaphore.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/semaphore.h	Tue Apr 17 17:19:30 2001
@@ -9,6 +9,7 @@
 
 #include <linux/wait.h>
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -155,167 +156,6 @@
 	if(wakeup) {
 		__up(sem);
 	}
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *              -ben
- */
-
-struct rw_semaphore {
-        atomic_t                count;
-	/* bit 0 means read bias granted;
-	   bit 1 means write bias granted.  */
-        unsigned granted;
-        wait_queue_head_t       wait;
-        wait_queue_head_t       write_bias_wait;
-#if WAITQUEUE_DEBUG
-        long                    __magic;
-        atomic_t                readers;
-        atomic_t                writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT      , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT      /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-        __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-        __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-        struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-        atomic_set(&sem->count, RW_LOCK_BIAS);
-        sem->granted = 0;
-        init_waitqueue_head(&sem->wait);
-        init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-        sem->__magic = (long)&sem->__magic;
-        atomic_set(&sem->readers, 0);
-        atomic_set(&sem->writers, 0);
-#endif
-}
-
-/* The expensive part is outlined.  */
-extern void __down_read(struct rw_semaphore *sem, int count);
-extern void __down_write(struct rw_semaphore *sem, int count);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-        int count;
-
-#if WAITQUEUE_DEBUG
-        CHECK_MAGIC(sem->__magic);
-#endif
-
-        count = atomic_dec_return(&sem->count);
-        if (count < 0) {
-                __down_read(sem, count);
-        }
-        mb();
-
-#if WAITQUEUE_DEBUG
-        if (sem->granted & 2)
-                BUG();
-        if (atomic_read(&sem->writers))
-                BUG();
-        atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-        int count;
-
-#if WAITQUEUE_DEBUG
-        CHECK_MAGIC(sem->__magic);
-#endif
-
-        count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-        if (count) {
-                __down_write(sem, count);
-        }
-        mb();
-
-#if WAITQUEUE_DEBUG
-        if (atomic_read(&sem->writers))
-                BUG();
-        if (atomic_read(&sem->readers))
-                BUG();
-        if (sem->granted & 3)
-                BUG();
-        atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant case is when
-   there was a writer waiting, and we've bumped the count to 0: we must
-   wake the writer up.  */
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-        CHECK_MAGIC(sem->__magic);
-        if (sem->granted & 2)
-                BUG();
-        if (atomic_read(&sem->writers))
-                BUG();
-        atomic_dec(&sem->readers);
-#endif
-
-        mb();
-        if (atomic_inc_return(&sem->count) == 0)
-                __rwsem_wake(sem, 0);
-}
-
-/*
- * Releasing the writer is easy -- just release it and wake up any sleepers.
- */
-extern inline void up_write(struct rw_semaphore *sem)
-{
-        int count;
-
-#if WAITQUEUE_DEBUG
-        CHECK_MAGIC(sem->__magic);
-        if (sem->granted & 3)
-                BUG();
-        if (atomic_read(&sem->readers))
-                BUG();
-        if (atomic_read(&sem->writers) != 1)
-                BUG();
-        atomic_dec(&sem->writers);
-#endif
-
-        mb();
-        count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-        if (count - RW_LOCK_BIAS < 0 && count >= 0) {
-                /* Only do the wake if we're no longer negative.  */
-                __rwsem_wake(sem, count);
-        }
 }
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/socket.h linux/include/asm-cris/socket.h
--- v2.4.3/linux/include/asm-cris/socket.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/socket.h	Fri Apr  6 10:51:19 2001
@@ -45,6 +45,8 @@
 #define SO_TIMESTAMP           29
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 
+#define SO_ACCEPTCONN          30
+
 #if defined(__KERNEL__)
 /* Socket types. */
 #define SOCK_STREAM     1               /* stream (connection) socket   */
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/sv_addr.agh linux/include/asm-cris/sv_addr.agh
--- v2.4.3/linux/include/asm-cris/sv_addr.agh	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/sv_addr.agh	Fri Apr  6 10:51:19 2001
@@ -1,8 +1,8 @@
 /*
 !* This file was automatically generated by /n/asic/bin/reg_macro_gen
-!* from the file `etrax_ng_regs.rd'.
+!* from the file `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd'.
 !* Editing within this file is thus not recommended,
-!* make the changes in `etrax_ng_regs.rd' instead.
+!* make the changes in `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd' instead.
 !*/
 
 
@@ -103,6 +103,10 @@
 #define R_BUS_STATUS__flashw__bw16 0
 
 #define R_DRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008)
+#define R_DRAM_TIMING__sdram__BITNR 31
+#define R_DRAM_TIMING__sdram__WIDTH 1
+#define R_DRAM_TIMING__sdram__enable 1
+#define R_DRAM_TIMING__sdram__disable 0
 #define R_DRAM_TIMING__ref__BITNR 14
 #define R_DRAM_TIMING__ref__WIDTH 2
 #define R_DRAM_TIMING__ref__e52us 0
@@ -683,10 +687,6 @@
 #define R_GEN_CONFIG__usb1__WIDTH 1
 #define R_GEN_CONFIG__usb1__select 1
 #define R_GEN_CONFIG__usb1__disable 0
-#define R_GEN_CONFIG__p21__BITNR 28
-#define R_GEN_CONFIG__p21__WIDTH 1
-#define R_GEN_CONFIG__p21__select 1
-#define R_GEN_CONFIG__p21__disable 0
 #define R_GEN_CONFIG__g24dir__BITNR 27
 #define R_GEN_CONFIG__g24dir__WIDTH 1
 #define R_GEN_CONFIG__g24dir__in 0
@@ -2331,6 +2331,10 @@
 #define R_NETWORK_GA_1__ga_high__WIDTH 32
 
 #define R_NETWORK_REC_CONFIG (IO_TYPECAST_UDWORD 0xb0000094)
+#define R_NETWORK_REC_CONFIG__max_size__BITNR 10
+#define R_NETWORK_REC_CONFIG__max_size__WIDTH 1
+#define R_NETWORK_REC_CONFIG__max_size__size1518 0
+#define R_NETWORK_REC_CONFIG__max_size__size1522 1
 #define R_NETWORK_REC_CONFIG__duplex__BITNR 9
 #define R_NETWORK_REC_CONFIG__duplex__WIDTH 1
 #define R_NETWORK_REC_CONFIG__duplex__full 1
@@ -2535,6 +2539,10 @@
 #define R_PAR0_STATUS_DATA__mode__ecp_fwd 5
 #define R_PAR0_STATUS_DATA__mode__ecp_rev 6
 #define R_PAR0_STATUS_DATA__mode__off 7
+#define R_PAR0_STATUS_DATA__mode__epp_wr1 5
+#define R_PAR0_STATUS_DATA__mode__epp_wr2 6
+#define R_PAR0_STATUS_DATA__mode__epp_wr3 7
+#define R_PAR0_STATUS_DATA__mode__epp_rd 0
 #define R_PAR0_STATUS_DATA__perr__BITNR 28
 #define R_PAR0_STATUS_DATA__perr__WIDTH 1
 #define R_PAR0_STATUS_DATA__perr__active 1
@@ -2555,6 +2563,14 @@
 #define R_PAR0_STATUS_DATA__sel__WIDTH 1
 #define R_PAR0_STATUS_DATA__sel__active 1
 #define R_PAR0_STATUS_DATA__sel__inactive 0
+#define R_PAR0_STATUS_DATA__ext_mode__BITNR 23
+#define R_PAR0_STATUS_DATA__ext_mode__WIDTH 1
+#define R_PAR0_STATUS_DATA__ext_mode__enable 1
+#define R_PAR0_STATUS_DATA__ext_mode__disable 0
+#define R_PAR0_STATUS_DATA__ecp_16__BITNR 22
+#define R_PAR0_STATUS_DATA__ecp_16__WIDTH 1
+#define R_PAR0_STATUS_DATA__ecp_16__active 1
+#define R_PAR0_STATUS_DATA__ecp_16__inactive 0
 #define R_PAR0_STATUS_DATA__tr_rdy__BITNR 17
 #define R_PAR0_STATUS_DATA__tr_rdy__WIDTH 1
 #define R_PAR0_STATUS_DATA__tr_rdy__ready 1
@@ -2570,7 +2586,59 @@
 #define R_PAR0_STATUS_DATA__data__BITNR 0
 #define R_PAR0_STATUS_DATA__data__WIDTH 8
 
-#define R_PAR_ECP16_DATA (IO_TYPECAST_RO_UWORD 0xb0000040)
+#define R_PAR0_STATUS (IO_TYPECAST_RO_UWORD 0xb0000042)
+#define R_PAR0_STATUS__mode__BITNR 13
+#define R_PAR0_STATUS__mode__WIDTH 3
+#define R_PAR0_STATUS__mode__manual 0
+#define R_PAR0_STATUS__mode__centronics 1
+#define R_PAR0_STATUS__mode__fastbyte 2
+#define R_PAR0_STATUS__mode__nibble 3
+#define R_PAR0_STATUS__mode__byte 4
+#define R_PAR0_STATUS__mode__ecp_fwd 5
+#define R_PAR0_STATUS__mode__ecp_rev 6
+#define R_PAR0_STATUS__mode__off 7
+#define R_PAR0_STATUS__mode__epp_wr1 5
+#define R_PAR0_STATUS__mode__epp_wr2 6
+#define R_PAR0_STATUS__mode__epp_wr3 7
+#define R_PAR0_STATUS__mode__epp_rd 0
+#define R_PAR0_STATUS__perr__BITNR 12
+#define R_PAR0_STATUS__perr__WIDTH 1
+#define R_PAR0_STATUS__perr__active 1
+#define R_PAR0_STATUS__perr__inactive 0
+#define R_PAR0_STATUS__ack__BITNR 11
+#define R_PAR0_STATUS__ack__WIDTH 1
+#define R_PAR0_STATUS__ack__active 0
+#define R_PAR0_STATUS__ack__inactive 1
+#define R_PAR0_STATUS__busy__BITNR 10
+#define R_PAR0_STATUS__busy__WIDTH 1
+#define R_PAR0_STATUS__busy__active 1
+#define R_PAR0_STATUS__busy__inactive 0
+#define R_PAR0_STATUS__fault__BITNR 9
+#define R_PAR0_STATUS__fault__WIDTH 1
+#define R_PAR0_STATUS__fault__active 0
+#define R_PAR0_STATUS__fault__inactive 1
+#define R_PAR0_STATUS__sel__BITNR 8
+#define R_PAR0_STATUS__sel__WIDTH 1
+#define R_PAR0_STATUS__sel__active 1
+#define R_PAR0_STATUS__sel__inactive 0
+#define R_PAR0_STATUS__ext_mode__BITNR 7
+#define R_PAR0_STATUS__ext_mode__WIDTH 1
+#define R_PAR0_STATUS__ext_mode__enable 1
+#define R_PAR0_STATUS__ext_mode__disable 0
+#define R_PAR0_STATUS__ecp_16__BITNR 6
+#define R_PAR0_STATUS__ecp_16__WIDTH 1
+#define R_PAR0_STATUS__ecp_16__active 1
+#define R_PAR0_STATUS__ecp_16__inactive 0
+#define R_PAR0_STATUS__tr_rdy__BITNR 1
+#define R_PAR0_STATUS__tr_rdy__WIDTH 1
+#define R_PAR0_STATUS__tr_rdy__ready 1
+#define R_PAR0_STATUS__tr_rdy__busy 0
+#define R_PAR0_STATUS__dav__BITNR 0
+#define R_PAR0_STATUS__dav__WIDTH 1
+#define R_PAR0_STATUS__dav__data 1
+#define R_PAR0_STATUS__dav__nodata 0
+
+#define R_PAR_ECP16_DATA (IO_TYPECAST_UWORD 0xb0000040)
 #define R_PAR_ECP16_DATA__data__BITNR 0
 #define R_PAR_ECP16_DATA__data__WIDTH 16
 
@@ -2669,6 +2737,10 @@
 #define R_PAR0_CONFIG__mode__ecp_fwd 5
 #define R_PAR0_CONFIG__mode__ecp_rev 6
 #define R_PAR0_CONFIG__mode__off 7
+#define R_PAR0_CONFIG__mode__epp_wr1 5
+#define R_PAR0_CONFIG__mode__epp_wr2 6
+#define R_PAR0_CONFIG__mode__epp_wr3 7
+#define R_PAR0_CONFIG__mode__epp_rd 0
 
 #define R_PAR0_DELAY (IO_TYPECAST_UDWORD 0xb0000048)
 #define R_PAR0_DELAY__fine_hold__BITNR 21
@@ -2731,6 +2803,10 @@
 #define R_PAR1_STATUS_DATA__mode__ecp_fwd 5
 #define R_PAR1_STATUS_DATA__mode__ecp_rev 6
 #define R_PAR1_STATUS_DATA__mode__off 7
+#define R_PAR1_STATUS_DATA__mode__epp_wr1 5
+#define R_PAR1_STATUS_DATA__mode__epp_wr2 6
+#define R_PAR1_STATUS_DATA__mode__epp_wr3 7
+#define R_PAR1_STATUS_DATA__mode__epp_rd 0
 #define R_PAR1_STATUS_DATA__perr__BITNR 28
 #define R_PAR1_STATUS_DATA__perr__WIDTH 1
 #define R_PAR1_STATUS_DATA__perr__active 1
@@ -2751,6 +2827,10 @@
 #define R_PAR1_STATUS_DATA__sel__WIDTH 1
 #define R_PAR1_STATUS_DATA__sel__active 1
 #define R_PAR1_STATUS_DATA__sel__inactive 0
+#define R_PAR1_STATUS_DATA__ext_mode__BITNR 23
+#define R_PAR1_STATUS_DATA__ext_mode__WIDTH 1
+#define R_PAR1_STATUS_DATA__ext_mode__enable 1
+#define R_PAR1_STATUS_DATA__ext_mode__disable 0
 #define R_PAR1_STATUS_DATA__tr_rdy__BITNR 17
 #define R_PAR1_STATUS_DATA__tr_rdy__WIDTH 1
 #define R_PAR1_STATUS_DATA__tr_rdy__ready 1
@@ -2766,6 +2846,54 @@
 #define R_PAR1_STATUS_DATA__data__BITNR 0
 #define R_PAR1_STATUS_DATA__data__WIDTH 8
 
+#define R_PAR1_STATUS (IO_TYPECAST_RO_UWORD 0xb0000052)
+#define R_PAR1_STATUS__mode__BITNR 13
+#define R_PAR1_STATUS__mode__WIDTH 3
+#define R_PAR1_STATUS__mode__manual 0
+#define R_PAR1_STATUS__mode__centronics 1
+#define R_PAR1_STATUS__mode__fastbyte 2
+#define R_PAR1_STATUS__mode__nibble 3
+#define R_PAR1_STATUS__mode__byte 4
+#define R_PAR1_STATUS__mode__ecp_fwd 5
+#define R_PAR1_STATUS__mode__ecp_rev 6
+#define R_PAR1_STATUS__mode__off 7
+#define R_PAR1_STATUS__mode__epp_wr1 5
+#define R_PAR1_STATUS__mode__epp_wr2 6
+#define R_PAR1_STATUS__mode__epp_wr3 7
+#define R_PAR1_STATUS__mode__epp_rd 0
+#define R_PAR1_STATUS__perr__BITNR 12
+#define R_PAR1_STATUS__perr__WIDTH 1
+#define R_PAR1_STATUS__perr__active 1
+#define R_PAR1_STATUS__perr__inactive 0
+#define R_PAR1_STATUS__ack__BITNR 11
+#define R_PAR1_STATUS__ack__WIDTH 1
+#define R_PAR1_STATUS__ack__active 0
+#define R_PAR1_STATUS__ack__inactive 1
+#define R_PAR1_STATUS__busy__BITNR 10
+#define R_PAR1_STATUS__busy__WIDTH 1
+#define R_PAR1_STATUS__busy__active 1
+#define R_PAR1_STATUS__busy__inactive 0
+#define R_PAR1_STATUS__fault__BITNR 9
+#define R_PAR1_STATUS__fault__WIDTH 1
+#define R_PAR1_STATUS__fault__active 0
+#define R_PAR1_STATUS__fault__inactive 1
+#define R_PAR1_STATUS__sel__BITNR 8
+#define R_PAR1_STATUS__sel__WIDTH 1
+#define R_PAR1_STATUS__sel__active 1
+#define R_PAR1_STATUS__sel__inactive 0
+#define R_PAR1_STATUS__ext_mode__BITNR 7
+#define R_PAR1_STATUS__ext_mode__WIDTH 1
+#define R_PAR1_STATUS__ext_mode__enable 1
+#define R_PAR1_STATUS__ext_mode__disable 0
+#define R_PAR1_STATUS__tr_rdy__BITNR 1
+#define R_PAR1_STATUS__tr_rdy__WIDTH 1
+#define R_PAR1_STATUS__tr_rdy__ready 1
+#define R_PAR1_STATUS__tr_rdy__busy 0
+#define R_PAR1_STATUS__dav__BITNR 0
+#define R_PAR1_STATUS__dav__WIDTH 1
+#define R_PAR1_STATUS__dav__data 1
+#define R_PAR1_STATUS__dav__nodata 0
+
 #define R_PAR1_CONFIG (IO_TYPECAST_UDWORD 0xb0000054)
 #define R_PAR1_CONFIG__ioe__BITNR 25
 #define R_PAR1_CONFIG__ioe__WIDTH 1
@@ -2857,6 +2985,10 @@
 #define R_PAR1_CONFIG__mode__ecp_fwd 5
 #define R_PAR1_CONFIG__mode__ecp_rev 6
 #define R_PAR1_CONFIG__mode__off 7
+#define R_PAR1_CONFIG__mode__epp_wr1 5
+#define R_PAR1_CONFIG__mode__epp_wr2 6
+#define R_PAR1_CONFIG__mode__epp_wr3 7
+#define R_PAR1_CONFIG__mode__epp_rd 0
 
 #define R_PAR1_DELAY (IO_TYPECAST_UDWORD 0xb0000058)
 #define R_PAR1_DELAY__fine_hold__BITNR 21
@@ -3437,10 +3569,6 @@
 #define R_IRQ_MASK0_RD__ata_irq2__WIDTH 1
 #define R_IRQ_MASK0_RD__ata_irq2__active 1
 #define R_IRQ_MASK0_RD__ata_irq2__inactive 0
-#define R_IRQ_MASK0_RD__p21_irq2__BITNR 10
-#define R_IRQ_MASK0_RD__p21_irq2__WIDTH 1
-#define R_IRQ_MASK0_RD__p21_irq2__active 1
-#define R_IRQ_MASK0_RD__p21_irq2__inactive 0
 #define R_IRQ_MASK0_RD__par0_data__BITNR 9
 #define R_IRQ_MASK0_RD__par0_data__WIDTH 1
 #define R_IRQ_MASK0_RD__par0_data__active 1
@@ -3449,10 +3577,6 @@
 #define R_IRQ_MASK0_RD__ata_irq1__WIDTH 1
 #define R_IRQ_MASK0_RD__ata_irq1__active 1
 #define R_IRQ_MASK0_RD__ata_irq1__inactive 0
-#define R_IRQ_MASK0_RD__p21_irq1__BITNR 9
-#define R_IRQ_MASK0_RD__p21_irq1__WIDTH 1
-#define R_IRQ_MASK0_RD__p21_irq1__active 1
-#define R_IRQ_MASK0_RD__p21_irq1__inactive 0
 #define R_IRQ_MASK0_RD__par0_ready__BITNR 8
 #define R_IRQ_MASK0_RD__par0_ready__WIDTH 1
 #define R_IRQ_MASK0_RD__par0_ready__active 1
@@ -3469,10 +3593,6 @@
 #define R_IRQ_MASK0_RD__scsi0__WIDTH 1
 #define R_IRQ_MASK0_RD__scsi0__active 1
 #define R_IRQ_MASK0_RD__scsi0__inactive 0
-#define R_IRQ_MASK0_RD__p21_irq0__BITNR 8
-#define R_IRQ_MASK0_RD__p21_irq0__WIDTH 1
-#define R_IRQ_MASK0_RD__p21_irq0__active 1
-#define R_IRQ_MASK0_RD__p21_irq0__inactive 0
 #define R_IRQ_MASK0_RD__ata_dmaend__BITNR 7
 #define R_IRQ_MASK0_RD__ata_dmaend__WIDTH 1
 #define R_IRQ_MASK0_RD__ata_dmaend__active 1
@@ -3599,10 +3719,6 @@
 #define R_IRQ_MASK0_CLR__ata_irq2__WIDTH 1
 #define R_IRQ_MASK0_CLR__ata_irq2__clr 1
 #define R_IRQ_MASK0_CLR__ata_irq2__nop 0
-#define R_IRQ_MASK0_CLR__p21_irq2__BITNR 10
-#define R_IRQ_MASK0_CLR__p21_irq2__WIDTH 1
-#define R_IRQ_MASK0_CLR__p21_irq2__clr 1
-#define R_IRQ_MASK0_CLR__p21_irq2__nop 0
 #define R_IRQ_MASK0_CLR__par0_data__BITNR 9
 #define R_IRQ_MASK0_CLR__par0_data__WIDTH 1
 #define R_IRQ_MASK0_CLR__par0_data__clr 1
@@ -3611,10 +3727,6 @@
 #define R_IRQ_MASK0_CLR__ata_irq1__WIDTH 1
 #define R_IRQ_MASK0_CLR__ata_irq1__clr 1
 #define R_IRQ_MASK0_CLR__ata_irq1__nop 0
-#define R_IRQ_MASK0_CLR__p21_irq1__BITNR 9
-#define R_IRQ_MASK0_CLR__p21_irq1__WIDTH 1
-#define R_IRQ_MASK0_CLR__p21_irq1__clr 1
-#define R_IRQ_MASK0_CLR__p21_irq1__nop 0
 #define R_IRQ_MASK0_CLR__par0_ready__BITNR 8
 #define R_IRQ_MASK0_CLR__par0_ready__WIDTH 1
 #define R_IRQ_MASK0_CLR__par0_ready__clr 1
@@ -3631,10 +3743,6 @@
 #define R_IRQ_MASK0_CLR__scsi0__WIDTH 1
 #define R_IRQ_MASK0_CLR__scsi0__clr 1
 #define R_IRQ_MASK0_CLR__scsi0__nop 0
-#define R_IRQ_MASK0_CLR__p21_irq0__BITNR 8
-#define R_IRQ_MASK0_CLR__p21_irq0__WIDTH 1
-#define R_IRQ_MASK0_CLR__p21_irq0__clr 1
-#define R_IRQ_MASK0_CLR__p21_irq0__nop 0
 #define R_IRQ_MASK0_CLR__ata_dmaend__BITNR 7
 #define R_IRQ_MASK0_CLR__ata_dmaend__WIDTH 1
 #define R_IRQ_MASK0_CLR__ata_dmaend__clr 1
@@ -3761,10 +3869,6 @@
 #define R_IRQ_READ0__ata_irq2__WIDTH 1
 #define R_IRQ_READ0__ata_irq2__active 1
 #define R_IRQ_READ0__ata_irq2__inactive 0
-#define R_IRQ_READ0__p21_irq2__BITNR 10
-#define R_IRQ_READ0__p21_irq2__WIDTH 1
-#define R_IRQ_READ0__p21_irq2__active 1
-#define R_IRQ_READ0__p21_irq2__inactive 0
 #define R_IRQ_READ0__par0_data__BITNR 9
 #define R_IRQ_READ0__par0_data__WIDTH 1
 #define R_IRQ_READ0__par0_data__active 1
@@ -3773,10 +3877,6 @@
 #define R_IRQ_READ0__ata_irq1__WIDTH 1
 #define R_IRQ_READ0__ata_irq1__active 1
 #define R_IRQ_READ0__ata_irq1__inactive 0
-#define R_IRQ_READ0__p21_irq1__BITNR 9
-#define R_IRQ_READ0__p21_irq1__WIDTH 1
-#define R_IRQ_READ0__p21_irq1__active 1
-#define R_IRQ_READ0__p21_irq1__inactive 0
 #define R_IRQ_READ0__par0_ready__BITNR 8
 #define R_IRQ_READ0__par0_ready__WIDTH 1
 #define R_IRQ_READ0__par0_ready__active 1
@@ -3793,10 +3893,6 @@
 #define R_IRQ_READ0__scsi0__WIDTH 1
 #define R_IRQ_READ0__scsi0__active 1
 #define R_IRQ_READ0__scsi0__inactive 0
-#define R_IRQ_READ0__p21_irq0__BITNR 8
-#define R_IRQ_READ0__p21_irq0__WIDTH 1
-#define R_IRQ_READ0__p21_irq0__active 1
-#define R_IRQ_READ0__p21_irq0__inactive 0
 #define R_IRQ_READ0__ata_dmaend__BITNR 7
 #define R_IRQ_READ0__ata_dmaend__WIDTH 1
 #define R_IRQ_READ0__ata_dmaend__active 1
@@ -3923,10 +4019,6 @@
 #define R_IRQ_MASK0_SET__ata_irq2__WIDTH 1
 #define R_IRQ_MASK0_SET__ata_irq2__set 1
 #define R_IRQ_MASK0_SET__ata_irq2__nop 0
-#define R_IRQ_MASK0_SET__p21_irq2__BITNR 10
-#define R_IRQ_MASK0_SET__p21_irq2__WIDTH 1
-#define R_IRQ_MASK0_SET__p21_irq2__set 1
-#define R_IRQ_MASK0_SET__p21_irq2__nop 0
 #define R_IRQ_MASK0_SET__par0_data__BITNR 9
 #define R_IRQ_MASK0_SET__par0_data__WIDTH 1
 #define R_IRQ_MASK0_SET__par0_data__set 1
@@ -3935,10 +4027,6 @@
 #define R_IRQ_MASK0_SET__ata_irq1__WIDTH 1
 #define R_IRQ_MASK0_SET__ata_irq1__set 1
 #define R_IRQ_MASK0_SET__ata_irq1__nop 0
-#define R_IRQ_MASK0_SET__p21_irq1__BITNR 9
-#define R_IRQ_MASK0_SET__p21_irq1__WIDTH 1
-#define R_IRQ_MASK0_SET__p21_irq1__set 1
-#define R_IRQ_MASK0_SET__p21_irq1__nop 0
 #define R_IRQ_MASK0_SET__par0_ready__BITNR 8
 #define R_IRQ_MASK0_SET__par0_ready__WIDTH 1
 #define R_IRQ_MASK0_SET__par0_ready__set 1
@@ -3955,10 +4043,6 @@
 #define R_IRQ_MASK0_SET__scsi0__WIDTH 1
 #define R_IRQ_MASK0_SET__scsi0__set 1
 #define R_IRQ_MASK0_SET__scsi0__nop 0
-#define R_IRQ_MASK0_SET__p21_irq0__BITNR 8
-#define R_IRQ_MASK0_SET__p21_irq0__WIDTH 1
-#define R_IRQ_MASK0_SET__p21_irq0__set 1
-#define R_IRQ_MASK0_SET__p21_irq0__nop 0
 #define R_IRQ_MASK0_SET__ata_dmaend__BITNR 7
 #define R_IRQ_MASK0_SET__ata_dmaend__WIDTH 1
 #define R_IRQ_MASK0_SET__ata_dmaend__set 1
@@ -4953,10 +5037,6 @@
 #define R_VECT_MASK_RD__mio__WIDTH 1
 #define R_VECT_MASK_RD__mio__active 1
 #define R_VECT_MASK_RD__mio__inactive 0
-#define R_VECT_MASK_RD__p21__BITNR 4
-#define R_VECT_MASK_RD__p21__WIDTH 1
-#define R_VECT_MASK_RD__p21__active 1
-#define R_VECT_MASK_RD__p21__inactive 0
 #define R_VECT_MASK_RD__timer1__BITNR 3
 #define R_VECT_MASK_RD__timer1__WIDTH 1
 #define R_VECT_MASK_RD__timer1__active 1
@@ -5075,10 +5155,6 @@
 #define R_VECT_MASK_CLR__mio__WIDTH 1
 #define R_VECT_MASK_CLR__mio__clr 1
 #define R_VECT_MASK_CLR__mio__nop 0
-#define R_VECT_MASK_CLR__p21__BITNR 4
-#define R_VECT_MASK_CLR__p21__WIDTH 1
-#define R_VECT_MASK_CLR__p21__clr 1
-#define R_VECT_MASK_CLR__p21__nop 0
 #define R_VECT_MASK_CLR__timer1__BITNR 3
 #define R_VECT_MASK_CLR__timer1__WIDTH 1
 #define R_VECT_MASK_CLR__timer1__clr 1
@@ -5197,10 +5273,6 @@
 #define R_VECT_READ__mio__WIDTH 1
 #define R_VECT_READ__mio__active 1
 #define R_VECT_READ__mio__inactive 0
-#define R_VECT_READ__p21__BITNR 4
-#define R_VECT_READ__p21__WIDTH 1
-#define R_VECT_READ__p21__active 1
-#define R_VECT_READ__p21__inactive 0
 #define R_VECT_READ__timer1__BITNR 3
 #define R_VECT_READ__timer1__WIDTH 1
 #define R_VECT_READ__timer1__active 1
@@ -5319,10 +5391,6 @@
 #define R_VECT_MASK_SET__mio__WIDTH 1
 #define R_VECT_MASK_SET__mio__set 1
 #define R_VECT_MASK_SET__mio__nop 0
-#define R_VECT_MASK_SET__p21__BITNR 4
-#define R_VECT_MASK_SET__p21__WIDTH 1
-#define R_VECT_MASK_SET__p21__set 1
-#define R_VECT_MASK_SET__p21__nop 0
 #define R_VECT_MASK_SET__timer1__BITNR 3
 #define R_VECT_MASK_SET__timer1__WIDTH 1
 #define R_VECT_MASK_SET__timer1__set 1
@@ -5997,6 +6065,10 @@
 #define R_USB_COMMAND__port_cmd__disable 1
 #define R_USB_COMMAND__port_cmd__suspend 2
 #define R_USB_COMMAND__port_cmd__resume 3
+#define R_USB_COMMAND__busy__BITNR 3
+#define R_USB_COMMAND__busy__WIDTH 1
+#define R_USB_COMMAND__busy__no 0
+#define R_USB_COMMAND__busy__yes 1
 #define R_USB_COMMAND__ctrl_cmd__BITNR 0
 #define R_USB_COMMAND__ctrl_cmd__WIDTH 3
 #define R_USB_COMMAND__ctrl_cmd__nop 0
@@ -6004,15 +6076,47 @@
 #define R_USB_COMMAND__ctrl_cmd__deconfig 2
 #define R_USB_COMMAND__ctrl_cmd__host_config 3
 #define R_USB_COMMAND__ctrl_cmd__dev_config 4
-#define R_USB_COMMAND__ctrl_cmd__host_reset 5
+#define R_USB_COMMAND__ctrl_cmd__host_nop 5
 #define R_USB_COMMAND__ctrl_cmd__host_run 6
 #define R_USB_COMMAND__ctrl_cmd__host_stop 7
 
+#define R_USB_COMMAND_DEV (IO_TYPECAST_BYTE 0xb0000201)
+#define R_USB_COMMAND_DEV__port_sel__BITNR 6
+#define R_USB_COMMAND_DEV__port_sel__WIDTH 2
+#define R_USB_COMMAND_DEV__port_sel__nop 0
+#define R_USB_COMMAND_DEV__port_sel__dummy1 1
+#define R_USB_COMMAND_DEV__port_sel__dummy2 2
+#define R_USB_COMMAND_DEV__port_sel__any 3
+#define R_USB_COMMAND_DEV__port_cmd__BITNR 4
+#define R_USB_COMMAND_DEV__port_cmd__WIDTH 2
+#define R_USB_COMMAND_DEV__port_cmd__active 0
+#define R_USB_COMMAND_DEV__port_cmd__passive 1
+#define R_USB_COMMAND_DEV__port_cmd__nop 2
+#define R_USB_COMMAND_DEV__port_cmd__wakeup 3
+#define R_USB_COMMAND_DEV__busy__BITNR 3
+#define R_USB_COMMAND_DEV__busy__WIDTH 1
+#define R_USB_COMMAND_DEV__busy__no 0
+#define R_USB_COMMAND_DEV__busy__yes 1
+#define R_USB_COMMAND_DEV__ctrl_cmd__BITNR 0
+#define R_USB_COMMAND_DEV__ctrl_cmd__WIDTH 3
+#define R_USB_COMMAND_DEV__ctrl_cmd__nop 0
+#define R_USB_COMMAND_DEV__ctrl_cmd__reset 1
+#define R_USB_COMMAND_DEV__ctrl_cmd__deconfig 2
+#define R_USB_COMMAND_DEV__ctrl_cmd__host_config 3
+#define R_USB_COMMAND_DEV__ctrl_cmd__dev_config 4
+#define R_USB_COMMAND_DEV__ctrl_cmd__dev_active 5
+#define R_USB_COMMAND_DEV__ctrl_cmd__dev_passive 6
+#define R_USB_COMMAND_DEV__ctrl_cmd__dev_nop 7
+
 #define R_USB_STATUS (IO_TYPECAST_RO_BYTE 0xb0000202)
-#define R_USB_STATUS__busy__BITNR 7
-#define R_USB_STATUS__busy__WIDTH 1
-#define R_USB_STATUS__busy__no 0
-#define R_USB_STATUS__busy__yes 1
+#define R_USB_STATUS__ourun__BITNR 5
+#define R_USB_STATUS__ourun__WIDTH 1
+#define R_USB_STATUS__ourun__no 0
+#define R_USB_STATUS__ourun__yes 1
+#define R_USB_STATUS__perror__BITNR 4
+#define R_USB_STATUS__perror__WIDTH 1
+#define R_USB_STATUS__perror__no 0
+#define R_USB_STATUS__perror__yes 1
 #define R_USB_STATUS__device_mode__BITNR 3
 #define R_USB_STATUS__device_mode__WIDTH 1
 #define R_USB_STATUS__device_mode__no 0
@@ -6031,30 +6135,34 @@
 #define R_USB_STATUS__running__yes 1
 
 #define R_USB_IRQ_MASK_SET (IO_TYPECAST_UWORD 0xb0000204)
-#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 13
-#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1
-#define R_USB_IRQ_MASK_SET__intr_eof__nop 0
-#define R_USB_IRQ_MASK_SET__intr_eof__set 1
-#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 12
+#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 13
 #define R_USB_IRQ_MASK_SET__iso_eof__WIDTH 1
 #define R_USB_IRQ_MASK_SET__iso_eof__nop 0
 #define R_USB_IRQ_MASK_SET__iso_eof__set 1
-#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 11
-#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1
-#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0
-#define R_USB_IRQ_MASK_SET__bulk_eot__set 1
-#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 10
-#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1
-#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0
-#define R_USB_IRQ_MASK_SET__ctl_eot__set 1
-#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 9
-#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1
-#define R_USB_IRQ_MASK_SET__intr_eot__nop 0
-#define R_USB_IRQ_MASK_SET__intr_eot__set 1
-#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 8
+#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 12
+#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1
+#define R_USB_IRQ_MASK_SET__intr_eof__nop 0
+#define R_USB_IRQ_MASK_SET__intr_eof__set 1
+#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 11
 #define R_USB_IRQ_MASK_SET__iso_eot__WIDTH 1
 #define R_USB_IRQ_MASK_SET__iso_eot__nop 0
 #define R_USB_IRQ_MASK_SET__iso_eot__set 1
+#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 10
+#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET__intr_eot__nop 0
+#define R_USB_IRQ_MASK_SET__intr_eot__set 1
+#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 9
+#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0
+#define R_USB_IRQ_MASK_SET__ctl_eot__set 1
+#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 8
+#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0
+#define R_USB_IRQ_MASK_SET__bulk_eot__set 1
+#define R_USB_IRQ_MASK_SET__epid_attn__BITNR 3
+#define R_USB_IRQ_MASK_SET__epid_attn__WIDTH 1
+#define R_USB_IRQ_MASK_SET__epid_attn__nop 0
+#define R_USB_IRQ_MASK_SET__epid_attn__set 1
 #define R_USB_IRQ_MASK_SET__sof__BITNR 2
 #define R_USB_IRQ_MASK_SET__sof__WIDTH 1
 #define R_USB_IRQ_MASK_SET__sof__nop 0
@@ -6069,30 +6177,34 @@
 #define R_USB_IRQ_MASK_SET__ctl_status__set 1
 
 #define R_USB_IRQ_MASK_READ (IO_TYPECAST_RO_UWORD 0xb0000204)
-#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 13
-#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1
-#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0
-#define R_USB_IRQ_MASK_READ__intr_eof__pend 1
-#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 12
+#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 13
 #define R_USB_IRQ_MASK_READ__iso_eof__WIDTH 1
 #define R_USB_IRQ_MASK_READ__iso_eof__no_pend 0
 #define R_USB_IRQ_MASK_READ__iso_eof__pend 1
-#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 11
-#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1
-#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0
-#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1
-#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 10
-#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1
-#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0
-#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1
-#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 9
-#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1
-#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0
-#define R_USB_IRQ_MASK_READ__intr_eot__pend 1
-#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 8
+#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 12
+#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1
+#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0
+#define R_USB_IRQ_MASK_READ__intr_eof__pend 1
+#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 11
 #define R_USB_IRQ_MASK_READ__iso_eot__WIDTH 1
 #define R_USB_IRQ_MASK_READ__iso_eot__no_pend 0
 #define R_USB_IRQ_MASK_READ__iso_eot__pend 1
+#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 10
+#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ__intr_eot__pend 1
+#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 9
+#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1
+#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 8
+#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1
+#define R_USB_IRQ_MASK_READ__epid_attn__BITNR 3
+#define R_USB_IRQ_MASK_READ__epid_attn__WIDTH 1
+#define R_USB_IRQ_MASK_READ__epid_attn__no_pend 0
+#define R_USB_IRQ_MASK_READ__epid_attn__pend 1
 #define R_USB_IRQ_MASK_READ__sof__BITNR 2
 #define R_USB_IRQ_MASK_READ__sof__WIDTH 1
 #define R_USB_IRQ_MASK_READ__sof__no_pend 0
@@ -6107,30 +6219,34 @@
 #define R_USB_IRQ_MASK_READ__ctl_status__pend 1
 
 #define R_USB_IRQ_MASK_CLR (IO_TYPECAST_UWORD 0xb0000206)
-#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 13
-#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1
-#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0
-#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1
-#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 12
+#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 13
 #define R_USB_IRQ_MASK_CLR__iso_eof__WIDTH 1
 #define R_USB_IRQ_MASK_CLR__iso_eof__nop 0
 #define R_USB_IRQ_MASK_CLR__iso_eof__clr 1
-#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 11
-#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1
-#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0
-#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1
-#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 10
-#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1
-#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0
-#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1
-#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 9
-#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1
-#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0
-#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1
-#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 8
+#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 12
+#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1
+#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0
+#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1
+#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 11
 #define R_USB_IRQ_MASK_CLR__iso_eot__WIDTH 1
 #define R_USB_IRQ_MASK_CLR__iso_eot__nop 0
 #define R_USB_IRQ_MASK_CLR__iso_eot__clr 1
+#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 10
+#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0
+#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1
+#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 9
+#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0
+#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1
+#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 8
+#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0
+#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1
+#define R_USB_IRQ_MASK_CLR__epid_attn__BITNR 3
+#define R_USB_IRQ_MASK_CLR__epid_attn__WIDTH 1
+#define R_USB_IRQ_MASK_CLR__epid_attn__nop 0
+#define R_USB_IRQ_MASK_CLR__epid_attn__clr 1
 #define R_USB_IRQ_MASK_CLR__sof__BITNR 2
 #define R_USB_IRQ_MASK_CLR__sof__WIDTH 1
 #define R_USB_IRQ_MASK_CLR__sof__nop 0
@@ -6145,30 +6261,34 @@
 #define R_USB_IRQ_MASK_CLR__ctl_status__clr 1
 
 #define R_USB_IRQ_READ (IO_TYPECAST_RO_UWORD 0xb0000206)
-#define R_USB_IRQ_READ__intr_eof__BITNR 13
-#define R_USB_IRQ_READ__intr_eof__WIDTH 1
-#define R_USB_IRQ_READ__intr_eof__no_pend 0
-#define R_USB_IRQ_READ__intr_eof__pend 1
-#define R_USB_IRQ_READ__iso_eof__BITNR 12
+#define R_USB_IRQ_READ__iso_eof__BITNR 13
 #define R_USB_IRQ_READ__iso_eof__WIDTH 1
 #define R_USB_IRQ_READ__iso_eof__no_pend 0
 #define R_USB_IRQ_READ__iso_eof__pend 1
-#define R_USB_IRQ_READ__bulk_eot__BITNR 11
-#define R_USB_IRQ_READ__bulk_eot__WIDTH 1
-#define R_USB_IRQ_READ__bulk_eot__no_pend 0
-#define R_USB_IRQ_READ__bulk_eot__pend 1
-#define R_USB_IRQ_READ__ctl_eot__BITNR 10
-#define R_USB_IRQ_READ__ctl_eot__WIDTH 1
-#define R_USB_IRQ_READ__ctl_eot__no_pend 0
-#define R_USB_IRQ_READ__ctl_eot__pend 1
-#define R_USB_IRQ_READ__intr_eot__BITNR 9
-#define R_USB_IRQ_READ__intr_eot__WIDTH 1
-#define R_USB_IRQ_READ__intr_eot__no_pend 0
-#define R_USB_IRQ_READ__intr_eot__pend 1
-#define R_USB_IRQ_READ__iso_eot__BITNR 8
+#define R_USB_IRQ_READ__intr_eof__BITNR 12
+#define R_USB_IRQ_READ__intr_eof__WIDTH 1
+#define R_USB_IRQ_READ__intr_eof__no_pend 0
+#define R_USB_IRQ_READ__intr_eof__pend 1
+#define R_USB_IRQ_READ__iso_eot__BITNR 11
 #define R_USB_IRQ_READ__iso_eot__WIDTH 1
 #define R_USB_IRQ_READ__iso_eot__no_pend 0
 #define R_USB_IRQ_READ__iso_eot__pend 1
+#define R_USB_IRQ_READ__intr_eot__BITNR 10
+#define R_USB_IRQ_READ__intr_eot__WIDTH 1
+#define R_USB_IRQ_READ__intr_eot__no_pend 0
+#define R_USB_IRQ_READ__intr_eot__pend 1
+#define R_USB_IRQ_READ__ctl_eot__BITNR 9
+#define R_USB_IRQ_READ__ctl_eot__WIDTH 1
+#define R_USB_IRQ_READ__ctl_eot__no_pend 0
+#define R_USB_IRQ_READ__ctl_eot__pend 1
+#define R_USB_IRQ_READ__bulk_eot__BITNR 8
+#define R_USB_IRQ_READ__bulk_eot__WIDTH 1
+#define R_USB_IRQ_READ__bulk_eot__no_pend 0
+#define R_USB_IRQ_READ__bulk_eot__pend 1
+#define R_USB_IRQ_READ__epid_attn__BITNR 3
+#define R_USB_IRQ_READ__epid_attn__WIDTH 1
+#define R_USB_IRQ_READ__epid_attn__no_pend 0
+#define R_USB_IRQ_READ__epid_attn__pend 1
 #define R_USB_IRQ_READ__sof__BITNR 2
 #define R_USB_IRQ_READ__sof__WIDTH 1
 #define R_USB_IRQ_READ__sof__no_pend 0
@@ -6182,7 +6302,159 @@
 #define R_USB_IRQ_READ__ctl_status__no_pend 0
 #define R_USB_IRQ_READ__ctl_status__pend 1
 
-#define R_USB_FM_NUMBER (IO_TYPECAST_RO_UDWORD 0xb000020c)
+#define R_USB_IRQ_MASK_SET_DEV (IO_TYPECAST_UWORD 0xb0000204)
+#define R_USB_IRQ_MASK_SET_DEV__out_eot__BITNR 12
+#define R_USB_IRQ_MASK_SET_DEV__out_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__out_eot__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__out_eot__set 1
+#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__BITNR 11
+#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__set 1
+#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__BITNR 10
+#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__set 1
+#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__BITNR 9
+#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__set 1
+#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__BITNR 8
+#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__set 1
+#define R_USB_IRQ_MASK_SET_DEV__epid_attn__BITNR 3
+#define R_USB_IRQ_MASK_SET_DEV__epid_attn__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__epid_attn__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__epid_attn__set 1
+#define R_USB_IRQ_MASK_SET_DEV__sof__BITNR 2
+#define R_USB_IRQ_MASK_SET_DEV__sof__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__sof__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__sof__set 1
+#define R_USB_IRQ_MASK_SET_DEV__port_status__BITNR 1
+#define R_USB_IRQ_MASK_SET_DEV__port_status__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__port_status__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__port_status__set 1
+#define R_USB_IRQ_MASK_SET_DEV__ctl_status__BITNR 0
+#define R_USB_IRQ_MASK_SET_DEV__ctl_status__WIDTH 1
+#define R_USB_IRQ_MASK_SET_DEV__ctl_status__nop 0
+#define R_USB_IRQ_MASK_SET_DEV__ctl_status__set 1
+
+#define R_USB_IRQ_MASK_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000204)
+#define R_USB_IRQ_MASK_READ_DEV__out_eot__BITNR 12
+#define R_USB_IRQ_MASK_READ_DEV__out_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__out_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__out_eot__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__BITNR 11
+#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__BITNR 10
+#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__BITNR 9
+#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__BITNR 8
+#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__epid_attn__BITNR 3
+#define R_USB_IRQ_MASK_READ_DEV__epid_attn__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__epid_attn__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__epid_attn__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__sof__BITNR 2
+#define R_USB_IRQ_MASK_READ_DEV__sof__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__sof__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__sof__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__port_status__BITNR 1
+#define R_USB_IRQ_MASK_READ_DEV__port_status__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__port_status__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__port_status__pend 1
+#define R_USB_IRQ_MASK_READ_DEV__ctl_status__BITNR 0
+#define R_USB_IRQ_MASK_READ_DEV__ctl_status__WIDTH 1
+#define R_USB_IRQ_MASK_READ_DEV__ctl_status__no_pend 0
+#define R_USB_IRQ_MASK_READ_DEV__ctl_status__pend 1
+
+#define R_USB_IRQ_MASK_CLR_DEV (IO_TYPECAST_UWORD 0xb0000206)
+#define R_USB_IRQ_MASK_CLR_DEV__out_eot__BITNR 12
+#define R_USB_IRQ_MASK_CLR_DEV__out_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__out_eot__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__out_eot__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__BITNR 11
+#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__BITNR 10
+#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__BITNR 9
+#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__BITNR 8
+#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__BITNR 3
+#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__sof__BITNR 2
+#define R_USB_IRQ_MASK_CLR_DEV__sof__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__sof__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__sof__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__port_status__BITNR 1
+#define R_USB_IRQ_MASK_CLR_DEV__port_status__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__port_status__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__port_status__clr 1
+#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__BITNR 0
+#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__WIDTH 1
+#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__nop 0
+#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__clr 1
+
+#define R_USB_IRQ_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000206)
+#define R_USB_IRQ_READ_DEV__out_eot__BITNR 12
+#define R_USB_IRQ_READ_DEV__out_eot__WIDTH 1
+#define R_USB_IRQ_READ_DEV__out_eot__no_pend 0
+#define R_USB_IRQ_READ_DEV__out_eot__pend 1
+#define R_USB_IRQ_READ_DEV__ep3_in_eot__BITNR 11
+#define R_USB_IRQ_READ_DEV__ep3_in_eot__WIDTH 1
+#define R_USB_IRQ_READ_DEV__ep3_in_eot__no_pend 0
+#define R_USB_IRQ_READ_DEV__ep3_in_eot__pend 1
+#define R_USB_IRQ_READ_DEV__ep2_in_eot__BITNR 10
+#define R_USB_IRQ_READ_DEV__ep2_in_eot__WIDTH 1
+#define R_USB_IRQ_READ_DEV__ep2_in_eot__no_pend 0
+#define R_USB_IRQ_READ_DEV__ep2_in_eot__pend 1
+#define R_USB_IRQ_READ_DEV__ep1_in_eot__BITNR 9
+#define R_USB_IRQ_READ_DEV__ep1_in_eot__WIDTH 1
+#define R_USB_IRQ_READ_DEV__ep1_in_eot__no_pend 0
+#define R_USB_IRQ_READ_DEV__ep1_in_eot__pend 1
+#define R_USB_IRQ_READ_DEV__ep0_in_eot__BITNR 8
+#define R_USB_IRQ_READ_DEV__ep0_in_eot__WIDTH 1
+#define R_USB_IRQ_READ_DEV__ep0_in_eot__no_pend 0
+#define R_USB_IRQ_READ_DEV__ep0_in_eot__pend 1
+#define R_USB_IRQ_READ_DEV__epid_attn__BITNR 3
+#define R_USB_IRQ_READ_DEV__epid_attn__WIDTH 1
+#define R_USB_IRQ_READ_DEV__epid_attn__no_pend 0
+#define R_USB_IRQ_READ_DEV__epid_attn__pend 1
+#define R_USB_IRQ_READ_DEV__sof__BITNR 2
+#define R_USB_IRQ_READ_DEV__sof__WIDTH 1
+#define R_USB_IRQ_READ_DEV__sof__no_pend 0
+#define R_USB_IRQ_READ_DEV__sof__pend 1
+#define R_USB_IRQ_READ_DEV__port_status__BITNR 1
+#define R_USB_IRQ_READ_DEV__port_status__WIDTH 1
+#define R_USB_IRQ_READ_DEV__port_status__no_pend 0
+#define R_USB_IRQ_READ_DEV__port_status__pend 1
+#define R_USB_IRQ_READ_DEV__ctl_status__BITNR 0
+#define R_USB_IRQ_READ_DEV__ctl_status__WIDTH 1
+#define R_USB_IRQ_READ_DEV__ctl_status__no_pend 0
+#define R_USB_IRQ_READ_DEV__ctl_status__pend 1
+
+#define R_USB_FM_NUMBER (IO_TYPECAST_UDWORD 0xb000020c)
 #define R_USB_FM_NUMBER__value__BITNR 0
 #define R_USB_FM_NUMBER__value__WIDTH 32
 
@@ -6200,22 +6472,26 @@
 #define R_USB_FM_PSTART__value__BITNR 0
 #define R_USB_FM_PSTART__value__WIDTH 14
 
-#define R_USB_LS_THRESHOLD (IO_TYPECAST_UWORD 0xb0000216)
-#define R_USB_LS_THRESHOLD__value__BITNR 0
-#define R_USB_LS_THRESHOLD__value__WIDTH 14
-
 #define R_USB_RH_STATUS (IO_TYPECAST_RO_BYTE 0xb0000203)
+#define R_USB_RH_STATUS__babble2__BITNR 7
+#define R_USB_RH_STATUS__babble2__WIDTH 1
+#define R_USB_RH_STATUS__babble2__no 0
+#define R_USB_RH_STATUS__babble2__yes 1
+#define R_USB_RH_STATUS__babble1__BITNR 6
+#define R_USB_RH_STATUS__babble1__WIDTH 1
+#define R_USB_RH_STATUS__babble1__no 0
+#define R_USB_RH_STATUS__babble1__yes 1
 #define R_USB_RH_STATUS__bus1__BITNR 4
 #define R_USB_RH_STATUS__bus1__WIDTH 2
 #define R_USB_RH_STATUS__bus1__SE0 0
 #define R_USB_RH_STATUS__bus1__Diff0 1
-#define R_USB_RH_STATUS__bus1__Diff1 1
+#define R_USB_RH_STATUS__bus1__Diff1 2
 #define R_USB_RH_STATUS__bus1__SE1 3
 #define R_USB_RH_STATUS__bus2__BITNR 2
 #define R_USB_RH_STATUS__bus2__WIDTH 2
 #define R_USB_RH_STATUS__bus2__SE0 0
 #define R_USB_RH_STATUS__bus2__Diff0 1
-#define R_USB_RH_STATUS__bus2__Diff1 1
+#define R_USB_RH_STATUS__bus2__Diff1 2
 #define R_USB_RH_STATUS__bus2__SE1 3
 #define R_USB_RH_STATUS__nports__BITNR 0
 #define R_USB_RH_STATUS__nports__WIDTH 2
@@ -6231,10 +6507,10 @@
 #define R_USB_RH_PORT_STATUS_1__reset__WIDTH 1
 #define R_USB_RH_PORT_STATUS_1__reset__no 0
 #define R_USB_RH_PORT_STATUS_1__reset__yes 1
-#define R_USB_RH_PORT_STATUS_1__overcurent__BITNR 3
-#define R_USB_RH_PORT_STATUS_1__overcurent__WIDTH 1
-#define R_USB_RH_PORT_STATUS_1__overcurent__no 0
-#define R_USB_RH_PORT_STATUS_1__overcurent__yes 1
+#define R_USB_RH_PORT_STATUS_1__overcurrent__BITNR 3
+#define R_USB_RH_PORT_STATUS_1__overcurrent__WIDTH 1
+#define R_USB_RH_PORT_STATUS_1__overcurrent__no 0
+#define R_USB_RH_PORT_STATUS_1__overcurrent__yes 1
 #define R_USB_RH_PORT_STATUS_1__suspended__BITNR 2
 #define R_USB_RH_PORT_STATUS_1__suspended__WIDTH 1
 #define R_USB_RH_PORT_STATUS_1__suspended__no 0
@@ -6259,10 +6535,10 @@
 #define R_USB_RH_PORT_STATUS_2__reset__WIDTH 1
 #define R_USB_RH_PORT_STATUS_2__reset__no 0
 #define R_USB_RH_PORT_STATUS_2__reset__yes 1
-#define R_USB_RH_PORT_STATUS_2__overcurent__BITNR 3
-#define R_USB_RH_PORT_STATUS_2__overcurent__WIDTH 1
-#define R_USB_RH_PORT_STATUS_2__overcurent__no 0
-#define R_USB_RH_PORT_STATUS_2__overcurent__yes 1
+#define R_USB_RH_PORT_STATUS_2__overcurrent__BITNR 3
+#define R_USB_RH_PORT_STATUS_2__overcurrent__WIDTH 1
+#define R_USB_RH_PORT_STATUS_2__overcurrent__no 0
+#define R_USB_RH_PORT_STATUS_2__overcurrent__yes 1
 #define R_USB_RH_PORT_STATUS_2__suspended__BITNR 2
 #define R_USB_RH_PORT_STATUS_2__suspended__WIDTH 1
 #define R_USB_RH_PORT_STATUS_2__suspended__no 0
@@ -6308,7 +6584,7 @@
 #define R_USB_EPT_DATA__error_code__no_error 0
 #define R_USB_EPT_DATA__error_code__stall 1
 #define R_USB_EPT_DATA__error_code__bus_error 2
-#define R_USB_EPT_DATA__error_code__TBD3 3
+#define R_USB_EPT_DATA__error_code__buffer_error 3
 #define R_USB_EPT_DATA__t_out__BITNR 21
 #define R_USB_EPT_DATA__t_out__WIDTH 1
 #define R_USB_EPT_DATA__error_count_out__BITNR 19
@@ -6357,10 +6633,10 @@
 #define R_USB_EPT_DATA_DEV__stall__WIDTH 1
 #define R_USB_EPT_DATA_DEV__stall__no 0
 #define R_USB_EPT_DATA_DEV__stall__yes 1
-#define R_USB_EPT_DATA_DEV__quiet__BITNR 28
-#define R_USB_EPT_DATA_DEV__quiet__WIDTH 1
-#define R_USB_EPT_DATA_DEV__quiet__no 0
-#define R_USB_EPT_DATA_DEV__quiet__yes 1
+#define R_USB_EPT_DATA_DEV__iso_resp__BITNR 28
+#define R_USB_EPT_DATA_DEV__iso_resp__WIDTH 1
+#define R_USB_EPT_DATA_DEV__iso_resp__quiet 0
+#define R_USB_EPT_DATA_DEV__iso_resp__yes 1
 #define R_USB_EPT_DATA_DEV__ctrl__BITNR 27
 #define R_USB_EPT_DATA_DEV__ctrl__WIDTH 1
 #define R_USB_EPT_DATA_DEV__ctrl__no 0
@@ -6371,6 +6647,8 @@
 #define R_USB_EPT_DATA_DEV__iso__yes 1
 #define R_USB_EPT_DATA_DEV__port__BITNR 24
 #define R_USB_EPT_DATA_DEV__port__WIDTH 2
+#define R_USB_EPT_DATA_DEV__control_phase__BITNR 22
+#define R_USB_EPT_DATA_DEV__control_phase__WIDTH 1
 #define R_USB_EPT_DATA_DEV__t__BITNR 21
 #define R_USB_EPT_DATA_DEV__t__WIDTH 1
 #define R_USB_EPT_DATA_DEV__max_len__BITNR 11
@@ -6384,6 +6662,22 @@
 #define R_USB_SNMP_TERROR__value__BITNR 0
 #define R_USB_SNMP_TERROR__value__WIDTH 32
 
+#define R_USB_EPID_ATTN (IO_TYPECAST_RO_UDWORD 0xb0000224)
+#define R_USB_EPID_ATTN__value__BITNR 0
+#define R_USB_EPID_ATTN__value__WIDTH 32
+
+#define R_USB_PORT1_DISABLE (IO_TYPECAST_BYTE 0xb000006a)
+#define R_USB_PORT1_DISABLE__disable__BITNR 0
+#define R_USB_PORT1_DISABLE__disable__WIDTH 1
+#define R_USB_PORT1_DISABLE__disable__yes 0
+#define R_USB_PORT1_DISABLE__disable__no 1
+
+#define R_USB_PORT2_DISABLE (IO_TYPECAST_BYTE 0xb0000052)
+#define R_USB_PORT2_DISABLE__disable__BITNR 0
+#define R_USB_PORT2_DISABLE__disable__WIDTH 1
+#define R_USB_PORT2_DISABLE__disable__yes 0
+#define R_USB_PORT2_DISABLE__disable__no 1
+
 /*
 !* MMU registers
 !*/
@@ -6615,6 +6909,10 @@
 #define R_MMU_CAUSE__we_excp__WIDTH 1
 #define R_MMU_CAUSE__we_excp__yes 1
 #define R_MMU_CAUSE__we_excp__no 0
+#define R_MMU_CAUSE__wr_rd__BITNR 8
+#define R_MMU_CAUSE__wr_rd__WIDTH 1
+#define R_MMU_CAUSE__wr_rd__write 1
+#define R_MMU_CAUSE__wr_rd__read 0
 #define R_MMU_CAUSE__page_id__BITNR 0
 #define R_MMU_CAUSE__page_id__WIDTH 6
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/sync_serial.h linux/include/asm-cris/sync_serial.h
--- v2.4.3/linux/include/asm-cris/sync_serial.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-cris/sync_serial.h	Fri Apr  6 10:51:19 2001
@@ -0,0 +1,97 @@
+/*  
+ * ioctl defines for synchrnous serial port driver
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ * 
+ * Author: Mikael Starvik 
+ *
+ */
+
+#ifndef SYNC_SERIAL_H
+#define SYNC_SERIAL_H
+
+#include <linux/ioctl.h>
+
+#define SSP_SPEED      _IOR('S', 0, unsigned int)
+#define SSP_MODE       _IOR('S', 1, unsigned int)
+#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int)
+#define SSP_IPOLARITY  _IOR('S', 3, unsigned int)
+#define SSP_OPOLARITY  _IOR('S', 4, unsigned int)
+#define SSP_SPI        _IOR('S', 5, unsigned int)
+
+/* Values for SSP_SPEED */
+#define SSP150        0
+#define SSP300        1
+#define SSP600        2
+#define SSP1200       3  
+#define SSP2400       4
+#define SSP4800       5
+#define SSP9600       6
+#define SSP19200      7
+#define SSP28800      8
+#define SSP57600      9
+#define SSP115200    10
+#define SSP230400    11
+#define SSP460800    12
+#define SSP921600    13
+#define SSP3125000   14
+#define CODEC        15
+
+#define FREQ_4MHz   0
+#define FREQ_2MHz   1
+#define FREQ_1MHz   2
+#define FREQ_512kHz 3
+#define FREQ_256kHz 4
+#define FREQ_128kHz 5
+#define FREQ_64kHz  6
+#define FREQ_32kHz  7
+
+/* Used by application to set CODEC divider, word rate and frame rate */
+#define CODEC_VAL(freq, word, frame) (CODEC | (freq << 8) | (word << 16) | (frame << 28))
+
+/* Used by driver to extract speed */
+#define GET_SPEED(x) (x & 0xff)
+#define GET_FREQ(x) ((x & 0xff00) >> 8)
+#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1)
+#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1)
+
+/* Values for SSP_MODE */
+#define MASTER_OUTPUT 0
+#define SLAVE_OUTPUT  1
+#define MASTER_INPUT  2
+#define SLAVE_INPUT   3
+#define MASTER_BIDIR  4
+#define SLAVE_BIDIR   5
+
+/* Values for SSP_FRAME_SYNC */
+#define NORMAL_SYNC                1
+#define EARLY_SYNC                 2
+#define BIT_SYNC                   4
+#define WORD_SYNC                  8
+#define EXTENDED_SYNC           0x10
+#define SYNC_OFF                0x20
+#define SYNC_ON                 0x40
+#define WORD_SIZE_8             0x80
+#define WORD_SIZE_12           0x100
+#define WORD_SIZE_16           0x200
+#define WORD_SIZE_24           0x300
+#define WORD_SIZE_32           0x800
+#define BIT_ORDER_LSB         0x1000
+#define BIT_ORDER_MSB         0x2000
+#define FLOW_CONTROL_ENABLE   0x4000
+#define FLOW_CONTROL_DISABLE  0x8000
+#define CLOCK_GATED          0x10000
+#define CLOCK_NOT_GATED      0x20000
+
+/* Values for SSP_IPOLARITY and SSP_OPOLARITY */
+#define CLOCK_NORMAL         1
+#define CLOCK_INVERT         2
+#define FRAME_NORMAL         4
+#define FRAME_INVERT         8
+#define STATUS_NORMAL      0x10
+#define STATUS_INVERT      0x20
+
+/* Values for SSP_SPI */
+#define SPI_MASTER           0
+#define SPI_SLAVE            1  
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/termios.h linux/include/asm-cris/termios.h
--- v2.4.3/linux/include/asm-cris/termios.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/termios.h	Fri Apr  6 10:51:19 2001
@@ -51,7 +51,7 @@
 #define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
 #define N_R3964		9	/* Reserved for Simatic R3964 module */
 #define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
-#define N_IRDA		11	/* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC		13	/* synchronous HDLC */
 #define N_SYNC_PPP	14	/* synchronous PPP */
diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/unistd.h linux/include/asm-cris/unistd.h
--- v2.4.3/linux/include/asm-cris/unistd.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/unistd.h	Fri Apr  6 10:51:19 2001
@@ -233,28 +233,28 @@
 type name(void) \
 { \
   register long __a __asm__ ("r10"); \
-  __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
 			: "=r" (__a) \
 			: "g" (__NR_##name) \
-			: "r10", "r1"); \
+			: "r10", "r9"); \
   if(__a >= 0) \
      return (type) __a; \
   errno = -__a; \
-  return -1; \
+  return (type) -1; \
 }
 
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
-  __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
 			: "=r" (__a) \
 			: "g" (__NR_##name), "0" (__a) \
-			: "r10", "r1"); \
+			: "r10", "r9"); \
   if(__a >= 0) \
      return (type) __a; \
   errno = -__a; \
-  return -1; \
+  return (type) -1; \
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2) \
@@ -262,14 +262,14 @@
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
-  __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
 			: "=r" (__a) \
 			: "g" (__NR_##name), "0" (__a), "r" (__b) \
-			: "r10", "r1"); \
+			: "r10", "r9"); \
   if(__a >= 0) \
      return (type) __a; \
   errno = -__a; \
-  return -1; \
+  return (type) -1; \
 }
 
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
@@ -278,14 +278,14 @@
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
-  __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
 			: "=r" (__a) \
 			: "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \
-			: "r10", "r1"); \
+			: "r10", "r9"); \
   if(__a >= 0) \
      return (type) __a; \
   errno = -__a; \
-  return -1; \
+  return (type) -1; \
 }
 
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
@@ -295,15 +295,15 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
 			: "=r" (__a) \
 			: "g" (__NR_##name), "0" (__a), "r" (__b), \
 			  "r" (__c), "r" (__d) \
-			: "r10", "r1"); \
+			: "r10", "r9"); \
   if(__a >= 0) \
      return (type) __a; \
   errno = -__a; \
-  return -1; \
+  return (type) -1; \
 } 
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
@@ -314,16 +314,36 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  register long __e __asm__ ("r0") = (long) arg5; \
-  __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \
+  __asm__ __volatile__ ("move %6,$mof\n\t" \
+			"movu.w %1,$r9\n\tbreak 13" \
 			: "=r" (__a) \
 			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d), "r" (__e) \
-			: "r10", "r1"); \
+			  "r" (__c), "r" (__d), "g" (arg5) \
+			: "r10", "r9"); \
   if(__a >= 0) \
      return (type) __a; \
   errno = -__a; \
-  return -1; \
+  return (type) -1; \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+	  type5,arg5,type6,arg6) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \
+			"movu.w %1,$r9\n\tbreak 13" \
+			: "=r" (__a) \
+			: "g" (__NR_##name), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\
+			: "r10", "r9", "srp"); \
+  if(__a >= 0) \
+     return (type) __a; \
+  errno = -__a; \
+  return (type) -1; \
 }
 
 #ifdef __KERNEL_SYSCALLS__
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h
--- v2.4.3/linux/include/asm-i386/atomic.h	Mon Mar 26 15:48:10 2001
+++ linux/include/asm-i386/atomic.h	Wed Apr 25 16:21:22 2001
@@ -75,7 +75,7 @@
 }
 
 /**
- * atomic_sub_and_test - test variable then subtract 
+ * atomic_sub_and_test - subtract value from variable and test result
  * @i: integer value to subtract
  * @v: pointer of type atomic_t
  * 
@@ -111,7 +111,7 @@
 }
 
 /**
- * atomic_dec - decrement the atomic variable
+ * atomic_dec - decrement atomic variable
  * @v: pointer of type atomic_t
  * 
  * Atomically decrements @v by 1.  Note that the guaranteed
@@ -126,7 +126,7 @@
 }
 
 /**
- * atomic_dec_and_test - decrement by 1 and test
+ * atomic_dec_and_test - decrement and test
  * @v: pointer of type atomic_t
  * 
  * Atomically decrements @v by 1 and
@@ -146,7 +146,7 @@
 }
 
 /**
- * atomic_inc_and_test - increment by 1 and test 
+ * atomic_inc_and_test - increment and test 
  * @v: pointer of type atomic_t
  * 
  * Atomically increments @v by 1
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.4.3/linux/include/asm-i386/bitops.h	Mon Mar 26 15:48:10 2001
+++ linux/include/asm-i386/bitops.h	Wed Apr 25 16:21:23 2001
@@ -23,6 +23,16 @@
 
 #define ADDR (*(volatile long *) addr)
 
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
 static __inline__ void set_bit(int nr, volatile void * addr)
 {
 	__asm__ __volatile__( LOCK_PREFIX
@@ -31,7 +41,15 @@
 		:"Ir" (nr));
 }
 
-/* WARNING: non atomic and it can be reordered! */
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
 static __inline__ void __set_bit(int nr, volatile void * addr)
 {
 	__asm__(
@@ -40,11 +58,16 @@
 		:"Ir" (nr));
 }
 
-/*
- * clear_bit() doesn't provide any barrier for the compiler.
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
  */
-#define smp_mb__before_clear_bit()	barrier()
-#define smp_mb__after_clear_bit()	barrier()
 static __inline__ void clear_bit(int nr, volatile void * addr)
 {
 	__asm__ __volatile__( LOCK_PREFIX
@@ -52,7 +75,18 @@
 		:"=m" (ADDR)
 		:"Ir" (nr));
 }
+#define smp_mb__before_clear_bit()	barrier()
+#define smp_mb__after_clear_bit()	barrier()
 
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
 static __inline__ void change_bit(int nr, volatile void * addr)
 {
 	__asm__ __volatile__( LOCK_PREFIX
@@ -61,10 +95,13 @@
 		:"Ir" (nr));
 }
 
-/*
- * It will also imply a memory barrier, thus it must clobber memory
- * to make sure to reload anything that was cached into registers
- * outside _this_ critical section.
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
  */
 static __inline__ int test_and_set_bit(int nr, volatile void * addr)
 {
@@ -77,7 +114,15 @@
 	return oldbit;
 }
 
-/* WARNING: non atomic and it can be reordered! */
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
 static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
 {
 	int oldbit;
@@ -89,6 +134,14 @@
 	return oldbit;
 }
 
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 {
 	int oldbit;
@@ -100,7 +153,15 @@
 	return oldbit;
 }
 
-/* WARNING: non atomic and it can be reordered! */
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
 static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
 {
 	int oldbit;
@@ -112,6 +173,14 @@
 	return oldbit;
 }
 
+/**
+ * test_and_change_bit - Change a bit and return its new value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 static __inline__ int test_and_change_bit(int nr, volatile void * addr)
 {
 	int oldbit;
@@ -123,9 +192,15 @@
 	return oldbit;
 }
 
-/*
- * This routine doesn't need to be atomic.
+#if 0 /* Fool kernel-doc since it doesn't do macros yet */
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
  */
+static int test_bit(int nr, const volatile void * addr);
+#endif
+
 static __inline__ int constant_test_bit(int nr, const volatile void * addr)
 {
 	return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
@@ -147,8 +222,13 @@
  constant_test_bit((nr),(addr)) : \
  variable_test_bit((nr),(addr)))
 
-/*
- * Find-bit routines..
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
  */
 static __inline__ int find_first_zero_bit(void * addr, unsigned size)
 {
@@ -174,6 +254,12 @@
 	return res;
 }
 
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
 static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
 	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
@@ -201,9 +287,11 @@
 	return (offset + set + res);
 }
 
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
  */
 static __inline__ unsigned long ffz(unsigned long word)
 {
@@ -215,12 +303,14 @@
 
 #ifdef __KERNEL__
 
-/*
- * ffs: find first bit set. This is defined the same way as
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from the above ffz (man ffs).
  */
-
 static __inline__ int ffs(int x)
 {
 	int r;
@@ -232,9 +322,11 @@
 	return r+1;
 }
 
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
  */
 
 #define hweight32(x) generic_hweight32(x)
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- v2.4.3/linux/include/asm-i386/io.h	Mon Mar 26 15:48:21 2001
+++ linux/include/asm-i386/io.h	Wed Apr 25 16:22:04 2001
@@ -111,7 +111,7 @@
  * Temporary debugging check to catch old code using
  * unmapped ISA addresses. Will be removed in 2.4.
  */
-#if 1
+#if 0
   extern void *__io_virt_debug(unsigned long x, const char *file, int line);
   extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line);
   #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/kmap_types.h linux/include/asm-i386/kmap_types.h
--- v2.4.3/linux/include/asm-i386/kmap_types.h	Thu Nov 11 10:33:42 1999
+++ linux/include/asm-i386/kmap_types.h	Thu Apr 12 12:11:39 2001
@@ -4,6 +4,8 @@
 enum km_type {
 	KM_BOUNCE_READ,
 	KM_BOUNCE_WRITE,
+	KM_SKB_DATA,
+	KM_SKB_DATA_SOFTIRQ,
 	KM_TYPE_NR
 };
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- v2.4.3/linux/include/asm-i386/pgalloc.h	Mon Mar 26 15:48:11 2001
+++ linux/include/asm-i386/pgalloc.h	Wed Apr 25 16:21:27 2001
@@ -130,7 +130,7 @@
 
 #define pte_free(pte)		pte_free_slow(pte)
 #define pgd_free(pgd)		free_pgd_slow(pgd)
-#define pgd_alloc()		get_pgd_fast()
+#define pgd_alloc(mm)		get_pgd_fast()
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/rwsem.h linux/include/asm-i386/rwsem.h
--- v2.4.3/linux/include/asm-i386/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/rwsem.h	Wed Apr 25 16:21:32 2001
@@ -0,0 +1,226 @@
+/* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for i486+
+ *
+ * Written by David Howells (dhowells@redhat.com).
+ *
+ * Derived from asm-i386/semaphore.h
+ *
+ *
+ * The MSW of the count is the negated number of active writers and waiting
+ * lockers, and the LSW is the total number of active locks
+ *
+ * The lock count is initialized to 0 (no active and no waiting lockers).
+ *
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
+ * uncontended lock. This can be determined because XADD returns the old value.
+ * Readers increment by 1 and see a positive value when uncontended, negative
+ * if there are writers (and maybe) readers waiting (in which case it goes to
+ * sleep).
+ *
+ * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
+ * be extended to 65534 by manually checking the whole MSW rather than relying
+ * on the S flag.
+ *
+ * The value of ACTIVE_BIAS supports up to 65535 active processes.
+ *
+ * This should be totally fair - if anything is waiting, a process that wants a
+ * lock will go to the back of the queue. When the currently active lock is
+ * released, if there's a writer at the front of the queue, then that and only
+ * that will be woken up; if there's a bunch of consequtive readers at the
+ * front, then they'll all be woken up, but no other readers will be.
+ */
+
+#ifndef _I386_RWSEM_H
+#define _I386_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *));
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	signed long		count;
+#define RWSEM_UNLOCKED_VALUE		0x00000000
+#define RWSEM_ACTIVE_BIAS		0x00000001
+#define RWSEM_ACTIVE_MASK		0x0000ffff
+#define RWSEM_WAITING_BIAS		(-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+#if RWSEM_DEBUG
+	int			debug;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
+	__RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+	sem->debug = 0;
+#endif
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"# beginning down_read\n\t"
+LOCK_PREFIX	"  incl      (%%eax)\n\t" /* adds 0x00000001, returns the old value */
+		"  js        2f\n\t" /* jump if we weren't granted the lock */
+		"1:\n\t"
+		".section .text.lock,\"ax\"\n"
+		"2:\n\t"
+		"  pushl     %%ecx\n\t"
+		"  pushl     %%edx\n\t"
+		"  call      rwsem_down_read_failed\n\t"
+		"  popl      %%edx\n\t"
+		"  popl      %%ecx\n\t"
+		"  jmp       1b\n"
+		".previous"
+		"# ending down_read\n\t"
+		: "+m"(sem->count)
+		: "a"(sem)
+		: "memory", "cc");
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"# beginning down_write\n\t"
+LOCK_PREFIX	"  xadd      %0,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */
+		"  testl     %0,%0\n\t" /* was the count 0 before? */
+		"  jnz       2f\n\t" /* jump if we weren't granted the lock */
+		"1:\n\t"
+		".section .text.lock,\"ax\"\n"
+		"2:\n\t"
+		"  pushl     %%ecx\n\t"
+		"  call      rwsem_down_write_failed\n\t"
+		"  popl      %%ecx\n\t"
+		"  jmp       1b\n"
+		".previous\n"
+		"# ending down_write"
+		: "+d"(tmp), "+m"(sem->count)
+		: "a"(sem)
+		: "memory", "cc");
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	__s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
+	__asm__ __volatile__(
+		"# beginning __up_read\n\t"
+LOCK_PREFIX	"  xadd      %%edx,(%%eax)\n\t" /* subtracts 1, returns the old value */
+		"  js        2f\n\t" /* jump if the lock is being waited upon */
+		"1:\n\t"
+		".section .text.lock,\"ax\"\n"
+		"2:\n\t"
+		"  decw      %%dx\n\t" /* do nothing if still outstanding active readers */
+		"  jnz       1b\n\t"
+		"  pushl     %%ecx\n\t"
+		"  call      rwsem_wake\n\t"
+		"  popl      %%ecx\n\t"
+		"  jmp       1b\n"
+		".previous\n"
+		"# ending __up_read\n"
+		: "+m"(sem->count), "+d"(tmp)
+		: "a"(sem)
+		: "memory", "cc");
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"# beginning __up_write\n\t"
+		"  movl      %2,%%edx\n\t"
+LOCK_PREFIX	"  xaddl     %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
+		"  jnz       2f\n\t" /* jump if the lock is being waited upon */
+		"1:\n\t"
+		".section .text.lock,\"ax\"\n"
+		"2:\n\t"
+		"  decw      %%dx\n\t" /* did the active count reduce to 0? */
+		"  jnz       1b\n\t" /* jump back if not */
+		"  pushl     %%ecx\n\t"
+		"  call      rwsem_wake\n\t"
+		"  popl      %%ecx\n\t"
+		"  jmp       1b\n"
+		".previous\n"
+		"# ending __up_write\n"
+		: "+m"(sem->count)
+		: "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS)
+		: "memory", "cc", "edx");
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+LOCK_PREFIX	"addl %1,%0"
+		:"=m"(sem->count)
+		:"ir"(delta), "m"(sem->count));
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+	int tmp = delta;
+
+	__asm__ __volatile__(
+LOCK_PREFIX	"xadd %0,(%2)"
+		: "+r"(tmp), "=m"(sem->count)
+		: "r"(sem), "m"(sem->count)
+		: "memory");
+
+	return tmp+delta;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _I386_RWSEM_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.4.3/linux/include/asm-i386/semaphore.h	Mon Mar 26 15:48:11 2001
+++ linux/include/asm-i386/semaphore.h	Wed Apr 25 16:21:35 2001
@@ -38,8 +38,8 @@
 
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/rwlock.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 	atomic_t count;
@@ -202,184 +202,6 @@
 		:"=m" (sem->count)
 		:"c" (sem)
 		:"memory");
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *		-ben
- */
-struct rw_semaphore {
-	atomic_t		count;
-	volatile unsigned char	write_bias_granted;
-	volatile unsigned char	read_bias_granted;
-	volatile unsigned char	pad1;
-	volatile unsigned char	pad2;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-/* we use FASTCALL convention for the helpers */
-extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
-
-static inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->__magic != (long)&sem->__magic)
-		BUG();
-#endif
-	__build_read_lock(sem, "__down_read_failed");
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->__magic != (long)&sem->__magic)
-		BUG();
-#endif
-	__build_write_lock(sem, "__down_write_failed");
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"# up_read\n\t"
-		LOCK "incl %0\n\t"
-		"jz 2f\n"			/* only do the wake if result == 0 (ie, a writer) */
-		"1:\n\t"
-		".section .text.lock,\"ax\"\n"
-		"2:\tcall __rwsem_wake\n\t"
-		"jmp 1b\n"
-		".previous"
-		:"=m" (sem->count)
-		:"a" (sem)
-		:"memory"
-		);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__(
-		"# up_write\n\t"
-		LOCK "addl $" RW_LOCK_BIAS_STR ",%0\n"
-		"jc 2f\n"			/* only do the wake if the result was -'ve to 0/+'ve */
-		"1:\n\t"
-		".section .text.lock,\"ax\"\n"
-		"2:\tcall __rwsem_wake\n\t"
-		"jmp 1b\n"
-		".previous"
-		:"=m" (sem->count)
-		:"a" (sem)
-		:"memory"
-		);
-}
-
-static inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-static inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
 }
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.4.3/linux/include/asm-i386/string.h	Mon Mar 26 15:48:10 2001
+++ linux/include/asm-i386/string.h	Wed Apr 25 16:21:26 2001
@@ -446,34 +446,8 @@
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
-static inline char * strstr(const char * cs,const char * ct)
-{
-int	d0, d1;
-register char * __res;
-__asm__ __volatile__(
-	"movl %6,%%edi\n\t"
-	"repne\n\t"
-	"scasb\n\t"
-	"notl %%ecx\n\t"
-	"decl %%ecx\n\t"	/* NOTE! This also sets Z if searchstring='' */
-	"movl %%ecx,%%edx\n"
-	"1:\tmovl %6,%%edi\n\t"
-	"movl %%esi,%%eax\n\t"
-	"movl %%edx,%%ecx\n\t"
-	"repe\n\t"
-	"cmpsb\n\t"
-	"je 2f\n\t"		/* also works for empty string, see above */
-	"xchgl %%eax,%%esi\n\t"
-	"incl %%esi\n\t"
-	"cmpb $0,-1(%%eax)\n\t"
-	"jne 1b\n\t"
-	"xorl %%eax,%%eax\n\t"
-	"2:"
-	:"=a" (__res), "=&c" (d0), "=&S" (d1)
-	:"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
-	:"dx", "di");
-return __res;
-}
+
+extern char *strstr(const char *cs, const char *ct);
 
 /*
  * This looks horribly ugly, but the compiler can optimize it totally,
diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- v2.4.3/linux/include/asm-i386/uaccess.h	Mon Mar 26 15:48:13 2001
+++ linux/include/asm-i386/uaccess.h	Wed Apr 25 16:21:43 2001
@@ -542,6 +542,8 @@
 {
 	if (access_ok(VERIFY_READ, from, n))
 		__constant_copy_user_zeroing(to,from,n);
+	else
+		memset(to, 0, n);
 	return n;
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/a.out.h linux/include/asm-ia64/a.out.h
--- v2.4.3/linux/include/asm-ia64/a.out.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/a.out.h	Thu Apr  5 12:51:47 2001
@@ -30,7 +30,8 @@
 #define N_TXTOFF(x)	0
 
 #ifdef __KERNEL__
-# define STACK_TOP	(0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)))
+# include <asm/page.h>
+# define STACK_TOP	(0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE)
 # define IA64_RBS_BOT	(STACK_TOP - 0x80000000L)	/* bottom of register backing store */
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/acpikcfg.h linux/include/asm-ia64/acpikcfg.h
--- v2.4.3/linux/include/asm-ia64/acpikcfg.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/acpikcfg.h	Thu Apr  5 12:51:47 2001
@@ -1,4 +1,5 @@
 #include <linux/config.h>
+
 #ifdef	CONFIG_ACPI_KERNEL_CONFIG
 /*
  *  acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/asmmacro.h linux/include/asm-ia64/asmmacro.h
--- v2.4.3/linux/include/asm-ia64/asmmacro.h	Fri Aug 11 19:09:06 2000
+++ linux/include/asm-ia64/asmmacro.h	Thu Apr  5 12:51:47 2001
@@ -2,26 +2,10 @@
 #define _ASM_IA64_ASMMACRO_H
 
 /*
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000-2001 Hewlett-Packard Co
+ * Copyright (C) 2000-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#if 1
-
-/*
- * This is a hack that's necessary as long as we support old versions
- * of gas, that have no unwind support.
- */
-#include <linux/config.h>
-
-#ifdef CONFIG_IA64_NEW_UNWIND
-# define UNW(args...)	args
-#else
-# define UNW(args...)
-#endif
-
-#endif
-
 #define ENTRY(name)				\
 	.align 32;				\
 	.proc name;				\
@@ -44,5 +28,28 @@
 #define ASM_UNW_PRLG_PSP		0x2
 #define ASM_UNW_PRLG_PR			0x1
 #define ASM_UNW_PRLG_GRSAVE(ninputs)	(32+(ninputs))
+
+/*
+ * Helper macros for accessing user memory.
+ */
+
+	.section "__ex_table", "a"		// declare section & section attributes
+	.previous
+
+#if __GNUC__ >= 3
+# define EX(y,x...)					\
+	.xdata4 "__ex_table", @gprel(99f), @gprel(y);	\
+  [99:]	x
+# define EXCLR(y,x...)					\
+	.xdata4 "__ex_table", @gprel(99f), @gprel(y)+4;	\
+  [99:]	x
+#else
+# define EX(y,x...)					\
+	.xdata4 "__ex_table", @gprel(99f), @gprel(y);	\
+  99:	x
+# define EXCLR(y,x...)					\
+	.xdata4 "__ex_table", @gprel(99f), @gprel(y)+4;	\
+  99:	x
+#endif
 
 #endif /* _ASM_IA64_ASMMACRO_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/bitops.h linux/include/asm-ia64/bitops.h
--- v2.4.3/linux/include/asm-ia64/bitops.h	Mon Oct  9 17:54:57 2000
+++ linux/include/asm-ia64/bitops.h	Thu Apr  5 12:51:47 2001
@@ -158,6 +158,7 @@
 	__asm__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d));
 	return exp - 0xffff;
 }
+
 /*
  * ffs: find first bit set. This is defined the same way as
  * the libc and compiler builtin ffs routines, therefore
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/byteorder.h linux/include/asm-ia64/byteorder.h
--- v2.4.3/linux/include/asm-ia64/byteorder.h	Sun Feb  6 18:42:40 2000
+++ linux/include/asm-ia64/byteorder.h	Thu Apr  5 12:51:47 2001
@@ -20,18 +20,18 @@
 static __inline__ __const__ __u32
 __ia64_swab32 (__u32 x)
 {
-	return __ia64_swab64 (x) >> 32;
+	return __ia64_swab64(x) >> 32;
 }
 
 static __inline__ __const__ __u16
 __ia64_swab16(__u16 x)
 {
-	return __ia64_swab64 (x) >> 48;
+	return __ia64_swab64(x) >> 48;
 }
 
-#define __arch__swab64(x) __ia64_swab64 (x)
-#define __arch__swab32(x) __ia64_swab32 (x)
-#define __arch__swab16(x) __ia64_swab16 (x)
+#define __arch__swab64(x) __ia64_swab64(x)
+#define __arch__swab32(x) __ia64_swab32(x)
+#define __arch__swab16(x) __ia64_swab16(x)
 
 #define __BYTEORDER_HAS_U64__
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/cache.h linux/include/asm-ia64/cache.h
--- v2.4.3/linux/include/asm-ia64/cache.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/cache.h	Thu Apr  5 12:51:47 2001
@@ -9,7 +9,7 @@
  */
 
 /* Bytes per L1 (data) cache line.  */
-#define L1_CACHE_SHIFT		6
+#define L1_CACHE_SHIFT		CONFIG_IA64_L1_CACHE_SHIFT
 #define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
 
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/delay.h linux/include/asm-ia64/delay.h
--- v2.4.3/linux/include/asm-ia64/delay.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/delay.h	Thu Apr  5 12:51:47 2001
@@ -34,13 +34,9 @@
 }
 
 static __inline__ void
-ia64_set_itv (unsigned char vector, unsigned char masked)
+ia64_set_itv (unsigned long val)
 {
-	if (masked > 1)
-		masked = 1;
-
-	__asm__ __volatile__("mov cr.itv=%0;; srlz.d;;"
-			     :: "r"((masked << 16) | vector) : "memory");
+	__asm__ __volatile__("mov cr.itv=%0;; srlz.d;;" :: "r"(val) : "memory");
 }
 
 static __inline__ void
@@ -79,16 +75,11 @@
 static __inline__ void
 udelay (unsigned long usecs)
 {
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-	while (usecs--)
-		;
-#else
 	unsigned long start = ia64_get_itc();
-	unsigned long cycles = usecs*my_cpu_data.cyc_per_usec;
+	unsigned long cycles = usecs*local_cpu_data->cyc_per_usec;
 
 	while (ia64_get_itc() - start < cycles)
 		/* skip */;
-#endif	/* CONFIG_IA64_SOFTSDV_HACKS */
 }
 
 #endif /* _ASM_IA64_DELAY_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/dma.h linux/include/asm-ia64/dma.h
--- v2.4.3/linux/include/asm-ia64/dma.h	Thu Jun 22 07:09:45 2000
+++ linux/include/asm-ia64/dma.h	Thu Apr  5 12:51:47 2001
@@ -2,35 +2,20 @@
 #define _ASM_IA64_DMA_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>
-#include <linux/spinlock.h>	/* And spinlocks */
-#include <linux/delay.h>
 
 #include <asm/io.h>		/* need byte IO */
 
-#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
-#define dma_outb	outb_p
-#else
-#define dma_outb	outb
-#endif
-
-#define dma_inb		inb
-
-#define MAX_DMA_CHANNELS	8
-#define MAX_DMA_ADDRESS		0xffffffffUL
-
-extern spinlock_t  dma_spin_lock;
-
-/* From PCI */
+extern unsigned long MAX_DMA_ADDRESS;
 
 #ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
+  extern int isa_dma_bridge_buggy;
 #else
-#define isa_dma_bridge_buggy 	(0)
+# define isa_dma_bridge_buggy 	(0)
 #endif
 
 #endif /* _ASM_IA64_DMA_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/efi.h linux/include/asm-ia64/efi.h
--- v2.4.3/linux/include/asm-ia64/efi.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/efi.h	Thu Apr  5 12:51:47 2001
@@ -4,7 +4,7 @@
 /*
  * Extensible Firmware Interface
  * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999
- * 
+ *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999 Hewlett-Packard Co.
@@ -20,9 +20,12 @@
 #include <asm/system.h>
 
 #define EFI_SUCCESS		0
-#define EFI_INVALID_PARAMETER	2
-#define EFI_UNSUPPORTED		3
-#define EFI_BUFFER_TOO_SMALL	4
+#define EFI_LOAD_ERROR          (1L | (1L << 63))
+#define EFI_INVALID_PARAMETER	(2L | (1L << 63))
+#define EFI_UNSUPPORTED		(3L | (1L << 63))
+#define EFI_BAD_BUFFER_SIZE     (4L | (1L << 63))
+#define EFI_BUFFER_TOO_SMALL	(5L | (1L << 63))
+#define EFI_NOT_FOUND          (14L | (1L << 63))
 
 typedef unsigned long efi_status_t;
 typedef u8 efi_bool_t;
@@ -173,7 +176,7 @@
 
 #define SMBIOS_TABLE_GUID    \
     ((efi_guid_t) { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
-	
+
 #define SAL_SYSTEM_TABLE_GUID    \
     ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
 
@@ -183,7 +186,7 @@
 } efi_config_table_t;
 
 #define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249
-#define EFI_SYSTEM_TABLE_REVISION  ((0 << 16) | (92))
+#define EFI_SYSTEM_TABLE_REVISION  ((1 << 16) | 00)
 
 typedef struct {
 	efi_table_hdr_t hdr;
@@ -234,5 +237,13 @@
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timeval *tv);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
+
+
+/*
+ * Variable Attributes
+ */
+#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
 
 #endif /* _ASM_IA64_EFI_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/hardirq.h linux/include/asm-ia64/hardirq.h
--- v2.4.3/linux/include/asm-ia64/hardirq.h	Sun Dec  3 17:45:23 2000
+++ linux/include/asm-ia64/hardirq.h	Thu Apr  5 12:51:47 2001
@@ -2,8 +2,8 @@
 #define _ASM_IA64_HARDIRQ_H
 
 /*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>
@@ -11,36 +11,38 @@
 #include <linux/threads.h>
 #include <linux/irq.h>
 
-/* entry.S is sensitive to the offsets of these fields */
-typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
-	unsigned int __local_irq_count;
-	unsigned int __local_bh_count;
-	unsigned int __syscall_count;
-	unsigned int __nmi_count;	/* arch dependent */
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+#include <asm/processor.h>
 
 /*
- * Are we in an interrupt context? Either doing bottom half
- * or hardware interrupt processing?
+ * No irq_cpustat_t for IA-64.  The data is held in the per-CPU data structure.
  */
-#define in_interrupt()						\
-({								\
-	int __cpu = smp_processor_id();				\
-	(local_irq_count(__cpu) + local_bh_count(__cpu)) != 0;	\
-})
+#define softirq_active(cpu)		(cpu_data[cpu].softirq.active)
+#define softirq_mask(cpu)		(cpu_data[cpu].softirq.mask)
+#define irq_count(cpu)			(cpu_data[cpu].irq_stat.f.irq_count)
+#define bh_count(cpu)			(cpu_data[cpu].irq_stat.f.bh_count)
+#define syscall_count(cpu)		/* unused on IA-64 */
+#define nmi_count(cpu)			0
+
+#define local_softirq_active()		(local_cpu_data->softirq.active)
+#define local_softirq_mask()		(local_cpu_data->softirq.mask)
+#define local_irq_count()		(local_cpu_data->irq_stat.f.irq_count)
+#define local_bh_count()		(local_cpu_data->irq_stat.f.bh_count)
+#define local_syscall_count()		/* unused on IA-64 */
+#define local_nmi_count()		0
 
-#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+/*
+ * Are we in an interrupt context? Either doing bottom half or hardware interrupt
+ * processing?
+ */
+#define in_interrupt()			(local_cpu_data->irq_stat.irq_and_bh_counts != 0)
+#define in_irq()			(local_cpu_data->irq_stat.f.irq_count != 0)
 
 #ifndef CONFIG_SMP
-# define hardirq_trylock(cpu)		(local_irq_count(cpu) == 0)
-# define hardirq_endlock(cpu)		do { } while (0)
+# define local_hardirq_trylock()	(local_irq_count() == 0)
+# define local_hardirq_endlock()	do { } while (0)
 
-# define irq_enter(cpu, irq)		(local_irq_count(cpu)++)
-# define irq_exit(cpu, irq)		(local_irq_count(cpu)--)
+# define local_irq_enter(irq)		(local_irq_count()++)
+# define local_irq_exit(irq)		(local_irq_count()--)
 
 # define synchronize_irq()		barrier()
 #else
@@ -51,17 +53,19 @@
 extern unsigned int global_irq_holder;
 extern volatile unsigned long global_irq_lock;
 
-static inline int irqs_running (void)
+static inline int
+irqs_running (void)
 {
 	int i;
 
 	for (i = 0; i < smp_num_cpus; i++)
-		if (local_irq_count(i))
+		if (irq_count(i))
 			return 1;
 	return 0;
 }
 
-static inline void release_irqlock(int cpu)
+static inline void
+release_irqlock (int cpu)
 {
 	/* if we didn't own the irq lock, just ignore.. */
 	if (global_irq_holder == cpu) {
@@ -70,28 +74,31 @@
         }
 }
 
-static inline void irq_enter(int cpu, int irq)
+static inline void
+local_irq_enter (int irq)
 {
-	local_irq_count(cpu)++;
+	local_irq_count()++;
 
 	while (test_bit(0,&global_irq_lock)) {
 		/* nothing */;
 	}
 }
 
-static inline void irq_exit(int cpu, int irq)
+static inline void
+local_irq_exit (int irq)
 {
-	local_irq_count(cpu)--;
+	local_irq_count()--;
 }
 
-static inline int hardirq_trylock(int cpu)
+static inline int
+local_hardirq_trylock (void)
 {
-	return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock);
+	return !local_irq_count() && !test_bit(0,&global_irq_lock);
 }
 
-#define hardirq_endlock(cpu)	do { } while (0)
+#define local_hardirq_endlock()		do { } while (0)
 
-extern void synchronize_irq(void);
+extern void synchronize_irq (void);
 
 #endif /* CONFIG_SMP */
 #endif /* _ASM_IA64_HARDIRQ_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/hw_irq.h linux/include/asm-ia64/hw_irq.h
--- v2.4.3/linux/include/asm-ia64/hw_irq.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/hw_irq.h	Thu Apr  5 12:51:47 2001
@@ -2,8 +2,8 @@
 #define _ASM_IA64_HW_IRQ_H
 
 /*
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/sched.h>
@@ -13,6 +13,8 @@
 #include <asm/ptrace.h>
 #include <asm/smp.h>
 
+typedef u8 ia64_vector;
+
 /*
  * 0 special
  *
@@ -26,31 +28,32 @@
  *
  * 15 classes of 16 interrupts each.
  */
-#define IA64_MIN_VECTORED_IRQ	 16
-#define IA64_MAX_VECTORED_IRQ	255
+#define IA64_MIN_VECTORED_IRQ		 16
+#define IA64_MAX_VECTORED_IRQ		255
+#define IA64_NUM_VECTORS		256
 
-#define IA64_SPURIOUS_INT	0x0f
+#define IA64_SPURIOUS_INT_VECTOR	0x0f
 
 /*
  * Vectors 0x10-0x1f are used for low priority interrupts, e.g. CMCI.
  */
-#define PCE_IRQ			0x1e	/* platform corrected error interrupt vector */
-#define CMC_IRQ			0x1f	/* correctable machine-check interrupt vector */
+#define IA64_PCE_VECTOR			0x1e	/* platform corrected error interrupt vector */
+#define IA64_CMC_VECTOR			0x1f	/* correctable machine-check interrupt vector */
 /*
  * Vectors 0x20-0x2f are reserved for legacy ISA IRQs.
  */
-#define FIRST_DEVICE_IRQ	0x30
-#define LAST_DEVICE_IRQ		0xe7
+#define IA64_FIRST_DEVICE_VECTOR	0x30
+#define IA64_LAST_DEVICE_VECTOR		0xe7
 
-#define MCA_RENDEZ_IRQ		0xe8	/* MCA rendez interrupt */
-#define PERFMON_IRQ		0xee	/* performanc monitor interrupt vector */
-#define TIMER_IRQ		0xef	/* use highest-prio group 15 interrupt for timer */
-#define	MCA_WAKEUP_IRQ		0xf0	/* MCA wakeup interrupt (must be higher than MCA_RENDEZ_IRQ) */
-#define IPI_IRQ			0xfe	/* inter-processor interrupt vector */
+#define IA64_MCA_RENDEZ_VECTOR		0xe8	/* MCA rendez interrupt */
+#define IA64_PERFMON_VECTOR		0xee	/* performanc monitor interrupt vector */
+#define IA64_TIMER_VECTOR		0xef	/* use highest-prio group 15 interrupt for timer */
+#define	IA64_MCA_WAKEUP_VECTOR		0xf0	/* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */
+#define IA64_IPI_VECTOR			0xfe	/* inter-processor interrupt vector */
 
 /* IA64 inter-cpu interrupt related definitions */
 
-#define IPI_DEFAULT_BASE_ADDR	0xfee00000
+#define IA64_IPI_DEFAULT_BASE_ADDR	0xfee00000
 
 /* Delivery modes for inter-cpu interrupts */
 enum {
@@ -61,9 +64,6 @@
         IA64_IPI_DM_EXTINT =    0x7,    /* pend an 8259-compatible interrupt. */
 };
 
-#define IA64_BUS_ID(cpu)        (cpu >> 8)
-#define IA64_LOCAL_ID(cpu)      (cpu & 0xff)
-
 extern __u8 isa_irq_to_vector_map[16];
 #define isa_irq_to_vector(x)	isa_irq_to_vector_map[(x)]
 
@@ -73,11 +73,71 @@
 
 extern int ia64_alloc_irq (void);	/* allocate a free irq */
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
+extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
 static inline void
 hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector)
 {
 	platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
+}
+
+/*
+ * Default implementations for the irq-descriptor API:
+ */
+
+extern struct irq_desc _irq_desc[NR_IRQS];
+
+static inline struct irq_desc *
+__ia64_irq_desc (unsigned int irq)
+{
+	return _irq_desc + irq;
+}
+
+static inline ia64_vector
+__ia64_irq_to_vector (unsigned int irq)
+{
+	return (ia64_vector) irq;
+}
+
+static inline unsigned int
+__ia64_local_vector_to_irq (ia64_vector vec)
+{
+	return (unsigned int) vec;
+}
+
+/*
+ * Next follows the irq descriptor interface.  On IA-64, each CPU supports 256 interrupt
+ * vectors.  On smaller systems, there is a one-to-one correspondence between interrupt
+ * vectors and the Linux irq numbers.  However, larger systems may have multiple interrupt
+ * domains meaning that the translation from vector number to irq number depends on the
+ * interrupt domain that a CPU belongs to.  This API abstracts such platform-dependent
+ * differences and provides a uniform means to translate between vector and irq numbers
+ * and to obtain the irq descriptor for a given irq number.
+ */
+
+/* Return a pointer to the irq descriptor for IRQ.  */
+static inline struct irq_desc *
+irq_desc (int irq)
+{
+	return platform_irq_desc(irq);
+}
+
+/* Extract the IA-64 vector that corresponds to IRQ.  */
+static inline ia64_vector
+irq_to_vector (int irq)
+{
+	return platform_irq_to_vector(irq);
+}
+
+/*
+ * Convert the local IA-64 vector to the corresponding irq number.  This translation is
+ * done in the context of the interrupt domain that the currently executing CPU belongs
+ * to.
+ */
+static inline unsigned int
+local_vector_to_irq (ia64_vector vec)
+{
+	return platform_local_vector_to_irq(vec);
 }
 
 #endif /* _ASM_IA64_HW_IRQ_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/ia32.h linux/include/asm-ia64/ia32.h
--- v2.4.3/linux/include/asm-ia64/ia32.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/ia32.h	Fri Apr 13 20:26:07 2001
@@ -355,7 +355,7 @@
 		(granularity << IA32_SEG_G)		       |       \
 		(((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE)) 
 
-#define IA32_IOBASE    0x2000000000000000 /* Virtual addres for I/O space */
+#define IA32_IOBASE    0x2000000000000000 /* Virtual address for I/O space */
 
 #define IA32_CR0       0x80000001      /* Enable PG and PE bits */
 #define IA32_CR4       0	       /* No architectural extensions */
@@ -378,9 +378,10 @@
 	ia64_psr(regs)->ri = 0;		/* clear return slot number */		\
 	ia64_psr(regs)->is = 1;		/* IA-32 instruction set */		\
 	regs->cr_iip = new_ip;							\
-	regs->r12 = new_sp;							\
+	regs->ar_rsc = 0xc;		/* enforced lazy mode, priv. level 3 */	\
 	regs->ar_rnat = 0;							\
 	regs->loadrs = 0;							\
+	regs->r12 = new_sp;							\
 } while (0)
 
 extern void ia32_gdt_init (void);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/io.h linux/include/asm-ia64/io.h
--- v2.4.3/linux/include/asm-ia64/io.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/io.h	Thu Apr  5 12:51:47 2001
@@ -13,8 +13,8 @@
  * over and over again with slight variations and possibly making a
  * mistake somewhere.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  */
@@ -82,21 +82,11 @@
 }
 
 /*
- * For the in/out instructions, we need to do:
- *
- *	o "mf" _before_ doing the I/O access to ensure that all prior
- *	  accesses to memory occur before the I/O access
- *	o "mf.a" _after_ doing the I/O access to ensure that the access
- *	  has completed before we're doing any other I/O accesses
- *
- * The former is necessary because we might be doing normal (cached) memory
- * accesses, e.g., to set up a DMA descriptor table and then do an "outX()"
- * to tell the DMA controller to start the DMA operation.  The "mf" ahead
- * of the I/O operation ensures that the DMA table is correct when the I/O
- * access occurs.
- *
- * The mf.a is necessary to ensure that all I/O access occur in program
- * order. --davidm 99/12/07 
+ * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure
+ * that the access has completed before executing other I/O accesses.  Since we're doing
+ * the accesses through an uncachable (UC) translation, the CPU will execute them in
+ * program order.  However, we still need to tell the compiler not to shuffle them around
+ * during optimization, which is why we use "volatile" pointers.
  */
 
 static inline unsigned int
@@ -378,17 +368,16 @@
 #endif
 
 /*
- * An "address" in IO memory space is not clearly either an integer
- * or a pointer. We will accept both, thus the casts.
+ * An "address" in IO memory space is not clearly either an integer or a pointer. We will
+ * accept both, thus the casts.
  *
- * On ia-64, we access the physical I/O memory space through the
- * uncached kernel region.
+ * On ia-64, we access the physical I/O memory space through the uncached kernel region.
  */
 static inline void *
 ioremap (unsigned long offset, unsigned long size)
 {
 	return (void *) (__IA64_UNCACHED_OFFSET | (offset));
-} 
+}
 
 static inline void
 iounmap (void *addr)
@@ -412,75 +401,6 @@
   __ia64_memcpy_toio((unsigned long)(to),(from),(len))
 #define memset_io(addr,c,len) \
   __ia64_memset_c_io((unsigned long)(addr),0x0101010101010101UL*(u8)(c),(len))
-
-#define __HAVE_ARCH_MEMSETW_IO
-#define memsetw_io(addr,c,len) \
-  _memset_c_io((unsigned long)(addr),0x0001000100010001UL*(u16)(c),(len))
-
-/*
- * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and 
- * just copy it. The net code will then do the checksum later. Presently 
- * only used by some shared memory 8390 Ethernet cards anyway.
- */
-
-#define eth_io_copy_and_sum(skb,src,len,unused)		memcpy_fromio((skb)->data,(src),(len))
-
-#if 0
-
-/*
- * XXX this is the kind of legacy stuff we want to get rid of with IA-64... --davidm 99/12/02
- */
-
-/*
- * This is used for checking BIOS signatures.  It's not clear at all
- * why this is here.  This implementation seems to be the same on
- * all architectures.  Strange.
- */
-static inline int
-check_signature (unsigned long io_addr, const unsigned char *signature, int length)
-{
-	int retval = 0;
-	do {
-		if (readb(io_addr) != *signature)
-			goto out;
-		io_addr++;
-		signature++;
-		length--;
-	} while (length);
-	retval = 1;
-out:
-	return retval;
-}
-
-#define RTC_PORT(x)		(0x70 + (x))
-#define RTC_ALWAYS_BCD		0
-
-#endif
-
-/*
- * The caches on some architectures aren't DMA-coherent and have need
- * to handle this in software.  There are two types of operations that
- * can be applied to dma buffers.
- *
- * - dma_cache_inv(start, size) invalidates the affected parts of the
- *   caches.  Dirty lines of the caches may be written back or simply
- *   be discarded.  This operation is necessary before dma operations
- *   to the memory.
- *
- * - dma_cache_wback(start, size) makes caches and memory coherent
- *   by writing the content of the caches back to memory, if necessary
- *   (cache flush).
- *
- * - dma_cache_wback_inv(start, size) Like dma_cache_wback() but the
- *   function also invalidates the affected part of the caches as
- *   necessary before DMA transfers from outside to memory.
- *
- * Fortunately, the IA-64 architecture mandates cache-coherent DMA, so
- * these functions can be implemented as no-ops.
- */
-#define dma_cache_inv(_start,_size)		do { } while (0)
-#define dma_cache_wback(_start,_size)		do { } while (0)
-#define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
 # endif /* __KERNEL__ */
 #endif /* _ASM_IA64_IO_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/kregs.h linux/include/asm-ia64/kregs.h
--- v2.4.3/linux/include/asm-ia64/kregs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ia64/kregs.h	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,33 @@
+#ifndef _ASM_IA64_KREGS_H
+#define _ASM_IA64_KREGS_H
+
+/*
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+/*
+ * This file defines the kernel register usage convention used by Linux/ia64.
+ */
+
+/*
+ * Kernel registers:
+ */
+#define IA64_KR_IO_BASE		0	/* ar.k0: legacy I/O base address */
+#define IA64_KR_CURRENT_STACK	4	/* ar.k4: what's mapped in IA64_TR_CURRENT_STACK */
+#define IA64_KR_FPU_OWNER	5	/* ar.k5: fpu-owner (UP only, at the moment) */
+#define IA64_KR_CURRENT		6	/* ar.k6: "current" task pointer */
+#define IA64_KR_PT_BASE		7	/* ar.k7: page table base address (physical) */
+
+#define _IA64_KR_PASTE(x,y)	x##y
+#define _IA64_KR_PREFIX(n)	_IA64_KR_PASTE(ar.k, n)
+#define IA64_KR(n)		_IA64_KR_PREFIX(IA64_KR_##n)
+
+/*
+ * Translation registers:
+ */
+#define IA64_TR_KERNEL		0	/* itr0, dtr0: maps kernel image (code & data) */
+#define IA64_TR_PALCODE		1	/* itr1: maps PALcode as required by EFI */
+#define IA64_TR_PERCPU_DATA	1	/* dtr1: percpu data */
+#define IA64_TR_CURRENT_STACK	2	/* dtr2: maps kernel memory & register stacks */
+
+#endif /* _ASM_IA64_kREGS_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/machvec.h linux/include/asm-ia64/machvec.h
--- v2.4.3/linux/include/asm-ia64/machvec.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/machvec.h	Thu Apr  5 12:51:47 2001
@@ -4,8 +4,8 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
  * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
- * Copyright (C) 1999-2000 Hewlett-Packard Co.
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 Hewlett-Packard Co.
+ * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef _ASM_IA64_MACHVEC_H
 #define _ASM_IA64_MACHVEC_H
@@ -17,6 +17,7 @@
 struct pci_dev;
 struct pt_regs;
 struct scatterlist;
+struct irq_desc;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_irq_init_t (void);
@@ -27,6 +28,9 @@
 typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *);
 typedef void ia64_mv_log_print_t (void);
 typedef void ia64_mv_send_ipi_t (int, int, int, int);
+typedef struct irq_desc *ia64_mv_irq_desc (unsigned int);
+typedef u8 ia64_mv_irq_to_vector (u8);
+typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector);
 
 /* PCI-DMA interface: */
 typedef void ia64_mv_pci_dma_init (void);
@@ -88,6 +92,9 @@
 #  define platform_pci_dma_sync_single	ia64_mv.sync_single
 #  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
 #  define platform_pci_dma_address	ia64_mv.dma_address
+#  define platform_irq_desc		ia64_mv.irq_desc
+#  define platform_irq_to_vector	ia64_mv.irq_to_vector
+#  define platform_local_vector_to_irq	ia64_mv.local_vector_to_irq
 #  define platform_inb		ia64_mv.inb
 #  define platform_inw		ia64_mv.inw
 #  define platform_inl		ia64_mv.inl
@@ -117,6 +124,9 @@
 	ia64_mv_pci_dma_sync_single *sync_single;
 	ia64_mv_pci_dma_sync_sg *sync_sg;
 	ia64_mv_pci_dma_address *dma_address;
+	ia64_mv_irq_desc *irq_desc;
+	ia64_mv_irq_to_vector *irq_to_vector;
+	ia64_mv_local_vector_to_irq *local_vector_to_irq;
 	ia64_mv_inb_t *inb;
 	ia64_mv_inw_t *inw;
 	ia64_mv_inl_t *inl;
@@ -147,6 +157,9 @@
 	platform_pci_dma_sync_single,		\
 	platform_pci_dma_sync_sg,		\
 	platform_pci_dma_address,		\
+	platform_irq_desc,			\
+	platform_irq_to_vector,			\
+	platform_local_vector_to_irq,		\
 	platform_inb,				\
 	platform_inw,				\
 	platform_inl,				\
@@ -233,6 +246,15 @@
 #endif
 #ifndef platform_pci_dma_address
 # define  platform_pci_dma_address	swiotlb_dma_address
+#endif
+#ifndef platform_irq_desc
+# define platform_irq_desc		__ia64_irq_desc
+#endif
+#ifndef platform_irq_to_vector
+# define platform_irq_to_vector		__ia64_irq_to_vector
+#endif
+#ifndef platform_local_vector_to_irq
+# define platform_local_vector_to_irq	__ia64_local_vector_to_irq
 #endif
 #ifndef platform_inb
 # define platform_inb		__ia64_inb
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/machvec_sn1.h linux/include/asm-ia64/machvec_sn1.h
--- v2.4.3/linux/include/asm-ia64/machvec_sn1.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/machvec_sn1.h	Thu Apr  5 12:51:47 2001
@@ -41,6 +41,7 @@
 #define platform_outb		sn1_outb
 #define platform_outw		sn1_outw
 #define platform_outl		sn1_outl
+#define platform_pci_dma_init	machvec_noop
 #define platform_pci_alloc_consistent	sn1_pci_alloc_consistent
 #define platform_pci_free_consistent	sn1_pci_free_consistent
 #define platform_pci_map_single		sn1_pci_map_single
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/mca.h linux/include/asm-ia64/mca.h
--- v2.4.3/linux/include/asm-ia64/mca.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/mca.h	Thu Apr  5 12:51:47 2001
@@ -1,6 +1,6 @@
 /*
- * File: 	mca.h
- * Purpose: 	Machine check handling specific defines
+ * File:	mca.h
+ * Purpose:	Machine check handling specific defines
  *
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
@@ -18,7 +18,6 @@
 #include <asm/param.h>
 #include <asm/sal.h>
 #include <asm/processor.h>
-#include <asm/hw_irq.h>
 
 /* These are the return codes from all the IA64_MCA specific interfaces */
 typedef	int ia64_mca_return_code_t;
@@ -30,11 +29,6 @@
 
 #define IA64_MCA_RENDEZ_TIMEOUT		(100 * HZ)	/* 1000 milliseconds */
 
-/* Interrupt vectors reserved for MC handling. */
-#define IA64_MCA_RENDEZ_INT_VECTOR	MCA_RENDEZ_IRQ	/* Rendez interrupt */
-#define IA64_MCA_WAKEUP_INT_VECTOR	MCA_WAKEUP_IRQ	/* Wakeup interrupt */
-#define IA64_MCA_CMC_INT_VECTOR		CMC_IRQ	/* Correctable machine check interrupt */
-
 #define IA64_CMC_INT_DISABLE		0
 #define IA64_CMC_INT_ENABLE		1
 
@@ -45,7 +39,7 @@
 typedef union cmcv_reg_u {
 	u64	cmcv_regval;
 	struct	{
-		u64  	cmcr_vector		: 8;
+		u64	cmcr_vector		: 8;
 		u64	cmcr_reserved1		: 4;
 		u64	cmcr_ignored1		: 1;
 		u64	cmcr_reserved2		: 3;
@@ -63,15 +57,15 @@
 #define IA64_INIT_HANDLER_SIZE		0x10
 
 enum {
-	IA64_MCA_RENDEZ_CHECKIN_NOTDONE	= 	0x0,
-	IA64_MCA_RENDEZ_CHECKIN_DONE 	= 	0x1
+	IA64_MCA_RENDEZ_CHECKIN_NOTDONE	=	0x0,
+	IA64_MCA_RENDEZ_CHECKIN_DONE	=	0x1
 };
 
 #define IA64_MAXCPUS	64	/* Need to do something about this */
 
 /* Information maintained by the MC infrastructure */
 typedef struct ia64_mc_info_s {
-	u64		imi_mca_handler;		
+	u64		imi_mca_handler;
 	size_t		imi_mca_handler_size;
 	u64		imi_monarch_init_handler;
 	size_t		imi_monarch_init_handler_size;
@@ -85,7 +79,7 @@
  * handoff
  */
 enum {
-	IA64_MCA_RENDEZ_NOT_RQD 		= 	0x0,
+	IA64_MCA_RENDEZ_NOT_RQD		=	0x0,
 	IA64_MCA_RENDEZ_DONE_WITHOUT_INIT	=	0x1,
 	IA64_MCA_RENDEZ_DONE_WITH_INIT		=	0x2,
 	IA64_MCA_RENDEZ_FAILURE			=	-1
@@ -103,12 +97,12 @@
 } ia64_mca_sal_to_os_state_t;
 
 enum {
-	IA64_MCA_CORRECTED 	= 	0x0,	/* Error has been corrected by OS_MCA */
+	IA64_MCA_CORRECTED	=	0x0,	/* Error has been corrected by OS_MCA */
 	IA64_MCA_WARM_BOOT	=	-1,	/* Warm boot of the system need from SAL */
 	IA64_MCA_COLD_BOOT	=	-2,	/* Cold boot of the system need from SAL */
 	IA64_MCA_HALT		=	-3	/* System to be halted by SAL */
 };
-	
+
 typedef struct ia64_mca_os_to_sal_state_s {
 	u64		imots_os_status;	/*   OS status to SAL as to what happened
 						 *   with the MCA handling.
@@ -138,7 +132,7 @@
 
 #define PLATFORM_CALL(fn, args)	printk("Platform call TBD\n")
 
-#undef 	MCA_TEST
+#undef	MCA_TEST
 
 #define IA64_MCA_DEBUG_INFO 1
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/mca_asm.h linux/include/asm-ia64/mca_asm.h
--- v2.4.3/linux/include/asm-ia64/mca_asm.h	Fri Apr 21 15:21:24 2000
+++ linux/include/asm-ia64/mca_asm.h	Thu Apr  5 12:51:47 2001
@@ -72,7 +72,7 @@
 	;;										\
 	dep	old_psr = 0, old_psr, 32, 32;						\
 	                                                                                \
-	mov	ar.rsc = r0 ;								\
+	mov	ar.rsc = 0 ;								\
 	;;										\
 	mov	temp2 = ar.bspstore;							\
 	;;										\
@@ -148,7 +148,7 @@
 	dep	temp2 = 0, temp2, PSR_IC, 2;						\
 	;;										\
 	mov	psr.l = temp2;								\
-	mov	ar.rsc = r0;								\
+	mov	ar.rsc = 0;								\
 	;;										\
 	srlz.d;										\
 	mov	temp2 = ar.bspstore;							\
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/mmu_context.h linux/include/asm-ia64/mmu_context.h
--- v2.4.3/linux/include/asm-ia64/mmu_context.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/mmu_context.h	Thu Apr  5 12:51:47 2001
@@ -2,35 +2,32 @@
 #define _ASM_IA64_MMU_CONTEXT_H
 
 /*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-
-#include <asm/processor.h>
-
 /*
- * Routines to manage the allocation of task context numbers.  Task
- * context numbers are used to reduce or eliminate the need to perform
- * TLB flushes due to context switches.  Context numbers are
- * implemented using ia-64 region ids.  Since ia-64 TLBs do not
- * guarantee that the region number is checked when performing a TLB
- * lookup, we need to assign a unique region id to each region in a
- * process.  We use the least significant three bits in a region id
- * for this purpose.  On processors where the region number is checked
- * in TLB lookups, we can get back those two bits by defining
- * CONFIG_IA64_TLB_CHECKS_REGION_NUMBER.  The macro
- * IA64_REGION_ID_BITS gives the number of bits in a region id.  The
- * architecture manual guarantees this number to be in the range
- * 18-24.
+ * Routines to manage the allocation of task context numbers.  Task context numbers are
+ * used to reduce or eliminate the need to perform TLB flushes due to context switches.
+ * Context numbers are implemented using ia-64 region ids.  Since the IA-64 TLB does not
+ * consider the region number when performing a TLB lookup, we need to assign a unique
+ * region id to each region in a process.  We use the least significant three bits in a
+ * region id for this purpose.
  *
- * Copyright (C) 1998 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #define IA64_REGION_ID_KERNEL	0 /* the kernel's region id (tlb.c depends on this being 0) */
 
+#define ia64_rid(ctx,addr)	(((ctx) << 3) | (addr >> 61))
+
+# ifndef __ASSEMBLY__
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/processor.h>
+
 struct ia64_ctx {
 	spinlock_t lock;
 	unsigned int next;	/* next context number to use */
@@ -47,12 +44,6 @@
 {
 }
 
-static inline unsigned long
-ia64_rid (unsigned long context, unsigned long region_addr)
-{
-	return context << 3 | (region_addr >> 61);
-}
-
 static inline void
 get_new_mmu_context (struct mm_struct *mm)
 {
@@ -123,11 +114,12 @@
 	 * We may get interrupts here, but that's OK because interrupt
 	 * handlers cannot touch user-space.
 	 */
-	__asm__ __volatile__ ("mov ar.k7=%0" :: "r"(__pa(next->pgd)));
+	ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd));
 	get_mmu_context(next);
 	reload_context(next);
 }
 
 #define switch_mm(prev_mm,next_mm,next_task,cpu)	activate_mm(prev_mm, next_mm)
 
+# endif /* ! __ASSEMBLY__ */
 #endif /* _ASM_IA64_MMU_CONTEXT_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/module.h linux/include/asm-ia64/module.h
--- v2.4.3/linux/include/asm-ia64/module.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/module.h	Thu Apr 12 12:16:36 2001
@@ -7,7 +7,6 @@
  * Copyright (C) 2000 Mike Stephens <mike.stephens@intel.com>
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <asm/unwind.h>
@@ -35,7 +34,6 @@
 static inline int
 ia64_module_init(struct module *mod)
 {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	struct archdata *archdata;
 
 	if (!mod_member_present(mod, archdata_start) || !mod->archdata_start)
@@ -79,14 +77,12 @@
 						   (unsigned long) archdata->segment_base,
 						   (unsigned long) archdata->gp,
 						   archdata->unw_start, archdata->unw_end);
-#endif /* CONFIG_IA64_NEW_UNWIND */
 	return 0;
 }
 
 static inline void
 ia64_module_unmap(void * addr)
 {
-#ifdef CONFIG_IA64_NEW_UNWIND
 	struct module *mod = (struct module *) addr;
 	struct archdata *archdata;
 
@@ -100,7 +96,6 @@
 		if (archdata->unw_table != NULL)
 			unw_remove_unwind_table((void *) archdata->unw_table);
 	}
-#endif /* CONFIG_IA64_NEW_UNWIND */
 
 	vfree(addr);
 }
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h
--- v2.4.3/linux/include/asm-ia64/offsets.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/offsets.h	Thu Apr  5 12:51:47 2001
@@ -11,10 +11,11 @@
 #define PT_PTRACED_BIT			0
 #define PT_TRACESYS_BIT			1
 
-#define IA64_TASK_SIZE			3376	/* 0xd30 */
+#define IA64_TASK_SIZE			3904	/* 0xf40 */
 #define IA64_PT_REGS_SIZE		400	/* 0x190 */
 #define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
 #define IA64_SIGINFO_SIZE		128	/* 0x80 */
+#define IA64_CPU_SIZE			16384	/* 0x4000 */
 #define UNW_FRAME_INFO_SIZE		448	/* 0x1c0 */
 
 #define IA64_TASK_PTRACE_OFFSET		48	/* 0x30 */
@@ -23,7 +24,8 @@
 #define IA64_TASK_PROCESSOR_OFFSET	100	/* 0x64 */
 #define IA64_TASK_THREAD_OFFSET		1456	/* 0x5b0 */
 #define IA64_TASK_THREAD_KSP_OFFSET	1456	/* 0x5b0 */
-#define IA64_TASK_THREAD_SIGMASK_OFFSET	3224	/* 0xc98 */
+#define IA64_TASK_THREAD_SIGMASK_OFFSET	3752	/* 0xea8 */
+#define IA64_TASK_PFM_NOTIFY_OFFSET	3648	/* 0xe40 */
 #define IA64_TASK_PID_OFFSET		196	/* 0xc4 */
 #define IA64_TASK_MM_OFFSET		88	/* 0x58 */
 #define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
@@ -123,5 +125,10 @@
 #define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
 #define IA64_CLONE_VFORK			16384	/* 0x4000 */
 #define IA64_CLONE_VM			256	/* 0x100 */
+#define IA64_CPU_IRQ_COUNT_OFFSET	8	/* 0x8 */
+#define IA64_CPU_BH_COUNT_OFFSET		12	/* 0xc */
+#define IA64_CPU_SOFTIRQ_ACTIVE_OFFSET	0	/* 0x0 */
+#define IA64_CPU_SOFTIRQ_MASK_OFFSET	4	/* 0x4 */
+#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 16	/* 0x10 */
 
 #endif /* _ASM_IA64_OFFSETS_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/page.h linux/include/asm-ia64/page.h
--- v2.4.3/linux/include/asm-ia64/page.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/page.h	Thu Apr  5 12:51:47 2001
@@ -40,43 +40,6 @@
 extern void clear_page (void *page);
 extern void copy_page (void *to, void *from);
 
-#  ifdef STRICT_MM_TYPECHECKS
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-#define pte_val(x)	((x).pte)
-#define pmd_val(x)	((x).pmd)
-#define pgd_val(x)	((x).pgd)
-#define pgprot_val(x)	((x).pgprot)
-
-#define __pte(x)	((pte_t) { (x) } )
-#define __pgprot(x)	((pgprot_t) { (x) } )
-
-#  else /* !STRICT_MM_TYPECHECKS */
-/*
- * .. while these make it easier on the compiler
- */
-typedef unsigned long pte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t;
-typedef unsigned long pgprot_t;
-
-#define pte_val(x)	(x)
-#define pmd_val(x)	(x)
-#define pgd_val(x)	(x)
-#define pgprot_val(x)	(x)
-
-#define __pte(x)	(x)
-#define __pgd(x)	(x)
-#define __pgprot(x)	(x)
-
-#  endif /* !STRICT_MM_TYPECHECKS */
-
 /*
  * Note: the MAP_NR_*() macro can't use __pa() because MAP_NR_*(X) MUST
  * map to something >= max_mapnr if X is outside the identity mapped
@@ -133,7 +96,7 @@
 {
 	double d = size - 1;
 	long order;
-                
+
 	__asm__ ("getf.exp %0=%1" : "=r"(order) : "f"(d));
 	order = order - PAGE_SHIFT - 0xffff + 1;
 	if (order < 0)
@@ -142,7 +105,45 @@
 }
 
 # endif /* __KERNEL__ */
-#endif /* !ASSEMBLY */
+#endif /* !__ASSEMBLY__ */
+
+#ifdef STRICT_MM_TYPECHECKS
+  /*
+   * These are used to make use of C type-checking..
+   */
+  typedef struct { unsigned long pte; } pte_t;
+  typedef struct { unsigned long pmd; } pmd_t;
+  typedef struct { unsigned long pgd; } pgd_t;
+  typedef struct { unsigned long pgprot; } pgprot_t;
+
+# define pte_val(x)	((x).pte)
+# define pmd_val(x)	((x).pmd)
+# define pgd_val(x)	((x).pgd)
+# define pgprot_val(x)	((x).pgprot)
+
+# define __pte(x)	((pte_t) { (x) } )
+# define __pgprot(x)	((pgprot_t) { (x) } )
+
+#else /* !STRICT_MM_TYPECHECKS */
+  /*
+   * .. while these make it easier on the compiler
+   */
+# ifndef __ASSEMBLY__
+    typedef unsigned long pte_t;
+    typedef unsigned long pmd_t;
+    typedef unsigned long pgd_t;
+    typedef unsigned long pgprot_t;
+# endif
+
+# define pte_val(x)	(x)
+# define pmd_val(x)	(x)
+# define pgd_val(x)	(x)
+# define pgprot_val(x)	(x)
+
+# define __pte(x)	(x)
+# define __pgd(x)	(x)
+# define __pgprot(x)	(x)
+#endif /* !STRICT_MM_TYPECHECKS */
 
 #define PAGE_OFFSET		0xe000000000000000
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h
--- v2.4.3/linux/include/asm-ia64/pal.h	Mon Oct  9 17:54:59 2000
+++ linux/include/asm-ia64/pal.h	Thu Apr  5 12:51:47 2001
@@ -1267,7 +1267,7 @@
 ia64_pal_version (pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) 
 {	
 	struct ia64_pal_retval iprv;
-	PAL_CALL(iprv, PAL_VERSION, 0, 0, 0);
+	PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0);
 	if (pal_min_version)
 		pal_min_version->pal_version_val = iprv.v0;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/param.h linux/include/asm-ia64/param.h
--- v2.4.3/linux/include/asm-ia64/param.h	Fri Oct 27 11:04:43 2000
+++ linux/include/asm-ia64/param.h	Thu Apr  5 12:51:47 2001
@@ -10,7 +10,7 @@
 
 #include <linux/config.h>
 
-#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_SOFTSDV_HACKS)
+#ifdef CONFIG_IA64_HP_SIM
 /*
  * Yeah, simulating stuff is slow, so let us catch some breath between
  * timer interrupts...
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/perfmon.h linux/include/asm-ia64/perfmon.h
--- v2.4.3/linux/include/asm-ia64/perfmon.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ia64/perfmon.h	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com>
+ */
+
+#ifndef _ASM_IA64_PERFMON_H
+#define _ASM_IA64_PERFMON_H
+
+#include <linux/types.h>
+
+/*
+ * Structure used to define a context
+ */
+typedef struct {
+	unsigned long smpl_entries;	/* how many entries in sampling buffer */
+	unsigned long smpl_regs;	/* which pmds to record on overflow */
+	void	      *smpl_vaddr;	/* returns address of BTB buffer */
+
+	pid_t	      notify_pid;	/* which process to notify on overflow */
+	int	      notify_sig; 	/* XXX: not used anymore */
+
+	int	      flags;		/* NOBLOCK/BLOCK/ INHERIT flags (will replace API flags) */
+} pfreq_context_t;
+
+/*
+ * Structure used to configure a PMC or PMD
+ */
+typedef struct {
+	unsigned long	reg_num;	/* which register */
+	unsigned long	reg_value;	/* configuration (PMC) or initial value (PMD) */
+	unsigned long	reg_smpl_reset;	/* reset of sampling buffer overflow (large) */
+	unsigned long	reg_ovfl_reset;	/* reset on counter overflow (small) */
+	int		reg_flags;	/* (PMD): notify/don't notify */
+} pfreq_reg_t;
+
+/*
+ * main request structure passed by user
+ */
+typedef union {
+	pfreq_context_t	pfr_ctx;	/* request to configure a context */
+	pfreq_reg_t	pfr_reg;	/* request to configure a PMD/PMC */
+} perfmon_req_t;
+
+extern void pfm_save_regs (struct task_struct *);
+extern void pfm_load_regs (struct task_struct *);
+
+extern int pfm_inherit (struct task_struct *);
+extern void pfm_context_exit (struct task_struct *);
+extern void pfm_flush_regs (struct task_struct *);
+
+#endif /* _ASM_IA64_PERFMON_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h
--- v2.4.3/linux/include/asm-ia64/pgalloc.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -8,8 +8,8 @@
  * This hopefully works with any (fixed) ia-64 page-size, as defined
  * in <asm/page.h> (currently 8192).
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 2000, Goutham Rao <goutham.rao@intel.com>
  */
 
@@ -28,68 +28,60 @@
  * a lot of work and caused unnecessary memory traffic.  How broken...
  * We fix this by caching them.
  */
-#define pgd_quicklist		(my_cpu_data.pgd_quick)
-#define pmd_quicklist		(my_cpu_data.pmd_quick)
-#define pte_quicklist		(my_cpu_data.pte_quick)
-#define pgtable_cache_size	(my_cpu_data.pgtable_cache_sz)
-
-static __inline__ pgd_t*
-get_pgd_slow (void)
-{
-	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
-	if (ret)
-		clear_page(ret);
-	return ret;
-}
+#define pgd_quicklist		(local_cpu_data->pgd_quick)
+#define pmd_quicklist		(local_cpu_data->pmd_quick)
+#define pte_quicklist		(local_cpu_data->pte_quick)
+#define pgtable_cache_size	(local_cpu_data->pgtable_cache_sz)
 
-static __inline__ pgd_t*
-get_pgd_fast (void)
+static inline pgd_t*
+pgd_alloc_one_fast (void)
 {
 	unsigned long *ret = pgd_quicklist;
 
-	if (ret != NULL) {
+	if (__builtin_expect(ret != NULL, 1)) {
 		pgd_quicklist = (unsigned long *)(*ret);
 		ret[0] = 0;
 		--pgtable_cache_size;
-	}
-	return (pgd_t *)ret;
+	} else
+		ret = NULL;
+	return (pgd_t *) ret;
 }
 
-static __inline__ pgd_t*
-pgd_alloc (void)
+static inline pgd_t*
+pgd_alloc (struct mm_struct *mm)
 {
-	pgd_t *pgd;
+	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
+	pgd_t *pgd = pgd_alloc_one_fast();
 
-	pgd = get_pgd_fast();
-	if (!pgd)
-		pgd = get_pgd_slow();
+	if (__builtin_expect(pgd == NULL, 0)) {
+		pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+		if (__builtin_expect(pgd != NULL, 1))
+			clear_page(pgd);
+	}
 	return pgd;
 }
 
-static __inline__ void
-free_pgd_fast (pgd_t *pgd)
+static inline void
+pgd_free (pgd_t *pgd)
 {
 	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
 	++pgtable_cache_size;
 }
 
-static __inline__ pmd_t *
-get_pmd_slow (void)
+static inline void
+pgd_populate (struct mm_struct *mm, pgd_t *pgd_entry, pmd_t *pmd)
 {
-	pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-
-	if (pmd)
-		clear_page(pmd);
-	return pmd;
+	pgd_val(*pgd_entry) = __pa(pmd);
 }
 
-static __inline__ pmd_t *
-get_pmd_fast (void)
+
+static inline pmd_t*
+pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
 {
 	unsigned long *ret = (unsigned long *)pmd_quicklist;
 
-	if (ret != NULL) {
+	if (__builtin_expect(ret != NULL, 1)) {
 		pmd_quicklist = (unsigned long *)(*ret);
 		ret[0] = 0;
 		--pgtable_cache_size;
@@ -97,28 +89,36 @@
 	return (pmd_t *)ret;
 }
 
-static __inline__ void
-free_pmd_fast (pmd_t *pmd)
+static inline pmd_t*
+pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
+{
+	pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+
+	if (__builtin_expect(pmd != NULL, 1))
+		clear_page(pmd);
+	return pmd;
+}
+
+static inline void
+pmd_free (pmd_t *pmd)
 {
 	*(unsigned long *)pmd = (unsigned long) pmd_quicklist;
 	pmd_quicklist = (unsigned long *) pmd;
 	++pgtable_cache_size;
 }
 
-static __inline__ void
-free_pmd_slow (pmd_t *pmd)
+static inline void
+pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte)
 {
-	free_page((unsigned long)pmd);
+	pmd_val(*pmd_entry) = __pa(pte);
 }
 
-extern pte_t *get_pte_slow (pmd_t *pmd, unsigned long address_preadjusted);
-
-static __inline__ pte_t *
-get_pte_fast (void)
+static inline pte_t*
+pte_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
 {
 	unsigned long *ret = (unsigned long *)pte_quicklist;
 
-	if (ret != NULL) {
+	if (__builtin_expect(ret != NULL, 1)) {
 		pte_quicklist = (unsigned long *)(*ret);
 		ret[0] = 0;
 		--pgtable_cache_size;
@@ -126,71 +126,25 @@
 	return (pte_t *)ret;
 }
 
-static __inline__ void
-free_pte_fast (pte_t *pte)
+
+static inline pte_t*
+pte_alloc_one (struct mm_struct *mm, unsigned long addr)
 {
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	++pgtable_cache_size;
-}
+	pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL);
 
-#define pte_free_kernel(pte)	free_pte_fast(pte)
-#define pte_free(pte)		free_pte_fast(pte)
-#define pmd_free_kernel(pmd)	free_pmd_fast(pmd)
-#define pmd_free(pmd)		free_pmd_fast(pmd)
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-
-extern void __handle_bad_pgd (pgd_t *pgd);
-extern void __handle_bad_pmd (pmd_t *pmd);
-
-static __inline__ pte_t*
-pte_alloc (pmd_t *pmd, unsigned long vmaddr)
-{
-	unsigned long offset;
-
-	offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *pte_page = get_pte_fast();
-
-		if (!pte_page)
-			return get_pte_slow(pmd, offset);
-		pmd_set(pmd, pte_page);
-		return pte_page + offset;
-	}
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
+	if (__builtin_expect(pte != NULL, 1))
+		clear_page(pte);
+	return pte;
 }
 
-static __inline__ pmd_t*
-pmd_alloc (pgd_t *pgd, unsigned long vmaddr)
+static inline void
+pte_free (pte_t *pte)
 {
-	unsigned long offset;
-
-	offset = (vmaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *pmd_page = get_pmd_fast();
-
-		if (!pmd_page)
-			pmd_page = get_pmd_slow();
-		if (pmd_page) {
-			pgd_set(pgd, pmd_page);
-			return pmd_page + offset;
-		} else
-			return NULL;
-	}
-	if (pgd_bad(*pgd)) {
-		__handle_bad_pgd(pgd);
-		return NULL;
-	}
-	return (pmd_t *) pgd_page(*pgd) + offset;
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	++pgtable_cache_size;
 }
 
-#define pte_alloc_kernel(pmd, addr)	pte_alloc(pmd, addr)
-#define pmd_alloc_kernel(pgd, addr)	pmd_alloc(pgd, addr)
-
 extern int do_check_pgt_cache (int, int);
 
 /*
@@ -219,7 +173,7 @@
 /*
  * Flush a specified user mapping
  */
-static __inline__ void
+static inline void
 flush_tlb_mm (struct mm_struct *mm)
 {
 	if (mm) {
@@ -237,7 +191,7 @@
 /*
  * Page-granular tlb flush.
  */
-static __inline__ void
+static inline void
 flush_tlb_page (struct vm_area_struct *vma, unsigned long addr)
 {
 #ifdef CONFIG_SMP
@@ -300,20 +254,22 @@
  * that may be necessary.
  */
 static inline void
-update_mmu_cache (struct vm_area_struct *vma, unsigned long address, pte_t pte)
+update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte)
 {
+	unsigned long addr;
 	struct page *page;
 
 	if (!pte_exec(pte))
 		return;				/* not an executable page... */
 
 	page = pte_page(pte);
-	address &= PAGE_MASK;
+	/* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */
+	addr = (unsigned long) page_address(page);
 
 	if (test_bit(PG_arch_1, &page->flags))
 		return;				/* i-cache is already coherent with d-cache */
 
-	flush_icache_range(address, address + PAGE_SIZE);
+	flush_icache_range(addr, addr + PAGE_SIZE);
 	set_bit(PG_arch_1, &page->flags);	/* mark page as clean */
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h
--- v2.4.3/linux/include/asm-ia64/pgtable.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/pgtable.h	Thu Apr 12 12:16:36 2001
@@ -8,11 +8,12 @@
  * This hopefully works with any (fixed) IA-64 page-size, as defined
  * in <asm/page.h> (currently 8192).
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/config.h>
+
 #include <asm/mman.h>
 #include <asm/page.h>
 #include <asm/processor.h>
@@ -103,12 +104,6 @@
  */
 #define PTRS_PER_PTE	(__IA64_UL(1) << (PAGE_SHIFT-3))
 
-# ifndef __ASSEMBLY__
-
-#include <asm/bitops.h>
-#include <asm/mmu_context.h>
-#include <asm/system.h>
-
 /*
  * All the normal masks have the "page accessed" bits on, as any time
  * they are used, the page is accessed. They are cleared only by the
@@ -126,6 +121,12 @@
 #define PAGE_GATE	__pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX)
 #define PAGE_KERNEL	__pgprot(__DIRTY_BITS  | _PAGE_PL_0 | _PAGE_AR_RWX)
 
+# ifndef __ASSEMBLY__
+
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
+#include <asm/system.h>
+
 /*
  * Next come the mappings that determine how mmap() protection bits
  * (PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE) get implemented.  The
@@ -173,7 +174,7 @@
 static inline long
 ia64_phys_addr_valid (unsigned long addr)
 {
-	return (addr & (my_cpu_data.unimpl_pa_mask)) == 0;
+	return (addr & (local_cpu_data->unimpl_pa_mask)) == 0;
 }
 
 /*
@@ -203,25 +204,12 @@
 #define set_pte(ptep, pteval)	(*(ptep) = (pteval))
 
 #define RGN_SIZE	(1UL << 61)
-#define RGN_MAP_LIMIT	(1UL << (4*PAGE_SHIFT - 12))	/* limit of mappable area in region */
+#define RGN_MAP_LIMIT	((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE)	/* per region addr limit */
 #define RGN_KERNEL	7
 
-#define VMALLOC_START		(0xa000000000000000 + 2*PAGE_SIZE)
+#define VMALLOC_START		(0xa000000000000000 + 3*PAGE_SIZE)
 #define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#define VMALLOC_END		(0xa000000000000000 + RGN_MAP_LIMIT)
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero:  used
- * for zero-mapped memory areas etc..
- */
-extern pte_t ia64_bad_page (void);
-extern pmd_t *ia64_bad_pagetable (void);
-
-#define BAD_PAGETABLE	ia64_bad_pagetable()
-#define BAD_PAGE	ia64_bad_page()
+#define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -251,14 +239,12 @@
 /* pte_page() returns the "struct page *" corresponding to the PTE: */
 #define pte_page(pte)			(mem_map + (unsigned long) ((pte_val(pte) & _PFN_MASK) >> PAGE_SHIFT))
 
-#define pmd_set(pmdp, ptep) 		(pmd_val(*(pmdp)) = __pa(ptep))
 #define pmd_none(pmd)			(!pmd_val(pmd))
 #define pmd_bad(pmd)			(!ia64_phys_addr_valid(pmd_val(pmd)))
 #define pmd_present(pmd)		(pmd_val(pmd) != 0UL)
 #define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0UL)
 #define pmd_page(pmd)			((unsigned long) __va(pmd_val(pmd) & _PFN_MASK))
 
-#define pgd_set(pgdp, pmdp)		(pgd_val(*(pgdp)) = __pa(pmdp))
 #define pgd_none(pgd)			(!pgd_val(pgd))
 #define pgd_bad(pgd)			(!ia64_phys_addr_valid(pgd_val(pgd)))
 #define pgd_present(pgd)		(pgd_val(pgd) != 0UL)
@@ -301,7 +287,11 @@
  * works bypasses the caches, but does allow for consecutive writes to
  * be combined into single (but larger) write transactions.
  */
-#define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
+#ifdef CONFIG_MCKINLEY_A0_SPECIFIC
+# define pgprot_writecombine(prot)	prot
+#else
+# define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
+#endif
 
 /*
  * Return the region index for virtual address ADDRESS.
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h
--- v2.4.3/linux/include/asm-ia64/processor.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/processor.h	Thu Apr 12 12:10:25 2001
@@ -2,9 +2,9 @@
 #define _ASM_IA64_PROCESSOR_H
 
 /*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1998-2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  *
@@ -16,6 +16,8 @@
 #include <linux/config.h>
 
 #include <asm/ptrace.h>
+#include <asm/kregs.h>
+#include <asm/system.h>
 #include <asm/types.h>
 
 #define IA64_NUM_DBG_REGS	8
@@ -27,6 +29,9 @@
 #define IA64_NUM_PMD_REGS	32
 #define IA64_NUM_PMD_COUNTERS	4
 
+#define DEFAULT_MAP_BASE	0x2000000000000000
+#define DEFAULT_TASK_SIZE	0xa000000000000000
+
 /*
  * TASK_SIZE really is a mis-named.  It really is the maximum user
  * space address (plus one).  On IA-64, there are five regions of 2TB
@@ -163,15 +168,21 @@
 #define IA64_THREAD_UAC_NOPRINT	(__IA64_UL(1) << 3)	/* don't log unaligned accesses */
 #define IA64_THREAD_UAC_SIGBUS	(__IA64_UL(1) << 4)	/* generate SIGBUS on unaligned acc. */
 #define IA64_THREAD_KRBS_SYNCED	(__IA64_UL(1) << 5)	/* krbs synced with process vm? */
-#define IA64_THREAD_MAP_SHARED	(__IA64_UL(1) << 6)	/* ugly: just a tmp flag for mmap() */
 #define IA64_KERNEL_DEATH	(__IA64_UL(1) << 63)	/* see die_if_kernel()... */
 
 #define IA64_THREAD_UAC_SHIFT	3
 #define IA64_THREAD_UAC_MASK	(IA64_THREAD_UAC_NOPRINT | IA64_THREAD_UAC_SIGBUS)
 
+
+/*
+ * This shift should be large enough to be able to represent
+ * 1000000/itc_freq with good accuracy while being small enough to fit
+ * 1000000<<IA64_USEC_PER_CYC_SHIFT in 64 bits.
+ */
+#define IA64_USEC_PER_CYC_SHIFT	41
+
 #ifndef __ASSEMBLY__
 
-#include <linux/smp.h>
 #include <linux/threads.h>
 
 #include <asm/fpu.h>
@@ -220,16 +231,26 @@
 };
 
 /*
- * This shift should be large enough to be able to represent
- * 1000000/itc_freq with good accuracy while being small enough to fit
- * 1000000<<IA64_USEC_PER_CYC_SHIFT in 64 bits.
- */
-#define IA64_USEC_PER_CYC_SHIFT	41
-
-/*
- * CPU type, hardware bug flags, and per-CPU state.
+ * CPU type, hardware bug flags, and per-CPU state.  Frequently used
+ * state comes earlier:
  */
 struct cpuinfo_ia64 {
+	/* irq_stat and softirq should be 64-bit aligned */
+	struct {
+		__u32 active;
+		__u32 mask;
+	} softirq;
+	union {
+		struct {
+			__u32 irq_count;
+			__u32 bh_count;
+		} f;
+		__u64 irq_and_bh_counts;
+	} irq_stat;
+	__u32 phys_stacked_size_p8;	/* size of physical stacked registers + 8 */
+	__u32 pad0;
+	__u64 itm_delta;	/* # of clock cycles between clock ticks */
+	__u64 itm_next;		/* interval timer mask value to use for next clock tick */
 	__u64 *pgd_quick;
 	__u64 *pmd_quick;
 	__u64 *pte_quick;
@@ -257,10 +278,15 @@
 	__u64 ipi_count;
 	__u64 prof_counter;
 	__u64 prof_multiplier;
+	__u64 ipi_operation;
 #endif
-};
+} __attribute__ ((aligned (PAGE_SIZE))) ;
 
-#define my_cpu_data		cpu_data[smp_processor_id()]
+/*
+ * The "local" data pointer.  It points to the per-CPU data of the currently executing
+ * CPU, much like "current" points to the per-task data of the currently executing task.
+ */
+#define local_cpu_data		((struct cpuinfo_ia64 *) PERCPU_ADDR)
 
 extern struct cpuinfo_ia64 cpu_data[NR_CPUS];
 
@@ -294,13 +320,9 @@
 #ifdef CONFIG_PERFMON
 	__u64 pmc[IA64_NUM_PMC_REGS];
 	__u64 pmd[IA64_NUM_PMD_REGS];
-	struct {
-		__u64		val;	/* virtual 64bit counter */
-		__u64		rval;	/* reset value on overflow */
-		int		sig;	/* signal used to notify */
-		int		pid;	/* process to notify */
-	} pmu_counters[IA64_NUM_PMD_COUNTERS];
-# define INIT_THREAD_PM		{0, }, {0, }, {{ 0, 0, 0, 0}, },
+	unsigned long pfm_pend_notify;	/* non-zero if we need to notify and block */
+	void *pfm_context;		/* pointer to detailed PMU context */
+# define INIT_THREAD_PM		{0, }, {0, }, 0, 0,
 #else
 # define INIT_THREAD_PM
 #endif
@@ -338,25 +360,53 @@
 	{0, },				/* dbr */	\
 	{0, },				/* ibr */	\
 	INIT_THREAD_PM					\
-	0x2000000000000000,		/* map_base */	\
-	0xa000000000000000,		/* task_size */	\
+	DEFAULT_MAP_BASE,		/* map_base */	\
+	DEFAULT_TASK_SIZE,		/* task_size */	\
 	INIT_THREAD_IA32				\
 	0				/* siginfo */	\
 }
 
-#define start_thread(regs,new_ip,new_sp) do {					\
-	set_fs(USER_DS);							\
-	ia64_psr(regs)->dfh = 1;	/* disable fph */			\
-	ia64_psr(regs)->mfh = 0;	/* clear mfh */				\
-	ia64_psr(regs)->cpl = 3;	/* set user mode */			\
-	ia64_psr(regs)->ri = 0;		/* clear return slot number */		\
-	ia64_psr(regs)->is = 0;		/* IA-64 instruction set */		\
-	regs->cr_iip = new_ip;							\
-	regs->ar_rsc = 0xf;		/* eager mode, privilege level 3 */	\
-	regs->r12 = new_sp - 16;	/* allocate 16 byte scratch area */	\
-	regs->ar_bspstore = IA64_RBS_BOT;					\
-	regs->ar_rnat = 0;							\
-	regs->loadrs = 0;							\
+#define start_thread(regs,new_ip,new_sp) do {							\
+	set_fs(USER_DS);									\
+	ia64_psr(regs)->dfh = 1;	/* disable fph */					\
+	ia64_psr(regs)->mfh = 0;	/* clear mfh */						\
+	ia64_psr(regs)->cpl = 3;	/* set user mode */					\
+	ia64_psr(regs)->ri = 0;		/* clear return slot number */				\
+	ia64_psr(regs)->is = 0;		/* IA-64 instruction set */				\
+	regs->cr_iip = new_ip;									\
+	regs->ar_rsc = 0xf;		/* eager mode, privilege level 3 */			\
+	regs->ar_rnat = 0;									\
+	regs->ar_bspstore = IA64_RBS_BOT;							\
+	regs->ar_fpsr = FPSR_DEFAULT;								\
+	regs->loadrs = 0;									\
+	regs->r8 = current->dumpable;	/* set "don't zap registers" flag */			\
+	regs->r12 = new_sp - 16;	/* allocate 16 byte scratch area */			\
+	if (!__builtin_expect (current->dumpable, 1)) {						\
+		/*										\
+		 * Zap scratch regs to avoid leaking bits between processes with different	\
+		 * uid/privileges.								\
+		 */										\
+		regs->ar_pfs = 0;								\
+		regs->pr = 0;									\
+		/*										\
+		 * XXX fix me: everything below can go away once we stop preserving scratch	\
+		 * regs on a system call.							\
+		 */										\
+		regs->b6 = 0;									\
+		regs->r1 = 0; regs->r2 = 0; regs->r3 = 0;					\
+		regs->r13 = 0; regs->r14 = 0; regs->r15 = 0;					\
+		regs->r9  = 0; regs->r11 = 0;							\
+		regs->r16 = 0; regs->r17 = 0; regs->r18 = 0; regs->r19 = 0;			\
+		regs->r20 = 0; regs->r21 = 0; regs->r22 = 0; regs->r23 = 0;			\
+		regs->r24 = 0; regs->r25 = 0; regs->r26 = 0; regs->r27 = 0;			\
+		regs->r28 = 0; regs->r29 = 0; regs->r30 = 0; regs->r31 = 0;			\
+		regs->ar_ccv = 0;								\
+		regs->b0 = 0; regs->b7 = 0;							\
+		regs->f6.u.bits[0] = 0; regs->f6.u.bits[1] = 0;					\
+		regs->f7.u.bits[0] = 0; regs->f7.u.bits[1] = 0;					\
+		regs->f8.u.bits[0] = 0; regs->f8.u.bits[1] = 0;					\
+		regs->f9.u.bits[0] = 0; regs->f9.u.bits[1] = 0;					\
+	}											\
 } while (0)
 
 /* Forward declarations, a strange C thing... */
@@ -368,7 +418,11 @@
  * parent of DEAD_TASK has collected the exist status of the task via
  * wait().  This is a no-op on IA-64.
  */
-#define release_thread(dead_task)
+#ifdef CONFIG_PERFMON
+  extern void release_thread (struct task_struct *task);
+#else
+# define release_thread(dead_task)
+#endif
 
 /*
  * This is the mechanism for creating a new kernel thread.
@@ -403,20 +457,51 @@
 /* Return stack pointer of blocked task TSK.  */
 #define KSTK_ESP(tsk)  ((tsk)->thread.ksp)
 
+static inline unsigned long
+ia64_get_kr (unsigned long regnum)
+{
+	unsigned long r;
+
+	switch (regnum) {
+	      case 0: asm volatile ("mov %0=ar.k0" : "=r"(r)); break;
+	      case 1: asm volatile ("mov %0=ar.k1" : "=r"(r)); break;
+	      case 2: asm volatile ("mov %0=ar.k2" : "=r"(r)); break;
+	      case 3: asm volatile ("mov %0=ar.k3" : "=r"(r)); break;
+	      case 4: asm volatile ("mov %0=ar.k4" : "=r"(r)); break;
+	      case 5: asm volatile ("mov %0=ar.k5" : "=r"(r)); break;
+	      case 6: asm volatile ("mov %0=ar.k6" : "=r"(r)); break;
+	      case 7: asm volatile ("mov %0=ar.k7" : "=r"(r)); break;
+	}
+	return r;
+}
+
+static inline void
+ia64_set_kr (unsigned long regnum, unsigned long r)
+{
+	switch (regnum) {
+	      case 0: asm volatile ("mov ar.k0=%0" :: "r"(r)); break;
+	      case 1: asm volatile ("mov ar.k1=%0" :: "r"(r)); break;
+	      case 2: asm volatile ("mov ar.k2=%0" :: "r"(r)); break;
+	      case 3: asm volatile ("mov ar.k3=%0" :: "r"(r)); break;
+	      case 4: asm volatile ("mov ar.k4=%0" :: "r"(r)); break;
+	      case 5: asm volatile ("mov ar.k5=%0" :: "r"(r)); break;
+	      case 6: asm volatile ("mov ar.k6=%0" :: "r"(r)); break;
+	      case 7: asm volatile ("mov ar.k7=%0" :: "r"(r)); break;
+	}
+}
+
 #ifndef CONFIG_SMP
 
 static inline struct task_struct *
 ia64_get_fpu_owner (void)
 {
-	struct task_struct *t;
-	__asm__ ("mov %0=ar.k5" : "=r"(t));
-	return t;
+	return (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER);
 }
 
 static inline void
 ia64_set_fpu_owner (struct task_struct *t)
 {
-	__asm__ __volatile__ ("mov ar.k5=%0" :: "r"(t));
+	ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t);
 }
 
 #endif /* !CONFIG_SMP */
@@ -437,8 +522,8 @@
 extern void ia64_load_pm_regs (struct task_struct *task);
 #endif
 
-#define ia64_fph_enable()	__asm__ __volatile__ (";; rsm psr.dfh;; srlz.d;;" ::: "memory");
-#define ia64_fph_disable()	__asm__ __volatile__ (";; ssm psr.dfh;; srlz.d;;" ::: "memory");
+#define ia64_fph_enable()	asm volatile (";; rsm psr.dfh;; srlz.d;;" ::: "memory");
+#define ia64_fph_disable()	asm volatile (";; ssm psr.dfh;; srlz.d;;" ::: "memory");
 
 /* load fp 0.0 into fph */
 static inline void
@@ -467,53 +552,53 @@
 static inline void
 ia64_fc (void *addr)
 {
-	__asm__ __volatile__ ("fc %0" :: "r"(addr) : "memory");
+	asm volatile ("fc %0" :: "r"(addr) : "memory");
 }
 
 static inline void
 ia64_sync_i (void)
 {
-	__asm__ __volatile__ (";; sync.i" ::: "memory");
+	asm volatile (";; sync.i" ::: "memory");
 }
 
 static inline void
 ia64_srlz_i (void)
 {
-	__asm__ __volatile__ (";; srlz.i ;;" ::: "memory");
+	asm volatile (";; srlz.i ;;" ::: "memory");
 }
 
 static inline void
 ia64_srlz_d (void)
 {
-	__asm__ __volatile__ (";; srlz.d" ::: "memory");
+	asm volatile (";; srlz.d" ::: "memory");
 }
 
 static inline __u64
 ia64_get_rr (__u64 reg_bits)
 {
 	__u64 r;
-	__asm__ __volatile__ ("mov %0=rr[%1]" : "=r"(r) : "r"(reg_bits) : "memory");
+	asm volatile ("mov %0=rr[%1]" : "=r"(r) : "r"(reg_bits) : "memory");
 	return r;
 }
 
 static inline void
 ia64_set_rr (__u64 reg_bits, __u64 rr_val)
 {
-	__asm__ __volatile__ ("mov rr[%0]=%1" :: "r"(reg_bits), "r"(rr_val) : "memory");
+	asm volatile ("mov rr[%0]=%1" :: "r"(reg_bits), "r"(rr_val) : "memory");
 }
 
 static inline __u64
 ia64_get_dcr (void)
 {
 	__u64 r;
-	__asm__ ("mov %0=cr.dcr" : "=r"(r));
+	asm volatile ("mov %0=cr.dcr" : "=r"(r));
 	return r;
 }
 
 static inline void
 ia64_set_dcr (__u64 val)
 {
-	__asm__ __volatile__ ("mov cr.dcr=%0;;" :: "r"(val) : "memory");
+	asm volatile ("mov cr.dcr=%0;;" :: "r"(val) : "memory");
 	ia64_srlz_d();
 }
 
@@ -521,14 +606,14 @@
 ia64_get_lid (void)
 {
 	__u64 r;
-	__asm__ ("mov %0=cr.lid" : "=r"(r));
+	asm volatile ("mov %0=cr.lid" : "=r"(r));
 	return r;
 }
 
 static inline void
 ia64_invala (void)
 {
-	__asm__ __volatile__ ("invala" ::: "memory");
+	asm volatile ("invala" ::: "memory");
 }
 
 /*
@@ -536,7 +621,7 @@
  * interrupt collection and interrupt enable bits.
  */
 #define ia64_clear_ic(flags)							\
-	__asm__ __volatile__ ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;"	\
+	asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;"	\
 			      : "=r"(flags) :: "memory");
 
 /*
@@ -548,13 +633,13 @@
 	  __u64 vmaddr, __u64 pte,
 	  __u64 log_page_size)
 {
-	__asm__ __volatile__ ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory");
-	__asm__ __volatile__ ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory");
+	asm volatile ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory");
+	asm volatile ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory");
 	if (target_mask & 0x1)
-		__asm__ __volatile__ ("itr.i itr[%0]=%1"
+		asm volatile ("itr.i itr[%0]=%1"
 				      :: "r"(tr_num), "r"(pte) : "memory");
 	if (target_mask & 0x2)
-		__asm__ __volatile__ (";;itr.d dtr[%0]=%1"
+		asm volatile (";;itr.d dtr[%0]=%1"
 				      :: "r"(tr_num), "r"(pte) : "memory");
 }
 
@@ -566,13 +651,13 @@
 ia64_itc (__u64 target_mask, __u64 vmaddr, __u64 pte,
 	  __u64 log_page_size)
 {
-	__asm__ __volatile__ ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory");
-	__asm__ __volatile__ ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory");
+	asm volatile ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory");
+	asm volatile ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory");
 	/* as per EAS2.6, itc must be the last instruction in an instruction group */
 	if (target_mask & 0x1)
-		__asm__ __volatile__ ("itc.i %0;;" :: "r"(pte) : "memory");
+		asm volatile ("itc.i %0;;" :: "r"(pte) : "memory");
 	if (target_mask & 0x2)
-		__asm__ __volatile__ (";;itc.d %0;;" :: "r"(pte) : "memory");
+		asm volatile (";;itc.d %0;;" :: "r"(pte) : "memory");
 }
 
 /*
@@ -583,16 +668,16 @@
 ia64_ptr (__u64 target_mask, __u64 vmaddr, __u64 log_size)
 {
 	if (target_mask & 0x1)
-		__asm__ __volatile__ ("ptr.i %0,%1" :: "r"(vmaddr), "r"(log_size << 2));
+		asm volatile ("ptr.i %0,%1" :: "r"(vmaddr), "r"(log_size << 2));
 	if (target_mask & 0x2)
-		__asm__ __volatile__ ("ptr.d %0,%1" :: "r"(vmaddr), "r"(log_size << 2));
+		asm volatile ("ptr.d %0,%1" :: "r"(vmaddr), "r"(log_size << 2));
 }
 
 /* Set the interrupt vector address.  The address must be suitably aligned (32KB).  */
 static inline void
 ia64_set_iva (void *ivt_addr)
 {
-	__asm__ __volatile__ ("mov cr.iva=%0;; srlz.i;;" :: "r"(ivt_addr) : "memory");
+	asm volatile ("mov cr.iva=%0;; srlz.i;;" :: "r"(ivt_addr) : "memory");
 }
 
 /* Set the page table address and control bits.  */
@@ -600,7 +685,7 @@
 ia64_set_pta (__u64 pta)
 {
 	/* Note: srlz.i implies srlz.d */
-	__asm__ __volatile__ ("mov cr.pta=%0;; srlz.i;;" :: "r"(pta) : "memory");
+	asm volatile ("mov cr.pta=%0;; srlz.i;;" :: "r"(pta) : "memory");
 }
 
 static inline __u64
@@ -608,41 +693,33 @@
 {
 	__u64 r;
 
-	__asm__ ("mov %0=cpuid[%r1]" : "=r"(r) : "rO"(regnum));
+	asm ("mov %0=cpuid[%r1]" : "=r"(r) : "rO"(regnum));
 	return r;
 }
 
 static inline void
 ia64_eoi (void)
 {
-	__asm__ ("mov cr.eoi=r0;; srlz.d;;" ::: "memory");
+	asm ("mov cr.eoi=r0;; srlz.d;;" ::: "memory");
 }
 
 static inline void
-ia64_set_lrr0 (__u8 vector, __u8 masked)
+ia64_set_lrr0 (unsigned long val)
 {
-	if (masked > 1)
-		masked = 1;
-
-	__asm__ __volatile__ ("mov cr.lrr0=%0;; srlz.d"
-			      :: "r"((masked << 16) | vector) : "memory");
+	asm volatile ("mov cr.lrr0=%0;; srlz.d" :: "r"(val) : "memory");
 }
 
 
 static inline void
-ia64_set_lrr1 (__u8 vector, __u8 masked)
+ia64_set_lrr1 (unsigned long val)
 {
-	if (masked > 1)
-		masked = 1;
-
-	__asm__ __volatile__ ("mov cr.lrr1=%0;; srlz.d"
-			      :: "r"((masked << 16) | vector) : "memory");
+	asm volatile ("mov cr.lrr1=%0;; srlz.d" :: "r"(val) : "memory");
 }
 
 static inline void
 ia64_set_pmv (__u64 val)
 {
-	__asm__ __volatile__ ("mov cr.pmv=%0" :: "r"(val) : "memory");
+	asm volatile ("mov cr.pmv=%0" :: "r"(val) : "memory");
 }
 
 static inline __u64
@@ -650,14 +727,14 @@
 {
 	__u64 retval;
 
-	__asm__ __volatile__ ("mov %0=pmc[%1]" : "=r"(retval) : "r"(regnum));
+	asm volatile ("mov %0=pmc[%1]" : "=r"(retval) : "r"(regnum));
 	return retval;
 }
 
 static inline void
 ia64_set_pmc (__u64 regnum, __u64 value)
 {
-	__asm__ __volatile__ ("mov pmc[%0]=%1" :: "r"(regnum), "r"(value));
+	asm volatile ("mov pmc[%0]=%1" :: "r"(regnum), "r"(value));
 }
 
 static inline __u64
@@ -665,14 +742,14 @@
 {
 	__u64 retval;
 
-	__asm__ __volatile__ ("mov %0=pmd[%1]" : "=r"(retval) : "r"(regnum));
+	asm volatile ("mov %0=pmd[%1]" : "=r"(retval) : "r"(regnum));
 	return retval;
 }
 
 static inline void
 ia64_set_pmd (__u64 regnum, __u64 value)
 {
-	__asm__ __volatile__ ("mov pmd[%0]=%1" :: "r"(regnum), "r"(value));
+	asm volatile ("mov pmd[%0]=%1" :: "r"(regnum), "r"(value));
 }
 
 /*
@@ -722,7 +799,7 @@
  * Get the current instruction/program counter value.
  */
 #define current_text_addr() \
-	({ void *_pc; __asm__ ("mov %0=ip" : "=r" (_pc)); _pc; })
+	({ void *_pc; asm volatile ("mov %0=ip" : "=r" (_pc)); _pc; })
 
 #define THREAD_SIZE	IA64_STK_OFFSET
 /* NOTE: The task struct and the stacks are allocated together.  */
@@ -740,7 +817,7 @@
 static inline void
 ia64_set_cmcv (__u64 val)
 {
-	__asm__ __volatile__ ("mov cr.cmcv=%0" :: "r"(val) : "memory");
+	asm volatile ("mov cr.cmcv=%0" :: "r"(val) : "memory");
 }
 
 /*
@@ -751,7 +828,7 @@
 {
 	__u64 val;
 
-	__asm__ ("mov %0=cr.cmcv" : "=r"(val) :: "memory");
+	asm volatile ("mov %0=cr.cmcv" : "=r"(val) :: "memory");
 	return val;
 }
 
@@ -759,28 +836,28 @@
 ia64_get_ivr (void)
 {
 	__u64 r;
-	__asm__ __volatile__ ("srlz.d;; mov %0=cr.ivr;; srlz.d;;" : "=r"(r));
+	asm volatile ("srlz.d;; mov %0=cr.ivr;; srlz.d;;" : "=r"(r));
 	return r;
 }
 
 static inline void
 ia64_set_tpr (__u64 val)
 {
-	__asm__ __volatile__ ("mov cr.tpr=%0" :: "r"(val));
+	asm volatile ("mov cr.tpr=%0" :: "r"(val));
 }
 
 static inline __u64
 ia64_get_tpr (void)
 {
 	__u64 r;
-	__asm__ ("mov %0=cr.tpr" : "=r"(r));
+	asm volatile ("mov %0=cr.tpr" : "=r"(r));
 	return r;
 }
 
 static inline void
 ia64_set_irr0 (__u64 val)
 {
-	__asm__ __volatile__("mov cr.irr0=%0;;" :: "r"(val) : "memory");
+	asm volatile("mov cr.irr0=%0;;" :: "r"(val) : "memory");
 	ia64_srlz_d();
 }
 
@@ -790,14 +867,14 @@
 	__u64 val;
 
 	/* this is volatile because irr may change unbeknownst to gcc... */
-	__asm__ __volatile__("mov %0=cr.irr0" : "=r"(val));
+	asm volatile("mov %0=cr.irr0" : "=r"(val));
 	return val;
 }
 
 static inline void
 ia64_set_irr1 (__u64 val)
 {
-	__asm__ __volatile__("mov cr.irr1=%0;;" :: "r"(val) : "memory");
+	asm volatile("mov cr.irr1=%0;;" :: "r"(val) : "memory");
 	ia64_srlz_d();
 }
 
@@ -807,14 +884,14 @@
 	__u64 val;
 
 	/* this is volatile because irr may change unbeknownst to gcc... */
-	__asm__ __volatile__("mov %0=cr.irr1" : "=r"(val));
+	asm volatile("mov %0=cr.irr1" : "=r"(val));
 	return val;
 }
 
 static inline void
 ia64_set_irr2 (__u64 val)
 {
-	__asm__ __volatile__("mov cr.irr2=%0;;" :: "r"(val) : "memory");
+	asm volatile("mov cr.irr2=%0;;" :: "r"(val) : "memory");
 	ia64_srlz_d();
 }
 
@@ -824,14 +901,14 @@
 	__u64 val;
 
 	/* this is volatile because irr may change unbeknownst to gcc... */
-	__asm__ __volatile__("mov %0=cr.irr2" : "=r"(val));
+	asm volatile("mov %0=cr.irr2" : "=r"(val));
 	return val;
 }
 
 static inline void
 ia64_set_irr3 (__u64 val)
 {
-	__asm__ __volatile__("mov cr.irr3=%0;;" :: "r"(val) : "memory");
+	asm volatile("mov cr.irr3=%0;;" :: "r"(val) : "memory");
 	ia64_srlz_d();
 }
 
@@ -841,7 +918,7 @@
 	__u64 val;
 
 	/* this is volatile because irr may change unbeknownst to gcc... */
-	__asm__ __volatile__("mov %0=cr.irr3" : "=r"(val));
+	asm volatile ("mov %0=cr.irr3" : "=r"(val));
 	return val;
 }
 
@@ -850,7 +927,7 @@
 {
 	__u64 val;
 
-	__asm__ ("mov %0=gp" : "=r"(val));
+	asm ("mov %0=gp" : "=r"(val));
 	return val;
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/ptrace.h linux/include/asm-ia64/ptrace.h
--- v2.4.3/linux/include/asm-ia64/ptrace.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/ptrace.h	Thu Apr  5 12:51:47 2001
@@ -2,8 +2,8 @@
 #define _ASM_IA64_PTRACE_H
 
 /*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
  * 12/07/98	S. Eranian	added pt_regs & switch_stack
@@ -67,7 +67,7 @@
 # define IA64_TASK_STRUCT_LOG_NUM_PAGES		0
 #endif
 
-#define IA64_RBS_OFFSET			((IA64_TASK_SIZE + 15) & ~15) 
+#define IA64_RBS_OFFSET			((IA64_TASK_SIZE + 15) & ~15)
 #define IA64_STK_OFFSET			((1 << IA64_TASK_STRUCT_LOG_NUM_PAGES)*PAGE_SIZE)
 
 #define INIT_TASK_SIZE			IA64_STK_OFFSET
@@ -96,11 +96,11 @@
 	unsigned long cr_iip;		/* interrupted task's instruction pointer */
 	unsigned long cr_ifs;		/* interrupted task's function state */
 
-	unsigned long ar_unat;		/* interrupted task's NaT register (preserved) */ 
+	unsigned long ar_unat;		/* interrupted task's NaT register (preserved) */
 	unsigned long ar_pfs;		/* prev function state  */
 	unsigned long ar_rsc;		/* RSE configuration */
 	/* The following two are valid only if cr_ipsr.cpl > 0: */
-	unsigned long ar_rnat;		/* RSE NaT */ 
+	unsigned long ar_rnat;		/* RSE NaT */
 	unsigned long ar_bspstore;	/* RSE bspstore */
 
 	unsigned long pr;		/* 64 predicate registers (1 bit each) */
@@ -160,7 +160,7 @@
  * "preserved" registers.
  */
 struct switch_stack {
-	unsigned long caller_unat;	/* user NaT collection register (preserved) */ 
+	unsigned long caller_unat;	/* user NaT collection register (preserved) */
 	unsigned long ar_fpsr;		/* floating-point status register */
 
 	struct ia64_fpreg f2;		/* preserved */
@@ -206,7 +206,7 @@
 	unsigned long ar_pfs;		/* previous function state */
 	unsigned long ar_lc;		/* loop counter (preserved) */
 	unsigned long ar_unat;		/* NaT bits for r4-r7 */
-	unsigned long ar_rnat;		/* RSE NaT collection register */ 
+	unsigned long ar_rnat;		/* RSE NaT collection register */
 	unsigned long ar_bspstore;	/* RSE dirty base (preserved) */
 	unsigned long pr;		/* 64 predicate registers (1 bit each) */
 };
@@ -220,22 +220,16 @@
   struct task_struct;			/* forward decl */
 
   extern void show_regs (struct pt_regs *);
-  extern long ia64_peek (struct pt_regs *, struct task_struct *, unsigned long addr, long *val);
-  extern long ia64_poke (struct pt_regs *, struct task_struct *, unsigned long addr, long val);
-  extern void ia64_flush_fph (struct task_struct *t);
-  extern void ia64_sync_fph (struct task_struct *t);
+  extern unsigned long ia64_get_user_bsp (struct task_struct *, struct pt_regs *);
+  extern long ia64_peek (struct task_struct *, unsigned long, unsigned long, long *);
+  extern long ia64_poke (struct task_struct *, unsigned long, unsigned long, long);
+  extern void ia64_flush_fph (struct task_struct *);
+  extern void ia64_sync_fph (struct task_struct *);
 
-#ifdef CONFIG_IA64_NEW_UNWIND
   /* get nat bits for scratch registers such that bit N==1 iff scratch register rN is a NaT */
   extern unsigned long ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat);
   /* put nat bits for scratch registers such that scratch register rN is a NaT iff bit N==1 */
   extern unsigned long ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat);
-#else
-  /* get nat bits for r1-r31 such that bit N==1 iff rN is a NaT */
-  extern long ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw);
-  /* put nat bits for r1-r31 such that rN is a NaT iff bit N==1 */
-  extern void ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat);
-#endif
 
   extern void ia64_increment_ip (struct pt_regs *pt);
   extern void ia64_decrement_ip (struct pt_regs *pt);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sal.h linux/include/asm-ia64/sal.h
--- v2.4.3/linux/include/asm-ia64/sal.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/sal.h	Thu Apr 12 12:16:36 2001
@@ -16,7 +16,6 @@
  *                      (plus examples of platform error info structures from smariset @ Intel)
  */
 
-#include <linux/config.h>
 #include <linux/spinlock.h>
 
 #include <asm/pal.h>
@@ -28,15 +27,12 @@
 #define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7)	\
 	result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7)
 
-#ifdef CONFIG_SMP
-# define SAL_CALL(result,args...) do {		\
-	  spin_lock(&sal_lock);			\
-	  __SAL_CALL(result,args);		\
-	  spin_unlock(&sal_lock);		\
+# define SAL_CALL(result,args...) do {			\
+	unsigned long flags;				\
+	spin_lock_irqsave(&sal_lock, flags);		\
+	__SAL_CALL(result,args);			\
+	spin_unlock_irqrestore(&sal_lock, flags);	\
 } while (0)
-#else
-# define SAL_CALL(result,args...)	__SAL_CALL(result,args)
-#endif
 
 #define SAL_SET_VECTORS			0x01000000
 #define SAL_GET_STATE_INFO		0x01000001
@@ -440,11 +436,10 @@
  * machine state at the time of MCA's, INITs or CMCs 
  */
 static inline s64
-ia64_sal_clear_state_info (u64 sal_info_type, u64 sal_info_sub_type)
+ia64_sal_clear_state_info (u64 sal_info_type)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, sal_info_sub_type,
-	         0, 0, 0, 0, 0);
+	SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, 0, 0, 0, 0, 0);
 	return isrv.status;
 }
 
@@ -453,10 +448,10 @@
  * state at the time of the MCAs, INITs or CMCs.
  */
 static inline u64
-ia64_sal_get_state_info (u64 sal_info_type, u64 sal_info_sub_type, u64 *sal_info)
+ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SAL_GET_STATE_INFO, sal_info_type, sal_info_sub_type,
+	SAL_CALL(isrv, SAL_GET_STATE_INFO, sal_info_type, 0,
 	         sal_info, 0, 0, 0, 0);
 	if (isrv.status)
 		return 0;
@@ -466,11 +461,10 @@
  * state at the time of MCAs, INITs or CMCs
  */
 static inline u64
-ia64_sal_get_state_info_size (u64 sal_info_type, u64 sal_info_sub_type)
+ia64_sal_get_state_info_size (u64 sal_info_type)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, sal_info_sub_type,
-	         0, 0, 0, 0, 0);
+	SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, 0, 0, 0, 0, 0);
 	if (isrv.status)
 		return 0;
 	return isrv.v0;
@@ -492,11 +486,10 @@
  * non-monarch processor at the end of machine check processing.
  */
 static inline s64
-ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout)
+ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout, u64 rz_always)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, timeout,
-	         0, 0, 0);
+	SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, timeout, rz_always, 0, 0);
 	return isrv.status;
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/segment.h linux/include/asm-ia64/segment.h
--- v2.4.3/linux/include/asm-ia64/segment.h	Sun Feb  6 18:42:40 2000
+++ linux/include/asm-ia64/segment.h	Thu Apr  5 12:51:47 2001
@@ -3,4 +3,4 @@
 
 /* Only here because we have some old header files that expect it.. */
 
-#endif /* __ALPHA_SEGMENT_H */
+#endif /* _ASM_IA64_SEGMENT_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/semaphore.h linux/include/asm-ia64/semaphore.h
--- v2.4.3/linux/include/asm-ia64/semaphore.h	Mon Oct  9 17:55:00 2000
+++ linux/include/asm-ia64/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -7,6 +7,7 @@
  */
 
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 #include <asm/atomic.h>
 
@@ -116,208 +117,6 @@
 #endif
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
-}	
-
-/*
- * rw mutexes (should that be mutices? =) -- throw rw spinlocks and
- * semaphores together, and this is what we end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer subtracts BIAS
- * ands gets 0 for the case of an uncontended lock.  Readers decrement
- * by 1 and see a positive value when uncontended, negative if there
- * are writers waiting (in which case it goes to sleep).  BIAS must be
- * chosen such that subtracting BIAS once per CPU will result either
- * in zero (uncontended case) or in a negative value (contention
- * case).  On the other hand, BIAS must be at least as big as the
- * number of processes in the system.
- *
- * On IA-64, we use a BIAS value of 0x100000000, which supports up to
- * 2 billion (2^31) processors and 4 billion processes.
- *
- * In terms of fairness, when there is heavy use of the lock, we want
- * to see the lock being passed back and forth between readers and
- * writers (like in a producer/consumer style of communication).
- *
- *	      -ben (with clarifications & IA-64 comments by davidm)
- */
-#define RW_LOCK_BIAS		0x100000000ul
-
-struct rw_semaphore {
-	volatile long		count;
-	volatile __u8		write_bias_granted;
-	volatile __u8		read_bias_granted;
-	__u16			pad1;
-	__u32			pad2;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-# define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-# define __RWSEM_DEBUG_INIT
-#endif
-
-#define __RWSEM_INITIALIZER(name,count)						\
-{										\
-	(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait),	\
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait)			\
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT				\
-}
-
-#define __DECLARE_RWSEM_GENERIC(name,count)					\
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name)			__DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name)		__DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS - 1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name)	__DECLARE_RWSEM_GENERIC(name, 0)
-
-extern void __down_read_failed (struct rw_semaphore *sem, long count);
-extern void __down_write_failed (struct rw_semaphore *sem, long count);
-extern void __rwsem_wake (struct rw_semaphore *sem, long count);
-
-static inline void
-init_rwsem (struct rw_semaphore *sem)
-{
-	sem->count = RW_LOCK_BIAS;
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-static inline void
-down_read (struct rw_semaphore *sem)
-{
-	long count;
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-
-	count = ia64_fetch_and_add(-1, &sem->count);
-	if (count < 0)
-		__down_read_failed(sem, count);
-
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void
-down_write (struct rw_semaphore *sem)
-{
-	long old_count, new_count;
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-
-	do {
-		old_count = sem->count;
-		new_count = old_count - RW_LOCK_BIAS;
-	} while (cmpxchg_acq(&sem->count, old_count, new_count) != old_count);
-
-	if (new_count != 0)
-		__down_write_failed(sem, new_count);
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/*
- * When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void
-__up_read (struct rw_semaphore *sem)
-{
-	long count;
-
-	count = ia64_fetch_and_add(1, &sem->count);
-	if (count == 0)
-		/*
-		 * Other processes are blocked already; resolve
-		 * contention by letting either a writer or a reader
-		 * proceed...
-		 */
-		__rwsem_wake(sem, count);
-}
-
-/*
- * Releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void
-__up_write (struct rw_semaphore *sem)
-{
-	long old_count, new_count;
-
-	do {
-		old_count = sem->count;
-		new_count = old_count + RW_LOCK_BIAS;
-	} while (cmpxchg_rel(&sem->count, old_count, new_count) != old_count);
-
-	/*
-	 * Note: new_count <u RW_LOCK_BIAS <=> old_count < 0 && new_count >= 0.
-	 *	 (where <u is "unsigned less-than").
-	 */
-	if ((unsigned long) new_count < RW_LOCK_BIAS)
-		/* someone is blocked already, resolve contention... */
-		__rwsem_wake(sem, new_count);
-}
-
-static inline void
-up_read (struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-static inline void
-up_write (struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
 }
 
 #endif /* _ASM_IA64_SEMAPHORE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sigcontext.h linux/include/asm-ia64/sigcontext.h
--- v2.4.3/linux/include/asm-ia64/sigcontext.h	Sun Feb  6 18:42:40 2000
+++ linux/include/asm-ia64/sigcontext.h	Thu Apr  5 12:51:47 2001
@@ -36,6 +36,7 @@
 	unsigned long		sc_ar_lc;	/* loop count register */
 	unsigned long		sc_pr;		/* predicate registers */
 	unsigned long		sc_br[8];	/* branch registers */
+	/* Note: sc_gr[0] is used as the "uc_link" member of ucontext_t */
 	unsigned long		sc_gr[32];	/* general registers (static partition) */
 	struct ia64_fpreg	sc_fr[128];	/* floating-point registers */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/siginfo.h linux/include/asm-ia64/siginfo.h
--- v2.4.3/linux/include/asm-ia64/siginfo.h	Mon Oct  9 17:55:00 2000
+++ linux/include/asm-ia64/siginfo.h	Thu Apr  5 12:51:47 2001
@@ -2,8 +2,8 @@
 #define _ASM_IA64_SIGINFO_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/types.h>
@@ -66,6 +66,12 @@
 			long _band;	/* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */
 			int _fd;
 		} _sigpoll;
+		/* SIGPROF */
+		struct {
+			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
+			unsigned long _pfm_ovfl_counters; /* which PMU counter overflowed */
+		} _sigprof;
 	} _sifields;
 } siginfo_t;
 
@@ -85,6 +91,7 @@
 #define si_isr		_sifields._sigfault._isr	/* valid if si_code==FPE_FLTxxx */
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
+#define si_pfm_ovfl	_sifields._sigprof._pfm_ovfl_counters
 
 /*
  * si_code values
@@ -98,6 +105,7 @@
 #define __SI_FAULT	(3 << 16)
 #define __SI_CHLD	(4 << 16)
 #define __SI_RT		(5 << 16)
+#define __SI_PROF	(6 << 16)
 #define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
 #else
 #define __SI_KILL	0
@@ -201,12 +209,16 @@
 #define NSIGPOLL	6
 
 /*
+ * SIGPROF si_codes
+ */
+#define PROF_OVFL	(__SI_PROF|1)  /* some counters overflowed */
+
+/*
  * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
+ *
+ * It seems likely that SIGEV_THREAD will have to be handled from userspace, libpthread
+ * transmuting it to SIGEV_SIGNAL, which the thread manager then catches and does the
+ * appropriate nonsense.  However, everything is written out here so as to not get lost.
  */
 #define SIGEV_SIGNAL	0	/* notify via signal */
 #define SIGEV_NONE	1	/* other notification: meaningless */
@@ -246,6 +258,7 @@
 }
 
 extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
+extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h
--- v2.4.3/linux/include/asm-ia64/smp.h	Mon Oct  9 17:55:00 2000
+++ linux/include/asm-ia64/smp.h	Thu Apr  5 12:51:47 2001
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1999 VA Linux Systems 
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef _ASM_IA64_SMP_H
 #define _ASM_IA64_SMP_H
@@ -15,13 +17,14 @@
 #include <linux/threads.h>
 #include <linux/kernel.h>
 
-#include <asm/ptrace.h>
 #include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
 
 #define XTP_OFFSET		0x1e0008
 
-#define SMP_IRQ_REDIRECTION     (1 << 0)
-#define SMP_IPI_REDIRECTION     (1 << 1)
+#define SMP_IRQ_REDIRECTION	(1 << 0)
+#define SMP_IPI_REDIRECTION	(1 << 1)
 
 #define smp_processor_id()	(current->processor)
 
@@ -30,15 +33,15 @@
 	int cpu_phys_id[NR_CPUS];
 } smp_boot_data __initdata;
 
+extern char no_int_routing __initdata;
+
 extern unsigned long cpu_present_map;
 extern unsigned long cpu_online_map;
 extern unsigned long ipi_base_addr;
-extern int bootstrap_processor;
-extern volatile int __cpu_physical_id[NR_CPUS];
+extern int __cpu_physical_id[NR_CPUS];
 extern unsigned char smp_int_redirect;
-extern char no_int_routing;
 extern int smp_num_cpus;
-  
+
 #define cpu_physical_id(i)	__cpu_physical_id[i]
 #define cpu_number_map(i)	(i)
 #define cpu_logical_map(i)	(i)
@@ -54,54 +57,55 @@
 {
 	int i;
 
-	for (i=0; i<smp_num_cpus; i++) {
-		if (cpu_physical_id(i) == cpuid)
+	for (i = 0; i < smp_num_cpus; ++i)
+		if (cpu_physical_id(i) == (__u32) cpuid)
 			break;
-	}
 	return i;
 }
 
 /*
  * XTP control functions:
- *    min_xtp   :  route all interrupts to this CPU
- *    normal_xtp:  nominal XTP value
- *    max_xtp   :  never deliver interrupts to this CPU.
+ *	min_xtp   : route all interrupts to this CPU
+ *	normal_xtp: nominal XTP value
+ *	max_xtp   : never deliver interrupts to this CPU.
  */
 
 static inline void 
-min_xtp(void)
+min_xtp (void)
 {
 	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
 		writeb(0x00, ipi_base_addr | XTP_OFFSET); /* XTP to min */
 }
 
 static inline void
-normal_xtp(void)
+normal_xtp (void)
 {
 	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
 		writeb(0x08, ipi_base_addr | XTP_OFFSET); /* XTP normal */
 }
 
 static inline void
-max_xtp(void) 
+max_xtp (void) 
 {
 	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
 		writeb(0x0f, ipi_base_addr | XTP_OFFSET); /* Set XTP to max */
 }
 
 static inline unsigned int 
-hard_smp_processor_id(void)
+hard_smp_processor_id (void)
 {
-	struct {
-		unsigned long reserved : 16;
-		unsigned long eid : 8;
-		unsigned long id  : 8;
-		unsigned long ignored : 32;
+	union {
+		struct {
+			unsigned long reserved : 16;
+			unsigned long eid : 8;
+			unsigned long id : 8;
+			unsigned long ignored : 32;
+		} f;
+		unsigned long bits;
 	} lid;
 
-	__asm__ ("mov %0=cr.lid" : "=r" (lid));
-
-	return lid.id << 8 | lid.eid;
+	lid.bits = ia64_get_lid();
+	return lid.f.id << 8 | lid.f.eid;
 }
 
 #define NO_PROC_ID		(-1)
@@ -111,7 +115,7 @@
 extern void smp_do_timer (struct pt_regs *regs);
 
 extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info,
-			      int retry, int wait);
+				     int retry, int wait);
 
 
 #endif /* CONFIG_SMP */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/smplock.h linux/include/asm-ia64/smplock.h
--- v2.4.3/linux/include/asm-ia64/smplock.h	Thu Mar 23 12:50:09 2000
+++ linux/include/asm-ia64/smplock.h	Thu Apr  5 12:51:47 2001
@@ -3,10 +3,12 @@
  *
  * Default SMP lock implementation
  */
-#include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
 
-#include <asm/spinlock.h>
+#include <asm/current.h>
+#include <asm/hardirq.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/addrs.h linux/include/asm-ia64/sn/addrs.h
--- v2.4.3/linux/include/asm-ia64/sn/addrs.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/addrs.h	Thu Apr  5 12:51:47 2001
@@ -11,6 +11,7 @@
 #define _ASM_SN_ADDRS_H
 
 #include <linux/config.h>
+
 #if _LANGUAGE_C
 #include <linux/types.h>
 #endif /* _LANGUAGE_C */
@@ -21,22 +22,15 @@
 #include <asm/sn/kldir.h>
 #endif	/* CONFIG_IA64_SGI_SN1 */
 
-#if defined(CONFIG_IA64_SGI_IO)
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/sn1/addrs.h>
 #endif
-#endif	/* CONFIG_IA64_SGI_IO */
 
 
 #if _LANGUAGE_C
 
-#if defined(CONFIG_IA64_SGI_IO)	/* FIXME */
 #define PS_UINT_CAST		(__psunsigned_t)
 #define UINT64_CAST		(uint64_t)
-#else	/* CONFIG_IA64_SGI_IO */
-#define PS_UINT_CAST		(unsigned long)
-#define UINT64_CAST		(unsigned long)
-#endif	/* CONFIG_IA64_SGI_IO */
 
 #define HUBREG_CAST		(volatile hubreg_t *)
 
@@ -138,6 +132,8 @@
 
 #define UALIAS_BASE		HSPEC_BASE
 #define UALIAS_SIZE		0x10000000	/* 256 Megabytes */
+#define CPU_UALIAS		0x20000		/* 128 Kilobytes */
+#define UALIAS_CPU_SIZE		(CPU_UALIAS / CPUS_PER_NODE)
 #define UALIAS_LIMIT		(UALIAS_BASE + UALIAS_SIZE)
 
 /*
@@ -408,24 +404,19 @@
 #define PHYS_RAMBASE		0x0
 #define K0_RAMBASE		PHYS_TO_K0(PHYS_RAMBASE)
 
-#define EX_HANDLER_OFFSET(slice) ((slice) << 16)
-#define EX_HANDLER_ADDR(nasid, slice)					\
-	PHYS_TO_K0(NODE_OFFSET(nasid) | EX_HANDLER_OFFSET(slice))
-#define EX_HANDLER_SIZE		0x0400
-
-#define EX_FRAME_OFFSET(slice)	((slice) << 16 | 0x400)
-#define EX_FRAME_ADDR(nasid, slice)					\
-	PHYS_TO_K0(NODE_OFFSET(nasid) | EX_FRAME_OFFSET(slice))
-#define EX_FRAME_SIZE		0x0c00
-
 #define ARCS_SPB_OFFSET		0x1000
 #define ARCS_SPB_ADDR(nasid)						\
 	PHYS_TO_K0(NODE_OFFSET(nasid) | ARCS_SPB_OFFSET)
 #define ARCS_SPB_SIZE		0x0400
 
 #define KLDIR_OFFSET		0x2000
+#ifndef __ia64
 #define KLDIR_ADDR(nasid)						\
 	TO_NODE_UNCAC((nasid), KLDIR_OFFSET)
+#else
+#define KLDIR_ADDR(nasid)                                               \
+        TO_NODE_CAC((nasid), KLDIR_OFFSET)
+#endif
 #define KLDIR_SIZE		0x0400
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/agent.h linux/include/asm-ia64/sn/agent.h
--- v2.4.3/linux/include/asm-ia64/sn/agent.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/agent.h	Thu Apr  5 12:51:47 2001
@@ -13,6 +13,7 @@
 #define _ASM_SGI_SN_AGENT_H
 
 #include <linux/config.h>
+
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
 //#include <asm/sn/io.h>
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/arc/hinv.h linux/include/asm-ia64/sn/arc/hinv.h
--- v2.4.3/linux/include/asm-ia64/sn/arc/hinv.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/arc/hinv.h	Thu Apr  5 12:51:47 2001
@@ -89,7 +89,7 @@
 	PCIAdapter,
 	GIOAdapter,
 	TPUAdapter,
-
+	TernaryCache,
 	Anonymous
 } CONFIGTYPE;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/arch.h linux/include/asm-ia64/sn/arch.h
--- v2.4.3/linux/include/asm-ia64/sn/arch.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/arch.h	Thu Apr  5 12:51:47 2001
@@ -15,12 +15,10 @@
 #include <linux/types.h>
 #include <linux/config.h>
 
-#if defined(CONFIG_IA64_SGI_IO)
 #include <asm/sn/types.h>
 #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_SGI_IP37) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/sn1/arch.h>
 #endif
-#endif	/* CONFIG_IA64_SGI_IO */
 
 
 #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
@@ -68,7 +66,7 @@
  *	cputolocalslice - returns a number 0..1 that identifies the local slice of
  *			the cpu within it's PI interface.
  */
-#ifdef notyet
+#ifdef LATER
 	/* These are dummied up for now ..... */
 #define cputocnode(cpu)				\
                (pdaindr[(cpu)].p_nodeid)
@@ -86,7 +84,7 @@
 #define cputoslice(cpu) 0
 #define cputolocalslice(cpu) 0
 #define cputosubnode(cpu) 0
-#endif	/* notyet */
+#endif	/* LATER */
 #endif	/* CONFIG_SGI_IP35 */
 
 #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
@@ -131,6 +129,7 @@
     ((nnode) >> \
      (is_fine_dirmode() ? NASID_TO_FINEREG_SHFT : NASID_TO_COARSEREG_SHFT))
 
+#ifndef __ia64
 extern cnodeid_t nasid_to_compact_node[MAX_NASIDS];
 extern nasid_t compact_to_nasid_node[MAX_COMPACT_NODES];
 extern cnodeid_t cpuid_to_compact_node[MAXCPUS];
@@ -153,6 +152,17 @@
 #define COMPACT_TO_NASID_NODEID(cnode)	compact_to_nasid_nodeid(cnode)
 #define CPUID_TO_COMPACT_NODEID(cpu)	(cpuid_to_compact_node[(cpu)])
 #endif
+
+#else
+
+/*
+ * IA64 specific nasid and cnode ids.
+ */
+#define NASID_TO_COMPACT_NODEID(nasid)  (nasid_to_cnodeid(nasid))
+#define COMPACT_TO_NASID_NODEID(cnode)  (cnodeid_to_nasid(cnode))
+#define CPUID_TO_COMPACT_NODEID(cpu)    (cpuid_to_cnodeid(cpu))
+
+#endif /* #ifndef __ia64 */
 
 extern int node_getlastslot(cnodeid_t);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/cdl.h linux/include/asm-ia64/sn/cdl.h
--- v2.4.3/linux/include/asm-ia64/sn/cdl.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/cdl.h	Thu Apr  5 12:51:47 2001
@@ -30,6 +30,15 @@
 cdl_iter_f		(devfs_handle_t vhdl);
 
 /*
+ *	cdl_drv_f is the type for the functions
+ *	that are called by cdl_add_driver and 
+ *      cdl_del_driver.
+ */
+
+typedef void	
+cdl_drv_f		(devfs_handle_t vhdl, int key1, int key2, int error);
+
+/*
  *	If CDL_PRI_HI is specified in the flags
  *	parameter for cdl_add_driver, then that driver's
  *	attach routine will be called for future connect
@@ -73,8 +82,10 @@
  *
  *	Calls the driver's attach routine with all
  *	connection points on the list that have the same
- *	key information as the driver; then places the
- *	driver on the list so that any connection points
+ *	key information as the driver; call-back the 
+ *      specified function to notify the driver of the 
+ *      attach status for each device.  Place the driver
+ *      on the list so that any connection points
  *	discovered in the future that match the driver
  *	can be handed off to the driver's attach
  *	routine.
@@ -86,14 +97,17 @@
 				       int key1,
 				       int key2,
 				       char *prefix,
-				       int flags);
+				       int flags,
+				       cdl_drv_f *func);
 
 /*
  *	cdl_del_driver: remove a device driver
  *
  *	Calls the driver's detach routine with all
  *	connection points on the list that match the
- *	driver; then forgets about the driver. Future
+ *	driver;  call-back the specified function to
+ *      notify the driver of the detach status for each
+ *      device.  Then forget about the driver.  Future
  *	calls to cdl_add_connpt with connections that
  *	would match this driver no longer trigger calls
  *	to the driver's attach routine.
@@ -107,7 +121,8 @@
  *	was successful.
  */
 extern void		cdl_del_driver(cdl_p reg, 
-				       char *prefix);
+				       char *prefix,
+				       cdl_drv_f *func);
 
 /*
  *	cdl_add_connpt: add a connection point
@@ -124,7 +139,8 @@
 extern int		cdl_add_connpt(cdl_p reg,
 				       int key1,
 				       int key2,
-				       devfs_handle_t conn);
+				       devfs_handle_t conn,
+				       int drv_flags);
 
 /*
  *	cdl_del_connpt: delete a connection point
@@ -138,10 +154,11 @@
  *	NOTE: Same caveat here about the detach calls as
  *	in the cdl_del_driver() comment above.
  */
-extern void		cdl_del_connpt(cdl_p reg,
+extern int		cdl_del_connpt(cdl_p reg,
 				       int key1,
 				       int key2,
-				       devfs_handle_t conn);
+				       devfs_handle_t conn,
+				       int drv_flags);
 
 /*
  *	cdl_iterate: find all verticies in the registry
@@ -162,7 +179,7 @@
  */
 
 struct async_attach_s {
-	sema_t async_sema;
+	struct semaphore async_sema;
 	int    async_count;
 };
 typedef struct async_attach_s *async_attach_t;
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/cmn_err.h linux/include/asm-ia64/sn/cmn_err.h
--- v2.4.3/linux/include/asm-ia64/sn/cmn_err.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/cmn_err.h	Wed Dec 31 16:00:00 1969
@@ -1,120 +0,0 @@
-/* $Id$
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
- */
-#ifndef _ASM_SN_CMN_ERR_H
-#define _ASM_SN_CMN_ERR_H
-
-/*
-** Common error handling severity levels.  Converted to be
-** represented by the associated 4.3BSD syslog priorities.
-*/
-
-#define CE_DEBUG	KERN_DEBUG	/* debug	*/
-#define CE_CONT		KERN_INFO	/* continuation	*/
-#define CE_NOTE		KERN_NOTICE	/* notice	*/
-#define CE_WARN		KERN_WARNING	/* warning	*/
-#define CE_ALERT	KERN_ALERT	/* alert	*/
-#define CE_PANIC	KERN_EMERG	/* panic	*/
-
-#define	CE_LEVELMASK	LOG_PRIMASK	/* mask for severity level	*/
-#define	CE_CPUID	0x8		/* prepend CPU id to output	*/
-#define CE_PHYSID	0x10		/* prepend CPU phys location    */
-#define CE_SYNC		0x20		/* wait for uart to drain before returning */
-
-/* Flags for Availmon Monitoring
- * When a developer or's these bits into the cmn_err flags above,
- * and they have availmon installed, certain "actions" will take
- * place depending upon how they have the availmon software configured.
- */
-#define CE_TOOKACTIONS   0x0100            /* Actions taken by some error   */
-#define CE_RUNNINGPOOR   0x0200            /* System running degraded       */
-#define CE_MAINTENANCE   0x0400            /* System needs maintenance      */
-#define CE_CONFIGERROR   0x0800            /* System configured incorrectly */
-
-/* Bitmasks for separating subtasks from priority levels */
-#define CE_PRIOLEVELMASK 0x00ff  /* bitmask for severity levels of cmn_err */
-#define CE_SUBTASKMASK   0xff00  /* bitmask for availmon actions of cmn_err */
-#define CE_AVAILMONALL   (CE_TOOKACTIONS|CE_RUNNINGPOOR| \
-                                 CE_MAINTENANCE|CE_CONFIGERROR)
-
-#ifdef __KERNEL__
-
-#define CE_PBPANIC	KERN_CRIT	/* Special define used to manipulate
-					 * putbufndx in kernel */
-
-/* Console output flushing flag and routine */
-
-extern int constrlen;		/* Length of current console string, if zero,
-				   there are no characters to flush */
-#define	CONBUF_LOCKED	0	/* conbuf is already locked */
-#define	CONBUF_UNLOCKED	1	/* need to reacquire lock */
-#define CONBUF_DRAIN	2	/* ensure output before returning */
-
-/*
- * bit field descriptions for printf %r and %R formats
- *
- * printf("%r %R", val, reg_descp);
- * struct reg_desc *reg_descp;
- *
- * the %r and %R formats allow formatted print of bit fields.  individual
- * bit fields are described by a struct reg_desc, multiple bit fields within
- * a single word can be described by multiple reg_desc structures.
- * %r outputs a string of the format "<bit field descriptions>"
- * %R outputs a string of the format "0x%x<bit field descriptions>"
- *
- * The fields in a reg_desc are:
- *	__psunsigned_t rd_mask;	An appropriate mask to isolate the bit field
- *				within a word, and'ed with val
- *
- *	int rd_shift;		A shift amount to be done to the isolated
- *				bit field.  done before printing the isolate
- *				bit field with rd_format and before searching
- *				for symbolic value names in rd_values
- *
- *	char *rd_name;		If non-null, a bit field name to label any
- *				out from rd_format or searching rd_values.
- *				if neither rd_format or rd_values is non-null
- *				rd_name is printed only if the isolated
- *				bit field is non-null.
- *
- *	char *rd_format;	If non-null, the shifted bit field value
- *				is printed using this format.
- *
- *	struct reg_values *rd_values;	If non-null, a pointer to a table
- *				matching numeric values with symbolic names.
- *				rd_values are searched and the symbolic
- *				value is printed if a match is found, if no
- *				match is found "???" is printed.
- *				
- */
-
-
-/*
- * register values
- * map between numeric values and symbolic values
- */
-struct reg_values {
-	__psunsigned_t rv_value;
-	char *rv_name;
-};
-
-/*
- * register descriptors are used for formatted prints of register values
- * rd_mask and rd_shift must be defined, other entries may be null
- */
-struct reg_desc {
-	k_machreg_t rd_mask;	/* mask to extract field */
-	int rd_shift;		/* shift for extracted value, - >>, + << */
-	char *rd_name;		/* field name */
-	char *rd_format;	/* format to print field */
-	struct reg_values *rd_values;	/* symbolic names of values */
-};
-
-#endif	/* __KERNEL__ */
-#endif	/* _ASM_SN_CMN_ERR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/dmamap.h linux/include/asm-ia64/sn/dmamap.h
--- v2.4.3/linux/include/asm-ia64/sn/dmamap.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/dmamap.h	Thu Apr  5 12:51:47 2001
@@ -10,6 +10,8 @@
 #ifndef _ASM_SN_DMAMAP_H
 #define _ASM_SN_DMAMAP_H
 
+#include <asm/sn/sv.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -53,7 +55,7 @@
 extern int	dma_map(dmamap_t *, caddr_t, int);
 extern int	dma_map2(dmamap_t *, caddr_t, caddr_t, int);
 extern paddr_t	dma_mapaddr(dmamap_t *, caddr_t);
-#ifdef IRIX
+#ifdef LATER
 extern int	dma_mapbp(dmamap_t *, buf_t *, int);
 #endif
 extern int	dma_map_alenlist(dmamap_t *, struct alenlist_s *, size_t);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/eeprom.h linux/include/asm-ia64/sn/eeprom.h
--- v2.4.3/linux/include/asm-ia64/sn/eeprom.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/eeprom.h	Thu Apr  5 12:51:47 2001
@@ -349,7 +349,7 @@
  * is ignored.
  */
 
-#ifdef IRIX
+#ifdef LATER
 char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v,
 			      net_vec_t path );
 #endif
@@ -363,7 +363,7 @@
  * if the part and mfg numbers stored there indicate that this widget
  * is an XBridge (and so must be part of a brick).
  */
-#ifdef IRIX
+#ifdef LATER
 int is_iobrick( int nasid, int widget_num );
 #endif
 
@@ -371,11 +371,7 @@
  * address passed to it and uses is_iobrick to determine whether
  * the widget in question is part of an SN1 IO brick.
  */
-#ifdef IRIX
 #define IS_IOBRICK(rg)	is_iobrick( NASID_GET((rg)), SWIN_WIDGETNUM((rg)) )
-#else
-#define IS_IOBRICK(rg)	1
-#endif
 
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/gda.h linux/include/asm-ia64/sn/gda.h
--- v2.4.3/linux/include/asm-ia64/sn/gda.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/gda.h	Thu Apr  5 12:51:47 2001
@@ -61,7 +61,7 @@
 				/* Pointer to a mask of nodes with copies
 				 * of the kernel. */
 	char	g_padding[56];	/* pad out to 128 bytes */
-	nasid_t	g_nasidtable[MAX_COMPACT_NODES]; /* NASID of each node,
+	nasid_t	g_nasidtable[MAX_COMPACT_NODES+1]; /* NASID of each node,
 						  * indexed by cnodeid.
 						  */
 } gda_t;
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/hack.h linux/include/asm-ia64/sn/hack.h
--- v2.4.3/linux/include/asm-ia64/sn/hack.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/hack.h	Thu Apr  5 12:51:47 2001
@@ -22,6 +22,10 @@
 typedef int cred_t;	/* This is for compilation reasons */
 struct cred { int x; };
 
+
+#define mrlock(_s, _t, _u)
+#define mrunlock(_s)
+
 /*
  * Hardware Graph routines that are currently stubbed!
  */
@@ -34,50 +38,26 @@
  * Routines redefined to use linux equivalents. *
  ************************************************/
 
-#define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__)
+/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */
 
-#define sv_init(a,b,c)          FIXME("Fixme: sv_init : no-op")
-#define sv_wait(a,b,c,d)        FIXME("Fixme: sv_wait : no-op")
-#define sv_broadcast(a)  	FIXME("Fixme: sv_broadcast : no-op")
-#define sv_destroy(a)		FIXME("Fixme: sv_destroy : no-op")
+#define FIXME(s)
 
 extern devfs_handle_t dummy_vrtx;
 #define cpuid_to_vertex(cpuid) dummy_vrtx /* (pdaindr[cpuid].pda->p_vertex) */
 
 #define PUTBUF_LOCK(a) { FIXME("PUTBUF_LOCK"); }
 #define PUTBUF_UNLOCK(a) { FIXME("PUTBUF_UNLOCK"); }
-static inline int sv_signal(sv_t *a) {FIXME("sv_signal : return 0"); return (0); }
-
-#define cmn_err(x,y...)         { FIXME("cmn_err : use printk"); printk(x y); }
 
 typedef int (*splfunc_t)(void);
-extern int badaddr_val(volatile void *, int , volatile void *);
-
-extern int cap_able_cred(uint64_t a, uint64_t b);
-
-#define _CAP_CRABLE(cr,c)	(cap_able_cred(cr,c))
-#define CAP_MEMORY_MGT          (0x01LL << 25)
-#define CAP_DEVICE_MGT          (0x01LL << 37)
-
-#define io_splock(l) l
-#define io_spunlock(l,s)
 
 /* move to stubs.c yet */
-#define spinlock_destroy(a)     /* needed by pcibr_detach() */
-#define mutex_spinlock(a) 0
-#define mutex_spinunlock(a,b)
-#define mutex_spinlock_spl(x,y) y
-#define mutex_init(a,b,c)               ;
-#define mutex_lock(a,b)                 ;
-#define mutex_unlock(a)                 ;
 #define dev_to_vhdl(dev) 0
 #define get_timestamp() 0
 #define us_delay(a)
-#define v_mapphys(a,b,c) printk("Fixme: v_mapphys - soft->base 0x%p\n", b);
+#define v_mapphys(a,b,c) 0    // printk("Fixme: v_mapphys - soft->base 0x%p\n", b);
 #define splhi()  0
 #define spl7	splhi()
 #define splx(s)
-#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name);
 
 extern void * kmem_alloc_node(register size_t, register int, cnodeid_t);
 extern void * kmem_zalloc(size_t, int);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/hcl.h linux/include/asm-ia64/sn/hcl.h
--- v2.4.3/linux/include/asm-ia64/sn/hcl.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/hcl.h	Thu Apr  5 12:51:47 2001
@@ -13,6 +13,7 @@
 extern spinlock_t hcl_spinlock;
 extern devfs_handle_t hcl_handle; /* HCL driver */
 extern devfs_handle_t hwgraph_root;
+extern devfs_handle_t linux_busnum;
 
 
 typedef long            labelcl_info_place_t;
@@ -22,7 +23,6 @@
 /* Support for INVENTORY */
 struct inventory_s;
 struct invplace_s;
-extern struct invplace_s invplace_none;
 
 
 /* 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/hwcntrs.h linux/include/asm-ia64/sn/hwcntrs.h
--- v2.4.3/linux/include/asm-ia64/sn/hwcntrs.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/hwcntrs.h	Thu Apr  5 12:51:47 2001
@@ -73,7 +73,6 @@
 } rcb_slot_t;
 
 #if defined(__KERNEL__)
-// #include <sys/immu.h>
 typedef struct sn0_refcnt_args_32 {
 	uint64_t    vaddr;
 	uint64_t    len;
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/intr.h linux/include/asm-ia64/sn/intr.h
--- v2.4.3/linux/include/asm-ia64/sn/intr.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/intr.h	Thu Apr  5 12:51:47 2001
@@ -10,6 +10,9 @@
 #ifndef _ASM_SN_INTR_H
 #define _ASM_SN_INTR_H
 
+/* Subnode wildcard */
+#define SUBNODE_ANY		-1
+
 /* Number of interrupt levels associated with each interrupt register. */
 #define N_INTPEND_BITS		64
 
@@ -24,8 +27,6 @@
 
 #if LANGUAGE_C
 
-#if defined(CONFIG_IA64_SGI_IO)
-
 #define II_NAMELEN	24
 
 /*
@@ -36,7 +37,7 @@
 	intr_func_t	iv_func;	/* Interrupt handler function */
 	intr_func_t	iv_prefunc;	/* Interrupt handler prologue func */
 	void		*iv_arg;	/* Argument to pass to handler */
-#ifdef IRIX
+#ifdef LATER
 	thd_int_t		iv_tinfo;	/* Thread info */
 #endif
 	cpuid_t			iv_mustruncpu;	/* Where we must run. */
@@ -93,7 +94,7 @@
 						     call an intr routine. */
 	intr_info_t	info[N_INTPEND_BITS];	  /* information needed only
 						     to maintain interrupts. */
-	lock_t		vector_lock;		  /* Lock for this and the
+	spinlock_t	vector_lock;		  /* Lock for this and the
 						     masks in the PDA. */
 	splfunc_t	vector_spl;		  /* vector_lock req'd spl */
 	int		vector_state;		  /* Initialized to zero.
@@ -122,15 +123,12 @@
 #define hub_intrinfo0	private.p_intmasks.dispatch0->info
 #define hub_intrinfo1	private.p_intmasks.dispatch1->info
 
-#endif	/* CONFIG_IA64_SGI_IO */
-
 /*
  * Macros to manipulate the interrupt register on the calling hub chip.
  */
 
 #define LOCAL_HUB_SEND_INTR(_level)	LOCAL_HUB_S(PI_INT_PEND_MOD, \
 						    (0x100|(_level)))
-#if defined(CONFIG_IA64_SGI_IO)
 #define REMOTE_HUB_PI_SEND_INTR(_hub, _sn, _level) \
 		REMOTE_HUB_PI_S((_hub), _sn, PI_INT_PEND_MOD, (0x100|(_level)))
 
@@ -138,7 +136,6 @@
 		REMOTE_HUB_PI_S(cputonasid(_cpuid),				\
 			SUBNODE(cputoslice(_cpuid)),				\
 			PI_INT_PEND_MOD, (0x100|(_level)))
-#endif	/* CONFIG_IA64_SGI_IO*/
 
 /*
  * When clearing the interrupt, make sure this clear does make it 
@@ -153,7 +150,6 @@
 		REMOTE_HUB_PI_S((_hub), (_sn), PI_INT_PEND_MOD, (_level)),	\
                 REMOTE_HUB_PI_L((_hub), (_sn), PI_INT_PEND0)
 
-#if defined(CONFIG_IA64_SGI_IO)
 /* Special support for use by gfx driver only.  Supports special gfx hub interrupt. */
 extern void install_gfxintr(cpuid_t cpu, ilvl_t swlevel, intr_func_t intr_func, void *intr_arg);
 
@@ -164,7 +160,6 @@
  */
 extern void intr_block_bit(cpuid_t cpu, int bit);
 extern void intr_unblock_bit(cpuid_t cpu, int bit);
-#endif	/* CONFIG_IA64_SGI_IO */
 
 #endif /* LANGUAGE_C */
 
@@ -246,6 +241,13 @@
 # define IO_ERROR_INTR	38	/* set up by prom */
 # define DEBUG_INTR_B	37	/* used by symmon to stop all cpus */
 # define DEBUG_INTR_A	36
+#endif
+
+#ifdef CONFIG_IA64_SGI_SN1
+// These aren't strictly accurate or complete.  See the
+// Synergy Spec. for details.
+#define SGI_UART_IRQ	(65)
+#define SGI_HUB_ERROR_IRQ	(182)
 #endif
 
 #endif /* _ASM_SN_INTR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/intr_public.h linux/include/asm-ia64/sn/intr_public.h
--- v2.4.3/linux/include/asm-ia64/sn/intr_public.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/intr_public.h	Thu Apr  5 12:51:47 2001
@@ -7,9 +7,10 @@
  * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2000 by Colin Ngam
  */
-#ifndef __SYS_SN_INTR_PUBLIC_H__
-#define __SYS_SN_INTR_PUBLIC_H__
+#ifndef _ASM_SN_INTR_PUBLIC_H__
+#define _ASM_SN_INTR_PUBLIC_H__
 
+#include <linux/config.h>
 
 /* REMEMBER: If you change these, the whole world needs to be recompiled.
  * It would also require changing the hubspl.s code and SN0/intr.c
@@ -22,7 +23,6 @@
 #define INTPEND0_MAXMASK	(N_INTPEND0_MASKS - 1)
 #define INTPEND1_MAXMASK	(N_INTPEND1_MASKS - 1)
 
-#include <linux/config.h>
 #if _LANGUAGE_C
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/sn1/arch.h>
@@ -56,5 +56,4 @@
 } hub_intmasks_t;
 
 #endif /* _LANGUAGE_C */
-#endif /* __SYS_SN_INTR_PUBLIC_H__ */
-
+#endif /* _ASM_SN_INTR_PUBLIC_H__ */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/invent.h linux/include/asm-ia64/sn/invent.h
--- v2.4.3/linux/include/asm-ia64/sn/invent.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/invent.h	Thu Apr  5 12:51:47 2001
@@ -30,6 +30,10 @@
 #define app32_ptr_t unsigned long
 #define graph_vertex_place_t long
 #define GRAPH_VERTEX_NONE ((devfs_handle_t)-1)
+#define GRAPH_EDGE_PLACE_NONE ((graph_edge_place_t)0)
+#define GRAPH_INFO_PLACE_NONE ((graph_info_place_t)0)
+#define GRAPH_VERTEX_PLACE_NONE ((graph_vertex_place_t)0)
+
 
 typedef struct inventory_s {
 	struct	inventory_s *inv_next;	/* next inventory record in list */
@@ -105,6 +109,8 @@
 #define INV_RPS		23      /* redundant power source */
 #define INV_TPU		24	/* Tensor Processing Unit */
 #define INV_FCNODE	25	/* Helper class for SCSI classes, not in classes[] */
+#define INV_USB		26	/* Universal Serial Bus */
+#define INV_1394NODE    27      /* helper class for 1394/SPB2 classes, not in classes[] */
 
 /* types for class processor */
 #define INV_CPUBOARD	1
@@ -187,8 +193,11 @@
 #define INV_QL_12160    17      /* qlogic 12160 */
 #define INV_QL_2100	18	/* qLogic 2100 Fibrechannel */
 #define INV_QL_2200	19	/* qLogic 2200 Fibrechannel */
-#define INV_SBP2	20	/* SBP2 protocol over OHCI on 1394 */
-
+#define INV_PR_HIO_D	20	/* Prisa HIO Dual channel */
+#define INV_PR_PCI64_D	21	/* Prisa PCI-64 Dual channel */
+#define INV_QL_2200A	22	/* qLogic 2200A Fibrechannel */
+#define INV_SBP2        23      /* SBP2 protocol over OHCI on 1394 */
+#define INV_QL_2300	24	/* qLogic 2300 Fibrechannel */
 
 
 /* states for INV_SCSIDRIVE type of class disk */
@@ -215,6 +224,7 @@
 #define INV_SIDCACHE	8
 #define INV_MAIN_MB	9
 #define INV_HUBSPC      10      /* HUBSPC */
+#define INV_TIDCACHE	11
 
 /* types for class serial */
 #define INV_CDSIO	1	/* Central Data serial board */
@@ -405,6 +415,7 @@
 #define INV_NET_ISDN_PRI	8	/* PRI ISDN */
 #define INV_NET_HIPPIS		9	/* HIPPI-Serial */
 #define	INV_NET_GSN		10	/* GSN (aka HIPPI-6400) */
+#define INV_NET_MYRINET		11	/* Myricom PCI network */
 
 /* controllers for network types, unique within class network */
 #define INV_ETHER_EC	0	/* IP6 integral controller */
@@ -463,6 +474,7 @@
 #define INV_OPTICAL	7	/* optical disks (read-write) */
 #define INV_CHANGER	8	/* jukebox's for CDROMS, for example */
 #define INV_COMM	9	/* Communications device */
+#define INV_STARCTLR	12	/* Storage Array Controller */
 #define INV_RAIDCTLR	32	/* RAID ctlr actually gives type 0 */
 
 /* bit definitions for state field for class INV_SCSI */
@@ -495,6 +507,7 @@
 #define	INV_VIDEO_RACER		11	/* SpeedRacer Pro Video */
 #define	INV_VIDEO_EVO		12	/* EVO Personal Video */
 #define INV_VIDEO_XTHD		13	/* XIO XT-HDTV video */
+#define INV_VIDEO_XTDIGVID      14      /* XIO XT-HDDIGVID video */
 
 /* states for video class INV_VIDEO_EXPRESS */
 
@@ -568,10 +581,7 @@
 #define INV_7of9_PANEL          5       /* 7of9 flatpanel board and panel */
 
 /* types for class INV_IEEE1394 */
-#define INV_OHCI		0	/* Ohci IEEE1394 pci card */
-#define INV_RAWISO1394   	10	/* Raw Isochronous IEEE 1394 protocol driver */
-#define INV_RAWASYNC1394 	11	/* Raw Asynchronous IEEE 1394 protocol driver */
-#define INV_AVC1394     	12	/* Audio, Video & Control (AV/C) IEEE 1394 protocol driver */
+#define INV_OHCI	0	/* Ohci IEEE1394 pci card */
 
 /* state for class INV_IEEE1394 & type INV_OHCI */
 #define INV_IEEE1394_STATE_TI_REV_1 0
@@ -583,6 +593,51 @@
 #define	INV_TPU_EXT		0	/* External XIO Tensor Processing Unit */
 #define	INV_TPU_XIO		1	/* Internal XIO Tensor Processing Unit */
 
+/*
+ * USB Types.  The upper 8 bits contain general usb device class and are used to
+ * qualify the lower 8 bits which contain device type within a usb class.
+ * Use USB_INV_DEVCLASS and USB_INV_DEVTYPE to to decode an i_type, and
+ * USB_INV_TYPE to set it.
+ */
+
+#define USB_INV_DEVCLASS(invtype)	((invtype) >> 8)
+#define USB_INV_DEVTYPE(invtype)	((invtype) & 0xf)
+#define USB_INV_TYPE(usbclass, usbtype)	(((usbclass) << 8) | (usbtype))
+
+/*
+ * USB device classes.  These classes might not match the classes as defined
+ * by the usb spec, but where possible we will try.
+ */
+
+#define USB_INV_CLASS_RH	0x00	/* root hub (ie. controller) */
+#define USB_INV_CLASS_HID	0x03	/* human interface device */
+#define USB_INV_CLASS_HUB	0x09	/* hub device */
+
+/*
+ * USB device types within a class.  These will not match USB device types,
+ * as the usb is not consistent on how specific types are defined (sometimes
+ * they are found in the interface subclass, sometimes (as in HID devices) they
+ * are found within data generated by the device (hid report descriptors for
+ * example).
+ */
+
+/*
+ * RH types
+ */
+
+#define USB_INV_RH_OHCI		0x01	/* ohci root hub */
+
+/*
+ * HID types
+ */
+
+#define USB_INV_HID_KEYBOARD	0x01	/* kbd (HID class) */
+#define USB_INV_HID_MOUSE	0x02	/* mouse (HID class) */
+
+/*
+ * HUB types - none yet
+ */
+
 typedef struct invent_generic_s {
 	unsigned short	ig_module;
 	unsigned short	ig_slot;
@@ -618,6 +673,8 @@
 	cpu_inv_t     ic_cpu_info;
 	unsigned short	ic_cpuid;
 	unsigned short	ic_slice;
+	unsigned short  ic_cpumode;
+
 } invent_cpuinfo_t;
 
 typedef struct invent_rpsinfo {
@@ -659,9 +716,14 @@
 	inventory_t		*invplace_inv;		/* place in inv list on vertex */
 } invplace_t; /* Magic cookie placeholder in inventory list */
 
+extern invplace_t invplace_none;
+#define INVPLACE_NONE invplace_none
+
 extern void	    add_to_inventory(int, int, int, int, int);
 extern void	    replace_in_inventory(inventory_t *, int, int, int, int, int);
+extern void         start_scan_inventory(invplace_t *);
 extern inventory_t  *get_next_inventory(invplace_t *);
+extern void         end_scan_inventory(invplace_t *);
 extern inventory_t  *find_inventory(inventory_t *, int, int, int, int, int);
 extern int	    scaninvent(int (*)(inventory_t *, void *), void *);
 extern int	    get_sizeof_inventory(int);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/io.h linux/include/asm-ia64/sn/io.h
--- v2.4.3/linux/include/asm-ia64/sn/io.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/io.h	Thu Apr  5 12:51:47 2001
@@ -12,20 +12,12 @@
 #define _ASM_SN_IO_H
 
 #include <linux/config.h>
+
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/sn1/addrs.h>
 #endif
 
-#define IO_SPACE_BASE IO_BASE
-
 /* Because we only have PCI I/O ports.  */
-#if !defined(CONFIG_IA64_SGI_IO)
-#define IO_SPACE_LIMIT 0xffffffff
-
-/* No isa_* versions, the Origin doesn't have ISA / EISA bridges.  */
-
-#else	/* CONFIG_IA64_SGI_IO */
-
 #define IIO_ITTE_BASE	0x400160	/* base of translation table entries */
 #define IIO_ITTE(bigwin)	(IIO_ITTE_BASE + 8*(bigwin))
 
@@ -71,7 +63,5 @@
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/sn1/hubio.h>
 #endif
-
-#endif	/* CONFIG_IA64_SGI_IO */
 
 #endif /* _ASM_SN_IO_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ioerror.h linux/include/asm-ia64/sn/ioerror.h
--- v2.4.3/linux/include/asm-ia64/sn/ioerror.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/ioerror.h	Thu Apr  5 12:51:47 2001
@@ -10,6 +10,7 @@
 #ifndef _ASM_SN_IOERROR_H
 #define _ASM_SN_IOERROR_H
 
+#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
 
 /*
  * Macros defining the various Errors to be handled as part of
@@ -177,6 +178,7 @@
     MODE_DEVREENABLE		/* Reenable pass                */
 } ioerror_mode_t;
 
+#endif				/* C || C++ */
 
 typedef int             error_handler_f(void *, int, ioerror_mode_t, ioerror_t *);
 typedef void           *error_handler_arg_t;
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ioerror_handling.h linux/include/asm-ia64/sn/ioerror_handling.h
--- v2.4.3/linux/include/asm-ia64/sn/ioerror_handling.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/ioerror_handling.h	Thu Apr  5 12:51:47 2001
@@ -12,7 +12,7 @@
 
 #include <linux/config.h>
 
-#ifdef __KERNEL__
+#if __KERNEL__
 
 /*
  * Basic types required for io error handling interfaces.
@@ -255,7 +255,7 @@
 	int		code = 0;		
 
 	/* Check if we have a valid hwgraph vertex */
-#ifdef IRIX
+#ifdef	LATER
 	if (!dev_is_vertex(v))
 		return(code);
 #endif
@@ -276,18 +276,6 @@
 	}								   
 	ASSERT(v_error_skip_env_get(v, error_env) == GRAPH_SUCCESS);
 	code = setjmp(*error_env);					   
-#ifdef IRIX
-	/* NOTE: It might be OK to leave the allocated jump buffer on the
-	 * vertex. This can be used for later purposes.
-	 */
-	if (code) {							   
-		/* This is the case where a long jump has been taken from one
-		 * one of the error handling interfaces.		     
-		 */							     
-		if (v_error_skip_env_clear(v, error_env) == GRAPH_SUCCESS)   
-			kfree(error_env);
-	}								     
-#endif
 	return(code);							     
 }
 #endif	/* CONFIG_SGI_IO_ERROR_HANDLING */
@@ -309,8 +297,6 @@
  * thru the calls the io error handling layer.
  */
 #if defined(CONFIG_SGI_IO_ERROR_HANDLING)
-#define IS_DEVICE_SHUTDOWN(_d) 	(error_state_get(_d) == ERROR_STATE_SHUTDOWN)
-#else
 extern boolean_t		is_device_shutdown(devfs_handle_t);
 #define IS_DEVICE_SHUTDOWN(_d) 	(is_device_shutdown(_d))
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/iograph.h linux/include/asm-ia64/sn/iograph.h
--- v2.4.3/linux/include/asm-ia64/sn/iograph.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/iograph.h	Thu Apr  5 12:51:47 2001
@@ -90,6 +90,7 @@
 #define EDGE_LBL_PROM			"prom"
 #define EDGE_LBL_RACK			"rack"
 #define EDGE_LBL_RDISK			"rdisk"
+#define EDGE_LBL_REPEATER_ROUTER	"repeaterrouter"
 #define EDGE_LBL_ROUTER			"router"
 #define EDGE_LBL_RPOS			"bay"		/* Position in rack */
 #define EDGE_LBL_SCSI			"scsi"
@@ -117,9 +118,9 @@
 #define EDGE_LBL_RPS                    "rps"           /* redundant power supply */ 
 #define EDGE_LBL_XBOX_RPS               "xbox_rps"      /* redundant power supply for xbox unit */ 
 #define EDGE_LBL_IOBRICK		"iobrick"
-#define EDGE_LBL_PBRICK			"pbrick"
-#define EDGE_LBL_IBRICK			"ibrick"
-#define EDGE_LBL_XBRICK			"xbrick"
+#define EDGE_LBL_PBRICK			"Pbrick"
+#define EDGE_LBL_IBRICK			"Ibrick"
+#define EDGE_LBL_XBRICK			"Xbrick"
 #define EDGE_LBL_CPUBUS			"cpubus"	/* CPU Interfaces (SysAd) */
 
 /* vertex info labels in hwgraph */
@@ -134,6 +135,8 @@
 #define INFO_LBL_DKIOTIME		"_dkiotime"
 #define INFO_LBL_DRIVER			"_driver"	/* points to attached device_driver_t */
 #define INFO_LBL_ELSC			"_elsc"
+#define	INFO_LBL_SUBCH			"_subch"	/* system controller subchannel */
+#define INFO_LBL_L1SCP			"_l1scp"	/* points to l1sc_t */
 #define INFO_LBL_FC_PORTNAME		"_fc_portname"
 #define INFO_LBL_GIOIO			"_gioio"
 #define INFO_LBL_GFUNCS			"_gioio_ops"	/* ops vector for gio providers */
@@ -196,5 +199,21 @@
 #if defined(__KERNEL__)
 void init_all_devices(void);
 #endif /* __KERNEL__ */
+
+#include <asm/sn/xtalk/xbow.h>	/* For get MAX_PORT_NUM */
+
+int io_brick_map_widget(char, int);
+int io_path_map_widget(devfs_handle_t);
+
+/*
+ * Map a brick's widget number to a meaningful int
+ */
+
+struct io_brick_map_s {
+    char                ibm_type;                  /* brick type, e.g. */
+                                                   /* 'I' for Ibrick   */
+    int                 ibm_map_wid[MAX_PORT_NUM]; /* wid to int map */
+};
+
 
 #endif /* _ASM_SN_IOGRAPH_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/klconfig.h linux/include/asm-ia64/sn/klconfig.h
--- v2.4.3/linux/include/asm-ia64/sn/klconfig.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/klconfig.h	Thu Apr  5 12:51:47 2001
@@ -12,6 +12,8 @@
 #ifndef	_ASM_SN_KLCONFIG_H
 #define	_ASM_SN_KLCONFIG_H
 
+#include <linux/config.h>
+
 /*
  * klconfig.h
  */
@@ -32,7 +34,6 @@
  *      that offsets of existing fields do not change.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/sn/types.h>
 #include <asm/sn/slotnum.h>
@@ -60,11 +61,10 @@
 #define SIZE_PAD		4096 /* 4k padding for structures */
 #if (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP) /* MAX_SLOTS_PER_NODE??? */
 /* 
- * 1 NODE brick, 2 Router bricks (1 local, 1 meta), 6 XIO Widgets, 
- * 1 Midplane (midplane will likely become IO brick when Bruce cleans
- * up IP35 klconfig)
+ * 1 NODE brick, 3 Router bricks (1 local, 1 meta, 1 repeater),
+ * 6 XIO Widgets, 1 Xbow, 1 gfx
  */
-#define MAX_SLOTS_PER_NODE	(1 + 2 + 6 + 1) 
+#define MAX_SLOTS_PER_NODE	(1 + 3 + 6 + 1 + 1) 
 #else
 /* 
  * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets, 
@@ -88,7 +88,7 @@
 #define VISITED_BOARD		0x08	/* Used for compact hub numbering. */
 #define LOCAL_MASTER_IO6	0x10 	/* master io6 for that node */
 #define GLOBAL_MASTER_IO6	0x20
-#define THIRD_NIC_PRESENT 	0x40  	/* for future use */
+#define GLOBAL_MASTER_EXT 	0x40  	/* extend master io6 to other bus on ibrick */
 #define SECOND_NIC_PRESENT 	0x80 	/* addons like MIO are present */
 
 /* klinfo->flags fields */
@@ -119,15 +119,9 @@
 
 
 typedef struct console_s {
-#if defined(CONFIG_IA64_SGI_IO)	/* FIXME */
 	__psunsigned_t 	uart_base;
 	__psunsigned_t 	config_base;
 	__psunsigned_t 	memory_base;
-#else
-	unsigned long 	uart_base;
-	unsigned long 	config_base;
-	unsigned long 	memory_base;
-#endif
 	short		baud;
 	short		flag;
 	int		type;
@@ -164,18 +158,20 @@
 #define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off)				\
         (KL_CONFIG_HDR(_nasid)->ch_board_info = (_off))
 
-#if !defined(SIMULATED_KLGRAPH)
+#ifndef __ia64
 #define KL_CONFIG_INFO(_nasid) 						\
         (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ?		\
 	 NODE_OFFSET_TO_K0((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \
 	 0)
 #else
-/*
- * For Fake klgraph info.
- */
-extern kl_config_hdr_t *linux_klcfg;
-#define KL_CONFIG_INFO(_nasid) (lboard_t *)((ulong)linux_klcfg->ch_board_info | 0xe000000000000000)
-#endif	/* CONFIG_IA64_SGI_IO */
+#define NODE_OFFSET_TO_LBOARD(nasid,off)        (lboard_t*)(NODE_CAC_BASE(nasid) + (off))
+
+#define KL_CONFIG_INFO(_nasid)                                          \
+	(lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ?           \
+	 NODE_OFFSET_TO_LBOARD((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \
+	 NULL)
+
+#endif	/* __ia64 */
 
 #define KL_CONFIG_MAGIC(_nasid)		(KL_CONFIG_HDR(_nasid)->ch_magic)
 
@@ -187,23 +183,13 @@
 
 /* --- New Macros for the changed kl_config_hdr_t structure --- */
 
-#if defined(CONFIG_IA64_SGI_IO)
 #define PTR_CH_MALLOC_HDR(_k)   ((klc_malloc_hdr_t *)\
 			((__psunsigned_t)_k + (_k->ch_malloc_hdr_off)))
-#else
-#define PTR_CH_MALLOC_HDR(_k)   ((klc_malloc_hdr_t *)\
-			(unsigned long)_k + (_k->ch_malloc_hdr_off)))
-#endif
 
 #define KL_CONFIG_CH_MALLOC_HDR(_n)   PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n))
 
-#if defined(CONFIG_IA64_SGI_IO)
 #define PTR_CH_CONS_INFO(_k)	((console_t *)\
 			((__psunsigned_t)_k + (_k->ch_cons_off)))
-#else
-#define PTR_CH_CONS_INFO(_k)	((console_t *)\
-			((unsigned long)_k + (_k->ch_cons_off)))
-#endif
 
 #define KL_CONFIG_CH_CONS_INFO(_n)   PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n))
 
@@ -374,6 +360,7 @@
 #define KLTYPE_IP27	(KLCLASS_CPU | 0x1) /* 2 CPUs(R10K) per board */
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #define KLTYPE_IP35	KLTYPE_IP27
+#define KLTYPE_IP37	KLTYPE_IP35
 #endif
 
 #define KLTYPE_WEIRDIO	(KLCLASS_IO  | 0x0)
@@ -394,6 +381,8 @@
 #define KLTYPE_TPU    	(KLCLASS_IO  | 0xB) /* Tensor Processing Unit */
 #define KLTYPE_GSN_A   	(KLCLASS_IO  | 0xC) /* Main GSN board */
 #define KLTYPE_GSN_B   	(KLCLASS_IO  | 0xD) /* Auxiliary GSN board */
+#define KLTYPE_SHOEHORN (KLCLASS_IO  | 0xE)
+#define KLTYPE_SERIAL_HIPPI (KLCLASS_IO  | 0xF)
 
 #define KLTYPE_GFX	(KLCLASS_GFX | 0x0) /* unknown graphics type */
 #define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* KONA graphics on IP27 */
@@ -404,11 +393,12 @@
 #define KLTYPE_ROUTER2    KLTYPE_ROUTER		/* Obsolete! */
 #define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2)
 #define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3)
+#define KLTYPE_REPEATER_ROUTER (KLCLASS_ROUTER | 0x4)
 
 #define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0)
 #define KLTYPE_MIDPLANE8  (KLCLASS_MIDPLANE | 0x1) /* 8 slot backplane */
 #define KLTYPE_MIDPLANE    KLTYPE_MIDPLANE8
-#define KLTYPE_PBRICK_XBOW	(KLCLASS_MIDPLANE | 0x2)
+#define KLTYPE_IOBRICK_XBOW	(KLCLASS_MIDPLANE | 0x2)
 
 #define KLTYPE_IOBRICK		(KLCLASS_IOBRICK | 0x0)
 #define KLTYPE_IBRICK		(KLCLASS_IOBRICK | 0x1)
@@ -485,7 +475,7 @@
 #define KLCF_NUM_COMPS(_brd)	((_brd)->brd_numcompts)
 #define KLCF_MODULE_ID(_brd)	((_brd)->brd_module)
 
-#ifndef SIMULATED_KLGRAPH
+#ifndef __ia64
 #define KLCF_NEXT(_brd) 		((_brd)->brd_next ? (lboard_t *)((_brd)->brd_next):  NULL)
 #define KLCF_COMP(_brd, _ndx)   \
 		(klinfo_t *)(NODE_OFFSET_TO_K0(NASID_GET(_brd), \
@@ -494,14 +484,18 @@
 		(NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo))
 
 #else
-/*
- * For fake klgraph info.
- */
-#define KLCF_COMP(_brd, _ndx)           (klinfo_t *)((ulong) 0xe000000000000000 |((_brd)->brd_compts[(_ndx)]))
-#define KLCF_NEXT(_brd)	((_brd)->brd_next ? (lboard_t *)((ulong) 0xe000000000000000 | (_brd->brd_next)) : NULL)
-#define KLCF_COMP_ERROR(_brd, _comp)    (_brd = _brd , (_comp)->errinfo)
 
-#endif	/* SIMULATED_KLGRAPH */
+#define NODE_OFFSET_TO_KLINFO(n,off)    ((klinfo_t*) TO_NODE_CAC(n,off))
+#define KLCF_NEXT(_brd)         \
+        ((_brd)->brd_next ?     \
+         (NODE_OFFSET_TO_LBOARD(NASID_GET(_brd), (_brd)->brd_next)): NULL)
+#define KLCF_COMP(_brd, _ndx)   \
+                (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)]))
+
+#define KLCF_COMP_ERROR(_brd, _comp)    \
+                (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo))
+
+#endif /* __ia64 */
 
 #define KLCF_COMP_TYPE(_comp)	((_comp)->struct_type)
 #define KLCF_BRIDGE_W_ID(_comp)	((_comp)->physid)	/* Widget ID */
@@ -581,6 +575,11 @@
 #define KLSTRUCT_GSN_A          29
 #define KLSTRUCT_GSN_B          30
 #define KLSTRUCT_XTHD           31
+#define KLSTRUCT_QLFIBRE        32
+#define KLSTRUCT_1394           33
+#define KLSTRUCT_USB		34
+#define KLSTRUCT_USBKBD		35
+#define KLSTRUCT_USBMS		36
 
 /*
  * These are the indices of various components within a lboard structure.
@@ -845,6 +844,15 @@
     	mio_t       	mio_specific   ; 
 } klmio_t ;
 
+/*
+ * USB info
+ */
+
+typedef struct klusb_s {
+	klinfo_t	usb_info;	/* controller info */
+	void		*usb_bus;	/* handle to usb_bus_t */
+	uint64_t	usb_controller;	/* ptr to controller info */
+} klusb_t ; 
 
 typedef union klcomp_s {
 	klcpu_t		kc_cpu;
@@ -862,6 +870,7 @@
 	klfddi_t	kc_fddi;
 	klmio_t		kc_mio;
 	klmod_serial_num_t kc_snum ;
+	klusb_t		kc_usb;
 } klcomp_t;
 
 typedef union kldev_s {      /* for device structure allocation */
@@ -925,7 +934,6 @@
 extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int);
 
 
-#if defined(CONFIG_IA64_SGI_IO)
 extern xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx);
 extern devfs_handle_t nodevertex_xbow_peer_get(devfs_handle_t node_vtx);
 extern lboard_t *find_gfxpipe(int pipenum);
@@ -954,8 +962,5 @@
 extern int	is_master_baseio(nasid_t,moduleid_t,slotid_t);
 extern nasid_t	get_actual_nasid(lboard_t *brd) ;
 extern net_vec_t klcfg_discover_route(lboard_t *, lboard_t *, int);
-#else	/* CONFIG_IA64_SGI_IO */
-extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu);
-#endif	/* CONFIG_IA64_SGI_IO */
 
 #endif /* _ASM_SN_KLCONFIG_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/kldir.h linux/include/asm-ia64/sn/kldir.h
--- v2.4.3/linux/include/asm-ia64/sn/kldir.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/kldir.h	Thu Apr  5 12:51:47 2001
@@ -13,9 +13,7 @@
 #define _ASM_SN_KLDIR_H
 
 #include <linux/config.h>
-#if defined(CONFIG_IA64_SGI_IO)
 #include <asm/sn/sgi.h>
-#endif
 
 /*
  * The kldir memory area resides at a fixed place in each node's memory and
@@ -136,88 +134,11 @@
 #define KLDIR_OFF_STRIDE		0x28
 #endif /* LANGUAGE_ASSEMBLY */
 
-#if !defined(CONFIG_IA64_SGI_IO)
-
-/*
- * This is defined here because IP27_SYMMON_STK_SIZE must be at least what
- * we define here.  Since it's set up in the prom.  We can't redefine it later
- * and expect more space to be allocated.  The way to find out the true size
- * of the symmon stacks is to divide SYMMON_STK_SIZE by SYMMON_STK_STRIDE
- * for a particular node.
- */
-#define SYMMON_STACK_SIZE		0x8000
-
-#if defined (PROM) || defined (SABLE)
-
-/*
- * These defines are prom version dependent.  No code other than the IP27
- * prom should attempt to use these values.
- */
-#define IP27_LAUNCH_OFFSET		0x2400
-#define IP27_LAUNCH_SIZE		0x400
-#define IP27_LAUNCH_COUNT		2
-#define IP27_LAUNCH_STRIDE		0x200
-
-#define IP27_KLCONFIG_OFFSET		0x4000
-#define IP27_KLCONFIG_SIZE		0xc000
-#define IP27_KLCONFIG_COUNT		1
-#define IP27_KLCONFIG_STRIDE		0
-
-#define IP27_NMI_OFFSET			0x3000
-#define IP27_NMI_SIZE			0x40
-#define IP27_NMI_COUNT			2
-#define IP27_NMI_STRIDE			0x40
-
-#define IP27_PI_ERROR_OFFSET		0x12000
-#define IP27_PI_ERROR_SIZE		0x4000
-#define IP27_PI_ERROR_COUNT		1
-#define IP27_PI_ERROR_STRIDE		0
-
-#define IP27_SYMMON_STK_OFFSET		0x25000
-#define IP27_SYMMON_STK_SIZE		0xe000
-#define IP27_SYMMON_STK_COUNT		2
-/* IP27_SYMMON_STK_STRIDE must be >= SYMMON_STACK_SIZE */
-#define IP27_SYMMON_STK_STRIDE		0x7000
-
-#define IP27_FREEMEM_OFFSET		0x19000
-#define IP27_FREEMEM_SIZE		-1
-#define IP27_FREEMEM_COUNT		1
-#define IP27_FREEMEM_STRIDE		0
-
-#endif /* PROM || SABLE*/
-/*
- * There will be only one of these in a partition so the IO6 must set it up.
- */
-#define IO6_GDA_OFFSET			0x11000
-#define IO6_GDA_SIZE			0x400
-#define IO6_GDA_COUNT			1
-#define IO6_GDA_STRIDE			0
-
-/*
- * save area of kernel nmi regs in the prom format
- */
-#define IP27_NMI_KREGS_OFFSET		0x11400
-#define IP27_NMI_KREGS_CPU_SIZE		0x200
-/*
- * save area of kernel nmi regs in eframe format 
- */
-#define IP27_NMI_EFRAME_OFFSET		0x11800
-#define IP27_NMI_EFRAME_SIZE		0x200
-
-#define KLDIR_ENT_SIZE			0x40
-#define KLDIR_MAX_ENTRIES		(0x400 / 0x40)
-
-#endif	/* !CONFIG_IA64_SGI_IO */
-
 #ifdef _LANGUAGE_C
 typedef struct kldir_ent_s {
 	u64		magic;		/* Indicates validity of entry      */
 	off_t		offset;		/* Offset from start of node space  */
-#if defined(CONFIG_IA64_SGI_IO)	/* FIXME */
 	__psunsigned_t	pointer;	/* Pointer to area in some cases    */
-#else
-	unsigned long	pointer;	/* Pointer to area in some cases    */
-#endif
 	size_t		size;		/* Size in bytes 		    */
 	u64		count;		/* Repeat count if array, 1 if not  */
 	size_t		stride;		/* Stride if array, 0 if not        */
@@ -227,7 +148,6 @@
 } kldir_ent_t;
 #endif /* _LANGUAGE_C */
 
-#if defined(CONFIG_IA64_SGI_IO)
 
 #define KLDIR_ENT_SIZE			0x40
 #define KLDIR_MAX_ENTRIES		(0x400 / 0x40)
@@ -240,7 +160,5 @@
 #else
 #error "kldir.h is currently defined for IP27 and IP35 platforms only"
 #endif
-
-#endif	/* CONFIG_IA64_SGI_IO */
 
 #endif /* _ASM_SN_KLDIR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ksys/elsc.h linux/include/asm-ia64/sn/ksys/elsc.h
--- v2.4.3/linux/include/asm-ia64/sn/ksys/elsc.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/ksys/elsc.h	Thu Apr  5 12:51:47 2001
@@ -11,6 +11,7 @@
 #define _ASM_SN_KSYS_ELSC_H
 
 #include <linux/config.h>
+
 #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/ksys/l1.h>
 #endif
@@ -48,7 +49,7 @@
 int	elsc_msg_callback(elsc_t *e,
 			  void (*callback)(void *callback_data, char *msg),
 			  void *callback_data);
-#if 0
+#ifdef LATER
 char   *elsc_errmsg(int code);
 
 int	elsc_nvram_write(elsc_t *e, int addr, char *buf, int len);
@@ -68,7 +69,7 @@
  */
 
 int	elsc_version(elsc_t *e, char *result);
-#if 0
+#ifdef LATER
 int	elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2);
 int	elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2);
 #endif
@@ -90,7 +91,7 @@
 int	elsc_unlock(elsc_t *e);
 int	elsc_display_char(elsc_t *e, int led, int chr);
 int	elsc_display_digit(elsc_t *e, int led, int num, int l_case);
-#if 0
+#ifdef LATER
 int	elsc_display_mesg(elsc_t *e, char *chr);	/* 8-char input */
 int	elsc_password_set(elsc_t *e, char *password);	/* 4-char input */
 int	elsc_password_get(elsc_t *e, char *password);	/* 4-char output */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ksys/l1.h linux/include/asm-ia64/sn/ksys/l1.h
--- v2.4.3/linux/include/asm-ia64/sn/ksys/l1.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/ksys/l1.h	Thu Apr  5 12:51:47 2001
@@ -80,11 +80,11 @@
 				 * use == BRL1_SUBCH_FREE */
     uint	target;		/* type, rack and slot of component to
 				 * which this subchannel is directed */
-    int		packet_arrived; /* true if packet arrived on
+    atomic_t	packet_arrived; /* true if packet arrived on
 				 * this subchannel */
     sc_cq_t *	iqp;		/* input queue for this subchannel */
     sv_t	arrive_sv;	/* used to wait for a packet */
-    lock_t	data_lock;	/* synchronize access to input queues and
+    spinlock_t	data_lock;	/* synchronize access to input queues and
 				 * other fields of the brl1_sch_s struct */
     brl1_notif_t tx_notify;     /* notify higher layer that transmission may 
 				 * continue */
@@ -118,9 +118,7 @@
     brl1_uartf_t putc_f;	/* pointer to UART putc function */
     brl1_uartf_t getc_f;	/* pointer to UART getc function */
 
-    lock_t	 send_lock;	/* arbitrates send synchronization */
-    lock_t	 recv_lock;	/* arbitrates uart receive access */
-    lock_t	 subch_lock;	/* arbitrates subchannel allocation */
+    spinlock_t	 subch_lock;	/* arbitrates subchannel allocation */
     cpuid_t	 intr_cpu;	/* cpu that receives L1 interrupts */
 
     u_char	 send_in_use;	/* non-zero if send buffer contains an
@@ -223,6 +221,7 @@
 #define L1_RESP_REQC	(-101)	/* bad request code	        */
 #define L1_RESP_NAVAIL	(-104)	/* requested data not available */
 #define L1_RESP_ARGVAL	(-105)  /* arg value out of range       */
+#define L1_RESP_INVAL   (-107)  /* requested data invalid       */
 
 /* L1 general requests */
 
@@ -239,16 +238,19 @@
 #define L1_REQ_PORTSPEED	0x000a	/* get ioport speed */
 
 #define L1_REQ_CONS_SUBCH	0x1002  /* select this node's console 
-					 * subchannel */
+					   subchannel */
 #define L1_REQ_CONS_NODE	0x1003  /* volunteer to be the master 
-					 * (console-hosting) node */
+					   (console-hosting) node */
 #define L1_REQ_DISP1		0x1004  /* write line 1 of L1 display */
 #define L1_REQ_DISP2		0x1005  /* write line 2 of L1 display */
 #define L1_REQ_PARTITION_SET	0x1006	/* set partition id */
 #define L1_REQ_EVENT_SUBCH	0x1007	/* set the subchannel for system
 					   controller event transmission */
 
-#define L1_REQ_RESET		0x2001	/* request a full system reset */
+#define L1_REQ_RESET		0x2000	/* request a full system reset */
+#define L1_REQ_PCI_UP		0x2001  /* power up pci slot or bus */
+#define L1_REQ_PCI_DOWN		0x2002  /* power down pci slot or bus */
+#define L1_REQ_PCI_RESET	0x2003  /* reset pci bus or slot */
 
 /* L1 command interpreter requests */
 
@@ -325,18 +327,6 @@
 void	sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart );
 void	sc_intr_enable( l1sc_t *sc );
 
-#if 0
-int	sc_portspeed_get( l1sc_t *sc );
-#endif
-
-int	l1_cons_poll( l1sc_t *sc );
-int	l1_cons_getc( l1sc_t *sc );
-void	l1_cons_init( l1sc_t *sc );
-int	l1_cons_read( l1sc_t *sc, char *buf, int avail );
-int	l1_cons_write( l1sc_t *sc, char *msg, int len, int wait );
-void	l1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func );
-void	l1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func );
-
 int	_elscuart_putc( l1sc_t *sc, int c );
 int	_elscuart_getc( l1sc_t *sc );
 int	_elscuart_poll( l1sc_t *sc );
@@ -354,11 +344,7 @@
 int	elsc_display_line(l1sc_t *e, char *line, int lnum);
 
 extern l1sc_t *get_elsc( void );
-extern void    set_elsc( l1sc_t *e );
-
 #define get_l1sc	get_elsc
-#define set_l1sc(e)	set_elsc(e)
-
 #define get_master_l1sc get_l1sc
 
 int	router_module_get( nasid_t nasid, net_vec_t path );
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/mmzone.h linux/include/asm-ia64/sn/mmzone.h
--- v2.4.3/linux/include/asm-ia64/sn/mmzone.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/mmzone.h	Thu Apr  5 12:51:47 2001
@@ -6,6 +6,7 @@
 #define _LINUX_ASM_SN_MMZONE_H
 
 #include <linux/config.h>
+
 #include <asm/sn/mmzone_sn1.h>
 #include <asm/sn/sn_cpuid.h>
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/mmzone_sn1.h linux/include/asm-ia64/sn/mmzone_sn1.h
--- v2.4.3/linux/include/asm-ia64/sn/mmzone_sn1.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/mmzone_sn1.h	Thu Apr  5 12:51:47 2001
@@ -1,12 +1,11 @@
 #ifndef _ASM_IA64_MMZONE_SN1_H
 #define _ASM_IA64_MMZONE_SN1_H
 
+#include <linux/config.h>
+
 /*
  * Copyright, 2000, Silicon Graphics, sprasad@engr.sgi.com
  */
-
-#include <linux/config.h>
-
 /* Maximum configuration supported by SNIA hardware. There are other
  * restrictions that may limit us to a smaller max configuration.
  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/module.h linux/include/asm-ia64/sn/module.h
--- v2.4.3/linux/include/asm-ia64/sn/module.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/module.h	Thu Apr  5 12:51:47 2001
@@ -15,6 +15,7 @@
 #endif
 
 #include <linux/config.h>
+
 #include <asm/sn/systeminfo.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/ksys/elsc.h>
@@ -178,22 +179,24 @@
 
     int			disable_alert;
     int			count_down;
+
+    /* System serial number info (used by SN1) */
+    char		sys_snum[MAX_SERIAL_NUM_SIZE];
+    int			sys_snum_valid;
 };
 
 /* module.c */
 extern module_t	       *modules[MODULE_MAX];	/* Indexed by cmoduleid_t   */
 extern int		nummodules;
 
-#ifndef CONFIG_IA64_SGI_IO
-/* Clashes with LINUX stuff */
-extern void		module_init(void);
-#endif
 extern module_t	       *module_lookup(moduleid_t id);
 
 extern elsc_t	       *get_elsc(void);
 
 extern int		get_kmod_info(cmoduleid_t cmod,
 				      module_info_t *mod_info);
+extern int		get_kmod_sys_snum(cmoduleid_t cmod,
+					  char *snum);
 
 extern void		format_module_id(char *buffer, moduleid_t m, int fmt);
 extern int		parse_module_id(char *buffer);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/nodemask.h linux/include/asm-ia64/sn/nodemask.h
--- v2.4.3/linux/include/asm-ia64/sn/nodemask.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/nodemask.h	Thu Apr  5 12:51:47 2001
@@ -13,6 +13,7 @@
 #if defined(__KERNEL__) || defined(_KMEMUSER)
 
 #include <linux/config.h>
+
 #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
 #include <asm/sn/sn1/arch.h>    /* needed for MAX_COMPACT_NODES */
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/nodepda.h linux/include/asm-ia64/sn/nodepda.h
--- v2.4.3/linux/include/asm-ia64/sn/nodepda.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/nodepda.h	Thu Apr  5 12:51:47 2001
@@ -15,11 +15,13 @@
 #endif
 
 #include <linux/config.h>
+
 #include <asm/sn/agent.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/router.h>
+#include <asm/sn/synergy.h>
 /* #include <SN/klkernvars.h> */
-#ifdef IRIX
+#ifdef LATER
 typedef struct module_s module_t;       /* Avoids sys/SN/module.h */
 #else
 #include <asm/sn/module.h>
@@ -54,6 +56,10 @@
 
 struct ptpool_s;
 
+#if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
+struct synergy_perf_s;
+#endif
+
 
 /*
  * Node-specific data structure.
@@ -67,7 +73,8 @@
  */
 
 
-#ifndef CONFIG_IA64_SGI_IO
+
+#ifdef LATER
 /*
  * The following structure is contained in the nodepda & contains
  * a lock & queue-head for sanon pages that belong to the node.
@@ -78,9 +85,6 @@
 	plist_t sal_listhead;
 } sanon_list_head_t;
 #endif
-
-
-
 struct nodepda_s {
 
 #ifdef	NUMA_BASE
@@ -133,7 +137,7 @@
 	 * Each node gets its own syswait counter to remove contention
 	 * on the global one.
 	 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	struct syswait syswait;
 #endif
 
@@ -141,7 +145,7 @@
 	/*
 	 * Node-specific Zone structures.
 	 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef LATER
 	zoneset_element_t	node_zones;
 	pg_data_t	node_pg_data;	/* VM page data structures */ 
 	plist_t	error_discard_plist;
@@ -154,7 +158,7 @@
 	/* Information needed for SN Hub chip interrupt handling. */
 	subnode_pda_t	snpda[NUM_SUBNODES];
 	/* Distributed kernel support */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	kern_vars_t	kern_vars;
 #endif
 	/* Vector operation support */
@@ -173,6 +177,17 @@
 	nodepda_router_info_t	*npda_rip_first;
 	nodepda_router_info_t	**npda_rip_last;
 	int		dependent_routers;
+
+#if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
+	int			synergy_perf_enabled;
+        int       		synergy_perf_freq;
+	spinlock_t		synergy_perf_lock;
+        uint64_t       		synergy_inactive_intervals;
+        uint64_t       		synergy_active_intervals;
+        struct synergy_perf_s	*synergy_perf_data;
+        struct synergy_perf_s	*synergy_perf_first; /* reporting consistency .. */
+#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */
+
 	devfs_handle_t 	xbow_vhdl;
 	nasid_t		xbow_peer;	/* NASID of our peer hub on xbow */
 	struct semaphore xbow_sema;	/* Sema for xbow synchronization */
@@ -189,13 +204,13 @@
 	char		ni_error_print; /* For printing ni error state
 					 * only once during system panic
 					 */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	md_perf_monitor_t node_md_perfmon;
 	hubstat_t	hubstats;
 	int		hubticks;
-	int		huberror_ticks;
 	sbe_info_t	*sbe_info;	/* ECC single-bit error statistics */
-#endif	/* !CONFIG_IA64_SGI_IO */
+#endif	/* LATER */
+	int		huberror_ticks;
 
 	router_queue_t  *visited_router_q;
 	router_queue_t	*bfs_router_q; 
@@ -218,11 +233,9 @@
 	void 		*pdinfo;	/* Platform-dependent per-node info */
 	uint64_t	*dump_stack;	/* Dump stack during nmi handling */
 	int		dump_count;	/* To allow only one cpu-per-node */
-#if defined BRINGUP
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	io_perf_monitor_t node_io_perfmon;
 #endif
-#endif
 
 	/*
 	 * Each node gets its own pdcount counter to remove contention
@@ -235,7 +248,7 @@
 	void		*cached_global_pool;	/* pointer to cached vmpool */
 #endif /* NUMA_BASE */
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	sanon_list_head_t sanon_list_head;	/* head for sanon pages */	
 #endif
 #ifdef	NUMA_BASE
@@ -246,7 +259,7 @@
 	 * The BTEs on this node are shared by the local cpus
 	 */
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	bteinfo_t	*node_bte_info[BTES_PER_NODE];
 #endif
 #endif
@@ -273,7 +286,7 @@
  *	SUBNODEPDA(x,s)	-> to access subnode PDA for cnodeid/slice 'x'
  */
 
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 #define	nodepda		private.p_nodepda	/* Ptr to this node's PDA */
 #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
 #define subnodepda	private.p_subnodepda	/* Ptr to this node's subnode PDA */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h
--- v2.4.3/linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h	Thu Apr  5 12:51:47 2001
@@ -26,4 +26,23 @@
 	int		isa64;
 };
 
+struct sn1_dma_maps_s{
+	struct pcibr_dmamap_s dma_map;
+        dma_addr_t      dma_addr;
+};
+
+struct ioports_to_tlbs_s {
+	unsigned long	p:1,
+			rv_1:1,
+			ma:3,
+			a:1,
+			d:1,
+			pl:2,
+			ar:3,
+			ppn:38,
+			rv_2:2,
+			ed:1,
+			ig:11;
+};
+
 #endif				/* _ASM_SN_PCI_CVLINK_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pciba.h linux/include/asm-ia64/sn/pci/pciba.h
--- v2.4.3/linux/include/asm-ia64/sn/pci/pciba.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ia64/sn/pci/pciba.h	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,103 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2000 by Colin Ngam
+ */
+#ifndef _ASM_SN_PCI_PCIBA_H
+#define _ASM_SN_PCI_PCIBA_H
+
+/*
+ * These are all the HACKS from ioccom.h ..
+ */
+#define IOCPARM_MASK    0xff            /* parameters must be < 256 bytes */
+#define IOC_VOID        0x20000000      /* no parameters */
+
+/*
+ * The above needs to be modified and follow LINUX ...
+ */
+
+/* /hw/.../pci/[slot]/config accepts ioctls to read
+ * and write specific registers as follows:
+ *
+ * "t" is the native type (char, short, uint32, uint64)
+ * to read from CFG space; results will be arranged in
+ * byte significance (ie. first byte from PCI is lowest
+ * or last byte in result).
+ *
+ * "r" is the byte offset in PCI CFG space of the first
+ * byte of the register (it's least significant byte,
+ * in the little-endian PCI numbering). This can actually
+ * be as much as 16 bits wide, and is intended to match
+ * the layout of a "Type 1 Configuration Space" address:
+ * the register number in the low eight bits, then three
+ * bits for the function number and five bits for the
+ * slot number.
+ */
+#define	PCIIOCCFGRD(t,r)	_IOR(0,(r),t)
+#define	PCIIOCCFGWR(t,r)	_IOW(0,(r),t)
+
+/* Some common config register access commands.
+ * Use these as examples of how to construct
+ * values for other registers you want to access.
+ */
+
+/* PCIIOCGETID: arg is ptr to 32-bit int,
+ * returns the 32-bit ID value with VENDOR
+ * in the bottom 16 bits and DEVICE in the top.
+ */
+#define	PCIIOCGETID		PCIIOCCFGRD(uint32_t,PCI_CFG_VENDOR_ID)
+
+/* PCIIOCSETCMD: arg is ptr to a 16-bit short,
+ * which will be written to the CMD register.
+ */
+#define	PCIIOCSETCMD		PCIIOCCFGWR(uint16_t,PCI_CFG_COMMAND)
+
+/* PCIIOCGETREV: arg is ptr to an 8-bit char,
+ * which will get the 8-bit revision number.
+ */
+#define	PCIIOCGETREV		PCIIOCCFGRD(uint8_t,PCI_CFG_REV_ID)
+
+/* PCIIOCGETHTYPE: arg is ptr to an 8-bit char,
+ * which will get the 8-bit header type.
+ */
+#define	PCIIOCGETHTYPE		PCIIOCCFGRD(uint8_t,PCI_CFG_HEADER_TYPE)
+
+/* PCIIOCGETBASE(n): arg is ptr to a 32-bit int,
+ * which will get the value of the BASE<n> register.
+ */
+#define	PCIIOCGETBASE(n)	PCIIOCCFGRD(uint32_t,PCI_CFG_BASE_ADDR(n))
+
+/* /hw/.../pci/[slot]/intr accepts an ioctl to
+ * set up user level interrupt handling as follows:
+ *
+ * "n" is a bitmap of which of the four PCI interrupt
+ * lines are of interest, using PCIIO_INTR_LINE_[ABCD].
+ */
+#define	PCIIOCSETULI(n)		_IOWR(1,n,struct uliargs)
+#if _KERNEL
+#define PCIIOCSETULI32(n)	_IOWR(1,n,struct uliargs32)
+#endif
+
+/* /hw/.../pci/[slot]/dma accepts ioctls to allocate
+ * and free physical memory for use in user-triggered
+ * DMA operations.
+ */
+#define	PCIIOCDMAALLOC		_IOWR(0,1,uint64_t)
+#define	PCIIOCDMAFREE		_IOW(0,1,uint64_t)
+
+/* The parameter for PCIIOCDMAALLOC needs to contain
+ * both the size of the request and the flag values
+ * to be used in setting up the DMA.
+ *
+ * Any flags normally useful in pciio_dmamap
+ * or pciio_dmatrans function calls can6 be used here.
+ */
+#define	PCIIOCDMAALLOC_REQUEST_PACK(flags,size)		\
+	((((uint64_t)(flags))<<32)|			\
+	 (((uint64_t)(size))&0xFFFFFFFF))
+
+#endif	/* _ASM_SN_PCI_PCIBA_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pcibr.h linux/include/asm-ia64/sn/pci/pcibr.h
--- v2.4.3/linux/include/asm-ia64/sn/pci/pcibr.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pci/pcibr.h	Thu Apr  5 12:51:47 2001
@@ -143,6 +143,14 @@
 
 extern void		pcibr_dmamap_done(pcibr_dmamap_t dmamap);
 
+/*
+ * pcibr_get_dmatrans_node() will return the compact node id to which  
+ * all 32-bit Direct Mapping memory accesses will be directed.
+ * (This node id can be different for each PCI bus.) 
+ */
+
+extern cnodeid_t	pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl);
+
 extern iopaddr_t	pcibr_dmatrans_addr(devfs_handle_t dev,
 					    device_desc_t dev_desc,
 					    paddr_t paddr,
@@ -215,10 +223,6 @@
 					    pciio_space_t *spacep,
 					    iopaddr_t *addrp);
 
-extern int		pcibr_rrb_alloc(devfs_handle_t pconn_vhdl,
-					int *count_vchan0,
-					int *count_vchan1);
-
 extern int		pcibr_wrb_flush(devfs_handle_t pconn_vhdl);
 extern int		pcibr_rrb_check(devfs_handle_t pconn_vhdl,
 					int *count_vchan0,
@@ -241,7 +245,7 @@
 void			pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl,
 					       rrb_alloc_funct_f *func);
 
-extern void		pcibr_device_unregister(devfs_handle_t);
+extern int		pcibr_device_unregister(devfs_handle_t);
 extern int		pcibr_dma_enabled(devfs_handle_t);
 /*
  * Bridge-specific flags that can be set via pcibr_device_flags_set
@@ -337,7 +341,7 @@
 
 extern void		pcibr_hints_fix_rrbs(devfs_handle_t);
 extern void		pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t);
-extern void		pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t);
+extern void		pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong);
 extern void		pcibr_hints_handsoff(devfs_handle_t);
 
 typedef unsigned	pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t);
@@ -353,8 +357,104 @@
 #define PCIBR			'p'
 #define _PCIBR(x)		((PCIBR << 8) | (x))
 
-#define PCIBR_SLOT_POWERUP	_PCIBR(1)
-#define PCIBR_SLOT_SHUTDOWN	_PCIBR(2)
-#define PCIBR_SLOT_INQUIRY	_PCIBR(3)
+#define PCIBR_SLOT_STARTUP	_PCIBR(1)
+#define PCIBR_SLOT_SHUTDOWN     _PCIBR(2)
+#define PCIBR_SLOT_QUERY	_PCIBR(3)
+
+/*
+ * Bit defintions for variable slot_status in struct
+ * pcibr_soft_slot_s.  They are here so that both
+ * the pcibr driver and the pciconfig command can
+ * reference them.
+ */
+#define SLOT_STARTUP_CMPLT      0x01
+#define SLOT_STARTUP_INCMPLT    0x02
+#define SLOT_SHUTDOWN_CMPLT     0x04
+#define SLOT_SHUTDOWN_INCMPLT   0x08
+#define SLOT_POWER_UP           0x10
+#define SLOT_POWER_DOWN         0x20
+#define SLOT_IS_SYS_CRITICAL    0x40
+
+#define SLOT_STATUS_MASK        (SLOT_STARTUP_CMPLT | SLOT_STARTUP_INCMPLT | \
+                                 SLOT_SHUTDOWN_CMPLT | SLOT_SHUTDOWN_INCMPLT)
+#define SLOT_POWER_MASK         (SLOT_POWER_UP | SLOT_POWER_DOWN)
+
+/*
+ * Bit definitions for variable resp_f_staus.
+ * They are here so that both the pcibr driver
+ * and the pciconfig command can reference them.
+ */
+#define FUNC_IS_VALID           0x01
+#define FUNC_IS_SYS_CRITICAL    0x02
+
+/*
+ * Structures for requesting PCI bridge information and receiving a response
+ */
+typedef struct pcibr_slot_info_req_s *pcibr_slot_info_req_t;
+typedef struct pcibr_slot_info_resp_s *pcibr_slot_info_resp_t;
+typedef struct pcibr_slot_func_info_resp_s *pcibr_slot_func_info_resp_t;
+
+struct pcibr_slot_info_req_s {
+   int                      req_slot;
+   pcibr_slot_info_resp_t   req_respp;
+   int                      req_size;
+};
+
+struct pcibr_slot_info_resp_s {
+    int                     resp_has_host;
+    char                    resp_host_slot;
+    devfs_handle_t            resp_slot_conn;
+    char                    resp_slot_conn_name[MAXDEVNAME];
+    int                     resp_slot_status;
+    int                     resp_l1_bus_num;
+    int                     resp_bss_ninfo;
+    char                    resp_bss_devio_bssd_space[16];
+    iopaddr_t               resp_bss_devio_bssd_base; 
+    bridgereg_t             resp_bss_device;
+    int                     resp_bss_pmu_uctr;
+    int                     resp_bss_d32_uctr;
+    int                     resp_bss_d64_uctr;
+    iopaddr_t               resp_bss_d64_base;
+    unsigned                resp_bss_d64_flags;
+    iopaddr_t               resp_bss_d32_base;
+    unsigned                resp_bss_d32_flags;
+    int                     resp_bss_ext_ates_active;
+    volatile unsigned      *resp_bss_cmd_pointer;
+    unsigned                resp_bss_cmd_shadow;
+    int                     resp_bs_rrb_valid;
+    int                     resp_bs_rrb_valid_v;
+    int                     resp_bs_rrb_res;
+    bridgereg_t             resp_b_resp;
+    bridgereg_t             resp_b_int_device;
+    bridgereg_t             resp_b_int_enable;
+    bridgereg_t             resp_b_int_host;
+
+    struct pcibr_slot_func_info_resp_s {
+        int                     resp_f_status;
+        char                    resp_f_slot_name[MAXDEVNAME];
+        char                    resp_f_bus;
+        char                    resp_f_slot;
+        char                    resp_f_func;
+        char                    resp_f_master_name[MAXDEVNAME];
+        void                   *resp_f_pops;
+        error_handler_f        *resp_f_efunc;
+        error_handler_arg_t     resp_f_einfo;
+        int                     resp_f_vendor;
+        int                     resp_f_device;
+
+        struct {
+            char                    resp_w_space[16];
+            iopaddr_t               resp_w_base;
+            size_t                  resp_w_size;
+        } resp_f_window[6];
+
+        unsigned                resp_f_rbase;
+        unsigned                resp_f_rsize;
+        int                     resp_f_ibit[4];
+        int                     resp_f_att_det_error;
+
+    } resp_func[8];
+
+};
 
 #endif				/* _ASM_SN_PCI_PCIBR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pcibr_private.h linux/include/asm-ia64/sn/pci/pcibr_private.h
--- v2.4.3/linux/include/asm-ia64/sn/pci/pcibr_private.h	Tue Mar  6 19:44:34 2001
+++ linux/include/asm-ia64/sn/pci/pcibr_private.h	Thu Apr  5 12:51:47 2001
@@ -17,6 +17,7 @@
  */
 
 #include <asm/sn/pci/pciio_private.h>
+#include <asm/sn/ksys/l1.h>
 
 /*
  * convenience typedefs
@@ -31,6 +32,7 @@
 typedef struct pcibr_hints_s *pcibr_hints_t;
 typedef struct pcibr_intr_list_s *pcibr_intr_list_t;
 typedef struct pcibr_intr_wrap_s *pcibr_intr_wrap_t;
+typedef struct pcibr_intr_cbuf_s *pcibr_intr_cbuf_t;
 
 /*
  * Bridge sets up PIO using this information.
@@ -50,7 +52,7 @@
     xtalk_piomap_t          bp_xtalk_pio;	/* corresponding xtalk resource */
     pcibr_piomap_t	    bp_next;	/* Next piomap on the list */
     pcibr_soft_t	    bp_soft;	/* backpointer to bridge soft data */
-    int			    bp_toc[1];	/* PCI timeout counter */
+    atomic_t		    bp_toc[1];	/* PCI timeout counter */
 
 };
 
@@ -77,6 +79,18 @@
     bridge_ate_t            bd_ate_prime;	/* value of 1st ATE written */
 };
 
+#define	IBUFSIZE	5		/* size of circular buffer (holds 4) */
+
+/*
+ * Circular buffer used for interrupt processing
+ */
+struct pcibr_intr_cbuf_s {
+    spinlock_t		ib_lock;		/* cbuf 'put' lock */
+    int			ib_in;			/* index of next free entry */
+    int			ib_out;			/* index of next full entry */
+    pcibr_intr_wrap_t   ib_cbuf[IBUFSIZE];	/* circular buffer of wrap  */
+};
+
 /*
  * Bridge sets up interrupts using this information.
  */
@@ -94,6 +108,7 @@
 #define bi_cpu		bi_pi.pi_cpu	/* cpu assigned. */
     unsigned                bi_ibits;	/* which Bridge interrupt bit(s) */
     pcibr_soft_t            bi_soft;	/* shortcut to soft info */
+    struct pcibr_intr_cbuf_s bi_ibuf;	/* circular buffer of wrap ptrs */
 };
 
 /*
@@ -121,6 +136,7 @@
     /* pcibr-specific connection state */
     int			    f_ibit[4];	/* Bridge bit for each INTx */
     pcibr_piomap_t	    f_piomap;
+    int                     f_att_det_error;
 };
 
 /* =====================================================================
@@ -139,8 +155,11 @@
 struct pcibr_intr_wrap_s {
     pcibr_soft_t            iw_soft;	/* which bridge */
     volatile bridgereg_t   *iw_stat;	/* ptr to b_int_status */
-    bridgereg_t             iw_intr;	/* bits in b_int_status */
+    bridgereg_t             iw_intr;	/* bit in b_int_status */
     pcibr_intr_list_t       iw_list;	/* ghostbusters! */
+    int			    iw_hdlrcnt;	/* running handler count */
+    int			    iw_shared;  /* if Bridge bit is shared */
+    int			    iw_connected; /* if already connected */
 };
 
 #define	PCIBR_ISR_ERR_START	8
@@ -175,11 +194,14 @@
 
     unsigned                bs_dma_flags;	/* revision-implied DMA flags */
 
+    l1sc_t                 *bs_l1sc;            /* io brick l1 system cntr */
+    moduleid_t		    bs_moduleid;	/* io brick moduleid */
+
     /*
      * Lock used primarily to get mutual exclusion while managing any
      * bridge resources..
      */
-    lock_t                  bs_lock;
+    spinlock_t              bs_lock;
     
     devfs_handle_t	    bs_noslot_conn;	/* NO-SLOT connection point */
     pcibr_info_t	    bs_noslot_info;
@@ -199,6 +221,9 @@
 	int                     has_host;
 	pciio_slot_t            host_slot;
 	devfs_handle_t		slot_conn;
+
+	int			slot_status;
+
 	/* Potentially several connection points
 	 * for this slot. bss_ninfo is how many,
 	 * and bss_infos is a pointer to
@@ -265,7 +290,7 @@
 	/* Shadow information used for implementing
 	 * Bridge Hardware WAR #484930
 	 */
-	int			bss_ext_ates_active;
+	atomic_t		bss_ext_ates_active;
         volatile unsigned      *bss_cmd_pointer;
 	unsigned		bss_cmd_shadow;
 
@@ -295,13 +320,10 @@
 	 */
 	xtalk_intr_t            bsi_xtalk_intr;
 	/*
-	 * We do not like sharing PCI interrrupt lines
-	 * between devices, but the Origin 200 PCI
-	 * layout forces us to do so.
+	 * A wrapper structure is associated with each
+	 * Bridge interrupt bit.
 	 */
-	pcibr_intr_list_t       bsi_pcibr_intr_list;
-	pcibr_intr_wrap_t       bsi_pcibr_intr_wrap;
-	int                     bsi_pcibr_wrap_set;
+	struct pcibr_intr_wrap_s  bsi_pcibr_intr_wrap;
 
     } bs_intr[8];
 
@@ -325,7 +347,7 @@
      */
     struct br_errintr_info {
 	int                     bserr_toutcnt;
-#ifdef IRIX
+#ifdef LATER
 	toid_t                  bserr_toutid;	/* Timeout started by errintr */
 #endif
 	iopaddr_t               bserr_addr;	/* Address where error occurred */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pciio.h linux/include/asm-ia64/sn/pci/pciio.h
--- v2.4.3/linux/include/asm-ia64/sn/pci/pciio.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pci/pciio.h	Thu Apr  5 12:51:47 2001
@@ -35,15 +35,9 @@
 
 #define PCIIO_DEVICE_ID_NONE	-1
 
-#ifdef colin
-typedef char pciio_bus_t;	/* PCI bus number (0..255) */
-typedef char pciio_slot_t;	/* PCI slot number (0..31, 255) */
-typedef char pciio_function_t;	/* PCI func number (0..7, 255) */
-#else
 typedef uint8_t pciio_bus_t;       /* PCI bus number (0..255) */
 typedef uint8_t pciio_slot_t;      /* PCI slot number (0..31, 255) */
 typedef uint8_t pciio_function_t;  /* PCI func number (0..7, 255) */
-#endif
 
 #define	PCIIO_SLOTS		((pciio_slot_t)32)
 #define	PCIIO_FUNCS		((pciio_function_t)8)
@@ -446,6 +440,24 @@
 			 pciio_space_t *spacep,
 			 iopaddr_t *addrp);
 
+typedef void
+pciio_driver_reg_callback_f	(devfs_handle_t conn,
+				int key1,
+				int key2,
+				int error);
+
+typedef void
+pciio_driver_unreg_callback_f	(devfs_handle_t conn, /* pci connection point */
+				 int key1,
+				 int key2,
+				 int error);
+
+typedef int
+pciio_device_unregister_f	(devfs_handle_t conn);
+
+typedef int
+pciio_dma_enabled_f		(devfs_handle_t conn);
+
 /*
  * Adapters that provide a PCI interface adhere to this software interface.
  */
@@ -491,6 +503,12 @@
     /* Error handling interface */
     pciio_error_devenable_f *error_devenable;
     pciio_error_extract_f *error_extract;
+
+    /* Callback support */
+    pciio_driver_reg_callback_f *driver_reg_callback;
+    pciio_driver_unreg_callback_f *driver_unreg_callback;
+    pciio_device_unregister_f 	*device_unregister;
+    pciio_dma_enabled_f		*dma_enabled;
 } pciio_provider_t;
 
 /* PCI devices use these standard PCI provider interfaces */
@@ -540,13 +558,8 @@
 #define PCIIO_WIDGETDEV_SLOT_MASK		0x1f
 #define PCIIO_WIDGETDEV_FUNC_MASK		0x7
 
-#ifdef IRIX
-#define pciio_widgetdev_create(slot,func)	\
-	((slot) << PCIIO_WIDGETDEV_SLOT_SHFT + (func))
-#else
 #define pciio_widgetdev_create(slot,func)       \
         (((slot) << PCIIO_WIDGETDEV_SLOT_SHFT) + (func))
-#endif
 
 #define pciio_widgetdev_slot_get(wdev)		\
 	(((wdev) >> PCIIO_WIDGETDEV_SLOT_SHFT) & PCIIO_WIDGETDEV_SLOT_MASK)
@@ -612,8 +625,14 @@
 			pciio_info_t pciio_info);	/* details about conn point */
 
 
-extern int              pciio_device_attach(devfs_handle_t pcicard);	/* vertex created by pciio_device_register */
-extern int             pciio_device_detach(devfs_handle_t pcicard);	/* vertex created by pciio_device_register */
+extern int              
+pciio_device_attach(
+			devfs_handle_t pcicard,   /* vertex created by pciio_device_register */
+			int drv_flags);
+extern int
+pciio_device_detach(
+			devfs_handle_t pcicard,   /* vertex created by pciio_device_register */
+                        int drv_flags);
 
 /*
  * Generic PCI interface, for use with all PCI providers
@@ -632,7 +651,7 @@
 extern ulong            pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap);
 extern caddr_t          pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap);
 
-#ifdef IRIX
+#ifdef LATER
 #ifdef USE_PCI_PIO
 extern uint8_t 		pciio_pio_read8(volatile uint8_t *addr);
 extern uint16_t 	pciio_pio_read16(volatile uint16_t *addr);
@@ -676,7 +695,7 @@
 	*addr = val;
 }
 #endif /* USE_PCI_PIO */
-#endif
+#endif	/* LATER */
 
 /* Generic PCI dma interfaces */
 extern devfs_handle_t     pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pciio_private.h linux/include/asm-ia64/sn/pci/pciio_private.h
--- v2.4.3/linux/include/asm-ia64/sn/pci/pciio_private.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pci/pciio_private.h	Thu Apr  5 12:51:47 2001
@@ -10,10 +10,6 @@
 #ifndef _ASM_SN_PCI_PCIIO_PRIVATE_H
 #define _ASM_SN_PCI_PCIIO_PRIVATE_H
 
-#ifdef colin
-#include <ksys/xthread.h>
-#endif
-
 /*
  * pciio_private.h -- private definitions for pciio
  * PCI drivers should NOT include this file.
@@ -54,12 +50,12 @@
     pciio_intr_line_t       pi_lines;	/* which interrupt line(s) */
     intr_func_t             pi_func;	/* handler function (when connected) */
     intr_arg_t              pi_arg;	/* handler parameter (when connected) */
-#ifdef IRIX
+#ifdef LATER
     thd_int_t               pi_tinfo;	/* Thread info (when connected) */
 #endif
     cpuid_t                 pi_mustruncpu; /* Where we must run. */
-    int			    pi_irq;	/* IRQ assigned */
-    int			    pi_cpu;	/* cpu assigned */
+    int                     pi_irq;     /* IRQ assigned */
+    int                     pi_cpu;     /* cpu assigned */
 };
 
 /* PCIIO_INTR (pi_flags) flags */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pio.h linux/include/asm-ia64/sn/pio.h
--- v2.4.3/linux/include/asm-ia64/sn/pio.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pio.h	Thu Apr  5 12:51:47 2001
@@ -33,7 +33,7 @@
 typedef struct piomap {
 	uint		pio_bus;
 	uint		pio_adap;
-#ifdef IRIX
+#ifdef LATER
 	iospace_t	pio_iospace;
 #endif
 	int		pio_flag;
@@ -41,7 +41,7 @@
 	char		pio_name[7];	/* to identify the mapped device */
 	struct piomap	*pio_next;	/* dlist to link active piomap's */
 	struct piomap	*pio_prev;	/* for debug and error reporting */
-#ifdef IRIX
+#ifdef LATER
 	void		(*pio_errfunc)(); /* Pointer to an error function */
 					  /* Used only for piomaps allocated
 					   * in user level vme driver     */
@@ -50,6 +50,10 @@
 	iobush_t	pio_bushandle;	/* bus-level handle */
 } piomap_t;
 
+#define pio_type	pio_iospace.ios_type
+#define pio_iopaddr	pio_iospace.ios_iopaddr
+#define pio_size	pio_iospace.ios_size
+#define pio_vaddr	pio_iospace.ios_vaddr
 
 /* Macro to get/set PIO error function */
 #define	pio_seterrf(p,f)	(p)->pio_errfunc = (f)
@@ -64,7 +68,7 @@
  * pio_mapfree()  - frees the mapping as specified in the piomap handle.
  * pio_mapaddr()  - returns the kv address that maps to piomap'ed io address.
  */
-#ifdef IRIX
+#ifdef LATER
 extern piomap_t	*pio_mapalloc(uint,uint,iospace_t*,int,char*);
 extern void	 pio_mapfree(piomap_t*);
 extern caddr_t	 pio_mapaddr(piomap_t*,iopaddr_t);
@@ -101,7 +105,7 @@
 extern void andb_rmw(volatile void*, unsigned int);
 extern void andh_rmw(volatile void*, unsigned int);
 extern void andw_rmw(volatile void*, unsigned int);
-#endif	/* IRIX */
+#endif	/* LATER */
 
 
 /*
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/router.h linux/include/asm-ia64/sn/router.h
--- v2.4.3/linux/include/asm-ia64/sn/router.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/router.h	Thu Apr  5 12:51:47 2001
@@ -11,6 +11,7 @@
 #define _ASM_SN_ROUTER_H
 
 #include <linux/config.h>
+
 #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
 #include <asm/sn/sn1/router.h>
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sgi.h linux/include/asm-ia64/sn/sgi.h
--- v2.4.3/linux/include/asm-ia64/sn/sgi.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/sgi.h	Thu Apr  5 12:51:47 2001
@@ -13,6 +13,7 @@
 #define _ASM_SN_SGI_H
 
 #include <linux/config.h>
+
 #include <asm/sn/types.h>
 #include <asm/uaccess.h>		/* for copy_??_user */
 #include <linux/mm.h>
@@ -121,18 +122,6 @@
 	GRAPH_IN_USE		/* 7 */
 } graph_error_t;
 
-#define SV_FIFO         0x0             /* sv_t is FIFO type */
-#define SV_LIFO         0x2             /* sv_t is LIFO type */
-#define SV_PRIO         0x4             /* sv_t is PRIO type */
-#define SV_KEYED        0x6             /* sv_t is KEYED type */
-#define SV_DEFAULT      SV_FIFO
-
-
-#define MUTEX_DEFAULT	0x0		/* needed by mutex_init() calls */
-#define PZERO		25		/* needed by mutex_lock(), sv_wait()
-					 * psema() calls */
-
-#define sema_t  uint64_t		/* FIXME */
 #define KM_SLEEP   0x0000
 #define KM_NOSLEEP 0x0001		/* needed by kmem_alloc_node(), kmem_zalloc()
 					 * calls */
@@ -140,10 +129,6 @@
 					 * calls */
 #define XG_WIDGET_PART_NUM      0xC102          /* KONA/xt_regs.h     XG_XT_PART_NUM_VALUE */
 
-#ifndef K1BASE
-#define K1BASE 0xA0000000
-#endif
-
 #ifndef TO_PHYS_MASK
 #define TO_PHYS_MASK 0x0000000fffffffff
 #endif
@@ -171,8 +156,6 @@
 #define _PAGESZ 4096
 #endif
 
-typedef uint64_t k_machreg_t;	/* needed by cmn_err.h */
-
 typedef uint64_t mrlock_t;	/* needed by devsupport.c */
 
 #define HUB_PIO_CONVEYOR 0x1
@@ -188,44 +171,64 @@
 #define POFFMASK		(NBPP - 1)
 #define poff(X)			((__psunsigned_t)(X) & POFFMASK)
 
-#define initnsema(a,b,c) 	sema_init(a,b)
-
 #define BZERO(a,b)		memset(a, 0, b)
 
-#define kern_malloc(x)	kmalloc(x, GFP_KERNEL)
-#define kern_free(x)	kfree(x)
+#define kern_malloc(x)		kmalloc(x, GFP_KERNEL)
+#define kern_free(x)		kfree(x)
 
 typedef cpuid_t cpu_cookie_t;
 #define CPU_NONE		-1
 
+/*
+ * mutext support mapping
+ */
+
+#define mutex_spinlock_init(s)	spin_lock_init(s)
+inline static unsigned long
+mutex_spinlock(spinlock_t *sem) {
+	unsigned long flags = 0;
+//	spin_lock_irqsave(sem, flags);
+	spin_lock(sem);
+	return(flags);
+}
+// #define mutex_spinunlock(s,t)	spin_unlock_irqrestore(s,t)
+#define mutex_spinunlock(s,t)	spin_unlock(s)
+
+
+#define mutex_t			struct semaphore
+#define mutex_init(s)		init_MUTEX(s)
+#define mutex_init_locked(s)	init_MUTEX_LOCKED(s)
+#define mutex_lock(s)		down(s)
+#define mutex_unlock(s)		up(s)
+
+#define io_splock(s)		mutex_spinlock(s)
+#define io_spunlock(s,t)	spin_unlock(s)
+
+#define spin_lock_destroy(s)
 
 #if defined(DISABLE_ASSERT)
 #define ASSERT(expr)
 #define ASSERT_ALWAYS(expr)
 #else
-#define ASSERT(expr)	\
+#define ASSERT(expr)  do {	\
         if(!(expr)) { \
 		printk( "Assertion [%s] failed! %s:%s(line=%d)\n",\
 			#expr,__FILE__,__FUNCTION__,__LINE__); \
 		panic("Assertion panic\n"); 	\
-        }
+        } } while(0)
 
-#define ASSERT_ALWAYS(expr)	\
+#define ASSERT_ALWAYS(expr)	do {\
         if(!(expr)) { \
 		printk( "Assertion [%s] failed! %s:%s(line=%d)\n",\
 			#expr,__FILE__,__FUNCTION__,__LINE__); \
 		panic("Assertion always panic\n"); 	\
-        }
+        } } while(0)
 #endif	/* DISABLE_ASSERT */
 
-/* These are defined as cmn_err() replacements */
-#define PRINT_WARNING(x...)	{ printk("WARNING : "); printk(x); }
-#define PRINT_NOTICE(x...)	{ printk("NOTICE : "); printk(x); }
-#define PRINT_ALERT(x...)	{ printk("ALERT : "); printk(x); }
+#define PRINT_WARNING(x...)	do { printk("WARNING : "); printk(x); } while(0)
+#define PRINT_NOTICE(x...)	do { printk("NOTICE : "); printk(x); } while(0)
+#define PRINT_ALERT(x...)	do { printk("ALERT : "); printk(x); } while(0)
 #define PRINT_PANIC		panic
-
-#define mutex_t int
-#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name);
 
 #ifdef CONFIG_SMP
 #define cpu_enabled(cpu)        (test_bit(cpu, &cpu_online_map))
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/slotnum.h linux/include/asm-ia64/sn/slotnum.h
--- v2.4.3/linux/include/asm-ia64/sn/slotnum.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/slotnum.h	Thu Apr  5 12:51:47 2001
@@ -10,9 +10,10 @@
 #ifndef _ASM_SN_SLOTNUM_H
 #define _ASM_SN_SLOTNUM_H
 
+#include <linux/config.h>
+
 typedef	unsigned char slotid_t;
 
-#include <linux/config.h>
 #if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/sn1/slotnum.h>
 #else
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/addrs.h linux/include/asm-ia64/sn/sn1/addrs.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/addrs.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/addrs.h	Thu Apr  5 12:51:47 2001
@@ -43,22 +43,19 @@
 #if defined(_RUN_UNCACHED)
 #define CAC_BASE		0x9600000000000000
 #else
+#ifndef __ia64
 #define CAC_BASE		0xa800000000000000
+#else
+#define CAC_BASE                0xe000000000000000
+#endif
 #endif
 
-#ifdef Colin
-#define HSPEC_BASE		0x9000000000000000
-#define IO_BASE			0x9200000000000000
-#define MSPEC_BASE		0x9400000000000000
-#define UNCAC_BASE		0x9600000000000000
-#else
 #define HSPEC_BASE              0xc0000b0000000000
 #define HSPEC_SWIZ_BASE         0xc000030000000000
 #define IO_BASE                 0xc0000a0000000000
 #define IO_SWIZ_BASE            0xc000020000000000
 #define MSPEC_BASE              0xc000000000000000
 #define UNCAC_BASE              0xc000000000000000
-#endif
 
 #define TO_PHYS(x)		(	      ((x) & TO_PHYS_MASK))
 #define TO_CAC(x)		(CAC_BASE   | ((x) & TO_PHYS_MASK))
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/bedrock.h linux/include/asm-ia64/sn/sn1/bedrock.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/bedrock.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/sn1/bedrock.h	Thu Apr  5 12:51:47 2001
@@ -11,6 +11,8 @@
 #ifndef _ASM_SN_SN1_BEDROCK_H
 #define _ASM_SN_SN1_BEDROCK_H
 
+#include <linux/config.h>
+
 /* The secret password; used to release protection */
 #define HUB_PASSWORD		0x53474972756c6573ull
 
@@ -22,7 +24,6 @@
 
 #define MAX_HUB_PATH		80
 
-#include <linux/config.h>
 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
 #include <asm/sn/arch.h>
 #include <asm/sn/sn1/addrs.h>
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/hubio_next.h linux/include/asm-ia64/sn/sn1/hubio_next.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/hubio_next.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/hubio_next.h	Thu Apr  5 12:51:47 2001
@@ -43,6 +43,8 @@
 #define IIO_IOPRB_0		IIO_IPRB0
 #define IIO_PRTE_0      	IIO_IPRTE0        /* PIO Read address table entry 0 */
 #define IIO_PRTE(_x)    	(IIO_PRTE_0 + (8 * (_x)))
+#define IIO_NUM_IPRBS 		(9) 
+#define IIO_WIDPRTE(x)  IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */
 
 #define IIO_LLP_CSR_IS_UP               0x00002000
 #define IIO_LLP_CSR_LLP_STAT_MASK       0x00003000
@@ -192,6 +194,21 @@
 #define       HUBII_XBOW_CREDIT       3
 #define       HUBII_XBOW_REV2_CREDIT  4
 
+/*
+ * Number of credits that xtalk devices should use when communicating
+ * with a Bedrock (depth of Bedrock's queue).
+ */
+#define HUB_CREDIT 4
+
+/*
+ * Some IIO_PRB fields
+ */
+#define IIO_PRB_MULTI_ERR	(1LL << 63)
+#define IIO_PRB_SPUR_RD		(1LL << 51)
+#define IIO_PRB_SPUR_WR		(1LL << 50)
+#define IIO_PRB_RD_TO		(1LL << 49)
+#define IIO_PRB_ERROR		(1LL << 48)
+
 /*************************************************************************
 
  Some of the IIO field masks and shifts are defined here.
@@ -245,6 +262,29 @@
 #define IBCT_ZFIL_MODE		(0x1 << 0)
 
 /*
+ * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2)
+ */
+#define IIEPH1_VALID		(1 << 44)
+#define IIEPH1_OVERRUN		(1 << 40)
+#define IIEPH1_ERR_TYPE_SHFT	32
+#define IIEPH1_ERR_TYPE_MASK	0xf
+#define IIEPH1_SOURCE_SHFT	20
+#define IIEPH1_SOURCE_MASK	11
+#define IIEPH1_SUPPL_SHFT	8
+#define IIEPH1_SUPPL_MASK	11
+#define IIEPH1_CMD_SHFT		0
+#define IIEPH1_CMD_MASK		7
+
+#define IIEPH2_TAIL		(1 << 40)
+#define IIEPH2_ADDRESS_SHFT	0
+#define IIEPH2_ADDRESS_MASK	38
+
+#define IIEPH1_ERR_SHORT_REQ	2
+#define IIEPH1_ERR_SHORT_REPLY	3
+#define IIEPH1_ERR_LONG_REQ	4
+#define IIEPH1_ERR_LONG_REPLY	5
+
+/*
  * IO Error Clear register bit field definitions
  */
 #define IECLR_PI1_FWD_INT	(1 << 31)  /* clear PI1_FORWARD_INT in iidsr */
@@ -363,6 +403,10 @@
 /* A few more #defines for backwards compatibility */
 #define iprb_t          ii_iprb0_u_t
 #define iprb_regval     ii_iprb0_regval
+#define iprb_mult_err	ii_iprb0_fld_s.i_mult_err
+#define iprb_spur_rd	ii_iprb0_fld_s.i_spur_rd
+#define iprb_spur_wr	ii_iprb0_fld_s.i_spur_wr
+#define iprb_rd_to	ii_iprb0_fld_s.i_rd_to
 #define iprb_ovflow     ii_iprb0_fld_s.i_of_cnt
 #define iprb_error      ii_iprb0_fld_s.i_error
 #define iprb_ff         ii_iprb0_fld_s.i_f
@@ -385,7 +429,6 @@
 
 #define IO_PERF_SETS	32
 
-#ifdef BRINGUP
 #if __KERNEL__
 #if _LANGUAGE_C
 /* XXX moved over from SN/SN0/hubio.h -- each should be checked for SN1 */
@@ -646,6 +689,11 @@
                 device_desc_t dev_desc,         /* device descriptor */
                 devfs_handle_t owner_dev);        /* owner of this interrupt */
 
+extern hub_intr_t
+hub_intr_alloc_nothd(devfs_handle_t dev,          /* which device */
+                device_desc_t dev_desc,         /* device descriptor */
+                devfs_handle_t owner_dev);        /* owner of this interrupt */
+
 extern void
 hub_intr_free(hub_intr_t intr_hdl);
 
@@ -710,5 +758,4 @@
 
 #endif /* _LANGUAGE_C */
 #endif /* _KERNEL */
-#endif /* BRINGUP */
 #endif  /* _ASM_SN_SN1_HUBIO_NEXT_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/hubpi_next.h linux/include/asm-ia64/sn/sn1/hubpi_next.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/hubpi_next.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/hubpi_next.h	Thu Apr  5 12:51:47 2001
@@ -274,7 +274,9 @@
  * The following three macros define all possible error int pends. 
  */
 
-#define PI_FATAL_ERR_CPU_A	(PI_ERR_SYSAD_BAD_DATA_A | \
+#define PI_FATAL_ERR_CPU_A	(PI_ERR_IRB_TIMEOUT_A	| \
+				 PI_ERR_IRB_ERR_A	| \
+				 PI_ERR_PKT_LEN_ERR_A	| \
 				 PI_ERR_SYSSTATE_TAG_A 	| \
 				 PI_ERR_BAD_SPOOL_A 	| \
 				 PI_ERR_SYSCMD_ADDR_A 	| \
@@ -283,17 +285,17 @@
 				 PI_ERR_SYSAD_DATA_A	| \
 				 PI_ERR_SYSSTATE_A)
 
-#define PI_MISC_ERR_CPU_A	(PI_ERR_IRB_TIMEOUT_A   | \
-				 PI_ERR_IRB_ERR_A       | \
-				 PI_ERR_PKT_LEN_ERR_A   | \
-				 PI_ERR_UE_CACHED_A     | \
+#define PI_MISC_ERR_CPU_A	(PI_ERR_UE_CACHED_A	| \
+				 PI_ERR_SYSAD_BAD_DATA_A| \
 				 PI_ERR_UNCAC_UNCORR_A 	| \
 				 PI_ERR_WRB_WERR_A 	| \
 				 PI_ERR_WRB_TERR_A 	| \
 				 PI_ERR_SPUR_MSG_A 	| \
 				 PI_ERR_SPOOL_CMP_A)
 
-#define PI_FATAL_ERR_CPU_B	(PI_ERR_SYSAD_BAD_DATA_B | \
+#define PI_FATAL_ERR_CPU_B	(PI_ERR_IRB_TIMEOUT_B	| \
+				 PI_ERR_IRB_ERR_B	| \
+				 PI_ERR_PKT_LEN_ERR_B	| \
 				 PI_ERR_SYSSTATE_TAG_B 	| \
 				 PI_ERR_BAD_SPOOL_B 	| \
 				 PI_ERR_SYSCMD_ADDR_B 	| \
@@ -302,11 +304,9 @@
 				 PI_ERR_SYSAD_DATA_B	| \
 				 PI_ERR_SYSSTATE_B)
 
-#define PI_MISC_ERR_CPU_B 	(PI_ERR_IRB_TIMEOUT_B   | \
-				 PI_ERR_IRB_ERR_B       | \
-				 PI_ERR_PKT_LEN_ERR_B   | \
-				 PI_ERR_UE_CACHED_B     | \
-				 PI_ERR_UNCAC_UNCORR_B  | \
+#define PI_MISC_ERR_CPU_B	(PI_ERR_UE_CACHED_B	| \
+				 PI_ERR_SYSAD_BAD_DATA_B| \
+				 PI_ERR_UNCAC_UNCORR_B 	| \
 				 PI_ERR_WRB_WERR_B 	| \
 				 PI_ERR_WRB_TERR_B 	| \
 				 PI_ERR_SPUR_MSG_B 	| \
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/hubxb_next.h linux/include/asm-ia64/sn/sn1/hubxb_next.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/hubxb_next.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/hubxb_next.h	Thu Apr  5 12:51:47 2001
@@ -28,5 +28,6 @@
 
 /* XB_PARMS fields */
 #define XBP_RESET_DEFAULTS	0x0008000080000021LL
+#define XBP_ACTIVE_DEFAULTS	0x00080000fffff021LL
 
 #endif	/* _ASM_SN_SN1_HUBXB_NEXT_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/ip27config.h linux/include/asm-ia64/sn/sn1/ip27config.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/ip27config.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/ip27config.h	Thu Apr  5 12:51:47 2001
@@ -188,6 +188,10 @@
 #define	IP27C_R10000_SCCD_MASK		(7 << IP27C_R10000_SCCD_SHFT)
 #define	IP27C_R10000_SCCD(_B)		((_B) << IP27C_R10000_SCCD_SHFT)
 
+#define	IP27C_R10000_DDR_SHFT		23
+#define	IP27C_R10000_DDR_MASK		(1 << IP27C_R10000_DDR_SHFT)
+#define	IP27C_R10000_DDR(_B)		((_B) << IP27C_R10000_DDR_SHFT)
+
 #define	IP27C_R10000_SCCT_SHFT		25
 #define	IP27C_R10000_SCCT_MASK		(0xf << IP27C_R10000_SCCT_SHFT)
 #define	IP27C_R10000_SCCT(_B)		((_B) << IP27C_R10000_SCCT_SHFT)
@@ -375,6 +379,7 @@
 	 IP27C_R10000_SCCE(0)	 + \
 	 IP27C_R10000_ME(1)	 + \
 	 IP27C_R10000_SCS(4)	 + \
+	 IP27C_R10000_DDR(1)     + \
 	 IP27C_R10000_SCCD(3)	 + \
 	 IP27C_R10000_SCCT(0xa)	 + \
 	 IP27C_R10000_ODSC(0)	 + \
@@ -503,12 +508,7 @@
  * for building hex images (as required by start.s)
  */
 #ifdef IP27_CONFIG_SN00_4MB_100_200_133
-#ifdef IRIX
-/* Set PrcReqMax to 0 to reduce memory problems */
-#define	BRINGUP_PRM_VAL	0
-#else
 #define	BRINGUP_PRM_VAL	3
-#endif
 #define CONFIG_CPU_MODE \
 	(IP27C_R10000_KSEG0CA(5) + \
 	 IP27C_R10000_DEVNUM(0)	 + \
@@ -593,6 +593,7 @@
 	 IP27C_R10000_ME(1)	 + \
 	 IP27C_R10000_SCS(4)	 + \
 	 IP27C_R10000_SCCD(3)	 + \
+         IP27C_R10000_DDR(1)     + \
 	 IP27C_R10000_SCCT(0xa)	 + \
 	 IP27C_R10000_ODSC(0)	 + \
 	 IP27C_R10000_ODSYS(1)	 + \
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/leds.h linux/include/asm-ia64/sn/sn1/leds.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/leds.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/leds.h	Thu Apr  5 12:51:47 2001
@@ -25,7 +25,7 @@
 	long	*ledp;
 	int	eid;
 
-	eid = hard_processor_sapicid() & 3;
+	eid = hard_smp_processor_id() & 3;
 	ledp = (long*) (LED0 + (eid<<3));
 	*ledp = val;
 }
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/router.h linux/include/asm-ia64/sn/sn1/router.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/router.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/router.h	Thu Apr  5 12:51:47 2001
@@ -513,7 +513,7 @@
 #ifdef DEBUG
 	int64_t	ri_deltatime;	/* Time it took to sample	    */
 #endif
-	lock_t		ri_lock;	/* Lock for access to router info   */
+	spinlock_t	ri_lock;	/* Lock for access to router info   */
 	net_vec_t	*ri_vecarray;	/* Pointer to array of vectors	    */
 	struct lboard_s	*ri_brd;	/* Pointer to board structure	    */
 	char *		ri_name;	/* This board's hwg path 	    */
@@ -566,6 +566,7 @@
 #define NORMAL_ROUTER_NAME	"normal_router"
 #define NULL_ROUTER_NAME	"null_router"
 #define META_ROUTER_NAME	"meta_router"
+#define REPEATER_ROUTER_NAME	"repeater_router"
 #define UNKNOWN_ROUTER_NAME	"unknown_router" 
 
 /* The following definitions are needed by the router traversing
@@ -630,7 +631,7 @@
  */
 
 #define RRM_RESETOK(_L)		(UINT64_CAST 1 << ((_L) - 1))
-#define RRM_RESETOK_ALL		(UINT64_CAST 0x3f)
+#define RRM_RESETOK_ALL		ALL_PORTS
 
 /*
  * RR_META_TABLE(_x) and RR_LOCAL_TABLE(_x) mask and shift definitions
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/slotnum.h linux/include/asm-ia64/sn/sn1/slotnum.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/slotnum.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/slotnum.h	Thu Apr  5 12:51:47 2001
@@ -14,8 +14,7 @@
 #define SLOTNUM_MAXLENGTH	16
 
 /*
- * This file attempts to define a slot number space across all slots
- * a IP27 module.  Here, we deal with the top level slots.
+ * This file attempts to define a slot number space across all slots.
  *
  *	Node slots
  *	Router slots
@@ -24,16 +23,20 @@
  *	Other slots are children of their parent crosstalk slot:
  *		PCI slots
  *		VME slots
+ *
+ *	The PCI class has been added since the XBridge ASIC on SN-MIPS
+ *	has built-in PCI bridges (2). On IBricks, widget E & F serve
+ *	PCI busses, and on PBricks all widgets serve as PCI busses
+ *	with the use of the super-bridge mode of the XBridge ASIC.
  */
-// #include <slotnum.h>
 
-// #ifdef NOTDEF	/* moved to sys/slotnum.h */
 #define SLOTNUM_NODE_CLASS	0x00	/* Node   */
 #define SLOTNUM_ROUTER_CLASS	0x10	/* Router */
 #define SLOTNUM_XTALK_CLASS	0x20	/* Xtalk  */
 #define SLOTNUM_MIDPLANE_CLASS	0x30	/* Midplane */
 #define SLOTNUM_XBOW_CLASS	0x40	/* Xbow  */
 #define SLOTNUM_KNODE_CLASS	0x50	/* Kego node */
+#define SLOTNUM_PCI_CLASS	0x60	/* PCI widgets on XBridge */
 #define SLOTNUM_INVALID_CLASS	0xf0	/* Invalid */
 
 #define SLOTNUM_CLASS_MASK	0xf0
@@ -41,7 +44,6 @@
 
 #define SLOTNUM_GETCLASS(_sn)	((_sn) & SLOTNUM_CLASS_MASK)
 #define SLOTNUM_GETSLOT(_sn)	((_sn) & SLOTNUM_SLOT_MASK)
-// #endif	/* NOTDEF */
 
 /* This determines module to pnode mapping. */
 /* NODESLOTS_PER_MODULE has changed from 4 to 6
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/uart16550.h linux/include/asm-ia64/sn/sn1/uart16550.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/uart16550.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/uart16550.h	Thu Apr  5 12:51:47 2001
@@ -1,3 +1,16 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2000 by Colin Ngam
+ */
+
+#ifndef _ASM_SN_SN1_UART16550_H
+#define _ASM_SN_SN1_UART16550_H
+
 
 /*
  * Definitions for 16550  chip
@@ -212,3 +225,4 @@
 #define INC_RING_POINTER(x) \
 	( ((x & 0xffe0) < 4064) ? (x += 32) : 0 )
 
+#endif /* _ASM_SN_SN1_UART16550_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/war.h linux/include/asm-ia64/sn/sn1/war.h
--- v2.4.3/linux/include/asm-ia64/sn/sn1/war.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/war.h	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-/* $Id$
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
- */
-#ifndef _ASM_SN_SN1_WAR_H
-#define _ASM_SN_SN1_WAR_H
-
-/****************************************************************************
- * Support macros and defitions for hardware workarounds in		    *
- * early chip versions.                                                     *
- ****************************************************************************/
-
-/*
- * This is the bitmap of runtime-switched workarounds.
- */
-typedef short warbits_t;
-
-extern int warbits_override;
-
-#endif /*  _ASM_SN_SN1_WAR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_cpuid.h linux/include/asm-ia64/sn/sn_cpuid.h
--- v2.4.3/linux/include/asm-ia64/sn/sn_cpuid.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/sn_cpuid.h	Thu Apr  5 12:51:47 2001
@@ -13,6 +13,7 @@
 #define _ASM_IA64_SN_SN_CPUID_H
 
 #include <linux/config.h>
+#include <asm/processor.h>
 #include <asm/sn/mmzone_sn1.h>
 
 /*
@@ -26,18 +27,35 @@
 
 
 /*
- * The following assumes the following mappings for LID register values:
+ *  Definitions of terms (these definitions are for IA64 ONLY. Other architectures
+ *  use cpuid/cpunum quite defferently):
+ *
+ *	   CPUID - a number in range of 0..NR_CPUS-1 that uniquely identifies
+ *		the cpu. The value cpuid has no significance on IA64 other than
+ *		the boot cpu is 0.
+ *			smp_processor_id() returns the cpuid of the current cpu.
+ *
+ *	   CPUNUM - On IA64, a cpunum and cpuid are the same. This is NOT true
+ *		on other architectures like IA32.
+ *
+ * 	   CPU_PHYSICAL_ID (also known as HARD_PROCESSOR_ID)
+ *		This is the same as 31:24 of the processor LID register
+ *			hard_smp_processor_id()- cpu_physical_id of current processor
+ *			cpu_physical_id(cpuid) - convert a <cpuid> to a <physical_cpuid>
+ *			cpu_logical_id(phy_id) - convert a <physical_cpuid> to a <cpuid> 
+ *				* not real efficient - dont use in perf critical code
  *
- *         LID
+ *         LID - processor defined register (see PRM V2).
  *		31:24 - id   Contains the NASID
  *		23:16 - eid  Contains 0-3 to identify the cpu on the node
  *				bit 17 - synergy number
- *				bit 16 - FSB number 
+ *				bit 16 - FSB slot number 
+ *
  *
- * 	   SAPICID
- *		This is the same as 31:24 of LID
  *
- * The macros convert between cpuid & slice/fsb/synergy/nasid/cnodeid.
+ * The following assumes the following mappings for LID register values:
+ *
+ * The macros convert between cpu physical ids & slice/fsb/synergy/nasid/cnodeid.
  * These terms are described below:
  *
  *
@@ -46,7 +64,7 @@
  *          -----   -----           -----   -----
  *            |       |               |       |
  *            |       |               |       |
- *          0 |       | 1           0 |       | 1       FSB
+ *          0 |       | 1           0 |       | 1       FSB SLOT
  *             -------                 -------  
  *                |                       |
  *                |                       |
@@ -68,25 +86,27 @@
  *
  */
 
+#ifndef CONFIG_SMP
+#define cpu_logical_id(cpu)				0
+#define cpu_physical_id(cpuid)			((ia64_get_lid() >> 16) & 0xffff)
+#endif
 
-
-#define sapicid_to_nasid(sid)		((sid) >> 8)
-#define sapicid_to_synergy(sid)		(((sid) >> 1) & 1)
-#define sapicid_to_fsb(sid)		((sid) & 1)
-#define sapicid_to_slice(sid)		((sid) & 3)
+#define cpu_physical_id_to_nasid(cpi)		((cpi) >> 8)
+#define cpu_physical_id_to_synergy(cpi)		(((cpi) >> 1) & 1)
+#define cpu_physical_id_to_fsb_slot(cpi)	((cpi) & 1)
+#define cpu_physical_id_to_slice(cpi)		((cpi) & 3)
 
 /*
  * NOTE: id & eid refer to Intels definitions of the LID register
  *	(id = NASID, eid = slice)
  * NOTE: on non-MP systems, only cpuid 0 exists
  */
-#define id_eid_to_sapicid(id,eid)       (((id)<<8) | (eid))
-#define id_eid_to_cpuid(id,eid)         ((NASID_TO_CNODEID(id)<<2) | (eid))
+#define id_eid_to_cpu_physical_id(id,eid)       (((id)<<8) | (eid))
+#define id_eid_to_cpuid(id,eid)         	(cpu_logical_id(id_eid_to_cpu_physical_id((id),(eid))))
 
 
 /*
- * The following table/struct is for translating between sapicid and cpuids.
- * It is also used for managing PTC coherency domains.
+ * The following table/struct  is used for managing PTC coherency domains.
  */
 typedef struct {
 	u8	domain;
@@ -99,28 +119,13 @@
 
 
 /*
- * cpuid_to_spaicid  - Convert a cpuid to a SAPIC id of the cpu. 
- * The SAPIC id is the same as bits 31:16 of the LID register.
- */
-static __inline__ int
-cpuid_to_spaicid(int cpuid)
-{
-#ifdef CONFIG_SMP
-	return cpu_physical_id(cpuid);
-#else
-	return ((ia64_get_lid() >> 16) & 0xffff);
-#endif
-}
-
-
-/*
  * cpuid_to_fsb_slot  - convert a cpuid to the fsb slot number that it is in.
  *   (there are 2 cpus per FSB. This function returns 0 or 1)
  */
 static __inline__ int
 cpuid_to_fsb_slot(int cpuid)
 {
-	return sapicid_to_fsb(cpuid_to_spaicid(cpuid));
+	return cpu_physical_id_to_fsb_slot(cpu_physical_id(cpuid));
 }
 
 
@@ -132,7 +137,7 @@
 static __inline__ int
 cpuid_to_synergy(int cpuid)
 {
-	return sapicid_to_synergy(cpuid_to_spaicid(cpuid));
+	return cpu_physical_id_to_synergy(cpu_physical_id(cpuid));
 }
 
 
@@ -143,7 +148,7 @@
 static __inline__ int
 cpuid_to_slice(int cpuid)
 {
-	return sapicid_to_slice(cpuid_to_spaicid(cpuid));
+	return cpu_physical_id_to_slice(cpu_physical_id(cpuid));
 }
 
 
@@ -153,7 +158,7 @@
 static __inline__ int
 cpuid_to_nasid(int cpuid)
 {
-	return sapicid_to_nasid(cpuid_to_spaicid(cpuid));
+	return cpu_physical_id_to_nasid(cpu_physical_id(cpuid));
 }
 
 
@@ -166,23 +171,42 @@
 	return nasid_map[cpuid_to_nasid(cpuid)];
 }
 
+/*
+ * cnodeid_to_nasid - convert a cnodeid to a NASID
+ */
 static __inline__ int
 cnodeid_to_nasid(int cnodeid)
 {
-	int i;
-	for (i = 0; i < MAXNASIDS; i++) {
-		if (nasid_map[i] == cnodeid) {
-			return(i);
-		}
-	}
-	return(-1);
+	if (nasid_map[cnodeid_map[cnodeid]] != cnodeid)
+		panic("cnodeid_to_nasid, cnode = %d", cnodeid);
+	return cnodeid_map[cnodeid];
 }
 
+/*
+ * nasid_to_cnodeid - convert a NASID to a cnodeid
+ */
+static __inline__ int
+nasid_to_cnodeid(int nasid)
+{
+	if (cnodeid_map[nasid_map[nasid]] != nasid)
+		panic("nasid_to_cnodeid");
+	return nasid_map[nasid];
+}
+
+
+/*
+ * cnode_slice_to_cpuid - convert a codeid & slice to a cpuid
+ */
 static __inline__ int
 cnode_slice_to_cpuid(int cnodeid, int slice) {
 	return(id_eid_to_cpuid(cnodeid_to_nasid(cnodeid),slice));
 }
 
+/*
+ * cpuid_to_subnode - convert a cpuid to the subnode it resides on.
+ *   slice 0 & 1 are on subnode 0
+ *   slice 2 & 3 are on subnode 1.
+ */
 static __inline__ int
 cpuid_to_subnode(int cpuid) {
 	int ret = cpuid_to_slice(cpuid);
@@ -190,9 +214,27 @@
 	else return 1;
 }
 
+/*
+ * cpuid_to_localslice - convert a cpuid to a local slice
+ *    slice 0 & 2 are local slice 0
+ *    slice 1 & 3 are local slice 1
+ */
 static __inline__ int
 cpuid_to_localslice(int cpuid) {
 	return(cpuid_to_slice(cpuid) & 1);
+}
+
+static __inline__ int
+cnodeid_to_cpuid(int cnode) {
+	int cpu;
+
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		if (cpuid_to_cnodeid(cpu) == cnode) {
+			break;
+		}
+	}
+	if (cpu == smp_num_cpus) cpu = -1;
+	return cpu;
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_fru.h linux/include/asm-ia64/sn/sn_fru.h
--- v2.4.3/linux/include/asm-ia64/sn/sn_fru.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn_fru.h	Thu Apr  5 12:51:47 2001
@@ -1,16 +1,14 @@
-/**************************************************************************
- *									  *
- *		 Copyright (C) 1992-1997, Silicon Graphics, Inc.	  *
- *									  *
- *  These coded instructions, statements, and computer programs	 contain  *
- *  unpublished	 proprietary  information of Silicon Graphics, Inc., and  *
- *  are protected by Federal copyright law.  They  may	not be disclosed  *
- *  to	third  parties	or copied or duplicated in any form, in whole or  *
- *  in part, without the prior written consent of Silicon Graphics, Inc.  *
- *									  *
- **************************************************************************/
-#ifndef __SYS_SN_SN0_FRU_H__
-#define __SYS_SN_SN0_FRU_H__
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 1999-2000 Silicon Graphics, Inc.
+ * Copyright (C) 2000 by Patrick Gefre
+ */
+#ifndef _ASM_SN_SN_FRU_H
+#define _ASM_SN_SN_FRU_H
 
 #define MAX_DIMMS			8	 /* max # of dimm banks */
 #define MAX_PCIDEV			8	 /* max # of pci devices on a pci bus */
@@ -44,6 +42,5 @@
 } kf_pci_bus_t;
 
 
-
-#endif /* #ifdef __SYS_SN_SN0_FRU_H__ */
+#endif	/* _ASM_SN_SN_FRU_H */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_private.h linux/include/asm-ia64/sn/sn_private.h
--- v2.4.3/linux/include/asm-ia64/sn/sn_private.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/sn_private.h	Thu Apr  5 12:51:47 2001
@@ -10,7 +10,6 @@
 #ifndef _ASM_SN_PRIVATE_H
 #define _ASM_SN_PRIVATE_H
 
-#include <linux/config.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/xtalk/xwidget.h>
 #include <asm/sn/xtalk/xtalk_private.h>
@@ -20,12 +19,12 @@
 extern hubreg_t get_region(cnodeid_t);
 extern hubreg_t	nasid_to_region(nasid_t);
 /* promif.c */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 extern cpuid_t cpu_node_probe(cpumask_t *cpumask, int *numnodes);
 #endif
 extern void he_arcs_set_vectors(void);
 extern void mem_init(void);
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 extern int cpu_enabled(cpuid_t);
 #endif
 extern void cpu_unenable(cpuid_t);
@@ -35,7 +34,7 @@
 extern int check_nasid_equiv(nasid_t, nasid_t);
 extern nasid_t get_console_nasid(void);
 extern char get_console_pcislot(void);
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int);
 #endif
 
@@ -112,19 +111,19 @@
 
 /* init.c */
 extern cnodeid_t get_compact_nodeid(void);	/* get compact node id */
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node);
 extern void init_platform_pda(pda_t *ppda, cpuid_t cpu);
 #endif
 extern void per_cpu_init(void);
 extern void per_hub_init(cnodeid_t);
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 extern cpumask_t boot_cpumask;
 #endif
 extern int is_fine_dirmode(void);
 extern void update_node_information(cnodeid_t);
  
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 /* clksupport.c */
 extern void early_counter_intr(eframe_t *);
 #endif
@@ -251,7 +250,7 @@
 /* IP27 cpu-specific information stored under INFO_LBL_CPU_INFO */
 /* TBD: IP27-dependent stuff currently in pda.h should be here */
 typedef struct cpuinfo_s {
-#ifndef CONFIG_IA64_SGI_IO
+#ifdef	LATER
 	pda_t		*ci_cpupda;	/* pointer to CPU's private data area */
 #endif
 	cpuid_t		ci_cpuid;	/* CPU ID */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_sal.h linux/include/asm-ia64/sn/sn_sal.h
--- v2.4.3/linux/include/asm-ia64/sn/sn_sal.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ia64/sn/sn_sal.h	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,25 @@
+#ifndef _ASM_IA64_SN_SAL_H
+#define _ASM_IA64_SN_SAL_H
+
+/*
+ * System Abstraction Layer definitions for IA64
+ *
+ *
+ * Copyright (C) 2000, Silicon Graphics.
+ * Copyright (C) 2000. Jack Steiner (steiner@sgi.com)
+ */
+
+
+#include <asm/sal.h>
+
+
+// SGI Specific Calls
+#define  SN_SAL_POD_MODE                           0x02000001
+#define  SN_SAL_SYSTEM_RESET                       0x02000002
+#define  SN_SAL_PROBE                              0x02000003
+
+
+u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr);
+
+
+#endif /* _ASM_IA64_SN_SN1_SAL_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sv.h linux/include/asm-ia64/sn/sv.h
--- v2.4.3/linux/include/asm-ia64/sn/sv.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ia64/sn/sv.h	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,153 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.  All rights reserved
+ *
+ * This implemenation of synchronization variables is heavily based on
+ * one done by Steve Lord <lord@sgi.com>
+ *
+ * Paul Cassella <pwc@sgi.com>
+ */
+
+#ifndef SV_H
+#define SV_H
+
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
+
+#ifndef ASSERT
+
+#define ASSERT(x) do {							  \
+                    if(!(x)) {						  \
+		      printk(KERN_ERR "%s\n", "Assertion failed: " # x);  \
+		      BUG();						  \
+		    }							  \
+                  } while(0)
+#define _SV_ASSERT
+#endif
+
+typedef void sv_mon_lock_t;
+typedef void (*sv_mon_unlock_func_t)(sv_mon_lock_t *lock);
+
+/* sv_flags values: */
+
+#define SV_ORDER_FIFO        0x001
+#define SV_ORDER_FILO        0x002
+#define SV_ORDER_LIFO        SV_ORDER_FILO
+
+/* If at some point one order becomes preferable to others, we can
+   switch to it if the caller of sv_init doesn't specify. */
+#define SV_ORDER_DEFAULT     SV_ORDER_FIFO
+
+#define SV_ORDER_MASK        0x00f
+
+
+#define SV_MON_SEMA          0x010
+#define SV_MON_SPIN          0x020
+
+#define SV_MON_MASK          0x0f0
+
+
+/*
+   If the monitor lock can be aquired from interrupts.  Note that this
+   is a superset of the cases in which the sv can be touched from
+   interrupts.
+
+   This is currently only valid when the monitor lock is a spinlock.
+
+   If this is used, sv_wait, sv_signal, and sv_broadcast must all be
+   called with interrupts disabled, which has to happen anyway to have
+   acquired the monitor spinlock. 
+ */
+#define SV_INTS              0x100
+
+/* ditto for bottom halves */
+#define SV_BHS               0x200
+
+
+
+/* sv_wait_flag values: */
+#define SV_WAIT_SIG          0x001 /* Allow sv_wait to be interrupted by a signal */
+
+typedef struct sv_s {
+	wait_queue_head_t sv_waiters;
+	sv_mon_lock_t *sv_mon_lock;   /* Lock held for exclusive access to monitor. */
+	sv_mon_unlock_func_t sv_mon_unlock_func;
+	spinlock_t sv_lock;  /* Spinlock protecting the sv itself. */
+	int sv_flags;
+} sv_t;
+
+#define DECLARE_SYNC_VARIABLE(sv, l, f) sv_t sv = sv_init(&sv, l, f)
+
+/* 
+ * @sv the sync variable to initialize
+ * @monitor_lock the lock enforcing exclusive running in the monitor
+ * @flags one of
+ *   SV_MON_SEMA monitor_lock is a semaphore
+ *   SV_MON_SPIN monitor_lock is a spinlock
+ * and a bitwise or of some subset of
+ *   SV_INTS - the monitor lock can be acquired from interrupts (and
+ *             hence, whenever we hold it, interrupts are disabled or
+ *             we're in an interrupt.)  This is only valid when
+ *             SV_MON_SPIN is set.
+ */
+void sv_init(sv_t *sv, sv_mon_lock_t *monitor_lock, int flags);
+
+/*
+ * Set SV_WAIT_SIG in sv_wait_flags to let the sv_wait be interrupted by signals.
+ *
+ * timeout is how long to wait before giving up, or 0 to wait
+ * indefinately.  It is given in jiffies, and is relative.
+ *
+ * The associated lock must be locked on entry.  It is unlocked on return.
+ *
+ * Return values:
+ *
+ * n < 0 : interrupted,  -n jiffies remaining on timeout, or -1 if timeout == 0
+ * n = 0 : timeout expired
+ * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0
+ */
+extern signed long sv_wait(sv_t *sv, int sv_wait_flags,
+			   unsigned long timeout /* relative jiffies */);
+
+static inline int sv_wait_compat(sv_t *sv, sv_mon_lock_t *lock, int sv_wait_flags,
+				 unsigned long timeout, int sv_mon_type)
+{
+	ASSERT(sv_mon_type == (sv->sv_flags & SV_MON_MASK));
+	if(sv->sv_mon_lock)
+		ASSERT(lock == sv->sv_mon_lock);
+	else
+		sv->sv_mon_lock = lock;
+
+	return sv_wait(sv, sv_wait_flags, timeout);
+}
+
+
+/* These work like Irix's sv_wait() and sv_wait_sig(), except the
+   caller must call the one correpsonding to the type of the monitor
+   lock. */
+#define sv_spin_wait(sv, lock)                              \
+        sv_wait_compat(sv, lock, 0, 0, SV_MON_SPIN)
+#define sv_spin_wait_sig(sv, lock)                          \
+        sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SPIN)
+
+#define sv_sema_wait(sv, lock)                              \
+        sv_wait_compat(sv, lock, 0, 0, SV_MON_SEMA)
+#define sv_sema_wait_sig(sv, lock)                          \
+        sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SEMA)
+
+/* These work as in Irix. */
+void sv_signal(sv_t *sv);
+void sv_broadcast(sv_t *sv);
+
+/* This works as in Irix. */
+void sv_destroy(sv_t *sv);
+
+#ifdef _SV_ASSERT
+#undef ASSERT
+#undef _SV_ASSERT
+#endif
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/synergy.h linux/include/asm-ia64/sn/synergy.h
--- v2.4.3/linux/include/asm-ia64/sn/synergy.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/synergy.h	Thu Apr 12 12:16:36 2001
@@ -1,7 +1,10 @@
 #ifndef ASM_IA64_SN_SYNERGY_H
 #define ASM_IA64_SN_SYNERGY_H
 
+#include <linux/config.h>
+
 #include "asm/io.h"
+#include "asm/sn/nodepda.h"
 #include "asm/sn/intr_public.h"
 
 
@@ -41,47 +44,52 @@
 #define WRITE_LOCAL_SYNERGY_REG(addr, value)	__synergy_out(addr, value)
 
 #define HUBREG_CAST             (volatile hubreg_t *)
-#define NODE_OFFSET(_n)         (UINT64_CAST (_n) << NODE_SIZE_BITS)
-#define SYN_UNCACHED_SPACE      0xc000000000000000
-#define NODE_HSPEC_BASE(_n)     (HSPEC_BASE + NODE_OFFSET(_n))
-#define NODE_LREG_BASE(_n)      (NODE_HSPEC_BASE(_n) + 0x30000000)
-#define RREG_BASE(_n)           (NODE_LREG_BASE(_n))
+#define HUB_L(_a)               *(_a)
+#define HUB_S(_a, _d)           *(_a) = (_d)
+
+#define HSPEC_SYNERGY0_0        0x04000000    /* Synergy0 Registers     */
+#define HSPEC_SYNERGY1_0        0x05000000    /* Synergy1 Registers     */
+#define HS_SYNERGY_STRIDE       (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0)
 #define REMOTE_HSPEC(_n, _x)    (HUBREG_CAST (RREG_BASE(_n) + (_x)))
-#define    HSPEC_SYNERGY0_0          0x04000000    /* Synergy0 Registers     */
-#define    HSPEC_SYNERGY1_0          0x05000000    /* Synergy1 Registers     */
-#define HS_SYNERGY_STRIDE               (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0)
 
+#define RREG_BASE(_n)           (NODE_LREG_BASE(_n))
+#define NODE_LREG_BASE(_n)      (NODE_HSPEC_BASE(_n) + 0x30000000)
+#define NODE_HSPEC_BASE(_n)     (HSPEC_BASE + NODE_OFFSET(_n))
+#ifndef HSPEC_BASE
+#define HSPEC_BASE              (SYN_UNCACHED_SPACE | HSPEC_BASE_SYN)
+#endif
+#define SYN_UNCACHED_SPACE      0xc000000000000000
+#define HSPEC_BASE_SYN          0x00000b0000000000
+#define NODE_OFFSET(_n)         (UINT64_CAST (_n) << NODE_SIZE_BITS)
+#define NODE_SIZE_BITS		33
 
-#define HUB_L(_a)                       *(_a)
-#define HUB_S(_a, _d)                   *(_a) = (_d)
 
+#define RSYN_REG_OFFSET(fsb, reg) (((fsb) ? HSPEC_SYNERGY1_0 : HSPEC_SYNERGY0_0) | (reg))
 
 #define REMOTE_SYNERGY_LOAD(nasid, fsb, reg)  __remote_synergy_in(nasid, fsb, reg)
 #define REMOTE_SYNERGY_STORE(nasid, fsb, reg, val) __remote_synergy_out(nasid, fsb, reg, val)
 
-extern inline void
-__remote_synergy_out(int nasid, int fsb, unsigned long reg, unsigned long val) {
-	unsigned long addr = ((RREG_BASE(nasid)) + 
-		((HSPEC_SYNERGY0_0 | (fsb)*HS_SYNERGY_STRIDE) | ((reg) << 2)));
-
-	HUB_S((unsigned long *)(addr),      (val) >> 48);
-	HUB_S((unsigned long *)(addr+0x08), (val) >> 32);
-	HUB_S((unsigned long *)(addr+0x10), (val) >> 16);
-	HUB_S((unsigned long *)(addr+0x18), (val)      );
-	__ia64_mf_a();
+extern inline uint64_t
+__remote_synergy_in(int nasid, int fsb, uint64_t reg) {
+	volatile uint64_t *addr;
+
+	addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, reg));
+	return (*addr);
 }
 
-extern inline unsigned long
-__remote_synergy_in(int nasid, int fsb, unsigned long reg) {
-	volatile unsigned long *addr = (unsigned long *) ((RREG_BASE(nasid)) + 
-		((HSPEC_SYNERGY0_0 | (fsb)*HS_SYNERGY_STRIDE) | (reg)));
-	unsigned long ret;
+extern inline void
+__remote_synergy_out(int nasid, int fsb, uint64_t reg, uint64_t value) {
+	volatile uint64_t *addr;
 
-	ret = *addr;
-	__ia64_mf_a();
-	return ret;
+        addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, (reg<<2)));
+        *(addr+0) = value >> 48;
+        *(addr+1) = value >> 32;
+        *(addr+2) = value >> 16;
+        *(addr+3) = value;
+        __ia64_mf_a();
 }
 
+/* XX this doesn't make a lot of sense. Which fsb?  */
 extern inline void
 __synergy_out(unsigned long addr, unsigned long value)
 {
@@ -94,6 +102,7 @@
 
 #define READ_LOCAL_SYNERGY_REG(addr)	__synergy_in(addr)
 
+/* XX this doesn't make a lot of sense. Which fsb? */
 extern inline unsigned long
 __synergy_in(unsigned long addr)
 {
@@ -120,7 +129,39 @@
 	spinlock_t action_list_lock;
 	struct sn1_intr_action *action_list;
 };
-	
+
+#if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
+
+/* multiplex the counters every 10 timer interrupts */ 
+#define SYNERGY_PERF_FREQ_DEFAULT 10
+
+/* synergy perf control registers */
+#define PERF_CNTL0_A            0xab0UL /* control A on FSB0 */
+#define PERF_CNTL0_B            0xab8UL /* control B on FSB0 */
+#define PERF_CNTL1_A            0xac0UL /* control A on FSB1 */
+#define PERF_CNTL1_B            0xac8UL /* control B on FSB1 */
+
+/* synergy perf counters */
+#define PERF_CNTR0_A            0xad0UL /* counter A on FSB0 */
+#define PERF_CNTR0_B            0xad8UL /* counter B on FSB0 */
+#define PERF_CNTR1_A            0xaf0UL /* counter A on FSB1 */
+#define PERF_CNTR1_B            0xaf8UL /* counter B on FSB1 */
+
+/* Synergy perf data. Each nodepda keeps a list of these */
+struct synergy_perf_s {
+        uint64_t        intervals;      /* count of active intervals for this event */
+        uint64_t        modesel;        /* mode and sel bits, both A and B registers */
+        struct synergy_perf_s *next;	/* next in circular linked list */
+        uint64_t        counts[2];      /* [0] is synergy-A counter, [1] synergy-B counter */
+};
+
+typedef struct synergy_perf_s synergy_perf_t;
+
+extern void synergy_perf_init(void);
+extern void synergy_perf_update(int);
+
+#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */
+
 
 /* Temporary defintions for testing: */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/types.h linux/include/asm-ia64/sn/types.h
--- v2.4.3/linux/include/asm-ia64/sn/types.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/types.h	Thu Apr  5 12:51:47 2001
@@ -9,7 +9,6 @@
 #ifndef _ASM_SN_TYPES_H
 #define _ASM_SN_TYPES_H
 
-#include <linux/config.h>
 #include <linux/types.h>
 
 typedef unsigned long 	cpuid_t;
@@ -22,15 +21,12 @@
 typedef signed short	cmoduleid_t;	/* kernel compact module id type */
 typedef unsigned char	clusterid_t;	/* Clusterid of the cell */
 
-#if defined(CONFIG_IA64_SGI_IO)
 #define __psunsigned_t uint64_t
 #define lock_t uint64_t
-#define sv_t uint64_t
 
 typedef unsigned long iopaddr_t;
 typedef unsigned char uchar_t;
 typedef unsigned long paddr_t;
 typedef unsigned long pfn_t;
-#endif        /* CONFIG_IA64_SGI_IO */
 
 #endif /* _ASM_SN_TYPES_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/war.h linux/include/asm-ia64/sn/war.h
--- v2.4.3/linux/include/asm-ia64/sn/war.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/war.h	Wed Dec 31 16:00:00 1969
@@ -1,18 +0,0 @@
-/* $Id$
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
- */
-#ifndef _ASM_SN_WAR_H
-#define _ASM_SN_WAR_H
-
-#include <linux/config.h>
-#if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
-#include <asm/sn/sn1/war.h>
-#endif
-
-#endif /* _ASM_SN_WAR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk.h linux/include/asm-ia64/sn/xtalk/xtalk.h
--- v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/xtalk/xtalk.h	Thu Apr  5 12:51:47 2001
@@ -278,6 +278,7 @@
 
     /* INTERRUPT MANAGEMENT */
     xtalk_intr_alloc_f     *intr_alloc;
+    xtalk_intr_alloc_f     *intr_alloc_nothd;
     xtalk_intr_free_f      *intr_free;
     xtalk_intr_connect_f   *intr_connect;
     xtalk_intr_disconnect_f *intr_disconnect;
@@ -308,6 +309,7 @@
 extern xtalk_dmaaddr_drain_f xtalk_dmaaddr_drain;
 extern xtalk_dmalist_drain_f xtalk_dmalist_drain;
 extern xtalk_intr_alloc_f xtalk_intr_alloc;
+extern xtalk_intr_alloc_f xtalk_intr_alloc_nothd;
 extern xtalk_intr_free_f xtalk_intr_free;
 extern xtalk_intr_connect_f xtalk_intr_connect;
 extern xtalk_intr_disconnect_f xtalk_intr_disconnect;
@@ -342,10 +344,6 @@
 extern iopaddr_t        xtalk_intr_addr_get(xtalk_intr_t xtalk_intr);
 extern devfs_handle_t     xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr);
 extern void            *xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr);
-
-extern int		xtalk_intr_flags_get(xtalk_intr_t xtalk_intr);
-/* XTALK_INTR flags */
-#define XTALK_INTR_NOTHREAD	1	/* interrupt handler wants to be called at interrupt level */
 
 /* Generic crosstalk pio interfaces */
 extern devfs_handle_t     xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap);
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk_private.h linux/include/asm-ia64/sn/xtalk/xtalk_private.h
--- v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk_private.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/xtalk/xtalk_private.h	Thu Apr  5 12:51:47 2001
@@ -10,11 +10,7 @@
 #ifndef _ASM_SN_XTALK_XTALK_PRIVATE_H
 #define _ASM_SN_XTALK_XTALK_PRIVATE_H
 
-#ifdef IRIX
-#include <sys/ioerror.h>	/* for error function and arg types */
-#else
 #include <asm/sn/ioerror.h>        /* for error function and arg types */
-#endif
 
 /*
  * xtalk_private.h -- private definitions for xtalk
@@ -44,7 +40,6 @@
  * All Crosstalk providers set up interrupts using this information.
  */
 struct xtalk_intr_s {
-    int                     xi_flags;	/* XTALK_INTR flags */
     devfs_handle_t            xi_dev;	/* requestor of this intr */
     xwidgetnum_t            xi_target;	/* master's widget number */
     xtalk_intr_vector_t     xi_vector;	/* 8-bit interrupt vector */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h
--- v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h	Thu Apr  5 12:51:47 2001
@@ -10,6 +10,8 @@
 #ifndef _ASM_SN_XTALK_XTALKADDRS_H
 #define _ASM_SN_XTALK_XTALKADDRS_H
 
+#include <linux/config.h>
+
 /*
  * CrossTalk to SN0 Hub addressing support
  *
@@ -58,8 +60,6 @@
  * This looks very much like a REMOTE_HUB access, except the nodeID
  * is in a different place, and the highest xtalk bit is set.
  */
-
-#include <linux/config.h>
 
 /* Hub-specific xtalk definitions */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/softirq.h linux/include/asm-ia64/softirq.h
--- v2.4.3/linux/include/asm-ia64/softirq.h	Fri Mar 10 15:24:02 2000
+++ linux/include/asm-ia64/softirq.h	Thu Apr  5 12:51:47 2001
@@ -2,17 +2,14 @@
 #define _ASM_IA64_SOFTIRQ_H
 
 /*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <asm/hardirq.h>
 
-#define cpu_bh_disable(cpu)	do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
+#define local_bh_disable()	do { local_bh_count()++; barrier(); } while (0)
+#define local_bh_enable()	do { barrier(); local_bh_count()--; } while (0)
 
-#define local_bh_disable()	cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()	cpu_bh_enable(smp_processor_id())
-
-#define in_softirq()		(local_bh_count(smp_processor_id()) != 0)
+#define in_softirq()		(local_bh_count() != 0)
 
 #endif /* _ASM_IA64_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h
--- v2.4.3/linux/include/asm-ia64/system.h	Tue Mar  6 19:44:34 2001
+++ linux/include/asm-ia64/system.h	Thu Apr  5 12:51:47 2001
@@ -7,8 +7,8 @@
  * on information published in the Processor Abstraction Layer
  * and the System Abstraction Layer manual.
  *
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
  */
@@ -16,16 +16,18 @@
 
 #include <asm/page.h>
 
-#define KERNEL_START		(PAGE_OFFSET + 0x500000)
+#define KERNEL_START		(PAGE_OFFSET + 68*1024*1024)
 
 /*
  * The following #defines must match with vmlinux.lds.S:
  */
+#define IVT_ADDR		(KERNEL_START)
 #define IVT_END_ADDR		(KERNEL_START + 0x8000)
-#define ZERO_PAGE_ADDR		(IVT_END_ADDR + 0*PAGE_SIZE)
-#define SWAPPER_PGD_ADDR	(IVT_END_ADDR + 1*PAGE_SIZE)
+#define ZERO_PAGE_ADDR		PAGE_ALIGN(IVT_END_ADDR)
+#define SWAPPER_PGD_ADDR	(ZERO_PAGE_ADDR + 1*PAGE_SIZE)
 
 #define GATE_ADDR		(0xa000000000000000 + PAGE_SIZE)
+#define PERCPU_ADDR		(0xa000000000000000 + 2*PAGE_SIZE)
 
 #if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
     || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
@@ -62,12 +64,10 @@
 		__u16 orig_x;	/* cursor's x position */
 		__u16 orig_y;	/* cursor's y position */
 	} console_info;
-	__u16 num_pci_vectors;	/* number of ACPI derived PCI IRQ's*/
-	__u64 pci_vectors;	/* physical address of PCI data (pci_vector_struct)*/
 	__u64 fpswa;		/* physical address of the fpswa interface */
 	__u64 initrd_start;
 	__u64 initrd_size;
-} ia64_boot_param;
+} *ia64_boot_param;
 
 static inline void
 ia64_insn_group_barrier (void)
@@ -181,50 +181,9 @@
 #define __save_flags(flags)	__asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory")
 #define __save_and_cli(flags)	local_irq_save(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
-
-
-#ifdef CONFIG_IA64_SOFTSDV_HACKS
-/*
- * Yech.  SoftSDV has a slight probem with psr.i and itc/itm.  If
- * PSR.i = 0 and ITC == ITM, you don't get the timer tick posted.  So,
- * I'll check if ITC is larger than ITM here and reset if neccessary.
- * I may miss a tick to two.
- * 
- * Don't include asm/delay.h; it causes include loops that are
- * mind-numbingly hard to follow.
- */
-
-#define get_itc(x) __asm__ __volatile__("mov %0=ar.itc" : "=r"((x)) :: "memory")
-#define get_itm(x) __asm__ __volatile__("mov %0=cr.itm" : "=r"((x)) :: "memory")
-#define set_itm(x) __asm__ __volatile__("mov cr.itm=%0" :: "r"((x)) : "memory")
-
-#define __restore_flags(x)			\
-do {						\
-        unsigned long itc, itm;			\
-	local_irq_restore(x);			\
-        get_itc(itc);				\
-        get_itm(itm);				\
-        if (itc > itm)				\
-		set_itm(itc + 10);		\
-} while (0)
-
-#define __sti()					\
-do {						\
-	unsigned long itc, itm;			\
-	local_irq_enable();			\
-	get_itc(itc);				\
-	get_itm(itm);				\
-	if (itc > itm)				\
-		set_itm(itc + 10);		\
-} while (0)
-
-#else /* !CONFIG_IA64_SOFTSDV_HACKS */
-
 #define __sti()			local_irq_enable ()
 #define __restore_flags(flags)	local_irq_restore(flags)
 
-#endif /* !CONFIG_IA64_SOFTSDV_HACKS */
-
 #ifdef CONFIG_SMP
   extern void __global_cli (void);
   extern void __global_sti (void);
@@ -325,7 +284,7 @@
 #define xchg(ptr,x)							     \
   ((__typeof__(*(ptr))) __xchg ((unsigned long) (x), (ptr), sizeof(*(ptr))))
 
-/* 
+/*
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
  * store NEW in MEM.  Return the initial value in MEM.  Success is
  * indicated by comparing RETURN with OLD.
@@ -350,7 +309,7 @@
 	      case 2: _o_ = (__u16) (long) (old); break;				\
 	      case 4: _o_ = (__u32) (long) (old); break;				\
 	      case 8: _o_ = (__u64) (long) (old); break;				\
-	      default:									\
+	      default: break;								\
 	}										\
 	 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_));				\
 	switch (size) {									\
@@ -439,7 +398,7 @@
 	(last) = ia64_switch_to((next));						\
 } while (0)
 
-#ifdef CONFIG_SMP 
+#ifdef CONFIG_SMP
   /*
    * In the SMP case, we save the fph state when context-switching
    * away from a thread that modified fph.  This way, when the thread
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/timex.h linux/include/asm-ia64/timex.h
--- v2.4.3/linux/include/asm-ia64/timex.h	Sun Feb  6 18:42:40 2000
+++ linux/include/asm-ia64/timex.h	Thu Apr  5 12:51:47 2001
@@ -2,14 +2,15 @@
 #define _ASM_IA64_TIMEX_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+/*
+ * 2001/01/18 davidm	Removed CLOCK_TICK_RATE.  It makes no sense on IA-64.
+ *			Also removed cacheflush_time as it's entirely unused.
  */
-
-#define CLOCK_TICK_RATE		1193180	/* Underlying HZ XXX fix me! */
 
 typedef unsigned long cycles_t;
-extern cycles_t cacheflush_time;
 
 static inline cycles_t
 get_cycles (void)
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/uaccess.h linux/include/asm-ia64/uaccess.h
--- v2.4.3/linux/include/asm-ia64/uaccess.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/uaccess.h	Thu Apr  5 12:51:47 2001
@@ -25,14 +25,16 @@
  * handler checks to see whether the faulting instruction has a fixup
  * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and
  * then resumes execution at the continuation point.
- * 
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/errno.h>
 #include <linux/sched.h>
 
+#include <asm/pgtable.h>
+
 /*
  * For historical reasons, the following macros are grossly misnamed:
  */
@@ -49,16 +51,13 @@
 #define segment_eq(a,b)	((a).seg == (b).seg)
 
 /*
- * When accessing user memory, we need to make sure the entire area
- * really is in user-level space.  In order to do this efficiently, we
- * make sure that the page at address TASK_SIZE is never valid (we do
- * this by selecting VMALLOC_START as TASK_SIZE+PAGE_SIZE).  This way,
- * we can simply check whether the starting address is < TASK_SIZE
- * and, if so, start accessing the memory.  If the user specified bad
- * length, we will fault on the NaT page and then return the
- * appropriate error.
+ * When accessing user memory, we need to make sure the entire area really is in
+ * user-level space.  In order to do this efficiently, we make sure that the page at
+ * address TASK_SIZE is never valid.  We also need to make sure that the address doesn't
+ * point inside the virtually mapped linear page table.
  */
-#define __access_ok(addr,size,segment)	(((unsigned long) (addr)) <= (segment).seg)
+#define __access_ok(addr,size,segment)	(((unsigned long) (addr)) <= (segment).seg		\
+	 && ((segment).seg == KERNEL_DS.seg || rgn_offset((unsigned long) (addr)) < RGN_MAP_LIMIT))
 #define access_ok(type,addr,size)	__access_ok((addr),(size),get_fs())
 
 static inline int
@@ -85,28 +84,28 @@
  */
 #define __put_user(x,ptr)	__put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 #define __get_user(x,ptr)	__get_user_nocheck((x),(ptr),sizeof(*(ptr)))
-  
+
 extern void __get_user_unknown (void);
 
-#define __get_user_nocheck(x,ptr,size)				\
-({								\
-	register long __gu_err __asm__ ("r8") = 0;		\
-	register long __gu_val __asm__ ("r9") = 0;		\
-	switch (size) {						\
-	  case 1: __get_user_8(ptr); break;			\
-	  case 2: __get_user_16(ptr); break;			\
-	  case 4: __get_user_32(ptr); break;			\
-	  case 8: __get_user_64(ptr); break;			\
-	  default: __get_user_unknown(); break;			\
-	}							\
-	(x) = (__typeof__(*(ptr))) __gu_val;			\
-	__gu_err;						\
+#define __get_user_nocheck(x,ptr,size)		\
+({						\
+	register long __gu_err asm ("r8") = 0;	\
+	register long __gu_val asm ("r9") = 0;	\
+	switch (size) {				\
+	  case 1: __get_user_8(ptr); break;	\
+	  case 2: __get_user_16(ptr); break;	\
+	  case 4: __get_user_32(ptr); break;	\
+	  case 8: __get_user_64(ptr); break;	\
+	  default: __get_user_unknown(); break;	\
+	}					\
+	(x) = (__typeof__(*(ptr))) __gu_val;	\
+	__gu_err;				\
 })
 
 #define __get_user_check(x,ptr,size,segment)			\
 ({								\
-	register long __gu_err __asm__ ("r8") = -EFAULT;	\
-	register long __gu_val __asm__ ("r9") = 0;		\
+	register long __gu_err asm ("r8") = -EFAULT;		\
+	register long __gu_val asm ("r9") = 0;			\
 	const __typeof__(*(ptr)) *__gu_addr = (ptr);		\
 	if (__access_ok((long)__gu_addr,size,segment)) {	\
 		__gu_err = 0;					\
@@ -126,46 +125,60 @@
 #define __m(x) (*(struct __large_struct *)(x))
 
 /* We need to declare the __ex_table section before we can use it in .xdata.  */
-__asm__ (".section \"__ex_table\", \"a\"\n\t.previous");
+asm (".section \"__ex_table\", \"a\"\n\t.previous");
+
+#if __GNUC__ >= 3
+#  define GAS_HAS_LOCAL_TAGS	/* define if gas supports local tags a la [1:] */
+#endif
+
+#ifdef GAS_HAS_LOCAL_TAGS
+# define _LL	"[1:]"
+#else
+# define _LL	"1:"
+#endif
 
 #define __get_user_64(addr)									\
-	__asm__ ("\n1:\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n"			\
-		: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
+	asm ("\n"_LL"\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
+	     "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n"				\
+	     _LL										\
+	     : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
 
 #define __get_user_32(addr)									\
-	__asm__ ("\n1:\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n"			\
-		: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
+	asm ("\n"_LL"\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
+	     "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n"				\
+	     _LL										\
+	     : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
 
 #define __get_user_16(addr)									\
-	__asm__ ("\n1:\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n"			\
-		: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
+	asm ("\n"_LL"\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
+	     "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n"				\
+	     _LL										\
+	     : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
 
 #define __get_user_8(addr)									\
-	__asm__ ("\n1:\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n"			\
-		: "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
+	asm ("\n"_LL"\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n"	\
+	     "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n"				\
+	     _LL										\
+	     : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err));
 
 extern void __put_user_unknown (void);
 
-#define __put_user_nocheck(x,ptr,size)				\
-({								\
-	register long __pu_err __asm__ ("r8") = 0;		\
-	switch (size) {						\
-	  case 1: __put_user_8(x,ptr); break;			\
-	  case 2: __put_user_16(x,ptr); break;			\
-	  case 4: __put_user_32(x,ptr); break;			\
-	  case 8: __put_user_64(x,ptr); break;			\
-	  default: __put_user_unknown(); break;			\
-	}							\
-	__pu_err;						\
+#define __put_user_nocheck(x,ptr,size)		\
+({						\
+	register long __pu_err asm ("r8") = 0;	\
+	switch (size) {				\
+	  case 1: __put_user_8(x,ptr); break;	\
+	  case 2: __put_user_16(x,ptr); break;	\
+	  case 4: __put_user_32(x,ptr); break;	\
+	  case 8: __put_user_64(x,ptr); break;	\
+	  default: __put_user_unknown(); break;	\
+	}					\
+	__pu_err;				\
 })
 
 #define __put_user_check(x,ptr,size,segment)			\
 ({								\
-	register long __pu_err __asm__ ("r8") = -EFAULT;	\
+	register long __pu_err asm ("r8") = -EFAULT;		\
 	__typeof__(*(ptr)) *__pu_addr = (ptr);			\
 	if (__access_ok((long)__pu_addr,size,segment)) {	\
 		__pu_err = 0;					\
@@ -186,27 +199,31 @@
  * any memory gcc knows about, so there are no aliasing issues
  */
 #define __put_user_64(x,addr)								\
-	__asm__ __volatile__ (								\
-		 "\n1:\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n"			\
+	asm volatile (									\
+		"\n"_LL"\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
+		"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n"			\
+		_LL									\
 		: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
 
 #define __put_user_32(x,addr)								\
-	__asm__ __volatile__ (								\
-		 "\n1:\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n"			\
+	asm volatile (									\
+		"\n"_LL"\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
+		"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n"			\
+		_LL									\
 		: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
 
 #define __put_user_16(x,addr)								\
-	__asm__ __volatile__ (								\
-		 "\n1:\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n"			\
+	asm volatile (									\
+		"\n"_LL"\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
+		"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n"			\
+		_LL									\
 		: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
 
 #define __put_user_8(x,addr)								\
-	__asm__ __volatile__ (								\
-		 "\n1:\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
-		 "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n"			\
+	asm volatile (									\
+		"\n"_LL"\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n"	\
+		"\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n"			\
+		_LL									\
 		: "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err))
 
 /*
@@ -215,7 +232,7 @@
 extern unsigned long __copy_user (void *to, const void *from, unsigned long count);
 
 #define __copy_to_user(to,from,n)	__copy_user((to), (from), (n))
-#define __copy_from_user(to,from,n) 	__copy_user((to), (from), (n))
+#define __copy_from_user(to,from,n)	__copy_user((to), (from), (n))
 
 #define copy_to_user(to,from,n)   __copy_tofrom_user((to), (from), (n), 1)
 #define copy_from_user(to,from,n) __copy_tofrom_user((to), (from), (n), 0)
@@ -293,10 +310,14 @@
 
 struct exception_table_entry {
 	int addr;	/* gp-relative address of insn this fixup is for */
-	int skip;	/* number of bytes to skip to get to the continuation point.
-			   Bit 0 tells us if r9 should be cleared to 0*/
+	int cont;	/* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */
+};
+
+struct exception_fixup {
+	unsigned long cont;	/* continuation point (bit 2: clear r9 if set) */
 };
 
-extern const struct exception_table_entry *search_exception_table (unsigned long addr);
+extern struct exception_fixup search_exception_table (unsigned long addr);
+extern void handle_exception (struct pt_regs *regs, struct exception_fixup fixup);
 
 #endif /* _ASM_IA64_UACCESS_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/ucontext.h linux/include/asm-ia64/ucontext.h
--- v2.4.3/linux/include/asm-ia64/ucontext.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ia64/ucontext.h	Thu Apr  5 12:51:47 2001
@@ -0,0 +1,12 @@
+#ifndef _ASM_IA64_UCONTEXT_H
+#define _ASM_IA64_UCONTEXT_H
+
+struct ucontext {
+	struct sigcontext uc_mcontext;
+};
+
+#define uc_link		uc_mcontext.sc_gr[0]	/* wrong type; nobody cares */
+#define uc_sigmask	uc_mcontext.sc_sigmask
+#define uc_stack	uc_mcontext.sc_stack
+
+#endif /* _ASM_IA64_UCONTEXT_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/unwind.h linux/include/asm-ia64/unwind.h
--- v2.4.3/linux/include/asm-ia64/unwind.h	Mon Oct  9 17:55:01 2000
+++ linux/include/asm-ia64/unwind.h	Thu Apr  5 12:51:47 2001
@@ -109,22 +109,6 @@
 				 struct switch_stack *sw);
 
 /*
- * Prepare to unwind the current task.  For this to work, the kernel
- * stack identified by REGS must look like this:
- *
- *	//		      //
- *	|		      |
- *	|   kernel stack      |
- *	|		      |
- *	+=====================+
- *	|   struct pt_regs    |
- *	+---------------------+ <--- REGS
- *	| struct switch_stack |
- *	+---------------------+
- */
-extern void unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs);
-
-/*
  * Prepare to unwind the currently running thread.
  */
 extern void unw_init_running (void (*callback)(struct unw_frame_info *info, void *arg), void *arg);
@@ -144,42 +128,42 @@
 
 #define unw_is_intr_frame(info)	(((info)->flags & UNW_FLAG_INTERRUPT_FRAME) != 0)
 
-static inline unsigned long
+static inline int
 unw_get_ip (struct unw_frame_info *info, unsigned long *valp)
 {
 	*valp = (info)->ip;
 	return 0;
 }
 
-static inline unsigned long
+static inline int
 unw_get_sp (struct unw_frame_info *info, unsigned long *valp)
 {
 	*valp = (info)->sp;
 	return 0;
 }
 
-static inline unsigned long
+static inline int
 unw_get_psp (struct unw_frame_info *info, unsigned long *valp)
 {
 	*valp = (info)->psp;
 	return 0;
 }
 
-static inline unsigned long
+static inline int
 unw_get_bsp (struct unw_frame_info *info, unsigned long *valp)
 {
 	*valp = (info)->bsp;
 	return 0;
 }
 
-static inline unsigned long
+static inline int
 unw_get_cfm (struct unw_frame_info *info, unsigned long *valp)
 {
 	*valp = *(info)->cfm_loc;
 	return 0;
 }
 
-static inline unsigned long
+static inline int
 unw_set_cfm (struct unw_frame_info *info, unsigned long val)
 {
 	*(info)->cfm_loc = val;
diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- v2.4.3/linux/include/asm-m68k/bootinfo.h	Wed Jan 26 12:44:21 2000
+++ linux/include/asm-m68k/bootinfo.h	Wed Apr 18 11:49:13 2001
@@ -163,7 +163,7 @@
 #define BI_MAC_SCCTYPE		0x801c	/* Mac SCC serial type (normal, IOP) */
 #define BI_MAC_ETHTYPE		0x801d	/* Mac builtin ethernet type (Sonic, MACE */
 #define BI_MAC_ETHBASE		0x801e	/* Mac builtin ethernet base address */
-#define BI_MAC_PMU		0x801f	/* Mac power managment / poweroff hardware */
+#define BI_MAC_PMU		0x801f	/* Mac power management / poweroff hardware */
 #define BI_MAC_IOP_SWIM		0x8020	/* Mac SWIM floppy IOP */
 #define BI_MAC_IOP_ADB		0x8021	/* Mac ADB IOP */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/mac_iop.h linux/include/asm-m68k/mac_iop.h
--- v2.4.3/linux/include/asm-m68k/mac_iop.h	Sat Sep  4 13:06:41 1999
+++ linux/include/asm-m68k/mac_iop.h	Wed Apr 18 11:49:13 2001
@@ -54,7 +54,7 @@
 #define IOP_MSGSTATUS_COMPLETE	3	/* message complete and reply rcvd */
 #define IOP_MSGSTATUS_UNSOL	6	/* message is unsolicited          */
 
-/* IOP memory addresses of the members of the the mac_iop_kernel structure. */
+/* IOP memory addresses of the members of the mac_iop_kernel structure. */
 
 #define IOP_ADDR_MAX_SEND_CHAN	0x0200
 #define IOP_ADDR_SEND_STATE	0x0201
diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/motorola_pgalloc.h linux/include/asm-m68k/motorola_pgalloc.h
--- v2.4.3/linux/include/asm-m68k/motorola_pgalloc.h	Mon Nov 27 18:00:49 2000
+++ linux/include/asm-m68k/motorola_pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -160,7 +160,7 @@
 	free_pmd_fast((pmd_t *)pgd);
 }
 
-extern inline pgd_t *pgd_alloc(void)
+extern inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *pgd = (pgd_t *)get_pmd_fast();
 	if (!pgd)
diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.4.3/linux/include/asm-m68k/semaphore.h	Mon Jan 31 10:32:53 2000
+++ linux/include/asm-m68k/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -8,6 +8,7 @@
 #include <linux/linkage.h>
 #include <linux/wait.h>
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -185,201 +186,6 @@
 		: "memory");
 }
 
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * m68k version by Roman Zippel
- */
-
-struct rw_semaphore {
-	atomic_t		count;
-	volatile unsigned char	write_bias_granted;
-	volatile unsigned char	read_bias_granted;
-	volatile unsigned char	pad1;
-	volatile unsigned char	pad2;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-	register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
-#if WAITQUEUE_DEBUG
-	if (sem->__magic != (long)&sem->__magic)
-		BUG();
-#endif
-	__asm__ __volatile__(
-		"| atomic down_read operation\n\t"
-		"subql #1,%0@\n\t"
-		"jmi 2f\n"
-		"1:\n"
-		".section .text.lock,\"ax\"\n"
-		".even\n"
-		"2:\n\t"
-		"pea 1b\n\t"
-		"jbra __down_read_failed\n"
-		".previous"
-		: /* no outputs */
-		: "a" (__sem)
-		: "memory");
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-	register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
-#if WAITQUEUE_DEBUG
-	if (sem->__magic != (long)&sem->__magic)
-		BUG();
-#endif
-	__asm__ __volatile__(
-		"| atomic down_write operation\n\t"
-		"subl %1,%0@\n\t"
-		"jne 2f\n"
-		"1:\n"
-		".section .text.lock,\"ax\"\n"
-		".even\n"
-		"2:\n\t"
-		"pea 1b\n\t"
-		"jbra __down_write_failed\n"
-		".previous"
-		: /* no outputs */
-		: "a" (__sem), "id" (RW_LOCK_BIAS)
-		: "memory");
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
-	register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
-	__asm__ __volatile__(
-		"| atomic up_read operation\n\t"
-		"addql #1,%0@\n\t"
-		"jeq 2f\n"
-		"1:\n"
-		".section .text.lock,\"ax\"\n"
-		".even\n"
-		"2:\n\t"
-		"pea 1b\n\t"
-		"jbra __rwsem_wake\n"
-		".previous"
-		: /* no outputs */
-		: "a" (__sem)
-		: "memory");
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
-	register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
-	__asm__ __volatile__(
-		"| atomic up_write operation\n\t"
-		"addl %1,%0@\n\t"
-		"jcs 2f\n"
-		"1:\n"
-		".section .text.lock,\"ax\"\n"
-		".even\n"
-		"2:\n\t"
-		"pea 1b\n\t"
-		"jbra __rwsem_wake\n"
-		".previous"
-		: /* no outputs */
-		: "a" (__sem), "id" (RW_LOCK_BIAS)
-		: "memory");
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
-}
 #endif /* __ASSEMBLY__ */
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- v2.4.3/linux/include/asm-m68k/serial.h	Thu Jan  4 13:00:55 2001
+++ linux/include/asm-m68k/serial.h	Wed Apr 18 11:49:13 2001
@@ -1,7 +1,7 @@
 /*
  * include/asm-m68k/serial.h
  *
- * currently this seems usefull only for a Q40,
+ * currently this seems useful only for a Q40,
  * its an almost exact copy of ../asm/alpha/serial.h 
  *
  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/sun3_pgalloc.h linux/include/asm-m68k/sun3_pgalloc.h
--- v2.4.3/linux/include/asm-m68k/sun3_pgalloc.h	Mon Nov 27 18:00:49 2000
+++ linux/include/asm-m68k/sun3_pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -134,7 +134,7 @@
         free_page((unsigned long) pgd);
 }
 
-extern inline pgd_t * pgd_alloc(void)
+extern inline pgd_t * pgd_alloc(struct mm_struct *mm)
 {
      pgd_t *new_pgd;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/bootinfo.h linux/include/asm-mips/bootinfo.h
--- v2.4.3/linux/include/asm-mips/bootinfo.h	Tue Jul 11 11:15:02 2000
+++ linux/include/asm-mips/bootinfo.h	Fri Apr 13 20:26:07 2001
@@ -1,16 +1,13 @@
-/* $Id: bootinfo.h,v 1.11 2000/03/06 11:14:32 raiko Exp $
- *
- * bootinfo.h -- Definition of the Linux/MIPS boot information structure
- *
- * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse,
- *                             Stoned Elipot and Paul M. Antoine.
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
+ *
+ * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse,
+ *                             Stoned Elipot and Paul M. Antoine.
  */
-#ifndef __ASM_MIPS_BOOTINFO_H
-#define __ASM_MIPS_BOOTINFO_H
+#ifndef _ASM_BOOTINFO_H
+#define _ASM_BOOTINFO_H
 
 /*
  * Values for machgroup
@@ -105,8 +102,9 @@
  * Valid machtype for group NEC DDB
  */
 #define MACH_NEC_DDB5074	 0	/* NEC DDB Vrc-5074 */
+#define MACH_NEC_DDB5476         1      /* NEC DDB Vrc-5476 */
 
-#define GROUP_NEC_DDB_NAMES { "Vrc-5074" }
+#define GROUP_NEC_DDB_NAMES { "Vrc-5074", "Vrc-5476"}
 
 /*
  * Valid machtype for group BAGET
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172.h linux/include/asm-mips/it8172/it8172.h
--- v2.4.3/linux/include/asm-mips/it8172/it8172.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8172/it8172.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,406 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172 system controller defines.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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 __IT8172__H__
+#define __IT8172__H__
+
+#include <asm/addrspace.h>
+
+#define IT8172_BASE			0x18000000	
+#define IT8172_PCI_IO_BASE		0x14000000
+#define IT8172_PCI_MEM_BASE		0x10000000
+
+// System registers offsets from IT8172_BASE
+#define IT_CMFPCR			0x0
+#define IT_DSRR				0x2
+#define IT_PCDCR			0x4
+#define IT_SPLLCR			0x6
+#define IT_CIDR				0x10
+#define IT_CRNR				0x12
+#define IT_CPUTR			0x14
+#define IT_CTCR				0x16
+#define IT_SDPR				0xF0
+
+// Power management register offset from IT8172_PCI_IO_BASE
+// Power Management Device Standby Register
+#define IT_PM_DSR		0x15800
+
+#define IT_PM_DSR_TMR0SB	0x0001
+#define IT_PM_DSR_TMR1SB	0x0002
+#define IT_PM_DSR_CIR0SB	0x0004
+#define IT_PM_DSR_CIR1SB	0x0008
+#define IT_PM_DSR_SCR0SB	0x0010
+#define IT_PM_DSR_SCR1SB	0x0020
+#define IT_PM_DSR_PPSB		0x0040
+#define IT_PM_DSR_I2CSB		0x0080
+#define IT_PM_DSR_UARTSB	0x0100
+#define IT_PM_DSR_IDESB		0x0200
+#define IT_PM_DSR_ACSB		0x0400
+#define IT_PM_DSR_M68KSB	0x0800
+
+// Power Management PCI Device Software Reset Register
+#define IT_PM_PCISR             0x15802
+
+#define IT_PM_PCISR_IDESR       0x0001
+#define IT_PM_PCISR_CDMASR      0x0002
+#define IT_PM_PCISR_USBSR       0x0004
+#define IT_PM_PCISR_DMASR       0x0008
+#define IT_PM_PCISR_ACSR        0x0010
+#define IT_PM_PCISR_MEMSR       0x0020
+#define IT_PM_PCISR_68KSR       0x0040
+
+
+// PCI Configuration address and data register offsets
+// from IT8172_BASE
+#define IT_CONFADDR			0x4000
+#define IT_BUSNUM_SHF                   16
+#define IT_DEVNUM_SHF                   11
+#define IT_FUNCNUM_SHF                  8
+#define IT_REGNUM_SHF                   2
+
+#define IT_CONFDATA			0x4004
+
+// PCI configuration header common register offsets
+#define IT_VID				0x00
+#define IT_DID				0x02
+#define IT_PCICMD			0x04
+#define IT_PCISTS			0x06
+#define IT_RID				0x08
+#define IT_CLASSC			0x09
+#define IT_HEADT			0x0E
+#define IT_SERIRQC			0x49
+
+// PCI to Internal/LPC Bus Bridge configuration header register offset
+#define IT_P2I_BCR				0x4C
+#define IT_P2I_D0IOSC				0x50 
+#define IT_P2I_D1IOSC				0x54
+#define IT_P2I_D2IOSC				0x58 
+#define IT_P2I_D3IOSC				0x5C 
+#define IT_P2I_D4IOSC				0x60 
+#define IT_P2I_D5IOSC				0x64 
+#define IT_P2I_D6IOSC				0x68 
+#define IT_P2I_D7IOSC				0x6C 
+#define IT_P2I_D8IOSC				0x70 
+#define IT_P2I_D9IOSC				0x74 
+#define IT_P2I_D10IOSC				0x78 
+#define IT_P2I_D11IOSC				0x7C 
+
+// Memory controller register offsets from IT8172_BASE
+#define IT_MC_SDRMR					0x1000
+#define IT_MC_SDRTR					0x1004
+#define IT_MC_MCR					0x1008
+#define IT_MC_SDTYPE					0x100C
+#define IT_MC_WPBA					0x1010
+#define IT_MC_WPTA					0x1014
+#define IT_MC_HATR					0x1018
+#define IT_MC_PCICR					0x101C
+
+// Flash/ROM control register offsets from IT8172_BASE
+#define IT_FC_BRCR					0x2000
+#define IT_FC_FCR					0x2004
+#define IT_FC_DCR					0x2008
+
+// M68K interface bridge configuration header register offset
+#define IT_M68K_MBCSR					0x54
+#define IT_M68K_TMR					0x58
+#define IT_M68K_BCR					0x5C
+#define IT_M68K_BSR					0x5D
+#define IT_M68K_DTR					0x5F
+
+// Register offset from IT8172_PCI_IO_BASE 
+// These registers are accessible through 8172 PCI IO window.
+
+// INTC 
+#define IT_INTC_BASE				0x10000
+#define IT_INTC_LBDNIRR				0x10000
+#define IT_INTC_LBDNIMR				0x10002
+#define IT_INTC_LBDNITR				0x10004
+#define IT_INTC_LBDNIAR				0x10006
+#define IT_INTC_LPCNIRR				0x10010
+#define IT_INTC_LPCNIMR				0x10012
+#define IT_INTC_LPCNITR				0x10014
+#define IT_INTC_LPCNIAR				0x10016
+#define IT_INTC_PDNIRR				0x10020
+#define IT_INTC_PDNIMR				0x10022
+#define IT_INTC_PDNITR				0x10024
+#define IT_INTC_PDNIAR				0x10026
+#define IT_INTC_UMNIRR				0x10030
+#define IT_INTC_UMNITR				0x10034
+#define IT_INTC_UMNIAR				0x10036
+#define IT_INTC_TYPER				0x107FE
+
+// IT8172 PCI device number
+#define IT_C2P_DEVICE				0
+#define IT_AUDIO_DEVICE				1
+#define IT_DMAC_DEVICE				1
+#define IT_CDMAC_DEVICE				1
+#define IT_USB_DEVICE				1
+#define IT_P2I_DEVICE				1
+#define IT_IDE_DEVICE				1
+#define IT_M68K_DEVICE				1
+
+// IT8172 PCI function number
+#define IT_C2P_FUNCION				0
+#define IT_AUDIO_FUNCTION			0
+#define IT_DMAC_FUNCTION			1
+#define IT_CDMAC_FUNCTION			2
+#define IT_USB_FUNCTION				3
+#define IT_P2I_FUNCTION				4
+#define IT_IDE_FUNCTION				5
+#define IT_M68K_FUNCTION			6
+
+// IT8172 GPIO
+#define IT_GPADR				0x13800
+#define IT_GPBDR				0x13808
+#define IT_GPCDR				0x13810
+#define IT_GPACR				0x13802
+#define IT_GPBCR				0x1380A
+#define IT_GPCCR				0x13812
+#define IT_GPAICR				0x13804
+#define IT_GPBICR				0x1380C
+#define IT_GPCICR				0x13814
+#define IT_GPAISR				0x13806
+#define IT_GPBISR				0x1380E
+#define IT_GPCISR				0x13816
+#define IT_GCR					0x13818
+
+// IT8172 RTC
+#define IT_RTC_BASE				0x14800
+#define IT_RTC_RIR0				0x00
+#define IT_RTC_RTR0				0x01
+#define IT_RTC_RIR1				0x02
+#define IT_RTC_RTR1				0x03
+#define IT_RTC_RIR2				0x04
+#define IT_RTC_RTR2				0x05
+#define IT_RTC_RCTR				0x08
+#define IT_RTC_RA				0x0A
+#define IT_RTC_RB				0x0B
+#define IT_RTC_RC				0x0C
+#define IT_RTC_RD				0x0D
+
+#define RTC_SEC_INDEX				0x00
+#define RTC_MIN_INDEX				0x02
+#define RTC_HOUR_INDEX				0x04
+#define RTC_DAY_INDEX				0x06
+#define RTC_DATE_INDEX				0x07
+#define RTC_MONTH_INDEX				0x08
+#define RTC_YEAR_INDEX				0x09
+
+// IT8172 internal device registers
+#define IT_TIMER_BASE				0x10800
+#define IT_CIR0_BASE				0x11000
+#define IT_UART_BASE				0x11800
+#define IT_SCR0_BASE				0x12000
+#define IT_SCR1_BASE				0x12800
+#define IT_PP_BASE				0x13000
+#define IT_I2C_BASE				0x14000
+#define IT_CIR1_BASE				0x15000
+
+// IT8172 Smart Card Reader offsets from IT_SCR*_BASE
+#define IT_SCR_SFR				0x08
+#define IT_SCR_SCDR				0x09
+
+// IT8172 IT_SCR_SFR bit definition & mask
+#define	IT_SCR_SFR_GATE_UART			0x40
+#define	IT_SCR_SFR_GATE_UART_BIT		6
+#define IT_SCR_SFR_GATE_UART_OFF		0
+#define	IT_SCR_SFR_GATE_UART_ON			1
+#define	IT_SCR_SFR_FET_CHARGE			0x30
+#define	IT_SCR_SFR_FET_CHARGE_BIT		4
+#define IT_SCR_SFR_FET_CHARGE_3_3_US		3
+#define IT_SCR_SFR_FET_CHARGE_13_US		2
+#define IT_SCR_SFR_FET_CHARGE_53_US		1
+#define IT_SCR_SFR_FET_CHARGE_213_US		0
+#define	IT_SCR_SFR_CARD_FREQ			0x0C
+#define	IT_SCR_SFR_CARD_FREQ_BIT		2
+#define IT_SCR_SFR_CARD_FREQ_STOP		3
+#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ		0
+#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ		2
+#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ		1
+#define	IT_SCR_SFR_FET_ACTIVE			0x02
+#define	IT_SCR_SFR_FET_ACTIVE_BIT		1
+#define IT_SCR_SFR_FET_ACTIVE_INVERT		0
+#define IT_SCR_SFR_FET_ACTIVE_NONINVERT		1
+#define	IT_SCR_SFR_ENABLE			0x01
+#define	IT_SCR_SFR_ENABLE_BIT			0
+#define IT_SCR_SFR_ENABLE_OFF			0
+#define IT_SCR_SFR_ENABLE_ON			1
+
+// IT8172 IT_SCR_SCDR bit definition & mask
+#define	IT_SCR_SCDR_RESET_MODE			0x80
+#define	IT_SCR_SCDR_RESET_MODE_BIT		7
+#define	IT_SCR_SCDR_RESET_MODE_ASYNC		0
+#define IT_SCR_SCDR_RESET_MODE_SYNC		1
+#define	IT_SCR_SCDR_DIVISOR			0x7F
+#define	IT_SCR_SCDR_DIVISOR_BIT			0
+#define	IT_SCR_SCDR_DIVISOR_STOP_VAL_1		0x00
+#define	IT_SCR_SCDR_DIVISOR_STOP_VAL_2		0x01
+#define	IT_SCR_SCDR_DIVISOR_STOP_VAL_3		0x7F
+
+// IT8172 DMA
+#define IT_DMAC_BASE				0x16000
+#define IT_DMAC_BCAR0				0x00
+#define IT_DMAC_BCAR1				0x04
+#define IT_DMAC_BCAR2				0x08
+#define IT_DMAC_BCAR3				0x0C
+#define IT_DMAC_BCCR0				0x02
+#define IT_DMAC_BCCR1				0x06
+#define IT_DMAC_BCCR2				0x0a
+#define IT_DMAC_BCCR3				0x0e
+#define IT_DMAC_CR				0x10
+#define IT_DMAC_SR				0x12
+#define IT_DMAC_ESR				0x13
+#define IT_DMAC_RQR				0x14
+#define IT_DMAC_MR				0x16
+#define IT_DMAC_EMR				0x17
+#define IT_DMAC_MKR				0x18
+#define IT_DMAC_PAR0				0x20
+#define IT_DMAC_PAR1				0x22
+#define IT_DMAC_PAR2				0x24
+#define IT_DMAC_PAR3				0x26
+
+// IT8172 IDE
+#define IT_IDE_BASE				0x17800
+#define IT_IDE_STATUS				0x1F7
+
+// IT8172 Audio Controller
+#define IT_AC_BASE				0x17000
+#define	IT_AC_PCMOV				0x00
+#define IT_AC_FMOV				0x02
+#define	IT_AC_I2SV				0x04
+#define IT_AC_DRSS				0x06
+#define IT_AC_PCC				0x08
+#define IT_AC_PCDL				0x0A
+#define IT_AC_PCB1STA				0x0C
+#define IT_AC_PCB2STA				0x10
+#define IT_AC_CAPCC				0x14
+#define IT_AC_CAPCDL				0x16
+#define IT_AC_CAPB1STA				0x18
+#define IT_AC_CAPB2STA				0x1C
+#define IT_AC_CODECC				0x22
+#define IT_AC_I2SMC				0x24
+#define IT_AC_VS				0x26
+#define IT_AC_SRCS				0x28
+#define IT_AC_CIRCP				0x2A
+#define IT_AC_CIRDP				0x2C
+#define IT_AC_TM				0x4A
+#define IT_AC_PFDP				0x4C
+#define IT_AC_GC				0x54
+#define IT_AC_IMC				0x56
+#define IT_AC_ISC				0x5B
+#define IT_AC_OPL3SR				0x68
+#define IT_AC_OPL3DWDR				0x69
+#define IT_AC_OPL3AB1W				0x6A
+#define IT_AC_OPL3DW				0x6B
+#define IT_AC_BPDC				0x70
+
+// Audio : IT_AC_PCC bit definition & mask
+#define	PCC_SM					0x8000
+#define	PCC_SM_BIT				15
+#define	PCC_SM_STEREO				1
+#define PCC_SM_MONO				0
+
+#define	PCC_DF					0x4000
+#define PCC_DF_BIT				14
+#define	PCC_DF_8				0
+#define PCC_DF_16				1
+
+#define	PCC_CF					0x3000
+#define PCC_CF_BIT				12
+#define	PCC_CF_2				0
+#define PCC_CF_4				1
+#define PCC_CF_6				2
+
+#define PCC_SR					0x0F00
+#define PCC_SR_BIT				8
+#define	PCC_SR_5500				0
+#define	PCC_SR_8000				1
+#define	PCC_SR_9600				2
+#define	PCC_SR_11025				3
+#define	PCC_SR_16000				4
+#define	PCC_SR_19200				5
+#define	PCC_SR_22050				6
+#define	PCC_SR_32000				7
+#define	PCC_SR_38400				8
+#define	PCC_SR_44100				9
+#define	PCC_SR_48000				10
+
+#define PCC_CSP					0x0080
+#define PCC_CSP_BIT				7
+#define PCC_CSP_STOP				0
+#define PCC_CSP_STOP_NOW			1
+
+#define PCC_CP					0x0040
+#define	PCC_CP_BIT				6
+#define PCC_CP_NORMAL				0
+#define PCC_CP_PAUSE				1
+
+#define PCC_CA					0x0020
+#define PCC_CA_BIT				5
+#define PCC_CA_NO_START				0
+#define PCC_CA_START				1
+
+#define PCC_CB2L				0x0004
+#define PCC_CB2L_BIT				2
+#define PCC_CB2L_NO				0
+#define PCC_CB2L_YES				1
+
+#define PCC_CB1L				0x0002
+#define PCC_CB1L_BIT				1
+#define PCC_CB1L_NO				0
+#define PCC_CB1L_YES				1
+
+#define PCC_DE					0x0001
+#define PCC_DE_BIT				0
+#define PCC_DE_NOT_EMPTY			0
+#define PCC_DE_EMPTY				1
+
+// IT8172 Timer
+#define IT_TIMER_BASE				0x10800
+#define	TIMER_TCVR0				0x00
+#define TIMER_TRVR0				0x02
+#define	TIMER_TCR0				0x04
+#define TIMER_TIRR				0x06
+#define	TIMER_TCVR1				0x08
+#define TIMER_TRVR1				0x0A
+#define	TIMER_TCR1				0x0C
+#define TIMER_TIDR				0x0E
+
+
+#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data
+#define IT_READ(ofs, data)  data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs))
+
+#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
+#define IT_IO_READ(ofs, data)  data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
+
+#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
+#define IT_IO_READ16(ofs, data)  data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_cir.h linux/include/asm-mips/it8172/it8172_cir.h
--- v2.4.3/linux/include/asm-mips/it8172/it8172_cir.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8172/it8172_cir.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,140 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172 Consumer IR port defines.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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 NUM_CIR_PORTS 2
+
+/* Master Control Register */
+#define CIR_RESET              0x1
+#define CIR_FIFO_CLEAR         0x2
+#define CIR_SET_FIFO_TL(x)     (((x)&0x3)<<2)
+#define CIR_ILE                0x10
+#define CIR_ILSEL              0x20
+
+/* Interrupt Enable Register */
+#define CIR_TLDLIE             0x1
+#define CIR_RDAIE              0x2
+#define CIR_RFOIE              0x4
+#define CIR_IEC                0x80
+
+/* Interrupt Identification Register */
+#define CIR_TLDLI              0x1
+#define CIR_RDAI               0x2
+#define CIR_RFOI               0x4
+#define CIR_NIP                0x80
+
+/* Carrier Frequency Register */
+#define CIR_SET_CF(x)          ((x)&0x1f)
+  #define CFQ_38_480           0xB       /* 38 KHz low, 480 KHz high */
+#define CIR_HCFS               0x20
+  #define CIR_SET_HS(x)        (((x)&0x1)<<5)
+    
+
+/* Receiver Control Register */
+#define CIR_SET_RXDCR(x)       ((x)&0x7)
+#define CIR_RXACT              0x8
+#define CIR_RXEND              0x10
+#define CIR_RDWOS              0x20
+  #define CIR_SET_RDWOS(x)     (((x)&0x1)<<5)
+#define CIR_RXEN               0x80
+
+/* Transmitter Control Register */
+#define CIR_SET_TXMPW(x)       ((x)&0x7)
+#define CIR_SET_TXMPM(x)       (((x)&0x3)<<3)
+#define CIR_TXENDF             0x20
+#define CIR_TXRLE              0x40
+
+/* Receiver FIFO Status Register */
+#define CIR_RXFBC_MASK         0x3f
+#define CIR_RXFTO              0x80
+
+/* Wakeup Code Length Register */
+#define CIR_SET_WCL            ((x)&0x3f)
+#define CIR_WCL_MASK(x)        ((x)&0x3f)
+
+/* Wakeup Power Control/Status Register */
+#define CIR_BTMON              0x2
+#define CIR_CIRON              0x4
+#define CIR_RCRST              0x10
+#define CIR_WCRST              0x20
+
+struct cir_port {
+	int port;
+	unsigned short baud_rate;
+	unsigned char fifo_tl;
+	unsigned char cfq;
+	unsigned char hcfs;
+	unsigned char rdwos;
+	unsigned char rxdcr;
+};
+
+struct it8172_cir_regs {
+	unsigned char dr;       /* data                        */
+	char pad;
+	unsigned char mstcr;    /* master control              */
+	char pad1;
+	unsigned char ier;      /* interrupt enable            */
+	char pad2;
+	unsigned char iir;      /* interrupt identification    */
+	char pad3;
+	unsigned char cfr;      /* carrier frequency           */
+	char pad4;
+	unsigned char rcr;      /* receiver control            */
+	char pad5;
+	unsigned char tcr;      /* transmitter control         */
+	char pad6;
+	char pad7;
+	char pad8;
+	unsigned char bdlr;     /* baud rate divisor low byte  */
+	char pad9;
+	unsigned char bdhr;     /* baud rate divisor high byte */
+	char pad10;
+	unsigned char tfsr;     /* tx fifo byte count          */
+	char pad11;
+	unsigned char rfsr;     /* rx fifo status              */
+	char pad12;
+	unsigned char wcl;      /* wakeup code length          */
+	char pad13;
+	unsigned char wcr;      /* wakeup code read/write      */
+	char pad14;
+	unsigned char wps;      /* wakeup power control/status */
+};
+
+int cir_port_init(struct cir_port *cir);
+extern void clear_fifo(struct cir_port *cir);
+extern void enable_receiver(struct cir_port *cir);
+extern void disable_receiver(struct cir_port *cir);
+extern void enable_rx_demodulation(struct cir_port *cir);
+extern void disable_rx_demodulation(struct cir_port *cir);
+extern void set_rx_active(struct cir_port *cir);
+extern void int_enable(struct cir_port *cir);
+extern void rx_int_enable(struct cir_port *cir);
+extern char get_int_status(struct cir_port *cir);
+extern int cir_get_rx_count(struct cir_port *cir);
+extern char cir_read_data(struct cir_port *cir);
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_dbg.h linux/include/asm-mips/it8172/it8172_dbg.h
--- v2.4.3/linux/include/asm-mips/it8172/it8172_dbg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8172/it8172_dbg.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,38 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Function prototypes for low level uart routines to 
+ *	directly access a 16550 uart.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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/types.h>
+
+extern void putch(const unsigned char c);
+extern void puts(unsigned char *cp);
+extern void fputs(unsigned char *cp);
+extern void put64(uint64_t ul);
+extern void put32(unsigned u);
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_int.h linux/include/asm-mips/it8172/it8172_int.h
--- v2.4.3/linux/include/asm-mips/it8172/it8172_int.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8172/it8172_int.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,146 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	ITE 8172 Interrupt Numbering
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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 _MIPS_ITEINT_H
+#define _MIPS_ITEINT_H
+
+/*
+ * Here's the "strategy":
+ * We number the LPC serial irqs from 0 to 15,
+ * the local bus irqs from 16 to 31,
+ * the pci dev register interrupts from 32 to 47,
+ * and the non-maskable ints from 48 to 53.
+ */
+
+#define IT8172_LPC_IRQ_BASE  0    /* first LPC int number */
+#define IT8172_SERIRQ_0      (IT8172_LPC_IRQ_BASE + 0)
+#define IT8172_SERIRQ_1      (IT8172_LPC_IRQ_BASE + 1)
+#define IT8172_SERIRQ_2      (IT8172_LPC_IRQ_BASE + 2)
+#define IT8172_SERIRQ_3      (IT8172_LPC_IRQ_BASE + 3)
+#define IT8172_SERIRQ_4      (IT8172_LPC_IRQ_BASE + 4)
+#define IT8172_SERIRQ_5      (IT8172_LPC_IRQ_BASE + 5)
+#define IT8172_SERIRQ_6      (IT8172_LPC_IRQ_BASE + 6)
+#define IT8172_SERIRQ_7      (IT8172_LPC_IRQ_BASE + 7)
+#define IT8172_SERIRQ_8      (IT8172_LPC_IRQ_BASE + 8)
+#define IT8172_SERIRQ_9      (IT8172_LPC_IRQ_BASE + 9)
+#define IT8172_SERIRQ_10     (IT8172_LPC_IRQ_BASE + 10)
+#define IT8172_SERIRQ_11     (IT8172_LPC_IRQ_BASE + 11)
+#define IT8172_SERIRQ_12     (IT8172_LPC_IRQ_BASE + 12)
+#define IT8172_SERIRQ_13     (IT8172_LPC_IRQ_BASE + 13)
+#define IT8172_SERIRQ_14     (IT8172_LPC_IRQ_BASE + 14)
+#define IT8172_SERIRQ_15     (IT8172_LPC_IRQ_BASE + 15)
+
+#define IT8172_LB_IRQ_BASE  16   /* first local bus int number */
+#define IT8172_PPR_IRQ          (IT8172_LB_IRQ_BASE + 0) /* parallel port */
+#define IT8172_TIMER0_IRQ       (IT8172_LB_IRQ_BASE + 1)
+#define IT8172_TIMER1_IRQ       (IT8172_LB_IRQ_BASE + 2)
+#define IT8172_I2C_IRQ          (IT8172_LB_IRQ_BASE + 3)
+#define IT8172_GPIO_IRQ         (IT8172_LB_IRQ_BASE + 4)
+#define IT8172_CIR0_IRQ         (IT8172_LB_IRQ_BASE + 5)
+#define IT8172_CIR1_IRQ         (IT8172_LB_IRQ_BASE + 6)
+#define IT8172_UART_IRQ         (IT8172_LB_IRQ_BASE + 7)
+#define IT8172_SCR0_IRQ         (IT8172_LB_IRQ_BASE + 8)
+#define IT8172_SCR1_IRQ         (IT8172_LB_IRQ_BASE + 9)
+#define IT8172_RTC_IRQ          (IT8172_LB_IRQ_BASE + 10)
+#define IT8172_IOCHK_IRQ        (IT8172_LB_IRQ_BASE + 11)
+/* 12 - 15 reserved */
+
+/*
+ * Note here that the pci dev registers includes bits for more than
+ * just the pci devices.
+ */
+#define IT8172_PCI_DEV_IRQ_BASE  32   /* first pci dev irq */
+#define IT8172_AC97_IRQ          (IT8172_PCI_DEV_IRQ_BASE + 0)
+#define IT8172_MC68K_IRQ         (IT8172_PCI_DEV_IRQ_BASE + 1)
+#define IT8172_IDE_IRQ           (IT8172_PCI_DEV_IRQ_BASE + 2)
+#define IT8172_USB_IRQ           (IT8172_PCI_DEV_IRQ_BASE + 3)
+#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4)
+#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5)
+#define IT8172_PCI_INTA_IRQ      (IT8172_PCI_DEV_IRQ_BASE + 6)
+#define IT8172_PCI_INTB_IRQ      (IT8172_PCI_DEV_IRQ_BASE + 7)
+#define IT8172_PCI_INTC_IRQ      (IT8172_PCI_DEV_IRQ_BASE + 8)
+#define IT8172_PCI_INTD_IRQ      (IT8172_PCI_DEV_IRQ_BASE + 9)
+#define IT8172_S_INTA_IRQ        (IT8172_PCI_DEV_IRQ_BASE + 10)
+#define IT8172_S_INTB_IRQ        (IT8172_PCI_DEV_IRQ_BASE + 11)
+#define IT8172_S_INTC_IRQ        (IT8172_PCI_DEV_IRQ_BASE + 12)
+#define IT8172_S_INTD_IRQ        (IT8172_PCI_DEV_IRQ_BASE + 13)
+#define IT8172_CDMA_IRQ          (IT8172_PCI_DEV_IRQ_BASE + 14)
+#define IT8172_DMA_IRQ           (IT8172_PCI_DEV_IRQ_BASE + 15)
+
+#define IT8172_NMI_IRQ_BASE      48
+#define IT8172_SER_NMI_IRQ       (IT8172_NMI_IRQ_BASE + 0)
+#define IT8172_PCI_NMI_IRQ       (IT8172_NMI_IRQ_BASE + 1)
+#define IT8172_RTC_NMI_IRQ       (IT8172_NMI_IRQ_BASE + 2)
+#define IT8172_CPUIF_NMI_IRQ     (IT8172_NMI_IRQ_BASE + 3)
+#define IT8172_PMER_NMI_IRQ      (IT8172_NMI_IRQ_BASE + 4)
+#define IT8172_POWER_NMI_IRQ     (IT8172_NMI_IRQ_BASE + 5)
+
+/* Finally, let's move over here the mips cpu timer interrupt.
+ * This is more or less strictly for statistics.
+ */
+#define MIPS_CPU_TIMER_IRQ       (IT8172_NMI_IRQ_BASE + 6)
+
+#define IT8172_INT_END           MIPS_CPU_TIMER_IRQ
+
+/* 
+ * IT8172 Interrupt Controller Registers
+ */
+struct it8172_intc_regs {
+        volatile unsigned short lb_req;      /* offset 0 */
+        volatile unsigned short lb_mask;
+        volatile unsigned short lb_trigger;
+        volatile unsigned short lb_level;
+	unsigned char pad0[8];
+
+        volatile unsigned short lpc_req;     /* offset 0x10 */
+        volatile unsigned short lpc_mask;
+        volatile unsigned short lpc_trigger;
+        volatile unsigned short lpc_level;
+	unsigned char pad1[8];
+
+        volatile unsigned short pci_req;     /* offset 0x20 */
+        volatile unsigned short pci_mask;
+        volatile unsigned short pci_trigger;
+        volatile unsigned short pci_level;
+	unsigned char pad2[8];
+
+        volatile unsigned short nmi_req;     /* offset 0x30 */
+        volatile unsigned short nmi_mask;
+        volatile unsigned short nmi_trigger;
+        volatile unsigned short nmi_level;
+	unsigned char pad3[6];
+
+        volatile unsigned short nmi_redir;   /* offset 0x3E */
+	unsigned char pad4[0xBE];
+
+        volatile unsigned short intstatus;    /* offset 0xFE */
+};
+
+#endif /* _MIPS_ITEINT_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_lpc.h linux/include/asm-mips/it8172/it8172_lpc.h
--- v2.4.3/linux/include/asm-mips/it8172/it8172_lpc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8172/it8172_lpc.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,29 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172 system controller defines.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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.
+ */
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_pci.h linux/include/asm-mips/it8172/it8172_pci.h
--- v2.4.3/linux/include/asm-mips/it8172/it8172_pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8172/it8172_pci.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,108 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IT8172 system controller specific pci defines.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or support@mvista.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  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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 _8172PCI_H_
+#define _8172PCI_H_
+
+// PCI configuration space Type0
+#define	PCI_IDREG	0x00
+#define	PCI_CMDSTSREG	0x04
+#define	PCI_CLASSREG	0x08
+#define	PCI_BHLCREG	0x0C
+#define	PCI_BASE1REG	0x10
+#define	PCI_BASE2REG	0x14
+#define	PCI_BASE3REG	0x18
+#define	PCI_BASE4REG	0x1C
+#define	PCI_BASE5REG	0x20
+#define	PCI_BASE6REG	0x24
+#define	PCI_ROMBASEREG	0x30
+#define	PCI_INTRREG	0x3C
+
+// PCI configuration space Type1
+#define	PCI_BUSNOREG	0x18
+
+#define	IT_PCI_VENDORID(x)	((x) & 0xFFFF)
+#define	IT_PCI_DEVICEID(x)	(((x)>>16) & 0xFFFF)
+
+// Command register
+#define	PCI_CMD_IOEN		0x00000001
+#define	PCI_CMD_MEMEN		0x00000002
+#define	PCI_CMD_BUSMASTER	0x00000004
+#define	PCI_CMD_SPCYCLE		0x00000008
+#define	PCI_CMD_WRINV		0x00000010
+#define	PCI_CMD_VGASNOOP	0x00000020
+#define	PCI_CMD_PERR		0x00000040
+#define	PCI_CMD_WAITCTRL	0x00000080
+#define	PCI_CMD_SERR		0x00000100
+#define	PCI_CMD_FAST_BACKTOBACK	0x00000200
+
+// Status register
+#define	PCI_STS_66MHZ		0x00200000
+#define	PCI_STS_SUPPORT_UDF	0x00400000
+#define	PCI_STS_FAST_BACKTOBACK	0x00800000
+#define	PCI_STS_DATA_PERR	0x01000000
+#define	PCI_STS_DEVSEL0		0x02000000
+#define	PCI_STS_DEVSEL1		0x04000000
+#define	PCI_STS_SIG_TGTABORT	0x08000000
+#define	PCI_STS_RCV_TGTABORT	0x10000000
+#define	PCI_STS_RCV_MSTABORT	0x20000000
+#define	PCI_STS_SYSERR		0x40000000
+#define	PCI_STS_DETCT_PERR	0x80000000
+
+#define	IT_PCI_CLASS(x)		(((x)>>24) & 0xFF)
+#define	IT_PCI_SUBCLASS(x)		(((x)>>16) & 0xFF)
+#define	IT_PCI_INTERFACE(x)	(((x)>>8) & 0xFF)
+#define	IT_PCI_REVISION(x)		((x) & 0xFF)
+
+// PCI class code
+#define	PCI_CLASS_BRIDGE			0x06
+
+// bridge subclass
+#define	PCI_SUBCLASS_BRIDGE_HOST		0x00
+#define	PCI_SUBCLASS_BRIDGE_PCI			0x04
+
+// BHLCREG
+#define	IT_PCI_BIST(x)		(((x)>>24) & 0xFF)
+#define	IT_PCI_HEADERTYPE(x)	(((x)>>16) & 0xFF)
+#define	IT_PCI_LATENCYTIMER(x)	(((x)>>8) & 0xFF)
+#define	IT_PCI_CACHELINESIZE(x)	((x) & 0xFF)
+
+#define	PCI_MULTIFUNC	0x80
+
+// INTRREG
+#define	IT_PCI_MAXLAT(x)		(((x)>>24) & 0xFF)
+#define	IT_PCI_MINGNT(x)		(((x)>>16) & 0xFF)
+#define	IT_PCI_INTRPIN(x)		(((x)>>8) & 0xFF)
+#define	IT_PCI_INTRLINE(x)		((x) & 0xFF)
+
+#define	PCI_VENDOR_NEC	0x1033
+#define PCI_VENDOR_DEC	0x1101
+
+#endif // _8172PCI_H_
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8712.h linux/include/asm-mips/it8712.h
--- v2.4.3/linux/include/asm-mips/it8712.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/it8712.h	Fri Apr 13 20:26:07 2001
@@ -0,0 +1,28 @@
+
+#ifndef __IT8712_H__
+#define __IT8712_H__
+
+#define LPC_BASE_ADDR	0x14000000
+
+// MB PnP configuration register 
+#define LPC_KEY_ADDR	0x1400002E
+#define LPC_DATA_ADDR	0x1400002F
+
+// Device LDN
+#define LDN_SERIAL1	0x01
+#define LDN_SERIAL2	0x02
+#define LDN_PARALLEL	0x03
+#define LDN_KEYBOARD	0x05
+#define LDN_MOUSE	0x06
+
+#define IT8712_UART1_PORT      0x3F8
+#define IT8712_UART2_PORT      0x2F8
+
+#ifndef ASM_ONLY
+
+void LPCSetConfig(char LdnNumber, char Index, char data);
+char LPCGetConfig(char LdnNumber, char Index);
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h
--- v2.4.3/linux/include/asm-mips/keyboard.h	Sun Jul  9 22:18:15 2000
+++ linux/include/asm-mips/keyboard.h	Fri Apr 13 20:26:07 2001
@@ -45,7 +45,7 @@
 	void (*kbd_request_region)(void);
 	int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
 
-	/* PSaux driver resource managment  */
+	/* PSaux driver resource management  */
 	int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
 	void (*aux_free_irq)(void);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/mipsregs.h linux/include/asm-mips/mipsregs.h
--- v2.4.3/linux/include/asm-mips/mipsregs.h	Sun Jul  9 22:18:15 2000
+++ linux/include/asm-mips/mipsregs.h	Fri Apr 13 20:26:07 2001
@@ -292,7 +292,7 @@
 /*
  * Bitfields and bit numbers in the coprocessor 0 cause register.
  *
- * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation.
+ * Refer to your MIPS R4xx0 manual, chapter 5 for explanation.
  */
 #define  CAUSEB_EXCCODE		2
 #define  CAUSEF_EXCCODE		(31  <<  2)
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h
--- v2.4.3/linux/include/asm-mips/pci.h	Thu Jun 22 07:17:16 2000
+++ linux/include/asm-mips/pci.h	Fri Apr 13 20:26:07 2001
@@ -40,7 +40,7 @@
 #include <linux/string.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_DDB5074
+#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476))
 #undef PCIBIOS_MIN_IO
 #undef PCIBIOS_MIN_MEM
 #define PCIBIOS_MIN_IO		0x0100000
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/pgalloc.h linux/include/asm-mips/pgalloc.h
--- v2.4.3/linux/include/asm-mips/pgalloc.h	Mon May 15 12:10:26 2000
+++ linux/include/asm-mips/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -128,7 +128,7 @@
 #define pte_free_kernel(pte)    free_pte_fast(pte)
 #define pte_free(pte)           free_pte_fast(pte)
 #define pgd_free(pgd)           free_pgd_fast(pgd)
-#define pgd_alloc()             get_pgd_fast()
+#define pgd_alloc(mm)           get_pgd_fast()
 
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.4.3/linux/include/asm-mips/processor.h	Sat Dec 30 09:35:40 2000
+++ linux/include/asm-mips/processor.h	Fri Apr 13 20:26:07 2001
@@ -98,15 +98,20 @@
 #define NUM_FPU_REGS	32
 
 struct mips_fpu_hard_struct {
-	unsigned int fp_regs[NUM_FPU_REGS];
+	double fp_regs[NUM_FPU_REGS];
 	unsigned int control;
-} __attribute__((aligned(8)));
+};
 
 /*
- * FIXME: no fpu emulator yet (but who cares anyway?)
+ * It would be nice to add some more fields for emulator statistics, but there
+ * are a number of fixed offsets in offset.h and elsewhere that would have to
+ * be recalculated by hand.  So the additional information will be private to
+ * the FPU emulator for now.  See asm-mips/fpu_emulator.h.
  */
+typedef u64 fpureg_t;
 struct mips_fpu_soft_struct {
-	long	dummy;
+	fpureg_t	regs[NUM_FPU_REGS];
+	unsigned int	sr;
 };
 
 union mips_fpu_union {
@@ -148,6 +153,21 @@
 	mm_segment_t current_ds;
 	unsigned long irix_trampoline;  /* Wheee... */
 	unsigned long irix_oldctx;
+
+	/*
+	 * These are really only needed if the full FPU emulator is configured.
+	 * Would be made conditional on MIPS_FPU_EMULATOR if it weren't for the
+	 * fact that having offset.h rebuilt differently for different config
+	 * options would be asking for trouble.
+	 *
+	 * Saved EPC during delay-slot emulation (see math-emu/cp1emu.c)
+	 */
+	unsigned long dsemul_epc;
+
+	/*
+	 * Pointer to instruction used to induce address error
+	 */
+	unsigned long dsemul_aerpc;
 };
 
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
@@ -176,7 +196,12 @@
 	/* \
 	 * For now the default is to fix address errors \
 	 */ \
-	MF_FIXADE, { 0 }, 0, 0 \
+	MF_FIXADE, { 0 }, 0, 0, \
+	/* \
+	 * dsemul_epc and dsemul_aerpc should never be used uninitialized, \
+	 * but... \
+	 */ \
+	0 ,0 \
 }
 
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/semaphore.h linux/include/asm-mips/semaphore.h
--- v2.4.3/linux/include/asm-mips/semaphore.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -18,6 +18,7 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/config.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 #ifdef __MIPSEB__
@@ -215,7 +216,7 @@
 	atomic_t		count;
 	/* bit 0 means read bias granted;
 	   bit 1 means write bias granted.  */
-	unsigned		granted;
+	unsigned long		granted; /* pedant: long req'd for set_bit */
 	wait_queue_head_t	wait;
 	wait_queue_head_t	write_bias_wait;
 #if WAITQUEUE_DEBUG
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/sgi/sgimc.h linux/include/asm-mips/sgi/sgimc.h
--- v2.4.3/linux/include/asm-mips/sgi/sgimc.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips/sgi/sgimc.h	Fri Apr 13 20:26:07 2001
@@ -200,7 +200,7 @@
 	u32 _unused7;
 	volatile u32 dmamode;     /* DMA mode config bit settings */
 	u32 _unused8;
-	volatile u32 dmacount;    /* Zoom and byte count for DMA */
+	volatile u32 dmaccount;    /* Zoom and byte count for DMA */
 	u32 _unused9;
 	volatile u32 dmastart;    /* Pedal to the metal. */
 	u32 _unused10;
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/shmiq.h linux/include/asm-mips/shmiq.h
--- v2.4.3/linux/include/asm-mips/shmiq.h	Tue Dec 16 12:46:13 1997
+++ linux/include/asm-mips/shmiq.h	Fri Apr 13 20:26:07 2001
@@ -146,7 +146,7 @@
 /* get time since last event */
 #define QIOCGETITIME    _IOR('Q', 11, time_t)
 
-/* set curent screen */
+/* set current screen */
 #define QIOCSETSCRN     _IOW('Q',6,int)
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/errno.h linux/include/asm-mips64/errno.h
--- v2.4.3/linux/include/asm-mips64/errno.h	Sun Feb  4 21:48:46 2001
+++ linux/include/asm-mips64/errno.h	Fri Apr 13 20:26:07 2001
@@ -142,7 +142,6 @@
  */
 #define ENOMEDIUM	159	/* No medium found */
 #define EMEDIUMTYPE	160	/* Wrong medium type */
-#define EHASHCOLLISION	125	/* Number of hash collisons exceeds maximum generation counter value.  */
 
 #define EDQUOT		1133	/* Quota exceeded */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/keyboard.h linux/include/asm-mips64/keyboard.h
--- v2.4.3/linux/include/asm-mips64/keyboard.h	Mon Feb 28 07:18:20 2000
+++ linux/include/asm-mips64/keyboard.h	Fri Apr 13 20:26:07 2001
@@ -44,7 +44,7 @@
 	void (*kbd_request_region)(void);
 	int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
 
-	/* PSaux driver resource managment  */
+	/* PSaux driver resource management  */
 	int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
 	void (*aux_free_irq)(void);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/mipsregs.h linux/include/asm-mips64/mipsregs.h
--- v2.4.3/linux/include/asm-mips64/mipsregs.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/mipsregs.h	Fri Apr 13 20:26:07 2001
@@ -216,7 +216,7 @@
 /*
  * Bitfields and bit numbers in the coprocessor 0 cause register.
  *
- * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation.
+ * Refer to your MIPS R4xx0 manual, chapter 5 for explanation.
  */
 #define  CAUSEB_EXCCODE		2
 #define  CAUSEF_EXCCODE		(31  <<  2)
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/mmzone.h linux/include/asm-mips64/mmzone.h
--- v2.4.3/linux/include/asm-mips64/mmzone.h	Wed Aug  9 13:46:02 2000
+++ linux/include/asm-mips64/mmzone.h	Fri Apr 13 20:26:07 2001
@@ -58,7 +58,7 @@
 
 /*
  * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the the mem_map of that node.
+ * and returns the mem_map of that node.
  */
 #define ADDR_TO_MAPBASE(kaddr) \
 			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/pci/bridge.h linux/include/asm-mips64/pci/bridge.h
--- v2.4.3/linux/include/asm-mips64/pci/bridge.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/pci/bridge.h	Fri Apr 13 20:26:07 2001
@@ -276,7 +276,7 @@
 				ds:2,		/* Data size	  */
 				gbr:1,		/* GBR enable	  */
 				vbpm:1,		/* VBPM message	  */
-				error:1,	/* Error occured  */
+				error:1,	/* Error occurred  */
 				barr:1,		/* Barrier op	  */
 				rsvd:8;
 		} berr_st;
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/pgalloc.h linux/include/asm-mips64/pgalloc.h
--- v2.4.3/linux/include/asm-mips64/pgalloc.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -151,7 +151,7 @@
 #define pte_free(pte)           free_pte_fast(pte)
 #define pmd_free(pte)           free_pmd_fast(pte)
 #define pgd_free(pgd)           free_pgd_fast(pgd)
-#define pgd_alloc()             get_pgd_fast()
+#define pgd_alloc(mm)           get_pgd_fast()
 
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/semaphore.h linux/include/asm-mips64/semaphore.h
--- v2.4.3/linux/include/asm-mips64/semaphore.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -13,6 +13,7 @@
 #include <asm/atomic.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 #ifdef __MIPSEB__
@@ -167,180 +168,6 @@
 #endif
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
-}
-
-/*
- * rw mutexes (should that be mutices? =) -- throw rw spinlocks and
- * semaphores together, and this is what we end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer subtracts BIAS ands
- * gets 0 for the case of an uncontended lock.  Readers decrement by 1 and
- * see a positive value when uncontended, negative if there are writers
- * waiting (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and lots of processes.
- * BIAS must be chosen such that subtracting BIAS once per CPU will result
- * in the int remaining negative.  In terms of fairness, this should result
- * in the lock flopping back and forth between readers and writers under
- * heavy use.
- *
- * Once we start supporting machines with more than 128 CPUs, we should go
- * for using a 64bit atomic type instead of 32bit as counter. We shall
- * probably go for bias 0x80000000 then, so that single sethi can set it.
- * */
-
-#define RW_LOCK_BIAS		0x01000000
-
-struct rw_semaphore {
-	atomic_t		count;
-	/* bit 0 means read bias granted;
-	   bit 1 means write bias granted.  */
-	unsigned long		granted;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count)					\
-	{ ATOMIC_INIT(count), 0,					\
-	  __WAIT_QUEUE_HEAD_INITIALIZER((name).wait),			\
-	  __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait)		\
-	  __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) \
-	__DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) \
-	__DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) \
-	__DECLARE_RWSEM_GENERIC(name, 0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-/* The expensive part is outlined.  */
-extern void __down_read(struct rw_semaphore *sem, int count);
-extern void __down_write(struct rw_semaphore *sem, int count);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
-	int count;
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-
-	count = atomic_dec_return(&sem->count);
-	if (count < 0) {
-		__down_read(sem, count);
-	}
-	mb();
-
-#if WAITQUEUE_DEBUG
-	if (sem->granted & 2)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
-	int count;
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-
-	count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
-	if (count) {
-		__down_write(sem, count);
-	}
-	mb();
-
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (sem->granted & 3)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant case is when
-   there was a writer waiting, and we've bumped the count to 0: we must
-   wake the writer up.  */
-
-static inline void up_read(struct rw_semaphore *sem)
-{
-	int count;
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-	if (sem->granted & 2)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-
-	mb();
-	count = atomic_inc_return(&sem->count);
-	if (count == 0) {
-		__rwsem_wake(sem, 0);
-	}
-}
-
-/*
- * Releasing the writer is easy -- just release it and wake up any sleepers.
- */
-static inline void up_write(struct rw_semaphore *sem)
-{
-	int count;
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-	if (sem->granted & 3)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-
-	mb();
-	count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-	if (count - RW_LOCK_BIAS < 0 && count >= 0) {
-		/* Only do the wake if we're no longer negative.  */
-		__rwsem_wake(sem, count);
-	}
 }
 
 #endif /* _ASM_SEMAPHORE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/shmiq.h linux/include/asm-mips64/shmiq.h
--- v2.4.3/linux/include/asm-mips64/shmiq.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/shmiq.h	Fri Apr 13 20:26:07 2001
@@ -153,7 +153,7 @@
 /* get time since last event */
 #define QIOCGETITIME    _IOR('Q', 11, time_t)
 
-/* set curent screen */
+/* set current screen */
 #define QIOCSETSCRN     _IOW('Q',6,int)
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-parisc/pgalloc.h linux/include/asm-parisc/pgalloc.h
--- v2.4.3/linux/include/asm-parisc/pgalloc.h	Tue Dec  5 12:29:39 2000
+++ linux/include/asm-parisc/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -372,7 +372,7 @@
 #define pte_free(pte)		free_pte_fast(pte)
 #define pmd_free(pmd)           free_pmd_fast(pmd)
 #define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
+#define pgd_alloc(mm)		get_pgd_fast()
 
 extern void __bad_pmd(pmd_t *pmd);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-parisc/semaphore.h linux/include/asm-parisc/semaphore.h
--- v2.4.3/linux/include/asm-parisc/semaphore.h	Tue Dec  5 12:29:39 2000
+++ linux/include/asm-parisc/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -17,6 +17,7 @@
  */
 
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -133,169 +134,6 @@
 #endif
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *              -ben
- */
-struct rw_semaphore {
-        atomic_t                count;
-        volatile unsigned char  write_bias_granted;
-        volatile unsigned char  read_bias_granted;
-        volatile unsigned char  pad1;
-        volatile unsigned char  pad2;
-        wait_queue_head_t       wait;
-        wait_queue_head_t       write_bias_wait;
-#if WAITQUEUE_DEBUG
-        long                    __magic;
-        atomic_t                readers;
-        atomic_t                writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT      , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT      /* */
-#endif
-
-#define RW_LOCK_BIAS 0x01000000
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-        __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-        __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-        struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-        atomic_set(&sem->count, RW_LOCK_BIAS);
-        sem->read_bias_granted = 0;
-        sem->write_bias_granted = 0;
-        init_waitqueue_head(&sem->wait);
-        init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-        sem->__magic = (long)&sem->__magic;
-        atomic_set(&sem->readers, 0);
-        atomic_set(&sem->writers, 0);
-#endif
-}
-
-#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
-extern struct rw_semaphore *__build_read_lock(struct rw_semaphore *sem, const char *what);
-extern struct rw_semaphore *__build_write_lock(struct rw_semaphore *sem, const char *what);
-#endif
-
-/* we use FASTCALL convention for the helpers */
-extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-        if (sem->__magic != (long)&sem->__magic)
-                BUG();
-#endif
-#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
-        __build_read_lock(sem, "__down_read_failed");
-#endif
-#if WAITQUEUE_DEBUG
-        if (sem->write_bias_granted)
-                BUG();
-        if (atomic_read(&sem->writers))
-                BUG();
-        atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-        if (sem->__magic != (long)&sem->__magic)
-                BUG();
-#endif
-#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
-        __build_write_lock(sem, "__down_write_failed");
-#endif
-#if WAITQUEUE_DEBUG
-        if (atomic_read(&sem->writers))
-                BUG();
-        if (atomic_read(&sem->readers))
-                BUG();
-        if (sem->read_bias_granted)
-                BUG();
-        if (sem->write_bias_granted)
-                BUG();
-        atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-        if (sem->write_bias_granted)
-                BUG();
-        if (atomic_read(&sem->writers))
-                BUG();
-        atomic_dec(&sem->readers);
-#endif
-        __up_read(sem);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-        if (sem->read_bias_granted)
-                BUG();
-        if (sem->write_bias_granted)
-                BUG();
-        if (atomic_read(&sem->readers))
-                BUG();
-        if (atomic_read(&sem->writers) != 1)
-                BUG();
-        atomic_dec(&sem->writers);
-#endif
-        __up_write(sem);
 }
 
 #endif /* _ASM_PARISC_SEMAPHORE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/kmap_types.h linux/include/asm-ppc/kmap_types.h
--- v2.4.3/linux/include/asm-ppc/kmap_types.h	Sat Nov 11 18:23:10 2000
+++ linux/include/asm-ppc/kmap_types.h	Thu Apr 12 12:11:39 2001
@@ -5,6 +5,8 @@
 enum km_type {
 	KM_BOUNCE_READ,
 	KM_BOUNCE_WRITE,
+	KM_SKB_DATA,
+	KM_SKB_DATA_SOFTIRQ,
 	KM_TYPE_NR
 };
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/pgalloc.h linux/include/asm-ppc/pgalloc.h
--- v2.4.3/linux/include/asm-ppc/pgalloc.h	Mon Mar 26 14:05:23 2001
+++ linux/include/asm-ppc/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -87,7 +87,7 @@
 }
 
 #define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
+#define pgd_alloc(mm)		get_pgd_fast()
 
 /*
  * We don't have any real pmd's, and this code never triggers because
diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.4.3/linux/include/asm-ppc/semaphore.h	Fri Mar 23 22:42:31 2001
+++ linux/include/asm-ppc/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -14,6 +14,7 @@
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 	atomic_t count;
@@ -105,99 +106,6 @@
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
 }	
-
-
-/* RW spinlock-based semaphores */
-
-struct rw_semaphore
-{
-	spinlock_t lock;
-	int rd, wr;
-	wait_queue_head_t wait;
-#if WAITQUEUE_DEBUG
-	long __magic;
-#endif
-};
-
-#define RW_LOCK_BIAS	2	/* XXX bogus */
-#define __RWSEM_INITIALIZER(name, count)		\
-{							\
-	SPIN_LOCK_UNLOCKED,				\
-	(count) == 1, (count) == 0,			\
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).wait)	\
-	__SEM_DEBUG_INIT(name)				\
-}
-
-#define __DECLARE_RWSEM_GENERIC(name, count)		\
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name, count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-	spin_lock_init(&sem->lock);
-	sem->rd = sem->wr = 0;
-	init_waitqueue_head(&sem->wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-#endif
-}
-
-#ifndef CHECK_MAGIC
-#define CHECK_MAGIC(x)
-#endif
-
-extern void down_read_failed(struct rw_semaphore *);
-extern void down_write_failed(struct rw_semaphore *);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-	CHECK_MAGIC(sem->__magic);
-
-	spin_lock_irq(&sem->lock);
-	if (sem->wr)
-		down_read_failed(sem);
-	sem->rd++;
-	spin_unlock_irq(&sem->lock);
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-	CHECK_MAGIC(sem->__magic);
-
-	spin_lock(&sem->lock);
-	if(sem->rd || sem->wr)
-		down_write_failed(sem);
-	sem->wr = 1;
-	spin_unlock(&sem->lock);
-}
-
-#define up_read(sem)							\
-	do {								\
-		unsigned long flags;					\
-									\
-		CHECK_MAGIC((sem)->__magic);				\
-									\
-		spin_lock_irqsave(&(sem)->lock, flags);			\
-		if (!--(sem)->rd && waitqueue_active(&(sem)->wait))	\
-			wake_up(&(sem)->wait);				\
-		spin_unlock_irqrestore(&(sem)->lock, flags);		\
-	} while (0)
-
-#define up_write(sem)							\
-	do {								\
-		unsigned long flags;					\
-									\
-		CHECK_MAGIC((sem)->__magic);				\
-									\
-		spin_lock_irqsave(&(sem)->lock, flags);			\
-		(sem)->wr = 0;						\
-		if (waitqueue_active(&(sem)->wait))			\
-			wake_up(&(sem)->wait);				\
-		spin_unlock_irqrestore(&(sem)->lock, flags);		\
-	} while (0)
 
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/tqm8xx.h linux/include/asm-ppc/tqm8xx.h
--- v2.4.3/linux/include/asm-ppc/tqm8xx.h	Sat Mar  3 10:52:14 2001
+++ linux/include/asm-ppc/tqm8xx.h	Thu Apr 12 12:16:36 2001
@@ -12,6 +12,8 @@
 #ifndef __MACH_TQM8xx_DEFS
 #define __MACH_TQM8xx_DEFS
 
+#include <linux/config.h>
+
 #ifndef __ASSEMBLY__
 
 typedef	void (interrupt_handler_t)(void *);
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h
--- v2.4.3/linux/include/asm-s390/atomic.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/atomic.h	Wed Apr 11 19:02:28 2001
@@ -25,6 +25,15 @@
 
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
+#define __CS_LOOP(old, new, ptr, op_val, op_string)			\
+        __asm__ __volatile__("   l     %0,0(%2)\n"			\
+                             "0: lr    %1,%0\n"				\
+                             op_string "  %1,%3\n"			\
+                             "   cs    %0,%1,0(%2)\n"			\
+                             "   jl    0b"				\
+                             : "=&d" (old), "=&d" (new)			\
+			     : "a" (ptr), "d" (op_val) : "cc" );
+
 static __inline__ int atomic_read(atomic_t *v)
 {
         int retval;
@@ -43,150 +52,80 @@
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    1,0\n"
-                             "   ar    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, i, "ar");
 }
 
 static __inline__ int atomic_add_return (int i, atomic_t *v)
 {
-	int newval;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ar    %1,%2\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (newval)
-			     : "d" (i) : "0", "1", "cc" );
-	return newval;
+	int old, new;
+	__CS_LOOP(old, new, v, i, "ar");
+	return new;
 }
 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
-	int newval;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ar    %1,%2\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b\n"
-                             : "+m" (*v), "=&d" (newval)
-                             : "d" (i) : "0", "1", "cc" );
-        return newval < 0;
+	int old, new;
+        __CS_LOOP(old, new, v, i, "ar");
+        return new < 0;
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    1,0\n"
-                             "   sr    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, i, "sr");
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    1,0\n"
-                             "   ahi   1,1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "ar");
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
-        int i;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
-        return i;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "ar");
+        return new;
 }
 
 static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
-       int i;
-
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
-       return i != 0;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "ar");
+	return new != 0;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    1,0\n"
-                             "   ahi   1,-1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "sr");
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
-        int i;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,-1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
-        return i;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "sr");
+        return new;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
-        int i;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,-1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
-        return i == 0;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "sr");
+        return new == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    1,0\n"
-                             "   nr    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (~(mask)) 
-                             : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, ~mask, "nr");
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,%0\n"
-                             "0: lr    1,0\n"
-                             "   or    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, mask, "or");
 }
 
 /*
@@ -199,15 +138,14 @@
         int retval;
 
         __asm__ __volatile__(
-                "  la   1,%1\n"
                 "  lr   0,%2\n"
-                "  cs   0,%3,0(1)\n"
+                "  cs   0,%3,0(%1)\n"
                 "  ipm  %0\n"
                 "  srl  %0,28\n"
                 "0:"
-                : "=&r" (retval), "+m" (*v)
-                : "d" (expected_oldval) , "d" (new_val)
-                : "0", "1", "cc");
+                : "=&d" (retval)
+                : "a" (v), "d" (expected_oldval) , "d" (new_val)
+                : "0", "cc");
         return retval;
 }
 
@@ -218,13 +156,11 @@
 atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
 {
         __asm__ __volatile__(
-                "   la  2,%0\n"
-                "0: lr  1,%1\n"
-                "   cs  1,%2,0(2)\n"
+                "0: lr  0,%1\n"
+                "   cs  0,%2,0(%0)\n"
                 "   jl  0b\n"
-                : "+m" (*v)
-                : "d" (expected_oldval) , "d" (new_val)
-                : "cc", "1", "2");
+                : : "a" (v), "d" (expected_oldval) , "d" (new_val)
+                : "cc", "0" );
 }
 
 #define atomic_compare_and_swap_debug(where,from,to) \
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h
--- v2.4.3/linux/include/asm-s390/bitops.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/bitops.h	Wed Apr 11 19:02:28 2001
@@ -475,9 +475,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"
@@ -501,9 +501,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"
@@ -527,9 +527,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"
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h
--- v2.4.3/linux/include/asm-s390/ccwcache.h	Fri Mar  2 11:12:06 2001
+++ linux/include/asm-s390/ccwcache.h	Wed Apr 11 19:02:28 2001
@@ -62,6 +62,7 @@
 #define CQR_STATUS_DONE     0x04	/* request is completed successfully */
 #define CQR_STATUS_ERROR    0x05	/* request is completed with error */
 #define CQR_STATUS_FAILED   0x06	/* request is finally failed */
+#define CQR_STATUS_PENDING  0x07        /* request is waiting for interrupt - ERP only */ 
 
 #define CQR_FLAGS_CHAINED  0x01	/* request is chained by another (last CCW is TIC) */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/chandev.h linux/include/asm-s390/chandev.h
--- v2.4.3/linux/include/asm-s390/chandev.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/chandev.h	Wed Apr 11 19:02:28 2001
@@ -66,6 +66,12 @@
                       unsigned long  irqflags,
                       const char    *devname,
                       void          *dev_id);
+/*
+ * I originally believed this function wouldn't be necessary
+ * I subsequently found that reprobing failed in certain cases :-(,
+ * It is just a wrapper for free irq.
+ */
+void chandev_free_irq(unsigned int irq, void *dev_id);
 
 typedef enum
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/checksum.h linux/include/asm-s390/checksum.h
--- v2.4.3/linux/include/asm-s390/checksum.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/checksum.h	Wed Apr 11 19:02:28 2001
@@ -36,14 +36,14 @@
 extern inline unsigned int 
 csum_partial_inline(const unsigned char * buff, int len, unsigned int sum)
 {
+	register_pair rp;
+
+	rp.subreg.even = (unsigned long) buff;
+	rp.subreg.odd = (unsigned long) len;
 	__asm__ __volatile__ (
-		"    lr   2,%1\n"    /* address in gpr 2 */
-		"    lr   3,%2\n"    /* length in gpr 3 */
-		"0:  cksm %0,2\n"    /* do checksum on longs */
+		"0:  cksm %0,%1\n"    /* do checksum on longs */
 		"    jo   0b\n"
-                : "+&d" (sum)
-		: "d" (buff), "d" (len)
-                : "cc", "2", "3" );
+                : "+&d" (sum), "+&a" (rp) : : "cc" );
 	return sum;
 }
 
@@ -97,14 +97,16 @@
 extern inline unsigned short
 csum_fold(unsigned int sum)
 {
+	register_pair rp;
+
 	__asm__ __volatile__ (
-		"    sr   3,3\n"   /* %0 = H*65536 + L */
-		"    lr   2,%0\n"  /* %0 = H L, R2/R3 = H L / 0 0 */
-		"    srdl 2,16\n"  /* %0 = H L, R2/R3 = 0 H / L 0 */
-		"    alr  2,3\n"   /* %0 = H L, R2/R3 = L H / L 0 */
-		"    alr  %0,2\n"  /* %0 = H+L+C L+H */
-                "    srl  %0,16\n" /* %0 = H+L+C */
-		: "+&d" (sum) : : "cc", "2", "3");
+		"    slr  %N1,%N1\n" /* %0 = H L */
+		"    lr   %1,%0\n"   /* %0 = H L, %1 = H L 0 0 */
+		"    srdl %1,16\n"   /* %0 = H L, %1 = 0 H L 0 */
+		"    alr  %1,%N1\n"  /* %0 = H L, %1 = L H L 0 */
+		"    alr  %0,%1\n"   /* %0 = H+L+C L+H */
+		"    srl  %0,16\n"   /* %0 = H+L+C */
+		: "+&d" (sum), "=d" (rp) : : "cc" );
 	return ((unsigned short) ~sum);
 }
 #endif
@@ -117,17 +119,16 @@
 extern inline unsigned short
 ip_fast_csum(unsigned char *iph, unsigned int ihl)
 {
+	register_pair rp;
 	unsigned long sum;
 
+	rp.subreg.even = (unsigned long) iph;
+	rp.subreg.odd = (unsigned long) ihl*4;
         __asm__ __volatile__ (
 		"    sr   %0,%0\n"   /* set sum to zero */
-                "    lr   2,%1\n"    /* address in gpr 2 */
-                "    lr   3,%2\n"    /* length in gpr 3 */
-                "0:  cksm %0,2\n"    /* do checksum on longs */
+                "0:  cksm %0,%1\n"   /* do checksum on longs */
                 "    jo   0b\n"
-                : "=&d" (sum)
-                : "d" (iph), "d" (ihl*4)
-                : "cc", "2", "3" );
+                : "=&d" (sum), "+&a" (rp) : : "cc" );
         return csum_fold(sum);
 }
 
@@ -144,16 +145,21 @@
                 "    alr   %0,%1\n"  /* sum += saddr */
                 "    brc   12,0f\n"
 		"    ahi   %0,1\n"   /* add carry */
-		"0:  alr   %0,%2\n"  /* sum += daddr */
+		"0:"
+		: "+&d" (sum) : "d" (saddr) : "cc" );
+	__asm__ __volatile__ (
+                "    alr   %0,%1\n"  /* sum += daddr */
                 "    brc   12,1f\n"
                 "    ahi   %0,1\n"   /* add carry */
-		"1:  alr   %0,%3\n"  /* sum += (len<<16) + (proto<<8) */
+		"1:"
+		: "+&d" (sum) : "d" (daddr) : "cc" );
+	__asm__ __volatile__ (
+                "    alr   %0,%1\n"  /* sum += (len<<16) + (proto<<8) */
 		"    brc   12,2f\n"
 		"    ahi   %0,1\n"   /* add carry */
 		"2:"
 		: "+&d" (sum)
-		: "d" (saddr), "d" (daddr),
-		  "d" (((unsigned int) len<<16) + (unsigned int) proto)
+		: "d" (((unsigned int) len<<16) + (unsigned int) proto)
 		: "cc" );
 	return sum;
 }
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/cpcmd.h linux/include/asm-s390/cpcmd.h
--- v2.4.3/linux/include/asm-s390/cpcmd.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/cpcmd.h	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,14 @@
+/*
+ *  arch/s390/kernel/cpcmd.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#ifndef __CPCMD__
+#define __CPCMD__
+
+extern void cpcmd(char *cmd, char *response, int rlen);
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- v2.4.3/linux/include/asm-s390/dasd.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/dasd.h	Wed Apr 11 19:02:28 2001
@@ -5,11 +5,16 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
  * History of changes (starts July 2000)
+ * 02/01/01 added dynamic registration of ioctls
  */
 
 #ifndef DASD_H
 #define DASD_H
 
+#undef ERP_DEBUG               /* enable debug messages */
+#undef ERP_FULL_ERP            /* enable full ERP - experimental code !!!! */
+#define CONFIG_DASD_DYNAMIC
+
 #include <linux/ioctl.h>
 #include <asm/irq.h>
 
@@ -29,6 +34,10 @@
 /* translate blocknumber of partition to absolute */
 #define BIODASDRWTB    _IOWR(IOCTL_LETTER,0,int)
 
+typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args);
+int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler);
+int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler);
+
 #define DASD_NAME "dasd"
 #define DASD_PARTN_BITS 2
 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
@@ -49,6 +58,10 @@
 #define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
 #define DASD_FORMAT_DEFAULT_INTENSITY -1
 
+#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
+#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
+#define DASD_FORMAT_INTENS_INVALIDATE    0x04
+#define DASD_FORMAT_INTENS_CDL 0x08
 #ifdef __KERNEL__
 #include <linux/version.h>
 #include <linux/major.h>
@@ -135,9 +148,15 @@
 typedef struct dasd_devreg_t {
         devreg_t devreg; /* the devreg itself */
         /* build a linked list of devregs, needed for cleanup */
-        struct dasd_devreg_t *next;
+        struct list_head list;
 } dasd_devreg_t;
 
+typedef struct {
+	struct list_head list;
+	int no;
+	dasd_ioctl_fn_t handler;
+} dasd_ioctl_list_t;
+
 typedef enum {
 	dasd_era_fatal = -1,	/* no chance to recover              */
 	dasd_era_none = 0,	/* don't recover, everything alright */
@@ -168,7 +187,7 @@
         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:" \
+               "/dev/%s(%d:%d),%04X IRQ0x%x:" \
                d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
 } while(0)
 
@@ -181,6 +200,7 @@
 	unsigned long blocks; /* size of volume in blocks */
 	unsigned int bp_block; /* bytes per block */
 	unsigned int s2b_shift; /* log2 (bp_block/512) */
+        unsigned int pt_block; /* from which block to read the partn table */
 } dasd_sizes_t;
 
 /* 
@@ -193,6 +213,38 @@
 	ccw_req_t *tail;
 } dasd_chanq_t;
 
+#define DASD_DEVICE_FORMAT_STRING "Device: %p"
+#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_event(d_device->debug_area,d_level,\
+                    DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                    d_device, d_data);\
+} while(0);
+#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_exception(d_device->debug_area,d_level,\
+                        DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                        d_device, d_data);\
+} while(0);
+
+#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
+#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_event(dasd_debug_area, d_level,\
+                    DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                    d_fn, d_data);\
+} while(0);
+#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_exception(dasd_debug_area, d_level,\
+                        DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                        d_fn, d_data);\
+} while(0);
+
 struct dasd_device_t;
 struct request;
 
@@ -230,7 +282,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;	/* maximum number of blocks to be chained */
 	dasd_ck_id_fn_t id_check;	/* to check sense data */
 	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
 	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
@@ -251,9 +303,13 @@
 	struct dasd_discipline_t *next;	/* used for list of disciplines */
 } dasd_discipline_t;
 
+#define DASD_MAJOR_INFO_REGISTERED 1
+#define DASD_MAJOR_INFO_IS_STATIC 2
+
 typedef struct major_info_t {
-	struct major_info_t *next;
+	struct list_head list;
 	struct dasd_device_t **dasd_device;
+	int flags;
 	struct gendisk gendisk; /* actually contains the major number */
 } __attribute__ ((packed)) major_info_t;
 
@@ -278,6 +334,7 @@
 	struct dasd_chanq_t queue;
         wait_queue_head_t wait_q;
         request_queue_t request_queue;
+        struct timer_list timer;      
 	devstat_t dev_status; /* needed ONLY!! for request_irq */
         dasd_sizes_t sizes;
         char name[16]; /* The name of the device in /dev */
@@ -300,7 +357,7 @@
 #define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
 #define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
 #define DASD_DEVICE_LEVEL_ANALYSED 0x08
-#define DASD_DEVICE_LEVEL_PARTITIONED 0x10
+#define DASD_DEVICE_LEVEL_ONLINE 0x10
 
 int dasd_init (void);
 void dasd_discipline_enq (dasd_discipline_t *);
@@ -312,8 +369,12 @@
 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 *);
-int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
 int dasd_oper_handler (int irq, devreg_t * devreg);
+void dasd_schedule_bh (dasd_device_t *);
+
+debug_info_t *dasd_debug_area;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/debug.h linux/include/asm-s390/debug.h
--- v2.4.3/linux/include/asm-s390/debug.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/debug.h	Wed Apr 11 19:02:28 2001
@@ -19,9 +19,8 @@
                 struct {
                         unsigned long long clock:52;
                         unsigned long long exception:1;
-                        unsigned long long used:1;
-                        unsigned long long unused:1;
-                        unsigned long long cpuid:9;
+                        unsigned long long level:3;
+                        unsigned long long cpuid:8;
                 } fields;
 
                 unsigned long long stck;
@@ -29,6 +28,9 @@
         void* caller;
 } __attribute__((packed));
 
+
+#define __DEBUG_FEATURE_VERSION      1  /* version of debug feature */
+
 #ifdef __KERNEL__
 #include <linux/version.h>
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
@@ -45,7 +47,6 @@
 #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_FEATURE_VERSION      1  /* version of debug feature */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
 
@@ -103,43 +104,98 @@
 	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_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);
 
 void debug_set_level(debug_info_t* id, int new_level);
 
-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);
+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));
+}
 
-static inline debug_entry_t *
+extern inline debug_entry_t *
 debug_long_event (debug_info_t* id, int level, unsigned long tag)
 {
-	unsigned long t=tag;
-	return debug_event(id,level,&t,sizeof(unsigned long));
+        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));
 }
-static inline debug_entry_t *
+
+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;
-	return debug_exception(id,level,&t,sizeof(unsigned long));
+        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 --recursive --new-file v2.4.3/linux/include/asm-s390/delay.h linux/include/asm-s390/delay.h
--- v2.4.3/linux/include/asm-s390/delay.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/delay.h	Wed Apr 11 19:02:28 2001
@@ -8,7 +8,7 @@
  *  Derived from "include/asm-i386/delay.h"
  *    Copyright (C) 1993 Linus Torvalds
  *
- *  Delay routines calling functions in arch/i386/lib/delay.c
+ *  Delay routines calling functions in arch/s390/lib/delay.c
  */
  
 #ifndef _S390_DELAY_H
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/div64.h linux/include/asm-s390/div64.h
--- v2.4.3/linux/include/asm-s390/div64.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/div64.h	Wed Apr 11 19:02:28 2001
@@ -1,10 +1,44 @@
 #ifndef __S390_DIV64
 #define __S390_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
+/* for do_div "base" needs to be smaller than 2^31-1 */
+ 
+#define do_div(n, base) ({                                      \
+	unsigned long long __n = (n);				\
+	unsigned long __r;					\
+								\
+	asm ("   slr  0,0\n"					\
+	     "   l    1,%1\n"					\
+	     "   srdl 0,1\n"					\
+	     "   dr   0,%2\n"					\
+	     "   alr  1,1\n"					\
+	     "   alr  0,0\n"					\
+	     "   lhi  2,1\n"					\
+	     "   n    2,%1\n"					\
+	     "   alr  0,2\n"					\
+	     "   clr  0,%2\n"					\
+	     "   jl   0f\n"					\
+	     "   slr  0,%2\n"					\
+             "   ahi  1,1\n"					\
+	     "0: st   1,%1\n"					\
+	     "   l    1,4+%1\n"					\
+	     "   srdl 0,1\n"					\
+             "   dr   0,%2\n"					\
+	     "   alr  1,1\n"					\
+	     "   alr  0,0\n"					\
+	     "   lhi  2,1\n"					\
+	     "   n    2,4+%1\n"					\
+	     "   alr  0,2\n"					\
+	     "   clr  0,%2\n"					\
+             "   jl   1f\n"					\
+	     "   slr  0,%2\n"					\
+	     "   ahi  1,1\n"					\
+	     "1: st   1,4+%1\n"					\
+             "   lr   %0,0"					\
+	     : "=d" (__r), "+m" (__n)				\
+	     : "d" (base) : "0", "1", "2" );			\
+	(n) = (__n);						\
+        __r;                                                    \
+})
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/ebcdic.h linux/include/asm-s390/ebcdic.h
--- v2.4.3/linux/include/asm-s390/ebcdic.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/ebcdic.h	Wed Apr 11 19:02:28 2001
@@ -24,24 +24,18 @@
 extern __inline__ 
 void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr)
 {
-        static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 };
+	if (nr <= 0)
+		return;
         __asm__ __volatile__(
-                "   lr    1,%0\n"
-                "   lr    2,%1\n"
-                "   lr    3,%2\n"
-                "   ahi   2,-256\n"
-                "   jm    1f\n"
-                "0: tr    0(256,1),0(3)\n"
-                "   ahi   1,256\n"
-                "   ahi   2,-256\n"
-                "   jp    0b\n"
-                "1: ahi   2,255\n"
-                "   jm    2f\n"
-                "   ex    2,%3\n"
-                "2:"
-                : /* no output */ 
-                : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0])
-                : "cc", "memory", "1", "2", "3" );
+		"   bras 1,1f\n"
+		"   tr   0(1,%0),0(%2)\n"
+		"0: la   %0,256(%0)\n"
+                "   tr   0(256,%0),0(%2)\n"
+		"1: ahi  %1,-256\n"
+		"   jp   0b\n"
+		"   ex   %1,0(1)"
+                : "+&a" (addr), "+&a" (nr-1)
+                : "a" (codepage) : "cc", "memory", "1" );
 }
 
 #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr)
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/elf.h linux/include/asm-s390/elf.h
--- v2.4.3/linux/include/asm-s390/elf.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/elf.h	Wed Apr 11 19:02:28 2001
@@ -31,7 +31,8 @@
  * This is used to ensure we don't load something for the wrong architecture.
  */
 #define elf_check_arch(x) \
-	((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) 
+	(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
+         && (x)->e_ident[EI_CLASS] == ELF_CLASS) 
 
 /* For SVR4/S390 the function pointer to be registered with `atexit` is
    passed in R14. */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/irq.h linux/include/asm-s390/irq.h
--- v2.4.3/linux/include/asm-s390/irq.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/irq.h	Wed Apr 11 19:02:28 2001
@@ -1,5 +1,5 @@
-#ifndef __irq_h
-#define __irq_h
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
 
 #include <linux/config.h>
 #ifdef __KERNEL__
@@ -19,28 +19,6 @@
 extern int enable_irq(unsigned int);
 
 /*
- * Interrupt controller descriptor. This is all we need
- * to describe about the low-level hardware.
- */
-struct hw_interrupt_type {
-        const __u8   *typename;
-        int         (*handle)(unsigned int irq,
-                              int cpu,
-                              struct pt_regs * regs);
-        int         (*enable) (unsigned int irq);
-        int         (*disable)(unsigned int irq);
-};
-
-/*
- * Status: reason for being disabled: somebody has
- * done a "disable_irq()" or we must not re-enter the
- * already executing irq..
- */
-#define IRQ_INPROGRESS  1
-#define IRQ_DISABLED    2
-#define IRQ_PENDING     4
-
-/*
  * path management control word
  */
 typedef struct {
@@ -86,7 +64,7 @@
       __u32 pfch : 1; /* prefetch */
       __u32 isic : 1; /* initial-status interruption control */
       __u32 alcc : 1; /* address-limit checking control */
-      __u32 ssi  : 1; /* suppress-suspended interruption */
+      __u32 ssi  : 1; /* supress-suspended interruption */
       __u32 zcc  : 1; /* zero condition code */
       __u32 ectl : 1; /* extended control */
       __u32 pno  : 1;     /* path not operational */
@@ -186,7 +164,7 @@
 
 typedef struct {
       __u8  cmd_code;/* command code */
-      __u8  flags;   /* flags, like IDA addressing, etc. */
+      __u8  flags;   /* flags, like IDA adressing, etc. */
       __u16 count;   /* byte count */
       __u32 cda;     /* data address */
    } __attribute__ ((packed,aligned(8))) ccw1_t;
@@ -456,24 +434,10 @@
 
 typedef  int  (* adapter_int_handler_t)( __u32 intparm );
 
-struct s390_irqaction {
-	io_handler_func_t  handler;
-	unsigned long      flags;
-	const char        *name;
-	devstat_t         *dev_id;
-};
-
-/*
- * This is the "IRQ descriptor", which contains various information
- * about the irq, including what kind of hardware handling it has,
- * whether it is disabled etc etc.
- *
- * Pad this out to 32 bytes for cache and indexing reasons.
- */
 typedef struct {
-      unsigned int              status;    /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */
-      struct hw_interrupt_type *handler;   /* handle/enable/disable functions */
-      struct s390_irqaction    *action;    /* IRQ action list */
+	io_handler_func_t         handler;  /* interrupt handler routine */
+	const char               *name;     /* device name */
+	devstat_t                *dev_id;   /* device status block */
    } irq_desc_t;
 
 typedef struct {
@@ -531,9 +495,8 @@
 /*
  * do_IO()
  *
- * Start a S/390 channel program. When the interrupt arrives
- *  handle_IRQ_event() is called, which eventually calls the
- *  IRQ handler, either immediately, delayed (dev-end missing,
+ *  Start a S/390 channel program. When the interrupt arrives, the
+ *  IRQ handler is called, either immediately, delayed (dev-end missing,
  *  or sense required) or never (no IRQ handler registered -
  *  should never occur, as the IRQ (subchannel ID) should be
  *  disabled if no handler is present. Depending on the action
@@ -606,8 +569,6 @@
                               const char              *devname,
                               void                    *dev_id);
 
-extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *);
-
 extern int set_cons_dev(int irq);
 extern int reset_cons_dev(int irq);
 extern int wait_cons_dev(int irq);
@@ -621,16 +582,13 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "STSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
-                : "cc", "1" );
+                "   lr    1,%1\n"
+                "   stsch 0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode)
+		: "d" (irq | 0x10000), "a" (addr)
+		: "cc", "1" );
         return ccode;
 }
 
@@ -639,15 +597,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "MSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                "   lr    1,%1\n"
+                "   msch  0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode)
+		: "d" (irq | 0x10000L), "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -657,12 +612,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "    lgr  1,%1\n"
+                "    lr   1,%1\n"
                 "    msch 0(%2)\n"
                 "0:  ipm  %0\n"
                 "    srl  %0,28\n"
                 "1:\n"
+#ifdef CONFIG_ARCH_S390X
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
                 "    jg   1b\n"
@@ -671,12 +626,12 @@
                 "   .align 8\n"
                 "   .quad 0b,2b\n"
                 ".previous"
-#else
                 "    lr   1,%1\n"
                 "    msch 0(%2)\n"
                 "0:  ipm  %0\n"
                 "    srl  %0,28\n"
                 "1:\n"
+#else
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
                 "    bras 1,3f\n"
@@ -690,7 +645,7 @@
                 ".previous"
 #endif
                 : "=d" (ccode)
-                : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC)
+                : "d" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC)
                 : "cc", "1" );
         return ccode;
 }
@@ -700,15 +655,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "TSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                "   lr    1,%1\n"
+                "   tsch  0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L), "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -718,10 +670,11 @@
         int ccode;
 
         __asm__ __volatile__(
-                "TPI 0(%1)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "a" (addr)
+                "   tpi   0(%1)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -731,15 +684,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "SSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                "   lr    1,%1\n"
+                "   ssch  0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L), "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -749,15 +699,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "RSCH\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L)
+                "   lr    1,%1\n"
+                "   rsch\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
                 : "cc", "1" );
         return ccode;
 }
@@ -767,15 +714,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "CSCH\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L)
+                "   lr    1,%1\n"
+                "   csch\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
                 : "cc", "1" );
         return ccode;
 }
@@ -785,15 +729,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "HSCH\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L)
+                "   lr    1,%1\n"
+                "   hsch\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
                 : "cc", "1" );
         return ccode;
 }
@@ -803,9 +744,9 @@
         int ccode;
 
         __asm__ __volatile__(
-                "IAC 1\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
+                "   iac   1\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
                 : "=d" (ccode) : : "cc", "1" );
         return ccode;
 }
@@ -815,15 +756,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "RCHP\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (chpid)
+                "   lr    1,%1\n"
+                "   rchp\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (chpid)
                 : "cc", "1" );
         return ccode;
 }
@@ -850,16 +788,16 @@
 
         __asm__ __volatile__(
 #ifdef CONFIG_ARCH_S390X
-                "SAM31\n\t"
-                "DIAG %1,0,0x210\n\t"
-                "SAM64\n\t"
-#else
-                "LR 1,%1\n\t"
-                ".long 0x83110210\n\t"
-#endif
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "a" (addr)
+                "   sam31\n"
+                "   diag  %1,0,0x210\n"
+                "   sam64\n"
+#else
+                "   diag  %1,0,0x210\n"
+#endif
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "a" (addr)
                 : "cc" );
         return ccode;
 }
@@ -885,15 +823,9 @@
 static inline void irq_enter(int cpu, unsigned int irq)
 {
         hardirq_enter(cpu);
-#ifdef CONFIG_ARCH_S390X
         while (atomic_read(&global_irq_lock) != 0) {
                 eieio();
         }
-#else
-        while (test_bit(0,&global_irq_lock)) {
-                eieio();
-        }
-#endif
 }
 
 static inline void irq_exit(int cpu, unsigned int irq)
@@ -957,6 +889,9 @@
         spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
+
+#define touch_nmi_watchdog() do { } while(0)
+
 #endif /* __KERNEL__ */
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/irqextras390.h linux/include/asm-s390/irqextras390.h
--- v2.4.3/linux/include/asm-s390/irqextras390.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/irqextras390.h	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/*
- *  include/asm-s390/irqextras390.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- */
-
-#ifndef __irqextras390_h
-#define __irqextras390_h
-
-/*
-  irqextras390.h by D.J. Barrow
-  if you are a bitfield fan &  are paranoid that ansi dosen't
-  give hard definitions about the size of an int or long you might
-  prefer these definitions as an alternative.
-
-*/
-
-#include <linux/types.h>
-
-typedef struct 
-{
-      unsigned key:4;
-      unsigned s:1;
-      unsigned l:1;
-      unsigned cc:2;
-      unsigned f:1;
-      unsigned p:1;
-      unsigned i:1;
-      unsigned a:1;
-      unsigned u:1;
-      unsigned z:1;
-      unsigned e:1;
-      unsigned n:1;
-      unsigned zero:1;
-      
-      unsigned fc_start:1;
-      unsigned fc_halt:1;
-      unsigned fc_clear:1;
-      
-      unsigned ac_resume_pending:1;
-      unsigned ac_start_pending:1;
-      unsigned ac_halt_pending:1;
-      unsigned ac_clear_pending:1;
-      unsigned ac_subchannel_active:1;
-      unsigned ac_device_active:1;
-      unsigned ac_suspended:1;
-      
-      unsigned sc_alert:1;
-      unsigned sc_intermediate:1;
-      unsigned sc_primary:1;
-      unsigned sc_seconary:1;
-      unsigned sc_status_pending:1;
-      
-      __u32	   ccw_address;
-      
-      unsigned dev_status_attention:1;
-      unsigned dev_status_modifier:1;
-      unsigned dev_status_control_unit_end:1;
-      unsigned dev_status_busy:1;
-      unsigned dev_status_channel_end:1;
-      unsigned dev_status_device_end:1;
-      unsigned dev_status_unit_check:1;
-      unsigned dev_status_unit_exception:1;
-      
-      unsigned sch_status_program_cont_int:1;
-      unsigned sch_status_incorrect_length:1;
-      unsigned sch_status_program_check:1;
-      unsigned sch_status_protection_check:1;
-      unsigned sch_status_channel_data_check:1;
-      unsigned sch_status_channel_control_check:1;
-      unsigned sch_status_interface_control_check:1;
-      unsigned sch_status_chaining_check:1;
-     
-      __u16	   byte_count;
-} scsw_bits_t __attribute__((packed));
-
-typedef struct
-{
-  __u32      flags;
-  __u32      ccw_address;
-  __u8       dev_status;
-  __u8       sch_status;
-  __u16      byte_count;
-} scsw_words_t __attribute__((packed));
-
-typedef struct
-{
-      __u8     cmd_code;
-      
-      unsigned cd:1;
-      unsigned cc:1;
-      unsigned sli:1;
-      unsigned skip:1;
-      unsigned pci:1;
-      unsigned ida:1;
-      unsigned s:1;
-      unsigned res1:1;
-
-      __u16	count;
-
-      __u32     ccw_data_address;
-} ccw1_bits_t __attribute__((packed,aligned(8)));
-
-typedef struct
-{
-      __u32		interruption_parm;
-      unsigned key:4;
-      unsigned s:1;
-      unsigned res1:3;
-      unsigned f:1;
-      unsigned p:1;
-      unsigned i:1;
-      unsigned a:1;
-      unsigned u:1;
-      __u8	   lpm;
-      unsigned l:1;
-      unsigned res2:7;
-      ccw1_bits_t	*ccw_program_address;
-} orb_bits_t __attribute__((packed));
-
-void fixchannelprogram(orb_bits_t *orbptr);
-void fixccws(ccw1_bits_t *ccwptr);
-enum
-{
-   ccw_write=0x1,
-   ccw_read=0x2,
-   ccw_read_backward=0xc,
-   ccw_control=0x3,
-   ccw_sense=0x4,
-   ccw_sense_id=0xe4,
-   ccw_transfer_in_channel0=0x8,
-   ccw_transfer_in_channel1=0x8,
-   ccw_set_x_mode=0xc3,		// according to uli's lan notes
-   ccw_nop=0x3			// according to uli's notes again
-                                        // n.b. ccw_control clashes with this
-                                        // so I presume its a special case of
-					// control
-};
-
-
-
-#endif
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/major.h linux/include/asm-s390/major.h
--- v2.4.3/linux/include/asm-s390/major.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/major.h	Wed Dec 31 16:00:00 1969
@@ -1,150 +0,0 @@
-#ifndef _LINUX_MAJOR_H
-#define _LINUX_MAJOR_H
-
-/*
- * This file has definitions for major device numbers.
- * For the device number assignments, see Documentation/devices.txt.
- */
-
-/* limits */
-
-/*
- * Important: Don't change this to 256.  Major number 255 is and must be
- * reserved for future expansion into a larger dev_t space.
- */
-#define MAX_CHRDEV	255
-#define MAX_BLKDEV	255
-
-#define UNNAMED_MAJOR	0
-#define MEM_MAJOR	1
-#define RAMDISK_MAJOR	1
-#define FLOPPY_MAJOR	2
-#define PTY_MASTER_MAJOR 2
-#define IDE0_MAJOR	3
-#define PTY_SLAVE_MAJOR 3
-#define HD_MAJOR	IDE0_MAJOR
-#define TTY_MAJOR	4
-#define TTYAUX_MAJOR	5
-#define LP_MAJOR	6
-#define VCS_MAJOR	7
-#define LOOP_MAJOR	7
-#define SCSI_DISK0_MAJOR 8
-#define SCSI_TAPE_MAJOR	9
-#define MD_MAJOR        9
-#define MISC_MAJOR	10
-#define SCSI_CDROM_MAJOR 11
-#define QIC02_TAPE_MAJOR 12
-#define XT_DISK_MAJOR	13
-#define SOUND_MAJOR	14
-#define CDU31A_CDROM_MAJOR 15
-#define JOYSTICK_MAJOR	15
-#define GOLDSTAR_CDROM_MAJOR 16
-#define OPTICS_CDROM_MAJOR 17
-#define SANYO_CDROM_MAJOR 18
-#define CYCLADES_MAJOR  19
-#define CYCLADESAUX_MAJOR 20
-#define MITSUMI_X_CDROM_MAJOR 20
-#define MFM_ACORN_MAJOR 21	/* ARM Linux /dev/mfm */
-#define SCSI_GENERIC_MAJOR 21
-#define Z8530_MAJOR 34
-#define DIGI_MAJOR 23
-#define IDE1_MAJOR	22
-#define DIGICU_MAJOR 22
-#define MITSUMI_CDROM_MAJOR 23
-#define CDU535_CDROM_MAJOR 24
-#define STL_SERIALMAJOR 24
-#define MATSUSHITA_CDROM_MAJOR 25
-#define STL_CALLOUTMAJOR 25
-#define MATSUSHITA_CDROM2_MAJOR 26
-#define QIC117_TAPE_MAJOR 27
-#define MATSUSHITA_CDROM3_MAJOR 27
-#define MATSUSHITA_CDROM4_MAJOR 28
-#define STL_SIOMEMMAJOR 28
-#define ACSI_MAJOR	28
-#define AZTECH_CDROM_MAJOR 29
-#define GRAPHDEV_MAJOR	29	/* SparcLinux & Linux/68k /dev/fb */
-#define SHMIQ_MAJOR	85	/* Linux/mips, SGI /dev/shmiq */
-#define CM206_CDROM_MAJOR 32
-#define IDE2_MAJOR	33
-#define IDE3_MAJOR	34
-#define NETLINK_MAJOR	36
-#define PS2ESDI_MAJOR	36
-#define IDETAPE_MAJOR	37
-#define Z2RAM_MAJOR	37
-#define APBLOCK_MAJOR   38   /* AP1000 Block device */
-#define DDV_MAJOR       39   /* AP1000 DDV block device */
-#define NBD_MAJOR	43   /* Network block device	*/
-#define RISCOM8_NORMAL_MAJOR 48
-#define DAC960_MAJOR	48	/* 48..55 */
-#define RISCOM8_CALLOUT_MAJOR 49
-#define MKISS_MAJOR	55
-#define DSP56K_MAJOR    55   /* DSP56001 processor device */
-
-#define IDE4_MAJOR	56
-#define IDE5_MAJOR	57
-
-#define SCSI_DISK1_MAJOR	65
-#define SCSI_DISK2_MAJOR	66
-#define SCSI_DISK3_MAJOR	67
-#define SCSI_DISK4_MAJOR	68
-#define SCSI_DISK5_MAJOR	69
-#define SCSI_DISK6_MAJOR	70
-#define SCSI_DISK7_MAJOR	71
-
-
-#define LVM_BLK_MAJOR	58	/* Logical Volume Manager */
-
-#define COMPAQ_SMART2_MAJOR	72
-#define COMPAQ_SMART2_MAJOR1	73
-#define COMPAQ_SMART2_MAJOR2	74
-#define COMPAQ_SMART2_MAJOR3	75
-#define COMPAQ_SMART2_MAJOR4	76
-#define COMPAQ_SMART2_MAJOR5	77
-#define COMPAQ_SMART2_MAJOR6	78
-#define COMPAQ_SMART2_MAJOR7	79
-
-#define SPECIALIX_NORMAL_MAJOR 75
-#define SPECIALIX_CALLOUT_MAJOR 76
-
-#define DASD_MAJOR      94
-
-#define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
-
-#define MDISK_MAJOR     64
-
-#define I2O_MAJOR		80	/* 80->87 */
-
-#define IDE6_MAJOR	88
-#define IDE7_MAJOR	89
-#define IDE8_MAJOR	90
-#define IDE9_MAJOR	91
-
-#define AURORA_MAJOR 79
-
-#define RTF_MAJOR	150
-#define RAW_MAJOR	162
-
-#define USB_ACM_MAJOR		166
-#define USB_ACM_AUX_MAJOR	167
-#define USB_CHAR_MAJOR		180
-
-#define UNIX98_PTY_MASTER_MAJOR	128
-#define UNIX98_PTY_MAJOR_COUNT	8
-#define UNIX98_PTY_SLAVE_MAJOR	(UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
-
-/*
- * Tests for SCSI devices.
- */
-
-#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
-  ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
-  
-#define SCSI_BLK_MAJOR(M) \
-  (SCSI_DISK_MAJOR(M)	\
-   || (M) == SCSI_CDROM_MAJOR)
-
-static __inline__ int scsi_blk_major(int m) {
-	return SCSI_BLK_MAJOR(m);
-}
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/mathemu.h linux/include/asm-s390/mathemu.h
--- v2.4.3/linux/include/asm-s390/mathemu.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/mathemu.h	Wed Apr 11 19:02:28 2001
@@ -22,28 +22,6 @@
 extern int math_emu_stfpc(__u8 *, struct pt_regs *);
 extern int math_emu_srnm(__u8 *, struct pt_regs *);
 
-
-extern __u64 __adddf3(__u64,__u64);
-extern __u64 __subdf3(__u64,__u64);
-extern __u64 __muldf3(__u64,__u64);
-extern __u64 __divdf3(__u64,__u64);
-extern long  __cmpdf2(__u64,__u64);
-extern __u64 __negdf2(__u64);
-extern __u64 __absdf2(__u64);
-extern __u32 __addsf3(__u32,__u32);
-extern __u32 __subsf3(__u32,__u32);
-extern __u32 __mulsf3(__u32,__u32);
-extern __u32 __divsf3(__u32,__u32);
-extern __u32 __negsf2(__u32);
-extern __u32 __abssf2(__u32);
-extern long  __cmpsf2(__u32,__u32);
-extern __u32 __truncdfsf2(__u64);
-extern __u32 __fixsfsi(__u32);
-extern __u32 __fixdfsi(__u64);
-extern __u64  __floatsidf(__u32);
-extern __u32  __floatsisf(__u32);
-extern __u64  __extendsfdf2(__u32);
-
 #endif                                 /* __MATHEMU__                      */
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/misc390.h linux/include/asm-s390/misc390.h
--- v2.4.3/linux/include/asm-s390/misc390.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/misc390.h	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/*
- *  include/asm-s390/misc390.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- */
-
-#define	allocaligned2(type,name,number,align)				\
-   __u8	name##buff[(sizeof(type)*(number+1))-1]; 	                \
-   type	*name=(type *)(((__u32)(&name##buff[align-1]))&(-align))
-
-#define	allocaligned(type,name,number)  allocaligned2(type,name,number,__alignof__(type))
-
-extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs);
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/page.h linux/include/asm-s390/page.h
--- v2.4.3/linux/include/asm-s390/page.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/page.h	Wed Apr 11 19:02:28 2001
@@ -9,6 +9,9 @@
 #ifndef _S390_PAGE_H
 #define _S390_PAGE_H
 
+#include <asm/setup.h>
+#include <asm/types.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT      12
 #define PAGE_SIZE       (1UL << PAGE_SHIFT)
@@ -17,12 +20,44 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-/*
- * gcc uses builtin, i.e. MVCLE for both operations
- */
+static inline void clear_page(void *page)
+{
+	register_pair rp;
+
+	rp.subreg.even = (unsigned long) page;
+	rp.subreg.odd = (unsigned long) 4096;
+        asm volatile ("   slr  1,1\n"
+		      "   mvcl %0,0"
+		      : "+&a" (rp) : : "memory", "1" );
+}
 
-#define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from)      memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+static inline void copy_page(void *to, void *from)
+{
+        if (MACHINE_HAS_MVPG)
+		asm volatile ("   sr   0,0\n"
+			      "   mvpg %0,%1"
+			      : : "a" ((void *)(to)), "a" ((void *)(from))
+			      : "memory", "0" );
+	else
+		asm volatile ("   mvc  0(256,%0),0(%1)\n"
+			      "   mvc  256(256,%0),256(%1)\n"
+			      "   mvc  512(256,%0),512(%1)\n"
+			      "   mvc  768(256,%0),768(%1)\n"
+			      "   mvc  1024(256,%0),1024(%1)\n"
+			      "   mvc  1280(256,%0),1280(%1)\n"
+			      "   mvc  1536(256,%0),1536(%1)\n"
+			      "   mvc  1792(256,%0),1792(%1)\n"
+			      "   mvc  2048(256,%0),2048(%1)\n"
+			      "   mvc  2304(256,%0),2304(%1)\n"
+			      "   mvc  2560(256,%0),2560(%1)\n"
+			      "   mvc  2816(256,%0),2816(%1)\n"
+			      "   mvc  3072(256,%0),3072(%1)\n"
+			      "   mvc  3328(256,%0),3328(%1)\n"
+			      "   mvc  3584(256,%0),3584(%1)\n"
+			      "   mvc  3840(256,%0),3840(%1)\n"
+			      : : "a"((void *)(to)),"a"((void *)(from)) 
+			      : "memory" );
+}
 
 #define clear_user_page(page, vaddr)	clear_page(page)
 #define copy_user_page(to, from, vaddr)	copy_page(to, from)
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/pgalloc.h linux/include/asm-s390/pgalloc.h
--- v2.4.3/linux/include/asm-s390/pgalloc.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -30,12 +30,14 @@
 
 extern __inline__ pgd_t* get_pgd_slow(void)
 {
+	pgd_t *ret;
         int i;
-        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));
-        return ret;
+
+	ret = (pgd_t *) __get_free_pages(GFP_KERNEL,1);
+        if (ret != NULL)
+		for (i = 0; i < USER_PTRS_PER_PGD; i++)
+			pmd_clear(pmd_offset(ret + i, i*PGDIR_SIZE));
+	return ret;
 }
 
 extern __inline__ pgd_t* get_pgd_fast(void)
@@ -50,7 +52,7 @@
         return (pgd_t *)ret;
 }
 
-extern __inline__ pgd_t *pgd_alloc(void)
+extern __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *pgd;
 
@@ -76,40 +78,40 @@
 
 /*
  * page middle directory allocation/free routines.
- * We don't use pmd cache, so these are dummy routines.
+ * We don't use pmd cache, so these are dummy routines. This
+ * code never triggers because the pgd will always be present.
  */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-        return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
-}
-
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
-{
-        return (pmd_t *) pgd;
-}
-
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
-{
+#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
+#define pmd_free(x)                     do { } while (0)
+#define pgd_populate(mm, pmd, pte)      BUG()
+
+extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
+{
+	pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte);
+	pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256);
+	pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte+512);
+	pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768);
 }
 
-extern inline void pmd_free(pmd_t * pmd)
-{
-}
-
-#define pmd_free_kernel         pmd_free
-#define pmd_alloc_kernel        pmd_alloc
-
 /*
  * page table entry allocation/free routines.
  */
-extern pte_t empty_bad_pte_table[];
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+{
+	pte_t *pte;
+        int i;
 
-extern __inline__ pte_t* get_pte_fast(void)
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte != NULL) {
+		for (i=0; i < PTRS_PER_PTE; i++)
+			pte_clear(pte+i);
+	}
+	return pte;
+}
+
+extern __inline__ pte_t *
+pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
         unsigned long *ret = (unsigned long *) pte_quicklist;
 
@@ -121,44 +123,19 @@
         return (pte_t *)ret;
 }
 
-extern __inline__ void free_pte_fast(pte_t *pte)
+extern __inline__ void pte_free_fast(pte_t *pte)
 {
-	if (pte == empty_bad_pte_table)
-		return;
         *(unsigned long *)pte = (unsigned long) pte_quicklist;
         pte_quicklist = (unsigned long *) pte;
         pgtable_cache_size++;
 }
 
-extern __inline__ void free_pte_slow(pte_t *pte)
+extern __inline__ void pte_free_slow(pte_t *pte)
 {
         free_page((unsigned long) pte);
 }
 
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long vmaddr)
-{
-	unsigned long offset;
-
-	offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-        if (pmd_none(*pmd)) {
-		unsigned long page = (unsigned long) get_pte_fast();
-		
-		if (!page)
-			return get_pte_slow(pmd, offset);
-		pmd_val(pmd[0]) = _PAGE_TABLE + __pa(page);
-		pmd_val(pmd[1]) = _PAGE_TABLE + __pa(page+1024);
-		pmd_val(pmd[2]) = _PAGE_TABLE + __pa(page+2048);
-		pmd_val(pmd[3]) = _PAGE_TABLE + __pa(page+3072);
-		return (pte_t *) page + offset;
-	}
-        if (pmd_bad(*pmd))
-		BUG();
-        return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr)
-#define pte_free_kernel(pte)    free_pte_fast(pte)
-#define pte_free(pte)           free_pte_fast(pte)
+#define pte_free(pte)           pte_free_fast(pte)
 
 extern int do_check_pgt_cache(int, int);
 
@@ -200,11 +177,28 @@
  * on each context switch
  */
 
-#define flush_tlb()			local_flush_tlb()
-#define flush_tlb_all()			local_flush_tlb()
-#define flush_tlb_mm(mm)		local_flush_tlb()
-#define flush_tlb_page(vma, va)		local_flush_tlb()
-#define flush_tlb_range(mm, start, end)	local_flush_tlb()
+static inline void flush_tlb(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_all(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_range(struct mm_struct *mm,
+				   unsigned long start, unsigned long end)
+{
+	local_flush_tlb();
+}
 
 #else
 
@@ -251,11 +245,28 @@
 	}
 }
 
-#define flush_tlb()			__flush_tlb_mm(current->mm)
-#define flush_tlb_all()			global_flush_tlb()
-#define flush_tlb_mm(mm)		__flush_tlb_mm(mm)
-#define flush_tlb_page(vma, va)		__flush_tlb_mm((vma)->vm_mm)
-#define flush_tlb_range(mm, start, end)	__flush_tlb_mm(mm)
+static inline void flush_tlb(void)
+{
+	__flush_tlb_mm(current->mm);
+}
+static inline void flush_tlb_all(void)
+{
+	global_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	__flush_tlb_mm(mm); 
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	__flush_tlb_mm(vma->vm_mm);
+}
+static inline void flush_tlb_range(struct mm_struct *mm,
+				   unsigned long start, unsigned long end)
+{
+	__flush_tlb_mm(mm); 
+}
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/ptrace.h linux/include/asm-s390/ptrace.h
--- v2.4.3/linux/include/asm-s390/ptrace.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/ptrace.h	Wed Apr 11 19:02:28 2001
@@ -8,63 +8,220 @@
 
 #ifndef _S390_PTRACE_H
 #define _S390_PTRACE_H
+
+/*
+ * Offsets in the user_regs_struct. They are used for the ptrace
+ * system call and in entry.S
+ */
+#define PT_PSWMASK  0x00
+#define PT_PSWADDR  0x04
+#define PT_GPR0     0x08
+#define PT_GPR1     0x0C
+#define PT_GPR2     0x10
+#define PT_GPR3     0x14
+#define PT_GPR4     0x18
+#define PT_GPR5     0x1C
+#define PT_GPR6     0x20
+#define PT_GPR7     0x24
+#define PT_GPR8     0x28
+#define PT_GPR9     0x2C
+#define PT_GPR10    0x30
+#define PT_GPR11    0x34
+#define PT_GPR12    0x38
+#define PT_GPR13    0x3C
+#define PT_GPR14    0x40
+#define PT_GPR15    0x44
+#define PT_ACR0     0x48
+#define PT_ACR1     0x4C
+#define PT_ACR2     0x50
+#define PT_ACR3     0x54
+#define PT_ACR4	    0x58
+#define PT_ACR5	    0x5C
+#define PT_ACR6	    0x60
+#define PT_ACR7	    0x64
+#define PT_ACR8	    0x68
+#define PT_ACR9	    0x6C
+#define PT_ACR10    0x70
+#define PT_ACR11    0x74
+#define PT_ACR12    0x78
+#define PT_ACR13    0x7C
+#define PT_ACR14    0x80
+#define PT_ACR15    0x84
+#define PT_ORIGGPR2 0x88
+#define PT_FPC	    0x90
+/*
+ * A nasty fact of life that the ptrace api
+ * only supports passing of longs.
+ */
+#define PT_FPR0_HI  0x98
+#define PT_FPR0_LO  0x9C
+#define PT_FPR1_HI  0xA0
+#define PT_FPR1_LO  0xA4
+#define PT_FPR2_HI  0xA8
+#define PT_FPR2_LO  0xAC
+#define PT_FPR3_HI  0xB0
+#define PT_FPR3_LO  0xB4
+#define PT_FPR4_HI  0xB8
+#define PT_FPR4_LO  0xBC
+#define PT_FPR5_HI  0xC0
+#define PT_FPR5_LO  0xC4
+#define PT_FPR6_HI  0xC8
+#define PT_FPR6_LO  0xCC
+#define PT_FPR7_HI  0xD0
+#define PT_FPR7_LO  0xD4
+#define PT_FPR8_HI  0xD8
+#define PT_FPR8_LO  0XDC
+#define PT_FPR9_HI  0xE0
+#define PT_FPR9_LO  0xE4
+#define PT_FPR10_HI 0xE8
+#define PT_FPR10_LO 0xEC
+#define PT_FPR11_HI 0xF0
+#define PT_FPR11_LO 0xF4
+#define PT_FPR12_HI 0xF8
+#define PT_FPR12_LO 0xFC
+#define PT_FPR13_HI 0x100
+#define PT_FPR13_LO 0x104
+#define PT_FPR14_HI 0x108
+#define PT_FPR14_LO 0x10C
+#define PT_FPR15_HI 0x110
+#define PT_FPR15_LO 0x114
+#define PT_CR_9	    0x118
+#define PT_CR_10    0x11C
+#define PT_CR_11    0x120
+#define PT_IEEE_IP  0x13C
+#define PT_LASTOFF  PT_IEEE_IP
+#define PT_ENDREGS  0x140-1
+
+#define NUM_GPRS	16
+#define NUM_FPRS	16
+#define NUM_CRS		16
+#define NUM_ACRS	16
+#define GPR_SIZE	4
+#define FPR_SIZE	8
+#define FPC_SIZE	4
+#define FPC_PAD_SIZE	4 /* gcc insists on aligning the fpregs */
+#define CR_SIZE		4
+#define ACR_SIZE	4
+
+#define STACK_FRAME_OVERHEAD	96	/* size of minimum stack frame */
+
+#ifndef __ASSEMBLY__
 #include <linux/config.h>
-#include <asm/s390-regs-common.h>
-#include <asm/current.h>
+#include <linux/stddef.h>
 #include <linux/types.h>
+
+#include <asm/current.h>
 #include <asm/setup.h>
-#include <linux/stddef.h>
 
+/* this typedef defines how a Program Status Word looks like */
+typedef struct 
+{
+        __u32   mask;
+        __u32   addr;
+} psw_t __attribute__ ((aligned(8)));
+
+#ifdef __KERNEL__
+#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL)
+#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff)
+#endif
 
-#define S390_REGS   \
-S390_REGS_COMMON    \
-__u32 orig_gpr2;
+typedef union
+{
+	float   f;
+	double  d;
+        __u64   ui;
+	struct
+	{
+		__u32 hi;
+		__u32 lo;
+	} fp;
+} freg_t;
+
+typedef struct
+{
+	__u32   fpc;
+	freg_t  fprs[NUM_FPRS];              
+} s390_fp_regs;
+
+#define FPC_EXCEPTION_MASK      0xF8000000
+#define FPC_FLAGS_MASK          0x00F80000
+#define FPC_DXC_MASK            0x0000FF00
+#define FPC_RM_MASK             0x00000003
+#define FPC_VALID_MASK          0xF8F8FF03
 
+/*
+ * The first entries in pt_regs, gdb_pt_regs and user_regs_struct
+ * are common for all three structures. The s390_regs structure
+ * covers the common parts. It simplifies copying the common part
+ * between the three structures.
+ */
 typedef struct
 {
-	S390_REGS
+	psw_t psw;
+	__u32 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u32 orig_gpr2;
 } s390_regs;
 
+/*
+ * The pt_regs struct defines the way the registers are stored on
+ * the stack during a system call.
+ */
 struct pt_regs 
 {
-	S390_REGS
+	psw_t psw;
+	__u32 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u32 orig_gpr2;
 	__u32 trap;
+        __u32 old_ilc;
 };
 
+/*
+ * The gdb_pt_regs struct is used instead of the pt_regs structure
+ * if kernel remote debugging is used.
+ */
 #if CONFIG_REMOTE_DEBUG
-typedef struct
+struct gdb_pt_regs
 {
-	S390_REGS
+	psw_t psw;
+	__u32 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u32 orig_gpr2;
 	__u32 trap;
 	__u32 crs[16];
 	s390_fp_regs fp_regs;
-} gdb_pt_regs;
+};
 #endif
 
-
+/*
+ * Now for the program event recording (trace) definitions.
+ */
 typedef struct
 {
-			__u32   cr[3];
+	__u32 cr[3];
 } per_cr_words  __attribute__((packed));
 
 #define PER_EM_MASK 0xE8000000
+
 typedef	struct
 {
-	unsigned    em_branching:1;
-	unsigned    em_instruction_fetch:1;
-	/* Switching on storage alteration automatically fixes
-	   the storage alteration event bit in the users std. */
-	unsigned    em_storage_alteration:1;
-	unsigned    em_gpr_alt_unused:1;
-	unsigned    em_store_real_address:1;
-	unsigned    :3;
-	unsigned    branch_addr_ctl:1;
-	unsigned    :1;
-	unsigned    storage_alt_space_ctl:1;
-	unsigned    :5;
-	unsigned    :16;
-	addr_t      starting_addr;
-	addr_t      ending_addr;
+	unsigned em_branching          : 1;
+	unsigned em_instruction_fetch  : 1;
+	/*
+	 * Switching on storage alteration automatically fixes
+	 * the storage alteration event bit in the users std.
+	 */
+	unsigned em_storage_alteration : 1;
+	unsigned em_gpr_alt_unused     : 1;
+	unsigned em_store_real_address : 1;
+	unsigned                       : 3;
+	unsigned branch_addr_ctl       : 1;
+	unsigned                       : 1;
+	unsigned storage_alt_space_ctl : 1;
+	unsigned                       : 21;
+	addr_t   starting_addr;
+	addr_t   ending_addr;
 } per_cr_bits  __attribute__((packed));
 
 typedef struct
@@ -76,228 +233,59 @@
 
 typedef struct
 {
-	unsigned       perc_branching:1;               /* 0x096 */
-	unsigned       perc_instruction_fetch:1;
-	unsigned       perc_storage_alteration:1;
-	unsigned       perc_gpr_alt_unused:1;
-	unsigned       perc_store_real_address:1;
-	unsigned       :3;
-	unsigned       :1;
-	unsigned       atmid_validity_bit:1;
-	unsigned       atmid_psw_bit_32:1;
-	unsigned       atmid_psw_bit_5:1;
-	unsigned       atmid_psw_bit_16:1;
-	unsigned       atmid_psw_bit_17:1;
-	unsigned       si:2;
-	addr_t         address;              /* 0x098 */
-	unsigned       :4;                   /* 0x0a1 */
-	unsigned       access_id:4;           
+	unsigned perc_branching          : 1; /* 0x096 */
+	unsigned perc_instruction_fetch  : 1;
+	unsigned perc_storage_alteration : 1;
+	unsigned perc_gpr_alt_unused     : 1;
+	unsigned perc_store_real_address : 1;
+	unsigned                         : 4;
+	unsigned atmid_validity_bit      : 1;
+	unsigned atmid_psw_bit_32        : 1;
+	unsigned atmid_psw_bit_5         : 1;
+	unsigned atmid_psw_bit_16        : 1;
+	unsigned atmid_psw_bit_17        : 1;
+	unsigned si                      : 2;
+	addr_t   address;                     /* 0x098 */
+	unsigned                         : 4; /* 0x0a1 */
+	unsigned access_id               : 4;
 } per_lowcore_bits __attribute__((packed));
 
-typedef enum
-{
-	primary_asce,
-	ar_asce,
-	secondary_asce,
-	home_space_asce
-} per_ai_codes;
-
 typedef struct
 {
-	union
-	{
+	union {
 		per_cr_words   words;
 		per_cr_bits    bits;
 	} control_regs  __attribute__((packed));
-	/* Use these flags instead of setting em_instruction_fetch */
-	/* directly they are used so that single stepping can be */
-	/* switched on & off while not affecting other tracing */
-	unsigned  single_step:1;
-	unsigned  instruction_fetch:1;
-	unsigned  :30;
-	/* These addresses are copied into cr10 & cr11 if single stepping
-	   is switched off */
+	/*
+	 * Use these flags instead of setting em_instruction_fetch
+	 * directly they are used so that single stepping can be
+	 * switched on & off while not affecting other tracing
+	 */
+	unsigned  single_step       : 1;
+	unsigned  instruction_fetch : 1;
+	unsigned                    : 30;
+	/*
+	 * These addresses are copied into cr10 & cr11 if single
+	 * stepping is switched off
+	 */
 	__u32     starting_addr;
 	__u32     ending_addr;
-	union
-	{
+	union {
 		per_lowcore_words words;
 		per_lowcore_bits  bits;
 	} lowcore; 
 } per_struct __attribute__((packed));
 
-
-
-/* this struct defines the way the registers are stored on the
-   stack during a system call. If you change the pt_regs structure,
-   you'll need to change user.h too. 
-
-   N.B. if you modify the pt_regs struct the strace command also has to be
-   modified & recompiled  ( just wait till we have gdb going ).
-
-*/
-
-struct user_regs_struct
-{
-	S390_REGS
-	s390_fp_regs fp_regs;
-/* These per registers are in here so that gdb can modify them itself
- * as there is no "official" ptrace interface for hardware watchpoints.
- * this is the way intel does it
- */
-	per_struct per_info;
-	addr_t  ieee_instruction_pointer; 
-	/* Used to give failing instruction back to user for ieee exceptions */
-};
-
-typedef struct user_regs_struct user_regs_struct;
-
-typedef struct pt_regs pt_regs;
-
-#ifdef __KERNEL__
-#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
-#define instruction_pointer(regs) ((regs)->psw.addr)
-extern void show_regs(struct pt_regs * regs);
-extern char *task_show_regs(struct task_struct *task, char *buffer);
-#endif
-
-
-
-
-
-#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL)
-
-#define MULT_PROCPTR_TYPES    ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC))
-
-typedef struct
-{
-  long addr;
-  long toc;
-} routine_descriptor;
-extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs);
-extern __inline__ void 
-fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs)
-{
-  regs->psw.addr=FIX_PSW(rdes->addr);
-  regs->gprs[12]=rdes->toc;
-}
-
-/*
- * Compiler optimisation should save this stuff from being non optimal
- * & remove uneccessary code ( isnt gcc great DJB. )
- */
-
-/*I'm just using this an indicator of what binformat we are using
- * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise
- * dereferencing incomplete pointer types in with load_toc_binary
- */
-#if MULT_PROCPTR_TYPES
-#define uses_routine_descriptors() \
-(current->binfmt->load_binary==load_toc_binary)
-#else
-#if CONFIG_BINFMT_TOC
-#define uses_routine_descriptors() 1
-#else
-#define uses_routine_descriptors() 0
-#endif
-#endif
-
-#define pt_off(ptreg)   offsetof(user_regs_struct,ptreg)
-enum
-{
-	PT_PSWMASK=pt_off(psw.mask),
-	PT_PSWADDR=pt_off(psw.addr),
-	PT_GPR0=pt_off(gprs[0]),
-	PT_GPR1=pt_off(gprs[1]),
-	PT_GPR2=pt_off(gprs[2]),
-	PT_GPR3=pt_off(gprs[3]),
-	PT_GPR4=pt_off(gprs[4]),
-	PT_GPR5=pt_off(gprs[5]),
-	PT_GPR6=pt_off(gprs[6]),
-	PT_GPR7=pt_off(gprs[7]),
-	PT_GPR8=pt_off(gprs[8]),
-	PT_GPR9=pt_off(gprs[9]),
-	PT_GPR10=pt_off(gprs[10]),
-	PT_GPR11=pt_off(gprs[11]),
-	PT_GPR12=pt_off(gprs[12]),
-	PT_GPR13=pt_off(gprs[13]),
-	PT_GPR14=pt_off(gprs[14]),
-	PT_GPR15=pt_off(gprs[15]),
-        PT_ACR0=pt_off(acrs[0]),
-        PT_ACR1=pt_off(acrs[1]),
-        PT_ACR2=pt_off(acrs[2]),
-        PT_ACR3=pt_off(acrs[3]),
-        PT_ACR4=pt_off(acrs[4]),
-        PT_ACR5=pt_off(acrs[5]),
-        PT_ACR6=pt_off(acrs[6]),
-        PT_ACR7=pt_off(acrs[7]),
-        PT_ACR8=pt_off(acrs[8]),
-        PT_ACR9=pt_off(acrs[9]),
-        PT_ACR10=pt_off(acrs[10]),
-        PT_ACR11=pt_off(acrs[11]),
-        PT_ACR12=pt_off(acrs[12]),
-        PT_ACR13=pt_off(acrs[13]),
-        PT_ACR14=pt_off(acrs[14]),
-        PT_ACR15=pt_off(acrs[15]),
-	PT_ORIGGPR2=pt_off(orig_gpr2),
-	PT_FPC=pt_off(fp_regs.fpc),
-/*
- *      A nasty fact of life that the ptrace api
- *      only supports passing of longs.
- */
-	PT_FPR0_HI=pt_off(fp_regs.fprs[0].fp.hi),
-	PT_FPR0_LO=pt_off(fp_regs.fprs[0].fp.lo),
-	PT_FPR1_HI=pt_off(fp_regs.fprs[1].fp.hi),
-	PT_FPR1_LO=pt_off(fp_regs.fprs[1].fp.lo),
-	PT_FPR2_HI=pt_off(fp_regs.fprs[2].fp.hi),
-	PT_FPR2_LO=pt_off(fp_regs.fprs[2].fp.lo),
-	PT_FPR3_HI=pt_off(fp_regs.fprs[3].fp.hi),
-	PT_FPR3_LO=pt_off(fp_regs.fprs[3].fp.lo),
-	PT_FPR4_HI=pt_off(fp_regs.fprs[4].fp.hi),
-	PT_FPR4_LO=pt_off(fp_regs.fprs[4].fp.lo),
-	PT_FPR5_HI=pt_off(fp_regs.fprs[5].fp.hi),
-	PT_FPR5_LO=pt_off(fp_regs.fprs[5].fp.lo),
-	PT_FPR6_HI=pt_off(fp_regs.fprs[6].fp.hi),
-	PT_FPR6_LO=pt_off(fp_regs.fprs[6].fp.lo),
-	PT_FPR7_HI=pt_off(fp_regs.fprs[7].fp.hi),
-	PT_FPR7_LO=pt_off(fp_regs.fprs[7].fp.lo),
-	PT_FPR8_HI=pt_off(fp_regs.fprs[8].fp.hi),
-	PT_FPR8_LO=pt_off(fp_regs.fprs[8].fp.lo),
-	PT_FPR9_HI=pt_off(fp_regs.fprs[9].fp.hi),
-	PT_FPR9_LO=pt_off(fp_regs.fprs[9].fp.lo),
-	PT_FPR10_HI=pt_off(fp_regs.fprs[10].fp.hi),
-	PT_FPR10_LO=pt_off(fp_regs.fprs[10].fp.lo),
-	PT_FPR11_HI=pt_off(fp_regs.fprs[11].fp.hi),
-	PT_FPR11_LO=pt_off(fp_regs.fprs[11].fp.lo),
-	PT_FPR12_HI=pt_off(fp_regs.fprs[12].fp.hi),
-	PT_FPR12_LO=pt_off(fp_regs.fprs[12].fp.lo),
-	PT_FPR13_HI=pt_off(fp_regs.fprs[13].fp.hi),
-	PT_FPR13_LO=pt_off(fp_regs.fprs[13].fp.lo),
-	PT_FPR14_HI=pt_off(fp_regs.fprs[14].fp.hi),
-	PT_FPR14_LO=pt_off(fp_regs.fprs[14].fp.lo),
-	PT_FPR15_HI=pt_off(fp_regs.fprs[15].fp.hi),
-	PT_FPR15_LO=pt_off(fp_regs.fprs[15].fp.lo),
-	PT_CR_9=pt_off(per_info.control_regs.words.cr[0]),
-	PT_CR_10=pt_off(per_info.control_regs.words.cr[1]),
-	PT_CR_11=pt_off(per_info.control_regs.words.cr[2]),
-	PT_IEEE_IP=pt_off(ieee_instruction_pointer),
-	PT_LASTOFF=PT_IEEE_IP,
-	PT_ENDREGS=sizeof(user_regs_struct)-1
-};
-
-#define PTRACE_AREA \
-__u32 len;          \
-addr_t  kernel_addr; \
-addr_t  process_addr;
-
 typedef struct
 {
-	 PTRACE_AREA
+	__u32  len;
+	addr_t kernel_addr;
+	addr_t process_addr;
 } ptrace_area;
 
 /*
-  390 specific non posix ptrace requests
-  I chose unusual values so they are unlikely to clash with future ptrace definitions.
+ * S/390 specific non posix ptrace requests. I chose unusual values so
+ * they are unlikely to clash with future ptrace definitions.
  */
 #define PTRACE_PEEKUSR_AREA           0x5000
 #define PTRACE_POKEUSR_AREA           0x5001
@@ -305,7 +293,10 @@
 #define PTRACE_PEEKDATA_AREA	      0x5003
 #define PTRACE_POKETEXT_AREA	      0x5004
 #define PTRACE_POKEDATA_AREA 	      0x5005
-/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */
+/*
+ * PT_PROT definition is loosely based on hppa bsd definition in
+ * gdb/hppab-nat.c
+ */
 #define PTRACE_PROT                       21
 
 typedef enum
@@ -321,18 +312,41 @@
 	addr_t           hiaddr;
 	ptprot_flags     prot;
 } ptprot_area;                     
-#endif
-
-
-
-
-
-
-
-
-
 
+/* Sequence of bytes for breakpoint illegal instruction.  */
+#define S390_BREAKPOINT     {0x0,0x1}
+#define S390_BREAKPOINT_U16 ((__u16)0x0001)
+#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
+#define S390_SYSCALL_SIZE   2
 
+/*
+ * The user_regs_struct defines the way the user registers are
+ * store on the stack for signal handling.
+ */
+struct user_regs_struct
+{
+	psw_t psw;
+	__u32 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u32 orig_gpr2;
+	s390_fp_regs fp_regs;
+	/*
+	 * These per registers are in here so that gdb can modify them
+	 * itself as there is no "official" ptrace interface for hardware
+	 * watchpoints. This is the way intel does it.
+	 */
+	per_struct per_info;
+	addr_t  ieee_instruction_pointer; 
+	/* Used to give failing instruction back to user for ieee exceptions */
+};
 
+#ifdef __KERNEL__
+#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
+#define instruction_pointer(regs) ((regs)->psw.addr)
+extern void show_regs(struct pt_regs * regs);
+extern char *task_show_regs(struct task_struct *task, char *buffer);
+#endif
 
+#endif /* __ASSEMBLY__ */
 
+#endif /* _S390_PTRACE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/queue.h linux/include/asm-s390/queue.h
--- v2.4.3/linux/include/asm-s390/queue.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/queue.h	Wed Apr 11 19:02:28 2001
@@ -7,8 +7,8 @@
  *
  *  A little set of queue utilies.
  */
+
 #include <linux/stddef.h>
-#include <asm/types.h>
 
 typedef struct queue
 {
@@ -105,8 +105,8 @@
 
 	for(curr=lhead;curr!=NULL;curr=curr->next)
 		if(curr==member)
-			return(TRUE);
-	return(FALSE);
+			return(1);
+	return(0);
 }
 
 static __inline__ int get_prev(list *lhead,list *member,list **prev)
@@ -117,11 +117,11 @@
 	for(curr=lhead;curr!=NULL;curr=curr->next)
 	{
 		if(curr==member)
-			return(TRUE);
+			return(1);
 		*prev=curr;
 	}
 	*prev=NULL;
-	return(FALSE);
+	return(0);
 }
 
 
@@ -137,9 +137,9 @@
 			prev->next=member->next;
 		else
 			*lhead=member->next;
-		return(TRUE);
+		return(1);
 	}
-	return(FALSE);
+	return(0);
 }
 
 static __inline__ int remove_from_queue(qheader *qhead,queue *member)
@@ -161,9 +161,9 @@
 				qhead->tail=NULL;
 			qhead->head=member->next;
 		}
-		return(TRUE);
+		return(1);
 	}
-	return(FALSE);
+	return(0);
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/s390-regs-common.h linux/include/asm-s390/s390-regs-common.h
--- v2.4.3/linux/include/asm-s390/s390-regs-common.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/s390-regs-common.h	Wed Dec 31 16:00:00 1969
@@ -1,112 +0,0 @@
-/*
- *  include/asm-s390/s390-regs-common.h
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *
- *  this file is designed to keep as much compatibility between
- *  gdb's representation of registers & the kernels representation of registers
- *  as possible so as to minimise translation between gdb registers &
- *  kernel registers please keep this matched with gdb & strace 
- */
-
-#ifndef _S390_REGS_COMMON_H
-#define _S390_REGS_COMMON_H
-#ifndef __ASSEMBLY__
-#include <asm/types.h>
-#endif
-#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__)
-#define REGISTER_SIZE 4
-#endif
-#define NUM_GPRS      16
-#define GPR_SIZE      4
-#define PSW_MASK_SIZE 4
-#define PSW_ADDR_SIZE 4
-#define NUM_FPRS      16
-#define FPR_SIZE      8
-#define FPC_SIZE      4
-#define FPC_PAD_SIZE  4 /* gcc insists on aligning the fpregs */
-#define NUM_CRS       16
-#define CR_SIZE       4
-#define NUM_ACRS      16
-#define ACR_SIZE      4
-
-#define STACK_FRAME_OVERHEAD    96      /* size of minimum stack frame */
-
-#ifndef __ASSEMBLY__
-/* this typedef defines how a Program Status Word looks like */
-typedef struct 
-{
-        __u32   mask;
-        __u32   addr;
-} psw_t __attribute__ ((aligned(8)));
-
-/* 2 __u32's are used for floats instead to compile  with a __STRICT_ANSI__ defined */ 
-typedef union
-{
-#ifdef __KERNEL__ 
-	__u64   d; /* mathemu.h gets upset otherwise */
-#else
-	double  d; /* ansi c dosen't like long longs & make sure that */
-	/* alignments are identical for both compiles */ 
-#endif
-       struct
-       {
-	       __u32 hi;
-	       __u32 lo;
-       } fp;
-       __u32    f; 
-} freg_t;
-
-typedef struct
-{
-/*
-  The compiler appears to like aligning freg_t on an 8 byte boundary
-  so I always access fpregs, this was causing fun when I was doing
-  coersions.
- */
-	__u32   fpc;
-	freg_t  fprs[NUM_FPRS];              
-} s390_fp_regs;
-
-#define FPC_EXCEPTION_MASK      0xF8000000
-#define FPC_FLAGS_MASK          0x00F80000
-#define FPC_DXC_MASK            0x0000FF00
-#define FPC_RM_MASK             0x00000003
-#define FPC_VALID_MASK         ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \
-                                 FPC_DXC_MASK|FPC_RM_MASK))
-
-/*
-  gdb structures & the kernel have this much always in common
- */
-#define S390_REGS_COMMON       \
-psw_t psw;                     \
-__u32 gprs[NUM_GPRS];          \
-__u32  acrs[NUM_ACRS];         \
-
-typedef struct
-{
-	S390_REGS_COMMON
-} s390_regs_common;
-
-
-/* Sequence of bytes for breakpoint illegal instruction.  */
-#define S390_BREAKPOINT {0x0,0x1}
-#define S390_BREAKPOINT_U16 ((__u16)0x0001)
-#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
-#define S390_SYSCALL_SIZE   2
-#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__)
-#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff)
-#endif
-#endif
-#endif
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/s390dyn.h linux/include/asm-s390/s390dyn.h
--- v2.4.3/linux/include/asm-s390/s390dyn.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/s390dyn.h	Wed Apr 11 19:02:28 2001
@@ -10,6 +10,10 @@
 #ifndef __s390dyn_h
 #define __s390dyn_h
 
+#ifndef _LINUX_LIST_H
+#include <linux/list.h>
+#endif
+
 struct _devreg;
 
 typedef  int  (* oper_handler_func_t)( int             irq,
@@ -23,6 +27,7 @@
    }  __attribute__ ((packed)) devreg_hc_t;
 
 typedef struct _devreg {
+	struct list_head list;
 	union {
 		int devno;
 		devreg_hc_t hc;       /* has controller info */
@@ -30,8 +35,6 @@
 
 	int                  flag;
 	oper_handler_func_t  oper_func;
-	struct _devreg      *prev;
-	struct _devreg      *next;
 } devreg_t;
 
 #define DEVREG_EXACT_MATCH      0x00000001
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/s390io.h linux/include/asm-s390/s390io.h
--- v2.4.3/linux/include/asm-s390/s390io.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/s390io.h	Wed Apr 11 19:02:28 2001
@@ -75,7 +75,6 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
-     __u32         syncnt;       /* sync I/O recursive usage count */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/semaphore-helper.h linux/include/asm-s390/semaphore-helper.h
--- v2.4.3/linux/include/asm-s390/semaphore-helper.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/semaphore-helper.h	Wed Dec 31 16:00:00 1969
@@ -1,100 +0,0 @@
-/*
- *  include/asm-s390/semaphore-helper.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- *  Derived from "include/asm-i386/semaphore-helper.h"
- *    (C) Copyright 1996 Linus Torvalds
- *    (C) Copyright 1999 Andrea Arcangeli
- */
-
-#ifndef _S390_SEMAPHORE_HELPER_H
-#define _S390_SEMAPHORE_HELPER_H
-
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * but on the x86 we need an external synchronizer.
- */
-static inline void wake_one_more(struct semaphore * sem)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	sem->waking++;
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-}
-
-static inline int waking_non_zero(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-/*
- * waking_non_zero_interruptible:
- *	1	got the lock
- *	0	go to sleep
- *	-EINTR	interrupted
- *
- * If we give up we must undo our count-decrease we previously did in down().
- * Subtle: up() can continue to happens and increase the semaphore count
- * even during our critical section protected by the spinlock. So
- * we must remeber to undo the sem->waking that will be run from
- * wake_one_more() some time soon, if the semaphore count become > 0.
- */
-static inline int waking_non_zero_interruptible(struct semaphore *sem,
-						struct task_struct *tsk)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	} else if (signal_pending(tsk)) {
-               if (atomic_inc_and_test_greater_zero(&sem->count))
-                       sem->waking--;
-		ret = -EINTR;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-/*
- * waking_non_zero_trylock:
- *	1	failed to lock
- *	0	got the lock
- *
- * Implementation details are the same of the interruptible case.
- */
-static inline int waking_non_zero_trylock(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking <= 0)
-        {
-                if (atomic_inc_and_test_greater_zero(&sem->count))
-                        sem->waking--;
-        } else {
-		sem->waking--;
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/semaphore.h linux/include/asm-s390/semaphore.h
--- v2.4.3/linux/include/asm-s390/semaphore.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -14,6 +14,7 @@
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 	atomic_t count;
@@ -89,103 +90,6 @@
 {
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *		-ben
- */
-struct rw_semaphore {
-	atomic_t		count;
-	volatile unsigned int	write_bias_granted;
-	volatile unsigned int	read_bias_granted;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-};
-
-#define RW_LOCK_BIAS		 0x01000000
-
-#define __RWSEM_DEBUG_INIT	/* */
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-}
-
-extern void __down_read_failed(int, struct rw_semaphore *);
-extern void __down_write_failed(int, struct rw_semaphore *);
-extern void __rwsem_wake(int, struct rw_semaphore *);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_dec_return(&sem->count);
-	if (count < 0)
-		__down_read_failed(count, sem);
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_add_return (-RW_LOCK_BIAS, &sem->count);
-	if (count < 0)
-		__down_write_failed(count, sem);
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void up_read(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_inc_return(&sem->count);
-	if (count == 0)
-		__rwsem_wake(count, sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void up_write(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-	if (count >= 0 && count < RW_LOCK_BIAS)
-		__rwsem_wake(count, sem);
 }
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/setup.h linux/include/asm-s390/setup.h
--- v2.4.3/linux/include/asm-s390/setup.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/setup.h	Wed Apr 11 19:02:28 2001
@@ -8,46 +8,36 @@
 #ifndef _ASM_S390_SETUP_H
 #define _ASM_S390_SETUP_H
 
-#define PARMAREA 0x10400
+#define PARMAREA		0x10400
+#define COMMAND_LINE_SIZE 	896
+#define RAMDISK_ORIGIN		0x800000
+#define RAMDISK_SIZE		0x800000
 
 #ifndef __ASSEMBLER__
 
-#define ORIG_ROOT_DEV     (*(unsigned long *) (0x10400))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10404))
-#define MEMORY_SIZE       (*(unsigned long *)  (0x10406))
-#define MACHINE_FLAGS     (*(unsigned long *)  (0x1040a))
-#define INITRD_START      (*(unsigned long *)  (0x1040e))
-#define INITRD_SIZE       (*(unsigned long *)  (0x10412))
-#define RAMDISK_FLAGS     (*(unsigned short *) (0x10416))
+#define IPL_DEVICE        (*(unsigned long *)  (0x10404))
+#define INITRD_START      (*(unsigned long *)  (0x1040C))
+#define INITRD_SIZE       (*(unsigned long *)  (0x10414))
 #define COMMAND_LINE      ((char *)            (0x10480))
 
+/*
+ * Machine features detected in head.S
+ */
+extern unsigned long machine_flags;
+
+#define MACHINE_IS_VM    (machine_flags & 1)
+#define MACHINE_HAS_IEEE (machine_flags & 2)
+#define MACHINE_IS_P390  (machine_flags & 4)
+#define MACHINE_HAS_CSP  (machine_flags & 8)
+#define MACHINE_HAS_MVPG (machine_flags & 16)
+
 #else 
 
-#define ORIG_ROOT_DEV     0x10400
-#define MOUNT_ROOT_RDONLY 0x10404
-#define MEMORY_SIZE       0x10406
-#define MACHINE_FLAGS     0x1040a
-#define INITRD_START      0x1040e
-#define INITRD_SIZE       0x10412
-#define RAMDISK_FLAGS     0x10416
+#define IPL_DEVICE        0x10404
+#define INITRD_START      0x1040C
+#define INITRD_SIZE       0x10414
 #define COMMAND_LINE      0x10480
 
 #endif
-
-#define COMMAND_LINE_SIZE 896
-/*
- * Machine features detected in head.S
- */
-#define MACHINE_IS_VM    (MACHINE_FLAGS & 1)
-#define MACHINE_HAS_IEEE (MACHINE_FLAGS & 2)
-#define MACHINE_IS_P390  (MACHINE_FLAGS & 4)
-#define MACHINE_HAS_CSP  (MACHINE_FLAGS & 8)
-
-#define RAMDISK_ORIGIN            0x800000
-#define RAMDISK_BLKSIZE           0x1000
-#define RAMDISK_IMAGE_START_MASK  0x07FF
-#define RAMDISK_PROMPT_FLAG       0x8000
-#define RAMDISK_LOAD_FLAG         0x4000
-
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/sfp-machine.h linux/include/asm-s390/sfp-machine.h
--- v2.4.3/linux/include/asm-s390/sfp-machine.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/sfp-machine.h	Thu Apr 12 12:16:36 2001
@@ -0,0 +1,139 @@
+/* Machine-dependent software floating-point definitions.
+   S/390 kernel version.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+   
+#include <linux/config.h>
+
+#define _FP_W_TYPE_SIZE		32
+#define _FP_W_TYPE		unsigned long
+#define _FP_WS_TYPE		signed long
+#define _FP_I_TYPE		long
+
+#define _FP_MUL_MEAT_S(R,X,Y)					\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)					\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)					\
+  _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S		0
+#define _FP_NANSIGN_D		0
+#define _FP_NANSIGN_Q		0
+
+#define _FP_KEEPNANFRACP 1
+
+/*
+ * If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)                      \
+  do {                                                          \
+    if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)          \
+        && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs))     \
+      {                                                         \
+        R##_s = Y##_s;                                          \
+        _FP_FRAC_COPY_##wc(R,Y);                                \
+      }                                                         \
+    else                                                        \
+      {                                                         \
+        R##_s = X##_s;                                          \
+        _FP_FRAC_COPY_##wc(R,X);                                \
+      }                                                         \
+    R##_c = FP_CLS_NAN;                                         \
+  } while (0)
+
+/* Some assembly to speed things up. */
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) ({		\
+	unsigned int __r2 = (x2) + (y2);			\
+	unsigned int __r1 = (x1);				\
+	unsigned int __r0 = (x0);				\
+	__asm__ ("   alr %2,%3\n"				\
+		 "   brc 12,0f\n"				\
+		 "   lhi 0,1\n"					\
+		 "   alr %1,0\n"				\
+		 "   brc 12,0f\n"				\
+		 "   alr %0,0\n"				\
+		 "0:"						\
+		 : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0)	\
+		 : "d" (y0), "i" (1) : "cc", "0" );		\
+	__asm__ ("   alr %1,%2\n"				\
+		 "   brc 12,0f\n"				\
+		 "   ahi %0,1\n"				\
+		 "0:"						\
+		 : "+&d" (__r2), "+&d" (__r1)			\
+		 : "d" (y1) : "cc" );				\
+	(r2) = __r2;						\
+	(r1) = __r1;						\
+	(r0) = __r0;						\
+})
+
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) ({		\
+	unsigned int __r2 = (x2) - (y2);			\
+	unsigned int __r1 = (x1);				\
+	unsigned int __r0 = (x0);				\
+	__asm__ ("   slr %2,%3\n"				\
+		 "   brc 3,0f\n"				\
+		 "   lhi 0,1\n"					\
+		 "   slr %1,0\n"				\
+		 "   brc 3,0f\n"				\
+		 "   slr %0,0\n"				\
+		 "0:"						\
+		 : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0)	\
+		 : "d" (y0) : "cc", "0" );			\
+	__asm__ ("   slr %1,%2\n"				\
+		 "   brc 3,0f\n"				\
+		 "   ahi %0,-1\n"				\
+		 "0:"						\
+		 : "+&d" (__r2), "+&d" (__r1)			\
+		 : "d" (y1) : "cc" );				\
+	(r2) = __r2;						\
+	(r1) = __r1;						\
+	(r0) = __r0;						\
+})
+
+#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0)
+
+/* Obtain the current rounding mode. */
+#define FP_ROUNDMODE	mode
+
+/* Exception flags. */
+#define FP_EX_INVALID		0x800000
+#define FP_EX_DIVZERO		0x400000
+#define FP_EX_OVERFLOW		0x200000
+#define FP_EX_UNDERFLOW		0x100000
+#define FP_EX_INEXACT		0x080000
+
+/* We write the results always */
+#define FP_INHIBIT_RESULTS 0
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/signal.h linux/include/asm-s390/signal.h
--- v2.4.3/linux/include/asm-s390/signal.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/signal.h	Wed Apr 11 19:02:28 2001
@@ -71,6 +71,7 @@
 #define SIGLOST         29
 */
 #define SIGPWR          30
+#define SIGSYS		31
 #define SIGUNUSED       31
 
 /* These should not be considered constants from userland.  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/sigp.h linux/include/asm-s390/sigp.h
--- v2.4.3/linux/include/asm-s390/sigp.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/sigp.h	Wed Apr 11 19:02:28 2001
@@ -15,7 +15,6 @@
 #define __SIGP__
 
 #include <asm/ptrace.h>
-#include <asm/misc390.h>
 #include <asm/atomic.h>
 
 /* get real cpu address from logical cpu number */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/smp.h linux/include/asm-s390/smp.h
--- v2.4.3/linux/include/asm-s390/smp.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/smp.h	Wed Apr 11 19:02:28 2001
@@ -8,15 +8,24 @@
  */
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
+
 #include <linux/config.h>
-#ifdef CONFIG_SMP
-#ifndef __ASSEMBLY__
+
+#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
 
 #include <asm/lowcore.h>
-#include <linux/threads.h>  // FOR NR_CPUS definition only.
-#include <linux/kernel.h>   // FOR FASTCALL definition
 
-#define smp_processor_id() (current->processor)
+/*
+  s390 specific smp.c headers
+ */
+typedef struct
+{
+	int        intresting;
+	sigp_ccode ccode; 
+	__u32      status;
+	__u16      cpu;
+} sigp_info;
+
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
 /*
@@ -31,7 +40,7 @@
  
 #define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
 
-extern void count_cpus(void);
+#define smp_processor_id() (current->processor)
 
 extern __inline__ int cpu_logical_map(int cpu)
 {
@@ -55,25 +64,12 @@
 
 void smp_local_timer_interrupt(struct pt_regs * regs);
 
-/*
-  s390 specific smp.c headers
- */
-typedef struct
-{
-	int        intresting;
-	sigp_ccode ccode; 
-	__u32      status;
-	__u16      cpu;
-} sigp_info;
-
-sigp_ccode
-smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait);
-void smp_ext_call_others(void (*callback)(void *info), void *info, int wait);
+sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait);
+void smp_ext_call_others(void (*cb)(void *info), void *info, int wait);
 sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig);
 void smp_ext_bitcall_others(ec_bit_sig sig);
 
 int smp_signal_others(sigp_order_code order_code,__u32 parameter,
                       int spin,sigp_info *info);
-#endif
 #endif
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/spinlock.h linux/include/asm-s390/spinlock.h
--- v2.4.3/linux/include/asm-s390/spinlock.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/spinlock.h	Wed Apr 11 19:02:28 2001
@@ -73,6 +73,8 @@
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
+#define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
 #define read_lock(rw)   \
         asm volatile("   l     2,%0\n"   \
                      "   j     1f\n"     \
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/system.h linux/include/asm-s390/system.h
--- v2.4.3/linux/include/asm-s390/system.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/system.h	Wed Apr 11 19:02:28 2001
@@ -12,7 +12,6 @@
 #define __ASM_SYSTEM_H
 
 #include <linux/config.h>
-#include <asm/types.h>
 #ifdef __KERNEL__
 #include <asm/lowcore.h>
 #endif
@@ -33,6 +32,8 @@
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
+extern void __misaligned_u16(void);
+extern void __misaligned_u32(void);
 
 static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
@@ -43,14 +44,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 */
@@ -59,20 +60,21 @@
                                 "   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");
+				__misaligned_u16();
                         asm volatile (
                                 "   lhi   1,2\n"
                                 "   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 */
@@ -81,12 +83,12 @@
                                 "   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:
                         if(((__u32)ptr)&3)
-                                panic("misaligned (__u32 *) in __xchg\n");
+				__misaligned_u32();
                         asm volatile (
                                 "    l   0,0(%1)\n"
                                 "0:  cs  0,%0,0(%1)\n"
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/todclk.h linux/include/asm-s390/todclk.h
--- v2.4.3/linux/include/asm-s390/todclk.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/todclk.h	Wed Apr 11 19:02:28 2001
@@ -10,10 +10,14 @@
 #ifndef __ASM_TODCLK_H
 #define __ASM_TODCLK_H
 
+#ifdef __KERNEL__
+
 #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
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/types.h linux/include/asm-s390/types.h
--- v2.4.3/linux/include/asm-s390/types.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/types.h	Wed Apr 11 19:02:28 2001
@@ -55,12 +55,13 @@
 
 typedef u32 dma_addr_t;
 
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
+typedef union {
+	unsigned long long pair;
+	struct {
+		unsigned long even;
+		unsigned long odd;
+	} subreg;
+} register_pair;
 
 #endif                                 /* __KERNEL__                       */
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h
--- v2.4.3/linux/include/asm-s390/uaccess.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/uaccess.h	Wed Apr 11 19:02:28 2001
@@ -15,9 +15,7 @@
  * User space memory access functions
  */
 #include <linux/sched.h>
-#if 0
-#include <asm/segment.h>
-#endif
+
 #define VERIFY_READ     0
 #define VERIFY_WRITE    1
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/vtoc.h linux/include/asm-s390/vtoc.h
--- v2.4.3/linux/include/asm-s390/vtoc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/vtoc.h	Wed Apr 11 19:02:28 2001
@@ -0,0 +1,234 @@
+#ifndef __KERNEL__
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/hdreg.h>
+#include <linux/version.h>
+#endif
+#include <asm/dasd.h>
+
+#define LINE_LENGTH 80
+#define VTOC_START_CC 0x0
+#define VTOC_START_HH 0x1
+
+enum failure {unable_to_open,
+	      unable_to_seek,
+	      unable_to_write,
+	      unable_to_read};
+
+typedef struct ttr {
+        __u16 tt;
+        __u8  r;
+} __attribute__ ((packed)) ttr_t;
+
+typedef struct cchhb {
+        __u16 cc;
+        __u16 hh;
+        __u8 b;
+} __attribute__ ((packed)) cchhb_t;
+
+typedef struct cchh {
+        __u16 cc;
+        __u16 hh;
+} __attribute__ ((packed)) cchh_t;
+
+typedef struct labeldate {
+        __u8  year;
+        __u16 day;
+} __attribute__ ((packed)) labeldate_t;
+
+
+typedef struct volume_label {
+        char volkey[4];         /* volume key = volume label                 */
+	char vollbl[4];	        /* volume label                              */
+	char volid[6];	        /* volume identifier                         */
+	__u8 security;	        /* security byte                             */
+	cchhb_t vtoc;           /* VTOC address                              */
+	char res1[5];	        /* reserved                                  */
+        char cisize[4];	        /* CI-size for FBA,...                       */
+                                /* ...blanks for CKD                         */
+	char blkperci[4];       /* no of blocks per CI (FBA), blanks for CKD */
+	char labperci[4];       /* no of labels per CI (FBA), blanks for CKD */
+	char res2[4];	        /* reserved                                  */
+	char lvtoc[14];	        /* owner code for LVTOC                      */
+	char res3[29];	        /* reserved                                  */
+} __attribute__ ((packed)) volume_label_t;
+
+
+typedef struct extent {
+        __u8  typeind;          /* extent type indicator                     */
+        __u8  seqno;            /* extent sequence number                    */
+        cchh_t llimit;          /* starting point of this extent             */
+        cchh_t ulimit;          /* ending point of this extent               */
+} __attribute__ ((packed)) extent_t;
+
+
+typedef struct dev_const {
+        __u16 DS4DSCYL;           /* number of logical cyls                  */
+        __u16 DS4DSTRK;           /* number of tracks in a logical cylinder  */
+        __u16 DS4DEVTK;           /* device track length                     */
+        __u8  DS4DEVI;            /* non-last keyed record overhead          */
+        __u8  DS4DEVL;            /* last keyed record overhead              */
+        __u8  DS4DEVK;            /* non-keyed record overhead differential  */
+        __u8  DS4DEVFG;           /* flag byte                               */
+        __u16 DS4DEVTL;           /* device tolerance                        */
+        __u8  DS4DEVDT;           /* number of DSCB's per track              */
+        __u8  DS4DEVDB;           /* number of directory blocks per track    */
+} __attribute__ ((packed)) dev_const_t;
+
+
+typedef struct format1_label {
+	char  DS1DSNAM[44];       /* data set name                           */
+	__u8  DS1FMTID;           /* format identifier                       */
+	char  DS1DSSN[6];         /* data set serial number                  */
+	__u16 DS1VOLSQ;           /* volume sequence number                  */
+	labeldate_t DS1CREDT;     /* creation date: ydd                      */
+	labeldate_t DS1EXPDT;     /* expiration date                         */
+	__u8  DS1NOEPV;           /* number of extents on volume             */
+        __u8  DS1NOBDB;           /* no. of bytes used in last direction blk */
+	__u8  DS1FLAG1;           /* flag 1                                  */
+	char  DS1SYSCD[13];       /* system code                             */
+	labeldate_t DS1REFD;      /* date last referenced                    */
+        __u8  DS1SMSFG;           /* system managed storage indicators       */
+        __u8  DS1SCXTF;           /* sec. space extension flag byte          */
+        __u16 DS1SCXTV;           /* secondary space extension value         */
+        __u8  DS1DSRG1;           /* data set organisation byte 1            */
+        __u8  DS1DSRG2;           /* data set organisation byte 2            */
+  	__u8  DS1RECFM;           /* record format                           */
+	__u8  DS1OPTCD;           /* option code                             */
+	__u16 DS1BLKL;            /* block length                            */
+	__u16 DS1LRECL;           /* record length                           */
+	__u8  DS1KEYL;            /* key length                              */
+	__u16 DS1RKP;             /* relative key position                   */
+	__u8  DS1DSIND;           /* data set indicators                     */
+        __u8  DS1SCAL1;           /* secondary allocation flag byte          */
+  	char DS1SCAL3[3];         /* secondary allocation quantity           */
+	ttr_t DS1LSTAR;           /* last used track and block on track      */
+	__u16 DS1TRBAL;           /* space remaining on last used track      */
+        __u16 res1;               /* reserved                                */
+	extent_t DS1EXT1;         /* first extent description                */
+	extent_t DS1EXT2;         /* second extent description               */
+	extent_t DS1EXT3;         /* third extent description                */
+	cchhb_t DS1PTRDS;         /* possible pointer to f2 or f3 DSCB       */
+} __attribute__ ((packed)) format1_label_t;
+
+
+typedef struct format4_label {
+	char  DS4KEYCD[44];       /* key code for VTOC labels: 44 times 0x04 */
+        __u8  DS4IDFMT;           /* format identifier                       */
+	cchhb_t DS4HPCHR;         /* highest address of a format 1 DSCB      */
+        __u16 DS4DSREC;           /* number of available DSCB's              */
+        cchh_t DS4HCCHH;          /* CCHH of next available alternate track  */
+        __u16 DS4NOATK;           /* number of remaining alternate tracks    */
+        __u8  DS4VTOCI;           /* VTOC indicators                         */
+        __u8  DS4NOEXT;           /* number of extents in VTOC               */
+        __u8  DS4SMSFG;           /* system managed storage indicators       */
+        __u8  DS4DEVAC;           /* number of alternate cylinders. 
+                                     Subtract from first two bytes of 
+                                     DS4DEVSZ to get number of usable
+				     cylinders. can be zero. valid
+				     only if DS4DEVAV on.                    */
+        dev_const_t DS4DEVCT;     /* device constants                        */
+        char DS4AMTIM[8];         /* VSAM time stamp                         */
+        char DS4AMCAT[3];         /* VSAM catalog indicator                  */
+        char DS4R2TIM[8];         /* VSAM volume/catalog match time stamp    */
+        char res1[5];             /* reserved                                */
+        char DS4F6PTR[5];         /* pointer to first format 6 DSCB          */
+        extent_t DS4VTOCE;        /* VTOC extent description                 */
+        char res2[10];            /* reserved                                */
+        __u8 DS4EFLVL;            /* extended free-space management level    */
+        cchhb_t DS4EFPTR;         /* pointer to extended free-space info     */
+        char res3[9];             /* reserved                                */
+} __attribute__ ((packed)) format4_label_t;
+
+
+char * vtoc_ebcdic_enc (
+        unsigned char source[LINE_LENGTH],
+        unsigned char target[LINE_LENGTH],
+	int l);
+char * vtoc_ebcdic_dec (
+        unsigned char source[LINE_LENGTH],
+	unsigned char target[LINE_LENGTH],
+	int l);
+void vtoc_set_extent (
+        extent_t * ext,
+        __u8 typeind,
+        __u8 seqno,
+        cchh_t * lower,
+        cchh_t * upper);
+void vtoc_set_cchh (
+        cchh_t * addr,
+	__u16 cc,
+	__u16 hh);
+void vtoc_set_cchhb (
+        cchhb_t * addr,
+        __u16 cc,
+        __u16 hh,
+        __u8 b);
+void vtoc_set_date (
+        labeldate_t * d,
+        __u8 year,
+        __u16 day);
+
+
+int vtoc_read_volume_label (
+        char * device,
+        unsigned long vlabel_start,
+        volume_label_t * vlabel);
+int vtoc_write_volume_label (
+        char * device,
+        unsigned long vlabel_start,
+        volume_label_t * vlabel);
+void vtoc_read_label (
+        char *device,
+        unsigned long position,
+        format4_label_t *f4,
+        format1_label_t *f1);
+void vtoc_write_label (
+        char *device,
+        unsigned long position,
+	format4_label_t *f4,
+	format1_label_t *f1);
+void vtoc_init_format4_label (
+        struct hd_geometry *geo,
+        format4_label_t *f4lbl,
+	unsigned int usable_partitions,
+	unsigned int cylinders,
+	unsigned int tracks,
+	unsigned int blocks);
+void vtoc_init_format1_label (
+        char *volid,
+        unsigned int blksize,
+        extent_t *part_extent,
+        format1_label_t *f1);
+void vtoc_update_format4_label (
+	format4_label_t *f4,
+	cchhb_t *highest_f1,
+	__u8 unused_update,
+	__u16 freespace_update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/atomic.h linux/include/asm-s390x/atomic.h
--- v2.4.3/linux/include/asm-s390x/atomic.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/atomic.h	Wed Apr 11 19:02:29 2001
@@ -5,7 +5,7 @@
  *  include/asm-s390x/atomic.h
  *
  *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Denis Joseph Barrow
  *
@@ -25,6 +25,15 @@
 
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
+#define __CS_LOOP(old, new, ptr, op_val, op_string)			\
+        __asm__ __volatile__("   l     %0,0(%2)\n"			\
+                             "0: lr    %1,%0\n"				\
+                             op_string "  %1,%3\n"			\
+                             "   cs    %0,%1,0(%2)\n"			\
+                             "   jl    0b"				\
+                             : "=&d" (old), "=&d" (new)			\
+			     : "a" (ptr), "d" (op_val) : "cc" );
+
 static __inline__ int atomic_read(atomic_t *v)
 {
         int retval;
@@ -43,149 +52,80 @@
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,0(2)\n"
-                             "0: lr    1,0\n"
-                             "   ar    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, i, "ar");
 }
 
 static __inline__ int atomic_add_return (int i, atomic_t *v)
 {
-	int newval;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,0(1)\n"
-                             "0: lr    %1,0\n"
-                             "   ar    %1,%2\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (newval)
-			     : "d" (i) : "0", "1", "cc" );
-	return newval;
-}
-
-static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
-{
-       int i;
-
-        __asm__ __volatile__("   l     0,%0\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,1\n"
-                             "   cs    0,%1,%0\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
-       return i != 0;
+	int old, new;
+	__CS_LOOP(old, new, v, i, "ar");
+	return new;
 }
 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
-	int newval;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,0(1)\n"
-                             "0: lr    %1,0\n"
-                             "   ar    %1,%2\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b\n"
-                             : "+m" (*v), "=&d" (newval)
-                             : "d" (i) : "0", "1", "cc" );
-        return newval < 0;
+	int old, new;
+        __CS_LOOP(old, new, v, i, "ar");
+        return new < 0;
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,0(2)\n"
-                             "0: lr    1,0\n"
-                             "   sr    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, i, "sr");
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,0(2)\n"
-                             "0: lr    1,0\n"
-                             "   ahi   1,1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "ar");
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
-        int i;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,0(1)\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
-        return i;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "ar");
+        return new;
+}
+
+static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
+{
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "ar");
+	return new != 0;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,0(2)\n"
-                             "0: lr    1,0\n"
-                             "   ahi   1,-1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "sr");
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
-        int i;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,0(1)\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,-1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
-        return i;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "sr");
+	return new;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
-        int i;
-        __asm__ __volatile__("   la    1,%0\n"
-                             "   l     0,0(1)\n"
-                             "0: lr    %1,0\n"
-                             "   ahi   %1,-1\n"
-                             "   cs    0,%1,0(1)\n"
-                             "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc");
-        return i == 0;
+	int old, new;
+	__CS_LOOP(old, new, v, 1, "sr");
+        return new == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,0(2)\n"
-                             "0: lr    1,0\n"
-                             "   nr    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (~(mask))
-                             : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, ~mask, "nr");
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-        __asm__ __volatile__("   la    2,%0\n"
-                             "   l     0,0(2)\n"
-                             "0: lr    1,0\n"
-                             "   or    1,%1\n"
-                             "   cs    0,1,0(2)\n"
-                             "   jl    0b"
-                             : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" );
+	int old, new;
+	__CS_LOOP(old, new, v, mask, "or");
 }
 
 /*
@@ -198,14 +138,14 @@
         int retval;
 
         __asm__ __volatile__(
-                "  la   1,%1\n"
                 "  lr   0,%2\n"
-                "  cs   0,%3,0(1)\n"
+                "  cs   0,%3,0(%1)\n"
                 "  ipm  %0\n"
-                "  srl  %0,28"
-                : "=&r" (retval), "+m" (*v)
-                : "d" (expected_oldval) , "d" (new_val)
-                : "0", "1", "cc");
+                "  srl  %0,28\n"
+                "0:"
+                : "=&d" (retval)
+                : "a" (v), "d" (expected_oldval) , "d" (new_val)
+                : "0", "cc");
         return retval;
 }
 
@@ -216,13 +156,11 @@
 atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
 {
         __asm__ __volatile__(
-                "   la  1,%0\n"
                 "0: lr  0,%1\n"
-                "   cs  0,%2,0(1)\n"
+                "   cs  0,%2,0(%0)\n"
                 "   jl  0b\n"
-                : "+m" (*v)
-                : "d" (expected_oldval) , "d" (new_val)
-                : "cc", "0", "1");
+                : : "a" (v), "d" (expected_oldval) , "d" (new_val)
+                : "cc", "0" );
 }
 
 #define atomic_compare_and_swap_debug(where,from,to) \
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/ccwcache.h linux/include/asm-s390x/ccwcache.h
--- v2.4.3/linux/include/asm-s390x/ccwcache.h	Fri Mar  2 11:12:06 2001
+++ linux/include/asm-s390x/ccwcache.h	Wed Apr 11 19:02:29 2001
@@ -62,6 +62,7 @@
 #define CQR_STATUS_DONE     0x04	/* request is completed successfully */
 #define CQR_STATUS_ERROR    0x05	/* request is completed with error */
 #define CQR_STATUS_FAILED   0x06	/* request is finally failed */
+#define CQR_STATUS_PENDING  0x07        /* request is waiting for interrupt - ERP only */ 
 
 #define CQR_FLAGS_CHAINED  0x01	/* request is chained by another (last CCW is TIC) */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/chandev.h linux/include/asm-s390x/chandev.h
--- v2.4.3/linux/include/asm-s390x/chandev.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/chandev.h	Wed Apr 11 19:02:29 2001
@@ -66,6 +66,12 @@
                       unsigned long  irqflags,
                       const char    *devname,
                       void          *dev_id);
+/*
+ * I originally believed this function wouldn't be necessary
+ * I subsequently found that reprobing failed in certain cases :-(,
+ * It is just a wrapper for free irq.
+ */
+void chandev_free_irq(unsigned int irq, void *dev_id);
 
 typedef enum
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/cpcmd.h linux/include/asm-s390x/cpcmd.h
--- v2.4.3/linux/include/asm-s390x/cpcmd.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390x/cpcmd.h	Wed Apr 11 19:02:29 2001
@@ -0,0 +1,14 @@
+/*
+ *  arch/s390/kernel/cpcmd.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#ifndef __CPCMD__
+#define __CPCMD__
+
+extern void cpcmd(char *cmd, char *response, int rlen);
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h
--- v2.4.3/linux/include/asm-s390x/dasd.h	Fri Mar  2 11:12:06 2001
+++ linux/include/asm-s390x/dasd.h	Wed Apr 11 19:02:29 2001
@@ -5,11 +5,16 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
  * History of changes (starts July 2000)
+ * 02/01/01 added dynamic registration of ioctls
  */
 
 #ifndef DASD_H
 #define DASD_H
 
+#undef ERP_DEBUG               /* enable debug messages */
+#undef ERP_FULL_ERP            /* enable full ERP - experimental code !!!! */
+#define CONFIG_DASD_DYNAMIC
+
 #include <linux/ioctl.h>
 #include <asm/irq.h>
 
@@ -29,6 +34,10 @@
 /* translate blocknumber of partition to absolute */
 #define BIODASDRWTB    _IOWR(IOCTL_LETTER,0,int)
 
+typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args);
+int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler);
+int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler);
+
 #define DASD_NAME "dasd"
 #define DASD_PARTN_BITS 2
 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
@@ -49,6 +58,10 @@
 #define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
 #define DASD_FORMAT_DEFAULT_INTENSITY -1
 
+#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
+#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
+#define DASD_FORMAT_INTENS_INVALIDATE    0x04
+#define DASD_FORMAT_INTENS_CDL 0x08
 #ifdef __KERNEL__
 #include <linux/version.h>
 #include <linux/major.h>
@@ -135,9 +148,15 @@
 typedef struct dasd_devreg_t {
         devreg_t devreg; /* the devreg itself */
         /* build a linked list of devregs, needed for cleanup */
-        struct dasd_devreg_t *next;
+        struct list_head list;
 } dasd_devreg_t;
 
+typedef struct {
+	struct list_head list;
+	int no;
+	dasd_ioctl_fn_t handler;
+} dasd_ioctl_list_t;
+
 typedef enum {
 	dasd_era_fatal = -1,	/* no chance to recover              */
 	dasd_era_none = 0,	/* don't recover, everything alright */
@@ -168,7 +187,7 @@
         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:" \
+               "/dev/%s(%d:%d),%04X IRQ0x%x:" \
                d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
 } while(0)
 
@@ -181,6 +200,7 @@
 	unsigned long blocks; /* size of volume in blocks */
 	unsigned int bp_block; /* bytes per block */
 	unsigned int s2b_shift; /* log2 (bp_block/512) */
+        unsigned int pt_block; /* from which block to read the partn table */
 } dasd_sizes_t;
 
 /* 
@@ -193,6 +213,38 @@
 	ccw_req_t *tail;
 } dasd_chanq_t;
 
+#define DASD_DEVICE_FORMAT_STRING "Device: %p"
+#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_event(d_device->debug_area,d_level,\
+                    DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                    d_device, d_data);\
+} while(0);
+#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_exception(d_device->debug_area,d_level,\
+                        DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                        d_device, d_data);\
+} while(0);
+
+#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
+#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_event(dasd_debug_area, d_level,\
+                    DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                    d_fn, d_data);\
+} while(0);
+#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_exception(dasd_debug_area, d_level,\
+                        DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                        d_fn, d_data);\
+} while(0);
+
 struct dasd_device_t;
 struct request;
 
@@ -230,7 +282,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;	/* maximum number of blocks to be chained */
 	dasd_ck_id_fn_t id_check;	/* to check sense data */
 	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
 	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
@@ -251,9 +303,13 @@
 	struct dasd_discipline_t *next;	/* used for list of disciplines */
 } dasd_discipline_t;
 
+#define DASD_MAJOR_INFO_REGISTERED 1
+#define DASD_MAJOR_INFO_IS_STATIC 2
+
 typedef struct major_info_t {
-	struct major_info_t *next;
+	struct list_head list;
 	struct dasd_device_t **dasd_device;
+	int flags;
 	struct gendisk gendisk; /* actually contains the major number */
 } __attribute__ ((packed)) major_info_t;
 
@@ -278,6 +334,7 @@
 	struct dasd_chanq_t queue;
         wait_queue_head_t wait_q;
         request_queue_t request_queue;
+        struct timer_list timer;      
 	devstat_t dev_status; /* needed ONLY!! for request_irq */
         dasd_sizes_t sizes;
         char name[16]; /* The name of the device in /dev */
@@ -300,7 +357,7 @@
 #define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
 #define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
 #define DASD_DEVICE_LEVEL_ANALYSED 0x08
-#define DASD_DEVICE_LEVEL_PARTITIONED 0x10
+#define DASD_DEVICE_LEVEL_ONLINE 0x10
 
 int dasd_init (void);
 void dasd_discipline_enq (dasd_discipline_t *);
@@ -312,8 +369,12 @@
 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 *);
-int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
 int dasd_oper_handler (int irq, devreg_t * devreg);
+void dasd_schedule_bh (dasd_device_t *);
+
+debug_info_t *dasd_debug_area;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/debug.h linux/include/asm-s390x/debug.h
--- v2.4.3/linux/include/asm-s390x/debug.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/debug.h	Wed Apr 11 19:02:29 2001
@@ -19,9 +19,8 @@
                 struct {
                         unsigned long long clock:52;
                         unsigned long long exception:1;
-                        unsigned long long used:1;
-                        unsigned long long unused:1;
-                        unsigned long long cpuid:9;
+                        unsigned long long level:3;
+                        unsigned long long cpuid:8;
                 } fields;
 
                 unsigned long long stck;
@@ -29,6 +28,9 @@
         void* caller;
 } __attribute__((packed));
 
+
+#define __DEBUG_FEATURE_VERSION      1  /* version of debug feature */
+
 #ifdef __KERNEL__
 #include <linux/version.h>
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
@@ -45,7 +47,6 @@
 #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_FEATURE_VERSION      1  /* version of debug feature */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
 
@@ -103,43 +104,98 @@
 	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_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);
 
 void debug_set_level(debug_info_t* id, int new_level);
 
-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);
+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));
+}
 
-static inline debug_entry_t *
+extern inline debug_entry_t *
 debug_long_event (debug_info_t* id, int level, unsigned long tag)
 {
-	unsigned long t=tag;
-	return debug_event(id,level,&t,sizeof(unsigned long));
+        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));
 }
-static inline debug_entry_t *
+
+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;
-	return debug_exception(id,level,&t,sizeof(unsigned long));
+        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 --recursive --new-file v2.4.3/linux/include/asm-s390x/delay.h linux/include/asm-s390x/delay.h
--- v2.4.3/linux/include/asm-s390x/delay.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/delay.h	Wed Apr 11 19:02:29 2001
@@ -8,7 +8,7 @@
  *  Derived from "include/asm-i386/delay.h"
  *    Copyright (C) 1993 Linus Torvalds
  *
- *  Delay routines calling functions in arch/i386/lib/delay.c
+ *  Delay routines calling functions in arch/s390x/lib/delay.c
  */
  
 #ifndef _S390_DELAY_H
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/ebcdic.h linux/include/asm-s390x/ebcdic.h
--- v2.4.3/linux/include/asm-s390x/ebcdic.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/ebcdic.h	Wed Apr 11 19:02:29 2001
@@ -24,24 +24,18 @@
 extern __inline__ void
 codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
 {
-        static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 };
+	if (nr <= 0)
+		return;
         __asm__ __volatile__(
-                "   lgr   1,%0\n"
-                "   lgr   2,%1\n"
-                "   lgr   3,%2\n"
-                "   aghi  2,-256\n"
-                "   jm    1f\n"
-                "0: tr    0(256,1),0(3)\n"
-                "   aghi  1,256\n"
-                "   aghi  2,-256\n"
-                "   jp    0b\n"
-                "1: aghi  2,255\n"
-                "   jm    2f\n"
-                "   ex    2,%3\n"
-                "2:"
-                : /* no output */ 
-                : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0])
-                : "cc", "memory", "1", "2", "3" );
+		"   bras  1,1f\n"
+		"   tr    0(1,%0),0(%2)\n"
+		"0: la    %0,256(%0)\n"
+		"   tr    0(256,%0),0(%2)\n"
+		"1: ahi   %1,-256\n"
+		"   jp    0b\n"
+		"   ex    %1,0(1)"
+		: "+&a" (addr), "+&a" (nr-1)
+		: "a" (codepage) : "cc", "memory", "1" );
 }
 
 #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr)
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/elf.h linux/include/asm-s390x/elf.h
--- v2.4.3/linux/include/asm-s390x/elf.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/elf.h	Wed Apr 11 19:02:29 2001
@@ -31,7 +31,8 @@
  * This is used to ensure we don't load something for the wrong architecture.
  */
 #define elf_check_arch(x) \
-        ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+        (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
+         && (x)->e_ident[EI_CLASS] == ELF_CLASS)
 
 /* For SVR4/S390 the function pointer to be registered with `atexit` is
    passed in R14. */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/irq.h linux/include/asm-s390x/irq.h
--- v2.4.3/linux/include/asm-s390x/irq.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/irq.h	Wed Apr 11 19:02:29 2001
@@ -1,5 +1,5 @@
-#ifndef __irq_h
-#define __irq_h
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
 
 #include <linux/config.h>
 #ifdef __KERNEL__
@@ -19,28 +19,6 @@
 extern int enable_irq(unsigned int);
 
 /*
- * Interrupt controller descriptor. This is all we need
- * to describe about the low-level hardware.
- */
-struct hw_interrupt_type {
-        const __u8   *typename;
-        int         (*handle)(unsigned int irq,
-                              int cpu,
-                              struct pt_regs * regs);
-        int         (*enable) (unsigned int irq);
-        int         (*disable)(unsigned int irq);
-};
-
-/*
- * Status: reason for being disabled: somebody has
- * done a "disable_irq()" or we must not re-enter the
- * already executing irq..
- */
-#define IRQ_INPROGRESS  1
-#define IRQ_DISABLED    2
-#define IRQ_PENDING     4
-
-/*
  * path management control word
  */
 typedef struct {
@@ -86,7 +64,7 @@
       __u32 pfch : 1; /* prefetch */
       __u32 isic : 1; /* initial-status interruption control */
       __u32 alcc : 1; /* address-limit checking control */
-      __u32 ssi  : 1; /* suppress-suspended interruption */
+      __u32 ssi  : 1; /* supress-suspended interruption */
       __u32 zcc  : 1; /* zero condition code */
       __u32 ectl : 1; /* extended control */
       __u32 pno  : 1;     /* path not operational */
@@ -186,7 +164,7 @@
 
 typedef struct {
       __u8  cmd_code;/* command code */
-      __u8  flags;   /* flags, like IDA addressing, etc. */
+      __u8  flags;   /* flags, like IDA adressing, etc. */
       __u16 count;   /* byte count */
       __u32 cda;     /* data address */
    } __attribute__ ((packed,aligned(8))) ccw1_t;
@@ -456,24 +434,10 @@
 
 typedef  int  (* adapter_int_handler_t)( __u32 intparm );
 
-struct s390_irqaction {
-	io_handler_func_t  handler;
-	unsigned long      flags;
-	const char        *name;
-	devstat_t         *dev_id;
-};
-
-/*
- * This is the "IRQ descriptor", which contains various information
- * about the irq, including what kind of hardware handling it has,
- * whether it is disabled etc etc.
- *
- * Pad this out to 32 bytes for cache and indexing reasons.
- */
 typedef struct {
-      unsigned int              status;    /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */
-      struct hw_interrupt_type *handler;   /* handle/enable/disable functions */
-      struct s390_irqaction    *action;    /* IRQ action list */
+	io_handler_func_t         handler;  /* interrupt handler routine */
+	const char               *name;     /* device name */
+	devstat_t                *dev_id;   /* device status block */
    } irq_desc_t;
 
 typedef struct {
@@ -531,9 +495,8 @@
 /*
  * do_IO()
  *
- * Start a S/390 channel program. When the interrupt arrives
- *  handle_IRQ_event() is called, which eventually calls the
- *  IRQ handler, either immediately, delayed (dev-end missing,
+ *  Start a S/390 channel program. When the interrupt arrives, the
+ *  IRQ handler is called, either immediately, delayed (dev-end missing,
  *  or sense required) or never (no IRQ handler registered -
  *  should never occur, as the IRQ (subchannel ID) should be
  *  disabled if no handler is present. Depending on the action
@@ -606,8 +569,6 @@
                               const char              *devname,
                               void                    *dev_id);
 
-extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *);
-
 extern int set_cons_dev(int irq);
 extern int reset_cons_dev(int irq);
 extern int wait_cons_dev(int irq);
@@ -621,16 +582,13 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "STSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
-                : "cc", "1" );
+                "   lr    1,%1\n"
+                "   stsch 0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode)
+		: "d" (irq | 0x10000), "a" (addr)
+		: "cc", "1" );
         return ccode;
 }
 
@@ -639,15 +597,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "MSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                "   lr    1,%1\n"
+                "   msch  0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode)
+		: "d" (irq | 0x10000L), "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -657,12 +612,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "    lgr  1,%1\n"
+                "    lr   1,%1\n"
                 "    msch 0(%2)\n"
                 "0:  ipm  %0\n"
                 "    srl  %0,28\n"
                 "1:\n"
+#ifdef CONFIG_ARCH_S390X
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
                 "    jg   1b\n"
@@ -671,12 +626,12 @@
                 "   .align 8\n"
                 "   .quad 0b,2b\n"
                 ".previous"
-#else
                 "    lr   1,%1\n"
                 "    msch 0(%2)\n"
                 "0:  ipm  %0\n"
                 "    srl  %0,28\n"
                 "1:\n"
+#else
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
                 "    bras 1,3f\n"
@@ -690,7 +645,7 @@
                 ".previous"
 #endif
                 : "=d" (ccode)
-                : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC)
+                : "d" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC)
                 : "cc", "1" );
         return ccode;
 }
@@ -700,15 +655,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "TSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                "   lr    1,%1\n"
+                "   tsch  0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L), "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -718,10 +670,11 @@
         int ccode;
 
         __asm__ __volatile__(
-                "TPI 0(%1)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "a" (addr)
+                "   tpi   0(%1)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -731,15 +684,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "SSCH 0(%2)\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                "   lr    1,%1\n"
+                "   ssch  0(%2)\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L), "a" (addr)
                 : "cc", "1" );
         return ccode;
 }
@@ -749,15 +699,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "RSCH\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L)
+                "   lr    1,%1\n"
+                "   rsch\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
                 : "cc", "1" );
         return ccode;
 }
@@ -767,15 +714,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "CSCH\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L)
+                "   lr    1,%1\n"
+                "   csch\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
                 : "cc", "1" );
         return ccode;
 }
@@ -785,15 +729,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "HSCH\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (irq | 0x10000L)
+                "   lr    1,%1\n"
+                "   hsch\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
                 : "cc", "1" );
         return ccode;
 }
@@ -803,9 +744,9 @@
         int ccode;
 
         __asm__ __volatile__(
-                "IAC 1\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
+                "   iac   1\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
                 : "=d" (ccode) : : "cc", "1" );
         return ccode;
 }
@@ -815,15 +756,12 @@
         int ccode;
 
         __asm__ __volatile__(
-#ifdef CONFIG_ARCH_S390X
-                "LGR 1,%1\n\t"
-#else
-                "LR 1,%1\n\t"
-#endif
-                "RCHP\n\t"
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "r" (chpid)
+                "   lr    1,%1\n"
+                "   rchp\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (chpid)
                 : "cc", "1" );
         return ccode;
 }
@@ -850,16 +788,16 @@
 
         __asm__ __volatile__(
 #ifdef CONFIG_ARCH_S390X
-                "SAM31\n\t"
-                "DIAG %1,0,0x210\n\t"
-                "SAM64\n\t"
-#else
-                "LR 1,%1\n\t"
-                ".long 0x83110210\n\t"
-#endif
-                "IPM %0\n\t"
-                "SRL %0,28\n\t"
-                : "=d" (ccode) : "a" (addr)
+                "   sam31\n"
+                "   diag  %1,0,0x210\n"
+                "   sam64\n"
+#else
+                "   diag  %1,0,0x210\n"
+#endif
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "a" (addr)
                 : "cc" );
         return ccode;
 }
@@ -885,15 +823,9 @@
 static inline void irq_enter(int cpu, unsigned int irq)
 {
         hardirq_enter(cpu);
-#ifdef CONFIG_ARCH_S390X
         while (atomic_read(&global_irq_lock) != 0) {
                 eieio();
         }
-#else
-        while (test_bit(0,&global_irq_lock)) {
-                eieio();
-        }
-#endif
 }
 
 static inline void irq_exit(int cpu, unsigned int irq)
@@ -958,5 +890,8 @@
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
 #endif /* __KERNEL__ */
+
+#define touch_nmi_watchdog() do { } while(0)
+
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/irqextras390.h linux/include/asm-s390x/irqextras390.h
--- v2.4.3/linux/include/asm-s390x/irqextras390.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/irqextras390.h	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/*
- *  include/asm-s390/irqextras390.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- */
-
-#ifndef __irqextras390_h
-#define __irqextras390_h
-
-/*
-  irqextras390.h by D.J. Barrow
-  if you are a bitfield fan &  are paranoid that ansi dosen't
-  give hard definitions about the size of an int or long you might
-  prefer these definitions as an alternative.
-
-*/
-
-#include <linux/types.h>
-
-typedef struct 
-{
-      unsigned key:4;
-      unsigned s:1;
-      unsigned l:1;
-      unsigned cc:2;
-      unsigned f:1;
-      unsigned p:1;
-      unsigned i:1;
-      unsigned a:1;
-      unsigned u:1;
-      unsigned z:1;
-      unsigned e:1;
-      unsigned n:1;
-      unsigned zero:1;
-      
-      unsigned fc_start:1;
-      unsigned fc_halt:1;
-      unsigned fc_clear:1;
-      
-      unsigned ac_resume_pending:1;
-      unsigned ac_start_pending:1;
-      unsigned ac_halt_pending:1;
-      unsigned ac_clear_pending:1;
-      unsigned ac_subchannel_active:1;
-      unsigned ac_device_active:1;
-      unsigned ac_suspended:1;
-      
-      unsigned sc_alert:1;
-      unsigned sc_intermediate:1;
-      unsigned sc_primary:1;
-      unsigned sc_seconary:1;
-      unsigned sc_status_pending:1;
-      
-      __u32	   ccw_address;
-      
-      unsigned dev_status_attention:1;
-      unsigned dev_status_modifier:1;
-      unsigned dev_status_control_unit_end:1;
-      unsigned dev_status_busy:1;
-      unsigned dev_status_channel_end:1;
-      unsigned dev_status_device_end:1;
-      unsigned dev_status_unit_check:1;
-      unsigned dev_status_unit_exception:1;
-      
-      unsigned sch_status_program_cont_int:1;
-      unsigned sch_status_incorrect_length:1;
-      unsigned sch_status_program_check:1;
-      unsigned sch_status_protection_check:1;
-      unsigned sch_status_channel_data_check:1;
-      unsigned sch_status_channel_control_check:1;
-      unsigned sch_status_interface_control_check:1;
-      unsigned sch_status_chaining_check:1;
-     
-      __u16	   byte_count;
-} scsw_bits_t __attribute__((packed));
-
-typedef struct
-{
-  __u32      flags;
-  __u32      ccw_address;
-  __u8       dev_status;
-  __u8       sch_status;
-  __u16      byte_count;
-} scsw_words_t __attribute__((packed));
-
-typedef struct
-{
-      __u8     cmd_code;
-      
-      unsigned cd:1;
-      unsigned cc:1;
-      unsigned sli:1;
-      unsigned skip:1;
-      unsigned pci:1;
-      unsigned ida:1;
-      unsigned s:1;
-      unsigned res1:1;
-
-      __u16	count;
-
-      __u32     ccw_data_address;
-} ccw1_bits_t __attribute__((packed,aligned(8)));
-
-typedef struct
-{
-      __u32		interruption_parm;
-      unsigned key:4;
-      unsigned s:1;
-      unsigned res1:3;
-      unsigned f:1;
-      unsigned p:1;
-      unsigned i:1;
-      unsigned a:1;
-      unsigned u:1;
-      __u8	   lpm;
-      unsigned l:1;
-      unsigned res2:7;
-      ccw1_bits_t	*ccw_program_address;
-} orb_bits_t __attribute__((packed));
-
-void fixchannelprogram(orb_bits_t *orbptr);
-void fixccws(ccw1_bits_t *ccwptr);
-enum
-{
-   ccw_write=0x1,
-   ccw_read=0x2,
-   ccw_read_backward=0xc,
-   ccw_control=0x3,
-   ccw_sense=0x4,
-   ccw_sense_id=0xe4,
-   ccw_transfer_in_channel0=0x8,
-   ccw_transfer_in_channel1=0x8,
-   ccw_set_x_mode=0xc3,		// according to uli's lan notes
-   ccw_nop=0x3			// according to uli's notes again
-                                        // n.b. ccw_control clashes with this
-                                        // so I presume its a special case of
-					// control
-};
-
-
-
-#endif
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/major.h linux/include/asm-s390x/major.h
--- v2.4.3/linux/include/asm-s390x/major.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/major.h	Wed Dec 31 16:00:00 1969
@@ -1,150 +0,0 @@
-#ifndef _LINUX_MAJOR_H
-#define _LINUX_MAJOR_H
-
-/*
- * This file has definitions for major device numbers.
- * For the device number assignments, see Documentation/devices.txt.
- */
-
-/* limits */
-
-/*
- * Important: Don't change this to 256.  Major number 255 is and must be
- * reserved for future expansion into a larger dev_t space.
- */
-#define MAX_CHRDEV	255
-#define MAX_BLKDEV	255
-
-#define UNNAMED_MAJOR	0
-#define MEM_MAJOR	1
-#define RAMDISK_MAJOR	1
-#define FLOPPY_MAJOR	2
-#define PTY_MASTER_MAJOR 2
-#define IDE0_MAJOR	3
-#define PTY_SLAVE_MAJOR 3
-#define HD_MAJOR	IDE0_MAJOR
-#define TTY_MAJOR	4
-#define TTYAUX_MAJOR	5
-#define LP_MAJOR	6
-#define VCS_MAJOR	7
-#define LOOP_MAJOR	7
-#define SCSI_DISK0_MAJOR 8
-#define SCSI_TAPE_MAJOR	9
-#define MD_MAJOR        9
-#define MISC_MAJOR	10
-#define SCSI_CDROM_MAJOR 11
-#define QIC02_TAPE_MAJOR 12
-#define XT_DISK_MAJOR	13
-#define SOUND_MAJOR	14
-#define CDU31A_CDROM_MAJOR 15
-#define JOYSTICK_MAJOR	15
-#define GOLDSTAR_CDROM_MAJOR 16
-#define OPTICS_CDROM_MAJOR 17
-#define SANYO_CDROM_MAJOR 18
-#define CYCLADES_MAJOR  19
-#define CYCLADESAUX_MAJOR 20
-#define MITSUMI_X_CDROM_MAJOR 20
-#define MFM_ACORN_MAJOR 21	/* ARM Linux /dev/mfm */
-#define SCSI_GENERIC_MAJOR 21
-#define Z8530_MAJOR 34
-#define DIGI_MAJOR 23
-#define IDE1_MAJOR	22
-#define DIGICU_MAJOR 22
-#define MITSUMI_CDROM_MAJOR 23
-#define CDU535_CDROM_MAJOR 24
-#define STL_SERIALMAJOR 24
-#define MATSUSHITA_CDROM_MAJOR 25
-#define STL_CALLOUTMAJOR 25
-#define MATSUSHITA_CDROM2_MAJOR 26
-#define QIC117_TAPE_MAJOR 27
-#define MATSUSHITA_CDROM3_MAJOR 27
-#define MATSUSHITA_CDROM4_MAJOR 28
-#define STL_SIOMEMMAJOR 28
-#define ACSI_MAJOR	28
-#define AZTECH_CDROM_MAJOR 29
-#define GRAPHDEV_MAJOR	29	/* SparcLinux & Linux/68k /dev/fb */
-#define SHMIQ_MAJOR	85	/* Linux/mips, SGI /dev/shmiq */
-#define CM206_CDROM_MAJOR 32
-#define IDE2_MAJOR	33
-#define IDE3_MAJOR	34
-#define NETLINK_MAJOR	36
-#define PS2ESDI_MAJOR	36
-#define IDETAPE_MAJOR	37
-#define Z2RAM_MAJOR	37
-#define APBLOCK_MAJOR   38   /* AP1000 Block device */
-#define DDV_MAJOR       39   /* AP1000 DDV block device */
-#define NBD_MAJOR	43   /* Network block device	*/
-#define RISCOM8_NORMAL_MAJOR 48
-#define DAC960_MAJOR	48	/* 48..55 */
-#define RISCOM8_CALLOUT_MAJOR 49
-#define MKISS_MAJOR	55
-#define DSP56K_MAJOR    55   /* DSP56001 processor device */
-
-#define IDE4_MAJOR	56
-#define IDE5_MAJOR	57
-
-#define SCSI_DISK1_MAJOR	65
-#define SCSI_DISK2_MAJOR	66
-#define SCSI_DISK3_MAJOR	67
-#define SCSI_DISK4_MAJOR	68
-#define SCSI_DISK5_MAJOR	69
-#define SCSI_DISK6_MAJOR	70
-#define SCSI_DISK7_MAJOR	71
-
-
-#define LVM_BLK_MAJOR	58	/* Logical Volume Manager */
-
-#define COMPAQ_SMART2_MAJOR	72
-#define COMPAQ_SMART2_MAJOR1	73
-#define COMPAQ_SMART2_MAJOR2	74
-#define COMPAQ_SMART2_MAJOR3	75
-#define COMPAQ_SMART2_MAJOR4	76
-#define COMPAQ_SMART2_MAJOR5	77
-#define COMPAQ_SMART2_MAJOR6	78
-#define COMPAQ_SMART2_MAJOR7	79
-
-#define SPECIALIX_NORMAL_MAJOR 75
-#define SPECIALIX_CALLOUT_MAJOR 76
-
-#define DASD_MAJOR      94
-
-#define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
-
-#define MDISK_MAJOR     64
-
-#define I2O_MAJOR		80	/* 80->87 */
-
-#define IDE6_MAJOR	88
-#define IDE7_MAJOR	89
-#define IDE8_MAJOR	90
-#define IDE9_MAJOR	91
-
-#define AURORA_MAJOR 79
-
-#define RTF_MAJOR	150
-#define RAW_MAJOR	162
-
-#define USB_ACM_MAJOR		166
-#define USB_ACM_AUX_MAJOR	167
-#define USB_CHAR_MAJOR		180
-
-#define UNIX98_PTY_MASTER_MAJOR	128
-#define UNIX98_PTY_MAJOR_COUNT	8
-#define UNIX98_PTY_SLAVE_MAJOR	(UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
-
-/*
- * Tests for SCSI devices.
- */
-
-#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
-  ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
-  
-#define SCSI_BLK_MAJOR(M) \
-  (SCSI_DISK_MAJOR(M)	\
-   || (M) == SCSI_CDROM_MAJOR)
-
-static __inline__ int scsi_blk_major(int m) {
-	return SCSI_BLK_MAJOR(m);
-}
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/misc390.h linux/include/asm-s390x/misc390.h
--- v2.4.3/linux/include/asm-s390x/misc390.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/misc390.h	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/*
- *  include/asm-s390/misc390.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- */
-
-#define	allocaligned2(type,name,number,align)				\
-   __u8	name##buff[(sizeof(type)*(number+1))-1]; 	                \
-   type	*name=(type *)(((__u32)(&name##buff[align-1]))&(-align))
-
-#define	allocaligned(type,name,number)  allocaligned2(type,name,number,__alignof__(type))
-
-extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs);
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/page.h linux/include/asm-s390x/page.h
--- v2.4.3/linux/include/asm-s390x/page.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/page.h	Wed Apr 11 19:02:29 2001
@@ -9,6 +9,8 @@
 #ifndef _S390_PAGE_H
 #define _S390_PAGE_H
 
+#include <asm/setup.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT      12
 #define PAGE_SIZE       (1UL << PAGE_SHIFT)
@@ -17,12 +19,43 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-/*
- * gcc uses builtin, i.e. MVCLE for both operations
- */
+static inline void clear_page(void *page)
+{
+        asm volatile ("   lgr  2,%0\n"
+                      "   lghi 3,4096\n"
+                      "   slgr 1,1\n"
+                      "   mvcl 2,0"
+                      : : "a" ((void *) (page))
+		      : "memory", "1", "2", "3" );
+}
 
-#define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from)      memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+static inline void copy_page(void *to, void *from)
+{
+        if (MACHINE_HAS_MVPG)
+		asm volatile ("   sgr  0,0\n"
+			      "   mvpg %0,%1"
+			      : : "a" ((void *)(to)), "a" ((void *)(from))
+			      : "memory", "0" );
+	else
+		asm volatile ("   mvc  0(256,%0),0(%1)\n"
+			      "   mvc  256(256,%0),256(%1)\n"
+			      "   mvc  512(256,%0),512(%1)\n"
+			      "   mvc  768(256,%0),768(%1)\n"
+			      "   mvc  1024(256,%0),1024(%1)\n"
+			      "   mvc  1280(256,%0),1280(%1)\n"
+			      "   mvc  1536(256,%0),1536(%1)\n"
+			      "   mvc  1792(256,%0),1792(%1)\n"
+			      "   mvc  2048(256,%0),2048(%1)\n"
+			      "   mvc  2304(256,%0),2304(%1)\n"
+			      "   mvc  2560(256,%0),2560(%1)\n"
+			      "   mvc  2816(256,%0),2816(%1)\n"
+			      "   mvc  3072(256,%0),3072(%1)\n"
+			      "   mvc  3328(256,%0),3328(%1)\n"
+			      "   mvc  3584(256,%0),3584(%1)\n"
+			      "   mvc  3840(256,%0),3840(%1)\n"
+			      : : "a"((void *)(to)),"a"((void *)(from)) 
+			      : "memory" );
+}
 
 #define clear_user_page(page, vaddr)    clear_page(page)
 #define copy_user_page(to, from, vaddr) copy_page(to, from)
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/pgalloc.h linux/include/asm-s390x/pgalloc.h
--- v2.4.3/linux/include/asm-s390x/pgalloc.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -33,9 +33,11 @@
  */
 extern __inline__ pgd_t *get_pgd_slow (void)
 {
+	pgd_t *ret;
         int i;
-	pgd_t *ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
-	if (ret)
+
+	ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2);
+	if (ret != NULL)
 	        for (i = 0; i < PTRS_PER_PGD; i++) 
 	                pgd_clear(ret + i);
 	return ret;
@@ -53,7 +55,7 @@
 	return (pgd_t *) ret;
 }
 
-extern __inline__ pgd_t *pgd_alloc (void)
+extern __inline__ pgd_t *pgd_alloc (struct mm_struct *mm)
 {
 	pgd_t *pgd;
 
@@ -77,15 +79,32 @@
 
 #define pgd_free(pgd)		free_pgd_fast(pgd)
 
+extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+{
+	pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
+}
+
 /*
  * page middle directory allocation/free routines.
  */
-extern pmd_t empty_bad_pmd_table[];
-extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address);
+extern inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+{
+	pmd_t *pmd;
+        int i;
 
-extern __inline__ pmd_t *get_pmd_fast (void)
+	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
+	if (pmd != NULL) {
+		for (i=0; i < PTRS_PER_PMD; i++)
+			pmd_clear(pmd+i);
+	}
+	return pmd;
+}
+
+extern __inline__ pmd_t *
+pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
 	unsigned long *ret = (unsigned long *) pmd_quicklist;
+
 	if (ret != NULL) {
 		pmd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
@@ -94,95 +113,67 @@
 	return (pmd_t *) ret;
 }
 
-extern __inline__ void free_pmd_fast (pmd_t *pmd)
+extern __inline__ void pmd_free_fast (pmd_t *pmd)
 {
-	if (pmd == empty_bad_pmd_table)
-		return;
 	*(unsigned long *) pmd = (unsigned long) pmd_quicklist;
 	pmd_quicklist = (unsigned long *) pmd;
 	pgtable_cache_size += 4;
 }
 
-extern __inline__ void free_pmd_slow (pmd_t *pmd)
+extern __inline__ void pmd_free_slow (pmd_t *pmd)
 {
 	free_pages((unsigned long) pmd, 2);
 }
 
-extern __inline__ pmd_t *pmd_alloc (pgd_t *pgd, unsigned long vmaddr)
-{
-	unsigned long offset;
+#define pmd_free(pmd)		pmd_free_fast(pmd)
 
-	offset = (vmaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *pmd_page = get_pmd_fast();
-
-		if (!pmd_page)
-			return get_pmd_slow(pgd, offset);
-                pgd_set(pgd, pmd_page);
-                return pmd_page + offset;
-	}
-	if (pgd_bad(*pgd))
-		BUG();
-	return (pmd_t *) pgd_page(*pgd) + offset;
+extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
+{
+	pmd_val(*pmd) = _PMD_ENTRY | __pa(pte);
+	pmd_val1(*pmd) = _PMD_ENTRY | __pa(pte+256);
 }
 
-#define pmd_alloc_kernel(pgd, addr)	pmd_alloc(pgd, addr)
-#define pmd_free_kernel(pmd)	free_pmd_fast(pmd)
-#define pmd_free(pmd)		free_pmd_fast(pmd)
-
 /*
  * page table entry allocation/free routines.
  */
-extern pte_t empty_bad_pte_table[];
-extern pte_t *get_pte_slow (pmd_t *pmd, unsigned long address_preadjusted);
-
-extern __inline__ pte_t *get_pte_fast (void)
+extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
-	unsigned long *ret = (unsigned long *) pte_quicklist;
+	pte_t *pte;
+        int i;
 
-	if (ret != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size--;
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte != NULL) {
+		for (i=0; i < PTRS_PER_PTE; i++)
+			pte_clear(pte+i);
 	}
-	return (pte_t *) ret;
+	return pte;
 }
 
-extern __inline__ void free_pte_fast (pte_t *pte)
+extern __inline__ pte_t* pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+{
+        unsigned long *ret = (unsigned long *) pte_quicklist;
+
+        if (ret != NULL) {
+                pte_quicklist = (unsigned long *)(*ret);
+                ret[0] = ret[1];
+                pgtable_cache_size--;
+        }
+        return (pte_t *)ret;
+}
+
+extern __inline__ void pte_free_fast (pte_t *pte)
 {
-	if (pte == empty_bad_pte_table)
-		return;
 	*(unsigned long *) pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
 
-extern __inline__ void free_pte_slow (pte_t *pte)
+extern __inline__ void pte_free_slow (pte_t *pte)
 {
         free_page((unsigned long) pte);
 }
 
-extern __inline__ pte_t *pte_alloc (pmd_t *pmd, unsigned long vmaddr)
-{
-	unsigned long offset;
-
-	offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *pte_page = get_pte_fast();
-
-		if (!pte_page)
-			return get_pte_slow(pmd, offset);
-		pmd_set(pmd, pte_page);
-		return pte_page + offset;
-	}
-	if (pmd_bad(*pmd))
-		BUG();
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-#define pte_alloc_kernel(pmd, addr)	pte_alloc(pmd, addr)
-#define pte_free_kernel(pte)	free_pte_fast(pte)
-#define pte_free(pte)		free_pte_fast(pte)
+#define pte_free(pte)		pte_free_fast(pte)
 
 extern int do_check_pgt_cache (int, int);
 
@@ -224,11 +215,28 @@
  * on each context switch
  */
 
-#define flush_tlb()			local_flush_tlb()
-#define flush_tlb_all()			local_flush_tlb()
-#define flush_tlb_mm(mm)		local_flush_tlb()
-#define flush_tlb_page(vma, va)		local_flush_tlb()
-#define flush_tlb_range(mm, start, end)	local_flush_tlb()
+static inline void flush_tlb(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_all(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_range(struct mm_struct *mm,
+				   unsigned long start, unsigned long end)
+{
+	local_flush_tlb();
+}
 
 #else
 
@@ -266,11 +274,28 @@
 	}
 }
 
-#define flush_tlb()			__flush_tlb_mm(current->mm)
-#define flush_tlb_all()			global_flush_tlb()
-#define flush_tlb_mm(mm)		__flush_tlb_mm(mm)
-#define flush_tlb_page(vma, va)		__flush_tlb_mm((vma)->vm_mm)
-#define flush_tlb_range(mm, start, end)	__flush_tlb_mm(mm)
+static inline void flush_tlb(void)
+{
+	__flush_tlb_mm(current->mm);
+}
+static inline void flush_tlb_all(void)
+{
+	global_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	__flush_tlb_mm(mm); 
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	__flush_tlb_mm(vma->vm_mm);
+}
+static inline void flush_tlb_range(struct mm_struct *mm,
+				   unsigned long start, unsigned long end)
+{
+	__flush_tlb_mm(mm); 
+}
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/pgtable.h linux/include/asm-s390x/pgtable.h
--- v2.4.3/linux/include/asm-s390x/pgtable.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/pgtable.h	Wed Apr 11 19:02:29 2001
@@ -228,21 +228,41 @@
 /*
  * pgd/pmd/pte query functions
  */
-extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) != 0; }
-extern inline int pgd_none(pgd_t pgd)    { return pgd_val(pgd) & _PGD_ENTRY_INV; }
+extern inline int pgd_present(pgd_t pgd)
+{
+	return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY;
+}
+
+extern inline int pgd_none(pgd_t pgd)
+{
+	return pgd_val(pgd) & _PGD_ENTRY_INV;
+}
+
 extern inline int pgd_bad(pgd_t pgd)
 {
 	return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY;
 }
 
-extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) != 0; }
-extern inline int pmd_none(pmd_t pmd)    { return pmd_val(pmd) & _PMD_ENTRY_INV; }
+extern inline int pmd_present(pmd_t pmd)
+{
+	return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY;
+}
+
+extern inline int pmd_none(pmd_t pmd)
+{
+	return pmd_val(pmd) & _PMD_ENTRY_INV;
+}
+
 extern inline int pmd_bad(pmd_t pmd)
 {
 	return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY;
 }
 
-extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
+extern inline int pte_present(pte_t pte)
+{
+	return pte_val(pte) & _PAGE_PRESENT;
+}
+
 extern inline int pte_none(pte_t pte)
 {
 	return ((pte_val(pte) & 
@@ -411,17 +431,6 @@
 #define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot)
 
 #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
-
-extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
-	pmd_val(*pmdp) = _PMD_ENTRY | __pa(ptep);
-	pmd_val1(*pmdp) = _PMD_ENTRY | __pa(ptep+256);
-}
-
-extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{
-	pgd_val(*pgdp) = _PGD_ENTRY | __pa(pmdp);
-}
 
 #define pmd_page(pmd) \
         ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/ptrace.h linux/include/asm-s390x/ptrace.h
--- v2.4.3/linux/include/asm-s390x/ptrace.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/ptrace.h	Wed Apr 11 19:02:29 2001
@@ -8,284 +8,266 @@
 
 #ifndef _S390_PTRACE_H
 #define _S390_PTRACE_H
+
+/*
+ * Offsets in the user_regs_struct. They are used for the ptrace
+ * system call and in entry.S
+ */
+#define PT_PSWMASK  0x00
+#define PT_PSWADDR  0x08
+#define PT_GPR0     0x10
+#define PT_GPR1     0x18
+#define PT_GPR2     0x20
+#define PT_GPR3     0x28
+#define PT_GPR4     0x30
+#define PT_GPR5     0x38
+#define PT_GPR6     0x40
+#define PT_GPR7     0x48
+#define PT_GPR8     0x50
+#define PT_GPR9     0x58
+#define PT_GPR10    0x60
+#define PT_GPR11    0x68
+#define PT_GPR12    0x70
+#define PT_GPR13    0x78
+#define PT_GPR14    0x80
+#define PT_GPR15    0x88
+#define PT_ACR0     0x90
+#define PT_ACR1     0x94
+#define PT_ACR2     0x98
+#define PT_ACR3     0x9C
+#define PT_ACR4	    0xA0
+#define PT_ACR5	    0xA4
+#define PT_ACR6	    0xA8
+#define PT_ACR7	    0xAC
+#define PT_ACR8	    0xB0
+#define PT_ACR9	    0xB4
+#define PT_ACR10    0xB8
+#define PT_ACR11    0xBC
+#define PT_ACR12    0xC0
+#define PT_ACR13    0xC4
+#define PT_ACR14    0xC8
+#define PT_ACR15    0xCC
+#define PT_ORIGGPR2 0xD0
+#define PT_FPC	    0xD8
+#define PT_FPR0     0xE0
+#define PT_FPR1     0xE8
+#define PT_FPR2     0xF0
+#define PT_FPR3     0xF8
+#define PT_FPR4     0x100
+#define PT_FPR5     0x108
+#define PT_FPR6     0x110
+#define PT_FPR7     0x118
+#define PT_FPR8     0x120
+#define PT_FPR9     0x128
+#define PT_FPR10    0x130
+#define PT_FPR11    0x138
+#define PT_FPR12    0x140
+#define PT_FPR13    0x148
+#define PT_FPR14    0x150
+#define PT_FPR15    0x158
+#define PT_CR_9     0x160
+#define PT_CR_10    0x168
+#define PT_CR_11    0x170
+#define PT_IEEE_IP  0x1A8
+#define PT_LASTOFF  PT_IEEE_IP
+#define PT_ENDREGS  0x1B0-1
+
+#define NUM_GPRS      16
+#define NUM_FPRS      16
+#define NUM_CRS       16
+#define NUM_ACRS      16
+#define GPR_SIZE      8
+#define FPR_SIZE      8
+#define FPC_SIZE      4
+#define FPC_PAD_SIZE  4 /* gcc insists on aligning the fpregs */
+#define CR_SIZE       8
+#define ACR_SIZE      4
+
+#define STACK_FRAME_OVERHEAD    160      /* size of minimum stack frame */
+
+#ifndef __ASSEMBLY__
 #include <linux/config.h>
-#include <asm/s390-regs-common.h>
-#include <asm/current.h>
+#include <linux/stddef.h>
 #include <linux/types.h>
+
+#include <asm/current.h>
 #include <asm/setup.h>
-#include <linux/stddef.h>
 
+/* this typedef defines how a Program Status Word looks like */
+typedef struct 
+{
+        __u64   mask;
+        __u64   addr;
+} psw_t __attribute__ ((aligned(8)));
 
-#define S390_REGS   \
-S390_REGS_COMMON    \
-addr_t orig_gpr2;
+#ifdef __KERNEL__
+#define FIX_PSW(addr) ((unsigned long)(addr))
+#define ADDR_BITS_REMOVE(addr) ((addr))
+#endif
 
+typedef union
+{
+	float   f;
+	double  d;
+	__u64   ui;
+	struct
+	{
+		__u32 hi;
+		__u32 lo;
+	} fp;
+} freg_t;
+
+typedef struct
+{
+	__u32   fpc;
+	freg_t  fprs[NUM_FPRS];              
+} s390_fp_regs;
+
+#define FPC_EXCEPTION_MASK      0xF8000000
+#define FPC_FLAGS_MASK          0x00F80000
+#define FPC_DXC_MASK            0x0000FF00
+#define FPC_RM_MASK             0x00000003
+#define FPC_VALID_MASK          0xF8F8FF03
+
+/*
+ * The first entries in pt_regs, gdb_pt_regs and user_regs_struct
+ * are common for all three structures. The s390_regs structure
+ * covers the common parts. It simplifies copying the common part
+ * between the three structures.
+ */
 typedef struct
 {
-	S390_REGS
-} __attribute__ ((packed)) s390_regs;
+	psw_t psw;
+	__u64 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u64 orig_gpr2;
+} s390_regs;
 
+/*
+ * The pt_regs struct defines the way the registers are stored on
+ * the stack during a system call.
+ */
 struct pt_regs 
 {
-	S390_REGS
+	psw_t psw;
+	__u64 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u64 orig_gpr2;
 	__u32 trap;
+	__u32 old_ilc;
 } __attribute__ ((packed));
 
+/*
+ * The gdb_pt_regs struct is used instead of the pt_regs structure
+ * if kernel remote debugging is used.
+ */
 #if CONFIG_REMOTE_DEBUG
-typedef struct
+struct gdb_pt_regs
 {
-	S390_REGS
+	psw_t psw;
+	__u64 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u64 orig_gpr2;
 	__u32 trap;
-	addr_t crs[16];
+	__u32 crs[16];
 	s390_fp_regs fp_regs;
-} __attribute__ ((packed)) gdb_pt_regs;
+};
 #endif
 
-
+/*
+ * Now for the program event recording (trace) definitions.
+ */
 typedef struct
 {
-			addr_t   cr[3];
+	__u64 cr[3];
 } per_cr_words  __attribute__((packed));
 
 #define PER_EM_MASK 0x00000000E8000000UL
+
 typedef	struct
 {
-	unsigned    :32;
-	unsigned    em_branching:1;
-	unsigned    em_instruction_fetch:1;
-	/* Switching on storage alteration automatically fixes
-	   the storage alteration event bit in the users std. */
-	unsigned    em_storage_alteration:1;
-	unsigned    em_gpr_alt_unused:1;
-	unsigned    em_store_real_address:1;
-	unsigned    :3;
-	unsigned    branch_addr_ctl:1;
-	unsigned    :1;
-	unsigned    storage_alt_space_ctl:1;
-	unsigned    :5;
-	unsigned    :16;
-	addr_t      starting_addr;
-	addr_t      ending_addr;
+	unsigned                       : 32;
+	unsigned em_branching          : 1;
+	unsigned em_instruction_fetch  : 1;
+	/*
+	 * Switching on storage alteration automatically fixes
+	 * the storage alteration event bit in the users std.
+	 */
+	unsigned em_storage_alteration : 1;
+	unsigned em_gpr_alt_unused     : 1;
+	unsigned em_store_real_address : 1;
+	unsigned                       : 3;
+	unsigned branch_addr_ctl       : 1;
+	unsigned                       : 1;
+	unsigned storage_alt_space_ctl : 1;
+	unsigned                       : 21;
+	addr_t   starting_addr;
+	addr_t   ending_addr;
 } per_cr_bits  __attribute__((packed));
 
 typedef struct
 {
-	__u16          perc_atmid;          /* 0x096 */
-	addr_t         address;             /* 0x098 */
-	__u8           access_id;           /* 0x0a1 */
+	__u16          perc_atmid;
+	addr_t         address;
+	__u8           access_id;
 } per_lowcore_words  __attribute__((packed));
 
 typedef struct
 {
-	unsigned       perc_branching:1;               /* 0x096 */
-	unsigned       perc_instruction_fetch:1;
-	unsigned       perc_storage_alteration:1;
-	unsigned       perc_gpr_alt_unused:1;
-	unsigned       perc_store_real_address:1;
-	unsigned       :3;
-	unsigned       atmid_psw_bit_31:1;
-	unsigned       atmid_validity_bit:1;
-	unsigned       atmid_psw_bit_32:1;
-	unsigned       atmid_psw_bit_5:1;
-	unsigned       atmid_psw_bit_16:1;
-	unsigned       atmid_psw_bit_17:1;
-	unsigned       ai:2;
-	addr_t         address;              /* 0x098 */
-	unsigned       :4;                   /* 0x0a1 */
-	unsigned       access_id:4;           
+	unsigned perc_branching          : 1; /* 0x096 */
+	unsigned perc_instruction_fetch  : 1;
+	unsigned perc_storage_alteration : 1;
+	unsigned perc_gpr_alt_unused     : 1;
+	unsigned perc_store_real_address : 1;
+	unsigned                         : 3;
+	unsigned atmid_psw_bit_31        : 1;
+	unsigned atmid_validity_bit      : 1;
+	unsigned atmid_psw_bit_32        : 1;
+	unsigned atmid_psw_bit_5         : 1;
+	unsigned atmid_psw_bit_16        : 1;
+	unsigned atmid_psw_bit_17        : 1;
+	unsigned si                      : 2;
+	addr_t   address;                     /* 0x098 */
+	unsigned                         : 4; /* 0x0a1 */
+	unsigned access_id               : 4;
 } per_lowcore_bits __attribute__((packed));
 
-
-typedef enum
-{
-	primary_asce,
-	ar_asce,
-	secondary_asce,
-	home_space_asce
-} per_ai_codes;
-
-
-
 typedef struct
 {
-	union
-	{
+	union {
 		per_cr_words   words;
 		per_cr_bits    bits;
 	} control_regs  __attribute__((packed));
-	/* Use these flags instead of setting em_instruction_fetch */
-	/* directly they are used so that single stepping can be */
-	/* switched on & off while not affecting other tracing */
-	unsigned  single_step:1;
-	unsigned  instruction_fetch:1;
-	unsigned  :30;
-	/* These addresses are copied into cr10 & cr11 if single stepping
-	   is switched off */
-	addr_t     starting_addr;
-	addr_t     ending_addr;
-	union
-	{
+	/*
+	 * Use these flags instead of setting em_instruction_fetch
+	 * directly they are used so that single stepping can be
+	 * switched on & off while not affecting other tracing
+	 */
+	unsigned  single_step       : 1;
+	unsigned  instruction_fetch : 1;
+	unsigned                    : 30;
+	/*
+	 * These addresses are copied into cr10 & cr11 if single
+	 * stepping is switched off
+	 */
+	addr_t    starting_addr;
+	addr_t    ending_addr;
+	union {
 		per_lowcore_words words;
 		per_lowcore_bits  bits;
 	} lowcore; 
 } per_struct __attribute__((packed));
 
-
-
-/* this struct defines the way the registers are stored on the
-   stack during a system call. If you change the pt_regs structure,
-   you'll need to change user.h too. 
-
-   N.B. if you modify the pt_regs struct the strace command also has to be
-   modified & recompiled  ( just wait till we have gdb going ).
-
-*/
-
-struct user_regs_struct
-{
-	S390_REGS
-	s390_fp_regs fp_regs;
-/* These per registers are in here so that gdb can modify them itself
- * as there is no "official" ptrace interface for hardware watchpoints.
- * this is the way intel does it
- */
-	per_struct per_info;
-	addr_t  ieee_instruction_pointer; 
-	/* Used to give failing instruction back to user for ieee exceptions */
-};
-
-typedef struct user_regs_struct user_regs_struct;
-
-typedef struct pt_regs pt_regs;
-
-#ifdef __KERNEL__
-#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
-#define instruction_pointer(regs) ((regs)->psw.addr)
-extern void show_regs(struct pt_regs * regs);
-extern char *task_show_regs(struct task_struct *task, char *buffer);
-#endif
-
-
-
-
-
-#define FIX_PSW(addr) ((unsigned long)(addr))
-
-#define MULT_PROCPTR_TYPES    ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC))
-
-typedef struct
-{
-  long addr;
-  long toc;
-} routine_descriptor;
-extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs);
-extern __inline__ void 
-fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs)
-{
-  regs->psw.addr=FIX_PSW(rdes->addr);
-  regs->gprs[12]=rdes->toc;
-}
-
-/*
- * Compiler optimisation should save this stuff from being non optimal
- * & remove uneccessary code ( isnt gcc great DJB. )
- */
-
-/*I'm just using this an indicator of what binformat we are using
- * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise
- * dereferencing incomplete pointer types in with load_toc_binary
- */
-#if MULT_PROCPTR_TYPES
-#define uses_routine_descriptors() \
-(current->binfmt->load_binary==load_toc_binary)
-#else
-#if CONFIG_BINFMT_TOC
-#define uses_routine_descriptors() 1
-#else
-#define uses_routine_descriptors() 0
-#endif
-#endif
-
-#define pt_off(ptreg)   offsetof(user_regs_struct,ptreg)
-enum
-{
-	PT_PSWMASK=pt_off(psw.mask),
-	PT_PSWADDR=pt_off(psw.addr),
-	PT_GPR0=pt_off(gprs[0]),
-	PT_GPR1=pt_off(gprs[1]),
-	PT_GPR2=pt_off(gprs[2]),
-	PT_GPR3=pt_off(gprs[3]),
-	PT_GPR4=pt_off(gprs[4]),
-	PT_GPR5=pt_off(gprs[5]),
-	PT_GPR6=pt_off(gprs[6]),
-	PT_GPR7=pt_off(gprs[7]),
-	PT_GPR8=pt_off(gprs[8]),
-	PT_GPR9=pt_off(gprs[9]),
-	PT_GPR10=pt_off(gprs[10]),
-	PT_GPR11=pt_off(gprs[11]),
-	PT_GPR12=pt_off(gprs[12]),
-	PT_GPR13=pt_off(gprs[13]),
-	PT_GPR14=pt_off(gprs[14]),
-	PT_GPR15=pt_off(gprs[15]),
-        PT_ACR0=pt_off(acrs[0]),
-        PT_ACR1=pt_off(acrs[1]),
-        PT_ACR2=pt_off(acrs[2]),
-        PT_ACR3=pt_off(acrs[3]),
-        PT_ACR4=pt_off(acrs[4]),
-        PT_ACR5=pt_off(acrs[5]),
-        PT_ACR6=pt_off(acrs[6]),
-        PT_ACR7=pt_off(acrs[7]),
-        PT_ACR8=pt_off(acrs[8]),
-        PT_ACR9=pt_off(acrs[9]),
-        PT_ACR10=pt_off(acrs[10]),
-        PT_ACR11=pt_off(acrs[11]),
-        PT_ACR12=pt_off(acrs[12]),
-        PT_ACR13=pt_off(acrs[13]),
-        PT_ACR14=pt_off(acrs[14]),
-        PT_ACR15=pt_off(acrs[15]),
-	PT_ORIGGPR2=pt_off(orig_gpr2),
-	PT_FPC=pt_off(fp_regs.fpc),
-/*
- *      A nasty fact of life that the ptrace api
- *      only supports passing of longs.
- */
-	PT_FPR0=pt_off(fp_regs.fprs[0].d),
-	PT_FPR1=pt_off(fp_regs.fprs[1].d),
-	PT_FPR2=pt_off(fp_regs.fprs[2].d),
-	PT_FPR3=pt_off(fp_regs.fprs[3].d),
-	PT_FPR4=pt_off(fp_regs.fprs[4].d),
-	PT_FPR5=pt_off(fp_regs.fprs[5].d),
-	PT_FPR6=pt_off(fp_regs.fprs[6].d),
-	PT_FPR7=pt_off(fp_regs.fprs[7].d),
-	PT_FPR8=pt_off(fp_regs.fprs[8].d),
-	PT_FPR9=pt_off(fp_regs.fprs[9].d),
-	PT_FPR10=pt_off(fp_regs.fprs[10].d),
-	PT_FPR11=pt_off(fp_regs.fprs[11].d),
-	PT_FPR12=pt_off(fp_regs.fprs[12].d),
-	PT_FPR13=pt_off(fp_regs.fprs[13].d),
-	PT_FPR14=pt_off(fp_regs.fprs[14].d),
-	PT_FPR15=pt_off(fp_regs.fprs[15].d),
-	PT_CR_9=pt_off(per_info.control_regs.words.cr[0]),
-	PT_CR_10=pt_off(per_info.control_regs.words.cr[1]),
-	PT_CR_11=pt_off(per_info.control_regs.words.cr[2]),
-        PT_IEEE_IP=pt_off(ieee_instruction_pointer),
-        PT_LASTOFF=PT_IEEE_IP,
-        PT_ENDREGS=sizeof(user_regs_struct)-1
-};
-
-#define PTRACE_AREA \
-__u32 len;          \
-addr_t  kernel_addr; \
-addr_t  process_addr;
-
 typedef struct
 {
-	 PTRACE_AREA
+	__u32  len;
+	addr_t kernel_addr;
+	addr_t process_addr;
 } ptrace_area;
 
 /*
-  390 specific non posix ptrace requests
-  I chose unusual values so they are unlikely to clash with future ptrace definitions.
+ * S/390 specific non posix ptrace requests. I chose unusual values so
+ * they are unlikely to clash with future ptrace definitions.
  */
 #define PTRACE_PEEKUSR_AREA           0x5000
 #define PTRACE_POKEUSR_AREA           0x5001
@@ -293,7 +275,10 @@
 #define PTRACE_PEEKDATA_AREA	      0x5003
 #define PTRACE_POKETEXT_AREA	      0x5004
 #define PTRACE_POKEDATA_AREA 	      0x5005
-/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */
+/*
+ * PT_PROT definition is loosely based on hppa bsd definition in
+ * gdb/hppab-nat.c
+ */
 #define PTRACE_PROT                       21
 
 typedef enum
@@ -309,18 +294,41 @@
 	addr_t           hiaddr;
 	ptprot_flags     prot;
 } ptprot_area;                     
-#endif
-
-
-
-
-
-
-
-
-
 
+/* Sequence of bytes for breakpoint illegal instruction.  */
+#define S390_BREAKPOINT     {0x0,0x1}
+#define S390_BREAKPOINT_U16 ((__u16)0x0001)
+#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
+#define S390_SYSCALL_SIZE   2
 
+/*
+ * The user_regs_struct defines the way the user registers are
+ * store on the stack for signal handling.
+ */
+struct user_regs_struct
+{
+	psw_t psw;
+	__u64 gprs[NUM_GPRS];
+	__u32 acrs[NUM_ACRS];
+	__u64 orig_gpr2;
+	s390_fp_regs fp_regs;
+	/*
+	 * These per registers are in here so that gdb can modify them
+	 * itself as there is no "official" ptrace interface for hardware
+	 * watchpoints. This is the way intel does it.
+	 */
+	per_struct per_info;
+	addr_t  ieee_instruction_pointer; 
+	/* Used to give failing instruction back to user for ieee exceptions */
+};
 
+#ifdef __KERNEL__
+#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
+#define instruction_pointer(regs) ((regs)->psw.addr)
+extern void show_regs(struct pt_regs * regs);
+extern char *task_show_regs(struct task_struct *task, char *buffer);
+#endif
 
+#endif /* __ASSEMBLY__ */
 
+#endif /* _S390X_PTRACE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/queue.h linux/include/asm-s390x/queue.h
--- v2.4.3/linux/include/asm-s390x/queue.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/queue.h	Wed Apr 11 19:02:29 2001
@@ -7,8 +7,8 @@
  *
  *  A little set of queue utilies.
  */
+
 #include <linux/stddef.h>
-#include <asm/types.h>
 
 typedef struct queue
 {
@@ -105,8 +105,8 @@
 
 	for(curr=lhead;curr!=NULL;curr=curr->next)
 		if(curr==member)
-			return(TRUE);
-	return(FALSE);
+			return(1);
+	return(0);
 }
 
 static __inline__ int get_prev(list *lhead,list *member,list **prev)
@@ -117,11 +117,11 @@
 	for(curr=lhead;curr!=NULL;curr=curr->next)
 	{
 		if(curr==member)
-			return(TRUE);
+			return(1);
 		*prev=curr;
 	}
 	*prev=NULL;
-	return(FALSE);
+	return(0);
 }
 
 
@@ -137,9 +137,9 @@
 			prev->next=member->next;
 		else
 			*lhead=member->next;
-		return(TRUE);
+		return(1);
 	}
-	return(FALSE);
+	return(0);
 }
 
 static __inline__ int remove_from_queue(qheader *qhead,queue *member)
@@ -161,9 +161,9 @@
 				qhead->tail=NULL;
 			qhead->head=member->next;
 		}
-		return(TRUE);
+		return(1);
 	}
-	return(FALSE);
+	return(0);
 }
 
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/s390dyn.h linux/include/asm-s390x/s390dyn.h
--- v2.4.3/linux/include/asm-s390x/s390dyn.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/s390dyn.h	Wed Apr 11 19:02:29 2001
@@ -10,6 +10,10 @@
 #ifndef __s390dyn_h
 #define __s390dyn_h
 
+#ifndef _LINUX_LIST_H
+#include <linux/list.h>
+#endif
+
 struct _devreg;
 
 typedef  int  (* oper_handler_func_t)( int             irq,
@@ -23,6 +27,7 @@
    }  __attribute__ ((packed)) devreg_hc_t;
 
 typedef struct _devreg {
+	struct list_head list;
 	union {
 		int devno;
 		devreg_hc_t hc;       /* has controller info */
@@ -30,8 +35,6 @@
 
 	int                  flag;
 	oper_handler_func_t  oper_func;
-	struct _devreg      *prev;
-	struct _devreg      *next;
 } devreg_t;
 
 #define DEVREG_EXACT_MATCH      0x00000001
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/s390io.h linux/include/asm-s390x/s390io.h
--- v2.4.3/linux/include/asm-s390x/s390io.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/s390io.h	Wed Apr 11 19:02:29 2001
@@ -75,7 +75,6 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
-     __u32         syncnt;       /* sync I/O recursive usage count */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/semaphore-helper.h linux/include/asm-s390x/semaphore-helper.h
--- v2.4.3/linux/include/asm-s390x/semaphore-helper.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/semaphore-helper.h	Wed Dec 31 16:00:00 1969
@@ -1,100 +0,0 @@
-/*
- *  include/asm-s390/semaphore-helper.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- *  Derived from "include/asm-i386/semaphore-helper.h"
- *    (C) Copyright 1996 Linus Torvalds
- *    (C) Copyright 1999 Andrea Arcangeli
- */
-
-#ifndef _S390_SEMAPHORE_HELPER_H
-#define _S390_SEMAPHORE_HELPER_H
-
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * but on the x86 we need an external synchronizer.
- */
-static inline void wake_one_more(struct semaphore * sem)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	sem->waking++;
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-}
-
-static inline int waking_non_zero(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-/*
- * waking_non_zero_interruptible:
- *	1	got the lock
- *	0	go to sleep
- *	-EINTR	interrupted
- *
- * If we give up we must undo our count-decrease we previously did in down().
- * Subtle: up() can continue to happens and increase the semaphore count
- * even during our critical section protected by the spinlock. So
- * we must remeber to undo the sem->waking that will be run from
- * wake_one_more() some time soon, if the semaphore count become > 0.
- */
-static inline int waking_non_zero_interruptible(struct semaphore *sem,
-						struct task_struct *tsk)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	} else if (signal_pending(tsk)) {
-               if (atomic_inc_and_test_greater_zero(&sem->count))
-                       sem->waking--;
-		ret = -EINTR;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-/*
- * waking_non_zero_trylock:
- *	1	failed to lock
- *	0	got the lock
- *
- * Implementation details are the same of the interruptible case.
- */
-static inline int waking_non_zero_trylock(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking <= 0)
-        {
-                if (atomic_inc_and_test_greater_zero(&sem->count))
-                        sem->waking--;
-        } else {
-		sem->waking--;
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-	return ret;
-}
-
-#endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/semaphore.h linux/include/asm-s390x/semaphore.h
--- v2.4.3/linux/include/asm-s390x/semaphore.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -14,6 +14,7 @@
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 	atomic_t count;
@@ -89,103 +90,6 @@
 {
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *		-ben
- */
-struct rw_semaphore {
-	atomic_t		count;
-	volatile unsigned int	write_bias_granted;
-	volatile unsigned int	read_bias_granted;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-};
-
-#define RW_LOCK_BIAS		 0x01000000
-
-#define __RWSEM_DEBUG_INIT	/* */
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-}
-
-extern void __down_read_failed(int, struct rw_semaphore *);
-extern void __down_write_failed(int, struct rw_semaphore *);
-extern void __rwsem_wake(int, struct rw_semaphore *);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_dec_return(&sem->count);
-	if (count < 0)
-		__down_read_failed(count, sem);
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_add_return (-RW_LOCK_BIAS, &sem->count);
-	if (count < 0)
-		__down_write_failed(count, sem);
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void up_read(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_inc_return(&sem->count);
-	if (count == 0)
-		__rwsem_wake(count, sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void up_write(struct rw_semaphore *sem)
-{
-	int count;
-	count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-	if (count >= 0 && count < RW_LOCK_BIAS)
-		__rwsem_wake(count, sem);
 }
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/setup.h linux/include/asm-s390x/setup.h
--- v2.4.3/linux/include/asm-s390x/setup.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/setup.h	Wed Apr 11 19:02:29 2001
@@ -8,45 +8,34 @@
 #ifndef _ASM_S390_SETUP_H
 #define _ASM_S390_SETUP_H
 
-#define PARMAREA 0x10400
+#define PARMAREA		0x10400
+#define COMMAND_LINE_SIZE 	896
+#define RAMDISK_ORIGIN		0x800000
+#define RAMDISK_SIZE		0x800000
 
 #ifndef __ASSEMBLER__
 
-#define ORIG_ROOT_DEV     (*(unsigned long *) (0x10400))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10408))
-#define MEMORY_SIZE       (*(unsigned long *)  (0x1040a))
-#define MACHINE_FLAGS     (*(unsigned long *)  (0x10412))
-#define INITRD_START      (*(unsigned long *)  (0x1041a))
-#define INITRD_SIZE       (*(unsigned long *)  (0x10422))
-#define RAMDISK_FLAGS     (*(unsigned short *) (0x1042a))
+#define IPL_DEVICE        (*(unsigned long *)  (0x10400))
+#define INITRD_START      (*(unsigned long *)  (0x10408))
+#define INITRD_SIZE       (*(unsigned long *)  (0x10410))
 #define COMMAND_LINE      ((char *)            (0x10480))
 
-#else 
-
-#define ORIG_ROOT_DEV     0x10400
-#define MOUNT_ROOT_RDONLY 0x10408
-#define MEMORY_SIZE       0x1040a
-#define MACHINE_FLAGS     0x10412
-#define INITRD_START      0x1041a
-#define INITRD_SIZE       0x10422
-#define RAMDISK_FLAGS     0x1042a
-#define COMMAND_LINE      0x10480
-
-#endif
-
-#define COMMAND_LINE_SIZE 896
 /*
  * Machine features detected in head.S
  */
-#define MACHINE_IS_VM    (MACHINE_FLAGS & 1)
-#define MACHINE_IS_P390  (MACHINE_FLAGS & 4)
+extern unsigned long machine_flags;
 
-#define RAMDISK_ORIGIN            0x800000
-#define RAMDISK_SIZE              0x800000
-#define RAMDISK_BLKSIZE           0x1000
-#define RAMDISK_IMAGE_START_MASK  0x07FF
-#define RAMDISK_PROMPT_FLAG       0x8000
-#define RAMDISK_LOAD_FLAG         0x4000
+#define MACHINE_IS_VM    (machine_flags & 1)
+#define MACHINE_IS_P390  (machine_flags & 4)
+#define MACHINE_HAS_MVPG (machine_flags & 16)
 
+#else 
+
+#define IPL_DEVICE        0x10400
+#define INITRD_START      0x10408
+#define INITRD_SIZE       0x10410
+#define COMMAND_LINE      0x10480
+
+#endif
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/signal.h linux/include/asm-s390x/signal.h
--- v2.4.3/linux/include/asm-s390x/signal.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/signal.h	Wed Apr 11 19:02:29 2001
@@ -71,6 +71,7 @@
 #define SIGLOST         29
 */
 #define SIGPWR          30
+#define SIGSYS		31
 #define SIGUNUSED       31
 
 /* These should not be considered constants from userland.  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/sigp.h linux/include/asm-s390x/sigp.h
--- v2.4.3/linux/include/asm-s390x/sigp.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/sigp.h	Wed Apr 11 19:02:29 2001
@@ -15,7 +15,6 @@
 #define __SIGP__
 
 #include <asm/ptrace.h>
-#include <asm/misc390.h>
 #include <asm/atomic.h>
 
 /* get real cpu address from logical cpu number */
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/smp.h linux/include/asm-s390x/smp.h
--- v2.4.3/linux/include/asm-s390x/smp.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/smp.h	Wed Apr 11 19:02:29 2001
@@ -8,14 +8,24 @@
  */
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
+
 #include <linux/config.h>
-#ifdef CONFIG_SMP
-#ifndef __ASSEMBLY__
+
+#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
 
 #include <asm/lowcore.h>
-#include <linux/kernel.h>   // FOR FASTCALL definition
 
-#define smp_processor_id() (current->processor)
+/*
+  s390 specific smp.c headers
+ */
+typedef struct
+{
+	int        intresting;
+	sigp_ccode ccode; 
+	__u32      status;
+	__u16      cpu;
+} sigp_info;
+
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
 /*
@@ -30,7 +40,7 @@
  
 #define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
 
-extern void count_cpus(void);
+#define smp_processor_id() (current->processor)
 
 extern __inline__ int cpu_logical_map(int cpu)
 {
@@ -54,25 +64,12 @@
 
 void smp_local_timer_interrupt(struct pt_regs * regs);
 
-/*
-  s390 specific smp.c headers
- */
-typedef struct
-{
-	int        intresting;
-	sigp_ccode ccode; 
-	__u32      status;
-	__u16      cpu;
-} sigp_info;
-
-sigp_ccode
-smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait);
-void smp_ext_call_others(void (*callback)(void *info), void *info, int wait);
+sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait);
+void smp_ext_call_others(void (*cb)(void *info), void *info, int wait);
 sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig);
 void smp_ext_bitcall_others(ec_bit_sig sig);
 
 int smp_signal_others(sigp_order_code order_code,__u32 parameter,
                       int spin,sigp_info *info);
-#endif
 #endif
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/spinlock.h linux/include/asm-s390x/spinlock.h
--- v2.4.3/linux/include/asm-s390x/spinlock.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/spinlock.h	Wed Apr 11 19:02:29 2001
@@ -73,6 +73,8 @@
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
+#define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
 #define read_lock(rw)   \
         asm volatile("   la    1,%0\n"   \
                      "   lg    2,0(1)\n"   \
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/system.h linux/include/asm-s390x/system.h
--- v2.4.3/linux/include/asm-s390x/system.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/system.h	Wed Apr 11 19:02:29 2001
@@ -33,6 +33,9 @@
 #define xchg(ptr,x) \
   ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(void *)(ptr),sizeof(*(ptr))))
 
+extern void __misaligned_u16(void);
+extern void __misaligned_u32(void);
+extern void __misaligned_u64(void);
 
 static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
@@ -43,14 +46,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,7(%1)\n"   /* for ptr&3 == 0 */
+                                "   stcm  0,8,7(%1)\n"
+                                "   icm   1,4,7(%1)\n"   /* for ptr&3 == 1 */
+                                "   stcm  0,4,7(%1)\n"
+                                "   icm   1,2,7(%1)\n"   /* for ptr&3 == 2 */
+                                "   stcm  0,2,7(%1)\n"
+                                "   icm   1,1,7(%1)\n"   /* for ptr&3 == 3 */
+                                "   stcm  0,1,7(%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 */
@@ -59,20 +62,21 @@
                                 "   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(((addr_t)ptr)&1)
-                                panic("misaligned (__u16 *) in __xchg\n");
+				__misaligned_u16();
                         asm volatile (
                                 "   lghi  1,2\n"
                                 "   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,6(%1)\n"   /* for ptr&2 == 0 */
+                                "   stcm  0,12,6(%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 */
@@ -81,12 +85,12 @@
                                 "   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:
                         if(((addr_t)ptr)&3)
-                                panic("misaligned (__u32 *) in __xchg\n");
+				__misaligned_u32();
                         asm volatile (
                                 "    l    0,0(%1)\n"
                                 "0:  cs   0,%0,0(%1)\n"
@@ -97,7 +101,7 @@
                         break;
                 case 8:
                         if(((addr_t)ptr)&7)
-                                panic("misaligned (__u64 *) in __xchg\n");
+				__misaligned_u64();
                         asm volatile (
                                 "    lg  0,0(%1)\n"
                                 "0:  csg 0,%0,0(%1)\n"
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/termios.h linux/include/asm-s390x/termios.h
--- v2.4.3/linux/include/asm-s390x/termios.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/termios.h	Wed Apr 11 19:02:29 2001
@@ -60,7 +60,7 @@
 #define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
 #define N_R3964		9	/* Reserved for Simatic R3964 module */
 #define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
-#define N_IRDA		11	/* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC         13	/* synchronous HDLC */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/todclk.h linux/include/asm-s390x/todclk.h
--- v2.4.3/linux/include/asm-s390x/todclk.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/todclk.h	Wed Apr 11 19:02:29 2001
@@ -10,10 +10,14 @@
 #ifndef __ASM_TODCLK_H
 #define __ASM_TODCLK_H
 
+#ifdef __KERNEL__
+
 #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
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/types.h linux/include/asm-s390x/types.h
--- v2.4.3/linux/include/asm-s390x/types.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/types.h	Wed Apr 11 19:02:29 2001
@@ -41,14 +41,6 @@
  */
 #ifdef __KERNEL__
 
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
 typedef signed char s8;
 typedef unsigned char u8;
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/uaccess.h linux/include/asm-s390x/uaccess.h
--- v2.4.3/linux/include/asm-s390x/uaccess.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/uaccess.h	Wed Apr 11 19:02:29 2001
@@ -432,21 +432,20 @@
                                 "   sacf  512\n"
                                 "0: ic    3,0(%0,4)\n"
                                 "1: stc   3,0(%0,2)\n"
+                                "   ltr   3,3\n"
+                                "   jz    2f\n"
                                 "   aghi  %0,1\n"
                                 "   cgr   %0,%3\n"
-                                "   je    2f\n"
-                                "   ltr   3,3\n"
-                                "   jne   0b\n"
+                                "   jl    0b\n"
                                 "2: sacf  0\n"
-				"3:\n"
 				".section .fixup,\"ax\"\n"
-				"4: lghi  %0,%h4\n"
-				"   jg    3b\n"  
+				"3: lghi  %0,%h4\n"
+				"   jg    2b\n"  
 				".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 8\n"
-				"   .quad  0b,4b\n"
-				"   .quad  1b,4b\n"
+				"   .quad  0b,3b\n"
+				"   .quad  1b,3b\n"
 				".previous"
                                 : "=&a" (len)
                                 : "a"  (dst), "d" (src), "d" (count),
diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/vtoc.h linux/include/asm-s390x/vtoc.h
--- v2.4.3/linux/include/asm-s390x/vtoc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390x/vtoc.h	Wed Apr 11 19:02:29 2001
@@ -0,0 +1,234 @@
+#ifndef __KERNEL__
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/hdreg.h>
+#include <linux/version.h>
+#endif
+#include <asm/dasd.h>
+
+#define LINE_LENGTH 80
+#define VTOC_START_CC 0x0
+#define VTOC_START_HH 0x1
+
+enum failure {unable_to_open,
+	      unable_to_seek,
+	      unable_to_write,
+	      unable_to_read};
+
+typedef struct ttr {
+        __u16 tt;
+        __u8  r;
+} __attribute__ ((packed)) ttr_t;
+
+typedef struct cchhb {
+        __u16 cc;
+        __u16 hh;
+        __u8 b;
+} __attribute__ ((packed)) cchhb_t;
+
+typedef struct cchh {
+        __u16 cc;
+        __u16 hh;
+} __attribute__ ((packed)) cchh_t;
+
+typedef struct labeldate {
+        __u8  year;
+        __u16 day;
+} __attribute__ ((packed)) labeldate_t;
+
+
+typedef struct volume_label {
+        char volkey[4];         /* volume key = volume label                 */
+	char vollbl[4];	        /* volume label                              */
+	char volid[6];	        /* volume identifier                         */
+	__u8 security;	        /* security byte                             */
+	cchhb_t vtoc;           /* VTOC address                              */
+	char res1[5];	        /* reserved                                  */
+        char cisize[4];	        /* CI-size for FBA,...                       */
+                                /* ...blanks for CKD                         */
+	char blkperci[4];       /* no of blocks per CI (FBA), blanks for CKD */
+	char labperci[4];       /* no of labels per CI (FBA), blanks for CKD */
+	char res2[4];	        /* reserved                                  */
+	char lvtoc[14];	        /* owner code for LVTOC                      */
+	char res3[29];	        /* reserved                                  */
+} __attribute__ ((packed)) volume_label_t;
+
+
+typedef struct extent {
+        __u8  typeind;          /* extent type indicator                     */
+        __u8  seqno;            /* extent sequence number                    */
+        cchh_t llimit;          /* starting point of this extent             */
+        cchh_t ulimit;          /* ending point of this extent               */
+} __attribute__ ((packed)) extent_t;
+
+
+typedef struct dev_const {
+        __u16 DS4DSCYL;           /* number of logical cyls                  */
+        __u16 DS4DSTRK;           /* number of tracks in a logical cylinder  */
+        __u16 DS4DEVTK;           /* device track length                     */
+        __u8  DS4DEVI;            /* non-last keyed record overhead          */
+        __u8  DS4DEVL;            /* last keyed record overhead              */
+        __u8  DS4DEVK;            /* non-keyed record overhead differential  */
+        __u8  DS4DEVFG;           /* flag byte                               */
+        __u16 DS4DEVTL;           /* device tolerance                        */
+        __u8  DS4DEVDT;           /* number of DSCB's per track              */
+        __u8  DS4DEVDB;           /* number of directory blocks per track    */
+} __attribute__ ((packed)) dev_const_t;
+
+
+typedef struct format1_label {
+	char  DS1DSNAM[44];       /* data set name                           */
+	__u8  DS1FMTID;           /* format identifier                       */
+	char  DS1DSSN[6];         /* data set serial number                  */
+	__u16 DS1VOLSQ;           /* volume sequence number                  */
+	labeldate_t DS1CREDT;     /* creation date: ydd                      */
+	labeldate_t DS1EXPDT;     /* expiration date                         */
+	__u8  DS1NOEPV;           /* number of extents on volume             */
+        __u8  DS1NOBDB;           /* no. of bytes used in last direction blk */
+	__u8  DS1FLAG1;           /* flag 1                                  */
+	char  DS1SYSCD[13];       /* system code                             */
+	labeldate_t DS1REFD;      /* date last referenced                    */
+        __u8  DS1SMSFG;           /* system managed storage indicators       */
+        __u8  DS1SCXTF;           /* sec. space extension flag byte          */
+        __u16 DS1SCXTV;           /* secondary space extension value         */
+        __u8  DS1DSRG1;           /* data set organisation byte 1            */
+        __u8  DS1DSRG2;           /* data set organisation byte 2            */
+  	__u8  DS1RECFM;           /* record format                           */
+	__u8  DS1OPTCD;           /* option code                             */
+	__u16 DS1BLKL;            /* block length                            */
+	__u16 DS1LRECL;           /* record length                           */
+	__u8  DS1KEYL;            /* key length                              */
+	__u16 DS1RKP;             /* relative key position                   */
+	__u8  DS1DSIND;           /* data set indicators                     */
+        __u8  DS1SCAL1;           /* secondary allocation flag byte          */
+  	char DS1SCAL3[3];         /* secondary allocation quantity           */
+	ttr_t DS1LSTAR;           /* last used track and block on track      */
+	__u16 DS1TRBAL;           /* space remaining on last used track      */
+        __u16 res1;               /* reserved                                */
+	extent_t DS1EXT1;         /* first extent description                */
+	extent_t DS1EXT2;         /* second extent description               */
+	extent_t DS1EXT3;         /* third extent description                */
+	cchhb_t DS1PTRDS;         /* possible pointer to f2 or f3 DSCB       */
+} __attribute__ ((packed)) format1_label_t;
+
+
+typedef struct format4_label {
+	char  DS4KEYCD[44];       /* key code for VTOC labels: 44 times 0x04 */
+        __u8  DS4IDFMT;           /* format identifier                       */
+	cchhb_t DS4HPCHR;         /* highest address of a format 1 DSCB      */
+        __u16 DS4DSREC;           /* number of available DSCB's              */
+        cchh_t DS4HCCHH;          /* CCHH of next available alternate track  */
+        __u16 DS4NOATK;           /* number of remaining alternate tracks    */
+        __u8  DS4VTOCI;           /* VTOC indicators                         */
+        __u8  DS4NOEXT;           /* number of extents in VTOC               */
+        __u8  DS4SMSFG;           /* system managed storage indicators       */
+        __u8  DS4DEVAC;           /* number of alternate cylinders. 
+                                     Subtract from first two bytes of 
+                                     DS4DEVSZ to get number of usable
+				     cylinders. can be zero. valid
+				     only if DS4DEVAV on.                    */
+        dev_const_t DS4DEVCT;     /* device constants                        */
+        char DS4AMTIM[8];         /* VSAM time stamp                         */
+        char DS4AMCAT[3];         /* VSAM catalog indicator                  */
+        char DS4R2TIM[8];         /* VSAM volume/catalog match time stamp    */
+        char res1[5];             /* reserved                                */
+        char DS4F6PTR[5];         /* pointer to first format 6 DSCB          */
+        extent_t DS4VTOCE;        /* VTOC extent description                 */
+        char res2[10];            /* reserved                                */
+        __u8 DS4EFLVL;            /* extended free-space management level    */
+        cchhb_t DS4EFPTR;         /* pointer to extended free-space info     */
+        char res3[9];             /* reserved                                */
+} __attribute__ ((packed)) format4_label_t;
+
+
+char * vtoc_ebcdic_enc (
+        unsigned char source[LINE_LENGTH],
+        unsigned char target[LINE_LENGTH],
+	int l);
+char * vtoc_ebcdic_dec (
+        unsigned char source[LINE_LENGTH],
+	unsigned char target[LINE_LENGTH],
+	int l);
+void vtoc_set_extent (
+        extent_t * ext,
+        __u8 typeind,
+        __u8 seqno,
+        cchh_t * lower,
+        cchh_t * upper);
+void vtoc_set_cchh (
+        cchh_t * addr,
+	__u16 cc,
+	__u16 hh);
+void vtoc_set_cchhb (
+        cchhb_t * addr,
+        __u16 cc,
+        __u16 hh,
+        __u8 b);
+void vtoc_set_date (
+        labeldate_t * d,
+        __u8 year,
+        __u16 day);
+
+
+int vtoc_read_volume_label (
+        char * device,
+        unsigned long vlabel_start,
+        volume_label_t * vlabel);
+int vtoc_write_volume_label (
+        char * device,
+        unsigned long vlabel_start,
+        volume_label_t * vlabel);
+void vtoc_read_label (
+        char *device,
+        unsigned long position,
+        format4_label_t *f4,
+        format1_label_t *f1);
+void vtoc_write_label (
+        char *device,
+        unsigned long position,
+	format4_label_t *f4,
+	format1_label_t *f1);
+void vtoc_init_format4_label (
+        struct hd_geometry *geo,
+        format4_label_t *f4lbl,
+	unsigned int usable_partitions,
+	unsigned int cylinders,
+	unsigned int tracks,
+	unsigned int blocks);
+void vtoc_init_format1_label (
+        char *volid,
+        unsigned int blksize,
+        extent_t *part_extent,
+        format1_label_t *f1);
+void vtoc_update_format4_label (
+	format4_label_t *f4,
+	cchhb_t *highest_f1,
+	__u8 unused_update,
+	__u16 freespace_update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h
--- v2.4.3/linux/include/asm-sh/bugs.h	Thu Jan  4 13:19:13 2001
+++ linux/include/asm-sh/bugs.h	Wed Apr 11 21:24:52 2001
@@ -34,6 +34,10 @@
 		*p++ = '4';
 		printk("CPU: SH7750\n");
 		break;
+	case CPU_ST40STB1:
+		*p++ = '4';
+		printk("CPU: ST40STB1\n");
+		break;
 	default:
 		printk("CPU: ??????\n");
 		break;
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/ec3104.h linux/include/asm-sh/ec3104.h
--- v2.4.3/linux/include/asm-sh/ec3104.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/ec3104.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,43 @@
+#ifndef __ASM_EC3104_H
+#define __ASM_EC3104_H
+
+
+/*
+ * Most of the register set is at 0xb0ec0000 - 0xb0ecffff.
+ *
+ * as far as I've figured it out the register map is:
+ * 0xb0ec0000 - id string
+ * 0xb0ec0XXX - power management
+ * 0xb0ec1XXX - interrupt control
+ * 0xb0ec3XXX - ps2 port (touch pad on aero 8000)
+ * 0xb0ec6XXX - i2c
+ * 0xb0ec7000 - first serial port (proprietary connector on aero 8000)
+ * 0xb0ec8000 - second serial port
+ * 0xb0ec9000 - third serial port
+ * 0xb0eca000 - fourth serial port (keyboard controller on aero 8000)
+ * 0xb0eccXXX - GPIO
+ * 0xb0ecdXXX - GPIO
+ */
+
+#define EC3104_BASE	0xb0ec0000
+
+#define EC3104_SER4_DATA	(EC3104_BASE+0xa000)
+#define EC3104_SER4_IIR		(EC3104_BASE+0xa008)
+#define EC3104_SER4_MCR		(EC3104_BASE+0xa010)
+#define EC3104_SER4_LSR		(EC3104_BASE+0xa014)
+#define EC3104_SER4_MSR		(EC3104_BASE+0xa018)
+
+/*
+ * our ISA bus.  this seems to be real ISA.
+ */
+#define EC3104_ISA_BASE	0xa5000000
+
+#define EC3104_IRQ	11
+#define EC3104_IRQBASE	64
+
+#define EC3104_IRQ_SER1	EC3104_IRQBASE + 7
+#define EC3104_IRQ_SER2	EC3104_IRQBASE + 8
+#define EC3104_IRQ_SER3	EC3104_IRQBASE + 9
+#define EC3104_IRQ_SER4	EC3104_IRQBASE + 10
+
+#endif /* __ASM_EC3104_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/hd64461.h linux/include/asm-sh/hd64461.h
--- v2.4.3/linux/include/asm-sh/hd64461.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/hd64461.h	Wed Apr 11 21:24:52 2001
@@ -11,10 +11,22 @@
 #define HD64461_SYSCR	0x10002
 #define HD64461_SCPUCR	0x10004
 
-#define HD64461_CPTWAR	0x11030	
-#define HD64461_CPTWDR	0x11032
-#define HD64461_CPTRAR	0x11034	
-#define HD64461_CPTRDR	0x11036
+#define HD64461_LCDCBAR		0x11000
+#define HD64461_LCDCLOR		0x11002
+#define HD64461_LCDCCRR		0x11004
+#define	HD64461_LDR1		0x11010
+#define	HD64461_LDR2		0x11012
+#define	HD64461_LDHNCR		0x11014
+#define	HD64461_LDHNSR		0x11016
+#define HD64461_LDVNTR		0x11018
+#define HD64461_LDVNDR		0x1101a
+#define HD64461_LDVSPR		0x1101c
+#define HD64461_LDR3		0x1101e
+
+#define HD64461_CPTWAR		0x11030	
+#define HD64461_CPTWDR		0x11032
+#define HD64461_CPTRAR		0x11034	
+#define HD64461_CPTRDR		0x11036
 
 #define HD64461_PCC0ISR         0x12000
 #define HD64461_PCC0GCR         0x12002
@@ -30,6 +42,23 @@
 #define HD64461_P1OCR           0x1202c
 #define HD64461_PGCR            0x1202e
 
+#define HD64461_GPACR		0x14000
+#define HD64461_GPBCR		0x14002
+#define HD64461_GPCCR		0x14004
+#define HD64461_GPDCR		0x14006
+#define HD64461_GPADR		0x14010
+#define HD64461_GPBDR		0x14012
+#define HD64461_GPCDR		0x14014
+#define HD64461_GPDDR		0x14016
+#define HD64461_GPAICR		0x14020
+#define HD64461_GPBICR		0x14022
+#define HD64461_GPCICR		0x14024
+#define HD64461_GPDICR		0x14026
+#define HD64461_GPAISR		0x14040
+#define HD64461_GPBISR		0x14042
+#define HD64461_GPCISR		0x14044
+#define HD64461_GPDISR		0x14046
+
 #define HD64461_NIRR		0x15000
 #define HD64461_NIMR		0x15002
 
@@ -40,6 +69,6 @@
 #define CONFIG_HD64461_IRQ	36
 #endif
 
-#define HD64461_IRQBASE	64
+#define HD64461_IRQBASE		OFFCHIP_IRQ_BASE
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/hd64465.h linux/include/asm-sh/hd64465.h
--- v2.4.3/linux/include/asm-sh/hd64465.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/hd64465.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,257 @@
+#ifndef _ASM_SH_HD64465_
+#define _ASM_SH_HD64465_ 1
+/*
+ * $Id: hd64465.h,v 1.3 2001/02/07 18:31:20 stuart_menefy Exp $
+ *
+ * Hitachi HD64465 companion chip support
+ *
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+ *
+ * Derived from <asm/hd64461.h> which bore the message:
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ */
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/*
+ * Note that registers are defined here as virtual port numbers,
+ * which have no meaning except to get translated by hd64465_isa_port2addr()
+ * to an address in the range 0xb0000000-0xb3ffffff.  Note that
+ * this translation happens to consist of adding the lower 16 bits
+ * of the virtual port number to 0xb0000000.  Note also that the manual
+ * shows addresses as absolute physical addresses starting at 0x10000000,
+ * so e.g. the NIRR register is listed as 0x15000 here, 0x10005000 in the
+ * manual, and accessed using address 0xb0005000 - Greg.
+ */
+
+/* System registers */
+#define HD64465_REG_SRR     0x1000c 	/* System Revision Register */
+#define HD64465_REG_SDID    0x10010 	/* System Device ID Reg */
+#define     HD64465_SDID            0x8122  /* 64465 device ID */
+
+/* Power Management registers */
+#define HD64465_REG_SMSCR   0x10000 	/* System Module Standby Control Reg */
+#define	    HD64465_SMSCR_PS2ST     0x4000  /* PS/2 Standby */
+#define	    HD64465_SMSCR_ADCST     0x1000  /* ADC Standby */
+#define	    HD64465_SMSCR_UARTST    0x0800  /* UART Standby */
+#define	    HD64465_SMSCR_SCDIST    0x0200  /* Serial Codec Standby */
+#define	    HD64465_SMSCR_PPST	    0x0100  /* Parallel Port Standby */
+#define	    HD64465_SMSCR_PC0ST     0x0040  /* PCMCIA0 Standby */
+#define	    HD64465_SMSCR_PC1ST     0x0020  /* PCMCIA1 Standby */
+#define	    HD64465_SMSCR_AFEST     0x0010  /* AFE Standby */
+#define	    HD64465_SMSCR_TM0ST     0x0008  /* Timer0 Standby */
+#define	    HD64465_SMSCR_TM1ST     0x0004  /* Timer1 Standby */
+#define	    HD64465_SMSCR_IRDAST    0x0002  /* IRDA Standby */
+#define	    HD64465_SMSCR_KBCST     0x0001  /* Keyboard Controller Standby */
+ 
+/* Interrupt Controller registers */
+#define HD64465_REG_NIRR    0x15000  	/* Interrupt Request Register */
+#define HD64465_REG_NIMR    0x15002  	/* Interrupt Mask Register */
+#define HD64465_REG_NITR    0x15004  	/* Interrupt Trigger Mode Register */
+
+/* Timer registers */
+#define HD64465_REG_TCVR1   0x16000  	/* Timer 1 constant value register  */
+#define HD64465_REG_TCVR0   0x16002	/* Timer 0 constant value register  */
+#define HD64465_REG_TRVR1   0x16004	/* Timer 1 read value register  */
+#define HD64465_REG_TRVR0   0x16006	/* Timer 0 read value register  */
+#define HD64465_REG_TCR1    0x16008	/* Timer 1 control register  */
+#define HD64465_REG_TCR0    0x1600A	/* Timer 0 control register  */
+#define	    HD64465_TCR_EADT 	0x10	    /* Enable ADTRIG# signal */
+#define	    HD64465_TCR_ETMO 	0x08	    /* Enable TMO signal */
+#define	    HD64465_TCR_PST_MASK 0x06	    /* Clock Prescale */
+#define	    HD64465_TCR_PST_1 	0x06	    /* 1:1 */
+#define	    HD64465_TCR_PST_4 	0x04	    /* 1:4 */
+#define	    HD64465_TCR_PST_8 	0x02	    /* 1:8 */
+#define	    HD64465_TCR_PST_16 	0x00	    /* 1:16 */
+#define	    HD64465_TCR_TSTP 	0x01	    /* Start/Stop timer */
+#define HD64465_REG_TIRR    0x1600C	/* Timer interrupt request register  */
+#define HD64465_REG_TIDR    0x1600E	/* Timer interrupt disable register  */
+#define HD64465_REG_PWM1CS  0x16010	/* PWM 1 clock scale register  */
+#define HD64465_REG_PWM1LPC 0x16012	/* PWM 1 low pulse width counter register  */
+#define HD64465_REG_PWM1HPC 0x16014	/* PWM 1 high pulse width counter register  */
+#define HD64465_REG_PWM0CS  0x16018	/* PWM 0 clock scale register  */
+#define HD64465_REG_PWM0LPC 0x1601A	/* PWM 0 low pulse width counter register  */
+#define HD64465_REG_PWM0HPC 0x1601C	/* PWM 0 high pulse width counter register  */
+
+/* Analog/Digital Converter registers */
+#define HD64465_REG_ADDRA   0x1E000	/* A/D data register A */
+#define HD64465_REG_ADDRB   0x1E002	/* A/D data register B */
+#define HD64465_REG_ADDRC   0x1E004	/* A/D data register C */
+#define HD64465_REG_ADDRD   0x1E006	/* A/D data register D */
+#define HD64465_REG_ADCSR   0x1E008	/* A/D control/status register */
+#define     HD64465_ADCSR_ADF	    0x80    /* A/D End Flag */
+#define     HD64465_ADCSR_ADST	    0x40    /* A/D Start Flag */
+#define     HD64465_ADCSR_ADIS	    0x20    /* A/D Interrupt Status */
+#define     HD64465_ADCSR_TRGE	    0x10    /* A/D Trigger Enable */
+#define     HD64465_ADCSR_ADIE	    0x08    /* A/D Interrupt Enable */
+#define     HD64465_ADCSR_SCAN	    0x04    /* A/D Scan Mode */
+#define     HD64465_ADCSR_CH_MASK   0x03    /* A/D Channel */
+#define HD64465_REG_ADCALCR 0x1E00A  	/* A/D calibration sample control */
+#define HD64465_REG_ADCAL   0x1E00C  	/* A/D calibration data register */
+
+
+/* General Purpose I/O ports registers */
+#define HD64465_REG_GPACR   0x14000  	/* Port A Control Register */
+#define HD64465_REG_GPBCR   0x14002  	/* Port B Control Register */
+#define HD64465_REG_GPCCR   0x14004  	/* Port C Control Register */
+#define HD64465_REG_GPDCR   0x14006  	/* Port D Control Register */
+#define HD64465_REG_GPECR   0x14008  	/* Port E Control Register */
+#define HD64465_REG_GPADR   0x14010  	/* Port A Data Register */
+#define HD64465_REG_GPBDR   0x14012  	/* Port B Data Register */
+#define HD64465_REG_GPCDR   0x14014  	/* Port C Data Register */
+#define HD64465_REG_GPDDR   0x14016  	/* Port D Data Register */
+#define HD64465_REG_GPEDR   0x14018  	/* Port E Data Register */
+#define HD64465_REG_GPAICR  0x14020  	/* Port A Interrupt Control Register */
+#define HD64465_REG_GPBICR  0x14022  	/* Port B Interrupt Control Register */
+#define HD64465_REG_GPCICR  0x14024  	/* Port C Interrupt Control Register */
+#define HD64465_REG_GPDICR  0x14026  	/* Port D Interrupt Control Register */
+#define HD64465_REG_GPEICR  0x14028  	/* Port E Interrupt Control Register */
+#define HD64465_REG_GPAISR  0x14040  	/* Port A Interrupt Status Register */
+#define HD64465_REG_GPBISR  0x14042  	/* Port B Interrupt Status Register */
+#define HD64465_REG_GPCISR  0x14044  	/* Port C Interrupt Status Register */
+#define HD64465_REG_GPDISR  0x14046  	/* Port D Interrupt Status Register */
+#define HD64465_REG_GPEISR  0x14048  	/* Port E Interrupt Status Register */
+
+/* PCMCIA bridge interface */
+#define HD64465_REG_PCC0ISR	0x12000	/* socket 0 interface status */ 
+#define     HD64465_PCCISR_PREADY   	 0x80    /* mem card ready / io card IREQ */
+#define     HD64465_PCCISR_PIREQ    	 0x80
+#define     HD64465_PCCISR_PMWP     	 0x40    /* mem card write-protected */
+#define     HD64465_PCCISR_PVS2 	 0x20    /* voltage select pin 2 */
+#define     HD64465_PCCISR_PVS1 	 0x10    /* voltage select pin 1 */
+#define     HD64465_PCCISR_PCD_MASK 	 0x0c    /* card detect */
+#define     HD64465_PCCISR_PBVD_MASK     0x03    /* battery voltage */
+#define     HD64465_PCCISR_PBVD_BATGOOD  0x03    /* battery good */
+#define     HD64465_PCCISR_PBVD_BATWARN  0x01    /* battery low warning */
+#define     HD64465_PCCISR_PBVD_BATDEAD1 0x02    /* battery dead */
+#define     HD64465_PCCISR_PBVD_BATDEAD2 0x00    /* battery dead */
+#define HD64465_REG_PCC0GCR	0x12002	/* socket 0 general control */ 
+#define     HD64465_PCCGCR_PDRV   	 0x80    /* output drive */
+#define     HD64465_PCCGCR_PCCR   	 0x40    /* PC card reset */
+#define     HD64465_PCCGCR_PCCT   	 0x20    /* PC card type, 1=IO&mem, 0=mem */
+#define     HD64465_PCCGCR_PVCC0   	 0x10    /* voltage control pin VCC0SEL0 */
+#define     HD64465_PCCGCR_PMMOD   	 0x08    /* memory mode */
+#define     HD64465_PCCGCR_PPA25   	 0x04    /* pin A25 */
+#define     HD64465_PCCGCR_PPA24   	 0x02    /* pin A24 */
+#define     HD64465_PCCGCR_PREG   	 0x01    /* ping PCC0REG# */
+#define HD64465_REG_PCC0CSCR	0x12004	/* socket 0 card status change */ 
+#define     HD64465_PCCCSCR_PSCDI   	 0x80    /* sw card detect intr */
+#define     HD64465_PCCCSCR_PSWSEL   	 0x40    /* power select */
+#define     HD64465_PCCCSCR_PIREQ   	 0x20    /* IREQ intr req */
+#define     HD64465_PCCCSCR_PSC   	 0x10    /* STSCHG (status change) pin */
+#define     HD64465_PCCCSCR_PCDC   	 0x08    /* CD (card detect) change */
+#define     HD64465_PCCCSCR_PRC   	 0x04    /* ready change */
+#define     HD64465_PCCCSCR_PBW   	 0x02    /* battery warning change */
+#define     HD64465_PCCCSCR_PBD   	 0x01    /* battery dead change */
+#define HD64465_REG_PCC0CSCIER	0x12006	/* socket 0 card status change interrupt enable */ 
+#define     HD64465_PCCCSCIER_PCRE   	 0x80    /* change reset enable */
+#define     HD64465_PCCCSCIER_PIREQE_MASK   	0x60   /* IREQ enable */
+#define     HD64465_PCCCSCIER_PIREQE_DISABLED	0x00   /* IREQ disabled */
+#define     HD64465_PCCCSCIER_PIREQE_LEVEL  	0x20   /* IREQ level-triggered */
+#define     HD64465_PCCCSCIER_PIREQE_FALLING	0x40   /* IREQ falling-edge-trig */
+#define     HD64465_PCCCSCIER_PIREQE_RISING 	0x60   /* IREQ rising-edge-trig */
+#define     HD64465_PCCCSCIER_PSCE   	 0x10    /* status change enable */
+#define     HD64465_PCCCSCIER_PCDE   	 0x08    /* card detect change enable */
+#define     HD64465_PCCCSCIER_PRE   	 0x04    /* ready change enable */
+#define     HD64465_PCCCSCIER_PBWE   	 0x02    /* battery warn change enable */
+#define     HD64465_PCCCSCIER_PBDE   	 0x01    /* battery dead change enable*/
+#define HD64465_REG_PCC0SCR	0x12008	/* socket 0 software control */ 
+#define     HD64465_PCCSCR_SHDN   	 0x10    /* TPS2206 SHutDowN pin */
+#define     HD64465_PCCSCR_SWP   	 0x01    /* write protect */
+#define HD64465_REG_PCCPSR	0x1200A	/* serial power switch control */ 
+#define HD64465_REG_PCC1ISR	0x12010	/* socket 1 interface status */ 
+#define HD64465_REG_PCC1GCR	0x12012	/* socket 1 general control */ 
+#define HD64465_REG_PCC1CSCR	0x12014	/* socket 1 card status change */ 
+#define HD64465_REG_PCC1CSCIER	0x12016	/* socket 1 card status change interrupt enable */ 
+#define HD64465_REG_PCC1SCR	0x12018	/* socket 1 software control */ 
+
+
+/* PS/2 Keyboard and mouse controller -- *not* register compatible */
+#define HD64465_REG_KBCSR   	0x1dc00 /* Keyboard Control/Status reg */
+#define     HD64465_KBCSR_KBCIE   	 0x8000    /* KBCK Input Enable */
+#define     HD64465_KBCSR_KBCOE   	 0x4000    /* KBCK Output Enable */
+#define     HD64465_KBCSR_KBDOE   	 0x2000    /* KB DATA Output Enable */
+#define     HD64465_KBCSR_KBCD   	 0x1000    /* KBCK Driven */
+#define     HD64465_KBCSR_KBDD   	 0x0800    /* KB DATA Driven */
+#define     HD64465_KBCSR_KBCS   	 0x0400    /* KBCK pin Status */
+#define     HD64465_KBCSR_KBDS   	 0x0200    /* KB DATA pin Status */
+#define     HD64465_KBCSR_KBDP   	 0x0100    /* KB DATA Parity bit */
+#define     HD64465_KBCSR_KBD_MASK   	 0x00ff    /* KD DATA shift reg */
+#define HD64465_REG_KBISR   	0x1dc04 /* Keyboard Interrupt Status reg */
+#define     HD64465_KBISR_KBRDF   	 0x0001    /* KB Received Data Full */
+#define HD64465_REG_MSCSR   	0x1dc10 /* Mouse Control/Status reg */
+#define HD64465_REG_MSISR   	0x1dc14 /* Mouse Interrupt Status reg */
+
+
+/*
+ * Logical address at which the HD64465 is mapped.  Note that this
+ * should always be in the P2 segment (uncached and untranslated).
+ */
+#ifndef CONFIG_HD64465_IOBASE
+#define CONFIG_HD64465_IOBASE	0xb0000000
+#endif
+/*
+ * The HD64465 multiplexes all its modules' interrupts onto
+ * this single interrupt.
+ */
+#ifndef CONFIG_HD64465_IRQ
+#define CONFIG_HD64465_IRQ	5
+#endif
+
+
+#define _HD64465_IO_MASK	0xf8000000
+#define is_hd64465_addr(addr) \
+	((addr & _HD64465_IO_MASK) == (CONFIG_HD64465_IOBASE & _HD64465_IO_MASK))
+
+/*
+ * A range of 16 virtual interrupts generated by
+ * demuxing the HD64465 muxed interrupt.
+ */
+#define HD64465_IRQ_BASE	OFFCHIP_IRQ_BASE
+#define HD64465_IRQ_NUM 	16
+#define HD64465_IRQ_ADC     	(HD64465_IRQ_BASE+0)
+#define HD64465_IRQ_USB     	(HD64465_IRQ_BASE+1)
+#define HD64465_IRQ_SCDI    	(HD64465_IRQ_BASE+2)
+#define HD64465_IRQ_PARALLEL	(HD64465_IRQ_BASE+3)
+/* bit 4 is reserved */
+#define HD64465_IRQ_UART    	(HD64465_IRQ_BASE+5)
+#define HD64465_IRQ_IRDA    	(HD64465_IRQ_BASE+6)
+#define HD64465_IRQ_PS2MOUSE	(HD64465_IRQ_BASE+7)
+#define HD64465_IRQ_KBC     	(HD64465_IRQ_BASE+8)
+#define HD64465_IRQ_TIMER1   	(HD64465_IRQ_BASE+9)
+#define HD64465_IRQ_TIMER0  	(HD64465_IRQ_BASE+10)
+#define HD64465_IRQ_GPIO    	(HD64465_IRQ_BASE+11)
+#define HD64465_IRQ_AFE     	(HD64465_IRQ_BASE+12)
+#define HD64465_IRQ_PCMCIA1 	(HD64465_IRQ_BASE+13)
+#define HD64465_IRQ_PCMCIA0 	(HD64465_IRQ_BASE+14)
+#define HD64465_IRQ_PS2KBD     	(HD64465_IRQ_BASE+15)
+
+/* Constants for PCMCIA mappings */
+#define HD64465_PCC_WINDOW	0x01000000
+
+#define HD64465_PCC0_BASE	0xb8000000	/* area 6 */
+#define HD64465_PCC0_ATTR	(HD64465_PCC0_BASE)
+#define HD64465_PCC0_COMM	(HD64465_PCC0_BASE+HD64465_PCC_WINDOW)
+#define HD64465_PCC0_IO		(HD64465_PCC0_BASE+2*HD64465_PCC_WINDOW)
+
+#define HD64465_PCC1_BASE	0xb4000000	/* area 5 */
+#define HD64465_PCC1_ATTR	(HD64465_PCC1_BASE)
+#define HD64465_PCC1_COMM	(HD64465_PCC1_BASE+HD64465_PCC_WINDOW)
+#define HD64465_PCC1_IO		(HD64465_PCC1_BASE+2*HD64465_PCC_WINDOW)
+
+/*
+ * Base of USB controller interface (as memory)
+ */
+#define HD64465_USB_BASE    	(CONFIG_HD64465_IOBASE+0xb000)
+#define HD64465_USB_LEN    	0x1000
+/*
+ * Base of embedded SRAM, used for USB controller.
+ */
+#define HD64465_SRAM_BASE    	(CONFIG_HD64465_IOBASE+0x9000)
+#define HD64465_SRAM_LEN    	0x1000
+
+
+
+#endif /* _ASM_SH_HD64465_  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/hd64465_gpio.h linux/include/asm-sh/hd64465_gpio.h
--- v2.4.3/linux/include/asm-sh/hd64465_gpio.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/hd64465_gpio.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,47 @@
+#ifndef _ASM_SH_HD64465_GPIO_
+#define _ASM_SH_HD64465_GPIO_ 1
+/*
+ * $Id: hd64465_gpio.h,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ *
+ * Hitachi HD64465 companion chip: General Purpose IO pins support.
+ * This layer enables other device drivers to configure GPIO
+ * pins, get and set their values, and register an interrupt
+ * routine for when input pins change in hardware.
+ *
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+ */
+#include <linux/config.h>
+#include <asm/hd64465.h>
+
+/* Macro to construct a portpin number (used in all
+ * subsequent functions) from a port letter and a pin
+ * number, e.g. HD64465_GPIO_PORTPIN('A', 5).
+ */
+#define HD64465_GPIO_PORTPIN(port,pin)	(((port)-'A')<<3|(pin))
+
+/* Pin configuration constants for _configure() */
+#define HD64465_GPIO_FUNCTION2	0	/* use the pin's *other* function */
+#define HD64465_GPIO_OUT	1	/* output */
+#define HD64465_GPIO_IN_PULLUP	2	/* input, pull-up MOS on */
+#define HD64465_GPIO_IN		3	/* input */
+
+/* Configure a pin's direction */
+extern void hd64465_gpio_configure(int portpin, int direction);
+
+/* Get, set value */
+extern void hd64465_gpio_set_pin(int portpin, unsigned int value);
+extern unsigned int hd64465_gpio_get_pin(int portpin);
+extern void hd64465_gpio_set_port(int port, unsigned int value);
+extern unsigned int hd64465_gpio_get_port(int port);
+
+/* mode constants for _register_irq() */
+#define HD64465_GPIO_FALLING	0
+#define HD64465_GPIO_RISING	1
+
+/* Interrupt on external value change */
+extern void hd64465_gpio_register_irq(int portpin, int mode,
+	void (*handler)(int portpin, void *dev), void *dev);
+extern void hd64465_gpio_unregister_irq(int portpin);
+
+#endif /* _ASM_SH_HD64465_GPIO_  */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h
--- v2.4.3/linux/include/asm-sh/ide.h	Mon Oct  2 11:57:34 2000
+++ linux/include/asm-sh/ide.h	Wed Apr 11 21:24:52 2001
@@ -28,7 +28,7 @@
 {
 	switch (base) {
 		case 0x01f0: return 77;
-		case 0x0170: return 77;
+		case 0x0170: return 78;
 		default:
 			return 0;
 	}
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io.h linux/include/asm-sh/io.h
--- v2.4.3/linux/include/asm-sh/io.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/io.h	Wed Apr 11 21:24:52 2001
@@ -35,7 +35,7 @@
  */
 
 #ifdef __KERNEL__
-#ifdef CONFIG_SH_GENERIC
+#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_CQREEK) || defined(CONFIG_SH_UNKNOWN)
 
 /* In a generic kernel, we always go through the machine vector.  */
 
@@ -70,7 +70,6 @@
 # define __writel(v,a)	sh_mv.mv_writel((v),(a))
 
 # define __ioremap(a,s)	sh_mv.mv_ioremap((a), (s))
-# define __ioremap_nocache(a,s)	sh_mv.mv_ioremap_nocache((a), (s))
 # define __iounmap(a)	sh_mv.mv_iounmap((a))
 
 # define __isa_port2addr(a)	sh_mv.mv_isa_port2addr(a)
@@ -110,10 +109,20 @@
 
 # if defined(CONFIG_SH_HP600)
 #  include <asm/io_hd64461.h>
-# elif defined(CONFIG_SH_OVERDRIVE)
+# elif defined(CONFIG_SH_7750_OVERDRIVE)
 #  include <asm/io_od.h>
 # elif defined(CONFIG_SH_SOLUTION_ENGINE)
 #  include <asm/io_se.h>
+# elif defined(CONFIG_SH_DMIDA) || \
+       defined(CONFIG_SH_STB1_HARP) || \
+       defined(CONFIG_SH_STB1_OVERDRIVE)
+#  include <asm/io_hd64465.h>
+# elif defined(CONFIG_SH_EC3104)
+#  include <asm/io_ec3104.h>
+# elif defined(CONFIG_SH_DREAMCAST)
+#  include <asm/io_dc.h>
+# elif defined(CONFIG_SH_CAT68701)
+#  include <asm/io_cat68701.h>
 # elif defined(CONFIG_SH_UNKNOWN)
 #  include <asm/io_unknown.h>
 # else
@@ -126,40 +135,38 @@
 #endif /* __KERNEL__ */
 
 /* These are always function calls, in both kernel and user space */
-extern unsigned int	_inb (unsigned long port);
-extern unsigned int	_inw (unsigned long port);
+extern unsigned char	_inb (unsigned long port);
+extern unsigned short	_inw (unsigned long port);
 extern unsigned int	_inl (unsigned long port);
-extern void		_outb (unsigned char b,unsigned long port);
-extern void		_outw (unsigned short w,unsigned long port);
-extern void		_outl (unsigned int l,unsigned long port);
-extern unsigned int	_inb_p (unsigned long port);
-extern unsigned int	_inw_p (unsigned long port);
+extern void		_outb (unsigned char b, unsigned long port);
+extern void		_outw (unsigned short w, unsigned long port);
+extern void		_outl (unsigned int l, unsigned long port);
+extern unsigned char	_inb_p (unsigned long port);
+extern unsigned short	_inw_p (unsigned long port);
 extern unsigned int	_inl_p (unsigned long port);
-extern void		_outb_p (unsigned char b,unsigned long port);
-extern void		_outw_p (unsigned short w,unsigned long port);
-extern void		_outl_p (unsigned int l,unsigned long port);
+extern void		_outb_p (unsigned char b, unsigned long port);
+extern void		_outw_p (unsigned short w, unsigned long port);
+extern void		_outl_p (unsigned int l, unsigned long port);
 extern void		_insb (unsigned long port, void *dst, unsigned long count);
 extern void		_insw (unsigned long port, void *dst, unsigned long count);
 extern void		_insl (unsigned long port, void *dst, unsigned long count);
 extern void		_outsb (unsigned long port, const void *src, unsigned long count);
 extern void		_outsw (unsigned long port, const void *src, unsigned long count);
 extern void		_outsl (unsigned long port, const void *src, unsigned long count);
-extern unsigned long	_readb(unsigned long addr);
-extern unsigned long	_readw(unsigned long addr);
-extern unsigned long	_readl(unsigned long addr);
+extern unsigned char	_readb(unsigned long addr);
+extern unsigned short	_readw(unsigned long addr);
+extern unsigned int	_readl(unsigned long addr);
 extern void		_writeb(unsigned char b, unsigned long addr);
 extern void		_writew(unsigned short b, unsigned long addr);
 extern void		_writel(unsigned int b, unsigned long addr);
 
 #ifdef __KERNEL__
-extern unsigned long	___raw_readb(unsigned long addr);
-extern unsigned long	___raw_readw(unsigned long addr);
-extern unsigned long	___raw_readl(unsigned long addr);
-extern unsigned long	___raw_readq(unsigned long addr);
+extern unsigned char	___raw_readb(unsigned long addr);
+extern unsigned short	___raw_readw(unsigned long addr);
+extern unsigned int	___raw_readl(unsigned long addr);
 extern void		___raw_writeb(unsigned char b, unsigned long addr);
 extern void		___raw_writew(unsigned short b, unsigned long addr);
 extern void		___raw_writel(unsigned int b, unsigned long addr);
-extern void		___raw_writeq(unsigned long b, unsigned long addr);
 #endif
 
 #ifdef __KERNEL__
@@ -291,20 +298,20 @@
 
 /* Userspace declarations.  */
 
-extern unsigned int	inb(unsigned long port);
-extern unsigned int	inw(unsigned long port);
+extern unsigned char	inb(unsigned long port);
+extern unsigned short	inw(unsigned long port);
 extern unsigned int	inl(unsigned long port);
-extern void		outb(unsigned char b,unsigned long port);
-extern void		outw(unsigned short w,unsigned long port);
-extern void		outl(unsigned int l,unsigned long port);
-extern void		insb (unsigned long port, void *dst, unsigned long count);
-extern void		insw (unsigned long port, void *dst, unsigned long count);
-extern void		insl (unsigned long port, void *dst, unsigned long count);
-extern void		outsb (unsigned long port, const void *src, unsigned long count);
-extern void		outsw (unsigned long port, const void *src, unsigned long count);
-extern void		outsl (unsigned long port, const void *src, unsigned long count);
-extern unsigned long	readb(unsigned long addr);
-extern unsigned long	readw(unsigned long addr);
+extern void		outb(unsigned char b, unsigned long port);
+extern void		outw(unsigned short w, unsigned long port);
+extern void		outl(unsigned int l, unsigned long port);
+extern void		insb(unsigned long port, void *dst, unsigned long count);
+extern void		insw(unsigned long port, void *dst, unsigned long count);
+extern void		insl(unsigned long port, void *dst, unsigned long count);
+extern void		outsb(unsigned long port, const void *src, unsigned long count);
+extern void		outsw(unsigned long port, const void *src, unsigned long count);
+extern void		outsl(unsigned long port, const void *src, unsigned long count);
+extern unsigned char	readb(unsigned long addr);
+extern unsigned short	readw(unsigned long addr);
 extern unsigned long	readl(unsigned long addr);
 extern void		writeb(unsigned char b, unsigned long addr);
 extern void		writew(unsigned short b, unsigned long addr);
@@ -342,17 +349,17 @@
 extern void memset_io(unsigned long, int, unsigned long);
 
 /* SuperH on-chip I/O functions */
-extern __inline__ unsigned long ctrl_inb(unsigned long addr)
+extern __inline__ unsigned char ctrl_inb(unsigned long addr)
 {
 	return *(volatile unsigned char*)addr;
 }
 
-extern __inline__ unsigned long ctrl_inw(unsigned long addr)
+extern __inline__ unsigned short ctrl_inw(unsigned long addr)
 {
 	return *(volatile unsigned short*)addr;
 }
 
-extern __inline__ unsigned long ctrl_inl(unsigned long addr)
+extern __inline__ unsigned int ctrl_inl(unsigned long addr)
 {
 	return *(volatile unsigned long*)addr;
 }
@@ -412,20 +419,12 @@
 	return __ioremap(offset, size);
 }
 
-/*
- * This one maps high address device memory and turns off caching for that area.
- * it's useful if some control registers are in such an area and write combining
- * or read caching is not desirable:
- */
-static __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size)
-{
-	return __ioremap_nocache(offset, size);
-}
-
 static __inline__ void iounmap(void *addr)
 {
 	return __iounmap(addr);
 }
+
+#define ioremap_nocache(off,size) ioremap(off,size)
 
 static __inline__ int check_signature(unsigned long io_addr,
 			const unsigned char *signature, int length)
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_cat68701.h linux/include/asm-sh/io_cat68701.h
--- v2.4.3/linux/include/asm-sh/io_cat68701.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/io_cat68701.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,89 @@
+/*
+ * include/asm-sh/io_cat68701.h
+ *
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *           2001 Yutarou Ebihar (ebihara@si-linux.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for an AONE Corp. CAT-68701 SH7708 Borad
+ */
+
+#ifndef _ASM_SH_IO_CAT68701_H
+#define _ASM_SH_IO_CAT68701_H
+
+#include <asm/io_generic.h>
+
+extern unsigned char cat68701_inb(unsigned long port);
+extern unsigned short cat68701_inw(unsigned long port);
+extern unsigned int cat68701_inl(unsigned long port);
+
+extern void cat68701_outb(unsigned char value, unsigned long port);
+extern void cat68701_outw(unsigned short value, unsigned long port);
+extern void cat68701_outl(unsigned int value, unsigned long port);
+
+extern unsigned char cat68701_inb_p(unsigned long port);
+extern void cat68701_outb_p(unsigned char value, unsigned long port);
+
+extern void cat68701_insb(unsigned long port, void *addr, unsigned long count);
+extern void cat68701_insw(unsigned long port, void *addr, unsigned long count);
+extern void cat68701_insl(unsigned long port, void *addr, unsigned long count);
+extern void cat68701_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void cat68701_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void cat68701_outsl(unsigned long port, const void *addr, unsigned long count);
+
+extern unsigned char cat68701_readb(unsigned long addr);
+extern unsigned short cat68701_readw(unsigned long addr);
+extern unsigned int cat68701_readl(unsigned long addr);
+extern void cat68701_writeb(unsigned char b, unsigned long addr);
+extern void cat68701_writew(unsigned short b, unsigned long addr);
+extern void cat68701_writel(unsigned int b, unsigned long addr);
+
+extern void * cat68701_ioremap(unsigned long offset, unsigned long size);
+extern void cat68701_iounmap(void *addr);
+
+extern unsigned long cat68701_isa_port2addr(unsigned long offset);
+extern int cat68701_irq_demux(int irq);
+
+extern void setup_cat68701(void);
+extern void init_cat68701_IRQ(void);
+extern void heartbeat_cat68701(void);
+
+#ifdef __WANT_IO_DEF
+
+# define __inb			cat68701_inb
+# define __inw			cat68701_inw
+# define __inl			cat68701_inl
+# define __outb			cat68701_outb
+# define __outw			cat68701_outw
+# define __outl			cat68701_outl
+
+# define __inb_p		cat68701_inb_p
+# define __inw_p		cat68701_inw
+# define __inl_p		cat68701_inl
+# define __outb_p		cat68701_outb_p
+# define __outw_p		cat68701_outw
+# define __outl_p		cat68701_outl
+
+# define __insb			cat68701_insb
+# define __insw			cat68701_insw
+# define __insl			cat68701_insl
+# define __outsb		cat68701_outsb
+# define __outsw		cat68701_outsw
+# define __outsl		cat68701_outsl
+
+# define __readb		cat68701_readb
+# define __readw		cat68701_readw
+# define __readl		cat68701_readl
+# define __writeb		cat68701_writeb
+# define __writew		cat68701_writew
+# define __writel		cat68701_writel
+
+# define __isa_port2addr	cat68701_isa_port2addr
+# define __ioremap		generic_ioremap
+# define __iounmap		generic_iounmap
+
+#endif
+
+#endif /* _ASM_SH_IO_CAT68701_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_dc.h linux/include/asm-sh/io_dc.h
--- v2.4.3/linux/include/asm-sh/io_dc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/io_dc.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,49 @@
+/*
+ *	$Id: io_dc.h,v 1.1 2001/04/01 15:02:56 yaegashi Exp $
+ *	IO functions for SEGA Dreamcast
+ */
+
+#ifndef _ASM_SH_IO_DREAMCAST_H
+#define _ASM_SH_IO_DREAMCAST_H
+
+#include <asm/io_generic.h>
+
+unsigned long dreamcast_isa_port2addr(unsigned long offset);
+
+#ifdef __WANT_IO_DEF
+
+# define __inb			generic_inb
+# define __inw			generic_inw
+# define __inl			generic_inl
+# define __outb			generic_outb
+# define __outw			generic_outw
+# define __outl			generic_outl
+
+# define __inb_p		generic_inb_p
+# define __inw_p		generic_inw
+# define __inl_p		generic_inl
+# define __outb_p		generic_outb_p
+# define __outw_p		generic_outw
+# define __outl_p		generic_outl
+
+# define __insb			generic_insb
+# define __insw			generic_insw
+# define __insl			generic_insl
+# define __outsb		generic_outsb
+# define __outsw		generic_outsw
+# define __outsl		generic_outsl
+
+# define __readb		generic_readb
+# define __readw		generic_readw
+# define __readl		generic_readl
+# define __writeb		generic_writeb
+# define __writew		generic_writew
+# define __writel		generic_writel
+
+# define __isa_port2addr	dreamcast_isa_port2addr
+# define __ioremap		generic_ioremap
+# define __iounmap		generic_iounmap
+
+#endif
+
+#endif /* _ASM_SH_IO_DREAMCAST_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_ec3104.h linux/include/asm-sh/io_ec3104.h
--- v2.4.3/linux/include/asm-sh/io_ec3104.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/io_ec3104.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,54 @@
+#ifndef _ASM_SH_IO_EC3104_H
+#define _ASM_SH_IO_EC3104_H
+
+#include <asm/io_generic.h>
+#include <linux/types.h>
+
+extern unsigned char ec3104_inb(unsigned long port);
+extern unsigned short ec3104_inw(unsigned long port);
+extern unsigned long ec3104_inl(unsigned long port);
+
+extern void ec3104_outb(unsigned char value, unsigned long port);
+extern void ec3104_outw(unsigned short value, unsigned long port);
+extern void ec3104_outl(unsigned long value, unsigned long port);
+
+extern int ec3104_irq_demux(int irq);
+
+#ifdef __WANT_IO_DEF
+
+# define __inb			ec3104_inb
+# define __inw			ec3104_inw
+# define __inl			ec3104_inl
+# define __outb			ec3104_outb
+# define __outw			ec3104_outw
+# define __outl			ec3104_outl
+
+# define __inb_p		ec3104_inb
+# define __inw_p		ec3104_inw
+# define __inl_p		ec3104_inl
+# define __outb_p		ec3104_outb
+# define __outw_p		ec3104_outw
+# define __outl_p		ec3104_outl
+
+# define __insb			generic_insb
+# define __insw			generic_insw
+# define __insl			generic_insl
+# define __outsb		generic_outsb
+# define __outsw		generic_outsw
+# define __outsl		generic_outsl
+
+# define __readb		generic_readb
+# define __readw		generic_readw
+# define __readl		generic_readl
+# define __writeb		generic_writeb
+# define __writew		generic_writew
+# define __writel		generic_writel
+
+# define __isa_port2addr	generic_isa_port2addr
+# define __ioremap		generic_ioremap
+# define __ioremap_nocache	generic_ioremap_nocache
+# define __iounmap		generic_iounmap
+
+#endif
+
+#endif /* _ASM_SH_IO_EC3104_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_generic.h linux/include/asm-sh/io_generic.h
--- v2.4.3/linux/include/asm-sh/io_generic.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/io_generic.h	Wed Apr 11 21:24:52 2001
@@ -14,37 +14,36 @@
 
 extern unsigned long generic_io_base;
 
-extern unsigned long generic_inb(unsigned int port);
-extern unsigned long generic_inw(unsigned int port);
-extern unsigned long generic_inl(unsigned int port);
+extern unsigned char generic_inb(unsigned long port);
+extern unsigned short generic_inw(unsigned long port);
+extern unsigned int generic_inl(unsigned long port);
 
-extern void generic_outb(unsigned long value, unsigned int port);
-extern void generic_outw(unsigned long value, unsigned int port);
-extern void generic_outl(unsigned long value, unsigned int port);
+extern void generic_outb(unsigned char value, unsigned long port);
+extern void generic_outw(unsigned short value, unsigned long port);
+extern void generic_outl(unsigned int value, unsigned long port);
 
-extern unsigned long generic_inb_p(unsigned int port);
-extern unsigned long generic_inw_p(unsigned int port);
-extern unsigned long generic_inl_p(unsigned int port);
-extern void generic_outb_p(unsigned long value, unsigned int port);
-extern void generic_outw_p(unsigned long value, unsigned int port);
-extern void generic_outl_p(unsigned long value, unsigned int port);
+extern unsigned char generic_inb_p(unsigned long port);
+extern unsigned short generic_inw_p(unsigned long port);
+extern unsigned int generic_inl_p(unsigned long port);
+extern void generic_outb_p(unsigned char value, unsigned long port);
+extern void generic_outw_p(unsigned short value, unsigned long port);
+extern void generic_outl_p(unsigned int value, unsigned long port);
 
-extern void generic_insb(unsigned int port, void *addr, unsigned long count);
-extern void generic_insw(unsigned int port, void *addr, unsigned long count);
-extern void generic_insl(unsigned int port, void *addr, unsigned long count);
-extern void generic_outsb(unsigned int port, const void *addr, unsigned long count);
-extern void generic_outsw(unsigned int port, const void *addr, unsigned long count);
-extern void generic_outsl(unsigned int port, const void *addr, unsigned long count);
+extern void generic_insb(unsigned long port, void *addr, unsigned long count);
+extern void generic_insw(unsigned long port, void *addr, unsigned long count);
+extern void generic_insl(unsigned long port, void *addr, unsigned long count);
+extern void generic_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void generic_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void generic_outsl(unsigned long port, const void *addr, unsigned long count);
 
-extern unsigned long generic_readb(unsigned long addr);
-extern unsigned long generic_readw(unsigned long addr);
-extern unsigned long generic_readl(unsigned long addr);
+extern unsigned char generic_readb(unsigned long addr);
+extern unsigned short generic_readw(unsigned long addr);
+extern unsigned int generic_readl(unsigned long addr);
 extern void generic_writeb(unsigned char b, unsigned long addr);
 extern void generic_writew(unsigned short b, unsigned long addr);
 extern void generic_writel(unsigned int b, unsigned long addr);
 
 extern void *generic_ioremap(unsigned long offset, unsigned long size);
-extern void *generic_ioremap_nocache (unsigned long offset, unsigned long size);
 extern void generic_iounmap(void *addr);
 
 extern unsigned long generic_isa_port2addr(unsigned long offset);
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_hd64461.h linux/include/asm-sh/io_hd64461.h
--- v2.4.3/linux/include/asm-sh/io_hd64461.h	Mon Oct  2 11:57:34 2000
+++ linux/include/asm-sh/io_hd64461.h	Wed Apr 11 21:24:52 2001
@@ -14,23 +14,24 @@
 
 #include <asm/io_generic.h>
 
-extern unsigned long hd64461_inb(unsigned int port);
-extern unsigned long hd64461_inw(unsigned int port);
-extern unsigned long hd64461_inl(unsigned int port);
-
-extern void hd64461_outb(unsigned long value, unsigned int port);
-extern void hd64461_outw(unsigned long value, unsigned int port);
-extern void hd64461_outl(unsigned long value, unsigned int port);
-
-extern unsigned long hd64461_inb_p(unsigned int port);
-extern void hd64461_outb_p(unsigned long value, unsigned int port);
-
-extern void hd64461_insb(unsigned int port, void *addr, unsigned long count);
-extern void hd64461_insw(unsigned int port, void *addr, unsigned long count);
-extern void hd64461_insl(unsigned int port, void *addr, unsigned long count);
-extern void hd64461_outsb(unsigned int port, const void *addr, unsigned long count);
-extern void hd64461_outsw(unsigned int port, const void *addr, unsigned long count);
-extern void hd64461_outsl(unsigned int port, const void *addr, unsigned long count);
+extern unsigned char hd64461_inb(unsigned long port);
+extern unsigned short hd64461_inw(unsigned long port);
+extern unsigned int hd64461_inl(unsigned long port);
+
+extern void hd64461_outb(unsigned char value, unsigned long port);
+extern void hd64461_outw(unsigned short value, unsigned long port);
+extern void hd64461_outl(unsigned int value, unsigned long port);
+
+extern unsigned char hd64461_inb_p(unsigned long port);
+extern void hd64461_outb_p(unsigned char value, unsigned long port);
+
+extern void hd64461_insb(unsigned long port, void *addr, unsigned long count);
+extern void hd64461_insw(unsigned long port, void *addr, unsigned long count);
+extern void hd64461_insl(unsigned long port, void *addr, unsigned long count);
+extern void hd64461_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void hd64461_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void hd64461_outsl(unsigned long port, const void *addr, unsigned long count);
+extern int hd64461_irq_demux(int irq);
 
 #ifdef __WANT_IO_DEF
 
@@ -64,6 +65,7 @@
 
 # define __isa_port2addr	generic_isa_port2addr
 # define __ioremap		generic_ioremap
+# define __ioremap_nocache	generic_ioremap_nocache
 # define __iounmap		generic_iounmap
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_hd64465.h linux/include/asm-sh/io_hd64465.h
--- v2.4.3/linux/include/asm-sh/io_hd64465.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/io_hd64465.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,90 @@
+/*
+ * include/asm-sh/io_hd64465.h
+ *
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+ *
+ * Derived from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for an HD64465 "Windows CE Intelligent Peripheral Controller".
+ */
+
+#ifndef _ASM_SH_IO_HD64465_H
+#define _ASM_SH_IO_HD64465_H
+
+#include <asm/io_generic.h>
+
+extern unsigned char hd64465_inb(unsigned long port);
+extern unsigned short hd64465_inw(unsigned long port);
+extern unsigned int hd64465_inl(unsigned long port);
+
+extern void hd64465_outb(unsigned char value, unsigned long port);
+extern void hd64465_outw(unsigned short value, unsigned long port);
+extern void hd64465_outl(unsigned int value, unsigned long port);
+
+extern unsigned char hd64465_inb_p(unsigned long port);
+extern void hd64465_outb_p(unsigned char value, unsigned long port);
+
+extern void hd64465_insb(unsigned long port, void *addr, unsigned long count);
+extern void hd64465_insw(unsigned long port, void *addr, unsigned long count);
+extern void hd64465_insl(unsigned long port, void *addr, unsigned long count);
+extern void hd64465_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void hd64465_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void hd64465_outsl(unsigned long port, const void *addr, unsigned long count);
+extern unsigned long hd64465_isa_port2addr(unsigned long offset);
+extern int hd64465_irq_demux(int irq);
+/* Provision for generic secondary demux step -- used by PCMCIA code */
+extern void hd64465_register_irq_demux(int irq,
+		int (*demux)(int irq, void *dev), void *dev);
+extern void hd64465_unregister_irq_demux(int irq);
+/* Set this variable to 1 to see port traffic */
+extern int hd64465_io_debug;
+/* Map a range of ports to a range of kernel virtual memory.
+ */
+extern void hd64465_port_map(unsigned short baseport, unsigned int nports,
+			     unsigned long addr, unsigned char shift);
+extern void hd64465_port_unmap(unsigned short baseport, unsigned int nports);
+
+
+#ifdef __WANT_IO_DEF
+
+# define __inb			hd64465_inb
+# define __inw			hd64465_inw
+# define __inl			hd64465_inl
+# define __outb			hd64465_outb
+# define __outw			hd64465_outw
+# define __outl			hd64465_outl
+
+# define __inb_p		hd64465_inb_p
+# define __inw_p		hd64465_inw
+# define __inl_p		hd64465_inl
+# define __outb_p		hd64465_outb_p
+# define __outw_p		hd64465_outw
+# define __outl_p		hd64465_outl
+
+# define __insb			hd64465_insb
+# define __insw			hd64465_insw
+# define __insl			hd64465_insl
+# define __outsb		hd64465_outsb
+# define __outsw		hd64465_outsw
+# define __outsl		hd64465_outsl
+
+# define __readb		generic_readb
+# define __readw		generic_readw
+# define __readl		generic_readl
+# define __writeb		generic_writeb
+# define __writew		generic_writew
+# define __writel		generic_writel
+
+# define __isa_port2addr	hd64465_isa_port2addr
+# define __ioremap		generic_ioremap
+# define __iounmap		generic_iounmap
+
+
+#endif
+
+#endif /* _ASM_SH_IO_HD64465_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_od.h linux/include/asm-sh/io_od.h
--- v2.4.3/linux/include/asm-sh/io_od.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/io_od.h	Wed Apr 11 21:24:52 2001
@@ -14,27 +14,27 @@
 
 #include <asm/io_generic.h>
 
-extern unsigned long od_inb(unsigned int port);
-extern unsigned long od_inw(unsigned int port);
-extern unsigned long od_inl(unsigned int port);
-
-extern void od_outb(unsigned long value, unsigned int port);
-extern void od_outw(unsigned long value, unsigned int port);
-extern void od_outl(unsigned long value, unsigned int port);
-
-extern unsigned long od_inb_p(unsigned int port);
-extern unsigned long od_inw_p(unsigned int port);
-extern unsigned long od_inl_p(unsigned int port);
-extern void od_outb_p(unsigned long value, unsigned int port);
-extern void od_outw_p(unsigned long value, unsigned int port);
-extern void od_outl_p(unsigned long value, unsigned int port);
-
-extern void od_insb(unsigned int port, void *addr, unsigned long count);
-extern void od_insw(unsigned int port, void *addr, unsigned long count);
-extern void od_insl(unsigned int port, void *addr, unsigned long count);
-extern void od_outsb(unsigned int port, const void *addr, unsigned long count);
-extern void od_outsw(unsigned int port, const void *addr, unsigned long count);
-extern void od_outsl(unsigned int port, const void *addr, unsigned long count);
+extern unsigned char od_inb(unsigned long port);
+extern unsigned short od_inw(unsigned long port);
+extern unsigned int od_inl(unsigned long port);
+
+extern void od_outb(unsigned char value, unsigned long port);
+extern void od_outw(unsigned short value, unsigned long port);
+extern void od_outl(unsigned int value, unsigned long port);
+
+extern unsigned char od_inb_p(unsigned long port);
+extern unsigned short od_inw_p(unsigned long port);
+extern unsigned int od_inl_p(unsigned long port);
+extern void od_outb_p(unsigned char value, unsigned long port);
+extern void od_outw_p(unsigned short value, unsigned long port);
+extern void od_outl_p(unsigned int value, unsigned long port);
+
+extern void od_insb(unsigned long port, void *addr, unsigned long count);
+extern void od_insw(unsigned long port, void *addr, unsigned long count);
+extern void od_insl(unsigned long port, void *addr, unsigned long count);
+extern void od_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void od_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void od_outsl(unsigned long port, const void *addr, unsigned long count);
 
 extern unsigned long od_isa_port2addr(unsigned long offset);
 
@@ -70,7 +70,6 @@
 
 # define __isa_port2addr	od_isa_port2addr
 # define __ioremap		generic_ioremap
-# define __ioremap_nocache	generic_ioremap_nocache
 # define __iounmap		generic_iounmap
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_se.h linux/include/asm-sh/io_se.h
--- v2.4.3/linux/include/asm-sh/io_se.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/io_se.h	Wed Apr 11 21:24:52 2001
@@ -14,27 +14,27 @@
 
 #include <asm/io_generic.h>
 
-extern unsigned long se_inb(unsigned int port);
-extern unsigned long se_inw(unsigned int port);
-extern unsigned long se_inl(unsigned int port);
-
-extern void se_outb(unsigned long value, unsigned int port);
-extern void se_outw(unsigned long value, unsigned int port);
-extern void se_outl(unsigned long value, unsigned int port);
-
-extern unsigned long se_inb_p(unsigned int port);
-extern void se_outb_p(unsigned long value, unsigned int port);
-
-extern void se_insb(unsigned int port, void *addr, unsigned long count);
-extern void se_insw(unsigned int port, void *addr, unsigned long count);
-extern void se_insl(unsigned int port, void *addr, unsigned long count);
-extern void se_outsb(unsigned int port, const void *addr, unsigned long count);
-extern void se_outsw(unsigned int port, const void *addr, unsigned long count);
-extern void se_outsl(unsigned int port, const void *addr, unsigned long count);
-
-extern unsigned long se_readb(unsigned long addr);
-extern unsigned long se_readw(unsigned long addr);
-extern unsigned long se_readl(unsigned long addr);
+extern unsigned char se_inb(unsigned long port);
+extern unsigned short se_inw(unsigned long port);
+extern unsigned int se_inl(unsigned long port);
+
+extern void se_outb(unsigned char value, unsigned long port);
+extern void se_outw(unsigned short value, unsigned long port);
+extern void se_outl(unsigned int value, unsigned long port);
+
+extern unsigned char se_inb_p(unsigned long port);
+extern void se_outb_p(unsigned char value, unsigned long port);
+
+extern void se_insb(unsigned long port, void *addr, unsigned long count);
+extern void se_insw(unsigned long port, void *addr, unsigned long count);
+extern void se_insl(unsigned long port, void *addr, unsigned long count);
+extern void se_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void se_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void se_outsl(unsigned long port, const void *addr, unsigned long count);
+
+extern unsigned char se_readb(unsigned long addr);
+extern unsigned short se_readw(unsigned long addr);
+extern unsigned int se_readl(unsigned long addr);
 extern void se_writeb(unsigned char b, unsigned long addr);
 extern void se_writew(unsigned short b, unsigned long addr);
 extern void se_writel(unsigned int b, unsigned long addr);
@@ -73,7 +73,6 @@
 
 # define __isa_port2addr	se_isa_port2addr
 # define __ioremap		generic_ioremap
-# define __ioremap_nocache	generic_ioremap_nocache
 # define __iounmap		generic_iounmap
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_unknown.h linux/include/asm-sh/io_unknown.h
--- v2.4.3/linux/include/asm-sh/io_unknown.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/io_unknown.h	Wed Apr 11 21:24:52 2001
@@ -12,38 +12,37 @@
 #ifndef _ASM_SH_IO_UNKNOWN_H
 #define _ASM_SH_IO_UNKNOWN_H
 
-extern unsigned long unknown_inb(unsigned int port);
-extern unsigned long unknown_inw(unsigned int port);
-extern unsigned long unknown_inl(unsigned int port);
-
-extern void unknown_outb(unsigned long value, unsigned int port);
-extern void unknown_outw(unsigned long value, unsigned int port);
-extern void unknown_outl(unsigned long value, unsigned int port);
-
-extern unsigned long unknown_inb_p(unsigned int port);
-extern unsigned long unknown_inw_p(unsigned int port);
-extern unsigned long unknown_inl_p(unsigned int port);
-extern void unknown_outb_p(unsigned long value, unsigned int port);
-extern void unknown_outw_p(unsigned long value, unsigned int port);
-extern void unknown_outl_p(unsigned long value, unsigned int port);
-
-extern void unknown_insb(unsigned int port, void *addr, unsigned long count);
-extern void unknown_insw(unsigned int port, void *addr, unsigned long count);
-extern void unknown_insl(unsigned int port, void *addr, unsigned long count);
-extern void unknown_outsb(unsigned int port, const void *addr, unsigned long count);
-extern void unknown_outsw(unsigned int port, const void *addr, unsigned long count);
-extern void unknown_outsl(unsigned int port, const void *addr, unsigned long count);
-
-extern unsigned long unknown_readb(unsigned long addr);
-extern unsigned long unknown_readw(unsigned long addr);
-extern unsigned long unknown_readl(unsigned long addr);
+extern unsigned char unknown_inb(unsigned long port);
+extern unsigned short unknown_inw(unsigned long port);
+extern unsigned int unknown_inl(unsigned long port);
+
+extern void unknown_outb(unsigned char value, unsigned long port);
+extern void unknown_outw(unsigned short value, unsigned long port);
+extern void unknown_outl(unsigned int value, unsigned long port);
+
+extern unsigned char unknown_inb_p(unsigned long port);
+extern unsigned short unknown_inw_p(unsigned long port);
+extern unsigned int unknown_inl_p(unsigned long port);
+extern void unknown_outb_p(unsigned char value, unsigned long port);
+extern void unknown_outw_p(unsigned short value, unsigned long port);
+extern void unknown_outl_p(unsigned int value, unsigned long port);
+
+extern void unknown_insb(unsigned long port, void *addr, unsigned long count);
+extern void unknown_insw(unsigned long port, void *addr, unsigned long count);
+extern void unknown_insl(unsigned long port, void *addr, unsigned long count);
+extern void unknown_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void unknown_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void unknown_outsl(unsigned long port, const void *addr, unsigned long count);
+
+extern unsigned char unknown_readb(unsigned long addr);
+extern unsigned short unknown_readw(unsigned long addr);
+extern unsigned int unknown_readl(unsigned long addr);
 extern void unknown_writeb(unsigned char b, unsigned long addr);
 extern void unknown_writew(unsigned short b, unsigned long addr);
 extern void unknown_writel(unsigned int b, unsigned long addr);
 
 extern unsigned long unknown_isa_port2addr(unsigned long offset);
-extern void * unknown_ioremap(unsigned long offset, unsigned long size);
-extern void * unknown_ioremap_nocache (unsigned long offset, unsigned long size);
+extern void *unknown_ioremap(unsigned long offset, unsigned long size);
 extern void unknown_iounmap(void *addr);
 
 #ifdef __WANT_IO_DEF
@@ -78,7 +77,6 @@
 
 # define __isa_port2addr	unknown_isa_port2addr
 # define __ioremap		unknown_ioremap
-# define __ioremap_nocache	unknown_ioremap_nocache
 # define __iounmap		unknown_iounmap
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/irq.h linux/include/asm-sh/irq.h
--- v2.4.3/linux/include/asm-sh/irq.h	Mon Oct  2 11:57:34 2000
+++ linux/include/asm-sh/irq.h	Wed Apr 11 21:24:52 2001
@@ -12,6 +12,7 @@
 
 #include <linux/config.h>
 #include <asm/machvec.h>
+#include <asm/ptrace.h>		/* for pt_regs */
 
 #if defined(__sh3__)
 #define INTC_IPRA  	0xfffffee2UL
@@ -32,12 +33,24 @@
 #define RTC_IPR_POS	 0
 #define RTC_PRIORITY	TIMER_PRIORITY
 
+#define DMTE0_IRQ	34
+#define DMTE1_IRQ	35
+#define DMTE2_IRQ	36
+#define DMTE3_IRQ	37
+#define DMAE_IRQ	38
+#define DMA_IPR_ADDR	INTC_IPRC
+#define DMA_IPR_POS	2
+#define DMA_PRIORITY	7
+
+#if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750)
 #define SCI_ERI_IRQ	23
 #define SCI_RXI_IRQ	24
 #define SCI_TXI_IRQ	25
 #define SCI_IPR_ADDR	INTC_IPRB
 #define SCI_IPR_POS	1
 #define SCI_PRIORITY	3
+#endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
 #define SCIF_ERI_IRQ	56
@@ -55,7 +68,7 @@
 #define IRDA_IPR_ADDR	INTC_IPRE
 #define IRDA_IPR_POS	2
 #define IRDA_PRIORITY	3
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 #define SCIF_ERI_IRQ	40
 #define SCIF_RXI_IRQ	41
 #define SCIF_BRI_IRQ	42
@@ -63,38 +76,87 @@
 #define SCIF_IPR_ADDR	INTC_IPRC
 #define SCIF_IPR_POS	1
 #define SCIF_PRIORITY	3
+#if defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#define SCIF1_ERI_IRQ	23
+#define SCIF1_RXI_IRQ	24
+#define SCIF1_BRI_IRQ	25
+#define SCIF1_TXI_IRQ	26
+#define SCIF1_IPR_ADDR	INTC_IPRB
+#define SCIF1_IPR_POS	1
+#define SCIF1_PRIORITY	3
+#endif
 #endif
 
-#ifdef CONFIG_SH_GENERIC
-/* In a generic kernel, NR_IRQS is an upper bound, and we should use
- * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value.
+/* NR_IRQS is made from three components:
+ *   1. ONCHIP_NR_IRQS - number of IRLS + on-chip peripherial modules
+ *   2. PINT_NR_IRQS   - number of PINT interrupts
+ *   3. OFFCHIP_NR_IRQS - numbe of IRQs from off-chip peripherial modules
  */
-#define NR_IRQS 80
-#define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs)
+
+/* 1. ONCHIP_NR_IRQS */
+#ifdef CONFIG_SH_GENERIC
+# define ONCHIP_NR_IRQS 89
 #else
-#if defined(__SH4__)
-/*
- * 48 = 32+16
- *
- * 32 for on chip support modules.
- * 16 for external interrupts.
- *
- */
-#define NR_IRQS	48
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707)
-#define NR_IRQS 64
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-#define NR_IRQS 32
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
-#ifdef CONFIG_HD64461
-#define NR_IRQS 80		/* HD64461_IRQBASE+16, see hd64461.h */
+# if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#  define ONCHIP_NR_IRQS 64
+#  define PINT_NR_IRQS   16
+# elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+#  define ONCHIP_NR_IRQS 32
+# elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+#  define ONCHIP_NR_IRQS 64	// Actually 61
+#  define PINT_NR_IRQS   16
+# elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#  define ONCHIP_NR_IRQS 48	// Actually 44
+# elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#  define ONCHIP_NR_IRQS 89
+# endif
+#endif
+
+/* 2. PINT_NR_IRQS */
+#ifdef CONFIG_SH_GENERIC
+# define PINT_NR_IRQS 16
 #else
-#define NR_IRQS 61
+# ifndef PINT_NR_IRQS
+#  define PINT_NR_IRQS 0
+# endif
 #endif
+
+#if PINT_NR_IRQS > 0
+# define PINT_IRQ_BASE  ONCHIP_NR_IRQS
 #endif
-#define ACTUAL_NR_IRQS NR_IRQS
+
+/* 3. OFFCHIP_NR_IRQS */
+#ifdef CONFIG_SH_GENERIC
+# define OFFCHIP_NR_IRQS 16
+#else
+# if defined(CONFIG_HD64461)
+#  define OFFCHIP_NR_IRQS 16
+# elif defined(CONFIG_HD64465)
+#  define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_EC3104)
+#  define OFFCHIP_NR_IRQS 16
+# else
+#  define OFFCHIP_NR_IRQS 0
+# endif
 #endif
 
+#if OFFCHIP_NR_IRQS > 0
+# define OFFCHIP_IRQ_BASE (ONCHIP_NR_IRQS + PINT_NR_IRQS)
+#endif
+
+/* NR_IRQS. 1+2+3 */
+#define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS)
+
+/* In a generic kernel, NR_IRQS is an upper bound, and we should use
+ * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value.
+ */
+#ifdef CONFIG_SH_GENERIC
+# define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs)
+#else
+# define ACTUAL_NR_IRQS NR_IRQS
+#endif
+
+
 extern void disable_irq(unsigned int);
 extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
@@ -123,6 +185,15 @@
 #define INTC_IPRF	0xa400001cUL
 #endif
 
+#define PORT_PACR	0xa4000100UL
+#define PORT_PBCR	0xa4000102UL
+#define PORT_PCCR	0xa4000104UL
+#define PORT_PFCR	0xa400010aUL
+#define PORT_PADR  	0xa4000120UL
+#define PORT_PBDR  	0xa4000122UL
+#define PORT_PCDR  	0xa4000124UL
+#define PORT_PFDR  	0xa400012aUL
+
 #define IRQ0_IRQ	32
 #define IRQ1_IRQ	33
 #define IRQ2_IRQ	34
@@ -130,19 +201,19 @@
 #define IRQ4_IRQ	36
 #define IRQ5_IRQ	37
 
-#define IRQ0_IRP_ADDR	INTC_IPRC
-#define IRQ1_IRP_ADDR	INTC_IPRC
-#define IRQ2_IRP_ADDR	INTC_IPRC
-#define IRQ3_IRP_ADDR	INTC_IPRC
-#define IRQ4_IRP_ADDR	INTC_IPRD
-#define IRQ5_IRP_ADDR	INTC_IPRD
-
-#define IRQ0_IRP_POS	0
-#define IRQ1_IRP_POS	1
-#define IRQ2_IRP_POS	2
-#define IRQ3_IRP_POS	3
-#define IRQ4_IRP_POS	0
-#define IRQ5_IRP_POS	1
+#define IRQ0_IPR_ADDR	INTC_IPRC
+#define IRQ1_IPR_ADDR	INTC_IPRC
+#define IRQ2_IPR_ADDR	INTC_IPRC
+#define IRQ3_IPR_ADDR	INTC_IPRC
+#define IRQ4_IPR_ADDR	INTC_IPRD
+#define IRQ5_IPR_ADDR	INTC_IPRD
+
+#define IRQ0_IPR_POS	0
+#define IRQ1_IPR_POS	1
+#define IRQ2_IPR_POS	2
+#define IRQ3_IPR_POS	3
+#define IRQ4_IPR_POS	0
+#define IRQ5_IPR_POS	1
 
 #define IRQ0_PRIORITY	1
 #define IRQ1_PRIORITY	1
@@ -150,21 +221,77 @@
 #define IRQ3_PRIORITY	1
 #define IRQ4_PRIORITY	1
 #define IRQ5_PRIORITY	1
-#endif
 
-extern int hd64461_irq_demux(int irq);
+#define PINT0_IRQ	40
+#define PINT8_IRQ	41
+
+#define PINT0_IPR_ADDR	INTC_IPRD
+#define PINT8_IPR_ADDR	INTC_IPRD
+
+#define PINT0_IPR_POS	3
+#define PINT8_IPR_POS	2
+#define PINT0_PRIORITY	2
+#define PINT8_PRIORITY	2
 
+extern int ipr_irq_demux(int irq);
+#define __irq_demux(irq) ipr_irq_demux(irq)
+
+#else
+#define __irq_demux(irq) irq
+#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+#define INTC2_FIRST_IRQ 64
+#define NR_INTC2_IRQS 25
+ 
+#define INTC2_BASE0 0xfe080000
+#define INTC2_INTC2MODE  (INTC2_BASE0+0x80)
+ 
+#define INTC2_INTPRI_OFFSET	0x00
+#define INTC2_INTREQ_OFFSET	0x20
+#define INTC2_INTMSK_OFFSET	0x40
+#define INTC2_INTMSKCLR_OFFSET	0x60
+ 
+extern void make_intc2_irq(unsigned int irq,unsigned int addr,
+                           unsigned int group,int pos,int priority);
+ 
+#endif                                                                        
+       
 #ifdef CONFIG_SH_GENERIC
+
 extern __inline__ int irq_demux(int irq) {
 	if (sh_mv.mv_irq_demux) {
 		irq = sh_mv.mv_irq_demux(irq);
 	}
-	return irq;
+	return __irq_demux(irq);
 }
+
 #elif defined(CONFIG_HD64461)
+
+extern int hd64461_irq_demux(int irq);
 #define irq_demux(irq) hd64461_irq_demux(irq)
+
+#elif defined(CONFIG_HD64465)
+
+extern int hd64465_irq_demux(int irq);
+#define irq_demux(irq) hd64465_irq_demux(irq)
+
+#elif defined(CONFIG_SH_EC3104)
+
+extern int ec3104_irq_demux(int irq);
+#define irq_demux ec3104_irq_demux
+
+#elif defined(CONFIG_SH_CAT68701)
+
+extern int cat68701_irq_demux(int irq);
+#define irq_demux cat68701_irq_demux
+
 #else
-#define irq_demux(irq) irq
+
+#define irq_demux(irq) __irq_demux(irq)
+
 #endif
+
+
 
 #endif /* __ASM_SH_IRQ_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/keyboard-ec3104.h linux/include/asm-sh/keyboard-ec3104.h
--- v2.4.3/linux/include/asm-sh/keyboard-ec3104.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/keyboard-ec3104.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,17 @@
+extern unsigned char ec3104_kbd_sysrq_xlate[];
+extern int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int ec3104_kbd_getkeycode(unsigned int scancode);
+extern int ec3104_kbd_translate(unsigned char, unsigned char *, char);
+extern char ec3104_kbd_unexpected_up(unsigned char);
+extern void ec3104_kbd_leds(unsigned char);
+extern void ec3104_kbd_init_hw(void);
+
+#define SYSRQ_KEY 0x54
+
+#define kbd_sysrq_xlate ec3104_kbd_sysrq_xlate
+#define kbd_setkeycode ec3104_kbd_setkeycode
+#define kbd_getkeycode ec3104_kbd_getkeycode
+#define kbd_translate ec3104_kbd_translate
+#define kbd_unexpected_up ec3104_kbd_unexpected_up
+#define kbd_leds ec3104_kbd_leds
+#define kbd_init_hw ec3104_kbd_init_hw
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/keyboard.h linux/include/asm-sh/keyboard.h
--- v2.4.3/linux/include/asm-sh/keyboard.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/keyboard.h	Wed Apr 11 21:24:52 2001
@@ -4,8 +4,12 @@
  *	$Id: keyboard.h,v 1.1 2000/06/10 21:45:48 yaegashi Exp $
  */
 
+#include <linux/config.h>
 #include <asm/machvec.h>
 
+#ifdef CONFIG_SH_EC3104
+#include <asm/keyboard-ec3104.h>
+#else
 static __inline__ int kbd_setkeycode(unsigned int scancode,
 				     unsigned int keycode)
 {
@@ -34,6 +38,7 @@
 }
 
 extern void hp600_kbd_init_hw(void);
+extern void dreamcast_kbd_init_hw(void);
 
 static __inline__ void kbd_init_hw(void)
 {
@@ -42,4 +47,5 @@
 	}
 }
 
+#endif
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/machvec.h linux/include/asm-sh/machvec.h
--- v2.4.3/linux/include/asm-sh/machvec.h	Wed Aug  9 13:59:04 2000
+++ linux/include/asm-sh/machvec.h	Wed Apr 11 21:24:52 2001
@@ -13,45 +13,45 @@
 #include <linux/config.h>
 #include <linux/types.h>
 
+struct timeval;
+
 struct sh_machine_vector
 {
 	const char *mv_name;
 
 	int mv_nr_irqs;
 
-	unsigned long (*mv_inb)(unsigned int);
-	unsigned long (*mv_inw)(unsigned int);
-	unsigned long (*mv_inl)(unsigned int);
-	void (*mv_outb)(unsigned long, unsigned int);
-	void (*mv_outw)(unsigned long, unsigned int);
-	void (*mv_outl)(unsigned long, unsigned int);
-
-	unsigned long (*mv_inb_p)(unsigned int);
-	unsigned long (*mv_inw_p)(unsigned int);
-	unsigned long (*mv_inl_p)(unsigned int);
-	void (*mv_outb_p)(unsigned long, unsigned int);
-	void (*mv_outw_p)(unsigned long, unsigned int);
-	void (*mv_outl_p)(unsigned long, unsigned int);
-
-	void (*mv_insb)(unsigned int port, void *addr, unsigned long count);
-	void (*mv_insw)(unsigned int port, void *addr, unsigned long count);
-	void (*mv_insl)(unsigned int port, void *addr, unsigned long count);
-	void (*mv_outsb)(unsigned int port, const void *addr, unsigned long count);
-	void (*mv_outsw)(unsigned int port, const void *addr, unsigned long count);
-	void (*mv_outsl)(unsigned int port, const void *addr, unsigned long count);
-	
-	unsigned long (*mv_readb)(unsigned long);
-	unsigned long (*mv_readw)(unsigned long);
-	unsigned long (*mv_readl)(unsigned long);
+	unsigned char (*mv_inb)(unsigned long);
+	unsigned short (*mv_inw)(unsigned long);
+	unsigned int (*mv_inl)(unsigned long);
+	void (*mv_outb)(unsigned char, unsigned long);
+	void (*mv_outw)(unsigned short, unsigned long);
+	void (*mv_outl)(unsigned int, unsigned long);
+
+	unsigned char (*mv_inb_p)(unsigned long);
+	unsigned short (*mv_inw_p)(unsigned long);
+	unsigned int (*mv_inl_p)(unsigned long);
+	void (*mv_outb_p)(unsigned char, unsigned long);
+	void (*mv_outw_p)(unsigned short, unsigned long);
+	void (*mv_outl_p)(unsigned int, unsigned long);
+
+	void (*mv_insb)(unsigned long port, void *addr, unsigned long count);
+	void (*mv_insw)(unsigned long port, void *addr, unsigned long count);
+	void (*mv_insl)(unsigned long port, void *addr, unsigned long count);
+	void (*mv_outsb)(unsigned long port, const void *addr, unsigned long count);
+	void (*mv_outsw)(unsigned long port, const void *addr, unsigned long count);
+	void (*mv_outsl)(unsigned long port, const void *addr, unsigned long count);
+
+	unsigned char (*mv_readb)(unsigned long);
+	unsigned short (*mv_readw)(unsigned long);
+	unsigned int (*mv_readl)(unsigned long);
 	void (*mv_writeb)(unsigned char, unsigned long);
 	void (*mv_writew)(unsigned short, unsigned long);
 	void (*mv_writel)(unsigned int, unsigned long);
 
 	void* (*mv_ioremap)(unsigned long offset, unsigned long size);
-	void* (*mv_ioremap_nocache)(unsigned long offset, unsigned long size);
 	void (*mv_iounmap)(void *addr);
 
-	unsigned long (*mv_port2addr)(unsigned long offset);
 	unsigned long (*mv_isa_port2addr)(unsigned long offset);
 
 	int (*mv_irq_demux)(int irq);
@@ -63,9 +63,17 @@
 
 	void (*mv_heartbeat)(void);
 
+	void (*mv_rtc_gettimeofday)(struct timeval *tv);
+	int (*mv_rtc_settimeofday)(const struct timeval *tv);
+
 	unsigned int mv_hw_se : 1;
 	unsigned int mv_hw_hp600 : 1;
+	unsigned int mv_hw_hp620 : 1;
+	unsigned int mv_hw_hp680 : 1;
+	unsigned int mv_hw_hp690 : 1;
 	unsigned int mv_hw_hd64461 : 1;
+	unsigned int mv_hw_hd64465 : 1;
+	unsigned int mv_hw_dreamcast : 1;
 };
 
 extern struct sh_machine_vector sh_mv;
@@ -74,7 +82,12 @@
 #ifdef CONFIG_SH_GENERIC
 #define MACH_SE		(sh_mv.mv_hw_se)
 #define MACH_HP600	(sh_mv.mv_hw_hp600)
+#define MACH_HP620	(sh_mv.mv_hw_hp620)
+#define MACH_HP680	(sh_mv.mv_hw_hp680)
+#define MACH_HP690	(sh_mv.mv_hw_hp690)
 #define MACH_HD64461	(sh_mv.mv_hw_hd64461)
+#define MACH_HD64465	(sh_mv.mv_hw_hd64465)
+#define MACH_DREAMCAST	(sh_mv.mv_hw_dreamcast)
 #else
 # ifdef CONFIG_SH_SOLUTION_ENGINE
 #  define MACH_SE		1
@@ -86,10 +99,40 @@
 # else
 #  define MACH_HP600		0
 # endif
+# ifdef CONFIG_SH_HP620
+#  define MACH_HP620		1
+# else
+#  define MACH_HP620		0
+# endif
+# ifdef CONFIG_SH_HP680
+#  define MACH_HP680		1
+# else
+#  define MACH_HP680		0
+# endif
+# ifdef CONFIG_SH_HP690
+#  define MACH_HP690		1
+# else
+#  define MACH_HP690		0
+# endif
 # ifdef CONFIG_HD64461
 #  define MACH_HD64461		1
 # else
 #  define MACH_HD64461		0
+# endif
+# ifdef CONFIG_HD64465
+#  define MACH_HD64465		1
+# else
+#  define MACH_HD64465		0
+# endif
+# ifdef CONFIG_SH_EC3104
+#  define MACH_EC3104		1
+# else
+#  define MACH_EC3104		0
+# endif
+# ifdef CONFIG_SH_DREAMCAST
+#  define MACH_DREAMCAST	1
+# else
+#  define MACH_DREAMCAST	0
 # endif
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- v2.4.3/linux/include/asm-sh/pci.h	Mon Oct  2 11:57:34 2000
+++ linux/include/asm-sh/pci.h	Wed Apr 11 21:24:52 2001
@@ -7,13 +7,13 @@
    already-configured bus numbers - to be used for buggy BIOSes
    or architectures with incomplete PCI setup by the loader */
 
-#define pcibios_assign_all_busses()	0
+#define pcibios_assign_all_busses()	1
 
 /* These are currently the correct values for the STM overdrive board. 
  * We need some way of setting this on a board specific way, it will 
  * not be the same on other boards I think
  */
-#if 1 /* def CONFIG_SH_OVERDRIVE */
+#if 1 /* def CONFIG_SH_7750_OVERDRIVE || def CONFIG_CPU_SUBTYPE_ST40STB1 */
 #define PCIBIOS_MIN_IO		0x2000
 #define PCIBIOS_MIN_MEM		0x10000000
 #endif
@@ -70,6 +70,8 @@
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size,int directoin)
 {
+  
+        flush_cache_all();
 	return virt_to_bus(ptr);
 }
 
@@ -104,6 +106,7 @@
 static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			     int nents,int direction)
 {
+        flush_cache_all();
 	return nents;
 }
 
@@ -145,6 +148,19 @@
 {
 	/* Nothing to do */
 }
+
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 1;
+}
+
+
 
 /* These macros should be used after a pci_map_sg call has been done
  * to get bus addresses of each of the SG entries and their lengths.
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgalloc-2level.h linux/include/asm-sh/pgalloc-2level.h
--- v2.4.3/linux/include/asm-sh/pgalloc-2level.h	Fri Oct 13 12:06:52 2000
+++ linux/include/asm-sh/pgalloc-2level.h	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-#ifndef __ASM_SH_PGALLOC_2LEVEL_H
-#define __ASM_SH_PGALLOC_2LEVEL_H
-
-/*
- * traditional two-level paging, page table allocation routines:
- */
-
-static __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-static __inline__ void free_pmd_fast(pmd_t *pmd) { }
-static __inline__ void free_pmd_slow(pmd_t *pmd) { }
-
-static __inline__ pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	if (!pgd)
-		BUG();
-	return (pmd_t *) pgd;
-}
-
-#endif /* __ASM_SH_PGALLOC_2LEVEL_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgalloc.h linux/include/asm-sh/pgalloc.h
--- v2.4.3/linux/include/asm-sh/pgalloc.h	Fri Oct 13 12:06:52 2000
+++ linux/include/asm-sh/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -10,23 +10,22 @@
 #define pte_quicklist (current_cpu_data.pte_quick)
 #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
 
-#include <asm/pgalloc-2level.h>
+#define pmd_populate(mm, pmd, pte) \
+		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
 
 /*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
+ * Allocate and free page tables.
  */
 
 static __inline__ pgd_t *get_pgd_slow(void)
 {
 	unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
-	pgd_t *ret = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
+	pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
 
-	if (ret)
-		memset(ret, 0, pgd_size);
+	if (pgd)
+		memset(pgd, 0, pgd_size);
 
-	return ret;
+	return pgd;
 }
 
 static __inline__ pgd_t *get_pgd_fast(void)
@@ -54,14 +53,21 @@
 	kfree(pgd);
 }
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte)
+		clear_page(pte);
+	return pte;
+}
 
-static __inline__ pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
 	unsigned long *ret;
 
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
 		pgtable_cache_size--;
@@ -69,65 +75,21 @@
 	return (pte_t *)ret;
 }
 
-static __inline__ void free_pte_fast(pte_t *pte)
+static __inline__ void pte_free_fast(pte_t *pte)
 {
 	*(unsigned long *)pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
 
-static __inline__ void free_pte_slow(pte_t *pte)
+static __inline__ void pte_free_slow(pte_t *pte)
 {
 	free_page((unsigned long)pte);
 }
 
-#define pte_free_kernel(pte)    free_pte_slow(pte)
-#define pte_free(pte)	   free_pte_slow(pte)
-#define pgd_free(pgd)	   free_pgd_slow(pgd)
-#define pgd_alloc()	     get_pgd_fast()
-
-static __inline__ pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
-{
-	if (!pmd)
-		BUG();
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t * page = (pte_t *) get_pte_fast();
-		
-		if (!page)
-			return get_pte_kernel_slow(pmd, address);
-		set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page)));
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-static __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
-	if (pmd_none(*pmd))
-		goto getnew;
-	if (pmd_bad(*pmd))
-		goto fix;
-	return (pte_t *)pmd_page(*pmd) + address;
-getnew:
-{
-	unsigned long page = (unsigned long) get_pte_fast();
-	
-	if (!page)
-		return get_pte_slow(pmd, address);
-	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page)));
-	return (pte_t *)page + address;
-}
-fix:
-	__handle_bad_pmd(pmd);
-	return NULL;
-}
+#define pte_free(pte)		pte_free_slow(pte)
+#define pgd_free(pgd)		free_pgd_slow(pgd)
+#define pgd_alloc(mm)		get_pgd_fast()
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -137,8 +99,12 @@
 {
 }
 
-#define pmd_free_kernel		pmd_free
-#define pmd_alloc_kernel	pmd_alloc
+#define pmd_alloc_one_fast(mm, addr)	({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, addr)		({ BUG(); ((pmd_t *)2); })
+#define pmd_free_slow(x)		do { } while (0)
+#define pmd_free_fast(x)		do { } while (0)
+#define pmd_free(x)			do { } while (0)
+#define pgd_populate(mm, pmd, pte)	BUG()
 
 extern int do_check_pgt_cache(int, int);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgtable-2level.h linux/include/asm-sh/pgtable-2level.h
--- v2.4.3/linux/include/asm-sh/pgtable-2level.h	Thu Jan  4 13:19:13 2001
+++ linux/include/asm-sh/pgtable-2level.h	Wed Apr 11 21:24:52 2001
@@ -32,7 +32,7 @@
 static inline int pgd_none(pgd_t pgd)		{ return 0; }
 static inline int pgd_bad(pgd_t pgd)		{ return 0; }
 static inline int pgd_present(pgd_t pgd)	{ return 1; }
-#define pgd_clear(xp)	do { } while (0)
+static inline void pgd_clear (pgd_t * pgd) 	{ }
 
 /*
  * Certain architectures need to do special things when PTEs
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- v2.4.3/linux/include/asm-sh/pgtable.h	Sun Jan 28 18:56:00 2001
+++ linux/include/asm-sh/pgtable.h	Wed Apr 11 21:24:52 2001
@@ -166,12 +166,6 @@
 #define __S110	PAGE_SHARED
 #define __S111	PAGE_SHARED
 
-/*
- * Handling allocation failures during page table setup.
- */
-extern void __handle_bad_pmd(pmd_t * pmd);
-extern void __handle_bad_pmd_kernel(pmd_t * pmd);
-
 #define pte_none(x)	(!pte_val(x))
 #define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
 #define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/processor.h linux/include/asm-sh/processor.h
--- v2.4.3/linux/include/asm-sh/processor.h	Thu Jan  4 13:19:13 2001
+++ linux/include/asm-sh/processor.h	Wed Apr 11 21:24:52 2001
@@ -24,6 +24,7 @@
 	CPU_SH7708,		/* Represents 7707, 7708, 7708S, 7708R, 7709 */
 	CPU_SH7729,		/* Represents 7709A, 7729 */
 	CPU_SH7750,
+	CPU_ST40STB1,
 	CPU_SH_NONE
 };
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/semaphore.h linux/include/asm-sh/semaphore.h
--- v2.4.3/linux/include/asm-sh/semaphore.h	Sun Mar  5 09:33:55 2000
+++ linux/include/asm-sh/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -13,6 +13,7 @@
  */
 
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -134,151 +135,6 @@
 #endif
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * SuperH version by Niibe Yutaka
- */
-struct rw_semaphore {
-	atomic_t		count;
-	volatile unsigned char	write_bias_granted;
-	volatile unsigned char	read_bias_granted;
-	volatile unsigned char	pad1;
-	volatile unsigned char	pad2;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#define RW_LOCK_BIAS		 0x01000000
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-	atomic_set(&sem->count, RW_LOCK_BIAS);
-	sem->read_bias_granted = 0;
-	sem->write_bias_granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-	int saved = atomic_read(&sem->count), new;
-#if WAITQUEUE_DEBUG
-	if (sem->__magic != (long)&sem->__magic)
-		BUG();
-#endif
-	if ((new = atomic_dec_return(&sem->count)) < 0)
-		__down_read(sem, (new < 0 && saved >=0));
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-	int saved = atomic_read(&sem->count), new;
-#if WAITQUEUE_DEBUG
-	if (sem->__magic != (long)&sem->__magic)
-		BUG();
-#endif
-	if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count)) != 0)
-		__down_write(sem, (new < 0 && saved >=0));
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
-	if (atomic_inc_return(&sem->count) == 0)
-		__rwsem_wake(sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
-	int saved = atomic_read(&sem->count), new;
-
-	new = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-	if (saved < 0 && new >= 0)
-		__rwsem_wake(sem);
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (sem->read_bias_granted)
-		BUG();
-	if (sem->write_bias_granted)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
 }
 
 #endif /* __ASM_SH_SEMAPHORE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/serial-ec3104.h linux/include/asm-sh/serial-ec3104.h
--- v2.4.3/linux/include/asm-sh/serial-ec3104.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/serial-ec3104.h	Wed Apr 11 21:24:52 2001
@@ -0,0 +1,24 @@
+#include <asm/ec3104.h>
+/* Naturally we don't know the exact value but 115200 baud has a divisor
+ * of 9 and 19200 baud has a divisor of 52, so this seems like a good
+ * guess.  */
+#define BASE_BAUD (16800000 / 16)
+
+#define RS_TABLE_SIZE  3
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+/* there is a fourth serial port with the expected values as well, but
+ * it's got the keyboard controller behind it so we can't really use it
+ * (without moving the keyboard driver to userspace, which doesn't sound
+ * like a very good idea) */
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x11C00, EC3104_IRQBASE+7, STD_COM_FLAGS }, /* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x12000, EC3104_IRQBASE+8, STD_COM_FLAGS }, /* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x12400, EC3104_IRQBASE+9, STD_COM_FLAGS }, /* ttyS2 */
+
+#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
+
+/* XXX: This should be moved ino irq.h */
+#define irq_cannonicalize(x) (x)
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/serial.h linux/include/asm-sh/serial.h
--- v2.4.3/linux/include/asm-sh/serial.h	Sat Jul 22 07:42:06 2000
+++ linux/include/asm-sh/serial.h	Wed Apr 11 21:24:52 2001
@@ -7,6 +7,13 @@
 #ifndef _ASM_SERIAL_H
 #define _ASM_SERIAL_H
 
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_SH_EC3104
+#include <asm/serial-ec3104.h>
+#else
+
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
  *
@@ -16,18 +23,32 @@
  */
 #define BASE_BAUD ( 1843200 / 16 )
 
-#define RS_TABLE_SIZE  2
-
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
+#ifdef CONFIG_HD64465
+#include <asm/hd64465.h>
+
+#define RS_TABLE_SIZE  1
+
+#define STD_SERIAL_PORT_DEFNS                   \
+        /* UART CLK   PORT IRQ     FLAGS        */                      \
+        { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS }  /* ttyS0 */
+
+#else
+
+#define RS_TABLE_SIZE  2
+
 #define STD_SERIAL_PORT_DEFNS			\
 	/* UART CLK   PORT IRQ     FLAGS        */			\
 	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
 	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }	/* ttyS1 */
 
+#endif
+
 #define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
 
 /* XXX: This should be moved ino irq.h */
 #define irq_cannonicalize(x) (x)
 
+#endif
 #endif /* _ASM_SERIAL_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/sigcontext.h linux/include/asm-sh/sigcontext.h
--- v2.4.3/linux/include/asm-sh/sigcontext.h	Mon Apr 24 13:54:17 2000
+++ linux/include/asm-sh/sigcontext.h	Wed Apr 11 21:24:52 2001
@@ -16,7 +16,7 @@
 #if defined(__SH4__)
 	/* FPU registers */
 	unsigned long sc_fpregs[16];
-	unsigned long long sc_xdregs[8];
+	unsigned long sc_xfpregs[16];
 	unsigned int sc_fpscr;
 	unsigned int sc_fpul;
 	unsigned int sc_ownedfp;
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/kmap_types.h linux/include/asm-sparc/kmap_types.h
--- v2.4.3/linux/include/asm-sparc/kmap_types.h	Fri Aug  4 18:16:11 2000
+++ linux/include/asm-sparc/kmap_types.h	Thu Apr 12 12:11:39 2001
@@ -4,6 +4,8 @@
 enum km_type {
 	KM_BOUNCE_READ,
 	KM_BOUNCE_WRITE,
+	KM_SKB_DATA,
+	KM_SKB_DATA_SOFTIRQ,
 	KM_TYPE_NR
 };
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/perfctr.h linux/include/asm-sparc/perfctr.h
--- v2.4.3/linux/include/asm-sparc/perfctr.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc/perfctr.h	Thu Apr 12 12:10:25 2001
@@ -60,10 +60,10 @@
 #ifndef __KERNEL__
 
 #define  PRIV 0x00000001
-#define  USR  0x00000002
-#define  SYS  0x00000004
+#define  SYS  0x00000002
+#define  USR  0x00000004
 
-/* Pic.S0 Selection Bit Field Encoding  */
+/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II  */
 #define  CYCLE_CNT            0x00000000
 #define  INSTR_CNT            0x00000010
 #define  DISPATCH0_IC_MISS    0x00000020
@@ -77,7 +77,38 @@
 #define  EC_SNOOP_INV         0x000000E0
 #define  EC_RD_HIT            0x000000F0
 
-/* Pic.S1 Selection Bit Field Encoding  */
+/* Pic.S0 Selection Bit Field Encoding, Ultra-III  */
+#define  US3_CYCLE_CNT	      	0x00000000
+#define  US3_INSTR_CNT	      	0x00000010
+#define  US3_DISPATCH0_IC_MISS	0x00000020
+#define  US3_DISPATCH0_BR_TGT	0x00000030
+#define  US3_DISPATCH0_2ND_BR	0x00000040
+#define  US3_RSTALL_STOREQ	0x00000050
+#define  US3_RSTALL_IU_USE	0x00000060
+#define  US3_IC_REF		0x00000080
+#define  US3_DC_RD		0x00000090
+#define  US3_DC_WR		0x000000a0
+#define  US3_EC_REF		0x000000c0
+#define  US3_EC_WR_HIT_RTO	0x000000d0
+#define  US3_EC_SNOOP_INV	0x000000e0
+#define  US3_EC_RD_MISS		0x000000f0
+#define  US3_PC_PORT0_RD	0x00000100
+#define  US3_SI_SNOOP		0x00000110
+#define  US3_SI_CIQ_FLOW	0x00000120
+#define  US3_SI_OWNED		0x00000130
+#define  US3_SW_COUNT_0		0x00000140
+#define  US3_IU_BR_MISS_TAKEN	0x00000150
+#define  US3_IU_BR_COUNT_TAKEN	0x00000160
+#define  US3_DISP_RS_MISPRED	0x00000170
+#define  US3_FA_PIPE_COMPL	0x00000180
+#define  US3_MC_READS_0		0x00000200
+#define  US3_MC_READS_1		0x00000210
+#define  US3_MC_READS_2		0x00000220
+#define  US3_MC_READS_3		0x00000230
+#define  US3_MC_STALLS_0	0x00000240
+#define  US3_MC_STALLS_2	0x00000250
+
+/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II  */
 #define  CYCLE_CNT_D1         0x00000000
 #define  INSTR_CNT_D1         0x00000800
 #define  DISPATCH0_IC_MISPRED 0x00001000
@@ -90,6 +121,47 @@
 #define  EC_WB                0x00006800
 #define  EC_SNOOP_CB          0x00007000
 #define  EC_IT_HIT            0x00007800
+
+/* Pic.S1 Selection Bit Field Encoding, Ultra-III  */
+#define  US3_CYCLE_CNT_D1	0x00000000
+#define  US3_INSTR_CNT_D1	0x00000800
+#define  US3_DISPATCH0_MISPRED	0x00001000
+#define  US3_IC_MISS_CANCELLED	0x00001800
+#define  US3_RE_ENDIAN_MISS	0x00002000
+#define  US3_RE_FPU_BYPASS	0x00002800
+#define  US3_RE_DC_MISS		0x00003000
+#define  US3_RE_EC_MISS		0x00003800
+#define  US3_IC_MISS		0x00004000
+#define  US3_DC_RD_MISS		0x00004800
+#define  US3_DC_WR_MISS		0x00005000
+#define  US3_RSTALL_FP_USE	0x00005800
+#define  US3_EC_MISSES		0x00006000
+#define  US3_EC_WB		0x00006800
+#define  US3_EC_SNOOP_CB	0x00007000
+#define  US3_EC_IC_MISS		0x00007800
+#define  US3_RE_PC_MISS		0x00008000
+#define  US3_ITLB_MISS		0x00008800
+#define  US3_DTLB_MISS		0x00009000
+#define  US3_WC_MISS		0x00009800
+#define  US3_WC_SNOOP_CB	0x0000a000
+#define  US3_WC_SCRUBBED	0x0000a800
+#define  US3_WC_WB_WO_READ	0x0000b000
+#define  US3_PC_SOFT_HIT	0x0000c000
+#define  US3_PC_SNOOP_INV	0x0000c800
+#define  US3_PC_HARD_HIT	0x0000d000
+#define  US3_PC_PORT1_RD	0x0000d800
+#define  US3_SW_COUNT_1		0x0000e000
+#define  US3_IU_STAT_BR_MIS_UNTAKEN	0x0000e800
+#define  US3_IU_STAT_BR_COUNT_UNTAKEN	0x0000f000
+#define  US3_PC_MS_MISSES	0x0000f800
+#define  US3_MC_WRITES_0	0x00010800
+#define  US3_MC_WRITES_1	0x00011000
+#define  US3_MC_WRITES_2	0x00011800
+#define  US3_MC_WRITES_3	0x00012000
+#define  US3_MC_STALLS_1	0x00012800
+#define  US3_MC_STALLS_3	0x00013000
+#define  US3_RE_RAW_MISS	0x00013800
+#define  US3_FM_PIPE_COMPLETION	0x00014000
 
 struct vcounter_struct {
   unsigned long long vcnt0;
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h
--- v2.4.3/linux/include/asm-sparc/pgalloc.h	Mon Oct 16 13:36:08 2000
+++ linux/include/asm-sparc/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -137,6 +137,6 @@
 BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void)
 
 #define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd)
-#define pgd_alloc() BTFIXUP_CALL(pgd_alloc)()
+#define pgd_alloc(mm) BTFIXUP_CALL(pgd_alloc)()
 
 #endif /* _SPARC64_PGALLOC_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v2.4.3/linux/include/asm-sparc/processor.h	Mon Jan  1 10:37:41 2001
+++ linux/include/asm-sparc/processor.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.80 2000/12/31 10:05:43 davem Exp $
+/* $Id: processor.h,v 1.81 2001/03/27 02:36:37 davem Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -90,7 +90,6 @@
 
 #define SPARC_FLAG_KTHREAD      0x1    /* task is a kernel thread */
 #define SPARC_FLAG_UNALIGNED    0x2    /* is allowed to do unaligned accesses */
-#define SPARC_FLAG_MMAPSHARED	0x4    /* task wants a shared mmap */
 
 #define INIT_MMAP { &init_mm, (0), (0), \
 		    NULL, __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h
--- v2.4.3/linux/include/asm-sparc/semaphore.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc/semaphore.h	Tue Apr 17 17:19:31 2001
@@ -7,6 +7,7 @@
 
 #include <asm/atomic.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 	atomic_t count;
@@ -207,201 +208,6 @@
 	: "0" (increment), "r" (ptr), "i" (__up)
 	: "g3", "g4", "g7", "memory", "cc");
 }	
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subtracting
- * BIAS once per CPU will result in the int remaining
- * negative.
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *	      -ben
- */
-#define RW_LOCK_BIAS		0x01000000
-
-struct rw_semaphore {
-	int			count;
-	unsigned char		lock;
-	unsigned char		read_not_granted;
-	unsigned char		write_not_granted;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ (count), 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-  __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-  __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	sem->count = RW_LOCK_BIAS;
-	sem->lock = 0;
-	sem->read_not_granted = 0xff;
-	sem->write_not_granted = 0xff;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern void ___down_read(/* Special calling convention */ void);
-extern void ___down_write(/* Special calling convention */ void);
-extern void ___up_read(/* Special calling convention */ void);
-extern void ___up_write(/* Special calling convention */ void);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
-	register volatile int *ptr asm("g1");
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-
-	ptr = &sem->count;
-
-	__asm__ __volatile__("
-	mov	%%o7, %%g4
-	call	%1
-	 add	%%o7, 8, %%o7
-	"
-	:: "r" (ptr), "i" (___down_read)
-	: "g2", "g3", "g4", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
-	if (!sem->write_not_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
-	register volatile int *ptr asm("g1");
-
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-
-	ptr = &sem->count;
-
-	__asm__ __volatile__("
-	mov	%%o7, %%g4
-	call	%1
-	 add	%%o7, 8, %%o7
-	"
-	:: "r" (ptr), "i" (___down_write)
-	: "g2", "g3", "g4", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (!sem->read_not_granted)
-		BUG();
-	if (!sem->write_not_granted)
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
-	register volatile int *ptr asm("g1");
-
-	ptr = &sem->count;
-
-	__asm__ __volatile__("
-	mov	%%o7, %%g4
-	call	%1
-	 add	%%o7, 8, %%o7
-	"
-	:: "r" (ptr), "i" (___up_read)
-	: "g2", "g3", "g4", "g7", "memory", "cc");
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
-	register volatile int *ptr asm("g1");
-
-	ptr = &sem->count;
-
-	__asm__ __volatile__("
-	mov	%%o7, %%g4
-	call	%1
-	 add	%%o7, 8, %%o7
-	"
-	:: "r" (ptr), "i" (___up_write)
-	: "g2", "g3", "g4", "g7", "memory", "cc");
-}
-
-static inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (!sem->write_not_granted)
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-static inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (!sem->read_not_granted)
-		BUG();
-	if (!sem->write_not_granted)
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
-}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/asi.h linux/include/asm-sparc64/asi.h
--- v2.4.3/linux/include/asm-sparc64/asi.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/asi.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.4 2001/03/15 02:08:46 davem Exp $ */
+/* $Id: asi.h,v 1.5 2001/03/29 11:47:47 davem Exp $ */
 #ifndef _SPARC64_ASI_H
 #define _SPARC64_ASI_H
 
@@ -80,6 +80,7 @@
 #define ASI_BRPRED_ARRAY	0x6f /* (III) Branch Prediction RAM diag	*/
 #define ASI_BLK_AIUP		0x70 /* Primary, user, block load/store		*/
 #define ASI_BLK_AIUS		0x71 /* Secondary, user, block load/store	*/
+#define ASI_MCU_CTRL_REG	0x72 /* (III) Memory controller registers	*/
 #define ASI_EC_DATA		0x74 /* (III) E-cache data staging register	*/
 #define ASI_EC_CTRL		0x75 /* (III) E-cache control register		*/
 #define ASI_EC_W		0x76 /* E-cache diag write access		*/
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/bbc.h linux/include/asm-sparc64/bbc.h
--- v2.4.3/linux/include/asm-sparc64/bbc.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/bbc.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: bbc.h,v 1.1 2001/03/24 06:03:03 davem Exp $
+/* $Id: bbc.h,v 1.2 2001/03/26 23:47:18 davem Exp $
  * bbc.h: Defines for BootBus Controller found on UltraSPARC-III
  *        systems.
  *
@@ -89,7 +89,7 @@
  * is asserted can be controlled by this regiser.
  */
 #define BBC_WDACTION_RST  0x01	/* When set, watchdog causes system reset.
-				 * When clear, all cpus receive XIR reset.
+				 * When clear, BBC ignores watchdog signal.
 				 */
 #define BBC_WDACTION_RESV 0xfe	/* Reserved */
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.4.3/linux/include/asm-sparc64/bitops.h	Tue Oct  3 09:24:41 2000
+++ linux/include/asm-sparc64/bitops.h	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.31 2000/09/23 02:09:21 davem Exp $
+/* $Id: bitops.h,v 1.32 2001/04/14 01:12:16 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -9,16 +9,24 @@
 
 #include <asm/byteorder.h>
 
-extern long __test_and_set_bit(unsigned long nr, volatile void *addr);
-extern long __test_and_clear_bit(unsigned long nr, volatile void *addr);
-extern long __test_and_change_bit(unsigned long nr, volatile void *addr);
-
-#define test_and_set_bit(nr,addr)	(__test_and_set_bit(nr,addr)!=0)
-#define test_and_clear_bit(nr,addr)	(__test_and_clear_bit(nr,addr)!=0)
-#define test_and_change_bit(nr,addr)	(__test_and_change_bit(nr,addr)!=0)
-#define set_bit(nr,addr)		((void)__test_and_set_bit(nr,addr))
-#define clear_bit(nr,addr)		((void)__test_and_clear_bit(nr,addr))
-#define change_bit(nr,addr)		((void)__test_and_change_bit(nr,addr))
+extern long ___test_and_set_bit(unsigned long nr, volatile void *addr);
+extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
+extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
+
+#define test_and_set_bit(nr,addr)	(___test_and_set_bit(nr,addr)!=0)
+#define test_and_clear_bit(nr,addr)	(___test_and_clear_bit(nr,addr)!=0)
+#define test_and_change_bit(nr,addr)	(___test_and_change_bit(nr,addr)!=0)
+#define set_bit(nr,addr)		((void)___test_and_set_bit(nr,addr))
+#define clear_bit(nr,addr)		((void)___test_and_clear_bit(nr,addr))
+#define change_bit(nr,addr)		((void)___test_and_change_bit(nr,addr))
+
+/* "non-atomic" versions, nothing special for now... */
+#define __set_bit(X,Y)		set_bit(X,Y)
+#define __clear_bit(X,Y)	clear_bit(X,Y)
+#define __change_bit(X,Y)	change_bit(X,Y)
+#define __test_and_set_bit(X,Y)		test_and_set_bit(X,Y)
+#define __test_and_clear_bit(X,Y)	test_and_clear_bit(X,Y)
+#define __test_and_change_bit(X,Y)	test_and_change_bit(X,Y)
 
 #define smp_mb__before_clear_bit()	do { } while(0)
 #define smp_mb__after_clear_bit()	do { } while(0)
@@ -170,13 +178,13 @@
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
 
-extern long __test_and_set_le_bit(int nr, volatile void *addr);
-extern long __test_and_clear_le_bit(int nr, volatile void *addr);
+extern long ___test_and_set_le_bit(int nr, volatile void *addr);
+extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
 
-#define test_and_set_le_bit(nr,addr)	(__test_and_set_le_bit(nr,addr)!=0)
-#define test_and_clear_le_bit(nr,addr)	(__test_and_clear_le_bit(nr,addr)!=0)
-#define set_le_bit(nr,addr)		((void)__test_and_set_le_bit(nr,addr))
-#define clear_le_bit(nr,addr)		((void)__test_and_clear_le_bit(nr,addr))
+#define test_and_set_le_bit(nr,addr)	(___test_and_set_le_bit(nr,addr)!=0)
+#define test_and_clear_le_bit(nr,addr)	(___test_and_clear_le_bit(nr,addr)!=0)
+#define set_le_bit(nr,addr)		((void)___test_and_set_le_bit(nr,addr))
+#define clear_le_bit(nr,addr)		((void)___test_and_clear_le_bit(nr,addr))
 
 extern __inline__ int test_le_bit(int nr, __const__ void * addr)
 {
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/chafsr.h linux/include/asm-sparc64/chafsr.h
--- v2.4.3/linux/include/asm-sparc64/chafsr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/chafsr.h	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,150 @@
+/* $Id: chafsr.h,v 1.1 2001/03/28 10:56:34 davem Exp $ */
+#ifndef _SPARC64_CHAFSR_H
+#define _SPARC64_CHAFSR_H
+
+/* Cheetah Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */
+
+/* All bits of this register except M_SYNDROME and E_SYNDROME are
+ * read, write 1 to clear.  M_SYNDROME and E_SYNDROME are read-only.
+ */
+
+/* Multiple errors of the same type have occurred.  This bit is set when
+ * an uncorrectable error or a SW correctable error occurs and the status
+ * bit to report that error is already set.  When multiple errors of
+ * different types are indicated by setting multiple status bits.
+ *
+ * This bit is not set if multiple HW corrected errors with the same
+ * status bit occur, only uncorrectable and SW correctable ones have
+ * this behavior.
+ *
+ * This bit is not set when multiple ECC errors happen within a single
+ * 64-byte system bus transaction.  Only the first ECC error in a 16-byte
+ * subunit will be logged.  All errors in subsequent 16-byte subunits
+ * from the same 64-byte transaction are ignored.
+ */
+#define CHAFSR_ME		0x0020000000000000
+
+/* Privileged state error has occurred.  This is a capture of PSTATE.PRIV
+ * at the time the error is detected.
+ */
+#define CHAFSR_PRIV		0x0010000000000000
+
+/* The following bits 51 (CHAFSR_PERR) to 33 (CHAFSR_CE) are sticky error
+ * bits and record the most recently detected errors.  Bits accumulate
+ * errors that have been detected since the last write to clear the bit.
+ */
+
+/* System interface protocol error.  The processor asserts its' ERROR
+ * pin when this event occurs and it also logs a specific cause code
+ * into a JTAG scannable flop.
+ */
+#define CHAFSR_PERR		0x0008000000000000
+
+/* Internal processor error.  The processor asserts its' ERROR
+ * pin when this event occurs and it also logs a specific cause code
+ * into a JTAG scannable flop.
+ */
+#define CHAFSR_IERR		0x0004000000000000
+
+/* System request parity error on incoming address */
+#define CHAFSR_ISAP		0x0002000000000000
+
+/* HW Corrected system bus MTAG ECC error */
+#define CHAFSR_EMC		0x0001000000000000
+
+/* Uncorrectable system bus MTAG ECC error */
+#define CHAFSR_EMU		0x0000800000000000
+
+/* HW Corrected system bus data ECC error for read of interrupt vector */
+#define CHAFSR_IVC		0x0000400000000000
+
+/* Uncorrectable system bus data ECC error for read of interrupt vector */
+#define CHAFSR_IVU		0x0000200000000000
+
+/* Unmappeed error from system bus */
+#define CHAFSR_TO		0x0000100000000000
+
+/* Bus error response from system bus */
+#define CHAFSR_BERR		0x0000080000000000
+
+/* SW Correctable E-cache ECC error for instruction fetch or data access
+ * other than block load.
+ */
+#define CHAFSR_UCC		0x0000040000000000
+
+/* Uncorrectable E-cache ECC error for instruction fetch or data access
+ * other than block load.
+ */
+#define CHAFSR_UCU		0x0000020000000000
+
+/* Copyout HW Corrected ECC error */
+#define CHAFSR_CPC		0x0000010000000000
+
+/* Copyout Uncorrectable ECC error */
+#define CHAFSR_CPU		0x0000008000000000
+
+/* HW Corrected ECC error from E-cache for writeback */
+#define CHAFSR_WDC		0x0000004000000000
+
+/* Uncorrectable ECC error from E-cache for writeback */
+#define CHAFSR_WDU		0x0000002000000000
+
+/* HW Corrected ECC error from E-cache for store merge or block load */
+#define CHAFSR_EDC		0x0000001000000000
+
+/* Uncorrectable ECC error from E-cache for store merge or block load */
+#define CHAFSR_EDU		0x0000000800000000
+
+/* Uncorrectable system bus data ECC error for read of memory or I/O */
+#define CHAFSR_UE		0x0000000400000000
+
+/* HW Corrected system bus data ECC error for read of memory or I/O */
+#define CHAFSR_CE		0x0000000200000000
+
+#define CHAFSR_ERRORS		(CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP | CHAFSR_EMC | \
+				 CHAFSR_EMU | CHAFSR_IVC | CHAFSR_IVU | CHAFSR_TO | \
+				 CHAFSR_BERR | CHAFSR_UCC | CHAFSR_UCU | CHAFSR_CPC | \
+				 CHAFSR_CPU | CHAFSR_WDC | CHAFSR_WDU | CHAFSR_EDC | \
+				 CHAFSR_EDU | CHAFSR_UE | CHAFSR_CE)
+
+/* System bus MTAG ECC syndrome.  This field captures the status of the
+ * first occurrence of the highest-priority error according to the M_SYND
+ * overwrite policy.  After the AFSR sticky bit, corresponding to the error
+ * for which the M_SYND is reported, is cleared, the contents of the M_SYND
+ * field will be unchanged by will be unfrozen for further error capture.
+ */
+#define CHAFSR_M_SYNDROME	0x00000000000f0000
+#define CHAFSR_M_SYNDROME_SHIFT	16
+
+/* System bus or E-cache data ECC syndrome.  This field captures the status
+ * of the first occurrence of the highest-priority error according to the
+ * E_SYND overwrite policy.  After the AFSR sticky bit, corresponding to the
+ * error for which the E_SYND is reported, is cleare, the contents of the E_SYND
+ * field will be unchanged but will be unfrozen for further error capture.
+ */
+#define CHAFSR_E_SYNDROME	0x00000000000001ff
+#define CHAFSR_E_SYNDROME_SHIFT	0
+
+/* The AFSR must be explicitly cleared by software, it is not cleared automatically
+ * by a read.  Writes to bits <51:33> with bits set will clear the corresponding
+ * bits in the AFSR.  Bits assosciated with disrupting traps must be cleared before
+ * interrupts are re-enabled to prevent multiple traps for the same error.  I.e.
+ * PSTATE.IE and AFSR bits control delivery of disrupting traps.
+ *
+ * Since there is only one AFAR, when multiple events have been logged by the
+ * bits in the AFSR, at most one of these events will have its status captured
+ * in the AFAR.  The highest priority of those event bits will get AFAR logging.
+ * The AFAR will be unlocked and available to capture the address of another event
+ * as soon as the one bit in AFSR that corresponds to the event logged in AFAR is
+ * cleared.  For example, if AFSR.CE is detected, then AFSR.UE (which overwrites
+ * the AFAR), and AFSR.UE is cleared by not AFSR.CE, then the AFAR will be unlocked
+ * and ready for another event, even though AFSR.CE is still set.  The same rules
+ * also apply to the M_SYNDROME and E_SYNDROME fields of the AFSR.
+ */
+
+/* Software bit set by linux trap handlers to indicate that the trap was
+ * signalled at %tl >= 1.
+ */
+#define CHAFSR_TL1		0x8000000000000000
+
+#endif /* _SPARC64_CHAFSR_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/chmctrl.h linux/include/asm-sparc64/chmctrl.h
--- v2.4.3/linux/include/asm-sparc64/chmctrl.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/chmctrl.h	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,184 @@
+/* $Id: chmctrl.h,v 1.1 2001/03/29 11:43:28 davem Exp $ */
+#ifndef _SPARC64_CHMCTRL_H
+#define _SPARC64_CHMCTRL_H
+
+/* Cheetah memory controller programmable registers. */
+#define CHMCTRL_TCTRL1		0x00 /* Memory Timing Control I		*/
+#define CHMCTRL_TCTRL2		0x08 /* Memory Timing Control II	*/
+#define CHMCTRL_TCTRL3		0x38 /* Memory Timing Control III	*/
+#define CHMCTRL_TCTRL4		0x40 /* Memory Timing Control IV	*/
+#define CHMCTRL_DECODE1		0x10 /* Memory Address Decode I		*/
+#define CHMCTRL_DECODE2		0x18 /* Memory Address Decode II	*/
+#define CHMCTRL_DECODE3		0x20 /* Memory Address Decode III	*/
+#define CHMCTRL_DECODE4		0x28 /* Memory Address Decode IV	*/
+#define CHMCTRL_MACTRL		0x30 /* Memory Address Control		*/
+
+/* Memory Timing Control I */
+#define TCTRL1_SDRAMCTL_DLY	0xf000000000000000
+#define TCTRL1_SDRAMCTL_DLY_SHIFT     60
+#define TCTRL1_SDRAMCLK_DLY	0x0e00000000000000
+#define TCTRL1_SDRAMCLK_DLY_SHIFT     57
+#define TCTRL1_R		0x0100000000000000
+#define TCTRL1_R_SHIFT 		      56
+#define TCTRL1_AUTORFR_CYCLE	0x00fe000000000000
+#define TCTRL1_AUTORFR_CYCLE_SHIFT    49
+#define TCTRL1_RD_WAIT		0x0001f00000000000
+#define TCTRL1_RD_WAIT_SHIFT	      44
+#define TCTRL1_PC_CYCLE		0x00000fc000000000
+#define TCTRL1_PC_CYCLE_SHIFT	      38
+#define TCTRL1_WR_MORE_RAS_PW	0x0000003f00000000
+#define TCTRL1_WR_MORE_RAS_PW_SHIFT   32
+#define TCTRL1_RD_MORE_RAW_PW	0x00000000fc000000
+#define TCTRL1_RD_MORE_RAS_PW_SHIFT   26
+#define TCTRL1_ACT_WR_DLY	0x0000000003f00000
+#define TCTRL1_ACT_WR_DLY_SHIFT	      20
+#define TCTRL1_ACT_RD_DLY	0x00000000000fc000
+#define TCTRL1_ACT_RD_DLY_SHIFT	      14
+#define TCTRL1_BANK_PRESENT	0x0000000000003000
+#define TCTRL1_BANK_PRESENT_SHIFT     12
+#define TCTRL1_RFR_INT		0x0000000000000ff8
+#define TCTRL1_RFR_INT_SHIFT	      3
+#define TCTRL1_SET_MODE_REG	0x0000000000000004
+#define TCTRL1_SET_MODE_REG_SHIFT     2
+#define TCTRL1_RFR_ENABLE	0x0000000000000002
+#define TCTRL1_RFR_ENABLE_SHIFT	      1
+#define TCTRL1_PRECHG_ALL	0x0000000000000001
+#define TCTRL1_PRECHG_ALL_SHIFT	      0
+
+/* Memory Timing Control II */
+#define TCTRL2_WR_MSEL_DLY	0xfc00000000000000
+#define TCTRL2_WR_MSEL_DLY_SHIFT      58
+#define TCTRL2_RD_MSEL_DLY	0x03f0000000000000
+#define TCTRL2_RD_MSEL_DLY_SHIFT      52
+#define TCTRL2_WRDATA_THLD	0x000c000000000000
+#define TCTRL2_WRDATA_THLD_SHIFT      50
+#define TCTRL2_RDWR_RD_TI_DLY	0x0003f00000000000
+#define TCTRL2_RDWR_RD_TI_DLY_SHIFT   44
+#define TCTRL2_AUTOPRECHG_ENBL	0x0000080000000000
+#define TCTRL2_AUTOPRECHG_ENBL_SHIFT  43
+#define TCTRL2_RDWR_PI_MORE_DLY	0x000007c000000000
+#define TCTRL2_RDWR_PI_MORE_DLY_SHIFT 38
+#define TCTRL2_RDWR_1_DLY	0x0000003f00000000
+#define TCTRL2_RDWR_1_DLY_SHIFT       32
+#define TCTRL2_WRWR_PI_MORE_DLY	0x00000000f8000000
+#define TCTRL2_WRWR_PI_MORE_DLY_SHIFT 27
+#define TCTRL2_WRWR_1_DLY	0x0000000007e00000
+#define TCTRL2_WRWR_1_DLY_SHIFT       21
+#define TCTRL2_RDWR_RD_PI_MORE_DLY 0x00000000001f0000
+#define TCTRL2_RDWR_RD_PI_MORE_DLY_SHIFT 16
+#define TCTRL2_R		0x0000000000008000
+#define TCTRL2_R_SHIFT		      15
+#define TCTRL2_SDRAM_MODE_REG_DATA 0x0000000000007fff
+#define TCTRL2_SDRAM_MODE_REG_DATA_SHIFT 0
+
+/* Memory Timing Control III */
+#define TCTRL3_SDRAM_CTL_DLY	0xf000000000000000
+#define TCTRL3_SDRAM_CTL_DLY_SHIFT    60
+#define TCTRL3_SDRAM_CLK_DLY	0x0e00000000000000
+#define TCTRL3_SDRAM_CLK_DLY_SHIFT    57
+#define TCTRL3_R		0x0100000000000000
+#define TCTRL3_R_SHIFT		      56
+#define TCTRL3_AUTO_RFR_CYCLE	0x00fe000000000000
+#define TCTRL3_AUTO_RFR_CYCLE_SHIFT   49
+#define TCTRL3_RD_WAIT		0x0001f00000000000
+#define TCTRL3_RD_WAIT_SHIFT	      44
+#define TCTRL3_PC_CYCLE		0x00000fc000000000
+#define TCTRL3_PC_CYCLE_SHIFT	      38
+#define TCTRL3_WR_MORE_RAW_PW	0x0000003f00000000
+#define TCTRL3_WR_MORE_RAW_PW_SHIFT   32
+#define TCTRL3_RD_MORE_RAW_PW	0x00000000fc000000
+#define TCTRL3_RD_MORE_RAW_PW_SHIFT   26
+#define TCTRL3_ACT_WR_DLY	0x0000000003f00000
+#define TCTRL3_ACT_WR_DLY_SHIFT       20
+#define TCTRL3_ACT_RD_DLY	0x00000000000fc000
+#define TCTRL3_ACT_RD_DLY_SHIFT       14
+#define TCTRL3_BANK_PRESENT	0x0000000000003000
+#define TCTRL3_BANK_PRESENT_SHIFT     12
+#define TCTRL3_RFR_INT		0x0000000000000ff8
+#define TCTRL3_RFR_INT_SHIFT	      3
+#define TCTRL3_SET_MODE_REG	0x0000000000000004
+#define TCTRL3_SET_MODE_REG_SHIFT     2
+#define TCTRL3_RFR_ENABLE	0x0000000000000002
+#define TCTRL3_RFR_ENABLE_SHIFT       1
+#define TCTRL3_PRECHG_ALL	0x0000000000000001
+#define TCTRL3_PRECHG_ALL_SHIFT	      0
+
+/* Memory Timing Control IV */
+#define TCTRL4_WR_MSEL_DLY	0xfc00000000000000
+#define TCTRL4_WR_MSEL_DLY_SHIFT      58
+#define TCTRL4_RD_MSEL_DLY	0x03f0000000000000
+#define TCTRL4_RD_MSEL_DLY_SHIFT      52
+#define TCTRL4_WRDATA_THLD	0x000c000000000000
+#define TCTRL4_WRDATA_THLD_SHIFT      50
+#define TCTRL4_RDWR_RD_RI_DLY	0x0003f00000000000
+#define TCTRL4_RDWR_RD_RI_DLY_SHIFT   44
+#define TCTRL4_AUTO_PRECHG_ENBL	0x0000080000000000
+#define TCTRL4_AUTO_PRECHG_ENBL_SHIFT 43
+#define TCTRL4_RD_WR_PI_MORE_DLY 0x000007c000000000
+#define TCTRL4_RD_WR_PI_MORE_DLY_SHIFT 38
+#define TCTRL4_RD_WR_TI_DLY	0x0000003f00000000
+#define TCTRL4_RD_WR_TI_DLY_SHIFT     32
+#define TCTRL4_WR_WR_PI_MORE_DLY 0x00000000f8000000
+#define TCTRL4_WR_WR_PI_MORE_DLY_SHIFT 27
+#define TCTRL4_WR_WR_TI_DLY	0x0000000007e00000
+#define TCTRL4_WR_WR_TI_DLY_SHIFT     21
+#define TCTRL4_RDWR_RD_PI_MORE_DLY 0x00000000001f0000
+#define TCTRL4_RDWR_RD_PI_MORE_DLY_SHIFT 16
+#define TCTRL4_R		0x0000000000008000
+#define TCTRL4_R_SHIFT		      15
+#define TCTRL4_SDRAM_MODE_REG_DATA 0x0000000000007fff
+#define TCTRL4_SDRAM_MODE_REG_DATA_SHIFT 0
+
+/* All 4 memory address decoding registers have the
+ * same layout.
+ */
+#define MEM_DECODE_VALID	0x8000000000000000 /* Valid */
+#define MEM_DECODE_VALID_SHIFT	      63
+#define MEM_DECODE_UK		0x001ffe0000000000 /* Upper mask */
+#define MEM_DECODE_UK_SHIFT	      41
+#define MEM_DECODE_UM		0x0000001ffff00000 /* Upper match */
+#define MEM_DECODE_UM_SHIFT	      20
+#define MEM_DECODE_LK		0x000000000003c000 /* Lower mask */
+#define MEM_DECODE_LK_SHIFT	      14
+#define MEM_DECODE_LM		0x0000000000000f00 /* Lower match */
+#define MEM_DECODE_LM_SHIFT           8
+
+#define PA_UPPER_BITS		0x000007fffc000000
+#define PA_UPPER_BITS_SHIFT	26
+#define PA_LOWER_BITS		0x00000000000003c0
+#define PA_LOWER_BITS_SHIFT	6
+
+#define MACTRL_R0		         0x8000000000000000
+#define MACTRL_R0_SHIFT		         63
+#define MACTRL_ADDR_LE_PW                0x7000000000000000
+#define MACTRL_ADDR_LE_PW_SHIFT		 60
+#define MACTRL_CMD_PW                    0x0f00000000000000
+#define MACTRL_CMD_PW_SHIFT		 56
+#define MACTRL_HALF_MODE_WR_MSEL_DLY     0x00fc000000000000
+#define MACTRL_HALF_MODE_WR_MSEL_DLY_SHIFT 50
+#define MACTRL_HALF_MODE_RD_MSEL_DLY     0x0003f00000000000
+#define MACTRL_HALF_MODE_RD_MSEL_DLY_SHIFT 44
+#define MACTRL_HALF_MODE_SDRAM_CTL_DLY   0x00000f0000000000
+#define MACTRL_HALF_MODE_SDRAM_CTL_DLY_SHIFT 40
+#define MACTRL_HALF_MODE_SDRAM_CLK_DLY   0x000000e000000000
+#define MACTRL_HALF_MODE_SDRAM_CLK_DLY_SHIFT 37
+#define MACTRL_R1                        0x0000001000000000
+#define MACTRL_R1_SHIFT                      36
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B3 0x0000000f00000000
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B3_SHIFT 32
+#define MACTRL_ENC_INTLV_B3              0x00000000f8000000
+#define MACTRL_ENC_INTLV_B3_SHIFT              27
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B2 0x0000000007800000
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B2_SHIFT 23
+#define MACTRL_ENC_INTLV_B2              0x00000000007c0000
+#define MACTRL_ENC_INTLV_B2_SHIFT              18
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B1 0x000000000003c000
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B1_SHIFT 14
+#define MACTRL_ENC_INTLV_B1              0x0000000000003e00
+#define MACTRL_ENC_INTLV_B1_SHIFT               9
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B0 0x00000000000001e0
+#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B0_SHIFT  5
+#define MACTRL_ENC_INTLV_B0              0x000000000000001f
+#define MACTRL_ENC_INTLV_B0_SHIFT               0
+
+#endif /* _SPARC64_CHMCTRL_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- v2.4.3/linux/include/asm-sparc64/elf.h	Mon Mar 26 11:00:29 2001
+++ linux/include/asm-sparc64/elf.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.28 2001/03/24 09:36:02 davem Exp $ */
+/* $Id: elf.h,v 1.29 2001/03/30 07:10:48 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/estate.h linux/include/asm-sparc64/estate.h
--- v2.4.3/linux/include/asm-sparc64/estate.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/estate.h	Thu Apr 12 12:10:25 2001
@@ -0,0 +1,50 @@
+/* $Id: estate.h,v 1.1 2001/03/28 10:56:34 davem Exp $ */
+#ifndef _SPARC64_ESTATE_H
+#define _SPARC64_ESTATE_H
+
+/* UltraSPARC-III E-cache Error Enable */
+#define ESTATE_ERROR_FMT	0x0000000000040000 /* Force MTAG ECC		*/
+#define ESTATE_ERROR_FMESS	0x000000000003c000 /* Forced MTAG ECC val	*/
+#define ESTATE_ERROR_FMD	0x0000000000002000 /* Force DATA ECC		*/
+#define ESTATE_ERROR_FDECC	0x0000000000001ff0 /* Forced DATA ECC val	*/
+#define ESTATE_ERROR_UCEEN	0x0000000000000008 /* See below			*/
+#define ESTATE_ERROR_NCEEN	0x0000000000000002 /* See below			*/
+#define ESTATE_ERROR_CEEN	0x0000000000000001 /* See below			*/
+
+/* UCEEN enables the fast_ECC_error trap for: 1) software correctable E-cache
+ * errors 2) uncorrectable E-cache errors.  Such events only occur on reads
+ * of the E-cache by the local processor for: 1) data loads 2) instruction
+ * fetches 3) atomic operations.  Such events _cannot_ occur for: 1) merge
+ * 2) writeback 2) copyout.  The AFSR bits assosciated with these traps are
+ * UCC and UCU.
+ */
+
+/* NCEEN enables instruction_access_error, data_access_error, and ECC_error traps
+ * for uncorrectable ECC errors and system errors.
+ *
+ * Uncorrectable system bus data error or MTAG ECC error, system bus TimeOUT,
+ * or system bus BusERR:
+ * 1) As the result of an instruction fetch, will generate instruction_access_error
+ * 2) As the result of a load etc. will generate data_access_error.
+ * 3) As the result of store merge completion, writeback, or copyout will
+ *    generate a disrupting ECC_error trap.
+ * 4) As the result of such errors on instruction vector fetch can generate any
+ *    of the 3 trap types.
+ *
+ * The AFSR bits assosciated with these traps are EMU, EDU, WDU, CPU, IVU, UE,
+ * BERR, and TO.
+ */
+
+/* CEEN enables the ECC_error trap for hardware corrected ECC errors.  System bus
+ * reads resulting in a hardware corrected data or MTAG ECC error will generate an
+ * ECC_error disrupting trap with this bit enabled.
+ *
+ * This same trap will also be generated when a hardware corrected ECC error results
+ * during store merge, writeback, and copyout operations.
+ */
+
+/* In general, if the trap enable bits above are disabled the AFSR bits will still
+ * log the events even though the trap will not be generated by the processor.
+ */
+
+#endif /* _SPARC64_ESTATE_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/mc146818rtc.h linux/include/asm-sparc64/mc146818rtc.h
--- v2.4.3/linux/include/asm-sparc64/mc146818rtc.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/mc146818rtc.h	Thu Apr 12 12:16:36 2001
@@ -4,6 +4,7 @@
 #ifndef __ASM_SPARC64_MC146818RTC_H
 #define __ASM_SPARC64_MC146818RTC_H
 
+#include <linux/config.h>
 #include <asm/io.h>
 
 #ifndef RTC_PORT
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/perfctr.h linux/include/asm-sparc64/perfctr.h
--- v2.4.3/linux/include/asm-sparc64/perfctr.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc64/perfctr.h	Thu Apr 12 12:10:25 2001
@@ -60,10 +60,10 @@
 #ifndef __KERNEL__
 
 #define  PRIV 0x00000001
-#define  USR  0x00000002
-#define  SYS  0x00000004
+#define  SYS  0x00000002
+#define  USR  0x00000004
 
-/* Pic.S0 Selection Bit Field Encoding  */
+/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II  */
 #define  CYCLE_CNT            0x00000000
 #define  INSTR_CNT            0x00000010
 #define  DISPATCH0_IC_MISS    0x00000020
@@ -77,7 +77,38 @@
 #define  EC_SNOOP_INV         0x000000E0
 #define  EC_RD_HIT            0x000000F0
 
-/* Pic.S1 Selection Bit Field Encoding  */
+/* Pic.S0 Selection Bit Field Encoding, Ultra-III  */
+#define  US3_CYCLE_CNT	      	0x00000000
+#define  US3_INSTR_CNT	      	0x00000010
+#define  US3_DISPATCH0_IC_MISS	0x00000020
+#define  US3_DISPATCH0_BR_TGT	0x00000030
+#define  US3_DISPATCH0_2ND_BR	0x00000040
+#define  US3_RSTALL_STOREQ	0x00000050
+#define  US3_RSTALL_IU_USE	0x00000060
+#define  US3_IC_REF		0x00000080
+#define  US3_DC_RD		0x00000090
+#define  US3_DC_WR		0x000000a0
+#define  US3_EC_REF		0x000000c0
+#define  US3_EC_WR_HIT_RTO	0x000000d0
+#define  US3_EC_SNOOP_INV	0x000000e0
+#define  US3_EC_RD_MISS		0x000000f0
+#define  US3_PC_PORT0_RD	0x00000100
+#define  US3_SI_SNOOP		0x00000110
+#define  US3_SI_CIQ_FLOW	0x00000120
+#define  US3_SI_OWNED		0x00000130
+#define  US3_SW_COUNT_0		0x00000140
+#define  US3_IU_BR_MISS_TAKEN	0x00000150
+#define  US3_IU_BR_COUNT_TAKEN	0x00000160
+#define  US3_DISP_RS_MISPRED	0x00000170
+#define  US3_FA_PIPE_COMPL	0x00000180
+#define  US3_MC_READS_0		0x00000200
+#define  US3_MC_READS_1		0x00000210
+#define  US3_MC_READS_2		0x00000220
+#define  US3_MC_READS_3		0x00000230
+#define  US3_MC_STALLS_0	0x00000240
+#define  US3_MC_STALLS_2	0x00000250
+
+/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II  */
 #define  CYCLE_CNT_D1         0x00000000
 #define  INSTR_CNT_D1         0x00000800
 #define  DISPATCH0_IC_MISPRED 0x00001000
@@ -90,6 +121,47 @@
 #define  EC_WB                0x00006800
 #define  EC_SNOOP_CB          0x00007000
 #define  EC_IT_HIT            0x00007800
+
+/* Pic.S1 Selection Bit Field Encoding, Ultra-III  */
+#define  US3_CYCLE_CNT_D1	0x00000000
+#define  US3_INSTR_CNT_D1	0x00000800
+#define  US3_DISPATCH0_MISPRED	0x00001000
+#define  US3_IC_MISS_CANCELLED	0x00001800
+#define  US3_RE_ENDIAN_MISS	0x00002000
+#define  US3_RE_FPU_BYPASS	0x00002800
+#define  US3_RE_DC_MISS		0x00003000
+#define  US3_RE_EC_MISS		0x00003800
+#define  US3_IC_MISS		0x00004000
+#define  US3_DC_RD_MISS		0x00004800
+#define  US3_DC_WR_MISS		0x00005000
+#define  US3_RSTALL_FP_USE	0x00005800
+#define  US3_EC_MISSES		0x00006000
+#define  US3_EC_WB		0x00006800
+#define  US3_EC_SNOOP_CB	0x00007000
+#define  US3_EC_IC_MISS		0x00007800
+#define  US3_RE_PC_MISS		0x00008000
+#define  US3_ITLB_MISS		0x00008800
+#define  US3_DTLB_MISS		0x00009000
+#define  US3_WC_MISS		0x00009800
+#define  US3_WC_SNOOP_CB	0x0000a000
+#define  US3_WC_SCRUBBED	0x0000a800
+#define  US3_WC_WB_WO_READ	0x0000b000
+#define  US3_PC_SOFT_HIT	0x0000c000
+#define  US3_PC_SNOOP_INV	0x0000c800
+#define  US3_PC_HARD_HIT	0x0000d000
+#define  US3_PC_PORT1_RD	0x0000d800
+#define  US3_SW_COUNT_1		0x0000e000
+#define  US3_IU_STAT_BR_MIS_UNTAKEN	0x0000e800
+#define  US3_IU_STAT_BR_COUNT_UNTAKEN	0x0000f000
+#define  US3_PC_MS_MISSES	0x0000f800
+#define  US3_MC_WRITES_0	0x00010800
+#define  US3_MC_WRITES_1	0x00011000
+#define  US3_MC_WRITES_2	0x00011800
+#define  US3_MC_WRITES_3	0x00012000
+#define  US3_MC_STALLS_1	0x00012800
+#define  US3_MC_STALLS_3	0x00013000
+#define  US3_RE_RAW_MISS	0x00013800
+#define  US3_FM_PIPE_COMPLETION	0x00014000
 
 struct vcounter_struct {
   unsigned long long vcnt0;
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.4.3/linux/include/asm-sparc64/pgalloc.h	Mon Mar 26 11:03:48 2001
+++ linux/include/asm-sparc64/pgalloc.h	Mon Apr 23 15:28:07 2001
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.18 2001/03/24 09:36:01 davem Exp $ */
+/* $Id: pgalloc.h,v 1.19 2001/03/30 07:10:48 davem Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
@@ -300,7 +300,7 @@
 #define pte_free(pte)		free_pte_fast(pte)
 #define pmd_free(pmd)		free_pmd_fast(pmd)
 #define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
+#define pgd_alloc(mm)		get_pgd_fast()
 
 extern int do_check_pgt_cache(int, int);
 
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.4.3/linux/include/asm-sparc64/pgtable.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/pgtable.h	Fri Apr 13 20:15:55 2001
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.138 2001/03/08 09:55:56 davem Exp $
+/* $Id: pgtable.h,v 1.140 2001/04/12 22:41:15 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -254,12 +254,13 @@
 }
 
 /* Encode and de-code a swap entry */
-#define SWP_TYPE(entry)		(((entry).val >> PAGE_SHIFT) & 0xff)
-#define SWP_OFFSET(entry)	((entry).val >> (PAGE_SHIFT + 8))
+#define SWP_TYPE(entry)		(((entry).val >> PAGE_SHIFT) & 0xffUL)
+#define SWP_OFFSET(entry)	((entry).val >> (PAGE_SHIFT + 8UL))
 #define SWP_ENTRY(type, offset)	\
 	( (swp_entry_t) \
 	  { \
-		((type << PAGE_SHIFT) | (offset << (PAGE_SHIFT + 8))) \
+		(((long)(type) << PAGE_SHIFT) | \
+                 ((long)(offset) << (PAGE_SHIFT + 8UL))) \
 	  } )
 #define pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
@@ -302,9 +303,15 @@
 
 #include <asm-generic/pgtable.h>
 
-#endif /* !(__ASSEMBLY__) */
-
 /* We provide our own get_unmapped_area to cope with VA holes for userland */
 #define HAVE_ARCH_UNMAPPED_AREA
+
+/* We provide a special get_unmapped_area for framebuffer mmaps to try and use
+ * the largest alignment possible such that larget PTEs can be used.
+ */
+extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long, unsigned long, unsigned long, unsigned long);
+#define HAVE_ARCH_FB_UNMAPPED_AREA
+
+#endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.4.3/linux/include/asm-sparc64/processor.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/processor.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.69 2001/03/08 22:08:51 davem Exp $
+/* $Id: processor.h,v 1.70 2001/03/27 02:36:38 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -79,7 +79,6 @@
 #define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary		*/
 #define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process	*/
 #define SPARC_FLAG_PERFCTR	0x10    /* task has performance counters active	*/
-#define SPARC_FLAG_MMAPSHARED	0x20    /* task wants a shared mmap             */
 
 #define FAULT_CODE_WRITE	0x01	/* Write access, implies D-TLB		*/
 #define FAULT_CODE_DTLB		0x02	/* Miss happened in D-TLB		*/
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/rwsem.h linux/include/asm-sparc64/rwsem.h
--- v2.4.3/linux/include/asm-sparc64/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/rwsem.h	Wed Apr 25 13:31:03 2001
@@ -0,0 +1,224 @@
+/* $Id: rwsem.h,v 1.2 2001/04/19 01:52:04 davem Exp $
+ * rwsem.h: R/W semaphores implemented using CAS
+ *
+ * Written by David S. Miller (davem@redhat.com), 2001.
+ * Derived from asm-i386/rwsem.h
+ */
+#ifndef _SPARC64_RWSEM_H
+#define _SPARC64_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+struct rwsem_waiter;
+
+struct rw_semaphore {
+	signed int count;
+#define RWSEM_UNLOCKED_VALUE		0x00000000
+#define RWSEM_ACTIVE_BIAS		0x00000001
+#define RWSEM_ACTIVE_MASK		0x0000ffff
+#define RWSEM_WAITING_BIAS		0xffff0000
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+	spinlock_t		wait_lock;
+	struct rwsem_waiter	*wait_front;
+	struct rwsem_waiter	**wait_back;
+};
+
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, NULL, &(name).wait_front }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	init_waitqueue_head(&sem->wait);
+}
+
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __down_read\n"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"add		%%g5, 1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" add		%%g7, 1, %%g7\n\t"
+		"cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 3f\n\t"
+		" membar	#StoreStore\n"
+		"2:\n\t"
+		".subsection	2\n"
+		"3:\tmov	%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g1, %%l1\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l1, %%g1\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __down_read"
+		: : "r" (sem), "i" (rwsem_down_read_failed)
+		: "g5", "g7", "memory", "cc");
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __down_write\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"add		%%g5, %%g1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" cmp		%%g7, 0\n\t"
+		"bne,pn		%%icc, 3f\n\t"
+		" membar	#StoreStore\n"
+		"2:\n\t"
+		".subsection	2\n"
+		"3:\tmov	%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o0\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __down_write"
+		: : "r" (sem), "i" (rwsem_down_write_failed),
+		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "g1", "g5", "g7", "memory", "cc");
+}
+
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __up_read\n\t"
+		"1:\tlduw	[%0], %%g5\n\t"
+		"sub		%%g5, 1, %%g7\n\t"
+		"cas		[%0], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" cmp		%%g7, 0\n\t"
+		"bl,pn		%%icc, 3f\n\t"
+		" membar	#StoreStore\n"
+		"2:\n\t"
+		".subsection	2\n"
+		"3:\tsethi	%%hi(%2), %%g1\n\t"
+		"sub		%%g7, 1, %%g7\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n\t"
+		"andcc		%%g7, %%g1, %%g0\n\t"
+		"bne,pn		%%icc, 2b\n\t"
+		" mov		%0, %%g5\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		" mov		%%g7, %%o0\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o1\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __up_read"
+		: : "r" (sem), "i" (rwsem_up_read_wake),
+		    "i" (RWSEM_ACTIVE_MASK)
+		: "g1", "g5", "g7", "memory", "cc");
+}
+
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"! beginning __up_write\n\t"
+		"sethi		%%hi(%2), %%g1\n\t"
+		"or		%%g1, %%lo(%2), %%g1\n"
+		"sub		%%g5, %%g5, %%g5\n\t"
+		"cas		[%0], %%g1, %%g5\n\t"
+		"cmp		%%g1, %%g5\n\t"
+		"bne,pn		%%icc, 1f\n\t"
+		" membar	#StoreStore\n"
+		"2:\n\t"
+		".subsection 2\n"
+		"3:\tmov	%0, %%g1\n\t"
+		"save		%%sp, -160, %%sp\n\t"
+		"mov		%%g2, %%l2\n\t"
+		"mov		%%g3, %%l3\n\t"
+		"mov		%%g1, %%o0\n\t"
+		"call		%1\n\t"
+		" mov		%%g5, %%o1\n\t"
+		"mov		%%l2, %%g2\n\t"
+		"ba,pt		%%xcc, 2b\n\t"
+		" restore	%%l3, %%g0, %%g3\n\t"
+		".previous\n\t"
+		"! ending __up_write"
+		: : "r" (sem), "i" (rwsem_up_write_wake),
+		    "i" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "g1", "g5", "memory", "cc");
+}
+
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+	int tmp = delta;
+
+	__asm__ __volatile__(
+		"1:\tlduw	[%2], %%g5\n\t"
+		"add		%%g5, %1, %%g7\n\t"
+		"cas		[%2], %%g5, %%g7\n\t"
+		"cmp		%%g5, %%g7\n\t"
+		"bne,pn		%%icc, 1b\n\t"
+		" nop\n\t"
+		"mov		%%g7, %0\n\t"
+		: "=&r" (tmp)
+		: "0" (tmp), "r" (sem)
+		: "g5", "g7", "memory");
+
+	return tmp + delta;
+}
+
+#define rwsem_atomic_add rwsem_atomic_update
+
+static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 __old, __u16 __new)
+{
+	u32 old = (sem->count & 0xffff0000) | (u32) __old;
+	u32 new = (old & 0xffff0000) | (u32) __new;
+	u32 prev;
+
+again:
+	__asm__ __volatile__("cas	[%2], %3, %0\n\t"
+			     "membar	#StoreStore | #StoreLoad"
+			     : "=&r" (prev)
+			     : "0" (new), "r" (sem), "r" (old)
+			     : "memory");
+
+	/* To give the same semantics as x86 cmpxchgw, keep trying
+	 * if only the upper 16-bits changed.
+	 */
+	if (prev != old &&
+	    ((prev & 0xffff) == (old & 0xffff)))
+		goto again;
+
+	return prev & 0xffff;
+}
+
+static inline signed long rwsem_cmpxchg(struct rw_semaphore *sem, signed long old, signed long new)
+{
+	return cmpxchg(&sem->count,old,new);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _SPARC64_RWSEM_H */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- v2.4.3/linux/include/asm-sparc64/semaphore.h	Wed Jul 12 16:45:30 2000
+++ linux/include/asm-sparc64/semaphore.h	Tue Apr 17 17:19:36 2001
@@ -8,6 +8,7 @@
 #include <asm/bitops.h>
 #include <asm/system.h>
 #include <linux/wait.h>
+#include <linux/rwsem.h>
 
 struct semaphore {
 	atomic_t count;
@@ -199,268 +200,6 @@
 		.previous\n"
 	: : "r" (sem), "i" (__up)
 	: "g5", "g7", "memory", "cc");
-}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS.  This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock.  Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes.  BIAS must be chosen such that subtracting
- * BIAS once per CPU will result in the int remaining
- * negative.
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- *	      -ben
- *
- * Once we start supporting machines with more than 128 CPUs,
- * we should go for using a 64bit atomic type instead of 32bit
- * as counter. We shall probably go for bias 0x80000000 then,
- * so that single sethi can set it.
- *
- *	      -jj
- */
-#define RW_LOCK_BIAS		0x01000000
-#define RW_LOCK_BIAS_STR	"0x01000000"
-
-struct rw_semaphore {
-	int			count;
-	/* So that this does not have to be 64bit type,
-	 * we'll use le bitops on it which use casa instead of casx.
-	 * bit 0 means read bias granted
-	 * bit 1 means write bias granted
-	 */
-	unsigned		granted;
-	wait_queue_head_t	wait;
-	wait_queue_head_t	write_bias_wait;
-#if WAITQUEUE_DEBUG
-	long			__magic;
-	atomic_t		readers;
-	atomic_t		writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT	/* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ (count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
-  __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
-  __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
-	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
-	sem->count = RW_LOCK_BIAS;
-	sem->granted = 0;
-	init_waitqueue_head(&sem->wait);
-	init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
-	sem->__magic = (long)&sem->__magic;
-	atomic_set(&sem->readers, 0);
-	atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern void __down_read_failed(/* Special calling convention */ void);
-extern void __down_write_failed(/* Special calling convention */ void);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-	__asm__ __volatile__("
-	1:	lduw	[%0], %%g5
-		subcc	%%g5, 1, %%g7
-		cas	[%0], %%g5, %%g7
-		bneg,pn	%%icc, 3f
-		 cmp	%%g5, %%g7
-		bne,pn	%%icc, 1b
-		 membar	#StoreStore
-	2:
-		.subsection 2
-	3:	bne,pn	%%icc, 1b
-		 mov	%0, %%g7
-		save	%%sp, -160, %%sp
-		mov	%%g1, %%l1
-		mov	%%g2, %%l2
-		call	%1
-		 mov	%%g3, %%l3
-		mov	%%l1, %%g1
-		mov	%%l2, %%g2
-		ba,pt	%%xcc, 2b
-		 restore %%l3, %%g0, %%g3
-		.previous\n"
-	: : "r" (sem), "i" (__down_read_failed)
-	: "g5", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
-	if (test_le_bit(1, &sem->granted))
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	CHECK_MAGIC(sem->__magic);
-#endif
-	__asm__ __volatile__("
-	1:	lduw	[%0], %%g5
-		sethi	%%hi(" RW_LOCK_BIAS_STR "), %%g7
-		subcc	%%g5, %%g7, %%g7
-		cas	[%0], %%g5, %%g7
-		bne,pn	%%icc, 3f
-		 cmp	%%g5, %%g7
-		bne,pn	%%icc, 1b
-		 membar	#StoreStore
-	2:
-		.subsection 2
-	3:	bne,pn	%%icc, 1b
-		 mov	%0, %%g7
-		save	%%sp, -160, %%sp
-		mov	%%g1, %%l1
-		mov	%%g2, %%l2
-		call	%1
-		 mov	%%g3, %%l3
-		mov	%%l1, %%g1
-		mov	%%l2, %%g2
-		ba,pt	%%xcc, 2b
-		 restore %%l3, %%g0, %%g3
-		.previous\n"
-	: : "r" (sem), "i" (__down_write_failed)
-	: "g5", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
-	if (atomic_read(&sem->writers))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (test_le_bit(0, &sem->granted))
-		BUG();
-	if (test_le_bit(1, &sem->granted))
-		BUG();
-	atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__("
-		membar	#StoreLoad | #LoadLoad
-	1:	lduw	[%0], %%g5
-		addcc	%%g5, 1, %%g7
-		cas	[%0], %%g5, %%g7
-		be,pn	%%icc, 3f
-		 cmp	%%g5, %%g7
-		bne,pn	%%icc, 1b
-		 nop
-	2:
-		.subsection 2
-	3:	bne,pn	%%icc, 1b
-		 mov	%0, %%g7
-		save	%%sp, -160, %%sp
-		mov	%%g1, %%l1
-		mov	%%g2, %%l2
-		clr	%%o1
-		mov	%%g7, %%o0
-		call	%1
-		 mov	%%g3, %%l3
-		mov	%%l1, %%g1
-		mov	%%l2, %%g2
-		ba,pt	%%xcc, 2b
-		 restore %%l3, %%g0, %%g3
-		.previous\n"
-	: : "r" (sem), "i" (__rwsem_wake)
-	: "g5", "g7", "memory", "cc");
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
-	__asm__ __volatile__("
-		membar	#StoreLoad | #LoadLoad
-	1:	lduw	[%0], %%g5
-		sethi	%%hi(" RW_LOCK_BIAS_STR "), %%g7
-		add	%%g5, %%g7, %%g7
-		cas	[%0], %%g5, %%g7
-		cmp	%%g5, %%g7
-		bne,pn	%%icc, 1b
-		 sethi	%%hi(" RW_LOCK_BIAS_STR "), %%g7
-		addcc	%%g5, %%g7, %%g5
-		bcs,pn	%%icc, 3f
-		 nop
-	2:
-		.subsection 2
-	3:	mov	%0, %%g7
-		save	%%sp, -160, %%sp
-		mov	%%g1, %%l1
-		mov	%%g2, %%l2
-		srl	%%g5, 0, %%o1
-		mov	%%g7, %%o0
-		call	%1
-		 mov	%%g3, %%l3
-		mov	%%l1, %%g1
-		mov	%%l2, %%g2
-		ba,pt	%%xcc, 2b
-		 restore %%l3, %%g0, %%g3
-		.previous\n"
-	: : "r" (sem), "i" (__rwsem_wake)
-	: "g5", "g7", "memory", "cc");
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (test_le_bit(1, &sem->granted))
-		BUG();
-	if (atomic_read(&sem->writers))
-		BUG();
-	atomic_dec(&sem->readers);
-#endif
-	__up_read(sem);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
-	if (test_le_bit(0, &sem->granted))
-		BUG();
-	if (test_le_bit(1, &sem->granted))
-		BUG();
-	if (atomic_read(&sem->readers))
-		BUG();
-	if (atomic_read(&sem->writers) != 1)
-		BUG();
-	atomic_dec(&sem->writers);
-#endif
-	__up_write(sem);
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h
--- v2.4.3/linux/include/asm-sparc64/spitfire.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/spitfire.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.14 2001/03/22 07:26:04 davem Exp $
+/* $Id: spitfire.h,v 1.15 2001/03/27 00:10:15 davem Exp $
  * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -13,10 +13,15 @@
  * and ASI_IMMU, that is there is a distinct and unique copy of
  * each these registers for each TLB.
  */
-#define TSB_TAG_TARGET		0x0000000000000000
-#define TLB_SFSR		0x0000000000000018
-#define TSB_REG			0x0000000000000028
-#define TLB_TAG_ACCESS		0x0000000000000030
+#define TSB_TAG_TARGET		0x0000000000000000 /* All chips				*/
+#define TLB_SFSR		0x0000000000000018 /* All chips				*/
+#define TSB_REG			0x0000000000000028 /* All chips				*/
+#define TLB_TAG_ACCESS		0x0000000000000030 /* All chips				*/
+#define VIRT_WATCHPOINT		0x0000000000000038 /* All chips				*/
+#define PHYS_WATCHPOINT		0x0000000000000040 /* All chips				*/
+#define TSB_EXTENSION_P		0x0000000000000048 /* Ultra-III and later		*/
+#define TSB_EXTENSION_S		0x0000000000000050 /* Ultra-III and later, D-TLB only	*/
+#define TSB_EXTENSION_N		0x0000000000000058 /* Ultra-III and later		*/
 
 /* These registers only exist as one entity, and are accessed
  * via ASI_DMMU only.
diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- v2.4.3/linux/include/asm-sparc64/ttable.h	Wed Apr 12 09:12:35 2000
+++ linux/include/asm-sparc64/ttable.h	Thu Apr 12 12:10:25 2001
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.15 2000/04/03 10:36:42 davem Exp $ */
+/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -54,13 +54,6 @@
 	 clr	%l6;					\
 	nop;
 	
-#define TRAPTL1_CEE			\
-	ldxa	[%g0] ASI_AFSR, %g1;	\
-	membar	#Sync;			\
-	stxa	%g1, [%g0] ASI_AFSR;	\
-	membar	#Sync;			\
-	retry; nop; nop; nop;
-
 #define TRAP_ARG(routine, arg)				\
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, etrap;				\
diff -u --recursive --new-file v2.4.3/linux/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h
--- v2.4.3/linux/include/linux/ac97_codec.h	Mon Mar 26 15:49:49 2001
+++ linux/include/linux/ac97_codec.h	Wed Apr 25 16:22:39 2001
@@ -133,7 +133,15 @@
 	SOUND_MASK_LINE1| SOUND_MASK_LINE|\
 	SOUND_MASK_PHONEIN)
 
-#define supported_mixer(CODEC,FOO) ((CODEC)->supported_mixers & (1<<FOO) )
+/* original check is not good enough in case FOO is greater than
+ * SOUND_MIXER_NRDEVICES because the supported_mixers has exactly
+ * SOUND_MIXER_NRDEVICES elements.
+ * before matching the given mixer against the bitmask in supported_mixers we
+ * check if mixer number exceeds maximum allowed size which is as mentioned
+ * above SOUND_MIXER_NRDEVICES */
+#define supported_mixer(CODEC,FOO) ((FOO >= 0) && \
+                                    (FOO < SOUND_MIXER_NRDEVICES) && \
+                                    (CODEC)->supported_mixers & (1<<FOO) )
 
 struct ac97_codec {
 	/* AC97 controller connected with */
diff -u --recursive --new-file v2.4.3/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- v2.4.3/linux/include/linux/affs_fs.h	Mon Dec 11 13:26:57 2000
+++ linux/include/linux/affs_fs.h	Thu Apr 19 22:57:06 2001
@@ -8,58 +8,36 @@
 
 #define AFFS_SUPER_MAGIC 0xadff
 
-/* Get the filesystem block size given an inode. */
-#define AFFS_I2BSIZE(inode) ((inode)->i_sb->s_blocksize)
-
-/* Get the filesystem hash table size given an inode. */
-#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize)
-
-/* Get the block number bits given an inode */
-#define AFFS_I2BITS(inode) ((inode)->i_sb->s_blocksize_bits)
-
-/* Get the fs type given an inode */
-#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL)
-
-struct DateStamp
-{
-  u32 ds_Days;
-  u32 ds_Minute;
-  u32 ds_Tick;
-};
+struct affs_date;
 
 /* --- Prototypes -----------------------------------------------------------------------------	*/
 
 /* amigaffs.c */
 
-extern int	affs_get_key_entry(int bsize, void *data, int entry_pos);
-extern int	affs_get_file_name(int bsize, void *fh_data, unsigned char **name);
-extern u32	affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype);
-extern void	affs_fix_checksum(int bsize, void *data, int cspos);
-extern void	secs_to_datestamp(time_t secs, struct DateStamp *ds);
-extern int	prot_to_mode(unsigned int prot);
-extern u32	mode_to_prot(int mode);
-extern int	affs_insert_hash(unsigned long dir_ino, struct buffer_head *header,
-			struct inode *inode);
-extern int	affs_remove_hash(struct buffer_head *bh, struct inode *inode);
-extern int	affs_remove_link(struct buffer_head *bh, struct inode *inode);
-extern int	affs_remove_header(struct buffer_head *bh, struct inode *inode);
+extern int	affs_insert_hash(struct inode *inode, struct buffer_head *bh);
+extern int	affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh);
+extern int	affs_remove_header(struct dentry *dentry);
+extern u32	affs_checksum_block(struct super_block *sb, struct buffer_head *bh);
+extern void	affs_fix_checksum(struct super_block *sb, struct buffer_head *bh);
+extern void	secs_to_datestamp(time_t secs, struct affs_date *ds);
+extern mode_t	prot_to_mode(u32 prot);
+extern void	mode_to_prot(struct inode *inode);
 extern void	affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
 extern void	affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
 extern int	affs_check_name(const unsigned char *name, int len);
-extern int	affs_copy_name(unsigned char *bstr, const unsigned char *name);
+extern int	affs_copy_name(unsigned char *bstr, struct dentry *dentry);
 
 /* bitmap. c */
 
-extern int	affs_count_free_blocks(struct super_block *s);
-extern int	affs_count_free_bits(int blocksize, const char *data);
-extern void	affs_free_block(struct super_block *sb, s32 block);
-extern s32	affs_new_header(struct inode *inode);
-extern s32	affs_new_data(struct inode *inode);
-extern void	affs_make_zones(struct super_block *sb);
+extern u32	affs_count_free_bits(u32 blocksize, const void *data);
+extern u32	affs_count_free_blocks(struct super_block *s);
+extern void	affs_free_block(struct super_block *sb, u32 block);
+extern u32	affs_alloc_block(struct inode *inode, u32 goal);
+extern int	affs_init_bitmap(struct super_block *sb);
 
 /* namei.c */
 
-extern int	affs_hash_name(const unsigned char *name, int len, int intl, int hashsize);
+extern int	affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);
 extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry);
 extern int	affs_unlink(struct inode *dir, struct dentry *dentry);
 extern int	affs_create(struct inode *dir, struct dentry *dentry, int mode);
@@ -74,17 +52,15 @@
 
 /* inode.c */
 
-extern struct buffer_head	*affs_bread(kdev_t dev, int block, int size);
-extern void			 affs_brelse(struct buffer_head *buf);
 extern unsigned long		 affs_parent_ino(struct inode *dir);
-extern struct inode		*affs_new_inode(const struct inode *dir);
+extern struct inode		*affs_new_inode(struct inode *dir);
 extern int			 affs_notify_change(struct dentry *dentry, struct iattr *attr);
-extern int			 affs_add_entry(struct inode *dir, struct inode *link,
-					  struct inode *inode, struct dentry *dentry, s32 type);
 extern void			 affs_put_inode(struct inode *inode);
 extern void			 affs_delete_inode(struct inode *inode);
+extern void			 affs_clear_inode(struct inode *inode);
 extern void			 affs_read_inode(struct inode *inode);
 extern void			 affs_write_inode(struct inode *inode, int);
+extern int			 affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);
 
 /* super.c */
 
@@ -109,9 +85,9 @@
 extern struct file_operations	 affs_dir_operations;
 extern struct address_space_operations	 affs_symlink_aops;
 extern struct address_space_operations	 affs_aops;
+extern struct address_space_operations	 affs_aops_ofs;
 
 extern struct dentry_operations	 affs_dentry_operations;
 extern struct dentry_operations	 affs_dentry_operations_intl;
 
-extern int affs_bmap(struct inode *, int);
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- v2.4.3/linux/include/linux/affs_fs_i.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/affs_fs_i.h	Wed Apr 25 16:21:27 2001
@@ -2,47 +2,56 @@
 #define _AFFS_FS_I
 
 #include <linux/a.out.h>
-#include <linux/time.h>
 
-#define AFFS_MAX_PREALLOC	16	/* MUST be a power of 2 */
-#define AFFS_KCSIZE		73	/* Allows for 1 extension block at 512 byte-blocks */
+// move this to linux/coda.h!!!
+#include <linux/time.h>
 
-struct key_cache {
-	struct timeval	 kc_lru_time;	/* Last time this cache was used */
-	s32	 kc_first;		/* First cached key */
-	s32	 kc_last;		/* Last cached key */
-	s32	 kc_this_key;		/* Key of extension block this data block keys are from */
-	int	 kc_this_seq;		/* Sequence number of this extension block */
-	s32	 kc_next_key;		/* Key of next extension block */
-	s32	 kc_keys[AFFS_KCSIZE];	/* Key cache */
-};
+#define AFFS_CACHE_SIZE		PAGE_SIZE
+//#define AFFS_CACHE_SIZE		(4*4)
 
-#define EC_SIZE	(PAGE_SIZE - 4 * sizeof(struct key_cache) - 4) / 4
+#define AFFS_MAX_PREALLOC	32
+#define AFFS_LC_SIZE		(AFFS_CACHE_SIZE/sizeof(u32)/2)
+#define AFFS_AC_SIZE		(AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2)
+#define AFFS_AC_MASK		(AFFS_AC_SIZE-1)
 
-struct ext_cache {
-	struct key_cache  kc[4];	/* The 4 key caches */
-	s32	 ec[EC_SIZE];		/* Keys of assorted extension blocks */
-	int	 max_ext;		/* Index of last known extension block */
+struct affs_ext_key {
+	u32	ext;				/* idx of the extended block */
+	u32	key;				/* block number */
 };
 
 /*
  * affs fs inode data in memory
  */
 struct affs_inode_info {
+	u32	 i_opencnt;
+	struct semaphore i_link_lock;		/* Protects internal inode access. */
+	struct semaphore i_ext_lock;		/* Protects internal inode access. */
+#define i_hash_lock i_ext_lock
+	u32	 i_blkcnt;			/* block count */
+	u32	 i_extcnt;			/* extended block count */
+	u32	*i_lc;				/* linear cache of extended blocks */
+	u32	 i_lc_size;
+	u32	 i_lc_shift;
+	u32	 i_lc_mask;
+	struct affs_ext_key *i_ac;		/* associative cache of extended blocks */
+	u32	 i_ext_last;			/* last accessed extended block */
+	struct buffer_head *i_ext_bh;		/* bh of last extended block */
 	unsigned long mmu_private;
 	u32	 i_protect;			/* unused attribute bits */
-	s32	 i_parent;			/* parent ino */
+	u32	 i_lastalloc;			/* last allocated block */
+	int	 i_pa_cnt;			/* number of preallocated blocks */
+#if 0
 	s32	 i_original;			/* if != 0, this is the key of the original */
-	s32	 i_data[AFFS_MAX_PREALLOC];	/* preallocated blocks */
-	struct ext_cache *i_ec;			/* Cache gets allocated dynamically */
+	u32	 i_data[AFFS_MAX_PREALLOC];	/* preallocated blocks */
 	int	 i_cache_users;			/* Cache cannot be freed while > 0 */
-	int	 i_lastblock;			/* last allocated block */
-	short	 i_pa_cnt;			/* number of preallocated blocks */
-	short	 i_pa_next;			/* Index of next block in i_data[] */
-	short	 i_pa_last;			/* Index of next free slot in i_data[] */
-	short	 i_zone;			/* write zone */
 	unsigned char i_hlink;			/* This is a fake */
 	unsigned char i_pad;
+	s32	 i_parent;			/* parent ino */
+#endif
 };
+
+/* short cut to get to the affs specific inode data */
+#define AFFS_INODE	(&inode->u.affs_i)
+#define AFFS_DIR	(&dir->u.affs_i)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h
--- v2.4.3/linux/include/linux/affs_fs_sb.h	Mon Feb 23 22:01:26 1998
+++ linux/include/linux/affs_fs_sb.h	Thu Apr 19 22:57:06 2001
@@ -8,51 +8,29 @@
  *
  */
 
-#define MAX_ZONES		8
-#define AFFS_DATA_MIN_FREE	512	/* Number of free blocks in zone for data blocks */
-#define AFFS_HDR_MIN_FREE	128	/* Same for header blocks */
-#define AFFS_ZONE_SIZE		1024	/* Blocks per alloc zone, must be multiple of 32 */
-
 struct affs_bm_info {
-	struct buffer_head *bm_bh;	/* Buffer head if loaded (bm_count > 0) */
-	s32 bm_firstblk;		/* Block number of first bit in this map */
-	s32 bm_key;			/* Disk block number */
-	int bm_count;			/* Usage counter */
-};
-
-struct affs_alloc_zone {
-	short az_size;			/* Size of this allocation zone in double words */
-	short az_count;			/* Number of users */
-	int az_free;			/* Free blocks in here (no. of bits) */
-};
-
-struct affs_zone {
-	unsigned long z_ino;		/* Associated inode number */
-	struct affs_bm_info *z_bm;	/* Zone lies in this bitmap */
-	int z_start;			/* Index of first word in bitmap */
-	int z_end;			/* Index of last word in zone + 1 */
-	int z_az_no;			/* Zone number */
-	unsigned long z_lru_time;	/* Time of last usage */
+	u32 bm_key;			/* Disk block number */
+	u32 bm_free;			/* Free blocks in here */
 };
 
 struct affs_sb_info {
 	int s_partition_size;		/* Partition size in blocks. */
-	int s_blksize;			/* Initial device blksize */
-	s32 s_root_block;		/* FFS root block number. */
+	int s_reserved;			/* Number of reserved blocks. */
+	//u32 s_blksize;			/* Initial device blksize */
+	u32 s_data_blksize;		/* size of the data block w/o header */
+	u32 s_root_block;		/* FFS root block number. */
 	int s_hashsize;			/* Size of hash table. */
 	unsigned long s_flags;		/* See below. */
-	s16 s_uid;			/* uid to override */
-	s16 s_gid;			/* gid to override */
+	uid_t s_uid;			/* uid to override */
+	gid_t s_gid;			/* gid to override */
 	umode_t s_mode;			/* mode to override */
-	int s_reserved;			/* Number of reserved blocks. */
 	struct buffer_head *s_root_bh;	/* Cached root block. */
+	struct semaphore s_bmlock;	/* Protects bitmap access. */
 	struct affs_bm_info *s_bitmap;	/* Bitmap infos. */
-	int s_bm_count;			/* Number of bitmap blocks. */
-	int s_nextzone;			/* Next zone to look for free blocks. */
-	int s_num_az;			/* Total number of alloc zones. */
-	struct affs_zone *s_zones;	/* The zones themselves. */
-	struct affs_alloc_zone *s_alloc;/* The allocation zones. */
-	char *s_zonemap;		/* Bitmap for allocation zones. */
+	u32 s_bmap_count;		/* # of bitmap blocks. */
+	u32 s_bmap_bits;		/* # of bits in one bitmap blocks */
+	u32 s_last_bmap;
+	struct buffer_head *s_bmap_bh;
 	char *s_prefix;			/* Prefix for volumes and assigns. */
 	int s_prefix_len;		/* Length of prefix. */
 	char s_volume[32];		/* Volume prefix for absolute symlinks. */
@@ -70,5 +48,8 @@
 #define SF_PREFIX	0x0400		/* Buffer for prefix is allocated */
 #define SF_VERBOSE	0x0800		/* Talk about fs when mounting */
 #define SF_READONLY	0x1000		/* Don't allow to remount rw */
+
+/* short cut to get to the affs specific sb data */
+#define AFFS_SB		(&sb->u.affs_sb)
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- v2.4.3/linux/include/linux/amigaffs.h	Mon Dec 11 13:26:57 2000
+++ linux/include/linux/amigaffs.h	Thu Apr 19 22:57:06 2001
@@ -1,8 +1,10 @@
 #ifndef AMIGAFFS_H
 #define AMIGAFFS_H
 
-#include <asm/byteorder.h>
 #include <linux/types.h>
+#include <linux/locks.h>
+
+#include <asm/byteorder.h>
 
 /* AmigaOS allows file names with up to 30 characters length.
  * Names longer than that will be silently truncated. If you
@@ -16,19 +18,83 @@
 
 #define GET_END_PTR(st,p,sz)		 ((st *)((char *)(p)+((sz)-sizeof(st))))
 #define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey])
-#define AFFS_BLOCK(data,ino,blk)	 ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-(blk)]
+#define AFFS_BLOCK(sb, bh, blk)		(AFFS_HEAD(bh)->table[(sb)->u.affs_sb.s_hashsize-1-(blk)])
 
-#define FILE_END(p,i)	GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i))
-#define ROOT_END(p,i)	GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i))
-#define DIR_END(p,i)	GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i))
-#define LINK_END(p,i)	GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i))
-#define ROOT_END_S(p,s)	GET_END_PTR(struct root_end,p,(s)->s_blocksize)
-#define DATA_FRONT(bh)	((struct data_front *)(bh)->b_data)
-#define DIR_FRONT(bh)	((struct dir_front *)(bh)->b_data)
-
-/* Only for easier debugging if need be */
-#define affs_bread	bread
-#define affs_brelse	brelse
+static inline void
+affs_set_blocksize(struct super_block *sb, int size)
+{
+	set_blocksize(sb->s_dev, size);
+	sb->s_blocksize = size;
+}
+static inline struct buffer_head *
+affs_bread(struct super_block *sb, int block)
+{
+	pr_debug(KERN_DEBUG "affs_bread: %d\n", block);
+	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size)
+		return bread(sb->s_dev, block, sb->s_blocksize);
+	return NULL;
+}
+static inline struct buffer_head *
+affs_getblk(struct super_block *sb, int block)
+{
+	pr_debug(KERN_DEBUG "affs_getblk: %d\n", block);
+	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size)
+		return getblk(sb->s_dev, block, sb->s_blocksize);
+	return NULL;
+}
+static inline struct buffer_head *
+affs_getzeroblk(struct super_block *sb, int block)
+{
+	struct buffer_head *bh;
+	pr_debug(KERN_DEBUG "affs_getzeroblk: %d\n", block);
+	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size) {
+		bh = getblk(sb->s_dev, block, sb->s_blocksize);
+		wait_on_buffer(bh);
+		memset(bh->b_data, 0 , sb->s_blocksize);
+		mark_buffer_uptodate(bh, 1);
+		return bh;
+	}
+	return NULL;
+}
+static inline struct buffer_head *
+affs_getemptyblk(struct super_block *sb, int block)
+{
+	struct buffer_head *bh;
+	pr_debug(KERN_DEBUG "affs_getemptyblk: %d\n", block);
+	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size) {
+		bh = getblk(sb->s_dev, block, sb->s_blocksize);
+		wait_on_buffer(bh);
+		mark_buffer_uptodate(bh, 1);
+		return bh;
+	}
+	return NULL;
+}
+static inline void
+affs_brelse(struct buffer_head *bh)
+{
+	if (bh)
+		pr_debug(KERN_DEBUG "affs_brelse: %ld\n", bh->b_blocknr);
+	brelse(bh);
+}
+
+static inline void
+affs_adjust_checksum(struct buffer_head *bh, u32 val)
+{
+	u32 tmp = be32_to_cpu(((u32 *)bh->b_data)[5]);
+	((u32 *)bh->b_data)[5] = cpu_to_be32(tmp - val);
+}
+static inline void
+affs_adjust_bitmapchecksum(struct buffer_head *bh, u32 val)
+{
+	u32 tmp = be32_to_cpu(((u32 *)bh->b_data)[0]);
+	((u32 *)bh->b_data)[0] = cpu_to_be32(tmp - val);
+}
+
+#define MIN(a, b) ({		\
+	typeof(a) _a = (a);	\
+	typeof(b) _b = (b);	\
+	_a < _b ? _a : _b;	\
+})	
 
 #ifdef __LITTLE_ENDIAN
 #define BO_EXBITS	0x18UL
@@ -63,133 +129,100 @@
 #define ST_SOFTLINK	3
 #define ST_LINKDIR	4
 
-struct root_front
-{
-  s32 primary_type;
-  s32 spare1[2];
-  s32 hash_size;
-  s32 spare2;
-  u32 checksum;
-  s32 hashtable[0];
-};
-
-struct root_end
-{
-  s32 bm_flag;
-  s32 bm_keys[25];
-  s32 bm_extend;
-  struct DateStamp dir_altered;
-  u8 disk_name[40];
-  struct DateStamp disk_altered;
-  struct DateStamp disk_made;
-  s32 spare1[3];
-  s32 secondary_type;
-};
-
-struct dir_front
-{
-  s32 primary_type;
-  s32 own_key;
-  s32 spare1[3];
-  u32 checksum;
-  s32 hashtable[0];
-};
-
-struct dir_end
-{
-  s32 spare1;
-  s16 owner_uid;
-  s16 owner_gid;
-  u32 protect;
-  s32 spare2;
-  u8 comment[92];
-  struct DateStamp created;
-  u8 dir_name[32];
-  s32 spare3[2];
-  s32 link_chain;
-  s32 spare4[5];
-  s32 hash_chain;
-  s32 parent;
-  s32 spare5;
-  s32 secondary_type;
-};
-
-struct file_front
-{
-  s32 primary_type;
-  s32 own_key;
-  s32 block_count;
-  s32 unknown1;
-  s32 first_data;
-  u32 checksum;
-  s32 blocks[0];
-};
-
-struct file_end
-{
-  s32 spare1;
-  s16 owner_uid;
-  s16 owner_gid;
-  u32 protect;
-  s32 byte_size;
-  u8 comment[92];
-  struct DateStamp created;
-  u8 file_name[32];
-  s32 spare2;
-  s32 original;	/* not really in file_end */
-  s32 link_chain;
-  s32 spare3[5];
-  s32 hash_chain;
-  s32 parent;
-  s32 extension;
-  s32 secondary_type;
-};
-
-struct hlink_front
-{
-  s32 primary_type;
-  s32 own_key;
-  s32 spare1[3];
-  u32 checksum;
-};
-
-struct hlink_end
-{
-  s32 spare1;
-  s16 owner_uid;
-  s16 owner_gid;
-  u32 protect;
-  u8 comment[92];
-  struct DateStamp created;
-  u8 link_name[32];
-  s32 spare2;
-  s32 original;
-  s32 link_chain;
-  s32 spare3[5];
-  s32 hash_chain;
-  s32 parent;
-  s32 spare4;
-  s32 secondary_type;
+#define AFFS_ROOT_BMAPS		25
+
+#define AFFS_HEAD(bh)		((struct affs_head *)(bh)->b_data)
+#define AFFS_TAIL(sb, bh)	((struct affs_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_tail)))
+#define AFFS_ROOT_HEAD(bh)	((struct affs_root_head *)(bh)->b_data)
+#define AFFS_ROOT_TAIL(sb, bh)	((struct affs_root_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_root_tail)))
+#define AFFS_DATA_HEAD(bh)	((struct affs_data_head *)(bh)->b_data)
+#define AFFS_DATA(bh)		(((struct affs_data_head *)(bh)->b_data)->data)
+
+struct affs_date {
+	u32 days;
+	u32 mins;
+	u32 ticks;
+};
+
+struct affs_short_date {
+	u16 days;
+	u16 mins;
+	u16 ticks;
+};
+
+struct affs_root_head {
+	u32 ptype;
+	u32 spare1;
+	u32 spare2;
+	u32 hash_size;
+	u32 spare3;
+	u32 checksum;
+	u32 hashtable[1];
+};
+
+struct affs_root_tail {
+	u32 bm_flag;
+	u32 bm_blk[AFFS_ROOT_BMAPS];
+	u32 bm_ext;
+	struct affs_date root_change;
+	u8 disk_name[32];
+	u32 spare1;
+	u32 spare2;
+	struct affs_date disk_change;
+	struct affs_date disk_create;
+	u32 spare3;
+	u32 spare4;
+	u32 dcache;
+	u32 stype;
+};
+
+struct affs_head {
+	u32 ptype;
+	u32 key;
+	u32 block_count;
+	u32 spare1;
+	u32 first_data;
+	u32 checksum;
+	u32 table[1];
+};
+
+struct affs_tail {
+	u32 spare1;
+	u16 uid;
+	u16 gid;
+	u32 protect;
+	u32 size;
+	u8 comment[92];
+	struct affs_date change;
+	u8 name[32];
+	u32 spare2;
+	u32 original;
+	u32 link_chain;
+	u32 spare[5];
+	u32 hash_chain;
+	u32 parent;
+	u32 extension;
+	u32 stype;
 };
 
 struct slink_front
 {
-  s32 primary_type;
-  s32 own_key;
-  s32 spare1[3];
-  s32 checksum;
-  u8	symname[288];	/* depends on block size */
-};
-
-struct data_front
-{
-  s32 primary_type;
-  s32 header_key;
-  s32 sequence_number;
-  s32 data_size;
-  s32 next_data;
-  s32 checksum;
-  u8 data[488];	/* depends on block size */
+	u32 ptype;
+	u32 key;
+	u32 spare1[3];
+	u32 checksum;
+	u8 symname[1];	/* depends on block size */
+};
+
+struct affs_data_head
+{
+	u32 ptype;
+	u32 key;
+	u32 sequence;
+	u32 size;
+	u32 next;
+	u32 checksum;
+	u8 data[1];	/* depends on block size */
 };
 
 /* Permission bits */
@@ -203,26 +236,16 @@
 #define FIBF_GRP_EXECUTE	0x0200
 #define FIBF_GRP_DELETE		0x0100
 
+#define FIBF_HIDDEN		0x0080
 #define FIBF_SCRIPT		0x0040
 #define FIBF_PURE		0x0020		/* no use under linux */
-#define FIBF_ARCHIVE		0x0010		/* never set, always cleared on write */
-#define FIBF_READ		0x0008		/* 0 means allowed */
-#define FIBF_WRITE		0x0004		/* 0 means allowed */
-#define FIBF_EXECUTE		0x0002		/* 0 means allowed, ignored under linux */
-#define FIBF_DELETE		0x0001		/* 0 means allowed */
+#define FIBF_ARCHIVED		0x0010		/* never set, always cleared on write */
+#define FIBF_NOREAD		0x0008		/* 0 means allowed */
+#define FIBF_NOWRITE		0x0004		/* 0 means allowed */
+#define FIBF_NOEXECUTE		0x0002		/* 0 means allowed, ignored under linux */
+#define FIBF_NODELETE		0x0001		/* 0 means allowed */
 
 #define FIBF_OWNER		0x000F		/* Bits pertaining to owner */
-
-#define AFFS_UMAYWRITE(prot)	(((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
-#define AFFS_UMAYREAD(prot)	((prot) & FIBF_READ)
-#define AFFS_UMAYEXECUTE(prot)	((prot) & FIBF_EXECUTE)
-#define AFFS_GMAYWRITE(prot)	(((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\
-							(FIBF_GRP_WRITE|FIBF_GRP_DELETE))
-#define AFFS_GMAYREAD(prot)	((prot) & FIBF_GRP_READ)
-#define AFFS_GMAYEXECUTE(prot)	((prot) & FIBF_EXECUTE)
-#define AFFS_OMAYWRITE(prot)	(((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\
-							(FIBF_OTR_WRITE|FIBF_OTR_DELETE))
-#define AFFS_OMAYREAD(prot)	((prot) & FIBF_OTR_READ)
-#define AFFS_OMAYEXECUTE(prot)	((prot) & FIBF_EXECUTE)
+#define FIBF_MASK		0xEE0E		/* Bits modified by Linux */
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h
--- v2.4.3/linux/include/linux/apm_bios.h	Wed Dec  6 21:00:13 2000
+++ linux/include/linux/apm_bios.h	Fri Apr  6 10:51:19 2001
@@ -3,7 +3,7 @@
 
 /*
  * Include file for the interface to an APM BIOS
- * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com)
+ * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au)
  *
  * 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
diff -u --recursive --new-file v2.4.3/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.4.3/linux/include/linux/blk.h	Mon Mar 26 15:48:46 2001
+++ linux/include/linux/blk.h	Wed Apr 25 16:22:36 2001
@@ -42,7 +42,6 @@
 extern int swimiop_init(void);
 extern int amiga_floppy_init(void);
 extern int atari_floppy_init(void);
-extern int nbd_init(void);
 extern int ez_init(void);
 extern int bpcd_init(void);
 extern int ps2esdi_init(void);
@@ -51,6 +50,7 @@
 #if defined(CONFIG_ARCH_S390)
 extern int mdisk_init(void);
 extern int dasd_init(void);
+extern int xpram_init(void);
 #endif /* CONFIG_ARCH_S390 */
 
 extern void set_device_ro(kdev_t dev,int flag);
diff -u --recursive --new-file v2.4.3/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.4.3/linux/include/linux/blkdev.h	Mon Mar 26 15:48:13 2001
+++ linux/include/linux/blkdev.h	Wed Apr 25 16:21:57 2001
@@ -161,7 +161,6 @@
 extern void blk_init_queue(request_queue_t *, request_fn_proc *);
 extern void blk_cleanup_queue(request_queue_t *);
 extern void blk_queue_headactive(request_queue_t *, int);
-extern void blk_queue_pluggable(request_queue_t *, plug_device_fn *);
 extern void blk_queue_make_request(request_queue_t *, make_request_fn *);
 extern void generic_unplug_device(void *);
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.4.3/linux/include/linux/cdrom.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/cdrom.h	Wed Apr 25 16:21:41 2001
@@ -128,8 +128,13 @@
 #define CDROM_DEBUG		0x5330	/* Turn debug messages on/off */
 #define CDROM_GET_CAPABILITY	0x5331	/* get capabilities */
 
+/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386.
+ * Future CDROM ioctls should be kept below 0x537F
+ */
+
 /* This ioctl is only used by sbpcd at the moment */
 #define CDROMAUDIOBUFSIZ        0x5382	/* set the audio buffer size */
+					/* conflict with SCSI_IOCTL_GET_IDLUN */
 
 /* DVD-ROM Specific ioctls */
 #define DVD_READ_STRUCT		0x5390  /* Read structure */
diff -u --recursive --new-file v2.4.3/linux/include/linux/coda.h linux/include/linux/coda.h
--- v2.4.3/linux/include/linux/coda.h	Tue Sep 19 15:08:59 2000
+++ linux/include/linux/coda.h	Wed Apr 25 16:18:54 2001
@@ -313,7 +313,9 @@
 #define CODA_RESOLVE     32
 #define CODA_REINTEGRATE 33
 #define CODA_STATFS	 34
-#define CODA_NCALLS 35
+#define CODA_STORE	 35
+#define CODA_RELEASE	 36
+#define CODA_NCALLS 37
 
 #define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID)
 
@@ -372,6 +374,28 @@
 };
 
 
+/* coda_store: */
+struct coda_store_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	flags;
+};
+
+struct coda_store_out {
+    struct coda_out_hdr out;
+};
+
+/* coda_release: */
+struct coda_release_in {
+    struct coda_in_hdr ih;
+    ViceFid	VFid;
+    int	flags;
+};
+
+struct coda_release_out {
+    struct coda_out_hdr out;
+};
+
 /* coda_close: */
 struct coda_close_in {
     struct coda_in_hdr ih;
@@ -641,6 +665,10 @@
 struct coda_open_by_fd_out {
     struct coda_out_hdr oh;
     int fd;
+
+#ifdef __KERNEL__
+    struct file *fh; /* not passed from userspace but used in-kernel only */
+#endif
 };
 
 /* coda_open_by_path: */
@@ -675,6 +703,8 @@
 union inputArgs {
     struct coda_in_hdr ih;		/* NB: every struct below begins with an ih */
     struct coda_open_in coda_open;
+    struct coda_store_in coda_store;
+    struct coda_release_in coda_release;
     struct coda_close_in coda_close;
     struct coda_ioctl_in coda_ioctl;
     struct coda_getattr_in coda_getattr;
diff -u --recursive --new-file v2.4.3/linux/include/linux/coda_fs_i.h linux/include/linux/coda_fs_i.h
--- v2.4.3/linux/include/linux/coda_fs_i.h	Mon Mar 26 15:48:10 2001
+++ linux/include/linux/coda_fs_i.h	Wed Apr 25 16:21:24 2001
@@ -13,20 +13,17 @@
 #include <linux/list.h>
 #include <linux/coda.h>
 
-#define CODA_CNODE_MAGIC        0x47114711
 /*
  * coda fs inode data
  */
 struct coda_inode_info {
         struct ViceFid     c_fid;	/* Coda identifier */
         u_short	           c_flags;     /* flags (see below) */
-	struct list_head   c_volrootlist; /* list of volroot cnoddes */
 	struct list_head   c_cilist;    /* list of all coda inodes */
-        struct inode      *c_vnode;     /* inode associated with cnode */
-        unsigned int       c_contcount; /* refcount for container inode */
+	struct file	  *c_container; /* container file for this cnode */
+	unsigned int       c_contcount; /* refcount for container file */
         struct coda_cred   c_cached_cred; /* credentials of cached perms */
         unsigned int       c_cached_perm; /* cached access permissions */
-        int                c_magic;     /* to verify the data structure */
 };
 
 /* flags */
diff -u --recursive --new-file v2.4.3/linux/include/linux/coda_linux.h linux/include/linux/coda_linux.h
--- v2.4.3/linux/include/linux/coda_linux.h	Fri Feb  9 11:29:44 2001
+++ linux/include/linux/coda_linux.h	Wed Apr 25 16:18:54 2001
@@ -36,15 +36,18 @@
 
 /* operations shared over more than one file */
 int coda_open(struct inode *i, struct file *f);
+int coda_flush(struct file *f);
 int coda_release(struct inode *i, struct file *f);
 int coda_permission(struct inode *inode, int mask);
 int coda_revalidate_inode(struct dentry *);
 int coda_notify_change(struct dentry *, struct iattr *);
+int coda_isnullfid(ViceFid *fid);
 
 /* global variables */
 extern int coda_debug;
 extern int coda_print_entry;
 extern int coda_access_cache;
+extern int coda_fake_statfs;
 
 /* this file:  heloers */
 static __inline__ struct ViceFid *coda_i2f(struct inode *);
@@ -53,8 +56,6 @@
 char *coda_f2s(ViceFid *f);
 char *coda_f2s2(ViceFid *f);
 int coda_isroot(struct inode *i);
-int coda_fid_is_volroot(struct ViceFid *);
-int coda_fid_is_weird(struct ViceFid *fid);
 int coda_iscontrol(const char *name, size_t length);
 
 void coda_load_creds(struct coda_cred *cred);
@@ -65,10 +66,6 @@
 int coda_cred_ok(struct coda_cred *cred);
 int coda_cred_eq(struct coda_cred *cred1, struct coda_cred *cred2);
 
-/* cache.c */
-void coda_purge_children(struct inode *, int);
-void coda_purge_dentries(struct inode *);
-
 /* sysctl.h */
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
@@ -120,22 +117,22 @@
 
 /* inode to cnode access functions */
 
+#define ITOC(inode) (&((inode)->u.coda_i))
+
 static __inline__ struct ViceFid *coda_i2f(struct inode *inode)
 {
-	return &(inode->u.coda_i.c_fid);
+	return &(ITOC(inode)->c_fid);
 }
 
 static __inline__ char *coda_i2s(struct inode *inode)
 {
-	return coda_f2s(&(inode->u.coda_i.c_fid));
+	return coda_f2s(&(ITOC(inode)->c_fid));
 }
 
 /* this will not zap the inode away */
 static __inline__ void coda_flag_inode(struct inode *inode, int flag)
 {
-	inode->u.coda_i.c_flags |= flag;
+	ITOC(inode)->c_flags |= flag;
 }		
-
-#define ITOC(inode) (&((inode)->u.coda_i))
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/coda_proc.h linux/include/linux/coda_proc.h
--- v2.4.3/linux/include/linux/coda_proc.h	Mon Dec 11 13:25:00 2000
+++ linux/include/linux/coda_proc.h	Wed Apr 25 16:18:54 2001
@@ -40,6 +40,7 @@
 {
 	/* file operations */
 	int open;
+	int flush;
 	int release;
 	int fsync;
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h
--- v2.4.3/linux/include/linux/coda_psdev.h	Tue Sep 19 15:08:59 2000
+++ linux/include/linux/coda_psdev.h	Wed Apr 25 16:18:54 2001
@@ -39,10 +39,13 @@
 int venus_lookup(struct super_block *sb, struct ViceFid *fid, 
 		    const char *name, int length, int *type, 
 		    struct ViceFid *resfid);
-int venus_release(struct super_block *sb, struct ViceFid *fid, int flags,
-		  struct coda_cred *);
+int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
+		struct coda_cred *);
+int venus_release(struct super_block *sb, struct ViceFid *fid, int flags);
+int venus_close(struct super_block *sb, struct ViceFid *fid, int flags,
+		struct coda_cred *);
 int venus_open(struct super_block *sb, struct ViceFid *fid,
-		  int flags, ino_t *ino, dev_t *dev);
+		int flags, struct file **f);
 int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid, 
 			  const char *name, int length, 
 			  struct ViceFid *newfid, struct coda_vattr *attrs);
diff -u --recursive --new-file v2.4.3/linux/include/linux/coff.h linux/include/linux/coff.h
--- v2.4.3/linux/include/linux/coff.h	Wed Aug 10 09:26:42 1994
+++ linux/include/linux/coff.h	Fri Apr  6 10:51:19 2001
@@ -1,5 +1,5 @@
 /* This file is derived from the GAS 2.1.4 assembler control file.
-   The GAS product is under the GNU Public License, version 2 or later.
+   The GAS product is under the GNU General Public License, version 2 or later.
    As such, this file is also under that license.
 
    If the file format changes in the COFF object, this file should be
diff -u --recursive --new-file v2.4.3/linux/include/linux/com20020.h linux/include/linux/com20020.h
--- v2.4.3/linux/include/linux/com20020.h	Tue May  2 12:36:09 2000
+++ linux/include/linux/com20020.h	Fri Apr  6 10:51:19 2001
@@ -15,7 +15,7 @@
  * skeleton.c 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
+ * and distributed according to the terms of the GNU General Public License as
  * modified by SRC, incorporated herein by reference.
  *
  * **********************
diff -u --recursive --new-file v2.4.3/linux/include/linux/compiler.h linux/include/linux/compiler.h
--- v2.4.3/linux/include/linux/compiler.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/compiler.h	Sun Apr 22 19:10:53 2001
@@ -0,0 +1,13 @@
+#ifndef __LINUX_COMPILER_H
+#define __LINUX_COMPILER_H
+
+/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented
+   a mechanism by which the user can annotate likely branch directions and
+   expect the blocks to be reordered appropriately.  Define __builtin_expect
+   to nothing for earlier compilers.  */
+
+#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#endif /* __LINUX_COMPILER_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- v2.4.3/linux/include/linux/devfs_fs_kernel.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/devfs_fs_kernel.h	Wed Apr 25 16:21:38 2001
@@ -96,7 +96,6 @@
 				   unsigned int minor_start,
 				   umode_t mode, void *ops, void *info);
 
-extern int init_devfs_fs (void);
 extern void mount_devfs_fs (void);
 extern void devfs_make_root (const char *name);
 #else  /*  CONFIG_DEVFS_FS  */
@@ -233,10 +232,6 @@
     return;
 }
 
-static inline int init_devfs_fs (void)
-{
-    return 0;
-}
 static inline void mount_devfs_fs (void)
 {
     return;
diff -u --recursive --new-file v2.4.3/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h
--- v2.4.3/linux/include/linux/etherdevice.h	Sun Mar 25 18:24:31 2001
+++ linux/include/linux/etherdevice.h	Thu Apr 19 09:34:52 2001
@@ -51,7 +51,8 @@
  * @addr: Pointer to a six-byte array containing the Ethernet address
  *
  * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
- * a multicast address, and is not FF:FF:FF:FF:FF:FF.
+ * a multicast address, and is not FF:FF:FF:FF:FF:FF.  The multicast
+ * and FF:FF:... tests are combined into the single test "!(addr[0]&1)".
  *
  * Return true if the address is valid.
  */
diff -u --recursive --new-file v2.4.3/linux/include/linux/ethtool.h linux/include/linux/ethtool.h
--- v2.4.3/linux/include/linux/ethtool.h	Sun Mar 25 18:24:31 2001
+++ linux/include/linux/ethtool.h	Thu Apr 19 09:35:46 2001
@@ -2,6 +2,7 @@
  * ethtool.h: Defines for Linux ethtool.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
  */
 
 #ifndef _LINUX_ETHTOOL_H
diff -u --recursive --new-file v2.4.3/linux/include/linux/filter.h linux/include/linux/filter.h
--- v2.4.3/linux/include/linux/filter.h	Thu Apr 27 15:55:09 2000
+++ linux/include/linux/filter.h	Fri Apr 20 11:54:24 2001
@@ -135,6 +135,7 @@
 #ifdef __KERNEL__
 extern int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen);
 extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+extern int sk_chk_filter(struct sock_filter *filter, int flen);
 #endif /* __KERNEL__ */
 
 #endif /* __LINUX_FILTER_H__ */
diff -u --recursive --new-file v2.4.3/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.3/linux/include/linux/fs.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/fs.h	Wed Apr 25 16:21:36 2001
@@ -774,6 +774,8 @@
 	int (*lock) (struct file *, int, struct file_lock *);
 	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 	ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
+	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
+	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 };
 
 struct inode_operations {
@@ -1225,6 +1227,7 @@
 	}
 	return inode;
 }
+extern void remove_suid(struct inode *inode);
 
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
@@ -1249,7 +1252,6 @@
 		__bforget(buf);
 }
 extern void set_blocksize(kdev_t, int);
-extern unsigned int get_hardblocksize(kdev_t);
 extern struct buffer_head * bread(kdev_t, int, int);
 extern void wakeup_bdflush(int wait);
 
@@ -1272,6 +1274,7 @@
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
 
 extern int generic_file_mmap(struct file *, struct vm_area_struct *);
+extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
@@ -1291,7 +1294,6 @@
 
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
-struct super_block *get_empty_super(void);
 extern void put_super(kdev_t);
 unsigned long generate_cluster(kdev_t, int b[], int);
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
diff -u --recursive --new-file v2.4.3/linux/include/linux/icmp.h linux/include/linux/icmp.h
--- v2.4.3/linux/include/linux/icmp.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/icmp.h	Thu Apr 12 12:11:39 2001
@@ -80,30 +80,6 @@
   } un;
 };
 
-#ifdef __KERNEL__
-
-#include <linux/ip.h>
-
-/*
- *	Build xmit assembly blocks
- */
-
-struct icmp_bxm
-{
-	void *data_ptr;
-	int data_len;
-	struct icmphdr icmph;
-	unsigned long csum;
-	struct ip_options replyopts;
-	unsigned char  optbuf[40];
-};
-
-struct sk_buff;
-
-extern void icmp_reply(struct icmp_bxm *, struct sk_buff *);
-
-#endif
-
 /*
  *	constants for (set|get)sockopt
  */
diff -u --recursive --new-file v2.4.3/linux/include/linux/icmpv6.h linux/include/linux/icmpv6.h
--- v2.4.3/linux/include/linux/icmpv6.h	Mon Mar 26 15:48:19 2001
+++ linux/include/linux/icmpv6.h	Wed Apr 25 16:22:03 2001
@@ -143,7 +143,7 @@
 							   int *err);
 extern void				icmpv6_cleanup(void);
 extern void				icmpv6_param_prob(struct sk_buff *skb,
-							  int code, void *pos);
+							  int code, int pos);
 #endif
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.4.3/linux/include/linux/if_arp.h	Mon Mar 26 15:48:19 2001
+++ linux/include/linux/if_arp.h	Wed Apr 25 16:22:18 2001
@@ -73,7 +73,7 @@
 #define ARPHRD_ECONET	782		/* Acorn Econet			*/
 #define ARPHRD_IRDA 	783		/* Linux-IrDA			*/
 /* ARP works differently on different FC media .. so  */
-#define ARPHRD_FCPP	784		/* Point to point fibrechanel	*/
+#define ARPHRD_FCPP	784		/* Point to point fibrechannel	*/
 #define ARPHRD_FCAL	785		/* Fibrechannel arbitrated loop */
 #define ARPHRD_FCPL	786		/* Fibrechannel public loop	*/
 #define ARPHRD_FCFABRIC	787		/* Fibrechannel fabric		*/
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_ec.h linux/include/linux/if_ec.h
--- v2.4.3/linux/include/linux/if_ec.h	Thu Mar  9 06:57:17 2000
+++ linux/include/linux/if_ec.h	Thu Apr 19 08:38:50 2001
@@ -60,9 +60,6 @@
   unsigned char station, net;		/* Econet protocol address */
 };
 
-extern struct sock *ec_listening_socket(unsigned char port, unsigned char
-				 station, unsigned char net);
-
 #endif
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v2.4.3/linux/include/linux/if_ether.h	Fri Oct 27 11:03:14 2000
+++ linux/include/linux/if_ether.h	Thu Apr 19 08:38:50 2001
@@ -37,12 +37,14 @@
  */
 
 #define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
-#define ETH_P_ECHO	0x0200		/* Ethernet Echo packet		*/
-#define ETH_P_PUP	0x0400		/* Xerox PUP packet		*/
+#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
+#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
 #define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
 #define ETH_P_X25	0x0805		/* CCITT X.25			*/
 #define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
 #define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet	[ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IEEEPUP	0x0a00		/* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT	0x0a01		/* Xerox IEEE802.3 PUP Addr Trans packet */
 #define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
 #define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
 #define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_packet.h linux/include/linux/if_packet.h
--- v2.4.3/linux/include/linux/if_packet.h	Thu Aug 10 13:01:26 2000
+++ linux/include/linux/if_packet.h	Thu Apr 12 12:11:39 2001
@@ -53,6 +53,7 @@
 #define TP_STATUS_USER		1
 #define TP_STATUS_COPY		2
 #define TP_STATUS_LOSING	4
+#define TP_STATUS_CSUMNOTREADY	8
 	unsigned int	tp_len;
 	unsigned int	tp_snaplen;
 	unsigned short	tp_mac;
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_ppp.h linux/include/linux/if_ppp.h
--- v2.4.3/linux/include/linux/if_ppp.h	Mon Mar 27 10:28:55 2000
+++ linux/include/linux/if_ppp.h	Fri Apr 20 16:18:35 2001
@@ -1,4 +1,4 @@
-/*	$Id: if_ppp.h,v 1.19 1999/03/31 06:07:57 paulus Exp $	*/
+/*	$Id: if_ppp.h,v 1.21 2000/03/27 06:03:36 paulus Exp $	*/
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
@@ -21,7 +21,7 @@
  */
 
 /*
- *  ==FILEVERSION 20000324==
+ *  ==FILEVERSION 20000724==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the above date.
@@ -130,6 +130,8 @@
 #define PPPIOCSCOMPRESS	_IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE	_IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE	_IOW('t', 75, struct npioctl)  /* set NP mode */
+#define PPPIOCSPASS	_IOW('t', 71, struct sock_fprog) /* set pass filter */
+#define PPPIOCSACTIVE	_IOW('t', 70, struct sock_fprog) /* set active filt */
 #define PPPIOCGDEBUG	_IOR('t', 65, int)	/* Read debug level */
 #define PPPIOCSDEBUG	_IOW('t', 64, int)	/* Set debug level */
 #define PPPIOCGIDLE	_IOR('t', 63, struct ppp_idle) /* get idle time */
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_wanpipe.h linux/include/linux/if_wanpipe.h
--- v2.4.3/linux/include/linux/if_wanpipe.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/if_wanpipe.h	Wed Apr 25 16:21:21 2001
@@ -0,0 +1,128 @@
+/*****************************************************************************
+* if_wanpipe.h	Header file for the Sangoma AF_WANPIPE Socket 	
+*
+* Author: 	Nenad Corbic 	
+*
+* Copyright:	(c) 2000 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+*
+* Jan 28, 2000	Nenad Corbic 	Initial Version
+*
+*****************************************************************************/
+
+#ifndef __LINUX_IF_WAN_PACKET_H
+#define __LINUX_IF_WAN_PACKET_H
+
+struct wan_sockaddr_ll
+{
+	unsigned short	sll_family;
+	unsigned short	sll_protocol;
+	int		sll_ifindex;
+	unsigned short	sll_hatype;
+	unsigned char	sll_pkttype;
+	unsigned char	sll_halen;
+	unsigned char	sll_addr[8];
+	unsigned char   sll_device[14];
+	unsigned char 	sll_card[14];
+};
+
+typedef struct 
+{
+	unsigned char free;
+	unsigned char sk_state;
+	int rcvbuf;
+	int sndbuf;
+	int rmem;
+	int wmem;
+	int sk_count;
+	unsigned char bound;
+	char name[14];
+	unsigned char d_state;
+	unsigned char svc;
+	unsigned short lcn;
+	unsigned char mbox;
+	unsigned char cmd_busy;
+	unsigned char command;
+	unsigned poll;
+	unsigned poll_cnt;
+	int rblock;	
+} wan_debug_hdr_t;
+
+#define MAX_NUM_DEBUG  10
+#define X25_PROT       0x16
+#define PVC_PROT       0x17	
+
+typedef struct
+{
+	wan_debug_hdr_t debug[MAX_NUM_DEBUG];
+}wan_debug_t;
+
+#define	SIOC_WANPIPE_GET_CALL_DATA	(SIOCPROTOPRIVATE + 0)
+#define	SIOC_WANPIPE_SET_CALL_DATA	(SIOCPROTOPRIVATE + 1)
+#define SIOC_WANPIPE_ACCEPT_CALL	(SIOCPROTOPRIVATE + 2)
+#define SIOC_WANPIPE_CLEAR_CALL	        (SIOCPROTOPRIVATE + 3)
+#define SIOC_WANPIPE_RESET_CALL	        (SIOCPROTOPRIVATE + 4)
+#define SIOC_WANPIPE_DEBUG	        (SIOCPROTOPRIVATE + 5)
+#define SIOC_WANPIPE_SET_NONBLOCK	(SIOCPROTOPRIVATE + 6)
+#define SIOC_WANPIPE_CHECK_TX		(SIOCPROTOPRIVATE + 7)
+#define SIOC_WANPIPE_SOCK_STATE		(SIOCPROTOPRIVATE + 8)
+
+/* Packet types */
+
+#define WAN_PACKET_HOST		0		/* To us		*/
+#define WAN_PACKET_BROADCAST	1		/* To all		*/
+#define WAN_PACKET_MULTICAST	2		/* To group		*/
+#define WAN_PACKET_OTHERHOST	3		/* To someone else 	*/
+#define WAN_PACKET_OUTGOING		4		/* Outgoing of any type */
+/* These ones are invisible by user level */
+#define WAN_PACKET_LOOPBACK		5		/* MC/BRD frame looped back */
+#define WAN_PACKET_FASTROUTE	6		/* Fastrouted frame	*/
+
+
+/* X25 specific */
+#define WAN_PACKET_DATA 	7
+#define WAN_PACKET_CMD 		8
+#define WAN_PACKET_ASYNC	9
+#define WAN_PACKET_ERR	       10
+
+/* Packet socket options */
+
+#define WAN_PACKET_ADD_MEMBERSHIP		1
+#define WAN_PACKET_DROP_MEMBERSHIP		2
+
+#define WAN_PACKET_MR_MULTICAST	0
+#define WAN_PACKET_MR_PROMISC	1
+#define WAN_PACKET_MR_ALLMULTI	2
+
+#ifdef __KERNEL__
+#ifndef netdevice_t
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ #define netdevice_t struct net_device
+#else
+ #define netdevice_t struct device
+#endif
+#endif
+
+/* Private wanpipe socket structures. */
+struct wanpipe_opt
+{
+	void   *mbox;		/* Mail box  */
+	void   *card; 		/* Card bouded to */
+	netdevice_t *dev;	/* Bounded device */
+	unsigned short lcn;	/* Binded LCN */
+	unsigned char  svc;	/* 0=pvc, 1=svc */
+	unsigned char  timer;   /* flag for delayed transmit*/	
+	struct timer_list tx_timer;
+	unsigned poll_cnt;
+	unsigned char force;	/* Used to force sock release */
+	atomic_t packet_sent;   
+};
+#endif
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/if_wanpipe_common.h linux/include/linux/if_wanpipe_common.h
--- v2.4.3/linux/include/linux/if_wanpipe_common.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/if_wanpipe_common.h	Thu Apr 12 12:11:39 2001
@@ -0,0 +1,67 @@
+/*****************************************************************************
+* if_wanipe_common.h   Sangoma Driver/Socket common area definitions.
+*
+* Author:       Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright:    (c) 2000 Sangoma Technologies Inc.
+*
+*               This program is free software; you can redistribute it and/or
+*               modify it under the terms of the GNU General Public License
+*               as published by the Free Software Foundation; either version
+*               2 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 13, 2000  Nenad Corbic      Initial version
+*****************************************************************************/
+
+
+#ifndef _WANPIPE_SOCK_DRIVER_COMMON_H
+#define _WANPIPE_SOCK_DRIVER_COMMON_H
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ #define netdevice_t struct net_device
+#else
+ #define netdevice_t struct device
+#endif
+
+
+typedef struct {
+	netdevice_t *slave;
+	atomic_t packet_sent;
+	atomic_t receive_block;
+	atomic_t command;
+	atomic_t disconnect;
+	atomic_t driver_busy;
+	unsigned char common_critical;
+	struct timer_list *tx_timer;
+	struct sock *sk;		/* Wanpipe Sock bind's here */ 
+	int   (*func) (struct sk_buff *, netdevice_t *, 
+                       struct sock *);
+
+	struct tq_struct wanpipe_task;    /* Immediate BH handler task */
+	unsigned char rw_bind;			  /* Sock bind state */
+	unsigned char usedby;
+	unsigned char state;
+	unsigned char svc;
+	unsigned short lcn;
+	void *mbox;
+} wanpipe_common_t;
+
+
+enum {
+	WANSOCK_UNCONFIGURED,	/* link/channel is not configured */
+	WANSOCK_DISCONNECTED,	/* link/channel is disconnected */
+	WANSOCK_CONNECTING,		/* connection is in progress */
+	WANSOCK_CONNECTED,		/* link/channel is operational */
+	WANSOCK_LIMIT,		/* for verification only */
+	WANSOCK_DUALPORT,		/* for Dual Port cards */
+	WANSOCK_DISCONNECTING,
+	WANSOCK_BINDED,
+	WANSOCK_BIND_LISTEN,
+	WANSOCK_LISTEN
+};
+
+#endif
+
+
diff -u --recursive --new-file v2.4.3/linux/include/linux/igmp.h linux/include/linux/igmp.h
--- v2.4.3/linux/include/linux/igmp.h	Mon Aug 23 10:01:02 1999
+++ linux/include/linux/igmp.h	Thu Apr 12 12:11:39 2001
@@ -104,7 +104,7 @@
 };
 
 extern int ip_check_mc(struct in_device *dev, u32 mc_addr);
-extern int igmp_rcv(struct sk_buff *, unsigned short);
+extern int igmp_rcv(struct sk_buff *);
 extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
 extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
 extern void ip_mc_drop_socket(struct sock *sk);
diff -u --recursive --new-file v2.4.3/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.4.3/linux/include/linux/isdn.h	Fri Feb  9 11:29:44 2001
+++ linux/include/linux/isdn.h	Thu Apr 19 22:30:09 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.111.6.1 2001/02/07 11:31:31 kai Exp $
+/* $Id: isdn.h,v 1.111.6.5 2001/04/20 02:40:48 keil Exp $
 
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -25,7 +25,9 @@
 #ifndef isdn_h
 #define isdn_h
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 #include <linux/ioctl.h>
 
 #define ISDN_TTY_MAJOR    43
@@ -37,7 +39,7 @@
  * the correspondent code in isdn.c
  */
 
-#ifdef CONFIG_COBALT_MICRO_SERVER
+#ifdef USE_MINIMUM_MEM
 /* Save memory */
 #define ISDN_MAX_DRIVERS    2
 #define ISDN_MAX_CHANNELS   8
@@ -104,6 +106,12 @@
 
 #define IIOCDRVCTL  _IO('I',128)
 
+/* cisco hdlck device private ioctls */
+#define SIOCGKEEPPERIOD	(SIOCDEVPRIVATE + 0)
+#define SIOCSKEEPPERIOD	(SIOCDEVPRIVATE + 1)
+#define SIOCGDEBSERINT	(SIOCDEVPRIVATE + 2)
+#define SIOCSDEBSERINT	(SIOCDEVPRIVATE + 3)
+
 /* Packet encapsulations for net-interfaces */
 #define ISDN_NET_ENCAP_ETHER      0
 #define ISDN_NET_ENCAP_RAWIP      1
@@ -264,9 +272,9 @@
                              ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)     )
 
 /* Timer-delays and scheduling-flags */
-#define ISDN_TIMER_RES         3                         /* Main Timer-Resolution   */
-#define ISDN_TIMER_02SEC       (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec      */
-#define ISDN_TIMER_1SEC        (HZ/(ISDN_TIMER_RES+1))   /* Slow-Timer2 1 sec       */
+#define ISDN_TIMER_RES         4                         /* Main Timer-Resolution   */
+#define ISDN_TIMER_02SEC       (HZ/ISDN_TIMER_RES/5)     /* Slow-Timer1 .2 sec      */
+#define ISDN_TIMER_1SEC        (HZ/ISDN_TIMER_RES)       /* Slow-Timer2 1 sec       */
 #define ISDN_TIMER_RINGING     5 /* tty RINGs = ISDN_TIMER_1SEC * this factor       */
 #define ISDN_TIMER_KEEPINT    10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
 #define ISDN_TIMER_MODEMREAD   1
@@ -275,13 +283,11 @@
 #define ISDN_TIMER_MODEMXMIT   8
 #define ISDN_TIMER_NETDIAL    16 
 #define ISDN_TIMER_NETHANGUP  32
-#define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */
 #define ISDN_TIMER_CARRIER   256 /* Wait for Carrier */
 #define ISDN_TIMER_FAST      (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
                               ISDN_TIMER_MODEMXMIT)
 #define ISDN_TIMER_SLOW      (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
-                              ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE | \
-                              ISDN_TIMER_CARRIER)
+                              ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER)
 
 /* Timeout-Values for isdn_net_dial() */
 #define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
@@ -403,9 +409,15 @@
 #ifdef CONFIG_ISDN_X25
   struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
 #endif
-  int  cisco_loop;                     /* Loop counter for Cisco-SLARP     */
+  /* use an own struct for that in later versions */
   ulong cisco_myseq;                   /* Local keepalive seq. for Cisco   */
+  ulong cisco_mineseen;                /* returned keepalive seq. from remote */
   ulong cisco_yourseq;                 /* Remote keepalive seq. for Cisco  */
+  int cisco_keepalive_period;		/* keepalive period */
+  ulong cisco_last_slarp_in;		/* jiffie of last keepalive packet we received */
+  char cisco_line_state;		/* state of line according to keepalive packets */
+  char cisco_debserint;			/* debugging flag of cisco hdlc with slarp */
+  struct timer_list cisco_timer;
   struct tq_struct tqueue;
 } isdn_net_local;
 
@@ -420,7 +432,7 @@
   struct net_device dev;               /* interface to upper levels        */
 #ifdef CONFIG_ISDN_PPP
   ippp_bundle * pb;		/* pointer to the common bundle structure
-   			         * with the the per-bundle data */
+   			         * with the per-bundle data */
 #endif
 #ifdef CONFIG_ISDN_X25
   struct concap_proto  *cprot; /* connection oriented encapsulation protocol */
diff -u --recursive --new-file v2.4.3/linux/include/linux/isdn_ppp.h linux/include/linux/isdn_ppp.h
--- v2.4.3/linux/include/linux/isdn_ppp.h	Mon Mar 26 15:38:19 2001
+++ linux/include/linux/isdn_ppp.h	Thu Apr 19 22:30:09 2001
@@ -3,7 +3,9 @@
 #ifndef _LINUX_ISDN_PPP_H
 #define _LINUX_ISDN_PPP_H
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 
 #define CALLTYPE_INCOMING 0x1
 #define CALLTYPE_OUTGOING 0x2
diff -u --recursive --new-file v2.4.3/linux/include/linux/isdnif.h linux/include/linux/isdnif.h
--- v2.4.3/linux/include/linux/isdnif.h	Mon Dec 11 13:20:27 2000
+++ linux/include/linux/isdnif.h	Thu Apr 19 22:30:09 2001
@@ -26,7 +26,9 @@
 #ifndef isdnif_h
 #define isdnif_h
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 
 /*
  * Values for general protocol-selection
diff -u --recursive --new-file v2.4.3/linux/include/linux/joystick.h linux/include/linux/joystick.h
--- v2.4.3/linux/include/linux/joystick.h	Wed Jun 21 08:22:21 2000
+++ linux/include/linux/joystick.h	Wed Apr 11 19:02:30 2001
@@ -2,7 +2,7 @@
 #define _LINUX_JOYSTICK_H
 
 /*
- * $Id: joystick.h,v 1.2 2000/05/29 10:54:53 vojtech Exp $
+ * $Id: joystick.h,v 1.3 2000/11/30 11:07:05 vojtech Exp $
  *
  *  Copyright (C) 1996-2000 Vojtech Pavlik
  *
@@ -30,12 +30,13 @@
  */
 
 #include <asm/types.h>
+#include <linux/input.h>
 
 /*
  * Version
  */
 
-#define JS_VERSION		0x020000
+#define JS_VERSION		0x020100
 
 /*
  * Types and constants for reading from /dev/js
@@ -46,7 +47,7 @@
 #define JS_EVENT_INIT		0x80	/* initial state of device */
 
 struct js_event {
-	__u32 time;	/* event timestamp in miliseconds */
+	__u32 time;	/* event timestamp in milliseconds */
 	__s16 value;	/* value */
 	__u8 type;	/* event type */
 	__u8 number;	/* axis/button number */
@@ -56,14 +57,19 @@
  * IOCTL commands for joystick driver
  */
 
-#define JSIOCGVERSION		_IOR('j', 0x01, __u32)			/* get driver version */
+#define JSIOCGVERSION		_IOR('j', 0x01, __u32)				/* get driver version */
 
-#define JSIOCGAXES		_IOR('j', 0x11, __u8)			/* get number of axes */
-#define JSIOCGBUTTONS		_IOR('j', 0x12, __u8)			/* get number of buttons */
-#define JSIOCGNAME(len)		_IOC(_IOC_READ, 'j', 0x13, len)         /* get identifier string */
-
-#define JSIOCSCORR		_IOW('j', 0x21, struct js_corr)		/* set correction values */
-#define JSIOCGCORR		_IOR('j', 0x22, struct js_corr)		/* get correction values */
+#define JSIOCGAXES		_IOR('j', 0x11, __u8)				/* get number of axes */
+#define JSIOCGBUTTONS		_IOR('j', 0x12, __u8)				/* get number of buttons */
+#define JSIOCGNAME(len)		_IOC(_IOC_READ, 'j', 0x13, len)			/* get identifier string */
+
+#define JSIOCSCORR		_IOW('j', 0x21, struct js_corr)			/* set correction values */
+#define JSIOCGCORR		_IOR('j', 0x22, struct js_corr)			/* get correction values */
+
+#define JSIOCSAXMAP		_IOW('j', 0x31, __u8[ABS_MAX])			/* set axis mapping */
+#define JSIOCGAXMAP		_IOR('j', 0x32, __u8[ABS_MAX])			/* get axis mapping */
+#define JSIOCSBTNMAP		_IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC])	/* set button mapping */
+#define JSIOCGBTNMAP		_IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC])	/* get button mapping */
 
 /*
  * Types and constants for get/set correction
diff -u --recursive --new-file v2.4.3/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.4.3/linux/include/linux/kernel.h	Mon Dec 11 12:49:54 2000
+++ linux/include/linux/kernel.h	Thu Apr 12 12:25:53 2001
@@ -62,7 +62,7 @@
 extern int vsprintf(char *buf, const char *, va_list);
 extern int get_option(char **str, int *pint);
 extern char *get_options(char *str, int nints, int *ints);
-extern unsigned long memparse(char *ptr, char **retptr);
+extern unsigned long long memparse(char *ptr, char **retptr);
 extern void dev_probe_lock(void);
 extern void dev_probe_unlock(void);
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/major.h linux/include/linux/major.h
--- v2.4.3/linux/include/linux/major.h	Sat Dec 30 11:23:14 2000
+++ linux/include/linux/major.h	Thu Apr 12 12:20:31 2001
@@ -128,6 +128,8 @@
 #define IDE8_MAJOR	90
 #define IDE9_MAJOR	91
 
+#define UBD_MAJOR	98
+
 #define AURORA_MAJOR 79
 
 #define JSFD_MAJOR	99
@@ -155,6 +157,9 @@
 #define CPUID_MAJOR		203
 
 #define OSST_MAJOR	206	/* OnStream-SCx0 SCSI tape */
+
+#define IBM_TTY3270_MAJOR       227	/* Official allocations now */
+#define IBM_FS3270_MAJOR        228
 
 /*
  * Tests for SCSI devices.
diff -u --recursive --new-file v2.4.3/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v2.4.3/linux/include/linux/miscdevice.h	Mon Mar 26 15:48:22 2001
+++ linux/include/linux/miscdevice.h	Wed Apr 25 16:23:14 2001
@@ -21,6 +21,7 @@
 #define NVRAM_MINOR 144
 #define I2O_MINOR 166
 #define MICROCODE_MINOR		184
+#define MPT_MINOR	220
 #define MISC_DYNAMIC_MINOR 255
 
 #define SGI_GRAPHICS_MINOR   146
diff -u --recursive --new-file v2.4.3/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.4.3/linux/include/linux/mm.h	Mon Mar 26 15:48:13 2001
+++ linux/include/linux/mm.h	Wed Apr 25 16:21:42 2001
@@ -434,7 +434,8 @@
 extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void build_mmap_avl(struct mm_struct *);
 extern void exit_mmap(struct mm_struct *);
-extern unsigned long get_unmapped_area(unsigned long, unsigned long);
+
+extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
 extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 	unsigned long len, unsigned long prot,
diff -u --recursive --new-file v2.4.3/linux/include/linux/mroute.h linux/include/linux/mroute.h
--- v2.4.3/linux/include/linux/mroute.h	Mon Mar 26 15:48:59 2001
+++ linux/include/linux/mroute.h	Wed Apr 25 16:21:39 2001
@@ -215,8 +215,8 @@
 	__u32	flags;
 };
 
-extern int pim_rcv(struct sk_buff * , unsigned short);
-extern int pim_rcv_v1(struct sk_buff * , unsigned short len);
+extern int pim_rcv(struct sk_buff *);
+extern int pim_rcv_v1(struct sk_buff *);
 
 struct rtmsg;
 extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
diff -u --recursive --new-file v2.4.3/linux/include/linux/nbd.h linux/include/linux/nbd.h
--- v2.4.3/linux/include/linux/nbd.h	Mon Dec 11 12:50:42 2000
+++ linux/include/linux/nbd.h	Wed Apr 11 19:02:30 2001
@@ -31,35 +31,27 @@
 extern int requests_out;
 #endif
 
-static int 
+static void
 nbd_end_request(struct request *req)
 {
+	struct buffer_head *bh;
+	unsigned nsect;
 	unsigned long flags;
-	int ret = 0;
+	int uptodate = (req->errors == 0) ? 1 : 0;
 
 #ifdef PARANOIA
 	requests_out++;
 #endif
-	/*
-	 * This is a very dirty hack that we have to do to handle
-	 * merged requests because end_request stuff is a bit
-	 * broken. The fact we have to do this only if there
-	 * aren't errors looks even more silly.
-	 */
-	if (!req->errors) {
-		req->sector += req->current_nr_sectors;
-		req->nr_sectors -= req->current_nr_sectors;
-	}
-
 	spin_lock_irqsave(&io_request_lock, flags);
-	if (end_that_request_first( req, !req->errors, "nbd" ))
-		goto out;
-	ret = 1;
-	end_that_request_last( req );
-
-out:
+	while((bh = req->bh) != NULL) {
+		nsect = bh->b_size >> 9;
+		blk_finished_io(nsect);
+		req->bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		bh->b_end_io(bh, uptodate);
+	}
+	blkdev_release_request(req);
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	return ret;
 }
 
 #define MAX_NBD 128
diff -u --recursive --new-file v2.4.3/linux/include/linux/net.h linux/include/linux/net.h
--- v2.4.3/linux/include/linux/net.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/net.h	Wed Apr 25 16:21:33 2001
@@ -82,6 +82,7 @@
 
 struct scm_cookie;
 struct vm_area_struct;
+struct page;
 
 struct proto_ops {
   int	family;
@@ -108,6 +109,7 @@
   int   (*sendmsg)	(struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
   int   (*recvmsg)	(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
   int	(*mmap)		(struct file *file, struct socket *sock, struct vm_area_struct * vma);
+  ssize_t (*sendpage)	(struct socket *sock, struct page *page, int offset, size_t size, int flags);
 };
 
 struct net_proto_family 
diff -u --recursive --new-file v2.4.3/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.4.3/linux/include/linux/netdevice.h	Mon Mar 26 15:48:19 2001
+++ linux/include/linux/netdevice.h	Wed Apr 25 16:22:00 2001
@@ -565,7 +565,7 @@
 
 static inline void dev_init_buffers(struct net_device *dev)
 {
-	/* DO NOTHING */
+	/* WILL BE REMOVED IN 2.5.0 */
 }
 
 extern int netdev_finish_unregister(struct net_device *dev);
@@ -653,6 +653,7 @@
 extern unsigned long	netdev_fc_xoff;
 extern atomic_t netdev_dropping;
 extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
+extern struct sk_buff * skb_checksum_help(struct sk_buff *skb);
 #ifdef CONFIG_NET_FASTROUTE
 extern int		netdev_fastroute;
 extern int		netdev_fastroute_obstacles;
diff -u --recursive --new-file v2.4.3/linux/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
--- v2.4.3/linux/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Jan  1 10:37:41 2001
+++ linux/include/linux/netfilter_ipv4/ip_conntrack.h	Wed Apr 25 15:00:28 2001
@@ -84,12 +84,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 #endif
 
-#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE)
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat_ftp.h>
-#endif
-#endif
 
 struct ip_conntrack
 {
@@ -127,18 +122,14 @@
 	} proto;
 
 	union {
-#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE)
 		struct ip_ct_ftp ct_ftp_info;
-#endif
 	} help;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 	struct {
 		struct ip_nat_info info;
 		union {
-#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE)
-			struct ip_nat_ftp_info ftp_info[IP_CT_DIR_MAX];
-#endif
+			/* insert nat helper private data here */
 		} help;
 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
 	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
diff -u --recursive --new-file v2.4.3/linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- v2.4.3/linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Mon Dec 11 13:31:23 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Wed Apr 25 15:00:28 2001
@@ -14,9 +14,13 @@
 enum ip_ct_ftp_type
 {
 	/* PORT command from client */
-	IP_CT_FTP_PORT = IP_CT_DIR_ORIGINAL,
+	IP_CT_FTP_PORT,
 	/* PASV response from server */
-	IP_CT_FTP_PASV = IP_CT_DIR_REPLY
+	IP_CT_FTP_PASV,
+	/* EPRT command from client */
+	IP_CT_FTP_EPRT,
+	/* EPSV response from server */
+	IP_CT_FTP_EPSV,
 };
 
 /* We record seq number and length of ftp ip/port text here: all in
diff -u --recursive --new-file v2.4.3/linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h
--- v2.4.3/linux/include/linux/netfilter_ipv4/ip_nat.h	Mon Dec 11 13:31:23 2000
+++ linux/include/linux/netfilter_ipv4/ip_nat.h	Wed Apr 25 15:00:28 2001
@@ -24,6 +24,15 @@
 /* Used internally by get_unique_tuple(). */
 #define IP_NAT_RANGE_FULL 4
 
+/* NAT sequence number modifications */
+struct ip_nat_seq {
+	/* position of the last TCP sequence number 
+	 * modification (if any) */
+	u_int32_t correction_pos;
+	/* sequence number offset before and after last modification */
+	int32_t offset_before, offset_after;
+};
+
 /* Single range specification. */
 struct ip_nat_range
 {
@@ -98,6 +107,8 @@
 
 	/* Helper (NULL if none). */
 	struct ip_nat_helper *helper;
+
+	struct ip_nat_seq seq[IP_CT_DIR_MAX];
 };
 
 /* Set up the info structure to map into this range. */
diff -u --recursive --new-file v2.4.3/linux/include/linux/netfilter_ipv4/ip_nat_ftp.h linux/include/linux/netfilter_ipv4/ip_nat_ftp.h
--- v2.4.3/linux/include/linux/netfilter_ipv4/ip_nat_ftp.h	Fri Mar 17 10:56:20 2000
+++ linux/include/linux/netfilter_ipv4/ip_nat_ftp.h	Wed Dec 31 16:00:00 1969
@@ -1,21 +0,0 @@
-#ifndef _IP_NAT_FTP_H
-#define _IP_NAT_FTP_H
-/* FTP extension for TCP NAT alteration. */
-
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
-
-/* Protects ftp part of conntracks */
-DECLARE_LOCK_EXTERN(ip_ftp_lock);
-
-/* We keep track of where the last SYN correction was, and the SYN
-   offsets before and after that correction.  Two of these (indexed by
-   direction). */
-struct ip_nat_ftp_info
-{
-	u_int32_t syn_correction_pos;                              
-	int32_t syn_offset_before, syn_offset_after; 
-};
-
-#endif /* _IP_NAT_FTP_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/netfilter_ipv4/ip_nat_helper.h linux/include/linux/netfilter_ipv4/ip_nat_helper.h
--- v2.4.3/linux/include/linux/netfilter_ipv4/ip_nat_helper.h	Mon Dec 11 13:31:32 2000
+++ linux/include/linux/netfilter_ipv4/ip_nat_helper.h	Wed Apr 25 15:00:28 2001
@@ -25,6 +25,19 @@
 	const char *name;
 };
 
+extern struct list_head helpers;
+
 extern int ip_nat_helper_register(struct ip_nat_helper *me);
 extern void ip_nat_helper_unregister(struct ip_nat_helper *me);
+extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
+				struct ip_conntrack *ct,
+				enum ip_conntrack_info ctinfo,
+				unsigned int match_offset,
+				unsigned int match_len,
+				char *rep_buffer,
+				unsigned int rep_len);
+extern int ip_nat_seq_adjust(struct sk_buff *skb,
+				struct ip_conntrack *ct,
+				enum ip_conntrack_info ctinfo);
+extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph);
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.4.3/linux/include/linux/nfs_fs.h	Mon Mar 26 15:48:42 2001
+++ linux/include/linux/nfs_fs.h	Wed Apr 25 16:22:39 2001
@@ -137,7 +137,6 @@
  * linux/fs/nfs/inode.c
  */
 extern struct super_block *nfs_read_super(struct super_block *, void *, int);
-extern int init_nfs_fs(void);
 extern void nfs_zap_caches(struct inode *);
 extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
 				struct nfs_fattr *);
diff -u --recursive --new-file v2.4.3/linux/include/linux/ntfs_fs_i.h linux/include/linux/ntfs_fs_i.h
--- v2.4.3/linux/include/linux/ntfs_fs_i.h	Thu Feb 10 12:17:00 2000
+++ linux/include/linux/ntfs_fs_i.h	Wed Apr 18 11:49:12 2001
@@ -60,24 +60,23 @@
 typedef unsigned int ntfs_cluster_t;
 #endif
 
-/* Definition of NTFS in-memory inode structure */
+/* Definition of the NTFS in-memory inode structure. */
 struct ntfs_inode_info{
 	unsigned long mmu_private;
 	struct ntfs_sb_info *vol;
-	int i_number;                /* should be really 48 bits */
-	unsigned sequence_number;
-	unsigned char* attr;         /* array of the attributes */
-	int attr_count;              /* size of attrs[] */
+	int i_number;                /* Should be really 48 bits. */
+	__u16 sequence_number;	     /* The current sequence number. */
+	unsigned char* attr;         /* Array of the attributes. */
+	int attr_count;              /* Size of attrs[]. */
 	struct ntfs_attribute *attrs;
-	int record_count;            /* size of records[] */
-	/* array of the record numbers of the MFT 
-	   whose attributes have been inserted in the inode */
-	int *records;
-	union{
-		struct{
+	int record_count;            /* Size of records[]. */
+	int *records; /* Array of the record numbers of the $Mft whose 
+		       * attributes have been inserted in the inode. */
+	union {
+		struct {
 			int recordsize;
 			int clusters_per_record;
-		}index;
+		} index;
 	} u;	
 };
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/ntfs_fs_sb.h linux/include/linux/ntfs_fs_sb.h
--- v2.4.3/linux/include/linux/ntfs_fs_sb.h	Tue May  2 13:46:53 2000
+++ linux/include/linux/ntfs_fs_sb.h	Wed Apr 18 11:49:12 2001
@@ -2,16 +2,17 @@
 #define _LINUX_NTFS_FS_SB_H
 
 struct ntfs_sb_info{
-	/* Configuration provided by user at mount time */
+	/* Configuration provided by user at mount time. */
 	ntfs_uid_t uid;
 	ntfs_gid_t gid;
 	ntmode_t umask;
         unsigned int nct;
 	void *nls_map;
 	unsigned int ngt;
-	/* Configuration provided by user with ntfstools */
-	ntfs_size_t partition_bias;	/* for access to underlying device */
-	/* Attribute definitions */
+	/* Configuration provided by user with the ntfstools.
+	 * FIXME: This is no longer possible. What is this good for? (AIA) */
+	ntfs_size_t partition_bias;	/* For access to underlying device. */
+	/* Attribute definitions. */
 	ntfs_u32 at_standard_information;
 	ntfs_u32 at_attribute_list;
 	ntfs_u32 at_file_name;
@@ -24,20 +25,20 @@
 	ntfs_u32 at_index_allocation;
 	ntfs_u32 at_bitmap;
 	ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */
-	/* Data read from the boot file */
+	/* Data read / calculated from the boot file. */
 	int blocksize;
-	int clusterfactor;
+	int clusterfactorbits;
 	int clustersize;
 	int mft_recordsize;
 	int mft_clusters_per_record;
 	int index_recordsize;
 	int index_clusters_per_record;
 	int mft_cluster;
-	/* data read from special files */
+	/* Data read from special files. */
 	unsigned char *mft;
 	unsigned short *upcase;
 	unsigned int upcase_length;
-	/* inodes we always hold onto */
+	/* Inodes we always hold onto. */
 	struct ntfs_inode_info *mft_ino;
 	struct ntfs_inode_info *mftmirr;
 	struct ntfs_inode_info *bitmap;
diff -u --recursive --new-file v2.4.3/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.4.3/linux/include/linux/pagemap.h	Mon Mar 26 15:48:15 2001
+++ linux/include/linux/pagemap.h	Wed Apr 25 16:21:47 2001
@@ -77,7 +77,12 @@
 				unsigned long index, struct page **hash);
 extern void lock_page(struct page *page);
 #define find_lock_page(mapping, index) \
-		__find_lock_page(mapping, index, page_hash(mapping, index))
+	__find_lock_page(mapping, index, page_hash(mapping, index))
+
+extern struct page * __find_get_swapcache_page (struct address_space * mapping,
+				unsigned long index, struct page **hash);
+#define find_get_swapcache_page(mapping, index) \
+	__find_get_swapcache_page(mapping, index, page_hash(mapping, index))
 
 extern void __add_page_to_hash_queue(struct page * page, struct page **p);
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.4.3/linux/include/linux/pci.h	Mon Mar 26 15:48:46 2001
+++ linux/include/linux/pci.h	Wed Apr 25 16:22:38 2001
@@ -525,7 +525,9 @@
 int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 
+#define HAVE_PCI_DISABLE_DEVICE
 int pci_enable_device(struct pci_dev *dev);
+void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask);
 int pci_set_power_state(struct pci_dev *dev, int state);
@@ -552,6 +554,14 @@
 struct pci_driver *pci_dev_driver(const struct pci_dev *);
 const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
 
+/* kmem_cache style wrapper around pci_alloc_consistent() */
+struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
+		size_t size, size_t align, size_t allocation, int flags);
+void pci_pool_destroy (struct pci_pool *pool);
+
+void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle);
+void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
+
 #endif /* CONFIG_PCI */
 
 /* Include architecture-dependent settings and functions */
@@ -594,6 +604,7 @@
 
 static inline void pci_set_master(struct pci_dev *dev) { }
 static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
+static inline void pci_disable_device(struct pci_dev *dev) { }
 static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; }
 static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
 static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
diff -u --recursive --new-file v2.4.3/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.3/linux/include/linux/pci_ids.h	Sun Mar 25 18:14:20 2001
+++ linux/include/linux/pci_ids.h	Wed Apr 18 14:40:06 2001
@@ -174,14 +174,62 @@
 #define PCI_DEVICE_ID_ATI_215LG		0x4c47
 #define PCI_DEVICE_ID_ATI_264LT		0x4c54
 #define PCI_DEVICE_ID_ATI_264VT		0x5654
+/* Rage128 Pro GL */
+#define PCI_DEVICE_ID_ATI_Rage128_PA	0x5041
+#define PCI_DEVICE_ID_ATI_Rage128_PB	0x5042
+#define PCI_DEVICE_ID_ATI_Rage128_PC	0x5043
+#define PCI_DEVICE_ID_ATI_Rage128_PD	0x5044
+#define PCI_DEVICE_ID_ATI_Rage128_PE	0x5045
+#define PCI_DEVICE_ID_ATI_RAGE128_PF	0x5046
+/* Rage128 Pro VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_PG	0x5047
+#define PCI_DEVICE_ID_ATI_RAGE128_PH	0x5048
+#define PCI_DEVICE_ID_ATI_RAGE128_PI	0x5049
+#define PCI_DEVICE_ID_ATI_RAGE128_PJ	0x504A
+#define PCI_DEVICE_ID_ATI_RAGE128_PK	0x504B
+#define PCI_DEVICE_ID_ATI_RAGE128_PL	0x504C
+#define PCI_DEVICE_ID_ATI_RAGE128_PM	0x504D
+#define PCI_DEVICE_ID_ATI_RAGE128_PN	0x504E
+#define PCI_DEVICE_ID_ATI_RAGE128_PO	0x504F
+#define PCI_DEVICE_ID_ATI_RAGE128_PP	0x5050
+#define PCI_DEVICE_ID_ATI_RAGE128_PQ	0x5051
+#define PCI_DEVICE_ID_ATI_RAGE128_PR	0x5052
+#define PCI_DEVICE_ID_ATI_RAGE128_PS	0x5053
+#define PCI_DEVICE_ID_ATI_RAGE128_PT	0x5054
+#define PCI_DEVICE_ID_ATI_RAGE128_PU	0x5055
+#define PCI_DEVICE_ID_ATI_RAGE128_PV	0x5056
+#define PCI_DEVICE_ID_ATI_RAGE128_PW	0x5057
+#define PCI_DEVICE_ID_ATI_RAGE128_PX	0x5058
+/* Rage128 GL */
 #define PCI_DEVICE_ID_ATI_RAGE128_RE	0x5245
 #define PCI_DEVICE_ID_ATI_RAGE128_RF	0x5246
+#define PCI_DEVICE_ID_ATI_RAGE128_RG	0x534b
+#define PCI_DEVICE_ID_ATI_RAGE128_RH	0x534c
+#define PCI_DEVICE_ID_ATI_RAGE128_RI	0x534d
+/* Rage128 VR */
 #define PCI_DEVICE_ID_ATI_RAGE128_RK	0x524b
 #define PCI_DEVICE_ID_ATI_RAGE128_RL	0x524c
-#define PCI_DEVICE_ID_ATI_RAGE128_PF	0x5046
-#define PCI_DEVICE_ID_ATI_RAGE128_PR	0x5052
+#define PCI_DEVICE_ID_ATI_RAGE128_RM	0x5345
+#define PCI_DEVICE_ID_ATI_RAGE128_RN	0x5346
+#define PCI_DEVICE_ID_ATI_RAGE128_RO	0x5347
+/* Rage128 M3 */
 #define PCI_DEVICE_ID_ATI_RAGE128_LE	0x4c45
 #define PCI_DEVICE_ID_ATI_RAGE128_LF	0x4c46
+/* Rage128 Pro Ultra */
+#define PCI_DEVICE_ID_ATI_RAGE128_U1	0x5446
+#define PCI_DEVICE_ID_ATI_RAGE128_U2	0x544C
+#define PCI_DEVICE_ID_ATI_RAGE128_U3	0x5452
+/* Radeon M4 */
+#define PCI_DEVICE_ID_ATI_RADEON_LE	0x4d45
+#define PCI_DEVICE_ID_ATI_RADEON_LF	0x4d46
+/* Radeon NV-100 */
+#define PCI_DEVICE_ID_ATI_RADEON_N1	0x5159
+#define PCI_DEVICE_ID_ATI_RADEON_N2	0x515a
+/* Radeon */
+#define PCI_DEVICE_ID_ATI_RADEON_RA	0x5144
+#define PCI_DEVICE_ID_ATI_RADEON_RB	0x5145
+#define PCI_DEVICE_ID_ATI_RADEON_RC	0x5146
+#define PCI_DEVICE_ID_ATI_RADEON_RD	0x5147
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
@@ -376,8 +424,15 @@
 #define PCI_DEVICE_ID_SI_7001		0x7001
 
 #define PCI_VENDOR_ID_HP		0x103c
+#define PCI_DEVICE_ID_HP_DONNER_GFX	0x1008
+#define PCI_DEVICE_ID_HP_TACHYON	0x1028
+#define PCI_DEVICE_ID_HP_TACHLITE	0x1029
 #define PCI_DEVICE_ID_HP_J2585A		0x1030
 #define PCI_DEVICE_ID_HP_J2585B		0x1031
+#define PCI_DEVICE_ID_HP_SAS		0x1048
+#define PCI_DEVICE_ID_HP_DIVA1		0x1049
+#define PCI_DEVICE_ID_HP_DIVA2		0x104A
+#define PCI_DEVICE_ID_HP_SP2_0		0x104B
 
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
@@ -408,6 +463,10 @@
 #define PCI_DEVICE_ID_ELSA_MICROLINK	0x1000
 #define PCI_DEVICE_ID_ELSA_QS3000	0x3000
 
+#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
@@ -658,6 +717,11 @@
 #define PCI_DEVICE_ID_AL_M1531		0x1531
 #define PCI_DEVICE_ID_AL_M1533		0x1533
 #define PCI_DEVICE_ID_AL_M1541		0x1541
+#define PCI_DEVICE_ID_AL_M1621          0x1621
+#define PCI_DEVICE_ID_AL_M1631          0x1631
+#define PCI_DEVICE_ID_AL_M1641          0x1641
+#define PCI_DEVICE_ID_AL_M1647          0x1647
+#define PCI_DEVICE_ID_AL_M1651          0x1651
 #define PCI_DEVICE_ID_AL_M1543		0x1543
 #define PCI_DEVICE_ID_AL_M3307		0x3307
 #define PCI_DEVICE_ID_AL_M4803		0x5215
@@ -811,6 +875,9 @@
 #define PCI_DEVICE_ID_VIA_8633_1	0xB091
 #define PCI_DEVICE_ID_VIA_8367_1	0xB099
 
+#define PCI_VENDOR_ID_SIEMENS           0x110A
+#define PCI_DEVICE_ID_SIEMENS_DSCC4     0x2102
+
 #define PCI_VENDOR_ID_SMC2		0x1113
 #define PCI_DEVICE_ID_SMC2_1211TX	0x1211
 
@@ -962,6 +1029,10 @@
 #define PCI_VENDOR_ID_OMEGA		0x119b
 #define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
 
+#define PCI_VENDOR_ID_FUJITSU_ME	0x119e
+#define PCI_DEVICE_ID_FUJITSU_FS155	0x0001
+#define PCI_DEVICE_ID_FUJITSU_FS50	0x0003
+
 #define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
 #define PCI_SUBDEVICE_ID_KEYSPAN_SX2	0x5334
 
@@ -993,6 +1064,9 @@
 #define PCI_VENDOR_ID_AURAVISION	0x11d1
 #define PCI_DEVICE_ID_AURAVISION_VXP524	0x01f7
 
+#define PCI_VENDOR_ID_ANALOG_DEVICES	0x11d4
+#define PCI_DEVICE_ID_AD1889JS		0x1889
+
 #define PCI_VENDOR_ID_IKON		0x11d5
 #define PCI_DEVICE_ID_IKON_10115	0x0115
 #define PCI_DEVICE_ID_IKON_10117	0x0117
@@ -1087,7 +1161,8 @@
 #define PCI_DEVICE_ID_HUGHES_DIRECPC	0x0002
 
 #define PCI_VENDOR_ID_ENSONIQ		0x1274
-#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI	0x5000
+#define PCI_DEVICE_ID_ENSONIQ_CT5880	0x5880
+#define PCI_DEVICE_ID_ENSONIQ_ES1370	0x5000
 #define PCI_DEVICE_ID_ENSONIQ_ES1371	0x1371
 
 #define PCI_VENDOR_ID_ROCKWELL		0x127A
@@ -1345,6 +1420,7 @@
 
 #define PCI_VENDOR_ID_DCI		0x6666
 #define PCI_DEVICE_ID_DCI_PCCOM4	0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8	0x0002
 
 #define PCI_VENDOR_ID_GENROCO		0x5555
 #define PCI_DEVICE_ID_GENROCO_HFP832	0x0003
diff -u --recursive --new-file v2.4.3/linux/include/linux/pipe_fs_i.h linux/include/linux/pipe_fs_i.h
--- v2.4.3/linux/include/linux/pipe_fs_i.h	Mon May  8 11:17:47 2000
+++ linux/include/linux/pipe_fs_i.h	Wed Apr 25 14:18:23 2001
@@ -5,6 +5,7 @@
 struct pipe_inode_info {
 	wait_queue_head_t wait;
 	char *base;
+	unsigned int len;
 	unsigned int start;
 	unsigned int readers;
 	unsigned int writers;
@@ -22,7 +23,7 @@
 #define PIPE_WAIT(inode)	(&(inode).i_pipe->wait)
 #define PIPE_BASE(inode)	((inode).i_pipe->base)
 #define PIPE_START(inode)	((inode).i_pipe->start)
-#define PIPE_LEN(inode)		((inode).i_size)
+#define PIPE_LEN(inode)		((inode).i_pipe->len)
 #define PIPE_READERS(inode)	((inode).i_pipe->readers)
 #define PIPE_WRITERS(inode)	((inode).i_pipe->writers)
 #define PIPE_WAITING_READERS(inode)	((inode).i_pipe->waiting_readers)
diff -u --recursive --new-file v2.4.3/linux/include/linux/ppp_channel.h linux/include/linux/ppp_channel.h
--- v2.4.3/linux/include/linux/ppp_channel.h	Mon Mar 26 15:48:19 2001
+++ linux/include/linux/ppp_channel.h	Wed Apr 25 16:22:01 2001
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/poll.h>
-#include <asm/atomic.h>
 
 struct ppp_channel;
 
@@ -32,7 +31,6 @@
 	int	(*start_xmit)(struct ppp_channel *, struct sk_buff *);
 	/* Handle an ioctl call that has come in via /dev/ppp. */
 	int	(*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
-	
 };
 
 struct ppp_channel {
@@ -78,16 +76,6 @@
  * in the start_xmit and ioctl routines for the channel by the time
  * that ppp_unregister_channel returns.
  */
-
-/* The following are temporary compatibility stuff */
-ssize_t ppp_channel_read(struct ppp_channel *chan, struct file *file,
-			 char *buf, size_t count);
-ssize_t ppp_channel_write(struct ppp_channel *chan, const char *buf,
-			  size_t count);
-unsigned int ppp_channel_poll(struct ppp_channel *chan, struct file *file,
-			      poll_table *wait);
-int ppp_channel_ioctl(struct ppp_channel *chan, unsigned int cmd,
-		      unsigned long arg);
 
 #endif /* __KERNEL__ */
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.4.3/linux/include/linux/proc_fs.h	Mon Mar 26 15:48:15 2001
+++ linux/include/linux/proc_fs.h	Wed Apr 25 16:21:47 2001
@@ -117,6 +117,7 @@
 /*
  * proc_tty.c
  */
+struct tty_driver;
 extern void proc_tty_init(void);
 extern void proc_tty_register_driver(struct tty_driver *driver);
 extern void proc_tty_unregister_driver(struct tty_driver *driver);
@@ -132,7 +133,7 @@
 		struct proc_dir_entry *,kdev_t);
 extern struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *);
 
-extern inline struct proc_dir_entry *create_proc_read_entry(const char *name,
+static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *base, 
 	read_proc_t *read_proc, void * data)
 {
@@ -144,7 +145,7 @@
 	return res;
 }
  
-extern inline struct proc_dir_entry *create_proc_info_entry(const char *name,
+static inline struct proc_dir_entry *create_proc_info_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
 {
 	struct proc_dir_entry *res=create_proc_entry(name,mode,base);
@@ -152,44 +153,44 @@
 	return res;
 }
  
-extern inline struct proc_dir_entry *proc_net_create(const char *name,
+static inline struct proc_dir_entry *proc_net_create(const char *name,
 	mode_t mode, get_info_t *get_info)
 {
 	return create_proc_info_entry(name,mode,proc_net,get_info);
 }
 
-extern inline void proc_net_remove(const char *name)
+static inline void proc_net_remove(const char *name)
 {
 	remove_proc_entry(name,proc_net);
 }
 
 #else
 
-extern inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, 
+static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, 
 	get_info_t *get_info) {return NULL;}
-extern inline void proc_net_remove(const char *name) {}
+static inline void proc_net_remove(const char *name) {}
 
-extern inline struct proc_dir_entry *create_proc_entry(const char *name,
+static inline struct proc_dir_entry *create_proc_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *parent) { return NULL; }
 
-extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {};
-extern inline struct proc_dir_entry *proc_symlink(const char *name,
+static inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {};
+static inline struct proc_dir_entry *proc_symlink(const char *name,
 		struct proc_dir_entry *parent,char *dest) {return NULL;}
-extern inline struct proc_dir_entry *proc_mknod(const char *name,mode_t mode,
+static inline struct proc_dir_entry *proc_mknod(const char *name,mode_t mode,
 		struct proc_dir_entry *parent,kdev_t rdev) {return NULL;}
-extern inline struct proc_dir_entry *proc_mkdir(const char *name,
+static inline struct proc_dir_entry *proc_mkdir(const char *name,
 	struct proc_dir_entry *parent) {return NULL;}
 
-extern inline struct proc_dir_entry *create_proc_read_entry(const char *name,
+static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *base, 
 	int (*read_proc)(char *, char **, off_t, int, int *, void *),
 	void * data) { return NULL; }
-extern inline struct proc_dir_entry *create_proc_info_entry(const char *name,
+static inline struct proc_dir_entry *create_proc_info_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
 	{ return NULL; }
 
-extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
-extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
+static inline void proc_tty_register_driver(struct tty_driver *driver) {};
+static inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
 extern struct proc_dir_entry proc_root;
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/rwsem-spinlock.h linux/include/linux/rwsem-spinlock.h
--- v2.4.3/linux/include/linux/rwsem-spinlock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/rwsem-spinlock.h	Wed Apr 25 16:21:32 2001
@@ -0,0 +1,62 @@
+/* rwsem-spinlock.h: fallback C implementation
+ *
+ * Copyright (c) 2001   David Howells (dhowells@redhat.com).
+ * - Derived partially from ideas by Andrea Arcangeli <andrea@suse.de>
+ * - Derived also from comments by Linus
+ */
+
+#ifndef _LINUX_RWSEM_SPINLOCK_H
+#define _LINUX_RWSEM_SPINLOCK_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem-spinlock.h directly, use linux/rwsem.h instead
+#endif
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+
+struct rwsem_waiter;
+
+/*
+ * the rw-semaphore definition
+ * - if activity is 0 then there are no active readers or writers
+ * - if activity is +ve then that is the number of active readers
+ * - if activity is -1 then there is one active writer
+ * - if wait_list is not empty, then there are processes waiting for the semaphore
+ */
+struct rw_semaphore {
+	__s32			activity;
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+#if RWSEM_DEBUG
+	int			debug;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+{ 0, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern void FASTCALL(init_rwsem(struct rw_semaphore *sem));
+extern void FASTCALL(__down_read(struct rw_semaphore *sem));
+extern void FASTCALL(__down_write(struct rw_semaphore *sem));
+extern void FASTCALL(__up_read(struct rw_semaphore *sem));
+extern void FASTCALL(__up_write(struct rw_semaphore *sem));
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_RWSEM_SPINLOCK_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/rwsem.h linux/include/linux/rwsem.h
--- v2.4.3/linux/include/linux/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/rwsem.h	Wed Apr 25 16:21:34 2001
@@ -0,0 +1,79 @@
+/* rwsem.h: R/W semaphores, public interface
+ *
+ * Written by David Howells (dhowells@redhat.com).
+ * Derived from asm-i386/semaphore.h
+ */
+
+#ifndef _LINUX_RWSEM_H
+#define _LINUX_RWSEM_H
+
+#include <linux/linkage.h>
+
+#define RWSEM_DEBUG 0
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+struct rw_semaphore;
+
+#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
+#include <linux/rwsem-spinlock.h> /* use a generic implementation */
+#else
+#include <asm/rwsem.h> /* use an arch-specific implementation */
+#endif
+
+#ifndef rwsemtrace
+#if RWSEM_DEBUG
+extern void FASTCALL(rwsemtrace(struct rw_semaphore *sem, const char *str));
+#else
+#define rwsemtrace(SEM,FMT)
+#endif
+#endif
+
+/*
+ * lock for reading
+ */
+static inline void down_read(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering down_read");
+	__down_read(sem);
+	rwsemtrace(sem,"Leaving down_read");
+}
+
+/*
+ * lock for writing
+ */
+static inline void down_write(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering down_write");
+	__down_write(sem);
+	rwsemtrace(sem,"Leaving down_write");
+}
+
+/*
+ * release a read lock
+ */
+static inline void up_read(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering up_read");
+	__up_read(sem);
+	rwsemtrace(sem,"Leaving up_read");
+}
+
+/*
+ * release a write lock
+ */
+static inline void up_write(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering up_write");
+	__up_write(sem);
+	rwsemtrace(sem,"Leaving up_write");
+}
+
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_RWSEM_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/scc.h linux/include/linux/scc.h
--- v2.4.3/linux/include/linux/scc.h	Thu Jan  4 12:50:12 2001
+++ linux/include/linux/scc.h	Thu Apr 12 12:20:31 2001
@@ -213,8 +213,6 @@
 /* SCC channel structure */
 
 struct scc_channel {
-	int magic;			/* magic word */
-
 	int init;			/* channel exists? */
 
 	struct net_device *dev;		/* link to device control structure */
diff -u --recursive --new-file v2.4.3/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.4.3/linux/include/linux/sched.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/sched.h	Wed Apr 25 16:21:42 2001
@@ -239,7 +239,7 @@
 	mm_users:	ATOMIC_INIT(2), 		\
 	mm_count:	ATOMIC_INIT(1), 		\
 	map_count:	1, 				\
-	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem, RW_LOCK_BIAS), \
+	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
 	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
 	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
 }
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_asy.h linux/include/linux/sdla_asy.h
--- v2.4.3/linux/include/linux/sdla_asy.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/sdla_asy.h	Thu Apr 12 12:11:39 2001
@@ -0,0 +1,226 @@
+/*****************************************************************************
+* sdla_asy.h	Header file for the Sangoma S508/S514 asynchronous code API	
+*
+* Author: 	Gideon Hack 	
+*
+* Copyright:	(c) 2000 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+*
+* Jan 28, 2000	Gideon Hack 	Initial Version
+*
+*****************************************************************************/
+
+
+#ifndef _WANPIPE_ASYNC_H
+#define _WANPIPE_ASYNC_H
+
+/* ----------------------------------------------------------------------------
+ *                        Interface commands
+ * --------------------------------------------------------------------------*/
+
+#define SET_ASY_CONFIGURATION		0xE2	/* set the asychronous operational configuration */
+#define READ_ASY_CONFIGURATION		0xE3	/* read the current asychronous operational configuration */
+#define ENABLE_ASY_COMMUNICATIONS	0xE4	/* enable asychronous communications */
+#define DISABLE_ASY_COMMUNICATIONS	0xE5	/* disable asychronous communications */
+#define READ_ASY_OPERATIONAL_STATS	0xE7	/* retrieve the asychronous operational statistics */
+#define FLUSH_ASY_OPERATIONAL_STATS	0xE8	/* flush the asychronous operational statistics */
+#define TRANSMIT_ASY_BREAK_SIGNAL	0xEC	/* transmit an asychronous break signal */
+
+
+
+/* ----------------------------------------------------------------------------
+ *                     Return codes from interface commands
+ * --------------------------------------------------------------------------*/
+
+#define COMMAND_INVALID_FOR_PORT	0x50	/* the command is invalid for the selected port */
+#define DISABLE_ASY_COMMS_BEFORE_CFG 	0xE1	/* communications must be disabled before setting the configuration */
+#define ASY_COMMS_ENABLED		0xE1	/* communications are currently enabled */
+#define ASY_COMMS_DISABLED		0xE1	/* communications are currently disabled */
+#define ASY_CFG_BEFORE_COMMS_ENABLED	0xE2	/* perform a SET_ASY_CONFIGURATION before enabling comms */
+#define LGTH_ASY_CFG_DATA_INVALID  	0xE2	/* the length of the passed configuration data is invalid */
+#define INVALID_ASY_CFG_DATA		0xE3	/* the passed configuration data is invalid */
+#define ASY_BREAK_SIGNAL_BUSY		0xEC	/* a break signal is being transmitted */
+
+
+
+/* ----------------------------------------------------------------------------
+ *   Constants for the SET_ASY_CONFIGURATION/READ_ASY_CONFIGURATION command
+ * --------------------------------------------------------------------------*/
+
+/* the asynchronous configuration structure */
+typedef struct {
+	unsigned long baud_rate			PACKED;							/* the baud rate */	
+	unsigned short line_config_options	PACKED;	/* line configuration options */
+	unsigned short modem_config_options	PACKED;	/* modem configuration options */
+	unsigned short asy_API_options		PACKED;	/* asynchronous API options */
+	unsigned short asy_protocol_options	PACKED; /* asynchronous protocol options */
+	unsigned short Tx_bits_per_char		PACKED;	/* number of bits per tx character */
+	unsigned short Rx_bits_per_char		PACKED;	/* number of bits per received character */
+	unsigned short stop_bits		PACKED;	/* number of stop bits per character */
+	unsigned short parity			PACKED;	/* parity definition */
+	unsigned short break_timer		PACKED;	/* the break signal timer */
+	unsigned short asy_Rx_inter_char_timer	PACKED;	/* the receive inter-character timer */
+	unsigned short asy_Rx_complete_length	PACKED;	/* the receive 'buffer complete' length */
+	unsigned short XON_char			PACKED;	/* the XON character */
+	unsigned short XOFF_char		PACKED;	/* the XOFF character */
+	unsigned short asy_statistics_options	PACKED;	/* async operational stat options */
+	unsigned long ptr_shared_mem_info_struct    PACKED;/* ptr to the shared memory area information structure */
+	unsigned long ptr_asy_Tx_stat_el_cfg_struct PACKED;/* ptr to the transmit status element configuration structure */
+	unsigned long ptr_asy_Rx_stat_el_cfg_struct PACKED;/* ptr to the receive status element configuration structure */
+} ASY_CONFIGURATION_STRUCT;
+
+/* permitted minimum and maximum values for setting the asynchronous configuration */
+#define MIN_ASY_BAUD_RATE		50	/* maximum baud rate */
+#define MAX_ASY_BAUD_RATE		250000	/* minimum baud rate */
+#define MIN_ASY_BITS_PER_CHAR		5	/* minimum number of bits per character */
+#define MAX_ASY_BITS_PER_CHAR		8	/* maximum number of bits per character */
+#define MIN_BREAK_TMR_VAL		0	/* minimum break signal timer */
+#define MAX_BREAK_TMR_VAL		5000	/* maximum break signal timer */
+#define MIN_ASY_RX_INTER_CHAR_TMR	0	/* minimum receive inter-character timer */
+#define MAX_ASY_RX_INTER_CHAR_TMR	30000	/* maximum receive inter-character timer */
+#define MIN_ASY_RX_CPLT_LENGTH		0	/* minimum receive 'length complete' value */
+#define MAX_ASY_RX_CPLT_LENGTH		2000	/* maximum receive 'length complete' value */
+
+/* bit settings for the 'asy_API_options' */
+#define ASY_RX_DATA_TRANSPARENT		0x0001	/* do not strip parity and unused bits from received characters */
+
+/* bit settings for the 'asy_protocol_options' */
+#define ASY_RTS_HS_FOR_RX		0x0001	/* RTS handshaking is used for reception control */
+#define ASY_XON_XOFF_HS_FOR_RX		0x0002	/* XON/XOFF handshaking is used for reception control */
+#define ASY_XON_XOFF_HS_FOR_TX		0x0004	/* XON/XOFF handshaking is used for transmission control */
+#define ASY_DCD_HS_FOR_TX		0x0008	/* DCD handshaking is used for transmission control */
+#define ASY_CTS_HS_FOR_TX		0x0020	/* CTS handshaking is used for transmission control */
+
+/* bit settings for the 'stop_bits' definition */
+#define ONE_STOP_BIT			1			/* representation for 1 stop bit */
+#define TWO_STOP_BITS			2			/* representation for 2 stop bits */
+#define ONE_AND_A_HALF_STOP_BITS	3			/* representation for 1.5 stop bits */
+
+/* bit settings for the 'parity' definition */
+#define NO_PARITY			0			/* representation for no parity */
+#define ODD_PARITY			1			/* representation for odd parity */
+#define EVEN_PARITY			2			/* representation for even parity */
+
+
+
+/* ----------------------------------------------------------------------------
+ *    Constants for the READ_COMMS_ERROR_STATS command (asynchronous mode)
+ * --------------------------------------------------------------------------*/
+
+/* the communications error statistics structure */
+typedef struct {
+	unsigned short Rx_overrun_err_count   	PACKED;	/* receiver overrun error count */
+	unsigned short Rx_parity_err_count	PACKED;	/* parity errors received count */
+	unsigned short Rx_framing_err_count	PACKED;	/* framing errors received count */
+	unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later use */
+	unsigned short comms_err_stat_reserved_2 PACKED;/* reserved for later use */
+	unsigned short comms_err_stat_reserved_3 PACKED;/* reserved for later use */
+	unsigned short comms_err_stat_reserved_4 PACKED;/* reserved for later use */
+	unsigned short comms_err_stat_reserved_5 PACKED;/* reserved for later use */
+	unsigned short DCD_state_change_count 	PACKED;	/* DCD state change count */
+	unsigned short CTS_state_change_count	PACKED;	/* CTS state change count */
+} ASY_COMMS_ERROR_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *         Constants for the READ_ASY_OPERATIONAL_STATS command
+ * --------------------------------------------------------------------------*/
+
+/* the asynchronous operational statistics structure */
+typedef struct {
+
+	/* Data transmission statistics */
+	unsigned long Data_blocks_Tx_count PACKED;/* number of blocks transmitted */
+	unsigned long Data_bytes_Tx_count  PACKED;/* number of bytes transmitted */
+	unsigned long Data_Tx_throughput   PACKED;/* transmit throughput */
+	unsigned long no_ms_for_Data_Tx_thruput_comp PACKED;/* millisecond time used for the Tx throughput computation */
+	unsigned long Tx_Data_discard_lgth_err_count PACKED;/* number of Data blocks discarded (length error) */
+	unsigned long reserved_Data_frm_Tx_stat1 PACKED;/* reserved for later use */
+	unsigned long reserved_Data_frm_Tx_stat2 PACKED;/* reserved for later use */
+	unsigned long reserved_Data_frm_Tx_stat3 PACKED;/* reserved for later use */
+
+	/* Data reception statistics */
+	unsigned long Data_blocks_Rx_count PACKED;/* number of blocks received */
+	unsigned long Data_bytes_Rx_count  PACKED;/* number of bytes received */
+	unsigned long Data_Rx_throughput   PACKED;/* receive throughput */
+	unsigned long no_ms_for_Data_Rx_thruput_comp PACKED;/* millisecond time used for the Rx throughput computation */
+	unsigned long Rx_Data_bytes_discard_count    PACKED;/* received Data bytes discarded */
+	unsigned long reserved_Data_frm_Rx_stat1     PACKED;/* reserved for later use */
+
+	/* handshaking protocol statistics */
+	unsigned short XON_chars_Tx_count	PACKED;	/* number of XON characters transmitted */
+	unsigned short XOFF_chars_Tx_count	PACKED;	/* number of XOFF characters transmitted */
+	unsigned short XON_chars_Rx_count	PACKED;	/* number of XON characters received */
+	unsigned short XOFF_chars_Rx_count	PACKED;	/* number of XOFF characters received */
+	unsigned short Tx_halt_modem_low_count	PACKED; /* number of times Tx halted (modem line low) */
+	unsigned short Rx_halt_RTS_low_count	PACKED;	/* number of times Rx halted by setting RTS low */
+	unsigned long reserved_handshaking_stat1 PACKED;/* reserved for later use */
+
+	/* break statistics */
+	unsigned short break_Tx_count	PACKED;	/* number of break sequences transmitted */
+	unsigned short break_Rx_count	PACKED;	/* number of break sequences received */
+	unsigned long reserved_break_stat1 PACKED;/* reserved for later use */
+
+	/* miscellaneous statistics */
+	unsigned long reserved_misc_stat1	PACKED;	/* reserved for later use */
+	unsigned long reserved_misc_stat2	PACKED;	/* reserved for later use */
+
+} ASY_OPERATIONAL_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *                      Constants for Data transmission
+ * --------------------------------------------------------------------------*/
+
+/* the Data block transmit status element configuration structure */
+typedef struct {
+	unsigned short number_Tx_status_elements PACKED;		/* number of transmit status elements */
+	unsigned long base_addr_Tx_status_elements PACKED;	/* base address of the transmit element list */
+	unsigned long next_Tx_status_element_to_use PACKED;	/* pointer to the next transmit element to be used */
+} ASY_TX_STATUS_EL_CFG_STRUCT;
+
+
+/* the Data block transmit status element structure */
+typedef struct {
+	unsigned char opp_flag PACKED;								/* opp flag */
+	unsigned short data_length PACKED;						/* length of the block to be transmitted */
+	unsigned char reserved_1 PACKED;							/* reserved for internal use */
+	unsigned long reserved_2 PACKED;							/* reserved for internal use */
+	unsigned long reserved_3 PACKED;							/* reserved for internal use */
+	unsigned long ptr_data_bfr PACKED;						/* pointer to the data area */
+} ASY_DATA_TX_STATUS_EL_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *                      Constants for Data reception
+ * --------------------------------------------------------------------------*/
+
+/* the Data block receive status element configuration structure */
+typedef struct {
+	unsigned short number_Rx_status_elements    PACKED;/* number of receive status elements */
+	unsigned long base_addr_Rx_status_elements  PACKED;/* base address of the receive element list */
+	unsigned long next_Rx_status_element_to_use PACKED;/* pointer to the next receive element to be used */
+	unsigned long base_addr_Rx_buffer	PACKED;/* base address of the receive data buffer */
+	unsigned long end_addr_Rx_buffer 	PACKED;/* end address of the receive data buffer */
+} ASY_RX_STATUS_EL_CFG_STRUCT;
+
+/* the Data block receive status element structure */
+typedef struct {
+	unsigned char opp_flag 		PACKED;	/* opp flag */
+	unsigned short data_length 	PACKED;	/* length of the received data block */
+	unsigned char reserved_1 	PACKED;	/* reserved for internal use */
+	unsigned short time_stamp 	PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */
+	unsigned short data_buffered 	PACKED;	/* the number of data bytes still buffered */
+	unsigned long reserved_2 	PACKED;	/* reserved for internal use */
+	unsigned long ptr_data_bfr 	PACKED;	/* pointer to the data area */
+} ASY_DATA_RX_STATUS_EL_STRUCT;
+
+#endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_chdlc.h linux/include/linux/sdla_chdlc.h
--- v2.4.3/linux/include/linux/sdla_chdlc.h	Wed Jan 26 13:25:58 2000
+++ linux/include/linux/sdla_chdlc.h	Thu Apr 12 12:11:39 2001
@@ -4,7 +4,7 @@
  Author:      	Gideon Hack
 		Nenad Corbic <ncorbic@sangoma.com>	
 
- Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+ Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 
 		This program is free software; you can redistribute it and/or
 		modify it under the term of the GNU General Public License
@@ -137,6 +137,8 @@
 #define TRACE_PROT			0x01
 #define TRACE_DATA			0x02
 
+#define DISCARD_RX_ERROR_FRAMES	0x0001
+
 /* ----------------------------------------------------------------------------
  *                     Return codes from interface commands
  * --------------------------------------------------------------------------*/
@@ -358,6 +360,9 @@
 #define IGNORE_KPALV_FOR_LINK_STAT		0x0004
 /* ignore keepalive frames in determining the CHDLC link status */ 
 
+#define SINGLE_TX_BUFFER			0x4000 
+/* configure a single transmit buffer */
+
 #define HDLC_STREAMING_MODE			0x8000
 
 /*   settings for the 'CHDLC_statistics_options' */
@@ -469,7 +474,7 @@
 	unsigned long reserved_CDP_stat5 PACKED;		/* reserved for later */
 	unsigned long reserved_CDP_stat6 PACKED;		/* reserved for later */
 
-	/* Incomming frames with a format error statistics */
+	/* Incoming frames with a format error statistics */
 	unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED;	/* frames received of with incomplete Cisco HDLC header */
 	unsigned short Rx_frms_too_long_count PACKED;		/* frames received of excessive length count */
 	unsigned short Rx_invalid_CHDLC_addr_count PACKED;	/* frames received with an invalid CHDLC address count */
@@ -484,7 +489,7 @@
 	unsigned long reserved_frm_format_err4 PACKED;		/* reserved for later */
 
 	/* CHDLC timeout/retry statistics */
-	unsigned short SLARP_Rx_keepalive_TO_count PACKED;	/* timeout count for incomming SLARP frames */
+	unsigned short SLARP_Rx_keepalive_TO_count PACKED;	/* timeout count for incoming SLARP frames */
 	unsigned short SLARP_Request_TO_count PACKED;		/* timeout count for SLARP Request frames */
 	unsigned long To_retry_reserved_stat1 PACKED;		/* reserved for later */
 	unsigned long To_retry_reserved_stat2 PACKED;		/* reserved for later */
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_fr.h linux/include/linux/sdla_fr.h
--- v2.4.3/linux/include/linux/sdla_fr.h	Wed Jan 26 13:25:58 2000
+++ linux/include/linux/sdla_fr.h	Thu Apr 12 12:11:39 2001
@@ -4,7 +4,7 @@
 * Author:       Gideon Hack  	
 *		Nenad Corbic <ncorbic@sangoma.com> 	
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
@@ -541,7 +541,7 @@
 } fr_encap_hdr_t;
 
 typedef struct {
-	fr_encap_hdr_t 		fr_encap_hdr	PACKED;
+//	fr_encap_hdr_t 		fr_encap_hdr	PACKED;
 	ip_pkt_t 		ip_pkt		PACKED;
 	udp_pkt_t		udp_pkt		PACKED;
 	wp_mgmt_t 		wp_mgmt       	PACKED;
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_ppp.h linux/include/linux/sdla_ppp.h
--- v2.4.3/linux/include/linux/sdla_ppp.h	Wed Jan 26 13:25:58 2000
+++ linux/include/linux/sdla_ppp.h	Thu Apr 12 12:11:39 2001
@@ -1,7 +1,7 @@
 /*****************************************************************************
 * sdla_ppp.h	Sangoma PPP firmware API definitions.
 *
-* Author:	Gene Kozin	<74604.152@compuserve.com>
+* Author:	Nenad Corbic	<ncorbic@sangoma.com>
 *
 * Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
 *
@@ -10,6 +10,7 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Feb 24, 2000  Nenad Corbic    v2.1.2
 * Jan 06, 1997	Gene Kozin	v2.0
 * Apr 11, 1996	Gene Kozin	Initial version.
 *****************************************************************************/
@@ -214,7 +215,8 @@
 {
 	unsigned short txb_num	PACKED;	/* 00: number of transmit buffers */
 	unsigned long  txb_ptr	PACKED;	/* 02: pointer to the buffer ctl. */
-	unsigned char  rsrv1[26] PACKED;
+	unsigned long  txb_nxt  PACKED;
+	unsigned char  rsrv1[22] PACKED;
 	unsigned short rxb_num	PACKED;	/* 20: number of receive buffers */
 	unsigned long  rxb_ptr	PACKED;	/* 22: pointer to the buffer ctl. */
 	unsigned long  rxb1_ptr	PACKED;	/* 26: pointer to the first buf.ctl. */
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_x25.h linux/include/linux/sdla_x25.h
--- v2.4.3/linux/include/linux/sdla_x25.h	Wed Jun 24 14:34:44 1998
+++ linux/include/linux/sdla_x25.h	Thu Apr 12 12:11:39 2001
@@ -1,15 +1,16 @@
 /*****************************************************************************
 * sdla_x25.h	Sangoma X.25 firmware API definitions.
 *
-* Author:	Gene Kozin	<74604.152@compuserve.com>
+* Author:	Nenad Corbic	<ncorbic@sangoma.com>
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
+		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Feb 28, 2000  Nenad Corbic    Updated for socket based x25api
 * Dec 13, 1996	Gene Kozin	Initial version
 *****************************************************************************/
 #ifndef	_SDLA_X25_H
@@ -18,39 +19,35 @@
 /*----------------------------------------------------------------------------
  * Notes:
  * ------
- * 1. All structures defined in this file are byte-aligned.  To ensure
- *    portability of this code between different platforms and compilers, one
- *    of the following defines must be defined before including this file:
- *
- *	Compiler	Platform	Define		Use option
- *	--------	--------	------		----------
- *	GNU C		Linux		_GNUC_		-
- *	Microsoft C	DOS/Windows	_MSC_		-
+ * 1. All structures defined in this file are byte-alined.  
+ *	Compiler	Platform	
+ *	--------	--------
+ *	GNU C		Linux
  *
  */
 
-#ifdef		_GNUC_
-#  ifndef	PACKED
-#    define	PACKED	__attribute__((packed))
-#  endif	/* PACKED */
-#else
-#  define	PACKED
-#endif
-#ifdef		_MSC_
-#  pragma	pack(1)
-#endif
+#ifndef	PACKED
+#	define	PACKED	__attribute__((packed))
+#endif	/* PACKED */
 
 /******	CONSTANTS DEFINITIONS ***********************************************/
 
 #define	X25_MAX_CHAN	255	/* max number of open X.25 circuits */
 #define	X25_MAX_DATA	1024	/* max length of X.25 data buffer */
-
 /*
  * X.25 shared memory layout.
  */
 #define	X25_MBOX_OFFS	0x16B0	/* general mailbox block */
 #define	X25_RXMBOX_OFFS	0x1AD0	/* receive mailbox */
 #define	X25_STATUS_OFFS	0x1EF0	/* X.25 status structure */
+#define X25_MB_VECTOR	0xE000	/* S514 mailbox window vecotr */
+#define X25_MISC_HDLC_BITS 0x1F00 /*X.25 miscallaneous HDLC bits */
+
+/* code levels */
+#define HDLC_LEVEL 0x01
+#define X25_LEVEL  0x02
+#define X25_AND_HDLC_LEVEL 0x03
+#define DO_HDLC_LEVEL_ERROR_CHECKING 0x04
 
 /****** DATA STRUCTURES *****************************************************/
 
@@ -100,11 +97,12 @@
 #define X25_HDLC_READ		0x21	/* read HDLC information frame */
 #define X25_HDLC_READ_CONFIG	0x12	/* read HDLC configuration */
 #define X25_HDLC_SET_CONFIG	0x13	/* set HDLC configuration */
+#define SET_PROTOCOL_LEVEL	0x1F	/* set protocol level */
 /*----- X.25-level commands -----------*/
 #define X25_READ		0x22	/* read X.25 packet */
 #define X25_WRITE		0x23	/* send X.25 packet */
 #define X25_PLACE_CALL		0x30	/* place a call on SVC */
-#define X25_ACCEPT_CALL		0x31	/* accept incoming call */
+#define X25_ACCEPT_CALL		0x31	/* accept incomming call */
 #define X25_CLEAR_CALL		0x32	/* clear call */
 #define X25_CLEAR_CONFRM	0x33	/* send clear confirmation packet */
 #define X25_RESET		0x34	/* send reset request packet */
@@ -116,14 +114,14 @@
 #define X25_REGISTRATION_RQST	0x3A	/* send registration request packet */
 #define X25_REGISTRATION_CONFRM	0x3B	/* send registration confirmation */
 #define X25_IS_DATA_AVAILABLE	0x40	/* querry receive queue */
-#define X25_INCOMING_CALL_CTL	0x41	/* select incoming call options */
+#define X25_INCOMMING_CALL_CTL	0x41	/* select incomming call options */
 #define X25_CONFIGURE_PVC	0x42	/* configure PVC */
 #define X25_GET_ACTIVE_CHANNELS	0x43	/* get a list of active circuits */
 #define X25_READ_CHANNEL_CONFIG	0x44	/* read virt. circuit configuration */
 #define X25_FLUSH_DATA_BUFFERS	0x45	/* flush X.25-level data buffers */
 #define X25_READ_HISTORY_TABLE	0x46	/* read asynchronous event log */
 #define X25_HISTORY_TABLE_CTL	0x47	/* control asynchronous event log */
-#define	X25_GET_TX_D_BIT_STATUS	0x48	/* is packet with D-bit acknowledged */
+#define	X25_GET_TX_D_BIT_STATUS	0x48	/* is packet with D-bit acknowleged */
 #define	X25_READ_STATISTICS	0x49	/* read X.25-level statistics */
 #define	X25_FLUSH_STATISTICS	0x4A	/* flush X.25-level statistics */
 #define	X25_READ_CONFIGURATION	0x50	/* read HDLC & X.25 configuration */
@@ -139,7 +137,7 @@
 #define X25RES_LINK_CLOSED	0x03
 #define X25RES_INVAL_LENGTH	0x04
 #define X25RES_INVAL_CMD	0x05
-#define X25RES_UNNUMBERED_FRAME	0x06	/* unnumbered frame received */
+#define X25RES_UNNUMBERED_FRAME	0x06	/* unnunbered frame received */
 #define X25RES_FRM_REJECT_MODE	0x07	/* link is in Frame Reject mode */
 #define X25RES_MODEM_FAILURE	0x08	/* DCD and/or CTS dropped */
 #define X25RES_N2_RETRY_LIMIT	0x09	/* N2 retry limit has been exceeded */
@@ -153,13 +151,13 @@
 #define X25RES_INVAL_FORMAT	0x37	/* invalid packet format */
 #define X25RES_D_BIT_NOT_SUPPRT	0x38	/* D-bit pragmatics not supported */
 #define X25RES_FACIL_NOT_SUPPRT	0x39	/* Call facility not supported */
-#define X25RES_INVAL_CALL_ARG	0x3A	/* erroneous call arguments */
-#define X25RES_INVAL_CALL_DATA	0x3B	/* erroneous call user data */
+#define X25RES_INVAL_CALL_ARG	0x3A	/* errorneous call arguments */
+#define X25RES_INVAL_CALL_DATA	0x3B	/* errorneous call user data */
 #define X25RES_ASYNC_PACKET	0x40	/* asynchronous packet received */
-#define X25RES_PROTO_VIOLATION	0x41	/* protocol violation occurred */
+#define X25RES_PROTO_VIOLATION	0x41	/* protocol violation occured */
 #define X25RES_PKT_TIMEOUT	0x42	/* X.25 packet time out */
 #define X25RES_PKT_RETRY_LIMIT	0x43	/* X.25 packet retry limit exceeded */
-/*----- Command-dependent results -----*/
+/*----- Command-dependant results -----*/
 #define X25RES_LINK_DISC	0x00	/* HDLC_LINK_STATUS */
 #define X25RES_LINK_IN_ABM	0x01	/* HDLC_LINK_STATUS */
 #define X25RES_NO_DATA		0x01	/* HDLC_READ/READ_TRACE_DATA*/
@@ -167,7 +165,7 @@
 #define X25RES_LINK_IS_OPEN	0x01	/* HDLC_LINK_OPEN */
 #define X25RES_LINK_IS_DISC	0x02	/* HDLC_LINK_DISC */
 #define X25RES_LINK_IS_CLOSED	0x03	/* HDLC_LINK_CLOSE */
-#define X25RES_INVAL_PARAM	0x31	/* INCOMING_CALL_CTL */
+#define X25RES_INVAL_PARAM	0x31	/* INCOMMING_CALL_CTL */
 #define X25RES_INVAL_CONFIG	0x35	/* REGISTR_RQST/CONFRM */
 
 /*
@@ -207,6 +205,22 @@
 #define PVE_RESTART_RQST	0x34
 #define PVE_DIAGNOSTIC		0x37
 
+#define INTR_ON_RX_FRAME            0x01
+#define INTR_ON_TX_FRAME            0x02
+#define INTR_ON_MODEM_STATUS_CHANGE 0x04
+#define INTR_ON_COMMAND_COMPLETE    0x08
+#define INTR_ON_X25_ASY_TRANSACTION 0x10
+#define INTR_ON_TIMER		    0x40
+#define DIRECT_RX_INTR_USAGE        0x80
+
+#define NO_INTR_PENDING  	        0x00
+#define RX_INTR_PENDING			0x01	
+#define TX_INTR_PENDING			0x02
+#define MODEM_INTR_PENDING		0x04
+#define COMMAND_COMPLETE_INTR_PENDING 	0x08
+#define X25_ASY_TRANS_INTR_PENDING	0x10
+#define TIMER_INTR_PENDING		0x40
+
 /*----------------------------------------------------------------------------
  * X.25 Mailbox.
  *	This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS
@@ -239,7 +253,7 @@
 typedef struct X25Status
 {
 	unsigned short pvc_map	PACKED;	/* 00h: PVC map */
-	unsigned short icc_map	PACKED;	/* 02h: Incoming Chan. map */
+	unsigned short icc_map	PACKED;	/* 02h: Incomming Chan. map */
 	unsigned short twc_map	PACKED;	/* 04h: Two-way Cnan. map */
 	unsigned short ogc_map	PACKED;	/* 06h: Outgoing Chan. map */
 	TX25TimeStamp tstamp	PACKED;	/* 08h: timestamp (BCD) */
@@ -256,7 +270,7 @@
 #define X25_RX_INTR	0x01	/* receive interrupt */
 #define X25_TX_INTR	0x02	/* transmit interrupt */
 #define X25_MODEM_INTR	0x04	/* modem status interrupt (CTS/DCD) */
-#define X25_EVENT_INTR	0x10	/* asynchronous event encountered */
+#define X25_EVENT_INTR	0x10	/* asyncronous event encountered */
 #define X25_CMD_INTR	0x08	/* interface command complete */
 
 /*
@@ -374,7 +388,7 @@
  */
 typedef struct X25Config
 {
-	unsigned char baudRate		PACKED;	/* 00h:  */
+unsigned char baudRate		PACKED;	/* 00h:  */
 	unsigned char t1		PACKED;	/* 01h:  */
 	unsigned char t2		PACKED;	/* 02h:  */
 	unsigned char n2		PACKED;	/* 03h:  */
@@ -390,8 +404,8 @@
 	unsigned short pktMTU		PACKED;	/* 0Fh:  */
 	unsigned short loPVC		PACKED;	/* 11h:  */
 	unsigned short hiPVC		PACKED;	/* 13h:  */
-	unsigned short loIncomingSVC	PACKED;	/* 15h:  */
-	unsigned short hiIncomingSVC	PACKED;	/* 17h:  */
+	unsigned short loIncommingSVC	PACKED;	/* 15h:  */
+	unsigned short hiIncommingSVC	PACKED;	/* 17h:  */
 	unsigned short loTwoWaySVC	PACKED;	/* 19h:  */
 	unsigned short hiTwoWaySVC	PACKED;	/* 1Bh:  */
 	unsigned short loOutgoingSVC	PACKED;	/* 1Dh:  */
@@ -421,8 +435,8 @@
 {
 	unsigned short loPVC		PACKED;	/* 00h: lowest PVC number */
 	unsigned short hiPVC		PACKED;	/* 02h: highest PVC number */
-	unsigned short loIncomingSVC	PACKED;	/* 04h: lowest incoming SVC */
-	unsigned short hiIncomingSVC	PACKED;	/* 06h: highest incoming SVC */
+	unsigned short loIncommingSVC	PACKED;	/* 04h: lowest incoming SVC */
+	unsigned short hiIncommingSVC	PACKED;	/* 06h: highest incoming SVC */
 	unsigned short loTwoWaySVC	PACKED;	/* 08h: lowest two-way SVC */
 	unsigned short hiTwoWaySVC	PACKED;	/* 0Ah: highest two-way SVC */
 	unsigned short loOutgoingSVC	PACKED;	/* 0Ch: lowest outgoing SVC */
@@ -499,7 +513,7 @@
 /*
  * Defines for the 'type' field.
  */
-#define X25LOG_INCOMING		0x00
+#define X25LOG_INCOMMING	0x00
 #define X25LOG_APPLICATION 	0x01
 #define X25LOG_AUTOMATIC	0x02
 #define X25LOG_ERROR		0x04
@@ -568,7 +582,7 @@
 #define X25_TRCERR_RX_BADCRC	0x20	/* receive CRC error */
 #define X25_TRCERR_RX_OVERRUN	0x30	/* receiver overrun error */
 #define X25_TRCERR_RX_TOO_LONG	0x40	/* excessive frame length error */
-#define X25_TRCERR_TX_ABORT	0x70	/* aborted frame transmission error */
+#define X25_TRCERR_TX_ABORT	0x70	/* aborted frame transmittion error */
 #define X25_TRCERR_TX_UNDERRUN	0x80	/* transmit underrun error */
 
 /*****************************************************************************
@@ -582,7 +596,7 @@
 	unsigned char data[0]	PACKED;
 } THDLCFrame;
 
-typedef struct X25Pkt			/*----- X.25 Packet Format ----------*/
+typedef struct X25Pkt			/*----- X.25 Paket Format ----------*/
 {
 	unsigned char lcn_hi	PACKED;	/* 4 MSB of Logical Channel Number */
 	unsigned char lcn_lo	PACKED;	/* 8 LSB of Logical Channel Number */
@@ -619,7 +633,140 @@
 #define	X25PKT_RR_MASKED	0x01	/* Receive Ready packet after masking */
 #define	X25PKT_RNR_MASKED	0x05	/* Receive Not Ready after masking  */
 
-#ifdef		_MSC_
-#  pragma	pack()
-#endif
+
+typedef struct {
+	TX25Cmd cmd		PACKED;
+	char data[X25_MAX_DATA]	PACKED;
+} mbox_cmd_t;
+
+
+typedef struct {
+	unsigned char  qdm	PACKED;	/* Q/D/M bits */
+	unsigned char  cause	PACKED;	/* cause field */
+	unsigned char  diagn	PACKED;	/* diagnostics */
+	unsigned char  pktType  PACKED;
+	unsigned short length   PACKED;
+	unsigned char  result	PACKED;
+	unsigned short lcn	PACKED;
+	char reserved[7]	PACKED;
+}x25api_hdr_t;
+
+
+typedef struct {
+	x25api_hdr_t hdr	PACKED;
+	char data[X25_MAX_DATA]	PACKED;
+}x25api_t;
+
+
+/* 
+ * XPIPEMON Definitions
+ */
+
+/* valid ip_protocol for UDP management */
+#define UDPMGMT_UDP_PROTOCOL 0x11
+#define UDPMGMT_XPIPE_SIGNATURE         "XLINK8ND"
+#define UDPMGMT_DRVRSTATS_SIGNATURE     "DRVSTATS"
+
+/* values for request/reply byte */
+#define UDPMGMT_REQUEST	0x01
+#define UDPMGMT_REPLY	0x02
+#define UDP_OFFSET	12
+
+
+typedef struct {
+	unsigned char opp_flag  PACKED; /* the opp flag */
+	unsigned char command	PACKED;	/* command code */
+	unsigned short length	PACKED;	/* transfer data length */
+	unsigned char result	PACKED;	/* return code */
+	unsigned char pf	PACKED;	/* P/F bit */
+	unsigned short lcn	PACKED;	/* logical channel */
+	unsigned char qdm	PACKED;	/* Q/D/M bits */
+	unsigned char cause	PACKED;	/* cause field */
+	unsigned char diagn	PACKED;	/* diagnostics */
+	unsigned char pktType	PACKED;	/* packet type */
+	unsigned char resrv[4]	PACKED;	/* reserved */
+} cblock_t;
+
+typedef struct {
+	ip_pkt_t 		ip_pkt		PACKED;
+	udp_pkt_t		udp_pkt		PACKED;
+	wp_mgmt_t 		wp_mgmt       	PACKED;
+        cblock_t                cblock          PACKED;
+        unsigned char           data[4080]      PACKED;
+} x25_udp_pkt_t;
+
+
+typedef struct read_hdlc_stat {
+	unsigned short inf_frames_rx_ok PACKED;
+        unsigned short inf_frames_rx_out_of_seq PACKED;
+	unsigned short inf_frames_rx_no_data PACKED;
+	unsigned short inf_frames_rx_dropped PACKED;
+	unsigned short inf_frames_rx_data_too_long PACKED;
+	unsigned short inf_frames_rx_invalid_addr PACKED;
+	unsigned short inf_frames_tx_ok PACKED;
+        unsigned short inf_frames_tx_retransmit PACKED;
+       	unsigned short T1_timeouts PACKED;
+	unsigned short SABM_frames_rx PACKED;
+	unsigned short DISC_frames_rx PACKED;
+	unsigned short DM_frames_rx PACKED;
+	unsigned short FRMR_frames_rx PACKED;
+	unsigned short SABM_frames_tx PACKED;
+	unsigned short DISC_frames_tx PACKED;
+	unsigned short DM_frames_tx PACKED;
+	unsigned short FRMR_frames_tx PACKED;
+} read_hdlc_stat_t;
+
+typedef struct read_comms_err_stats{
+	unsigned char overrun_err_rx PACKED;
+	unsigned char CRC_err PACKED;
+	unsigned char abort_frames_rx PACKED;
+	unsigned char frames_dropped_buf_full PACKED;
+	unsigned char abort_frames_tx PACKED;
+	unsigned char transmit_underruns PACKED;
+	unsigned char missed_tx_underruns_intr PACKED;
+	unsigned char reserved PACKED;
+	unsigned char DCD_drop PACKED;
+	unsigned char CTS_drop PACKED;
+} read_comms_err_stats_t;
+
+typedef struct trace_data {
+	unsigned short length PACKED;
+	unsigned char  type PACKED;
+	unsigned char  trace_dropped PACKED;
+	unsigned char  reserved[5] PACKED;
+	unsigned short timestamp PACKED;
+        unsigned char  data PACKED;
+} trace_data_t;
+
+enum {UDP_XPIPE_TYPE};
+
+#define XPIPE_ENABLE_TRACING                    0x14
+#define XPIPE_DISABLE_TRACING                   0x14
+#define XPIPE_GET_TRACE_INFO                    0x16
+#define XPIPE_FT1_READ_STATUS                   0x74
+#define XPIPE_DRIVER_STAT_IFSEND                0x75
+#define XPIPE_DRIVER_STAT_INTR                  0x76
+#define XPIPE_DRIVER_STAT_GEN                   0x77
+#define XPIPE_FLUSH_DRIVER_STATS                0x78
+#define XPIPE_ROUTER_UP_TIME                    0x79        
+#define XPIPE_SET_FT1_MODE			0x81
+#define XPIPE_FT1_STATUS_CTRL			0x80
+
+
+/* error messages */
+#define NO_BUFFS_OR_CLOSED_WIN  0x33
+#define DATA_LENGTH_TOO_BIG     0x32
+#define NO_DATA_AVAILABLE       0x33
+#define Z80_TIMEOUT_ERROR       0x0a   
+#define	NO_BUFFS		0x08
+
+
+/* Trace options */
+#define TRACE_DEFAULT		0x03
+#define TRACE_SUPERVISOR_FRMS	0x10
+#define TRACE_ASYNC_FRMS	0x20
+#define TRACE_ALL_HDLC_FRMS	0x40
+#define TRACE_DATA_FRMS		0x08
+
+
 #endif	/* _SDLA_X25_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdladrv.h linux/include/linux/sdladrv.h
--- v2.4.3/linux/include/linux/sdladrv.h	Mon Dec 11 13:00:00 2000
+++ linux/include/linux/sdladrv.h	Thu Apr 12 12:11:39 2001
@@ -3,7 +3,7 @@
 *
 * Author: 	Gideon Hack	
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
@@ -20,13 +20,21 @@
 #define	_SDLADRV_H
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE >= 0x020100
+
+#ifndef KERNEL_VERSION
+  #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#define LINUX_2_4	
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 #define LINUX_2_1
+#else
+#define LINUX_2_0
 #endif
 
 #define	SDLA_MAXIORANGE	4	/* maximum I/O port range */
 #define	SDLA_WINDOWSIZE	0x2000	/* default dual-port memory window size */
-
 /****** Data Structures *****************************************************/
 
 /*----------------------------------------------------------------------------
@@ -41,7 +49,8 @@
 	int irq;			/* interrupt request level */
 	char S514_cpu_no[1];		/* PCI CPU Number */
 	unsigned char S514_slot_no;	/* PCI Slot Number */
-#ifdef LINUX_2_1
+	char auto_pci_cfg;		/* Autodetect PCI Slot */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct pci_dev *pci_dev;	/* PCI device */
 #else
 	unsigned char pci_bus;		/* PCI bus number */
@@ -73,5 +82,7 @@
 extern int sdla_poke	(sdlahw_t* hw, unsigned long addr, void* buf,
 			 unsigned len);
 extern int sdla_exec	(void* opflag);
+
+extern unsigned wanpipe_hw_probe(void);
 
 #endif	/* _SDLADRV_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/sdlapci.h linux/include/linux/sdlapci.h
--- v2.4.3/linux/include/linux/sdlapci.h	Wed Jan 26 13:25:58 2000
+++ linux/include/linux/sdlapci.h	Thu Apr 12 12:11:39 2001
@@ -4,7 +4,7 @@
 *
 * Author:	Gideon Hack	<ghack@sangoma.com>
 *
-* Copyright:	(c) 1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1999-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
@@ -62,7 +62,11 @@
 #define S514_CPU_START		0x01
 
 /* The maximum number of S514 adapters supported */
-#define MAX_S514_CARDS		8
+#define MAX_S514_CARDS		20	
+
+#define PCI_CARD_TYPE		0x2E
+#define S514_DUAL_CPU		0x12
+#define S514_SINGLE_CPU		0x11
 
 #endif	/* _SDLAPCI_H */
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/serialP.h linux/include/linux/serialP.h
--- v2.4.3/linux/include/linux/serialP.h	Mon Mar 26 15:50:00 2001
+++ linux/include/linux/serialP.h	Wed Apr 25 16:23:23 2001
@@ -181,7 +181,7 @@
 #define SPCI_FL_IRQBASE4       (0x0004 << 4)
 #define SPCI_FL_GET_IRQBASE(x)        ((x & SPCI_FL_IRQ_MASK) >> 4)
 
-/* Use sucessive BARs (PCI base address registers), 
+/* Use successive BARs (PCI base address registers), 
    else use offset into some specified BAR */
 #define SPCI_FL_BASE_TABLE	0x0100
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/serio.h linux/include/linux/serio.h
--- v2.4.3/linux/include/linux/serio.h	Wed Jun 21 08:22:21 2000
+++ linux/include/linux/serio.h	Thu Apr 12 12:20:31 2001
@@ -2,7 +2,7 @@
 #define _SERIO_H
 
 /*
- * $Id: serio.h,v 1.7 2000/06/01 11:39:46 vojtech Exp $
+ * $Id: serio.h,v 1.8 2000/07/17 10:42:14 vojtech Exp $
  *
  * Copyright (C) 1999 Vojtech Pavlik
  *
@@ -103,6 +103,7 @@
 #define SERIO_SPACEBALL	0x1b
 #define SERIO_GUNZE	0x1c
 #define SERIO_IFORCE	0x1d
+#define SERIO_STINGER	0x1e
 
 #define SERIO_ID	0xff00UL
 #define SERIO_EXTRA	0xff0000UL
diff -u --recursive --new-file v2.4.3/linux/include/linux/shmem_fs.h linux/include/linux/shmem_fs.h
--- v2.4.3/linux/include/linux/shmem_fs.h	Fri Dec 29 14:07:24 2000
+++ linux/include/linux/shmem_fs.h	Thu Apr 12 12:25:53 2001
@@ -19,6 +19,7 @@
 
 struct shmem_inode_info {
 	spinlock_t	lock;
+	unsigned long	max_index;
 	swp_entry_t	i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
 	swp_entry_t   **i_indirect; /* doubly indirect blocks */
 	unsigned long	swapped;
diff -u --recursive --new-file v2.4.3/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.4.3/linux/include/linux/skbuff.h	Mon Mar 26 15:48:19 2001
+++ linux/include/linux/skbuff.h	Wed Apr 25 16:21:58 2001
@@ -18,10 +18,13 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/time.h>
+#include <linux/cache.h>
 
 #include <asm/atomic.h>
 #include <asm/types.h>
 #include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
 
 #define HAVE_ALLOC_SKB		/* For the drivers to know */
 #define HAVE_ALIGNABLE_SKB	/* Ditto 8)		   */
@@ -31,6 +34,47 @@
 #define CHECKSUM_HW 1
 #define CHECKSUM_UNNECESSARY 2
 
+#define SKB_DATA_ALIGN(X)	(((X) + (SMP_CACHE_BYTES-1)) & ~(SMP_CACHE_BYTES-1))
+#define SKB_MAX_HEAD(X)		((PAGE_SIZE - (X) - sizeof(struct skb_shared_info))&~(SMP_CACHE_BYTES-1))
+
+/* A. Checksumming of received packets by device.
+ *
+ *	NONE: device failed to checksum this packet.
+ *		skb->csum is undefined.
+ *
+ *	UNNECESSARY: device parsed packet and wouldbe verified checksum.
+ *		skb->csum is undefined.
+ *	      It is bad option, but, unfortunately, many of vendors do this.
+ *	      Apparently with secret goal to sell you new device, when you
+ *	      will add new protocol to your host. F.e. IPv6. 8)
+ *
+ *	HW: the most generic way. Device supplied checksum of _all_
+ *	    the packet as seen by netif_rx in skb->csum.
+ *	    NOTE: Even if device supports only some protocols, but
+ *	    is able to produce some skb->csum, it MUST use HW,
+ *	    not UNNECESSARY.
+ *
+ * B. Checksumming on output.
+ *
+ *	NONE: skb is checksummed by protocol or csum is not required.
+ *
+ *	HW: device is required to csum packet as seen by hard_start_xmit
+ *	from skb->h.raw to the end and to record the checksum
+ *	at skb->h.raw+skb->csum.
+ *
+ *	Device must show its capabilities in dev->features, set
+ *	at device setup time.
+ *	NETIF_F_HW_CSUM	- it is clever device, it is able to checksum
+ *			  everything.
+ *	NETIF_F_NO_CSUM - loopback or reliable single hop media.
+ *	NETIF_F_IP_CSUM - device is dumb. It is able to csum only
+ *			  TCP/UDP over IPv4. Sigh. Vendors like this
+ *			  way by an unknown reason. Though, see comment above
+ *			  about CHECKSUM_UNNECESSARY. 8)
+ *
+ *	Any questions? No questions, good. 		--ANK
+ */
+
 #ifdef __i386__
 #define NET_CALLER(arg) (*(((void**)&arg)-1))
 #else
@@ -57,6 +101,29 @@
 	spinlock_t	lock;
 };
 
+struct sk_buff;
+
+#define MAX_SKB_FRAGS 6
+
+typedef struct skb_frag_struct skb_frag_t;
+
+struct skb_frag_struct
+{
+	struct page *page;
+	__u16 page_offset;
+	__u16 size;
+};
+
+/* This data is invariant across clones and lives at
+ * the end of the header data, ie. at skb->end.
+ */
+struct skb_shared_info {
+	atomic_t	dataref;
+	unsigned int	nr_frags;
+	struct sk_buff	*frag_list;
+	skb_frag_t	frags[MAX_SKB_FRAGS];
+};
+
 struct sk_buff {
 	/* These two members must be first. */
 	struct sk_buff	* next;			/* Next buffer in list 				*/
@@ -107,9 +174,10 @@
 	char		cb[48];	 
 
 	unsigned int 	len;			/* Length of actual data			*/
+ 	unsigned int 	data_len;
 	unsigned int	csum;			/* Checksum 					*/
-	volatile char 	used;			/* Data moved to user and not MSG_PEEK		*/
-	unsigned char	cloned, 		/* head may be cloned (check refcnt to be sure). */
+	unsigned char 	__unused,		/* Dead field, may be reused			*/
+			cloned, 		/* head may be cloned (check refcnt to be sure). */
   			pkt_type,		/* Packet class					*/
   			ip_summed;		/* Driver fed us an IP checksum			*/
 	__u32		priority;		/* Packet queueing priority			*/
@@ -122,6 +190,7 @@
 	unsigned char	*data;			/* Data head pointer				*/
 	unsigned char	*tail;			/* Tail pointer					*/
 	unsigned char 	*end;			/* End pointer					*/
+
 	void 		(*destructor)(struct sk_buff *);	/* Destruct function		*/
 #ifdef CONFIG_NETFILTER
 	/* Can be used for communication between hooks. */
@@ -158,11 +227,13 @@
 #include <asm/system.h>
 
 extern void			__kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *		skb_peek_copy(struct sk_buff_head *list);
 extern struct sk_buff *		alloc_skb(unsigned int size, int priority);
 extern void			kfree_skbmem(struct sk_buff *skb);
 extern struct sk_buff *		skb_clone(struct sk_buff *skb, int priority);
 extern struct sk_buff *		skb_copy(const struct sk_buff *skb, int priority);
+extern struct sk_buff *		pskb_copy(struct sk_buff *skb, int gfp_mask);
+extern int			pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask);
+extern struct sk_buff *		skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom);
 extern struct sk_buff *		skb_copy_expand(const struct sk_buff *skb, 
 						int newheadroom,
 						int newtailroom,
@@ -171,14 +242,8 @@
 extern void	skb_over_panic(struct sk_buff *skb, int len, void *here);
 extern void	skb_under_panic(struct sk_buff *skb, int len, void *here);
 
-/* Backwards compatibility */
-#define skb_realloc_headroom(skb, nhr) skb_copy_expand(skb, nhr, skb_tailroom(skb), GFP_ATOMIC)
-
 /* Internal */
-static inline atomic_t *skb_datarefp(struct sk_buff *skb)
-{
-	return (atomic_t *)(skb->end);
-}
+#define skb_shinfo(SKB)		((struct skb_shared_info *)((SKB)->end))
 
 /**
  *	skb_queue_empty - check if a queue is empty
@@ -243,7 +308,7 @@
 
 static inline int skb_cloned(struct sk_buff *skb)
 {
-	return skb->cloned && atomic_read(skb_datarefp(skb)) != 1;
+	return skb->cloned && atomic_read(&skb_shinfo(skb)->dataref) != 1;
 }
 
 /**
@@ -679,6 +744,20 @@
 	return result;
 }
 
+static inline int skb_is_nonlinear(const struct sk_buff *skb)
+{
+	return skb->data_len;
+}
+
+static inline int skb_headlen(const struct sk_buff *skb)
+{
+	return skb->len - skb->data_len;
+}
+
+#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) BUG(); } while (0)
+#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) BUG(); } while (0)
+#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) BUG(); } while (0)
+
 /*
  *	Add data to an sk_buff
  */
@@ -686,6 +765,7 @@
 static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
 {
 	unsigned char *tmp=skb->tail;
+	SKB_LINEAR_ASSERT(skb);
 	skb->tail+=len;
 	skb->len+=len;
 	return tmp;
@@ -704,6 +784,7 @@
 static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
 {
 	unsigned char *tmp=skb->tail;
+	SKB_LINEAR_ASSERT(skb);
 	skb->tail+=len;
 	skb->len+=len;
 	if(skb->tail>skb->end) {
@@ -742,6 +823,8 @@
 static inline char *__skb_pull(struct sk_buff *skb, unsigned int len)
 {
 	skb->len-=len;
+	if (skb->len < skb->data_len)
+		BUG();
 	return 	skb->data+=len;
 }
 
@@ -763,6 +846,33 @@
 	return __skb_pull(skb,len);
 }
 
+extern unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta);
+
+static inline char *__pskb_pull(struct sk_buff *skb, unsigned int len)
+{
+	if (len > skb_headlen(skb) &&
+	    __pskb_pull_tail(skb, len-skb_headlen(skb)) == NULL)
+		return NULL;
+	skb->len -= len;
+	return 	skb->data += len;
+}
+
+static inline unsigned char * pskb_pull(struct sk_buff *skb, unsigned int len)
+{	
+	if (len > skb->len)
+		return NULL;
+	return __pskb_pull(skb,len);
+}
+
+static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
+{
+	if (len <= skb_headlen(skb))
+		return 1;
+	if (len > skb->len)
+		return 0;
+	return (__pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL);
+}
+
 /**
  *	skb_headroom - bytes at buffer head
  *	@skb: buffer to check
@@ -784,7 +894,7 @@
 
 static inline int skb_tailroom(const struct sk_buff *skb)
 {
-	return skb->end-skb->tail;
+	return skb_is_nonlinear(skb) ? 0 : skb->end-skb->tail;
 }
 
 /**
@@ -802,11 +912,16 @@
 	skb->tail+=len;
 }
 
+extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc);
 
 static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
 {
-	skb->len = len;
-	skb->tail = skb->data+len;
+	if (!skb->data_len) {
+		skb->len = len;
+		skb->tail = skb->data+len;
+	} else {
+		___pskb_trim(skb, len, 0);
+	}
 }
 
 /**
@@ -825,6 +940,25 @@
 	}
 }
 
+
+static inline int __pskb_trim(struct sk_buff *skb, unsigned int len)
+{
+	if (!skb->data_len) {
+		skb->len = len;
+		skb->tail = skb->data+len;
+		return 0;
+	} else {
+		return ___pskb_trim(skb, len, 1);
+	}
+}
+
+static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
+{
+	if (len < skb->len)
+		return __pskb_trim(skb, len);
+	return 0;
+}
+
 /**
  *	skb_orphan - orphan a buffer
  *	@skb: buffer to orphan
@@ -920,32 +1054,57 @@
 }
 
 /**
- *	skb_cow - copy a buffer if need be
- *	@skb: buffer to copy
+ *	skb_cow - copy header of skb when it is required
+ *	@skb: buffer to cow
  *	@headroom: needed headroom
  *
- *	If the buffer passed lacks sufficient headroom or is a clone then
- *	it is copied and the additional headroom made available. If there
- *	is no free memory %NULL is returned. The new buffer is returned if
- *	a copy was made (and the old one dropped a reference). The existing
- *	buffer is returned otherwise.
+ *	If the skb passed lacks sufficient headroom or its data part
+ *	is shared, data is reallocated. If reallocation fails, an error
+ *	is returned and original skb is not changed.
  *
- *	This function primarily exists to avoid making two copies when making
- *	a writable copy of a buffer and then growing the headroom.
+ *	The result is skb with writable area skb->head...skb->tail
+ *	and at least @headroom of space at head.
  */
- 
 
-static inline struct sk_buff *
+static inline int
 skb_cow(struct sk_buff *skb, unsigned int headroom)
 {
-	headroom = (headroom+15)&~15;
+	int delta = headroom - skb_headroom(skb);
 
-	if ((unsigned)skb_headroom(skb) < headroom || skb_cloned(skb)) {
-		struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
-		kfree_skb(skb);
-		skb = skb2;
-	}
-	return skb;
+	if (delta < 0)
+		delta = 0;
+
+	if (delta || skb_cloned(skb))
+		return pskb_expand_head(skb, (delta+15)&~15, 0, GFP_ATOMIC);
+	return 0;
+}
+
+/**
+ *	skb_linearize - convert paged skb to linear one
+ *	@skb: buffer to linarize
+ *	@gfp_mask: allocation mode
+ *
+ *	If there is no free memory -ENOMEM is returned, otherwise zero
+ *	is returned and the old skb data released.  */
+int skb_linearize(struct sk_buff *skb, int gfp);
+
+static inline void *kmap_skb_frag(const skb_frag_t *frag)
+{
+#ifdef CONFIG_HIGHMEM
+	if (in_irq())
+		BUG();
+
+	local_bh_disable();
+#endif
+	return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ);
+}
+
+static inline void kunmap_skb_frag(void *vaddr)
+{
+	kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
+#ifdef CONFIG_HIGHMEM
+	local_bh_enable();
+#endif
 }
 
 #define skb_queue_walk(queue, skb) \
@@ -956,9 +1115,15 @@
 
 extern struct sk_buff *		skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
 extern unsigned int		datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait);
-extern int			skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
-extern int			skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
+extern int			skb_copy_datagram(const struct sk_buff *from, int offset, char *to,int size);
+extern int			skb_copy_datagram_iovec(const struct sk_buff *from, int offset, struct iovec *to,int size);
+extern int			skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump);
+extern int			skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov);
 extern void			skb_free_datagram(struct sock * sk, struct sk_buff *skb);
+
+extern unsigned int		skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum);
+extern int			skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
+extern unsigned int		skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum);
 
 extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
diff -u --recursive --new-file v2.4.3/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.4.3/linux/include/linux/socket.h	Mon Mar 26 15:48:10 2001
+++ linux/include/linux/socket.h	Wed Apr 25 16:21:25 2001
@@ -155,6 +155,7 @@
 #define AF_SNA		22	/* Linux SNA Project (nutters!) */
 #define AF_IRDA		23	/* IRDA sockets			*/
 #define AF_PPPOX	24	/* PPPoX sockets		*/
+#define AF_WANPIPE	25	/* Wanpipe API Sockets */
 #define AF_MAX		32	/* For now.. */
 
 /* Protocol families, same as address families. */
@@ -184,6 +185,7 @@
 #define PF_SNA		AF_SNA
 #define PF_IRDA		AF_IRDA
 #define PF_PPPOX	AF_PPPOX
+#define PF_WANPIPE	AF_WANPIPE
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -209,6 +211,7 @@
 #define MSG_RST		0x1000
 #define MSG_ERRQUEUE	0x2000	/* Fetch message from error queue */
 #define MSG_NOSIGNAL	0x4000	/* Do not generate SIGPIPE */
+#define MSG_MORE	0x8000	/* Sender will send more */
 
 #define MSG_EOF         MSG_FIN
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h
--- v2.4.3/linux/include/linux/sunrpc/sched.h	Mon Mar 26 15:48:29 2001
+++ linux/include/linux/sunrpc/sched.h	Wed Apr 25 16:21:36 2001
@@ -80,7 +80,7 @@
 	unsigned short		tk_lock;	/* Task lock counter */
 	unsigned char		tk_active   : 1,/* Task has been activated */
 				tk_wakeup   : 1;/* Task waiting to wake up */
-	unsigned int		tk_runstate;	/* Task run status */
+	unsigned long		tk_runstate;	/* Task run status */
 #ifdef RPC_DEBUG
 	unsigned short		tk_pid;		/* debugging aid */
 #endif
diff -u --recursive --new-file v2.4.3/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.4.3/linux/include/linux/swap.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/swap.h	Wed Apr 25 16:21:30 2001
@@ -111,8 +111,8 @@
 extern int try_to_free_pages(unsigned int gfp_mask);
 
 /* linux/mm/page_io.c */
-extern void rw_swap_page(int, struct page *, int);
-extern void rw_swap_page_nolock(int, swp_entry_t, char *, int);
+extern void rw_swap_page(int, struct page *);
+extern void rw_swap_page_nolock(int, swp_entry_t, char *);
 
 /* linux/mm/page_alloc.c */
 
@@ -121,8 +121,7 @@
 extern void add_to_swap_cache(struct page *, swp_entry_t);
 extern int swap_check_entry(unsigned long);
 extern struct page * lookup_swap_cache(swp_entry_t);
-extern struct page * read_swap_cache_async(swp_entry_t, int);
-#define read_swap_cache(entry) read_swap_cache_async(entry, 1);
+extern struct page * read_swap_cache_async(swp_entry_t);
 
 /* linux/mm/oom_kill.c */
 extern int out_of_memory(void);
@@ -134,7 +133,6 @@
 extern void __delete_from_swap_cache(struct page *page);
 extern void delete_from_swap_cache(struct page *page);
 extern void delete_from_swap_cache_nolock(struct page *page);
-extern void free_page_and_swap_cache(struct page *page);
 
 /* linux/mm/swapfile.c */
 extern unsigned int nr_swapfiles;
@@ -166,23 +164,6 @@
 extern unsigned long swap_cache_find_total;
 extern unsigned long swap_cache_find_success;
 #endif
-
-/*
- * Work out if there are any other processes sharing this page, ignoring
- * any page reference coming from the swap cache, or from outstanding
- * swap IO on this page.  (The page cache _does_ count as another valid
- * reference to the page, however.)
- */
-static inline int is_page_shared(struct page *page)
-{
-	unsigned int count;
-	if (PageReserved(page))
-		return 1;
-	count = page_count(page);
-	if (PageSwapCache(page))
-		count += swap_count(page) - 2 - !!page->buffers;
-	return  count > 1;
-}
 
 extern spinlock_t pagemap_lru_lock;
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.4.3/linux/include/linux/sysctl.h	Mon Mar 26 15:48:10 2001
+++ linux/include/linux/sysctl.h	Wed Apr 25 16:21:25 2001
@@ -117,6 +117,8 @@
 	KERN_OVERFLOWGID=47,	/* int: overflow GID */
 	KERN_SHMPATH=48,	/* string: path to shm fs */
 	KERN_HOTPLUG=49,	/* string: path to hotplug policy agent */
+	KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */
+	KERN_S390_USER_DEBUG_LOGGING=51  /* int: dumps of user faults */
 };
 
 
diff -u --recursive --new-file v2.4.3/linux/include/linux/tcp.h linux/include/linux/tcp.h
--- v2.4.3/linux/include/linux/tcp.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/tcp.h	Wed Apr 25 16:21:25 2001
@@ -126,6 +126,7 @@
 #define TCP_DEFER_ACCEPT	9	/* Wake up listener only when data arrive */
 #define TCP_WINDOW_CLAMP	10	/* Bound advertised window */
 #define TCP_INFO		11	/* Information about this connection. */
+#define TCP_QUICKACK		12	/* Block/reenable quick acks */
 
 #define TCPI_OPT_TIMESTAMPS	1
 #define TCPI_OPT_SACK		2
diff -u --recursive --new-file v2.4.3/linux/include/linux/tpqic02.h linux/include/linux/tpqic02.h
--- v2.4.3/linux/include/linux/tpqic02.h	Mon Mar 26 15:50:01 2001
+++ linux/include/linux/tpqic02.h	Wed Apr 25 16:23:27 2001
@@ -588,7 +588,7 @@
  */
 
 #define	TP_REWCLOSE(d)	((MINOR(d)&0x01) == 1)	   		/* rewind bit */
-			   /* rewind is only done if data has been transfered */
+			   /* rewind is only done if data has been transferred */
 #define	TP_DENS(dev)	((MINOR(dev) >> 1) & 0x07) 	      /* tape density */
 #define TP_UNIT(dev)	((MINOR(dev) >> 4) & 0x07)	       /* unit number */
 
@@ -633,8 +633,8 @@
 #define EXC_WP		3	/* Write protected */
 #define EXC_EOM		4	/* EOM */
 #define EXC_RWA		5	/* read/write abort */
-#define EXC_XBAD	6	/* read error, bad block transfered */
-#define EXC_XFILLER	7	/* read error, filler block transfered */
+#define EXC_XBAD	6	/* read error, bad block transferred */
+#define EXC_XFILLER	7	/* read error, filler block transferred */
 #define EXC_NDT		8	/* read error, no data */
 #define EXC_NDTEOM	9	/* read error, no data & EOM */
 #define EXC_NDTBOM	10	/* read error, no data & BOM */
diff -u --recursive --new-file v2.4.3/linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h
--- v2.4.3/linux/include/linux/tty_ldisc.h	Mon Mar 26 15:48:11 2001
+++ linux/include/linux/tty_ldisc.h	Wed Apr 25 16:21:39 2001
@@ -2,22 +2,22 @@
 #define _LINUX_TTY_LDISC_H
 
 /*
- * This structure defines the interface between the tty line discpline
+ * This structure defines the interface between the tty line discipline
  * implementation and the tty routines.  The following routines can be
  * defined; unless noted otherwise, they are optional, and can be
  * filled in with a null pointer.
  *
  * int	(*open)(struct tty_struct *);
  *
- * 	This function is called when the line discpline is associated
- * 	with the tty.  The line discpline can use this as an
+ * 	This function is called when the line discipline is associated
+ * 	with the tty.  The line discipline can use this as an
  * 	opportunity to initialize any state needed by the ldisc routines.
  * 
  * void	(*close)(struct tty_struct *);
  *
- *	This function is called when the line discpline is being
+ *	This function is called when the line discipline is being
  * 	shutdown, either because the tty is being closed or because
- * 	the tty is being changed to use a new line discpline
+ * 	the tty is being changed to use a new line discipline
  * 
  * void	(*flush_buffer)(struct tty_struct *tty);
  *
@@ -28,14 +28,14 @@
  * ssize_t (*chars_in_buffer)(struct tty_struct *tty);
  *
  * 	This function returns the number of input characters the line
- *	iscpline may have queued up to be delivered to the user mode
+ *	discipline may have queued up to be delivered to the user mode
  *	process.
  * 
  * ssize_t (*read)(struct tty_struct * tty, struct file * file,
  *		   unsigned char * buf, size_t nr);
  *
  * 	This function is called when the user requests to read from
- * 	the tty.  The line discpline will return whatever characters
+ * 	the tty.  The line discipline will return whatever characters
  * 	it has buffered up for the user.  If this function is not
  * 	defined, the user will receive an EIO error.
  * 
@@ -43,7 +43,7 @@
  * 		    const unsigned char * buf, size_t nr);
  *
  * 	This function is called when the user requests to write to the
- * 	tty.  The line discpline will deliver the characters to the
+ * 	tty.  The line discipline will deliver the characters to the
  * 	low-level tty device for transmission, optionally performing
  * 	some processing on the characters first.  If this function is
  * 	not defined, the user will receive an EIO error.
@@ -54,7 +54,7 @@
  *	This function is called when the user requests an ioctl which
  * 	is not handled by the tty layer or the low-level tty driver.
  * 	It is intended for ioctls which affect line discpline
- * 	operation.  Not that the search order for ioctls is (1) tty
+ * 	operation.  Note that the search order for ioctls is (1) tty
  * 	layer, (2) tty low-level driver, (3) line discpline.  So a
  * 	low-level driver can "grab" an ioctl request before the line
  * 	discpline has a chance to see it.
@@ -62,7 +62,7 @@
  * void	(*set_termios)(struct tty_struct *tty, struct termios * old);
  *
  * 	This function notifies the line discpline that a change has
- * 	been made to the termios stucture.
+ * 	been made to the termios structure.
  * 
  * int	(*poll)(struct tty_struct * tty, struct file * file,
  * 		  poll_table *wait);
diff -u --recursive --new-file v2.4.3/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.4.3/linux/include/linux/usb.h	Mon Mar 26 15:49:54 2001
+++ linux/include/linux/usb.h	Wed Apr 25 16:22:38 2001
@@ -583,6 +583,8 @@
 
 	/* usbdevfs inode list */
 	struct list_head inodes;
+
+	atomic_t refcnt;
 };
 
 #define USB_MAXCHILDREN		(16)	/* This is arbitrary */
diff -u --recursive --new-file v2.4.3/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.4.3/linux/include/linux/videodev.h	Fri Mar  2 11:12:10 2001
+++ linux/include/linux/videodev.h	Thu Apr 12 12:20:31 2001
@@ -373,6 +373,8 @@
 #define VID_HARDWARE_ZR36067	26	/* Zoran ZR36067/36060 */
 #define VID_HARDWARE_OV511	27	
 #define VID_HARDWARE_ZR356700	28	/* Zoran 36700 series */
+#define VID_HARDWARE_W9966	29
+
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.4.3/linux/include/linux/wanpipe.h linux/include/linux/wanpipe.h
--- v2.4.3/linux/include/linux/wanpipe.h	Mon Dec 11 13:00:10 2000
+++ linux/include/linux/wanpipe.h	Thu Apr 12 12:11:39 2001
@@ -5,13 +5,17 @@
 * Author: 	Nenad Corbic <ncorbic@sangoma.com>
 *		Gideon Hack  	
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Nov 3,  2000  Nenad Corbic    Added config_id to sdla_t structure.
+*                               Used to determine the protocol running.
+* Jul 13, 2000  Nenad Corbic	Added SyncPPP Support
+* Feb 24, 2000  Nenad Corbic    Added support for x25api driver
 * Oct 04, 1999  Nenad Corbic    New CHDLC and FRAME RELAY code, SMP support
 * Jun 02, 1999  Gideon Hack	Added 'update_call_count' for Cisco HDLC 
 *				support
@@ -35,10 +39,58 @@
 #ifndef	_WANPIPE_H
 #define	_WANPIPE_H
 
-#include <linux/config.h>
+#include <linux/version.h>
 
-#ifdef CONFIG_SMP
-#include <asm/spinlock.h>       /* Support for SMP Locking */
+#ifndef KERNEL_VERSION
+  #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ 
+ #define LINUX_2_4
+ #define netdevice_t struct net_device
+
+ #define FREE_READ 1
+ #define FREE_WRITE 0
+
+ #define stop_net_queue(a) 	netif_stop_queue(a) 
+ #define start_net_queue(a) 	netif_start_queue(a)
+ #define is_queue_stopped(a)	netif_queue_stopped(a)
+ #define wake_net_dev(a)	netif_wake_queue(a)
+ #define is_dev_running(a)	netif_running(a)
+ #define wan_dev_kfree_skb(a,b)	dev_kfree_skb_any(a)
+
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+
+ #define LINUX_2_1
+ #define netdevice_t struct device
+ #define FREE_READ 1
+ #define FREE_WRITE 0
+
+ #define stop_net_queue(a) 	(set_bit(0, &##a->tbusy)) 
+ #define start_net_queue(a) 	(clear_bit(0,&##a->tbusy))
+ #define is_queue_stopped(a)	(##a->tbusy)
+ #define wake_net_dev(a)	{clear_bit(0,&##a->tbusy);mark_bh(NET_BH);}
+ #define is_dev_running(a)	(test_bit(0,&##a->start))
+ #define wan_dev_kfree_skb(a,b)	dev_kfree_skb(a)
+
+#else
+ #define LINUX_2_0
+ #define netdevice_t struct device
+
+ #define test_and_set_bit set_bit
+ #define net_ratelimit() 1 
+
+ #define stop_net_queue(a) 	(set_bit(0, &##a->tbusy)) 
+ #define start_net_queue(a) 	(clear_bit(0,&##a->tbusy))
+ #define is_queue_stopped(a)	(##a->tbusy)
+ #define wake_net_dev(a)	{clear_bit(0,&##a->tbusy);mark_bh(NET_BH);}
+ #define is_dev_running(a)	(test_bit(0,(void*)&##a->start))
+ #define wan_dev_kfree_skb(a,b) dev_kfree_skb(a,b)  		 
+ #define spin_lock_init(a)
+ #define spin_lock(a)
+ #define spin_unlock(a)
 #endif
 
 #include <linux/wanrouter.h>
@@ -49,7 +101,7 @@
 #define	PACKED	__attribute__((packed))
 #endif
 
-#define	WANPIPE_MAGIC	0x414C4453L	/* signatire: 'SDLA' reversed */
+#define	WANPIPE_MAGIC	0x414C4453L	/* signature: 'SDLA' reversed */
 
 /* IOCTL numbers (up to 16) */
 #define	WANPIPE_DUMP	(ROUTER_USER+0)	/* dump adapter's memory */
@@ -64,6 +116,51 @@
 #define UDPMGMT_REPLY	0x02
 #define UDP_OFFSET	12
 
+#define MAX_CMD_BUFF 	10
+#define MAX_X25_LCN 	255	/* Maximum number of x25 channels */
+#define MAX_LCN_NUM	4095	/* Maximum lcn number */
+#define MAX_FT1_RETRY 	100
+
+#ifdef LINUX_2_4
+  #ifndef AF_WANPIPE
+	#define AF_WANPIPE 25
+	#ifndef PF_WANPIPE
+		#define PF_WANPIPE AF_WANPIPE
+	#endif
+  #endif
+
+#else
+  #ifndef AF_WANPIPE
+	#define AF_WANPIPE 24
+	#ifndef PF_WANPIPE
+		#define PF_WANPIPE AF_WANPIPE
+	#endif
+  #endif
+#endif
+
+
+#define TX_TIMEOUT 5*HZ
+
+/* General Critical Flags */
+#define SEND_CRIT	0x00
+#define PERI_CRIT	0x01
+
+/* Chdlc and PPP polling critical flag */
+#define POLL_CRIT	0x03
+
+/* Frame Relay Tx IRQ send critical flag */
+#define SEND_TXIRQ_CRIT 0x02
+
+/* Frame Relay ARP critical flag */
+#define ARP_CRIT	0x03
+
+/* Bit maps for dynamic interface configuration
+ * DYN_OPT_ON : turns this option on/off 
+ * DEV_DOWN   : device was shutdown by the driver not
+ *              by user 
+ */
+#define DYN_OPT_ON	0x00
+#define DEV_DOWN	0x01
 
 /*
  * Data structures for IOCTL calls.
@@ -197,6 +294,9 @@
 } pipe_mgmt_stat_t;
 
 
+typedef struct {
+	struct sk_buff *skb;
+} bh_data_t, cmd_data_t;
 
 #define MAX_LGTH_UDP_MGNT_PKT 2000
  
@@ -210,11 +310,27 @@
 #define	WUM_KILL	0x50
 #define	WUM_EXEC	0x51
 
+#define WANPIPE		0x00
+#define API		0x01
+#define BRIDGE		0x02
+#define BRIDGE_NODE	0x03
+
 #ifdef	__KERNEL__
 /****** Kernel Interface ****************************************************/
 
 #include <linux/sdladrv.h>	/* SDLA support module API definitions */
 #include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
+#include <linux/tqueue.h>
+#ifdef LINUX_2_4
+  #include <linux/serial.h>
+  #include <linux/serialP.h>
+  #include <linux/serial_reg.h>
+  #include <asm/serial.h>
+#endif
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
 
 #ifndef	min
 #define min(a,b) (((a)<(b))?(a):(b))
@@ -230,6 +346,7 @@
 	 	  ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\
 	 	  ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0)
 
+
 /****** Data Structures *****************************************************/
 
 /* Adapter Data Space.
@@ -241,6 +358,7 @@
 	char devname[WAN_DRVNAME_SZ+1];	/* card name */
 	sdlahw_t hw;			/* hardware configuration */
 	wan_device_t wandev;		/* WAN device data space */
+	
 	unsigned open_cnt;		/* number of open interfaces */
 	unsigned long state_tick;	/* link state timestamp */
 	unsigned intr_mode;		/* Type of Interrupt Mode */
@@ -248,30 +366,71 @@
 	char buff_int_mode_unbusy;	/* flag for carrying out dev_tint */  
 	char dlci_int_mode_unbusy;	/* flag for carrying out dev_tint */
 	char configured;		/* flag for previous configurations */
+	
 	unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/
 	unsigned short irq_dis_poll_count;   /* Disabling irqs in poll routine*/
 	unsigned short force_enable_irq;
 	char TracingEnabled;		/* flag for enabling trace */
 	global_stats_t statistics;	/* global statistics */
-#ifdef CONFIG_SMP
-	spinlock_t lock;                /* Support for SMP Locking */
-#endif
 	void* mbox;			/* -> mailbox */
 	void* rxmb;			/* -> receive mailbox */
 	void* flags;			/* -> adapter status flags */
 	void (*isr)(struct sdla* card);	/* interrupt service routine */
 	void (*poll)(struct sdla* card); /* polling routine */
 	int (*exec)(struct sdla* card, void* u_cmd, void* u_data);
-
-	struct sdla *next;		/* Secondary Port Device: Piggibacking */
+					/* Used by the listen() system call */		
+	/* Wanpipe Socket Interface */
+	int   (*func) (struct sk_buff *, struct sock *);
+	struct sock *sk;
+
+	/* Shutdown function */
+	void (*disable_comm) (struct sdla *card);
+
+	/* Secondary Port Device: Piggibacking */
+	struct sdla *next;
+
+	/* TTY driver variables */
+	unsigned char tty_opt;
+	struct tty_struct *tty;
+	unsigned int tty_minor;
+	unsigned int tty_open;
+	unsigned char *tty_buf;
+	unsigned char *tty_rx;
+	struct tq_struct tty_task_queue;
+	
 	union
 	{
 		struct
 		{			/****** X.25 specific data **********/
-			unsigned lo_pvc;
-			unsigned hi_pvc;
-			unsigned lo_svc;
-			unsigned hi_svc;
+			u32 lo_pvc;
+			u32 hi_pvc;
+			u32 lo_svc;
+			u32 hi_svc;
+			netdevice_t *svc_to_dev_map[MAX_X25_LCN];
+			netdevice_t *pvc_to_dev_map[MAX_X25_LCN];
+			netdevice_t *tx_dev;
+			netdevice_t *cmd_dev;
+			u32 no_dev;
+			volatile u8 *hdlc_buf_status;
+			u32 tx_interrupts_pending;
+                        u16 timer_int_enabled;
+			netdevice_t *poll_device;
+			atomic_t command_busy;
+
+			u16 udp_pkt_lgth;
+                        u32 udp_type;
+                        u8  udp_pkt_src;
+			u32 udp_lcn;
+                        netdevice_t * udp_dev;
+                        s8 udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+
+		 	u8 LAPB_hdlc;		/* Option to turn off X25 and run only LAPB */
+			u8 logging;		/* Option to log call messages */
+			u8 oob_on_modem;	/* Option to send modem status to the api */
+			u16 num_of_ch;		/* Number of channels configured by the user */
+
+			struct tq_struct x25_poll_task;
+			struct timer_list x25_timer;
 		} x;
 		struct
 		{			/****** frame relay specific data ***/
@@ -281,7 +440,7 @@
 			unsigned rx_top;	/* S508 receive buffer end */
 			unsigned short node_dlci[100];
 			unsigned short dlci_num;
-                        struct net_device *dlci_to_dev_map[991 + 1];
+                        netdevice_t *dlci_to_dev_map[991 + 1];
                         unsigned tx_interrupts_pending;
                         unsigned short timer_int_enabled;
                         unsigned short udp_pkt_lgth;
@@ -289,11 +448,13 @@
                         char udp_pkt_src;
                         unsigned udp_dlci;
                         char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
-                        void* trc_el_base;      /* first trace element */
-                        void* trc_el_last;      /* last trace element */
-                        void *curr_trc_el;      /* current trace element */
-                        unsigned short trc_bfr_space; /* trace buffer space */
+                        void* trc_el_base;      		/* first trace element */
+                        void* trc_el_last;      		/* last trace element */
+                        void *curr_trc_el;      		/* current trace element */
+                        unsigned short trc_bfr_space; 		/* trace buffer space */
 			unsigned char  update_comms_stats;
+			netdevice_t *arp_dev;
+			spinlock_t if_send_lock;
 		} f;
 		struct			/****** PPP-specific data ***********/
 		{
@@ -307,6 +468,10 @@
 			unsigned rx_top;	/* S508 receive buffer end */
 			char ip_mode;		/* STATIC/HOST/PEER IP Mode */
 			char authenticator;	/* Authenticator for PAP/CHAP */
+			unsigned char comm_enabled; /* Is comm enabled or not */
+			unsigned char peer_route;   /* Process Peer Route */	
+			unsigned long *txbuf_next;  /* Next Tx buffer to use */ 
+			unsigned long *rxbuf_next;  /* Next Rx buffer to use */
 		} p;
 		struct			/* Cisco HDLC-specific data */
 		{
@@ -324,6 +489,7 @@
 			void* rxbuf_last;	/* -> last Rx buffer */
 			unsigned rx_base;	/* S508 receive buffer base */
 			unsigned rx_top;	/* S508 receive buffer end */
+			unsigned char receive_only; /* high speed receivers */
 			unsigned short protocol_options;
 			unsigned short kpalv_tx;	/* Tx kpalv timer */
 			unsigned short kpalv_rx;	/* Rx kpalv timer */
@@ -332,6 +498,19 @@
 			unsigned state;			/* state of the link */
 			unsigned char api_status;
 			unsigned char update_call_count;
+			unsigned short api_options;	/* for async config */
+			unsigned char  async_mode;
+		        unsigned short tx_bits_per_char;
+		        unsigned short rx_bits_per_char;
+		        unsigned short stop_bits;
+		        unsigned short parity;
+			unsigned short break_timer;
+		        unsigned short inter_char_timer;
+		        unsigned short rx_complete_length;
+		        unsigned short xon_char;
+		        unsigned short xoff_char;
+			unsigned char comm_enabled; /* Is comm enabled or not */
+			unsigned char backup;
 		} c;
 		struct
 		{
@@ -368,6 +547,18 @@
 int bsc_init (sdla_t* card, wandev_conf_t* conf);	/* BSC streaming */
 int hdlc_init(sdla_t* card, wandev_conf_t* conf);	/* HDLC support */
 int wpft1_init (sdla_t* card, wandev_conf_t* conf);     /* FT1 Config support */
+int wsppp_init (sdla_t* card, wandev_conf_t* conf);	/* Sync PPP on top of RAW CHDLC */
+
+extern sdla_t * wanpipe_find_card(char *);
+extern sdla_t * wanpipe_find_card_num (int);
+
+extern void wanpipe_queue_tq (struct tq_struct *);
+extern void wanpipe_mark_bh (void);
+extern void wakeup_sk_bh (netdevice_t *);
+extern int change_dev_flags (netdevice_t *, unsigned); 
+extern unsigned long get_ip_address (netdevice_t *dev, int option);
+extern void add_gateway(sdla_t *, netdevice_t *);
+
 
 #endif	/* __KERNEL__ */
 #endif	/* _WANPIPE_H */
diff -u --recursive --new-file v2.4.3/linux/include/linux/wanrouter.h linux/include/linux/wanrouter.h
--- v2.4.3/linux/include/linux/wanrouter.h	Mon Mar 26 15:50:18 2001
+++ linux/include/linux/wanrouter.h	Wed Apr 25 16:23:30 2001
@@ -5,15 +5,18 @@
 *
 * Author: 	Nenad Corbic <ncorbic@sangoma.com>
 *		Gideon Hack 	
-* Additions:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+* Additions:	Arnaldo Melo
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Jul 21, 2000  Nenad Corbic	Added WAN_FT1_READY State
+* Feb 24, 2000  Nenad Corbic    Added support for socket based x25api
+* Jan 28, 2000  Nenad Corbic    Added support for the ASYNC protocol.
 * Oct 04, 1999  Nenad Corbic 	Updated for 2.1.0 release
 * Jun 02, 1999  Gideon Hack	Added support for the S514 adapter.
 * May 23, 1999	Arnaldo Melo	Added local_addr to wanif_conf_t
@@ -42,8 +45,24 @@
 *****************************************************************************/
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= 0x020100
-#define LINUX_2_1
+#ifndef KERNEL_VERSION
+  #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ #define LINUX_2_4
+ #define netdevice_t struct net_device
+ #include <linux/spinlock.h>       /* Support for SMP Locking */
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+ #define LINUX_2_1
+ #define netdevice_t struct device
+ #include <asm/spinlock.h>       /* Support for SMP Locking */
+
+#else
+ #define LINUX_2_0
+ #define netdevice_t struct device
+ #define spinlock_t int
 #endif
 
 #ifndef	_ROUTER_H
@@ -135,6 +154,10 @@
 	unsigned r12_r22;	/* RESET retransmission limit (0..250) */
 	unsigned r13_r23;	/* CLEAR retransmission limit (0..250) */
 	unsigned ccitt_compat;	/* compatibility mode: 1988/1984/1980 */
+	unsigned x25_conf_opt;   /* User defined x25 config optoins */
+	unsigned char LAPB_hdlc_only; /* Run in HDLC only mode */
+	unsigned char logging;   /* Control connection logging */  
+	unsigned char oob_on_modem; /* Whether to send modem status to the user app */
 } wan_x25_conf_t;
 
 /*----------------------------------------------------------------------------
@@ -182,6 +205,7 @@
 	unsigned char ignore_cts;	/*  Ignore these to determine	*/
 	unsigned char ignore_keepalive;	/*  link status (Yes or No)	*/
 	unsigned char hdlc_streaming;	/*  hdlc_streaming mode (Y/N) */
+	unsigned char receive_only;	/*  no transmit buffering (Y/N) */
 	unsigned keepalive_tx_tmr;	/* transmit keepalive timer */
 	unsigned keepalive_rx_tmr;	/* receive  keepalive timer */
 	unsigned keepalive_err_margin;	/* keepalive_error_tolerance */
@@ -204,6 +228,7 @@
 	int dma;		/* DMA request level */
         char S514_CPU_no[1];	/* S514 PCI adapter CPU number ('A' or 'B') */
         unsigned PCI_slot_no;	/* S514 PCI adapter slot number */
+	char auto_pci_cfg;	/* S515 PCI automatic slot detection */
 	char comm_port;		/* Communication Port (PRI=0, SEC=1) */ 
 	unsigned bps;		/* data transfer rate */
 	unsigned mtu;		/* maximum transmit unit size */
@@ -216,6 +241,12 @@
 	char station;		/* DTE/DCE, primary/secondary, etc. */
 	char connection;	/* permanent/switched/on-demand */
 	char read_mode;		/* read mode: Polling or interrupt */
+	char receive_only;	/* disable tx buffers */
+	char tty;		/* Create a fake tty device */
+	unsigned tty_major;	/* Major number for wanpipe tty device */
+	unsigned tty_minor; 	/* Minor number for wanpipe tty device */
+	unsigned tty_mode;	/* TTY operation mode SYNC or ASYNC */
+	char backup;		/* Backup Mode */
 	unsigned hw_opt[4];	/* other hardware options */
 	unsigned reserved[4];
 				/****** arbitrary data ***************/
@@ -237,6 +268,7 @@
 #define WANCONFIG_CHDLC	104	/* Cisco HDLC Link */
 #define WANCONFIG_BSC	105	/* BiSync Streaming */
 #define WANCONFIG_HDLC	106	/* HDLC Support */
+#define WANCONFIG_MPPP  107	/* Multi Port PPP over RAW CHDLC */
 
 /*
  * Configuration options defines.
@@ -288,6 +320,15 @@
 #define	WANOPT_PPP_HOST		1
 #define	WANOPT_PPP_PEER		2
 
+/* ASY Mode Options */
+#define WANOPT_ONE 		1
+#define WANOPT_TWO		2
+#define WANOPT_ONE_AND_HALF	3
+
+#define WANOPT_NONE	0
+#define WANOPT_ODD      1
+#define WANOPT_EVEN	2
+
 /* CHDLC Protocol Options */
 /* DF Commmented out for now.
 
@@ -303,6 +344,9 @@
 #define	WANOPT_INTR	0
 #define WANOPT_POLL	1
 
+
+#define WANOPT_TTY_SYNC  0
+#define WANOPT_TTY_ASYNC 1
 /*----------------------------------------------------------------------------
  * WAN Link Status Info (for ROUTER_STAT IOCTL).
  */
@@ -345,7 +389,15 @@
 	WAN_CONNECTED,		/* link/channel is operational */
 	WAN_LIMIT,		/* for verification only */
 	WAN_DUALPORT,		/* for Dual Port cards */
-	WAN_DISCONNECTING	/* link/channel is disconnecting */
+	WAN_DISCONNECTING,
+	WAN_FT1_READY		/* FT1 Configurator Ready */
+};
+
+enum {
+	WAN_LOCAL_IP,
+	WAN_POINTOPOINT_IP,
+	WAN_NETMASK_IP,
+	WAN_BROADCAST_IP
 };
 
 /* 'modem_status' masks */
@@ -395,6 +447,27 @@
 	char clocking;			/* external/internal */
 	unsigned bps;			/* data transfer rate */
 	unsigned mtu;			/* maximum transmit unit size */
+	unsigned char if_down;		/* brind down interface when disconnected */
+	unsigned char gateway;		/* Is this interface a gateway */
+	unsigned char true_if_encoding;	/* Set the dev->type to true board protocol */
+
+	unsigned char asy_data_trans;     /* async API options */
+        unsigned char rts_hs_for_receive; /* async Protocol options */
+        unsigned char xon_xoff_hs_for_receive;
+	unsigned char xon_xoff_hs_for_transmit;
+	unsigned char dcd_hs_for_transmit;
+	unsigned char cts_hs_for_transmit;
+	unsigned char async_mode;
+	unsigned tx_bits_per_char;
+	unsigned rx_bits_per_char;
+	unsigned stop_bits;  
+	unsigned char parity;
+ 	unsigned break_timer;
+        unsigned inter_char_timer;
+	unsigned rx_complete_length;
+	unsigned xon_char;
+	unsigned xoff_char;
+	unsigned char receive_only;	/*  no transmit buffering (Y/N) */
 } wanif_conf_t;
 
 #ifdef	__KERNEL__
@@ -440,30 +513,40 @@
 					/****** status and statistics *******/
 	char state;			/* device state */
 	char api_status;		/* device api status */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct net_device_stats stats; 	/* interface statistics */
+#else
+	struct enet_statistics stats;	/* interface statistics */
+#endif
 	unsigned reserved[16];		/* reserved for future use */
 	unsigned long critical;		/* critical section flag */
+	spinlock_t lock;                /* Support for SMP Locking */
+
 					/****** device management methods ***/
 	int (*setup) (struct wan_device *wandev, wandev_conf_t *conf);
 	int (*shutdown) (struct wan_device *wandev);
 	int (*update) (struct wan_device *wandev);
 	int (*ioctl) (struct wan_device *wandev, unsigned cmd,
 		unsigned long arg);
-	int (*new_if) (struct wan_device *wandev, struct net_device *dev,
+	int (*new_if) (struct wan_device *wandev, netdevice_t *dev,
 		wanif_conf_t *conf);
-	int (*del_if) (struct wan_device *wandev, struct net_device *dev);
+	int (*del_if) (struct wan_device *wandev, netdevice_t *dev);
 					/****** maintained by the router ****/
 	struct wan_device* next;	/* -> next device */
-	struct net_device* dev;		/* list of network interfaces */
+	netdevice_t* dev;		/* list of network interfaces */
 	unsigned ndev;			/* number of interfaces */
+#ifdef LINUX_2_4
 	struct proc_dir_entry *dent;	/* proc filesystem entry */
+#else
+	struct proc_dir_entry dent;	/* proc filesystem entry */
+#endif
 } wan_device_t;
 
 /* Public functions available for device drivers */
 extern int register_wan_device(wan_device_t *wandev);
 extern int unregister_wan_device(char *name);
-unsigned short wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev);
-int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev);
+unsigned short wanrouter_type_trans(struct sk_buff *skb, netdevice_t *dev);
+int wanrouter_encapsulate(struct sk_buff *skb, netdevice_t *dev,unsigned short type);
 
 /* Proc interface functions. These must not be called by the drivers! */
 extern int wanrouter_proc_init(void);
@@ -471,6 +554,11 @@
 extern int wanrouter_proc_add(wan_device_t *wandev);
 extern int wanrouter_proc_delete(wan_device_t *wandev);
 extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+
+
 
 /* Public Data */
 extern wan_device_t *router_devlist;	/* list of registered devices */
diff -u --recursive --new-file v2.4.3/linux/include/linux/wavefront.h linux/include/linux/wavefront.h
--- v2.4.3/linux/include/linux/wavefront.h	Mon Jan  4 11:42:43 1999
+++ linux/include/linux/wavefront.h	Thu Apr 12 12:20:31 2001
@@ -31,7 +31,7 @@
 	member, which has the same semantics anyway. 
      */
 
-#endif __GNUC__
+#endif /* __GNUC__ */
 
 /***************************** WARNING ********************************
   PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO 
@@ -40,11 +40,11 @@
 
 #ifndef NUM_MIDIKEYS 
 #define NUM_MIDIKEYS 128
-#endif  NUM_MIDIKEYS
+#endif  /* NUM_MIDIKEYS */
 
 #ifndef NUM_MIDICHANNELS
 #define NUM_MIDICHANNELS 16
-#endif  NUM_MIDICHANNELS
+#endif  /* NUM_MIDICHANNELS */
 
 /* These are very useful/important. the original wavefront interface
    was developed on a 16 bit system, where sizeof(int) = 2
@@ -667,9 +667,9 @@
 
 /* Allow direct user-space control over FX memory/coefficient data.
    In theory this could be used to download the FX microprogram,
-   but it would be a little slower, and involve some wierd code.
+   but it would be a little slower, and involve some weird code.
  */
 
 #define WFFX_MEMSET              69
 
-#endif __wavefront_h__
+#endif /* __wavefront_h__ */
diff -u --recursive --new-file v2.4.3/linux/include/linux/wireless.h linux/include/linux/wireless.h
--- v2.4.3/linux/include/linux/wireless.h	Mon Mar 26 15:48:17 2001
+++ linux/include/linux/wireless.h	Wed Apr 25 16:21:28 2001
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	9	16.10.99
+ * Version :	11	28.3.01
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  */
@@ -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	10
+#define WIRELESS_EXT	11
 
 /*
  * Changes :
@@ -111,6 +111,11 @@
  *	- Add PM modifier : MAX/MIN/RELATIVE
  *	- Add encoding option : IW_ENCODE_NOKEY
  *	- Add TxPower ioctls (work like TxRate)
+ *
+ * V10 to V11
+ * ----------
+ *	- Add WE version in range (help backward/forward compatibility)
+ *	- Add retry ioctls (work like PM)
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
@@ -153,7 +158,7 @@
  * The "flags" member indicate if the ESSID is active or not (promiscuous).
  */
 
-/* Other parameters usefull in 802.11 and some other devices */
+/* Other parameters useful in 802.11 and some other devices */
 #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
 #define SIOCGIWRATE	0x8B21		/* get default bit rate (bps) */
 #define SIOCSIWRTS	0x8B22		/* set RTS/CTS threshold (bytes) */
@@ -162,6 +167,8 @@
 #define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
 #define SIOCSIWTXPOW	0x8B26		/* set transmit power (dBm) */
 #define SIOCGIWTXPOW	0x8B27		/* get transmit power (dBm) */
+#define SIOCSIWRETRY	0x8B28		/* set retry limits and lifetime */
+#define SIOCGIWRETRY	0x8B29		/* get retry limits and lifetime */
 
 /* Encoding stuff (scrambling, hardware security, WEP...) */
 #define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
@@ -272,6 +279,16 @@
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
 
+/* Retry limits and lifetime flags available */
+#define IW_RETRY_ON		0x0000	/* No details... */
+#define IW_RETRY_TYPE		0xF000	/* Type of parameter */
+#define IW_RETRY_LIMIT		0x1000	/* Maximum number of retries*/
+#define IW_RETRY_LIFETIME	0x2000	/* Maximum duration of retries in us */
+#define IW_RETRY_MODIFIER	0x000F	/* Modify a parameter */
+#define IW_RETRY_MIN		0x0001	/* Value is a minimum  */
+#define IW_RETRY_MAX		0x0002	/* Value is a maximum */
+#define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -288,7 +305,7 @@
 
 /*
  *	For all data larger than 16 octets, we need to use a
- *	pointer to memory alocated in user space.
+ *	pointer to memory allocated in user space.
  */
 struct	iw_point
 {
@@ -385,6 +402,7 @@
 		struct iw_param	rts;		/* RTS threshold threshold */
 		struct iw_param	frag;		/* Fragmentation threshold */
 		__u32		mode;		/* Operation mode */
+		struct iw_param	retry;		/* Retry limits & lifetime */
 
 		struct iw_point	encoding;	/* Encoding stuff : tokens */
 		struct iw_param	power;		/* PM duration/timeout */
@@ -462,6 +480,19 @@
 	__u16		txpower_capa;	/* What options are supported */
 	__u8		num_txpower;	/* Number of entries in the list */
 	__s32		txpower[IW_MAX_TXPOWER];	/* list, in bps */
+
+	/* Wireless Extension version info */
+	__u8		we_version_compiled;	/* Must be WIRELESS_EXT */
+	__u8		we_version_source;	/* Last update of source */
+
+	/* Retry limits and lifetime */
+	__u16		retry_capa;	/* What retry options are supported */
+	__u16		retry_flags;	/* How to decode max/min retry limit */
+	__u16		r_time_flags;	/* How to decode max/min retry life */
+	__s32		min_retry;	/* Minimal number of retries */
+	__s32		max_retry;	/* Maximal number of retries */
+	__s32		min_r_time;	/* Minimal retry lifetime */
+	__s32		max_r_time;	/* Maximal retry lifetime */
 };
 
 /*
diff -u --recursive --new-file v2.4.3/linux/include/net/icmp.h linux/include/net/icmp.h
--- v2.4.3/linux/include/net/icmp.h	Mon Mar 26 15:48:59 2001
+++ linux/include/net/icmp.h	Wed Apr 25 16:23:32 2001
@@ -35,9 +35,8 @@
 #define ICMP_INC_STATS_BH(field)	SNMP_INC_STATS_BH(icmp_statistics, field)
 #define ICMP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(icmp_statistics, field)
 
-extern void	icmp_send(struct sk_buff *skb_in,  int type, int code,
-			  unsigned long info);
-extern int	icmp_rcv(struct sk_buff *skb, unsigned short len);
+extern void	icmp_send(struct sk_buff *skb_in,  int type, int code, u32 info);
+extern int	icmp_rcv(struct sk_buff *skb);
 extern int	icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern void	icmp_init(struct net_proto_family *ops);
 
diff -u --recursive --new-file v2.4.3/linux/include/net/ip.h linux/include/net/ip.h
--- v2.4.3/linux/include/net/ip.h	Mon Mar 26 15:48:31 2001
+++ linux/include/net/ip.h	Wed Apr 25 16:23:00 2001
@@ -188,11 +188,16 @@
 
 extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst);
 
-static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst)
+static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk)
 {
-	if (iph->frag_off&__constant_htons(IP_DF))
-		iph->id = 0;
-	else
+	if (iph->frag_off&__constant_htons(IP_DF)) {
+		/* This is only to work around buggy Windows95/2000
+		 * VJ compression implementations.  If the ID field
+		 * does not change, they drop every other packet in
+		 * a TCP stream using header compression.
+		 */
+		iph->id = ((sk && sk->daddr) ? htons(sk->protinfo.af_inet.id++) : 0);
+	} else
 		__ip_select_ident(iph, dst);
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/net/ipip.h linux/include/net/ipip.h
--- v2.4.3/linux/include/net/ipip.h	Fri Aug  4 18:18:49 2000
+++ linux/include/net/ipip.h	Thu Apr 12 12:11:39 2001
@@ -29,8 +29,9 @@
 	int err;							\
 	int pkt_len = skb->len;						\
 									\
+	skb->ip_summed = CHECKSUM_NONE;					\
 	iph->tot_len = htons(skb->len);					\
-	ip_select_ident(iph, &rt->u.dst);				\
+	ip_select_ident(iph, &rt->u.dst, NULL);				\
 	ip_send_check(iph);						\
 									\
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, do_ip_send); \
diff -u --recursive --new-file v2.4.3/linux/include/net/ipv6.h linux/include/net/ipv6.h
--- v2.4.3/linux/include/net/ipv6.h	Mon Mar 26 15:48:54 2001
+++ linux/include/net/ipv6.h	Wed Apr 25 16:23:34 2001
@@ -4,7 +4,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: ipv6.h,v 1.22 2000/09/18 05:54:13 davem Exp $
+ *	$Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -181,11 +181,11 @@
 
 extern int			ip6_call_ra_chain(struct sk_buff *skb, int sel);
 
-extern u8 *			ipv6_reassembly(struct sk_buff **skb, u8 *nhptr);
+extern int			ipv6_reassembly(struct sk_buff **skb, int);
 
-extern u8 *			ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr);
+extern int			ipv6_parse_hopopts(struct sk_buff *skb, int);
 
-extern u8 *			ipv6_parse_exthdrs(struct sk_buff **skb, u8 *nhptr);
+extern int			ipv6_parse_exthdrs(struct sk_buff **skb, int);
 
 extern struct ipv6_txoptions *  ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
 
@@ -303,8 +303,10 @@
 						    struct ipv6_txoptions *opt,
 						    u8 *proto);
 
-extern u8 *			ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, 
+extern int			ipv6_skip_exthdr(struct sk_buff *, int start,
 					         u8 *nexthdrp, int len);
+
+extern int 			ipv6_ext_hdr(u8 nexthdr);
 
 extern struct ipv6_txoptions *	ipv6_invert_rthdr(struct sock *sk,
 						  struct ipv6_rt_hdr *hdr);
diff -u --recursive --new-file v2.4.3/linux/include/net/ndisc.h linux/include/net/ndisc.h
--- v2.4.3/linux/include/net/ndisc.h	Mon Mar 26 15:48:52 2001
+++ linux/include/net/ndisc.h	Wed Apr 25 16:23:33 2001
@@ -60,7 +60,7 @@
 
 extern void			ndisc_cleanup(void);
 
-extern int			ndisc_rcv(struct sk_buff *skb, unsigned long len);
+extern int			ndisc_rcv(struct sk_buff *skb);
 
 extern void			ndisc_send_ns(struct net_device *dev,
 					      struct neighbour *neigh,
@@ -91,13 +91,9 @@
 
 extern void			igmp6_cleanup(void);
 
-extern int			igmp6_event_query(struct sk_buff *skb,
-						  struct icmp6hdr *hdr,
-						  int len);
-
-extern int			igmp6_event_report(struct sk_buff *skb,
-						   struct icmp6hdr *hdr,
-						   int len);
+extern int			igmp6_event_query(struct sk_buff *skb);
+
+extern int			igmp6_event_report(struct sk_buff *skb);
 
 extern void			igmp6_cleanup(void);
 
diff -u --recursive --new-file v2.4.3/linux/include/net/protocol.h linux/include/net/protocol.h
--- v2.4.3/linux/include/net/protocol.h	Mon Mar 26 15:48:11 2001
+++ linux/include/net/protocol.h	Wed Apr 25 16:21:28 2001
@@ -36,8 +36,8 @@
 /* This is used to register protocols. */
 struct inet_protocol 
 {
-	int			(*handler)(struct sk_buff *skb, unsigned short len);
-	void			(*err_handler)(struct sk_buff *skb, unsigned char *dp, int len);
+	int			(*handler)(struct sk_buff *skb);
+	void			(*err_handler)(struct sk_buff *skb, u32 info);
 	struct inet_protocol	*next;
 	unsigned char		protocol;
 	unsigned char		copy:1;
@@ -48,12 +48,11 @@
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 struct inet6_protocol 
 {
-	int	(*handler)(struct sk_buff *skb,
-			unsigned long len);
+	int	(*handler)(struct sk_buff *skb);
 
-	void	(*err_handler)(struct sk_buff *skb, struct ipv6hdr *hdr,
+	void	(*err_handler)(struct sk_buff *skb,
 			       struct inet6_skb_parm *opt,
-			       int type, int code, unsigned char *buff,
+			       int type, int code, int offset,
 			       __u32 info);
 	struct inet6_protocol *next;
 	unsigned char	protocol;
diff -u --recursive --new-file v2.4.3/linux/include/net/raw.h linux/include/net/raw.h
--- v2.4.3/linux/include/net/raw.h	Mon Aug 23 10:01:02 1999
+++ linux/include/net/raw.h	Thu Apr 12 12:11:39 2001
@@ -21,7 +21,7 @@
 extern struct proto raw_prot;
 
 
-extern void 	raw_err(struct sock *, struct sk_buff *);
+extern void 	raw_err(struct sock *, struct sk_buff *, u32 info);
 extern int 	raw_rcv(struct sock *, struct sk_buff *);
 
 /* Note: v4 ICMP wants to get at this stuff, if you change the
diff -u --recursive --new-file v2.4.3/linux/include/net/rawv6.h linux/include/net/rawv6.h
--- v2.4.3/linux/include/net/rawv6.h	Mon Aug 23 10:01:02 1999
+++ linux/include/net/rawv6.h	Thu Apr 12 12:11:39 2001
@@ -8,23 +8,21 @@
 extern rwlock_t raw_v6_lock;
 
 extern struct sock * ipv6_raw_deliver(struct sk_buff *skb,
-				      int nexthdr, unsigned long len);
+				      int nexthdr);
 
 
 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
 				    struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
 
 extern int			rawv6_rcv(struct sock *sk,
-					  struct sk_buff *skb, 
-					  unsigned long len);
+					  struct sk_buff *skb);
 
 
 extern void			rawv6_err(struct sock *sk,
 					  struct sk_buff *skb,
-					  struct ipv6hdr *hdr,
 					  struct inet6_skb_parm *opt,
 					  int type, int code, 
-					  unsigned char *buff, u32 info);
+					  int offset, u32 info);
 
 #endif
 
diff -u --recursive --new-file v2.4.3/linux/include/net/sock.h linux/include/net/sock.h
--- v2.4.3/linux/include/net/sock.h	Mon Mar 26 15:48:31 2001
+++ linux/include/net/sock.h	Wed Apr 25 16:22:27 2001
@@ -56,6 +56,10 @@
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
 #include <net/x25.h>
 #endif
+#if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE)
+#include <linux/if_wanpipe.h>
+#endif
+
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 #include <net/ax25.h>
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
@@ -204,6 +208,7 @@
 	__u8			mc_loop;		/* Loopback */
 	unsigned		recverr : 1,
 				freebind : 1;
+	__u16			id;			/* ID counter for DF pkts */
 	__u8			pmtudisc;
 	int			mc_index;		/* Multicast device index */
 	__u32			mc_addr;
@@ -331,6 +336,8 @@
 
 	struct tcp_func		*af_specific;	/* Operations which are AF_INET{4,6} specific	*/
 	struct sk_buff		*send_head;	/* Front of stuff to transmit			*/
+	struct page		*sndmsg_page;	/* Cached page for sendmsg			*/
+	u32			sndmsg_off;	/* Cached offset for sendmsg			*/
 
  	__u32	rcv_wnd;	/* Current receiver window		*/
 	__u32	rcv_wup;	/* rcv_nxt on last window update sent	*/
@@ -381,8 +388,6 @@
 				 * the first SYN. */
 	__u32	undo_marker;	/* tracking retrans started here. */
 	int	undo_retrans;	/* number of undoable retransmissions. */
-	__u32	syn_seq;	/* Seq of received SYN. */
-	__u32	fin_seq;	/* Seq of received FIN. */
 	__u32	urg_seq;	/* Seq of received urgent pointer */
 	__u16	urg_data;	/* Saved octet of OOB data and control flags */
 	__u8	pending;	/* Scheduled timer event	*/
@@ -534,7 +539,10 @@
 				bsdism;
 	unsigned char		debug;
 	unsigned char		rcvtstamp;
+	unsigned char		use_write_queue;
 	unsigned char		userlocks;
+	/* Hole of 3 bytes. Try to pack. */
+	int			route_caps;
 	int			proc;
 	unsigned long	        lingertime;
 
@@ -645,6 +653,9 @@
 #if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE)
 		struct irda_sock        *irda;
 #endif
+#if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE)
+               struct wanpipe_opt      *af_wanpipe;
+#endif
 	} protinfo;  		
 
 
@@ -730,12 +741,12 @@
 };
 
 /* Called with local bh disabled */
-static void __inline__ sock_prot_inc_use(struct proto *prot)
+static __inline__ void sock_prot_inc_use(struct proto *prot)
 {
 	prot->stats[smp_processor_id()].inuse++;
 }
 
-static void __inline__ sock_prot_dec_use(struct proto *prot)
+static __inline__ void sock_prot_dec_use(struct proto *prot)
 {
 	prot->stats[smp_processor_id()].inuse--;
 }
@@ -833,14 +844,11 @@
 						int *optlen);
 extern struct sk_buff 		*sock_alloc_send_skb(struct sock *sk,
 						     unsigned long size,
-						     unsigned long fallback,
 						     int noblock,
 						     int *errcode);
 extern void *sock_kmalloc(struct sock *sk, int size, int priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
 
-extern int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen);
-
 /*
  * Functions to fill in entries in struct proto_ops when a protocol
  * does not implement a particular function.
@@ -877,6 +885,10 @@
 extern int			sock_no_mmap(struct file *file,
 					     struct socket *sock,
 					     struct vm_area_struct *vma);
+extern ssize_t			sock_no_sendpage(struct socket *sock,
+						struct page *page,
+						int offset, size_t size, 
+						int flags);
 
 /*
  *	Default socket callbacks and setup code
diff -u --recursive --new-file v2.4.3/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.4.3/linux/include/net/tcp.h	Mon Mar 26 15:48:33 2001
+++ linux/include/net/tcp.h	Wed Apr 25 16:23:31 2001
@@ -21,9 +21,6 @@
 #define TCP_DEBUG 1
 #define FASTRETRANS_DEBUG 1
 
-/* Be paranoid about data immediately beyond right edge of window. */
-#undef  TCP_FORMAL_WINDOW
-
 /* Cancel timers, when they are not required. */
 #undef TCP_CLEAR_TIMERS
 
@@ -182,7 +179,6 @@
 	__u32			rcv_nxt;
 	__u32			snd_nxt;
 	__u32			rcv_wnd;
-	__u32			syn_seq;
         __u32			ts_recent;
         long			ts_recent_stamp;
 	unsigned long		ttd;
@@ -357,7 +353,7 @@
 #define TCP_TWKILL_PERIOD	(TCP_TIMEWAIT_LEN/TCP_TWKILL_SLOTS)
 
 #define TCP_SYNQ_INTERVAL	(HZ/5)	/* Period of SYNACK timer */
-#define TCP_SYNQ_HSIZE		64	/* Size of SYNACK hash table */
+#define TCP_SYNQ_HSIZE		512	/* Size of SYNACK hash table */
 
 #define TCP_PAWS_24DAYS	(60 * 60 * 24 * 24)
 #define TCP_PAWS_MSL	60		/* Per-host timestamps are invalidated
@@ -632,19 +628,18 @@
 extern void			__tcp_put_port(struct sock *sk);
 extern void			tcp_inherit_port(struct sock *sk, struct sock *child);
 
-extern void			tcp_v4_err(struct sk_buff *skb,
-					   unsigned char *, int);
+extern void			tcp_v4_err(struct sk_buff *skb, u32);
 
 extern void			tcp_shutdown (struct sock *sk, int how);
 
-extern int			tcp_v4_rcv(struct sk_buff *skb,
-					   unsigned short len);
+extern int			tcp_v4_rcv(struct sk_buff *skb);
 
 extern int			tcp_v4_remember_stamp(struct sock *sk);
 
 extern int		    	tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw);
 
 extern int			tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size);
+extern ssize_t			tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags);
 
 extern int			tcp_ioctl(struct sock *sk, 
 					  int cmd, 
@@ -799,7 +794,7 @@
 
 /* tcp_output.c */
 
-extern int tcp_write_xmit(struct sock *);
+extern int tcp_write_xmit(struct sock *, int nonagle);
 extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
 extern void tcp_xmit_retransmit_queue(struct sock *);
 extern void tcp_simple_retransmit(struct sock *);
@@ -812,6 +807,7 @@
 extern int  tcp_send_synack(struct sock *);
 extern int  tcp_transmit_skb(struct sock *, struct sk_buff *);
 extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue, unsigned mss_now);
+extern void tcp_push_one(struct sock *, unsigned mss_now);
 extern void tcp_send_ack(struct sock *sk);
 extern void tcp_send_delayed_ack(struct sock *sk);
 
@@ -942,6 +938,15 @@
 	__tcp_fast_path_on(tp, tp->snd_wnd>>tp->snd_wscale);
 }
 
+static inline void tcp_fast_path_check(struct sock *sk, struct tcp_opt *tp)
+{
+	if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
+	    tp->rcv_wnd &&
+	    atomic_read(&sk->rmem_alloc) < sk->rcvbuf &&
+	    !tp->urg_data)
+		tcp_fast_path_on(tp);
+}
+
 /* Compute the actual receive window we are currently advertising.
  * Rcv_nxt can be after the window if our peer push more data
  * than the offered window.
@@ -1084,6 +1089,13 @@
 		return max(tp->snd_ssthresh, (tp->snd_cwnd>>1)+(tp->snd_cwnd>>2));
 }
 
+static inline void tcp_sync_left_out(struct tcp_opt *tp)
+{
+	if (tp->sack_ok && tp->sacked_out >= tp->packets_out - tp->lost_out)
+		tp->sacked_out = tp->packets_out - tp->lost_out;
+	tp->left_out = tp->sacked_out + tp->lost_out;
+}
+
 extern void tcp_cwnd_application_limited(struct sock *sk);
 
 /* Congestion window validation. (RFC2861) */
@@ -1229,7 +1241,7 @@
 		if (!tcp_skb_is_last(sk, skb))
 			nonagle = 1;
 		if (!tcp_snd_test(tp, skb, cur_mss, nonagle) ||
-		    tcp_write_xmit(sk))
+		    tcp_write_xmit(sk, nonagle))
 			tcp_check_probe_timer(sk, tp);
 	}
 	tcp_cwnd_validate(sk, tp);
@@ -1275,7 +1287,7 @@
 
 static __inline__ int __tcp_checksum_complete(struct sk_buff *skb)
 {
-	return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum));
+	return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
 }
 
 static __inline__ int tcp_checksum_complete(struct sk_buff *skb)
@@ -1299,23 +1311,31 @@
  * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93)
  * failed somewhere. Latency? Burstiness? Well, at least now we will
  * see, why it failed. 8)8)				  --ANK
+ *
+ * NOTE: is this not too big to inline?
  */
 static __inline__ int tcp_prequeue(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
 	if (tp->ucopy.task) {
-		if ((tp->ucopy.memory += skb->truesize) <= (sk->rcvbuf<<1)) {
-			__skb_queue_tail(&tp->ucopy.prequeue, skb);
-			if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
-				wake_up_interruptible(sk->sleep);
-				if (!tcp_ack_scheduled(tp))
-					tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4);
+		__skb_queue_tail(&tp->ucopy.prequeue, skb);
+		tp->ucopy.memory += skb->truesize;
+		if (tp->ucopy.memory > sk->rcvbuf) {
+			struct sk_buff *skb1;
+
+			if (sk->lock.users) BUG();
+
+			while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
+				sk->backlog_rcv(sk, skb1);
+				NET_INC_STATS_BH(TCPPrequeueDropped);
 			}
-		} else {
-			NET_INC_STATS_BH(TCPPrequeueDropped);
-			tp->ucopy.memory -= skb->truesize;
-			__kfree_skb(skb);
+
+			tp->ucopy.memory = 0;
+		} else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
+			wake_up_interruptible(sk->sleep);
+			if (!tcp_ack_scheduled(tp))
+				tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4);
 		}
 		return 1;
 	}
@@ -1677,19 +1697,40 @@
 	}
 }
 
-static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp)
+static inline struct sk_buff *tcp_alloc_pskb(struct sock *sk, int size, int mem, int gfp)
 {
-	struct sk_buff *skb = alloc_skb(size, gfp);
+	struct sk_buff *skb = alloc_skb(size+MAX_TCP_HEADER, gfp);
 
 	if (skb) {
+		skb->truesize += mem;
 		if (sk->forward_alloc >= (int)skb->truesize ||
-		    tcp_mem_schedule(sk, skb->truesize, 0))
+		    tcp_mem_schedule(sk, skb->truesize, 0)) {
+			skb_reserve(skb, MAX_TCP_HEADER);
 			return skb;
+		}
 		__kfree_skb(skb);
 	} else {
 		tcp_enter_memory_pressure();
 		tcp_moderate_sndbuf(sk);
 	}
+	return NULL;
+}
+
+static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp)
+{
+	return tcp_alloc_pskb(sk, size, 0, gfp);
+}
+
+static inline struct page * tcp_alloc_page(struct sock *sk)
+{
+	if (sk->forward_alloc >= (int)PAGE_SIZE ||
+	    tcp_mem_schedule(sk, PAGE_SIZE, 0)) {
+		struct page *page = alloc_pages(sk->allocation, 0);
+		if (page)
+			return page;
+	}
+	tcp_enter_memory_pressure();
+	tcp_moderate_sndbuf(sk);
 	return NULL;
 }
 
diff -u --recursive --new-file v2.4.3/linux/include/net/udp.h linux/include/net/udp.h
--- v2.4.3/linux/include/net/udp.h	Mon Mar 26 15:49:02 2001
+++ linux/include/net/udp.h	Wed Apr 25 16:23:31 2001
@@ -59,13 +59,13 @@
 extern struct proto udp_prot;
 
 
-extern void	udp_err(struct sk_buff *, unsigned char *, int);
+extern void	udp_err(struct sk_buff *, u32);
 extern int	udp_connect(struct sock *sk,
 			    struct sockaddr *usin, int addr_len);
 
 extern int	udp_sendmsg(struct sock *sk, struct msghdr *msg, int len);
 
-extern int	udp_rcv(struct sk_buff *skb, unsigned short len);
+extern int	udp_rcv(struct sk_buff *skb);
 extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int	udp_disconnect(struct sock *sk, int flags);
 
diff -u --recursive --new-file v2.4.3/linux/include/scsi/scsi.h linux/include/scsi/scsi.h
--- v2.4.3/linux/include/scsi/scsi.h	Tue Sep  5 14:08:55 2000
+++ linux/include/scsi/scsi.h	Wed Apr 11 19:10:03 2001
@@ -196,8 +196,9 @@
  * Here are some scsi specific ioctl commands which are sometimes useful.
  */
 /* These are a few other constants  only used by scsi  devices */
+/* Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395 */
 
-#define SCSI_IOCTL_GET_IDLUN 0x5382
+#define SCSI_IOCTL_GET_IDLUN 0x5382	/* conflicts with CDROMAUDIOBUFSIZ */
 
 /* Used to turn on and off tagged queuing for scsi devices */
 
diff -u --recursive --new-file v2.4.3/linux/include/video/newport.h linux/include/video/newport.h
--- v2.4.3/linux/include/video/newport.h	Fri Feb 25 10:30:57 2000
+++ linux/include/video/newport.h	Thu Apr 12 12:20:31 2001
@@ -486,7 +486,7 @@
  * DCBMODE register defines:
  */
 
-/* Widht of the data being transfered for each DCBDATA[01] word */
+/* Width of the data being transferred for each DCBDATA[01] word */
 #define DCB_DATAWIDTH_4 0x0
 #define DCB_DATAWIDTH_1 0x1
 #define DCB_DATAWIDTH_2 0x2
diff -u --recursive --new-file v2.4.3/linux/init/main.c linux/init/main.c
--- v2.4.3/linux/init/main.c	Mon Mar 19 12:26:25 2001
+++ linux/init/main.c	Thu Apr 19 09:34:05 2001
@@ -27,6 +27,7 @@
 #include <linux/hdreg.h>
 #include <linux/iobuf.h>
 #include <linux/bootmem.h>
+#include <linux/tty.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -96,7 +97,6 @@
 extern void net_notifier_init(void);
 
 extern void free_initmem(void);
-extern void filesystem_setup(void);
 
 #ifdef CONFIG_TC
 extern void tc_init(void);
@@ -722,9 +722,6 @@
 
 	start_context_thread();
 	do_initcalls();
-
-	/* .. filesystems .. */
-	filesystem_setup();
 
 #ifdef CONFIG_IRDA
 	irda_device_init(); /* Must be done after protocol initialization */
diff -u --recursive --new-file v2.4.3/linux/kernel/fork.c linux/kernel/fork.c
--- v2.4.3/linux/kernel/fork.c	Mon Mar 19 12:35:08 2001
+++ linux/kernel/fork.c	Mon Apr 23 15:28:07 2001
@@ -39,7 +39,7 @@
 	unsigned long flags;
 
 	wq_write_lock_irqsave(&q->lock, flags);
-	wait->flags = 0;
+	wait->flags &= ~WQ_FLAG_EXCLUSIVE;
 	__add_wait_queue(q, wait);
 	wq_write_unlock_irqrestore(&q->lock, flags);
 }
@@ -49,7 +49,7 @@
 	unsigned long flags;
 
 	wq_write_lock_irqsave(&q->lock, flags);
-	wait->flags = WQ_FLAG_EXCLUSIVE;
+	wait->flags |= WQ_FLAG_EXCLUSIVE;
 	__add_wait_queue_tail(q, wait);
 	wq_write_unlock_irqrestore(&q->lock, flags);
 }
@@ -203,7 +203,7 @@
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
-	mm->pgd = pgd_alloc();
+	mm->pgd = pgd_alloc(mm);
 	if (mm->pgd)
 		return mm;
 	free_mm(mm);
@@ -666,15 +666,17 @@
 	p->pdeath_signal = 0;
 
 	/*
-	 * "share" dynamic priority between parent and child, thus the
-	 * total amount of dynamic priorities in the system doesnt change,
-	 * more scheduling fairness. This is only important in the first
-	 * timeslice, on the long run the scheduling behaviour is unchanged.
+	 * Give the parent's dynamic priority entirely to the child.  The
+	 * total amount of dynamic priorities in the system doesn't change
+	 * (more scheduling fairness), but the child will run first, which
+	 * is especially useful in avoiding a lot of copy-on-write faults
+	 * if the child for a fork() just wants to do a few simple things
+	 * and then exec(). This is only important in the first timeslice.
+	 * In the long run, the scheduling behavior is unchanged.
 	 */
-	p->counter = (current->counter + 1) >> 1;
-	current->counter >>= 1;
-	if (!current->counter)
-		current->need_resched = 1;
+	p->counter = current->counter;
+	current->counter = 0;
+	current->need_resched = 1;
 
 	/*
 	 * Ok, add it to the run-queues and make it
diff -u --recursive --new-file v2.4.3/linux/kernel/info.c linux/kernel/info.c
--- v2.4.3/linux/kernel/info.c	Tue Sep  5 13:57:57 2000
+++ linux/kernel/info.c	Fri Apr 20 16:15:40 2001
@@ -33,41 +33,46 @@
 	si_swapinfo(&val);
 
 	{
-		/* If the sum of all the available memory (i.e. ram + swap +
-		 * highmem) is less then can be stored in a 32 bit unsigned long
-		 * then we can be binary compatible with 2.2.x kernels.  If not,
-		 * well, who cares since in that case 2.2.x was broken anyways...
+		unsigned long mem_total, sav_total;
+		unsigned int mem_unit, bitcount;
+
+		/* If the sum of all the available memory (i.e. ram + swap)
+		 * is less than can be stored in a 32 bit unsigned long then
+		 * we can be binary compatible with 2.2.x kernels.  If not,
+		 * well, in that case 2.2.x was broken anyways...
 		 *
 		 *  -Erik Andersen <andersee@debian.org> */
 
-		unsigned long mem_total = val.totalram + val.totalswap;
-		if ( !(mem_total < val.totalram || mem_total < val.totalswap)) {
-			unsigned long mem_total2 = mem_total + val.totalhigh; 
-			if (!(mem_total2 < mem_total || mem_total2 < val.totalhigh))
-			{
-				/* If mem_total did not overflow.  Divide all memory values by
-				 * mem_unit and set mem_unit=1.  This leaves things compatible with
-				 * 2.2.x, and also retains compatibility with earlier 2.4.x
-				 * kernels...  */
-
-				int bitcount = 0;
-				while (val.mem_unit > 1) 
-				{
-					bitcount++;
-					val.mem_unit >>= 1;
-				}
-				val.totalram <<= bitcount;
-				val.freeram <<= bitcount;
-				val.sharedram <<= bitcount;
-				val.bufferram <<= bitcount;
-				val.totalswap <<= bitcount;
-				val.freeswap <<= bitcount;
-				val.totalhigh <<= bitcount;
-				val.freehigh <<= bitcount;
-			}
+		mem_total = val.totalram + val.totalswap;
+		if (mem_total < val.totalram || mem_total < val.totalswap)
+			goto out;
+		bitcount = 0;
+		mem_unit = val.mem_unit;
+		while (mem_unit > 1) {
+			bitcount++;
+			mem_unit >>= 1;
+			sav_total = mem_total;
+			mem_total <<= 1;
+			if (mem_total < sav_total)
+				goto out;
 		}
-	}
 
+		/* If mem_total did not overflow, multiply all memory values by
+		 * val.mem_unit and set it to 1.  This leaves things compatible
+		 * with 2.2.x, and also retains compatibility with earlier 2.4.x
+		 * kernels...  */
+
+		val.mem_unit = 1;
+		val.totalram <<= bitcount;
+		val.freeram <<= bitcount;
+		val.sharedram <<= bitcount;
+		val.bufferram <<= bitcount;
+		val.totalswap <<= bitcount;
+		val.freeswap <<= bitcount;
+		val.totalhigh <<= bitcount;
+		val.freehigh <<= bitcount;
+	}
+out:
 	if (copy_to_user(info, &val, sizeof(struct sysinfo)))
 		return -EFAULT;
 	return 0;
diff -u --recursive --new-file v2.4.3/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.3/linux/kernel/ksyms.c	Fri Mar  2 15:16:59 2001
+++ linux/kernel/ksyms.c	Thu Apr 19 08:38:50 2001
@@ -46,6 +46,8 @@
 #include <linux/brlock.h>
 #include <linux/fs.h>
 #include <linux/tty.h>
+#include <linux/in6.h>
+#include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
@@ -129,7 +131,6 @@
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_fs_type);
 EXPORT_SYMBOL(get_super);
-EXPORT_SYMBOL(get_empty_super);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(names_cachep);
 EXPORT_SYMBOL(fput);
@@ -182,7 +183,6 @@
 EXPORT_SYMBOL(inode_change_ok);
 EXPORT_SYMBOL(write_inode_now);
 EXPORT_SYMBOL(notify_change);
-EXPORT_SYMBOL(get_hardblocksize);
 EXPORT_SYMBOL(set_blocksize);
 EXPORT_SYMBOL(getblk);
 EXPORT_SYMBOL(bdget);
@@ -464,6 +464,7 @@
 EXPORT_SYMBOL(securebits);
 EXPORT_SYMBOL(cap_bset);
 EXPORT_SYMBOL(daemonize);
+EXPORT_SYMBOL(csum_partial); /* for networking and md */
 
 /* Program loader interfaces */
 EXPORT_SYMBOL(setup_arg_pages);
diff -u --recursive --new-file v2.4.3/linux/kernel/pm.c linux/kernel/pm.c
--- v2.4.3/linux/kernel/pm.c	Tue Mar  6 19:44:37 2001
+++ linux/kernel/pm.c	Fri Apr  6 10:51:19 2001
@@ -22,6 +22,7 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/pm.h>
+#include <linux/interrupt.h>
 
 int pm_active;
 
@@ -49,6 +50,9 @@
  *	Add a device to the list of devices that wish to be notified about
  *	power management events. A &pm_dev structure is returned on success,
  *	on failure the return is %NULL.
+ *
+ *      The callback function will be called in process context and
+ *      it may sleep.
  */
  
 struct pm_dev *pm_register(pm_dev_t type,
@@ -150,6 +154,10 @@
 {
 	int status = 0;
 	int prev_state, next_state;
+
+	if (in_interrupt())
+		BUG();
+
 	switch (rqst) {
 	case PM_SUSPEND:
 	case PM_RESUME:
diff -u --recursive --new-file v2.4.3/linux/kernel/sched.c linux/kernel/sched.c
--- v2.4.3/linux/kernel/sched.c	Thu Mar 22 09:20:45 2001
+++ linux/kernel/sched.c	Fri Apr 20 18:26:16 2001
@@ -739,7 +739,7 @@
 		state = p->state;
 		if (state & mode) {
 			WQ_NOTE_WAKER(curr);
-			if (try_to_wake_up(p, sync) && curr->flags && !--nr_exclusive)
+			if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
 				break;
 		}
 	}
@@ -1024,9 +1024,11 @@
 	int i;
 
 	// Substract non-idle processes running on other CPUs.
-	for (i = 0; i < smp_num_cpus; i++)
-		if (aligned_data[i].schedule_data.curr != idle_task(i))
+	for (i = 0; i < smp_num_cpus; i++) {
+		int cpu = cpu_logical_map(i);
+		if (aligned_data[cpu].schedule_data.curr != idle_task(cpu))
 			nr_pending--;
+	}
 #else
 	// on UP this process is on the runqueue as well
 	nr_pending--;
diff -u --recursive --new-file v2.4.3/linux/kernel/sys.c linux/kernel/sys.c
--- v2.4.3/linux/kernel/sys.c	Tue Mar  6 19:44:37 2001
+++ linux/kernel/sys.c	Thu Apr 12 12:20:31 2001
@@ -1089,7 +1089,7 @@
 			? -EFAULT : 0;
 }
 
-#if !defined(__ia64__) && !defined(__s390__)
+#if !defined(__ia64__) 
 
 /*
  *	Back compatibility for getrlimit. Needed for some apps.
diff -u --recursive --new-file v2.4.3/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.4.3/linux/kernel/sysctl.c	Fri Feb 16 16:02:37 2001
+++ linux/kernel/sysctl.c	Thu Apr 12 12:20:31 2001
@@ -77,7 +77,7 @@
 #endif
 
 #ifdef CONFIG_ARCH_S390
-#ifdef CONFIG_IEEEFPU_EMULATION
+#ifdef CONFIG_MATHEMU
 extern int sysctl_ieee_emulation_warnings;
 #endif
 extern int sysctl_userprocess_debug;
@@ -242,7 +242,7 @@
 	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
 	 &minolduid, &maxolduid},
 #ifdef CONFIG_ARCH_S390
-#ifdef CONFIG_IEEEFPU_EMULATION
+#ifdef CONFIG_MATHEMU
 	{KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
 	 &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
 #endif
diff -u --recursive --new-file v2.4.3/linux/lib/Makefile linux/lib/Makefile
--- v2.4.3/linux/lib/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/lib/Makefile	Wed Apr 25 13:31:03 2001
@@ -8,9 +8,12 @@
 
 L_TARGET := lib.a
 
-export-objs := cmdline.o
+export-objs := cmdline.o rwsem-spinlock.o rwsem.o
 
 obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o
+
+obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
+obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 
 ifneq ($(CONFIG_HAVE_DEC_LOCK),y) 
   obj-y += dec_and_lock.o
diff -u --recursive --new-file v2.4.3/linux/lib/cmdline.c linux/lib/cmdline.c
--- v2.4.3/linux/lib/cmdline.c	Fri Aug 11 19:14:46 2000
+++ linux/lib/cmdline.c	Thu Apr 12 12:25:53 2001
@@ -93,9 +93,9 @@
  *	megabyte, or one gigabyte, respectively.
  */
 
-unsigned long memparse (char *ptr, char **retptr)
+unsigned long long memparse (char *ptr, char **retptr)
 {
-	unsigned long ret = simple_strtoul (ptr, retptr, 0);
+	unsigned long long ret = simple_strtoull (ptr, retptr, 0);
 
 	switch (**retptr) {
 	case 'G':
diff -u --recursive --new-file v2.4.3/linux/lib/rwsem-spinlock.c linux/lib/rwsem-spinlock.c
--- v2.4.3/linux/lib/rwsem-spinlock.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/rwsem-spinlock.c	Wed Apr 25 13:31:03 2001
@@ -0,0 +1,239 @@
+/* rwsem-spinlock.c: R/W semaphores: contention handling functions for generic spinlock
+ *                                   implementation
+ *
+ * Copyright (c) 2001   David Howells (dhowells@redhat.com).
+ * - Derived partially from idea by Andrea Arcangeli <andrea@suse.de>
+ * - Derived also from comments by Linus
+ */
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+struct rwsem_waiter {
+	struct list_head	list;
+	struct task_struct	*task;
+	unsigned int		flags;
+#define RWSEM_WAITING_FOR_READ	0x00000001
+#define RWSEM_WAITING_FOR_WRITE	0x00000002
+};
+
+#if RWSEM_DEBUG
+void rwsemtrace(struct rw_semaphore *sem, const char *str)
+{
+	if (sem->debug)
+		printk("[%d] %s({%d,%d})\n",
+		       current->pid,str,sem->activity,list_empty(&sem->wait_list)?0:1);
+}
+#endif
+
+/*
+ * initialise the semaphore
+ */
+void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->activity = 0;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+	sem->debug = 0;
+#endif
+}
+
+/*
+ * handle the lock being released whilst there are processes blocked on it that can now run
+ * - if we come here, then:
+ *   - the 'active count' _reached_ zero
+ *   - the 'waiting count' is non-zero
+ * - the spinlock must be held by the caller
+ * - woken process blocks are discarded from the list after having flags zeroised
+ */
+static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter *waiter;
+	int woken;
+
+	rwsemtrace(sem,"Entering __rwsem_do_wake");
+
+	waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
+
+	/* try to grant a single write lock if there's a writer at the front of the queue
+	 * - we leave the 'waiting count' incremented to signify potential contention
+	 */
+	if (waiter->flags & RWSEM_WAITING_FOR_WRITE) {
+		sem->activity = -1;
+		list_del(&waiter->list);
+		waiter->flags = 0;
+		wake_up_process(waiter->task);
+		goto out;
+	}
+
+	/* grant an infinite number of read locks to the readers at the front of the queue */
+	woken = 0;
+	do {
+		list_del(&waiter->list);
+		waiter->flags = 0;
+		wake_up_process(waiter->task);
+		woken++;
+		if (list_empty(&sem->wait_list))
+			break;
+		waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
+	} while (waiter->flags&RWSEM_WAITING_FOR_READ);
+
+	sem->activity += woken;
+
+ out:
+	rwsemtrace(sem,"Leaving __rwsem_do_wake");
+	return sem;
+}
+
+/*
+ * wake a single writer
+ */
+static inline struct rw_semaphore *__rwsem_wake_one_writer(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter *waiter;
+
+	sem->activity = -1;
+
+	waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
+	list_del(&waiter->list);
+
+	waiter->flags = 0;
+	wake_up_process(waiter->task);
+	return sem;
+}
+
+/*
+ * get a read lock on the semaphore
+ */
+void __down_read(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter waiter;
+	struct task_struct *tsk;
+
+	rwsemtrace(sem,"Entering __down_read");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity>=0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity++;
+		spin_unlock(&sem->wait_lock);
+		goto out;
+	}
+
+	tsk = current;
+	set_task_state(tsk,TASK_UNINTERRUPTIBLE);
+
+	/* set up my own style of waitqueue */
+	waiter.task = tsk;
+	waiter.flags = RWSEM_WAITING_FOR_READ;
+
+	list_add_tail(&waiter.list,&sem->wait_list);
+
+	/* we don't need to touch the semaphore struct anymore */
+	spin_unlock(&sem->wait_lock);
+
+	/* wait to be given the lock */
+	for (;;) {
+		if (!waiter.flags)
+			break;
+		schedule();
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	}
+
+	tsk->state = TASK_RUNNING;
+
+ out:
+	rwsemtrace(sem,"Leaving __down_read");
+}
+
+/*
+ * get a write lock on the semaphore
+ * - note that we increment the waiting count anyway to indicate an exclusive lock
+ */
+void __down_write(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter waiter;
+	struct task_struct *tsk;
+
+	rwsemtrace(sem,"Entering __down_write");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity==0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity = -1;
+		spin_unlock(&sem->wait_lock);
+		goto out;
+	}
+
+	tsk = current;
+	set_task_state(tsk,TASK_UNINTERRUPTIBLE);
+
+	/* set up my own style of waitqueue */
+	waiter.task = tsk;
+	waiter.flags = RWSEM_WAITING_FOR_WRITE;
+
+	list_add_tail(&waiter.list,&sem->wait_list);
+
+	/* we don't need to touch the semaphore struct anymore */
+	spin_unlock(&sem->wait_lock);
+
+	/* wait to be given the lock */
+	for (;;) {
+		if (!waiter.flags)
+			break;
+		schedule();
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	}
+
+	tsk->state = TASK_RUNNING;
+
+ out:
+	rwsemtrace(sem,"Leaving __down_write");
+}
+
+/*
+ * release a read lock on the semaphore
+ */
+void __up_read(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering __up_read");
+
+	spin_lock(&sem->wait_lock);
+
+	if (--sem->activity==0 && !list_empty(&sem->wait_list))
+		sem = __rwsem_wake_one_writer(sem);
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __up_read");
+}
+
+/*
+ * release a write lock on the semaphore
+ */
+void __up_write(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering __up_write");
+
+	spin_lock(&sem->wait_lock);
+
+	sem->activity = 0;
+	if (!list_empty(&sem->wait_list))
+		sem = __rwsem_do_wake(sem);
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __up_write");
+}
+
+EXPORT_SYMBOL(init_rwsem);
+EXPORT_SYMBOL(__down_read);
+EXPORT_SYMBOL(__down_write);
+EXPORT_SYMBOL(__up_read);
+EXPORT_SYMBOL(__up_write);
+#if RWSEM_DEBUG
+EXPORT_SYMBOL(rwsemtrace);
+#endif
diff -u --recursive --new-file v2.4.3/linux/lib/rwsem.c linux/lib/rwsem.c
--- v2.4.3/linux/lib/rwsem.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/rwsem.c	Wed Apr 25 13:31:03 2001
@@ -0,0 +1,210 @@
+/* rwsem.c: R/W semaphores: contention handling functions
+ *
+ * Written by David Howells (dhowells@redhat.com).
+ * Derived from arch/i386/kernel/semaphore.c
+ */
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+struct rwsem_waiter {
+	struct list_head	list;
+	struct task_struct	*task;
+	unsigned int		flags;
+#define RWSEM_WAITING_FOR_READ	0x00000001
+#define RWSEM_WAITING_FOR_WRITE	0x00000002
+};
+
+#if RWSEM_DEBUG
+#undef rwsemtrace
+void rwsemtrace(struct rw_semaphore *sem, const char *str)
+{
+	printk("sem=%p\n",sem);
+	printk("(sem)=%08lx\n",sem->count);
+	if (sem->debug)
+		printk("[%d] %s({%08lx})\n",current->pid,str,sem->count);
+}
+#endif
+
+/*
+ * handle the lock being released whilst there are processes blocked on it that can now run
+ * - if we come here, then:
+ *   - the 'active part' of the count (&0x0000ffff) reached zero but has been re-incremented
+ *   - the 'waiting part' of the count (&0xffff0000) is negative (and will still be so)
+ *   - there must be someone on the queue
+ * - the spinlock must be held by the caller
+ * - woken process blocks are discarded from the list after having flags zeroised
+ */
+static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter *waiter;
+	struct list_head *next;
+	signed long oldcount;
+	int woken, loop;
+
+	rwsemtrace(sem,"Entering __rwsem_do_wake");
+
+	/* only wake someone up if we can transition the active part of the count from 0 -> 1 */
+ try_again:
+	oldcount = rwsem_atomic_update(RWSEM_ACTIVE_BIAS,sem) - RWSEM_ACTIVE_BIAS;
+	if (oldcount & RWSEM_ACTIVE_MASK)
+		goto undo;
+
+	waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
+
+	/* try to grant a single write lock if there's a writer at the front of the queue
+	 * - note we leave the 'active part' of the count incremented by 1 and the waiting part
+	 *   incremented by 0x00010000
+	 */
+	if (!(waiter->flags & RWSEM_WAITING_FOR_WRITE))
+		goto readers_only;
+
+	list_del(&waiter->list);
+	waiter->flags = 0;
+	wake_up_process(waiter->task);
+	goto out;
+
+	/* grant an infinite number of read locks to the readers at the front of the queue
+	 * - note we increment the 'active part' of the count by the number of readers (less one
+	 *   for the activity decrement we've already done) before waking any processes up
+	 */
+ readers_only:
+	woken = 0;
+	do {
+		woken++;
+
+		if (waiter->list.next==&sem->wait_list)
+			break;
+
+		waiter = list_entry(waiter->list.next,struct rwsem_waiter,list);
+
+	} while (waiter->flags & RWSEM_WAITING_FOR_READ);
+
+	loop = woken;
+	woken *= RWSEM_ACTIVE_BIAS-RWSEM_WAITING_BIAS;
+	woken -= RWSEM_ACTIVE_BIAS;
+	rwsem_atomic_add(woken,sem);
+
+	next = sem->wait_list.next;
+	for (; loop>0; loop--) {
+		waiter = list_entry(next,struct rwsem_waiter,list);
+		next = waiter->list.next;
+		waiter->flags = 0;
+		wake_up_process(waiter->task);
+	}
+
+	sem->wait_list.next = next;
+	next->prev = &sem->wait_list;
+
+ out:
+	rwsemtrace(sem,"Leaving __rwsem_do_wake");
+	return sem;
+
+	/* undo the change to count, but check for a transition 1->0 */
+ undo:
+	if (rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem)!=0)
+		goto out;
+	goto try_again;
+}
+
+/*
+ * wait for a lock to be granted
+ */
+static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore *sem,
+								 struct rwsem_waiter *waiter,
+								 __s32 adjustment)
+{
+	struct task_struct *tsk = current;
+	signed long count;
+
+	set_task_state(tsk,TASK_UNINTERRUPTIBLE);
+
+	/* set up my own style of waitqueue */
+	spin_lock(&sem->wait_lock);
+	waiter->task = tsk;
+
+	list_add_tail(&waiter->list,&sem->wait_list);
+
+	/* note that we're now waiting on the lock, but no longer actively read-locking */
+	count = rwsem_atomic_update(adjustment,sem);
+
+	/* if there are no longer active locks, wake the front queued process(es) up
+	 * - it might even be this process, since the waker takes a more active part
+	 */
+	if (!(count & RWSEM_ACTIVE_MASK))
+		sem = __rwsem_do_wake(sem);
+
+	spin_unlock(&sem->wait_lock);
+
+	/* wait to be given the lock */
+	for (;;) {
+		if (!waiter->flags)
+			break;
+		schedule();
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	}
+
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+/*
+ * wait for the read lock to be granted
+ */
+struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter waiter;
+
+	rwsemtrace(sem,"Entering rwsem_down_read_failed");
+
+	waiter.flags = RWSEM_WAITING_FOR_READ;
+	rwsem_down_failed_common(sem,&waiter,RWSEM_WAITING_BIAS-RWSEM_ACTIVE_BIAS);
+
+	rwsemtrace(sem,"Leaving rwsem_down_read_failed");
+	return sem;
+}
+
+/*
+ * wait for the write lock to be granted
+ */
+struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem)
+{
+	struct rwsem_waiter waiter;
+
+	rwsemtrace(sem,"Entering rwsem_down_write_failed");
+
+	waiter.flags = RWSEM_WAITING_FOR_WRITE;
+	rwsem_down_failed_common(sem,&waiter,-RWSEM_ACTIVE_BIAS);
+
+	rwsemtrace(sem,"Leaving rwsem_down_write_failed");
+	return sem;
+}
+
+/*
+ * handle waking up a waiter on the semaphore
+ * - up_read has decremented the active part of the count if we come here
+ */
+struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
+{
+	rwsemtrace(sem,"Entering rwsem_wake");
+
+	spin_lock(&sem->wait_lock);
+
+	/* do nothing if list empty */
+	if (!list_empty(&sem->wait_list))
+		sem = __rwsem_do_wake(sem);
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving rwsem_wake");
+
+	return sem;
+}
+
+EXPORT_SYMBOL(rwsem_down_read_failed);
+EXPORT_SYMBOL(rwsem_down_write_failed);
+EXPORT_SYMBOL(rwsem_wake);
+#if RWSEM_DEBUG
+EXPORT_SYMBOL(rwsemtrace);
+#endif
diff -u --recursive --new-file v2.4.3/linux/lib/string.c linux/lib/string.c
--- v2.4.3/linux/lib/string.c	Tue Mar  6 19:44:37 2001
+++ linux/lib/string.c	Fri Apr  6 10:51:19 2001
@@ -350,6 +350,8 @@
  * @s: Pointer to the start of the area.
  * @c: The byte to fill the area with
  * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
  */
 void * memset(void * s,int c,size_t count)
 {
@@ -369,11 +371,11 @@
  * @dest: Where to copy to
  * @count: The size of the area.
  *
- * When using copies for I/O remember that bcopy and memcpy are entitled
- * to do out of order writes and may well exactly that.
+ * Note that this is the same as memcpy(), with the arguments reversed.
+ * memcpy() is the standard, bcopy() is a legacy BSD function.
  *
- * Note that this is the same as memcpy, with the arguments reversed. memcpy
- * is the standard, bcopy is a legacy BSD function.
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
  */
 char * bcopy(const char * src, char * dest, int count)
 {
@@ -393,8 +395,8 @@
  * @src: Where to copy from
  * @count: The size of the area.
  *
- * When using copies for I/O remember that bcopy and memcpy are entitled
- * to do out of order writes and may well exactly that.
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
  */
 void * memcpy(void * dest,const void *src,size_t count)
 {
@@ -414,7 +416,7 @@
  * @src: Where to copy from
  * @count: The size of the area.
  *
- * memmove copes with overlapping areas.
+ * Unlike memcpy(), memmove() copes with overlapping areas.
  */
 void * memmove(void * dest,const void *src,size_t count)
 {
@@ -439,7 +441,7 @@
 
 #ifndef __HAVE_ARCH_MEMCMP
 /**
- * memmove - Compare two areas of memory
+ * memcmp - Compare two areas of memory
  * @cs: One area of memory
  * @ct: Another area of memory
  * @count: The size of the area.
diff -u --recursive --new-file v2.4.3/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.4.3/linux/lib/vsprintf.c	Tue Mar  6 19:44:37 2001
+++ linux/lib/vsprintf.c	Fri Apr 13 20:26:07 2001
@@ -377,7 +377,7 @@
  * sprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @fmt: The format string to use
- * @args: Arguments for the format string
+ * @...: Arguments for the format string
  */
 int sprintf(char * buf, const char *fmt, ...)
 {
diff -u --recursive --new-file v2.4.3/linux/mm/bootmem.c linux/mm/bootmem.c
--- v2.4.3/linux/mm/bootmem.c	Wed Oct 18 15:18:41 2000
+++ linux/mm/bootmem.c	Fri Apr 13 20:26:07 2001
@@ -176,6 +176,7 @@
 		preferred = 0;
 		goto restart_scan;
 	}
+	return NULL;
 found:
 	if (start >= eidx)
 		BUG();
@@ -316,7 +317,8 @@
 	/*
 	 * Whoops, we cannot satisfy the allocation request.
 	 */
-	BUG();
+	printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+	panic("Out of memory");
 	return NULL;
 }
 
diff -u --recursive --new-file v2.4.3/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.3/linux/mm/filemap.c	Fri Mar 23 14:38:48 2001
+++ linux/mm/filemap.c	Wed Apr 25 16:13:50 2001
@@ -108,7 +108,6 @@
 	if (PageDirty(page)) BUG();
 	remove_page_from_inode_queue(page);
 	remove_page_from_hash_queue(page);
-	page->mapping = NULL;
 }
 
 void remove_inode_page(struct page *page)
@@ -679,6 +678,34 @@
 }
 
 /*
+ * Find a swapcache page (and get a reference) or return NULL.
+ * The SwapCache check is protected by the pagecache lock.
+ */
+struct page * __find_get_swapcache_page(struct address_space *mapping,
+			      unsigned long offset, struct page **hash)
+{
+	struct page *page;
+
+	/*
+	 * We need the LRU lock to protect against page_launder().
+	 */
+
+	spin_lock(&pagecache_lock);
+	page = __find_page_nolock(mapping, offset, *hash);
+	if (page) {
+		spin_lock(&pagemap_lru_lock);
+		if (PageSwapCache(page)) 
+			page_cache_get(page);
+		else
+			page = NULL;
+		spin_unlock(&pagemap_lru_lock);
+	}
+	spin_unlock(&pagecache_lock);
+
+	return page;
+}
+
+/*
  * Same as the above, but lock the page too, verifying that
  * it's still valid once we own it.
  */
@@ -1062,7 +1089,7 @@
 
 	for (;;) {
 		struct page *page, **hash;
-		unsigned long end_index, nr;
+		unsigned long end_index, nr, ret;
 
 		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 		if (index > end_index)
@@ -1110,13 +1137,13 @@
 		 * "pos" here (the actor routine has to update the user buffer
 		 * pointers and the remaining count).
 		 */
-		nr = actor(desc, page, offset, nr);
-		offset += nr;
+		ret = actor(desc, page, offset, nr);
+		offset += ret;
 		index += offset >> PAGE_CACHE_SHIFT;
 		offset &= ~PAGE_CACHE_MASK;
 	
 		page_cache_release(page);
-		if (nr && desc->count)
+		if (ret == nr && desc->count)
 			continue;
 		break;
 
@@ -1209,7 +1236,7 @@
 	UPDATE_ATIME(inode);
 }
 
-static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
+int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
 {
 	char *kaddr;
 	unsigned long left, count = desc->count;
@@ -1262,21 +1289,29 @@
 
 static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size)
 {
-	char *kaddr;
 	ssize_t written;
 	unsigned long count = desc->count;
 	struct file *file = (struct file *) desc->buf;
-	mm_segment_t old_fs;
 
 	if (size > count)
 		size = count;
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
 
-	kaddr = kmap(page);
-	written = file->f_op->write(file, kaddr + offset, size, &file->f_pos);
-	kunmap(page);
-	set_fs(old_fs);
+ 	if (file->f_op->sendpage) {
+ 		written = file->f_op->sendpage(file, page, offset,
+					       size, &file->f_pos, size<count);
+	} else {
+		char *kaddr;
+		mm_segment_t old_fs;
+
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+
+		kaddr = kmap(page);
+		written = file->f_op->write(file, kaddr + offset, size, &file->f_pos);
+		kunmap(page);
+
+		set_fs(old_fs);
+	}
 	if (written < 0) {
 		desc->error = written;
 		written = 0;
@@ -2408,7 +2443,7 @@
 	return page;
 }
 
-static inline void remove_suid(struct inode *inode)
+inline void remove_suid(struct inode *inode)
 {
 	unsigned int mode;
 
@@ -2449,9 +2484,13 @@
 	unsigned long	written;
 	long		status;
 	int		err;
+	unsigned	bytes;
 
 	cached_page = NULL;
 
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
+		
 	down(&inode->i_sem);
 
 	pos = *ppos;
@@ -2474,26 +2513,64 @@
 	 * Check whether we've reached the file size limit.
 	 */
 	err = -EFBIG;
+	
 	if (limit != RLIM_INFINITY) {
 		if (pos >= limit) {
 			send_sig(SIGXFSZ, current, 0);
 			goto out;
 		}
-		if (count > limit - pos) {
+		if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) {
+			/* send_sig(SIGXFSZ, current, 0); */
+			count = limit - (u32)pos;
+		}
+	}
+
+	/*
+	 *	LFS rule 
+	 */
+	if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
+		if (pos >= MAX_NON_LFS) {
 			send_sig(SIGXFSZ, current, 0);
-			count = limit - pos;
+			goto out;
+		}
+		if (count > MAX_NON_LFS - (u32)pos) {
+			/* send_sig(SIGXFSZ, current, 0); */
+			count = MAX_NON_LFS - (u32)pos;
 		}
 	}
 
-	status  = 0;
-	if (count) {
-		remove_suid(inode);
-		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-		mark_inode_dirty_sync(inode);
+	/*
+	 *	Are we about to exceed the fs block limit ?
+	 *
+	 *	If we have written data it becomes a short write
+	 *	If we have exceeded without writing data we send
+	 *	a signal and give them an EFBIG.
+	 *
+	 *	Linus frestrict idea will clean these up nicely..
+	 */
+	 
+	if (pos > inode->i_sb->s_maxbytes)
+	{
+		send_sig(SIGXFSZ, current, 0);
+		err = -EFBIG;
+		goto out;	
+	}
+
+	if (pos + count > inode->i_sb->s_maxbytes)
+		count = inode->i_sb->s_maxbytes - pos;
+
+	if (count == 0) {
+		err = 0;
+		goto out;
 	}
 
+	status  = 0;
+	remove_suid(inode);
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+
 	while (count) {
-		unsigned long bytes, index, offset;
+		unsigned long index, offset;
 		char *kaddr;
 		int deactivate = 1;
 
@@ -2534,7 +2611,7 @@
 		if (status)
 			goto unlock;
 		kaddr = page_address(page);
-		status = copy_from_user(kaddr+offset, buf, bytes);
+		status = __copy_from_user(kaddr+offset, buf, bytes);
 		flush_dcache_page(page);
 		if (status)
 			goto fail_write;
diff -u --recursive --new-file v2.4.3/linux/mm/memory.c linux/mm/memory.c
--- v2.4.3/linux/mm/memory.c	Mon Mar 26 11:02:24 2001
+++ linux/mm/memory.c	Wed Apr 25 14:46:21 2001
@@ -274,7 +274,7 @@
 		 */
 		if (pte_dirty(pte) && page->mapping)
 			set_page_dirty(page);
-		free_page_and_swap_cache(page);
+		page_cache_release(page);
 		return 1;
 	}
 	swap_free(pte_to_swp_entry(pte));
@@ -815,6 +815,24 @@
 }
 
 /*
+ * Work out if there are any other processes sharing this
+ * swap cache page. Never mind the buffers.
+ */
+static inline int exclusive_swap_page(struct page *page)
+{
+	unsigned int count;
+
+	if (!PageLocked(page))
+		BUG();
+	if (!PageSwapCache(page))
+		return 0;
+	count = page_count(page) - !!page->buffers;	/*  2: us + swap cache */
+	count += swap_count(page);			/* +1: just swap cache */
+	return count == 3;				/* =3: total */
+}
+
+
+/*
  * This routine handles present pages, when users try to write
  * to a shared page. It is done by copying the page to a new address
  * and decrementing the shared-page counter for the old page.
@@ -853,19 +871,21 @@
 	 *   marked dirty).
 	 */
 	switch (page_count(old_page)) {
+	int can_reuse;
+	case 3:
+		if (!old_page->buffers)
+			break;
+		/* FallThrough */
 	case 2:
-		/*
-		 * Lock the page so that no one can look it up from
-		 * the swap cache, grab a reference and start using it.
-		 * Can not do lock_page, holding page_table_lock.
-		 */
-		if (!PageSwapCache(old_page) || TryLockPage(old_page))
+		if (!PageSwapCache(old_page))
 			break;
-		if (is_page_shared(old_page)) {
-			UnlockPage(old_page);
+		if (TryLockPage(old_page))
 			break;
-		}
+		/* Recheck swapcachedness once the page is locked */
+		can_reuse = exclusive_swap_page(old_page);
 		UnlockPage(old_page);
+		if (!can_reuse)
+			break;
 		/* FallThrough */
 	case 1:
 		if (PageReserved(old_page))
@@ -903,8 +923,7 @@
 	return -1;
 }
 
-static void vmtruncate_list(struct vm_area_struct *mpnt,
-			    unsigned long pgoff, unsigned long partial)
+static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
 {
 	do {
 		struct mm_struct *mm = mpnt->vm_mm;
@@ -947,7 +966,7 @@
  */
 void vmtruncate(struct inode * inode, loff_t offset)
 {
-	unsigned long partial, pgoff;
+	unsigned long pgoff;
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long limit;
 
@@ -959,19 +978,15 @@
 		goto out_unlock;
 
 	pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1);
-
 	if (mapping->i_mmap != NULL)
-		vmtruncate_list(mapping->i_mmap, pgoff, partial);
+		vmtruncate_list(mapping->i_mmap, pgoff);
 	if (mapping->i_mmap_shared != NULL)
-		vmtruncate_list(mapping->i_mmap_shared, pgoff, partial);
+		vmtruncate_list(mapping->i_mmap_shared, pgoff);
 
 out_unlock:
 	spin_unlock(&mapping->i_shared_lock);
 	truncate_inode_pages(mapping, offset);
-	if (inode->i_op && inode->i_op->truncate)
-		inode->i_op->truncate(inode);
-	return;
+	goto out_truncate;
 
 do_expand:
 	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
@@ -986,8 +1001,13 @@
 		}
 	}
 	inode->i_size = offset;
-	if (inode->i_op && inode->i_op->truncate)
+
+out_truncate:
+	if (inode->i_op && inode->i_op->truncate) {
+		lock_kernel();
 		inode->i_op->truncate(inode);
+		unlock_kernel();
+	}
 out:
 	return;
 }
@@ -1020,7 +1040,7 @@
 			break;
 		}
 		/* Ok, do the async read-ahead now */
-		new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
+		new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset));
 		if (new_page != NULL)
 			page_cache_release(new_page);
 		swap_free(SWP_ENTRY(SWP_TYPE(entry), offset));
@@ -1043,13 +1063,13 @@
 	if (!page) {
 		lock_kernel();
 		swapin_readahead(entry);
-		page = read_swap_cache(entry);
+		page = read_swap_cache_async(entry);
 		unlock_kernel();
 		if (!page) {
 			spin_lock(&mm->page_table_lock);
 			return -1;
 		}
-
+		wait_on_page(page);
 		flush_page_to_ram(page);
 		flush_icache_page(vma, page);
 	}
@@ -1077,7 +1097,7 @@
 	pte = mk_pte(page, vma->vm_page_prot);
 
 	swap_free(entry);
-	if (write_access && !is_page_shared(page))
+	if (write_access && exclusive_swap_page(page))
 		pte = pte_mkwrite(pte_mkdirty(pte));
 	UnlockPage(page);
 
diff -u --recursive --new-file v2.4.3/linux/mm/mmap.c linux/mm/mmap.c
--- v2.4.3/linux/mm/mmap.c	Wed Mar 28 12:55:34 2001
+++ linux/mm/mmap.c	Fri Apr 13 20:15:55 2001
@@ -64,6 +64,15 @@
 	free += atomic_read(&page_cache_size);
 	free += nr_free_pages();
 	free += nr_swap_pages;
+
+	/*
+	 * This double-counts: the nrpages are both in the page-cache
+	 * and in the swapper space. At the same time, this compensates
+	 * for the swap-space over-allocation (ie "nr_swap_pages" being
+	 * too small. 
+	 */
+	free += swapper_space.nrpages;
+
 	/*
 	 * The code below doesn't account for free space in the inode
 	 * and dentry slab cache, slab cache fragmentation, inodes and
@@ -224,14 +233,9 @@
 	/* Obtain the address to map to. we verify (or select) it and ensure
 	 * that it represents a valid section of the address space.
 	 */
-	if (flags & MAP_FIXED) {
-		if (addr & ~PAGE_MASK)
-			return -EINVAL;
-	} else {
-		addr = get_unmapped_area(addr, len);
-		if (!addr)
-			return -ENOMEM;
-	}
+	addr = get_unmapped_area(file, addr, len, pgoff, flags);
+	if (addr & ~PAGE_MASK)
+		return addr;
 
 	/* Do simple checking here so the lower-level routines won't have
 	 * to. we assume access permissions have been handled by the open
@@ -384,30 +388,53 @@
 }
 
 /* Get an address range which is currently unmapped.
- * For mmap() without MAP_FIXED and shmat() with addr=0.
- * Return value 0 means ENOMEM.
+ * For shmat() with addr=0.
+ *
+ * Ugly calling convention alert:
+ * Return value with the low bits set means error value,
+ * ie
+ *	if (ret & ~PAGE_MASK)
+ *		error = ret;
+ *
+ * This function "knows" that -ENOMEM has the bits set.
  */
 #ifndef HAVE_ARCH_UNMAPPED_AREA
-unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
+static inline unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
-	struct vm_area_struct * vmm;
+	struct vm_area_struct *vma;
 
 	if (len > TASK_SIZE)
-		return 0;
+		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 	addr = PAGE_ALIGN(addr);
 
-	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
-		/* At this point:  (!vmm || addr < vmm->vm_end). */
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
 		if (TASK_SIZE - len < addr)
-			return 0;
-		if (!vmm || addr + len <= vmm->vm_start)
+			return -ENOMEM;
+		if (!vma || addr + len <= vma->vm_start)
 			return addr;
-		addr = vmm->vm_end;
+		addr = vma->vm_end;
 	}
 }
-#endif
+#else
+extern unsigned long arch_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+#endif	
+
+unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	if (flags & MAP_FIXED) {
+		if (addr & ~PAGE_MASK)
+			return -EINVAL;
+		return addr;
+	}
+
+	if (file && file->f_op && file->f_op->get_unmapped_area)
+		return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags);
+
+	return arch_get_unmapped_area(file, addr, len, pgoff, flags);
+}
 
 #define vm_avl_empty	(struct vm_area_struct *) NULL
 
diff -u --recursive --new-file v2.4.3/linux/mm/mremap.c linux/mm/mremap.c
--- v2.4.3/linux/mm/mremap.c	Mon Mar 19 17:17:43 2001
+++ linux/mm/mremap.c	Fri Apr 13 15:17:21 2001
@@ -276,8 +276,13 @@
 	ret = -ENOMEM;
 	if (flags & MREMAP_MAYMOVE) {
 		if (!(flags & MREMAP_FIXED)) {
-			new_addr = get_unmapped_area(0, new_len);
-			if (!new_addr)
+			unsigned long map_flags = 0;
+			if (vma->vm_flags & VM_SHARED)
+				map_flags |= MAP_SHARED;
+
+			new_addr = get_unmapped_area(vma->vm_file, 0, new_len, vma->vm_pgoff, map_flags);
+			ret = new_addr;
+			if (new_addr & ~PAGE_MASK)
 				goto out;
 		}
 		ret = move_vma(vma, addr, old_len, new_len, new_addr);
diff -u --recursive --new-file v2.4.3/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.4.3/linux/mm/page_alloc.c	Tue Mar 20 15:05:46 2001
+++ linux/mm/page_alloc.c	Wed Apr 25 14:44:38 2001
@@ -454,7 +454,6 @@
 		if (gfp_mask & __GFP_WAIT) {
 			memory_pressure++;
 			try_to_free_pages(gfp_mask);
-			wakeup_bdflush(0);
 			goto try_again;
 		}
 	}
diff -u --recursive --new-file v2.4.3/linux/mm/page_io.c linux/mm/page_io.c
--- v2.4.3/linux/mm/page_io.c	Mon Dec  4 15:38:02 2000
+++ linux/mm/page_io.c	Wed Apr 25 14:46:21 2001
@@ -33,7 +33,7 @@
  * that shared pages stay shared while being swapped.
  */
 
-static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page, int wait)
+static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
 {
 	unsigned long offset;
 	int zones[PAGE_SIZE/512];
@@ -41,6 +41,7 @@
 	kdev_t dev = 0;
 	int block_size;
 	struct inode *swapf = 0;
+	int wait = 0;
 
 	/* Don't allow too many pending pages in flight.. */
 	if ((rw == WRITE) && atomic_read(&nr_async_pages) >
@@ -104,7 +105,7 @@
  *  - it's marked as being swap-cache
  *  - it's associated with the swap inode
  */
-void rw_swap_page(int rw, struct page *page, int wait)
+void rw_swap_page(int rw, struct page *page)
 {
 	swp_entry_t entry;
 
@@ -116,7 +117,7 @@
 		PAGE_BUG(page);
 	if (page->mapping != &swapper_space)
 		PAGE_BUG(page);
-	if (!rw_swap_page_base(rw, entry, page, wait))
+	if (!rw_swap_page_base(rw, entry, page))
 		UnlockPage(page);
 }
 
@@ -125,7 +126,7 @@
  * Therefore we can't use it.  Later when we can remove the need for the
  * lock map and we can reduce the number of functions exported.
  */
-void rw_swap_page_nolock(int rw, swp_entry_t entry, char *buf, int wait)
+void rw_swap_page_nolock(int rw, swp_entry_t entry, char *buf)
 {
 	struct page *page = virt_to_page(buf);
 	
@@ -137,7 +138,8 @@
 		PAGE_BUG(page);
 	/* needs sync_page to wait I/O completation */
 	page->mapping = &swapper_space;
-	if (!rw_swap_page_base(rw, entry, page, wait))
+	if (!rw_swap_page_base(rw, entry, page))
 		UnlockPage(page);
+	wait_on_page(page);
 	page->mapping = NULL;
 }
diff -u --recursive --new-file v2.4.3/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.3/linux/mm/shmem.c	Fri Mar  2 15:16:59 2001
+++ linux/mm/shmem.c	Wed Apr 25 14:46:21 2001
@@ -1,5 +1,5 @@
 /*
- * Resizable simple shmem filesystem for Linux.
+ * Resizable virtual memory filesystem for Linux.
  *
  * Copyright (C) 2000 Linus Torvalds.
  *		 2000 Transmeta Corp.
@@ -9,14 +9,12 @@
  */
 
 /*
- * This shared memory handling is heavily based on the ramfs. It
- * extends the ramfs by the ability to use swap which would makes it a
- * completely usable filesystem.
- *
- * But read and write are not supported (yet)
- *
+ * This virtual memory filesystem is heavily based on the ramfs. It
+ * extends ramfs by the ability to use swap and honor resource limits
+ * which makes it a completely usable filesystem.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
@@ -31,7 +29,8 @@
 
 #include <asm/uaccess.h>
 
-#define SHMEM_MAGIC	0x01021994
+/* This magic number is used in glibc for posix shared memory */
+#define TMPFS_MAGIC	0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
 #define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT)
@@ -42,52 +41,90 @@
 static struct inode_operations shmem_inode_operations;
 static struct file_operations shmem_dir_operations;
 static struct inode_operations shmem_dir_inode_operations;
-static struct vm_operations_struct shmem_shared_vm_ops;
-static struct vm_operations_struct shmem_private_vm_ops;
+static struct inode_operations shmem_symlink_inode_operations;
+static struct vm_operations_struct shmem_vm_ops;
 
 LIST_HEAD (shmem_inodes);
 static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
 
+#define BLOCKS_PER_PAGE (PAGE_SIZE/512)
+
+/*
+ * shmem_recalc_inode - recalculate the size of an inode
+ *
+ * @inode: inode to recalc
+ *
+ * We have to calculate the free blocks since the mm can drop pages
+ * behind our back
+ *
+ * But we know that normally
+ * inodes->i_blocks/BLOCKS_PER_PAGE == 
+ * 			inode->i_mapping->nrpages + info->swapped
+ *
+ * So the mm freed 
+ * inodes->i_blocks/BLOCKS_PER_PAGE - 
+ *			(inode->i_mapping->nrpages + info->swapped)
+ *
+ * It has to be called with the spinlock held.
+ */
+
+static void shmem_recalc_inode(struct inode * inode)
+{
+	unsigned long freed;
+
+	freed = (inode->i_blocks/BLOCKS_PER_PAGE) -
+		(inode->i_mapping->nrpages + inode->u.shmem_i.swapped);
+	if (freed){
+		struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb;
+		inode->i_blocks -= freed*BLOCKS_PER_PAGE;
+		spin_lock (&info->stat_lock);
+		info->free_blocks += freed;
+		spin_unlock (&info->stat_lock);
+	}
+}
+
 static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index) 
 {
+	unsigned long offset;
+
 	if (index < SHMEM_NR_DIRECT)
 		return info->i_direct+index;
 
 	index -= SHMEM_NR_DIRECT;
-	if (index >= ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
-		return NULL;
+	offset = index % ENTRIES_PER_PAGE;
+	index /= ENTRIES_PER_PAGE;
+
+	if (index >= ENTRIES_PER_PAGE)
+		return ERR_PTR(-EFBIG);
 
 	if (!info->i_indirect) {
 		info->i_indirect = (swp_entry_t **) get_zeroed_page(GFP_USER);
 		if (!info->i_indirect)
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 	}
-	if(!(info->i_indirect[index/ENTRIES_PER_PAGE])) {
-		info->i_indirect[index/ENTRIES_PER_PAGE] = (swp_entry_t *) get_zeroed_page(GFP_USER);
-		if (!info->i_indirect[index/ENTRIES_PER_PAGE])
-			return NULL;
+	if(!(info->i_indirect[index])) {
+		info->i_indirect[index] = (swp_entry_t *) get_zeroed_page(GFP_USER);
+		if (!info->i_indirect[index])
+			return ERR_PTR(-ENOMEM);
 	}
 	
-	return info->i_indirect[index/ENTRIES_PER_PAGE]+index%ENTRIES_PER_PAGE;
+	return info->i_indirect[index]+offset;
 }
 
 static int shmem_free_swp(swp_entry_t *dir, unsigned int count)
 {
 	swp_entry_t *ptr, entry;
-	struct page * page;
 	int freed = 0;
 
 	for (ptr = dir; ptr < dir + count; ptr++) {
 		if (!ptr->val)
 			continue;
 		entry = *ptr;
-		swap_free (entry);
 		*ptr = (swp_entry_t){0};
 		freed++;
-		if (!(page = lookup_swap_cache(entry)))
-			continue;
-		delete_from_swap_cache(page);
-		page_cache_release(page);
+
+		/* vmscan will do the actual page freeing later.. */
+		swap_free (entry);
 	}
 	return freed;
 }
@@ -98,7 +135,6 @@
  * @dir:	pointer to swp_entries 
  * @size:	number of entries in dir
  * @start:	offset to start from
- * @inode:	inode for statistics
  * @freed:	counter for freed pages
  *
  * It frees the swap entries from dir+start til dir+size
@@ -108,7 +144,7 @@
 
 static unsigned long 
 shmem_truncate_part (swp_entry_t * dir, unsigned long size, 
-		     unsigned long start, struct inode * inode, unsigned long *freed) {
+		     unsigned long start, unsigned long *freed) {
 	if (start > size)
 		return start - size;
 	if (dir)
@@ -117,56 +153,28 @@
 	return 0;
 }
 
-/*
- * shmem_recalc_inode - recalculate the size of an inode
- *
- * @inode: inode to recalc
- *
- * We have to calculate the free blocks since the mm can drop pages
- * behind our back
- *
- * But we know that normally
- * inodes->i_blocks == inode->i_mapping->nrpages + info->swapped
- *
- * So the mm freed 
- * inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped)
- *
- * It has to be called with the spinlock held.
- */
-
-static void shmem_recalc_inode(struct inode * inode)
-{
-	unsigned long freed;
-
-	freed = inode->i_blocks -
-		(inode->i_mapping->nrpages + inode->u.shmem_i.swapped);
-	if (freed){
-		struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb;
-		inode->i_blocks -= freed;
-		spin_lock (&info->stat_lock);
-		info->free_blocks += freed;
-		spin_unlock (&info->stat_lock);
-	}
-}
-
 static void shmem_truncate (struct inode * inode)
 {
 	int clear_base;
-	unsigned long start;
+	unsigned long index, start;
 	unsigned long freed = 0;
-	swp_entry_t **base, **ptr;
+	swp_entry_t **base, **ptr, **last;
 	struct shmem_inode_info * info = &inode->u.shmem_i;
 
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	spin_lock (&info->lock);
-	start = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	if (index > info->max_index)
+		goto out;
 
-	start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, start, inode, &freed);
+	start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, index, &freed);
 
 	if (!(base = info->i_indirect))
-		goto out;;
+		goto out;
 
 	clear_base = 1;
-	for (ptr = base; ptr < base + ENTRIES_PER_PAGE; ptr++) {
+	last = base + ((info->max_index - SHMEM_NR_DIRECT + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE);
+	for (ptr = base; ptr < last; ptr++) {
 		if (!start) {
 			if (!*ptr)
 				continue;
@@ -176,16 +184,16 @@
 			continue;
 		}
 		clear_base = 0;
-		start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, inode, &freed);
+		start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, &freed);
 	}
 
-	if (!clear_base) 
-		goto out;
-
-	free_page ((unsigned long)base);
-	info->i_indirect = 0;
+	if (clear_base) {
+		free_page ((unsigned long)base);
+		info->i_indirect = 0;
+	}
 
 out:
+	info->max_index = index;
 	info->swapped -= freed;
 	shmem_recalc_inode(inode);
 	spin_unlock (&info->lock);
@@ -207,34 +215,44 @@
 }
 
 /*
- * Move the page from the page cache to the swap cache
+ * Move the page from the page cache to the swap cache.
+ *
+ * The page lock prevents multiple occurences of shmem_writepage at
+ * once.  We still need to guard against racing with
+ * shmem_getpage_locked().  
  */
 static int shmem_writepage(struct page * page)
 {
-	int error;
+	int error = 0;
 	struct shmem_inode_info *info;
 	swp_entry_t *entry, swap;
+	struct inode *inode;
 
-	info = &page->mapping->host->u.shmem_i;
+	if (!PageLocked(page))
+		BUG();
+	
+	/* Only move to the swap cache if there are no other users of
+	 * the page. */
+	if (atomic_read(&page->count) > 2)
+		goto out;
+	
+	inode = page->mapping->host;
+	info = &inode->u.shmem_i;
 	swap = __get_swap_page(2);
-	if (!swap.val) {
-		set_page_dirty(page);
-		UnlockPage(page);
-		return -ENOMEM;
-	}
+	error = -ENOMEM;
+	if (!swap.val)
+		goto out;
 
 	spin_lock(&info->lock);
-	shmem_recalc_inode(page->mapping->host);
-	entry = shmem_swp_entry (info, page->index);
-	if (!entry)	/* this had been allocted on page allocation */
+	entry = shmem_swp_entry(info, page->index);
+	if (IS_ERR(entry))	/* this had been allocted on page allocation */
 		BUG();
+	shmem_recalc_inode(page->mapping->host);
 	error = -EAGAIN;
-	if (entry->val) {
-                __swap_free(swap, 2);
-		goto out;
-        }
+	if (entry->val)
+		BUG();
 
-        *entry = swap;
+	*entry = swap;
 	error = 0;
 	/* Remove the from the page cache */
 	lru_cache_del(page);
@@ -243,99 +261,186 @@
 	/* Add it to the swap cache */
 	add_to_swap_cache(page, swap);
 	page_cache_release(page);
-	set_page_dirty(page);
 	info->swapped++;
-out:
+
 	spin_unlock(&info->lock);
+out:
+	set_page_dirty(page);
 	UnlockPage(page);
 	return error;
 }
 
 /*
- * shmem_nopage - either get the page from swap or allocate a new one
+ * shmem_getpage_locked - either get the page from swap or allocate a new one
  *
  * If we allocate a new one we do not mark it dirty. That's up to the
  * vm. If we swap it in we mark it dirty since we also free the swap
  * entry since a page cannot live in both the swap and page cache
+ *
+ * Called with the inode locked, so it cannot race with itself, but we
+ * still need to guard against racing with shm_writepage(), which might
+ * be trying to move the page to the swap cache as we run.
  */
-struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share)
+static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx)
 {
-	unsigned long size;
-	struct page * page;
-	unsigned int idx;
-	swp_entry_t *entry;
-	struct inode * inode = vma->vm_file->f_dentry->d_inode;
 	struct address_space * mapping = inode->i_mapping;
 	struct shmem_inode_info *info;
+	struct page * page;
+	swp_entry_t *entry;
 
-	idx = (address - vma->vm_start) >> PAGE_SHIFT;
-	idx += vma->vm_pgoff;
-
-	down (&inode->i_sem);
-	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	page = NOPAGE_SIGBUS;
-	if ((idx >= size) && (vma->vm_mm == current->mm))
-		goto out;
+	info = &inode->u.shmem_i;
 
-	/* retry, we may have slept */
-	page = __find_lock_page(mapping, idx, page_hash (mapping, idx));
+repeat:
+	page = find_lock_page(mapping, idx);
 	if (page)
-		goto cached_page;
+		return page;
 
-	info = &inode->u.shmem_i;
 	entry = shmem_swp_entry (info, idx);
-	if (!entry)
-		goto oom;
+	if (IS_ERR(entry))
+		return (void *)entry;
+
 	spin_lock (&info->lock);
-	shmem_recalc_inode(inode);
-	spin_unlock (&info->lock);
+	
+	/* The shmem_swp_entry() call may have blocked, and
+	 * shmem_writepage may have been moving a page between the page
+	 * cache and swap cache.  We need to recheck the page cache
+	 * under the protection of the info->lock spinlock. */
+
+	page = __find_get_page(mapping, idx, page_hash(mapping, idx));
+	if (page) {
+		if (TryLockPage(page))
+			goto wait_retry;
+		spin_unlock (&info->lock);
+		return page;
+	}
+	
 	if (entry->val) {
 		unsigned long flags;
 
 		/* Look it up and read it in.. */
-		page = lookup_swap_cache(*entry);
+		page = __find_get_page(&swapper_space, entry->val,
+				       page_hash(&swapper_space, entry->val));
 		if (!page) {
+			spin_unlock (&info->lock);
 			lock_kernel();
 			swapin_readahead(*entry);
-			page = read_swap_cache(*entry);
+			page = read_swap_cache_async(*entry);
 			unlock_kernel();
 			if (!page) 
-				goto oom;
+				return ERR_PTR(-ENOMEM);
+			wait_on_page(page);
+			if (!Page_Uptodate(page)) {
+				page_cache_release(page);
+				return ERR_PTR(-EIO);
+			}
+			
+			/* Too bad we can't trust this page, because we
+			 * dropped the info->lock spinlock */
+			page_cache_release(page);
+			goto repeat;
 		}
 
 		/* We have to this with page locked to prevent races */
-		spin_lock (&info->lock);
+		if (TryLockPage(page)) 
+			goto wait_retry;
+
 		swap_free(*entry);
-		lock_page(page);
-		delete_from_swap_cache_nolock(page);
 		*entry = (swp_entry_t) {0};
+		delete_from_swap_cache_nolock(page);
 		flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1));
 		page->flags = flags | (1 << PG_dirty);
 		add_to_page_cache_locked(page, mapping, idx);
 		info->swapped--;
 		spin_unlock (&info->lock);
 	} else {
+		spin_unlock (&info->lock);
 		spin_lock (&inode->i_sb->u.shmem_sb.stat_lock);
 		if (inode->i_sb->u.shmem_sb.free_blocks == 0)
 			goto no_space;
 		inode->i_sb->u.shmem_sb.free_blocks--;
 		spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
-		/* Ok, get a new page */
+
+		/* Ok, get a new page.  We don't have to worry about the
+		 * info->lock spinlock here: we cannot race against
+		 * shm_writepage because we have already verified that
+		 * there is no page present either in memory or in the
+		 * swap cache, so we are guaranteed to be populating a
+		 * new shm entry.  The inode semaphore we already hold
+		 * is enough to make this atomic. */
 		page = page_cache_alloc(mapping);
 		if (!page)
-			goto oom;
-		clear_user_highpage(page, address);
-		inode->i_blocks++;
+			return ERR_PTR(-ENOMEM);
+		clear_highpage(page);
+		inode->i_blocks += BLOCKS_PER_PAGE;
 		add_to_page_cache (page, mapping, idx);
 	}
+
 	/* We have the page */
-	SetPageUptodate (page);
+	SetPageUptodate(page);
 	if (info->locked)
 		page_cache_get(page);
+	return page;
+no_space:
+	spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
+	return ERR_PTR(-ENOSPC);
 
-cached_page:
-	UnlockPage (page);
-	up(&inode->i_sem);
+wait_retry:
+	spin_unlock (&info->lock);
+	wait_on_page(page);
+	page_cache_release(page);
+	goto repeat;
+}
+
+static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
+{
+	struct address_space * mapping = inode->i_mapping;
+	int error;
+
+	*ptr = NOPAGE_SIGBUS;
+	if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE)
+		return -EFAULT;
+
+	*ptr = __find_get_page(mapping, idx, page_hash(mapping, idx));
+	if (*ptr) {
+		if (Page_Uptodate(*ptr))
+			return 0;
+		page_cache_release(*ptr);
+	}
+
+	down (&inode->i_sem);
+	/* retest we may have slept */
+	if (inode->i_size < (loff_t) idx * PAGE_CACHE_SIZE)
+		goto sigbus;
+	*ptr = shmem_getpage_locked(inode, idx);
+	if (IS_ERR (*ptr))
+		goto failed;
+	UnlockPage(*ptr);
+	up (&inode->i_sem);
+	return 0;
+failed:
+	up (&inode->i_sem);
+	error = PTR_ERR(*ptr);
+	*ptr = NOPAGE_OOM;
+	if (error != -EFBIG)
+		*ptr = NOPAGE_SIGBUS;
+	return error;
+sigbus:
+	up (&inode->i_sem);
+	*ptr = NOPAGE_SIGBUS;
+	return -EFAULT;
+}
+
+struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share)
+{
+	struct page * page;
+	unsigned int idx;
+	struct inode * inode = vma->vm_file->f_dentry->d_inode;
+
+	idx = (address - vma->vm_start) >> PAGE_SHIFT;
+	idx += vma->vm_pgoff;
+
+	if (shmem_getpage(inode, idx, &page))
+		return page;
 
 	if (no_share) {
 		struct page *new_page = page_cache_alloc(inode->i_mapping);
@@ -351,13 +456,45 @@
 
 	flush_page_to_ram (page);
 	return(page);
-no_space:
-	spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
-oom:
-	page = NOPAGE_OOM;
-out:
+}
+
+void shmem_lock(struct file * file, int lock)
+{
+	struct inode * inode = file->f_dentry->d_inode;
+	struct shmem_inode_info * info = &inode->u.shmem_i;
+	struct page * page;
+	unsigned long idx, size;
+
+	if (info->locked == lock)
+		return;
+	down(&inode->i_sem);
+	info->locked = lock;
+	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	for (idx = 0; idx < size; idx++) {
+		page = find_lock_page(inode->i_mapping, idx);
+		if (!page)
+			continue;
+		if (!lock) {
+			/* release the extra count and our reference */
+			page_cache_release(page);
+			page_cache_release(page);
+		}
+		UnlockPage(page);
+	}
 	up(&inode->i_sem);
-	return page;
+}
+
+static int shmem_mmap(struct file * file, struct vm_area_struct * vma)
+{
+	struct vm_operations_struct * ops;
+	struct inode *inode = file->f_dentry->d_inode;
+
+	ops = &shmem_vm_ops;
+	if (!inode->i_sb || !S_ISREG(inode->i_mode))
+		return -EACCES;
+	UPDATE_ATIME(inode);
+	vma->vm_ops = ops;
+	return 0;
 }
 
 struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
@@ -392,11 +529,13 @@
 			inode->i_fop = &shmem_file_operations;
 			break;
 		case S_IFDIR:
+			inode->i_nlink++;
 			inode->i_op = &shmem_dir_inode_operations;
 			inode->i_fop = &shmem_dir_operations;
 			break;
 		case S_IFLNK:
-			BUG();
+			inode->i_op = &shmem_symlink_inode_operations;
+			break;
 		}
 		spin_lock (&shmem_ilock);
 		list_add (&inode->u.shmem_i.list, &shmem_inodes);
@@ -405,49 +544,242 @@
 	return inode;
 }
 
+#ifdef CONFIG_TMPFS
+static ssize_t
+shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
+{
+	struct inode	*inode = file->f_dentry->d_inode; 
+	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	loff_t		pos;
+	struct page	*page;
+	unsigned long	written;
+	long		status;
+	int		err;
+
+
+	down(&inode->i_sem);
+
+	pos = *ppos;
+	err = -EINVAL;
+	if (pos < 0)
+		goto out;
+
+	err = file->f_error;
+	if (err) {
+		file->f_error = 0;
+		goto out;
+	}
+
+	written = 0;
+
+	if (file->f_flags & O_APPEND)
+		pos = inode->i_size;
+
+	/*
+	 * Check whether we've reached the file size limit.
+	 */
+	err = -EFBIG;
+	if (limit != RLIM_INFINITY) {
+		if (pos >= limit) {
+			send_sig(SIGXFSZ, current, 0);
+			goto out;
+		}
+		if (count > limit - pos) {
+			send_sig(SIGXFSZ, current, 0);
+			count = limit - pos;
+		}
+	}
+
+	status	= 0;
+	if (count) {
+		remove_suid(inode);
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	}
+
+	while (count) {
+		unsigned long bytes, index, offset;
+		char *kaddr;
+		int deactivate = 1;
+
+		/*
+		 * Try to find the page in the cache. If it isn't there,
+		 * allocate a free page.
+		 */
+		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
+		index = pos >> PAGE_CACHE_SHIFT;
+		bytes = PAGE_CACHE_SIZE - offset;
+		if (bytes > count) {
+			bytes = count;
+			deactivate = 0;
+		}
+
+		/*
+		 * Bring in the user page that we will copy from _first_.
+		 * Otherwise there's a nasty deadlock on copying from the
+		 * same page as we're writing to, without it being marked
+		 * up-to-date.
+		 */
+		{ volatile unsigned char dummy;
+			__get_user(dummy, buf);
+			__get_user(dummy, buf+bytes-1);
+		}
+
+		page = shmem_getpage_locked(inode, index);
+		status = PTR_ERR(page);
+		if (IS_ERR(page))
+			break;
+
+		/* We have exclusive IO access to the page.. */
+		if (!PageLocked(page)) {
+			PAGE_BUG(page);
+		}
+
+		kaddr = kmap(page);
+// can this do a truncated write? cr
+		status = copy_from_user(kaddr+offset, buf, bytes);
+		kunmap(page);
+		if (status)
+			goto fail_write;
+
+		flush_dcache_page(page);
+		if (bytes > 0) {
+			SetPageDirty(page);
+			written += bytes;
+			count -= bytes;
+			pos += bytes;
+			buf += bytes;
+			if (pos > inode->i_size) 
+				inode->i_size = pos;
+			if (inode->u.shmem_i.max_index <= index)
+				inode->u.shmem_i.max_index = index+1;
+
+		}
+unlock:
+		/* Mark it unlocked again and drop the page.. */
+		UnlockPage(page);
+		if (deactivate)
+			deactivate_page(page);
+		page_cache_release(page);
+
+		if (status < 0)
+			break;
+	}
+	*ppos = pos;
+
+	err = written ? written : status;
+out:
+	up(&inode->i_sem);
+	return err;
+fail_write:
+	status = -EFAULT;
+	ClearPageUptodate(page);
+	kunmap(page);
+	goto unlock;
+}
+
+static void do_shmem_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct address_space *mapping = inode->i_mapping;
+	unsigned long index, offset;
+	int nr = 1;
+
+	index = *ppos >> PAGE_CACHE_SHIFT;
+	offset = *ppos & ~PAGE_CACHE_MASK;
+
+	while (nr && desc->count) {
+		struct page *page;
+		unsigned long end_index, nr;
+
+		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+		if (index > end_index)
+			break;
+		nr = PAGE_CACHE_SIZE;
+		if (index == end_index) {
+			nr = inode->i_size & ~PAGE_CACHE_MASK;
+			if (nr <= offset)
+				break;
+		}
+
+		nr = nr - offset;
+
+		if ((desc->error = shmem_getpage(inode, index, &page)))
+			break;
+
+		if (mapping->i_mmap_shared != NULL)
+			flush_dcache_page(page);
+
+		/*
+		 * Ok, we have the page, and it's up-to-date, so
+		 * now we can copy it to user space...
+		 *
+		 * The actor routine returns how many bytes were actually used..
+		 * NOTE! This may not be the same as how much of a user buffer
+		 * we filled up (we may be padding etc), so we can only update
+		 * "pos" here (the actor routine has to update the user buffer
+		 * pointers and the remaining count).
+		 */
+		nr = file_read_actor(desc, page, offset, nr);
+		offset += nr;
+		index += offset >> PAGE_CACHE_SHIFT;
+		offset &= ~PAGE_CACHE_MASK;
+	
+		page_cache_release(page);
+	}
+
+	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
+	UPDATE_ATIME(inode);
+}
+
+static ssize_t shmem_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+{
+	ssize_t retval;
+
+	retval = -EFAULT;
+	if (access_ok(VERIFY_WRITE, buf, count)) {
+		retval = 0;
+
+		if (count) {
+			read_descriptor_t desc;
+
+			desc.written = 0;
+			desc.count = count;
+			desc.buf = buf;
+			desc.error = 0;
+			do_shmem_file_read(filp, ppos, &desc);
+
+			retval = desc.written;
+			if (!retval)
+				retval = desc.error;
+		}
+	}
+	return retval;
+}
+
 static int shmem_statfs(struct super_block *sb, struct statfs *buf)
 {
-	buf->f_type = SHMEM_MAGIC;
+	buf->f_type = TMPFS_MAGIC;
 	buf->f_bsize = PAGE_CACHE_SIZE;
 	spin_lock (&sb->u.shmem_sb.stat_lock);
-	if (sb->u.shmem_sb.max_blocks != ULONG_MAX || 
-	    sb->u.shmem_sb.max_inodes != ULONG_MAX) {
+	if (sb->u.shmem_sb.max_blocks == ULONG_MAX) {
+		/*
+		 * This is only a guestimate and not honoured.
+		 * We need it to make some programs happy which like to
+		 * test the free space of a file system.
+		 */
+		buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages);
+		buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks;
+	} else {
 		buf->f_blocks = sb->u.shmem_sb.max_blocks;
 		buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
-		buf->f_files = sb->u.shmem_sb.max_inodes;
-		buf->f_ffree = sb->u.shmem_sb.free_inodes;
 	}
+	buf->f_files = sb->u.shmem_sb.max_inodes;
+	buf->f_ffree = sb->u.shmem_sb.free_inodes;
 	spin_unlock (&sb->u.shmem_sb.stat_lock);
 	buf->f_namelen = 255;
 	return 0;
 }
 
-void shmem_lock(struct file * file, int lock)
-{
-	struct inode * inode = file->f_dentry->d_inode;
-	struct shmem_inode_info * info = &inode->u.shmem_i;
-	struct page * page;
-	unsigned long idx, size;
-
-	if (info->locked == lock)
-		return;
-	down(&inode->i_sem);
-	info->locked = lock;
-	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	for (idx = 0; idx < size; idx++) {
-		page = find_lock_page(inode->i_mapping, idx);
-		if (!page)
-			continue;
-		if (!lock) {
-			/* release the extra count and our reference */
-			page_cache_release(page);
-			page_cache_release(page);
-		}
-		UnlockPage(page);
-	}
-	up(&inode->i_sem);
-}
-
 /*
  * Lookup the data. This is trivial - if the dentry didn't already
  * exist, we know it is negative.
@@ -466,6 +798,7 @@
 	struct inode * inode = shmem_get_inode(dir->i_sb, mode, dev);
 	int error = -ENOSPC;
 
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	if (inode) {
 		d_instantiate(dentry, inode);
 		dget(dentry); /* Extra count - pin the dentry in core */
@@ -476,7 +809,12 @@
 
 static int shmem_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
-	return shmem_mknod(dir, dentry, mode | S_IFDIR, 0);
+	int error;
+
+	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
+		return error;
+	dir->i_nlink++;
+	return 0;
 }
 
 static int shmem_create(struct inode *dir, struct dentry *dentry, int mode)
@@ -494,6 +832,7 @@
 	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
 
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	inode->i_nlink++;
 	atomic_inc(&inode->i_count);	/* New dentry reference */
 	dget(dentry);		/* Extra pinning count for the created dentry */
@@ -534,26 +873,24 @@
 	return 1;
 }
 
-/*
- * This works for both directories and regular files.
- * (non-directories will always have empty subdirs)
- */
 static int shmem_unlink(struct inode * dir, struct dentry *dentry)
 {
-	int retval = -ENOTEMPTY;
+	struct inode *inode = dentry->d_inode;
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	inode->i_nlink--;
+	dput(dentry);	/* Undo the count from "create" - this does all the work */
+	return 0;
+}
 
-	if (shmem_empty(dentry)) {
-		struct inode *inode = dentry->d_inode;
+static int shmem_rmdir(struct inode * dir, struct dentry *dentry)
+{
+	if (!shmem_empty(dentry))
+		return -ENOTEMPTY;
 
-		inode->i_nlink--;
-		dput(dentry);	/* Undo the count from "create" - this does all the work */
-		retval = 0;
-	}
-	return retval;
+	dir->i_nlink--;
+	return shmem_unlink(dir, dentry);
 }
 
-#define shmem_rmdir shmem_unlink
-
 /*
  * The VFS layer already does all the dentry stuff for rename,
  * we just have to decrement the usage count for the target if
@@ -567,27 +904,77 @@
 	if (shmem_empty(new_dentry)) {
 		struct inode *inode = new_dentry->d_inode;
 		if (inode) {
+			inode->i_ctime = CURRENT_TIME;
 			inode->i_nlink--;
 			dput(new_dentry);
 		}
 		error = 0;
+		old_dentry->d_inode->i_ctime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	}
 	return error;
 }
 
-static int shmem_mmap(struct file * file, struct vm_area_struct * vma)
+static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
 {
-	struct vm_operations_struct * ops;
-	struct inode *inode = file->f_dentry->d_inode;
+	int error;
+	int len;
+	struct inode *inode;
+	struct page *page;
+	char *kaddr;
 
-	ops = &shmem_private_vm_ops;
-	if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
-		ops = &shmem_shared_vm_ops;
-	if (!inode->i_sb || !S_ISREG(inode->i_mode))
-		return -EACCES;
-	UPDATE_ATIME(inode);
-	vma->vm_ops = ops;
+	error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
+	if (error)
+		return error;
+
+	len = strlen(symname);
+	if (len > PAGE_SIZE)
+		return -ENAMETOOLONG;
+		
+	inode = dentry->d_inode;
+	down(&inode->i_sem);
+	page = shmem_getpage_locked(inode, 0);
+	if (IS_ERR(page))
+		goto fail;
+	kaddr = kmap(page);
+	memcpy(kaddr, symname, len);
+	kunmap(page);
+	inode->i_size = len;
+	SetPageDirty(page);
+	UnlockPage(page);
+	page_cache_release(page);
+	up(&inode->i_sem);
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	return 0;
+fail:
+	up(&inode->i_sem);
+	return PTR_ERR(page);
+}
+
+static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+	struct page * page;
+	int res = shmem_getpage(dentry->d_inode, 0, &page);
+
+	if (res)
+		return res;
+
+	res = vfs_readlink(dentry,buffer,buflen, kmap(page));
+	kunmap(page);
+	page_cache_release(page);
+	return res;
+}
+
+static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct page * page;
+	int res = shmem_getpage(dentry->d_inode, 0, &page);
+	if (res)
+		return res;
+
+	res = vfs_follow_link(nd, kmap(page));
+	kunmap(page);
+	page_cache_release(page);
+	return res;
 }
 
 static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes)
@@ -600,16 +987,24 @@
 	for ( ; this_char; this_char = strtok(NULL,",")) {
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
-		if (!strcmp(this_char,"nr_blocks")) {
+		if (!strcmp(this_char,"size")) {
+			unsigned long long size;
 			if (!value || !*value || !blocks)
 				return 1;
-			*blocks = simple_strtoul(value,&value,0);
+			size = memparse(value,&value);
+			if (*value)
+				return 1;
+			*blocks = size >> PAGE_CACHE_SHIFT;
+		} else if (!strcmp(this_char,"nr_blocks")) {
+			if (!value || !*value || !blocks)
+				return 1;
+			*blocks = memparse(value,&value);
 			if (*value)
 				return 1;
 		} else if (!strcmp(this_char,"nr_inodes")) {
 			if (!value || !*value || !inodes)
 				return 1;
-			*inodes = simple_strtoul(value,&value,0);
+			*inodes = memparse(value,&value);
 			if (*value)
 				return 1;
 		} else if (!strcmp(this_char,"mode")) {
@@ -622,9 +1017,42 @@
 		else
 			return 1;
 	}
+	return 0;
+}
 
+static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+{
+	int error;
+	unsigned long max_blocks, blocks;
+	unsigned long max_inodes, inodes;
+	struct shmem_sb_info *info = &sb->u.shmem_sb;
+
+	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
+		return -EINVAL;
+
+	spin_lock(&info->stat_lock);
+	blocks = info->max_blocks - info->free_blocks;
+	inodes = info->max_inodes - info->free_inodes;
+	error = -EINVAL;
+	if (max_blocks < blocks)
+		goto out;
+	if (max_inodes < inodes)
+		goto out;
+	error = 0;
+	info->max_blocks  = max_blocks;
+	info->free_blocks = max_blocks - blocks;
+	info->max_inodes  = max_inodes;
+	info->free_inodes = max_inodes - inodes;
+out:
+	spin_unlock(&info->stat_lock);
+	return error;
+}
+
+int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync)
+{
 	return 0;
 }
+#endif
 
 static struct super_block *shmem_read_super(struct super_block * sb, void * data, int silent)
 {
@@ -634,19 +1062,22 @@
 	unsigned long inodes = ULONG_MAX;	/* unlimited */
 	int mode   = S_IRWXUGO | S_ISVTX;
 
+#ifdef CONFIG_TMPFS
 	if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
-		printk(KERN_ERR "shmem fs invalid option\n");
+		printk(KERN_ERR "tmpfs invalid option\n");
 		return NULL;
 	}
+#endif
 
 	spin_lock_init (&sb->u.shmem_sb.stat_lock);
 	sb->u.shmem_sb.max_blocks = blocks;
 	sb->u.shmem_sb.free_blocks = blocks;
 	sb->u.shmem_sb.max_inodes = inodes;
 	sb->u.shmem_sb.free_inodes = inodes;
+	sb->s_maxbytes = (unsigned long long)(SHMEM_NR_DIRECT + (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)) << PAGE_CACHE_SHIFT;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-	sb->s_magic = SHMEM_MAGIC;
+	sb->s_magic = TMPFS_MAGIC;
 	sb->s_op = &shmem_ops;
 	inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
 	if (!inode)
@@ -661,103 +1092,108 @@
 	return sb;
 }
 
-static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
-{
-	int error;
-	unsigned long max_blocks, blocks;
-	unsigned long max_inodes, inodes;
-	struct shmem_sb_info *info = &sb->u.shmem_sb;
 
-	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
-		return -EINVAL;
-
-	spin_lock(&info->stat_lock);
-	blocks = info->max_blocks - info->free_blocks;
-	inodes = info->max_inodes - info->free_inodes;
-	error = -EINVAL;
-	if (max_blocks < blocks)
-		goto out;
-	if (max_inodes < inodes)
-		goto out;
-	error = 0;
-	info->max_blocks  = max_blocks;
-	info->free_blocks = max_blocks - blocks;
-	info->max_inodes  = max_inodes;
-	info->free_inodes = max_inodes - inodes;
-out:
-	spin_unlock(&info->stat_lock);
-	return error;
-}
 
 static struct address_space_operations shmem_aops = {
 	writepage: shmem_writepage
 };
 
 static struct file_operations shmem_file_operations = {
-	mmap:		shmem_mmap
+	mmap:	shmem_mmap,
+#ifdef CONFIG_TMPFS
+	read:	shmem_file_read,
+	write:	shmem_file_write,
+	fsync:	shmem_sync_file,
+#endif
 };
 
 static struct inode_operations shmem_inode_operations = {
 	truncate:	shmem_truncate,
 };
 
+static struct inode_operations shmem_symlink_inode_operations = {
+	truncate:	shmem_truncate,
+#ifdef CONFIG_TMPFS
+	readlink:	shmem_readlink,
+	follow_link:	shmem_follow_link,
+#endif
+};
+
 static struct file_operations shmem_dir_operations = {
 	read:		generic_read_dir,
 	readdir:	dcache_readdir,
+#ifdef CONFIG_TMPFS
+	fsync:		shmem_sync_file,
+#endif
 };
 
 static struct inode_operations shmem_dir_inode_operations = {
+#ifdef CONFIG_TMPFS
 	create:		shmem_create,
 	lookup:		shmem_lookup,
 	link:		shmem_link,
 	unlink:		shmem_unlink,
+	symlink:	shmem_symlink,
 	mkdir:		shmem_mkdir,
 	rmdir:		shmem_rmdir,
 	mknod:		shmem_mknod,
 	rename:		shmem_rename,
+#endif
 };
 
 static struct super_operations shmem_ops = {
+#ifdef CONFIG_TMPFS
 	statfs:		shmem_statfs,
 	remount_fs:	shmem_remount_fs,
+#endif
 	delete_inode:	shmem_delete_inode,
 	put_inode:	force_delete,	
 };
 
-static struct vm_operations_struct shmem_private_vm_ops = {
-	nopage:	shmem_nopage,
-};
-
-static struct vm_operations_struct shmem_shared_vm_ops = {
+static struct vm_operations_struct shmem_vm_ops = {
 	nopage:	shmem_nopage,
 };
 
+#ifdef CONFIG_TMPFS
+/* type "shm" will be tagged obsolete in 2.5 */
 static DECLARE_FSTYPE(shmem_fs_type, "shm", shmem_read_super, FS_LITTER);
+static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER);
+#else
+static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER|FS_NOMOUNT);
+#endif
 
 static int __init init_shmem_fs(void)
 {
 	int error;
 	struct vfsmount * res;
 
+	if ((error = register_filesystem(&tmpfs_fs_type))) {
+		printk (KERN_ERR "Could not register tmpfs\n");
+		return error;
+	}
+#ifdef CONFIG_TMPFS
 	if ((error = register_filesystem(&shmem_fs_type))) {
-		printk (KERN_ERR "Could not register shmem fs\n");
+		printk (KERN_ERR "Could not register shm fs\n");
 		return error;
 	}
-
-	res = kern_mount(&shmem_fs_type);
+	devfs_mk_dir (NULL, "shm", NULL);
+#endif
+	res = kern_mount(&tmpfs_fs_type);
 	if (IS_ERR (res)) {
-		printk (KERN_ERR "could not kern_mount shmem fs\n");
-		unregister_filesystem(&shmem_fs_type);
+		printk (KERN_ERR "could not kern_mount tmpfs\n");
+		unregister_filesystem(&tmpfs_fs_type);
 		return PTR_ERR(res);
 	}
 
-	devfs_mk_dir (NULL, "shm", NULL);
 	return 0;
 }
 
 static void __exit exit_shmem_fs(void)
 {
+#ifdef CONFIG_TMPFS
 	unregister_filesystem(&shmem_fs_type);
+#endif
+	unregister_filesystem(&tmpfs_fs_type);
 }
 
 module_init(init_shmem_fs)
@@ -853,7 +1289,7 @@
 	this.name = name;
 	this.len = strlen(name);
 	this.hash = 0; /* will go */
-	root = shmem_fs_type.kern_mnt->mnt_root;
+	root = tmpfs_fs_type.kern_mnt->mnt_root;
 	dentry = d_alloc(root, &this);
 	if (!dentry)
 		goto out;
@@ -870,7 +1306,8 @@
 
 	d_instantiate(dentry, inode);
 	dentry->d_inode->i_size = size;
-	file->f_vfsmnt = mntget(shmem_fs_type.kern_mnt);
+	shmem_truncate(inode);
+	file->f_vfsmnt = mntget(tmpfs_fs_type.kern_mnt);
 	file->f_dentry = dentry;
 	file->f_op = &shmem_file_operations;
 	file->f_mode = FMODE_WRITE | FMODE_READ;
@@ -901,6 +1338,8 @@
 	if (vma->vm_file)
 		fput (vma->vm_file);
 	vma->vm_file = file;
-	vma->vm_ops = &shmem_shared_vm_ops;
+	vma->vm_ops = &shmem_vm_ops;
 	return 0;
 }
+
+EXPORT_SYMBOL(shmem_file_setup);
diff -u --recursive --new-file v2.4.3/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.4.3/linux/mm/swap_state.c	Fri Dec 29 15:04:27 2000
+++ linux/mm/swap_state.c	Wed Apr 25 14:46:21 2001
@@ -17,9 +17,24 @@
 
 #include <asm/pgtable.h>
 
+/*
+ * We may have stale swap cache pages in memory: notice
+ * them here and get rid of the unnecessary final write.
+ */
 static int swap_writepage(struct page *page)
 {
-	rw_swap_page(WRITE, page, 0);
+	/* One for the page cache, one for this user, one for page->buffers */
+	if (page_count(page) > 2 + !!page->buffers)
+		goto in_use;
+	if (swap_count(page) > 1)
+		goto in_use;
+
+	/* We could remove it here, but page_launder will do it anyway */
+	UnlockPage(page);
+	return 0;
+
+in_use:
+	rw_swap_page(WRITE, page);
 	return 0;
 }
 
@@ -130,26 +145,6 @@
 	UnlockPage(page);
 }
 
-/* 
- * Perform a free_page(), also freeing any swap cache associated with
- * this page if it is the last user of the page. Can not do a lock_page,
- * as we are holding the page_table_lock spinlock.
- */
-void free_page_and_swap_cache(struct page *page)
-{
-	/* 
-	 * If we are the only user, then try to free up the swap cache. 
-	 */
-	if (PageSwapCache(page) && !TryLockPage(page)) {
-		if (!is_page_shared(page)) {
-			delete_from_swap_cache_nolock(page);
-		}
-		UnlockPage(page);
-	}
-	page_cache_release(page);
-}
-
-
 /*
  * Lookup a swap entry in the swap cache. A found page will be returned
  * unlocked and with its refcount incremented - we rely on the kernel
@@ -168,37 +163,18 @@
 		/*
 		 * Right now the pagecache is 32-bit only.  But it's a 32 bit index. =)
 		 */
-repeat:
-		found = find_lock_page(&swapper_space, entry.val);
+		found = find_get_swapcache_page(&swapper_space, entry.val);
 		if (!found)
 			return 0;
-		/*
-		 * Though the "found" page was in the swap cache an instant
-		 * earlier, it might have been removed by refill_inactive etc.
-		 * Re search ... Since find_lock_page grabs a reference on
-		 * the page, it can not be reused for anything else, namely
-		 * it can not be associated with another swaphandle, so it
-		 * is enough to check whether the page is still in the scache.
-		 */
-		if (!PageSwapCache(found)) {
-			UnlockPage(found);
-			page_cache_release(found);
-			goto repeat;
-		}
+		if (!PageSwapCache(found))
+			BUG();
 		if (found->mapping != &swapper_space)
-			goto out_bad;
+			BUG();
 #ifdef SWAP_CACHE_INFO
 		swap_cache_find_success++;
 #endif
-		UnlockPage(found);
 		return found;
 	}
-
-out_bad:
-	printk (KERN_ERR "VM: Found a non-swapper swap page!\n");
-	UnlockPage(found);
-	page_cache_release(found);
-	return 0;
 }
 
 /* 
@@ -210,7 +186,7 @@
  * the swap entry is no longer in use.
  */
 
-struct page * read_swap_cache_async(swp_entry_t entry, int wait)
+struct page * read_swap_cache_async(swp_entry_t entry)
 {
 	struct page *found_page = 0, *new_page;
 	unsigned long new_page_addr;
@@ -243,7 +219,7 @@
 	 */
 	lock_page(new_page);
 	add_to_swap_cache(new_page, entry);
-	rw_swap_page(READ, new_page, wait);
+	rw_swap_page(READ, new_page);
 	return new_page;
 
 out_free_page:
diff -u --recursive --new-file v2.4.3/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.4.3/linux/mm/swapfile.c	Thu Mar 22 09:22:15 2001
+++ linux/mm/swapfile.c	Wed Apr 25 14:46:21 2001
@@ -369,13 +369,15 @@
 		/* Get a page for the entry, using the existing swap
                    cache page if there is one.  Otherwise, get a clean
                    page and read the swap into it. */
-		page = read_swap_cache(entry);
+		page = read_swap_cache_async(entry);
 		if (!page) {
 			swap_free(entry);
   			return -ENOMEM;
 		}
+		lock_page(page);
 		if (PageSwapCache(page))
-			delete_from_swap_cache(page);
+			delete_from_swap_cache_nolock(page);
+		UnlockPage(page);
 		read_lock(&tasklist_lock);
 		for_each_task(p)
 			unuse_process(p->mm, entry, page);
@@ -650,7 +652,7 @@
 	}
 
 	lock_page(virt_to_page(swap_header));
-	rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header, 1);
+	rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header);
 
 	if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
 		swap_header_version = 1;
diff -u --recursive --new-file v2.4.3/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.4.3/linux/mm/vmscan.c	Thu Mar 22 11:00:51 2001
+++ linux/mm/vmscan.c	Thu Apr 12 12:10:25 2001
@@ -563,7 +563,7 @@
 
 			/*
 			 * Unlock the page and drop the extra reference.
-			 * We can only do it here because we ar accessing
+			 * We can only do it here because we are accessing
 			 * the page struct above.
 			 */
 			UnlockPage(page);
@@ -912,7 +912,7 @@
 	 * Kswapd main loop.
 	 */
 	for (;;) {
-		static int recalc = 0;
+		static long recalc = 0;
 
 		/* If needed, try to free some memory. */
 		if (inactive_shortage() || free_shortage()) 
diff -u --recursive --new-file v2.4.3/linux/net/802/TODO linux/net/802/TODO
--- v2.4.3/linux/net/802/TODO	Thu Dec 12 06:54:22 1996
+++ linux/net/802/TODO	Fri Apr  6 10:51:19 2001
@@ -9,7 +9,7 @@
 2. The code is currently able to handle one connection only,
 there is more work in register_cl2llc_client() to make a chain
 of llc structures and in mac_data_indicate() to find back
-the llc structure addressed by an incomming frame.
+the llc structure addressed by an incoming frame.
 According to IEEE, connections are identified by (remote mac + local mac
 + dsap + ssap). dsap and ssap do not seem important: existing applications
 always use the same dsap/ssap. Its probably sufficient to index on 
diff -u --recursive --new-file v2.4.3/linux/net/802/cl2llc.c linux/net/802/cl2llc.c
--- v2.4.3/linux/net/802/cl2llc.c	Fri Feb  9 11:34:13 2001
+++ linux/net/802/cl2llc.c	Fri Apr  6 10:51:19 2001
@@ -162,7 +162,7 @@
  *	Interpret_pseudo_code() executes the actions in the connection component
  *	state transition table. Table 4 in document on p88.
  *
- *	If this function is called to handle an incomming pdu, skb will point
+ *	If this function is called to handle an incoming pdu, skb will point
  *	to the buffer with the pdu and type will contain the decoded pdu type.
  *
  *	If called by data_request skb points to an skb that was skb_alloc-ed by 
diff -u --recursive --new-file v2.4.3/linux/net/802/cl2llc.pre linux/net/802/cl2llc.pre
--- v2.4.3/linux/net/802/cl2llc.pre	Sat Nov 29 10:41:10 1997
+++ linux/net/802/cl2llc.pre	Fri Apr  6 10:51:19 2001
@@ -162,7 +162,7 @@
  *	Interpret_pseudo_code() executes the actions in the connection component
  *	state transition table. Table 4 in document on p88.
  *
- *	If this function is called to handle an incomming pdu, skb will point
+ *	If this function is called to handle an incoming pdu, skb will point
  *	to the buffer with the pdu and type will contain the decoded pdu type.
  *
  *	If called by data_request skb points to an skb that was skb_alloc-ed by 
diff -u --recursive --new-file v2.4.3/linux/net/802/llc_sendpdu.c linux/net/802/llc_sendpdu.c
--- v2.4.3/linux/net/802/llc_sendpdu.c	Fri Feb  9 11:29:44 2001
+++ linux/net/802/llc_sendpdu.c	Fri Apr  6 10:51:19 2001
@@ -98,7 +98,7 @@
 
 /*
  *	Sendpdu() constructs an output frame in a new skb and
- *	gives it to the MAC layer for transmision.
+ *	gives it to the MAC layer for transmission.
  *	This function is not used to send I pdus.
  *	No queues are updated here, nothing is saved for retransmission.
  *
@@ -186,7 +186,7 @@
 
 /*
  *	llc_sendipdu() Completes an I pdu in an existing skb and gives it
- *	to the MAC layer for transmision.
+ *	to the MAC layer for transmission.
  *	Parameter "type" must be either I_CMD or I_RSP.
  *	The skb is not freed after xmit, it is kept in case a retransmission
  *	is requested. If needed it can be picked up again from the rtq.
diff -u --recursive --new-file v2.4.3/linux/net/802/pseudo/pseudocode linux/net/802/pseudo/pseudocode
--- v2.4.3/linux/net/802/pseudo/pseudocode	Thu Dec 12 06:54:22 1996
+++ linux/net/802/pseudo/pseudocode	Fri Apr  6 10:51:19 2001
@@ -246,7 +246,7 @@
 		START_REJ_TIMER
 ;
 ; the order of opcodes in NORMAL8 is changed.
-; the transition table will execute NORMAL8A for incomming pdus
+; the transition table will execute NORMAL8A for incoming pdus
 ; with p/f 1, pdus with pf 0 are treated in NORMAL8B.
 ;   
 NORMAL8A	V(R):=V(R)+1
diff -u --recursive --new-file v2.4.3/linux/net/802/transit/pdutr.pre linux/net/802/transit/pdutr.pre
--- v2.4.3/linux/net/802/transit/pdutr.pre	Thu Dec 12 06:54:22 1996
+++ linux/net/802/transit/pdutr.pre	Fri Apr  6 10:51:19 2001
@@ -1,6 +1,6 @@
 COMPILE pdutr INDEX
 ;
-; Transition tables for incomming pdu events.
+; Transition tables for incoming pdu events.
 ; translate this thing into C with
 ;  	awk -f ./compile.awk pdu.trans > pdutr.h
 ;
diff -u --recursive --new-file v2.4.3/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.4.3/linux/net/appletalk/ddp.c	Mon Jan 22 13:32:10 2001
+++ linux/net/appletalk/ddp.c	Thu Apr 12 12:11:39 2001
@@ -1672,7 +1672,7 @@
 			sk, size, dev->name);
 
 	size += dev->hard_header_len;
-	skb = sock_alloc_send_skb(sk, size, 0, (flags & MSG_DONTWAIT), &err);
+	skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
 	if (!skb)
 		return err;
 	
@@ -1913,6 +1913,7 @@
 	sendmsg:	atalk_sendmsg,
 	recvmsg:	atalk_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
@@ -1988,7 +1989,7 @@
  * Use counts are incremented/decremented when
  * sockets are created/deleted.
  *
- * AppleTalk interfaces are not incremented untill atalkd is run
+ * AppleTalk interfaces are not incremented until atalkd is run
  * and are only decremented when they are downed.
  *
  * Ergo, before the AppleTalk module can be removed, all AppleTalk
diff -u --recursive --new-file v2.4.3/linux/net/atm/addr.c linux/net/atm/addr.c
--- v2.4.3/linux/net/atm/addr.c	Fri Dec 29 14:35:47 2000
+++ linux/net/atm/addr.c	Fri Apr  6 10:51:19 2001
@@ -52,25 +52,26 @@
 	sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
 }
 
+/*
+ *	This is called from atm_ioctl only. You must hold the lock as a caller
+ */
 
-void reset_addr(struct atm_dev *dev)
+void atm_reset_addr(struct atm_dev *dev)
 {
 	struct atm_dev_addr *this;
 
 	down(&local_lock);
-	spin_lock (&atm_dev_lock);		
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
 	up(&local_lock);
-	spin_unlock (&atm_dev_lock);
 	notify_sigd(dev);
 }
 
 
-int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
+int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
 {
 	struct atm_dev_addr **walk;
 	int error;
@@ -96,7 +97,7 @@
 }
 
 
-int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
+int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
 {
 	struct atm_dev_addr **walk,*this;
 	int error;
@@ -119,7 +120,7 @@
 }
 
 
-int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
+int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
 {
 	struct atm_dev_addr *walk;
 	int total;
diff -u --recursive --new-file v2.4.3/linux/net/atm/addr.h linux/net/atm/addr.h
--- v2.4.3/linux/net/atm/addr.h	Mon Dec 11 13:33:43 2000
+++ linux/net/atm/addr.h	Fri Apr  6 10:51:19 2001
@@ -10,9 +10,9 @@
 #include <linux/atmdev.h>
 
 
-void reset_addr(struct atm_dev *dev);
-int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
-int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
-int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size);
+void atm_reset_addr(struct atm_dev *dev);
+int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
+int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
+int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size);
 
 #endif
diff -u --recursive --new-file v2.4.3/linux/net/atm/clip.c linux/net/atm/clip.c
--- v2.4.3/linux/net/atm/clip.c	Thu Jul  6 21:37:24 2000
+++ linux/net/atm/clip.c	Wed Apr 18 14:40:07 2001
@@ -571,7 +571,6 @@
 	    /* compromise between decent burst-tolerance and protection */
 	    /* against memory hogs. */
 	dev->flags = 0;
-	dev_init_buffers(dev); /* is this ever supposed to be used ? */
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/net/atm/common.c linux/net/atm/common.c
--- v2.4.3/linux/net/atm/common.c	Fri Feb  9 11:34:13 2001
+++ linux/net/atm/common.c	Fri Apr  6 10:51:19 2001
@@ -867,7 +867,7 @@
 				ret_val = -EPERM;
 				goto done;
 			}
-			reset_addr(dev);
+			atm_reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
@@ -883,13 +883,13 @@
 					goto done;
 				}
 				if (cmd == ATM_ADDADDR)
-					ret_val = add_addr(dev,&addr);
+					ret_val = atm_add_addr(dev,&addr);
 				else
-					ret_val = del_addr(dev,&addr);
+					ret_val = atm_del_addr(dev,&addr);
 				goto done;
 			}
 		case ATM_GETADDR:
-			size = get_addr(dev,buf,len);
+			size = atm_get_addr(dev,buf,len);
 			if (size < 0)
 				ret_val = size;
 			else
diff -u --recursive --new-file v2.4.3/linux/net/atm/pvc.c linux/net/atm/pvc.c
--- v2.4.3/linux/net/atm/pvc.c	Sat Nov 11 18:53:33 2000
+++ linux/net/atm/pvc.c	Thu Apr 12 12:11:39 2001
@@ -95,6 +95,7 @@
 	sendmsg:	atm_sendmsg,
 	recvmsg:	atm_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 
diff -u --recursive --new-file v2.4.3/linux/net/atm/svc.c linux/net/atm/svc.c
--- v2.4.3/linux/net/atm/svc.c	Wed Nov 15 00:41:03 2000
+++ linux/net/atm/svc.c	Thu Apr 12 12:11:39 2001
@@ -408,6 +408,7 @@
 	sendmsg:	atm_sendmsg,
 	recvmsg:	atm_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 
diff -u --recursive --new-file v2.4.3/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.4.3/linux/net/ax25/af_ax25.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ax25/af_ax25.c	Thu Apr 12 12:11:39 2001
@@ -1451,7 +1451,7 @@
 	/* Assume the worst case */
 	size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
 	skb_reserve(skb, size - len);
@@ -1805,6 +1805,7 @@
 	sendmsg:	ax25_sendmsg,
 	recvmsg:	ax25_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.4.3/linux/net/bridge/br_stp_if.c linux/net/bridge/br_stp_if.c
--- v2.4.3/linux/net/bridge/br_stp_if.c	Mon May  8 22:21:58 2000
+++ linux/net/bridge/br_stp_if.c	Thu Apr 19 08:38:50 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_stp_if.c,v 1.3 2000/05/05 02:17:17 davem Exp $
+ *	$Id: br_stp_if.c,v 1.4 2001/04/14 21:14:39 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -203,7 +203,10 @@
 /* called under bridge lock */
 void br_stp_set_port_priority(struct net_bridge_port *p, int newprio)
 {
-	int new_port_id = ((newprio & 0xFF) << 8) | p->port_no;
+	__u16 new_port_id;
+
+	p->priority = newprio & 0xFF;
+	new_port_id = br_make_port_id(p);
 
 	if (br_is_designated_port(p))
 		p->designated_port = new_port_id;
diff -u --recursive --new-file v2.4.3/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.4.3/linux/net/core/datagram.c	Sat Feb  3 10:39:12 2001
+++ linux/net/core/datagram.c	Thu Apr 12 12:11:39 2001
@@ -36,6 +36,7 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/poll.h>
+#include <linux/highmem.h>
 
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -192,26 +193,216 @@
  *	Copy a datagram to a linear buffer.
  */
 
-int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
+int skb_copy_datagram(const struct sk_buff *skb, int offset, char *to, int size)
 {
-	int err = -EFAULT;
+	struct iovec iov = { to, size };
 
-	if (!copy_to_user(to, skb->h.raw + offset, size))
-		err = 0;
-	return err;
+	return skb_copy_datagram_iovec(skb, offset, &iov, size);
 }
 
-
 /*
  *	Copy a datagram to an iovec.
  *	Note: the iovec is modified during the copy.
  */
- 
-int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to,
-			    int size)
+int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec *to,
+			    int len)
+{
+	int i, copy;
+	int start = skb->len - skb->data_len;
+
+	/* Copy header. */
+	if ((copy = start-offset) > 0) {
+		if (copy > len)
+			copy = len;
+		if (memcpy_toiovec(to, skb->data + offset, copy))
+			goto fault;
+		if ((len -= copy) == 0)
+			return 0;
+		offset += copy;
+	}
+
+	/* Copy paged appendix. Hmm... why does this look so complicated? */
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset+len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end-offset) > 0) {
+			int err;
+			u8  *vaddr;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			struct page *page = frag->page;
+
+			if (copy > len)
+				copy = len;
+			vaddr = kmap(page);
+			err = memcpy_toiovec(to, vaddr + frag->page_offset +
+					     offset-start, copy);
+			kunmap(page);
+			if (err)
+				goto fault;
+			if (!(len -= copy))
+				return 0;
+			offset += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list;
+
+		for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset+len);
+
+			end = start + list->len;
+			if ((copy = end-offset) > 0) {
+				if (copy > len)
+					copy = len;
+				if (skb_copy_datagram_iovec(list, offset-start, to, copy))
+					goto fault;
+				if ((len -= copy) == 0)
+					return 0;
+				offset += copy;
+			}
+			start = end;
+		}
+	}
+	if (len == 0)
+		return 0;
+
+fault:
+	return -EFAULT;
+}
+
+int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump)
+{
+	int i, copy;
+	int start = skb->len - skb->data_len;
+	int pos = 0;
+
+	/* Copy header. */
+	if ((copy = start-offset) > 0) {
+		int err = 0;
+		if (copy > len)
+			copy = len;
+		*csump = csum_and_copy_to_user(skb->data+offset, to, copy, *csump, &err);
+		if (err)
+			goto fault;
+		if ((len -= copy) == 0)
+			return 0;
+		offset += copy;
+		to += copy;
+		pos = copy;
+	}
+
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset+len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end-offset) > 0) {
+			unsigned int csum2;
+			int err = 0;
+			u8  *vaddr;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			struct page *page = frag->page;
+
+			if (copy > len)
+				copy = len;
+			vaddr = kmap(page);
+			csum2 = csum_and_copy_to_user(vaddr + frag->page_offset +
+						      offset-start, to, copy, 0, &err);
+			kunmap(page);
+			if (err)
+				goto fault;
+			*csump = csum_block_add(*csump, csum2, pos);
+			if (!(len -= copy))
+				return 0;
+			offset += copy;
+			to += copy;
+			pos += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list;
+
+		for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset+len);
+
+			end = start + list->len;
+			if ((copy = end-offset) > 0) {
+				unsigned int csum2 = 0;
+				if (copy > len)
+					copy = len;
+				if (skb_copy_and_csum_datagram(list, offset-start, to, copy, &csum2))
+					goto fault;
+				*csump = csum_block_add(*csump, csum2, pos);
+				if ((len -= copy) == 0)
+					return 0;
+				offset += copy;
+				to += copy;
+				pos += copy;
+			}
+			start = end;
+		}
+	}
+	if (len == 0)
+		return 0;
+
+fault:
+	return -EFAULT;
+}
+
+/* Copy and checkum skb to user iovec. Caller _must_ check that
+   skb will fit to this iovec.
+
+   Returns: 0       - success.
+            -EINVAL - checksum failure.
+	    -EFAULT - fault during copy. Beware, in this case iovec can be
+	              modified!
+ */
+
+int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov)
 {
-	return memcpy_toiovec(to, skb->h.raw + offset, size);
+	unsigned int csum;
+	int chunk = skb->len - hlen;
+
+	/* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */
+	while (iov->iov_len == 0)
+		iov++;
+
+	if (iov->iov_len < chunk) {
+		if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk+hlen, skb->csum)))
+			goto csum_error;
+		if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
+			goto fault;
+	} else {
+		csum = csum_partial(skb->data, hlen, skb->csum);
+		if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base, chunk, &csum))
+			goto fault;
+		if ((unsigned short)csum_fold(csum))
+			goto csum_error;
+		iov->iov_len -= chunk;
+		iov->iov_base += chunk;
+	}
+	return 0;
+
+csum_error:
+	return -EINVAL;
+
+fault:
+	return -EFAULT;
 }
+
+
 
 /*
  *	Datagram poll: Again totally generic. This also handles
diff -u --recursive --new-file v2.4.3/linux/net/core/dev.c linux/net/core/dev.c
--- v2.4.3/linux/net/core/dev.c	Fri Mar  2 11:02:15 2001
+++ linux/net/core/dev.c	Thu Apr 19 08:38:50 2001
@@ -91,6 +91,8 @@
 #include <net/dst.h>
 #include <net/pkt_sched.h>
 #include <net/profile.h>
+#include <net/checksum.h>
+#include <linux/highmem.h>
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
@@ -503,7 +505,7 @@
 }
 
 /**
- *	dev_getbyhwaddr - find a device by its hardware addres
+ *	dev_getbyhwaddr - find a device by its hardware address
  *	@type: media type of device
  *	@ha: hardware address
  *
@@ -871,12 +873,10 @@
 			 */
 			skb2->mac.raw = skb2->data;
 
-			if (skb2->nh.raw < skb2->data || skb2->nh.raw >= skb2->tail) {
+			if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) {
 				if (net_ratelimit())
 					printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);
 				skb2->nh.raw = skb2->data;
-				if (dev->hard_header)
-					skb2->nh.raw += dev->hard_header_len;
 			}
 
 			skb2->h.raw = skb2->nh.raw;
@@ -887,6 +887,55 @@
 	br_read_unlock(BR_NETPROTO_LOCK);
 }
 
+/* Calculate csum in the case, when packet is misrouted.
+ * If it failed by some reason, ignore and send skb with wrong
+ * checksum.
+ */
+struct sk_buff * skb_checksum_help(struct sk_buff *skb)
+{
+	int offset;
+	unsigned int csum;
+
+	offset = skb->h.raw - skb->data;
+	if (offset > (int)skb->len)
+		BUG();
+	csum = skb_checksum(skb, offset, skb->len-offset, 0);
+
+	offset = skb->tail - skb->h.raw;
+	if (offset <= 0)
+		BUG();
+	if (skb->csum+2 > offset)
+		BUG();
+
+	*(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
+	skb->ip_summed = CHECKSUM_NONE;
+	return skb;
+}
+
+#ifdef CONFIG_HIGHMEM
+/* Actually, we should eliminate this check as soon as we know, that:
+ * 1. IOMMU is present and allows to map all the memory.
+ * 2. No high memory really exists on this machine.
+ */
+
+static inline int
+illegal_highdma(struct net_device *dev, struct sk_buff *skb)
+{
+	int i;
+
+	if (dev->features&NETIF_F_HIGHDMA)
+		return 0;
+
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
+		if (skb_shinfo(skb)->frags[i].page >= highmem_start_page)
+			return 1;
+
+	return 0;
+}
+#else
+#define illegal_highdma(dev, skb)	(0)
+#endif
+
 /**
  *	dev_queue_xmit - transmit a buffer
  *	@skb: buffer to transmit
@@ -899,12 +948,41 @@
  *	guarantee the frame will be transmitted as it may be dropped due
  *	to congestion or traffic shaping.
  */
- 
+
 int dev_queue_xmit(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
 	struct Qdisc  *q;
 
+	if (skb_shinfo(skb)->frag_list &&
+	    !(dev->features&NETIF_F_FRAGLIST) &&
+	    skb_linearize(skb, GFP_ATOMIC) != 0) {
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	/* Fragmented skb is linearized if device does not support SG,
+	 * or if at least one of fragments is in highmem and device
+	 * does not support DMA from it.
+	 */
+	if (skb_shinfo(skb)->nr_frags &&
+	    (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) &&
+	    skb_linearize(skb, GFP_ATOMIC) != 0) {
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	/* If packet is not checksummed and device does not support
+	 * checksumming for this protocol, complete checksumming here.
+	 */
+	if (skb->ip_summed == CHECKSUM_HW &&
+	    (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) &&
+	     (!(dev->features&NETIF_F_IP_CSUM) ||
+	      skb->protocol != htons(ETH_P_IP)))) {
+		if ((skb = skb_checksum_help(skb)) == NULL)
+			return -ENOMEM;
+	}
+
 	/* Grab device queue */
 	spin_lock_bh(&dev->queue_lock);
 	q = dev->qdisc;
@@ -1183,6 +1261,10 @@
 		if (skb == NULL)
 			return ret;
 	}
+	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
+		kfree_skb(skb);
+		return ret;
+	}
 
 	/* The assumption (correct one) is that old protocols
 	   did not depened on BHs different of NET_BH and TIMER_BH.
@@ -1281,7 +1363,7 @@
 void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
 #endif
 
-static int __inline__ handle_bridge(struct sk_buff *skb,
+static __inline__ int handle_bridge(struct sk_buff *skb,
 				     struct packet_type *pt_prev)
 {
 	int ret = NET_RX_DROP;
diff -u --recursive --new-file v2.4.3/linux/net/core/filter.c linux/net/core/filter.c
--- v2.4.3/linux/net/core/filter.c	Sun Apr  2 15:38:54 2000
+++ linux/net/core/filter.c	Thu Apr 12 12:11:39 2001
@@ -72,7 +72,7 @@
 	/* len is UNSIGNED. Byte wide insns relies only on implicit
 	   type casts to prevent reading arbitrary memory locations.
 	 */
-	unsigned int len = skb->len;
+	unsigned int len = skb->len-skb->data_len;
 	struct sock_filter *fentry;	/* We walk down these */
 	u32 A = 0;	   		/* Accumulator */
 	u32 X = 0;   			/* Index Register */
@@ -201,7 +201,7 @@
 			case BPF_LD|BPF_W|BPF_ABS:
 				k = fentry->k;
 load_w:
-				if(k+sizeof(u32) <= len) {
+				if(k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) {
 					A = ntohl(*(u32*)&data[k]);
 					continue;
 				}
@@ -214,13 +214,19 @@
 						A = ntohl(*(u32*)ptr);
 						continue;
 					}
+				} else {
+					u32 tmp;
+					if (!skb_copy_bits(skb, k, &tmp, 4)) {
+						A = ntohl(tmp);
+						continue;
+					}
 				}
 				return 0;
 
 			case BPF_LD|BPF_H|BPF_ABS:
 				k = fentry->k;
 load_h:
-				if(k + sizeof(u16) <= len) {
+				if(k >= 0 && (unsigned int) (k + sizeof(u16)) <= len) {
 					A = ntohs(*(u16*)&data[k]);
 					continue;
 				}
@@ -233,13 +239,19 @@
 						A = ntohs(*(u16*)ptr);
 						continue;
 					}
+				} else {
+					u16 tmp;
+					if (!skb_copy_bits(skb, k, &tmp, 2)) {
+						A = ntohs(tmp);
+						continue;
+					}
 				}
 				return 0;
 
 			case BPF_LD|BPF_B|BPF_ABS:
 				k = fentry->k;
 load_b:
-				if(k < len) {
+				if(k >= 0 && (unsigned int)k < len) {
 					A = data[k];
 					continue;
 				}
@@ -252,6 +264,12 @@
 						A = *ptr;
 						continue;
 					}
+				} else {
+					u8 tmp;
+					if (!skb_copy_bits(skb, k, &tmp, 1)) {
+						A = tmp;
+						continue;
+					}
 				}
 				return 0;
 
@@ -277,7 +295,7 @@
 
 			case BPF_LDX|BPF_B|BPF_MSH:
 				k = fentry->k;
-				if(k >= len)
+				if(k >= 0 && (unsigned int)k >= len)
 					return (0);
 				X = (data[k] & 0xf) << 2;
 				continue;
diff -u --recursive --new-file v2.4.3/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.4.3/linux/net/core/iovec.c	Fri Feb  9 11:29:44 2001
+++ linux/net/core/iovec.c	Thu Apr 12 12:11:39 2001
@@ -102,48 +102,6 @@
 	return err;
 }
 
-/* Copy and checkum skb to user iovec. Caller _must_ check that
-   skb will fit to this iovec.
-
-   Returns: 0       - success.
-            -EINVAL - checksum failure.
-	    -EFAULT - fault during copy. Beware, in this case iovec can be
-	              modified!
- */
-
-int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen)
-{
-	unsigned int csum;
-	int chunk = skb->len - hlen;
-
-	/* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */
-	while (iov->iov_len == 0)
-		iov++;
-
-	if (iov->iov_len < chunk) {
-		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, chunk+hlen, skb->csum)))
-			goto csum_error;
-		if (memcpy_toiovec(iov, skb->h.raw + hlen, chunk))
-			goto fault;
-	} else {
-		int err = 0;
-		csum = csum_partial(skb->h.raw, hlen, skb->csum);
-		csum = csum_and_copy_to_user(skb->h.raw+hlen, iov->iov_base,
-					     chunk, csum, &err);
-		if (err || ((unsigned short)csum_fold(csum)))
-			goto csum_error;
-		iov->iov_len -= chunk;
-		iov->iov_base += chunk;
-	}
-	return 0;
-
-csum_error:
-	return -EINVAL;
-
-fault:
-	return -EFAULT;
-}
-
 /*
  *	In kernel copy to iovec. Returns -EFAULT on error.
  *
diff -u --recursive --new-file v2.4.3/linux/net/core/netfilter.c linux/net/core/netfilter.c
--- v2.4.3/linux/net/core/netfilter.c	Mon Jan 22 13:30:21 2001
+++ linux/net/core/netfilter.c	Thu Apr 12 12:11:39 2001
@@ -451,6 +451,19 @@
 	unsigned int verdict;
 	int ret = 0;
 
+	/* This stopgap cannot be removed until all the hooks are audited. */
+	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+	if (skb->ip_summed == CHECKSUM_HW) {
+		if (outdev == NULL) {
+			skb->ip_summed = CHECKSUM_NONE;
+		} else {
+			skb_checksum_help(skb);
+		}
+	}
+
 	/* We may already have this, but read-locks nest anyway */
 	br_read_lock_bh(BR_NETPROTO_LOCK);
 
diff -u --recursive --new-file v2.4.3/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.4.3/linux/net/core/skbuff.c	Fri Feb 16 16:06:17 2001
+++ linux/net/core/skbuff.c	Thu Apr 12 12:11:39 2001
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.75 2000/12/08 17:15:53 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.87 2001/03/06 22:09:50 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -50,6 +50,7 @@
 #include <linux/skbuff.h>
 #include <linux/cache.h>
 #include <linux/init.h>
+#include <linux/highmem.h>
 
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -185,8 +186,8 @@
 	}
 
 	/* Get the DATA. Size must match skb_add_mtu(). */
-	size = ((size + 15) & ~15); 
-	data = kmalloc(size + sizeof(atomic_t), gfp_mask);
+	size = SKB_DATA_ALIGN(size);
+	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
 	if (data == NULL)
 		goto nodata;
 
@@ -202,9 +203,12 @@
 	/* Set up other state */
 	skb->len = 0;
 	skb->cloned = 0;
+	skb->data_len = 0;
 
 	atomic_set(&skb->users, 1); 
-	atomic_set(skb_datarefp(skb), 1);
+	atomic_set(&(skb_shinfo(skb)->dataref), 1);
+	skb_shinfo(skb)->nr_frags = 0;
+	skb_shinfo(skb)->frag_list = NULL;
 	return skb;
 
 nodata:
@@ -248,14 +252,50 @@
 #endif
 }
 
+static void skb_drop_fraglist(struct sk_buff *skb)
+{
+	struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+	skb_shinfo(skb)->frag_list = NULL;
+
+	do {
+		struct sk_buff *this = list;
+		list = list->next;
+		kfree_skb(this);
+	} while (list);
+}
+
+static void skb_clone_fraglist(struct sk_buff *skb)
+{
+	struct sk_buff *list;
+
+	for (list = skb_shinfo(skb)->frag_list; list; list=list->next)
+		skb_get(list);
+}
+
+static void skb_release_data(struct sk_buff *skb)
+{
+	if (!skb->cloned ||
+	    atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) {
+		if (skb_shinfo(skb)->nr_frags) {
+			int i;
+			for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+				put_page(skb_shinfo(skb)->frags[i].page);
+		}
+
+		if (skb_shinfo(skb)->frag_list)
+			skb_drop_fraglist(skb);
+
+		kfree(skb->head);
+	}
+}
+
 /*
  *	Free an skbuff by memory without cleaning the state. 
  */
 void kfree_skbmem(struct sk_buff *skb)
 {
-	if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb)))  
-		kfree(skb->head);
-
+	skb_release_data(skb);
 	skb_head_to_pool(skb);
 }
 
@@ -316,18 +356,53 @@
 			return NULL;
 	}
 
-	memcpy(n, skb, sizeof(*n));
-	atomic_inc(skb_datarefp(skb));
-	skb->cloned = 1;
-       
-	dst_clone(n->dst);
-	n->cloned = 1;
+#define C(x) n->x = skb->x
+
 	n->next = n->prev = NULL;
 	n->list = NULL;
 	n->sk = NULL;
+	C(stamp);
+	C(dev);
+	C(h);
+	C(nh);
+	C(mac);
+	C(dst);
+	dst_clone(n->dst);
+	memcpy(n->cb, skb->cb, sizeof(skb->cb));
+	C(len);
+	C(data_len);
+	C(csum);
+	n->cloned = 1;
+	C(pkt_type);
+	C(ip_summed);
+	C(priority);
 	atomic_set(&n->users, 1);
+	C(protocol);
+	C(security);
+	C(truesize);
+	C(head);
+	C(data);
+	C(tail);
+	C(end);
 	n->destructor = NULL;
 #ifdef CONFIG_NETFILTER
+	C(nfmark);
+	C(nfcache);
+	C(nfct);
+#ifdef CONFIG_NETFILTER_DEBUG
+	C(nf_debug);
+#endif
+#endif /*CONFIG_NETFILTER*/
+#if defined(CONFIG_HIPPI)
+	C(private);
+#endif
+#ifdef CONFIG_NET_SCHED
+	C(tc_index);
+#endif
+
+	atomic_inc(&(skb_shinfo(skb)->dataref));
+	skb->cloned = 1;
+#ifdef CONFIG_NETFILTER
 	nf_conntrack_get(skb->nfct);
 #endif
 	return n;
@@ -350,7 +425,6 @@
 	new->nh.raw=old->nh.raw+offset;
 	new->mac.raw=old->mac.raw+offset;
 	memcpy(new->cb, old->cb, sizeof(old->cb));
-	new->used=old->used;
 	atomic_set(&new->users, 1);
 	new->pkt_type=old->pkt_type;
 	new->stamp=old->stamp;
@@ -371,7 +445,7 @@
 }
 
 /**
- *	skb_copy	-	copy an sk_buff
+ *	skb_copy	-	create private copy of an sk_buff
  *	@skb: buffer to copy
  *	@gfp_mask: allocation priority
  *
@@ -380,18 +454,115 @@
  *	data to alter. Returns %NULL on failure or the pointer to the buffer
  *	on success. The returned buffer has a reference count of 1.
  *
- *	You must pass %GFP_ATOMIC as the allocation priority if this function
- *	is called from an interrupt.
+ *	As by-product this function converts non-linear &sk_buff to linear
+ *	one, so that &sk_buff becomes completely private and caller is allowed
+ *	to modify all the data of returned buffer. This means that this
+ *	function is not recommended for use in circumstances when only
+ *	header is going to be modified. Use pskb_copy() instead.
  */
  
 struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
 {
 	struct sk_buff *n;
+	int headerlen = skb->data-skb->head;
+
+	/*
+	 *	Allocate the copy buffer
+	 */
+	n=alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
+	if(n==NULL)
+		return NULL;
+
+	/* Set the data pointer */
+	skb_reserve(n,headerlen);
+	/* Set the tail pointer and length */
+	skb_put(n,skb->len);
+	n->csum = skb->csum;
+	n->ip_summed = skb->ip_summed;
+
+	if (skb_copy_bits(skb, -headerlen, n->head, headerlen+skb->len))
+		BUG();
+
+	copy_skb_header(n, skb);
+
+	return n;
+}
+
+/* Keep head the same: replace data */
+int skb_linearize(struct sk_buff *skb, int gfp_mask)
+{
+	unsigned int size;
+	u8 *data;
+	long offset;
+	int headerlen = skb->data - skb->head;
+	int expand = (skb->tail+skb->data_len) - skb->end;
+
+	if (skb_shared(skb))
+		BUG();
+
+	if (expand <= 0)
+		expand = 0;
+
+	size = (skb->end - skb->head + expand);
+	size = SKB_DATA_ALIGN(size);
+	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+	if (data == NULL)
+		return -ENOMEM;
+
+	/* Copy entire thing */
+	if (skb_copy_bits(skb, -headerlen, data, headerlen+skb->len))
+		BUG();
+
+	/* Offset between the two in bytes */
+	offset = data - skb->head;
+
+	/* Free old data. */
+	skb_release_data(skb);
+
+	skb->head = data;
+	skb->end  = data + size;
+
+	/* Set up new pointers */
+	skb->h.raw += offset;
+	skb->nh.raw += offset;
+	skb->mac.raw += offset;
+	skb->tail += offset;
+	skb->data += offset;
+
+	/* Set up shinfo */
+	atomic_set(&(skb_shinfo(skb)->dataref), 1);
+	skb_shinfo(skb)->nr_frags = 0;
+	skb_shinfo(skb)->frag_list = NULL;
+
+	/* We are no longer a clone, even if we were. */
+	skb->cloned = 0;
+
+	skb->tail += skb->data_len;
+	skb->data_len = 0;
+	return 0;
+}
+
+
+/**
+ *	pskb_copy	-	create copy of an sk_buff with private head.
+ *	@skb: buffer to copy
+ *	@gfp_mask: allocation priority
+ *
+ *	Make a copy of both an &sk_buff and part of its data, located
+ *	in header. Fragmented data remain shared. This is used when
+ *	the caller wishes to modify only header of &sk_buff and needs
+ *	private copy of the header to alter. Returns %NULL on failure
+ *	or the pointer to the buffer on success.
+ *	The returned buffer has a reference count of 1.
+ */
+
+struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask)
+{
+	struct sk_buff *n;
 
 	/*
 	 *	Allocate the copy buffer
 	 */
-	 
 	n=alloc_skb(skb->end - skb->head, gfp_mask);
 	if(n==NULL)
 		return NULL;
@@ -399,16 +570,120 @@
 	/* Set the data pointer */
 	skb_reserve(n,skb->data-skb->head);
 	/* Set the tail pointer and length */
-	skb_put(n,skb->len);
+	skb_put(n,skb_headlen(skb));
 	/* Copy the bytes */
-	memcpy(n->head,skb->head,skb->end-skb->head);
+	memcpy(n->data, skb->data, n->len);
 	n->csum = skb->csum;
+	n->ip_summed = skb->ip_summed;
+
+	n->data_len = skb->data_len;
+	n->len = skb->len;
+
+	if (skb_shinfo(skb)->nr_frags) {
+		int i;
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
+			get_page(skb_shinfo(n)->frags[i].page);
+		}
+		skb_shinfo(n)->nr_frags = i;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
+		skb_clone_fraglist(n);
+	}
+
 	copy_skb_header(n, skb);
 
 	return n;
 }
 
 /**
+ *	pskb_expand_head - reallocate header of &sk_buff
+ *	@skb: buffer to reallocate
+ *	@nhead: room to add at head
+ *	@ntail: room to add at tail
+ *	@gfp_mask: allocation priority
+ *
+ *	Expands (or creates identical copy, if &nhead and &ntail are zero)
+ *	header of skb. &sk_buff itself is not changed. &sk_buff MUST have
+ *	reference count of 1. Returns zero in the case of success or error,
+ *	if expansion failed. In the last case, &sk_buff is not changed.
+ *
+ *	All the pointers pointing into skb header may change and must be
+ *	reloaded after call to this function.
+ */
+
+int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask)
+{
+	int i;
+	u8 *data;
+	int size = nhead + (skb->end - skb->head) + ntail;
+	long off;
+
+	if (skb_shared(skb))
+		BUG();
+
+	size = SKB_DATA_ALIGN(size);
+
+	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+	if (data == NULL)
+		goto nodata;
+
+	/* Copy only real data... and, alas, header. This should be
+	 * optimized for the cases when header is void. */
+	memcpy(data+nhead, skb->head, skb->tail-skb->head);
+	memcpy(data+size, skb->end, sizeof(struct skb_shared_info));
+
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
+		get_page(skb_shinfo(skb)->frags[i].page);
+
+	if (skb_shinfo(skb)->frag_list)
+		skb_clone_fraglist(skb);
+
+	skb_release_data(skb);
+
+	off = (data+nhead) - skb->head;
+
+	skb->head = data;
+	skb->end  = data+size;
+
+	skb->data += off;
+	skb->tail += off;
+	skb->mac.raw += off;
+	skb->h.raw += off;
+	skb->nh.raw += off;
+	skb->cloned = 0;
+	atomic_set(&skb_shinfo(skb)->dataref, 1);
+	return 0;
+
+nodata:
+	return -ENOMEM;
+}
+
+/* Make private copy of skb with writable head and some headroom */
+
+struct sk_buff *
+skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
+{
+	struct sk_buff *skb2;
+	int delta = headroom - skb_headroom(skb);
+
+	if (delta <= 0)
+		return pskb_copy(skb, GFP_ATOMIC);
+
+	skb2 = skb_clone(skb, GFP_ATOMIC);
+	if (skb2 == NULL ||
+	    !pskb_expand_head(skb2, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
+		return skb2;
+
+	kfree_skb(skb2);
+	return NULL;
+}
+
+
+/**
  *	skb_copy_expand	-	copy and expand sk_buff
  *	@skb: buffer to copy
  *	@newheadroom: new free bytes at head
@@ -439,7 +714,7 @@
 	 *	Allocate the copy buffer
 	 */
  	 
-	n=alloc_skb(newheadroom + (skb->tail - skb->data) + newtailroom,
+	n=alloc_skb(newheadroom + skb->len + newtailroom,
 		    gfp_mask);
 	if(n==NULL)
 		return NULL;
@@ -450,12 +725,431 @@
 	skb_put(n,skb->len);
 
 	/* Copy the data only. */
-	memcpy(n->data, skb->data, skb->len);
+	if (skb_copy_bits(skb, 0, n->data, skb->len))
+		BUG();
 
 	copy_skb_header(n, skb);
 	return n;
 }
 
+/* Trims skb to length len. It can change skb pointers, if "realloc" is 1.
+ * If realloc==0 and trimming is impossible without change of data,
+ * it is BUG().
+ */
+
+int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc)
+{
+	int offset = skb_headlen(skb);
+	int nfrags = skb_shinfo(skb)->nr_frags;
+	int i;
+
+	for (i=0; i<nfrags; i++) {
+		int end = offset + skb_shinfo(skb)->frags[i].size;
+		if (end > len) {
+			if (skb_cloned(skb)) {
+				if (!realloc)
+					BUG();
+				if (!pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+					return -ENOMEM;
+			}
+			if (len <= offset) {
+				put_page(skb_shinfo(skb)->frags[i].page);
+				skb_shinfo(skb)->nr_frags--;
+			} else {
+				skb_shinfo(skb)->frags[i].size = len-offset;
+			}
+		}
+		offset = end;
+	}
+
+	if (offset < len) {
+		skb->data_len -= skb->len - len;
+		skb->len = len;
+	} else {
+		if (len <= skb_headlen(skb)) {
+			skb->len = len;
+			skb->data_len = 0;
+			skb->tail = skb->data + len;
+			if (skb_shinfo(skb)->frag_list && !skb_cloned(skb))
+				skb_drop_fraglist(skb);
+		} else {
+			skb->data_len -= skb->len - len;
+			skb->len = len;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *	__pskb_pull_tail - advance tail of skb header 
+ *	@skb: buffer to reallocate
+ *	@delta: number of bytes to advance tail
+ *
+ *	The function makes a sense only on a fragmented &sk_buff,
+ *	it expands header moving its tail forward and copying necessary
+ *	data from fragmented part.
+ *
+ *	&sk_buff MUST have reference count of 1.
+ *
+ *	Returns %NULL (and &sk_buff does not change) if pull failed
+ *	or value of new tail of skb in the case of success.
+ *
+ *	All the pointers pointing into skb header may change and must be
+ *	reloaded after call to this function.
+ */
+
+/* Moves tail of skb head forward, copying data from fragmented part,
+ * when it is necessary.
+ * 1. It may fail due to malloc failure.
+ * 2. It may change skb pointers.
+ *
+ * It is pretty complicated. Luckily, it is called only in exceptional cases.
+ */
+unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta)
+{
+	int i, k, eat;
+
+	/* If skb has not enough free space at tail, get new one
+	 * plus 128 bytes for future expansions. If we have enough
+	 * room at tail, reallocate without expansion only if skb is cloned.
+	 */
+	eat = (skb->tail+delta) - skb->end;
+
+	if (eat > 0 || skb_cloned(skb)) {
+		if (pskb_expand_head(skb, 0, eat>0 ? eat+128 : 0, GFP_ATOMIC))
+			return NULL;
+	}
+
+	if (skb_copy_bits(skb, skb_headlen(skb), skb->tail, delta))
+		BUG();
+
+	/* Optimization: no fragments, no reasons to preestimate
+	 * size of pulled pages. Superb.
+	 */
+	if (skb_shinfo(skb)->frag_list == NULL)
+		goto pull_pages;
+
+	/* Estimate size of pulled pages. */
+	eat = delta;
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+		if (skb_shinfo(skb)->frags[i].size >= eat)
+			goto pull_pages;
+		eat -= skb_shinfo(skb)->frags[i].size;
+	}
+
+	/* If we need update frag list, we are in troubles.
+	 * Certainly, it possible to add an offset to skb data,
+	 * but taking into account that pulling is expected to
+	 * be very rare operation, it is worth to fight against
+	 * further bloating skb head and crucify ourselves here instead.
+	 * Pure masohism, indeed. 8)8)
+	 */
+	if (eat) {
+		struct sk_buff *list = skb_shinfo(skb)->frag_list;
+		struct sk_buff *clone = NULL;
+		struct sk_buff *insp = NULL;
+
+		do {
+			if (list == NULL)
+				BUG();
+
+			if (list->len <= eat) {
+				/* Eaten as whole. */
+				eat -= list->len;
+				list = list->next;
+				insp = list;
+			} else {
+				/* Eaten partially. */
+
+				if (skb_shared(list)) {
+					/* Sucks! We need to fork list. :-( */
+					clone = skb_clone(list, GFP_ATOMIC);
+					if (clone == NULL)
+						return NULL;
+					insp = list->next;
+					list = clone;
+				} else {
+					/* This may be pulled without
+					 * problems. */
+					insp = list;
+				}
+				if (pskb_pull(list, eat) == NULL) {
+					if (clone)
+						kfree_skb(clone);
+					return NULL;
+				}
+				break;
+			}
+		} while (eat);
+
+		/* Free pulled out fragments. */
+		while ((list = skb_shinfo(skb)->frag_list) != insp) {
+			skb_shinfo(skb)->frag_list = list->next;
+			kfree_skb(list);
+		}
+		/* And insert new clone at head. */
+		if (clone) {
+			clone->next = list;
+			skb_shinfo(skb)->frag_list = clone;
+		}
+	}
+	/* Success! Now we may commit changes to skb data. */
+
+pull_pages:
+	eat = delta;
+	k = 0;
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+		if (skb_shinfo(skb)->frags[i].size <= eat) {
+			put_page(skb_shinfo(skb)->frags[i].page);
+			eat -= skb_shinfo(skb)->frags[i].size;
+		} else {
+			skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
+			if (eat) {
+				skb_shinfo(skb)->frags[k].page_offset += eat;
+				skb_shinfo(skb)->frags[k].size -= eat;
+				eat = 0;
+			}
+			k++;
+		}
+	}
+	skb_shinfo(skb)->nr_frags = k;
+
+	skb->tail += delta;
+	skb->data_len -= delta;
+
+	return skb->tail;
+}
+
+/* Copy some data bits from skb to kernel buffer. */
+
+int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
+{
+	int i, copy;
+	int start = skb->len - skb->data_len;
+
+	if (offset > (int)skb->len-len)
+		goto fault;
+
+	/* Copy header. */
+	if ((copy = start-offset) > 0) {
+		if (copy > len)
+			copy = len;
+		memcpy(to, skb->data + offset, copy);
+		if ((len -= copy) == 0)
+			return 0;
+		offset += copy;
+		to += copy;
+	}
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset+len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end-offset) > 0) {
+			u8 *vaddr;
+
+			if (copy > len)
+				copy = len;
+
+			vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
+			memcpy(to, vaddr+skb_shinfo(skb)->frags[i].page_offset+
+			       offset-start, copy);
+			kunmap_skb_frag(vaddr);
+
+			if ((len -= copy) == 0)
+				return 0;
+			offset += copy;
+			to += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list;
+
+		for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset+len);
+
+			end = start + list->len;
+			if ((copy = end-offset) > 0) {
+				if (copy > len)
+					copy = len;
+				if (skb_copy_bits(list, offset-start, to, copy))
+					goto fault;
+				if ((len -= copy) == 0)
+					return 0;
+				offset += copy;
+				to += copy;
+			}
+			start = end;
+		}
+	}
+	if (len == 0)
+		return 0;
+
+fault:
+	return -EFAULT;
+}
+
+/* Checksum skb data. */
+
+unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum)
+{
+	int i, copy;
+	int start = skb->len - skb->data_len;
+	int pos = 0;
+
+	/* Checksum header. */
+	if ((copy = start-offset) > 0) {
+		if (copy > len)
+			copy = len;
+		csum = csum_partial(skb->data+offset, copy, csum);
+		if ((len -= copy) == 0)
+			return csum;
+		offset += copy;
+		pos = copy;
+	}
+
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset+len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end-offset) > 0) {
+			unsigned int csum2;
+			u8 *vaddr;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			if (copy > len)
+				copy = len;
+			vaddr = kmap_skb_frag(frag);
+			csum2 = csum_partial(vaddr + frag->page_offset +
+					     offset-start, copy, 0);
+			kunmap_skb_frag(vaddr);
+			csum = csum_block_add(csum, csum2, pos);
+			if (!(len -= copy))
+				return csum;
+			offset += copy;
+			pos += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list;
+
+		for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset+len);
+
+			end = start + list->len;
+			if ((copy = end-offset) > 0) {
+				unsigned int csum2;
+				if (copy > len)
+					copy = len;
+				csum2 = skb_checksum(list, offset-start, copy, 0);
+				csum = csum_block_add(csum, csum2, pos);
+				if ((len -= copy) == 0)
+					return csum;
+				offset += copy;
+				pos += copy;
+			}
+			start = end;
+		}
+	}
+	if (len == 0)
+		return csum;
+
+	BUG();
+	return csum;
+}
+
+/* Both of above in one bottle. */
+
+unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum)
+{
+	int i, copy;
+	int start = skb->len - skb->data_len;
+	int pos = 0;
+
+	/* Copy header. */
+	if ((copy = start-offset) > 0) {
+		if (copy > len)
+			copy = len;
+		csum = csum_partial_copy_nocheck(skb->data+offset, to, copy, csum);
+		if ((len -= copy) == 0)
+			return csum;
+		offset += copy;
+		to += copy;
+		pos = copy;
+	}
+
+	for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset+len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end-offset) > 0) {
+			unsigned int csum2;
+			u8 *vaddr;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			if (copy > len)
+				copy = len;
+			vaddr = kmap_skb_frag(frag);
+			csum2 = csum_partial_copy_nocheck(vaddr + frag->page_offset +
+						      offset-start, to, copy, 0);
+			kunmap_skb_frag(vaddr);
+			csum = csum_block_add(csum, csum2, pos);
+			if (!(len -= copy))
+				return csum;
+			offset += copy;
+			to += copy;
+			pos += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list;
+
+		for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
+			unsigned int csum2;
+			int end;
+
+			BUG_TRAP(start <= offset+len);
+
+			end = start + list->len;
+			if ((copy = end-offset) > 0) {
+				if (copy > len)
+					copy = len;
+				csum2 = skb_copy_and_csum_bits(list, offset-start, to, copy, 0);
+				csum = csum_block_add(csum, csum2, pos);
+				if ((len -= copy) == 0)
+					return csum;
+				offset += copy;
+				to += copy;
+				pos += copy;
+			}
+			start = end;
+		}
+	}
+	if (len == 0)
+		return csum;
+
+	BUG();
+	return csum;
+}
+
+
 #if 0
 /* 
  * 	Tune the memory allocator for a new MTU size.
@@ -463,7 +1157,7 @@
 void skb_add_mtu(int mtu)
 {
 	/* Must match allocation in alloc_skb */
-	mtu = ((mtu + 15) & ~15) + sizeof(atomic_t);
+	mtu = SKB_DATA_ALIGN(mtu) + sizeof(struct skb_shared_info);
 
 	kmem_add_cache_size(mtu);
 }
diff -u --recursive --new-file v2.4.3/linux/net/core/sock.c linux/net/core/sock.c
--- v2.4.3/linux/net/core/sock.c	Sat Feb  3 11:26:44 2001
+++ linux/net/core/sock.c	Wed Apr 25 14:57:39 2001
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.104 2001/01/30 07:48:30 davem Exp $
+ * Version:	$Id: sock.c,v 1.110 2001/04/20 20:46:19 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -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:
  *
@@ -425,11 +426,13 @@
 		struct timeval tm;
 	} v;
 	
-	int lv=sizeof(int),len;
+	unsigned int lv=sizeof(int),len;
   	
   	if(get_user(len,optlen))
   		return -EFAULT;
-
+	if(len < 0)
+		return -EINVAL;
+		
   	switch(optname) 
   	{
 		case SO_DEBUG:		
@@ -644,7 +647,8 @@
 
 	/* In case it might be waiting for more memory. */
 	atomic_sub(skb->truesize, &sk->wmem_alloc);
-	sk->write_space(sk);
+	if (!sk->use_write_queue)
+		sk->write_space(sk);
 	sock_put(sk);
 }
 
@@ -727,6 +731,8 @@
 	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
+		if (!timeo)
+			break;
 		if (signal_pending(current))
 			break;
 		set_bit(SOCK_NOSPACE, &sk->socket->flags);
@@ -750,7 +756,7 @@
  */
 
 struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
-			unsigned long fallback, int noblock, int *errcode)
+			int noblock, int *errcode)
 {
 	int err;
 	struct sk_buff *skb;
@@ -780,15 +786,6 @@
 			goto failure;
 
 		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
-			if (fallback) {
-				/* The buffer get won't block, or use the atomic queue.
-			 	* It does produce annoying no free page messages still.
-			 	*/
-				skb = alloc_skb(size, GFP_BUFFER);
-				if (skb)
-					break;
-				try_size = fallback;
-			}
 			skb = alloc_skb(try_size, sk->allocation);
 			if (skb)
 				break;
@@ -1064,6 +1061,36 @@
 {
 	/* Mirror missing mmap method error code */
 	return -ENODEV;
+}
+
+ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
+{
+	ssize_t res;
+	struct msghdr msg;
+	struct iovec iov;
+	mm_segment_t old_fs;
+	char *kaddr;
+
+	kaddr = kmap(page);
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = flags;
+
+	iov.iov_base = kaddr + offset;
+	iov.iov_len = size;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	res = sock_sendmsg(sock, &msg, size);
+	set_fs(old_fs);
+
+	kunmap(page);
+	return res;
 }
 
 /*
diff -u --recursive --new-file v2.4.3/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.4.3/linux/net/decnet/af_decnet.c	Sun Mar 25 18:14:25 2001
+++ linux/net/decnet/af_decnet.c	Thu Apr 12 12:11:39 2001
@@ -2128,6 +2128,7 @@
 	sendmsg:	dn_sendmsg,
 	recvmsg:	dn_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #ifdef CONFIG_SYSCTL
diff -u --recursive --new-file v2.4.3/linux/net/econet/Makefile linux/net/econet/Makefile
--- v2.4.3/linux/net/econet/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/net/econet/Makefile	Thu Apr 19 08:38:50 2001
@@ -9,7 +9,8 @@
 
 O_TARGET := econet.o
 
-obj-y := af_econet.o sysctl_net_ec.o
+obj-y := af_econet.o
 obj-m := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.4.3/linux/net/econet/af_econet.c linux/net/econet/af_econet.c
--- v2.4.3/linux/net/econet/af_econet.c	Mon Oct 16 12:42:54 2000
+++ linux/net/econet/af_econet.c	Thu Apr 19 08:38:50 2001
@@ -297,7 +297,7 @@
 #ifdef CONFIG_ECONET_NATIVE
 		atomic_inc(&dev->refcnt);
 		
-		skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
+		skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 
 					  msg->msg_flags & MSG_DONTWAIT, &err);
 		if (skb==NULL)
 			goto out_unlock;
@@ -410,7 +410,7 @@
 	}
 
 	/* Get a skbuff (no data, just holds our cb information) */
-	if ((skb = sock_alloc_send_skb(sk, 0, 0, 
+	if ((skb = sock_alloc_send_skb(sk, 0, 
 			     msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
@@ -695,8 +695,8 @@
 }
 
 static struct net_proto_family econet_family_ops = {
-	PF_ECONET,
-	econet_create
+	family:		PF_ECONET,
+	create:		econet_create,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
@@ -717,6 +717,7 @@
 	sendmsg:	econet_sendmsg,
 	recvmsg:	econet_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
@@ -726,7 +727,7 @@
  *	Find the listening socket, if any, for the given data.
  */
 
-struct sock *ec_listening_socket(unsigned char port, unsigned char
+static struct sock *ec_listening_socket(unsigned char port, unsigned char
 				 station, unsigned char net)
 {
 	struct sock *sk = econet_sklist;
@@ -1064,18 +1065,13 @@
 			       hdr->port);
 }
 
-struct packet_type econet_packet_type=
-{
-	0,
-	NULL,
-	econet_rcv,
-	NULL,
-	NULL
+static struct packet_type econet_packet_type = {
+	type:		__constant_htons(ETH_P_ECONET),
+	func:		econet_rcv,
 };
 
 static void econet_hw_initialise(void)
 {
-	econet_packet_type.type = htons(ETH_P_ECONET);
 	dev_add_pack(&econet_packet_type);
 }
 
@@ -1104,15 +1100,12 @@
 	return NOTIFY_DONE;
 }
 
-struct notifier_block econet_netdev_notifier={
-	econet_notifier,
-	NULL,
-	0
+static struct notifier_block econet_netdev_notifier = {
+	notifier_call:	econet_notifier,
 };
 
-void __exit econet_proto_exit(void)
+static void __exit econet_proto_exit(void)
 {
-	extern void econet_sysctl_unregister(void);
 #ifdef CONFIG_ECONET_AUNUDP
 	del_timer(&ab_cleanup_timer);
 	if (udpsock)
@@ -1120,14 +1113,10 @@
 #endif
 	unregister_netdevice_notifier(&econet_netdev_notifier);
 	sock_unregister(econet_family_ops.family);
-#ifdef CONFIG_SYSCTL
-	econet_sysctl_unregister();
-#endif
 }
 
-int __init econet_proto_init(void)
+static int __init econet_proto_init(void)
 {
-	extern void econet_sysctl_register(void);
 	sock_register(&econet_family_ops);
 #ifdef CONFIG_ECONET_AUNUDP
 	spin_lock_init(&aun_queue_lock);
@@ -1137,9 +1126,6 @@
 	econet_hw_initialise();
 #endif
 	register_netdevice_notifier(&econet_netdev_notifier);
-#ifdef CONFIG_SYSCTL
-	econet_sysctl_register();
-#endif
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/net/econet/sysctl_net_ec.c linux/net/econet/sysctl_net_ec.c
--- v2.4.3/linux/net/econet/sysctl_net_ec.c	Thu Mar  9 06:57:17 2000
+++ linux/net/econet/sysctl_net_ec.c	Wed Dec 31 16:00:00 1969
@@ -1,43 +0,0 @@
-/*
- *	An implementation of the Acorn Econet and AUN protocols.
- *	Philip Blundell <philb@gnu.org>
- *
- *	Fixes:
- *
- *	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.
- *
- */
-
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-
-ctl_table econet_table[] = {
-	{0}
-};
-
-static struct ctl_table_header *econet_sysctl_header;
-
-static ctl_table econet_net_table[] = {
-	{NET_ECONET, "econet", NULL, 0, 0555, econet_table},
-        {0}
-};
-
-static ctl_table econet_root_table[] = {
-	{CTL_NET, "net", NULL, 0, 0555, econet_net_table},
-        {0}
-};
-
-void econet_sysctl_register(void)
-{
-	econet_sysctl_header = register_sysctl_table(econet_root_table, 0);
-}
-
-#ifdef MODULE
-void econet_sysctl_unregister(void)
-{
-	unregister_sysctl_table(econet_sysctl_header);
-}
-#endif	/* MODULE */
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.4.3/linux/net/ipv4/af_inet.c	Fri Dec 29 14:07:24 2000
+++ linux/net/ipv4/af_inet.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.127 2000/12/22 19:51:50 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.129 2001/03/02 03:13:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -355,6 +355,8 @@
 	else
 		sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT;
 
+	sk->protinfo.af_inet.id = 0;
+
 	sock_init_data(sock,sk);
 
 	sk->destruct = inet_sock_destruct;
@@ -934,7 +936,8 @@
 	getsockopt:	inet_getsockopt,
 	sendmsg:	inet_sendmsg,
 	recvmsg:	inet_recvmsg,
-	mmap:		sock_no_mmap
+	mmap:		sock_no_mmap,
+	sendpage:	tcp_sendpage
 };
 
 struct proto_ops inet_dgram_ops = {
@@ -955,6 +958,7 @@
 	sendmsg:	inet_sendmsg,
 	recvmsg:	inet_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 struct net_proto_family inet_family_ops = {
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.4.3/linux/net/ipv4/arp.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/arp.c	Thu Apr 12 12:11:39 2001
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.90 2000/10/04 09:20:56 anton Exp $
+ * Version:	$Id: arp.c,v 1.96 2001/02/02 08:42:59 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -590,6 +590,13 @@
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		goto out_of_mem;
 
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0)
+			goto freeskb;
+		arp = skb->nh.arph;
+		arp_ptr= (unsigned char *)(arp+1);
+	}
+
 	switch (dev_type) {
 	default:	
 		if (arp->ar_pro != __constant_htons(ETH_P_IP))
@@ -796,9 +803,10 @@
 	}
 
 out:
-	kfree_skb(skb);
 	if (in_dev)
 		in_dev_put(in_dev);
+freeskb:
+	kfree_skb(skb);
 out_of_mem:
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.4.3/linux/net/ipv4/icmp.c	Fri Aug  4 18:18:49 2000
+++ linux/net/ipv4/icmp.c	Thu Apr 19 08:38:50 2001
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.71 2000/08/02 06:01:48 davem Exp $
+ *	Version: $Id: icmp.c,v 1.74 2001/04/16 23:58:51 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -58,197 +58,6 @@
  *	- Should use skb_pull() instead of all the manual checking.
  *	  This would also greatly simply some upper layer error handlers. --AK
  *
- * RFC1122 (Host Requirements -- Comm. Layer) Status:
- * (boy, are there a lot of rules for ICMP)
- *  3.2.2 (Generic ICMP stuff)
- *   MUST discard messages of unknown type. (OK)
- *   MUST copy at least the first 8 bytes from the offending packet
- *     when sending ICMP errors. (OBSOLETE -- see RFC1812)
- *   MUST pass received ICMP errors up to protocol level. (OK)
- *   SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812)
- *   MUST NOT send ICMP errors in reply to:
- *     ICMP errors (OK)
- *     Broadcast/multicast datagrams (OK)
- *     MAC broadcasts (OK)
- *     Non-initial fragments (OK)
- *     Datagram with a source address that isn't a single host. (OK)
- *  3.2.2.1 (Destination Unreachable)
- *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
- *  3.2.2.2 (Redirect)
- *   Host SHOULD NOT send ICMP_REDIRECTs.  (OK)
- *   MUST update routing table in response to host or network redirects.
- *     (host OK, network OBSOLETE)
- *   SHOULD drop redirects if they're not from directly connected gateway
- *     (OK -- we drop it if it's not from our old gateway, which is close
- *      enough)
- * 3.2.2.3 (Source Quench)
- *   MUST pass incoming SOURCE_QUENCHs to transport layer (OK)
- *   Other requirements are dealt with at the transport layer.
- * 3.2.2.4 (Time Exceeded)
- *   MUST pass TIME_EXCEEDED to transport layer (OK)
- *   Other requirements dealt with at IP (generating TIME_EXCEEDED).
- * 3.2.2.5 (Parameter Problem)
- *   SHOULD generate these (OK)
- *   MUST pass received PARAMPROBLEM to transport layer (NOT YET)
- *   	[Solaris 2.X seems to assert EPROTO when this occurs] -- AC
- * 3.2.2.6 (Echo Request/Reply)
- *   MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK)
- *   MAY discard broadcast ECHO_REQUESTs. (Configurable with a sysctl.)
- *   MUST reply using same source address as the request was sent to.
- *     We're OK for unicast ECHOs, and it doesn't say anything about
- *     how to handle broadcast ones, since it's optional.
- *   MUST copy data from REQUEST to REPLY (OK)
- *     unless it would require illegal fragmentation (OK)
- *   MUST pass REPLYs to transport/user layer (OK)
- *   MUST use any provided source route (reversed) for REPLY. (NOT YET)
- * 3.2.2.7 (Information Request/Reply)
- *   MUST NOT implement this. (I guess that means silently discard...?) (OK)
- * 3.2.2.8 (Timestamp Request/Reply)
- *   MAY implement (OK)
- *   SHOULD be in-kernel for "minimum variability" (OK)
- *   MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
- *   MUST reply using same source address as the request was sent to. (OK)
- *   MUST reverse source route, as per ECHO (NOT YET)
- *   MUST pass REPLYs to transport/user layer (requires RAW, just like 
- *	ECHO) (OK)
- *   MUST update clock for timestamp at least 15 times/sec (OK)
- *   MUST be "correct within a few minutes" (OK)
- * 3.2.2.9 (Address Mask Request/Reply)
- *   MAY implement (OK)
- *   MUST send a broadcast REQUEST if using this system to set netmask
- *     (OK... we don't use it)
- *   MUST discard received REPLYs if not using this system (OK)
- *   MUST NOT send replies unless specifically made agent for this sort
- *     of thing. (OK)
- *
- *
- * RFC 1812 (IPv4 Router Requirements) Status (even longer):
- *  4.3.2.1 (Unknown Message Types)
- *   MUST pass messages of unknown type to ICMP user iface or silently discard
- *     them (OK)
- *  4.3.2.2 (ICMP Message TTL)
- *   MUST initialize TTL when originating an ICMP message (OK)
- *  4.3.2.3 (Original Message Header)
- *   SHOULD copy as much data from the offending packet as possible without
- *     the length of the ICMP datagram exceeding 576 bytes (OK)
- *   MUST leave original IP header of the offending packet, but we're not
- *     required to undo modifications made (OK)
- *  4.3.2.4 (Original Message Source Address)
- *   MUST use one of addresses for the interface the orig. packet arrived as
- *     source address (OK)
- *  4.3.2.5 (TOS and Precedence)
- *   SHOULD leave TOS set to the same value unless the packet would be 
- *     discarded for that reason (OK)
- *   MUST use TOS=0 if not possible to leave original value (OK)
- *   MUST leave IP Precedence for Source Quench messages (OK -- not sent 
- *	at all)
- *   SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control)
- *     for all other error messages (OK, we use 6)
- *   MAY allow configuration of IP Precedence (OK -- not done)
- *   MUST leave IP Precedence and TOS for reply messages (OK)
- *  4.3.2.6 (Source Route)
- *   SHOULD use reverse source route UNLESS sending Parameter Problem on source
- *     routing and UNLESS the packet would be immediately discarded (NOT YET)
- *  4.3.2.7 (When Not to Send ICMP Errors)
- *   MUST NOT send ICMP errors in reply to:
- *     ICMP errors (OK)
- *     Packets failing IP header validation tests unless otherwise noted (OK)
- *     Broadcast/multicast datagrams (OK)
- *     MAC broadcasts (OK)
- *     Non-initial fragments (OK)
- *     Datagram with a source address that isn't a single host. (OK)
- *  4.3.2.8 (Rate Limiting)
- *   SHOULD be able to limit error message rate (OK)
- *   SHOULD allow setting of rate limits (OK, in the source)
- *  4.3.3.1 (Destination Unreachable)
- *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
- *  4.3.3.2 (Redirect)
- *   MAY ignore ICMP Redirects if running a routing protocol or if forwarding
- *     is enabled on the interface (OK -- ignores)
- *  4.3.3.3 (Source Quench)
- *   SHOULD NOT originate SQ messages (OK)
- *   MUST be able to limit SQ rate if originates them (OK as we don't 
- *	send them)
- *   MAY ignore SQ messages it receives (OK -- we don't)
- *  4.3.3.4 (Time Exceeded)
- *   Requirements dealt with at IP (generating TIME_EXCEEDED).
- *  4.3.3.5 (Parameter Problem)
- *   MUST generate these for all errors not covered by other messages (OK)
- *   MUST include original value of the value pointed by (OK)
- *  4.3.3.6 (Echo Request)
- *   MUST implement echo server function (OK)
- *   MUST process at ER of at least max(576, MTU) (OK)
- *   MAY reject broadcast/multicast ER's (We don't, but that's OK)
- *   SHOULD have a config option for silently ignoring ER's (OK)
- *   MUST have a default value for the above switch = NO (OK)
- *   MUST have application layer interface for Echo Request/Reply (OK)
- *   MUST reply using same source address as the request was sent to.
- *     We're OK for unicast ECHOs, and it doesn't say anything about
- *     how to handle broadcast ones, since it's optional.
- *   MUST copy data from Request to Reply (OK)
- *   SHOULD update Record Route / Timestamp options (??)
- *   MUST use reversed Source Route for Reply if possible (NOT YET)
- *  4.3.3.7 (Information Request/Reply)
- *   SHOULD NOT originate or respond to these (OK)
- *  4.3.3.8 (Timestamp / Timestamp Reply)
- *   MAY implement (OK)
- *   MUST reply to every Timestamp message received (OK)
- *   MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
- *   MUST reply using same source address as the request was sent to. (OK)
- *   MUST use reversed Source Route if possible (NOT YET)
- *   SHOULD update Record Route / Timestamp options (??)
- *   MUST pass REPLYs to transport/user layer (requires RAW, just like 
- *	ECHO) (OK)
- *   MUST update clock for timestamp at least 16 times/sec (OK)
- *   MUST be "correct within a few minutes" (OK)
- * 4.3.3.9 (Address Mask Request/Reply)
- *   MUST have support for receiving AMRq and responding with AMRe (OK, 
- *	but only as a compile-time option)
- *   SHOULD have option for each interface for AMRe's, MUST default to 
- *	NO (NOT YET)
- *   MUST NOT reply to AMRq before knows the correct AM (OK)
- *   MUST NOT respond to AMRq with source address 0.0.0.0 on physical
- *    	interfaces having multiple logical i-faces with different masks
- *	(NOT YET)
- *   SHOULD examine all AMRe's it receives and check them (NOT YET)
- *   SHOULD log invalid AMRe's (AM+sender) (NOT YET)
- *   MUST NOT use contents of AMRe to determine correct AM (OK)
- *   MAY broadcast AMRe's after having configured address masks (OK -- doesn't)
- *   MUST NOT do broadcast AMRe's if not set by extra option (OK, no option)
- *   MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK)
- * 4.3.3.10 (Router Advertisement and Solicitations)
- *   MUST support router part of Router Discovery Protocol on all networks we
- *     support broadcast or multicast addressing. (OK -- done by gated)
- *   MUST have all config parameters with the respective defaults (OK)
- * 5.2.7.1 (Destination Unreachable)
- *   MUST generate DU's (OK)
- *   SHOULD choose a best-match response code (OK)
- *   SHOULD NOT generate Host Isolated codes (OK)
- *   SHOULD use Communication Administratively Prohibited when administratively
- *     filtering packets (NOT YET -- bug-to-bug compatibility)
- *   MAY include config option for not generating the above and silently
- *	discard the packets instead (OK)
- *   MAY include config option for not generating Precedence Violation and
- *     Precedence Cutoff messages (OK as we don't generate them at all)
- *   MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts
- *     on the same network might be reachable (OK -- no net unreach's at all)
- *   MUST use new form of Fragmentation Needed and DF Set messages (OK)
- * 5.2.7.2 (Redirect)
- *   MUST NOT generate network redirects (OK)
- *   MUST be able to generate host redirects (OK)
- *   SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS)
- *   MUST have an option to use Host redirects instead of Host+TOS ones (OK as
- *     no Host+TOS Redirects are used)
- *   MUST NOT generate redirects unless forwarding to the same i-face and the
- *     dest. address is on the same subnet as the src. address and no source
- *     routing is in use. (OK)
- *   MUST NOT follow redirects when using a routing protocol (OK)
- *   MAY use redirects if not using a routing protocol (OK, compile-time option)
- *   MUST comply to Host Requirements when not acting as a router (OK)
- *  5.2.7.3 (Time Exceeded)
- *   MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK)
- *   MAY have a per-interface option to disable origination of TE messages, but
- *     it MUST default to "originate" (OK -- we don't support it)
  */
 
 #include <linux/config.h>
@@ -282,6 +91,26 @@
 #define min(a,b)	((a)<(b)?(a):(b))
 
 /*
+ *	Build xmit assembly blocks
+ */
+
+struct icmp_bxm
+{
+	struct sk_buff *skb;
+	int offset;
+	int data_len;
+
+	unsigned int csum;
+	struct {
+		struct icmphdr icmph;
+		__u32	       times[3];
+	} data;
+	int head_len;
+	struct ip_options replyopts;
+	unsigned char  optbuf[40];
+};
+
+/*
  *	Statistics
  */
  
@@ -324,7 +153,7 @@
 {
 	unsigned long *output;		/* Address to increment on output */
 	unsigned long *input;		/* Address to increment on input */
-	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len);
+	void (*handler)(struct sk_buff *skb);
 	short	error;		/* This ICMP is classed as an error message */
 	int *timeout; /* Rate limit */
 };
@@ -466,11 +295,12 @@
 {
 	struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
 	struct icmphdr *icmph;
-	unsigned long csum;
+	unsigned int csum;
 
 	if (offset) {
-		icmp_param->csum=csum_partial_copy_nocheck(icmp_param->data_ptr+offset-sizeof(struct icmphdr), 
-				to, fraglen,icmp_param->csum);
+		icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb,
+							icmp_param->offset+(offset-icmp_param->head_len), 
+							to, fraglen,icmp_param->csum);
 		return 0;
 	}
 
@@ -479,22 +309,24 @@
 	 *	the other fragments first, so that we get the checksum
 	 *	for the whole packet here.
 	 */
-	csum = csum_partial_copy_nocheck((void *)&icmp_param->icmph,
-		to, sizeof(struct icmphdr), 
+	csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
+		to, icmp_param->head_len,
 		icmp_param->csum);
-	csum = csum_partial_copy_nocheck(icmp_param->data_ptr,
-		to+sizeof(struct icmphdr),
-		fraglen-sizeof(struct icmphdr), csum);
+	csum=skb_copy_and_csum_bits(icmp_param->skb,
+				    icmp_param->offset, 
+				    to+icmp_param->head_len,
+				    fraglen-icmp_param->head_len,
+				    csum);
 	icmph=(struct icmphdr *)to;
 	icmph->checksum = csum_fold(csum);
 	return 0;
 }
- 
+
 /*
  *	Driving logic for building and sending ICMP messages.
  */
 
-void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
+static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 {
 	struct sock *sk=icmp_socket->sk;
 	struct ipcm_cookie ipc;
@@ -507,9 +339,9 @@
 	if (icmp_xmit_lock_bh())
 		return;
 
-	icmp_param->icmph.checksum=0;
+	icmp_param->data.icmph.checksum=0;
 	icmp_param->csum=0;
-	icmp_out_count(icmp_param->icmph.type);
+	icmp_out_count(icmp_param->data.icmph.type);
 
 	sk->protinfo.af_inet.tos = skb->nh.iph->tos;
 	daddr = ipc.addr = rt->rt_src;
@@ -521,10 +353,10 @@
 	}
 	if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
 		goto out;
-	if (icmpv4_xrlim_allow(rt, icmp_param->icmph.type, 
-			       icmp_param->icmph.code)) { 
+	if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, 
+			       icmp_param->data.icmph.code)) { 
 		ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
-			      icmp_param->data_len+sizeof(struct icmphdr),
+			      icmp_param->data_len+icmp_param->head_len,
 			      &ipc, rt, MSG_DONTWAIT);
 	}
 	ip_rt_put(rt);
@@ -543,10 +375,9 @@
  *			MUST reply to only the first fragment.
  */
 
-void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info)
+void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
 {
 	struct iphdr *iph;
-	struct icmphdr *icmph;
 	int room;
 	struct icmp_bxm icmp_param;
 	struct rtable *rt = (struct rtable*)skb_in->dst;
@@ -558,10 +389,15 @@
 		return;
 
 	/*
-	 *	Find the original header
+	 *	Find the original header. It is expected to be valid, of course.
+	 *	Check this, icmp_send is called from the most obscure devices
+	 *	sometimes.
 	 */
 	iph = skb_in->nh.iph;
 
+	if ((u8*)iph < skb_in->head || (u8*)(iph+1) > skb_in->tail)
+		return;
+
 	/*
 	 *	No replies to physical multicast/broadcast
 	 */
@@ -589,17 +425,24 @@
 		 *	We are an error, check if we are replying to an ICMP error
 		 */
 		if (iph->protocol==IPPROTO_ICMP) {
-			icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+			u8 inner_type;
+
+			if (skb_copy_bits(skb_in,
+					  skb_in->nh.raw + (iph->ihl<<2)
+					  + offsetof(struct icmphdr, type)
+					  - skb_in->data,
+					  &inner_type, 1))
+				return;
+
 			/*
 			 *	Assume any unknown ICMP type is an error. This isn't
 			 *	specified by the RFC, but think about it..
 			 */
-			if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error)
+			if (inner_type>NR_ICMP_TYPES || icmp_pointers[inner_type].error)
 				return;
 		}
 	}
 
-
 	if (icmp_xmit_lock())
 		return;
 
@@ -625,12 +468,6 @@
 		((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) :
 			iph->tos;
 
-	/* XXX: use a more aggressive expire for routes created by 
-	 * this call (not longer than the rate limit timeout). 
-	 * It could be also worthwhile to not put them into ipv4
-	 * fast routing cache at first. Otherwise an attacker can
-	 * grow the routing table.
-	 */
 	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
 		goto out;
 
@@ -642,13 +479,14 @@
 	 *	Prepare data for ICMP header.
 	 */
 
-	icmp_param.icmph.type=type;
-	icmp_param.icmph.code=code;
-	icmp_param.icmph.un.gateway = info;
-	icmp_param.icmph.checksum=0;
+	icmp_param.data.icmph.type=type;
+	icmp_param.data.icmph.code=code;
+	icmp_param.data.icmph.un.gateway = info;
+	icmp_param.data.icmph.checksum=0;
 	icmp_param.csum=0;
-	icmp_param.data_ptr=iph;
-	icmp_out_count(icmp_param.icmph.type);
+	icmp_param.skb=skb_in;
+	icmp_param.offset=skb_in->nh.raw - skb_in->data;
+	icmp_out_count(icmp_param.data.icmph.type);
 	icmp_socket->sk->protinfo.af_inet.tos = tos;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
@@ -669,10 +507,11 @@
 	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
 	room -= sizeof(struct icmphdr);
 
-	icmp_param.data_len=(skb_in->tail-(u8*)iph);
+	icmp_param.data_len=skb_in->len-icmp_param.offset;
 	if (icmp_param.data_len > room)
 		icmp_param.data_len = room;
-	
+	icmp_param.head_len = sizeof(struct icmphdr);
+
 	ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param, 
 		icmp_param.data_len+sizeof(struct icmphdr),
 		&ipc, rt, MSG_DONTWAIT);
@@ -688,28 +527,35 @@
  *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. 
  */
 
-static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_unreach(struct sk_buff *skb)
 {
 	struct iphdr *iph;
-	int hash;
+	struct icmphdr *icmph;
+	int hash, protocol;
 	struct inet_protocol *ipprot;
-	unsigned char *dp;
 	struct sock *raw_sk;
-	
+	u32 info = 0;
+
 	/*
 	 *	Incomplete header ?
 	 * 	Only checks for the IP header, there should be an
 	 *	additional check for longer headers in upper levels.
 	 */
 
-	if(len<sizeof(struct iphdr)) {
+	if (!pskb_may_pull(skb, sizeof(struct iphdr))) {
 		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
-		
-	iph = (struct iphdr *) (icmph + 1);
-	dp = (unsigned char*)iph;
-	
+
+	icmph = skb->h.icmph;
+	iph = (struct iphdr *) skb->data;
+
+	if (iph->ihl<5) {
+		/* Mangled header, drop. */
+		ICMP_INC_STATS_BH(IcmpInErrors);
+		return;
+	}
+
 	if(icmph->type==ICMP_DEST_UNREACH) {
 		switch(icmph->code & 15) {
 			case ICMP_NET_UNREACH:
@@ -726,11 +572,9 @@
 						printk(KERN_INFO "ICMP: %u.%u.%u.%u: fragmentation needed and DF set.\n",
 						       NIPQUAD(iph->daddr));
 				} else {
-					unsigned short new_mtu;
-					new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
-					if (!new_mtu) 
-						return;
-					icmph->un.frag.mtu = htons(new_mtu);
+					info = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
+					if (!info) 
+						goto out;
 				}
 				break;
 			case ICMP_SR_FAILED:
@@ -740,10 +584,12 @@
 			default:
 				break;
 		}
-		if (icmph->code>NR_ICMP_UNREACH) 
-			return;
+		if (icmph->code>NR_ICMP_UNREACH)
+			goto out;
+	} else if (icmph->type == ICMP_PARAMETERPROB) {
+		info = ntohl(icmph->un.gateway)>>24;
 	}
-	
+
 	/*
 	 *	Throw it at our lower layers
 	 *
@@ -751,7 +597,7 @@
 	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.
 	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.
 	 */
-	 
+
 	/*
 	 *	Check the other end isnt violating RFC 1122. Some routers send
 	 *	bogus responses to broadcast frames. If you see this message
@@ -767,23 +613,33 @@
 			if (net_ratelimit())
 				printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP error to a broadcast.\n",
 			       	NIPQUAD(skb->nh.iph->saddr));
-			return; 
+			goto out;
 		}
 	}
 
+	/* Checkin full IP header plus 8 bytes of protocol to
+	 * avoid additional coding at protocol handlers.
+	 */
+	if (!pskb_may_pull(skb, iph->ihl*4+8))
+		goto out;
+
+	iph = (struct iphdr *) skb->data;
+	protocol = iph->protocol;
+
 	/*
 	 *	Deliver ICMP message to raw sockets. Pretty useless feature?
 	 */
 
 	/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
-	hash = iph->protocol & (MAX_INET_PROTOS - 1);
+	hash = protocol & (MAX_INET_PROTOS - 1);
 	read_lock(&raw_v4_lock);
 	if ((raw_sk = raw_v4_htable[hash]) != NULL) 
 	{
-		while ((raw_sk = __raw_v4_lookup(raw_sk, iph->protocol, iph->saddr,
+		while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->saddr,
 						 iph->daddr, skb->dev->ifindex)) != NULL) {
-			raw_err(raw_sk, skb);
+			raw_err(raw_sk, skb, info);
 			raw_sk = raw_sk->next;
+			iph = (struct iphdr *)skb->data;
 		}
 	}
 	read_unlock(&raw_v4_lock);
@@ -807,11 +663,12 @@
 		/* RFC1122: OK. Passes appropriate ICMP errors to the */
 		/* appropriate protocol layer (MUST), as per 3.2.2. */
 
-		if (iph->protocol == ipprot->protocol && ipprot->err_handler)
- 			ipprot->err_handler(skb, dp, len);
+		if (protocol == ipprot->protocol && ipprot->err_handler)
+ 			ipprot->err_handler(skb, info);
 
 		ipprot = nextip;
   	}
+out:;
 }
 
 
@@ -819,24 +676,26 @@
  *	Handle ICMP_REDIRECT. 
  */
 
-static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_redirect(struct sk_buff *skb)
 {
 	struct iphdr *iph;
 	unsigned long ip;
 
-	if (len < sizeof(struct iphdr)) {
+	if (skb->len < sizeof(struct iphdr)) {
 		ICMP_INC_STATS_BH(IcmpInErrors);
 		return; 
 	}
-		
+
 	/*
 	 *	Get the copied header of the packet that caused the redirect
 	 */
-	 
-	iph = (struct iphdr *) (icmph + 1);
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		return;
+
+	iph = (struct iphdr *) skb->data;
 	ip = iph->daddr;
 
-	switch(icmph->code & 7) {
+	switch(skb->h.icmph->code & 7) {
 		case ICMP_REDIR_NET:
 		case ICMP_REDIR_NETTOS:
 			/*
@@ -846,7 +705,7 @@
 			 
 		case ICMP_REDIR_HOST:
 		case ICMP_REDIR_HOSTTOS:
-			ip_rt_redirect(skb->nh.iph->saddr, ip, icmph->un.gateway, iph->saddr, iph->tos, skb->dev);
+			ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway, iph->saddr, iph->tos, skb->dev);
 			break;
 		default:
 			break;
@@ -862,15 +721,17 @@
  *	See also WRT handling of options once they are done and working.
  */
 
-static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_echo(struct sk_buff *skb)
 {
 	if (!sysctl_icmp_echo_ignore_all) {
 		struct icmp_bxm icmp_param;
 
-		icmp_param.icmph=*icmph;
-		icmp_param.icmph.type=ICMP_ECHOREPLY;
-		icmp_param.data_ptr=(icmph+1);
-		icmp_param.data_len=len;
+		icmp_param.data.icmph=*skb->h.icmph;
+		icmp_param.data.icmph.type=ICMP_ECHOREPLY;
+		icmp_param.skb=skb;
+		icmp_param.offset=0;
+		icmp_param.data_len=skb->len;
+		icmp_param.head_len=sizeof(struct icmphdr);
 		icmp_reply(&icmp_param, skb);
 	}
 }
@@ -883,34 +744,35 @@
  *		  MUST be updated at least at 15Hz.
  */
  
-static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_timestamp(struct sk_buff *skb)
 {
 	struct timeval tv;
-	__u32 times[3];		/* So the new timestamp works on ALPHA's.. */
 	struct icmp_bxm icmp_param;
 	
 	/*
 	 *	Too short.
 	 */
 	 
-	if(len<12) {
+	if(skb->len<4) {
 		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
-	
+
 	/*
 	 *	Fill in the current time as ms since midnight UT: 
 	 */
-	 
 	do_gettimeofday(&tv);
-	times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
-	times[2] = times[1];
-	memcpy((void *)&times[0], icmph+1, 4);		/* Incoming stamp */
-	icmp_param.icmph=*icmph;
-	icmp_param.icmph.type=ICMP_TIMESTAMPREPLY;
-	icmp_param.icmph.code=0;
-	icmp_param.data_ptr=&times;
-	icmp_param.data_len=12;
+	icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+	icmp_param.data.times[2] = icmp_param.data.times[1];
+	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
+		BUG();
+	icmp_param.data.icmph=*skb->h.icmph;
+	icmp_param.data.icmph.type=ICMP_TIMESTAMPREPLY;
+	icmp_param.data.icmph.code=0;
+	icmp_param.skb=skb;
+	icmp_param.offset=0;
+	icmp_param.data_len=0;
+	icmp_param.head_len=sizeof(struct icmphdr)+12;
 	icmp_reply(&icmp_param, skb);
 }
 
@@ -948,7 +810,7 @@
  * anyway...
  */
 
-static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_address(struct sk_buff *skb)
 {
 #if 0
 	if (net_ratelimit())
@@ -961,7 +823,7 @@
  *			loudly if an inconsistency is found.
  */
 
-static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_address_reply(struct sk_buff *skb)
 {
 	struct rtable *rt = (struct rtable*)skb->dst;
 	struct net_device *dev = skb->dev;
@@ -969,7 +831,7 @@
 	struct in_ifaddr *ifa;
 	u32 mask;
 
-	if (len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
+	if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
 		return;
 
 	in_dev = in_dev_get(dev);
@@ -979,8 +841,8 @@
 	if (in_dev->ifa_list &&
 	    IN_DEV_LOG_MARTIANS(in_dev) &&
 	    IN_DEV_FORWARD(in_dev)) {
-
-		mask = *(u32*)&icmph[1];
+		if (skb_copy_bits(skb, 0, &mask, 4))
+			BUG();
 		for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
 			if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
 				break;
@@ -994,7 +856,7 @@
 	in_dev_put(in_dev);
 }
 
-static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len)
+static void icmp_discard(struct sk_buff *skb)
 {
 }
 
@@ -1002,23 +864,36 @@
  *	Deal with incoming ICMP packets.
  */
  
-int icmp_rcv(struct sk_buff *skb, unsigned short len)
+int icmp_rcv(struct sk_buff *skb)
 {
 	struct icmphdr *icmph = skb->h.icmph;
 	struct rtable *rt = (struct rtable*)skb->dst;
 
 	ICMP_INC_STATS_BH(IcmpInMsgs);
 
+	switch (skb->ip_summed) {
+	case CHECKSUM_HW:
+		if ((u16)csum_fold(skb->csum) == 0)
+			break;
+		NETDEBUG(printk(KERN_DEBUG "icmp v4 hw csum failure\n"));
+	case CHECKSUM_NONE:
+		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))
+			goto error;
+	default:;
+	}
+
+	if (!pskb_pull(skb, sizeof(struct icmphdr)))
+		goto error;
+
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
 	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently discarded.
 	 */
-	if(len < sizeof(struct icmphdr) ||
-	   ip_compute_csum((unsigned char *) icmph, len) ||
-	   icmph->type > NR_ICMP_TYPES)
+	if (icmph->type > NR_ICMP_TYPES)
 		goto error;
-	 
+
+
 	/*
 	 *	Parse the ICMP message 
 	 */
@@ -1042,9 +917,8 @@
   		}
 	}
 
-	len -= sizeof(struct icmphdr);
 	icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++;
-	(icmp_pointers[icmph->type].handler)(icmph, skb, len);
+	(icmp_pointers[icmph->type].handler)(skb);
 
 drop:
 	kfree_skb(skb);
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.4.3/linux/net/ipv4/igmp.c	Tue Jan  9 10:54:57 2001
+++ linux/net/ipv4/igmp.c	Thu Apr 12 12:11:39 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.41 2000/08/31 23:39:12 davem Exp $
+ *	Version: $Id: igmp.c,v 1.45 2001/02/23 06:32:11 davem Exp $
  *
  *	Authors:
  *		Alan Cox <Alan.Cox@linux.org>
@@ -235,7 +235,7 @@
 	iph->saddr    = rt->rt_src;
 	iph->protocol = IPPROTO_IGMP;
 	iph->tot_len  = htons(IGMP_SIZE);
-	ip_select_ident(iph, &rt->u.dst);
+	ip_select_ident(iph, &rt->u.dst, NULL);
 	((u8*)&iph[1])[0] = IPOPT_RA;
 	((u8*)&iph[1])[1] = 4;
 	((u8*)&iph[1])[2] = 0;
@@ -341,23 +341,32 @@
 	read_unlock(&in_dev->lock);
 }
 
-int igmp_rcv(struct sk_buff *skb, unsigned short len)
+int igmp_rcv(struct sk_buff *skb)
 {
 	/* This basically follows the spec line by line -- see RFC1112 */
 	struct igmphdr *ih = skb->h.igmph;
 	struct in_device *in_dev = in_dev_get(skb->dev);
+	int len = skb->len;
 
 	if (in_dev==NULL) {
 		kfree_skb(skb);
 		return 0;
 	}
 
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+			kfree_skb(skb);
+			return -ENOMEM;
+		}
+		ih = skb->h.igmph;
+	}
+
 	if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) {
 		in_dev_put(in_dev);
 		kfree_skb(skb);
 		return 0;
 	}
-	
+
 	switch (ih->type) {
 	case IGMP_HOST_MEMBERSHIP_QUERY:
 		igmp_heard_query(in_dev, ih->code, ih->group);
@@ -372,7 +381,7 @@
 	case IGMP_PIM:
 #ifdef CONFIG_IP_PIMSM_V1
 		in_dev_put(in_dev);
-		return pim_rcv_v1(skb, len);
+		return pim_rcv_v1(skb);
 #endif
 	case IGMP_DVMRP:
 	case IGMP_TRACE:
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.4.3/linux/net/ipv4/ip_forward.c	Fri Oct 27 11:03:14 2000
+++ linux/net/ipv4/ip_forward.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		The IP forwarding functionality.
  *		
- * Version:	$Id: ip_forward.c,v 1.47 2000/10/24 22:54:26 davem Exp $
+ * Version:	$Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $
  *
  * Authors:	see ip.c
  *
@@ -83,6 +83,8 @@
 
 	if (skb->pkt_type != PACKET_HOST)
 		goto drop;
+
+	skb->ip_summed = CHECKSUM_NONE;
 	
 	/*
 	 *	According to the RFC, we must first decrease the TTL field. If
@@ -116,10 +118,9 @@
 		ip_rt_send_redirect(skb);
 
 	/* We are about to mangle packet. Copy it! */
-	if ((skb = skb_cow(skb, dev2->hard_header_len)) == NULL)
-		return NET_RX_DROP;
+	if (skb_cow(skb, dev2->hard_header_len))
+		goto drop;
 	iph = skb->nh.iph;
-	opt = &(IPCB(skb)->opt);
 
 	/* Decrease ttl after skb cow done */
 	ip_decrease_ttl(iph);
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.4.3/linux/net/ipv4/ip_fragment.c	Sun Mar 25 18:14:25 2001
+++ linux/net/ipv4/ip_fragment.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.53 2000/12/08 17:15:53 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.57 2001/03/07 22:00:57 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -83,7 +83,8 @@
 	atomic_t	refcnt;
 	struct timer_list timer;	/* when will this queue expire?		*/
 	struct ipq	**pprev;
-	int		iif;		/* Device index - for icmp replies	*/
+	int		iif;
+	struct timeval	stamp;
 };
 
 /* Hash table. */
@@ -255,7 +256,6 @@
 
 	if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
 		struct sk_buff *head = qp->fragments;
-
 		/* Send an ICMP "Fragment Reassembly Timeout" message. */
 		if ((head->dev = dev_get_by_index(qp->iif)) != NULL) {
 			icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
@@ -370,7 +370,6 @@
 /* Add new segment to existing queue. */
 static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
 	struct sk_buff *prev, *next;
 	int flags, offset;
 	int ihl, end;
@@ -378,14 +377,14 @@
 	if (qp->last_in & COMPLETE)
 		goto err;
 
-	offset = ntohs(iph->frag_off);
+ 	offset = ntohs(skb->nh.iph->frag_off);
 	flags = offset & ~IP_OFFSET;
 	offset &= IP_OFFSET;
 	offset <<= 3;		/* offset is in 8-byte chunks */
-	ihl = iph->ihl * 4;
+ 	ihl = skb->nh.iph->ihl * 4;
 
 	/* Determine the position of this fragment. */
-	end = offset + (ntohs(iph->tot_len) - ihl);
+ 	end = offset + skb->len - ihl;
 
 	/* Is this the final fragment? */
 	if ((flags & IP_MF) == 0) {
@@ -413,9 +412,10 @@
 	if (end == offset)
 		goto err;
 
-	/* Point into the IP datagram 'data' part. */
-	skb_pull(skb, (skb->nh.raw+ihl) - skb->data);
-	skb_trim(skb, end - offset);
+	if (pskb_pull(skb, ihl) == NULL)
+		goto err;
+	if (pskb_trim(skb, end-offset))
+		goto err;
 
 	/* Find out which fragments are in front and at the back of us
 	 * in the chain of fragments so far.  We must know where to put
@@ -439,7 +439,8 @@
 			offset += i;
 			if (end <= offset)
 				goto err;
-			skb_pull(skb, i);
+			if (!pskb_pull(skb, i))
+				goto err;
 			if (skb->ip_summed != CHECKSUM_UNNECESSARY)
 				skb->ip_summed = CHECKSUM_NONE;
 		}
@@ -452,8 +453,9 @@
 			/* Eat head of the next overlapped fragment
 			 * and leave the loop. The next ones cannot overlap.
 			 */
+			if (!pskb_pull(next, i))
+				goto err;
 			FRAG_CB(next)->offset += i;
-			skb_pull(next, i);
 			qp->meat -= i;
 			if (next->ip_summed != CHECKSUM_UNNECESSARY)
 				next->ip_summed = CHECKSUM_NONE;
@@ -485,9 +487,10 @@
 	else
 		qp->fragments = skb;
 
-	if (skb->dev)
-		qp->iif = skb->dev->ifindex;
+ 	if (skb->dev)
+ 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
+	qp->stamp = skb->stamp;
 	qp->meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
@@ -500,15 +503,10 @@
 }
 
 
-/* Build a new IP datagram from all its fragments.
- *
- * FIXME: We copy here because we lack an effective way of handling lists
- * of bits on input. Until the new skb data handling is in I'm not going
- * to touch this with a bargepole. 
- */
+/* Build a new IP datagram from all its fragments. */
+
 static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 {
-	struct sk_buff *skb;
 	struct iphdr *iph;
 	struct sk_buff *fp, *head = qp->fragments;
 	int len;
@@ -526,61 +524,58 @@
 	if(len > 65535)
 		goto out_oversize;
 
-	skb = dev_alloc_skb(len);
-	if (!skb)
+	/* Head of list must not be cloned. */
+	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
 		goto out_nomem;
 
-	/* Fill in the basic details. */
-	skb->mac.raw = skb->data;
-	skb->nh.raw = skb->data;
-	FRAG_CB(skb)->h = FRAG_CB(head)->h;
-	skb->ip_summed = head->ip_summed;
-	skb->csum = 0;
-
-	/* Copy the original IP headers into the new buffer. */
-	memcpy(skb_put(skb, ihlen), head->nh.iph, ihlen);
-
-	/* Copy the data portions of all fragments into the new buffer. */
-	for (fp=head; fp; fp = fp->next) {
-		memcpy(skb_put(skb, fp->len), fp->data, fp->len);
-
-		if (skb->ip_summed != fp->ip_summed)
-			skb->ip_summed = CHECKSUM_NONE;
-		else if (skb->ip_summed == CHECKSUM_HW)
-			skb->csum = csum_add(skb->csum, fp->csum);
-	}
-
-	skb->dst = dst_clone(head->dst);
-	skb->pkt_type = head->pkt_type;
-	skb->protocol = head->protocol;
-	skb->dev = dev;
-
-	/*
-	*  Clearly bogus, because security markings of the individual
-	*  fragments should have been checked for consistency before
-	*  gluing, and intermediate coalescing of fragments may have
-	*  taken place in ip_defrag() before ip_glue() ever got called.
-	*  If we're not going to do the consistency checking, we might
-	*  as well take the value associated with the first fragment.
-	*	--rct
-	*/
-	skb->security = head->security;
-
-#ifdef CONFIG_NETFILTER
-	/* Connection association is same as fragment (if any). */
-	skb->nfct = head->nfct;
-	nf_conntrack_get(skb->nfct);
-#ifdef CONFIG_NETFILTER_DEBUG
-	skb->nf_debug = head->nf_debug;
-#endif
-#endif
+	/* If the first fragment is fragmented itself, we split
+	 * it to two chunks: the first with data and paged part
+	 * and the second, holding only fragments. */
+	if (skb_shinfo(head)->frag_list) {
+		struct sk_buff *clone;
+		int i, plen = 0;
+
+		if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
+			goto out_nomem;
+		clone->next = head->next;
+		head->next = clone;
+		skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+		skb_shinfo(head)->frag_list = NULL;
+		for (i=0; i<skb_shinfo(head)->nr_frags; i++)
+			plen += skb_shinfo(head)->frags[i].size;
+		clone->len = clone->data_len = head->data_len - plen;
+		head->data_len -= clone->len;
+		head->len -= clone->len;
+		clone->csum = 0;
+		clone->ip_summed = head->ip_summed;
+		atomic_add(clone->truesize, &ip_frag_mem);
+	}
 
-	/* Done with all fragments. Fixup the new IP header. */
-	iph = skb->nh.iph;
+	skb_shinfo(head)->frag_list = head->next;
+	skb_push(head, head->data - head->nh.raw);
+	atomic_sub(head->truesize, &ip_frag_mem);
+
+	for (fp=head->next; fp; fp = fp->next) {
+		head->data_len += fp->len;
+		head->len += fp->len;
+		if (head->ip_summed != fp->ip_summed)
+			head->ip_summed = CHECKSUM_NONE;
+		else if (head->ip_summed == CHECKSUM_HW)
+			head->csum = csum_add(head->csum, fp->csum);
+		head->truesize += fp->truesize;
+		atomic_sub(fp->truesize, &ip_frag_mem);
+	}
+
+	head->next = NULL;
+	head->dev = dev;
+	head->stamp = qp->stamp;
+
+	iph = head->nh.iph;
 	iph->frag_off = 0;
 	iph->tot_len = htons(len);
 	IP_INC_STATS_BH(IpReasmOKs);
-	return skb;
+	qp->fragments = NULL;
+	return head;
 
 out_nomem:
  	NETDEBUG(printk(KERN_ERR 
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c
--- v2.4.3/linux/net/ipv4/ip_gre.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv4/ip_gre.c	Wed Apr 18 14:40:07 2001
@@ -313,7 +313,7 @@
 }
 
 
-void ipgre_err(struct sk_buff *skb, unsigned char *dp, int len)
+void ipgre_err(struct sk_buff *skb, u32 info)
 {
 #ifndef I_WISH_WORLD_WERE_PERFECT
 
@@ -330,8 +330,8 @@
    by themself???
  */
 
-	struct iphdr *iph = (struct iphdr*)dp;
-	u16	     *p = (u16*)(dp+(iph->ihl<<2));
+	struct iphdr *iph = (struct iphdr*)skb->data;
+	u16	     *p = (u16*)(skb->data+(iph->ihl<<2));
 	int grehlen = (iph->ihl<<2) + 4;
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
@@ -350,7 +350,7 @@
 	}
 
 	/* If only 8 bytes returned, keyed message will be dropped here */
-	if (len < grehlen)
+	if (skb_headlen(skb) < grehlen)
 		return;
 
 	switch (type) {
@@ -559,17 +559,24 @@
 #endif
 }
 
-int ipgre_rcv(struct sk_buff *skb, unsigned short len)
+int ipgre_rcv(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
-	u8     *h = skb->h.raw;
-	u16    flags = *(u16*)h;
+	struct iphdr *iph;
+	u8     *h;
+	u16    flags;
 	u16    csum = 0;
 	u32    key = 0;
 	u32    seqno = 0;
 	struct ip_tunnel *tunnel;
 	int    offset = 4;
 
+	if (!pskb_may_pull(skb, 16))
+		goto drop_nolock;
+
+	iph = skb->nh.iph;
+	h = skb->data;
+	flags = *(u16*)h;
+
 	if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
 		/* - Version must be 0.
 		   - We do not support routing headers.
@@ -578,7 +585,16 @@
 			goto drop_nolock;
 
 		if (flags&GRE_CSUM) {
-			csum = ip_compute_csum(h, len);
+			if (skb->ip_summed == CHECKSUM_HW) {
+				csum = (u16)csum_fold(skb->csum);
+				if (csum)
+					skb->ip_summed = CHECKSUM_NONE;
+			}
+			if (skb->ip_summed == CHECKSUM_NONE) {
+				skb->csum = skb_checksum(skb, 0, skb->len, 0);
+				skb->ip_summed = CHECKSUM_HW;
+				csum = (u16)csum_fold(skb->csum);
+			}
 			offset += 4;
 		}
 		if (flags&GRE_KEY) {
@@ -594,9 +610,11 @@
 	read_lock(&ipgre_lock);
 	if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) {
 		skb->mac.raw = skb->nh.raw;
-		skb->nh.raw = skb_pull(skb, h + offset - skb->data);
+		skb->nh.raw = __pskb_pull(skb, offset);
 		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-		skb->ip_summed = 0;
+		if (skb->ip_summed == CHECKSUM_HW)
+			skb->csum = csum_sub(skb->csum,
+					     csum_partial(skb->mac.raw, skb->nh.raw-skb->mac.raw, 0));
 		skb->protocol = *(u16*)(h + 2);
 		skb->pkt_type = PACKET_HOST;
 #ifdef CONFIG_NET_IPGRE_BROADCAST
@@ -1129,8 +1147,6 @@
 	dev->do_ioctl		= ipgre_tunnel_ioctl;
 	dev->change_mtu		= ipgre_tunnel_change_mtu;
 
-	dev_init_buffers(dev);
-
 	dev->type		= ARPHRD_IPGRE;
 	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr) + 4;
 	dev->mtu		= 1500 - sizeof(struct iphdr) - 4;
@@ -1263,14 +1279,7 @@
 	printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
 
 	ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel;
-#ifdef MODULE
 	register_netdev(&ipgre_fb_tunnel_dev);
-#else
-	rtnl_lock();
-	register_netdevice(&ipgre_fb_tunnel_dev);
-	rtnl_unlock();
-#endif
-
 	inet_add_protocol(&ipgre_protocol);
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.4.3/linux/net/ipv4/ip_input.c	Mon Dec 11 12:37:04 2000
+++ linux/net/ipv4/ip_input.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.51 2000/12/08 17:15:53 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.53 2000/12/18 19:01:50 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -207,8 +207,7 @@
 				skb2 = skb_clone(skb, GFP_ATOMIC);
 			if(skb2 != NULL) {
 				ret = 1;
-				ipprot->handler(skb2,
-						ntohs(iph->tot_len) - (iph->ihl * 4));
+				ipprot->handler(skb2);
 			}
 		}
 		ipprot = (struct inet_protocol *) ipprot->next;
@@ -219,18 +218,31 @@
 
 static inline int ip_local_deliver_finish(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
+	int ihl = skb->nh.iph->ihl*4;
 
 #ifdef CONFIG_NETFILTER_DEBUG
 	nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
+	/* Pull out additionl 8 bytes to save some space in protocols. */
+	if (!pskb_may_pull(skb, ihl+8))
+		goto out;
+	__skb_pull(skb, ihl);
+
+#ifdef CONFIG_NETFILTER
+	/* Free reference early: we don't need it any more, and it may
+           hold ip_conntrack module loaded indefinitely. */
+	nf_conntrack_put(skb->nfct);
+	skb->nfct = NULL;
+#endif /*CONFIG_NETFILTER*/
+
         /* Point into the IP datagram, just past the header. */
-        skb->h.raw = skb->nh.raw + iph->ihl*4;
+        skb->h.raw = skb->data;
 
 	{
 		/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
-		int hash = iph->protocol & (MAX_INET_PROTOS - 1);
+		int protocol = skb->nh.iph->protocol;
+		int hash = protocol & (MAX_INET_PROTOS - 1);
 		struct sock *raw_sk = raw_v4_htable[hash];
 		struct inet_protocol *ipprot;
 		int flag;
@@ -239,23 +251,22 @@
 		 * don't care less
 		 */
 		if(raw_sk != NULL)
-			raw_sk = raw_v4_input(skb, iph, hash);
+			raw_sk = raw_v4_input(skb, skb->nh.iph, hash);
 
 		ipprot = (struct inet_protocol *) inet_protos[hash];
 		flag = 0;
 		if(ipprot != NULL) {
 			if(raw_sk == NULL &&
 			   ipprot->next == NULL &&
-			   ipprot->protocol == iph->protocol) {
+			   ipprot->protocol == protocol) {
 				int ret;
-				
+
 				/* Fast path... */
-				ret = ipprot->handler(skb, (ntohs(iph->tot_len) -
-							    (iph->ihl * 4)));
+				ret = ipprot->handler(skb);
 
 				return ret;
 			} else {
-				flag = ip_run_ipprot(skb, iph, ipprot, (raw_sk != NULL));
+				flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL));
 			}
 		}
 
@@ -269,6 +280,7 @@
 			sock_put(raw_sk);
 		} else if (!flag) {		/* Free and report errors */
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	
+out:
 			kfree_skb(skb);
 		}
 	}
@@ -281,13 +293,11 @@
  */ 
 int ip_local_deliver(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
-
 	/*
 	 *	Reassemble IP fragments.
 	 */
 
-	if (iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+	if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
 		skb = ip_defrag(skb);
 		if (!skb)
 			return 0;
@@ -333,9 +343,8 @@
 		                                      --ANK (980813)
 		*/
 
-		skb = skb_cow(skb, skb_headroom(skb));
-		if (skb == NULL)
-			return NET_RX_DROP;
+		if (skb_cow(skb, skb_headroom(skb)))
+			goto drop;
 		iph = skb->nh.iph;
 
 		skb->ip_summed = 0;
@@ -387,6 +396,11 @@
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		goto out;
 
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto inhdr_error;
+
+	iph = skb->nh.iph;
+
 	/*
 	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
 	 *
@@ -398,9 +412,13 @@
 	 *	4.	Doesn't have a bogus length
 	 */
 
-	if (skb->len < sizeof(struct iphdr) || skb->len < (iph->ihl<<2))
+	if (iph->ihl < 5 || iph->version != 4)
 		goto inhdr_error; 
-	if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+
+	if (!pskb_may_pull(skb, iph->ihl*4))
+		goto inhdr_error;
+
+	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
 		goto inhdr_error; 
 
 	{
@@ -412,7 +430,11 @@
 		 * is IP we can trim to the true length of the frame.
 		 * Note this now means skb->len holds ntohs(iph->tot_len).
 		 */
-		__skb_trim(skb, len);
+		if (skb->len > len) {
+			__pskb_trim(skb, len);
+			if (skb->ip_summed == CHECKSUM_HW)
+				skb->ip_summed = CHECKSUM_NONE;
+		}
 	}
 
 	return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c
--- v2.4.3/linux/net/ipv4/ip_nat_dumb.c	Fri Oct 27 11:03:14 2000
+++ linux/net/ipv4/ip_nat_dumb.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		Dumb Network Address Translation.
  *
- * Version:	$Id: ip_nat_dumb.c,v 1.10 2000/10/24 22:54:26 davem Exp $
+ * Version:	$Id: ip_nat_dumb.c,v 1.11 2000/12/13 18:31:48 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -70,8 +70,14 @@
 			cksum  = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
 			if ((u8*)(cksum+1) > skb->tail)
 				goto truncated;
-			check  = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum));
-			*cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
+			check = *cksum;
+			if (skb->ip_summed != CHECKSUM_HW)
+				check = ~check;
+			check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check);
+			check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
+			if (skb->ip_summed == CHECKSUM_HW)
+				check = ~check;
+			*cksum = check;
 			break;
 		case IPPROTO_UDP:
 			cksum  = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.4.3/linux/net/ipv4/ip_output.c	Fri Oct 27 11:03:14 2000
+++ linux/net/ipv4/ip_output.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.87 2000/10/25 20:07:22 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.91 2001/03/29 06:25:55 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -95,7 +95,7 @@
 static int ip_dev_loopback_xmit(struct sk_buff *newskb)
 {
 	newskb->mac.raw = newskb->data;
-	skb_pull(newskb, newskb->nh.raw - newskb->data);
+	__skb_pull(newskb, newskb->nh.raw - newskb->data);
 	newskb->pkt_type = PACKET_LOOPBACK;
 	newskb->ip_summed = CHECKSUM_UNNECESSARY;
 	BUG_TRAP(newskb->dst);
@@ -141,7 +141,7 @@
 	iph->saddr    = rt->rt_src;
 	iph->protocol = sk->protocol;
 	iph->tot_len  = htons(skb->len);
-	ip_select_ident(iph, &rt->u.dst);
+	ip_select_ident(iph, &rt->u.dst, sk);
 	skb->nh.iph   = iph;
 
 	if (opt && opt->optlen) {
@@ -307,7 +307,7 @@
 	if (ip_dont_fragment(sk, &rt->u.dst))
 		iph->frag_off |= __constant_htons(IP_DF);
 
-	ip_select_ident(iph, &rt->u.dst);
+	ip_select_ident(iph, &rt->u.dst, sk);
 
 	/* Add an IP checksum. */
 	ip_send_check(iph);
@@ -328,7 +328,10 @@
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
-	ip_select_ident(iph, &rt->u.dst);
+	ip_select_ident(iph, &rt->u.dst, sk);
+	if (skb->ip_summed == CHECKSUM_HW &&
+	    (skb = skb_checksum_help(skb)) == NULL)
+		return -ENOMEM;
 	return ip_fragment(skb, skb->dst->output);
 }
 
@@ -358,6 +361,7 @@
 				    sk->bound_dev_if))
 			goto no_route;
 		__sk_dst_set(sk, &rt->u.dst);
+		sk->route_caps = rt->u.dst.dev->features;
 	}
 	skb->dst = dst_clone(&rt->u.dst);
 
@@ -425,7 +429,7 @@
 	int err;
 	int offset, mf;
 	int mtu;
-	u16 id = 0;
+	u16 id;
 
 	int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
 	int nfrags=0;
@@ -495,6 +499,8 @@
 	 *	Begin outputting the bytes.
 	 */
 
+	id = (sk ? sk->protinfo.af_inet.id++ : 0);
+
 	do {
 		char *data;
 		struct sk_buff * skb;
@@ -503,7 +509,7 @@
 		 *	Get the memory we require with some space left for alignment.
 		 */
 
-		skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, 0, flags&MSG_DONTWAIT, &err);
+		skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, flags&MSG_DONTWAIT, &err);
 		if (skb == NULL)
 			goto error;
 
@@ -659,7 +665,7 @@
 	int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
 
 	skb = sock_alloc_send_skb(sk, length+hh_len+15,
-				  0, flags&MSG_DONTWAIT, &err);
+				  flags&MSG_DONTWAIT, &err);
 	if(skb==NULL)
 		goto error; 
 	skb_reserve(skb, hh_len);
@@ -677,7 +683,7 @@
 		iph->tot_len = htons(length);
 		iph->frag_off = df;
 		iph->ttl=sk->protinfo.af_inet.mc_ttl;
-		ip_select_ident(iph, &rt->u.dst);
+		ip_select_ident(iph, &rt->u.dst, sk);
 		if (rt->rt_type != RTN_MULTICAST)
 			iph->ttl=sk->protinfo.af_inet.ttl;
 		iph->protocol=sk->protocol;
@@ -722,8 +728,8 @@
 int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 {
 	struct iphdr *iph;
-	unsigned char *raw;
-	unsigned char *ptr;
+	int raw = 0;
+	int ptr;
 	struct net_device *dev;
 	struct sk_buff *skb2;
 	unsigned int mtu, hlen, left, len; 
@@ -738,17 +744,16 @@
 	 *	Point into the IP datagram header.
 	 */
 
-	raw = skb->nh.raw;
-	iph = (struct iphdr*)raw;
+	iph = skb->nh.iph;
 
 	/*
 	 *	Setup starting values.
 	 */
 
 	hlen = iph->ihl * 4;
-	left = ntohs(iph->tot_len) - hlen;	/* Space per frame */
+	left = skb->len - hlen;		/* Space per frame */
 	mtu = rt->u.dst.pmtu - hlen;	/* Size of data space */
-	ptr = raw + hlen;			/* Where to start from */
+	ptr = raw + hlen;		/* Where to start from */
 
 	/*
 	 *	Fragment the datagram.
@@ -806,12 +811,13 @@
 		 *	Copy the packet header into the new buffer.
 		 */
 
-		memcpy(skb2->nh.raw, raw, hlen);
+		memcpy(skb2->nh.raw, skb->data, hlen);
 
 		/*
 		 *	Copy a block of the IP datagram.
 		 */
-		memcpy(skb2->h.raw, ptr, len);
+		if (skb_copy_bits(skb, ptr, skb2->h.raw, len))
+			BUG();
 		left -= len;
 
 		/*
@@ -828,6 +834,9 @@
 		 */
 		if (offset == 0)
 			ip_options_fragment(skb);
+
+		/* Copy the flags to each fragment. */
+		IPCB(skb2)->flags = IPCB(skb)->flags;
 
 		/*
 		 *	Added AC : If we are fragmenting a fragment that's not the
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.4.3/linux/net/ipv4/ip_sockglue.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv4/ip_sockglue.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		The IP to API glue.
  *		
- * Version:	$Id: ip_sockglue.c,v 1.54 2000/11/28 13:34:56 davem Exp $
+ * Version:	$Id: ip_sockglue.c,v 1.56 2001/02/18 09:07:58 davem Exp $
  *
  * Authors:	see ip.c
  *
@@ -257,9 +257,8 @@
 	serr->port = port;
 
 	skb->h.raw = payload;
-	skb_pull(skb, payload - skb->data);
-
-	if (sock_queue_err_skb(sk, skb))
+	if (!skb_pull(skb, payload - skb->data) ||
+	    sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
 }
 
@@ -292,7 +291,7 @@
 	serr->port = port;
 
 	skb->h.raw = skb->tail;
-	skb_pull(skb, skb->tail - skb->data);
+	__skb_pull(skb, skb->tail - skb->data);
 
 	if (sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
@@ -323,7 +322,7 @@
 		msg->msg_flags |= MSG_TRUNC;
 		copied = len;
 	}
-	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	if (err)
 		goto out_free_skb;
 
@@ -333,9 +332,10 @@
 
 	sin = (struct sockaddr_in *)msg->msg_name;
 	if (sin) {
-		sin->sin_family = AF_INET; 
+		sin->sin_family = AF_INET;
 		sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
-		sin->sin_port = serr->port; 
+		sin->sin_port = serr->port;
+		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 	}
 
 	memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
@@ -344,6 +344,8 @@
 	if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
 		sin->sin_family = AF_INET;
 		sin->sin_addr.s_addr = skb->nh.iph->saddr;
+		sin->sin_port = 0;
+		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 		if (sk->protinfo.af_inet.cmsg_flags)
 			ip_cmsg_recv(msg, skb);
 	}
@@ -661,7 +663,9 @@
 
 	if(get_user(len,optlen))
 		return -EFAULT;
-
+	if(len < 0)
+		return -EINVAL;
+		
 	lock_sock(sk);
 
 	switch(optname)	{
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v2.4.3/linux/net/ipv4/ipip.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv4/ipip.c	Wed Apr 25 14:57:39 2001
@@ -1,7 +1,7 @@
 /*
  *	Linux NET3:	IP/IP protocol decoder. 
  *
- *	Version: $Id: ipip.c,v 1.41 2000/11/28 13:13:27 davem Exp $
+ *	Version: $Id: ipip.c,v 1.45 2001/04/19 22:32:55 davem Exp $
  *
  *	Authors:
  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
@@ -123,11 +123,13 @@
 static int ipip_tunnel_init(struct net_device *dev);
 
 static struct net_device ipip_fb_tunnel_dev = {
-	"tunl0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip_fb_tunnel_init,
+	name:	"tunl0",
+	init:	ipip_fb_tunnel_init,
 };
 
 static struct ip_tunnel ipip_fb_tunnel = {
-	NULL, &ipip_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"tunl0", }
+	dev:	&ipip_fb_tunnel_dev,
+	parms:	{ name:	"tunl0", }
 };
 
 static struct ip_tunnel *tunnels_r_l[HASH_SIZE];
@@ -281,14 +283,12 @@
 		write_lock_bh(&ipip_lock);
 		tunnels_wc[0] = NULL;
 		write_unlock_bh(&ipip_lock);
-		dev_put(dev);
-	} else {
+	} else
 		ipip_tunnel_unlink((struct ip_tunnel*)dev->priv);
-		dev_put(dev);
-	}
+	dev_put(dev);
 }
 
-void ipip_err(struct sk_buff *skb, unsigned char *dp, int len)
+void ipip_err(struct sk_buff *skb, u32 info)
 {
 #ifndef I_WISH_WORLD_WERE_PERFECT
 
@@ -296,14 +296,11 @@
    8 bytes of packet payload. It means, that precise relaying of
    ICMP in the real Internet is absolutely infeasible.
  */
-	struct iphdr *iph = (struct iphdr*)dp;
+	struct iphdr *iph = (struct iphdr*)skb->data;
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	struct ip_tunnel *t;
 
-	if (len < sizeof(struct iphdr))
-		return;
-
 	switch (type) {
 	default:
 	case ICMP_PARAMETERPROB:
@@ -473,17 +470,19 @@
 		IP_ECN_set_ce(iph);
 }
 
-int ipip_rcv(struct sk_buff *skb, unsigned short len)
+int ipip_rcv(struct sk_buff *skb)
 {
 	struct iphdr *iph;
 	struct ip_tunnel *tunnel;
 
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto out;
+
 	iph = skb->nh.iph;
 	skb->mac.raw = skb->nh.raw;
-	skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data);
+	skb->nh.raw = skb->data;
 	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
 	skb->protocol = __constant_htons(ETH_P_IP);
-	skb->ip_summed = 0;
 	skb->pkt_type = PACKET_HOST;
 
 	read_lock(&ipip_lock);
@@ -508,6 +507,7 @@
 	read_unlock(&ipip_lock);
 
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+out:
 	kfree_skb(skb);
 	return 0;
 }
@@ -794,8 +794,6 @@
 	dev->do_ioctl		= ipip_tunnel_ioctl;
 	dev->change_mtu		= ipip_tunnel_change_mtu;
 
-	dev_init_buffers(dev);
-
 	dev->type		= ARPHRD_TUNNEL;
 	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr);
 	dev->mtu		= 1500 - sizeof(struct iphdr);
@@ -873,44 +871,34 @@
 }
 
 static struct inet_protocol ipip_protocol = {
-  ipip_rcv,             /* IPIP handler          */
-  ipip_err,             /* TUNNEL error control */
-  0,                    /* next                 */
-  IPPROTO_IPIP,         /* protocol ID          */
-  0,                    /* copy                 */
-  NULL,                 /* data                 */
-  "IPIP"                /* name                 */
+	handler:	ipip_rcv,
+	err_handler:	ipip_err,
+	protocol:	IPPROTO_IPIP,
+	name:		"IPIP"
 };
 
-#ifdef MODULE
-int init_module(void) 
-#else
+static const char banner[] __initdata =
+	KERN_INFO "IPv4 over IPv4 tunneling driver\n";
+
 int __init ipip_init(void)
-#endif
 {
-	printk(KERN_INFO "IPv4 over IPv4 tunneling driver\n");
+	printk(banner);
 
 	ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel;
-#ifdef MODULE
 	register_netdev(&ipip_fb_tunnel_dev);
-#else
-	rtnl_lock();
-	register_netdevice(&ipip_fb_tunnel_dev);
-	rtnl_unlock();
-#endif
-
 	inet_add_protocol(&ipip_protocol);
 	return 0;
 }
 
-#ifdef MODULE
-
-void cleanup_module(void)
+static void __exit ipip_fini(void)
 {
 	if ( inet_del_protocol(&ipip_protocol) < 0 )
 		printk(KERN_INFO "ipip close: can't remove protocol\n");
 
-	unregister_netdevice(&ipip_fb_tunnel_dev);
+	unregister_netdev(&ipip_fb_tunnel_dev);
 }
 
+#ifdef MODULE
+module_init(ipip_init);
 #endif
+module_exit(ipip_fini);
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.4.3/linux/net/ipv4/ipmr.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv4/ipmr.c	Thu Apr 12 12:11:39 2001
@@ -9,7 +9,7 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
- *	Version: $Id: ipmr.c,v 1.55 2000/11/28 13:13:27 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.59 2001/02/23 06:32:11 davem Exp $
  *
  *	Fixes:
  *	Michael Chastain	:	Incorrect size of copying.
@@ -980,6 +980,9 @@
 		return -EFAULT;
 
 	olr=min(olr,sizeof(int));
+	if(olr<0)
+		return -EINVAL;
+		
 	if(put_user(olr,optlen))
 		return -EFAULT;
 	if(optname==MRT_VERSION)
@@ -1092,7 +1095,7 @@
 	iph->protocol	=	IPPROTO_IPIP;
 	iph->ihl	=	5;
 	iph->tot_len	=	htons(skb->len);
-	ip_select_ident(iph, skb->dst);
+	ip_select_ident(iph, skb->dst, NULL);
 	ip_send_check(iph);
 
 	skb->h.ipiph = skb->nh.iph;
@@ -1383,14 +1386,22 @@
  * Handle IGMP messages of PIMv1
  */
 
-int pim_rcv_v1(struct sk_buff * skb, unsigned short len)
+int pim_rcv_v1(struct sk_buff * skb)
 {
 	struct igmphdr *pim = (struct igmphdr*)skb->h.raw;
 	struct iphdr   *encap;
 	struct net_device  *reg_dev = NULL;
 
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+			kfree_skb(skb);
+			return -ENOMEM;
+		}
+		pim = (struct igmphdr*)skb->h.raw;
+	}
+
         if (!mroute_do_pim ||
-	    len < sizeof(*pim) + sizeof(*encap) ||
+	    skb->len < sizeof(*pim) + sizeof(*encap) ||
 	    pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) {
 		kfree_skb(skb);
                 return -EINVAL;
@@ -1405,7 +1416,7 @@
 	 */
 	if (!MULTICAST(encap->daddr) ||
 	    ntohs(encap->tot_len) == 0 ||
-	    ntohs(encap->tot_len) + sizeof(*pim) > len) {
+	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len) {
 		kfree_skb(skb);
 		return -EINVAL;
 	}
@@ -1445,17 +1456,25 @@
 #endif
 
 #ifdef CONFIG_IP_PIMSM_V2
-int pim_rcv(struct sk_buff * skb, unsigned short len)
+int pim_rcv(struct sk_buff * skb)
 {
 	struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw;
 	struct iphdr   *encap;
 	struct net_device  *reg_dev = NULL;
 
-        if (len < sizeof(*pim) + sizeof(*encap) ||
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+			kfree_skb(skb);
+			return -ENOMEM;
+		}
+		pim = (struct pimreghdr*)skb->h.raw;
+	}
+
+        if (skb->len < sizeof(*pim) + sizeof(*encap) ||
 	    pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
 	    (pim->flags&PIM_NULL_REGISTER) ||
 	    (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
-	     ip_compute_csum((void *)pim, len))) {
+	     ip_compute_csum((void *)pim, skb->len))) {
 		kfree_skb(skb);
                 return -EINVAL;
         }
@@ -1464,7 +1483,7 @@
 	encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr));
 	if (!MULTICAST(encap->daddr) ||
 	    ntohs(encap->tot_len) == 0 ||
-	    ntohs(encap->tot_len) + sizeof(*pim) > len) {
+	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len) {
 		kfree_skb(skb);
 		return -EINVAL;
 	}
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
--- v2.4.3/linux/net/ipv4/netfilter/Makefile	Tue Mar  6 22:44:16 2001
+++ linux/net/ipv4/netfilter/Makefile	Wed Apr 25 15:00:28 2001
@@ -20,7 +20,7 @@
 
 # objects for the standalone - connection tracking / NAT
 ip_conntrack-objs	:= ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
-iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
+iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o ip_nat_helper.o $(ip_nf_nat-objs)
 
 # objects for backwards compatibility mode
 ip_nf_compat-objs	:= ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_conntrack_core.c	Mon Jan 22 13:30:21 2001
+++ linux/net/ipv4/netfilter/ip_conntrack_core.c	Thu Apr 19 08:38:50 2001
@@ -894,7 +894,12 @@
 	if (!skb) {
 		if (sk) sock_put(sk);
 		return skb;
+	} else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
+		kfree_skb(skb);
+		if (sk) sock_put(sk);
+		return NULL;
 	}
+
 	if (sk) {
 		skb_set_owner_w(skb, sk);
 		sock_put(sk);
@@ -986,7 +991,7 @@
 		return -ENOPROTOOPT;
 	}
 
-	if (*len != sizeof(struct sockaddr_in)) {
+	if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
 		DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
 		       *len, sizeof(struct sockaddr_in));
 		return -EINVAL;
@@ -1076,10 +1081,14 @@
 	int ret;
 
 	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
-	 * machine has 256 buckets.  1GB machine has 8192 buckets. */
+	 * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
 	ip_conntrack_htable_size
 		= (((num_physpages << PAGE_SHIFT) / 16384)
 		   / sizeof(struct list_head));
+	if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
+		ip_conntrack_htable_size = 8192;
+	if (ip_conntrack_htable_size < 16)
+		ip_conntrack_htable_size = 16;
 	ip_conntrack_max = 8 * ip_conntrack_htable_size;
 
 	printk("ip_conntrack (%u buckets, %d max)\n",
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_conntrack_ftp.c linux/net/ipv4/netfilter/ip_conntrack_ftp.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_conntrack_ftp.c	Thu Aug 10 12:35:15 2000
+++ linux/net/ipv4/netfilter/ip_conntrack_ftp.c	Wed Apr 25 15:02:09 2001
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
+#include <linux/ctype.h>
 #include <net/checksum.h>
 #include <net/tcp.h>
 
@@ -12,8 +13,15 @@
 DECLARE_LOCK(ip_ftp_lock);
 struct module *ip_conntrack_ftp = THIS_MODULE;
 
-#define SERVER_STRING "227 Entering Passive Mode ("
-#define CLIENT_STRING "PORT "
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c;
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+#endif
+
+static int loose = 0;
+MODULE_PARM(loose, "i");
 
 #if 0
 #define DEBUGP printk
@@ -21,32 +29,63 @@
 #define DEBUGP(format, args...)
 #endif
 
-static struct {
+static int try_rfc959(const char *, size_t, u_int32_t [], char);
+static int try_eprt(const char *, size_t, u_int32_t [], char);
+static int try_espv_response(const char *, size_t, u_int32_t [], char);
+
+static struct ftp_search {
+	enum ip_conntrack_dir dir;
 	const char *pattern;
 	size_t plen;
+	char skip;
 	char term;
-} search[2] = {
-	[IP_CT_FTP_PORT] { CLIENT_STRING, sizeof(CLIENT_STRING) - 1, '\r' },
-	[IP_CT_FTP_PASV] { SERVER_STRING, sizeof(SERVER_STRING) - 1, ')' }
+	enum ip_ct_ftp_type ftptype;
+	int (*getnum)(const char *, size_t, u_int32_t[], char);
+} search[] = {
+	{
+		IP_CT_DIR_ORIGINAL,
+		"PORT",	sizeof("PORT") - 1, ' ', '\r',
+		IP_CT_FTP_PORT,
+		try_rfc959,
+	},
+	{
+		IP_CT_DIR_REPLY,
+		"227 ",	sizeof("227 ") - 1, '(', ')',
+		IP_CT_FTP_PASV,
+		try_rfc959,
+	},
+	{
+		IP_CT_DIR_ORIGINAL,
+		"EPRT", sizeof("EPRT") - 1, ' ', '\r',
+		IP_CT_FTP_EPRT,
+		try_eprt,
+	},
+	{
+		IP_CT_DIR_REPLY,
+		"229 ", sizeof("229 ") - 1, '(', ')',
+		IP_CT_FTP_EPSV,
+		try_espv_response,
+	},
 };
 
-/* Returns 0, or length of numbers */
-static int try_number(const char *data, size_t dlen, u_int32_t array[6],
-		      char term)
+static int try_number(const char *data, size_t dlen, u_int32_t array[],
+		      int array_size, char sep, char term)
 {
 	u_int32_t i, len;
 
+	memset(array, 0, sizeof(array[0])*array_size);
+
 	/* Keep data pointing at next char. */
-	for (i = 0, len = 0; len < dlen; len++, data++) {
+	for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) {
 		if (*data >= '0' && *data <= '9') {
 			array[i] = array[i]*10 + *data - '0';
 		}
-		else if (*data == ',')
+		else if (*data == sep)
 			i++;
 		else {
 			/* Unexpected character; true if it's the
 			   terminator and we're finished. */
-			if (*data == term && i == 5)
+			if (*data == term && i == array_size - 1)
 				return len;
 
 			DEBUGP("Char %u (got %u nums) `%u' unexpected\n",
@@ -54,22 +93,100 @@
 			return 0;
 		}
 	}
+	DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep);
 
 	return 0;
 }
 
+/* Returns 0, or length of numbers: 192,168,1,1,5,6 */
+static int try_rfc959(const char *data, size_t dlen, u_int32_t array[6],
+		       char term)
+{
+	return try_number(data, dlen, array, 6, ',', term);
+}
+
+/* Grab port: number up to delimiter */
+static int get_port(const char *data, int start, size_t dlen, char delim,
+		    u_int32_t array[2])
+{
+	u_int16_t port = 0;
+	int i;
+
+	for (i = start; i < dlen; i++) {
+		/* Finished? */
+		if (data[i] == delim) {
+			if (port == 0)
+				break;
+			array[0] = port >> 8;
+			array[1] = port;
+			return i + 1;
+		}
+		else if (data[i] >= '0' && data[i] <= '9')
+			port = port*10 + data[i] - '0';
+		else /* Some other crap */
+			break;
+	}
+	return 0;
+}
+
+/* Returns 0, or length of numbers: |1|132.235.1.2|6275| */
+static int try_eprt(const char *data, size_t dlen, u_int32_t array[6],
+		    char term)
+{
+	char delim;
+	int length;
+
+	/* First character is delimiter, then "1" for IPv4, then
+           delimiter again. */
+	if (dlen <= 3) return 0;
+	delim = data[0];
+	if (isdigit(delim) || delim < 33 || delim > 126
+	    || data[1] != '1' || data[2] != delim)
+		return 0;
+
+	DEBUGP("EPRT: Got |1|!\n");
+	/* Now we have IP address. */
+	length = try_number(data + 3, dlen - 3, array, 4, '.', delim);
+	if (length == 0)
+		return 0;
+
+	DEBUGP("EPRT: Got IP address!\n");
+	/* Start offset includes initial "|1|", and trailing delimiter */
+	return get_port(data, 3 + length + 1, dlen, delim, array+4);
+}
+
+/* Returns 0, or length of numbers: |||6446| */
+static int try_espv_response(const char *data, size_t dlen, u_int32_t array[6],
+			     char term)
+{
+	char delim;
+
+	/* Three delimiters. */
+	if (dlen <= 3) return 0;
+	delim = data[0];
+	if (isdigit(delim) || delim < 33 || delim > 126
+	    || data[1] != delim || data[2] != delim)
+		return 0;
+
+	return get_port(data, 3, dlen, delim, array+4);
+}
+
 /* Return 1 for match, 0 for accept, -1 for partial. */
 static int find_pattern(const char *data, size_t dlen,
 			const char *pattern, size_t plen,
-			char term,
+			char skip, char term,
 			unsigned int *numoff,
 			unsigned int *numlen,
-			u_int32_t array[6])
+			u_int32_t array[6],
+			int (*getnum)(const char *, size_t, u_int32_t[], char))
 {
+	size_t i;
+
+	DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
 	if (dlen == 0)
 		return 0;
 
-	if (dlen < plen) {
+	if (dlen <= plen) {
 		/* Short packet: try for partial? */
 		if (strnicmp(data, pattern, dlen) == 0)
 			return -1;
@@ -90,11 +207,23 @@
 		return 0;
 	}
 
-	*numoff = plen;
-	*numlen = try_number(data + plen, dlen - plen, array, term);
+	DEBUGP("Pattern matches!\n");
+	/* Now we've found the constant string, try to skip
+	   to the 'skip' character */
+	for (i = plen; data[i] != skip; i++)
+		if (i == dlen - 1) return -1;
+
+	/* Skip over the last character */
+	i++;
+
+	DEBUGP("Skipped up to `%c'!\n", skip);
+
+	*numoff = i;
+	*numlen = getnum(data + i, dlen - i, array, term);
 	if (!*numlen)
 		return -1;
 
+	DEBUGP("Match succeeded!\n");
 	return 1;
 }
 
@@ -115,6 +244,8 @@
 	unsigned int matchlen, matchoff;
 	struct ip_conntrack_tuple t, mask;
 	struct ip_ct_ftp *info = &ct->help.ct_ftp_info;
+	unsigned int i;
+	int found = 0;
 
 	/* Until there's been traffic both ways, don't look in packets. */
 	if (ctinfo != IP_CT_ESTABLISHED
@@ -163,25 +294,38 @@
 		return NF_ACCEPT;
 	}
 
-	switch (find_pattern(data, datalen,
-			     search[dir].pattern,
-			     search[dir].plen, search[dir].term,
-			     &matchoff, &matchlen,
-			     array)) {
-	case -1: /* partial */
+	/* Initialize IP array to expected address (it's not mentioned
+           in EPSV responses) */
+	array[0] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 24) & 0xFF;
+	array[1] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 16) & 0xFF;
+	array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF;
+	array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF;
+
+	for (i = 0; i < sizeof(search) / sizeof(search[0]); i++) {
+		if (search[i].dir != dir) continue;
+
+		found = find_pattern(data, datalen,
+				     search[i].pattern,
+				     search[i].plen,
+				     search[i].skip,
+				     search[i].term,
+				     &matchoff, &matchlen,
+				     array,
+				     search[i].getnum);
+		if (found) break;
+	}
+	if (found == -1) {
 		/* We don't usually drop packets.  After all, this is
 		   connection tracking, not packet filtering.
 		   However, it is neccessary for accurate tracking in
 		   this case. */
 		if (net_ratelimit())
-			printk("conntrack_ftp: partial %u+%u\n",
+			printk("conntrack_ftp: partial %s %u+%u\n",
+			       search[i].pattern,
 			       ntohl(tcph->seq), datalen);
 		return NF_DROP;
-
-	case 0: /* no match */
-		DEBUGP("ip_conntrack_ftp_help: no match\n");
+	} else if (found == 0) /* No match */
 		return NF_ACCEPT;
-	}
 
 	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
 	       (int)matchlen, data + matchoff,
@@ -194,7 +338,7 @@
 		info->is_ftp = 1;
 		info->seq = ntohl(tcph->seq) + matchoff;
 		info->len = matchlen;
-		info->ftptype = dir;
+		info->ftptype = search[i].ftptype;
 		info->port = array[4] << 8 | array[5];
 	} else {
 		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
@@ -204,6 +348,12 @@
 		DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
 		       array[0], array[1], array[2], array[3],
 		       NIPQUAD(ct->tuplehash[dir].tuple.src.ip));
+
+		/* Thanks to Cristiano Lincoln Mattos
+		   <lincoln@cesar.org.br> for reporting this potential
+		   problem (DMZ machines opening holes to internal
+		   networks, or the packet filter itself). */
+		if (!loose) goto out;
 	}
 
 	t = ((struct ip_conntrack_tuple)
@@ -218,27 +368,52 @@
 		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
 	/* Ignore failure; should only happen with NAT */
 	ip_conntrack_expect_related(ct, &t, &mask, NULL);
+ out:
 	UNLOCK_BH(&ip_ftp_lock);
 
 	return NF_ACCEPT;
 }
 
-static struct ip_conntrack_helper ftp = { { NULL, NULL },
-					  { { 0, { __constant_htons(21) } },
-					    { 0, { 0 }, IPPROTO_TCP } },
-					  { { 0, { 0xFFFF } },
-					    { 0, { 0 }, 0xFFFF } },
-					  help };
+static struct ip_conntrack_helper ftp[MAX_PORTS];
 
-static int __init init(void)
+/* Not __exit: called from init() */
+static void fini(void)
 {
-	return ip_conntrack_helper_register(&ftp);
+	int i;
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
+				ports[i]);
+		ip_conntrack_helper_unregister(&ftp[i]);
+	}
 }
 
-static void __exit fini(void)
+static int __init init(void)
 {
-	ip_conntrack_helper_unregister(&ftp);
+	int i, ret;
+
+	if (ports[0] == 0)
+		ports[0] = 21;
+
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper));
+		ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+		ftp[i].mask.src.u.tcp.port = 0xFFFF;
+		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].help = help;
+		DEBUGP("ip_ct_ftp: registering helper for port %d\n", 
+				ports[i]);
+		ret = ip_conntrack_helper_register(&ftp[i]);
+
+		if (ret) {
+			fini();
+			return ret;
+		}
+		ports_c++;
+	}
+	return 0;
 }
+
 
 EXPORT_SYMBOL(ip_ftp_lock);
 EXPORT_SYMBOL(ip_conntrack_ftp);
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_fw_compat.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat.c	Thu Apr 12 12:11:39 2001
@@ -96,7 +96,8 @@
 
 	/* Assume worse case: any hook could change packet */
 	(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
-	(*pskb)->ip_summed = CHECKSUM_NONE;
+	if ((*pskb)->ip_summed == CHECKSUM_HW)
+		(*pskb)->ip_summed = CHECKSUM_NONE;
 
 	switch (hooknum) {
 	case NF_IP_PRE_ROUTING:
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_nat_core.c	Mon Jan 29 08:07:30 2001
+++ linux/net/ipv4/netfilter/ip_nat_core.c	Wed Apr 25 15:00:28 2001
@@ -39,7 +39,6 @@
 static struct list_head bysource[IP_NAT_HTABLE_SIZE];
 static struct list_head byipsproto[IP_NAT_HTABLE_SIZE];
 LIST_HEAD(protos);
-static LIST_HEAD(helpers);
 
 extern struct ip_nat_protocol unknown_nat_protocol;
 
@@ -848,56 +847,6 @@
 					sizeof(*hdr) + datalen);
 
 	return NF_ACCEPT;
-}
-
-int ip_nat_helper_register(struct ip_nat_helper *me)
-{
-	int ret = 0;
-
-	WRITE_LOCK(&ip_nat_lock);
-	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
-		ret = -EBUSY;
-	else {
-		list_prepend(&helpers, me);
-		MOD_INC_USE_COUNT;
-	}
-	WRITE_UNLOCK(&ip_nat_lock);
-
-	return ret;
-}
-
-static int
-kill_helper(const struct ip_conntrack *i, void *helper)
-{
-	int ret;
-
-	READ_LOCK(&ip_nat_lock);
-	ret = (i->nat.info.helper == helper);
-	READ_UNLOCK(&ip_nat_lock);
-
-	return ret;
-}
-
-void ip_nat_helper_unregister(struct ip_nat_helper *me)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&helpers, me);
-	WRITE_UNLOCK(&ip_nat_lock);
-
-	/* Someone could be still looking at the helper in a bh. */
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
-
-	/* Find anything using it, and umm, kill them.  We can't turn
-	   them into normal connections: if we've adjusted SYNs, then
-	   they'll ackstorm.  So we just drop it.  We used to just
-	   bump module count when a connection existed, but that
-	   forces admins to gen fake RSTs or bounce box, either of
-	   which is just a long-winded way of making things
-	   worse. --RR */
-	ip_ct_selective_cleanup(kill_helper, me);
-
-	MOD_DEC_USE_COUNT;
 }
 
 int __init ip_nat_init(void)
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_nat_ftp.c linux/net/ipv4/netfilter/ip_nat_ftp.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_nat_ftp.c	Sun Sep 17 10:15:00 2000
+++ linux/net/ipv4/netfilter/ip_nat_ftp.c	Wed Apr 25 15:02:35 2001
@@ -7,7 +7,6 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_helper.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_nat_ftp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 
@@ -17,6 +16,16 @@
 #define DEBUGP(format, args...)
 #endif
 
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c = 0;
+
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+#endif
+
+DECLARE_LOCK_EXTERN(ip_ftp_lock);
+
 /* FIXME: Time out? --RR */
 
 static int
@@ -49,7 +58,8 @@
 		return 0;
 	}
 
-	if (ftpinfo->ftptype == IP_CT_FTP_PORT) {
+	if (ftpinfo->ftptype == IP_CT_FTP_PORT
+	    || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
 		/* PORT command: make connection go to the client. */
 		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
@@ -89,159 +99,88 @@
 	return 1;
 }
 
-/* This is interesting.  We simply use the port given us by the client
-   or server.  In practice it's extremely unlikely to clash; if it
-   does, the rule won't be able to get a unique tuple and will drop
-   the packets. */
 static int
-mangle_packet(struct sk_buff **pskb,
-	      u_int32_t newip,
-	      u_int16_t port,
-	      unsigned int matchoff,
-	      unsigned int matchlen,
-	      struct ip_nat_ftp_info *this_way,
-	      struct ip_nat_ftp_info *other_way)
+mangle_rfc959_packet(struct sk_buff **pskb,
+		     u_int32_t newip,
+		     u_int16_t port,
+		     unsigned int matchoff,
+		     unsigned int matchlen,
+		     struct ip_conntrack *ct,
+		     enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct tcphdr *tcph;
-	unsigned char *data;
-	unsigned int tcplen, newlen, newtcplen;
 	char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
 
 	MUST_BE_LOCKED(&ip_ftp_lock);
+
 	sprintf(buffer, "%u,%u,%u,%u,%u,%u",
 		NIPQUAD(newip), port>>8, port&0xFF);
 
-	tcplen = (*pskb)->len - iph->ihl * 4;
-	newtcplen = tcplen - matchlen + strlen(buffer);
-	newlen = iph->ihl*4 + newtcplen;
-
-	/* So there I am, in the middle of my `netfilter-is-wonderful'
-	   talk in Sydney, and someone asks `What happens if you try
-	   to enlarge a 64k packet here?'.  I think I said something
-	   eloquent like `fuck'. */
-	if (newlen > 65535) {
-		if (net_ratelimit())
-			printk("nat_ftp cheat: %u.%u.%u.%u->%u.%u.%u.%u %u\n",
-			       NIPQUAD((*pskb)->nh.iph->saddr),
-			       NIPQUAD((*pskb)->nh.iph->daddr),
-			       (*pskb)->nh.iph->protocol);
-		return 0;
-	}
+	DEBUGP("calling ip_nat_mangle_tcp_packet\n");
 
-	if (newlen > (*pskb)->len + skb_tailroom(*pskb)) {
-		struct sk_buff *newskb;
-		newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
-					 newlen - (*pskb)->len,
-					 GFP_ATOMIC);
-		if (!newskb) {
-			DEBUGP("ftp: oom\n");
-			return 0;
-		} else {
-			kfree_skb(*pskb);
-			*pskb = newskb;
-			iph = (*pskb)->nh.iph;
-		}
-	}
+	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 
+					matchlen, buffer, strlen(buffer));
+}
 
-	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
+/* |1|132.235.1.2|6275| */
+static int
+mangle_eprt_packet(struct sk_buff **pskb,
+		   u_int32_t newip,
+		   u_int16_t port,
+		   unsigned int matchoff,
+		   unsigned int matchlen,
+		   struct ip_conntrack *ct,
+		   enum ip_conntrack_info ctinfo)
+{
+	char buffer[sizeof("|1|255.255.255.255|65535|")];
 
-	DEBUGP("Mapping `%.*s' [%u %u %u] to new `%s' [%u]\n",
-		 (int)matchlen, data+matchoff,
-		 data[matchoff], data[matchoff+1],
-		 matchlen, buffer, strlen(buffer));
-
-	/* SYN adjust.  If it's uninitialized, or this is after last
-           correction, record it: we don't handle more than one
-           adjustment in the window, but do deal with common case of a
-           retransmit. */
-	if (this_way->syn_offset_before == this_way->syn_offset_after
-	    || before(this_way->syn_correction_pos, ntohl(tcph->seq))) {
-		this_way->syn_correction_pos = ntohl(tcph->seq);
-		this_way->syn_offset_before = this_way->syn_offset_after;
-		this_way->syn_offset_after = (int32_t)
-			this_way->syn_offset_before + newlen - (*pskb)->len;
-	}
+	MUST_BE_LOCKED(&ip_ftp_lock);
 
-	/* Move post-replacement */
-	memmove(data + matchoff + strlen(buffer),
-		data + matchoff + matchlen,
-		(*pskb)->tail - (data + matchoff + matchlen));
-	memcpy(data + matchoff, buffer, strlen(buffer));
-
-	/* Resize packet. */
-	if (newlen > (*pskb)->len) {
-		DEBUGP("ip_nat_ftp: Extending packet by %u to %u bytes\n",
-		       newlen - (*pskb)->len, newlen);
-		skb_put(*pskb, newlen - (*pskb)->len);
-	} else {
-		DEBUGP("ip_nat_ftp: Shrinking packet from %u to %u bytes\n",
-		       (*pskb)->len, newlen);
-		skb_trim(*pskb, newlen);
-	}
+	sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
 
-	/* Fix checksums */
-	iph->tot_len = htons(newlen);
-	(*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
-				     newtcplen - tcph->doff*4, 0);
-	tcph->check = 0;
-	tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
-				   csum_partial((char *)tcph, tcph->doff*4,
-						(*pskb)->csum));
-	ip_send_check(iph);
-	return 1;
+	DEBUGP("calling ip_nat_mangle_tcp_packet\n");
+
+	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 
+					matchlen, buffer, strlen(buffer));
 }
 
-/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
-   fly, so blow it away. */
-static void
-delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
+/* |1|132.235.1.2|6275| */
+static int
+mangle_epsv_packet(struct sk_buff **pskb,
+		   u_int32_t newip,
+		   u_int16_t port,
+		   unsigned int matchoff,
+		   unsigned int matchlen,
+		   struct ip_conntrack *ct,
+		   enum ip_conntrack_info ctinfo)
 {
-	unsigned int i;
-	u_int8_t *opt = (u_int8_t *)tcph;
+	char buffer[sizeof("|||65535|")];
 
-	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
-	       tcph->doff * 4);
-	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
-		DEBUGP("%u ", opt[i]);
-		switch (opt[i]) {
-		case TCPOPT_NOP:
-		case TCPOPT_EOL:
-			i++;
-			break;
+	MUST_BE_LOCKED(&ip_ftp_lock);
 
-		case TCPOPT_SACK_PERM:
-			goto found_opt;
+	sprintf(buffer, "|||%u|", port);
 
-		default:
-			/* Worst that can happen: it will take us over. */
-			i += opt[i+1] ?: 1;
-		}
-	}
-	DEBUGP("\n");
-	return;
+	DEBUGP("calling ip_nat_mangle_tcp_packet\n");
 
- found_opt:
-	DEBUGP("\n");
-	DEBUGP("Found SACKPERM at offset %u.\n", i);
-
-	/* Must be within TCP header, and valid SACK perm. */
-	if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
-		/* Replace with NOPs. */
-		tcph->check
-			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
-					     0, tcph->check);
-		opt[i] = opt[i+1] = 0;
-	}
-	else DEBUGP("Something wrong with SACK_PERM.\n");
+	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 
+					matchlen, buffer, strlen(buffer));
 }
 
+static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
+		     unsigned int,
+		     unsigned int,
+		     struct ip_conntrack *,
+		     enum ip_conntrack_info)
+= { [IP_CT_FTP_PORT] mangle_rfc959_packet,
+    [IP_CT_FTP_PASV] mangle_rfc959_packet,
+    [IP_CT_FTP_EPRT] mangle_eprt_packet,
+    [IP_CT_FTP_EPSV] mangle_epsv_packet
+};
+
 static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
 			  struct ip_conntrack *ct,
-			  struct ip_nat_ftp_info *ftp,
 			  unsigned int datalen,
-			  struct sk_buff **pskb)
+			  struct sk_buff **pskb,
+			  enum ip_conntrack_info ctinfo)
 {
 	u_int32_t newip;
 	struct iphdr *iph = (*pskb)->nh.iph;
@@ -261,8 +200,9 @@
 
 	/* Change address inside packet to match way we're mapping
 	   this connection. */
-	if (ct_ftp_info->ftptype == IP_CT_FTP_PASV) {
-		/* PASV response: must be where client thinks server
+	if (ct_ftp_info->ftptype == IP_CT_FTP_PASV
+	    || ct_ftp_info->ftptype == IP_CT_FTP_EPSV) {
+		/* PASV/EPSV response: must be where client thinks server
 		   is */
 		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 		/* Expect something from client->server */
@@ -287,11 +227,9 @@
 	if (port == 0)
 		return 0;
 
-	if (!mangle_packet(pskb, newip, port,
-			   ct_ftp_info->seq - ntohl(tcph->seq),
-			   ct_ftp_info->len,
-			   &ftp[ct_ftp_info->ftptype],
-			   &ftp[!ct_ftp_info->ftptype]))
+	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
+					  ct_ftp_info->seq - ntohl(tcph->seq),
+					  ct_ftp_info->len, ct, ctinfo))
 		return 0;
 
 	return 1;
@@ -305,18 +243,15 @@
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
-	u_int32_t newseq, newack;
 	unsigned int datalen;
 	int dir;
 	int score;
 	struct ip_ct_ftp *ct_ftp_info
 		= &ct->help.ct_ftp_info;
-	struct ip_nat_ftp_info *ftp
-		= &ct->nat.help.ftp_info[0];
 
 	/* Delete SACK_OK on initial TCP SYNs. */
 	if (tcph->syn && !tcph->ack)
-		delete_sack(*pskb, tcph);
+		ip_nat_delete_sack(*pskb, tcph);
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -353,71 +288,83 @@
 			UNLOCK_BH(&ip_ftp_lock);
 			return NF_DROP;
 		} else if (score == 2) {
-			if (!ftp_data_fixup(ct_ftp_info, ct, ftp, datalen,
-					    pskb)) {
+			if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
+					    pskb, ctinfo)) {
 				UNLOCK_BH(&ip_ftp_lock);
 				return NF_DROP;
 			}
-
 			/* skb may have been reallocated */
 			iph = (*pskb)->nh.iph;
 			tcph = (void *)iph + iph->ihl*4;
 		}
 	}
 
-	/* Sequence adjust */
-	if (after(ntohl(tcph->seq), ftp[dir].syn_correction_pos))
-		newseq = ntohl(tcph->seq) + ftp[dir].syn_offset_after;
-	else
-		newseq = ntohl(tcph->seq) + ftp[dir].syn_offset_before;
-	newseq = htonl(newseq);
-
-	/* Ack adjust: other dir sees offset seq numbers */
-	if (after(ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_before, 
-		  ftp[!dir].syn_correction_pos))
-		newack = ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_after;
-	else
-		newack = ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_before;
-	newack = htonl(newack);
 	UNLOCK_BH(&ip_ftp_lock);
 
-	tcph->check = ip_nat_cheat_check(~tcph->seq, newseq,
-					 ip_nat_cheat_check(~tcph->ack_seq,
-							    newack,
-							    tcph->check));
-	tcph->seq = newseq;
-	tcph->ack_seq = newack;
+	ip_nat_seq_adjust(*pskb, ct, ctinfo);
 
 	return NF_ACCEPT;
 }
 
-static struct ip_nat_helper ftp = { { NULL, NULL },
-				    { { 0, { __constant_htons(21) } },
-				      { 0, { 0 }, IPPROTO_TCP } },
-				    { { 0, { 0xFFFF } },
-				      { 0, { 0 }, 0xFFFF } },
-				    help, "ftp" };
+static struct ip_nat_helper ftp[MAX_PORTS];
+static char ftp_names[MAX_PORTS][6];
+
 static struct ip_nat_expect ftp_expect
 = { { NULL, NULL }, ftp_nat_expected };
 
+/* Not __exit: called from init() */
+static void fini(void)
+{
+	int i;
+
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
+		ip_nat_helper_unregister(&ftp[i]);
+	}
+
+	ip_nat_expect_unregister(&ftp_expect);
+}
+
 static int __init init(void)
 {
-	int ret;
+	int i, ret;
+	char *tmpname;
 
 	ret = ip_nat_expect_register(&ftp_expect);
 	if (ret == 0) {
-		ret = ip_nat_helper_register(&ftp);
+		if (ports[0] == 0)
+			ports[0] = 21;
+
+		for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+
+			memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
+
+			ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+			ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+			ftp[i].mask.dst.protonum = 0xFFFF;
+			ftp[i].mask.src.u.tcp.port = 0xFFFF;
+			ftp[i].help = help;
+
+			tmpname = &ftp_names[i][0];
+			sprintf(tmpname, "ftp%2.2d", i);
+			ftp[i].name = tmpname;
+
+			DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
+					ports[i]);
+			ret = ip_nat_helper_register(&ftp[i]);
+
+			if (ret) {
+				printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);
+				fini();
+				return ret;
+			}
+			ports_c++;
+		}
 
-		if (ret != 0)
-			ip_nat_expect_unregister(&ftp_expect);
+	} else {
+		ip_nat_expect_unregister(&ftp_expect);
 	}
 	return ret;
-}
-
-static void __exit fini(void)
-{
-	ip_nat_helper_unregister(&ftp);
-	ip_nat_expect_unregister(&ftp_expect);
 }
 
 module_init(init);
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_nat_helper.c linux/net/ipv4/netfilter/ip_nat_helper.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_nat_helper.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ip_nat_helper.c	Wed Apr 25 15:00:28 2001
@@ -0,0 +1,332 @@
+/* ip_nat_mangle.c - generic support functions for NAT helpers 
+ *
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ *
+ * distributed under the terms of GNU GPL
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/brlock.h>
+#include <net/checksum.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+
+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
+
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#if 0
+#define DEBUGP printk
+#define DUMP_OFFSET(x)	printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
+#else
+#define DEBUGP(format, args...)
+#define DUMP_OFFSET(x)
+#endif
+	
+DECLARE_LOCK(ip_nat_seqofs_lock);
+LIST_HEAD(helpers);
+			 
+static inline int 
+ip_nat_resize_packet(struct sk_buff **skb,
+		     struct ip_conntrack *ct, 
+		     enum ip_conntrack_info ctinfo,
+		     int new_size)
+{
+	struct iphdr *iph;
+	struct tcphdr *tcph;
+	void *data;
+	int dir;
+	struct ip_nat_seq *this_way, *other_way;
+
+	DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n",
+		(*skb)->len, new_size);
+
+	iph = (*skb)->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+	data = (void *)tcph + tcph->doff*4;
+
+	dir = CTINFO2DIR(ctinfo);
+
+	this_way = &ct->nat.info.seq[dir];
+	other_way = &ct->nat.info.seq[!dir];
+
+	if (new_size > (*skb)->len + skb_tailroom(*skb)) {
+		struct sk_buff *newskb;
+		newskb = skb_copy_expand(*skb, skb_headroom(*skb),
+					 new_size - (*skb)->len,
+					 GFP_ATOMIC);
+
+		if (!newskb) {
+			printk("ip_nat_resize_packet: oom\n");
+			return 0;
+		} else {
+			kfree_skb(*skb);
+			*skb = newskb;
+		}
+	}
+
+	iph = (*skb)->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+	data = (void *)tcph + tcph->doff*4;
+
+	DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
+	DUMP_OFFSET(this_way);
+
+	LOCK_BH(&ip_nat_seqofs_lock);
+
+	/* SYN adjust. If it's uninitialized, of this is after last 
+	 * correction, record it: we don't handle more than one 
+	 * adjustment in the window, but do deal with common case of a 
+	 * retransmit */
+	if (this_way->offset_before == this_way->offset_after
+	    || before(this_way->correction_pos, ntohl(tcph->seq))) {
+		this_way->correction_pos = ntohl(tcph->seq);
+		this_way->offset_before = this_way->offset_after;
+		this_way->offset_after = (int32_t)
+			this_way->offset_before + new_size - (*skb)->len;
+	}
+
+	UNLOCK_BH(&ip_nat_seqofs_lock);
+
+	DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
+	DUMP_OFFSET(this_way);
+	
+	return 1;
+}
+
+
+/* Generic function for mangling variable-length address changes inside
+ * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP).
+ *
+ * Takes care about all the nasty sequence number changes, checksumming,
+ * skb enlargement, ...
+ *
+ * */
+int 
+ip_nat_mangle_tcp_packet(struct sk_buff **skb,
+			 struct ip_conntrack *ct,
+			 enum ip_conntrack_info ctinfo,
+			 unsigned int match_offset,
+			 unsigned int match_len,
+			 char *rep_buffer,
+			 unsigned int rep_len)
+{
+	struct iphdr *iph = (*skb)->nh.iph;
+	struct tcphdr *tcph;
+	unsigned char *data;
+	u_int32_t tcplen, newlen, newtcplen;
+
+	tcplen = (*skb)->len - iph->ihl*4;
+	newtcplen = tcplen - match_len + rep_len;
+	newlen = iph->ihl*4 + newtcplen;
+
+	if (newlen > 65535) {
+		if (net_ratelimit())
+			printk("ip_nat_mangle_tcp_packet: nat'ed packet "
+				"exceeds maximum packet size\n");
+		return 0;
+	}
+
+	if ((*skb)->len != newlen) {
+		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
+			printk("resize_packet failed!!\n");
+			return 0;
+		}
+	}
+
+	/* skb may be copied !! */
+	iph = (*skb)->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+	data = (void *)tcph + tcph->doff*4;
+
+	/* move post-replacement */
+	memmove(data + match_offset + rep_len,
+		 data + match_offset + match_len,
+		 (*skb)->tail - (data + match_offset + match_len));
+
+	/* insert data from buffer */
+	memcpy(data + match_offset, rep_buffer, rep_len);
+
+	/* update skb info */
+	if (newlen > (*skb)->len) {
+		DEBUGP("ip_nat_mangle_tcp_packet: Extending packet by "
+			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
+		skb_put(*skb, newlen - (*skb)->len);
+	} else {
+		DEBUGP("ip_nat_mangle_tcp_packet: Shrinking packet from "
+			"%u to %u bytes\n", (*skb)->len, newlen);
+		skb_trim(*skb, newlen);
+	}
+
+	/* fix checksum information */
+
+	iph->tot_len = htons(newlen);
+	(*skb)->csum = csum_partial((char *)tcph + tcph->doff*4,
+				    newtcplen - tcph->doff*4, 0);
+
+	tcph->check = 0;
+	tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
+				   csum_partial((char *)tcph, tcph->doff*4,
+					   (*skb)->csum));
+	ip_send_check(iph);
+
+	return 1;
+}
+
+/* TCP sequence number adjustment */
+int 
+ip_nat_seq_adjust(struct sk_buff *skb, 
+		  struct ip_conntrack *ct, 
+		  enum ip_conntrack_info ctinfo)
+{
+	struct iphdr *iph;
+	struct tcphdr *tcph;
+	int dir, newseq, newack;
+	struct ip_nat_seq *this_way, *other_way;	
+	
+	iph = skb->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+
+	dir = CTINFO2DIR(ctinfo);
+
+	this_way = &ct->nat.info.seq[dir];
+	other_way = &ct->nat.info.seq[!dir];
+	
+	if (after(ntohl(tcph->seq), this_way->correction_pos))
+		newseq = ntohl(tcph->seq) + this_way->offset_after;
+	else
+		newseq = ntohl(tcph->seq) + this_way->offset_before;
+	newseq = htonl(newseq);
+
+	if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
+		  other_way->correction_pos))
+		newack = ntohl(tcph->ack_seq) - other_way->offset_after;
+	else
+		newack = ntohl(tcph->ack_seq) - other_way->offset_before;
+	newack = htonl(newack);
+
+	tcph->check = ip_nat_cheat_check(~tcph->seq, newseq,
+					 ip_nat_cheat_check(~tcph->ack_seq, 
+					 		    newack, 
+							    tcph->check));
+
+	DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
+		ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
+		ntohl(newack));
+
+	tcph->seq = newseq;
+	tcph->ack_seq = newack;
+
+	return 0;
+}
+
+/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
+   fly, so blow it away. */
+void
+ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
+{
+	unsigned int i;
+	u_int8_t *opt = (u_int8_t *)tcph;
+
+	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
+	       tcph->doff * 4);
+	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
+		DEBUGP("%u ", opt[i]);
+		switch (opt[i]) {
+		case TCPOPT_NOP:
+		case TCPOPT_EOL:
+			i++;
+			break;
+
+		case TCPOPT_SACK_PERM:
+			goto found_opt;
+
+		default:
+			/* Worst that can happen: it will take us over. */
+			i += opt[i+1] ?: 1;
+		}
+	}
+	DEBUGP("\n");
+	return;
+
+ found_opt:
+	DEBUGP("\n");
+	DEBUGP("Found SACKPERM at offset %u.\n", i);
+
+	/* Must be within TCP header, and valid SACK perm. */
+	if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
+		/* Replace with NOPs. */
+		tcph->check
+			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
+					     0, tcph->check);
+		opt[i] = opt[i+1] = 0;
+	}
+	else DEBUGP("Something wrong with SACK_PERM.\n");
+}
+
+static inline int
+helper_cmp(const struct ip_nat_helper *helper,
+	   const struct ip_conntrack_tuple *tuple)
+{
+	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
+}
+
+int ip_nat_helper_register(struct ip_nat_helper *me)
+{
+	int ret = 0;
+
+	WRITE_LOCK(&ip_nat_lock);
+	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
+		ret = -EBUSY;
+	else {
+		list_prepend(&helpers, me);
+		MOD_INC_USE_COUNT;
+	}
+	WRITE_UNLOCK(&ip_nat_lock);
+
+	return ret;
+}
+
+static int
+kill_helper(const struct ip_conntrack *i, void *helper)
+{
+	int ret;
+
+	READ_LOCK(&ip_nat_lock);
+	ret = (i->nat.info.helper == helper);
+	READ_UNLOCK(&ip_nat_lock);
+
+	return ret;
+}
+
+void ip_nat_helper_unregister(struct ip_nat_helper *me)
+{
+	WRITE_LOCK(&ip_nat_lock);
+	LIST_DELETE(&helpers, me);
+	WRITE_UNLOCK(&ip_nat_lock);
+
+	/* Someone could be still looking at the helper in a bh. */
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+
+	/* Find anything using it, and umm, kill them.  We can't turn
+	   them into normal connections: if we've adjusted SYNs, then
+	   they'll ackstorm.  So we just drop it.  We used to just
+	   bump module count when a connection existed, but that
+	   forces admins to gen fake RSTs or bounce box, either of
+	   which is just a long-winded way of making things
+	   worse. --RR */
+	ip_ct_selective_cleanup(kill_helper, me);
+
+	MOD_DEC_USE_COUNT;
+}
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- v2.4.3/linux/net/ipv4/netfilter/ip_nat_standalone.c	Sat Feb  3 11:45:55 2001
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Wed Apr 25 15:00:28 2001
@@ -64,7 +64,7 @@
 	(*pskb)->nfcache |= NFC_UNKNOWN;
 
 	/* If we had a hardware checksum before, it's now invalid */
-	if ((*pskb)->pkt_type != PACKET_LOOPBACK)
+	if ((*pskb)->ip_summed == CHECKSUM_HW)
 		(*pskb)->ip_summed = CHECKSUM_NONE;
 
 	ct = ip_conntrack_get(*pskb, &ctinfo);
@@ -336,3 +336,6 @@
 EXPORT_SYMBOL(ip_nat_expect_register);
 EXPORT_SYMBOL(ip_nat_expect_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
+EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
+EXPORT_SYMBOL(ip_nat_seq_adjust);
+EXPORT_SYMBOL(ip_nat_delete_sack);
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c
--- v2.4.3/linux/net/ipv4/netfilter/ipchains_core.c	Thu Apr 13 17:19:57 2000
+++ linux/net/ipv4/netfilter/ipchains_core.c	Thu Apr 12 12:11:39 2001
@@ -871,7 +871,7 @@
 	if (chainptr->chain == NULL) {
 
 		/* If pointer writes are atomic then turning off
-		 * interupts is not necessary. */
+		 * interrupts is not necessary. */
 		chainptr->chain = rule;
 		if (rule->branch) rule->branch->refcount++;
 		return 0;
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.4.3/linux/net/ipv4/raw.c	Fri Feb  9 11:29:44 2001
+++ linux/net/ipv4/raw.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.56 2000/11/28 13:38:38 davem Exp $
+ * Version:	$Id: raw.c,v 1.60 2001/02/23 06:32:11 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -170,11 +170,10 @@
 	return sk;
 }
 
-void raw_err (struct sock *sk, struct sk_buff *skb)
+void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
 {
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
-	u32 info = 0;
 	int err = 0;
 	int harderr = 0;
 
@@ -195,7 +194,6 @@
 		return;
 	case ICMP_PARAMETERPROB:
 		err = EPROTO;
-		info = ntohl(skb->h.icmph->un.gateway)>>24;
 		harderr = 1;
 		break;
 	case ICMP_DEST_UNREACH:
@@ -207,12 +205,17 @@
 		if (code == ICMP_FRAG_NEEDED) {
 			harderr = (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT);
 			err = EMSGSIZE;
-			info = ntohs(skb->h.icmph->un.frag.mtu);
 		}
 	}
 
-	if (sk->protinfo.af_inet.recverr)
-		ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1));
+	if (sk->protinfo.af_inet.recverr) {
+		struct iphdr *iph = (struct iphdr*)skb->data;
+		u8 *payload = skb->data+(iph->ihl<<2);
+
+		if (sk->protinfo.af_inet.hdrincl)
+			payload = skb->data;
+		ip_icmp_error(sk, skb, err, 0, info, payload);
+	}
 
 	if (sk->protinfo.af_inet.recverr || harderr) {
 		sk->err = err;
@@ -235,18 +238,9 @@
 	return NET_RX_SUCCESS;
 }
 
-/*
- *	This should be the easiest of all, all we do is
- *	copy it into a buffer. All demultiplexing is done
- *	in ip.c
- */
-
 int raw_rcv(struct sock *sk, struct sk_buff *skb)
 {
-	/* Now we need to copy this into memory. */
-	skb_trim(skb, ntohs(skb->nh.iph->tot_len));
-	
-	skb->h.raw = skb->nh.raw;
+	skb_push(skb, skb->data-skb->nh.raw);
 
 	raw_rcv_skb(sk, skb);
 	return 0;
@@ -296,7 +290,7 @@
 	 	 *	ip_build_xmit clean (well less messy).
 		 */
 		if (!iph->id)
-			ip_select_ident(iph, rfh->dst);
+			ip_select_ident(iph, rfh->dst, NULL);
 		iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl);
 	}
 	return 0;
@@ -498,7 +492,7 @@
 		msg->msg_flags |= MSG_TRUNC;
 		copied = len;
 	}
-	
+
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	if (err)
 		goto done;
@@ -540,6 +534,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 --recursive --new-file v2.4.3/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.4.3/linux/net/ipv4/route.c	Tue Oct 10 10:33:52 2000
+++ linux/net/ipv4/route.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.91 2000/10/03 07:29:00 anton Exp $
+ * Version:	$Id: route.c,v 1.93 2001/02/22 01:03:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -115,7 +115,7 @@
 int ip_rt_gc_elasticity = 8;
 int ip_rt_mtu_expires = 10*60*HZ;
 int ip_rt_min_pmtu = 512+20+20;
-int ip_rt_min_advmss = 536;
+int ip_rt_min_advmss = 256;
 
 static unsigned long rt_deadline;
 
@@ -667,7 +667,7 @@
 
 	spin_lock_bh(&ip_fb_id_lock);
 	salt = secure_ip_id(ip_fallback_id ^ iph->daddr);
-	iph->id = salt & 0xFFFF;
+	iph->id = htons(salt & 0xFFFF);
 	ip_fallback_id = salt;
 	spin_unlock_bh(&ip_fb_id_lock);
 }
@@ -684,7 +684,7 @@
 		   so that we need not to grab a lock to dereference it.
 		 */
 		if (rt->peer) {
-			iph->id = inet_getid(rt->peer);
+			iph->id = htons(inet_getid(rt->peer));
 			return;
 		}
 	} else {
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c
--- v2.4.3/linux/net/ipv4/syncookies.c	Fri Feb  9 11:29:44 2001
+++ linux/net/ipv4/syncookies.c	Thu Apr 12 12:11:39 2001
@@ -9,7 +9,7 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  * 
- *  $Id: syncookies.c,v 1.12 2000/07/26 01:04:19 davem Exp $
+ *  $Id: syncookies.c,v 1.13 2001/02/13 01:17:26 davem Exp $
  *
  *  Missing: IPv6 support. 
  */
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.4.3/linux/net/ipv4/tcp.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/tcp.c	Wed Apr 25 14:57:39 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.180 2000/11/28 17:04:09 davem Exp $
+ * Version:	$Id: tcp.c,v 1.202 2001/04/20 20:46:19 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -458,10 +458,21 @@
 }
 
 /*
- *	TCP socket write_space callback. Not used.
+ *	TCP socket write_space callback.
  */
 void tcp_write_space(struct sock *sk)
 {
+	struct socket *sock = sk->socket;
+
+	if (tcp_wspace(sk) >= tcp_min_write_space(sk) && sock) {
+		clear_bit(SOCK_NOSPACE, &sock->flags);
+
+		if (sk->sleep && waitqueue_active(sk->sleep))
+			wake_up_interruptible(sk->sleep);
+
+		if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN))
+			sock_wake_async(sock, 2, POLL_OUT);
+	}
 }
 
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
@@ -520,6 +531,7 @@
 	sk->ack_backlog = 0;
 	tp->accept_queue = tp->accept_queue_tail = NULL;
 	tp->syn_wait_lock = RW_LOCK_UNLOCKED;
+	tcp_delack_init(tp);
 
 	lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL);
 	if (!lopt)
@@ -642,11 +654,8 @@
 		if(sk->err)
 			return sock_error(sk);
 		if((1 << sk->state) &
-		   ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
-			if(sk->keepopen && !(flags&MSG_NOSIGNAL))
-				send_sig(SIGPIPE, tsk, 0);
+		   ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
 			return -EPIPE;
-		}
 		if(!*timeo_p)
 			return -EAGAIN;
 		if(signal_pending(tsk))
@@ -675,56 +684,326 @@
 /*
  *	Wait for more memory for a socket
  */
-static long wait_for_tcp_memory(struct sock * sk, long timeo)
+static int wait_for_tcp_memory(struct sock * sk, long *timeo)
 {
+	int err = 0;
 	long vm_wait = 0;
-	long current_timeo = timeo;
+	long current_timeo = *timeo;
 	DECLARE_WAITQUEUE(wait, current);
 
 	if (tcp_memory_free(sk))
 		current_timeo = vm_wait = (net_random()%(HZ/5))+2;
 
-	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
-		set_bit(SOCK_NOSPACE, &sk->socket->flags);
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 
 		set_current_state(TASK_INTERRUPTIBLE);
 
+		if (sk->err || (sk->shutdown & SEND_SHUTDOWN))
+			goto do_error;
+		if (!*timeo)
+			goto do_nonblock;
 		if (signal_pending(current))
-			break;
+			goto do_interrupted;
+		clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 		if (tcp_memory_free(sk) && !vm_wait)
 			break;
-		if (sk->shutdown & SEND_SHUTDOWN)
-			break;
-		if (sk->err)
-			break;
+
+		set_bit(SOCK_NOSPACE, &sk->socket->flags);
+		sk->tp_pinfo.af_tcp.write_pending++;
 		release_sock(sk);
 		if (!tcp_memory_free(sk) || vm_wait)
 			current_timeo = schedule_timeout(current_timeo);
 		lock_sock(sk);
+		sk->tp_pinfo.af_tcp.write_pending--;
+
 		if (vm_wait) {
-			if (timeo != MAX_SCHEDULE_TIMEOUT &&
-			    (timeo -= vm_wait-current_timeo) < 0)
-				timeo = 0;
-			break;
-		} else {
-			timeo = current_timeo;
+			vm_wait -= current_timeo;
+			current_timeo = *timeo;
+			if (current_timeo != MAX_SCHEDULE_TIMEOUT &&
+			    (current_timeo -= vm_wait) < 0)
+				current_timeo = 0;
+			vm_wait = 0;
 		}
+		*timeo = current_timeo;
 	}
+out:
 	current->state = TASK_RUNNING;
 	remove_wait_queue(sk->sleep, &wait);
-	return timeo;
+	return err;
+
+do_error:
+	err = -EPIPE;
+	goto out;
+do_nonblock:
+	err = -EAGAIN;
+	goto out;
+do_interrupted:
+	err = sock_intr_errno(*timeo);
+	goto out;
 }
 
-/* When all user supplied data has been queued set the PSH bit */
-#define PSH_NEEDED (seglen == 0 && iovlen == 0)
+ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags);
 
-/*
- *	This routine copies from a user buffer into a socket,
- *	and starts the transmit system.
- */
+static inline int
+can_coalesce(struct sk_buff *skb, int i, struct page *page, int off)
+{
+	if (i) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+		return page == frag->page &&
+			off == frag->page_offset+frag->size;
+	}
+	return 0;
+}
+
+static inline void
+fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size)
+{
+	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+	frag->page = page;
+	frag->page_offset = off;
+	frag->size = size;
+	skb_shinfo(skb)->nr_frags = i+1;
+}
+
+static inline void tcp_mark_push(struct tcp_opt *tp, struct sk_buff *skb)
+{
+	TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+	tp->pushed_seq = tp->write_seq;
+}
+
+static inline int forced_push(struct tcp_opt *tp)
+{
+	return after(tp->write_seq, tp->pushed_seq + (tp->max_window>>1));
+}
+
+static inline void
+skb_entail(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb)
+{
+	skb->csum = 0;
+	TCP_SKB_CB(skb)->seq = tp->write_seq;
+	TCP_SKB_CB(skb)->end_seq = tp->write_seq;
+	TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
+	TCP_SKB_CB(skb)->sacked = 0;
+	__skb_queue_tail(&sk->write_queue, skb);
+	tcp_charge_skb(sk, skb);
+	if (tp->send_head == NULL)
+		tp->send_head = skb;
+}
+
+static inline void
+tcp_mark_urg(struct tcp_opt *tp, int flags, struct sk_buff *skb)
+{
+	if (flags & MSG_OOB) {
+		tp->urg_mode = 1;
+		tp->snd_up = tp->write_seq;
+		TCP_SKB_CB(skb)->sacked |= TCPCB_URG;
+	}
+}
+
+static inline void
+tcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle)
+{
+	if (tp->send_head) {
+		struct sk_buff *skb = sk->write_queue.prev;
+		if (!(flags&MSG_MORE) || forced_push(tp))
+			tcp_mark_push(tp, skb);
+		tcp_mark_urg(tp, flags, skb);
+		__tcp_push_pending_frames(sk, tp, mss_now, (flags&MSG_MORE) ? 2 : nonagle);
+	}
+}
+
+static int tcp_error(struct sock *sk, int flags, int err)
+{
+	if (err == -EPIPE)
+		err = sock_error(sk) ? : -EPIPE;
+	if (err == -EPIPE && !(flags&MSG_NOSIGNAL))
+		send_sig(SIGPIPE, current, 0);
+	return err;
+}
+
+ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	int mss_now;
+	int err;
+	ssize_t copied;
+	long timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT);
+
+	/* Wait for a connection to finish. */
+	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
+		if((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0)
+			goto out_err;
+
+	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
+	mss_now = tcp_current_mss(sk);
+	copied = 0;
+
+	err = -EPIPE;
+	if (sk->err || (sk->shutdown & SEND_SHUTDOWN))
+		goto do_error;
+
+	while (psize > 0) {
+		struct sk_buff *skb = sk->write_queue.prev;
+		int offset, size, copy, i;
+		struct page *page;
+
+		page = pages[poffset/PAGE_SIZE];
+		offset = poffset % PAGE_SIZE;
+		size = min(psize, PAGE_SIZE-offset);
+
+		if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) {
+new_segment:
+			if (!tcp_memory_free(sk))
+				goto wait_for_sndbuf;
+
+			skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, sk->allocation);
+			if (skb == NULL)
+				goto wait_for_memory;
+
+			skb_entail(sk, tp, skb);
+			copy = mss_now;
+		}
+
+		if (copy > size)
+			copy = size;
+
+		i = skb_shinfo(skb)->nr_frags;
+		if (can_coalesce(skb, i, page, offset)) {
+			skb_shinfo(skb)->frags[i-1].size += copy;
+		} else if (i < MAX_SKB_FRAGS) {
+			get_page(page);
+			fill_page_desc(skb, i, page, offset, copy);
+		} else {
+			tcp_mark_push(tp, skb);
+			goto new_segment;
+		}
+
+		skb->len += copy;
+		skb->data_len += copy;
+		skb->ip_summed = CHECKSUM_HW;
+		tp->write_seq += copy;
+		TCP_SKB_CB(skb)->end_seq += copy;
+
+		if (!copied)
+			TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
+
+		copied += copy;
+		poffset += copy;
+		if (!(psize -= copy))
+			goto out;
+
+		if (skb->len != mss_now || (flags&MSG_OOB))
+			continue;
+
+		if (forced_push(tp)) {
+			tcp_mark_push(tp, skb);
+			__tcp_push_pending_frames(sk, tp, mss_now, 1);
+		} else if (skb == tp->send_head)
+			tcp_push_one(sk, mss_now);
+		continue;
+
+wait_for_sndbuf:
+		set_bit(SOCK_NOSPACE, &sk->socket->flags);
+wait_for_memory:
+		if (copied)
+			tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1);
+
+		if ((err = wait_for_tcp_memory(sk, &timeo)) != 0)
+			goto do_error;
+
+		mss_now = tcp_current_mss(sk);
+	}
+
+out:
+	if (copied)
+		tcp_push(sk, tp, flags, mss_now, tp->nonagle);
+	return copied;
+
+do_error:
+	if (copied)
+		goto out;
+out_err:
+	return tcp_error(sk, flags, err);
+}
+
+ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
+{
+	ssize_t res;
+	struct sock *sk = sock->sk;
+
+#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
+
+	if (!(sk->route_caps & NETIF_F_SG) || 
+	    !(sk->route_caps & TCP_ZC_CSUM_FLAGS))
+		return sock_no_sendpage(sock, page, offset, size, flags);
+
+#undef TCP_ZC_CSUM_FLAGS
+
+	lock_sock(sk);
+	TCP_CHECK_TIMER(sk);
+	res = do_tcp_sendpages(sk, &page, offset, size, flags);
+	TCP_CHECK_TIMER(sk);
+	release_sock(sk);
+	return res;
+}
+
+#define TCP_PAGE(sk)	(sk->tp_pinfo.af_tcp.sndmsg_page)
+#define TCP_OFF(sk)	(sk->tp_pinfo.af_tcp.sndmsg_off)
+
+static inline int
+tcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb,
+		 struct page *page, int off, int copy)
+{
+	int err = 0;
+	unsigned int csum;
+
+	csum = csum_and_copy_from_user(from, page_address(page)+off,
+				       copy, 0, &err);
+	if (!err) {
+		if (skb->ip_summed == CHECKSUM_NONE)
+			skb->csum = csum_block_add(skb->csum, csum, skb->len);
+		skb->len += copy;
+		skb->data_len += copy;
+		skb->truesize += copy;
+		sk->wmem_queued += copy;
+		sk->forward_alloc -= copy;
+	}
+	return err;
+}
+
+static inline int
+skb_add_data(struct sk_buff *skb, char *from, int copy)
+{
+	int err = 0;
+	unsigned int csum;
+	int off = skb->len;
+
+	csum = csum_and_copy_from_user(from, skb_put(skb, copy),
+				       copy, 0, &err);
+	if (!err) {
+		skb->csum = csum_block_add(skb->csum, csum, off);
+		return 0;
+	}
+
+	__skb_trim(skb, off);
+	return -EFAULT;
+}
+
+static inline int select_size(struct sock *sk, struct tcp_opt *tp)
+{
+	int tmp = tp->mss_cache;
+
+	if (sk->route_caps&NETIF_F_SG) {
+		int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
+
+		if (tmp >= pgbreak && tmp <= pgbreak + (MAX_SKB_FRAGS-1)*PAGE_SIZE)
+			tmp = pgbreak;
+	}
+	return tmp;
+}
 
 int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
 {
@@ -736,20 +1015,18 @@
 	int err, copied;
 	long timeo;
 
-	err = 0;
 	tp = &(sk->tp_pinfo.af_tcp);
 
 	lock_sock(sk);
 	TCP_CHECK_TIMER(sk);
 
 	flags = msg->msg_flags;
-
 	timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT);
 
 	/* Wait for a connection to finish. */
 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
 		if((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0)
-			goto out_unlock;
+			goto out_err;
 
 	/* This should be in poll */
 	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
@@ -761,6 +1038,10 @@
 	iov = msg->msg_iov;
 	copied = 0;
 
+	err = -EPIPE;
+	if (sk->err || (sk->shutdown&SEND_SHUTDOWN))
+		goto do_error;
+
 	while (--iovlen >= 0) {
 		int seglen=iov->iov_len;
 		unsigned char * from=iov->iov_base;
@@ -768,200 +1049,159 @@
 		iov++;
 
 		while (seglen > 0) {
-			int copy, tmp, queue_it;
-
-			if (err)
-				goto do_fault2;
-
-			/* Stop on errors. */
-			if (sk->err)
-				goto do_sock_err;
-
-			/* Make sure that we are established. */
-			if (sk->shutdown & SEND_SHUTDOWN)
-				goto do_shutdown;
-	
-			/* Now we need to check if we have a half
-			 * built packet we can tack some data onto.
-			 */
+			int copy;
+			
 			skb = sk->write_queue.prev;
-			if (tp->send_head &&
-			    (mss_now > skb->len)) {
-				copy = skb->len;
-				if (skb_tailroom(skb) > 0) {
-					int last_byte_was_odd = (copy % 4);
-
-					copy = mss_now - copy;
-					if(copy > skb_tailroom(skb))
-						copy = skb_tailroom(skb);
-					if(copy > seglen)
-						copy = seglen;
-					if(last_byte_was_odd) {
-						if(copy_from_user(skb_put(skb, copy),
-								  from, copy))
-							err = -EFAULT;
-						skb->csum = csum_partial(skb->data,
-									 skb->len, 0);
-					} else {
-						skb->csum =
-							csum_and_copy_from_user(
-							from, skb_put(skb, copy),
-							copy, skb->csum, &err);
-					}
-					/*
-					 * FIXME: the *_user functions should
-					 *	  return how much data was
-					 *	  copied before the fault
-					 *	  occurred and then a partial
-					 *	  packet with this data should
-					 *	  be sent.  Unfortunately
-					 *	  csum_and_copy_from_user doesn't
-					 *	  return this information.
-					 *	  ATM it might send partly zeroed
-					 *	  data in this case.
-					 */
-					tp->write_seq += copy;
-					TCP_SKB_CB(skb)->end_seq += copy;
-					from += copy;
-					copied += copy;
-					seglen -= copy;
-					if (PSH_NEEDED ||
-					    after(tp->write_seq, tp->pushed_seq+(tp->max_window>>1))) {
-						TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
-						tp->pushed_seq = tp->write_seq;
-					}
-					if (flags&MSG_OOB) {
-						tp->urg_mode = 1;
-						tp->snd_up = tp->write_seq;
-						TCP_SKB_CB(skb)->sacked |= TCPCB_URG;
-					}
-					continue;
-				} else {
-					TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
-					tp->pushed_seq = tp->write_seq;
-				}
-			}
 
-			copy = min(seglen, mss_now);
+			if (tp->send_head == NULL ||
+			    (copy = mss_now - skb->len) <= 0) {
 
-			/* Determine how large of a buffer to allocate.  */
-			tmp = MAX_TCP_HEADER + 15 + tp->mss_cache;
-			if (copy < mss_now && !(flags & MSG_OOB)) {
-				/* What is happening here is that we want to
-				 * tack on later members of the users iovec
-				 * if possible into a single frame.  When we
-				 * leave this loop our we check to see if
-				 * we can send queued frames onto the wire.
+new_segment:
+				/* Allocate new segment. If the interface is SG,
+				 * allocate skb fitting to single page.
 				 */
-				queue_it = 1;
-			} else {
-				queue_it = 0;
-			}
-
-			skb = NULL;
-			if (tcp_memory_free(sk))
-				skb = tcp_alloc_skb(sk, tmp, sk->allocation);
-			if (skb == NULL) {
-				/* If we didn't get any memory, we need to sleep. */
-				set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-				set_bit(SOCK_NOSPACE, &sk->socket->flags);
-
-				__tcp_push_pending_frames(sk, tp, mss_now, 1);
+				if (!tcp_memory_free(sk))
+					goto wait_for_sndbuf;
 
-				if (!timeo) {
-					err = -EAGAIN;
-					goto do_interrupted;
+				skb = tcp_alloc_pskb(sk, select_size(sk, tp), 0, sk->allocation);
+				if (skb == NULL)
+					goto wait_for_memory;
+
+				skb_entail(sk, tp, skb);
+				copy = mss_now;
+			}
+
+			/* Try to append data to the end of skb. */
+			if (copy > seglen)
+				copy = seglen;
+
+			/* Where to copy to? */
+			if (skb_tailroom(skb) > 0) {
+				/* We have some space in skb head. Superb! */
+				if (copy > skb_tailroom(skb))
+					copy = skb_tailroom(skb);
+				if ((err = skb_add_data(skb, from, copy)) != 0)
+					goto do_fault;
+			} else {
+				int merge = 0;
+				int i = skb_shinfo(skb)->nr_frags;
+				struct page *page = TCP_PAGE(sk);
+				int off = TCP_OFF(sk);
+
+				if (can_coalesce(skb, i, page, off) && off != PAGE_SIZE) {
+					/* We can extend the last page fragment. */
+					merge = 1;
+				} else if (i == MAX_SKB_FRAGS ||
+					   (i == 0 && !(sk->route_caps&NETIF_F_SG))) {
+					/* Need to add new fragment and cannot
+					 * do this because interface is non-SG,
+					 * or because all the page slots are busy.
+					 */
+					tcp_mark_push(tp, skb);
+					goto new_segment;
+				} else if (page) {
+					/* If page is cached, align
+					 * offset to L1 cache boundary
+					 */
+					off = (off+L1_CACHE_BYTES-1)&~(L1_CACHE_BYTES-1);
+					if (off == PAGE_SIZE) {
+						put_page(page);
+						TCP_PAGE(sk) = page = NULL;
+					}
 				}
-				if (signal_pending(current)) {
-					err = sock_intr_errno(timeo);
-					goto do_interrupted;
+
+				if (!page) {
+					/* Allocate new cache page. */
+					if (!(page=tcp_alloc_page(sk)))
+						goto wait_for_memory;
+					off = 0;
 				}
-				timeo = wait_for_tcp_memory(sk, timeo);
 
-				/* If SACK's were formed or PMTU events happened,
-				 * we must find out about it.
-				 */
-				mss_now = tcp_current_mss(sk);
-				continue;
-			}
+				if (copy > PAGE_SIZE-off)
+					copy = PAGE_SIZE-off;
 
-			seglen -= copy;
+				/* Time to copy data. We are close to the end! */
+				err = tcp_copy_to_page(sk, from, skb, page, off, copy);
+				if (err)
+					goto do_error;
+
+				/* Update the skb. */
+				if (merge) {
+					skb_shinfo(skb)->frags[i-1].size += copy;
+				} else {
+					fill_page_desc(skb, i, page, off, copy);
+					if (TCP_PAGE(sk)) {
+						get_page(page);
+					} else if (off + copy < PAGE_SIZE) {
+						get_page(page);
+						TCP_PAGE(sk) = page;
+					}
+				}
 
-			/* Prepare control bits for TCP header creation engine. */
-			if (PSH_NEEDED ||
-			    after(tp->write_seq+copy, tp->pushed_seq+(tp->max_window>>1))) {
-				TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK|TCPCB_FLAG_PSH;
-				tp->pushed_seq = tp->write_seq + copy;
-			} else {
-				TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
-			}
-			TCP_SKB_CB(skb)->sacked = 0;
-			if (flags & MSG_OOB) {
-				TCP_SKB_CB(skb)->sacked |= TCPCB_URG;
-				tp->urg_mode = 1;
-				tp->snd_up = tp->write_seq + copy;
+				TCP_OFF(sk) = off+copy;
 			}
 
-			/* TCP data bytes are SKB_PUT() on top, later
-			 * TCP+IP+DEV headers are SKB_PUSH()'d beneath.
-			 * Reserve header space and checksum the data.
-			 */
-			skb_reserve(skb, MAX_TCP_HEADER);
-			skb->csum = csum_and_copy_from_user(from,
-					skb_put(skb, copy), copy, 0, &err);
+			if (!copied)
+				TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
 
-			if (err)
-				goto do_fault;
+			tp->write_seq += copy;
+			TCP_SKB_CB(skb)->end_seq += copy;
 
 			from += copy;
 			copied += copy;
+			seglen -= copy;
 
-			TCP_SKB_CB(skb)->seq = tp->write_seq;
-			TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + copy;
+			if (skb->len != mss_now || (flags&MSG_OOB))
+				continue;
+
+			if (forced_push(tp)) {
+				tcp_mark_push(tp, skb);
+				__tcp_push_pending_frames(sk, tp, mss_now, 1);
+			} else if (skb == tp->send_head)
+				tcp_push_one(sk, mss_now);
+			continue;
+
+wait_for_sndbuf:
+			set_bit(SOCK_NOSPACE, &sk->socket->flags);
+wait_for_memory:
+			if (copied)
+				tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1);
+
+			if ((err = wait_for_tcp_memory(sk, &timeo)) != 0)
+				goto do_error;
 
-			/* This advances tp->write_seq for us. */
-			tcp_send_skb(sk, skb, queue_it, mss_now);
+			mss_now = tcp_current_mss(sk);
 		}
 	}
-	err = copied;
+
 out:
-	__tcp_push_pending_frames(sk, tp, mss_now, tp->nonagle);
-out_unlock:
+	if (copied)
+		tcp_push(sk, tp, flags, mss_now, tp->nonagle);
 	TCP_CHECK_TIMER(sk);
 	release_sock(sk);
-	return err;
+	return copied;
 
-do_sock_err:
-	if (copied)
-		err = copied;
-	else
-		err = sock_error(sk);
-	goto out;
-do_shutdown:
-	if (copied)
-		err = copied;
-	else {
-		if (!(flags&MSG_NOSIGNAL))
-			send_sig(SIGPIPE, current, 0);
-		err = -EPIPE;
-	}
-	goto out;
-do_interrupted:
-	if (copied)
-		err = copied;
-	goto out_unlock;
 do_fault:
-	__kfree_skb(skb);
-do_fault2:
+	if (skb->len==0) {
+		if (tp->send_head == skb) {
+			tp->send_head = skb->prev;
+			if (tp->send_head == (struct sk_buff*)&sk->write_queue)
+				tp->send_head = NULL;
+		}
+		__skb_unlink(skb, skb->list);
+		tcp_free_skb(sk, skb);
+	}
+
+do_error:
 	if (copied)
-		err = copied;
-	else
-		err = -EFAULT;
-	goto out;
+		goto out;
+out_err:
+	err = tcp_error(sk, flags, err);
+	TCP_CHECK_TIMER(sk);
+	release_sock(sk);
+	return err;
 }
 
-#undef PSH_NEEDED
-
 /*
  *	Handle reading urgent data. BSD has very simple semantics for
  *	this, no blocking and very strange errors 8)
@@ -991,7 +1231,7 @@
 		msg->msg_flags|=MSG_OOB;
 
 		if(len>0) {
-			if (!(flags & MSG_PEEK))
+			if (!(flags & MSG_PEEK) && !(flags & MSG_TRUNC))
 				err = memcpy_toiovec(msg->msg_iov, &c, 1);
 			len = 1;
 		} else
@@ -1033,17 +1273,13 @@
 static void cleanup_rbuf(struct sock *sk, int copied)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct sk_buff *skb;
 	int time_to_ack = 0;
 
-	/* NOTE! The socket must be locked, so that we don't get
-	 * a messed-up receive queue.
-	 */
-	while ((skb=skb_peek(&sk->receive_queue)) != NULL) {
-		if (!skb->used)
-			break;
-		tcp_eat_skb(sk, skb);
-	}
+#if TCP_DEBUG
+	struct sk_buff *skb = skb_peek(&sk->receive_queue);
+
+	BUG_TRAP(skb==NULL || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq));
+#endif
 
 	if (tcp_ack_scheduled(tp)) {
 		   /* Delayed ACKs frequently hit locked sockets during bulk receive. */
@@ -1219,8 +1455,7 @@
 				goto found_ok_skb;
 			if (skb->h.th->fin)
 				goto found_fin_ok;
-			if (!(flags & MSG_PEEK))
-				skb->used = 1;
+			BUG_TRAP(flags&MSG_PEEK);
 			skb = skb->next;
 		} while (skb != (struct sk_buff *)&sk->receive_queue);
 
@@ -1233,7 +1468,8 @@
 			if (sk->err ||
 			    sk->state == TCP_CLOSE ||
 			    (sk->shutdown & RCV_SHUTDOWN) ||
-			    !timeo)
+			    !timeo ||
+			    (flags & MSG_PEEK))
 				break;
 		} else {
 			if (sk->done)
@@ -1358,15 +1594,16 @@
 						++*seq;
 						offset++;
 						used--;
+						if (!used)
+							goto skip_copy;
 					}
 				} else
 					used = urg_offset;
 			}
 		}
 
-		err = 0;
 		if (!(flags&MSG_TRUNC)) {
-			err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
+			err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used);
 			if (err) {
 				/* Exception. Bailout! */
 				if (!copied)
@@ -1379,37 +1616,25 @@
 		copied += used;
 		len -= used;
 
-		if (after(tp->copied_seq,tp->urg_seq)) {
+skip_copy:
+		if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) {
 			tp->urg_data = 0;
-			if (skb_queue_len(&tp->out_of_order_queue) == 0
-#ifdef TCP_FORMAL_WINDOW
-			    && tcp_receive_window(tp)
-#endif
-			    ) {
-				tcp_fast_path_on(tp);
-			}
+			tcp_fast_path_check(sk, tp);
 		}
 		if (used + offset < skb->len)
 			continue;
 
-		/*	Process the FIN. We may also need to handle PSH
-		 *	here and make it break out of MSG_WAITALL.
-		 */
 		if (skb->h.th->fin)
 			goto found_fin_ok;
-		if (flags & MSG_PEEK)
-			continue;
-		skb->used = 1;
-		tcp_eat_skb(sk, skb);
+		if (!(flags & MSG_PEEK))
+			tcp_eat_skb(sk, skb);
 		continue;
 
 	found_fin_ok:
+		/* Process the FIN. */
 		++*seq;
-		if (flags & MSG_PEEK)
-			break;
-
-		/* All is done. */
-		skb->used = 1;
+		if (!(flags & MSG_PEEK))
+			tcp_eat_skb(sk, skb);
 		break;
 	} while (len > 0);
 
@@ -1556,7 +1781,7 @@
 	/* It cannot be in hash table! */
 	BUG_TRAP(sk->pprev==NULL);
 
-	/* It it has not 0 sk->num, it must be bound */
+	/* If it has not 0 sk->num, it must be bound */
 	BUG_TRAP(!sk->num || sk->prev!=NULL);
 
 #ifdef TCP_DEBUG
@@ -2041,7 +2266,7 @@
 		tp->defer_accept = 0;
 		if (val > 0) {
 			/* Translate value in seconds to number of retransmits */
-			while (val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept))
+			while (tp->defer_accept < 32 && val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept))
 				tp->defer_accept++;
 			tp->defer_accept++;
 		}
@@ -2060,6 +2285,21 @@
 		}
 		break;
 
+	case TCP_QUICKACK:
+		if (!val) {
+			tp->ack.pingpong = 1;
+		} else {
+			tp->ack.pingpong = 0;
+			if ((1<<sk->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT) &&
+			    tcp_ack_scheduled(tp)) {
+				tp->ack.pending |= TCP_ACK_PUSHED;
+				cleanup_rbuf(sk, 1);
+				if (!(val & 1))
+					tp->ack.pingpong = 1;
+			}
+		}
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -2082,6 +2322,9 @@
 		return -EFAULT;
 
 	len = min(len, sizeof(int));
+	
+	if(len < 0)
+		return -EINVAL;
 
 	switch(optname) {
 	case TCP_MAXSEG:
@@ -2180,6 +2423,9 @@
 			return -EFAULT;
 		return 0;
 	}
+	case TCP_QUICKACK:
+		val = !tp->ack.pingpong;
+		break;
 	default:
 		return -ENOPROTOOPT;
 	};
@@ -2230,7 +2476,10 @@
 	 *
 	 * The methodology is similar to that of the buffer cache.
 	 */
-	goal = num_physpages >> (23 - PAGE_SHIFT);
+	if (num_physpages >= (128 * 1024))
+		goal = num_physpages >> (21 - PAGE_SHIFT);
+	else
+		goal = num_physpages >> (23 - PAGE_SHIFT);
 
 	for(order = 0; (1UL << order) < goal; order++)
 		;
@@ -2284,9 +2533,9 @@
 	}
 	tcp_port_rover = sysctl_local_port_range[0] - 1;
 
-	sysctl_tcp_mem[0] = 64<<order;
-	sysctl_tcp_mem[1] = 200<<order;
-	sysctl_tcp_mem[2] = 256<<order;
+	sysctl_tcp_mem[0] = 768<<order;
+	sysctl_tcp_mem[1] = 1024<<order;
+	sysctl_tcp_mem[2] = 1536<<order;
 	if (sysctl_tcp_mem[2] - sysctl_tcp_mem[1] > 512)
 		sysctl_tcp_mem[1] = sysctl_tcp_mem[2] - 512;
 	if (sysctl_tcp_mem[1] - sysctl_tcp_mem[0] > 512)
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.4.3/linux/net/ipv4/tcp_input.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/tcp_input.c	Wed Apr 25 14:57:39 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.205 2000/12/13 18:31:48 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.228 2001/04/20 20:46:19 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -137,7 +137,7 @@
 		 *
 		 * "len" is invariant segment length, including TCP header.
 		 */
-		len = skb->tail - skb->h.raw;
+		len += skb->data - skb->h.raw;
 		if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) ||
 		    /* If PSH is not set, packet should be
 		     * full sized, provided peer TCP is not badly broken.
@@ -378,7 +378,8 @@
 		/* The _first_ data packet received, initialize
 		 * delayed ACK engine.
 		 */
-		tcp_enter_quickack_mode(tp);
+		tcp_incr_quickack(tp);
+		tp->ack.ato = TCP_ATO_MIN;
 	} else {
 		int m = now - tp->ack.lrcvtime;
 
@@ -510,7 +511,7 @@
 }
 
 /* Save metrics learned by this TCP session.
-   This function is called only, when TCP finishes sucessfully
+   This function is called only, when TCP finishes successfully
    i.e. when it enters TIME-WAIT or goes from LAST-ACK to CLOSE.
  */
 void tcp_update_metrics(struct sock *sk)
@@ -1016,7 +1017,7 @@
 			tp->fackets_out = cnt;
 		}
 	}
-	tp->left_out = tp->sacked_out + tp->lost_out;
+	tcp_sync_left_out(tp);
 
 	tp->reordering = min(tp->reordering, sysctl_tcp_reordering);
 	tp->ca_state = TCP_CA_Loss;
@@ -1052,6 +1053,15 @@
 	return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out;
 }
 
+static inline int tcp_skb_timedout(struct tcp_opt *tp, struct sk_buff *skb)
+{
+	return (tcp_time_stamp - TCP_SKB_CB(skb)->when > tp->rto);
+}
+
+static inline int tcp_head_timedout(struct sock *sk, struct tcp_opt *tp)
+{
+	return tp->packets_out && tcp_skb_timedout(tp, skb_peek(&sk->write_queue));
+}
 
 /* Linux NewReno/SACK/FACK/ECN state machine.
  * --------------------------------------
@@ -1157,7 +1167,13 @@
 	if (tcp_fackets_out(tp) > tp->reordering)
 		return 1;
 
-	/* Trick#3: It is still not OK... But will it be useful to delay
+	/* Trick#3 : when we use RFC2988 timer restart, fast
+	 * retransmit can be triggered by timeout of queue head.
+	 */
+	if (tcp_head_timedout(sk, tp))
+		return 1;
+
+	/* Trick#4: It is still not OK... But will it be useful to delay
 	 * recovery more?
 	 */
 	if (tp->packets_out <= tp->reordering &&
@@ -1178,8 +1194,10 @@
  */
 static void tcp_check_reno_reordering(struct tcp_opt *tp, int addend)
 {
-	if (tp->sacked_out + 1 > tp->packets_out) {
-		tp->sacked_out = tp->packets_out ? tp->packets_out - 1 : 0;
+	int holes = min(max(tp->lost_out, 1), tp->packets_out);
+
+	if (tp->sacked_out + holes > tp->packets_out) {
+		tp->sacked_out = tp->packets_out - holes;
 		tcp_update_reordering(tp, tp->packets_out+addend, 0);
 	}
 }
@@ -1190,7 +1208,7 @@
 {
 	++tp->sacked_out;
 	tcp_check_reno_reordering(tp, 0);
-	tp->left_out = tp->sacked_out + tp->lost_out;
+	tcp_sync_left_out(tp);
 }
 
 /* Account for ACK, ACKing some data in Reno Recovery phase. */
@@ -1198,17 +1216,14 @@
 static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_opt *tp, int acked)
 {
 	if (acked > 0) {
-		/* One ACK eated lost packet. Must eat! */
-		BUG_TRAP(tp->lost_out == 0);
-
-		/* The rest eat duplicate ACKs. */
+		/* One ACK acked hole. The rest eat duplicate ACKs. */
 		if (acked-1 >= tp->sacked_out)
 			tp->sacked_out = 0;
 		else
 			tp->sacked_out -= acked-1;
 	}
 	tcp_check_reno_reordering(tp, acked);
-	tp->left_out = tp->sacked_out + tp->lost_out;
+	tcp_sync_left_out(tp);
 }
 
 static inline void tcp_reset_reno_sack(struct tcp_opt *tp)
@@ -1234,7 +1249,7 @@
 			tp->lost_out++;
 		}
 	}
-	tp->left_out = tp->sacked_out + tp->lost_out;
+	tcp_sync_left_out(tp);
 }
 
 /* Account newly detected lost packet(s) */
@@ -1249,6 +1264,24 @@
 	} else {
 		tcp_mark_head_lost(sk, tp, 1, tp->high_seq);
 	}
+
+	/* New heuristics: it is possible only after we switched
+	 * to restart timer each time when something is ACKed.
+	 * Hence, we can detect timed out packets during fast
+	 * retransmit without falling to slow start.
+	 */
+	if (tcp_head_timedout(sk, tp)) {
+		struct sk_buff *skb;
+
+		for_retrans_queue(skb, sk, tp) {
+			if (tcp_skb_timedout(tp, skb) &&
+			    !(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
+				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+				tp->lost_out++;
+			}
+		}
+		tcp_sync_left_out(tp);
+	}
 }
 
 /* CWND moderation, preventing bursts due to too big ACKs
@@ -1490,7 +1523,7 @@
 	}
 
 	/* D. Synchronize left_out to current state. */
-	tp->left_out = tp->sacked_out + tp->lost_out;
+	tcp_sync_left_out(tp);
 
 	/* E. Check state exit conditions. State can be terminated
 	 *    when high_seq is ACKed. */
@@ -1516,8 +1549,13 @@
 
 		case TCP_CA_Disorder:
 			tcp_try_undo_dsack(sk, tp);
-			tp->undo_marker = 0;
-			tp->ca_state = TCP_CA_Open;
+			if (!tp->undo_marker ||
+			    /* For SACK case do not Open to allow to undo
+			     * catching for all duplicate ACKs. */
+			    IsReno(tp) || tp->snd_una != tp->high_seq) {
+				tp->undo_marker = 0;
+				tp->ca_state = TCP_CA_Open;
+			}
 			break;
 
 		case TCP_CA_Recovery:
@@ -1544,8 +1582,8 @@
 		}
 		break;
 	case TCP_CA_Loss:
-		if (flag & FLAG_ACKED)
-			tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+		if (flag&FLAG_DATA_ACKED)
+			tp->retransmits = 0;
 		if (!tcp_try_undo_loss(sk, tp)) {
 			tcp_moderate_cwnd(tp);
 			tcp_xmit_retransmit_queue(sk);
@@ -1593,7 +1631,7 @@
 		tp->ca_state = TCP_CA_Recovery;
 	}
 
-	if (is_dupack)
+	if (is_dupack || tcp_head_timedout(sk, tp))
 		tcp_update_scoreboard(sk, tp);
 	tcp_cwnd_down(tp);
 	tcp_xmit_retransmit_queue(sk);
@@ -1613,16 +1651,18 @@
 	 *
 	 * See draft-ietf-tcplw-high-performance-00, section 3.3.
 	 * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
+	 *
+	 * Changed: reset backoff as soon as we see the first valid sample.
+	 * If we do not, we get strongly overstimated rto. With timestamps
+	 * samples are accepted even from very old segments: f.e., when rtt=1
+	 * increases to 8, we retransmit 5 times and after 8 seconds delayed
+	 * answer arrives rto becomes 120 seconds! If at least one of segments
+	 * in window is lost... Voila.	 			--ANK (010210)
 	 */
 	seq_rtt = tcp_time_stamp - tp->rcv_tsecr;
 	tcp_rtt_estimator(tp, seq_rtt);
 	tcp_set_rto(tp);
-	if (tp->backoff) {
-		if (!tp->retransmits || !(flag & FLAG_RETRANS_DATA_ACKED))
-			tp->backoff = 0;
-		else
-			tp->rto <<= tp->backoff;
-	}
+	tp->backoff = 0;
 	tcp_bound_rto(tp);
 }
 
@@ -1642,15 +1682,7 @@
 
 	tcp_rtt_estimator(tp, seq_rtt);
 	tcp_set_rto(tp);
-	if (tp->backoff) {
-		/* To relax it? We have valid sample as soon as we are
-		 * here. Why not to clear backoff?
-		 */
-		if (!tp->retransmits)
-			tp->backoff = 0;
-		else
-			tp->rto <<= tp->backoff;
-	}
+	tp->backoff = 0;
 	tcp_bound_rto(tp);
 }
 
@@ -1684,15 +1716,11 @@
 		} else
 			tp->snd_cwnd_cnt++;
         }
+	tp->snd_cwnd_stamp = tcp_time_stamp;
 }
 
 /* Restart timer after forward progress on connection.
- * RFC2988 recommends (and BSD does) to restart timer to now+rto,
- * which is certainly wrong and effectively means that
- * rto includes one more _full_ rtt.
- *
- * For details see:
- * 	ftp://ftp.inr.ac.ru:/ip-routing/README.rto
+ * RFC2988 recommends to restart timer to now+rto.
  */
 
 static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
@@ -1700,12 +1728,7 @@
 	if (tp->packets_out==0) {
 		tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS);
 	} else {
-		struct sk_buff *skb = skb_peek(&sk->write_queue);
-		__u32 when = tp->rto + tp->rttvar - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
-
-		if ((__s32)when < (__s32)tp->rttvar)
-			when = tp->rttvar;
-		tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, min(when, TCP_RTO_MAX));
+		tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
 	}
 }
 
@@ -1857,12 +1880,7 @@
 			/* Note, it is the only place, where
 			 * fast path is recovered for sending TCP.
 			 */
-			if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
-#ifdef TCP_FORMAL_WINDOW
-			    tcp_receive_window(tp) &&
-#endif
-			    !tp->urg_data)
-				tcp_fast_path_on(tp);
+			tcp_fast_path_check(sk, tp);
 
 			if (nwin > tp->max_window) {
 				tp->max_window = nwin;
@@ -1873,16 +1891,6 @@
 
 	tp->snd_una = ack;
 
-#ifdef TCP_DEBUG
-	if (before(tp->snd_una + tp->snd_wnd, tp->snd_nxt)) {
-		if (tp->snd_nxt-(tp->snd_una + tp->snd_wnd) >= (1<<tp->snd_wscale)
-		    && net_ratelimit())
-			printk(KERN_DEBUG "TCP: peer %u.%u.%u.%u:%u/%u shrinks window %u:%u:%u. Bad, what else can I say?\n",
-			       NIPQUAD(sk->daddr), htons(sk->dport), sk->num,
-			       tp->snd_una, tp->snd_wnd, tp->snd_nxt);
-	}
-#endif
-
 	return flag;
 }
 
@@ -2224,7 +2232,6 @@
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-	tp->fin_seq = TCP_SKB_CB(skb)->end_seq;
 	tcp_schedule_ack(tp);
 
 	sk->shutdown |= RCV_SHUTDOWN;
@@ -2506,10 +2513,27 @@
 	}
 }
 
+static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb)
+{
+	return (int)skb->truesize <= sk->forward_alloc ||
+		tcp_mem_schedule(sk, skb->truesize, 1);
+}
+
+static int tcp_prune_queue(struct sock *sk);
+
 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 {
+	struct tcphdr *th = skb->h.th;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int eaten = 0;
+	int eaten = -1;
+
+	th = skb->h.th;
+	__skb_pull(skb, th->doff*4);
+
+        if (skb->len == 0 && !th->fin)
+		goto drop;
+
+	TCP_ECN_accept_cwr(tp, skb);
 
 	if (tp->dsack) {
 		tp->dsack = 0;
@@ -2535,26 +2559,32 @@
 			__set_current_state(TASK_RUNNING);
 
 			local_bh_enable();
-			if (memcpy_toiovec(tp->ucopy.iov, skb->data, chunk)) {
+			if (skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
 				sk->err = EFAULT;
 				sk->error_report(sk);
 			}
 			local_bh_disable();
 			tp->ucopy.len -= chunk;
 			tp->copied_seq += chunk;
-			eaten = (chunk == skb->len && !skb->h.th->fin);
+			eaten = (chunk == skb->len && !th->fin);
 		}
 
-		if (!eaten) {
+		if (eaten <= 0) {
 queue_and_out:
+			if (eaten < 0 &&
+			    (atomic_read(&sk->rmem_alloc) > sk->rcvbuf ||
+			     !tcp_rmem_schedule(sk, skb))) {
+				if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb))
+					goto drop;
+			}
 			tcp_set_owner_r(skb, sk);
 			__skb_queue_tail(&sk->receive_queue, skb);
 		}
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 		if(skb->len)
 			tcp_event_data_recv(sk, tp, skb);
-		if(skb->h.th->fin)
-			tcp_fin(skb, sk, skb->h.th);
+		if(th->fin)
+			tcp_fin(skb, sk, th);
 
 		if (skb_queue_len(&tp->out_of_order_queue)) {
 			tcp_ofo_queue(sk);
@@ -2569,15 +2599,9 @@
 		if(tp->num_sacks)
 			tcp_sack_remove(tp);
 
-		/* Turn on fast path. */ 
-		if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
-#ifdef TCP_FORMAL_WINDOW
-		    tcp_receive_window(tp) &&
-#endif
-		    !tp->urg_data)
-			tcp_fast_path_on(tp);
+		tcp_fast_path_check(sk, tp);
 
-		if (eaten) {
+		if (eaten > 0) {
 			__kfree_skb(skb);
 		} else if (!sk->dead)
 			sk->data_ready(sk, 0);
@@ -2592,17 +2616,12 @@
 
 out_of_window:
 		tcp_schedule_ack(tp);
+drop:
 		__kfree_skb(skb);
 		return;
 	}
 
-	/* 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.
-	 */
+	/* Out of window. F.e. zero window probe. */
 	if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt+tcp_receive_window(tp)))
 		goto out_of_window;
 
@@ -2626,6 +2645,12 @@
 
 	TCP_ECN_check_ce(tp, skb);
 
+	if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf ||
+	    !tcp_rmem_schedule(sk, skb)) {
+		if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb))
+			goto drop;
+	}
+
 	/* Disable header prediction. */
 	tp->pred_flags = 0;
 	tcp_schedule_ack(tp);
@@ -2704,52 +2729,142 @@
 	}
 }
 
-
-static void tcp_collapse_queue(struct sock *sk, struct sk_buff_head *q)
+/* Collapse contiguous sequence of skbs head..tail with
+ * sequence numbers start..end.
+ * Segments with FIN/SYN are not collapsed (only because this
+ * simplifies code)
+ */
+static void
+tcp_collapse(struct sock *sk, struct sk_buff *head,
+	     struct sk_buff *tail, u32 start, u32 end)
 {
-	struct sk_buff *skb = skb_peek(q);
-	struct sk_buff *skb_next;
+	struct sk_buff *skb;
 
-	while (skb &&
-	       skb != (struct sk_buff *)q &&
-	       (skb_next = skb->next) != (struct sk_buff *)q) {
-		struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
-		struct tcp_skb_cb *scb_next = TCP_SKB_CB(skb_next);
-
-		if (scb->end_seq == scb_next->seq &&
-		    skb_tailroom(skb) >= skb_next->len &&
-#define TCP_DONT_COLLAPSE (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN)
-		    !(tcp_flag_word(skb->h.th)&TCP_DONT_COLLAPSE) &&
-		    !(tcp_flag_word(skb_next->h.th)&TCP_DONT_COLLAPSE)) {
-			/* OK to collapse two skbs to one */
-			memcpy(skb_put(skb, skb_next->len), skb_next->data, skb_next->len);
-			__skb_unlink(skb_next, skb_next->list);
-			scb->end_seq = scb_next->end_seq;
-			__kfree_skb(skb_next);
+	/* First, check that queue is collapsable and find
+	 * the point where collapsing can be useful. */
+	for (skb = head; skb != tail; ) {
+		/* No new bits? It is possible on ofo queue. */
+		if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
+			struct sk_buff *next = skb->next;
+			__skb_unlink(skb, skb->list);
+			__kfree_skb(skb);
 			NET_INC_STATS_BH(TCPRcvCollapsed);
-		} else {
-			/* Lots of spare tailroom, reallocate this skb to trim it. */
-			if (tcp_win_from_space(skb->truesize) > skb->len &&
-			    skb_tailroom(skb) > sizeof(struct sk_buff) + 16) {
-				struct sk_buff *nskb;
-
-				nskb = skb_copy_expand(skb, skb_headroom(skb), 0, GFP_ATOMIC);
-				if (nskb) {
-					tcp_set_owner_r(nskb, sk);
-					memcpy(nskb->data-skb_headroom(skb),
-					       skb->data-skb_headroom(skb),
-					       skb_headroom(skb));
-					__skb_append(skb, nskb);
-					__skb_unlink(skb, skb->list);
-					__kfree_skb(skb);
-				}
+			skb = next;
+			continue;
+		}
+
+		/* The first skb to collapse is:
+		 * - not SYN/FIN and
+		 * - bloated or contains data before "start" or
+		 *   overlaps to the next one.
+		 */
+		if (!skb->h.th->syn && !skb->h.th->fin &&
+		    (tcp_win_from_space(skb->truesize) > skb->len ||
+		     before(TCP_SKB_CB(skb)->seq, start) ||
+		     (skb->next != tail &&
+		      TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq)))
+			break;
+
+		/* Decided to skip this, advance start seq. */
+		start = TCP_SKB_CB(skb)->end_seq;
+		skb = skb->next;
+	}
+	if (skb == tail || skb->h.th->syn || skb->h.th->fin)
+		return;
+
+	while (before(start, end)) {
+		struct sk_buff *nskb;
+		int header = skb_headroom(skb);
+		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
+			    sizeof(struct skb_shared_info) - header - 31)&~15;
+
+		/* Too big header? This can happen with IPv6. */
+		if (copy < 0)
+			return;
+		if (end-start < copy)
+			copy = end-start;
+		nskb = alloc_skb(copy+header, GFP_ATOMIC);
+		if (!nskb)
+			return;
+		skb_reserve(nskb, header);
+		memcpy(nskb->head, skb->head, header);
+		nskb->nh.raw = nskb->head + (skb->nh.raw-skb->head);
+		nskb->h.raw = nskb->head + (skb->h.raw-skb->head);
+		nskb->mac.raw = nskb->head + (skb->mac.raw-skb->head);
+		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
+		TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
+		__skb_insert(nskb, skb->prev, skb, skb->list);
+		tcp_set_owner_r(nskb, sk);
+
+		/* Copy data, releasing collapsed skbs. */
+		while (copy > 0) {
+			int offset = start - TCP_SKB_CB(skb)->seq;
+			int size = TCP_SKB_CB(skb)->end_seq - start;
+
+			if (offset < 0) BUG();
+			if (size > 0) {
+				size = min(copy, size);
+				if (skb_copy_bits(skb, offset, skb_put(nskb, size), size))
+					BUG();
+				TCP_SKB_CB(nskb)->end_seq += size;
+				copy -= size;
+				start += size;
+			}
+			if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
+				struct sk_buff *next = skb->next;
+				__skb_unlink(skb, skb->list);
+				__kfree_skb(skb);
+				NET_INC_STATS_BH(TCPRcvCollapsed);
+				skb = next;
+				if (skb == tail || skb->h.th->syn || skb->h.th->fin)
+					return;
 			}
-			skb = skb_next;
 		}
 	}
 }
 
-/* Clean the out_of_order queue if we can, trying to get
+/* Collapse ofo queue. Algorithm: select contiguous sequence of skbs
+ * and tcp_collapse() them until all the queue is collapsed.
+ */
+static void tcp_collapse_ofo_queue(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct sk_buff *skb = skb_peek(&tp->out_of_order_queue);
+	struct sk_buff *head;
+	u32 start, end;
+
+	if (skb == NULL)
+		return;
+
+	start = TCP_SKB_CB(skb)->seq;
+	end = TCP_SKB_CB(skb)->end_seq;
+	head = skb;
+
+	for (;;) {
+		skb = skb->next;
+
+		/* Segment is terminated when we see gap or when
+		 * we are at the end of all the queue. */
+		if (skb == (struct sk_buff *)&tp->out_of_order_queue ||
+		    after(TCP_SKB_CB(skb)->seq, end) ||
+		    before(TCP_SKB_CB(skb)->end_seq, start)) {
+			tcp_collapse(sk, head, skb, start, end);
+			head = skb;
+			if (skb == (struct sk_buff *)&tp->out_of_order_queue)
+				break;
+			/* Start new segment */
+			start = TCP_SKB_CB(skb)->seq;
+			end = TCP_SKB_CB(skb)->end_seq;
+		} else {
+			if (before(TCP_SKB_CB(skb)->seq, start))
+				start = TCP_SKB_CB(skb)->seq;
+			if (after(TCP_SKB_CB(skb)->end_seq, end))
+				end = TCP_SKB_CB(skb)->end_seq;
+		}
+	}
+}
+
+/* Reduce allocated memory if we can, trying to get
  * the socket within its memory limits again.
  *
  * Return less than zero if we should start dropping frames
@@ -2769,8 +2884,10 @@
 	else if (tcp_memory_pressure)
 		tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss);
 
-	tcp_collapse_queue(sk, &sk->receive_queue);
-	tcp_collapse_queue(sk, &tp->out_of_order_queue);
+	tcp_collapse_ofo_queue(sk);
+	tcp_collapse(sk, sk->receive_queue.next,
+		     (struct sk_buff*)&sk->receive_queue,
+		     tp->copied_seq, tp->rcv_nxt);
 	tcp_mem_reclaim(sk);
 
 	if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf)
@@ -2804,59 +2921,10 @@
 	NET_INC_STATS_BH(RcvPruned);
 
 	/* Massive buffer overcommit. */
+	tp->pred_flags = 0;
 	return -1;
 }
 
-static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb)
-{
-	return (int)skb->truesize <= sk->forward_alloc ||
-		tcp_mem_schedule(sk, skb->truesize, 1);
-}
-
-/*
- *	This routine handles the data.  If there is room in the buffer,
- *	it will be have already been moved into it.  If there is no
- *	room, then we will just have to discard the packet.
- */
-
-static void tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
-{
-	struct tcphdr *th;
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-
-	th = skb->h.th;
-	skb_pull(skb, th->doff*4);
-	skb_trim(skb, len - (th->doff*4));
-
-        if (skb->len == 0 && !th->fin)
-		goto drop;
-
-	TCP_ECN_accept_cwr(tp, skb);
-
-	/* 
-	 *	If our receive queue has grown past its limits shrink it.
-	 *	Make sure to do this before moving rcv_nxt, otherwise
-	 *	data might be acked for that we don't have enough room.
-	 */
-	if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf ||
-	    !tcp_rmem_schedule(sk, skb)) {
-		if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb))
-			goto drop;
-	}
-
-	tcp_data_queue(sk, skb);
-
-#ifdef TCP_DEBUG
-	if (before(tp->rcv_nxt, tp->copied_seq)) {
-		printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n");
-		tp->rcv_nxt = tp->copied_seq;
-	}
-#endif
-	return;
-
-drop:
-	__kfree_skb(skb);
-}
 
 /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto.
  * As additional protections, we do not touch cwnd in retransmission phases,
@@ -2902,22 +2970,7 @@
 		tp->snd_cwnd_stamp = tcp_time_stamp;
 	}
 
-	/* Wakeup users. */
-	if (tcp_wspace(sk) >= tcp_min_write_space(sk)) {
-		struct socket *sock = sk->socket;
-
-		clear_bit(SOCK_NOSPACE, &sock->flags);
-
-		if (sk->sleep && waitqueue_active(sk->sleep))
-			wake_up_interruptible(sk->sleep);
-
-		if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN))
-			sock_wake_async(sock, 2, POLL_OUT);
-
-		/* Satisfy those who hook write_space() callback. */
-		if (sk->write_space != tcp_write_space)
-			sk->write_space(sk);
-	}
+	sk->write_space(sk);
 }
 
 static inline void tcp_check_space(struct sock *sk)
@@ -2937,7 +2990,7 @@
 
 	if (after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) ||
 	    tcp_packets_in_flight(tp) >= tp->snd_cwnd ||
-	    tcp_write_xmit(sk))
+	    tcp_write_xmit(sk, tp->nonagle))
 		tcp_check_probe_timer(sk, tp);
 }
 
@@ -3009,6 +3062,19 @@
 	if (after(tp->copied_seq, ptr))
 		return;
 
+	/* Do not replay urg ptr.
+	 *
+	 * NOTE: interesting situation not covered by specs.
+	 * Misbehaving sender may send urg ptr, pointing to segment,
+	 * which we already have in ofo queue. We are not able to fetch
+	 * such data and will stay in TCP_URG_NOTYET until will be eaten
+	 * by recvmsg(). Seems, we are not obliged to handle such wicked
+	 * situations. But it is worth to think about possibility of some
+	 * DoSes using some hypothetical application level deadlock.
+	 */
+	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;
@@ -3027,9 +3093,27 @@
 	 * tp->copied_seq since we would read the last urgent byte again
 	 * 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 */
+	 *
+	 * NOTE. Double Dutch. Rendering to plain English: author of comment
+	 * above did something sort of 	send("A", MSG_OOB); send("B", MSG_OOB);
+	 * and expect that both A and B disappear from stream. This is _wrong_.
+	 * Though this happens in BSD with high probability, this is occasional.
+	 * Any application relying on this is buggy. Note also, that fix "works"
+	 * only in this artificial test. Insert some normal data between A and B and we will
+	 * decline of BSD again. Verdict: it is better to remove to trap
+	 * buggy users.
+	 */
+	if (tp->urg_seq == tp->copied_seq && tp->urg_data &&
+	    !sk->urginline &&
+	    tp->copied_seq != tp->rcv_nxt) {
+		struct sk_buff *skb = skb_peek(&sk->receive_queue);
+		tp->copied_seq++;
+		if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) {
+			__skb_unlink(skb, skb->list);
+			__kfree_skb(skb);
+		}
+	}
+
 	tp->urg_data = TCP_URG_NOTYET;
 	tp->urg_seq = ptr;
 
@@ -3038,7 +3122,7 @@
 }
 
 /* This is the 'fast' part of urgent handling. */
-static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len)
+static inline void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
@@ -3048,11 +3132,14 @@
 
 	/* Do we wait for any urgent data? - normally not... */
 	if (tp->urg_data == TCP_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) {
-			tp->urg_data = TCP_URG_VALID | *(ptr + (unsigned char *) th);
+		if (ptr < skb->len) {
+			u8 tmp;
+			if (skb_copy_bits(skb, ptr, &tmp, 1))
+				BUG();
+			tp->urg_data = TCP_URG_VALID | tmp;
 			if (!sk->dead)
 				sk->data_ready(sk,0);
 		}
@@ -3067,9 +3154,9 @@
 
 	local_bh_enable();
 	if (skb->ip_summed==CHECKSUM_UNNECESSARY)
-		err = memcpy_toiovec(tp->ucopy.iov, skb->h.raw + hlen, chunk);
+		err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk);
 	else
-		err = copy_and_csum_toiovec(tp->ucopy.iov, skb, hlen);
+		err = skb_copy_and_csum_datagram_iovec(skb, hlen, tp->ucopy.iov);
 
 	if (!err) {
 update:
@@ -3117,32 +3204,6 @@
  * 	disabled when:
  *	- A zero window was announced from us - zero window probing
  *        is only handled properly in the slow path. 
- *	  [ NOTE: actually, it was made incorrectly and nobody ever noticed
- *	    this! Reason is clear: 1. Correct senders do not send
- *	    to zero window. 2. Even if a sender sends to zero window,
- *	    nothing terrible occurs.
- *
- *	    For now I cleaned this and fast path is really always disabled,
- *	    when window is zero, but I would be more happy to remove these
- *	    checks. Code will be only cleaner and _faster_.    --ANK
- *	
- *	    Later note. I've just found that slow path also accepts
- *	    out of window segments, look at tcp_sequence(). So...
- *	    it is the last argument: I repair all and comment out
- *	    repaired code by TCP_FORMAL_WINDOW.
- *	    [ I remember one rhyme from a chidren's book. (I apologize,
- *	      the trasnlation is not rhymed 8)): people in one (jewish) village
- *	      decided to build sauna, but divided to two parties.
- *	      The first one insisted that battens should not be dubbed,
- *	      another objected that foots will suffer of splinters,
- *	      the first fended that dubbed wet battens are too slippy
- *	      and people will fall and it is much more serious!
- *	      Certaiinly, all they went to rabbi.
- *	      After some thinking, he judged: "Do not be lazy!
- *	      Certainly, dub the battens! But put them by dubbed surface down."
- *          ]
- *        ]
- *
  *	- Out of order segments arrived.
  *	- Urgent data is expected.
  *	- There is no buffer space left
@@ -3348,7 +3409,7 @@
 
 	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
 
-	if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
+	if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
 		TCP_INC_STATS_BH(TcpInErrs);
 		NET_INC_STATS_BH(TCPAbortOnSyn);
 		tcp_reset(sk);
@@ -3360,10 +3421,10 @@
 		tcp_ack(sk, skb, FLAG_SLOWPATH);
 
 	/* Process urgent data. */
-	tcp_urg(sk, th, len);
+	tcp_urg(sk, skb, th);
 
 	/* step 7: process the segment text */
-	tcp_data(skb, sk, len);
+	tcp_data_queue(sk, skb);
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
@@ -3452,8 +3513,6 @@
 		 */
 		tp->snd_wnd = ntohs(th->window);
 		tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq);
-		tp->syn_seq = TCP_SKB_CB(skb)->seq;
-		tp->fin_seq = TCP_SKB_CB(skb)->seq;
 
 		if (tp->wscale_ok == 0) {
 			tp->snd_wscale = tp->rcv_wscale = 0;
@@ -3488,7 +3547,7 @@
 
 		/* Remember, tcp_poll() does not lock socket!
 		 * Change state from SYN-SENT only after copied_seq
-		 * is initilized. */
+		 * is initialized. */
 		tp->copied_seq = tp->rcv_nxt;
 		mb();
 		tcp_set_state(sk, TCP_ESTABLISHED);
@@ -3498,7 +3557,7 @@
 			sk_wake_async(sk, 0, POLL_OUT);
 		}
 
-		if (tp->write_pending || tp->defer_accept) {
+		if (tp->write_pending || tp->defer_accept || tp->ack.pingpong) {
 			/* Save one ACK. Data will be ready after
 			 * several ticks, if write_pending is set.
 			 *
@@ -3508,6 +3567,8 @@
 			 */
 			tcp_schedule_ack(tp);
 			tp->ack.lrcvtime = tcp_time_stamp;
+			tp->ack.ato = TCP_ATO_MIN;
+			tcp_incr_quickack(tp);
 			tcp_enter_quickack_mode(tp);
 			tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX);
 
@@ -3683,21 +3744,9 @@
 
 	/*	step 4:
 	 *
-	 *	Check for a SYN, and ensure it matches the SYN we were
-	 *	first sent. We have to handle the rather unusual (but valid)
-	 *	sequence that KA9Q derived products may generate of
-	 *
-	 *	SYN
-	 *				SYN|ACK Data
-	 *	ACK	(lost)
-	 *				SYN|ACK Data + More Data
-	 *	.. we must ACK not RST...
-	 *
-	 *	We keep syn_seq as the sequence space occupied by the 
-	 *	original syn. 
+	 *	Check for a SYN in window.
 	 */
-
-	if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
+	if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
 		NET_INC_STATS_BH(TCPAbortOnSyn);
 		tcp_reset(sk);
 		return 1;
@@ -3713,6 +3762,7 @@
 				tp->copied_seq = tp->rcv_nxt;
 				mb();
 				tcp_set_state(sk, TCP_ESTABLISHED);
+				sk->state_change(sk);
 
 				/* Note, that this wakeup is only for marginal
 				 * crossed SYN case. Passively open sockets
@@ -3720,7 +3770,6 @@
 				 * and sk->socket == NULL.
 				 */
 				if (sk->socket) {
-					sk->state_change(sk);
 					sk_wake_async(sk,0,POLL_OUT);
 				}
 
@@ -3806,13 +3855,13 @@
 
 step6:
 	/* step 6: check the URG bit */
-	tcp_urg(sk, th, len);
+	tcp_urg(sk, skb, th);
 
 	/* step 7: process the segment text */
 	switch (sk->state) {
 	case TCP_CLOSE_WAIT:
 	case TCP_CLOSING:
-		if (!before(TCP_SKB_CB(skb)->seq, tp->fin_seq))
+		if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
 			break;
 	case TCP_FIN_WAIT1:
 	case TCP_FIN_WAIT2:
@@ -3830,7 +3879,7 @@
 		}
 		/* Fall through */
 	case TCP_ESTABLISHED: 
-		tcp_data(skb, sk, len);
+		tcp_data_queue(sk, skb);
 		queued = 1;
 		break;
 	}
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.4.3/linux/net/ipv4/tcp_ipv4.c	Mon Jan  1 11:01:58 2001
+++ linux/net/ipv4/tcp_ipv4.c	Wed Apr 25 14:57:39 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.222 2000/12/08 17:15:53 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.229 2001/04/20 20:46:19 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -670,6 +670,7 @@
 	}
 
 	__sk_dst_set(sk, &rt->u.dst);
+	sk->route_caps = rt->u.dst.dev->features;
 
 	if (!sk->protinfo.af_inet.opt || !sk->protinfo.af_inet.opt->srr)
 		daddr = rt->rt_dst;
@@ -717,6 +718,7 @@
 	tp->ext_header_len = 0;
 	if (sk->protinfo.af_inet.opt)
 		tp->ext_header_len = sk->protinfo.af_inet.opt->optlen;
+	sk->protinfo.af_inet.id = tp->write_seq^jiffies;
 
 	tp->mss_clamp = 536;
 
@@ -726,6 +728,7 @@
 
 failure:
 	__sk_dst_reset(sk);
+	sk->route_caps = 0;
 	sk->dport = 0;
 	return err;
 }
@@ -850,32 +853,21 @@
  *
  */
 
-void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
+void tcp_v4_err(struct sk_buff *skb, u32 info)
 {
-	struct iphdr *iph = (struct iphdr*)dp;
-	struct tcphdr *th; 
+	struct iphdr *iph = (struct iphdr*)skb->data;
+	struct tcphdr *th = (struct tcphdr*)(skb->data+(iph->ihl<<2));
 	struct tcp_opt *tp;
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
-#if ICMP_MIN_LENGTH < 14
-	int no_flags = 0;
-#else
-#define no_flags 0
-#endif
 	struct sock *sk;
 	__u32 seq;
 	int err;
 
-	if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) { 
+	if (skb->len < (iph->ihl << 2) + 8) {
 		ICMP_INC_STATS_BH(IcmpInErrors); 
 		return;
 	}
-#if ICMP_MIN_LENGTH < 14
-	if (len < (iph->ihl << 2) + 14)
-		no_flags = 1;
-#endif
-
-	th = (struct tcphdr*)(dp+(iph->ihl<<2));
 
 	sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, tcp_v4_iif(skb));
 	if (sk == NULL) {
@@ -921,7 +913,7 @@
 
 		if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
 			if (sk->lock.users == 0)
-				do_pmtu_discovery(sk, iph, ntohs(skb->h.icmph->un.frag.mtu));
+				do_pmtu_discovery(sk, iph, info);
 			goto out;
 		}
 
@@ -940,15 +932,6 @@
 		if (sk->lock.users != 0)
 			goto out;
 
-		/* The final ACK of the handshake should be already 
-		 * handled in the new socket context, not here.
-		 * Strictly speaking - an ICMP error for the final
-		 * ACK should set the opening flag, but that is too
-		 * complicated right now. 
-		 */ 
-		if (!no_flags && !th->syn && !th->ack)
-			goto out;
-
 		req = tcp_v4_search_req(tp, iph, th, &prev); 
 		if (!req)
 			goto out;
@@ -976,8 +959,6 @@
 	case TCP_SYN_RECV:  /* Cannot happen.
 			       It can f.e. if SYNs crossed.
 			     */ 
-		if (!no_flags && !th->syn)
-			goto out;
 		if (sk->lock.users == 0) {
 			TCP_INC_STATS_BH(TcpAttemptFails);
 			sk->err = err;
@@ -1023,8 +1004,13 @@
 void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
 		       struct sk_buff *skb)
 {
-	th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr,
-				 csum_partial((char *)th, th->doff<<2, skb->csum));
+	if (skb->ip_summed == CHECKSUM_HW) {
+		th->check = ~tcp_v4_check(th, len, sk->saddr, sk->daddr, 0);
+		skb->csum = offsetof(struct tcphdr, check);
+	} else {
+		th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr,
+					 csum_partial((char *)th, th->doff<<2, skb->csum));
+	}
 }
 
 /*
@@ -1445,6 +1431,7 @@
 		goto exit;
 
 	newsk->dst_cache = dst;
+	newsk->route_caps = dst->dev->features;
 
 	newtp = &(newsk->tp_pinfo.af_tcp);
 	newsk->daddr = req->af.v4_req.rmt_addr;
@@ -1457,6 +1444,7 @@
 	newtp->ext_header_len = 0;
 	if (newsk->protinfo.af_inet.opt)
 		newtp->ext_header_len = newsk->protinfo.af_inet.opt->optlen;
+	newsk->protinfo.af_inet.id = newtp->write_seq^jiffies;
 
 	tcp_sync_mss(newsk, dst->pmtu);
 	newtp->advmss = dst->advmss;
@@ -1512,23 +1500,23 @@
 static int tcp_v4_checksum_init(struct sk_buff *skb)
 {
 	if (skb->ip_summed == CHECKSUM_HW) {
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		if (!tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
+				  skb->nh.iph->daddr,skb->csum))
+			return 0;
+
+		NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n"));
+		skb->ip_summed = CHECKSUM_NONE;
+	}
+	if (skb->len <= 76) {
 		if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
-				 skb->nh.iph->daddr,skb->csum)) {
-			NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n"));
+				 skb->nh.iph->daddr,
+				 skb_checksum(skb, 0, skb->len, 0)))
 			return -1;
-		}
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else {
-		if (skb->len <= 76) {
-			if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
-					 skb->nh.iph->daddr,
-					 csum_partial((char *)skb->h.th, skb->len, 0)))
-				return -1;
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-		} else {
-			skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
-						  skb->nh.iph->daddr,0);
-		}
+		skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
+					  skb->nh.iph->daddr,0);
 	}
 	return 0;
 }
@@ -1601,7 +1589,7 @@
  *	From tcp_input.c
  */
 
-int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
+int tcp_v4_rcv(struct sk_buff *skb)
 {
 	struct tcphdr *th;
 	struct sock *sk;
@@ -1610,31 +1598,35 @@
 	if (skb->pkt_type!=PACKET_HOST)
 		goto discard_it;
 
-	th = skb->h.th;
-
-	/* Pull up the IP header. */
-	__skb_pull(skb, skb->h.raw - skb->data);
-
 	/* Count it even if it's bad */
 	TCP_INC_STATS_BH(TcpInSegs);
 
+	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
+		goto discard_it;
+
+	th = skb->h.th;
+
+	if (th->doff < sizeof(struct tcphdr)/4)
+		goto bad_packet;
+	if (!pskb_may_pull(skb, th->doff*4))
+		goto discard_it;
+
 	/* An explanation is required here, I think.
 	 * Packet length and doff are validated by header prediction,
 	 * provided case of th->doff==0 is elimineted.
 	 * So, we defer the checks. */
-	if (th->doff < sizeof(struct tcphdr)/4 ||
-	    (skb->ip_summed != CHECKSUM_UNNECESSARY &&
+	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
 	     tcp_v4_checksum_init(skb) < 0))
 		goto bad_packet;
 
+	th = skb->h.th;
 	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
 	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
-				    len - th->doff*4);
+				    skb->len - th->doff*4);
 	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
 	TCP_SKB_CB(skb)->when = 0;
 	TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;
 	TCP_SKB_CB(skb)->sacked = 0;
-	skb->used = 0;
 
 	sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
 			     skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb));
@@ -1665,7 +1657,7 @@
 	return ret;
 
 no_tcp_socket:
-	if (len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 bad_packet:
 		TCP_INC_STATS_BH(TcpInErrs);
 	} else {
@@ -1682,7 +1674,7 @@
 	goto discard_it;
 
 do_time_wait:
-	if (len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 		TCP_INC_STATS_BH(TcpInErrs);
 		goto discard_and_relse;
 	}
@@ -1740,7 +1732,7 @@
 		return err;
 
 	__sk_dst_set(sk, &rt->u.dst);
-	/* sk->route_caps = rt->u.dst.dev->features; */
+	sk->route_caps = rt->u.dst.dev->features;
 
 	new_saddr = rt->rt_src;
 
@@ -1788,20 +1780,19 @@
 			      sk->bound_dev_if);
 	if (!err) {
 		__sk_dst_set(sk, &rt->u.dst);
-		/* sk->route_caps = rt->u.dst.dev->features; */
+		sk->route_caps = rt->u.dst.dev->features;
 		return 0;
 	}
 
 	/* Routing failed... */
-	/* sk->route_caps = 0; */
+	sk->route_caps = 0;
 
 	if (!sysctl_ip_dynaddr ||
 	    sk->state != TCP_SYN_SENT ||
 	    (sk->userlocks & SOCK_BINDADDR_LOCK) ||
-	    (err = tcp_v4_reselect_saddr(sk)) != 0) {
+	    (err = tcp_v4_reselect_saddr(sk)) != 0)
 		sk->err_soft=-err;
-		/* sk->error_report(sk); */
-	}
+
 	return err;
 }
 
@@ -1919,7 +1910,8 @@
 
 	sk->state = TCP_CLOSE;
 
-	sk->write_space = tcp_write_space; 
+	sk->write_space = tcp_write_space;
+	sk->use_write_queue = 1;
 
 	sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific;
 
@@ -1940,7 +1932,7 @@
 	/* Cleanup up the write buffer. */
   	tcp_writequeue_purge(sk);
 
-	/* Cleans up our, hopefuly empty, out_of_order_queue. */
+	/* Cleans up our, hopefully empty, out_of_order_queue. */
   	__skb_queue_purge(&tp->out_of_order_queue);
 
 	/* Clean prequeue, it must be empty really */
@@ -1950,6 +1942,10 @@
 	if(sk->prev != NULL)
 		tcp_put_port(sk);
 
+	/* If sendmsg cached page exists, toss it. */
+	if (tp->sndmsg_page != NULL)
+		__free_page(tp->sndmsg_page);
+
 	atomic_dec(&tcp_sockets_allocated);
 
 	return 0;
@@ -2076,7 +2072,7 @@
 			if (pos >= offset) {
 				get_tcp_sock(sk, tmpbuf, num);
 				len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
-				if (len >= length) {
+				if (pos >= offset + length) {
 					tcp_listen_unlock();
 					goto out_no_bh;
 				}
@@ -2097,7 +2093,7 @@
 							continue;
 						get_openreq(sk, req, tmpbuf, num, uid);
 						len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
-						if(len >= length) {
+						if (pos >= offset + length) {
 							read_unlock_bh(&tp->syn_wait_lock);
 							tcp_listen_unlock();
 							goto out_no_bh;
@@ -2129,7 +2125,7 @@
 				continue;
 			get_tcp_sock(sk, tmpbuf, num);
 			len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
-			if(len >= length) {
+			if (pos >= offset + length) {
 				read_unlock(&head->lock);
 				goto out;
 			}
@@ -2144,7 +2140,7 @@
 				continue;
 			get_timewait_sock(tw, tmpbuf, num);
 			len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
-			if(len >= length) {
+			if (pos >= offset + length) {
 				read_unlock(&head->lock);
 				goto out;
 			}
@@ -2159,7 +2155,7 @@
 	begin = len - (pos - offset);
 	*start = buffer + begin;
 	len -= begin;
-	if(len > length)
+	if (len > length)
 		len = length;
 	if (len < 0)
 		len = 0; 
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_minisocks.c linux/net/ipv4/tcp_minisocks.c
--- v2.4.3/linux/net/ipv4/tcp_minisocks.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv4/tcp_minisocks.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_minisocks.c,v 1.5 2000/11/28 17:04:10 davem Exp $
+ * Version:	$Id: tcp_minisocks.c,v 1.9 2001/03/06 22:42:56 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -105,7 +105,7 @@
  *   lifetime in the internet, which results in wrong conclusion, that
  *   it is set to catch "old duplicate segments" wandering out of their path.
  *   It is not quite correct. This timeout is calculated so that it exceeds
- *   maximal retransmision timeout enough to allow to lose one (or more)
+ *   maximal retransmission timeout enough to allow to lose one (or more)
  *   segments sent by peer and our ACKs. This time may be calculated from RTO.
  * * When TIME-WAIT socket receives RST, it means that another end
  *   finally closed and we are allowed to kill TIME-WAIT too.
@@ -155,7 +155,7 @@
 		if (th->rst)
 			goto kill;
 
-		if (th->syn && TCP_SKB_CB(skb)->seq != tw->syn_seq)
+		if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->rcv_nxt))
 			goto kill_with_rst;
 
 		/* Dup ACK? */
@@ -377,7 +377,6 @@
 		tw->rcv_nxt	= tp->rcv_nxt;
 		tw->snd_nxt	= tp->snd_nxt;
 		tw->rcv_wnd	= tcp_receive_window(tp);
-		tw->syn_seq	= tp->syn_seq;
 		tw->ts_recent	= tp->ts_recent;
 		tw->ts_recent_stamp= tp->ts_recent_stamp;
 		tw->pprev_death = NULL;
@@ -691,8 +690,6 @@
 		newtp->snd_una = req->snt_isn + 1;
 		newtp->snd_sml = req->snt_isn + 1;
 
-		tcp_delack_init(newtp);
-
 		tcp_prequeue_init(newtp);
 
 		tcp_init_wl(newtp, req->snt_isn, req->rcv_isn);
@@ -734,8 +731,6 @@
 
 		newtp->probes_out = 0;
 		newtp->num_sacks = 0;
-		newtp->syn_seq = req->rcv_isn;
-		newtp->fin_seq = req->rcv_isn;
 		newtp->urg_data = 0;
 		newtp->listen_opt = NULL;
 		newtp->accept_queue = newtp->accept_queue_tail = NULL;
@@ -822,7 +817,7 @@
 		}
 	}
 
-	/* Check for pure retransmited SYN. */
+	/* Check for pure retransmitted SYN. */
 	if (TCP_SKB_CB(skb)->seq == req->rcv_isn &&
 	    flg == TCP_FLAG_SYN &&
 	    !paws_reject) {
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.4.3/linux/net/ipv4/tcp_output.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv4/tcp_output.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.129 2000/11/28 17:04:10 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.136 2001/03/06 22:42:56 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -166,20 +166,9 @@
 	/* RFC1323 scaling applied */
 	new_win >>= tp->rcv_wscale;
 
-#ifdef TCP_FORMAL_WINDOW
-	if (new_win == 0) {
-		/* If we advertise zero window, disable fast path. */
+	/* If we advertise zero window, disable fast path. */
+	if (new_win == 0)
 		tp->pred_flags = 0;
-	} else if (cur_win == 0 && tp->pred_flags == 0 &&
-		   skb_queue_len(&tp->out_of_order_queue) == 0 &&
-		   !tp->urg_data) {
-		/* If we open zero window, enable fast path.
-		   Without this it will be open by the first data packet,
-		   it is too late to merge checksumming to copy.
-		 */
-		tcp_fast_path_on(tp);
-	}
-#endif
 
 	return new_win;
 }
@@ -337,6 +326,91 @@
 		tp->send_head = skb;
 }
 
+/* Send _single_ skb sitting at the send head. This function requires
+ * true push pending frames to setup probe timer etc.
+ */
+void tcp_push_one(struct sock *sk, unsigned cur_mss)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct sk_buff *skb = tp->send_head;
+
+	if (tcp_snd_test(tp, skb, cur_mss, 1)) {
+		/* Send it out now. */
+		TCP_SKB_CB(skb)->when = tcp_time_stamp;
+		if (tcp_transmit_skb(sk, skb_clone(skb, sk->allocation)) == 0) {
+			tp->send_head = NULL;
+			tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+			if (tp->packets_out++ == 0)
+				tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
+			return;
+		}
+	}
+}
+
+/* Split fragmented skb to two parts at length len. */
+
+static void skb_split(struct sk_buff *skb, struct sk_buff *skb1, u32 len)
+{
+	int i;
+	int pos = skb->len - skb->data_len;
+
+	if (len < pos) {
+		/* Split line is inside header. */
+		memcpy(skb_put(skb1, pos-len), skb->data + len, pos-len);
+
+		/* And move data appendix as is. */
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+			skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i];
+
+		skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags;
+		skb_shinfo(skb)->nr_frags = 0;
+
+		skb1->data_len = skb->data_len;
+		skb1->len += skb1->data_len;
+		skb->data_len = 0;
+		skb->len = len;
+		skb->tail = skb->data+len;
+	} else {
+		int k = 0;
+		int nfrags = skb_shinfo(skb)->nr_frags;
+
+		/* Second chunk has no header, nothing to copy. */
+
+		skb_shinfo(skb)->nr_frags = 0;
+		skb1->len = skb1->data_len = skb->len - len;
+		skb->len = len;
+		skb->data_len = len - pos;
+
+		for (i=0; i<nfrags; i++) {
+			int size = skb_shinfo(skb)->frags[i].size;
+			if (pos + size > len) {
+				skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i];
+
+				if (pos < len) {
+					/* Split frag.
+					 * We have to variants in this case:
+					 * 1. Move all the frag to the second
+					 *    part, if it is possible. F.e.
+					 *    this approach is mandatory for TUX,
+					 *    where splitting is expensive.
+					 * 2. Split is accurately. We make this.
+					 */
+					get_page(skb_shinfo(skb)->frags[i].page);
+					skb_shinfo(skb1)->frags[0].page_offset += (len-pos);
+					skb_shinfo(skb1)->frags[0].size -= (len-pos);
+					skb_shinfo(skb)->frags[i].size = len-pos;
+					skb_shinfo(skb)->nr_frags++;
+				}
+				k++;
+			} else {
+				skb_shinfo(skb)->nr_frags++;
+			}
+			pos += size;
+		}
+		skb_shinfo(skb1)->nr_frags = k;
+	}
+}
+
 /* Function to create two new TCP segments.  Shrinks the given segment
  * to the specified size and appends a new segment with the rest of the
  * packet to the list.  This won't be called frequently, I hope. 
@@ -349,19 +423,22 @@
 	int nsize = skb->len - len;
 	u16 flags;
 
+	if (skb_cloned(skb) &&
+	    skb_is_nonlinear(skb) &&
+	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+		return -ENOMEM;
+
 	/* Get a new skb... force flag on. */
-	buff = tcp_alloc_skb(sk, nsize + MAX_TCP_HEADER, GFP_ATOMIC);
+	buff = tcp_alloc_skb(sk, nsize, GFP_ATOMIC);
 	if (buff == NULL)
 		return -ENOMEM; /* We'll just try again later. */
 	tcp_charge_skb(sk, buff);
 
-	/* Reserve space for headers. */
-	skb_reserve(buff, MAX_TCP_HEADER);
-		
 	/* Correct the sequence numbers. */
 	TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len;
 	TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq;
-	
+	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
+
 	/* PSH and FIN should only be set in the second packet. */
 	flags = TCP_SKB_CB(skb)->flags;
 	TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
@@ -371,18 +448,22 @@
 		tp->lost_out++;
 		tp->left_out++;
 	}
-	TCP_SKB_CB(buff)->sacked &= ~TCPCB_AT_TAIL;
+	TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL;
 
-	/* Copy and checksum data tail into the new buffer. */
-	buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize),
-					       nsize, 0);
+	if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) {
+		/* Copy and checksum data tail into the new buffer. */
+		buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize),
+						       nsize, 0);
 
-	/* This takes care of the FIN sequence number too. */
-	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
-	skb_trim(skb, len);
+		skb_trim(skb, len);
 
-	/* Rechecksum original buffer. */
-	skb->csum = csum_partial(skb->data, skb->len, 0);
+		skb->csum = csum_block_sub(skb->csum, buff->csum, len);
+	} else {
+		skb->ip_summed = CHECKSUM_HW;
+		skb_split(skb, buff, len);
+	}
+
+	buff->ip_summed = skb->ip_summed;
 
 	/* Looks stupid, but our code really uses when of
 	 * skbs, which it never sent before. --ANK
@@ -461,7 +542,7 @@
  * Returns 1, if no segments are in flight and we have queued segments, but
  * cannot send anything now because of SWS or another problem.
  */
-int tcp_write_xmit(struct sock *sk)
+int tcp_write_xmit(struct sock *sk, int nonagle)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	unsigned int mss_now;
@@ -482,7 +563,7 @@
 		mss_now = tcp_current_mss(sk); 
 
 		while((skb = tp->send_head) &&
-		      tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? tp->nonagle : 1)) {
+		      tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : 1)) {
 			if (skb->len > mss_now) {
 				if (tcp_fragment(sk, skb, mss_now))
 					break;
@@ -568,22 +649,21 @@
 	 * but may be worse for the performance because of rcv_mss
 	 * fluctuations.  --SAW  1998/11/1
 	 */
-	unsigned int mss = tp->ack.rcv_mss;
-	int free_space;
-	u32 window;
-
-	/* Sometimes free_space can be < 0. */
-	free_space = tcp_space(sk); 
-	if (tp->window_clamp < mss)
-		mss = tp->window_clamp; 
+	int mss = tp->ack.rcv_mss;
+	int free_space = tcp_space(sk);
+	int full_space = min(tp->window_clamp, tcp_full_space(sk));
+	int window;
+
+	if (mss > full_space)
+		mss = full_space; 
 
-	if (free_space < (int)min(tp->window_clamp, tcp_full_space(sk)) / 2) {
+	if (free_space < full_space/2) {
 		tp->ack.quick = 0;
 
 		if (tcp_memory_pressure)
 			tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss);
 
-		if (free_space < ((int)mss))
+		if (free_space < mss)
 			return 0;
 	}
 
@@ -599,9 +679,8 @@
 	 * is too small.
 	 */
 	window = tp->rcv_wnd;
-	if ((((int) window) <= (free_space - ((int) mss))) ||
-	    (((int) window) > free_space))
-		window = (((unsigned int) free_space)/mss)*mss;
+	if (window <= free_space - mss || window > free_space)
+		window = (free_space/mss)*mss;
 
 	return window;
 }
@@ -638,19 +717,14 @@
 		/* Ok.  We will be able to collapse the packet. */
 		__skb_unlink(next_skb, next_skb->list);
 
-		if(skb->len % 4) {
-			/* Must copy and rechecksum all data. */
+		if (next_skb->ip_summed == CHECKSUM_HW)
+			skb->ip_summed = CHECKSUM_HW;
+
+		if (skb->ip_summed != CHECKSUM_HW) {
 			memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
-			skb->csum = csum_partial(skb->data, skb->len, 0);
-		} else {
-			/* Optimize, actually we could also combine next_skb->csum
-			 * to skb->csum using a single add w/carry operation too.
-			 */
-			skb->csum = csum_partial_copy_nocheck(next_skb->data,
-							      skb_put(skb, next_skb_size),
-							      next_skb_size, skb->csum);
+			skb->csum = csum_block_add(skb->csum, next_skb->csum, skb->len);
 		}
-	
+
 		/* Update sequence range on original skb. */
 		TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq;
 
@@ -668,11 +742,12 @@
 			tp->lost_out--;
 			tp->left_out--;
 		}
+		/* Reno case is special. Sigh... */
 		if (!tp->sack_ok && tp->sacked_out) {
-			/* Reno case is special. Sigh... */
 			tp->sacked_out--;
 			tp->left_out--;
 		}
+
 		/* Not quite right: it can be > snd.fack, but
 		 * it is better to underestimate fackets.
 		 */
@@ -712,7 +787,7 @@
 	if (!lost)
 		return;
 
-	tp->left_out = tp->sacked_out + tp->lost_out;
+	tcp_sync_left_out(tp);
 
  	/* Don't muck with the congestion window here.
 	 * Reason is that we do not increase amount of _data_
@@ -745,6 +820,15 @@
 	if (atomic_read(&sk->wmem_alloc) > min(sk->wmem_queued+(sk->wmem_queued>>2),sk->sndbuf))
 		return -EAGAIN;
 
+	/* If receiver has shrunk his window, and skb is out of
+	 * new window, do not retransmit it. The exception is the
+	 * case, when window is shrunk to zero. In this case
+	 * our retransmit serves as a zero window probe.
+	 */
+	if (!before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)
+	    && TCP_SKB_CB(skb)->seq != tp->snd_una)
+		return -EAGAIN;
+
 	if(skb->len > cur_mss) {
 		if(tcp_fragment(sk, skb, cur_mss))
 			return -ENOMEM; /* We'll try again later. */
@@ -758,6 +842,7 @@
 	   (skb->len < (cur_mss >> 1)) &&
 	   (skb->next != tp->send_head) &&
 	   (skb->next != (struct sk_buff *)&sk->write_queue) &&
+	   (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(skb->next)->nr_frags == 0) &&
 	   (sysctl_tcp_retrans_collapse != 0))
 		tcp_retrans_try_collapse(sk, skb, cur_mss);
 
@@ -771,9 +856,11 @@
 	if(skb->len > 0 &&
 	   (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
 	   tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
-		TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
-		skb_trim(skb, 0);
-		skb->csum = 0;
+		if (!pskb_trim(skb, 0)) {
+			TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
+			skb->ip_summed = CHECKSUM_NONE;
+			skb->csum = 0;
+		}
 	}
 
 	/* Make a copy, if the first transmission SKB clone we made
@@ -782,7 +869,7 @@
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
 	err = tcp_transmit_skb(sk, (skb_cloned(skb) ?
-				    skb_copy(skb, GFP_ATOMIC):
+				    pskb_copy(skb, GFP_ATOMIC):
 				    skb_clone(skb, GFP_ATOMIC)));
 
 	if (err == 0) {
@@ -912,28 +999,10 @@
 	 */
 	mss_now = tcp_current_mss(sk); 
 
-	/* Please, find seven differences of 2.3.33 and loook
-	 * what I broke here. 8) --ANK
-	 */
-
 	if(tp->send_head != NULL) {
-		/* tcp_write_xmit() takes care of the rest. */
 		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
 		TCP_SKB_CB(skb)->end_seq++;
 		tp->write_seq++;
-
-		/* Special case to avoid Nagle bogosity.  If this
-		 * segment is the last segment, and it was queued
-		 * due to Nagle/SWS-avoidance, send it out now.
-		 */
-		if(tp->send_head == skb &&
-		   !after(tp->write_seq, tp->snd_una + tp->snd_wnd)) {
-			TCP_SKB_CB(skb)->when = tcp_time_stamp;
-			if (!tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)))
-				update_send_head(sk, tp, skb);
-			else
-				tcp_check_probe_timer(sk, tp);
-		}
 	} else {
 		/* Socket is locked, keep trying until memory is available. */
 		for (;;) {
@@ -953,9 +1022,9 @@
 		/* FIN eats a sequence byte, write_seq advanced by tcp_send_skb(). */
 		TCP_SKB_CB(skb)->seq = tp->write_seq;
 		TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
-		tcp_send_skb(sk, skb, 0, mss_now);
-		__tcp_push_pending_frames(sk, tp, mss_now, 1);
+		tcp_send_skb(sk, skb, 1, mss_now);
 	}
+	__tcp_push_pending_frames(sk, tp, mss_now, 1);
 }
 
 /* We get here when a process closes a file descriptor (either due to
@@ -1224,23 +1293,6 @@
 	tp->ack.timeout = timeout;
 	if (!mod_timer(&tp->delack_timer, timeout))
 		sock_hold(sk);
-
-#ifdef TCP_FORMAL_WINDOW
-	/* Explanation. Header prediction path does not handle
-	 * case of zero window. If we send ACK immediately, pred_flags
-	 * are reset when sending ACK. If rcv_nxt is advanced and
-	 * ack is not sent, than delayed ack is scheduled.
-	 * Hence, it is the best place to check for zero window.
-	 */
-	if (tp->pred_flags) {
-		if (tcp_receive_window(tp) == 0)
-			tp->pred_flags = 0;
-	} else {
-		if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
-		    !tp->urg_data)
-			tcp_fast_path_on(tp);
-	}
-#endif
 }
 
 /* This routine sends an ack and also updates the window. */
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.4.3/linux/net/ipv4/tcp_timer.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/tcp_timer.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.81 2001/01/01 02:38:30 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.83 2001/03/07 22:00:57 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -326,6 +326,29 @@
 
 	BUG_TRAP(!skb_queue_empty(&sk->write_queue));
 
+	if (tp->snd_wnd == 0 && !sk->dead &&
+	    !((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV))) {
+		/* Receiver dastardly shrinks window. Our retransmits
+		 * become zero probes, but we should not timeout this
+		 * connection. If the socket is an orphan, time it out,
+		 * we cannot allow such beasts to hang infinitely.
+		 */
+#ifdef TCP_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n",
+			       NIPQUAD(sk->daddr), htons(sk->dport), sk->num,
+			       tp->snd_una, tp->snd_nxt);
+#endif
+		if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) {
+			tcp_write_err(sk);
+			goto out;
+		}
+		tcp_enter_loss(sk, 0);
+		tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+		__sk_dst_reset(sk);
+		goto out_reset_timer;
+	}
+
 	if (tcp_write_timeout(sk))
 		goto out;
 
@@ -379,6 +402,8 @@
 	 */
 	tp->backoff++;
 	tp->retransmits++;
+
+out_reset_timer:
 	tp->rto = min(tp->rto << 1, TCP_RTO_MAX);
 	tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
 	if (tp->retransmits > sysctl_tcp_retries1)
diff -u --recursive --new-file v2.4.3/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.4.3/linux/net/ipv4/udp.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/udp.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.91 2000/11/28 13:38:38 davem Exp $
+ * Version:	$Id: udp.c,v 1.98 2001/03/06 21:15:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -291,22 +291,16 @@
  * to find the appropriate port.
  */
 
-void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
+void udp_err(struct sk_buff *skb, u32 info)
 {
-	struct iphdr *iph = (struct iphdr*)dp;
-	struct udphdr *uh = (struct udphdr*)(dp+(iph->ihl<<2));
+	struct iphdr *iph = (struct iphdr*)skb->data;
+	struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	struct sock *sk;
 	int harderr;
-	u32 info;
 	int err;
 
-	if (len < (iph->ihl<<2)+sizeof(struct udphdr)) {
-		ICMP_INC_STATS_BH(IcmpInErrors);
-		return;
-	}
-
 	sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex);
 	if (sk == NULL) {
 		ICMP_INC_STATS_BH(IcmpInErrors);
@@ -314,7 +308,6 @@
 	}
 
 	err = 0;
-	info = 0;
 	harderr = 0;
 
 	switch (type) {
@@ -326,14 +319,12 @@
 		goto out;
 	case ICMP_PARAMETERPROB:
 		err = EPROTO;
-		info = ntohl(skb->h.icmph->un.gateway)>>24;
 		harderr = 1;
 		break;
 	case ICMP_DEST_UNREACH:
 		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
 			if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT) {
 				err = EMSGSIZE;
-				info = ntohs(skb->h.icmph->un.frag.mtu);
 				harderr = 1;
 				break;
 			}
@@ -379,10 +370,7 @@
 };
 
 /*
- *	Copy and checksum a UDP packet from user space into a buffer. We still have
- *	to do the planning to get ip_build_xmit to spot direct transfer to network
- *	card and provide an additional callback mode for direct user->board I/O
- *	transfers. That one will be fun.
+ *	Copy and checksum a UDP packet from user space into a buffer.
  */
  
 static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
@@ -409,10 +397,7 @@
 }
 
 /*
- *	Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing
- *	that we use two routines for this for speed. Probably we ought to have a
- *	CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding.
- *	Timing needed to verify if this is a valid decision.
+ *	Copy a UDP packet from user space into a buffer without checksumming.
  */
  
 static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
@@ -625,7 +610,7 @@
 
 static __inline__ int __udp_checksum_complete(struct sk_buff *skb)
 {
-	return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum));
+	return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
 }
 
 static __inline__ int udp_checksum_complete(struct sk_buff *skb)
@@ -655,11 +640,6 @@
 	if (flags & MSG_ERRQUEUE)
 		return ip_recv_error(sk, msg, len);
 
-	/*
-	 *	From here the generic datagram does a lot of the work. Come
-	 *	the finished NET3, it will do _ALL_ the work!
-	 */
-
 	skb = skb_recv_datagram(sk, flags, noblock, &err);
 	if (!skb)
 		goto out;
@@ -679,9 +659,9 @@
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
 					      copied);
 	} else {
-		err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr));
+		err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
 
-		if (err)
+		if (err == -EINVAL)
 			goto csum_copy_err;
 	}
 
@@ -758,6 +738,7 @@
 	sk->daddr = rt->rt_dst;
 	sk->dport = usin->sin_port;
 	sk->state = TCP_ESTABLISHED;
+	sk->protinfo.af_inet.id = jiffies;
 
 	sk_dst_set(sk, &rt->u.dst);
 	return(0);
@@ -872,10 +853,13 @@
 	if (uh->check == 0) {
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else if (skb->ip_summed == CHECKSUM_HW) {
-		if (udp_check(uh, ulen, saddr, daddr, skb->csum))
-			return -1;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+		if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
+			return 0;
+		NETDEBUG(printk(KERN_DEBUG "udp v4 hw csum failure.\n"));
+		skb->ip_summed = CHECKSUM_NONE;
+	}
+	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
 		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
 	/* Probably, we should checksum udp header (it should be in cache
 	 * in any case) and data in tiny packets (< rx copybreak).
@@ -887,7 +871,7 @@
  *	All we need to do is get the socket, and then do a checksum. 
  */
  
-int udp_rcv(struct sk_buff *skb, unsigned short len)
+int udp_rcv(struct sk_buff *skb)
 {
   	struct sock *sk;
   	struct udphdr *uh;
@@ -895,29 +879,22 @@
 	struct rtable *rt = (struct rtable*)skb->dst;
 	u32 saddr = skb->nh.iph->saddr;
 	u32 daddr = skb->nh.iph->daddr;
-
-	/*
-	 *	Get the header.
-	 */
-	 
-  	uh = skb->h.uh;
-	__skb_pull(skb, skb->h.raw - skb->data);
+	int len = skb->len;
 
   	IP_INC_STATS_BH(IpInDelivers);
 
 	/*
 	 *	Validate the packet and the UDP length.
 	 */
-	 
-	ulen = ntohs(uh->len);
+	ulen = ntohs(skb->h.uh->len);
 
-	if (ulen > len || ulen < sizeof(*uh)) {
-		NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
-		UDP_INC_STATS_BH(UdpInErrors);
-		kfree_skb(skb);
-		return(0);
-	}
-	skb_trim(skb, ulen);
+	if (ulen > len || ulen < sizeof(*uh))
+		goto short_packet;
+
+	if (pskb_trim(skb, ulen))
+		goto short_packet;
+
+  	uh = skb->h.uh;
 
 	if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
 		goto csum_error;
@@ -944,6 +921,12 @@
 	 * Hmm.  We got an UDP packet to a port to which we
 	 * don't wanna listen.  Ignore it.
 	 */
+	kfree_skb(skb);
+	return(0);
+
+short_packet:
+	NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
+	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
 
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.4.3/linux/net/ipv6/af_inet6.c	Mon Oct 23 15:48:28 2000
+++ linux/net/ipv6/af_inet6.c	Thu Apr 12 12:11:39 2001
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.60 2000/10/19 01:05:34 davem Exp $
+ *	$Id: af_inet6.c,v 1.63 2001/03/02 03:13:05 davem Exp $
  *
  * 	Fixes:
  * 	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -461,6 +461,7 @@
 	sendmsg:	inet_sendmsg,			/* ok		*/
 	recvmsg:	inet_recvmsg,			/* ok		*/
 	mmap:		sock_no_mmap,
+	sendpage:	tcp_sendpage
 };
 
 struct proto_ops inet6_dgram_ops = {
@@ -481,6 +482,7 @@
 	sendmsg:	inet_sendmsg,			/* ok		*/
 	recvmsg:	inet_recvmsg,			/* ok		*/
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 struct net_proto_family inet6_family_ops = {
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c
--- v2.4.3/linux/net/ipv6/datagram.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv6/datagram.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: datagram.c,v 1.21 2000/11/28 13:42:08 davem Exp $
+ *	$Id: datagram.c,v 1.22 2000/12/13 18:31:50 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -57,7 +57,7 @@
 	serr->port = port;
 
 	skb->h.raw = payload;
-	skb_pull(skb, payload - skb->data);
+	__skb_pull(skb, payload - skb->data);
 
 	if (sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
@@ -92,7 +92,7 @@
 	serr->port = fl->uli_u.ports.dport;
 
 	skb->h.raw = skb->tail;
-	skb_pull(skb, skb->tail - skb->data);
+	__skb_pull(skb, skb->tail - skb->data);
 
 	if (sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
@@ -123,7 +123,7 @@
 		msg->msg_flags |= MSG_TRUNC;
 		copied = len;
 	}
-	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	if (err)
 		goto out_free_skb;
 
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/exthdrs.c linux/net/ipv6/exthdrs.c
--- v2.4.3/linux/net/ipv6/exthdrs.c	Sat Jan  8 21:36:21 2000
+++ linux/net/ipv6/exthdrs.c	Thu Apr 12 12:11:39 2001
@@ -7,7 +7,7 @@
  *	Andi Kleen		<ak@muc.de>
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: exthdrs.c,v 1.10 2000/01/09 02:19:55 davem Exp $
+ *	$Id: exthdrs.c,v 1.12 2001/01/22 02:36:37 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -15,6 +15,11 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+/* Changes:
+ *	yoshfuji		: ensure not to overrun while parsing 
+ *				  tlv options.
+ */
+
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -41,15 +46,15 @@
 /*
  *	Parsing inbound headers.
  *
- *	Parsing function "func" returns pointer to the place,
+ *	Parsing function "func" returns offset wrt skb->nh of the place,
  *	where next nexthdr value is stored or NULL, if parsing
- *	failed. It should also update skb->h.
+ *	failed. It should also update skb->h tp point at the next header.
  */
 
 struct hdrtype_proc
 {
 	int	type;
-	u8*	(*func) (struct sk_buff **, u8 *ptr);
+	int	(*func) (struct sk_buff **, int offset);
 };
 
 /*
@@ -63,7 +68,7 @@
 struct tlvtype_proc
 {
 	int	type;
-	int	(*func) (struct sk_buff *, __u8 *ptr);
+	int	(*func) (struct sk_buff *, int offset);
 };
 
 /*********************
@@ -72,12 +77,12 @@
 
 /* An unknown option is detected, decide what to do */
 
-int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt)
+int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
 {
-	switch ((opt[0] & 0xC0) >> 6) {
+	switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
 	case 0: /* ignore */
 		return 1;
-		
+
 	case 1: /* drop packet */
 		break;
 
@@ -88,7 +93,7 @@
 		if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
 			break;
 	case 2: /* send ICMP PARM PROB regardless and drop packet */
-		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, opt);
+		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
 		return 0;
 	};
 
@@ -98,24 +103,21 @@
 
 /* Parse tlv encoded option header (hop-by-hop or destination) */
 
-static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
-			 __u8 *nhptr)
+static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
 {
 	struct tlvtype_proc *curr;
-	u8 *ptr = skb->h.raw;
-	int len = ((ptr[1]+1)<<3) - 2;
+	int off = skb->h.raw - skb->nh.raw;
+	int len = ((skb->h.raw[1]+1)<<3);
 
-	ptr += 2;
+	if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
+		goto bad;
 
-	if (skb->tail - (ptr + len) < 0) {
-		kfree_skb(skb);
-		return 0;
-	}
+	len -= 2;
 
 	while (len > 0) {
-		int optlen = ptr[1]+2;
+		int optlen = skb->nh.raw[off+1]+2;
 
-		switch (ptr[0]) {
+		switch (skb->nh.raw[off]) {
 		case IPV6_TLV_PAD0:
 			optlen = 1;
 			break;
@@ -124,24 +126,30 @@
 			break;
 
 		default: /* Other TLV code so scan list */
+			if (optlen > len)
+				goto bad;
 			for (curr=procs; curr->type >= 0; curr++) {
-				if (curr->type == ptr[0]) {
-					if (curr->func(skb, ptr) == 0)
+				if (curr->type == skb->nh.raw[off]) {
+					/* type specific length/alignment 
+					   checks will be perfomed in the 
+					   func(). */
+					if (curr->func(skb, off) == 0)
 						return 0;
 					break;
 				}
 			}
 			if (curr->type < 0) {
-				if (ip6_tlvopt_unknown(skb, ptr) == 0)
+				if (ip6_tlvopt_unknown(skb, off) == 0)
 					return 0;
 			}
 			break;
 		}
-		ptr += optlen;
+		off += optlen;
 		len -= optlen;
 	}
 	if (len == 0)
 		return 1;
+bad:
 	kfree_skb(skb);
 	return 0;
 }
@@ -155,37 +163,42 @@
 	{-1,			NULL}
 };
 
-static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr)
+static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff)
 {
 	struct sk_buff *skb=*skb_ptr;
 	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
-	struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
 
-	opt->dst1 = (u8*)hdr - skb->nh.raw;
+	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
+	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
+		kfree_skb(skb);
+		return -1;
+	}
+
+	opt->dst1 = skb->h.raw - skb->nh.raw;
 
-	if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) {
-		skb->h.raw += ((hdr->hdrlen+1)<<3);
-		return &hdr->nexthdr;
+	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
+		skb->h.raw += ((skb->h.raw[1]+1)<<3);
+		return opt->dst1;
 	}
 
-	return NULL;
+	return -1;
 }
 
 /********************************
   NONE header. No data in packet.
  ********************************/
 
-static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr)
+static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff)
 {
 	kfree_skb(*skb_ptr);
-	return NULL;
+	return -1;
 }
 
 /********************************
   Routing header.
  ********************************/
 
-static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr)
+static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
 {
 	struct sk_buff *skb = *skb_ptr;
 	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
@@ -194,36 +207,38 @@
 	int addr_type;
 	int n, i;
 
-	struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw;
+	struct ipv6_rt_hdr *hdr;
 	struct rt0_hdr *rthdr;
 
-	if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) {
+	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
+	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
 		IP6_INC_STATS_BH(Ip6InHdrErrors);
 		kfree_skb(skb);
-		return NULL;
+		return -1;
+	}
+
+	hdr = (struct ipv6_rt_hdr *) skb->h.raw;
+
+	if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||
+	    skb->pkt_type != PACKET_HOST) {
+		kfree_skb(skb);
+		return -1;
 	}
 
 looped_back:
 	if (hdr->segments_left == 0) {
-		opt->srcrt = (u8*)hdr - skb->nh.raw;
+		opt->srcrt = skb->h.raw - skb->nh.raw;
 		skb->h.raw += (hdr->hdrlen + 1) << 3;
 		opt->dst0 = opt->dst1;
 		opt->dst1 = 0;
-		return &hdr->nexthdr;		
+		return (&hdr->nexthdr) - skb->nh.raw;
 	}
 
-	if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) {
-		u8 *pos = (u8*) hdr;
-
-		if (hdr->type != IPV6_SRCRT_TYPE_0)
-			pos += 2;
-		else
-			pos += 1;
-
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos);
-		return NULL;	
+	if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
+		return -1;
 	}
-	
+
 	/*
 	 *	This is the routing header forwarding algorithm from
 	 *	RFC 1883, page 17.
@@ -232,8 +247,8 @@
 	n = hdr->hdrlen >> 1;
 
 	if (hdr->segments_left > n) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left);
-		return NULL;
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
+		return -1;
 	}
 
 	/* We are about to mangle packet header. Be careful!
@@ -243,12 +258,15 @@
 		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
 		kfree_skb(skb);
 		if (skb2 == NULL)
-			return NULL;
+			return -1;
 		*skb_ptr = skb = skb2;
 		opt = (struct inet6_skb_parm *)skb2->cb;
 		hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
 	}
 
+	if (skb->ip_summed == CHECKSUM_HW)
+		skb->ip_summed = CHECKSUM_NONE;
+
 	i = n - --hdr->segments_left;
 
 	rthdr = (struct rt0_hdr *) hdr;
@@ -257,9 +275,9 @@
 
 	addr_type = ipv6_addr_type(addr);
 
-	if (addr_type == IPV6_ADDR_MULTICAST) {
+	if (addr_type&IPV6_ADDR_MULTICAST) {
 		kfree_skb(skb);
-		return NULL;
+		return -1;
 	}
 
 	ipv6_addr_copy(&daddr, addr);
@@ -270,21 +288,21 @@
 	ip6_route_input(skb);
 	if (skb->dst->error) {
 		skb->dst->input(skb);
-		return NULL;
+		return -1;
 	}
 	if (skb->dst->dev->flags&IFF_LOOPBACK) {
 		if (skb->nh.ipv6h->hop_limit <= 1) {
 			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
 				    0, skb->dev);
 			kfree_skb(skb);
-			return NULL;
+			return -1;
 		}
 		skb->nh.ipv6h->hop_limit--;
 		goto looped_back;
 	}
 
 	skb->dst->input(skb);
-	return NULL;
+	return -1;
 }
 
 /*
@@ -374,20 +392,30 @@
    and opt->hdrlen is even. Shit!		--ANK (980730)
  */
 
-static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr)
+static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff)
 {
 	struct sk_buff *skb=*skb_ptr;
 	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
-	struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw;
-	int len = (hdr->hdrlen+2)<<2;
+	int len;
+
+	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
+		goto fail;
+
+	len = (skb->h.raw[1]+1)<<2;
 
 	if (len&7)
-		return NULL;
-	opt->auth = (u8*)hdr - skb->nh.raw;
-	if (skb->h.raw + len > skb->tail)
-		return NULL;
+		goto fail;
+
+	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len))
+		goto fail;
+
+	opt->auth = skb->h.raw - skb->nh.raw;
 	skb->h.raw += len;
-	return &hdr->nexthdr;
+	return opt->auth;
+
+fail:
+	kfree_skb(skb);
+	return -1;
 }
 
 /* This list MUST NOT contain entry for NEXTHDR_HOP.
@@ -408,22 +436,22 @@
 	{-1,			NULL}
 };
 
-u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr)
+int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff)
 {
 	struct hdrtype_proc *hdrt;
-	u8 nexthdr = *nhptr;
+	u8 nexthdr = (*skb_in)->nh.raw[nhoff];
 
 restart:
 	for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
 		if (hdrt->type == nexthdr) {
-			if ((nhptr = hdrt->func(skb_in, nhptr)) != NULL) {
-				nexthdr = *nhptr;
+			if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) {
+				nexthdr = (*skb_in)->nh.raw[nhoff];
 				goto restart;
 			}
-			return NULL;
+			return -1;
 		}
 	}
-	return nhptr;
+	return nhoff;
 }
 
 
@@ -433,37 +461,37 @@
 
 /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
 
-static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr)
+static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
 {
-	if (ptr[1] == 2) {
-		((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw;
+	if (skb->nh.raw[optoff+1] == 2) {
+		((struct inet6_skb_parm*)skb->cb)->ra = optoff;
 		return 1;
 	}
 	if (net_ratelimit())
-		printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", ptr[1]);
+		printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]);
 	kfree_skb(skb);
 	return 0;
 }
 
 /* Jumbo payload */
 
-static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr)
+static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
 {
 	u32 pkt_len;
 
-	if (ptr[1] != 4 || ((ptr-skb->nh.raw)&3) != 2) {
+	if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
 		if (net_ratelimit())
-			printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", ptr[1]);
+			printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]);
 		goto drop;
 	}
 
-	pkt_len = ntohl(*(u32*)(ptr+2));
+	pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
 	if (pkt_len < 0x10000) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr+2);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
 		return 0;
 	}
 	if (skb->nh.ipv6h->payload_len) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
 		return 0;
 	}
 
@@ -471,7 +499,11 @@
 		IP6_INC_STATS_BH(Ip6InTruncatedPkts);
 		goto drop;
 	}
-	skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+	if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
+		__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+		if (skb->ip_summed == CHECKSUM_HW)
+			skb->ip_summed = CHECKSUM_NONE;
+	}
 	return 1;
 
 drop:
@@ -485,12 +517,12 @@
 	{-1,			NULL}
 };
 
-u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr)
+int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
 {
 	((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr);
-	if (ip6_parse_tlv(tlvprochopopt_lst, skb, nhptr))
-		return nhptr+((nhptr[1]+1)<<3);
-	return NULL;
+	if (ip6_parse_tlv(tlvprochopopt_lst, skb))
+		return sizeof(struct ipv6hdr);
+	return -1;
 }
 
 /*
@@ -684,7 +716,7 @@
  * find out if nexthdr is a well-known extension header or a protocol
  */
 
-static __inline__ int ipv6_ext_hdr(u8 nexthdr)
+int ipv6_ext_hdr(u8 nexthdr)
 {
 	/* 
 	 * find out if nexthdr is an extension header or a protocol
@@ -739,33 +771,36 @@
  * --ANK (980726)
  */
 
-u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len)
+int ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len)
 {
 	u8 nexthdr = *nexthdrp;
 
 	while (ipv6_ext_hdr(nexthdr)) {
-		int hdrlen; 
+		struct ipv6_opt_hdr hdr;
+		int hdrlen;
 
-		if (len < sizeof(struct ipv6_opt_hdr))
-			return NULL;
+		if (len < (int)sizeof(struct ipv6_opt_hdr))
+			return -1;
 		if (nexthdr == NEXTHDR_NONE)
-			return NULL;
+			return -1;
+		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+			BUG();
 		if (nexthdr == NEXTHDR_FRAGMENT) {
-			struct frag_hdr *fhdr = (struct frag_hdr *) hdr;
+			struct frag_hdr *fhdr = (struct frag_hdr *) &hdr;
 			if (ntohs(fhdr->frag_off) & ~0x7)
 				break;
 			hdrlen = 8;
 		} else if (nexthdr == NEXTHDR_AUTH)
-			hdrlen = (hdr->hdrlen+2)<<2; 
+			hdrlen = (hdr.hdrlen+2)<<2; 
 		else
-			hdrlen = ipv6_optlen(hdr); 
+			hdrlen = ipv6_optlen(&hdr); 
 
-		nexthdr = hdr->nexthdr;
-		hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen);
+		nexthdr = hdr.nexthdr;
 		len -= hdrlen;
+		start += hdrlen;
 	}
 
 	*nexthdrp = nexthdr;
-	return (u8*)hdr;
+	return start;
 }
 
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
--- v2.4.3/linux/net/ipv6/icmp.c	Mon Jan  1 11:01:58 2001
+++ linux/net/ipv6/icmp.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: icmp.c,v 1.28 2000/03/25 01:55:20 davem Exp $
+ *	$Id: icmp.c,v 1.31 2001/01/22 02:36:37 davem Exp $
  *
  *	Based on net/ipv4/icmp.c
  *
@@ -23,6 +23,8 @@
  *	Andi Kleen		:	exception handling
  *	Andi Kleen			add rate limits. never reply to a icmp.
  *					add more length checks and other fixes.
+ *	yoshfuji		:	ensure to sent parameter problem for
+ *					fragments.
  */
 
 #define __NO_VERSION__
@@ -66,7 +68,7 @@
 
 struct socket *icmpv6_socket;
 
-int icmpv6_rcv(struct sk_buff *skb, unsigned long len);
+int icmpv6_rcv(struct sk_buff *skb);
 
 static struct inet6_protocol icmpv6_protocol = 
 {
@@ -81,7 +83,8 @@
 
 struct icmpv6_msg {
 	struct icmp6hdr		icmph;
-	__u8 			*data;
+	struct sk_buff		*skb;
+	int			offset;
 	struct in6_addr		*daddr;
 	int			len;
 	__u32			csum;
@@ -136,19 +139,10 @@
 	struct icmp6hdr *icmph;
 	__u32 csum;
 
-	/* 
-	 *	in theory offset must be 0 since we never send more 
-	 *	than IPV6_MIN_MTU bytes on an error or more than the path mtu
-	 *	on an echo reply. (those are the rules on RFC 1883)
-	 *
-	 * 	Luckily, this statement is obsolete after
-	 *	draft-ietf-ipngwg-icmp-v2-00           --ANK (980730)
-	 */
-
 	if (offset) {
-		csum = csum_partial_copy_nocheck((void *) msg->data +
-						 offset - sizeof(struct icmp6hdr), 
-						 buff, len, msg->csum);
+		csum = skb_copy_and_csum_bits(msg->skb, msg->offset +
+					      (offset - sizeof(struct icmp6hdr)),
+					      buff, len, msg->csum);
 		msg->csum = csum;
 		return 0;
 	}
@@ -156,9 +150,9 @@
 	csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff,
 					 sizeof(struct icmp6hdr), msg->csum);
 
-	csum = csum_partial_copy_nocheck((void *) msg->data, 
-					 buff + sizeof(struct icmp6hdr),
-					 len - sizeof(struct icmp6hdr), csum);
+	csum = skb_copy_and_csum_bits(msg->skb, msg->offset,
+				      buff + sizeof(struct icmp6hdr),
+				      len - sizeof(struct icmp6hdr), csum);
 
 	icmph = (struct icmp6hdr *) buff;
 
@@ -171,11 +165,9 @@
 /* 
  * Slightly more convenient version of icmpv6_send.
  */
-void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos)
+void icmpv6_param_prob(struct sk_buff *skb, int code, int pos)
 {
-	int offset = (u8*)pos - (u8*)skb->nh.ipv6h; 
-	
-	icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev);
+	icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
 	kfree_skb(skb);
 }
 
@@ -186,29 +178,30 @@
  *	- it was icmp error message.
  *	- it is truncated, so that it is known, that protocol is ICMPV6
  *	  (i.e. in the middle of some exthdr)
- *	- it is not the first fragment. BTW IPv6 specs say nothing about
- *	  this case, but it is clear, that our reply would be useless
- *	  for sender.
  *
  *	--ANK (980726)
  */
 
-static int is_ineligible(struct ipv6hdr *hdr, int len)
+static int is_ineligible(struct sk_buff *skb)
 {
-	u8 *ptr;
-	__u8 nexthdr = hdr->nexthdr;
+	int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
+	int len = skb->len - ptr;
+	__u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
-	if (len < (int)sizeof(*hdr))
+	if (len < 0)
 		return 1;
 
-	ptr = ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len - sizeof(*hdr));
-	if (!ptr)
+	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
+	if (ptr < 0)
 		return 0;
 	if (nexthdr == IPPROTO_ICMPV6) {
-		struct icmp6hdr *ihdr =	(struct icmp6hdr *)ptr;
-		return (ptr - (u8*)hdr) > len || !(ihdr->icmp6_type & 0x80); 
+		u8 type;
+		if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type),
+				  &type, 1)
+		    || !(type & 0x80))
+			return 1;
 	}
-	return nexthdr == NEXTHDR_FRAGMENT;
+	return 0;
 }
 
 int sysctl_icmpv6_time = 1*HZ; 
@@ -263,9 +256,12 @@
 
 static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
 {
-	u8 *buff = skb->nh.raw;
+	u8 optval;
 
-	return ( ( *(buff + offset) & 0xC0 ) == 0x80 );
+	offset += skb->nh.raw - skb->data;
+	if (skb_copy_bits(skb, offset, &optval, 1))
+		return 1;
+	return (optval&0xC0) == 0x80;
 }
 
 /*
@@ -284,15 +280,8 @@
 	int addr_type = 0;
 	int len;
 
-	/*
-	 *	sanity check pointer in case of parameter problem
-	 */
-
-	if (type == ICMPV6_PARAMPROB && 
-	    (info > (skb->tail - ((unsigned char *) hdr)))) {
-		printk(KERN_DEBUG "icmpv6_send: bug! pointer > skb\n");
+	if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
 		return;
-	}
 
 	/*
 	 *	Make sure we respect the rules 
@@ -300,7 +289,6 @@
 	 *	Rule (e.1) is enforced by not using icmpv6_send
 	 *	in any code that processes icmp errors.
 	 */
-	
 	addr_type = ipv6_addr_type(&hdr->daddr);
 
 	if (ipv6_chk_addr(&hdr->daddr, skb->dev))
@@ -341,9 +329,9 @@
 	/* 
 	 *	Never answer to a ICMP packet.
 	 */
-	if (is_ineligible(hdr, (u8*)skb->tail - (u8*)hdr)) {
+	if (is_ineligible(skb)) {
 		if (net_ratelimit())
-			printk(KERN_DEBUG "icmpv6_send: no reply to icmp error/fragment\n"); 
+			printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); 
 		return;
 	}
 
@@ -371,12 +359,13 @@
 	msg.icmph.icmp6_cksum = 0;
 	msg.icmph.icmp6_pointer = htonl(info);
 
-	msg.data = skb->nh.raw;
+	msg.skb = skb;
+	msg.offset = skb->nh.raw - skb->data;
 	msg.csum = 0;
 	msg.daddr = &hdr->saddr;
 
-	len = min((skb->tail - ((unsigned char *) hdr)) + sizeof(struct icmp6hdr), 
-		  IPV6_MIN_MTU - sizeof(struct ipv6hdr));
+	len = skb->len - msg.offset + sizeof(struct icmp6hdr);
+	len = min(len, IPV6_MIN_MTU - sizeof(struct ipv6hdr));
 
 	if (len < 0) {
 		printk(KERN_DEBUG "icmp: len problem\n");
@@ -397,37 +386,30 @@
 static void icmpv6_echo_reply(struct sk_buff *skb)
 {
 	struct sock *sk = icmpv6_socket->sk;
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
 	struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
 	struct in6_addr *saddr;
 	struct icmpv6_msg msg;
 	struct flowi fl;
-	unsigned char *data;
-	int len;
-
-	data = (char *) (icmph + 1);
 
-	saddr = &hdr->daddr;
+	saddr = &skb->nh.ipv6h->daddr;
 
 	if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST)
 		saddr = NULL;
 
-	len = skb->tail - data;
-	len += sizeof(struct icmp6hdr);
-
 	msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
 	msg.icmph.icmp6_code = 0;
 	msg.icmph.icmp6_cksum = 0;
 	msg.icmph.icmp6_identifier = icmph->icmp6_identifier;
 	msg.icmph.icmp6_sequence = icmph->icmp6_sequence;
 
-	msg.data = data;
+	msg.skb = skb;
+	msg.offset = 0;
 	msg.csum = 0;
-	msg.len = len;
-	msg.daddr = &hdr->saddr;
+	msg.len = skb->len + sizeof(struct icmp6hdr);
+	msg.daddr =  &skb->nh.ipv6h->saddr;
 
 	fl.proto = IPPROTO_ICMPV6;
-	fl.nl_u.ip6_u.daddr = &hdr->saddr;
+	fl.nl_u.ip6_u.daddr = msg.daddr;
 	fl.nl_u.ip6_u.saddr = saddr;
 	fl.oif = skb->dev->ifindex;
 	fl.fl6_flowlabel = 0;
@@ -437,7 +419,7 @@
 	if (icmpv6_xmit_lock_bh())
 		return;
 
-	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
+	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
 		       MSG_DONTWAIT);
 	ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
 	ICMP6_INC_STATS_BH(Icmp6OutMsgs);
@@ -445,29 +427,35 @@
 	icmpv6_xmit_unlock_bh();
 }
 
-static void icmpv6_notify(struct sk_buff *skb,
-			  int type, int code, u32 info, unsigned char *buff, int len)
+static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
 {
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
-	struct ipv6hdr *hdr = (struct ipv6hdr *) buff;
+	struct in6_addr *saddr, *daddr;
 	struct inet6_protocol *ipprot;
 	struct sock *sk;
-	u8 *pb;
+	int inner_offset;
 	int hash;
 	u8 nexthdr;
 
-	nexthdr = hdr->nexthdr;
-
-	len -= sizeof(struct ipv6hdr);
-	if (len < 0)
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		return;
 
-	/* now skip over extension headers */
-	pb = ipv6_skip_exthdr((struct ipv6_opt_hdr *) (hdr + 1), &nexthdr, len);
-	if (!pb)
+	nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
+	if (ipv6_ext_hdr(nexthdr)) {
+		/* now skip over extension headers */
+		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr));
+		if (inner_offset<0)
+			return;
+	} else {
+		inner_offset = sizeof(struct ipv6hdr);
+	}
+
+	/* Checkin header including 8 bytes of inner protocol header. */
+	if (!pskb_may_pull(skb, inner_offset+8))
 		return;
 
+	saddr = &skb->nh.ipv6h->saddr;
+	daddr = &skb->nh.ipv6h->daddr;
+
 	/* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
 	   Without this we will not able f.e. to make source routed
 	   pmtu discovery.
@@ -484,13 +472,13 @@
 			continue;
 
 		if (ipprot->err_handler)
-			ipprot->err_handler(skb, hdr, NULL, type, code, pb, info);
+			ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
 	}
 
 	read_lock(&raw_v6_lock);
 	if ((sk = raw_v6_htable[hash]) != NULL) {
 		while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
-			rawv6_err(sk, skb, hdr, NULL, type, code, pb, info);
+			rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
 			sk = sk->next;
 		}
 	}
@@ -501,28 +489,31 @@
  *	Handle icmp messages
  */
 
-int icmpv6_rcv(struct sk_buff *skb, unsigned long len)
+int icmpv6_rcv(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+	struct in6_addr *saddr, *daddr;
 	struct ipv6hdr *orig_hdr;
-	struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
-	int ulen;
+	struct icmp6hdr *hdr;
 	int type;
 
 	ICMP6_INC_STATS_BH(Icmp6InMsgs);
 
-	if (len < sizeof(struct icmp6hdr))
-		goto discard_it;
+	saddr = &skb->nh.ipv6h->saddr;
+	daddr = &skb->nh.ipv6h->daddr;
 
 	/* Perform checksum. */
-	switch (skb->ip_summed) {	
-	case CHECKSUM_NONE:
-		skb->csum = csum_partial((char *)hdr, len, 0);
-	case CHECKSUM_HW:
-		if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, 
+	if (skb->ip_summed == CHECKSUM_HW) {
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
 				    skb->csum)) {
+			printk(KERN_DEBUG "ICMPv6 hw checksum failed\n");
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+	}
+	if (skb->ip_summed == CHECKSUM_NONE) {
+		if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
+				    skb_checksum(skb, 0, skb->len, 0))) {
 			printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
 				ntohs(saddr->in6_u.u6_addr16[0]),
 				ntohs(saddr->in6_u.u6_addr16[1]),
@@ -542,14 +533,12 @@
 				ntohs(daddr->in6_u.u6_addr16[7]));
 			goto discard_it;
 		}
-	default:;
-		/* CHECKSUM_UNNECESSARY */
-	};
+	}
 
-	/*
-	 *	length of original packet carried in skb
-	 */
-	ulen = skb->tail - (unsigned char *) (hdr + 1);
+	if (!pskb_pull(skb, sizeof(struct icmp6hdr)))
+		goto discard_it;
+
+	hdr = (struct icmp6hdr *) skb->h.raw;
 
 	type = hdr->icmp6_type;
 
@@ -559,7 +548,6 @@
 		(&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++;
 
 	switch (type) {
-
 	case ICMPV6_ECHO_REQUEST:
 		icmpv6_echo_reply(skb);
 		break;
@@ -574,10 +562,12 @@
 		   destination cache will allow to solve this problem
 		   --ANK (980726)
 		 */
+		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+			goto discard_it;
+		hdr = (struct icmp6hdr *) skb->data;
 		orig_hdr = (struct ipv6hdr *) (hdr + 1);
-		if (ulen >= sizeof(struct ipv6hdr))
-			rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
-					   ntohl(hdr->icmp6_mtu));
+		rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
+				   ntohl(hdr->icmp6_mtu));
 
 		/*
 		 *	Drop through to notify
@@ -586,8 +576,7 @@
 	case ICMPV6_DEST_UNREACH:
 	case ICMPV6_TIME_EXCEED:
 	case ICMPV6_PARAMPROB:
-		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu,
-			      (char *) (hdr + 1), ulen);
+		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
 		break;
 
 	case NDISC_ROUTER_SOLICITATION:
@@ -595,15 +584,21 @@
 	case NDISC_NEIGHBOUR_SOLICITATION:
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
 	case NDISC_REDIRECT:
-		ndisc_rcv(skb, len);
+		if (skb_is_nonlinear(skb) &&
+		    skb_linearize(skb, GFP_ATOMIC) != 0) {
+			kfree_skb(skb);
+			return 0;
+		}
+
+		ndisc_rcv(skb);
 		break;
 
 	case ICMPV6_MGM_QUERY:
-		igmp6_event_query(skb, hdr, len);
+		igmp6_event_query(skb);
 		break;
 
 	case ICMPV6_MGM_REPORT:
-		igmp6_event_report(skb, hdr, len);
+		igmp6_event_report(skb);
 		break;
 
 	case ICMPV6_MGM_REDUCTION:
@@ -612,7 +607,7 @@
 	default:
 		if (net_ratelimit())
 			printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
-		
+
 		/* informational */
 		if (type & 0x80)
 			break;
@@ -622,8 +617,7 @@
 		 * must pass to upper level 
 		 */
 
-		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu,
-			      (char *) (hdr + 1), ulen);
+		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
 	};
 	kfree_skb(skb);
 	return 0;
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c
--- v2.4.3/linux/net/ipv6/ip6_input.c	Mon Dec 11 12:37:04 2000
+++ linux/net/ipv6/ip6_input.c	Thu Apr 12 12:11:39 2001
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *	Ian P. Morris		<I.P.Morris@soton.ac.uk>
  *
- *	$Id: ip6_input.c,v 1.18 2000/12/08 17:15:54 davem Exp $
+ *	$Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $
  *
  *	Based in linux/net/ipv4/ip_input.c
  *
@@ -44,7 +44,6 @@
 
 static inline int ip6_rcv_finish( struct sk_buff *skb) 
 {
-
 	if (skb->dst == NULL)
 		ip6_route_input(skb);
 
@@ -69,9 +68,15 @@
 	 */
 	((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex;
 
+	if (skb->len < sizeof(struct ipv6hdr))
+		goto err;
+
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+		goto drop;
+
 	hdr = skb->nh.ipv6h;
 
-	if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6)
+	if (hdr->version != 6)
 		goto err;
 
 	pkt_len = ntohs(hdr->payload_len);
@@ -80,16 +85,24 @@
 	if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
 		if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
 			goto truncated;
-		skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+		if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
+			if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)))
+				goto drop;
+			hdr = skb->nh.ipv6h;
+			if (skb->ip_summed == CHECKSUM_HW)
+				skb->ip_summed = CHECKSUM_NONE;
+		}
 	}
 
 	if (hdr->nexthdr == NEXTHDR_HOP) {
 		skb->h.raw = (u8*)(hdr+1);
-		if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) {
+		if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
 			IP6_INC_STATS_BH(Ip6InHdrErrors);
 			return 0;
 		}
+		hdr = skb->nh.ipv6h;
 	}
+
 	return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
 truncated:
 	IP6_INC_STATS_BH(Ip6InTruncatedPkts);
@@ -111,12 +124,11 @@
 	struct ipv6hdr *hdr = skb->nh.ipv6h;
 	struct inet6_protocol *ipprot;
 	struct sock *raw_sk;
-	__u8 *nhptr;
+	int nhoff;
 	int nexthdr;
 	int found = 0;
 	u8 hash;
-	int len;
-	
+
 	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
 
 	/*
@@ -124,13 +136,13 @@
 	 */
 
 	nexthdr = hdr->nexthdr;
-	nhptr = &hdr->nexthdr;
+	nhoff = offsetof(struct ipv6hdr, nexthdr);
 
 	/* Skip  hop-by-hop options, they are already parsed. */
 	if (nexthdr == NEXTHDR_HOP) {
-		nhptr = (u8*)(hdr+1);
-		nexthdr = *nhptr;
-		skb->h.raw += (nhptr[1]+1)<<3;
+		nhoff = sizeof(struct ipv6hdr);
+		nexthdr = skb->h.raw[0];
+		skb->h.raw += (skb->h.raw[1]+1)<<3;
 	}
 
 	/* This check is sort of optimization.
@@ -138,17 +150,23 @@
 	   which are missing with probability of 200%
 	 */
 	if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
-		nhptr = ipv6_parse_exthdrs(&skb, nhptr);
-		if (nhptr == NULL)
+		nhoff = ipv6_parse_exthdrs(&skb, nhoff);
+		if (nhoff < 0)
 			return 0;
-		nexthdr = *nhptr;
+		nexthdr = skb->nh.raw[nhoff];
 		hdr = skb->nh.ipv6h;
 	}
-	len = skb->tail - skb->h.raw;
+
+	if (!pskb_pull(skb, skb->h.raw - skb->data))
+		goto discard;
+
+	if (skb->ip_summed == CHECKSUM_HW)
+		skb->csum = csum_sub(skb->csum,
+				     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
 
 	raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
 	if (raw_sk)
-		raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
+		raw_sk = ipv6_raw_deliver(skb, nexthdr);
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
 	for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
@@ -163,12 +181,12 @@
 			buff = skb_clone(skb, GFP_ATOMIC);
 
 		if (buff)
-			ipprot->handler(buff, len);
+			ipprot->handler(buff);
 		found = 1;
 	}
 
 	if (raw_sk) {
-		rawv6_rcv(raw_sk, skb, len);
+		rawv6_rcv(raw_sk, skb);
 		sock_put(raw_sk);
 		found = 1;
 	}
@@ -178,9 +196,13 @@
 	 */
 	if (!found) {
 		IP6_INC_STATS_BH(Ip6InUnknownProtos);
-		icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr);
+		icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
 	}
 
+	return 0;
+
+discard:
+	kfree_skb(skb);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c
--- v2.4.3/linux/net/ipv6/ip6_output.c	Thu Jun 22 07:23:26 2000
+++ linux/net/ipv6/ip6_output.c	Thu Apr 19 08:38:50 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_output.c,v 1.27 2000/06/21 17:18:40 davem Exp $
+ *	$Id: ip6_output.c,v 1.31 2001/04/17 20:39:51 davem Exp $
  *
  *	Based on linux/net/ipv4/ip_output.c
  *
@@ -22,6 +22,7 @@
  *				etc.
  *
  *      H. von Brand    :       Added missing #include <linux/string.h>
+ *	Imran Patel	: 	frag id should be in NBO
  */
 
 #include <linux/config.h>
@@ -55,7 +56,7 @@
 	static spinlock_t ip6_id_lock = SPIN_LOCK_UNLOCKED;
 
 	spin_lock_bh(&ip6_id_lock);
-	fhdr->identification = ipv6_fragmentation_id;
+	fhdr->identification = htonl(ipv6_fragmentation_id);
 	if (++ipv6_fragmentation_id == 0)
 		ipv6_fragmentation_id = 1;
 	spin_unlock_bh(&ip6_id_lock);
@@ -85,7 +86,7 @@
 static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
 {
 	newskb->mac.raw = newskb->data;
-	skb_pull(newskb, newskb->nh.raw - newskb->data);
+	__skb_pull(newskb, newskb->nh.raw - newskb->data);
 	newskb->pkt_type = PACKET_LOOPBACK;
 	newskb->ip_summed = CHECKSUM_UNNECESSARY;
 	BUG_TRAP(newskb->dst);
@@ -113,7 +114,7 @@
 			   is not supported in any case.
 			 */
 			if (newskb)
-				NF_HOOK(PF_INET, NF_IP6_POST_ROUTING, newskb, NULL,
+				NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, newskb, NULL,
 					newskb->dev,
 					ip6_dev_loopback_xmit);
 
@@ -405,7 +406,7 @@
 
 	last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len +
 				       dst->dev->hard_header_len + 15,
-				       0, flags & MSG_DONTWAIT, &err);
+				       flags & MSG_DONTWAIT, &err);
 
 	if (last_skb == NULL)
 		return err;
@@ -624,7 +625,7 @@
 			goto out;
 
 		skb = sock_alloc_send_skb(sk, pktlength + 15 +
-					  dev->hard_header_len, 0,
+					  dev->hard_header_len,
 					  flags & MSG_DONTWAIT, &err);
 
 		if (skb == NULL) {
@@ -697,14 +698,14 @@
 			if (last) {
 				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 				if (skb2)
-					rawv6_rcv(last, skb2, skb2->len);
+					rawv6_rcv(last, skb2);
 			}
 			last = sk;
 		}
 	}
 
 	if (last) {
-		rawv6_rcv(last, skb, skb->len);
+		rawv6_rcv(last, skb);
 		read_unlock(&ip6_ra_lock);
 		return 1;
 	}
@@ -724,7 +725,9 @@
 	struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb;
 	
 	if (ipv6_devconf.forwarding == 0 && opt->srcrt == 0)
-		goto drop;
+		goto error;
+
+	skb->ip_summed = CHECKSUM_NONE;
 
 	/*
 	 *	We DO NOT make any processing on
@@ -785,7 +788,7 @@
 	} else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK
 						|IPV6_ADDR_LINKLOCAL)) {
 		/* This check is security critical. */
-		goto drop;
+		goto error;
 	}
 
 	if (skb->len > dst->pmtu) {
@@ -797,8 +800,8 @@
 		return -EMSGSIZE;
 	}
 
-	if ((skb = skb_cow(skb, dst->dev->hard_header_len)) == NULL)
-		return 0;
+	if (skb_cow(skb, dst->dev->hard_header_len))
+		goto drop;
 
 	hdr = skb->nh.ipv6h;
 
@@ -809,8 +812,9 @@
 	IP6_INC_STATS_BH(Ip6OutForwDatagrams);
 	return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
 
-drop:
+error:
 	IP6_INC_STATS_BH(Ip6InAddrErrors);
+drop:
 	kfree_skb(skb);
 	return -EINVAL;
 }
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- v2.4.3/linux/net/ipv6/mcast.c	Mon Sep 18 15:04:13 2000
+++ linux/net/ipv6/mcast.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: mcast.c,v 1.33 2000/09/18 05:59:48 davem Exp $
+ *	$Id: mcast.c,v 1.36 2001/03/03 01:20:10 davem Exp $
  *
  *	Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
  *
@@ -15,6 +15,11 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+/* Changes:
+ *
+ *	yoshfuji	: fix format of router-alert option
+ */
+
 #define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
@@ -392,17 +397,19 @@
 	spin_unlock(&ma->mca_lock);
 }
 
-int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
+int igmp6_event_query(struct sk_buff *skb)
 {
 	struct ifmcaddr6 *ma;
 	struct in6_addr *addrp;
 	unsigned long resptime;
 	struct inet6_dev *idev;
+	struct icmp6hdr *hdr;
 
-
-	if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
+	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
 		return -EINVAL;
 
+	hdr = (struct icmp6hdr*) skb->h.raw;
+
 	/* Drop queries with not link local source */
 	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
@@ -437,19 +444,22 @@
 }
 
 
-int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
+int igmp6_event_report(struct sk_buff *skb)
 {
 	struct ifmcaddr6 *ma;
 	struct in6_addr *addrp;
 	struct inet6_dev *idev;
+	struct icmp6hdr *hdr;
 
 	/* Our own report looped back. Ignore it. */
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		return 0;
 
-	if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
+	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
 		return -EINVAL;
 
+	hdr = (struct icmp6hdr*) skb->h.raw;
+
 	/* Drop reports with not link local source */
 	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
@@ -491,7 +501,7 @@
 	struct in6_addr all_routers;
 	int err, len, payload_len, full_len;
 	u8 ra[8] = { IPPROTO_ICMPV6, 0,
-		     IPV6_TLV_ROUTERALERT, 0, 0, 0,
+		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
 		     IPV6_TLV_PADN, 0 };
 
 	snd_addr = addr;
@@ -504,7 +514,7 @@
 	payload_len = len + sizeof(ra);
 	full_len = sizeof(struct ipv6hdr) + payload_len;
 
-	skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err);
+	skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err);
 
 	if (skb == NULL)
 		return;
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.4.3/linux/net/ipv6/ndisc.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv6/ndisc.c	Wed Apr 25 14:57:39 2001
@@ -338,7 +338,7 @@
 	}
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, 0, &err);
+				  0, &err);
 
 	if (skb == NULL) {
 		ND_PRINTK1("send_na: alloc skb failed\n");
@@ -397,7 +397,7 @@
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, 0, &err);
+				  0, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
 		return;
@@ -458,7 +458,7 @@
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
         skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, 0, &err);
+				  0, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
 		return;
@@ -869,7 +869,7 @@
  	}
 
 	buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				   0, 0, &err);
+				   0, &err);
 	if (buff == NULL) {
 		ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n");
 		return;
@@ -957,11 +957,11 @@
 
 static void pndisc_redo(struct sk_buff *skb)
 {
-	ndisc_rcv(skb, skb->len);
+	ndisc_rcv(skb);
 	kfree_skb(skb);
 }
 
-int ndisc_rcv(struct sk_buff *skb, unsigned long len)
+int ndisc_rcv(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
 	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
@@ -970,6 +970,8 @@
 	struct neighbour *neigh;
 	struct inet6_ifaddr *ifp;
 
+	__skb_push(skb, skb->data-skb->h.raw);
+
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
 		if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
@@ -1073,7 +1075,7 @@
 		return 0;
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
-		if ((ipv6_addr_type(saddr)&IPV6_ADDR_MULTICAST) &&
+		if ((ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST) &&
 		    msg->icmph.icmp6_solicited) {
 			ND_PRINTK0("NDISC: solicited NA is multicasted\n");
 			return 0;
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
--- v2.4.3/linux/net/ipv6/netfilter/Makefile	Mon Jan 22 13:30:21 2001
+++ linux/net/ipv6/netfilter/Makefile	Thu Apr 19 14:10:22 2001
@@ -9,7 +9,6 @@
 
 O_TARGET := netfilter.o
 
-multi-objs :=
 export-objs :=
 
 # Link order matters here.
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.4.3/linux/net/ipv6/raw.c	Fri Feb  9 11:29:44 2001
+++ linux/net/ipv6/raw.c	Thu Apr 12 12:11:39 2001
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.42 2000/11/28 13:38:38 davem Exp $
+ *	$Id: raw.c,v 1.45 2001/02/18 09:10:42 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -116,8 +116,11 @@
 	struct raw6_opt *opt;
 
 	opt = &sk->tp_pinfo.tp_raw;
-	icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1);
-	return test_bit(icmph->icmp6_type, &opt->filter);
+	if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) {
+		icmph = (struct icmp6hdr *) skb->data;
+		return test_bit(icmph->icmp6_type, &opt->filter);
+	}
+	return 0;
 }
 
 /*
@@ -125,8 +128,7 @@
  *	(should consider queueing the skb in the sock receive_queue
  *	without calling rawv6.c)
  */
-struct sock * ipv6_raw_deliver(struct sk_buff *skb,
-			       int nexthdr, unsigned long len)
+struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
 	struct in6_addr *saddr;
 	struct in6_addr *daddr;
@@ -163,7 +165,7 @@
 
 			buff = skb_clone(skb, GFP_ATOMIC);
 			if (buff)
-				rawv6_rcv(sk2, buff, len);
+				rawv6_rcv(sk2, buff);
 		}
 	}
 
@@ -177,8 +179,6 @@
 	return sk;
 }
 
-
-
 /* This cleans up af_inet6 a bit. -DaveM */
 static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
@@ -239,16 +239,13 @@
 	return err;
 }
 
-void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr,
+void rawv6_err(struct sock *sk, struct sk_buff *skb,
 	       struct inet6_skb_parm *opt,
-	       int type, int code, unsigned char *buff, u32 info)
+	       int type, int code, int offset, u32 info)
 {
 	int err;
 	int harderr;
 
-	if (buff > skb->tail)
-		return;
-
 	/* Report error on raw socket, if:
 	   1. User requested recverr.
 	   2. Socket is connected (otherwise the error indication
@@ -261,8 +258,12 @@
 	if (type == ICMPV6_PKT_TOOBIG)
 		harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO);
 
-	if (sk->net_pinfo.af_inet6.recverr)
-		ipv6_icmp_error(sk, skb, err, 0, ntohl(info), buff);
+	if (sk->net_pinfo.af_inet6.recverr) {
+		u8 *payload = skb->data;
+		if (!sk->protinfo.af_inet.hdrincl)
+			payload += offset;
+		ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);
+	}
 
 	if (sk->net_pinfo.af_inet6.recverr || harderr) {
 		sk->err = err;
@@ -290,10 +291,12 @@
  *	maybe we could have the network decide uppon a hint if it 
  *	should call raw_rcv for demultiplexing
  */
-int rawv6_rcv(struct sock *sk, struct sk_buff *skb, unsigned long len)
+int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
 {
-	if (sk->protinfo.af_inet.hdrincl)
+	if (sk->protinfo.af_inet.hdrincl) {
+		__skb_push(skb, skb->nh.raw - skb->data);
 		skb->h.raw = skb->nh.raw;
+	}
 
 	rawv6_rcv_skb(sk, skb);
 	return 0;
@@ -325,7 +328,7 @@
 	if (!skb)
 		goto out;
 
-	copied = skb->tail - skb->h.raw;
+	copied = skb->len;
   	if (copied > len) {
   		copied = len;
   		msg->msg_flags |= MSG_TRUNC;
@@ -594,6 +597,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 --recursive --new-file v2.4.3/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c
--- v2.4.3/linux/net/ipv6/reassembly.c	Sun Mar 25 18:14:25 2001
+++ linux/net/ipv6/reassembly.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: reassembly.c,v 1.22 2000/12/08 17:41:54 davem Exp $
+ *	$Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $
  *
  *	Based on: net/ipv4/ip_fragment.c
  *
@@ -79,11 +79,12 @@
 	int			len;
 	int			meat;
 	int			iif;
+	struct timeval		stamp;
+	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
 #define FIRST_IN		2
 #define LAST_IN			1
-	__u8			nexthdr;
 	__u16			nhoffset;
 	struct frag_queue	**pprev;
 };
@@ -349,7 +350,7 @@
 
 
 static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, 
-			   struct frag_hdr *fhdr, u8 *nhptr)
+			   struct frag_hdr *fhdr, int nhoff)
 {
 	struct sk_buff *prev, *next;
 	int offset, end;
@@ -362,10 +363,14 @@
 			((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
 
 	if ((unsigned int)end >= 65536) {
-		icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off); 
-		goto err;
+ 		icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
+ 		return;
 	}
 
+ 	if (skb->ip_summed == CHECKSUM_HW)
+ 		skb->csum = csum_sub(skb->csum,
+ 				     csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
+
 	/* Is this the final fragment? */
 	if (!(fhdr->frag_off & __constant_htons(0x0001))) {
 		/* If we already have some bits beyond end
@@ -381,16 +386,12 @@
 		 * Required by the RFC.
 		 */
 		if (end & 0x7) {
-			printk(KERN_DEBUG "fragment not rounded to 8bytes\n");
-
-			/*
-			   It is not in specs, but I see no reasons
-			   to send an error in this case. --ANK
+			/* RFC2460 says always send parameter problem in
+			 * this case. -DaveM
 			 */
-			if (offset == 0)
-				icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 
-						  &skb->nh.ipv6h->payload_len);
-			goto err;
+			icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 
+					  offsetof(struct ipv6hdr, payload_len));
+			return;
 		}
 		if (end > fq->len) {
 			/* Some bits beyond end -> corruption. */
@@ -404,8 +405,14 @@
 		goto err;
 
 	/* Point into the IP datagram 'data' part. */
-	skb_pull(skb, (u8 *) (fhdr + 1) - skb->data);
-	skb_trim(skb, end - offset);
+	if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data))
+		goto err;
+	if (end-offset < skb->len) {
+		if (pskb_trim(skb, end - offset))
+			goto err;
+		if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+			skb->ip_summed = CHECKSUM_NONE;
+	}
 
 	/* Find out which fragments are in front and at the back of us
 	 * in the chain of fragments so far.  We must know where to put
@@ -429,7 +436,10 @@
 			offset += i;
 			if (end <= offset)
 				goto err;
-			skb_pull(skb, i);
+			if (!pskb_pull(skb, i))
+				goto err;
+			if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+				skb->ip_summed = CHECKSUM_NONE;
 		}
 	}
 
@@ -443,9 +453,12 @@
 			/* Eat head of the next overlapped fragment
 			 * and leave the loop. The next ones cannot overlap.
 			 */
+			if (!pskb_pull(next, i))
+				goto err;
 			FRAG6_CB(next)->offset += i;	/* next fragment */
-			skb_pull(next, i);
 			fq->meat -= i;
+			if (next->ip_summed != CHECKSUM_UNNECESSARY)
+				next->ip_summed = CHECKSUM_NONE;
 			break;
 		} else {
 			struct sk_buff *free_it = next;
@@ -474,20 +487,18 @@
 	else
 		fq->fragments = skb;
 
-	fq->iif = skb->dev->ifindex;
+	if (skb->dev)
+		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
+	fq->stamp = skb->stamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
-	/* First fragment.
-	   nexthdr and nhptr are get from the first fragment.
-	   Moreover, nexthdr is UNDEFINED for all the fragments but the
-	   first one.
-	   (fixed --ANK (980728))
+	/* The first fragment.
+	 * nhoffset is obtained from the first fragment, of course.
 	 */
 	if (offset == 0) {
-		fq->nexthdr = fhdr->nexthdr;
-		fq->nhoffset = nhptr - skb->nh.raw;
+		fq->nhoffset = nhoff;
 		fq->last_in |= FIRST_IN;
 	}
 	return;
@@ -505,21 +516,13 @@
  *	queue is eligible for reassembly i.e. it is not COMPLETE,
  *	the last and the first frames arrived and all the bits are here.
  */
-static u8 *ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
+static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 			  struct net_device *dev)
 {
 	struct sk_buff *fp, *head = fq->fragments;
-	struct sk_buff *skb;
+	int    remove_fraghdr = 0;
 	int    payload_len;
-	int    unfrag_len;
-	int    copy;
-	u8     *nhptr;
-
-	/* 
-	 * we know the m_flag arrived and we have a queue,
-	 * starting from 0, without gaps.
-	 * this means we have all fragments.
-	 */
+	int    nhoff;
 
 	fq_kill(fq);
 
@@ -527,40 +530,86 @@
 	BUG_TRAP(FRAG6_CB(head)->offset == 0);
 
 	/* Unfragmented part is taken from the first segment. */
-	unfrag_len = head->h.raw - (u8 *) (head->nh.ipv6h + 1);
-	payload_len = unfrag_len + fq->len;
+	payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
+	nhoff = head->h.raw - head->nh.raw;
 
-	if (payload_len > 65535)
-		goto out_oversize;
+	if (payload_len > 65535) {
+		payload_len -= 8;
+		if (payload_len > 65535)
+			goto out_oversize;
+		remove_fraghdr = 1;
+	}
 
-	if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL)
+	/* Head of list must not be cloned. */
+	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
 		goto out_oom;
 
-	copy = unfrag_len + sizeof(struct ipv6hdr);
-
-	skb->mac.raw = skb->data;
-	skb->nh.ipv6h = (struct ipv6hdr *) skb->data;
-	skb->dev = dev;
-	skb->protocol = __constant_htons(ETH_P_IPV6);
-	skb->pkt_type = head->pkt_type;
-	FRAG6_CB(skb)->h = FRAG6_CB(head)->h;
-	skb->dst = dst_clone(head->dst);
-
-	memcpy(skb_put(skb, copy), head->nh.ipv6h, copy);
-	nhptr = skb->nh.raw + fq->nhoffset;
-	*nhptr = fq->nexthdr;
-
-	skb->h.raw = skb->tail;
-
-	skb->nh.ipv6h->payload_len = ntohs(payload_len);
-
-	*skb_in = skb;
+	/* If the first fragment is fragmented itself, we split
+	 * it to two chunks: the first with data and paged part
+	 * and the second, holding only fragments. */
+	if (skb_shinfo(head)->frag_list) {
+		struct sk_buff *clone;
+		int i, plen = 0;
+
+		if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
+			goto out_oom;
+		clone->next = head->next;
+		head->next = clone;
+		skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+		skb_shinfo(head)->frag_list = NULL;
+		for (i=0; i<skb_shinfo(head)->nr_frags; i++)
+			plen += skb_shinfo(head)->frags[i].size;
+		clone->len = clone->data_len = head->data_len - plen;
+		head->data_len -= clone->len;
+		head->len -= clone->len;
+		clone->csum = 0;
+		clone->ip_summed = head->ip_summed;
+		atomic_add(clone->truesize, &ip6_frag_mem);
+	}
+
+	/* Normally we do not remove frag header from datagram, but
+	 * we have to do this and to relocate header, when payload
+	 * is > 65535-8. */
+	if (remove_fraghdr) {
+		nhoff = fq->nhoffset;
+		head->nh.raw[nhoff] = head->h.raw[0];
+		memmove(head->head+8, head->head, (head->data-head->head)-8);
+		head->mac.raw += 8;
+		head->nh.raw += 8;
+	} else {
+		((struct frag_hdr*)head->h.raw)->frag_off = 0;
+	}
 
-	for (fp = fq->fragments; fp; fp=fp->next)
-		memcpy(skb_put(skb, fp->len), fp->data, fp->len);
+	skb_shinfo(head)->frag_list = head->next;
+	head->h.raw = head->data;
+	skb_push(head, head->data - head->nh.raw);
+	atomic_sub(head->truesize, &ip6_frag_mem);
+
+	for (fp=head->next; fp; fp = fp->next) {
+		head->data_len += fp->len;
+		head->len += fp->len;
+		if (head->ip_summed != fp->ip_summed)
+			head->ip_summed = CHECKSUM_NONE;
+		else if (head->ip_summed == CHECKSUM_HW)
+			head->csum = csum_add(head->csum, fp->csum);
+		head->truesize += fp->truesize;
+		atomic_sub(fp->truesize, &ip6_frag_mem);
+	}
+
+	head->next = NULL;
+	head->dev = dev;
+	head->stamp = fq->stamp;
+	head->nh.ipv6h->payload_len = ntohs(payload_len);
+
+	*skb_in = head;
+
+	/* Yes, and fold redundant checksum back. 8) */
+	if (head->ip_summed == CHECKSUM_HW)
+		head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
 
 	IP6_INC_STATS_BH(Ip6ReasmOKs);
-	return nhptr;
+	fq->fragments = NULL;
+	return nhoff;
 
 out_oversize:
 	if (net_ratelimit())
@@ -571,14 +620,14 @@
 		printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
 out_fail:
 	IP6_INC_STATS_BH(Ip6ReasmFails);
-	return NULL;
+	return -1;
 }
 
-u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr)
+int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
 {
 	struct sk_buff *skb = *skbp; 
-	struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw);
 	struct net_device *dev = skb->dev;
+	struct frag_hdr *fhdr;
 	struct frag_queue *fq;
 	struct ipv6hdr *hdr;
 
@@ -588,31 +637,34 @@
 
 	/* Jumbo payload inhibits frag. header */
 	if (hdr->payload_len==0) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw);
-		return NULL;
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
+		return -1;
 	}
-	if ((u8 *)(fhdr+1) > skb->tail) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw);
-		return NULL;
+	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
+		return -1;
 	}
 
+	hdr = skb->nh.ipv6h;
+	fhdr = (struct frag_hdr *)skb->h.raw;
+
 	if (!(fhdr->frag_off & __constant_htons(0xFFF9))) {
 		/* It is not a fragmented frame */
 		skb->h.raw += sizeof(struct frag_hdr);
 		IP6_INC_STATS_BH(Ip6ReasmOKs);
 
-		return &fhdr->nexthdr;
+		return (u8*)fhdr - skb->nh.raw;
 	}
 
 	if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
 		ip6_evictor();
 
 	if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) {
-		u8 *ret = NULL;
+		int ret = -1;
 
 		spin_lock(&fq->lock);
 
-		ip6_frag_queue(fq, skb, fhdr, nhptr);
+		ip6_frag_queue(fq, skb, fhdr, nhoff);
 
 		if (fq->last_in == (FIRST_IN|LAST_IN) &&
 		    fq->meat == fq->len)
@@ -625,5 +677,5 @@
 
 	IP6_INC_STATS_BH(Ip6ReasmFails);
 	kfree_skb(skb);
-	return NULL;
+	return -1;
 }
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/sit.c linux/net/ipv6/sit.c
--- v2.4.3/linux/net/ipv6/sit.c	Tue Nov 28 21:53:45 2000
+++ linux/net/ipv6/sit.c	Wed Apr 25 14:57:39 2001
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: sit.c,v 1.47 2000/11/28 13:49:22 davem Exp $
+ *	$Id: sit.c,v 1.50 2001/04/19 22:32:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -229,7 +229,7 @@
 }
 
 
-void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len)
+void ipip6_err(struct sk_buff *skb, u32 info)
 {
 #ifndef I_WISH_WORLD_WERE_PERFECT
 
@@ -237,14 +237,11 @@
    8 bytes of packet payload. It means, that precise relaying of
    ICMP in the real Internet is absolutely infeasible.
  */
-	struct iphdr *iph = (struct iphdr*)dp;
+	struct iphdr *iph = (struct iphdr*)skb->data;
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	struct ip_tunnel *t;
 
-	if (len < sizeof(struct iphdr))
-		return;
-
 	switch (type) {
 	default:
 	case ICMP_PARAMETERPROB:
@@ -382,20 +379,22 @@
 		IP6_ECN_set_ce(skb->nh.ipv6h);
 }
 
-int ipip6_rcv(struct sk_buff *skb, unsigned short len)
+int ipip6_rcv(struct sk_buff *skb)
 {
 	struct iphdr *iph;
 	struct ip_tunnel *tunnel;
 
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+		goto out;
+
 	iph = skb->nh.iph;
 
 	read_lock(&ipip6_lock);
 	if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
 		skb->mac.raw = skb->nh.raw;
-		skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data);
+		skb->nh.raw = skb->data;
 		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
 		skb->protocol = __constant_htons(ETH_P_IPV6);
-		skb->ip_summed = 0;
 		skb->pkt_type = PACKET_HOST;
 		tunnel->stat.rx_packets++;
 		tunnel->stat.rx_bytes += skb->len;
@@ -418,6 +417,7 @@
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
 	kfree_skb(skb);
 	read_unlock(&ipip6_lock);
+out:
 	return 0;
 }
 
@@ -747,8 +747,6 @@
 	dev->do_ioctl		= ipip6_tunnel_ioctl;
 	dev->change_mtu		= ipip6_tunnel_change_mtu;
 
-	dev_init_buffers(dev);
-
 	dev->type		= ARPHRD_SIT;
 	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr);
 	dev->mtu		= 1500 - sizeof(struct iphdr);
@@ -842,7 +840,7 @@
 void sit_cleanup(void)
 {
 	inet_del_protocol(&sit_protocol);
-	unregister_netdevice(&ipip6_fb_tunnel_dev);
+	unregister_netdev(&ipip6_fb_tunnel_dev);
 }
 #endif
 
@@ -852,13 +850,7 @@
 
 	ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel;
 	strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name);
-#ifdef MODULE
 	register_netdev(&ipip6_fb_tunnel_dev);
-#else
-	rtnl_lock();
-	register_netdevice(&ipip6_fb_tunnel_dev);
-	rtnl_unlock();
-#endif
 	inet_add_protocol(&sit_protocol);
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.4.3/linux/net/ipv6/tcp_ipv6.c	Sun Mar 25 18:14:25 2001
+++ linux/net/ipv6/tcp_ipv6.c	Wed Apr 25 14:57:39 2001
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.128 2000/12/08 17:15:54 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.136 2001/04/20 20:46:19 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -635,6 +635,7 @@
 	}
 
 	ip6_dst_store(sk, dst, NULL);
+	sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
 
 	if (saddr == NULL) {
 		err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
@@ -678,25 +679,23 @@
 failure:
 	__sk_dst_reset(sk);
 	sk->dport = 0;
+	sk->route_caps = 0;
 	return err;
 }
 
-void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
-		struct inet6_skb_parm *opt,
-		int type, int code, unsigned char *header, __u32 info)
+void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+		int type, int code, int offset, __u32 info)
 {
+	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
 	struct in6_addr *saddr = &hdr->saddr;
 	struct in6_addr *daddr = &hdr->daddr;
-	struct tcphdr *th = (struct tcphdr *)header;
+	struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
 	struct ipv6_pinfo *np;
 	struct sock *sk;
 	int err;
 	struct tcp_opt *tp; 
 	__u32 seq;
 
-	if (header + 8 > skb->tail)
-		return;
-
 	sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
 
 	if (sk == NULL) {
@@ -914,10 +913,15 @@
 			      struct sk_buff *skb)
 {
 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-	
-	th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 
-				    csum_partial((char *)th, th->doff<<2, 
-						 skb->csum));
+
+	if (skb->ip_summed == CHECKSUM_HW) {
+		th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,  0);
+		skb->csum = offsetof(struct tcphdr, check);
+	} else {
+		th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 
+					    csum_partial((char *)th, th->doff<<2, 
+							 skb->csum));
+	}
 }
 
 
@@ -1298,6 +1302,7 @@
 	MOD_INC_USE_COUNT;
 
 	ip6_dst_store(newsk, dst, NULL);
+	sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
 
 	newtp = &(newsk->tp_pinfo.af_tcp);
 
@@ -1371,22 +1376,20 @@
 static int tcp_v6_checksum_init(struct sk_buff *skb)
 {
 	if (skb->ip_summed == CHECKSUM_HW) {
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+				  &skb->nh.ipv6h->daddr,skb->csum))
+			return 0;
+		NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n"));
+	}
+	if (skb->len <= 76) {
 		if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-				 &skb->nh.ipv6h->daddr,skb->csum)) {
-			NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n"));
+				 &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0)))
 			return -1;
-		}
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else {
-		if (skb->len <= 76) {
-			if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-					 &skb->nh.ipv6h->daddr,csum_partial((char *)skb->h.th, skb->len, 0)))
-				return -1;
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-		} else {
-			skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-						  &skb->nh.ipv6h->daddr,0);
-		}
+		skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+					  &skb->nh.ipv6h->daddr,0);
 	}
 	return 0;
 }
@@ -1526,46 +1529,45 @@
 	return 0;
 }
 
-int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
+int tcp_v6_rcv(struct sk_buff *skb)
 {
 	struct tcphdr *th;	
 	struct sock *sk;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
 	int ret;
 
-	th = skb->h.th;
-
 	if (skb->pkt_type != PACKET_HOST)
 		goto discard_it;
 
 	/*
-	 *	Pull up the IP header.
+	 *	Count it even if it's bad.
 	 */
+	TCP_INC_STATS_BH(TcpInSegs);
 
-	__skb_pull(skb, skb->h.raw - skb->data);
+	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
+		goto discard_it;
 
-	/*
-	 *	Count it even if it's bad.
-	 */
+	th = skb->h.th;
 
-	TCP_INC_STATS_BH(TcpInSegs);
+	if (th->doff < sizeof(struct tcphdr)/4)
+		goto bad_packet;
+	if (!pskb_may_pull(skb, th->doff*4))
+		goto discard_it;
 
-	if (th->doff < sizeof(struct tcphdr)/4 ||
-	    (skb->ip_summed != CHECKSUM_UNNECESSARY &&
+	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
 	     tcp_v6_checksum_init(skb) < 0))
 		goto bad_packet;
 
+	th = skb->h.th;
 	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
 	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
-				    len - th->doff*4);
+				    skb->len - th->doff*4);
 	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
 	TCP_SKB_CB(skb)->when = 0;
 	TCP_SKB_CB(skb)->flags = ip6_get_dsfield(skb->nh.ipv6h);
 	TCP_SKB_CB(skb)->sacked = 0;
-	skb->used = 0;
 
-	sk = __tcp_v6_lookup(saddr, th->source, daddr, ntohs(th->dest), tcp_v6_iif(skb));
+	sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source,
+			     &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));
 
 	if (!sk)
 		goto no_tcp_socket;
@@ -1591,7 +1593,7 @@
 	return ret;
 
 no_tcp_socket:
-	if (len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 bad_packet:
 		TCP_INC_STATS_BH(TcpInErrs);
 	} else {
@@ -1612,7 +1614,7 @@
 	goto discard_it;
 
 do_time_wait:
-	if (len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 		TCP_INC_STATS_BH(TcpInErrs);
 		sock_put(sk);
 		goto discard_it;
@@ -1673,10 +1675,12 @@
 		if (dst->error) {
 			err = dst->error;
 			dst_release(dst);
+			sk->route_caps = 0;
 			return err;
 		}
 
 		ip6_dst_store(sk, dst, NULL);
+		sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
 	}
 
 	return 0;
@@ -1819,6 +1823,7 @@
 	sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
 
 	sk->write_space = tcp_write_space;
+	sk->use_write_queue = 1;
 
 	sk->sndbuf = sysctl_tcp_wmem[1];
 	sk->rcvbuf = sysctl_tcp_rmem[1];
@@ -1837,7 +1842,7 @@
 	/* Cleanup up the write buffer. */
   	tcp_writequeue_purge(sk);
 
-	/* Cleans up our, hopefuly empty, out_of_order_queue. */
+	/* Cleans up our, hopefully empty, out_of_order_queue. */
   	__skb_queue_purge(&tp->out_of_order_queue);
 
 	/* Clean prequeue, it must be empty really */
@@ -1847,6 +1852,10 @@
 	if(sk->prev != NULL)
 		tcp_put_port(sk);
 
+	/* If sendmsg cached page exists, toss it. */
+	if (tp->sndmsg_page != NULL)
+		__free_page(tp->sndmsg_page);
+
 	atomic_dec(&tcp_sockets_allocated);
 
 	return inet6_destroy_sock(sk);
@@ -1967,7 +1976,7 @@
 	off_t begin, pos = 0;
 	char tmpbuf[LINE_LEN+2];
 
-	if(offset < LINE_LEN+1)
+	if (offset < LINE_LEN+1)
 		len += sprintf(buffer, LINE_FMT,
 			       "  sl  "						/* 6 */
 			       "local_address                         "		/* 38 */
@@ -1997,7 +2006,7 @@
 			if (pos >= offset) {
 				get_tcp6_sock(sk, tmpbuf, num);
 				len += sprintf(buffer+len, LINE_FMT, tmpbuf);
-				if (len >= length) {
+				if (pos >= offset + length) {
 					tcp_listen_unlock();
 					goto out_no_bh;
 				}
@@ -2016,7 +2025,7 @@
 							continue;
 						get_openreq6(sk, req, tmpbuf, num, uid);
 						len += sprintf(buffer+len, LINE_FMT, tmpbuf);
-						if(len >= length) { 
+						if (pos >= offset + length) { 
 							read_unlock_bh(&tp->syn_wait_lock);
 							tcp_listen_unlock();
 							goto out_no_bh;
@@ -2048,7 +2057,7 @@
 				continue;
 			get_tcp6_sock(sk, tmpbuf, num);
 			len += sprintf(buffer+len, LINE_FMT, tmpbuf);
-			if(len >= length) {
+			if (pos >= offset + length) {
 				read_unlock(&head->lock);
 				goto out;
 			}
@@ -2063,7 +2072,7 @@
 				continue;
 			get_timewait6_sock(tw, tmpbuf, num);
 			len += sprintf(buffer+len, LINE_FMT, tmpbuf);
-			if(len >= length) {
+			if (pos >= offset + length) {
 				read_unlock(&head->lock);
 				goto out;
 			}
@@ -2078,7 +2087,7 @@
 	begin = len - (pos - offset);
 	*start = buffer + begin;
 	len -= begin;
-	if(len > length)
+	if (len > length)
 		len = length;
 	if (len < 0)
 		len = 0; 
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.4.3/linux/net/ipv6/udp.c	Mon Jan  1 11:01:58 2001
+++ linux/net/ipv6/udp.c	Thu Apr 12 12:11:39 2001
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.59 2000/11/28 13:38:38 davem Exp $
+ *	$Id: udp.c,v 1.62 2001/03/06 21:15:11 davem Exp $
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
@@ -391,13 +391,13 @@
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
 					      copied);
 	} else if (msg->msg_flags&MSG_TRUNC) {
-		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)))
+		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
 			goto csum_copy_err;
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
 					      copied);
 	} else {
-		err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr));
-		if (err)
+		err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
+		if (err == -EINVAL)
 			goto csum_copy_err;
 	}
 	if (err)
@@ -461,22 +461,17 @@
 	goto out_free;
 }
 
-void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
-	       struct inet6_skb_parm *opt,
-	       int type, int code, unsigned char *buff, __u32 info)
+void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+	       int type, int code, int offset, __u32 info)
 {
+	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
 	struct net_device *dev = skb->dev;
 	struct in6_addr *saddr = &hdr->saddr;
 	struct in6_addr *daddr = &hdr->daddr;
+	struct udphdr *uh = (struct udphdr*)(skb->data+offset);
 	struct sock *sk;
-	struct udphdr *uh;
 	int err;
 
-	if (buff + sizeof(struct udphdr) > skb->tail)
-		return;
-
-	uh = (struct udphdr *) buff;
-
 	sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex);
    
 	if (sk == NULL)
@@ -577,8 +572,8 @@
 
 	buff = NULL;
 	sk2 = sk;
-	while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,
-						  uh->source, daddr, dif))) {
+	while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr,
+						  uh->source, saddr, dif))) {
 		if (!buff) {
 			buff = skb_clone(skb, GFP_ATOMIC);
 			if (!buff)
@@ -596,31 +591,29 @@
 	read_unlock(&udp_hash_lock);
 }
 
-int udpv6_rcv(struct sk_buff *skb, unsigned long len)
+int udpv6_rcv(struct sk_buff *skb)
 {
 	struct sock *sk;
   	struct udphdr *uh;
 	struct net_device *dev = skb->dev;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
-	u32 ulen;
+	struct in6_addr *saddr, *daddr;
+	u32 ulen = 0;
 
+	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+		goto short_packet;
+
+	saddr = &skb->nh.ipv6h->saddr;
+	daddr = &skb->nh.ipv6h->daddr;
 	uh = skb->h.uh;
-	__skb_pull(skb, skb->h.raw - skb->data);
 
 	ulen = ntohs(uh->len);
 
 	/* Check for jumbo payload */
-	if (ulen == 0 && skb->nh.ipv6h->payload_len == 0)
-		ulen = len;
+	if (ulen == 0)
+		ulen = skb->len;
 
-	if (ulen > len || len < sizeof(*uh)) {
-		if (net_ratelimit())
-			printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len);
-		UDP6_INC_STATS_BH(UdpInErrors);
-		kfree_skb(skb);
-		return(0);
-	}
+	if (ulen > skb->len || ulen < sizeof(*uh))
+		goto short_packet;
 
 	if (uh->check == 0) {
 		/* IPv6 draft-v2 section 8.1 says that we SHOULD log
@@ -631,17 +624,24 @@
 		goto discard;
 	}
 
-	skb_trim(skb, ulen);
+	if (ulen < skb->len) {
+		if (__pskb_trim(skb, ulen))
+			goto discard;
+		saddr = &skb->nh.ipv6h->saddr;
+		daddr = &skb->nh.ipv6h->daddr;
+		uh = skb->h.uh;
+	}
 
 	if (skb->ip_summed==CHECKSUM_HW) {
-		if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum))
-			goto discard;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+		if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) {
+			NETDEBUG(printk(KERN_DEBUG "udp v6 hw csum failure.\n"));
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+	}
+	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
 		skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0);
 
-	len = ulen;
-
 	/* 
 	 *	Multicast receive code 
 	 */
@@ -656,12 +656,11 @@
 	 * check socket cache ... must talk to Alan about his plans
 	 * for sock caches... i'll skip this for now.
 	 */
-	
 	sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex);
-	
+
 	if (sk == NULL) {
 		if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
-		    (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum)))
+		    (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
 			goto discard;
 		UDP6_INC_STATS_BH(UdpNoPorts);
 
@@ -676,7 +675,11 @@
 	udpv6_queue_rcv_skb(sk, skb);
 	sock_put(sk);
 	return(0);
-	
+
+short_packet:	
+	if (net_ratelimit())
+		printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len);
+
 discard:
 	UDP6_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
diff -u --recursive --new-file v2.4.3/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.4.3/linux/net/ipx/af_ipx.c	Mon Mar 26 15:43:01 2001
+++ linux/net/ipx/af_ipx.c	Thu Apr 12 12:11:39 2001
@@ -123,7 +123,7 @@
 static unsigned char ipxcfg_max_hops = 16;
 static char ipxcfg_auto_select_primary;
 static char ipxcfg_auto_create_interfaces;
-static int sysctl_ipx_pprop_broadcasting = 1;
+int sysctl_ipx_pprop_broadcasting = 1;
 
 /* Global Variables */
 static struct datalink_proto *p8022_datalink;
@@ -1542,7 +1542,7 @@
 	ipx_offset = intrfc->if_ipx_offset;
 	size = sizeof(struct ipxhdr) + len + ipx_offset;
 
-	skb = sock_alloc_send_skb(sk, size, 0, noblock, &err);
+	skb = sock_alloc_send_skb(sk, size, noblock, &err);
 	if (!skb)
 		goto out_put;
 
@@ -2531,6 +2531,7 @@
 	sendmsg:	ipx_sendmsg,
 	recvmsg:	ipx_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.4.3/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- v2.4.3/linux/net/ipx/af_spx.c	Sun Aug  6 22:20:09 2000
+++ linux/net/ipx/af_spx.c	Thu Apr 19 08:38:50 2001
@@ -31,8 +31,6 @@
  *	This material is provided "as is" and at no charge.
  */
 
-#include <linux/config.h>
-#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
 #include <linux/module.h>
 #include <net/ipx.h>
 #include <net/spx.h>
@@ -440,7 +438,7 @@
 
 		save_flags(flags);
 		cli();
-        	skb = sock_alloc_send_skb(sk, size, 1, 0, &err);
+        	skb = sock_alloc_send_skb(sk, size, 0, &err);
         	if(skb == NULL) {
 			restore_flags(flags);
                 	return (-ENOMEM);
@@ -742,7 +740,7 @@
         size 	= offset + sizeof(struct ipxspxhdr) + len;
 
 	cli();
-        skb  	= sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
+        skb  	= sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err);
 	sti();
         if(skb == NULL)
                 return (err);
@@ -901,20 +899,20 @@
 	sendmsg:	spx_sendmsg,
 	recvmsg:	spx_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
 SOCKOPS_WRAP(spx, PF_IPX);
 
-
-static struct net_proto_family spx_family_ops=
-{
-	PF_IPX,
-	spx_create
+static struct net_proto_family spx_family_ops = {
+	family:		PF_IPX,
+	create:		spx_create,
 };
 
+static const char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n";
 
-void spx_proto_init(void)
+static int __init spx_proto_init(void)
 {
 	int error;
 
@@ -926,29 +924,14 @@
 
 	/* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
 
-	printk(KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n");
-	return;
+	printk(banner);
+	return 0;
 }
+module_init(spx_proto_init);
 
-void spx_proto_finito(void)
+static void __exit spx_proto_finito(void)
 {
 	ipx_unregister_spx();
 	return;
 }
-
-#ifdef MODULE
-
-int init_module(void)
-{
-        spx_proto_init();
-        return 0;
-}
-
-void cleanup_module(void)
-{
-        spx_proto_finito();
-        return;
-}
-
-#endif /* MODULE */
-#endif /* CONFIG_SPX || CONFIG_SPX_MODULE */
+module_exit(spx_proto_finito);
diff -u --recursive --new-file v2.4.3/linux/net/ipx/sysctl_net_ipx.c linux/net/ipx/sysctl_net_ipx.c
--- v2.4.3/linux/net/ipx/sysctl_net_ipx.c	Sun Mar 25 18:14:25 2001
+++ linux/net/ipx/sysctl_net_ipx.c	Thu Apr 12 12:16:36 2001
@@ -6,6 +6,7 @@
  * Added /proc/sys/net/ipx/ipx_pprop_broadcasting - acme March 4, 2001
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 
diff -u --recursive --new-file v2.4.3/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.4.3/linux/net/irda/af_irda.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/af_irda.c	Thu Apr 12 12:11:39 2001
@@ -1257,7 +1257,7 @@
 		len = self->max_data_size;
 	}
 
-	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, 
+	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 
 				  msg->msg_flags & MSG_DONTWAIT, &err);
 	if (!skb)
 		return -ENOBUFS;
@@ -1500,7 +1500,7 @@
 		len = self->max_data_size;
 	}
 
-	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, 
+	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 
 				  msg->msg_flags & MSG_DONTWAIT, &err);
 	if (!skb)
 		return -ENOBUFS;
@@ -1563,7 +1563,7 @@
 		len = self->max_data_size;
 	}
 
-	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, 
+	skb = sock_alloc_send_skb(sk, len + self->max_header_size, 
 				  msg->msg_flags & MSG_DONTWAIT, &err);
 	if (!skb)
 		return -ENOBUFS;
@@ -2256,6 +2256,7 @@
 	sendmsg:	irda_sendmsg,
 	recvmsg:	irda_recvmsg_stream,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = {
@@ -2276,6 +2277,7 @@
 	sendmsg:	irda_sendmsg,
 	recvmsg:	irda_recvmsg_dgram,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
@@ -2296,6 +2298,7 @@
 	sendmsg:	irda_sendmsg_dgram,
 	recvmsg:	irda_recvmsg_dgram,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #ifdef CONFIG_IRDA_ULTRA
@@ -2317,6 +2320,7 @@
 	sendmsg:	irda_sendmsg_ultra,
 	recvmsg:	irda_recvmsg_dgram,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 #endif /* CONFIG_IRDA_ULTRA */
 
diff -u --recursive --new-file v2.4.3/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.4.3/linux/net/irda/irda_device.c	Tue Nov 28 21:53:45 2000
+++ linux/net/irda/irda_device.c	Wed Apr 18 14:40:07 2001
@@ -430,7 +430,6 @@
 	memset(dev->broadcast, 0xff, 4);
 
 	dev->mtu = 2048;
-	dev_init_buffers(dev);
 	dev->flags = IFF_NOARP;
 	return 0;
 }
diff -u --recursive --new-file v2.4.3/linux/net/irda/irnet/irnet_ppp.c linux/net/irda/irnet/irnet_ppp.c
--- v2.4.3/linux/net/irda/irnet/irnet_ppp.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/irnet/irnet_ppp.c	Fri Apr 20 11:54:24 2001
@@ -476,7 +476,7 @@
 
   /* If we are connected to ppp_generic, let it handle the job */
   if(ap->ppp_open)
-    return ppp_channel_write(&ap->chan, buf, count);
+    return -EAGAIN;
   else
     return irnet_ctrl_write(ap, buf, count);
 }
@@ -500,7 +500,7 @@
 
   /* If we are connected to ppp_generic, let it handle the job */
   if(ap->ppp_open)
-    return ppp_channel_read(&ap->chan, file, buf, count);
+    return -EAGAIN;
   else
     return irnet_ctrl_read(ap, file, buf, count);
 }
@@ -523,9 +523,7 @@
   DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n");
 
   /* If we are connected to ppp_generic, let it handle the job */
-  if(ap->ppp_open)
-    mask |= ppp_channel_poll(&ap->chan, file, wait);
-  else
+  if(!ap->ppp_open)
     mask |= irnet_ctrl_poll(ap, file, wait);
 
   DEXIT(FS_TRACE, " - mask=0x%X\n", mask);
@@ -597,15 +595,6 @@
 	  ap->ppp_open = 0;
 	  err = 0;
 	}
-      break;
-
-      /* Attach this PPP instance to the PPP driver (set it active) */
-    case PPPIOCATTACH:
-    case PPPIOCDETACH:
-      if(ap->ppp_open)
-	err = ppp_channel_ioctl(&ap->chan, cmd, arg);
-      else
-	DERROR(FS_ERROR, "Channel not registered !\n");
       break;
 
       /* Query PPP channel and unit number */
diff -u --recursive --new-file v2.4.3/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c
--- v2.4.3/linux/net/lapb/lapb_iface.c	Fri Feb 16 16:06:17 2001
+++ linux/net/lapb/lapb_iface.c	Thu Apr 12 12:16:36 2001
@@ -15,7 +15,6 @@
  *	2000-10-29	Henner Eisen	lapb_data_indication() return status.
  */
  
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.4.3/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.4.3/linux/net/netlink/af_netlink.c	Fri Feb  9 11:29:44 2001
+++ linux/net/netlink/af_netlink.c	Thu Apr 12 12:11:39 2001
@@ -962,6 +962,7 @@
 	sendmsg:	netlink_sendmsg,
 	recvmsg:	netlink_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 struct net_proto_family netlink_family_ops = {
diff -u --recursive --new-file v2.4.3/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.4.3/linux/net/netrom/af_netrom.c	Fri Dec 29 14:35:47 2000
+++ linux/net/netrom/af_netrom.c	Thu Apr 19 08:38:50 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;
@@ -1010,7 +1013,7 @@
 	SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
 	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
 	skb_reserve(skb, size - len);
@@ -1224,10 +1227,9 @@
 	return(len);
 } 
 
-static struct net_proto_family nr_family_ops = 
-{
-	PF_NETROM,
-	nr_create
+static struct net_proto_family nr_family_ops = {
+	family:		PF_NETROM,
+	create:		nr_create,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = {
@@ -1248,22 +1250,29 @@
 	sendmsg:	nr_sendmsg,
 	recvmsg:	nr_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
 SOCKOPS_WRAP(nr_proto, PF_NETROM);
 
 static struct notifier_block nr_dev_notifier = {
-	nr_device_event,
-	0
+	notifier_call:	nr_device_event,
 };
 
 static struct net_device *dev_nr;
 
+static const char banner[] __initdata = KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n";
+
 static int __init nr_proto_init(void)
 {
 	int i;
 
+	if (nr_ndevs > 0x7fffffff/sizeof(struct net_device)) {
+		printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n");
+		return -1;
+	}
+
 	if ((dev_nr = kmalloc(nr_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
 		return -1;
@@ -1279,7 +1288,7 @@
 
 	sock_register(&nr_family_ops);
 	register_netdevice_notifier(&nr_dev_notifier);
-	printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n");
+	printk(banner);
 
 	ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
 	ax25_linkfail_register(nr_link_failed);
diff -u --recursive --new-file v2.4.3/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.4.3/linux/net/netrom/nr_dev.c	Fri Dec 29 14:35:47 2000
+++ linux/net/netrom/nr_dev.c	Wed Apr 18 14:40:07 2001
@@ -231,7 +231,5 @@
 
 	dev->get_stats = nr_get_stats;
 
-	dev_init_buffers(dev);
-
 	return 0;
 };
diff -u --recursive --new-file v2.4.3/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c
--- v2.4.3/linux/net/netrom/nr_out.c	Fri Dec 29 14:44:46 2000
+++ linux/net/netrom/nr_out.c	Thu Apr 12 12:11:39 2001
@@ -56,7 +56,7 @@
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, 0, &err)) == NULL)
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL)
 				return;
 
 			skb_reserve(skbn, frontlen);
diff -u --recursive --new-file v2.4.3/linux/net/netsyms.c linux/net/netsyms.c
--- v2.4.3/linux/net/netsyms.c	Sun Mar 25 18:24:31 2001
+++ linux/net/netsyms.c	Sun Apr 22 18:36:08 2001
@@ -130,15 +130,27 @@
 EXPORT_SYMBOL(sock_no_sendmsg);
 EXPORT_SYMBOL(sock_no_recvmsg);
 EXPORT_SYMBOL(sock_no_mmap);
+EXPORT_SYMBOL(sock_no_sendpage);
 EXPORT_SYMBOL(sock_rfree);
 EXPORT_SYMBOL(sock_wfree);
 EXPORT_SYMBOL(sock_wmalloc);
 EXPORT_SYMBOL(sock_rmalloc);
+EXPORT_SYMBOL(skb_linearize);
+EXPORT_SYMBOL(skb_checksum);
+EXPORT_SYMBOL(skb_checksum_help);
 EXPORT_SYMBOL(skb_recv_datagram);
 EXPORT_SYMBOL(skb_free_datagram);
 EXPORT_SYMBOL(skb_copy_datagram);
 EXPORT_SYMBOL(skb_copy_datagram_iovec);
+EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
+EXPORT_SYMBOL(skb_copy_bits);
+EXPORT_SYMBOL(skb_copy_and_csum_bits);
 EXPORT_SYMBOL(skb_copy_expand);
+EXPORT_SYMBOL(___pskb_trim);
+EXPORT_SYMBOL(__pskb_pull_tail);
+EXPORT_SYMBOL(pskb_expand_head);
+EXPORT_SYMBOL(pskb_copy);
+EXPORT_SYMBOL(skb_realloc_headroom);
 EXPORT_SYMBOL(datagram_poll);
 EXPORT_SYMBOL(put_cmsg);
 EXPORT_SYMBOL(sock_kmalloc);
@@ -146,6 +158,7 @@
 
 #ifdef CONFIG_FILTER
 EXPORT_SYMBOL(sk_run_filter);
+EXPORT_SYMBOL(sk_chk_filter);
 #endif
 
 EXPORT_SYMBOL(neigh_table_init);
@@ -190,7 +203,6 @@
 EXPORT_SYMBOL(scm_fp_dup);
 EXPORT_SYMBOL(files_stat);
 EXPORT_SYMBOL(memcpy_toiovec);
-EXPORT_SYMBOL(csum_partial);
 
 #ifdef CONFIG_IPX_MODULE
 EXPORT_SYMBOL(make_8023_client);
@@ -225,7 +237,6 @@
 EXPORT_SYMBOL(ip_route_output_key);
 EXPORT_SYMBOL(ip_route_input);
 EXPORT_SYMBOL(icmp_send);
-EXPORT_SYMBOL(icmp_reply);
 EXPORT_SYMBOL(ip_options_compile);
 EXPORT_SYMBOL(ip_options_undo);
 EXPORT_SYMBOL(arp_send);
@@ -295,7 +306,6 @@
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(memcpy_fromiovecend);
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
-EXPORT_SYMBOL(copy_and_csum_toiovec);
 EXPORT_SYMBOL(tcp_v4_lookup_listener);
 /* UDP/TCP exported functions for TCPv6 */
 EXPORT_SYMBOL(udp_ioctl);
@@ -362,6 +372,7 @@
 EXPORT_SYMBOL(sysctl_tcp_wmem);
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(tcp_cwnd_application_limited);
+EXPORT_SYMBOL(tcp_sendpage);
 
 EXPORT_SYMBOL(xrlim_allow);
 
diff -u --recursive --new-file v2.4.3/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.4.3/linux/net/packet/af_packet.c	Fri Feb  9 11:29:44 2001
+++ linux/net/packet/af_packet.c	Thu Apr 12 12:11:39 2001
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.47 2000/12/08 17:15:54 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.54 2001/03/03 01:20:11 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -149,7 +149,7 @@
  */
 
 /* List of all packet sockets. */
-static struct sock * packet_sklist = NULL;
+static struct sock * packet_sklist;
 static rwlock_t packet_sklist_lock = RW_LOCK_UNLOCKED;
 
 atomic_t packet_socks_nr;
@@ -404,6 +404,7 @@
 	struct sockaddr_ll *sll;
 	struct packet_opt *po;
 	u8 * skb_head = skb->data;
+	int skb_len = skb->len;
 #ifdef CONFIG_FILTER
 	unsigned snaplen;
 #endif
@@ -461,7 +462,7 @@
 
 		if (skb_head != skb->data) {
 			skb->data = skb_head;
-			skb->len = skb->tail - skb->data;
+			skb->len = skb_len;
 		}
 		kfree_skb(skb);
 		skb = nskb;
@@ -479,8 +480,8 @@
 		sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
 
 #ifdef CONFIG_FILTER
-	if (skb->len > snaplen)
-		__skb_trim(skb, snaplen);
+	if (pskb_trim(skb, snaplen))
+		goto drop_n_acct;
 #endif
 
 	skb_set_owner_r(skb, sk);
@@ -502,7 +503,7 @@
 #endif
 	if (skb_head != skb->data && skb_shared(skb)) {
 		skb->data = skb_head;
-		skb->len = skb->tail - skb->data;
+		skb->len = skb_len;
 	}
 drop:
 	kfree_skb(skb);
@@ -517,6 +518,7 @@
 	struct sockaddr_ll *sll;
 	struct tpacket_hdr *h;
 	u8 * skb_head = skb->data;
+	int skb_len = skb->len;
 	unsigned snaplen;
 	unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
 	unsigned short macoff, netoff;
@@ -534,6 +536,8 @@
 		else if (skb->pkt_type == PACKET_OUTGOING) {
 			/* Special case: outgoing packets have ll header at head */
 			skb_pull(skb, skb->nh.raw - skb->data);
+			if (skb->ip_summed == CHECKSUM_HW)
+				status |= TP_STATUS_CSUMNOTREADY;
 		}
 	}
 
@@ -580,6 +584,8 @@
 		if ((int)snaplen < 0)
 			snaplen = 0;
 	}
+	if (snaplen > skb->len-skb->data_len)
+		snaplen = skb->len-skb->data_len;
 
 	spin_lock(&sk->receive_queue.lock);
 	h = po->iovec[po->head];
@@ -623,7 +629,7 @@
 drop_n_restore:
 	if (skb_head != skb->data && skb_shared(skb)) {
 		skb->data = skb_head;
-		skb->len = skb->tail - skb->data;
+		skb->len = skb_len;
 	}
 drop:
         kfree_skb(skb);
@@ -682,7 +688,7 @@
 	if (len > dev->mtu+reserve)
 		goto out_unlock;
 
-	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
+	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 
 				msg->msg_flags & MSG_DONTWAIT, &err);
 	if (skb==NULL)
 		goto out_unlock;
@@ -1051,8 +1057,7 @@
 		msg->msg_flags|=MSG_TRUNC;
 	}
 
-	/* We can't use skb_copy_datagram here */
-	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	if (err)
 		goto out_free;
 
@@ -1318,6 +1323,9 @@
   	if (get_user(len,optlen))
   		return -EFAULT;
 
+	if (len < 0)
+		return -EINVAL;
+		
 	switch(optname)	{
 	case PACKET_STATISTICS:
 	{
@@ -1780,6 +1788,7 @@
 	sendmsg:	packet_sendmsg_spkt,
 	recvmsg:	packet_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 #endif
 
@@ -1801,17 +1810,16 @@
 	sendmsg:	packet_sendmsg,
 	recvmsg:	packet_recvmsg,
 	mmap:		packet_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 static struct net_proto_family packet_family_ops = {
-	PF_PACKET,
-	packet_create
+	family:		PF_PACKET,
+	create:		packet_create,
 };
 
-struct notifier_block packet_netdev_notifier={
-	packet_notifier,
-	NULL,
-	0
+static struct notifier_block packet_netdev_notifier = {
+	notifier_call:	packet_notifier,
 };
 
 #ifdef CONFIG_PROC_FS
@@ -1864,19 +1872,14 @@
 }
 #endif
 
-
-
 static void __exit packet_exit(void)
 {
-#ifdef CONFIG_PROC_FS
 	remove_proc_entry("net/packet", 0);
-#endif
 	unregister_netdevice_notifier(&packet_netdev_notifier);
 	sock_unregister(PF_PACKET);
 	return;
 }
 
-
 static int __init packet_init(void)
 {
 	sock_register(&packet_family_ops);
@@ -1886,7 +1889,6 @@
 #endif
 	return 0;
 }
-
 
 module_init(packet_init);
 module_exit(packet_exit);
diff -u --recursive --new-file v2.4.3/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.4.3/linux/net/rose/af_rose.c	Fri Dec 29 14:35:47 2000
+++ linux/net/rose/af_rose.c	Thu Apr 19 08:38:50 2001
@@ -70,7 +70,7 @@
 int sysctl_rose_maximum_vcs             = ROSE_DEFAULT_MAXVC;
 int sysctl_rose_window_size             = ROSE_DEFAULT_WINDOW_SIZE;
 
-static struct sock *volatile rose_list = NULL;
+static struct sock *rose_list;
 
 static struct proto_ops rose_proto_ops;
 
@@ -471,7 +471,10 @@
 		
 	if (get_user(len, optlen))
 		return -EFAULT;
-	
+
+	if (len < 0)
+		return -EINVAL;
+			
 	switch (optname) {
 		case ROSE_DEFER:
 			val = sk->protinfo.rose->defer;
@@ -1056,7 +1059,7 @@
 	SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n");
 	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN);
@@ -1118,7 +1121,7 @@
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL)
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL)
 				return err;
 
 			skbn->sk   = sk;
@@ -1392,8 +1395,8 @@
 } 
 
 static struct net_proto_family rose_family_ops = {
-	PF_ROSE,
-	rose_create
+	family:		PF_ROSE,
+	create:		rose_create,
 };
 
 static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {
@@ -1414,24 +1417,31 @@
 	sendmsg:	rose_sendmsg,
 	recvmsg:	rose_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
 SOCKOPS_WRAP(rose_proto, PF_ROSE);
 
 static struct notifier_block rose_dev_notifier = {
-	rose_device_event,
-	0
+	notifier_call:	rose_device_event,
 };
 
 static struct net_device *dev_rose;
 
+static const char banner[] = KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n";
+
 static int __init rose_proto_init(void)
 {
 	int i;
 
 	rose_callsign = null_ax25_address;
 
+	if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device)) {
+		printk(KERN_ERR "ROSE: rose_proto_init - rose_ndevs parameter to large\n");
+		return -1;
+	}
+
 	if ((dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n");
 		return -1;
@@ -1447,7 +1457,7 @@
 
 	sock_register(&rose_family_ops);
 	register_netdevice_notifier(&rose_dev_notifier);
-	printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n");
+	printk(banner);
 
 	ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
 	ax25_linkfail_register(rose_link_failed);
diff -u --recursive --new-file v2.4.3/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.4.3/linux/net/rose/rose_dev.c	Fri Dec 29 14:35:47 2000
+++ linux/net/rose/rose_dev.c	Wed Apr 18 14:40:08 2001
@@ -200,7 +200,5 @@
 
 	dev->get_stats = rose_get_stats;
 
-	dev_init_buffers(dev);
-
 	return 0;
 };
diff -u --recursive --new-file v2.4.3/linux/net/socket.c linux/net/socket.c
--- v2.4.3/linux/net/socket.c	Fri Nov 17 11:36:27 2000
+++ linux/net/socket.c	Wed Apr 25 16:13:50 2001
@@ -71,6 +71,7 @@
 #include <linux/poll.h>
 #include <linux/cache.h>
 #include <linux/module.h>
+#include <linux/highmem.h>
 
 #if defined(CONFIG_KMOD) && defined(CONFIG_NET)
 #include <linux/kmod.h>
@@ -104,6 +105,8 @@
 			  unsigned long count, loff_t *ppos);
 static ssize_t sock_writev(struct file *file, const struct iovec *vector,
 			  unsigned long count, loff_t *ppos);
+static ssize_t sock_sendpage(struct file *file, struct page *page,
+			     int offset, size_t size, loff_t *ppos, int more);
 
 
 /*
@@ -122,7 +125,8 @@
 	release:	sock_close,
 	fasync:		sock_fasync,
 	readv:		sock_readv,
-	writev:		sock_writev
+	writev:		sock_writev,
+	sendpage:	sock_sendpage
 };
 
 /*
@@ -602,6 +606,24 @@
 	return sock_sendmsg(sock, &msg, size);
 }
 
+ssize_t sock_sendpage(struct file *file, struct page *page,
+		      int offset, size_t size, loff_t *ppos, int more)
+{
+	struct socket *sock;
+	int flags;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	sock = socki_lookup(file->f_dentry->d_inode);
+
+	flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
+	if (more)
+		flags |= MSG_MORE;
+
+	return sock->ops->sendpage(sock, page, offset, size, flags);
+}
+
 int sock_readv_writev(int type, struct inode * inode, struct file * file,
 		      const struct iovec * iov, long count, long size)
 {
@@ -1269,7 +1291,10 @@
 {
 	int err;
 	struct socket *sock;
-	
+
+	if (optlen < 0)
+		return -EINVAL;
+			
 	if ((sock = sockfd_lookup(fd, &err))!=NULL)
 	{
 		if (level == SOL_SOCKET)
diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- v2.4.3/linux/net/sunrpc/clnt.c	Fri Feb  9 11:29:44 2001
+++ linux/net/sunrpc/clnt.c	Thu Apr 19 08:38:50 2001
@@ -694,9 +694,14 @@
 	}
 
 	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;
 	}
 
diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.4.3/linux/net/sunrpc/sched.c	Fri Feb  9 11:29:44 2001
+++ linux/net/sunrpc/sched.c	Tue Apr  3 13:45:37 2001
@@ -1072,6 +1072,8 @@
 	current->pgrp = 1;
 	strcpy(current->comm, "rpciod");
 
+	current->flags |= PF_MEMALLOC;
+
 	dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
 	while (rpciod_users) {
 		if (signalled()) {
diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.4.3/linux/net/sunrpc/svcsock.c	Wed Mar 14 14:37:36 2001
+++ linux/net/sunrpc/svcsock.c	Thu Apr 12 12:11:39 2001
@@ -381,10 +381,17 @@
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
 
+	/* Sorry. */
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+			kfree_skb(skb);
+			svc_sock_received(svsk, 0);
+			return 0;
+		}
+	}
+
 	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
-		unsigned int csum = skb->csum;
-		csum = csum_partial(skb->h.raw, skb->len, csum);
-		if ((unsigned short)csum_fold(csum)) {
+		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
 			skb_free_datagram(svsk->sk_sk, skb);
 			svc_sock_received(svsk, 0);
 			return 0;
@@ -395,7 +402,7 @@
 	svsk->sk_data = 1;
 
 	len  = skb->len - sizeof(struct udphdr);
-	data = (u32 *) (skb->h.raw + sizeof(struct udphdr));
+	data = (u32 *) (skb->data + sizeof(struct udphdr));
 
 	rqstp->rq_skbuff      = skb;
 	rqstp->rq_argbuf.base = data;
diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/sysctl.c linux/net/sunrpc/sysctl.c
--- v2.4.3/linux/net/sunrpc/sysctl.c	Sun Oct  1 20:35:16 2000
+++ linux/net/sunrpc/sysctl.c	Fri Apr 13 20:26:07 2001
@@ -63,7 +63,7 @@
 {
 	char		tmpbuf[20], *p, c;
 	unsigned int	value;
-	int		left, len;
+	size_t		left, len;
 
 	if ((file->f_pos && !write) || !*lenp) {
 		*lenp = 0;
diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.4.3/linux/net/sunrpc/xprt.c	Fri Feb  9 11:29:44 2001
+++ linux/net/sunrpc/xprt.c	Thu Apr 12 12:11:39 2001
@@ -591,7 +591,7 @@
 					   struct sk_buff *skb,
 					   int copied)
 {
-	__u8 *pkt_data = skb->h.raw + sizeof(struct udphdr);
+	int offset = sizeof(struct udphdr);
 	__u8 *cur_ptr = iov->iov_base;
 	__kernel_size_t cur_len = iov->iov_len;
 	unsigned int csum = skb->csum;
@@ -599,18 +599,18 @@
 	int slack = skb->len - copied - sizeof(struct udphdr);
 
 	if (need_csum)
-		csum = csum_partial(skb->h.raw, sizeof(struct udphdr), csum);
+		csum = csum_partial(skb->data, sizeof(struct udphdr), csum);
 	while (copied > 0) {
 		if (cur_len) {
 			int to_move = cur_len;
 			if (to_move > copied)
 				to_move = copied;
 			if (need_csum)
-				csum = csum_partial_copy_nocheck(pkt_data, cur_ptr,
-								 to_move, csum);
+				csum = skb_copy_and_csum_bits(skb, offset, cur_ptr,
+							      to_move, csum);
 			else
-				memcpy(cur_ptr, pkt_data, to_move);
-			pkt_data += to_move;
+				skb_copy_bits(skb, offset, cur_ptr, to_move);
+			offset += to_move;
 			copied -= to_move;
 			cur_ptr += to_move;
 			cur_len -= to_move;
@@ -623,7 +623,7 @@
 	}
 	if (need_csum) {
 		if (slack > 0)
-			csum = csum_partial(pkt_data, slack, csum);
+			csum = skb_checksum(skb, offset, slack, csum);
 		if ((unsigned short)csum_fold(csum))
 			return -1;
 	}
@@ -1116,6 +1116,7 @@
 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 	struct rpc_rqst	*req = task->tk_rqstp;
 
+	spin_lock_bh(&xprt_sock_lock);
 	spin_lock(&xprt_lock);
 	if (xprt->snd_task && xprt->snd_task != task) {
 		dprintk("RPC: %4d TCP write queue full (task %d)\n",
@@ -1131,6 +1132,7 @@
 		req->rq_bytes_sent = 0;
 	}
 	spin_unlock(&xprt_lock);
+	spin_unlock_bh(&xprt_sock_lock);
 	return xprt->snd_task == task;
 }
 
@@ -1143,10 +1145,12 @@
 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 
 	if (xprt->snd_task && xprt->snd_task == task) {
+		spin_lock_bh(&xprt_sock_lock);
 		spin_lock(&xprt_lock);
 		xprt->snd_task = NULL;
 		rpc_wake_up_next(&xprt->sending);
 		spin_unlock(&xprt_lock);
+		spin_unlock_bh(&xprt_sock_lock);
 	}
 }
 
diff -u --recursive --new-file v2.4.3/linux/net/sysctl_net.c linux/net/sysctl_net.c
--- v2.4.3/linux/net/sysctl_net.c	Sun Mar 25 18:14:25 2001
+++ linux/net/sysctl_net.c	Thu Apr 19 08:38:50 2001
@@ -34,10 +34,6 @@
 extern ctl_table tr_table[];
 #endif
 
-#ifdef CONFIG_ECONET
-extern ctl_table econet_table[];
-#endif
-
 ctl_table net_table[] = {
 	{NET_CORE,   "core",      NULL, 0, 0555, core_table},      
 #ifdef CONFIG_NET
@@ -52,9 +48,6 @@
 #endif
 #ifdef CONFIG_TR
 	{NET_TR, "token-ring", NULL, 0, 0555, tr_table},
-#endif
-#ifdef CONFIG_ECONET
-	{NET_ECONET, "econet",    NULL, 0, 0555, econet_table},
 #endif
 	{0}
 };
diff -u --recursive --new-file v2.4.3/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.4.3/linux/net/unix/af_unix.c	Tue Mar  6 19:44:37 2001
+++ linux/net/unix/af_unix.c	Thu Apr 12 12:11:39 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.111 2001/02/02 11:37:28 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.116 2001/03/03 01:20:11 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -1182,7 +1182,7 @@
 	if ((unsigned)len > sk->sndbuf - 32)
 		goto out;
 
-	skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err);
+	skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);
 	if (skb==NULL)
 		goto out;
 
@@ -1285,7 +1285,6 @@
 	struct sockaddr_un *sunaddr=msg->msg_name;
 	int err,size;
 	struct sk_buff *skb;
-	int limit=0;
 	int sent=0;
 
 	err = -EOPNOTSUPP;
@@ -1323,21 +1322,10 @@
 			size = (128 * 1024) / 2;
 			
 		/*
-		 *	Keep to page sized kmalloc()'s as various people
-		 *	have suggested. Big mallocs stress the vm too
-		 *	much.
-		 */
-
-		if (size > PAGE_SIZE-16)
-			limit = PAGE_SIZE-16; /* Fall back to a page if we can't grab a big buffer this instant */
-		else
-			limit = 0;	/* Otherwise just grab and wait */
-
-		/*
 		 *	Grab a buffer
 		 */
 		 
-		skb=sock_alloc_send_skb(sk,size,limit,msg->msg_flags&MSG_DONTWAIT, &err);
+		skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err);
 
 		if (skb==NULL)
 			goto out_err;
@@ -1821,6 +1809,7 @@
 	sendmsg:	unix_stream_sendmsg,
 	recvmsg:	unix_stream_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 struct proto_ops unix_dgram_ops = {
@@ -1841,6 +1830,7 @@
 	sendmsg:	unix_dgram_sendmsg,
 	recvmsg:	unix_dgram_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 struct net_proto_family unix_family_ops = {
diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/Makefile linux/net/wanrouter/Makefile
--- v2.4.3/linux/net/wanrouter/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/net/wanrouter/Makefile	Thu Apr 12 12:11:39 2001
@@ -12,7 +12,7 @@
 export-objs := wanmain.o
 
 obj-y :=  wanproc.o wanmain.o
-obj-m := $(O_TARGET)
+obj-m := $(O_TARGET) af_wanpipe.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/af_wanpipe.c linux/net/wanrouter/af_wanpipe.c
--- v2.4.3/linux/net/wanrouter/af_wanpipe.c	Wed Dec 31 16:00:00 1969
+++ linux/net/wanrouter/af_wanpipe.c	Thu Apr 12 12:11:39 2001
@@ -0,0 +1,2765 @@
+/*****************************************************************************
+* af_wanpipe.c	WANPIPE(tm) Secure Socket Layer.
+*
+* Author:	Nenad Corbic	<ncorbic@sangoma.com>
+*
+* Copyright:	(c) 2000 Sangoma Technologies Inc.
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Due Credit:
+*               Wanpipe socket layer is based on Packet and 
+*               the X25 socket layers. The above sockets were 
+*               used for the specific use of Sangoma Technoloiges 
+*               API programs. 
+*               Packet socket Authors: Ross Biro, Fred N. van Kempen and 
+*                                      Alan Cox.
+*               X25 socket Author: Jonathan Naylor.
+* ============================================================================
+* Apr 25, 2000  Nenad Corbic     o Added the ability to send zero length packets.
+* Mar 13, 2000  Nenad Corbic	 o Added a tx buffer check via ioctl call.
+* Mar 06, 2000  Nenad Corbic     o Fixed the corrupt sock lcn problem.
+*                                  Server and client applicaton can run
+*                                  simultaneously without conflicts.
+* Feb 29, 2000  Nenad Corbic     o Added support for PVC protocols, such as
+*                                  CHDLC, Frame Relay and HDLC API.
+* Jan 17, 2000 	Nenad Corbic	 o Initial version, based on AF_PACKET socket.
+*			           X25API support only. 
+*
+******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/wireless.h>
+#include <linux/kmod.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/wanpipe.h>
+#include <linux/if_wanpipe.h>
+#include <linux/pkt_sched.h>
+#include <linux/tcp.h>
+#include <linux/if_wanpipe_common.h>
+#include <linux/sdla_x25.h>
+
+#ifdef CONFIG_INET
+#include <net/inet_common.h>
+#endif
+
+#define SLOW_BACKOFF 0.1*HZ
+#define FAST_BACKOFF 0.01*HZ
+
+//#define PRINT_DEBUG
+#ifdef PRINT_DEBUG
+	#define DBG_PRINTK(format, a...) printk(format, ## a)
+#else
+	#define DBG_PRINTK(format, a...)
+#endif      
+
+#if defined(LINUX_2_1)
+ #define dev_put(a)
+ #define __sock_put(a)
+ #define sock_hold(a)
+ #define DECLARE_WAITQUEUE(a,b) \
+		struct wait_queue a = { b, NULL }
+#endif
+		
+/* SECURE SOCKET IMPLEMENTATION 
+ * 
+ *   TRANSMIT:
+ *
+ *      When the user sends a packet via send() system call
+ *      the wanpipe_sendmsg() function is executed.  
+ *      
+ *      Each packet is enqueud into sk->write_queue transmit
+ *      queue. When the packet is enqueued, a delayed transmit
+ *      timer is triggerd which acts as a Bottom Half hander. 
+ *
+ *      wanpipe_delay_transmit() function (BH), dequeues packets
+ *      from the sk->write_queue transmit queue and sends it 
+ *      to the deriver via dev->hard_start_xmit(skb, dev) function.  
+ *      Note, this function is actual a function pointer of if_send()
+ *      routine in the wanpipe driver.
+ *
+ *      X25API GUARANTEED DELIVERY:
+ *
+ *         In order to provide 100% guaranteed packet delivery, 
+ *         an atomic 'packet_sent' counter is implemented.  Counter 
+ *         is incremented for each packet enqueued 
+ *         into sk->write_queue.  Counter is decremented each
+ *         time wanpipe_delayed_transmit() function successfuly 
+ *         passes the packet to the driver. Before each send(), a poll
+ *         routine checks the sock resources The maximum value of
+ *         packet sent counter is 1, thus if one packet is queued, the
+ *         application will block untill that packet is passed to the
+ *         driver.
+ *
+ *   RECEIVE:
+ *
+ *      Wanpipe device drivers call the socket bottom half
+ *      function, wanpipe_rcv() to queue the incoming packets
+ *      into an AF_WANPIPE socket queue.  Based on wanpipe_rcv()
+ *      return code, the driver knows whether the packet was
+ *      sucessfully queued.  If the socket queue is full, 
+ *      protocol flow control is used by the driver, if any, 
+ *      to slow down the traffic untill the sock queue is free.
+ *
+ *      Every time a packet arrives into a socket queue the 
+ *      socket wakes up processes which are waiting to receive
+ *      data.
+ *
+ *      If the socket queue is full, the driver sets a block
+ *      bit which signals the socket to kick the wanpipe driver
+ *      bottom half hander when the socket queue is partialy
+ *      empty. wanpipe_recvmsg() function performs this action.
+ * 
+ *      In case of x25api, packets will never be dropped, since
+ *      flow control is available. 
+ *      
+ *      In case of streaming protocols like CHDLC, packets will 
+ *      be dropped but the statistics will be generated. 
+ */
+
+
+/* The code below is used to test memory leaks. It prints out
+ * a message every time kmalloc and kfree system calls get executed.
+ * If the calls match there is no leak :)
+ */
+
+/***********FOR DEBUGGING PURPOSES*********************************************
+#define KMEM_SAFETYZONE 8
+
+static void * dbg_kmalloc(unsigned int size, int prio, int line) {
+	void * v = kmalloc(size,prio);
+	printk(KERN_INFO "line %d  kmalloc(%d,%d) = %p\n",line,size,prio,v);
+	return v;
+}
+static void dbg_kfree(void * v, int line) {
+	printk(KERN_INFO "line %d  kfree(%p)\n",line,v);
+	kfree(v);
+}
+
+#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
+#define kfree(x) dbg_kfree(x,__LINE__)
+******************************************************************************/
+
+
+/* List of all wanpipe sockets. */
+struct sock * wanpipe_sklist = NULL;
+static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED;
+
+atomic_t wanpipe_socks_nr;
+static unsigned long wanpipe_tx_critical=0;
+
+#if 0
+/* Private wanpipe socket structures. */
+struct wanpipe_opt
+{
+	void   *mbox;		/* Mail box  */
+	void   *card; 		/* Card bouded to */
+	netdevice_t *dev;	/* Bounded device */
+	unsigned short lcn;	/* Binded LCN */
+	unsigned char  svc;	/* 0=pvc, 1=svc */
+	unsigned char  timer;   /* flag for delayed transmit*/	
+	struct timer_list tx_timer;
+	unsigned poll_cnt;
+	unsigned char force;	/* Used to force sock release */
+	atomic_t packet_sent;   
+};
+#endif
+
+static int sk_count=0;
+extern struct proto_ops wanpipe_ops;
+static unsigned long find_free_critical=0;
+
+static void wanpipe_unlink_driver (struct sock *);
+static void wanpipe_link_driver (netdevice_t *,struct sock *sk);
+static void wanpipe_wakeup_driver(struct sock *sk);
+static int execute_command(struct sock *, unsigned char, unsigned int);
+static int check_dev (netdevice_t *, sdla_t *);
+netdevice_t * wanpipe_find_free_dev (sdla_t *);
+static void wanpipe_unlink_card (struct sock *);
+static int wanpipe_link_card (struct sock *);
+static struct sock *wanpipe_make_new(struct sock *);
+static struct sock *wanpipe_alloc_socket(void);
+static inline int get_atomic_device (netdevice_t *);
+static int wanpipe_exec_cmd(struct sock *, int, unsigned int);
+static int get_ioctl_cmd (struct sock *, void *);
+static int set_ioctl_cmd (struct sock *, void *);
+static void release_device (netdevice_t *);
+static void wanpipe_kill_sock_timer (unsigned long data);
+static void wanpipe_kill_sock_irq (struct sock *);
+static void wanpipe_kill_sock_accept (struct sock *);
+static int wanpipe_do_bind(struct sock *, netdevice_t *, int);
+struct sock * get_newsk_from_skb (struct sk_buff *);
+static int wanpipe_debug (struct sock *, void *);
+static void wanpipe_delayed_transmit (unsigned long data);
+static void release_driver(struct sock *);
+static void start_cleanup_timer (struct sock *);
+static void check_write_queue(struct sock *);
+static int check_driver_busy (struct sock *);
+
+/*============================================================
+ * wanpipe_rcv
+ *
+ *	Wanpipe socket bottom half handler.  This function
+ *      is called by the WANPIPE device drivers to queue a
+ *      incomming packet into the socket receive queue. 
+ *      Once the packet is queued, all processes waiting to 
+ *      read are woken up.
+ *
+ *      During socket bind, this function is bounded into
+ *      WANPIPE driver private.
+ *===========================================================*/
+
+static int wanpipe_rcv(struct sk_buff *skb, netdevice_t *dev,  struct sock *sk)
+{
+	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb;
+	wanpipe_common_t *chan = dev->priv;
+	/*
+	 *	When we registered the protocol we saved the socket in the data
+	 *	field for just this event.
+	 */
+
+	skb->dev = dev;
+
+	sll->sll_family = AF_WANPIPE;
+	sll->sll_hatype = dev->type;
+	sll->sll_protocol = skb->protocol;
+	sll->sll_pkttype = skb->pkt_type;
+	sll->sll_ifindex = dev->ifindex;
+	sll->sll_halen = 0;
+
+	if (dev->hard_header_parse)
+		sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
+
+	/* 
+	 * WAN_PACKET_DATA : Data which should be passed up the receive queue.
+         * WAN_PACKET_ASYC : Asynchronous data like place call, which should
+         *                   be passed up the listening sock.
+         * WAN_PACKET_ERR  : Asynchronous data like clear call or restart 
+         *                   which should go into an error queue.
+         */
+	switch (skb->pkt_type){
+
+		case WAN_PACKET_DATA:
+			if (sock_queue_rcv_skb(sk,skb)<0){
+				return -ENOMEM;
+			}
+			break;
+		case WAN_PACKET_CMD:
+			sk->state = chan->state;
+			/* Bug fix: update Mar6. 
+                         * Do not set the sock lcn number here, since
+         		 * cmd is not guaranteed to be executed on the
+                         * board, thus Lcn could be wrong */
+			sk->data_ready(sk,skb->len);
+			kfree_skb(skb);
+			break;
+		case WAN_PACKET_ERR:
+			sk->state = chan->state;
+			if (sock_queue_err_skb(sk,skb)<0){
+				return -ENOMEM;
+			}
+			break;
+		default:
+			printk(KERN_INFO "wansock: BH Illegal Packet Type Dropping\n");
+			kfree_skb(skb); 
+			break;
+	}
+
+//??????????????????????
+//	if (sk->state == WANSOCK_DISCONNECTED){
+//		if (sk->zapped){
+//			//printk(KERN_INFO "wansock: Disconnected, killing early\n");
+//			wanpipe_unlink_driver(sk);
+//			sk->bound_dev_if = 0;
+//		}
+//	}
+
+	return 0;
+}
+
+/*============================================================
+ * wanpipe_listen_rcv
+ *
+ *	Wanpipe LISTEN socket bottom half handler.  This function
+ *      is called by the WANPIPE device drivers to queue an
+ *      incomming call into the socket listening queue. 
+ *      Once the packet is queued, the waiting accept() process 
+ *      is woken up.
+ *
+ *      During socket bind, this function is bounded into
+ *      WANPIPE driver private. 
+ * 
+ *      IMPORTANT NOTE:
+ *          The accept call() is waiting for an skb packet
+ *          which contains a pointer to a device structure.
+ *
+ *          When we do a bind to a device structre, we 
+ *          bind a newly created socket into "chan->sk".  Thus, 
+ *          when accept receives the skb packet, it will know 
+ *          from which dev it came form, and in turn it will know
+ *          the address of the new sock.
+ *
+ *  	NOTE: This function gets called from driver ISR.
+ *===========================================================*/
+
+static int wanpipe_listen_rcv (struct sk_buff *skb,  struct sock *sk)
+{
+
+	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb;
+	struct sock *newsk;
+	netdevice_t *dev; 
+	sdla_t *card;
+	mbox_cmd_t *mbox_ptr;
+	wanpipe_common_t *chan;
+
+	/* Find a free device, if none found, all svc's are busy 
+         */
+
+	card = (sdla_t*)sk->protinfo.af_wanpipe->card;
+	if (!card){
+		printk(KERN_INFO "wansock: LISTEN ERROR, No Card\n");
+		return -ENODEV;
+	}
+	
+	dev = wanpipe_find_free_dev(card);
+	if (!dev){
+		printk(KERN_INFO "wansock: LISTEN ERROR, No Free Device\n");
+		return -ENODEV;
+	}
+
+	chan=dev->priv;	
+	chan->state = WANSOCK_CONNECTING;
+
+	/* Allocate a new sock, which accept will bind
+         * and pass up to the user 
+	 */
+	if ((newsk = wanpipe_make_new(sk)) == NULL){
+		release_device(dev);
+		return -ENOMEM;
+	}
+
+
+	/* Initialize the new sock structure 
+	 */
+	newsk->bound_dev_if = dev->ifindex;
+	newsk->protinfo.af_wanpipe->card = sk->protinfo.af_wanpipe->card;
+
+	/* Insert the sock into the main wanpipe
+         * sock list.
+         */
+	atomic_inc(&wanpipe_socks_nr);
+
+	/* Allocate and fill in the new Mail Box. Then
+         * bind the mail box to the sock. It will be 
+         * used by the ioctl call to read call information
+         * and to execute commands. 
+         */	
+	if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) {
+		wanpipe_kill_sock_irq (newsk);
+		release_device(dev);		
+		return -ENOMEM;
+	}
+	memset(mbox_ptr, 0, sizeof(mbox_cmd_t));
+	memcpy(mbox_ptr,skb->data,skb->len);
+
+	/* Register the lcn on which incoming call came
+         * from. Thus, if we have to clear it, we know
+         * whic lcn to clear 
+	 */ 
+
+	newsk->protinfo.af_wanpipe->lcn = mbox_ptr->cmd.lcn;
+	newsk->protinfo.af_wanpipe->mbox = (void *)mbox_ptr;
+
+	DBG_PRINTK(KERN_INFO "NEWSOCK : Device %s, bind to lcn %i\n",
+			dev->name,mbox_ptr->cmd.lcn);
+
+	chan->lcn = mbox_ptr->cmd.lcn;
+	card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev;
+
+	newsk->zapped=0;
+	newsk->num = htons(X25_PROT);
+
+	if (wanpipe_do_bind(newsk,dev,newsk->num)){
+		wanpipe_kill_sock_irq (newsk);
+		release_device(dev);
+		return -EINVAL;
+	}
+	newsk->state = WANSOCK_CONNECTING;
+
+
+	/* Fill in the standard sock address info */
+
+	sll->sll_family = AF_WANPIPE;
+	sll->sll_hatype = dev->type;
+	sll->sll_protocol = skb->protocol;
+	sll->sll_pkttype = skb->pkt_type;
+	sll->sll_ifindex = dev->ifindex;
+	sll->sll_halen = 0;
+
+	skb->dev = dev;
+	sk->ack_backlog++;
+
+	/* We must do this manually, since the sock_queue_rcv_skb()
+	 * function sets the skb->dev to NULL.  However, we use
+	 * the dev field in the accept function.*/ 
+	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= 
+			(unsigned)sk->rcvbuf){
+
+         	wanpipe_unlink_driver(newsk);
+		wanpipe_kill_sock_irq (newsk);
+		--sk->ack_backlog;
+		return -ENOMEM;
+	}	
+
+	skb_set_owner_r(skb, sk);
+	skb_queue_tail(&sk->receive_queue, skb);
+	sk->data_ready(sk,skb->len);
+	
+	return 0;
+}
+
+
+
+/*============================================================
+ * wanpipe_make_new
+ *
+ *	Create a new sock, and allocate a wanpipe private
+ *      structure to it. Also, copy the important data
+ *      from the original sock to the new sock.
+ *
+ *      This function is used by wanpipe_listen_rcv() listen
+ *      bottom half handler.  A copy of the listening sock
+ *      is created using this function.
+ *
+ *===========================================================*/
+
+static struct sock *wanpipe_make_new(struct sock *osk)
+{
+	struct sock *sk;
+
+	if (osk->type != SOCK_RAW)
+		return NULL;
+
+	if ((sk = wanpipe_alloc_socket()) == NULL)
+		return NULL;
+
+	sk->type        = osk->type;
+	sk->socket      = osk->socket;
+	sk->priority    = osk->priority;
+	sk->protocol    = osk->protocol;
+	sk->num		= osk->num;
+	sk->rcvbuf      = osk->rcvbuf;
+	sk->sndbuf      = osk->sndbuf;
+	sk->debug       = osk->debug;
+	sk->state       = WANSOCK_CONNECTING;
+	sk->sleep       = osk->sleep;
+
+	return sk;
+}
+
+/*============================================================
+ * wanpipe_make_new
+ *
+ *	Allocate memory for the a new sock, and sock
+ *      private data.  
+ *	
+ *	Increment the module use count.
+ *       	
+ *      This function is used by wanpipe_create() and 
+ *      wanpipe_make_new() functions. 
+ *
+ *===========================================================*/
+
+static struct sock *wanpipe_alloc_socket(void)
+{
+	struct sock *sk;
+	struct wanpipe_opt *wan_opt;
+
+	if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1)) == NULL)
+		return NULL;
+
+	if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) {
+		sk_free(sk);
+		return NULL;
+	}
+	memset(wan_opt, 0x00, sizeof(struct wanpipe_opt));
+
+	sk->protinfo.af_wanpipe = wan_opt;
+	sk->protinfo.destruct_hook = wan_opt;
+
+	/* Use timer to send data to the driver. This will act
+         * as a BH handler for sendmsg functions */
+	sk->protinfo.af_wanpipe->tx_timer.data=(unsigned long)sk;
+	sk->protinfo.af_wanpipe->tx_timer.function=wanpipe_delayed_transmit;
+
+	MOD_INC_USE_COUNT;
+
+	sock_init_data(NULL, sk);
+	return sk;
+}
+
+
+/*============================================================
+ * wanpipe_sendmsg
+ *
+ *	This function implements a sendto() system call,
+ *      for AF_WANPIPE socket family. 
+ *      During socket bind() sk->bound_dev_if is initialized
+ *      to a correct network device. This number is used
+ *      to find a network device to which the packet should
+ *      be passed to.
+ *
+ *      Each packet is queued into sk->write_queue and 
+ *      delayed transmit bottom half handler is marked for 
+ *      execution.
+ *
+ *      A socket must be in WANSOCK_CONNECTED state before
+ *      a packet is queued into sk->write_queue.
+ *===========================================================*/
+
+static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			  struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name;
+	struct sk_buff *skb;
+	netdevice_t *dev;
+	unsigned short proto;
+	unsigned char *addr;
+	int ifindex, err, reserve = 0;
+
+	
+	if (!sk->zapped)
+		return -ENETDOWN;
+
+	if (sk->state != WANSOCK_CONNECTED)
+		return -ENOTCONN;	
+
+	if (msg->msg_flags&~MSG_DONTWAIT) 
+		return(-EINVAL);
+
+	/* it was <=, now one can send
+         * zero length packets */
+	if (len < sizeof(x25api_hdr_t))
+		return -EINVAL;
+
+	if (saddr == NULL) {
+		ifindex	= sk->bound_dev_if;
+		proto	= sk->num;
+		addr	= NULL;
+
+	}else{
+		if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ 
+			return -EINVAL;
+		}
+
+		ifindex = sk->bound_dev_if;
+		proto	= saddr->sll_protocol;
+		addr	= saddr->sll_addr;
+	}
+
+	dev = dev_get_by_index(ifindex);
+	if (dev == NULL){
+		printk(KERN_INFO "wansock: Send failed, dev index: %i\n",ifindex);
+		return -ENXIO;
+	}
+	dev_put(dev);
+	
+	if (sock->type == SOCK_RAW)
+		reserve = dev->hard_header_len;
+
+	if (len > dev->mtu+reserve){
+  		return -EMSGSIZE;
+	}
+
+      #ifndef LINUX_2_4
+	dev_lock_list();
+      #endif
+      
+      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
+	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 
+				msg->msg_flags & MSG_DONTWAIT, &err);
+      #else
+	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
+				msg->msg_flags & MSG_DONTWAIT, &err);
+      #endif
+
+	if (skb==NULL){
+		goto out_unlock;
+	}
+		
+	skb_reserve(skb, (dev->hard_header_len+15)&~15);
+	skb->nh.raw = skb->data;
+
+	/* Returns -EFAULT on error */
+	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+	if (err){
+		goto out_free;
+	}
+
+	if (dev->hard_header) {
+		int res;
+		err = -EINVAL;
+		res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
+		if (res<0){
+			goto out_free;
+		}
+	}
+
+	skb->protocol = proto;
+	skb->dev = dev;
+	skb->priority = sk->priority;
+	skb->pkt_type = WAN_PACKET_DATA;
+
+	err = -ENETDOWN;
+	if (!(dev->flags & IFF_UP))
+		goto out_free;
+
+      #ifndef LINUX_2_4
+	dev_unlock_list();
+      #endif
+	
+	if (atomic_read(&sk->wmem_alloc) + skb->truesize > (unsigned int)sk->sndbuf){
+		kfree_skb(skb);
+		return -ENOBUFS;
+	}
+
+	skb_queue_tail(&sk->write_queue,skb);
+	atomic_inc(&sk->protinfo.af_wanpipe->packet_sent);
+
+	if (!(test_and_set_bit(0,&sk->protinfo.af_wanpipe->timer))){
+		del_timer(&sk->protinfo.af_wanpipe->tx_timer);
+		sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1;
+		add_timer(&sk->protinfo.af_wanpipe->tx_timer);
+	}	
+	
+	return(len);
+
+out_free:
+	kfree_skb(skb);
+out_unlock:
+#ifndef LINUX_2_4
+	dev_unlock_list();
+#endif
+	return err;
+}
+
+/*============================================================
+ * wanpipe_delayed_tarnsmit
+ *
+ *	Transmit bottom half handeler. It dequeues packets
+ *      from sk->write_queue and passes them to the 
+ *      driver.  If the driver is busy, the packet is 
+ *      re-enqueued.  
+ *
+ *      Packet Sent counter is decremented on successful
+ *      transmission. 
+ *===========================================================*/
+
+
+static void wanpipe_delayed_transmit (unsigned long data)
+{
+	struct sock *sk=(struct sock *)data;
+	struct sk_buff *skb;
+	netdevice_t *dev = sk->protinfo.af_wanpipe->dev;
+	sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card;
+
+	if (!card || !dev){
+		clear_bit (0,&sk->protinfo.af_wanpipe->timer);
+		DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n");
+		return;
+	}
+	
+	if (sk->state != WANSOCK_CONNECTED || !sk->zapped){	
+		clear_bit (0,&sk->protinfo.af_wanpipe->timer);
+		DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n");
+		return;
+	}
+	
+	/* If driver is executing command, we must offload
+         * the board by not sending data. Otherwise a 
+         * pending command will never get a free buffer
+         * to execute */ 	
+	if (atomic_read(&card->u.x.command_busy)){
+		sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF;
+		add_timer(&sk->protinfo.af_wanpipe->tx_timer);
+		DBG_PRINTK(KERN_INFO "wansock: Tx Timer, command bys BACKOFF\n");
+		return;
+	}
+
+	
+	if (test_and_set_bit(0,&wanpipe_tx_critical)){
+		printk(KERN_INFO "WanSock: Tx timer critical %s\n",dev->name);
+		sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF;
+		add_timer(&sk->protinfo.af_wanpipe->tx_timer);
+		return;
+	}	
+	
+	/* Check for a packet in the fifo and send */
+	if ((skb=skb_dequeue(&sk->write_queue)) != NULL){
+
+		if (dev->hard_start_xmit(skb, dev) != 0){			
+
+			/* Driver failed to transmit, re-enqueue
+                         * the packet and retry again later */
+			skb_queue_head(&sk->write_queue,skb);
+			clear_bit(0,&wanpipe_tx_critical);
+			return;
+		}else{
+
+			/* Packet Sent successful. Check for more packets
+                         * if more packets, re-trigger the transmit routine 
+                         * other wise exit
+                         */
+			atomic_dec(&sk->protinfo.af_wanpipe->packet_sent);
+
+			if (skb_peek(&sk->write_queue) == NULL){
+				/* If there is nothing to send, kick
+				 * the poll routine, which will trigger
+				 * the application to send more data */
+				sk->data_ready(sk,0);
+				clear_bit (0,&sk->protinfo.af_wanpipe->timer);
+			}else{
+				/* Reschedule as fast as possible */
+				sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1;
+				add_timer(&sk->protinfo.af_wanpipe->tx_timer);
+			}
+		}
+	}
+	clear_bit(0,&wanpipe_tx_critical);
+}
+
+/*============================================================
+ * execute_command 
+ *
+ *	Execute x25api commands.  The atomic variable
+ *      chan->command is used to indicate to the driver that
+ *      command is pending for exection.  The acutal command
+ *      structure is placed into a sock mbox structure 
+ *      (sk->protinfo.af_wanpipe->mbox).
+ *
+ *      The sock private structure, mbox is
+ *      used as shared memory between sock and the driver.
+ *      Driver uses the sock mbox to execute the command
+ *      and return the result.  
+ *
+ *      For all command except PLACE CALL, the function
+ *      waits for the result.  PLACE CALL can be ether
+ *      blocking or nonblocking. The user sets this option
+ *      via ioctl call.
+ *===========================================================*/
+
+
+static int execute_command(struct sock *sk,  unsigned char cmd, unsigned int flags)
+{
+	netdevice_t *dev;
+	wanpipe_common_t *chan=NULL;
+	int err=0;
+	DECLARE_WAITQUEUE(wait, current);
+	
+	dev = dev_get_by_index(sk->bound_dev_if);
+	if (dev == NULL){
+		printk(KERN_INFO "wansock: Exec failed no dev %i\n",
+			sk->bound_dev_if);
+		return -ENODEV;
+	}
+	dev_put(dev);
+
+	if ((chan=dev->priv) == NULL){
+		printk(KERN_INFO "wansock: Exec cmd failed no priv area\n");
+		return -ENODEV;
+	}
+
+	if (atomic_read(&chan->command)){
+		printk(KERN_INFO "wansock: ERROR: Command already running %x, %s\n",
+			atomic_read(&chan->command),dev->name);
+		return -EINVAL;
+	}
+
+	if (!sk->protinfo.af_wanpipe->mbox){
+		printk(KERN_INFO "wansock: In execute without MBOX\n");
+		return -EINVAL;
+	}
+
+	((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.command=cmd;	
+	((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn = 
+					sk->protinfo.af_wanpipe->lcn;
+	((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result=0x7F;
+
+
+	if (flags & O_NONBLOCK){
+		cmd |= 0x80;
+		atomic_set(&chan->command, cmd);
+	}else{
+		atomic_set(&chan->command, cmd);
+	}
+
+	add_wait_queue(sk->sleep,&wait);
+	current->state = TASK_INTERRUPTIBLE;
+	for (;;){
+		if (((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result != 0x7F) {
+			err = 0;
+			break;
+		}
+		if (signal_pending(current)) {
+			err = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep,&wait);
+	
+	return err;
+}
+
+/*============================================================
+ * wanpipe_destroy_timer 
+ *
+ *	Used by wanpipe_release, to delay release of
+ *      the socket.
+ *===========================================================*/
+
+static void wanpipe_destroy_timer(unsigned long data)
+{
+	struct sock *sk=(struct sock *)data;
+
+	if ((!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) ||
+	    (++sk->protinfo.af_wanpipe->force == 5)) {
+
+		if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc))
+			printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n");
+
+		if (sk->protinfo.af_wanpipe){
+			kfree(sk->protinfo.af_wanpipe);
+			sk->protinfo.af_wanpipe=NULL;
+		}
+		
+              #ifdef LINUX_2_4
+		if (atomic_read(&sk->refcnt) != 1){
+			atomic_set(&sk->refcnt,1);
+			DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n",
+					atomic_read(&sk->refcnt));
+		}
+		sock_put(sk);
+              #else
+		sk_free(sk);
+              #endif
+		atomic_dec(&wanpipe_socks_nr);
+		MOD_DEC_USE_COUNT;
+		return;
+	}
+
+	sk->timer.expires=jiffies+5*HZ;
+	add_timer(&sk->timer);
+	printk(KERN_INFO "wansock: packet sk destroy delayed\n");
+}
+
+/*============================================================
+ * wanpipe_unlink_driver
+ *
+ * 	When the socket is released, this function is 
+ *      used to remove links that bind the sock and the
+ *      driver together.  
+ *===========================================================*/
+static void wanpipe_unlink_driver (struct sock *sk)
+{
+	netdevice_t *dev;
+	wanpipe_common_t *chan=NULL;
+
+	sk->zapped=0;
+	sk->state = WANSOCK_DISCONNECTED;
+	sk->protinfo.af_wanpipe->dev = NULL;
+
+	dev = dev_get_by_index(sk->bound_dev_if);
+	if (!dev){
+		printk(KERN_INFO "wansock: No dev on release\n");
+		return;
+	}			
+	dev_put(dev);
+
+	if ((chan = dev->priv) == NULL){
+		printk(KERN_INFO "wansock: No Priv Area on release\n");
+		return;
+	}
+
+	set_bit(0,&chan->common_critical);
+	chan->sk=NULL;
+	chan->func=NULL;
+	chan->mbox=NULL;
+	chan->tx_timer=NULL;
+	clear_bit(0,&chan->common_critical);
+	release_device(dev);
+	
+	return;
+}
+
+/*============================================================
+ * wanpipe_link_driver
+ *
+ * 	Upon successful bind(), sock is linked to a driver
+ *      by binding in the wanpipe_rcv() bottom half handler
+ *      to the driver function pointer, as well as sock and
+ *      sock mailbox addresses.  This way driver can pass
+ *      data up the socket.
+ *===========================================================*/
+
+static void wanpipe_link_driver (netdevice_t *dev, struct sock *sk)
+{
+	wanpipe_common_t *chan = dev->priv;
+	if (!chan)
+		return;
+	set_bit(0,&chan->common_critical);
+	chan->sk=sk;
+	chan->func=wanpipe_rcv;
+	chan->mbox=sk->protinfo.af_wanpipe->mbox;
+	chan->tx_timer = &sk->protinfo.af_wanpipe->tx_timer;
+	sk->protinfo.af_wanpipe->dev=dev;
+	sk->zapped = 1;
+	clear_bit(0,&chan->common_critical);
+}
+
+
+/*============================================================
+ * release_device
+ *
+ *   	During sock release, clear a critical bit, which 
+ *      marks the device a being taken.
+ *===========================================================*/
+
+
+static void release_device (netdevice_t *dev)
+{
+	wanpipe_common_t *chan=dev->priv;
+	clear_bit(0,(void*)&chan->rw_bind);
+}
+
+/*============================================================
+ * wanpipe_release
+ *
+ *	Close a PACKET socket. This is fairly simple. We 
+ *      immediately go to 'closed' state and remove our 
+ *      protocol entry in the device list.
+ *===========================================================*/
+
+#ifdef LINUX_2_4
+static int wanpipe_release(struct socket *sock)
+#else
+static int wanpipe_release(struct socket *sock, struct socket *peersock)
+#endif
+{
+	
+#ifndef LINUX_2_4
+	struct sk_buff	*skb;
+#endif
+	struct sock *sk = sock->sk;
+	struct sock **skp;
+	
+	if (!sk)
+		return 0;
+
+	check_write_queue(sk);
+
+	/* Kill the tx timer, if we don't kill it now, the timer
+         * will run after we kill the sock.  Timer code will 
+         * try to access the sock which has been killed and cause
+         * kernel panic */
+
+	del_timer(&sk->protinfo.af_wanpipe->tx_timer);
+
+	/*
+	 *	Unhook packet receive handler.
+	 */
+
+	if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->zapped){
+		netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+		wanpipe_common_t *chan;
+		if (dev){
+			chan=dev->priv;
+			atomic_set(&chan->disconnect,1);
+			DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n",
+					sk->state);
+			dev_put(dev);
+		}	
+	}
+
+	set_bit(1,&wanpipe_tx_critical);
+	write_lock(&wanpipe_sklist_lock);
+	for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) {
+		if (*skp == sk) {
+			*skp = sk->next;
+			__sock_put(sk);
+			break;
+		}
+	}
+	write_unlock(&wanpipe_sklist_lock);
+	clear_bit(1,&wanpipe_tx_critical);
+
+
+	
+	release_driver(sk);
+
+	
+	/*
+	 *	Now the socket is dead. No more input will appear.
+	 */
+
+	sk->state_change(sk);	/* It is useless. Just for sanity. */
+
+	sock->sk = NULL;
+	sk->socket = NULL;
+	sk->dead = 1;
+
+	/* Purge queues */
+#ifdef LINUX_2_4
+	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sk->write_queue);
+	skb_queue_purge(&sk->error_queue);
+#else	
+
+	while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){
+		kfree_skb(skb);
+	}
+	while ((skb=skb_dequeue(&sk->error_queue))!=NULL){
+		kfree_skb(skb);
+	}
+	while ((skb=skb_dequeue(&sk->write_queue))!=NULL){
+		kfree_skb(skb);
+	}
+#endif	
+	if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) {
+		del_timer(&sk->timer);
+		printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n",
+			atomic_read(&sk->rmem_alloc),atomic_read(&sk->wmem_alloc));
+		sk->timer.data=(unsigned long)sk;
+		sk->timer.expires=jiffies+HZ;
+		sk->timer.function=wanpipe_destroy_timer;
+		add_timer(&sk->timer);
+		return 0;
+	}
+
+	if (sk->protinfo.af_wanpipe){
+		kfree(sk->protinfo.af_wanpipe);
+		sk->protinfo.af_wanpipe=NULL;
+	}
+
+      #ifdef LINUX_2_4
+	if (atomic_read(&sk->refcnt) != 1){
+		DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n",
+					atomic_read(&sk->refcnt));
+		atomic_set(&sk->refcnt,1);
+	}
+	sock_put(sk);
+      #else	
+	sk_free(sk);
+      #endif
+	atomic_dec(&wanpipe_socks_nr);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*============================================================
+ * check_write_queue
+ *
+ *  	During sock shutdown, if the sock state is 
+ *      WANSOCK_CONNECTED and there is transmit data 
+ *      pending. Wait until data is released 
+ *      before proceeding.
+ *===========================================================*/
+
+static void check_write_queue(struct sock *sk)
+{
+
+	if (sk->state != WANSOCK_CONNECTED)
+		return;
+
+	if (!atomic_read(&sk->wmem_alloc))
+		return;
+
+	printk(KERN_INFO "wansock: MAJOR ERROR, Data lost on sock release !!!\n");
+
+}
+
+/*============================================================
+ * release_driver
+ *
+ *	This function is called during sock shutdown, to 
+ *      release any resources and links that bind the sock
+ *      to the driver.  It also changes the state of the
+ *      sock to WANSOCK_DISCONNECTED
+ *===========================================================*/
+
+static void release_driver(struct sock *sk)
+{
+	struct sk_buff *skb=NULL;
+	struct sock *deadsk=NULL;
+
+	if (sk->state == WANSOCK_LISTEN || sk->state == WANSOCK_BIND_LISTEN){
+		while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){
+			if ((deadsk = get_newsk_from_skb(skb))){
+				DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n");
+				deadsk->dead=1;
+				start_cleanup_timer(deadsk);
+			}
+			kfree_skb(skb);
+		}
+		if (sk->zapped)
+			wanpipe_unlink_card(sk);
+	}else{
+		if (sk->zapped)
+			wanpipe_unlink_driver(sk);
+	}
+	sk->state = WANSOCK_DISCONNECTED;
+	sk->bound_dev_if = 0;
+	sk->zapped=0;
+
+	if (sk->protinfo.af_wanpipe){
+		if (sk->protinfo.af_wanpipe->mbox){
+			kfree(sk->protinfo.af_wanpipe->mbox);
+			sk->protinfo.af_wanpipe->mbox=NULL;
+		}
+	}
+}
+
+/*============================================================
+ *  start_cleanup_timer
+ *
+ *  	If new incoming call's are pending but the socket
+ *      is being released, start the timer which will 
+ *      envoke the kill routines for pending socks.
+ *===========================================================*/
+
+
+static void start_cleanup_timer (struct sock *sk)
+{
+	del_timer(&sk->timer);
+	sk->timer.data = (unsigned long)sk;
+	sk->timer.expires = jiffies + HZ;
+	sk->timer.function = wanpipe_kill_sock_timer;
+	add_timer(&sk->timer);
+}
+
+
+/*============================================================
+ *  wanpipe_kill_sock
+ *
+ *	This is a function which performs actual killing
+ *      of the sock.  It releases socket resources,
+ *      and unlinks the sock from the driver. 
+ *===========================================================*/
+
+static void wanpipe_kill_sock_timer (unsigned long data)
+{
+
+	struct sock *sk = (struct sock *)data;
+#ifndef LINUX_2_4
+	struct sk_buff *skb;
+#endif
+
+	struct sock **skp;
+
+	if (!sk)
+		return;
+
+	/* This functin can be called from interrupt. We must use
+	 * appropriate locks */
+	
+	if (test_bit(1,&wanpipe_tx_critical)){
+		sk->timer.expires=jiffies+10;
+		add_timer(&sk->timer);
+		return;
+	}
+	
+	write_lock(&wanpipe_sklist_lock);
+	for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) {
+		if (*skp == sk) {
+			*skp = sk->next;
+			__sock_put(sk);
+			break;
+		}
+	}
+	write_unlock(&wanpipe_sklist_lock);
+
+
+	if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED){
+		netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+		wanpipe_common_t *chan;
+		if (dev){
+			chan=dev->priv;
+			atomic_set(&chan->disconnect,1);
+			dev_put(dev);
+		}	
+	}
+
+	release_driver(sk);
+
+	sk->socket = NULL;
+
+	/* Purge queues */
+#ifdef LINUX_2_4
+	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sk->write_queue);
+	skb_queue_purge(&sk->error_queue);
+#else	
+	while ((skb=skb_dequeue(&sk->receive_queue)) != NULL){
+		kfree_skb(skb);
+	}
+	while ((skb=skb_dequeue(&sk->write_queue)) != NULL) {
+		kfree_skb(skb);
+	}
+	while ((skb=skb_dequeue(&sk->error_queue)) != NULL){
+		kfree_skb(skb);
+	}
+#endif
+	
+	if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) {
+		del_timer(&sk->timer);
+		printk(KERN_INFO "wansock: Killing SOCK in Timer\n");
+		sk->timer.data=(unsigned long)sk;
+		sk->timer.expires=jiffies+HZ;
+		sk->timer.function=wanpipe_destroy_timer;
+		add_timer(&sk->timer);
+		return;
+	}
+
+	if (sk->protinfo.af_wanpipe){
+		kfree(sk->protinfo.af_wanpipe);
+		sk->protinfo.af_wanpipe=NULL;
+	}
+
+      #ifdef LINUX_2_4
+	if (atomic_read(&sk->refcnt) != 1){
+		atomic_set(&sk->refcnt,1);
+		DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n",
+					atomic_read(&sk->refcnt));
+	}
+	sock_put(sk);
+      #else
+	sk_free(sk);
+      #endif
+	atomic_dec(&wanpipe_socks_nr);
+	MOD_DEC_USE_COUNT;
+	return;
+}
+
+static void wanpipe_kill_sock_accept (struct sock *sk)
+{
+
+	struct sock **skp;
+
+	if (!sk)
+		return;
+
+	/* This functin can be called from interrupt. We must use
+	 * appropriate locks */
+	
+	write_lock(&wanpipe_sklist_lock);
+	for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) {
+		if (*skp == sk) {
+			*skp = sk->next;
+			__sock_put(sk);
+			break;
+		}
+	}
+	write_unlock(&wanpipe_sklist_lock);
+
+	sk->socket = NULL;
+
+
+	if (sk->protinfo.af_wanpipe){
+		kfree(sk->protinfo.af_wanpipe);
+		sk->protinfo.af_wanpipe=NULL;
+	}
+
+      #ifdef LINUX_2_4
+	if (atomic_read(&sk->refcnt) != 1){
+		atomic_set(&sk->refcnt,1);
+		DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n",
+					atomic_read(&sk->refcnt));
+	}
+	sock_put(sk);
+      #else
+	sk_free(sk);
+      #endif
+	atomic_dec(&wanpipe_socks_nr);
+	MOD_DEC_USE_COUNT;
+	return;
+}
+
+
+static void wanpipe_kill_sock_irq (struct sock *sk)
+{
+
+	if (!sk)
+		return;
+
+	sk->socket = NULL;
+
+	if (sk->protinfo.af_wanpipe){
+		kfree(sk->protinfo.af_wanpipe);
+		sk->protinfo.af_wanpipe=NULL;
+	}
+
+      #ifdef LINUX_2_4
+	if (atomic_read(&sk->refcnt) != 1){
+		atomic_set(&sk->refcnt,1);
+		DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:listen.\n",
+					atomic_read(&sk->refcnt));
+	}
+	sock_put(sk);
+      #else
+	sk_free(sk);
+      #endif
+	atomic_dec(&wanpipe_socks_nr);
+	MOD_DEC_USE_COUNT;
+	return;
+}
+
+
+/*============================================================
+ *  wanpipe_do_bind
+ *
+ * 	Bottom half of the binding system call.
+ *      Once the wanpipe_bind() function checks  the
+ *      legality of the call, this function binds the
+ *      sock to the driver.
+ *===========================================================*/
+
+static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol)
+{
+	wanpipe_common_t *chan=NULL;
+	int err=0;
+
+	if (sk->zapped){
+		err = -EALREADY;
+		goto bind_unlock_exit;
+	}
+
+	sk->num = protocol;
+
+	if (protocol == 0){
+		release_device(dev);
+		err = -EINVAL;
+		goto bind_unlock_exit;
+	}
+
+	if (dev) {
+		if (dev->flags&IFF_UP) {
+			chan=dev->priv;
+			sk->state = chan->state;
+
+			if (sk->num == htons(X25_PROT) && 
+			    sk->state != WANSOCK_DISCONNECTED && 
+			    sk->state != WANSOCK_CONNECTING){
+				DBG_PRINTK(KERN_INFO 
+					"wansock: Binding to Device not DISCONNECTED %i\n",
+						sk->state);
+				release_device(dev);
+				err = -EAGAIN;
+				goto bind_unlock_exit;
+			}
+
+			wanpipe_link_driver(dev,sk);
+			sk->bound_dev_if = dev->ifindex;
+
+			/* X25 Specific option */
+			if (sk->num == htons(X25_PROT))
+				sk->protinfo.af_wanpipe->svc = chan->svc;
+
+		} else {
+			sk->err = ENETDOWN;
+			sk->error_report(sk);
+			release_device(dev);
+			err = -EINVAL;
+		}
+	} else {
+		err = -ENODEV;
+	}
+bind_unlock_exit:
+	/* FIXME where is this lock */
+
+	return err;
+}
+
+/*============================================================
+ *  wanpipe_bind
+ *
+ *      BIND() System call, which is bound to the AF_WANPIPE
+ *      operations structure.  It checks for correct wanpipe
+ *      card name, and cross references interface names with
+ *      the card names.  Thus, interface name must belong to
+ *      the actual card.
+ *===========================================================*/
+
+
+static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr;
+	struct sock *sk=sock->sk;
+	netdevice_t *dev = NULL;
+	sdla_t *card=NULL;
+	char name[15];
+
+	/*
+	 *	Check legality
+	 */
+	 
+	if (addr_len < sizeof(struct wan_sockaddr_ll)){
+		printk(KERN_INFO "wansock: Address length error\n");
+		return -EINVAL;
+	}
+	if (sll->sll_family != AF_WANPIPE){
+		printk(KERN_INFO "wansock: Illegal family name specified.\n");
+		return -EINVAL;
+	}
+
+	card = wanpipe_find_card (sll->sll_card);
+	if (!card){
+		printk(KERN_INFO "wansock: Wanpipe card not found: %s\n",sll->sll_card);
+		return -ENODEV;
+	}else{
+		sk->protinfo.af_wanpipe->card = (void *)card;
+	}
+
+	if (!strcmp(sll->sll_device,"svc_listen")){
+
+		/* Bind a sock to a card structure for listening 
+		 */		
+		int err=0; 
+
+		/* This is x25 specific area if protocol doesn't
+                 * match, return error */
+		if (sll->sll_protocol != htons(X25_PROT))
+			return -EINVAL;
+
+		err= wanpipe_link_card (sk);
+		if (err < 0)
+			return err;
+
+		if (sll->sll_protocol)
+			sk->num = sll->sll_protocol;
+		sk->state = WANSOCK_BIND_LISTEN;
+		return 0;
+
+	}else if (!strcmp(sll->sll_device,"svc_connect")){ 
+
+		/* This is x25 specific area if protocol doesn't
+                 * match, return error */
+		if (sll->sll_protocol != htons(X25_PROT))
+			return -EINVAL;
+
+		/* Find a free device 
+		 */
+		dev = wanpipe_find_free_dev(card);
+		if (dev == NULL){
+			DBG_PRINTK(KERN_INFO "wansock: No free network devices for card %s\n",
+				card->devname);
+			return -EINVAL;
+		}
+	}else{
+		/* Bind a socket to a interface name 
+                 * This is used by PVC mostly
+                 */
+		strncpy(name,sll->sll_device,14);
+		name[14]=0;
+#ifdef LINUX_2_4
+		dev = dev_get_by_name(name);
+#else
+		dev = dev_get(name);
+#endif
+		if (dev == NULL){
+			printk(KERN_INFO "wansock: Failed to get Dev from name: %s,\n",
+					name);
+			return -ENODEV;
+		}
+
+		dev_put(dev);
+
+		if (check_dev(dev, card)){
+			printk(KERN_INFO "wansock: Device %s, doesn't belong to card %s\n",
+				dev->name, card->devname);
+			return -EINVAL;
+		}
+		if (get_atomic_device (dev))
+			return -EINVAL;
+	}
+
+	return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : sk->num);
+}
+
+/*============================================================
+ * get_atomic_device
+ *	
+ *	Sets a bit atomically which indicates that 
+ *      the interface is taken. This avoids race conditions.
+ *===========================================================*/
+
+
+static inline int get_atomic_device (netdevice_t *dev)
+{
+	wanpipe_common_t *chan = dev->priv;
+	if (!test_and_set_bit(0,(void *)&chan->rw_bind)){
+		return 0;
+	}
+	return 1;
+}
+
+/*============================================================
+ * check_dev
+ *	
+ *  	Check that device name belongs to a particular card.
+ *===========================================================*/
+
+static int check_dev (netdevice_t *dev, sdla_t *card)
+{
+	netdevice_t* tmp_dev;
+
+	for (tmp_dev = card->wandev.dev; tmp_dev; tmp_dev=*((netdevice_t**)tmp_dev->priv)){
+		if (tmp_dev->ifindex == dev->ifindex){ 
+			return 0;	
+		}
+	}
+	return 1;
+}
+
+/*============================================================
+ *  wanpipe_find_free_dev
+ *	
+ *	Find a free network interface. If found set atomic
+ *      bit indicating that the interface is taken.
+ *      X25API Specific.
+ *===========================================================*/
+
+netdevice_t * wanpipe_find_free_dev (sdla_t *card)
+{
+	netdevice_t* dev;
+	volatile wanpipe_common_t *chan;
+
+	if (test_and_set_bit(0,&find_free_critical)){
+		printk(KERN_INFO "CRITICAL in Find Free\n");
+	}	
+
+	for (dev = card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+		chan = dev->priv;
+		if (!chan) 
+			continue;
+		if (chan->usedby == API && chan->svc){
+			if (!get_atomic_device (dev)){
+				if (chan->state != WANSOCK_DISCONNECTED){
+					release_device(dev);
+				}else{
+					clear_bit(0,&find_free_critical);
+					return dev;
+				}
+			}
+		}
+	}
+	clear_bit(0,&find_free_critical);
+	return NULL;
+}
+
+/*============================================================
+ *  wanpipe_create
+ *	
+ * 	SOCKET() System call.  It allocates a sock structure
+ *      and adds the socket to the wanpipe_sk_list. 
+ *      Crates AF_WANPIPE socket.
+ *===========================================================*/
+
+static int wanpipe_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	
+	//FIXME: This checks for root user, SECURITY ?
+	//if (!capable(CAP_NET_RAW))
+	//	return -EPERM;
+
+	if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->state = SS_UNCONNECTED;
+
+	if ((sk = wanpipe_alloc_socket()) == NULL)
+		return -ENOBUFS;
+
+	sk->reuse = 1;
+	sock->ops = &wanpipe_ops;
+	sock_init_data(sock,sk);
+
+	sk->zapped=0;
+	sk->family = PF_WANPIPE;
+	sk->num = protocol;
+	sk->state = WANSOCK_DISCONNECTED;
+	sk->ack_backlog = 0;
+	sk->bound_dev_if=0;
+
+	atomic_inc(&wanpipe_socks_nr);
+	
+	/* We must disable interrupts because the ISR
+	 * can also change the list */
+	set_bit(1,&wanpipe_tx_critical);
+	write_lock(&wanpipe_sklist_lock);
+	sk->next = wanpipe_sklist;
+	wanpipe_sklist = sk;
+	sock_hold(sk);
+	write_unlock(&wanpipe_sklist_lock);
+	clear_bit(1,&wanpipe_tx_critical);
+
+	return(0);
+}
+
+
+/*============================================================
+ *  wanpipe_recvmsg
+ *	
+ *	Pull a packet from our receive queue and hand it 
+ *      to the user. If necessary we block.
+ *===========================================================*/
+
+static int wanpipe_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+			  int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int copied, err=-ENOBUFS;
+
+
+	/*
+	 *	If the address length field is there to be filled in, we fill
+	 *	it in now.
+	 */
+
+	msg->msg_namelen = sizeof(struct wan_sockaddr_ll);
+
+	/*
+	 *	Call the generic datagram receiver. This handles all sorts
+	 *	of horrible races and re-entrancy so we can forget about it
+	 *	in the protocol layers.
+	 *
+	 *	Now it will return ENETDOWN, if device have just gone down,
+	 *	but then it will block.
+	 */
+
+	if (flags & MSG_OOB){	
+		skb=skb_dequeue(&sk->error_queue);
+	}else{
+		skb=skb_recv_datagram(sk,flags,1,&err);
+	}
+	/*
+	 *	An error occurred so return it. Because skb_recv_datagram() 
+	 *	handles the blocking we don't see and worry about blocking
+	 *	retries.
+	 */
+
+	if(skb==NULL)
+		goto out;
+
+	/*
+	 *	You lose any data beyond the buffer you gave. If it worries a
+	 *	user program they can ask the device for its MTU anyway.
+	 */
+
+	copied = skb->len;
+	if (copied > len)
+	{
+		copied=len;
+		msg->msg_flags|=MSG_TRUNC;
+	}
+
+	wanpipe_wakeup_driver(sk);
+
+	/* We can't use skb_copy_datagram here */
+	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+	if (err)
+		goto out_free;
+	
+#ifdef LINUX_2_1
+	sk->stamp=skb->stamp;
+#else
+	sock_recv_timestamp(msg, sk, skb);
+#endif
+	
+	if (msg->msg_name)
+		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
+
+	/*
+	 *	Free or return the buffer as appropriate. Again this
+	 *	hides all the races and re-entrancy issues from us.
+	 */
+	err = (flags&MSG_TRUNC) ? skb->len : copied;
+
+out_free:
+	skb_free_datagram(sk, skb);
+out:
+	return err;
+}
+
+
+/*============================================================
+ *  wanpipe_wakeup_driver
+ *	
+ * 	If socket receive buffer is full and driver cannot
+ *      pass data up the sock, it sets a packet_block flag.
+ *      This function check that flag and if sock receive 
+ *      queue has room it kicks the driver BH handler. 
+ *
+ * 	This way, driver doesn't have to poll the sock 
+ *      receive queue.
+ *===========================================================*/
+
+static void wanpipe_wakeup_driver(struct sock *sk)
+{
+	netdevice_t *dev=NULL;
+	wanpipe_common_t *chan=NULL;
+
+	dev = dev_get_by_index(sk->bound_dev_if);
+	if (!dev)
+		return;
+
+	dev_put(dev);
+
+	if ((chan = dev->priv) == NULL)
+		return;
+	
+	if (atomic_read(&chan->receive_block)){  
+		if (atomic_read(&sk->rmem_alloc) < ((unsigned)sk->rcvbuf*0.9) ){
+			printk(KERN_INFO "wansock: Queuing task for wanpipe\n");
+			atomic_set(&chan->receive_block,0);
+			wanpipe_queue_tq(&chan->wanpipe_task);
+			wanpipe_mark_bh();
+		}
+	}	
+}	
+
+/*============================================================
+ *  wanpipe_getname
+ *	
+ * 	I don't know what to do with this yet. 
+ *      User can use this function to get sock address
+ *      information. Not very useful for Sangoma's purposes.
+ *===========================================================*/
+
+
+static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr,
+			  int *uaddr_len, int peer)
+{
+	netdevice_t *dev;
+	struct sock *sk = sock->sk;
+	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr;
+
+	sll->sll_family = AF_WANPIPE;
+	sll->sll_ifindex = sk->bound_dev_if;
+	sll->sll_protocol = sk->num;
+	dev = dev_get_by_index(sk->bound_dev_if);
+	if (dev) {
+		sll->sll_hatype = dev->type;
+		sll->sll_halen = dev->addr_len;
+		memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len);
+	} else {
+		sll->sll_hatype = 0;	/* Bad: we have no ARPHRD_UNSPEC */
+		sll->sll_halen = 0;
+	}
+	*uaddr_len = sizeof(*sll);
+	
+	dev_put(dev);
+	
+	return 0;
+}
+
+/*============================================================
+ *  wanpipe_notifier
+ *	
+ *	If driver turns off network interface, this function
+ *      will be envoked. Currently I treate it as a 
+ *      call disconnect. More thought should go into this
+ *      function.
+ *
+ * FIXME: More thought should go into this function.
+ *
+ *===========================================================*/
+
+static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data)
+{
+	struct sock *sk;
+	netdevice_t *dev = (netdevice_t*)data;
+	struct wanpipe_opt *po;
+
+	for (sk = wanpipe_sklist; sk; sk = sk->next) {
+
+		if ((po = sk->protinfo.af_wanpipe)==NULL)
+			continue;
+		if (dev == NULL)
+			continue;
+		
+		switch (msg) {
+		case NETDEV_DOWN:
+		case NETDEV_UNREGISTER:
+			if (dev->ifindex == sk->bound_dev_if) {
+				printk(KERN_INFO "wansock: Device down %s\n",dev->name);
+				if (sk->zapped){
+					wanpipe_unlink_driver(sk);
+					sk->err = ENETDOWN;
+					sk->error_report(sk);
+				}
+
+				if (msg == NETDEV_UNREGISTER) {
+					printk(KERN_INFO "wansock: Unregistering Device: %s\n",
+						 	  dev->name);
+					wanpipe_unlink_driver(sk);
+					sk->bound_dev_if = 0;
+				}
+			}
+			break;
+		case NETDEV_UP:
+			if (dev->ifindex == sk->bound_dev_if && sk->num && !sk->zapped) {
+				printk(KERN_INFO "wansock: Registering Device: %s\n",
+						dev->name);
+				wanpipe_link_driver(dev,sk);
+			}
+			break;
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+/*============================================================
+ *  wanpipe_ioctl
+ *	
+ * 	Execute a user commands, and set socket options.
+ *
+ * FIXME: More thought should go into this function.
+ *
+ *===========================================================*/
+
+static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	int err;
+	int pid;
+
+	switch(cmd) 
+	{
+		case FIOSETOWN:
+		case SIOCSPGRP:
+			err = get_user(pid, (int *) arg);
+			if (err)
+				return err; 
+			if (current->pid != pid && current->pgrp != -pid && 
+			    !capable(CAP_NET_ADMIN))
+				return -EPERM;
+			sk->proc = pid;
+			return(0);
+		case FIOGETOWN:
+		case SIOCGPGRP:
+			return put_user(sk->proc, (int *)arg);
+		case SIOCGSTAMP:
+			if(sk->stamp.tv_sec==0)
+				return -ENOENT;
+			err = -EFAULT;
+			if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+				err = 0;
+			return err;
+
+		case SIOC_WANPIPE_CHECK_TX:
+
+			return atomic_read(&sk->wmem_alloc);
+
+		case SIOC_WANPIPE_SOCK_STATE:
+
+			if (sk->state == WANSOCK_CONNECTED)
+				return 0;
+			
+			return 1;
+
+
+		case SIOC_WANPIPE_GET_CALL_DATA:
+
+			return get_ioctl_cmd (sk,(void*)arg);
+
+		case SIOC_WANPIPE_SET_CALL_DATA:
+
+			return set_ioctl_cmd (sk,(void*)arg);
+
+		case SIOC_WANPIPE_ACCEPT_CALL:
+		case SIOC_WANPIPE_CLEAR_CALL:
+		case SIOC_WANPIPE_RESET_CALL:
+
+			if ((err=set_ioctl_cmd(sk,(void*)arg)) < 0)
+				return err;
+
+			err=wanpipe_exec_cmd(sk,cmd,0);
+			get_ioctl_cmd(sk,(void*)arg);
+			return err;
+
+		case SIOC_WANPIPE_DEBUG:
+
+			return wanpipe_debug(sk,(void*)arg);
+	
+		case SIOC_WANPIPE_SET_NONBLOCK:
+
+			if (sk->state != WANSOCK_DISCONNECTED)
+				return -EINVAL;
+
+			sock->file->f_flags |= O_NONBLOCK;
+			return 0;
+	
+		case SIOCGIFFLAGS:
+#ifndef CONFIG_INET
+		case SIOCSIFFLAGS:
+#endif
+		case SIOCGIFCONF:
+		case SIOCGIFMETRIC:
+		case SIOCSIFMETRIC:
+		case SIOCGIFMEM:
+		case SIOCSIFMEM:
+		case SIOCGIFMTU:
+		case SIOCSIFMTU:
+		case SIOCSIFLINK:
+		case SIOCGIFHWADDR:
+		case SIOCSIFHWADDR:
+		case SIOCSIFMAP:
+		case SIOCGIFMAP:
+		case SIOCSIFSLAVE:
+		case SIOCGIFSLAVE:
+		case SIOCGIFINDEX:
+		case SIOCGIFNAME:
+		case SIOCGIFCOUNT:
+		case SIOCSIFHWBROADCAST:
+			return(dev_ioctl(cmd,(void *) arg));
+
+#ifdef CONFIG_INET
+		case SIOCADDRT:
+		case SIOCDELRT:
+		case SIOCDARP:
+		case SIOCGARP:
+		case SIOCSARP:
+		case SIOCDRARP:
+		case SIOCGRARP:
+		case SIOCSRARP:
+		case SIOCGIFADDR:
+		case SIOCSIFADDR:
+		case SIOCGIFBRDADDR:
+		case SIOCSIFBRDADDR:
+		case SIOCGIFNETMASK:
+		case SIOCSIFNETMASK:
+		case SIOCGIFDSTADDR:
+		case SIOCSIFDSTADDR:
+		case SIOCSIFFLAGS:
+		case SIOCADDDLCI:
+		case SIOCDELDLCI:
+			return inet_dgram_ops.ioctl(sock, cmd, arg);
+#endif
+
+		default:
+			if ((cmd >= SIOCDEVPRIVATE) &&
+			    (cmd <= (SIOCDEVPRIVATE + 15)))
+				return(dev_ioctl(cmd,(void *) arg));
+
+#ifdef CONFIG_NET_RADIO
+			if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST))
+				return(dev_ioctl(cmd,(void *) arg));
+#endif
+			return -EOPNOTSUPP;
+	}
+	/*NOTREACHED*/
+}
+
+/*============================================================
+ *  wanpipe_debug
+ *	
+ *	This function will pass up information about all
+ *      active sockets.
+ *
+ * FIXME: More thought should go into this function.
+ *
+ *===========================================================*/
+
+static int wanpipe_debug (struct sock *origsk, void *arg)
+{
+	struct sock *sk=NULL;
+	netdevice_t *dev=NULL;
+	wanpipe_common_t *chan=NULL;
+	int cnt=0, err=0;
+	wan_debug_t *dbg_data = (wan_debug_t *)arg;
+
+	for (sk = wanpipe_sklist; sk; sk = sk->next){
+
+		if (sk == origsk){
+			continue;
+		}
+
+		if ((err=put_user(1, &dbg_data->debug[cnt].free)))
+			return err;
+		if ((err=put_user(sk->state, &dbg_data->debug[cnt].sk_state)))
+			return err;
+		if ((err=put_user(sk->rcvbuf, &dbg_data->debug[cnt].rcvbuf)))
+			return err;
+		if ((err=put_user(atomic_read(&sk->rmem_alloc), &dbg_data->debug[cnt].rmem)))
+			return err;
+		if ((err=put_user(atomic_read(&sk->wmem_alloc), &dbg_data->debug[cnt].wmem)))
+			return err;
+		if ((err=put_user(sk->sndbuf, &dbg_data->debug[cnt].sndbuf)))
+			return err;
+		if ((err=put_user(sk_count, &dbg_data->debug[cnt].sk_count)))
+			return err;
+		if ((err=put_user(sk->protinfo.af_wanpipe->poll_cnt, 
+						&dbg_data->debug[cnt].poll_cnt)))
+			return err;
+		if ((err=put_user(sk->bound_dev_if, &dbg_data->debug[cnt].bound)))
+			return err;
+
+		if (sk->bound_dev_if){
+			dev = dev_get_by_index(sk->bound_dev_if);
+			if (!dev)	
+				continue;
+
+			chan=dev->priv;
+			dev_put(dev);
+	
+			if ((err=put_user(chan->state, &dbg_data->debug[cnt].d_state)))
+				return err;
+			if ((err=put_user(chan->svc, &dbg_data->debug[cnt].svc)))
+				return err;
+
+			if ((err=put_user(atomic_read(&chan->command), 
+						&dbg_data->debug[cnt].command)))
+				return err;
+
+
+			if (sk->protinfo.af_wanpipe){
+				sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card;			
+	
+				if (card){
+					if ((err=put_user(atomic_read(&card->u.x.command_busy), 
+								&dbg_data->debug[cnt].cmd_busy)))
+						return err;
+				}
+
+				if ((err=put_user(sk->protinfo.af_wanpipe->lcn, 
+								&dbg_data->debug[cnt].lcn)))
+					return err;
+				
+				if (sk->protinfo.af_wanpipe->mbox){
+					if ((err=put_user(1, &dbg_data->debug[cnt].mbox)))
+						return err;
+				}
+			}
+
+			if ((err=put_user(atomic_read(&chan->receive_block), 
+								&dbg_data->debug[cnt].rblock)))
+				return err;
+
+			if (copy_to_user(dbg_data->debug[cnt].name, dev->name, strlen(dev->name)))
+				return -EFAULT;
+		}
+	
+		if (++cnt == MAX_NUM_DEBUG)
+			break;
+	}
+	return 0;
+}
+
+/*============================================================
+ *  get_ioctl_cmd
+ *	
+ *	Pass up the contents of socket MBOX to the user.
+ *===========================================================*/
+
+static int get_ioctl_cmd (struct sock *sk, void *arg)
+{
+	x25api_t *usr_data = (x25api_t *)arg;
+	mbox_cmd_t *mbox_ptr;
+	int err;
+
+	if (usr_data == NULL)
+		return -EINVAL;
+
+	if (!sk->protinfo.af_wanpipe->mbox){
+		return -EINVAL;
+	}
+
+	mbox_ptr = (mbox_cmd_t *)sk->protinfo.af_wanpipe->mbox;
+
+	if ((err=put_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm)))
+		return err;
+	if ((err=put_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause)))
+		return err;
+	if ((err=put_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn)))
+		return err;
+	if ((err=put_user(mbox_ptr->cmd.length, &usr_data->hdr.length)))
+		return err;
+	if ((err=put_user(mbox_ptr->cmd.result, &usr_data->hdr.result)))
+		return err;
+	if ((err=put_user(mbox_ptr->cmd.lcn, &usr_data->hdr.lcn)))
+		return err;	
+
+	if (mbox_ptr->cmd.length > 0){
+		if (mbox_ptr->cmd.length > X25_MAX_DATA)
+			return -EINVAL;
+
+		if (copy_to_user(usr_data->data, mbox_ptr->data, mbox_ptr->cmd.length)){
+			printk(KERN_INFO "wansock: Copy failed !!!\n");
+			return -EFAULT;
+		}
+	}
+	return 0;
+} 
+
+/*============================================================
+ *  set_ioctl_cmd
+ *	
+ *	Before command can be execute, socket MBOX must
+ *      be created, and initialized with user data.	
+ *===========================================================*/
+
+static int set_ioctl_cmd (struct sock *sk, void *arg)
+{
+	x25api_t *usr_data = (x25api_t *)arg;
+	mbox_cmd_t *mbox_ptr;
+	int err;
+
+	if (!sk->protinfo.af_wanpipe->mbox){
+		void *mbox_ptr;
+		netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+		if (!dev)
+			return -ENODEV;
+
+		dev_put(dev);
+		
+		if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL)
+			return -ENOMEM;
+
+		memset(mbox_ptr, 0, sizeof(mbox_cmd_t));
+		sk->protinfo.af_wanpipe->mbox = mbox_ptr;
+
+		wanpipe_link_driver(dev,sk);
+	}
+
+	mbox_ptr = (mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox;
+	memset(mbox_ptr, 0, sizeof(mbox_cmd_t));
+
+	if (usr_data == NULL){
+		return 0;
+	}
+	if ((err=get_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm)))
+		return err;
+	if ((err=get_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause)))
+		return err;
+	if ((err=get_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn)))
+		return err;
+	if ((err=get_user(mbox_ptr->cmd.length, &usr_data->hdr.length)))
+		return err;
+	if ((err=get_user(mbox_ptr->cmd.result, &usr_data->hdr.result)))
+		return err;
+
+	if (mbox_ptr->cmd.length > 0){
+		if (mbox_ptr->cmd.length > X25_MAX_DATA)
+			return -EINVAL;
+
+		if (copy_from_user(mbox_ptr->data, usr_data->data, mbox_ptr->cmd.length)){
+			printk(KERN_INFO "Copy failed\n");
+			return -EFAULT;
+		}
+	}
+	return 0;
+}
+
+
+/*======================================================================
+ * wanpipe_poll
+ *
+ *	Datagram poll: Again totally generic. This also handles
+ *	sequenced packet sockets providing the socket receive queue
+ *	is only ever holding data ready to receive.
+ *
+ *	Note: when you _don't_ use this routine for this protocol,
+ *	and you use a different write policy from sock_writeable()
+ *	then please supply your own write_space callback.
+ *=====================================================================*/
+
+unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	unsigned int mask;
+
+	++sk->protinfo.af_wanpipe->poll_cnt;
+
+	poll_wait(file, sk->sleep, wait);
+	mask = 0;
+
+	/* exceptional events? */
+	if (sk->err || !skb_queue_empty(&sk->error_queue)){
+		mask |= POLLPRI;
+		return mask;
+	}
+	if (sk->shutdown & RCV_SHUTDOWN)
+		mask |= POLLHUP;
+
+	/* readable? */
+	if (!skb_queue_empty(&sk->receive_queue)){
+		mask |= POLLIN | POLLRDNORM;
+	}
+
+	/* connection hasn't started yet */
+	if (sk->state == WANSOCK_CONNECTING){
+		return mask;
+	}
+
+	if (sk->state == WANSOCK_DISCONNECTED){
+		mask = POLLPRI;
+		return mask;
+	}
+
+	/* This check blocks the user process if there is   
+	 * a packet already queued in the socket write queue.
+         * This option is only for X25API protocol, for other
+         * protocol like chdlc enable streaming mode, 
+         * where multiple packets can be pending in the socket 
+         * transmit queue */
+
+	if (sk->num == htons(X25_PROT)){
+		if (atomic_read(&sk->protinfo.af_wanpipe->packet_sent))
+			return mask;
+	}
+
+	/* writable? */
+	if (sock_writeable(sk)){
+		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+	}else{
+	      #ifdef LINUX_2_4
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+	      #else
+ 		sk->socket->flags |= SO_NOSPACE;
+	      #endif
+	}
+		
+	return mask;
+}
+
+/*======================================================================
+ * wanpipe_listen
+ *
+ *	X25API Specific function. Set a socket into LISTENING  MODE.
+ *=====================================================================*/
+
+
+static int wanpipe_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+
+ 	/* This is x25 specific area if protocol doesn't
+         * match, return error */
+	if (sk->num != htons(X25_PROT))
+		return -EINVAL;
+
+	if (sk->state == WANSOCK_BIND_LISTEN) {
+
+		sk->max_ack_backlog = backlog;
+		sk->state           = WANSOCK_LISTEN;
+		return 0;
+	}else{
+		printk(KERN_INFO "wansock: Listening sock was not binded\n");
+	}
+
+	return -EINVAL;
+}
+
+/*======================================================================
+ * wanpipe_link_card
+ *
+ *	Connects the listening socket to the driver
+ *=====================================================================*/
+
+static int wanpipe_link_card (struct sock *sk)
+{
+	sdla_t *card;
+
+	card = (sdla_t*)sk->protinfo.af_wanpipe->card;
+	if (!card)
+		return -ENOMEM;
+
+	if ((card->sk != NULL) || (card->func != NULL)){
+		printk(KERN_INFO "wansock: Listening queue is already established\n");
+		return -EINVAL;
+	}
+
+	card->sk=sk;
+	card->func=wanpipe_listen_rcv;
+	sk->zapped=1;
+ 
+	return 0;
+}
+
+/*======================================================================
+ * wanpipe_listen
+ *
+ *	X25API Specific function. Disconnect listening socket from
+ *      the driver.
+ *=====================================================================*/
+
+static void wanpipe_unlink_card (struct sock *sk)
+{
+	sdla_t *card; 
+
+	card = (sdla_t*)sk->protinfo.af_wanpipe->card; 
+
+	if (card){
+		card->sk=NULL;
+		card->func=NULL;
+	}
+}
+
+/*======================================================================
+ * wanpipe_exec_cmd
+ *
+ *	Ioctl function calls this function to execute user command.
+ *      Connect() sytem call also calls this function to execute
+ *      place call.  This function blocks until command is executed.
+ *=====================================================================*/
+
+static int wanpipe_exec_cmd(struct sock *sk, int cmd, unsigned int flags)
+{
+	int err = -EINVAL;
+	mbox_cmd_t *mbox_ptr = (mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox;
+
+	if (!mbox_ptr){
+		printk(KERN_INFO "NO MBOX PTR !!!!!\n");
+		return -EINVAL;
+	}
+	
+	/* This is x25 specific area if protocol doesn't
+         * match, return error */
+	if (sk->num != htons(X25_PROT))
+		return -EINVAL;
+
+
+	switch (cmd){
+
+		case SIOC_WANPIPE_ACCEPT_CALL:
+
+			if (sk->state != WANSOCK_CONNECTING){
+				err = -EHOSTDOWN;
+				break;
+			}
+			
+			err = execute_command(sk,X25_ACCEPT_CALL,0);
+			if (err < 0)
+				break;
+
+			/* Update. Mar6 2000. 
+                         * Do not set the sock lcn number here, since
+                         * it is done in wanpipe_listen_rcv(). 
+                         */ 
+		 	if (sk->state == WANSOCK_CONNECTED){
+				sk->protinfo.af_wanpipe->lcn =
+				((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn;	
+				DBG_PRINTK(KERN_INFO "\nwansock: Accept OK %i\n",
+					sk->protinfo.af_wanpipe->lcn );
+				err = 0;
+
+			}else{
+				DBG_PRINTK (KERN_INFO "\nwansock: Accept Failed %i\n",
+					sk->protinfo.af_wanpipe->lcn);
+				sk->protinfo.af_wanpipe->lcn = 0;
+				err = -ECONNREFUSED;
+			}
+			break;
+
+		case SIOC_WANPIPE_CLEAR_CALL:
+
+			if (sk->state == WANSOCK_DISCONNECTED){
+				err = -EINVAL;
+				break;
+			}
+
+
+			/* Check if data buffers are pending for transmission,
+                         * if so, check wheter user wants to wait untill data
+                         * is transmitted, or clear a call and drop packets */
+                          
+			if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){
+			  	mbox_cmd_t *mbox = sk->protinfo.af_wanpipe->mbox;
+				if (mbox->cmd.qdm & 0x80){
+					mbox->cmd.result = 0x35;
+					err = -EAGAIN;	
+					break;
+				}
+			}
+
+			sk->state = WANSOCK_DISCONNECTING;
+
+			err = execute_command(sk,X25_CLEAR_CALL,0);
+			if (err < 0)
+				break;
+
+			err = -ECONNREFUSED;
+			if (sk->state == WANSOCK_DISCONNECTED){
+				DBG_PRINTK(KERN_INFO "\nwansock: CLEAR OK %i\n",
+					sk->protinfo.af_wanpipe->lcn);
+				sk->protinfo.af_wanpipe->lcn=0;
+				err = 0;
+			}
+			break;
+
+		case SIOC_WANPIPE_RESET_CALL:
+
+			if (sk->state != WANSOCK_CONNECTED){
+				err = -EINVAL;
+				break;
+			}
+
+
+			/* Check if data buffers are pending for transmission,
+                         * if so, check wheter user wants to wait untill data
+                         * is transmitted, or reset a call and drop packets */
+                          
+			if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){
+			  	mbox_cmd_t *mbox = sk->protinfo.af_wanpipe->mbox;
+				if (mbox->cmd.qdm & 0x80){
+					mbox->cmd.result = 0x35;
+					err = -EAGAIN;	
+					break;
+				}
+			}
+
+
+			err = execute_command(sk, X25_RESET,0);
+			if (err < 0)
+				break;
+
+			err = mbox_ptr->cmd.result;
+			break;
+
+
+		case X25_PLACE_CALL:
+
+			err=execute_command(sk,X25_PLACE_CALL,flags);
+			if (err < 0)
+				break;
+
+			if (sk->state == WANSOCK_CONNECTED){
+
+				sk->protinfo.af_wanpipe->lcn =
+				((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn;	
+
+				DBG_PRINTK(KERN_INFO "\nwansock: PLACE CALL OK %i\n",
+					sk->protinfo.af_wanpipe->lcn);
+				err = 0;
+
+			}else if (sk->state == WANSOCK_CONNECTING && (flags & O_NONBLOCK)){
+				sk->protinfo.af_wanpipe->lcn = 
+				((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn;
+				DBG_PRINTK(KERN_INFO "\nwansock: Place Call OK: Waiting %i\n",
+					sk->protinfo.af_wanpipe->lcn);
+
+				err = 0;
+
+			}else{
+				DBG_PRINTK(KERN_INFO "\nwansock: Place call Failed\n");
+				err = -ECONNREFUSED;
+			}
+
+			break;
+
+		default: 
+			return -EINVAL;
+	}
+
+	return err;
+}
+
+static int check_driver_busy (struct sock *sk)
+{
+	netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+	wanpipe_common_t *chan;
+
+	if (!dev)
+		return 0;
+
+	dev_put(dev);
+
+	if ((chan=dev->priv) == NULL)
+		return 0;
+
+	return atomic_read(&chan->driver_busy);
+}
+
+
+/*======================================================================
+ * wanpipe_accept
+ *
+ *	ACCEPT() System call.	X25API Specific function. 
+ *	For each incoming call, create a new socket and 
+ *      return it to the user.	
+ *=====================================================================*/
+
+static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	struct sock *sk;
+	struct sock *newsk;
+	struct sk_buff *skb;
+	DECLARE_WAITQUEUE(wait, current);
+	int err=0;
+
+	if (newsock->sk != NULL){
+		wanpipe_kill_sock_accept(newsock->sk);	
+		newsock->sk=NULL;
+	}
+	
+	if ((sk = sock->sk) == NULL)
+		return -EINVAL;
+
+	if (sk->type != SOCK_RAW)
+		return -EOPNOTSUPP;
+
+	if (sk->state != WANSOCK_LISTEN)
+		return -EINVAL;
+
+	if (sk->num != htons(X25_PROT))
+		return -EINVAL;
+
+	add_wait_queue(sk->sleep,&wait);
+	current->state = TASK_INTERRUPTIBLE;
+	for (;;){
+		skb = skb_dequeue(&sk->receive_queue);
+		if (skb){
+			err=0;
+			break;
+		}
+		if (signal_pending(current)) {
+			err = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep,&wait);
+	
+	if (err != 0)
+		return err;
+	
+	newsk = get_newsk_from_skb(skb);
+	if (!newsk){
+		return -EINVAL;
+	}
+
+	set_bit(1,&wanpipe_tx_critical);
+	write_lock(&wanpipe_sklist_lock);
+	newsk->next = wanpipe_sklist;
+	wanpipe_sklist = newsk;
+	sock_hold(sk);
+	write_unlock(&wanpipe_sklist_lock);
+	clear_bit(1,&wanpipe_tx_critical);
+
+	newsk->pair = NULL;
+	newsk->socket = newsock;
+	newsk->sleep = &newsock->wait;
+
+	/* Now attach up the new socket */
+	sk->ack_backlog--;
+	newsock->sk = newsk;
+	
+	kfree_skb(skb);
+
+	DBG_PRINTK(KERN_INFO "\nwansock: ACCEPT Got LCN %i\n",newsk->protinfo.af_wanpipe->lcn);
+	return 0;
+}
+
+/*======================================================================
+ *  get_newsk_from_skb
+ *
+ *	Accept() uses this function to get the address of the new
+ *      socket structure.
+ *=====================================================================*/
+
+struct sock * get_newsk_from_skb (struct sk_buff *skb)
+{
+	netdevice_t *dev = skb->dev;
+	wanpipe_common_t *chan;	
+
+	if (!dev){
+		return NULL;
+	}
+		
+	if ((chan = dev->priv) == NULL){
+		return NULL;
+	}
+		
+	if (!chan->sk){
+		return NULL;
+	}
+	return (struct sock *)chan->sk;
+}
+
+/*======================================================================
+ *  wanpipe_connect
+ *
+ *  	CONNECT() System Call. X25API specific function
+ * 	Check the state of the sock, and execute PLACE_CALL command.
+ *      Connect can ether block or return without waiting for connection, 
+ *      if specified by user.
+ *=====================================================================*/
+
+static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr;
+	netdevice_t *dev;
+	int err;
+
+	if (sk->num != htons(X25_PROT))
+		return -EINVAL;
+
+	if (sk->state == WANSOCK_CONNECTED)
+		return EISCONN;	/* No reconnect on a seqpacket socket */
+
+	if (sk->state != WAN_DISCONNECTED){
+		printk(KERN_INFO "wansock: Trying to connect on channel NON DISCONNECT\n");
+		return -ECONNREFUSED;
+	}
+
+	sk->state   = WANSOCK_DISCONNECTED;	
+	sock->state = SS_UNCONNECTED;
+
+	if (addr_len != sizeof(struct wan_sockaddr_ll))
+		return -EINVAL;
+
+	if (addr->sll_family != AF_WANPIPE)
+		return -EINVAL;
+
+	if ((dev = dev_get_by_index(sk->bound_dev_if)) == NULL)
+		return -ENETUNREACH;
+
+	dev_put(dev);
+	
+	if (!sk->zapped)		/* Must bind first - autobinding does not work */
+		return -EINVAL;
+
+	sock->state   = SS_CONNECTING;
+	sk->state     = WANSOCK_CONNECTING;
+
+	if (!sk->protinfo.af_wanpipe->mbox){
+		if (sk->protinfo.af_wanpipe->svc){
+			return -EINVAL;
+		}else{
+			int err;
+			if ((err=set_ioctl_cmd(sk,NULL)) < 0)
+				return err;
+		}
+	}
+
+	if ((err=wanpipe_exec_cmd(sk, X25_PLACE_CALL,flags)) != 0){
+		sock->state = SS_UNCONNECTED;
+		sk->state = WANSOCK_CONNECTED;
+		return err;
+	}
+
+	if (sk->state != WANSOCK_CONNECTED && (flags & O_NONBLOCK)){
+		return 0;
+	}
+
+	if (sk->state != WANSOCK_CONNECTED) {
+		sock->state = SS_UNCONNECTED;
+		return -ECONNREFUSED; 
+	}
+
+	sock->state = SS_CONNECTED;
+	return 0;
+}
+
+#ifdef LINUX_2_4
+struct proto_ops wanpipe_ops = {
+	family: 	PF_WANPIPE,
+
+	release: 	wanpipe_release,
+	bind: 		wanpipe_bind,
+	connect: 	wanpipe_connect,
+	socketpair: 	sock_no_socketpair,
+	accept: 	wanpipe_accept,
+	getname: 	wanpipe_getname, 
+	poll: 		wanpipe_poll,
+	ioctl: 		wanpipe_ioctl,
+	listen: 	wanpipe_listen, 
+	shutdown: 	sock_no_shutdown,
+	setsockopt: 	sock_no_setsockopt,
+	getsockopt: 	sock_no_getsockopt,
+	sendmsg: 	wanpipe_sendmsg,
+	recvmsg: 	wanpipe_recvmsg
+};
+#else
+struct proto_ops wanpipe_ops = {
+	PF_WANPIPE,
+
+	sock_no_dup,
+	wanpipe_release,
+	wanpipe_bind,
+	wanpipe_connect,
+	sock_no_socketpair,
+	wanpipe_accept,
+	wanpipe_getname, 
+	wanpipe_poll,
+	wanpipe_ioctl,
+	wanpipe_listen, 
+	sock_no_shutdown,
+	sock_no_setsockopt,
+	sock_no_getsockopt,
+	sock_no_fcntl,
+	wanpipe_sendmsg,
+	wanpipe_recvmsg
+};
+#endif
+
+
+static struct net_proto_family wanpipe_family_ops = {
+	PF_WANPIPE,
+	wanpipe_create
+};
+
+struct notifier_block wanpipe_netdev_notifier={
+	wanpipe_notifier,
+	NULL,
+	0
+};
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	printk(KERN_INFO "wansock: Cleaning up \n");
+	unregister_netdevice_notifier(&wanpipe_netdev_notifier);
+	sock_unregister(PF_WANPIPE);
+	return;
+}
+
+
+int init_module(void)
+{
+
+	printk(KERN_INFO "wansock: Registering Socket \n");
+	sock_register(&wanpipe_family_ops);
+	register_netdevice_notifier(&wanpipe_netdev_notifier);
+	return 0;
+}
+#endif
diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/patchlevel linux/net/wanrouter/patchlevel
--- v2.4.3/linux/net/wanrouter/patchlevel	Thu Jan  7 09:25:02 1999
+++ linux/net/wanrouter/patchlevel	Thu Apr 12 12:11:39 2001
@@ -1 +1 @@
-2.0.3
+2.2.1
diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.4.3/linux/net/wanrouter/wanmain.c	Sun Mar 25 18:14:25 2001
+++ linux/net/wanrouter/wanmain.c	Thu Apr 12 12:11:39 2001
@@ -18,6 +18,14 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Nov 24, 2000  Nenad Corbic	Updated for 2.4.X kernels 
+* Nov 07, 2000  Nenad Corbic	Fixed the Mulit-Port PPP for kernels 2.2.16 and
+*  				greater.
+* Aug 2,  2000  Nenad Corbic	Block the Multi-Port PPP from running on
+*  			        kernels 2.2.16 or greater.  The SyncPPP 
+*  			        has changed.
+* Jul 13, 2000  Nenad Corbic	Added SyncPPP support
+* 				Added extra debugging in device_setup().
 * Oct 01, 1999  Gideon Hack     Update for s514 PCI card
 * Dec 27, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 * Jan 16, 1997	Gene Kozin	router_devlist made public
@@ -31,7 +39,6 @@
 * Dec 22, 1998  Arnaldo Melo    vmalloc/vfree used in device_setup to allocate
 *                               kernel memory and copy configuration data to
 *                               kernel space (for big firmwares)
-* May 19, 1999  Arnaldo Melo    __init in wanrouter_init
 * Jun 02, 1999  Gideon Hack	Updates for Linux 2.0.X and 2.2.X kernels.	
 *****************************************************************************/
 
@@ -41,17 +48,95 @@
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
 #include <linux/module.h>	/* support for loadable modules */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
-#include <linux/vmalloc.h>	/* vmalloc, vfree */
-#include <asm/segment.h>	/* kernel <-> user copy */
+
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copy_to/from_user */
 #include <linux/wanrouter.h>	/* WAN router API definitions */
-#include <linux/init.h>		/* __init et al. */
 
 
+#if defined(LINUX_2_4)
+ #include <linux/vmalloc.h>	/* vmalloc, vfree */
+ #include <asm/uaccess.h>        /* copy_to/from_user */
+ #include <linux/init.h>         /* __initfunc et al. */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
+ #include <net/syncppp.h>
+#else
+ #include <../drivers/net/wan/syncppp.h>
+#endif
+
+#elif defined(LINUX_2_1) 
+ #define LINUX_2_1
+ #include <linux/vmalloc.h>	/* vmalloc, vfree */
+ #include <asm/uaccess.h>        /* copy_to/from_user */
+ #include <linux/init.h>         /* __initfunc et al. */
+ #include <../drivers/net/syncppp.h>
+
+#else
+ #include <asm/segment.h>	/* kernel <-> user copy */
+#endif
+
+#define KMEM_SAFETYZONE 8
+
+/***********FOR DEBUGGING PURPOSES*********************************************
+static void * dbg_kmalloc(unsigned int size, int prio, int line) {
+	int i = 0;
+	void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio);
+	char * c1 = v;	
+	c1 += sizeof(unsigned int);
+	*((unsigned int *)v) = size;
+
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D';
+		c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F';
+		c1 += 8;
+	}
+	c1 += size;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G';
+		c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L';
+		c1 += 8;
+	}
+	v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8;
+	printk(KERN_INFO "line %d  kmalloc(%d,%d) = %p\n",line,size,prio,v);
+	return v;
+}
+static void dbg_kfree(void * v, int line) {
+	unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8));
+	unsigned int size = *sp;
+	char * c1 = ((char *)v) - KMEM_SAFETYZONE*8;
+	int i = 0;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		if (   c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D'
+		    || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') {
+			printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v);
+			printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
+			                c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
+		}
+		c1 += 8;
+	}
+	c1 += size;
+	for (i = 0; i < KMEM_SAFETYZONE; i++) {
+		if (   c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G'
+		    || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L'
+		   ) {
+			printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v);
+			printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
+			                c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
+		}
+		c1 += 8;
+	}
+	printk(KERN_INFO "line %d  kfree(%p)\n",line,v);
+	v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8);
+	kfree(v);
+}
+
+#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
+#define kfree(x) dbg_kfree(x,__LINE__)
+*****************************************************************************/
+
 
 /*
  * 	Defines and Macros 
@@ -91,14 +176,18 @@
  */
 
 static wan_device_t *find_device (char *name);
-static int delete_interface (wan_device_t *wandev, char *name, int force);
+static int delete_interface (wan_device_t *wandev, char *name);
+void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+
+
 
 /*
  *	Global Data
  */
 
-static char fullname[]		= "WAN Router";
-static char copyright[]		= "(c) 1995-1999 Sangoma Technologies Inc.";
+static char fullname[]		= "Sangoma WANPIPE Router";
+static char copyright[]		= "(c) 1995-2000 Sangoma Technologies Inc.";
 static char modname[]		= ROUTER_NAME;	/* short module name */
 wan_device_t* router_devlist 	= NULL;	/* list of registered devices */
 static int devcnt 		= 0;
@@ -113,31 +202,41 @@
 #endif
 
 #ifndef MODULE
-int __init wanrouter_init(void)
+
+int wanrouter_init(void)
 {
 	int err;
-	extern int wanpipe_init(void),
-		   cyclomx_init(void);
+	extern int wanpipe_init(void);
+	extern int sdladrv_init(void);
 
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
+
 	err = wanrouter_proc_init();
-	if (err)
-		printk(KERN_ERR "%s: can't create entry in proc filesystem!\n",	modname);
+	if (err){
+		printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname);
+	}
+
+        /*
+         *      Initialise compiled in boards
+         */
 
-	/*
-	 *	Initialise compiled in boards
-	 */		
-	 
 #ifdef CONFIG_VENDOR_SANGOMA
+	sdladrv_init();
 	wanpipe_init();
 #endif	
-#ifdef CONFIG_CYCLADES_SYNC
-	cyclomx_init();
-#endif
+ 
 	return err;
 }
 
+
+#ifdef LINUX_2_4
+static void __exit wanrouter_cleanup (void)
+{
+	wanrouter_proc_cleanup();
+}
+#endif
+
 #else
 
 /*
@@ -161,9 +260,13 @@
 
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
+	
 	err = wanrouter_proc_init();
-	if (err) printk(KERN_ERR
+	
+	if (err){ 
+		printk(KERN_INFO
 		"%s: can't create entry in proc filesystem!\n", modname);
+	}
 	return err;
 }
 
@@ -207,7 +310,7 @@
 	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) ||
 	    (wandev->name == NULL))
 		return -EINVAL;
-
+ 		
 	namelen = strlen(wandev->name);
 	if (!namelen || (namelen > WAN_DRVNAME_SZ))
 		return -EINVAL;
@@ -219,12 +322,13 @@
 	printk(KERN_INFO "%s: registering WAN device %s\n",
 		modname, wandev->name);
 #endif
+
 	/*
 	 *	Register /proc directory entry 
 	 */
 	err = wanrouter_proc_add(wandev);
 	if (err) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"%s: can't create /proc/net/router/%s entry!\n",
 			modname, wandev->name);
 		return err;
@@ -274,17 +378,17 @@
 #ifdef WANDEBUG		
 	printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name);
 #endif
-	
+
 	if (wandev->state != WAN_UNCONFIGURED) {
-		while(wandev->dev)
-			delete_interface(wandev, wandev->dev->name, 1);
-		if (wandev->shutdown)	
-			wandev->shutdown(wandev);
+		device_shutdown(wandev);
 	}
-	if (prev)
+	
+	if (prev){
 		prev->next = wandev->next;
-	else
+	}else{
 		router_devlist = wandev->next;
+	}
+	
 	--devcnt;
 	wanrouter_proc_delete(wandev);
         MOD_DEC_USE_COUNT;
@@ -302,12 +406,12 @@
  */
 
 
-int wanrouter_encapsulate (struct sk_buff* skb, struct net_device* dev)
+int wanrouter_encapsulate (struct sk_buff *skb, netdevice_t *dev,
+	unsigned short type)
 {
 	int hdr_len = 0;
 
-	switch (skb->protocol)
-	{
+	switch (type) {
 	case ETH_P_IP:		/* IP datagram encapsulation */
 		hdr_len += 1;
 		skb_push(skb, 1);
@@ -321,18 +425,19 @@
 		skb->data[0] = 0;
 		skb->data[1] = NLPID_SNAP;
 		memcpy(&skb->data[2], oui_ether, sizeof(oui_ether));
-		*((unsigned short*)&skb->data[5]) = htons(skb->protocol);
+		*((unsigned short*)&skb->data[5]) = htons(type);
 		break;
 
 	default:		/* Unknown packet type */
 		printk(KERN_INFO
 			"%s: unsupported Ethertype 0x%04X on interface %s!\n",
-			modname, skb->protocol, dev->name);
+			modname, type, dev->name);
 		hdr_len = -EINVAL;
 	}
 	return hdr_len;
 }
 
+
 /*
  *	Decapsulate packet.
  *
@@ -344,21 +449,19 @@
  */
 
 
-unsigned short wanrouter_type_trans (struct sk_buff* skb, struct net_device* dev)
+unsigned short wanrouter_type_trans (struct sk_buff *skb, netdevice_t *dev)
 {
 	int cnt = skb->data[0] ? 0 : 1;	/* there may be a pad present */
 	unsigned short ethertype;
 
-	switch (skb->data[cnt])
-	{
+	switch (skb->data[cnt]) {
 	case NLPID_IP:		/* IP datagramm */
 		ethertype = htons(ETH_P_IP);
 		cnt += 1;
 		break;
 
         case NLPID_SNAP:	/* SNAP encapsulation */
-		if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether)))
-		{
+		if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))){
           		printk(KERN_INFO
 				"%s: unsupported SNAP OUI %02X-%02X-%02X "
 				"on interface %s!\n", modname,
@@ -380,8 +483,8 @@
 	}
 	skb->protocol = ethertype;
 	skb->pkt_type = PACKET_HOST;	/*	Physically point to point */
-	skb->mac.raw  = skb->data;
 	skb_pull(skb, cnt);
+	skb->mac.raw  = skb->data;
 	return ethertype;
 }
 
@@ -399,9 +502,11 @@
 	struct proc_dir_entry *dent;
 	wan_device_t *wandev;
 
+      #if defined (LINUX_2_1) || defined (LINUX_2_4)
 	if (!capable(CAP_NET_ADMIN)){
 		return -EPERM;
 	}
+      #endif
 		
 	if ((cmd >> 8) != ROUTER_IOCTL)
 		return -EINVAL;
@@ -466,44 +571,105 @@
 	wandev_conf_t *conf;
 	int err = -EINVAL;
 
-	if (wandev->setup == NULL)	/* Nothing to do ? */
+	if (wandev->setup == NULL){	/* Nothing to do ? */
+		printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n",
+				wandev->name);
 		return 0;
+	}
+
+      #ifdef LINUX_2_0 
+	err = verify_area (VERIFY_READ, u_conf, sizeof(wandev_conf_t));
+	if(err){
+		return err;
+	}
+      #endif	
 
 	conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL);
-	if (conf == NULL)
+	if (conf == NULL){
+		printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n",
+				wandev->name);
 		return -ENOBUFS;
-
+	}
+		
+      #if defined (LINUX_2_1) || defined (LINUX_2_4)		
 	if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) {
+		printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n",
+				wandev->name);
 		kfree(conf);
 		return -EFAULT;
 	}
+      #else
+	memcpy_fromfs ((void *)conf, (void *)u_conf, sizeof(wandev_conf_t));
+      #endif
 	
-	if (conf->magic != ROUTER_MAGIC) {
+	if (conf->magic != ROUTER_MAGIC){
 		kfree(conf);
+		printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n",
+				wandev->name);
 	        return -EINVAL; 
 	}
 
-	if (conf->data_size && conf->data) {
+	if (conf->data_size && conf->data){
 		if(conf->data_size > 128000 || conf->data_size < 0) {
 			kfree(conf);
+			printk(KERN_INFO 
+			    "%s: ERROR, Invalid firmware data size %i !\n",
+					wandev->name, conf->data_size);
 		        return -EINVAL;;
 		}
 
+#if defined (LINUX_2_1) || defined (LINUX_2_4)
 		data = vmalloc(conf->data_size);
 		if (data) {
 			if(!copy_from_user(data, conf->data, conf->data_size)){
 				conf->data=data;
 				err = wandev->setup(wandev,conf);
-			}
-			else 
+			}else{ 
+				printk(KERN_INFO 
+				     "%s: ERROR, Faild to copy from user data !\n",
+				       wandev->name);
 				err = -EFAULT;
-		}
-		else 
+			}
+		}else{ 
+			printk(KERN_INFO 
+			 	"%s: ERROR, Faild allocate kernel memory !\n",
+				wandev->name);
 			err = -ENOBUFS;
-
-		if (data)
+		}
+			
+		if (data){
 			vfree(data);
+		}
+#else
+                err = verify_area(VERIFY_READ, conf->data, conf->data_size);
+                if (!err) {
+                        data = kmalloc(conf->data_size, GFP_KERNEL);
+                        if (data) {
+                                memcpy_fromfs(data, (void*)conf->data,
+                                        conf->data_size);
+                                conf->data = data;
+                        }else{
+				printk(KERN_INFO 
+				    "%s: ERROR, Faild allocate kernel memory !\n",wandev->name);
+				err = -ENOMEM;
+			}
+                }else{
+			printk(KERN_INFO 
+			 	"%s: ERROR, Faild to copy from user data !\n",wandev->name);
+		}
 
+		if (!err){
+			err = wandev->setup(wandev, conf);
+		}
+		
+        	if (data){
+			kfree(data);
+		}
+#endif
+	}else{
+		printk(KERN_INFO 
+		    "%s: ERROR, No firmware found ! Firmware size = %i !\n",
+				wandev->name, conf->data_size);
 	}
 
 	kfree(conf);
@@ -516,27 +682,37 @@
  *	o call driver's shutdown() entry point
  */
  
-static int device_shutdown (wan_device_t* wandev)
+static int device_shutdown (wan_device_t *wandev)
 {
-	struct net_device* dev;
-
-	if (wandev->state == WAN_UNCONFIGURED)
+	netdevice_t *dev;
+	int err=0;
+		
+	if (wandev->state == WAN_UNCONFIGURED){
 		return 0;
+	}
+
+	printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name);
 		
-	for (dev = wandev->dev; dev;)
-	{
-		if (delete_interface(wandev, dev->name, 0))
-		{
-			struct net_device **slave = dev->priv;
-			dev = *slave;
+	for (dev = wandev->dev; dev;) {
+		if ((err=delete_interface(wandev, dev->name)) != 0){
+			return err;
 		}
+
+		/* The above function deallocates the current dev
+		 * structure. Therefore, we cannot use dev->priv
+		 * as the next element: wandev->dev points to the
+		 * next element */
+		dev = wandev->dev;
 	}
-	if (wandev->ndev)
+	
+	if (wandev->ndev){
 		return -EBUSY;	/* there are opened interfaces  */
-		
+	}	
+	
 	if (wandev->shutdown)
-		return wandev->shutdown(wandev);
-	return 0;
+		err=wandev->shutdown(wandev);
+	
+	return err;
 }
 
 /*
@@ -547,6 +723,13 @@
 {
 	wandev_stat_t stat;
 
+      #ifdef LINUX_2_0
+	int err;
+	err = verify_area(VERIFY_WRITE, u_stat, sizeof(wandev_stat_t));
+        if (err)
+                return err;
+      #endif
+
 	memset(&stat, 0, sizeof(stat));
 
 	/* Ask device driver to update device statistics */
@@ -557,8 +740,12 @@
 	stat.ndev  = wandev->ndev;
 	stat.state = wandev->state;
 
+      #if defined (LINUX_2_1) || defined (LINUX_2_4)
 	if(copy_to_user(u_stat, &stat, sizeof(stat)))
 		return -EFAULT;
+      #else
+        memcpy_tofs((void*)u_stat, (void*)&stat, sizeof(stat));
+      #endif
 
 	return 0;
 }
@@ -573,58 +760,149 @@
  *	o register network interface
  */
 
-static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf)
+static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf)
 {
 	wanif_conf_t conf;
-	struct net_device *dev;
+	netdevice_t *dev=NULL;
+      #ifdef CONFIG_WANPIPE_MULTPPP
+	struct ppp_device *pppdev=NULL;
+      #endif
 	int err;
 
 	if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
 		return -ENODEV;
-		
+	
+      #if defined (LINUX_2_1) || defined (LINUX_2_4)	
 	if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
 		return -EFAULT;
+      #else
+        err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t));
+        if (err)
+                return err;
+        memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t));
+      #endif
 		
 	if (conf.magic != ROUTER_MAGIC)
 		return -EINVAL;
+
+	err = -EPROTONOSUPPORT;
+
+	
+#ifdef CONFIG_WANPIPE_MULTPPP
+	if (conf.config_id == WANCONFIG_MPPP){
+
+		pppdev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+		if (pppdev == NULL){
+			return -ENOBUFS;
+		}
+		memset(pppdev, 0, sizeof(struct ppp_device));
+
+	      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
+		pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
+		if (pppdev->dev == NULL){
+			return -ENOBUFS;
+		}
+		memset(pppdev->dev, 0, sizeof(netdevice_t));
+	      #endif
 		
-	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-	if (dev == NULL)
-		return -ENOBUFS;
+		err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf);
 		
-	memset(dev, 0, sizeof(struct net_device));
-	err = wandev->new_if(wandev, dev, &conf);
+		      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
+			dev = pppdev->dev;
+		      #else
+			dev = &pppdev->dev;
+		      #endif
+			
+	}else{
+
+		dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
+		if (dev == NULL){
+			return -ENOBUFS;
+		}
+		memset(dev, 0, sizeof(netdevice_t));	
+		err = wandev->new_if(wandev, dev, &conf);
+	}
+
+#else
+	/* Sync PPP is disabled */
+	if (conf.config_id != WANCONFIG_MPPP){
+
+		dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
+		if (dev == NULL){
+			return -ENOBUFS;
+		}
+		memset(dev, 0, sizeof(netdevice_t));	
+		err = wandev->new_if(wandev, dev, &conf);
+	}else{
+		printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n",
+				wandev->name);
+		return err;
+	}
+#endif
+	
 	if (!err) {
 		/* Register network interface. This will invoke init()
 		 * function supplied by the driver.  If device registered
 		 * successfully, add it to the interface list.
 		 */
-		if (dev->name == NULL)
+
+		if (dev->name == NULL){
 			err = -EINVAL;
-			
-		else if (dev_get(dev->name))
+		}else if (dev_get(dev->name)){
 			err = -EEXIST;	/* name already exists */
-		else {
-#ifdef WANDEBUG		
+		}else{
+				
+			#ifdef WANDEBUG		
 			printk(KERN_INFO "%s: registering interface %s...\n",
 				modname, dev->name);
-#endif				
+			#endif				
+			
 			err = register_netdev(dev);
 			if (!err) {
-				struct net_device **slave = dev->priv;
+				netdevice_t *slave=NULL;
+				unsigned long smp_flags=0;
+				
+				lock_adapter_irq(&wandev->lock, &smp_flags);
+			
+				if (wandev->dev == NULL){
+					wandev->dev = dev;
+				}else{
+					for (slave=wandev->dev;
+					     *((netdevice_t**)slave->priv);
+					     slave=*((netdevice_t**)slave->priv));
 
-				cli();	/***** critical section start *****/
-				*slave = wandev->dev;
-				wandev->dev = dev;
+					*((netdevice_t**)slave->priv) = dev;
+				}
 				++wandev->ndev;
-				sti();	/****** critical section end ******/
+				
+				unlock_adapter_irq(&wandev->lock, &smp_flags);
 				return 0;	/* done !!! */
 			}
 		}
 		if (wandev->del_if)
 			wandev->del_if(wandev, dev);
 	}
-	kfree(dev);
+
+	/* This code has moved from del_if() function */
+	if (dev->priv){
+		kfree(dev->priv);
+		dev->priv=NULL;
+	}
+
+	
+      #ifdef CONFIG_WANPIPE_MULTPPP
+	if (conf.config_id == WANCONFIG_MPPP){
+		kfree(pppdev);
+	}else{
+		kfree(dev);
+	}
+      #else
+	/* Sync PPP is disabled */
+	if (conf.config_id != WANCONFIG_MPPP){
+		kfree(dev);
+	}
+      #endif
+	
 	return err;
 }
 
@@ -638,15 +916,43 @@
 static int device_del_if (wan_device_t *wandev, char *u_name)
 {
 	char name[WAN_IFNAME_SZ + 1];
+        int err = 0;
 
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
 	
+      #ifdef LINUX_2_0
+        err = verify_area(VERIFY_READ, u_name, WAN_IFNAME_SZ);
+        if (err)
+		return err;
+      #endif	
+
 	memset(name, 0, sizeof(name));
 
+      #if defined (LINUX_2_1) || defined (LINUX_2_4)
 	if(copy_from_user(name, u_name, WAN_IFNAME_SZ))
 		return -EFAULT;
-	return delete_interface(wandev, name, 0);
+      #else
+        memcpy_fromfs((void*)name, (void*)u_name, WAN_IFNAME_SZ);
+      #endif
+
+	err = delete_interface(wandev, name);
+	if (err)
+		return(err);
+
+	/* If last interface being deleted, shutdown card
+	 * This helps with administration at leaf nodes
+	 * (You can tell if the person at the other end of the phone 
+	 * has an interface configured) and avoids DoS vulnerabilities
+	 * in binary driver files - this fixes a problem with the current
+	 * Sangoma driver going into strange states when all the network
+	 * interfaces are deleted and the link irrecoverably disconnected.
+	 */ 
+
+        if (!wandev->ndev && wandev->shutdown){
+                err = wandev->shutdown(wandev);
+	}
+	return err;
 }
 
 
@@ -685,59 +991,102 @@
  *	sure that opened interfaces are not removed!
  */
 
-static int delete_interface (wan_device_t *wandev, char *name, int force)
+static int delete_interface (wan_device_t *wandev, char *name)
 {
-	struct net_device *dev, *prev;
+	netdevice_t *dev=NULL, *prev=NULL;
+	unsigned long smp_flags=0;
 
+	lock_adapter_irq(&wandev->lock, &smp_flags);
 	dev = wandev->dev;
 	prev = NULL;
 	while (dev && strcmp(name, dev->name)) {
-		struct net_device **slave = dev->priv;
-
+		netdevice_t **slave = dev->priv;
 		prev = dev;
 		dev = *slave;
 	}
-
-	if (dev == NULL)
+	unlock_adapter_irq(&wandev->lock, &smp_flags);
+	
+	if (dev == NULL){
 		return -ENODEV;	/* interface not found */
-
-	if (netif_running(dev)) {
-		if (force) {
-			printk(KERN_WARNING
-				"%s: deleting opened interface %s!\n",
-				modname, name);
-		}
-		else
-			return -EBUSY;	/* interface in use */
+	}
+		
+       #ifdef LINUX_2_4
+	if (netif_running(dev)){
+       #else
+	if (dev->start) {
+       #endif
+		return -EBUSY;	/* interface in use */
 	}
 
 	if (wandev->del_if)
 		wandev->del_if(wandev, dev);
 
-	cli();			/***** critical section start *****/
+	lock_adapter_irq(&wandev->lock, &smp_flags);
 	if (prev) {
-		struct net_device **prev_slave = prev->priv;
-		struct net_device **slave = dev->priv;
+		netdevice_t **prev_slave = prev->priv;
+		netdevice_t **slave = dev->priv;
 
 		*prev_slave = *slave;
 	} else {
-		struct net_device **slave = dev->priv;
-
+		netdevice_t **slave = dev->priv;
 		wandev->dev = *slave;
 	}
 	--wandev->ndev;
-	sti();			/****** critical section end ******/
+	unlock_adapter_irq(&wandev->lock, &smp_flags);
+	
+	printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); 
+	
+	/* Due to new interface linking method using dev->priv,
+	 * this code has moved from del_if() function.*/
+	if (dev->priv){
+		kfree(dev->priv);
+		dev->priv=NULL;
+	}
 
-	printk("Unregistering '%s'\n", dev->name); 
 	unregister_netdev(dev);
+
+      #ifdef LINUX_2_4
+	kfree(dev);
+      #else
+	if (dev->name){
+		kfree(dev->name);
+	}
 	kfree(dev);
+      #endif
+
 	return 0;
 }
 
+void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+{
+      #ifdef LINUX_2_0
+	save_flags(*smp_flags);
+	cli();
+      #else
+       	spin_lock_irqsave(lock, *smp_flags);
+      #endif
+}
+
+
+void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+{
+      #ifdef LINUX_2_0
+	restore_flags(*smp_flags);
+      #else
+	spin_unlock_irqrestore(lock, *smp_flags);
+      #endif
+}
+
+
+
+#if defined (LINUX_2_1) || defined (LINUX_2_4)
 EXPORT_SYMBOL(register_wan_device);
 EXPORT_SYMBOL(unregister_wan_device);
 EXPORT_SYMBOL(wanrouter_encapsulate);
 EXPORT_SYMBOL(wanrouter_type_trans);
+EXPORT_SYMBOL(lock_adapter_irq);
+EXPORT_SYMBOL(unlock_adapter_irq);
+#endif
 
 /*
  *	End
diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.4.3/linux/net/wanrouter/wanproc.c	Fri Feb  9 11:34:13 2001
+++ linux/net/wanrouter/wanproc.c	Thu Apr 12 12:11:39 2001
@@ -13,7 +13,6 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* Jan 20, 2001  Arnaldo C.Melo  Fix leak on error in router_proc_read, cleanups
 * Jun 02, 1999  Gideon Hack	Updates for Linux 2.2.X kernels.
 * Jun 29, 1997	Alan Cox	Merged with 1.0.3 vendor code
 * Jan 29, 1997	Gene Kozin	v1.0.1. Implemented /proc read routines
@@ -26,397 +25,1017 @@
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
-#include <linux/init.h>		/* __init et al. */
-#include <asm/segment.h>	/* kernel <-> user copy */
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copy_to_user */
 #include <asm/io.h>
 #include <linux/wanrouter.h>	/* WAN router API definitions */
 
 
-/****** Defines and Macros **************************************************/
 
-#define PROC_STATS_FORMAT "%30s: %12lu\n"
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+ #include <linux/init.h>	/* __initfunc et al. */
+ #include <asm/uaccess.h>       /* copy_to_user */
+ #define PROC_STATS_FORMAT "%30s: %12lu\n"
+#else
+ #define PROC_STATS_FORMAT "%30s: %12u\n"
+ #include <asm/segment.h>	/* kernel <-> user copy */
+#endif
+
+
+/****** Defines and Macros **************************************************/
 
 #ifndef	min
 #define min(a,b) (((a)<(b))?(a):(b))
 #endif
+#ifndef	max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
 
 #define	PROC_BUFSZ	4000	/* buffer size for printing proc info */
 
+#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\
+			      (prot == WANCONFIG_X25) ? " X25" : \
+			         (prot == WANCONFIG_PPP) ? " PPP" : \
+				    (prot == WANCONFIG_CHDLC) ? " CHDLC": \
+				       (prot == WANCONFIG_MPPP) ? " MPPP" : \
+				           " Unknown" )
+	
+/****** Data Types **********************************************************/
+
+typedef struct wan_stat_entry
+{
+	struct wan_stat_entry *next;
+	char *description;		/* description string */
+	void *data;			/* -> data */
+	unsigned data_type;		/* data type */
+} wan_stat_entry_t;
+
 /****** Function Prototypes *************************************************/
 
 #ifdef CONFIG_PROC_FS
 
-/* Proc filesystem interface */
-static int router_proc_perms(struct inode *, int);
-static ssize_t router_proc_read(struct file* file, char* buf, size_t count, 					loff_t *ppos);
 
-/* Methods for preparing data for reading proc entries */
+#ifdef LINUX_2_4  /* Start of LINUX 2.4.X code */
 
-static int config_get_info(char* buf, char** start, off_t offs, int len);
-static int status_get_info(char* buf, char** start, off_t offs, int len);
-static int wandev_get_info(char* buf, char** start, off_t offs, int len);
 
-/* Miscellaneous */
+	/* Proc filesystem interface */
+	static int router_proc_perms(struct inode *, int);
+	static ssize_t router_proc_read(struct file* file, char* buf, size_t count, 					loff_t *ppos);
+
+	/* Methods for preparing data for reading proc entries */
+
+	static int config_get_info(char* buf, char** start, off_t offs, int len);
+	static int status_get_info(char* buf, char** start, off_t offs, int len);
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len);
+
+	/* Miscellaneous */
+
+	/*
+	 *	Structures for interfacing with the /proc filesystem.
+	 *	Router creates its own directory /proc/net/router with the folowing
+	 *	entries:
+	 *	config		device configuration
+	 *	status		global device statistics
+	 *	<device>	entry for each WAN device
+	 */
+
+	/*
+	 *	Generic /proc/net/router/<file> file and inode operations 
+	 */
+	static struct file_operations router_fops =
+	{
+		read:		router_proc_read,
+	};
+
+	static struct inode_operations router_inode =
+	{
+		permission:	router_proc_perms,
+	};
+
+	/*
+	 *	/proc/net/router/<device> file operations
+	 */
+
+	static struct file_operations wandev_fops =
+	{
+		read:		router_proc_read,
+		ioctl:		wanrouter_ioctl,
+	};
+
+	/*
+	 *	/proc/net/router 
+	 */
+
+	static struct proc_dir_entry *proc_router;
+
+	/* Strings */
+	static char conf_hdr[] =
+		"Device name    | port |IRQ|DMA|  mem.addr  |mem.size|"
+		"option1|option2|option3|option4\n";
+		
+	static char stat_hdr[] =
+		"Device name    |protocol|station|interface|clocking|baud rate"
+		"| MTU |ndev|link state\n";
+
+
+	/*
+	 *	Interface functions
+	 */
+
+	/*
+	 *	Initialize router proc interface.
+	 */
+
+	int __init wanrouter_proc_init (void)
+	{
+		struct proc_dir_entry *p;
+		proc_router = proc_mkdir(ROUTER_NAME, proc_net);
+		if (!proc_router)
+			goto fail;
+
+		p = create_proc_entry("config",0,proc_router);
+		if (!p)
+			goto fail_config;
+		p->proc_fops = &router_fops;
+		p->proc_iops = &router_inode;
+		p->get_info = config_get_info;
+		p = create_proc_entry("status",0,proc_router);
+		if (!p)
+			goto fail_stat;
+		p->proc_fops = &router_fops;
+		p->proc_iops = &router_inode;
+		p->get_info = status_get_info;
+		return 0;
+	fail_stat:
+		remove_proc_entry("config", proc_router);
+	fail_config:
+		remove_proc_entry(ROUTER_NAME, proc_net);
+	fail:
+		return -ENOMEM;
+	}
 
-/*
- *	Structures for interfacing with the /proc filesystem.
- *	Router creates its own directory /proc/net/wanrouter with the folowing
- *	entries:
- *	config		device configuration
- *	status		global device statistics
- *	<device>	entry for each WAN device
- */
+	/*
+	 *	Clean up router proc interface.
+	 */
+
+	void wanrouter_proc_cleanup (void)
+	{
+		remove_proc_entry("config", proc_router);
+		remove_proc_entry("status", proc_router);
+		remove_proc_entry(ROUTER_NAME,proc_net);
+	}
 
-/*
- *	Generic /proc/net/wanrouter/<file> file and inode operations 
- */
-static struct file_operations router_fops =
-{
-	read:		router_proc_read,
-};
+	/*
+	 *	Add directory entry for WAN device.
+	 */
+
+	int wanrouter_proc_add (wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
+			
+		wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
+		if (!wandev->dent)
+			return -ENOMEM;
+		wandev->dent->proc_fops	= &wandev_fops;
+		wandev->dent->proc_iops	= &router_inode;
+		wandev->dent->get_info	= wandev_get_info;
+		wandev->dent->data	= wandev;
+		return 0;
+	}
 
-static struct inode_operations router_inode =
-{
-	permission:	router_proc_perms,
-};
+	/*
+	 *	Delete directory entry for WAN device.
+	 */
+	 
+	int wanrouter_proc_delete(wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
+		remove_proc_entry(wandev->name, proc_router);
+		return 0;
+	}
 
-/*
- *	/proc/net/wanrouter/<device> file operations
- */
+	/****** Proc filesystem entry points ****************************************/
 
-static struct file_operations wandev_fops =
-{
-	read:		router_proc_read,
-	ioctl:		wanrouter_ioctl,
-};
+	/*
+	 *	Verify access rights.
+	 */
 
-/*
- *	/proc/net/wanrouter 
- */
+	static int router_proc_perms (struct inode* inode, int op)
+	{
+		return 0;
+	}
 
-static struct proc_dir_entry *proc_router;
+	/*
+	 *	Read router proc directory entry.
+	 *	This is universal routine for reading all entries in /proc/net/wanrouter
+	 *	directory.  Each directory entry contains a pointer to the 'method' for
+	 *	preparing data for that entry.
+	 *	o verify arguments
+	 *	o allocate kernel buffer
+	 *	o call get_info() to prepare data
+	 *	o copy data to user space
+	 *	o release kernel buffer
+	 *
+	 *	Return:	number of bytes copied to user space (0, if no data)
+	 *		<0	error
+	 */
+
+	static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
+					loff_t *ppos)
+	{
+		struct inode *inode = file->f_dentry->d_inode;
+		struct proc_dir_entry* dent;
+		char* page;
+		int pos, offs, len;
+
+		if (count <= 0)
+			return 0;
+			
+		dent = inode->u.generic_ip;
+		if ((dent == NULL) || (dent->get_info == NULL))
+			return 0;
+			
+		page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
+		if (page == NULL)
+			return -ENOBUFS;
+			
+		pos = dent->get_info(page, dent->data, 0, 0);
+		offs = file->f_pos;
+		if (offs < pos) {
+			len = min(pos - offs, count);
+			if(copy_to_user(buf, (page + offs), len))
+				return -EFAULT;
+			file->f_pos += len;
+		}
+		else
+			len = 0;
+		kfree(page);
+		return len;
+	}
 
-/* Strings */
-static char conf_hdr[] =
-	"Device name    | port |IRQ|DMA| mem.addr |mem.size|"
-	"option1|option2|option3|option4\n";
-	
-static char stat_hdr[] =
-	"Device name    |station|interface|clocking|baud rate| MTU |ndev"
-	"|link state\n";
+	/*
+	 *	Prepare data for reading 'Config' entry.
+	 *	Return length of data.
+	 */
+
+	static int config_get_info(char* buf, char** start, off_t offs, int len)
+	{
+		int cnt = sizeof(conf_hdr) - 1;
+		wan_device_t* wandev;
+		strcpy(buf, conf_hdr);
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 120));
+		     wandev = wandev->next) {
+			if (wandev->state) cnt += sprintf(&buf[cnt],
+				"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
+				wandev->name,
+				wandev->ioport,
+				wandev->irq,
+				wandev->dma,
+				wandev->maddr,
+				wandev->msize,
+				wandev->hw_opt[0],
+				wandev->hw_opt[1],
+				wandev->hw_opt[2],
+				wandev->hw_opt[3]);
+		}
 
+		return cnt;
+	}
 
-/*
- *	Interface functions
- */
+	/*
+	 *	Prepare data for reading 'Status' entry.
+	 *	Return length of data.
+	 */
+
+	static int status_get_info(char* buf, char** start, off_t offs, int len)
+	{
+		int cnt = 0;
+		wan_device_t* wandev;
+
+		//cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n");
+		strcpy(&buf[cnt], stat_hdr);
+		cnt += sizeof(stat_hdr) - 1;
+
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 80));
+		     wandev = wandev->next) {
+			if (!wandev->state) continue;
+			cnt += sprintf(&buf[cnt],
+				"%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+				wandev->name,
+				PROT_DECODE(wandev->config_id),
+				wandev->config_id == WANCONFIG_FR ? 
+					(wandev->station ? " Node" : " CPE") :
+					(wandev->config_id == WANCONFIG_X25 ?
+					(wandev->station ? " DCE" : " DTE") :
+					(" N/A")),
+				wandev->interface ? " V.35" : " RS-232",
+				wandev->clocking ? "internal" : "external",
+				wandev->bps,
+				wandev->mtu,
+				wandev->ndev);
+
+			switch (wandev->state) {
+
+			case WAN_UNCONFIGURED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
+				break;
+
+			case WAN_DISCONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
+				break;
+
+			case WAN_CONNECTING:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
+				break;
+
+			case WAN_CONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
+				break;
 
-/*
- *	Initialize router proc interface.
- */
+			default:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
+				break;
+			}
+		}
+		return cnt;
+	}
 
-int __init wanrouter_proc_init (void)
-{
-	struct proc_dir_entry *p;
-	proc_router = proc_mkdir(ROUTER_NAME, proc_net);
-	if (!proc_router)
-		goto fail;
-
-	p = create_proc_entry("config",0,proc_router);
-	if (!p)
-		goto fail_config;
-	p->proc_fops = &router_fops;
-	p->proc_iops = &router_inode;
-	p->get_info = config_get_info;
-	p = create_proc_entry("status",0,proc_router);
-	if (!p)
-		goto fail_stat;
-	p->proc_fops = &router_fops;
-	p->proc_iops = &router_inode;
-	p->get_info = status_get_info;
-	return 0;
-fail_stat:
-	remove_proc_entry("config", proc_router);
-fail_config:
-	remove_proc_entry(ROUTER_NAME, proc_net);
-fail:
-	return -ENOMEM;
-}
+	/*
+	 *	Prepare data for reading <device> entry.
+	 *	Return length of data.
+	 *
+	 *	On entry, the 'start' argument will contain a pointer to WAN device
+	 *	data space.
+	 */
+
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len)
+	{
+		wan_device_t* wandev = (void*)start;
+		int cnt = 0;
+		int rslt = 0;
+
+		if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
+			return 0;
+		if (!wandev->state)
+			return sprintf(&buf[cnt], "device is not configured!\n");
+
+		/* Update device statistics */
+		if (wandev->update) {
+
+			rslt = wandev->update(wandev);
+			if(rslt) {
+				switch (rslt) {
+				case -EAGAIN:
+					return sprintf(&buf[cnt], "Device is busy!\n");
+
+				default:
+					return sprintf(&buf[cnt],
+						"Device is not configured!\n");
+				}
+			}
+		}
 
-/*
- *	Clean up router proc interface.
- */
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets received", wandev->stats.rx_packets);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets transmitted", wandev->stats.tx_packets);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes received", wandev->stats.rx_bytes);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes transmitted", wandev->stats.tx_bytes);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"bad packets received", wandev->stats.rx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"packet transmit problems", wandev->stats.tx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"received frames dropped", wandev->stats.rx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit frames dropped", wandev->stats.tx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"multicast packets received", wandev->stats.multicast);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit collisions", wandev->stats.collisions);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receive length errors", wandev->stats.rx_length_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver overrun errors", wandev->stats.rx_over_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"CRC errors", wandev->stats.rx_crc_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"frame format errors (aborts)", wandev->stats.rx_frame_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver fifo overrun", wandev->stats.rx_fifo_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver missed packet", wandev->stats.rx_missed_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"aborted frames transmitted", wandev->stats.tx_aborted_errors);
+		return cnt;
+	}
 
-void wanrouter_proc_cleanup (void)
-{
-	remove_proc_entry("config", proc_router);
-	remove_proc_entry("status", proc_router);
-	remove_proc_entry(ROUTER_NAME,proc_net);
-}
 
-/*
- *	Add directory entry for WAN device.
- */
+#else /* ------------------- END OF LINUX 2.4.X VERSION -------------*/
 
-int wanrouter_proc_add (wan_device_t* wandev)
-{
-	if (wandev->magic != ROUTER_MAGIC)
-		return -EINVAL;
-		
-	wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
-	if (!wandev->dent)
-		return -ENOMEM;
-	wandev->dent->proc_fops	= &wandev_fops;
-	wandev->dent->proc_iops	= &router_inode;
-	wandev->dent->get_info	= wandev_get_info;
-	wandev->dent->data	= wandev;
-	return 0;
-}
 
-/*
- *	Delete directory entry for WAN device.
- */
- 
-int wanrouter_proc_delete(wan_device_t* wandev)
-{
-	if (wandev->magic != ROUTER_MAGIC)
-		return -EINVAL;
-	remove_proc_entry(wandev->name, proc_router);
-	return 0;
-}
 
-/****** Proc filesystem entry points ****************************************/
+	/* Proc filesystem interface */
+	static int router_proc_perms(struct inode *, int);
+#ifdef LINUX_2_1
+	static ssize_t router_proc_read(struct file *file, char *buf, size_t count, 					loff_t *ppos);
+#else
+	static int router_proc_read(
+		struct inode* inode, struct file* file, char* buf, int count);
+	static int device_write(
+		struct inode* inode, struct file* file, const char* buf, int count);
+#endif
 
-/*
- *	Verify access rights.
- */
+	/* Methods for preparing data for reading proc entries */
+	static int config_get_info(char* buf, char** start, off_t offs, int len,
+		int dummy);
+	static int status_get_info(char* buf, char** start, off_t offs, int len,
+		int dummy);
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len,
+		int dummy);
+
+	/* Miscellaneous */
+
+	/*
+	 *	Global Data
+	 */
+
+	/*
+	 *	Names of the proc directory entries 
+	 */
+
+	static char name_root[]	= ROUTER_NAME;
+	static char name_conf[]	= "config";
+	static char name_stat[]	= "status";
+
+	/*
+	 *	Structures for interfacing with the /proc filesystem.
+	 *	Router creates its own directory /proc/net/router with the folowing
+	 *	entries:
+	 *	config		device configuration
+	 *	status		global device statistics
+	 *	<device>	entry for each WAN device
+	 */
+
+	/*
+	 *	Generic /proc/net/router/<file> file and inode operations 
+	 */
+#ifdef LINUX_2_1
+	static struct file_operations router_fops =
+	{
+		NULL,			/* lseek   */
+		router_proc_read,	/* read	   */
+		NULL,			/* write   */
+		NULL,			/* readdir */
+		NULL,			/* select  */
+		NULL,			/* ioctl   */
+		NULL,			/* mmap	   */
+		NULL,			/* no special open code	   */
+		NULL,			/* flush */
+		NULL,			/* no special release code */
+		NULL			/* can't fsync */
+	};
+#else
+	static struct file_operations router_fops =
+	{
+		NULL,                   /* lseek   */
+		router_proc_read,       /* read    */
+		NULL,                   /* write   */
+		NULL,                   /* readdir */
+		NULL,                   /* select  */
+		NULL,                   /* ioctl   */
+		NULL,                   /* mmap    */
+		NULL,                   /* no special open code    */
+		NULL,                   /* no special release code */
+		NULL                    /* can't fsync */
+	};
+#endif
 
-static int router_proc_perms (struct inode* inode, int op)
-{
-	return 0;
-}
+	static struct inode_operations router_inode =
+	{
+		&router_fops,
+		NULL,			/* create */
+		NULL,			/* lookup */
+		NULL,			/* link */
+		NULL,			/* unlink */
+		NULL,			/* symlink */
+		NULL,			/* mkdir */
+		NULL,			/* rmdir */
+		NULL,			/* mknod */
+		NULL,			/* rename */
+		NULL,			/* follow link */
+		NULL,			/* readlink */
+		NULL,			/* readpage */
+		NULL,			/* writepage */
+		NULL,			/* bmap */
+		NULL,			/* truncate */
+		router_proc_perms
+	};
+
+	/*
+	 *	/proc/net/router/<device> file and inode operations
+	 */
+
+#ifdef LINUX_2_1
+	static struct file_operations wandev_fops =
+	{
+		NULL,			/* lseek   */
+		router_proc_read,	/* read	   */
+		NULL,			/* write   */
+		NULL,			/* readdir */
+		NULL,			/* select  */
+		wanrouter_ioctl,	/* ioctl   */
+		NULL,			/* mmap	   */
+		NULL,			/* no special open code	   */
+		NULL,			/* flush */
+		NULL,			/* no special release code */
+		NULL			/* can't fsync */
+	};
+#else
+	static struct file_operations wandev_fops =
+	{
+		NULL,                   /* lseek   */
+		router_proc_read,       /* read    */
+		device_write,           /* write   */
+		NULL,                   /* readdir */
+		NULL,                   /* select  */
+		wanrouter_ioctl,        /* ioctl   */
+		NULL,                   /* mmap    */
+		NULL,                   /* no special open code    */
+		NULL,                   /* no special release code */
+		NULL                    /* can't fsync */
+	};
+#endif
 
-/*
- *	Read router proc directory entry.
- *	This is universal routine for reading all entries in /proc/net/wanrouter
- *	directory.  Each directory entry contains a pointer to the 'method' for
- *	preparing data for that entry.
- *	o verify arguments
- *	o allocate kernel buffer
- *	o call get_info() to prepare data
- *	o copy data to user space
- *	o release kernel buffer
- *
- *	Return:	number of bytes copied to user space (0, if no data)
- *		<0	error
- */
+	static struct inode_operations wandev_inode =
+	{
+		&wandev_fops,
+		NULL,			/* create */
+		NULL,			/* lookup */
+		NULL,			/* link */
+		NULL,			/* unlink */
+		NULL,			/* symlink */
+		NULL,			/* mkdir */
+		NULL,			/* rmdir */
+		NULL,			/* mknod */
+		NULL,			/* rename */
+		NULL,			/* readlink */
+		NULL,			/* follow_link */
+		NULL,			/* readpage */
+		NULL,			/* writepage */
+		NULL,			/* bmap */
+		NULL,			/* truncate */
+		router_proc_perms
+	};
+
+	/*
+	 * Proc filesystem derectory entries.
+	 */
+
+	/*
+	 *	/proc/net/router 
+	 */
+	 
+	static struct proc_dir_entry proc_router =
+	{
+		0,			/* .low_ino */
+		sizeof(name_root) - 1,	/* .namelen */
+		name_root,		/* .name */
+		0555 | S_IFDIR,		/* .mode */
+		2,			/* .nlink */
+		0,			/* .uid */
+		0,			/* .gid */
+		0,			/* .size */
+		&proc_dir_inode_operations, /* .ops */
+		NULL,			/* .get_info */
+		NULL,			/* .fill_node */
+		NULL,			/* .next */
+		NULL,			/* .parent */
+		NULL,			/* .subdir */
+		NULL,			/* .data */
+	};
+
+	/*
+	 *	/proc/net/router/config 
+	 */
+	 
+	static struct proc_dir_entry proc_router_conf =
+	{
+		0,			/* .low_ino */
+		sizeof(name_conf) - 1,	/* .namelen */
+		name_conf,		/* .name */
+		0444 | S_IFREG,		/* .mode */
+		1,			/* .nlink */
+		0,			/* .uid */
+		0,			/* .gid */
+		0,			/* .size */
+		&router_inode,		/* .ops */
+		&config_get_info,	/* .get_info */
+		NULL,			/* .fill_node */
+		NULL,			/* .next */
+		NULL,			/* .parent */
+		NULL,			/* .subdir */
+		NULL,			/* .data */
+	};
+
+	/*
+	 *	/proc/net/router/status 
+	 */
+	 
+	static struct proc_dir_entry proc_router_stat =
+	{
+		0,			/* .low_ino */
+		sizeof(name_stat) - 1,	/* .namelen */
+		name_stat,		/* .name */
+		0444 | S_IFREG,		/* .mode */
+		1,			/* .nlink */
+		0,			/* .uid */
+		0,			/* .gid */
+		0,			/* .size */
+		&router_inode,		/* .ops */
+		status_get_info,	/* .get_info */
+		NULL,			/* .fill_node */
+		NULL,			/* .next */
+		NULL,			/* .parent */
+		NULL,			/* .subdir */
+		NULL,			/* .data */
+	};
+
+	/* Strings */
+	static char conf_hdr[] =
+		"Device name    | port |IRQ|DMA|  mem.addr  |mem.size|"
+		"option1|option2|option3|option4\n";
+		
+	static char stat_hdr[] =
+		"Device name    |protocol|station|interface|clocking|baud rate| MTU |ndev"
+		"|link state\n";
+
+
+	/*
+	 *	Interface functions
+	 */
+
+	/*
+	 *	Initialize router proc interface.
+	 */
+
+#ifdef LINUX_2_1
+	__initfunc(int wanrouter_proc_init (void))
+	{
+		int err = proc_register(proc_net, &proc_router);
+
+		if (!err) {
+			proc_register(&proc_router, &proc_router_conf);
+			proc_register(&proc_router, &proc_router_stat);
+		}
+		return err;
+	}
+#else
+	int wanrouter_proc_init (void)
+	{
+		int err = proc_register_dynamic(&proc_net, &proc_router);
+
+		if (!err) {
+			proc_register_dynamic(&proc_router, &proc_router_conf);
+			proc_register_dynamic(&proc_router, &proc_router_stat);
+		}
+		return err;
+	}
+#endif
 
-static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
-				loff_t *ppos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct proc_dir_entry* dent;
-	char* page;
-	int pos, offs, len;
+	/*
+	 *	Clean up router proc interface.
+	 */
+
+	void wanrouter_proc_cleanup (void)
+	{
+		proc_unregister(&proc_router, proc_router_conf.low_ino);
+		proc_unregister(&proc_router, proc_router_stat.low_ino);
+#ifdef LINUX_2_1
+		proc_unregister(proc_net, proc_router.low_ino);
+#else
+		proc_unregister(&proc_net, proc_router.low_ino);
+#endif
+	}
 
-	if (count <= 0)
-		return 0;
-		
-	dent = inode->u.generic_ip;
-	if ((dent == NULL) || (dent->get_info == NULL))
-		return 0;
+	/*
+	 *	Add directory entry for WAN device.
+	 */
+
+	int wanrouter_proc_add (wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
 		
-	page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
-	if (page == NULL)
-		return -ENOBUFS;
-		
-	pos = dent->get_info(page, dent->data, 0, 0);
-	offs = file->f_pos;
-	if (offs < pos) {
-		len = min(pos - offs, count);
-		if(copy_to_user(buf, (page + offs), len)) {
-			len = -EFAULT;
-			goto out;
-		}
-		file->f_pos += len;
-	}
-	else
-		len = 0;
-out:	kfree(page);
-	return len;
-}
-
-/*
- *	Prepare data for reading 'Config' entry.
- *	Return length of data.
- */
+		memset(&wandev->dent, 0, sizeof(wandev->dent));
+		wandev->dent.namelen	= strlen(wandev->name);
+		wandev->dent.name	= wandev->name;
+		wandev->dent.mode	= 0444 | S_IFREG;
+		wandev->dent.nlink	= 1;
+		wandev->dent.ops	= &wandev_inode;
+		wandev->dent.get_info	= &wandev_get_info;
+		wandev->dent.data	= wandev;
+#ifdef LINUX_2_1
+		return proc_register(&proc_router, &wandev->dent);
+#else
+		return proc_register_dynamic(&proc_router, &wandev->dent);
+#endif
+	}
 
-static int config_get_info(char* buf, char** start, off_t offs, int len)
-{
-	int cnt = sizeof(conf_hdr) - 1;
-	wan_device_t* wandev;
-	strcpy(buf, conf_hdr);
-	for (wandev = router_devlist;
-	     wandev && (cnt < (PROC_BUFSZ - 120));
-	     wandev = wandev->next) {
-		if (wandev->state) cnt += sprintf(&buf[cnt],
-			"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
-			wandev->name,
-			wandev->ioport,
-			wandev->irq,
-			wandev->dma,
-			wandev->maddr,
-			wandev->msize,
-			wandev->hw_opt[0],
-			wandev->hw_opt[1],
-			wandev->hw_opt[2],
-			wandev->hw_opt[3]);
+	/*
+	 *	Delete directory entry for WAN device.
+	 */
+	 
+	int wanrouter_proc_delete(wan_device_t* wandev)
+	{
+		if (wandev->magic != ROUTER_MAGIC)
+			return -EINVAL;
+		proc_unregister(&proc_router, wandev->dent.low_ino);
+		return 0;
 	}
 
-	return cnt;
-}
+	/****** Proc filesystem entry points ****************************************/
 
-/*
- *	Prepare data for reading 'Status' entry.
- *	Return length of data.
- */
+	/*
+	 *	Verify access rights.
+	 */
 
-static int status_get_info(char* buf, char** start, off_t offs, int len)
-{
-	int cnt = 0;
-	wan_device_t* wandev;
+	static int router_proc_perms (struct inode* inode, int op)
+	{
+		return 0;
+	}
 
-	cnt += sprintf(&buf[cnt], "\nSTATUS FOR PORT 0\n\n");
-	strcpy(&buf[cnt], stat_hdr);
-	cnt += sizeof(stat_hdr) - 1;
-
-	for (wandev = router_devlist;
-	     wandev && (cnt < (PROC_BUFSZ - 80));
-	     wandev = wandev->next) {
-		if (!wandev->state) continue;
-		cnt += sprintf(&buf[cnt],
-			"%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
-			wandev->name,
-			wandev->station ? " DCE" : " DTE",
-			wandev->interface ? " V.35" : " RS-232",
-			wandev->clocking ? "internal" : "external",
-			wandev->bps,
-			wandev->mtu,
-			wandev->ndev);
-
-		switch (wandev->state) {
-
-		case WAN_UNCONFIGURED:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
-			break;
-
-		case WAN_DISCONNECTED:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
-			break;
-
-		case WAN_CONNECTING:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
-			break;
-
-		case WAN_CONNECTED:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
-			break;
-
-		default:
-			cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
-			break;
+	/*
+	 *	Read router proc directory entry.
+	 *	This is universal routine for reading all entries in /proc/net/wanrouter
+	 *	directory.  Each directory entry contains a pointer to the 'method' for
+	 *	preparing data for that entry.
+	 *	o verify arguments
+	 *	o allocate kernel buffer
+	 *	o call get_info() to prepare data
+	 *	o copy data to user space
+	 *	o release kernel buffer
+	 *
+	 *	Return:	number of bytes copied to user space (0, if no data)
+	 *		<0	error
+	 */
+#ifdef LINUX_2_1
+	static ssize_t router_proc_read(struct file* file, char* buf, size_t count,
+					loff_t *ppos)
+	{
+		struct inode *inode = file->f_dentry->d_inode;
+		struct proc_dir_entry* dent;
+		char* page;
+		int pos, offs, len;
+
+		if (count <= 0)
+			return 0;
+			
+		dent = inode->u.generic_ip;
+		if ((dent == NULL) || (dent->get_info == NULL))
+			return 0;
+			
+		page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
+		if (page == NULL)
+			return -ENOBUFS;
+			
+		pos = dent->get_info(page, dent->data, 0, 0, 0);
+		offs = file->f_pos;
+		if (offs < pos) {
+			len = min(pos - offs, count);
+			if(copy_to_user(buf, (page + offs), len))
+				return -EFAULT;
+			file->f_pos += len;
 		}
+		else
+			len = 0;
+		kfree(page);
+		return len;
 	}
-	return cnt;
-}
 
-/*
- *	Prepare data for reading <device> entry.
- *	Return length of data.
- *
- *	On entry, the 'start' argument will contain a pointer to WAN device
- *	data space.
- */
+#else
+	static int router_proc_read(
+		struct inode* inode, struct file* file, char* buf, int count)
+	{
+		struct proc_dir_entry* dent;
+		char* page;
+		int err, pos, offs, len;
+
+		if (count <= 0)
+			return 0;
+		dent = inode->u.generic_ip;
+		if ((dent == NULL) || (dent->get_info == NULL))
+			return -ENODATA;
+		err = verify_area(VERIFY_WRITE, buf, count);
+		if (err) return err;
+
+		page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
+		if (page == NULL)
+			return -ENOMEM;
+
+		pos = dent->get_info(page, dent->data, 0, 0, 0);
+		offs = file->f_pos;
+		if (offs < pos) {
+			len = min(pos - offs, count);
+			memcpy_tofs((void*)buf, (void*)(page + offs), len);
+			file->f_pos += len;
+		}
+		else len = 0;
+		kfree(page);
+		return len;
+	}
+#endif
 
-static int wandev_get_info(char* buf, char** start, off_t offs, int len)
-{
-	wan_device_t* wandev = (void*)start;
-	int cnt = 0;
-	int rslt = 0;
 
-	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
-		return 0;
-	if (!wandev->state)
-		return sprintf(&buf[cnt], "device is not configured!\n");
+	/*
+	 *	Prepare data for reading 'Config' entry.
+	 *	Return length of data.
+	 */
+
+	static int config_get_info(char* buf, char** start, off_t offs, int len, 
+		int dummy)
+	{
+		int cnt = sizeof(conf_hdr) - 1;
+		wan_device_t* wandev;
+		strcpy(buf, conf_hdr);
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 120));
+		     wandev = wandev->next) {
+			if (wandev->state) cnt += sprintf(&buf[cnt],
+				"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
+				wandev->name,
+				wandev->ioport,
+				wandev->irq,
+				wandev->dma,
+				wandev->maddr,
+				wandev->msize,
+				wandev->hw_opt[0],
+				wandev->hw_opt[1],
+				wandev->hw_opt[2],
+				wandev->hw_opt[3]);
+		}
 
-	/* Update device statistics */
-	if (wandev->update) {
+		return cnt;
+	}
 
-		rslt = wandev->update(wandev);
-		if(rslt) {
-			switch (rslt) {
-			case -EAGAIN:
-				return sprintf(&buf[cnt], "Device is busy!\n");
+	/*
+	 *	Prepare data for reading 'Status' entry.
+	 *	Return length of data.
+	 */
+
+	static int status_get_info(char* buf, char** start, off_t offs, int len, 
+				int dummy)
+	{
+		int cnt = 0;
+		wan_device_t* wandev;
+
+		//cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n");
+		strcpy(&buf[cnt], stat_hdr);
+		cnt += sizeof(stat_hdr) - 1;
+
+		for (wandev = router_devlist;
+		     wandev && (cnt < (PROC_BUFSZ - 80));
+		     wandev = wandev->next) {
+			if (!wandev->state) continue;
+			cnt += sprintf(&buf[cnt],
+				"%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+				wandev->name,
+				PROT_DECODE(wandev->config_id),
+				wandev->config_id == WANCONFIG_FR ? 
+					(wandev->station ? " Node" : " CPE") :
+					(wandev->config_id == WANCONFIG_X25 ?
+					(wandev->station ? " DCE" : " DTE") :
+					(" N/A")),
+				wandev->interface ? " V.35" : " RS-232",
+				wandev->clocking ? "internal" : "external",
+				wandev->bps,
+				wandev->mtu,
+				wandev->ndev);
+
+			switch (wandev->state) {
+
+			case WAN_UNCONFIGURED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
+				break;
+
+			case WAN_DISCONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
+				break;
+
+			case WAN_CONNECTING:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
+				break;
+
+			case WAN_CONNECTED:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
+				break;
+
+			case WAN_FT1_READY:
+				cnt += sprintf(&buf[cnt], "%-12s\n", "ft1 ready");
+				break;
 
 			default:
-				return sprintf(&buf[cnt],
-					"Device is not configured!\n");
+				cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
+				break;
 			}
 		}
+		return cnt;
 	}
 
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total packets received", wandev->stats.rx_packets);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total packets transmitted", wandev->stats.tx_packets);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total bytes received", wandev->stats.rx_bytes);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "total bytes transmitted", wandev->stats.tx_bytes);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "bad packets received", wandev->stats.rx_errors);
-       	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "packet transmit problems", wandev->stats.tx_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "received frames dropped", wandev->stats.rx_dropped);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "transmit frames dropped", wandev->stats.tx_dropped);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "multicast packets received", wandev->stats.multicast);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "transmit collisions", wandev->stats.collisions);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "receive length errors", wandev->stats.rx_length_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"receiver overrun errors", wandev->stats.rx_over_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"CRC errors", wandev->stats.rx_crc_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"frame format errors (aborts)", wandev->stats.rx_frame_errors);
-        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-                "receiver fifo overrun", wandev->stats.rx_fifo_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"receiver missed packet", wandev->stats.rx_missed_errors);
-	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
-		"aborted frames transmitted", wandev->stats.tx_aborted_errors);
-  	return cnt;
-}
+	/*
+	 *	Prepare data for reading <device> entry.
+	 *	Return length of data.
+	 *
+	 *	On entry, the 'start' argument will contain a pointer to WAN device
+	 *	data space.
+	 */
+
+	static int wandev_get_info(char* buf, char** start, off_t offs, int len, 
+				int dummy)
+	{
+		wan_device_t* wandev = (void*)start;
+		int cnt = 0;
+		int rslt = 0;
+
+		if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
+			return 0;
+		if (!wandev->state)
+			return sprintf(&buf[cnt], "Device is not configured!\n");
+
+		/* Update device statistics */
+		if (wandev->update) {
+
+			rslt = wandev->update(wandev);
+			if(rslt) {
+				switch (rslt) {
+				case -EAGAIN:
+					return sprintf(&buf[cnt], "Device is busy!\n");
+
+				default:
+					return sprintf(&buf[cnt],
+						"Device is not configured!\n");
+				}
+			}
+		}
+
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets received", wandev->stats.rx_packets);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total packets transmitted", wandev->stats.tx_packets);
+#ifdef LINUX_2_1
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes received", wandev->stats.rx_bytes);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"total bytes transmitted", wandev->stats.tx_bytes);
+#endif
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"bad packets received", wandev->stats.rx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"packet transmit problems", wandev->stats.tx_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"received frames dropped", wandev->stats.rx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit frames dropped", wandev->stats.tx_dropped);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"multicast packets received", wandev->stats.multicast);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"transmit collisions", wandev->stats.collisions);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receive length errors", wandev->stats.rx_length_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver overrun errors", wandev->stats.rx_over_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"CRC errors", wandev->stats.rx_crc_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"frame format errors (aborts)", wandev->stats.rx_frame_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver fifo overrun", wandev->stats.rx_fifo_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"receiver missed packet", wandev->stats.rx_missed_errors);
+		cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+			"aborted frames transmitted", wandev->stats.tx_aborted_errors);
+
+		return cnt;
+	}
+
+#endif /* End of ifdef LINUX_2_4 */
+
 
-/*
- *	End
- */
- 
 #else
 
 /*
  *	No /proc - output stubs
  */
- 
-int __init wanrouter_proc_init(void)
+
+__initfunc(int wanrouter_proc_init(void))
 {
 	return 0;
 }
@@ -436,6 +1055,33 @@
 	return 0;
 }
 
+#endif
+
+/*============================================================================
+ * Write WAN device ???.
+ * o Find WAN device associated with this node
+ */
+#ifdef LINUX_2_0
+static int device_write(
+        struct inode* inode, struct file* file, const char* buf, int count)
+{
+        int err = verify_area(VERIFY_READ, buf, count);
+        struct proc_dir_entry* dent;
+        wan_device_t* wandev;
+
+        if (err) return err;
+
+        dent = inode->u.generic_ip;
+        if ((dent == NULL) || (dent->data == NULL))
+                return -ENODATA;
+
+        wandev = dent->data;
+
+        printk(KERN_ERR "%s: writing %d bytes to %s...\n",
+                name_root, count, dent->name);
+        
+	return 0;
+}
 #endif
 
 /*
diff -u --recursive --new-file v2.4.3/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.4.3/linux/net/x25/af_x25.c	Mon Jan 22 13:32:10 2001
+++ linux/net/x25/af_x25.c	Thu Apr 12 12:11:39 2001
@@ -409,6 +409,9 @@
 
 	len = min(len, sizeof(int));
 
+	if (len < 0)
+		return -EINVAL;
+		
 	if (put_user(len, optlen))
 		return -EFAULT;
 
@@ -912,7 +915,7 @@
 
 	size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 	X25_SKB_CB(skb)->flags = msg->msg_flags;
 
@@ -1283,6 +1286,7 @@
 	sendmsg:	x25_sendmsg,
 	recvmsg:	x25_recvmsg,
 	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
 };
 
 #include <linux/smp_lock.h>
diff -u --recursive --new-file v2.4.3/linux/net/x25/x25_out.c linux/net/x25/x25_out.c
--- v2.4.3/linux/net/x25/x25_out.c	Wed Jan 24 15:28:36 2001
+++ linux/net/x25/x25_out.c	Thu Apr 12 12:11:39 2001
@@ -79,7 +79,7 @@
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, noblock, &err)) == NULL){
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, noblock, &err)) == NULL){
 				if(err == -EWOULDBLOCK && noblock){
 					kfree_skb(skb);
 					return sent;
diff -u --recursive --new-file v2.4.3/linux/scripts/kernel-doc linux/scripts/kernel-doc
--- v2.4.3/linux/scripts/kernel-doc	Fri Dec 29 14:35:47 2000
+++ linux/scripts/kernel-doc	Wed Apr 25 16:31:16 2001
@@ -1,16 +1,27 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w
+
+use strict;
 
 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
-## Copyright (C) 2000  Tim Waugh <twaugh@redhat.com>             ##
+## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
+## Copyright (C) 2001  Simon Huggins                             ##
+## 								 ##
+## #define enhancements by Armin Kuster <akuster@mvista.com>	 ##
+## Copyright (c) 2000 MontaVista Software, Inc.			 ##
 ## 								 ##
-## #define enhancements by Armin Kuster <akuster@mvista.com>	 ## 
-## Copyright (c) 2000 MontaVista Software, Inc.			 ##   
-##                                                               ##
 ## This software falls under the GNU General Public License.     ##
 ## Please read the COPYING file for more information             ##
 
 # w.o. 03-11-2000: added the '-filelist' option.
 
+# 18/01/2001 - 	Cleanups
+# 		Functions prototyped as foo(void) same as foo()
+# 		Stop eval'ing where we don't need to.
+# -- huggie@earth.li
+# Still to do:
+# 	- add perldoc documentation
+# 	- Look more closely at some of the scarier bits :)
+
 #
 # This will read a 'c' file and scan for embedded comments in the
 # style of gnome comments (+minor extensions - see below).
@@ -87,53 +98,53 @@
 # '%CONST' - name of a constant.
 
 # match expressions used to find embedded type information
-$type_constant = "\\\%([-_\\w]+)";
-$type_func = "(\\w+)\\(\\)";
-$type_param = "\\\@(\\w+)";
-$type_struct = "\\\&((struct\\s*)?[_\\w]+)";
-$type_env = "(\\\$\\w+)";
+my $type_constant = '\%([-_\w]+)';
+my $type_func = '(\w+)\(\)';
+my $type_param = '\@(\w+)';
+my $type_struct = '\&((struct\s*)?[_\w]+)';
+my $type_env = '(\$\w+)';
 
 
 # Output conversion substitutions.
 #  One for each output format
 
 # these work fairly well
-%highlights_html = ( $type_constant, "<i>\$1</i>",
-		     $type_func, "<b>\$1</b>",
-		     $type_struct, "<i>\$1</i>",
-		     $type_param, "<tt><b>\$1</b></tt>" );
-$blankline_html = "<p>";
+my %highlights_html = ( $type_constant, "<i>\$1</i>",
+			$type_func, "<b>\$1</b>",
+			$type_struct, "<i>\$1</i>",
+			$type_param, "<tt><b>\$1</b></tt>" );
+my $blankline_html = "<p>";
 
 # sgml, docbook format
-%highlights_sgml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
-		     $type_constant, "<constant>\$1</constant>",
-		     $type_func, "<function>\$1</function>",
-		     $type_struct, "<structname>\$1</structname>",
-		     $type_env, "<envar>\$1</envar>",
-		     $type_param, "<parameter>\$1</parameter>" );
-$blankline_sgml = "</para><para>\n";
+my %highlights_sgml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
+			$type_constant, "<constant>\$1</constant>",
+			$type_func, "<function>\$1</function>",
+			$type_struct, "<structname>\$1</structname>",
+			$type_env, "<envar>\$1</envar>",
+			$type_param, "<parameter>\$1</parameter>" );
+my $blankline_sgml = "</para><para>\n";
 
 # gnome, docbook format
-%highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
-		     $type_func, "<function>\$1</function>",
-		     $type_struct, "<structname>\$1</structname>",
-		     $type_env, "<envar>\$1</envar>",
-		     $type_param, "<parameter>\$1</parameter>" );
-$blankline_gnome = "</para><para>\n";
+my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
+			 $type_func, "<function>\$1</function>",
+			 $type_struct, "<structname>\$1</structname>",
+			 $type_env, "<envar>\$1</envar>",
+			 $type_param, "<parameter>\$1</parameter>" );
+my $blankline_gnome = "</para><para>\n";
 
 # these are pretty rough
-%highlights_man = ( $type_constant, "\$1",
-		    $type_func, "\\\\fB\$1\\\\fP",
-		    $type_struct, "\\\\fI\$1\\\\fP",
-		    $type_param, "\\\\fI\$1\\\\fP" );
-$blankline_man = "";
+my %highlights_man = ( $type_constant, "\$1",
+		       $type_func, "\\\\fB\$1\\\\fP",
+		       $type_struct, "\\\\fI\$1\\\\fP",
+		       $type_param, "\\\\fI\$1\\\\fP" );
+my $blankline_man = "";
 
 # text-mode
-%highlights_text = ( $type_constant, "\$1",
-		     $type_func, "\$1",
-		     $type_struct, "\$1",
-		     $type_param, "\$1" );
-$blankline_text = "";
+my %highlights_text = ( $type_constant, "\$1",
+			$type_func, "\$1",
+			$type_struct, "\$1",
+			$type_param, "\$1" );
+my $blankline_text = "";
 
 
 sub usage {
@@ -149,16 +160,52 @@
     usage();
 }
 
-$verbose = 0;
-$output_mode = "man";
-%highlights = %highlights_man;
-$blankline = $blankline_man;
-$modulename = "API Documentation";
-$function_only = 0;
-$filelist = '';
+my $verbose = 0;
+my $output_mode = "man";
+my %highlights = %highlights_man;
+my $blankline = $blankline_man;
+my $modulename = "Kernel API";
+my $function_only = 0;
+
+# Essentially these are globals
+# They probably want to be tidied up made more localised or summat.
+# CAVEAT EMPTOR!  Some of the others I localised may not want to be which
+# could cause "use of undefined value" or other bugs.
+my ($function, %function_table,%parametertypes,$function_purpose);
+my ($type,$file,$function_name,$return_type);
+my ($newsection,$newcontents,$prototype,$filelist);
+
+my $lineprefix="";
+
+# states
+# 0 - normal code
+# 1 - looking for function name
+# 2 - scanning field start.
+# 3 - scanning prototype.
+my $state = 0;
+my $doc_special = "\@\%\$\&";
+
+my $doc_start = "^/\\*\\*\$";
+my $doc_end = "\\*/";
+my $doc_com = "\\s*\\*\\s*";
+my $doc_func = $doc_com."(\\w+):?";
+my $doc_sect = $doc_com."([".$doc_special."]?[\\w ]+):(.*)";
+my $doc_content = $doc_com."(.*)";
+my $doc_block = $doc_com."DOC:\\s*(.*)?";
+
+my %constants = ();
+my %parameters = ();
+my @parameterlist = ();
+my %sections = ();
+my @sectionlist = ();
+
+my $contents = "";
+my $section_default = "Description";	# default section
+my $section_intro = "Introduction";
+my $section = $section_default;
 
 while ($ARGV[0] =~ m/^-(.*)/) {
-    $cmd = shift @ARGV;
+    my $cmd = shift @ARGV;
     if ($cmd eq "-html") {
 	$output_mode = "html";
 	%highlights = %highlights_html;
@@ -201,8 +248,8 @@
 
 # generate a sequence of code that will splice in highlighting information
 # using the s// operator.
-$dohighlight = "";
-foreach $pattern (keys %highlights) {
+my $dohighlight = "";
+foreach my $pattern (keys %highlights) {
 #    print "scanning pattern $pattern ($highlights{$pattern})\n";
     $dohighlight .=  "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
 }
@@ -211,7 +258,7 @@
 # dumps section contents to arrays/hashes intended for that purpose.
 #
 sub dump_section {
-    my $name = shift @_;
+    my $name = shift;
     my $contents = join "\n", @_;
 
     if ($name =~ m/$type_constant/) {
@@ -240,11 +287,18 @@
 #  sections => %descriont descriptions
 #  
 
-sub output_highlight {
-    my $contents = join "\n", @_;
+sub output_highlight(@) {
+    my $contents = join "\n",@_;
     my $line;
 
+#	DEBUG
+#	if (!defined $contents) {
+#	    use Carp;
+#	    confess "output_highlight got called with no args?\n";
+#    }
+
     eval $dohighlight;
+    die $@ if $@;
     foreach $line (split "\n", $contents) {
 	if ($line eq ""){
 	    print $lineprefix, $blankline;
@@ -258,7 +312,7 @@
 
 
 # output in html
-sub output_html {
+sub output_html(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -302,7 +356,7 @@
 
 
 # output in html
-sub output_intro_html {
+sub output_intro_html(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -316,10 +370,8 @@
     print "<hr>\n";
 }
 
-
-
 # output in sgml DocBook
-sub output_sgml {
+sub output_sgml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -347,13 +399,6 @@
     print "<function>".$args{'function'}." ";
     print "</function></funcdef>\n";
 
-#    print "<refsect1>\n";
-#    print " <title>Synopsis</title>\n";
-#    print "  <funcsynopsis>\n";
-#    print "   <funcdef>".$args{'functiontype'}." ";
-#    print "<function>".$args{'function'}." ";
-#    print "</function></funcdef>\n";
-
     $count = 0;
     if ($#{$args{'parameterlist'}} >= 0) {
 	foreach $parameter (@{$args{'parameterlist'}}) {
@@ -372,11 +417,9 @@
     }
     print "  </funcsynopsis>\n";
     print "</refsynopsisdiv>\n";
-#    print "</refsect1>\n";
 
     # print parameters
     print "<refsect1>\n <title>Arguments</title>\n";
-#    print "<para>\nArguments\n";
     if ($#{$args{'parameterlist'}} >= 0) {
 	print " <variablelist>\n";
 	foreach $parameter (@{$args{'parameterlist'}}) {
@@ -396,12 +439,10 @@
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
 	print "<refsect1>\n <title>$section</title>\n <para>\n";
-#	print "<para>\n$section\n";
 	if ($section =~ m/EXAMPLE/i) {
 	    print "<example><para>\n";
 	}
 	output_highlight($args{'sections'}{$section});
-#	print "</para>";
 	if ($section =~ m/EXAMPLE/i) {
 	    print "</para></example>\n";
 	}
@@ -412,25 +453,22 @@
 }
 
 # output in sgml DocBook
-sub output_intro_sgml {
+sub output_intro_sgml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
-    my $id;
 
-    $id = $args{'module'};
+    my $id = $args{'module'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     # print out each section
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
 	print "<refsect1>\n <title>$section</title>\n <para>\n";
-#	print "<para>\n$section\n";
 	if ($section =~ m/EXAMPLE/i) {
 	    print "<example><para>\n";
 	}
 	output_highlight($args{'sections'}{$section});
-#	print "</para>";
 	if ($section =~ m/EXAMPLE/i) {
 	    print "</para></example>\n";
 	}
@@ -453,8 +491,6 @@
     print "<sect2>\n";
     print " <title id=\"$id\">".$args{'function'}."</title>\n";
 
-#    print "<simplesect>\n";
-#    print " <title>Synopsis</title>\n";
     print "  <funcsynopsis>\n";
     print "   <funcdef>".$args{'functiontype'}." ";
     print "<function>".$args{'function'}." ";
@@ -477,27 +513,6 @@
 	print "  <void>\n";
     }
     print "  </funcsynopsis>\n";
-#    print "</simplesect>\n";
-#    print "</refsect1>\n";
-
-    # print parameters
-#    print "<simplesect>\n <title>Arguments</title>\n";
-#    if ($#{$args{'parameterlist'}} >= 0) {
-#	print " <variablelist>\n";
-#	foreach $parameter (@{$args{'parameterlist'}}) {
-#	    print "  <varlistentry>\n   <term><parameter>$parameter</parameter></term>\n";
-#	    print "   <listitem>\n    <para>\n";
-#	    $lineprefix="     ";
-#	    output_highlight($args{'parameters'}{$parameter});
-#	    print "    </para>\n   </listitem>\n  </varlistentry>\n";
-#	}
-#	print " </variablelist>\n";
-#    } else {
-#	print " <para>\n  None\n </para>\n";
-#    }
-#    print "</simplesect>\n";
-
-#    print "<simplesect>\n <title>Arguments</title>\n";
     if ($#{$args{'parameterlist'}} >= 0) {
 	print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
 	print "<tgroup cols=\"2\">\n";
@@ -515,20 +530,17 @@
     } else {
 	print " <para>\n  None\n </para>\n";
     }
-#    print "</simplesect>\n";
 
     # print out each section
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
 	print "<simplesect>\n <title>$section</title>\n";
-#	print "<para>\n$section\n";
 	if ($section =~ m/EXAMPLE/i) {
 	    print "<example><programlisting>\n";
 	} else {
 	}
 	print "<para>\n";
 	output_highlight($args{'sections'}{$section});
-#	print "</para>";
 	print "</para>\n";
 	if ($section =~ m/EXAMPLE/i) {
 	    print "</programlisting></example>\n";
@@ -542,12 +554,12 @@
 
 ##
 # output in man
-sub output_man {
+sub output_man(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
 
-    print ".TH \"$args{'module'}\" 4 \"$args{'function'}\" \"25 May 1998\" \"API Manual\" LINUX\n";
+    print ".TH \"$args{'module'}\" 9 \"$args{'function'}\" \"April 2001\" \"API Manual\" LINUX\n";
 
     print ".SH NAME\n";
     print $args{'function'}." \\- ".$args{'purpose'}."\n";
@@ -555,9 +567,9 @@
     print ".SH SYNOPSIS\n";
     print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n";
     $count = 0;
-    $parenth = "(";
-    $post = ",";
-    foreach $parameter (@{$args{'parameterlist'}}) {
+    my $parenth = "(";
+    my $post = ",";
+    foreach my $parameter (@{$args{'parameterlist'}}) {
 	if ($count == $#{$args{'parameterlist'}}) {
 	    $post = ");";
 	}
@@ -566,7 +578,7 @@
 	    # pointer-to-function
 	    print ".BI \"".$parenth.$1."\" ".$parameter." \") (".$2.")".$post."\"\n";
 	} else {
-	    $type =~ s/([^\*])$/\1 /;
+	    $type =~ s/([^\*])$/$1 /;
 	    print ".BI \"".$parenth.$type."\" ".$parameter." \"".$post."\"\n";
 	}
 	$count++;
@@ -584,12 +596,12 @@
     }
 }
 
-sub output_intro_man {
+sub output_intro_man(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
 
-    print ".TH \"$args{'module'}\" 4 \"$args{'module'}\" \"25 May 1998\" \"API Manual\" LINUX\n";
+    print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"April 2001\" \"API Manual\" LINUX\n";
 
     foreach $section (@{$args{'sectionlist'}}) {
 	print ".SH \"$section\"\n";
@@ -599,15 +611,15 @@
 
 ##
 # output in text
-sub output_text {
+sub output_text(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
 
     print "Function:\n\n";
-    $start=$args{'functiontype'}." ".$args{'function'}." (";
+    my $start=$args{'functiontype'}." ".$args{'function'}." (";
     print $start;
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
+    my $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
 	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
 	    # pointer-to-function
 	    print $1.$parameter.") (".$2;
@@ -634,7 +646,7 @@
     print "\n\n";
 }
 
-sub output_intro_text {
+sub output_intro_text(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
 
@@ -649,24 +661,28 @@
 # generic output function - calls the right one based
 # on current output mode.
 sub output_function {
-#    output_html(@_);
-    eval "output_".$output_mode."(\@_);";
+    no strict 'refs';
+    my $func = "output_".$output_mode;
+    &$func(@_);
 }
 
 ##
 # generic output function - calls the right one based
 # on current output mode.
 sub output_intro {
-#    output_html(@_);
-    eval "output_intro_".$output_mode."(\@_);";
+    no strict 'refs';
+    my $func = "output_intro_".$output_mode;
+    &$func(@_);
 }
 
 
 ##
-# takes a function prototype and spits out all the details
-# stored in the global arrays/hashes.
-sub dump_function {
-    my $prototype = shift @_;
+# takes a function prototype and the name of the current file being
+# processed and spits out all the details stored in the global
+# arrays/hashes.
+sub dump_function($$) {
+    my $prototype = shift;
+    my $file = shift;
 
     $prototype =~ s/^static +//;
     $prototype =~ s/^extern +//;
@@ -706,15 +722,18 @@
 	$prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
 	$return_type = $1;
 	$function_name = $2;
-	$args = $3;
+	my $args = $3;
+	my ($param);
 
-	# allow for up to fours args to function pointers
-	$args =~ s/(\([^\),]+),/\1#/g;
-	$args =~ s/(\([^\),]+),/\1#/g;
-	$args =~ s/(\([^\),]+),/\1#/g;
+	# allow for up to six args to function pointers
+	$args =~ s/(\([^\),]+),/$1#/g;
+	$args =~ s/(\([^\),]+),/$1#/g;
+	$args =~ s/(\([^\),]+),/$1#/g;
+	$args =~ s/(\([^\),]+),/$1#/g;
+	$args =~ s/(\([^\),]+),/$1#/g;
 #	print STDERR "ARGS = '$args'\n";
 
-	foreach $arg (split ',', $args) {
+	foreach my $arg (split ',', $args) {
 	    # strip leading/trailing spaces
 	    $arg =~ s/^\s*//;
 	    $arg =~ s/\s*$//;
@@ -725,12 +744,12 @@
 		$arg =~ m/[^\(]+\(\*([^\)]+)\)/;
 		$param = $1;
 		$type = $arg;
-		$type =~ s/([^\(]+\(\*)$param/\1/;
+		$type =~ s/([^\(]+\(\*)$param/$1/;
 	    } else {
 		# evil magic to get fixed array parameters to work
-		$arg =~ s/(.+\s+)(.+)\[.*/\1* \2/;
+		$arg =~ s/(.+\s+)(.+)\[.*/$1* $2/;
 #		print STDERR "SCAN ARG: '$arg'\n";
-		@args = split('\s', $arg);
+		my @args = split('\s', $arg);
 
 #		print STDERR " -> @args\n";
 		$param = pop @args;
@@ -748,15 +767,15 @@
 		$param="...";
 		$parameters{"..."} = "variable arguments";
 	    }
-	    elsif ($type eq "" && $param eq "")
+	    elsif ($type eq "" && ($param eq "" or $param eq "void"))
 	    {
 		$type="";
 		$param="void";
 		$parameters{void} = "no arguments";
 	    }
-            if ($type ne "" && $parameters{$param} eq "") {
+            if (defined $type && $type && !defined $parameters{$param}) {
 	        $parameters{$param} = "-- undescribed --";
-	        print STDERR "Warning($file:$lineno): Function parameter '$param' not described in '$function_name'\n";
+	        print STDERR "Warning($file:$.): Function parameter '$param' not described in '$function_name'\n";
 	    }
 
 	    push @parameterlist, $param;
@@ -764,7 +783,7 @@
 #	    print STDERR "param = '$param', type = '$type'\n";
 	}
     } else {
-	print STDERR "Error($lineno): cannot understand prototype: '$prototype'\n";
+	print STDERR "Error($.): cannot understand prototype: '$prototype'\n";
 	return;
     }
 
@@ -816,7 +835,9 @@
 $section_intro = "Introduction";
 $section = $section_default;
 
-if( $filelist ne '' ) {
+sub process_file($);
+
+if ($filelist) {
 	open(FLIST,"<$filelist") or die "Can't open file list $filelist";
 	while(<FLIST>) {
 		chop;
@@ -824,9 +845,9 @@
 	}
 }
 
-foreach $file (@ARGV) {
-    chomp($file);
-    process_file($file);
+foreach (@ARGV) {
+    chomp;
+    process_file($_);
 }
 
 sub process_file($) {
@@ -837,10 +858,7 @@
 	return;
     }
 
-    $lineno = 0;
     while (<IN>) {
-	$lineno++;
-
 	if ($state == 0) {
 	    if (/$doc_start/o) {
 		$state = 1;		# next line is always the function name
@@ -864,10 +882,10 @@
 		    $function_purpose = "";
 		}
 		if ($verbose) {
-		    print STDERR "Info($lineno): Scanning doc for $function\n";
+		    print STDERR "Info($.): Scanning doc for $function\n";
 		}
 	    } else {
-		print STDERR "WARN($lineno): Cannot understand $_ on line $lineno",
+		print STDERR "WARN($.): Cannot understand $_ on line $.",
 		" - I thought it was a doc line\n";
 		$state = 0;
 	    }
@@ -918,7 +936,7 @@
 		}
 	    } else {
 		# i dont know - bad line?  ignore.
-		print STDERR "WARNING($lineno): bad line: $_"; 
+		print STDERR "WARNING($.): bad line: $_"; 
 	    }
 	} elsif ($state == 3) {	# scanning for function { (end of prototype)
 	    if (m#\s*/\*\s+MACDOC\s*#io) {
@@ -931,7 +949,7 @@
 		$prototype =~ s@/\*.*?\*/@@gos;	# strip comments.
 		$prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
 		$prototype =~ s@^ +@@gos; # strip leading spaces
-		dump_function($prototype);
+		dump_function($prototype,$file);
 
 		$function = "";
 		%constants = ();
diff -u --recursive --new-file v2.4.3/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c
--- v2.4.3/linux/scripts/lxdialog/checklist.c	Sun Feb  4 10:05:30 2001
+++ linux/scripts/lxdialog/checklist.c	Fri Apr  6 10:42:55 2001
@@ -211,13 +211,15 @@
 		    status[i+scroll], i, i == choice);
     }
 
-    wnoutrefresh (list);
-
     print_arrows(dialog, choice, item_no, scroll,
 			box_y, box_x + check_x + 5, list_height);
 
     print_buttons(dialog, height, width, 0);
 
+    wnoutrefresh (list);
+    wnoutrefresh (dialog);
+    doupdate ();
+
     while (key != ESC) {
 	key = wgetch (dialog);
 
@@ -355,7 +357,11 @@
 	case ESC:
 	    break;
 	}
+
+	/* Now, update everything... */
+	doupdate ();
     }
+    
 
     delwin (dialog);
     free (status);
diff -u --recursive --new-file v2.4.3/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.4.3/linux/scripts/tkgen.c	Mon Jun 19 13:45:52 2000
+++ linux/scripts/tkgen.c	Fri Apr  6 10:42:55 2001
@@ -155,7 +155,7 @@
     printf("\"catch {focus $oldFocus}; " );
     /* 
      * We are checking which windows should be destroyed and which are 
-     * common parrents with the next one. Remember that menu_num field
+     * common parents with the next one. Remember that menu_num field
      * in mainmenu_option record reports number of its *parent* menu.
      */
     if ( menu_num < tot_menu_num
diff -u --recursive --new-file v2.4.3/linux/scripts/ver_linux linux/scripts/ver_linux
--- v2.4.3/linux/scripts/ver_linux	Fri Mar  2 11:12:12 2001
+++ linux/scripts/ver_linux	Thu Apr 12 12:16:36 2001
@@ -20,7 +20,9 @@
 ld -v 2>&1 | awk -F\) '{print $1}' | awk \
       '/BFD/{print "binutils              ",$NF}'
 
-mount --version | awk -F\- '{print "util-linux            ", $NF}'
+fdformat --version | awk -F\- '{print "util-linux            ", $NF}'
+
+mount --version | awk -F\- '{print "mount                 ", $NF}'
 
 insmod -V  2>&1 | awk 'NR==1 {print "modutils              ",$NF}'
 
